/// <summary> /// Transactional Write procedure. /// </summary> public void Save() { var info = TransactionContext.GetTransactionInfo(); if (this.logger.IsEnabled(LogLevel.Debug)) { this.logger.Debug("Write {0}", info); } if (info.IsReadOnly) { // For obvious reasons... throw new OrleansReadOnlyViolatedException(info.TransactionId); } Rollback(); var copiedValue = this.transactionCopy[info.TransactionId]; // // Validation // if (this.version.TransactionId > info.TransactionId || this.highestReadTransactionId >= info.TransactionId) { // Prevent cycles. Wait-die throw new OrleansTransactionWaitDieException(info.TransactionId); } TransactionalResourceVersion nextVersion = TransactionalResourceVersion.Create(info.TransactionId, this.version.TransactionId == info.TransactionId ? this.version.WriteNumber + 1 : 1); // // Update Transaction Context // info.RecordWrite(transactionalResource, this.version, this.metadata.StableVersion.TransactionId); // // Modify the State // if (!this.log.ContainsKey(info.TransactionId)) { LogRecord <TState> r = new LogRecord <TState>(); this.log[info.TransactionId] = r; } LogRecord <TState> logRecord = this.log[info.TransactionId]; logRecord.NewVal = copiedValue; logRecord.Version = nextVersion; this.value = copiedValue; this.version = nextVersion; this.transactionCopy.Remove(info.TransactionId); }
public async Task Commit(ITransactionInfo info) { var transactionInfo = (TransactionInfo)info; TransactionsStatisticsGroup.OnTransactionCommitRequest(); if (transactionInfo.IsReadOnly) { return; } var completion = new TaskCompletionSource <bool>(); bool canCommit = true; List <Task <bool> > prepareTasks = new List <Task <bool> >(transactionInfo.WriteSet.Count); foreach (var g in transactionInfo.WriteSet.Keys) { TransactionalResourceVersion write = TransactionalResourceVersion.Create(transactionInfo.TransactionId, transactionInfo.WriteSet[g]); TransactionalResourceVersion?read = null; if (transactionInfo.ReadSet.ContainsKey(g)) { read = transactionInfo.ReadSet[g]; transactionInfo.ReadSet.Remove(g); } prepareTasks.Add(g.Prepare(transactionInfo.TransactionId, write, read)); } foreach (var g in transactionInfo.ReadSet.Keys) { TransactionalResourceVersion read = transactionInfo.ReadSet[g]; prepareTasks.Add(g.Prepare(transactionInfo.TransactionId, null, read)); } await Task.WhenAll(prepareTasks); foreach (var t in prepareTasks) { if (!t.Result) { canCommit = false; } } if (!canCommit) { TransactionsStatisticsGroup.OnTransactionAborted(); abortedTransactions.TryAdd(transactionInfo.TransactionId, 0); throw new OrleansPrepareFailedException(transactionInfo.TransactionId); } commitCompletions.TryAdd(transactionInfo.TransactionId, completion); transactionCommitQueue.Enqueue(transactionInfo); await completion.Task; }
/// <summary> /// Read Log from persistent state interface. /// </summary> private void RevertToPersistedLog() { this.log.Clear(); foreach (KeyValuePair <long, TState> kvp in this.storage.State.Logs) { this.log[kvp.Key] = new LogRecord <TState> { NewVal = kvp.Value, Version = TransactionalResourceVersion.Create(kvp.Key, 1) }; } }
/// <summary> /// Undo writes to restore state to pre transaction value. /// </summary> private void Rollback(long transactionId) { List <KeyValuePair <long, LogRecord <TState> > > records = this.log.SkipWhile(kvp => kvp.Key < transactionId).ToList(); foreach (KeyValuePair <long, LogRecord <TState> > kvp in records) { this.log.Remove(kvp.Key); this.transactionCopy.Remove(kvp.Key); } if (this.log.Count > 0) { LogRecord <TState> lastLogRecord = this.log.Values.Last(); this.version = lastLogRecord.Version; this.value = lastLogRecord.NewVal; } else { this.version = TransactionalResourceVersion.Create(0, 0); this.value = new TState(); } }