/// <summary> /// Initializes a new instance of the BeginCheckpointLogRecord class. /// </summary> /// <remarks>Only used for generating invalid BeginCheckpointLogRecord.</remarks> private BeginCheckpointLogRecord() { this.IsFirstCheckpointOnFullCopy = false; this.progressVector = null; this.earliestPendingTransactionOffset = LogicalLogRecord.InvalidLogicalRecordOffset; this.earliestPendingTransaction = BeginTransactionOperationLogRecord.InvalidBeginTransactionLogRecord; this.checkpointState = CheckpointState.Invalid; this.lastStableLsn = LogicalSequenceNumber.InvalidLsn; this.epoch = LogicalSequenceNumber.InvalidEpoch; // Initializes the backup information to invalid. this.highestBackedUpEpoch = new Epoch( LogicalSequenceNumber.InvalidLsn.LSN, LogicalSequenceNumber.InvalidLsn.LSN); this.highestBackedUpLsn = LogicalSequenceNumber.InvalidLsn; // Uint.MaxValue is used to indicate invalid. 4,294,967,295 log records, 4.294967295 TB. this.backupLogRecordCount = uint.MaxValue; this.backupLogSize = uint.MaxValue; this.earliestPendingTransactionInvalidated = 0; this.lastPeriodicCheckpointTimeTicks = 0; this.lastPeriodicTruncationTimeTicks = 0; }
private static LogRecord ReadFromOperationData(OperationData operationData) { LogRecord record; long lsn; const ulong RecordPosition = InvalidRecordPosition; LogRecordType recordType; var index = -1; using (var reader = new BinaryReader(IncrementIndexAndGetMemoryStreamAt(operationData, ref index))) { // Logical metadata section. var startingPosition = reader.BaseStream.Position; var sizeOfSection = reader.ReadInt32(); var endPosition = startingPosition + sizeOfSection; // Logical metadata read. recordType = (LogRecordType)reader.ReadUInt32(); lsn = reader.ReadInt64(); // Jump to the end of the section ignoring fields that are not understood. Utility.Assert(endPosition >= reader.BaseStream.Position, "Could not have read more than section size."); reader.BaseStream.Position = endPosition; } switch (recordType) { case LogRecordType.BeginTransaction: record = new BeginTransactionOperationLogRecord(recordType, RecordPosition, lsn); break; case LogRecordType.Operation: record = new OperationLogRecord(recordType, RecordPosition, lsn); break; case LogRecordType.EndTransaction: record = new EndTransactionLogRecord(recordType, RecordPosition, lsn); break; case LogRecordType.Barrier: record = new BarrierLogRecord(recordType, RecordPosition, lsn); break; case LogRecordType.UpdateEpoch: record = new UpdateEpochLogRecord(recordType, RecordPosition, lsn); break; case LogRecordType.Backup: record = new BackupLogRecord(recordType, RecordPosition, lsn); break; default: Utility.CodingError( "Unexpected record type received during replication/copy processing {0}", recordType); return(null); } record.ReadLogical(operationData, ref index); return(record); }
internal BeginCheckpointLogRecord(LogRecordType recordType, ulong recordPosition, long lsn) : base(recordType, recordPosition, lsn) { Utility.Assert( recordType == LogRecordType.BeginCheckpoint, "Record type is expected to be begin checkpoint but the record type is : {0}", recordType); this.IsFirstCheckpointOnFullCopy = false; this.progressVector = null; this.earliestPendingTransactionOffset = LogicalLogRecord.InvalidLogicalRecordOffset; this.earliestPendingTransaction = BeginTransactionOperationLogRecord.InvalidBeginTransactionLogRecord; this.checkpointState = CheckpointState.Invalid; this.lastStableLsn = LogicalSequenceNumber.InvalidLsn; this.epoch = LogicalSequenceNumber.InvalidEpoch; // Initializes the backup information to invalid. this.backupId = BackupLogRecord.InvalidBackupId; this.highestBackedUpEpoch = new Epoch( LogicalSequenceNumber.InvalidLsn.LSN, LogicalSequenceNumber.InvalidLsn.LSN); this.highestBackedUpLsn = LogicalSequenceNumber.InvalidLsn; // Uint.MaxValue is used to indicate invalid. 4,294,967,295 log records, 4.294967295 TB. this.backupLogRecordCount = uint.MaxValue; this.backupLogSize = uint.MaxValue; this.earliestPendingTransactionInvalidated = 0; this.lastPeriodicCheckpointTimeTicks = 0; this.lastPeriodicTruncationTimeTicks = 0; }
public void BeginTransaction(Transaction transaction, OperationData metaData, OperationData undo, OperationData redo, object operationContext) { var record = new BeginTransactionOperationLogRecord( transaction, metaData, undo, redo, operationContext, isSingleOperationTransaction: false); this.ProcessLogicalRecordOnPrimary(record); }
/// <summary> /// Process the begin transaction log record. /// </summary> /// <param name="beginTransactionRecord">The begin transaction record to be processed.</param> /// <param name="isRecoverableRecord">Is this a recoverable record.</param> private void ProcessLogRecord( BeginTransactionOperationLogRecord beginTransactionRecord, out bool isRecoverableRecord) { isRecoverableRecord = true; this.LastLogicalSequenceNumber++; Utility.Assert( beginTransactionRecord.Lsn == this.LastLogicalSequenceNumber, "beginTransactionRecord.LastLogicalSequenceNumber == lsn"); beginTransactionRecord.RecordEpoch = this.CurrentLogTailEpoch; this.TransactionsMap.CreateTransaction(beginTransactionRecord); }
public async Task <long> BeginTransactionAsync(Transaction transaction, OperationData metaData, OperationData undo, OperationData redo, object operationContext) { var record = new BeginTransactionOperationLogRecord( transaction, metaData, undo, redo, operationContext, isSingleOperationTransaction: true); await this.ProcessLogicalRecordOnPrimaryAsync(record).ConfigureAwait(false); return(record.Lsn.LSN); }
internal override bool FreePreviousLinksLowerThanPsn(PhysicalSequenceNumber newHeadPsn) { bool ret = base.FreePreviousLinksLowerThanPsn(newHeadPsn); if (this.earliestPendingTransaction != null && this.earliestPendingTransaction.Psn < newHeadPsn) { Utility.Assert( this.earliestPendingTransactionOffset != LogicalLogRecord.InvalidLogicalRecordOffset, "FreePreviousLinksLowerThanPsn: Earliest pending transaction offset cannot be invalid for checkpoint record lsn: {0}, psn: {1}", Lsn, Psn); this.earliestPendingTransaction = BeginTransactionOperationLogRecord.InvalidBeginTransactionLogRecord; Interlocked.Increment(ref this.earliestPendingTransactionInvalidated); return(true); } return(ret); }
internal void CompleteTransaction(EndTransactionLogRecord record) { Utility.Assert( record.Transaction.IsAtomicOperation == false, "record.Transaction.IsAtomicOperation == false"); lock (this.txmapLock) { if (this.latestRecords.ContainsKey(record.Transaction.Id)) { record.IsEnlistedTransaction = this.latestRecords[record.Transaction.Id].IsEnlistedTransaction; record.ParentTransactionRecord = this.latestRecords[record.Transaction.Id]; record.ParentTransactionRecord.ChildTransactionRecord = record; this.latestRecords.Remove(record.Transaction.Id); } else { Utility.Assert(record.IsEnlistedTransaction == false, "record.IsEnlistedTransaction == false"); record.ParentTransactionRecord = null; } BeginTransactionOperationLogRecord beginTransactionRecord = null; if (this.transactionIdPendingTransactionsPair.ContainsKey(record.Transaction.Id)) { beginTransactionRecord = this.transactionIdPendingTransactionsPair[record.Transaction.Id]; this.lsnPendingTransactionsPair.Remove( this.transactionIdPendingTransactionsPair[record.Transaction.Id].Lsn.LSN); this.transactionIdPendingTransactionsPair.Remove(record.Transaction.Id); } Utility.Assert( (record.IsEnlistedTransaction == true) == (beginTransactionRecord != null), "(record.IsEnlistedTransaction == true) == (beginTransactionRecord != null)"); if (beginTransactionRecord != null) { this.AddUnstableTransactionCallerHoldsLock(beginTransactionRecord, record); } } }
private void AddUnstableTransactionCallerHoldsLock( BeginTransactionOperationLogRecord beginTransactionRecord, EndTransactionLogRecord endTransactionRecord) { Utility.Assert( beginTransactionRecord.IsSingleOperationTransaction == false, "beginTransactionRecord.IsSingleOperationTransaction == false"); // Transactions tend to complete in order int i; for (i = this.completedTransactions.Count - 1; i >= 0; i--) { if (this.completedTransactions[i].Lsn < beginTransactionRecord.Lsn) { this.completedTransactions.Insert(i + 1, beginTransactionRecord); break; } } if (i == -1) { this.completedTransactions.Insert(0, beginTransactionRecord); } for (i = this.unstableTransactions.Count - 1; i >= 0; i--) { if (this.unstableTransactions[i].Lsn < endTransactionRecord.Lsn) { this.unstableTransactions.Insert(i + 1, endTransactionRecord); break; } } if (i == -1) { this.unstableTransactions.Insert(0, endTransactionRecord); } }
internal BeginTransactionOperationLogRecord DeleteTransaction(BeginTransactionOperationLogRecord record) { Utility.Assert( record.Transaction.IsAtomicOperation == false, "record.Transaction.IsAtomicOperation == false"); Utility.Assert(record.ParentTransactionRecord == null, "record.ParentTransactionRecord == null"); if (record.IsSingleOperationTransaction) { Utility.Assert(record.ParentTransactionRecord == null, "record.ParentTransactionRecord == null"); } else { lock (this.txmapLock) { Utility.Assert( this.latestRecords.ContainsKey(record.Transaction.Id), "transaction log record not found in latest records"); Utility.Assert( this.transactionIdPendingTransactionsPair.ContainsKey(record.Transaction.Id), "transaction log record not found in penging records"); record = (BeginTransactionOperationLogRecord)this.latestRecords[record.Transaction.Id]; Utility.Assert( record == this.transactionIdPendingTransactionsPair[record.Transaction.Id], "pendingTransactions_[id] == record"); this.latestRecords.Remove(record.Transaction.Id); record.IsEnlistedTransaction = false; this.lsnPendingTransactionsPair.Remove( this.transactionIdPendingTransactionsPair[record.Transaction.Id].Lsn.LSN); this.transactionIdPendingTransactionsPair.Remove(record.Transaction.Id); } } return(record); }
internal void CreateTransaction(BeginTransactionOperationLogRecord record) { Utility.Assert( record.Transaction.IsAtomicOperation == false, "record.Transaction.IsAtomicOperation == false"); Utility.Assert(record.ParentTransactionRecord == null, "record.ParentTransactionRecord == null"); if (record.IsSingleOperationTransaction) { record.IsEnlistedTransaction = true; } else { lock (this.txmapLock) { this.latestRecords[record.Transaction.Id] = record; record.IsEnlistedTransaction = true; this.transactionIdPendingTransactionsPair[record.Transaction.Id] = record; this.lsnPendingTransactionsPair[record.Lsn.LSN] = record; } } }
/// <summary> /// Initializes a new instance of the BeginCheckpointLogRecord class. /// </summary> /// <param name="dummy">Used to indicate that this is not an Invalid BeginCheckpointLogRecord.</param> private BeginCheckpointLogRecord(bool dummy) : base(LogRecordType.BeginCheckpoint, LogicalSequenceNumber.ZeroLsn, null) { this.IsFirstCheckpointOnFullCopy = false; this.progressVector = ProgressVector.Clone(ProgressVector.ZeroProgressVector, 0, LogicalSequenceNumber.ZeroEpoch, LogicalSequenceNumber.ZeroEpoch); this.earliestPendingTransactionOffset = 0; this.earliestPendingTransaction = null; this.checkpointState = CheckpointState.Completed; this.lastStableLsn = LogicalSequenceNumber.ZeroLsn; this.epoch = LogicalSequenceNumber.ZeroEpoch; // Indicates that a full backup has not been taken yet. this.highestBackedUpEpoch = LogicalSequenceNumber.ZeroEpoch; this.highestBackedUpLsn = LogicalSequenceNumber.ZeroLsn; // Indicates that the current backup stream has zero logs and hence 0 KB size. this.backupLogRecordCount = (uint)0; this.backupLogSize = (uint)0; this.earliestPendingTransactionInvalidated = 0; this.lastPeriodicCheckpointTimeTicks = DateTime.Now.Ticks; this.lastPeriodicTruncationTimeTicks = this.lastPeriodicCheckpointTimeTicks; }
internal BeginTransactionOperationLogRecord FindTransaction(BeginTransactionOperationLogRecord record) { Utility.Assert( record.Transaction.IsAtomicOperation == false, "record.Transaction.IsAtomicOperation == false"); Utility.Assert(record.ParentTransactionRecord == null, "record.ParentTransactionRecord == null"); if (record.IsSingleOperationTransaction) { Utility.Assert(record.ParentTransactionRecord == null, "record.ParentTransactionRecord == null"); } else { lock (this.txmapLock) { Utility.Assert( this.latestRecords.ContainsKey(record.Transaction.Id), "Begin transaction log record was not found in latest records"); record = (BeginTransactionOperationLogRecord)this.latestRecords[record.Transaction.Id]; } } return(record); }
/// <summary> /// Initializes a new instance of the BeginCheckpointLogRecord class. /// </summary> /// <remarks>Called when the replicator decides to checkpoint.</remarks> internal BeginCheckpointLogRecord( bool isFirstCheckpointOnFullCopy, ProgressVector progressVector, BeginTransactionOperationLogRecord earliestPendingTransaction, Epoch headEpoch, Epoch epoch, LogicalSequenceNumber lsn, PhysicalLogRecord lastLinkedPhysicalRecord, BackupLogRecord lastCompletedBackupLogRecord, uint progressVectorMaxEntries, long periodicCheckpointTimeTicks, long periodicTruncationTimeTicks) : base(LogRecordType.BeginCheckpoint, lsn, lastLinkedPhysicalRecord) { this.IsFirstCheckpointOnFullCopy = isFirstCheckpointOnFullCopy; this.progressVector = ProgressVector.Clone(progressVector, progressVectorMaxEntries, lastCompletedBackupLogRecord.HighestBackedUpEpoch, headEpoch); this.earliestPendingTransactionOffset = LogicalLogRecord.InvalidLogicalRecordOffset; this.earliestPendingTransaction = earliestPendingTransaction; this.checkpointState = CheckpointState.Invalid; this.lastStableLsn = LogicalSequenceNumber.InvalidLsn; this.epoch = (earliestPendingTransaction != null) ? earliestPendingTransaction.RecordEpoch : epoch; // Initialize backup log record fields. this.highestBackedUpEpoch = lastCompletedBackupLogRecord.HighestBackedUpEpoch; this.highestBackedUpLsn = lastCompletedBackupLogRecord.HighestBackedUpLsn; this.backupLogRecordCount = lastCompletedBackupLogRecord.BackupLogRecordCount; this.backupLogSize = lastCompletedBackupLogRecord.BackupLogSizeInKB; this.earliestPendingTransactionInvalidated = 0; this.lastPeriodicCheckpointTimeTicks = periodicCheckpointTimeTicks; this.lastPeriodicTruncationTimeTicks = periodicTruncationTimeTicks; this.UpdateApproximateDiskSize(); }
private async Task ApplyCallback(LogRecord record) { Utility.Assert( this.roleContextDrainState.DrainingStream != DrainingStream.Invalid && this.roleContextDrainState.DrainingStream != DrainingStream.StateStream, "ApplyCallback: this.roleContextDrainState.DrainingStream != DrainingStream.Invalid && this.roleContextDrainState.DrainingStream != DrainingStream.StateStream. It is {0} for log record lsn: {1} and psn: {2}", this.roleContextDrainState.DrainingStream, record.Lsn, record.Psn); var serviceException = this.serviceException; if (serviceException != null) { record.CompletedApply(serviceException); return; } try { OperationLogRecord operationRecord; var callbackRedoContext = this.roleContextDrainState.ApplyRedoContext; switch (record.RecordType) { case LogRecordType.BeginTransaction: var beginTransactionRecordExtra = (BeginTransactionOperationLogRecord)record; FabricEvents.Events.ApplyCallbackTransactionRecordNoise( this.tracer.Type, (int)this.roleContextDrainState.DrainingStream, (uint)beginTransactionRecordExtra.RecordType, beginTransactionRecordExtra.Lsn.LSN, beginTransactionRecordExtra.Psn.PSN, beginTransactionRecordExtra.RecordPosition, beginTransactionRecordExtra.Transaction.Id); if (beginTransactionRecordExtra.IsSingleOperationTransaction) { if (beginTransactionRecordExtra.Lsn > this.recoveredOrCopiedCheckpointLsn.Value) { beginTransactionRecordExtra.Transaction.CommitSequenceNumber = beginTransactionRecordExtra.Lsn.LSN; var operationContext = await this.stateManager.OnApplyAsync( beginTransactionRecordExtra.Lsn.LSN, beginTransactionRecordExtra.Transaction, beginTransactionRecordExtra.MetaData, beginTransactionRecordExtra.Redo, callbackRedoContext).ConfigureAwait(false); if (operationContext != null) { beginTransactionRecordExtra.OperationContext = operationContext; } FabricEvents.Events.ApplyCallbackSingleOperationTransaction( this.tracer.Type, (int)this.roleContextDrainState.DrainingStream, beginTransactionRecordExtra.Lsn.LSN, beginTransactionRecordExtra.Psn.PSN, beginTransactionRecordExtra.RecordPosition, beginTransactionRecordExtra.Transaction.Id); } } break; case LogRecordType.Operation: operationRecord = (OperationLogRecord)record; if (operationRecord.Transaction.IsAtomicOperation == true) { if (operationRecord.Lsn > this.recoveredOrCopiedCheckpointLsn.Value) { // For atomic operations create lsn equals commit lsn. operationRecord.Transaction.CommitSequenceNumber = operationRecord.Lsn.LSN; var operationContext = await this.stateManager.OnApplyAsync( operationRecord.Lsn.LSN, operationRecord.Transaction, operationRecord.MetaData, operationRecord.Redo, callbackRedoContext).ConfigureAwait(false); if (operationContext != null) { operationRecord.OperationContext = operationContext; } FabricEvents.Events.ApplyCallbackAtomicOperationRecord( this.tracer.Type, (int)this.roleContextDrainState.DrainingStream, operationRecord.Lsn.LSN, operationRecord.Psn.PSN, operationRecord.RecordPosition, operationRecord.Transaction.Id, operationRecord.IsRedoOnly); } } else { FabricEvents.Events.ApplyCallbackTransactionRecordNoise( this.tracer.Type, (int)this.roleContextDrainState.DrainingStream, (uint)operationRecord.RecordType, operationRecord.Lsn.LSN, operationRecord.Psn.PSN, operationRecord.RecordPosition, operationRecord.Transaction.Id); } break; case LogRecordType.EndTransaction: var endTransactionRecord = (EndTransactionLogRecord)record; if ((endTransactionRecord.IsCommitted == true) && (endTransactionRecord.Lsn > this.recoveredOrCopiedCheckpointLsn.Value)) { // GopalK: I am currently adopting the approach of only applying updates that do not // belong to any transaction in the update switch above and // applying the updates that belong to a transaction only when if it commits. // The other approach is to immediately apply updates of all // transactions in the update switch case above and then undoing updates of // aborted transactions here. // Both approaches have their pros and cons and we may want to look into // making this a replicator option that the service developer can choose. // If on Primary, Transaction object is shared. endTransactionRecord.Transaction.CommitSequenceNumber = endTransactionRecord.Lsn.LSN; BeginTransactionOperationLogRecord beginTransactionRecord = null; TransactionLogRecord transactionRecord = endTransactionRecord; do { transactionRecord = transactionRecord.ParentTransactionRecord; beginTransactionRecord = transactionRecord as BeginTransactionOperationLogRecord; } while (beginTransactionRecord == null); { Utility.Assert( LogRecord.IsInvalidRecord(beginTransactionRecord) == false, "TransactionLogRecord.IsInvalidRecord(beginTransactionRecord) == false"); Utility.Assert( beginTransactionRecord.IsSingleOperationTransaction == false, "beginTransactionRecord.IsSingleOperationTransaction must be false when endTxRecord is being processed"); // If on not Primary, Transaction object is shared. if (callbackRedoContext.HasFlag(ApplyContext.PRIMARY) == false) { beginTransactionRecord.Transaction.CommitSequenceNumber = endTransactionRecord.Lsn.LSN; } else { // TODO: Temporary assert. Should be removed later. Utility.Assert( beginTransactionRecord.Transaction.CommitSequenceNumber == endTransactionRecord.Lsn.LSN, "Transaction's commit sequence number must have already been set. Expected: {0} Actual: {1}", transactionRecord.Transaction.CommitSequenceNumber, endTransactionRecord.Lsn.LSN); } var operationContext = await this.stateManager.OnApplyAsync( beginTransactionRecord.Lsn.LSN, beginTransactionRecord.Transaction, beginTransactionRecord.MetaData, beginTransactionRecord.Redo, callbackRedoContext).ConfigureAwait(false); if (operationContext != null) { beginTransactionRecord.OperationContext = operationContext; } FabricEvents.Events.ApplyCallbackTransactionRecordNoise( this.tracer.Type, (int)this.roleContextDrainState.DrainingStream, (uint)beginTransactionRecord.RecordType, beginTransactionRecord.Lsn.LSN, beginTransactionRecord.Psn.PSN, beginTransactionRecord.RecordPosition, beginTransactionRecord.Transaction.Id); } do { transactionRecord = transactionRecord.ChildTransactionRecord; Utility.Assert( (transactionRecord != null) && (LogRecord.IsInvalidRecord(transactionRecord) == false), "(transactionRecord != null) && (TransactionLogRecord.IsInvalidRecord(transactionRecord) == false"); if (transactionRecord == endTransactionRecord) { break; } operationRecord = (OperationLogRecord)transactionRecord; // If on Primary, Transaction object is shared. if (callbackRedoContext.HasFlag(ApplyContext.PRIMARY) == false) { operationRecord.Transaction.CommitSequenceNumber = endTransactionRecord.Lsn.LSN; } else { // TODO: Temporary assert. Should be removed later. Utility.Assert( operationRecord.Transaction.CommitSequenceNumber == endTransactionRecord.Lsn.LSN, "Transaction's commit sequence number must have already been set. Expected: {0} Actual: {1}", transactionRecord.Transaction.CommitSequenceNumber, endTransactionRecord.Lsn.LSN); } var operationContext = await this.stateManager.OnApplyAsync( operationRecord.Lsn.LSN, operationRecord.Transaction, operationRecord.MetaData, operationRecord.Redo, callbackRedoContext).ConfigureAwait(false); if (operationContext != null) { operationRecord.OperationContext = operationContext; } FabricEvents.Events.ApplyCallbackTransactionRecordNoise( this.tracer.Type, (int)this.roleContextDrainState.DrainingStream, (uint)operationRecord.RecordType, operationRecord.Lsn.LSN, operationRecord.Psn.PSN, operationRecord.RecordPosition, operationRecord.Transaction.Id); } while (true); FabricEvents.Events.ApplyCallbackTransactionRecord( this.tracer.Type, (int)this.roleContextDrainState.DrainingStream, endTransactionRecord.Psn.PSN, endTransactionRecord.Transaction.Id); } break; case LogRecordType.Barrier: this.LastAppliedBarrierRecord = (BarrierLogRecord)record; FabricEvents.Events.ApplyCallbackBarrierRecord( this.tracer.Type, (int)this.roleContextDrainState.DrainingStream, record.Lsn.LSN, record.Psn.PSN, record.RecordPosition); break; case LogRecordType.Backup: // TODO: Trace. break; default: Utility.CodingError("Unexpected record type {0}", record.RecordType); break; } } catch (Exception e) { this.ProcessServiceException("OnApply", record, e); serviceException = e; } record.CompletedApply(serviceException); return; }
internal EndTransactionLogRecord ReifyTransaction(EndTransactionLogRecord record) { Utility.Assert( record.Transaction.IsAtomicOperation == false, "record.Transaction.IsAtomicOperation == false"); Utility.Assert( LogRecord.IsInvalidRecord(record.ParentTransactionRecord) == true, "LogRecord.IsInvalidRecord(record.ParentTransactionRecord) == true"); BeginTransactionOperationLogRecord reifiedBeginTransactionRecord = null; EndTransactionLogRecord reifiedEndTransactionRecord = null; int i; lock (this.txmapLock) { for (i = this.completedTransactions.Count - 1; i >= 0; i--) { if (this.completedTransactions[i].Transaction == record.Transaction) { reifiedBeginTransactionRecord = this.completedTransactions[i]; Utility.Assert( reifiedBeginTransactionRecord.IsSingleOperationTransaction == false, "reifiedBeginTransactionRecord.IsSingleOperationTransaction == false"); this.completedTransactions.RemoveAt(i); break; } } Utility.Assert(i > -1, "Begin transaction record is not present in completed transactions"); for (i = this.unstableTransactions.Count - 1; i >= 0; i--) { if (this.unstableTransactions[i].Transaction == record.Transaction) { reifiedEndTransactionRecord = this.unstableTransactions[i]; this.unstableTransactions.RemoveAt(i); break; } } Utility.Assert(i > -1, "End transaction record is not present in unstable transactions"); this.latestRecords[record.Transaction.Id] = reifiedEndTransactionRecord.ParentTransactionRecord; reifiedEndTransactionRecord.ParentTransactionRecord.ChildTransactionRecord = TransactionLogRecord.InvalidTransactionLogRecord; TransactionLogRecord parentRecord = reifiedEndTransactionRecord; BeginTransactionOperationLogRecord chainedBeginTransactionRecord; do { parentRecord = parentRecord.ParentTransactionRecord; chainedBeginTransactionRecord = parentRecord as BeginTransactionOperationLogRecord; } while (chainedBeginTransactionRecord == null); Utility.Assert( reifiedBeginTransactionRecord == chainedBeginTransactionRecord, "reifiedBeginTransactionRecord == chainedBeginTransactionRecord"); Utility.Assert( reifiedBeginTransactionRecord.IsEnlistedTransaction, "reifiedBeginTransactionRecord.IsEnlistedTransaction == true"); this.transactionIdPendingTransactionsPair[reifiedBeginTransactionRecord.Transaction.Id] = reifiedBeginTransactionRecord; this.lsnPendingTransactionsPair[reifiedBeginTransactionRecord.Lsn.LSN] = reifiedBeginTransactionRecord; } return(reifiedEndTransactionRecord); }
private static LogRecord ReadRecord(BinaryReader br, ulong recordPosition, bool isPhysicalRead) { LogRecord record; var lsn = LogicalSequenceNumber.InvalidLsn.LSN; LogRecordType recordType; // Metadata section. var startingPosition = br.BaseStream.Position; var sizeOfSection = br.ReadInt32(); var endPosition = startingPosition + sizeOfSection; // Read Logical Metadata recordType = (LogRecordType)br.ReadUInt32(); switch (recordType) { case LogRecordType.BeginTransaction: record = new BeginTransactionOperationLogRecord(recordType, recordPosition, lsn); break; case LogRecordType.Operation: record = new OperationLogRecord(recordType, recordPosition, lsn); break; case LogRecordType.EndTransaction: record = new EndTransactionLogRecord(recordType, recordPosition, lsn); break; case LogRecordType.Barrier: record = new BarrierLogRecord(recordType, recordPosition, lsn); break; case LogRecordType.UpdateEpoch: record = new UpdateEpochLogRecord(recordType, recordPosition, lsn); break; case LogRecordType.Backup: record = new BackupLogRecord(recordType, recordPosition, lsn); break; case LogRecordType.BeginCheckpoint: record = new BeginCheckpointLogRecord(recordType, recordPosition, lsn); break; case LogRecordType.EndCheckpoint: record = new EndCheckpointLogRecord(recordType, recordPosition, lsn); break; case LogRecordType.Indexing: record = new IndexingLogRecord(recordType, recordPosition, lsn); break; case LogRecordType.TruncateHead: record = new TruncateHeadLogRecord(recordType, recordPosition, lsn); break; case LogRecordType.TruncateTail: record = new TruncateTailLogRecord(recordType, recordPosition, lsn); break; case LogRecordType.Information: record = new InformationLogRecord(recordType, recordPosition, lsn); break; case LogRecordType.CompleteCheckpoint: record = new CompleteCheckpointLogRecord(recordType, recordPosition, lsn); break; default: Utility.CodingError("Unexpected record type {0}", recordType); return(null); } record.lsn = new LogicalSequenceNumber(br.ReadInt64()); // Jump to the end of the section ignoring fields that are not understood. Utility.Assert(endPosition >= br.BaseStream.Position, "Could not have read more than section size."); br.BaseStream.Position = endPosition; record.Read(br, isPhysicalRead); return(record); }