Example #1
0
 public void Join(TransactionInfo x)
 {
     joined.Enqueue(x);
 }
Example #2
0
        public void CommitTransaction(TransactionInfo transactionInfo)
        {
            if (transactionsTable.TryGetValue(transactionInfo.TransactionId, out Transaction tx))
            {
                bool abort = false;
                long cascadingDependentId = 0;

                bool pending = false;
                bool signal  = false;
                lock (tx)
                {
                    if (tx.State == TransactionState.Started)
                    {
                        tx.Info = transactionInfo;

                        // Check our dependent transactions.
                        // - If all dependent transactions committed, put transaction in validating queue
                        //   (dependencyQueue)
                        // - If at least one dependent transaction aborted, abort.
                        // - If at least one dependent transaction is still pending, put in pending queue
                        //   (dependentTx.WaitingTransactions)
                        foreach (var dependentId in tx.Info.DependentTransactions)
                        {
                            // Transaction does not exist in the transaction table;
                            // therefore, presumed abort.
                            if (!transactionsTable.TryGetValue(dependentId, out Transaction dependentTx))
                            {
                                abort = true;
                                cascadingDependentId = dependentId;
                                break;
                            }

                            // NOTE: our deadlock prevention mechanism ensures that we are acquiring
                            // the locks in proper order and there is no risk of deadlock.
                            lock (dependentTx)
                            {
                                // Dependent transactions has aborted; therefore, abort.
                                if (dependentTx.State == TransactionState.Aborted)
                                {
                                    abort = true;
                                    cascadingDependentId = dependentId;
                                    break;
                                }

                                // Dependent transaction is still executing or has a pending dependency.
                                if (dependentTx.State == TransactionState.Started ||
                                    dependentTx.State == TransactionState.PendingDependency)
                                {
                                    pending = true;
                                    dependentTx.WaitingTransactions.Add(tx);
                                    tx.PendingCount++;
                                }
                            }
                        }

                        if (abort)
                        {
                            AbortTransaction(transactionInfo.TransactionId, new OrleansCascadingAbortException(transactionInfo.TransactionId, cascadingDependentId));
                        }
                        else if (pending)
                        {
                            tx.State = TransactionState.PendingDependency;
                        }
                        else
                        {
                            tx.State = TransactionState.Validated;
                            dependencyQueue.Enqueue(tx);
                            signal = true;
                        }
                    }
                }
                if (signal)
                {
                    this.SignalDependencyEnqueued();
                }
            }
            else
            {
                // Don't have a record of the transaction any more so presumably it's aborted.
                throw new OrleansTransactionAbortedException(transactionInfo.TransactionId, "Transaction presumed to be aborted");
            }
        }
Example #3
0
        private async Task <TransactionalStatus> CommitReadWriteTransaction(TransactionInfo transactionInfo, List <ParticipantId> writeResources, List <KeyValuePair <ParticipantId, AccessCounter> > resources, KeyValuePair <ParticipantId, AccessCounter> manager)
        {
            TransactionalStatus status = TransactionalStatus.Ok;

            try
            {
                foreach (var p in resources)
                {
                    if (p.Key.Equals(manager.Key))
                    {
                        continue;
                    }
                    // one-way prepare message
                    p.Key.Reference.AsReference <ITransactionalResourceExtension>()
                    .Prepare(p.Key.Name, transactionInfo.TransactionId, p.Value, transactionInfo.TimeStamp, manager.Key)
                    .Ignore();
                }

                // wait for the TM to commit the transaction
                status = await manager.Key.Reference.AsReference <ITransactionManagerExtension>()
                         .PrepareAndCommit(manager.Key.Name, transactionInfo.TransactionId, manager.Value, transactionInfo.TimeStamp, writeResources, resources.Count);
            }
            catch (TimeoutException)
            {
                if (logger.IsEnabled(LogLevel.Debug))
                {
                    logger.Debug($"{stopwatch.Elapsed.TotalMilliseconds:f2} timeout {transactionInfo.TransactionId} on CommitReadWriteTransaction");
                }
                status = TransactionalStatus.TMResponseTimeout;
            }
            catch (Exception ex)
            {
                if (logger.IsEnabled(LogLevel.Debug))
                {
                    logger.Debug($"{stopwatch.Elapsed.TotalMilliseconds:f2} failure {transactionInfo.TransactionId} CommitReadWriteTransaction");
                }
                this.logger.LogWarning(ex, "Unknown error while commiting transaction {TransactionId}", transactionInfo.TransactionId);
                status = TransactionalStatus.PresumedAbort;
            }

            if (status != TransactionalStatus.Ok)
            {
                try
                {
                    if (logger.IsEnabled(LogLevel.Debug))
                    {
                        logger.Debug($"{stopwatch.Elapsed.TotalMilliseconds:f2} failed {transactionInfo.TransactionId} with status={status}");
                    }

                    // notify participants
                    if (status.DefinitelyAborted())
                    {
                        await Task.WhenAll(writeResources
                                           .Where(p => !p.Equals(manager.Key))
                                           .Select(p => p.Reference.AsReference <ITransactionalResourceExtension>()
                                                   .Cancel(p.Name, transactionInfo.TransactionId, transactionInfo.TimeStamp, status)));
                    }
                }
                catch (Exception ex)
                {
                    if (logger.IsEnabled(LogLevel.Debug))
                    {
                        logger.Debug($"{stopwatch.Elapsed.TotalMilliseconds:f2} failure aborting {transactionInfo.TransactionId} CommitReadWriteTransaction");
                    }
                    this.logger.LogWarning(ex, "Failed to abort transaction {TransactionId}", transactionInfo.TransactionId);
                }
            }


            if (logger.IsEnabled(LogLevel.Trace))
            {
                logger.Trace($"{stopwatch.Elapsed.TotalMilliseconds:f2} finish {transactionInfo.TransactionId}");
            }

            return(status);
        }
Example #4
0
        private async Task <TransactionalStatus> CommitReadOnlyTransaction(TransactionInfo transactionInfo, List <KeyValuePair <ParticipantId, AccessCounter> > resources)
        {
            TransactionalStatus status = TransactionalStatus.Ok;
            var tasks = new List <Task <TransactionalStatus> >();

            try
            {
                foreach (KeyValuePair <ParticipantId, AccessCounter> resource in resources)
                {
                    tasks.Add(resource.Key.Reference.AsReference <ITransactionalResourceExtension>()
                              .CommitReadOnly(resource.Key.Name, transactionInfo.TransactionId, resource.Value, transactionInfo.TimeStamp));
                }

                // wait for all responses
                TransactionalStatus[] results = await Task.WhenAll(tasks);

                // examine the return status
                foreach (var s in results)
                {
                    if (s != TransactionalStatus.Ok)
                    {
                        status = s;
                        if (logger.IsEnabled(LogLevel.Debug))
                        {
                            logger.Debug($"{stopwatch.Elapsed.TotalMilliseconds:f2} fail {transactionInfo.TransactionId} prepare response status={status}");
                        }
                        break;
                    }
                }
            }
            catch (TimeoutException)
            {
                if (logger.IsEnabled(LogLevel.Debug))
                {
                    logger.Debug($"{stopwatch.Elapsed.TotalMilliseconds:f2} timeout {transactionInfo.TransactionId} on CommitReadOnly");
                }
                status = TransactionalStatus.ParticipantResponseTimeout;
            }
            catch (Exception ex)
            {
                if (logger.IsEnabled(LogLevel.Debug))
                {
                    logger.Debug($"{stopwatch.Elapsed.TotalMilliseconds:f2} failure {transactionInfo.TransactionId} CommitReadOnly");
                }
                this.logger.LogWarning(ex, "Unknown error while commiting readonly transaction {TransactionId}", transactionInfo.TransactionId);
                status = TransactionalStatus.PresumedAbort;
            }

            if (status != TransactionalStatus.Ok)
            {
                try
                {
                    await Task.WhenAll(resources.Select(r => r.Key.Reference.AsReference <ITransactionalResourceExtension>()
                                                        .Abort(r.Key.Name, transactionInfo.TransactionId)));
                }
                catch (Exception ex)
                {
                    if (logger.IsEnabled(LogLevel.Debug))
                    {
                        logger.Debug($"{stopwatch.Elapsed.TotalMilliseconds:f2} failure aborting {transactionInfo.TransactionId} CommitReadOnly");
                    }
                    this.logger.LogWarning(ex, "Failed to abort readonly transaction {TransactionId}", transactionInfo.TransactionId);
                }
            }

            if (logger.IsEnabled(LogLevel.Trace))
            {
                logger.Trace($"{stopwatch.Elapsed.TotalMilliseconds:f2} finish (reads only) {transactionInfo.TransactionId}");
            }

            return(status);
        }
 public Task <(TransactionalStatus Status, Exception exception)> Resolve(TransactionInfo transactionInfo)
 {
     throw new OrleansTransactionsDisabledException();
 }
 public Task Abort(TransactionInfo transactionInfo)
 {
     throw new OrleansTransactionsDisabledException();
 }
Example #7
0
        private async Task CommitReadOnlyTransaction(TransactionInfo transactionInfo)
        {
            var participants = transactionInfo.Participants;

            var tasks = new List <Task <TransactionalStatus> >();

            foreach (var p in participants)
            {
                tasks.Add(p.Key.CommitReadOnly(transactionInfo.TransactionId, p.Value, transactionInfo.TimeStamp));
            }
            transactionInfo.PrepareMessagesSent = true;

            try
            {
                // wait for all responses
                await Task.WhenAll(tasks);

                // examine the return status
                foreach (var s in tasks)
                {
                    var status = s.Result;
                    if (status != TransactionalStatus.Ok)
                    {
                        if (logger.IsEnabled(LogLevel.Debug))
                        {
                            logger.Debug($"{stopwatch.Elapsed.TotalMilliseconds:f2} fail {transactionInfo.TransactionId} prepare response status={status}");
                        }

                        foreach (var p in participants)
                        {
                            p.Key.Abort(transactionInfo.TransactionId).Ignore();
                        }

                        throw status.ConvertToUserException(transactionInfo.TransactionId.ToString());
                    }
                }
            }
            catch (TimeoutException)
            {
                if (logger.IsEnabled(LogLevel.Debug))
                {
                    logger.Debug($"{stopwatch.Elapsed.TotalMilliseconds:f2} timeout {transactionInfo.TransactionId} prepare responses");
                }

                foreach (var p in participants)
                {
                    p.Key.Abort(transactionInfo.TransactionId).Ignore();
                }

                throw new OrleansTransactionAbortedException(transactionInfo.TransactionId.ToString(),
                                                             "transaction agent timed out waiting for read-only transaction participant responses");
            }
            catch (Exception e)
            {
                if (logger.IsEnabled(LogLevel.Debug))
                {
                    logger.Debug($"{stopwatch.Elapsed.TotalMilliseconds:f2} fail {transactionInfo.TransactionId} with {e.GetType().Name}");
                }

                throw;
            }

            if (logger.IsEnabled(LogLevel.Trace))
            {
                logger.Trace($"{stopwatch.Elapsed.TotalMilliseconds:f2} finish (reads only) {transactionInfo.TransactionId}");
            }
        }
Example #8
0
        private async Task CommitReadWriteTransaction(TransactionInfo transactionInfo, List <ITransactionParticipant> writeParticipants)
        {
            var tm           = selectTMByBatchSize ? transactionInfo.TMCandidate : writeParticipants[0];
            var participants = transactionInfo.Participants;

            Task <TransactionalStatus> tmPrepareAndCommitTask = null;

            foreach (var p in participants)
            {
                if (p.Key.Equals(tm))
                {
                    tmPrepareAndCommitTask = p.Key.PrepareAndCommit(transactionInfo.TransactionId, p.Value, transactionInfo.TimeStamp, writeParticipants, participants.Count);
                }
                else
                {
                    // one-way prepare message
                    p.Key.Prepare(transactionInfo.TransactionId, p.Value, transactionInfo.TimeStamp, tm).Ignore();
                }
            }
            transactionInfo.PrepareMessagesSent = true;

            try
            {
                // wait for the TM to commit the transaction
                var status = await tmPrepareAndCommitTask;

                if (status != TransactionalStatus.Ok)
                {
                    if (logger.IsEnabled(LogLevel.Debug))
                    {
                        logger.Debug($"{stopwatch.Elapsed.TotalMilliseconds:f2} fail {transactionInfo.TransactionId} TM response status={status}");
                    }

                    // notify participants
                    if (status.DefinitelyAborted())
                    {
                        foreach (var p in writeParticipants)
                        {
                            if (!p.Equals(tm))
                            {
                                // one-way cancel message
                                p.Cancel(transactionInfo.TransactionId, transactionInfo.TimeStamp, status).Ignore();
                            }
                        }
                    }

                    throw status.ConvertToUserException(transactionInfo.TransactionId.ToString());
                }
            }
            catch (TimeoutException)
            {
                if (logger.IsEnabled(LogLevel.Debug))
                {
                    logger.Debug($"{stopwatch.Elapsed.TotalMilliseconds:f2} timeout {transactionInfo.TransactionId} TM response");
                }

                throw new OrleansTransactionInDoubtException(transactionInfo.TransactionId.ToString(),
                                                             "transaction agent timed out waiting for TM response");
            }
            catch (Exception e)
            {
                if (logger.IsEnabled(LogLevel.Debug))
                {
                    logger.Debug($"{stopwatch.Elapsed.TotalMilliseconds:f2} fail {transactionInfo.TransactionId} with {e.GetType().Name}");
                }

                throw;
            }

            if (logger.IsEnabled(LogLevel.Trace))
            {
                logger.Trace($"{stopwatch.Elapsed.TotalMilliseconds:f2} finish {transactionInfo.TransactionId}");
            }
        }
Example #9
0
        private async Task <TransactionalStatus> CommitReadOnlyTransaction(TransactionInfo transactionInfo)
        {
            var participants = transactionInfo.Participants;

            var tasks = new List <Task <TransactionalStatus> >();

            foreach (var p in participants)
            {
                tasks.Add(p.Key.Reference.AsReference <ITransactionManagerExtension>()
                          .CommitReadOnly(p.Key.Name, transactionInfo.TransactionId, p.Value, transactionInfo.TimeStamp));
            }

            try
            {
                // wait for all responses
                await Task.WhenAll(tasks);

                // examine the return status
                foreach (var s in tasks)
                {
                    var status = s.Result;
                    if (status != TransactionalStatus.Ok)
                    {
                        if (logger.IsEnabled(LogLevel.Debug))
                        {
                            logger.Debug($"{stopwatch.Elapsed.TotalMilliseconds:f2} fail {transactionInfo.TransactionId} prepare response status={status}");
                        }

                        foreach (var p in participants)
                        {
                            p.Key.Reference.AsReference <ITransactionalResourceExtension>()
                            .Abort(p.Key.Name, transactionInfo.TransactionId)
                            .Ignore();
                        }

                        return(status);
                    }
                }
            }
            catch (TimeoutException)
            {
                if (logger.IsEnabled(LogLevel.Debug))
                {
                    logger.Debug($"{stopwatch.Elapsed.TotalMilliseconds:f2} timeout {transactionInfo.TransactionId} prepare responses");
                }

                foreach (var p in participants)
                {
                    p.Key.Reference.AsReference <ITransactionalResourceExtension>()
                    .Abort(p.Key.Name, transactionInfo.TransactionId)
                    .Ignore();
                }

                return(TransactionalStatus.ParticipantResponseTimeout);
            }

            if (logger.IsEnabled(LogLevel.Trace))
            {
                logger.Trace($"{stopwatch.Elapsed.TotalMilliseconds:f2} finish (reads only) {transactionInfo.TransactionId}");
            }

            return(TransactionalStatus.Ok);
        }
Example #10
0
        private async Task <TransactionalStatus> CommitReadWriteTransaction(TransactionInfo transactionInfo, List <ParticipantId> writeResources)
        {
            ParticipantId tm = selectTMByBatchSize ? transactionInfo.TMCandidate : writeResources[0];
            Dictionary <ParticipantId, AccessCounter> participants = transactionInfo.Participants;

            Task <TransactionalStatus> tmPrepareAndCommitTask = null;

            foreach (var p in participants)
            {
                if (p.Key.Equals(tm))
                {
                    tmPrepareAndCommitTask = p.Key.Reference.AsReference <ITransactionManagerExtension>()
                                             .PrepareAndCommit(p.Key.Name, transactionInfo.TransactionId, p.Value, transactionInfo.TimeStamp, writeResources, participants.Count);
                }
                else
                {
                    // one-way prepare message
                    p.Key.Reference.AsReference <ITransactionalResourceExtension>()
                    .Prepare(p.Key.Name, transactionInfo.TransactionId, p.Value, transactionInfo.TimeStamp, tm)
                    .Ignore();
                }
            }

            try
            {
                // wait for the TM to commit the transaction
                TransactionalStatus status = await tmPrepareAndCommitTask;

                if (status != TransactionalStatus.Ok)
                {
                    if (logger.IsEnabled(LogLevel.Debug))
                    {
                        logger.Debug($"{stopwatch.Elapsed.TotalMilliseconds:f2} fail {transactionInfo.TransactionId} TM response status={status}");
                    }

                    // notify participants
                    if (status.DefinitelyAborted())
                    {
                        foreach (var p in writeResources)
                        {
                            if (!p.Equals(tm))
                            {
                                // one-way cancel message
                                p.Reference.AsReference <ITransactionalResourceExtension>()
                                .Cancel(p.Name, transactionInfo.TransactionId, transactionInfo.TimeStamp, status)
                                .Ignore();
                            }
                        }
                    }

                    return(status);
                }
            }
            catch (TimeoutException)
            {
                if (logger.IsEnabled(LogLevel.Debug))
                {
                    logger.Debug($"{stopwatch.Elapsed.TotalMilliseconds:f2} timeout {transactionInfo.TransactionId} TM response");
                }

                return(TransactionalStatus.TMResponseTimeout);
            }

            if (logger.IsEnabled(LogLevel.Trace))
            {
                logger.Trace($"{stopwatch.Elapsed.TotalMilliseconds:f2} finish {transactionInfo.TransactionId}");
            }

            return(TransactionalStatus.Ok);
        }
Example #11
0
 public void Join(TransactionInfo other)
 {
     this.joined.Enqueue(other);
 }