Example #1
0
        private async Task Restore()
        {
            TransactionalStorageLoadResponse <TState> loadresponse = await storage.Load();

            this.storageBatch = new StorageBatch <TState>(loadresponse);

            this.stableState          = loadresponse.CommittedState;
            this.stableSequenceNumber = loadresponse.CommittedSequenceId;

            if (logger.IsEnabled(LogLevel.Debug))
            {
                logger.Debug($"Load v{this.stableSequenceNumber} {loadresponse.PendingStates.Count}p {storageBatch.MetaData.CommitRecords.Count}c");
            }

            // ensure clock is consistent with loaded state
            this.Clock.Merge(storageBatch.MetaData.TimeStamp);

            // resume prepared transactions (not TM)
            foreach (var pr in loadresponse.PendingStates.OrderBy(ps => ps.TimeStamp))
            {
                if (pr.SequenceId > loadresponse.CommittedSequenceId && pr.TransactionManager.Reference != null)
                {
                    if (logger.IsEnabled(LogLevel.Debug))
                    {
                        logger.Debug($"recover two-phase-commit {pr.TransactionId}");
                    }

                    ParticipantId tm = pr.TransactionManager;

                    commitQueue.Add(new TransactionRecord <TState>()
                    {
                        Role                        = CommitRole.RemoteCommit,
                        TransactionId               = Guid.Parse(pr.TransactionId),
                        Timestamp                   = pr.TimeStamp,
                        State                       = pr.State,
                        SequenceNumber              = pr.SequenceId,
                        TransactionManager          = tm,
                        PrepareIsPersisted          = true,
                        LastSent                    = default(DateTime),
                        ConfirmationResponsePromise = null,
                        NumberWrites                = 1 // was a writing transaction
                    });
                    this.stableSequenceNumber = pr.SequenceId;
                }
            }

            // resume committed transactions (on TM)
            foreach (var kvp in storageBatch.MetaData.CommitRecords)
            {
                if (logger.IsEnabled(LogLevel.Debug))
                {
                    logger.Debug($"recover commit confirmation {kvp.Key}");
                }
                this.confirmationWorker.Add(kvp.Key, kvp.Value.Timestamp, kvp.Value.WriteParticipants);
            }

            // check for work
            this.storageWorker.Notify();
            this.RWLock.Notify();
        }
        /// <summary>
        /// called on activation, and when recovering from storage conflicts or other exceptions.
        /// </summary>
        public async Task NotifyOfRestore()
        {
            var loadresponse = await storage.Load();

            this.storageBatch = new StorageBatch <TState>(loadresponse, this.serializerSettings);

            this.stableState          = loadresponse.CommittedState;
            this.stableSequenceNumber = loadresponse.CommittedSequenceId;

            if (logger.IsEnabled(LogLevel.Debug))
            {
                logger.Debug($"Load v{this.stableSequenceNumber} {loadresponse.PendingStates.Count}p {storageBatch.MetaData.CommitRecords.Count}c");
            }

            // ensure clock is consistent with loaded state
            this.Clock.Merge(storageBatch.MetaData.TimeStamp);

            // resume prepared transactions (not TM)
            foreach (var pr in loadresponse.PendingStates.OrderBy(ps => ps.TimeStamp))
            {
                if (pr.SequenceId > this.stableSequenceNumber && pr.TransactionManager != null)
                {
                    if (logger.IsEnabled(LogLevel.Debug))
                    {
                        logger.Debug($"recover two-phase-commit {pr.TransactionId}");
                    }
                    var tm = (pr.TransactionManager == null) ? null :
                             JsonConvert.DeserializeObject <ITransactionParticipant>(pr.TransactionManager, this.serializerSettings);

                    commitQueue.Add(new TransactionRecord <TState>()
                    {
                        Role                        = CommitRole.RemoteCommit,
                        TransactionId               = Guid.Parse(pr.TransactionId),
                        Timestamp                   = pr.TimeStamp,
                        State                       = pr.State,
                        TransactionManager          = tm,
                        PrepareIsPersisted          = true,
                        LastSent                    = default(DateTime),
                        ConfirmationResponsePromise = null
                    });
                }
            }

            // resume committed transactions (on TM)
            foreach (var kvp in storageBatch.MetaData.CommitRecords)
            {
                if (logger.IsEnabled(LogLevel.Debug))
                {
                    logger.Debug($"recover commit confirmation {kvp.Key}");
                }

                confirmationTasks.Add(kvp.Key, new TransactionRecord <TState>()
                {
                    Role              = CommitRole.LocalCommit,
                    TransactionId     = kvp.Key,
                    Timestamp         = kvp.Value.Timestamp,
                    WriteParticipants = kvp.Value.WriteParticipants
                });
            }

            // clear the problem flag
            problemFlag = TransactionalStatus.Ok;

            // check for work
            this.confirmationWorker.Notify();
            this.storageWorker.Notify();
            this.RWLock.Notify();
        }