示例#1
0
        public override int Execute(IEnumerable <ModificationCommandBatch> commandBatches, IRelationalConnection connection)
        {
            // Convert the list of batches to a list to prevent it from being re-generated each time that we iterate over the enumerator.
            var batchesList = commandBatches.ToList();
            var tracer      = TracerProviderExtension.GetTracer();

            using var span = tracer.StartActiveSpan(TracerProviderExtension.SPAN_NAME_SAVECHANGES);
            try
            {
                base.Execute(batchesList, connection);
                foreach (var batch in batchesList)
                {
                    if (batch is SpannerModificationCommandBatch spannerModificationCommandBatch)
                    {
                        spannerModificationCommandBatch.PropagateResults();
                    }
                }
                span.SetStatus(Status.Ok);
            }
            catch (Exception ex)
            {
                span.SetStatus(Status.Error.WithDescription(ex.Message));
                throw;
            }
            finally
            {
                span.End();
            }
            return(SpannerCount(batchesList));
        }
示例#2
0
        public override async Task <int> ExecuteAsync(IEnumerable <ModificationCommandBatch> commandBatches, IRelationalConnection connection, CancellationToken cancellationToken = default)
        {
            // Convert the list of batches to a list to prevent it from being re-generated each time that we iterate over the enumerator.
            var batchesList = commandBatches.ToList();
            var tracer      = TracerProviderExtension.GetTracer();

            using var span = tracer.StartActiveSpan(TracerProviderExtension.SPAN_NAME_SAVECHANGES);
            try
            {
                await base.ExecuteAsync(batchesList, connection, cancellationToken);

                // Results that need to be propagated after an update are executed after the batch has been saved.
                // This ensures that when implict transactions are being used the updated value is fetched after the
                // transaction has been committed. This makes it possible to use mutations for implicit transactions
                // and still automatically propagate computed columns.
                foreach (var batch in batchesList)
                {
                    if (batch is SpannerModificationCommandBatch spannerModificationCommandBatch)
                    {
                        await spannerModificationCommandBatch.PropagateResultsAsync(cancellationToken);
                    }
                }
                span.SetStatus(Status.Ok);
            }
            catch (Exception ex)
            {
                span.SetStatus(Status.Error.WithDescription(ex.Message));
                throw;
            }
            finally
            {
                span.End();
            }
            return(SpannerCount(batchesList));
        }
        /// <summary>
        /// Commits the database transaction asynchronously.
        /// </summary>
        /// <param name="cancellationToken">A cancellation token used for this task.</param>
        /// <returns>Returns the UTC timestamp when the data was written to the database.</returns>
        public async Task <DateTime> CommitAsync(CancellationToken cancellationToken = default)
        {
            var tracer = TracerProviderExtension.GetTracer();

            using var span = tracer.StartActiveSpan(TracerProviderExtension.SPAN_NAME_COMMIT);
            while (true)
            {
                try
                {
                    _commitTimestamp = await SpannerTransaction.CommitAsync(cancellationToken).ConfigureAwait(false);

                    // Propagate the commit timestamp to all columns that were automatically updated during this transaction.
                    // Note that this transaction could both be a manual transaction started by the application, as well as
                    // an implicit transaction started by Entity Framework.
                    foreach (var modificationCommand in _commitTimestampModificationCommands)
                    {
                        foreach (var columnModification in modificationCommand.ColumnModifications)
                        {
                            if (columnModification is SpannerPendingCommitTimestampColumnModification pendingCommitTimestampColumnModification)
                            {
                                var property = pendingCommitTimestampColumnModification.Property.PropertyInfo;
                                if (property != null)
                                {
                                    var entry         = pendingCommitTimestampColumnModification.Entry;
                                    var originalState = entry.EntityState;
                                    var entity        = entry.ToEntityEntry().Entity;
                                    property.SetValue(entity, _commitTimestamp);
                                    entry.EntityState = originalState;
                                }
                            }
                        }
                    }
                    span.SetStatus(OpenTelemetry.Trace.Status.Ok);
                    span.End();
                    return((DateTime)_commitTimestamp);
                }
                catch (SpannerException e) when(e.ErrorCode == ErrorCode.Aborted)
                {
                    span.SetAttribute(TracerProviderExtension.ATTRIBUTE_NAME_RETRYING, e.Message);
                    await RetryAsync(e, cancellationToken).ConfigureAwait(false);
                }
                catch (Exception e)
                {
                    span.SetStatus(OpenTelemetry.Trace.Status.Error.WithDescription(e.Message));
                    span.End();
                    throw;
                }
            }
        }