/// <summary> /// Initializes a new instance of <see cref="SpannerCommand"/> /// </summary> /// <param name="commandText">If this command is a SQL Query, then commandText is /// the SQL statement. If its an update, insert or delete command, then this text /// is "[operation] [table]" such as "UPDATE MYTABLE"</param>. Must not be null. /// <param name="connection">The <see cref="SpannerConnection"/> that is /// associated with this <see cref="SpannerCommand"/>. Must not be null.</param> /// <param name="transaction">An optional <see cref="SpannerTransaction"/> /// created through <see> /// <cref>SpannerConnection.BeginTransactionAsync</cref></see>. May be null.</param> /// <param name="parameters">An optional collection of <see cref="SpannerParameter"/> /// that is used in the command. May be null.</param> public SpannerCommand( string commandText, SpannerConnection connection, SpannerTransaction transaction = null, SpannerParameterCollection parameters = null) : this(SpannerCommandTextBuilder.FromCommandText(commandText), connection, transaction, parameters) { }
private SpannerCommand( SpannerConnection connection, SpannerTransaction transaction, SpannerParameterCollection parameters) : this() { SpannerConnection = connection; _transaction = transaction; Parameters = parameters; }
/// <summary> /// Initializes a new instance of <see cref="SpannerCommand"/>. /// </summary> /// <param name="connection">The <see cref="SpannerConnection"/> that is /// associated with this <see cref="SpannerCommand"/>. Must not be null.</param> /// <param name="transaction">The <see cref="SpannerTransaction"/> /// used when creating the <see cref="CommandPartition"/>. /// </param> /// <param name="commandPartition"> /// The partition which this command is restricted to. /// See <see cref="SpannerConnection.BeginReadOnlyTransaction(TransactionId)"/> /// </param> public SpannerCommand( SpannerConnection connection, SpannerTransaction transaction, CommandPartition commandPartition) : this(connection, transaction, null, commandPartition) { GaxPreconditions.CheckNotNull(connection, nameof(connection)); GaxPreconditions.CheckNotNull(transaction, nameof(transaction)); GaxPreconditions.CheckNotNull(commandPartition, nameof(commandPartition)); SpannerCommandTextBuilder = SpannerCommandTextBuilder.FromCommandText(commandPartition.ExecuteSqlRequest.Sql); }
/// <summary> /// Initializes a new instance of <see cref="SpannerCommand"/>. /// </summary> /// <param name="commandTextBuilder">The <see cref="SpannerCommandTextBuilder"/> /// that configures the text of this command. Must not be null.</param> /// <param name="connection">The <see cref="SpannerConnection"/> that is /// associated with this <see cref="SpannerCommand"/>. Must not be null.</param> /// <param name="transaction">An optional <see cref="SpannerTransaction"/> /// created through <see> /// <cref>SpannerConnection.BeginTransactionAsync</cref> /// </see> /// </param>. May be null. /// <param name="parameters">An optional collection of <see cref="SpannerParameter"/> /// that is used in the command. May be null.</param> public SpannerCommand( SpannerCommandTextBuilder commandTextBuilder, SpannerConnection connection, SpannerTransaction transaction = null, SpannerParameterCollection parameters = null) : this(connection, transaction, parameters) { GaxPreconditions.CheckNotNull(commandTextBuilder, nameof(commandTextBuilder)); GaxPreconditions.CheckNotNull(connection, nameof(connection)); SpannerCommandTextBuilder = commandTextBuilder; }
/// <summary> /// Initializes a new instance of <see cref="SpannerCommand"/> for a read operation. /// </summary> /// <remarks> /// The initial command timeout is taken from the options associated with <paramref name="connection"/>. /// </remarks> /// <param name="commandTextBuilder">The <see cref="SpannerCommandTextBuilder"/> /// that configures the text of this command. Must be a read command and not be null.</param> /// <param name="connection">The <see cref="SpannerConnection"/> that is /// associated with this <see cref="SpannerCommand"/>. Must not be null.</param> /// <param name="keySet">The <see cref="KeySet"/> that is used to select rows. Must not be null.</param> /// <param name="transaction">An optional <see cref="SpannerTransaction"/> /// created through <see cref="SpannerConnection.BeginTransactionAsync" />. May be null.</param> internal SpannerCommand( SpannerCommandTextBuilder commandTextBuilder, SpannerConnection connection, KeySet keySet, SpannerTransaction transaction = null) : this(connection, transaction, null, null) { GaxPreconditions.CheckArgument(commandTextBuilder.SpannerCommandType == SpannerCommandType.Read, nameof(commandTextBuilder.SpannerCommandType), "KeySet is only allowed for Read commands"); SpannerCommandTextBuilder = GaxPreconditions.CheckNotNull(commandTextBuilder, nameof(commandTextBuilder)); KeySet = GaxPreconditions.CheckNotNull(keySet, nameof(keySet)); }
private async Task <SpannerTransaction> GetTransactionAsync(CancellationToken cancellationToken) { //note that we delay transaction creation (and thereby session allocation) if (_timestampBound != null) { return(_transaction ?? (_transaction = await _spannerConnection.BeginReadOnlyTransactionAsync(_timestampBound, cancellationToken) .ConfigureAwait(false))); } return(_transaction ?? (_transaction = await _spannerConnection.BeginTransactionAsync(cancellationToken) .ConfigureAwait(false))); }
public void Dispose() { try { _transaction?.Dispose(); // Protect against multiple disposals _transaction = null; } catch (Exception e) { Logger.Error("Error disposing", e); } }
private SpannerCommand( SpannerConnection connection, SpannerTransaction transaction, SpannerParameterCollection parameters, CommandPartition commandPartition) : this(connection) { _transaction = transaction; Partition = commandPartition; if (parameters != null) { Parameters = parameters; } }
public void Dispose() { try { _transaction?.DisposeWithClient(_spannerClient); _spannerClientDisposal?.Invoke(); // Protect against multiple disposals _transaction = null; _spannerClientDisposal = null; } catch (Exception e) { Logger.DefaultLogger.Error(() => "Error disposing", e); } }
/// <summary> /// Initializes a new instance of <see cref="SpannerCommand"/>. /// </summary> /// <param name="connection">The <see cref="SpannerConnection"/> that is /// associated with this <see cref="SpannerCommand"/>. Must not be null.</param> /// <param name="transaction">The <see cref="SpannerTransaction"/> /// used when creating the <see cref="CommandPartition"/>. /// </param> /// <param name="commandPartition"> /// The partition which this command is restricted to. /// See <see cref="SpannerConnection.BeginReadOnlyTransaction(TransactionId)"/> /// </param> public SpannerCommand( SpannerConnection connection, SpannerTransaction transaction, CommandPartition commandPartition) : this(connection, transaction, null, commandPartition) { GaxPreconditions.CheckNotNull(connection, nameof(connection)); GaxPreconditions.CheckNotNull(transaction, nameof(transaction)); GaxPreconditions.CheckNotNull(commandPartition, nameof(commandPartition)); SpannerCommandTextBuilder = commandPartition.Request.IsQuery ? SpannerCommandTextBuilder.FromCommandText(commandPartition.Request.ExecuteSqlRequest.Sql) : SpannerCommandTextBuilder.CreateReadTextBuilder( commandPartition.Request.ReadRequest.Table, ReadOptions.FromColumns(commandPartition.Request.ReadRequest.Columns)); }
private async Task <SpannerTransaction> GetTransactionAsync(CancellationToken cancellationToken, int timeoutSeconds) { // Note that we delay transaction creation (and thereby session allocation) until the first operation // (ExecuteMutations, ExecuteQuery, ExecuteDml) if (_transaction == null) { _transaction = _timestampBound != null ? await _spannerConnection.BeginReadOnlyTransactionAsync(_timestampBound, cancellationToken).ConfigureAwait(false) : _transactionId != null?_spannerConnection.BeginReadOnlyTransaction(_transactionId) : await _spannerConnection.BeginTransactionAsync(cancellationToken).ConfigureAwait(false); // The commit timeout is irrelevant for read-only transactions, but it's easier to set it unconditionally. _transaction.CommitTimeout = timeoutSeconds; } return(_transaction); }
private async Task <SpannerTransaction> GetTransactionAsync(CancellationToken cancellationToken, int timeoutSeconds) { //note that we delay transaction creation (and thereby session allocation) if (_timestampBound != null) { return(_transaction ?? (_transaction = await _spannerConnection.BeginReadOnlyTransactionAsync(_timestampBound, cancellationToken) .ConfigureAwait(false))); } else if (_transactionId != null) { return(SpannerTransaction.FromTransactionId(_spannerConnection, _transactionId)); } var result = _transaction ?? (_transaction = await _spannerConnection.BeginTransactionAsync(cancellationToken) .ConfigureAwait(false)); result.CommitTimeout = timeoutSeconds; return(result); }
internal async Task <TResult> RunAsync <TResult>(Func <SpannerTransaction, Task <TResult> > asyncWork, CancellationToken cancellationToken = default) { GaxPreconditions.CheckNotNull(asyncWork, nameof(asyncWork)); // Session will be initialized and subsequently modified by CommitAttempt. PooledSession session = null; try { return(await ExecuteWithRetryAsync(CommitAttempt, cancellationToken).ConfigureAwait(false)); } finally { session?.Dispose(); } async Task <TResult> CommitAttempt() { return(await ExecuteHelper.WithErrorTranslationAndProfiling( async() => { SpannerTransaction transaction = null; try { session = await(session?.WithFreshTransactionOrNewAsync(SpannerConnection.s_readWriteTransactionOptions, cancellationToken) ?? _connection.AcquireReadWriteSessionAsync(cancellationToken)).ConfigureAwait(false); transaction = new SpannerTransaction(_connection, TransactionMode.ReadWrite, session, null); TResult result = await asyncWork(transaction).ConfigureAwait(false); await transaction.CommitAsync(cancellationToken).ConfigureAwait(false); return result; } // We only catch to attempt a rollback, and that is possible if we have a transaction already. // If the exception was thrown when refreshing the session the we don't have a transaction yet. catch when(transaction != null) { try { await transaction.RollbackAsync(cancellationToken).ConfigureAwait(false); } catch (Exception e) { // If the commit failed, calling Rollback will fail as well. // We don't want that or any other rollback exception to propagate, // it will not trigger the retry _connection.Logger.Warn("A rollback attempt failed on RetriableTransaction.RunAsync.CommitAttempt", e); } // Throw, the retry helper will know when to retry. throw; } finally { if (transaction != null) { // Let's make sure that the associated session is not released to the pool // because we'll be attempting to get a fresh transaction for this same session first. // If that fails will attempt a new session acquisition. // This session will be disposed of by the pool if it can't be refreshed or by the RunAsync method // if we are not retrying anymore. transaction.DisposeBehavior = DisposeBehavior.Detach; transaction.Dispose(); } } }, "RetriableTransaction.RunAsync.CommitAttempt", _connection.Logger).ConfigureAwait(false)); } }
internal SpannerBatchCommand(SpannerTransaction transaction) { Transaction = GaxPreconditions.CheckNotNull(transaction, nameof(transaction)); Connection = transaction.SpannerConnection; // Never null }