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(); }