コード例 #1
0
ファイル: TransactionalState.cs プロジェクト: yyzreal/orleans
        private async Task DoLoad()
        {
            this.logger.Debug("DoLoad");
            // load inital state
            TransactionalStorageLoadResponse <TState> loadResponse = await this.storage.Load(StateName);

            this.eTag     = loadResponse.ETag;
            this.metadata = Metadata.FromString(loadResponse.Metadata);
            this.version  = this.metadata.HighestVersion;
            this.highestReadTransactionId = this.metadata.HighestReadTransactionId;
            this.commitedState            = loadResponse.CommittedState;
            foreach (PendingTransactionState <TState> pendingState in loadResponse.PendingStates)
            {
                if (this.logger.IsEnabled(LogLevel.Debug))
                {
                    this.logger.Debug("Rebuilding log from storage for {0}", pendingState.SequenceId);
                }
                this.log[pendingState.SequenceId] = new LogRecord <TState>
                {
                    NewVal  = pendingState.State,
                    Version = (TransactionalResourceVersion.TryParse(pendingState.TransactionId, out TransactionalResourceVersion version)) ? version : default(TransactionalResourceVersion)
                };
            }

            UpdateActiveState();
        }
コード例 #2
0
ファイル: TransactionalState.cs プロジェクト: yyzreal/orleans
        /// <summary>
        /// Find the appropriate version of the state to serve for this transaction.
        /// We enforce reads in transaction id order, hence we find the version written by the highest
        /// transaction less than or equal to this one
        /// </summary>
        private bool TryGetVersion(long transactionId, out TState readState, out TransactionalResourceVersion readVersion)
        {
            readState   = this.value;
            readVersion = this.version;
            bool versionAvailable = this.version.TransactionId <= transactionId;

            LogRecord <TState> logRecord = null;

            foreach (KeyValuePair <long, LogRecord <TState> > kvp in this.log)
            {
                if (kvp.Key > transactionId)
                {
                    break;
                }
                logRecord = kvp.Value;
            }

            if (logRecord == null)
            {
                return(versionAvailable);
            }

            readState   = logRecord.NewVal;
            readVersion = logRecord.Version;

            return(true);
        }
コード例 #3
0
ファイル: TransactionalState.cs プロジェクト: yyzreal/orleans
        /// <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)
            {
                if (this.logger.IsEnabled(LogLevel.Debug))
                {
                    this.logger.Debug("Removing transaction {0} in rollback", kvp.Key);
                }
                this.log.Remove(kvp.Key);
                this.transactionCopy.Remove(kvp.Key);
            }

            if (this.log.Count > 0)
            {
                LogRecord <TState> lastLogRecord = this.log.Values.Last();
                if (this.logger.IsEnabled(LogLevel.Debug) && this.version != lastLogRecord.Version)
                {
                    this.logger.Debug("Rolling back from {0} to {1}", this.version, lastLogRecord.Version);
                }
                this.version = lastLogRecord.Version;
                this.value   = lastLogRecord.NewVal;
            }
            else
            {
                if (this.logger.IsEnabled(LogLevel.Debug) && this.version != this.metadata.StableVersion)
                {
                    this.logger.Debug("Rolling back to stable version, from {0} to {1}", this.version, this.metadata.StableVersion);
                }
                this.version = this.metadata.StableVersion;
                this.value   = this.commitedState;
            }
        }
コード例 #4
0
        public void RecordRead(ITransactionalResource transactionalResource, TransactionalResourceVersion readVersion, long stableVersion)
        {
            if (readVersion.TransactionId == TransactionId)
            {
                // Just reading our own write here.
                // Sanity check to see if there's a lost write.
                int resourceWriteNumber;
                if (WriteSet.TryGetValue(transactionalResource, out resourceWriteNumber) &&
                    resourceWriteNumber > readVersion.WriteNumber)
                {
                    // Context has record of more writes than we have, some writes must be lost.
                    throw new OrleansTransactionAbortedException(TransactionId, "Lost Write");
                }
            }
            else
            {
                TransactionalResourceVersion resourceReadVersion;
                if (ReadSet.TryGetValue(transactionalResource, out resourceReadVersion) &&
                    resourceReadVersion != readVersion)
                {
                    // Uh-oh. Read two different versions of the grain.
                    throw new OrleansValidationFailedException(TransactionId);
                }

                ReadSet[transactionalResource] = readVersion;

                if (readVersion.TransactionId != TransactionId &&
                    readVersion.TransactionId > stableVersion)
                {
                    DependentTransactions.Add(readVersion.TransactionId);
                }
            }
        }
コード例 #5
0
ファイル: TransactionalState.cs プロジェクト: yyzreal/orleans
        /// <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);
        }
コード例 #6
0
ファイル: TransactionalState.cs プロジェクト: yyzreal/orleans
        private async Task <bool> PersistCommit(long transactionId)
        {
            transactionId = Math.Max(this.highCommitTransactionId, transactionId);
            if (transactionId <= this.metadata.StableVersion.TransactionId)
            {
                // Transaction commit already persisted.
                return(true);
            }

            // find version related to this transaction
            LogRecord <TState>           stableRecord  = this.log.First(kvp => kvp.Key <= transactionId).Value;
            TransactionalResourceVersion stableversion = stableRecord.Version;
            TState stableState = stableRecord.NewVal;

            // Trim the logs to remove old versions.
            // Note that we try to keep the highest version that is below or equal to the ReadOnlyTransactionId
            // so that we can use it to serve read only transactions.
            long highestKey = transactionId;

            foreach (var key in this.log.Keys)
            {
                if (key > this.transactionAgent.ReadOnlyTransactionId)
                {
                    break;
                }

                highestKey = key;
            }

            if (this.log.Count != 0)
            {
                List <KeyValuePair <long, LogRecord <TState> > > records = this.log.TakeWhile(kvp => kvp.Key < highestKey).ToList();
                if (this.logger.IsEnabled(LogLevel.Debug))
                {
                    records.ForEach(kvp => this.logger.Debug("Removing committed transaction from log: transactionId: {1}", kvp.Key));
                }
                records.ForEach(kvp => this.log.Remove(kvp.Key));
            }

            Metadata newMetadata = new Metadata()
            {
                StableVersion            = stableversion,
                HighestVersion           = this.version,
                HighestReadTransactionId = this.highestReadTransactionId,
            };

            this.eTag = await this.storage.Confirm(StateName, this.eTag, newMetadata.ToString(), stableversion.ToString());

            this.metadata      = newMetadata;
            this.commitedState = stableState;
            UpdateActiveState();

            return(true);
        }
コード例 #7
0
        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;
        }
コード例 #8
0
ファイル: TransactionalState.cs プロジェクト: vansha/orleans
 /// <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)
         };
     }
 }
コード例 #9
0
        public void RecordWrite(ITransactionalResource transactionalResource, TransactionalResourceVersion latestVersion, long stableVersion)
        {
            int writeNumber;

            WriteSet.TryGetValue(transactionalResource, out writeNumber);
            WriteSet[transactionalResource] = writeNumber + 1;

            if (latestVersion.TransactionId != TransactionId && latestVersion.TransactionId > stableVersion)
            {
                DependentTransactions.Add(latestVersion.TransactionId);
            }
        }
コード例 #10
0
ファイル: TransactionalState.cs プロジェクト: vansha/orleans
        private void DoRecovery()
        {
            TransactionalStateRecord <TState> storageState = this.storage.State;

            this.stableVersion   = storageState.StableVersion;
            this.writeLowerBound = storageState.WriteLowerBound;
            this.version         = storageState.Version;
            this.value           = storageState.Value;
            RevertToPersistedLog();

            // Rollback any known aborted transactions
            Restore();
        }
コード例 #11
0
ファイル: TransactionalState.cs プロジェクト: yyzreal/orleans
        private void UpdateActiveState()
        {
            this.logger.Debug("UpdateActiveState");
            if (this.metadata.HighestVersion > this.version)
            {
                this.version = this.metadata.HighestVersion;
            }
            this.value = this.log.TryGetValue(this.version.TransactionId, out LogRecord <TState> record)
                ? record.NewVal
                : this.commitedState;
            this.log.Clear();

            // Rollback any known aborted transactions
            Rollback();
        }
コード例 #12
0
        private async Task <bool> PersistCommit(long transactionId)
        {
            transactionId = Math.Max(this.highCommitTransactionId, transactionId);
            if (transactionId <= this.metadata.StableVersion.TransactionId)
            {
                // Transaction commit already persisted.
                return(true);
            }

            // find version related to this transaction
            TransactionalResourceVersion stableversion = this.log.First(kvp => kvp.Key <= transactionId).Value.Version;

            // Trim the logs to remove old versions.
            // Note that we try to keep the highest version that is below or equal to the ReadOnlyTransactionId
            // so that we can use it to serve read only transactions.
            long highestKey = transactionId;

            foreach (var key in this.log.Keys)
            {
                if (key > this.transactionAgent.ReadOnlyTransactionId)
                {
                    break;
                }

                highestKey = key;
            }

            if (this.log.Count != 0)
            {
                List <KeyValuePair <long, LogRecord <TState> > > records = this.log.TakeWhile(kvp => kvp.Key < highestKey).ToList();
                records.ForEach(kvp => this.log.Remove(kvp.Key));
            }

            this.metadata.StableVersion            = stableversion;
            this.metadata.HighestVersion           = this.version;
            this.metadata.HighestReadTransactionId = this.highestReadTransactionId;
            this.eTag = await this.storage.Confirm(StateName, this.eTag, this.metadata.ToString(), stableversion.ToString());

            return(true);
        }
コード例 #13
0
ファイル: TransactionalState.cs プロジェクト: vansha/orleans
        /// <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();
            }
        }
コード例 #14
0
        private async Task DoRecovery()
        {
            // load inital state
            TransactionalStorageLoadResponse <TState> loadResponse = await this.storage.Load(StateName);

            this.eTag     = loadResponse.ETag;
            this.metadata = Metadata.FromString(loadResponse.Metadata);
            this.highestReadTransactionId = this.metadata.HighestReadTransactionId;
            this.version = this.metadata.HighestVersion;
            this.value   = loadResponse.CommittedState;
            this.log.Clear();
            foreach (PendingTransactionState <TState> pendingState in loadResponse.PendingStates)
            {
                this.log[pendingState.SequenceId] = new LogRecord <TState>
                {
                    NewVal  = pendingState.State,
                    Version = (TransactionalResourceVersion.TryParse(pendingState.TransactionId, out TransactionalResourceVersion version)) ? version : default(TransactionalResourceVersion)
                };
            }

            // Rollback any known aborted transactions
            Restore();
        }