/// <inheritdoc/> public ITransaction CreateTransaction() { lock (lockObject) { if (RollInProgress) throw new TransactionException("Unable to create a transaction. A rollback or rollforward operation is in progress."); var transaction = new Transaction(this); transactionsInProgress.Push(transaction); TransactionInProgress = true; return transaction; } }
/// <inheritdoc/> public void CompleteTransaction(Transaction transaction) { lock (lockObject) { try { if (transactionsInProgress.Count == 0) throw new TransactionException("There is not transaction in progress in the transaction stack."); if (transaction != transactionsInProgress.Pop()) throw new TransactionException("The transaction being completed is not that last created transaction."); // Check if we're completing the last transaction TransactionInProgress = transactionsInProgress.Count > 0; // Ignore the transaction if it is empty if (transaction.IsEmpty) return; // If this transaction has no effect, discard it. if (transaction.Operations.All(x => !x.HasEffect)) return; // If we're not the last transaction, consider this transaction as an operation of its parent transaction if (TransactionInProgress) { // Avoid useless nested transaction if we have a single operation inside. PushOperation(transaction.Operations.Count == 1 ? transaction.Operations.Single() : transaction); return; } // Remove transactions that will be overwritten by this one if (currentPosition < transactions.Count) { PurgeFromIndex(currentPosition); } if (currentPosition == Capacity) { // If the stack has a capacity of 0, immediately freeze the new transaction. var oldestTransaction = Capacity > 0 ? transactions[0] : transaction; oldestTransaction.Interface.Freeze(); for (var i = 1; i < transactions.Count; ++i) { transactions[i - 1] = transactions[i]; } if (Capacity > 0) { transactions[--currentPosition] = null; } TransactionDiscarded?.Invoke(this, new TransactionsDiscardedEventArgs(oldestTransaction, DiscardReason.StackFull)); } if (Capacity > 0) { if (currentPosition == transactions.Count) { transactions.Add(transaction); } else { transactions[currentPosition] = transaction; } ++currentPosition; } } finally { if (!TransactionInProgress) { TransactionCompleted?.Invoke(this, new TransactionEventArgs(transaction)); } } } }