public void Join(TransactionInfo x) { joined.Enqueue(x); }
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"); } }
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); }
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(); }
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}"); } }
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}"); } }
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); }
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); }
public void Join(TransactionInfo other) { this.joined.Enqueue(other); }