/// <summary> /// Process the end checkpoint log record. /// </summary> /// <param name="endCheckpointLogRecord">The end checkpoint record to be processed.</param> /// <param name="isRecoverableRecord">Is this a recoverable record.</param> private void ProcessLogRecord(EndCheckpointLogRecord endCheckpointLogRecord, out bool isRecoverableRecord) { if (this.mode == Mode.Restore) { endCheckpointLogRecord.HeadRecord = this.firstIndexingLogRecord; } this.LastStableLsn = endCheckpointLogRecord.LastStableLsn; this.LastLinkedPhysicalRecord = endCheckpointLogRecord; if (Mode.Recovery == this.mode) { if (endCheckpointLogRecord.RecordPosition == this.recoveredLastEndCheckpointRecord.RecordPosition) { Utility.Assert( this.LastStableLsn >= this.recoveredLastCompletedBeginCheckpointRecord.Lsn, "this.lastStableLsn ({0}) >= recoveredLastCompletedBeginCheckpointRecord.LastLogicalSequenceNumber ({1}).", this.LastStableLsn, this.recoveredLastCompletedBeginCheckpointRecord.Lsn); } } this.LastCompletedEndCheckpointRecord = endCheckpointLogRecord; if (this.LastInProgressCheckpointRecord != null) { this.LastInProgressCheckpointRecord.LastStableLsn = this.LastStableLsn; this.LastCompletedEndCheckpointRecord.LastCompletedBeginCheckpointRecord = this.LastInProgressCheckpointRecord; this.LastInProgressCheckpointRecord = null; } isRecoverableRecord = false; }
/// <summary> /// Creates or finds the log stream. /// If being created either initializes the log with default log records or records from backup log. /// </summary> /// <param name="openMode">Open mode of the replica.</param> /// <returns>Task that represents the asynchronous open operation.</returns> internal async Task <PhysicalLogReader> OpenAsync(ReplicaOpenMode openMode) { // TODO: Anurag: do we plumb c.token up? this.LogicalLog = await this.CreateLogFileAsync(openMode == ReplicaOpenMode.New, CancellationToken.None).ConfigureAwait(false); var logLogLength = this.LogicalLog.Length; if (logLogLength <= sizeof(int)) { // No usable content in the log if (this.LogicalLog.WritePosition > 0) { await this.LogicalLog.TruncateTail(0, CancellationToken.None).ConfigureAwait(false); // Remove all contents and reset write cursor back to 0 Utility.Assert(this.LogicalLog.Length == 0, "this.logicalLog.Length == 0"); Utility.Assert(this.LogicalLog.WritePosition == 0, "this.logicalLog.WritePosition == 0"); } using ( var logWriter = new PhysicalLogWriter( this.LogicalLog, this.emptyCallbackManager, this.Tracer, this.MaxWriteCacheSizeInMB, this.IncomingBytesRateCounterWriter, this.LogFlushBytesRateCounterWriter, this.BytesPerFlushCounterWriter, this.AvgFlushLatencyCounterWriter, this.AvgSerializationLatencyCounterWriter, false)) { var zeroIndexRecord = IndexingLogRecord.CreateZeroIndexingLogRecord(); logWriter.InsertBufferedRecord(zeroIndexRecord); logWriter.InsertBufferedRecord(UpdateEpochLogRecord.CreateZeroUpdateEpochLogRecord()); var zeroBeginCheckpointRecord = BeginCheckpointLogRecord.CreateZeroBeginCheckpointLogRecord(); logWriter.InsertBufferedRecord(zeroBeginCheckpointRecord); logWriter.InsertBufferedRecord(BarrierLogRecord.CreateOneBarrierLogRecord()); var oneEndCheckpointRecord = EndCheckpointLogRecord.CreateOneEndCheckpointLogRecord( zeroBeginCheckpointRecord, zeroIndexRecord); logWriter.InsertBufferedRecord(oneEndCheckpointRecord); var endCompleteCheckpointRecord = new CompleteCheckpointLogRecord( LogicalSequenceNumber.OneLsn, zeroIndexRecord, oneEndCheckpointRecord); logWriter.InsertBufferedRecord(endCompleteCheckpointRecord); await logWriter.FlushAsync("OpenAsync").ConfigureAwait(false); // This additional await is required to ensure the log record was indeed flushed. // Without this, the flushasync could succeed, but the log record flush could have failed due to a write error await endCompleteCheckpointRecord.AwaitFlush().ConfigureAwait(false); } } return(new PhysicalLogReader(this)); }
public void Reuse( ProgressVector progressVector, EndCheckpointLogRecord lastCompletedEndCheckpointRecord, BeginCheckpointLogRecord lastInProgressBeginCheckpointRecord, PhysicalLogRecord lastLinkedPhysicalRecord, InformationLogRecord lastInformationRecord, IndexingLogRecord currentLogHeadRecord, Epoch tailEpoch, LogicalSequenceNumber tailLsn) { this.LastInProgressCheckpointRecord = lastInProgressBeginCheckpointRecord; Utility.Assert(this.LastInProgressCheckpointRecord == null, "ReInitialize of ReplicatedLogManager must have null in progress checkpoint"); this.LastInProgressTruncateHeadRecord = null; this.ProgressVector = progressVector; this.LastCompletedEndCheckpointRecord = lastCompletedEndCheckpointRecord; this.LastLinkedPhysicalRecord = lastLinkedPhysicalRecord; this.CurrentLogHeadRecord = currentLogHeadRecord; this.LastInformationRecord = lastInformationRecord; this.CurrentLogTailEpoch = tailEpoch; this.CurrentLogTailLsn = tailLsn; }
internal async Task <BeginCheckpointLogRecord> GetLastCompletedBeginCheckpointRecord( EndCheckpointLogRecord record) { var lastCompletedBeginCheckpointRecord = record.LastCompletedBeginCheckpointRecord; if (!LogRecord.IsInvalidRecord(lastCompletedBeginCheckpointRecord)) { return(lastCompletedBeginCheckpointRecord); } var lastCompletedBeginCheckpointRecordOffset = record.LastCompletedBeginCheckpointRecordOffset; Utility.Assert( lastCompletedBeginCheckpointRecordOffset > 0, "lastCompletedBeginCheckpointRecordOffset {0} > 0", lastCompletedBeginCheckpointRecordOffset); // Read desired checkpoint record var recordPosition = record.RecordPosition; Utility.Assert( recordPosition != LogRecord.InvalidRecordPosition, "recordPosition ({0}) != LogRecord.INVALID_RECORD_POSITION", recordPosition); var lastCompletedBeginCheckpointRecordPosition = recordPosition - lastCompletedBeginCheckpointRecordOffset; Utility.Assert( lastCompletedBeginCheckpointRecordPosition >= this.startingRecordPosition, "lastCompletedBeginCheckpointRecordPosition ({0}) >= this.startingRecordPosition ({1})", lastCompletedBeginCheckpointRecordPosition, this.startingRecordPosition); lastCompletedBeginCheckpointRecord = (BeginCheckpointLogRecord)await this.GetNextLogRecord(lastCompletedBeginCheckpointRecordPosition).ConfigureAwait(false); record.LastCompletedBeginCheckpointRecord = lastCompletedBeginCheckpointRecord; return(lastCompletedBeginCheckpointRecord); }
/// <summary> /// Initializes a new instance of the LogRecordsMap class for recovery. /// </summary> /// <param name="startingLogicalSequenceNumber"></param> /// <param name="transactionsMap"></param> /// <param name="currentLogTailEpoch"></param> /// <param name="lastStableLsn"></param> /// <param name="progressVector"></param> /// <param name="recoveredLastCompletedBeginCheckpointRecord"></param> /// <param name="tracer"></param> /// <param name="recoveredLastEndCheckpointRecord"></param> public LogRecordsMap( LogicalSequenceNumber startingLogicalSequenceNumber, TransactionMap transactionsMap, Epoch currentLogTailEpoch, LogicalSequenceNumber lastStableLsn, ProgressVector progressVector, BeginCheckpointLogRecord recoveredLastCompletedBeginCheckpointRecord, ITracer tracer, EndCheckpointLogRecord recoveredLastEndCheckpointRecord) { this.mode = Mode.Recovery; this.LastLogicalSequenceNumber = startingLogicalSequenceNumber; this.TransactionsMap = transactionsMap; this.CurrentLogTailEpoch = currentLogTailEpoch; this.LastStableLsn = lastStableLsn; this.LastPhysicalRecord = PhysicalLogRecord.InvalidPhysicalLogRecord; this.ProgressVector = progressVector; this.recoveredLastCompletedBeginCheckpointRecord = recoveredLastCompletedBeginCheckpointRecord; this.tracer = tracer; this.recoveredLastEndCheckpointRecord = recoveredLastEndCheckpointRecord; }
public async Task <LogRecord> TruncateTailAsync() { Utility.Assert( tailLsn < this.replicatedLogManager.CurrentLogTailLsn, "tailLsn < this.currentLogTailLsn. Current log tail lsn: {0}", this.replicatedLogManager.CurrentLogTailLsn.LSN); Utility.Assert( tailLsn >= this.replicatedLogManager.LastCompletedBeginCheckpointRecord.Lsn, "tailLsn >= this.LastCompletedBeginCheckpointRecord.LastLogicalSequenceNumber. LastCompletedBeginCheckpointLogRecord: {0}", this.replicatedLogManager.LastCompletedBeginCheckpointRecord.Lsn); Utility.Assert( this.replicatedLogManager.LastInProgressTruncateHeadRecord == null, "this.lastInProgressTruncateHeadRecord == null"); var currentRecord = this.replicatedLogManager.LogManager.CurrentLogTailRecord; var currentLsn = currentRecord.Lsn; var isUpdateRecordAtTail = true; var recoveredLsn = currentLsn; EndCheckpointLogRecord endCheckpointLogRecord = null; CompleteCheckpointLogRecord completeCheckpointLogRecord = null; var lastPhysicalRecord = this.replicatedLogManager.LogManager.CurrentLastPhysicalRecord; do { Utility.Assert( LogRecord.IsInvalidRecord(currentRecord) == false, "LogRecord.IsInvalidRecord(currentRecord ({0})) == false", currentRecord); if (isUpdateRecordAtTail == true) { isUpdateRecordAtTail = currentRecord.Lsn == recoveredLsn; } OperationData metaData = null; switch (currentRecord.RecordType) { case LogRecordType.BeginTransaction: var beginTransactionRecord = (BeginTransactionOperationLogRecord)currentRecord; // Cache the latest metadata just read from disk metaData = beginTransactionRecord.MetaData; beginTransactionRecord = this.transactionsMap.DeleteTransaction(beginTransactionRecord); // Reset the metadata of the transaction as it may have been modified during redo pass beginTransactionRecord.MetaData = metaData; if (beginTransactionRecord.IsSingleOperationTransaction) { Utility.Assert( beginTransactionRecord.Lsn != LogicalSequenceNumber.InvalidLsn, "begin transaction record lsn must not be invalid."); beginTransactionRecord.Transaction.CommitSequenceNumber = beginTransactionRecord.Lsn.LSN; var operationContext = await this.stateManager.OnApplyAsync( beginTransactionRecord.Lsn.LSN, beginTransactionRecord.Transaction, beginTransactionRecord.MetaData, beginTransactionRecord.Undo, falseProgressApplyContext).ConfigureAwait(false); if (operationContext != null) { this.stateManager.Unlock(operationContext); } FabricEvents.Events.TruncateTailSingleOperationTransactionRecord( this.tracer.Type, "Deleted", beginTransactionRecord.Lsn.LSN, beginTransactionRecord.Psn.PSN, beginTransactionRecord.RecordPosition, beginTransactionRecord.Transaction.Id); } else { FabricEvents.Events.TruncateTailTransactionRecord( this.tracer.Type, "Deleted", beginTransactionRecord.Lsn.LSN, beginTransactionRecord.Psn.PSN, beginTransactionRecord.RecordPosition, beginTransactionRecord.Transaction.Id); } break; case LogRecordType.Operation: var operationRecord = (OperationLogRecord)currentRecord; // Cache the latest metadata just read from disk metaData = operationRecord.MetaData; operationRecord = this.transactionsMap.RedactOperation(operationRecord); // Reset the metadata of the operation as it may have been modified during redo pass operationRecord.MetaData = metaData; if (operationRecord.Transaction.IsAtomicOperation == true) { Utility.Assert( operationRecord.IsRedoOnly == false, "TruncateTail- RedoOnly operation cannot be undone"); Utility.Assert( operationRecord.Lsn != LogicalSequenceNumber.InvalidLsn, "Operation's lsn must not be invalid."); operationRecord.Transaction.CommitSequenceNumber = operationRecord.Lsn.LSN; var operationContext = await this.stateManager.OnApplyAsync( operationRecord.Lsn.LSN, operationRecord.Transaction, operationRecord.MetaData, operationRecord.Undo, falseProgressApplyContext).ConfigureAwait(false); if (operationContext != null) { this.stateManager.Unlock(operationContext); } FabricEvents.Events.TruncateTailAtomicOperation( this.tracer.Type, operationRecord.Lsn.LSN, operationRecord.Psn.PSN, operationRecord.RecordPosition, operationRecord.Transaction.Id); } else { FabricEvents.Events.TruncateTailOperationRecord( this.tracer.Type, "Deleted", operationRecord.Lsn.LSN, operationRecord.Psn.PSN, operationRecord.RecordPosition, operationRecord.Transaction.Id); } break; case LogRecordType.EndTransaction: var endTransactionRecord = (EndTransactionLogRecord)currentRecord; endTransactionRecord = this.transactionsMap.ReifyTransaction(endTransactionRecord); Utility.Assert( endTransactionRecord.Lsn != LogicalSequenceNumber.InvalidLsn, "end transaction record cannot have an invalid lsn."); // Undo all operations (Call apply with undo). if (endTransactionRecord.IsCommitted == true) { TransactionLogRecord transactionRecord = endTransactionRecord; do { // During recovery operations that may be undo are kept in memory. // Since Truncate tail uses the in-memory links, Transaction have already been created and their commit sequence numbers // have been set during recovery redo. Utility.Assert( transactionRecord.RecordType == LogRecordType.EndTransaction || transactionRecord.Transaction.CommitSequenceNumber != LogicalSequenceNumber.InvalidLsn.LSN, "For an operation to be undone, it must already have been done."); object operationContext = null; transactionRecord = transactionRecord.ParentTransactionRecord; Utility.Assert(transactionRecord != null, "transactionRecord != null"); if (transactionRecord is BeginTransactionOperationLogRecord) { // Cache the metadata read from disk var justReadTransactionRecord = await this.recoveryLogsReader.GetNextLogRecord(transactionRecord.RecordPosition).ConfigureAwait(false); Utility.Assert( justReadTransactionRecord.RecordType == LogRecordType.BeginTransaction, "Just read transaction during false progress is not begintransaction. It is {0}", justReadTransactionRecord.RecordType); var justReadBeginTransactionRecord = (BeginTransactionOperationLogRecord)justReadTransactionRecord; var beginTx = (BeginTransactionOperationLogRecord)transactionRecord; beginTx.MetaData = justReadBeginTransactionRecord.MetaData; Utility.Assert( beginTx.IsSingleOperationTransaction == false, "beginTx.IsSingleOperationTransaction must be false when endTxRecord is being processed"); operationContext = await this.stateManager.OnApplyAsync( beginTx.Lsn.LSN, beginTx.Transaction, beginTx.MetaData, beginTx.Undo, falseProgressApplyContext).ConfigureAwait(false); if (operationContext != null) { beginTx.OperationContext = operationContext; } break; } // Cache the metadata read from disk var justReadOperationLogRecord = await this.recoveryLogsReader.GetNextLogRecord(transactionRecord.RecordPosition).ConfigureAwait(false); Utility.Assert( justReadOperationLogRecord.RecordType == LogRecordType.Operation, "Just read operation during false progress is not of the right type. It is {0}", justReadOperationLogRecord.RecordType); var justReadOperationRecord = (OperationLogRecord)justReadOperationLogRecord; operationRecord = (OperationLogRecord)transactionRecord; operationRecord.MetaData = justReadOperationRecord.MetaData; operationContext = await this.stateManager.OnApplyAsync( operationRecord.Lsn.LSN, operationRecord.Transaction, operationRecord.MetaData, operationRecord.Undo, falseProgressApplyContext).ConfigureAwait(false); if (operationContext != null) { operationRecord.OperationContext = operationContext; } } while (true); // call unlock transactionRecord = endTransactionRecord; do { object operationContext = null; transactionRecord = transactionRecord.ParentTransactionRecord; Utility.Assert(transactionRecord != null, "transactionRecord != null"); if (transactionRecord is BeginTransactionOperationLogRecord) { var beginTx = (BeginTransactionOperationLogRecord)transactionRecord; operationContext = beginTx.ResetOperationContext(); if (operationContext != null) { this.stateManager.Unlock(operationContext); } FabricEvents.Events.TruncateTailOperationRecord( this.tracer.Type, "Undone", beginTx.Lsn.LSN, beginTx.Psn.PSN, beginTx.RecordPosition, beginTx.Transaction.Id); break; } operationRecord = (OperationLogRecord)transactionRecord; operationContext = operationRecord.ResetOperationContext(); if (operationContext != null) { this.stateManager.Unlock(operationContext); } FabricEvents.Events.TruncateTailOperationRecord( this.tracer.Type, "Undone", operationRecord.Lsn.LSN, operationRecord.Psn.PSN, operationRecord.RecordPosition, operationRecord.Transaction.Id); } while (true); } FabricEvents.Events.TruncateTailTransactionRecord( this.tracer.Type, "Reified", endTransactionRecord.Lsn.LSN, endTransactionRecord.Psn.PSN, endTransactionRecord.RecordPosition, endTransactionRecord.Transaction.Id); break; case LogRecordType.Barrier: var barrierRecord = (BarrierLogRecord)currentRecord; FabricEvents.Events.TruncateTailBarrier( this.tracer.Type, barrierRecord.Lsn.LSN, barrierRecord.Psn.PSN, barrierRecord.RecordPosition); break; case LogRecordType.Backup: // Inform the backup manager that the last backup log record has been undone. this.backupManager.UndoLastCompletedBackupLogRecord(); // Trace that the backup log record has been false progressed. var backupRecord = (BackupLogRecord)currentRecord; #if !DotNetCoreClr // These are new events defined in System.Fabric, existing CoreCLR apps would break // if these events are refernced as it wont be found. As CoreCLR apps carry System.Fabric // along with application // This is just a mitigation for now. Actual fix being tracked via bug# 11614507 FabricEvents.Events.TruncateTailBackup( this.tracer.Type, backupRecord.Lsn.LSN, backupRecord.Psn.PSN, backupRecord.RecordPosition); #endif break; case LogRecordType.UpdateEpoch: // These records can only occur at the tail Utility.Assert(isUpdateRecordAtTail == true, "isUpdateRecordAtTail == true"); var updateEpochRecord = (UpdateEpochLogRecord)currentRecord; var lastVector = new ProgressVectorEntry(updateEpochRecord); this.replicatedLogManager.ProgressVector.TruncateTail(lastVector); FabricEvents.Events.TruncateTailUpdateEpoch( this.tracer.Type, lastVector.Epoch.DataLossNumber, lastVector.Epoch.ConfigurationNumber, updateEpochRecord.Lsn.LSN, updateEpochRecord.Psn.PSN, updateEpochRecord.RecordPosition); break; case LogRecordType.EndCheckpoint: Utility.Assert( currentRecord.Psn == this.replicatedLogManager.LastCompletedEndCheckpointRecord.Psn, "currentRecord.Psn == this.lastCompletedEndCheckpointRecord.Psn"); Utility.Assert( currentRecord.Psn == this.replicatedLogManager.LastLinkedPhysicalRecord.Psn, "currentRecord.Psn == this.lastLinkedPhysicalRecord.Psn"); endCheckpointLogRecord = this.replicatedLogManager.LastCompletedEndCheckpointRecord; this.replicatedLogManager.OnTruncateTailOfLastLinkedPhysicalRecord(); goto case LogRecordType.Indexing; case LogRecordType.TruncateHead: Utility.Assert( currentRecord.Psn == this.replicatedLogManager.LastLinkedPhysicalRecord.Psn, "currentRecord.Psn == this.lastLinkedPhysicalRecord.Psn"); var truncateHeadRecord = (TruncateHeadLogRecord)currentRecord; Utility.Assert( truncateHeadRecord.IsStable == false, "Stable truncateHeadRecord cannot be undone due to false progress"); this.replicatedLogManager.OnTruncateTailOfLastLinkedPhysicalRecord(); goto case LogRecordType.Indexing; case LogRecordType.CompleteCheckpoint: completeCheckpointLogRecord = currentRecord as CompleteCheckpointLogRecord; this.replicatedLogManager.OnTruncateTailOfLastLinkedPhysicalRecord(); goto case LogRecordType.Indexing; case LogRecordType.Indexing: case LogRecordType.TruncateTail: case LogRecordType.BeginCheckpoint: case LogRecordType.Information: Utility.Assert( currentRecord.Psn == lastPhysicalRecord.Psn, "currentRecord.Psn == lastPhysicalRecord.Psn"); lastPhysicalRecord = lastPhysicalRecord.PreviousPhysicalRecord; break; default: Utility.CodingError("Unexpected record type {0}", currentRecord.RecordType); break; } currentRecord = await this.recoveryLogsReader.GetPreviousLogRecord(currentRecord.RecordPosition).ConfigureAwait(false); currentLsn = currentRecord.Lsn; } while (currentLsn > tailLsn); Utility.Assert(currentLsn == tailLsn, "V1 replicator ensures that lsns are continuous. currentLsn {0} == tailLsn {1}", currentLsn, tailLsn); if (currentRecord is LogicalLogRecord) { switch (currentRecord.RecordType) { case LogRecordType.BeginTransaction: var beginTransactionRecord = (BeginTransactionOperationLogRecord)currentRecord; currentRecord = this.transactionsMap.FindTransaction(beginTransactionRecord); // Single operation transactions are not stored in the tx map and hence are not returned above. As a result, they dont have a valid indexing of the previous physical record if (beginTransactionRecord.IsSingleOperationTransaction) { currentRecord.PreviousPhysicalRecord = lastPhysicalRecord; } break; case LogRecordType.Operation: var operationRecord = (OperationLogRecord)currentRecord; currentRecord = this.transactionsMap.FindOperation(operationRecord); // Atomic operations are not stored in the tx map and hence are not returned above. As a result, they dont have a valid indexing of the previous physical record if (operationRecord.Transaction.IsAtomicOperation) { currentRecord.PreviousPhysicalRecord = lastPhysicalRecord; } break; case LogRecordType.EndTransaction: var endTransactionRecord = (EndTransactionLogRecord)currentRecord; currentRecord = this.transactionsMap.FindUnstableTransaction(endTransactionRecord); break; case LogRecordType.Backup: case LogRecordType.Barrier: currentRecord.PreviousPhysicalRecord = lastPhysicalRecord; break; case LogRecordType.UpdateEpoch: currentRecord.PreviousPhysicalRecord = lastPhysicalRecord; break; default: Utility.CodingError("Unexpected record type {0}", currentRecord.RecordType); break; } Utility.Assert( currentRecord.PreviousPhysicalRecord == lastPhysicalRecord, "currentRecord.PreviousPhysicalRecord == lastPhysicalRecord"); } else { Utility.Assert( lastPhysicalRecord.Psn == currentRecord.Psn, "lastPhysicalRecord.Psn == currentRecord.Psn"); currentRecord = lastPhysicalRecord; } Utility.Assert( (this.replicatedLogManager.LastLinkedPhysicalRecord == lastPhysicalRecord) || (this.replicatedLogManager.LastLinkedPhysicalRecord == lastPhysicalRecord.LinkedPhysicalRecord), "(this.lastLinkedPhysicalRecord == lastPhysicalRecord) || (this.lastLinkedPhysicalRecord == lastPhysicalRecord.LinkedPhysicalRecord)"); await this.replicatedLogManager.LogManager.PerformLogTailTruncationAsync(currentRecord).ConfigureAwait(false); this.replicatedLogManager.SetTailLsn(tailLsn); // If endchkpoint was truncated, even complete checkpoint must be truncated if (endCheckpointLogRecord != null) { Utility.Assert( completeCheckpointLogRecord != null, "TruncateTailAsync: EndCheckpoint was truncated but CompleteCheckpoint was not"); this.replicatedLogManager.EndCheckpoint(endCheckpointLogRecord.LastCompletedBeginCheckpointRecord); } if (completeCheckpointLogRecord != null) { this.replicatedLogManager.CompleteCheckpoint(); } this.replicatedLogManager.TruncateTail(tailLsn); await this.replicatedLogManager.LogManager.FlushAsync("TruncateTailAsync").ConfigureAwait(false); FabricEvents.Events.TruncateTailDone( this.tracer.Type, currentRecord.RecordType.ToString(), currentRecord.Lsn.LSN, currentRecord.Psn.PSN, currentRecord.RecordPosition); return(currentRecord); }
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); }