Exemplo n.º 1
0
        /// <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;
        }
Exemplo n.º 2
0
        /// <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));
        }
Exemplo n.º 3
0
 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;
 }
Exemplo n.º 4
0
        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);
        }
Exemplo n.º 5
0
        /// <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;
        }
Exemplo n.º 6
0
        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);
        }
Exemplo n.º 7
0
        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);
        }