コード例 #1
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));
        }
コード例 #2
0
        /// <summary>
        /// Process the complete checkpoint log record.
        /// </summary>
        /// <param name="completeCheckpointLogRecord">The complete checkpoint record to be processed.</param>
        /// <param name="isRecoverableRecord">Is this a recoverable record.</param>
        private void ProcessLogRecord(
            CompleteCheckpointLogRecord completeCheckpointLogRecord,
            out bool isRecoverableRecord)
        {
            if (this.mode == Mode.Restore)
            {
                completeCheckpointLogRecord.HeadRecord = this.firstIndexingLogRecord;
            }

            isRecoverableRecord           = false;
            this.LastLinkedPhysicalRecord = completeCheckpointLogRecord;
        }
コード例 #3
0
 ///
 /// Append complete checkpoint record
 ///
 public void CompleteCheckpoint()
 {
     lock (lsnOrderingLock)
     {
         var record = new CompleteCheckpointLogRecord(
             this.CurrentLogTailLsn,
             this.CurrentLogHeadRecord,
             this.LastLinkedPhysicalRecord);
         this.LastLinkedPhysicalRecord = record;
         this.LogManager.PhysicalLogWriter.InsertBufferedRecord(record);
     }
 }
コード例 #4
0
        public async Task <RecoveryInformation> OpenAsync(
            ReplicaOpenMode openMode,
            TransactionalReplicatorSettings replicatorSettings,
            ITracer tracer,
            LogManager logManager,
            bool shouldLocalStateBeRemoved,
            PhysicalLogReader recoveryReader,
            bool isRestoring)
        {
            this.RecoveryLogsReader = recoveryReader;
            this.tracer             = tracer;

            PhysicalLogRecord           recoveredLinkedPhysicalRecord;
            TruncateHeadLogRecord       recoveredLastTruncateHeadLogRecord = null;
            CompleteCheckpointLogRecord recoveredCompleteCheckpointRecord  = null;

            this.logCompleteCheckpointAfterRecovery = true;

            this.tailRecordAtStart = await this.RecoveryLogsReader.SeekToLastRecord().ConfigureAwait(false);

            var logUsage = logManager.Length;
            var trace    = "OpenAsync: Log Usage: " + logUsage + " Recovered Replica Tail Record Type: "
                           + tailRecordAtStart.RecordType + " LSN: " + tailRecordAtStart.Lsn.LSN + " PSN: "
                           + tailRecordAtStart.Psn.PSN + " Position: " + tailRecordAtStart.RecordPosition;

            FabricEvents.Events.Api(tracer.Type, trace);

            var lastPhysicalRecord = tailRecordAtStart as PhysicalLogRecord;

            if (lastPhysicalRecord == null)
            {
                lastPhysicalRecord = await this.RecoveryLogsReader.GetPreviousPhysicalRecord(tailRecordAtStart).ConfigureAwait(false);
            }

            trace = "OpenAsync: Recovered last physical record Type: " + lastPhysicalRecord.RecordType + " LSN: "
                    + lastPhysicalRecord.Lsn.LSN + " PSN: " + lastPhysicalRecord.Psn.PSN + " Position: "
                    + lastPhysicalRecord.RecordPosition;

            FabricEvents.Events.Api(tracer.Type, trace);

            if (lastPhysicalRecord.RecordType == LogRecordType.Information)
            {
                var removingStateRecord = lastPhysicalRecord as InformationLogRecord;
                if (removingStateRecord.InformationEvent == InformationEvent.RemovingState)
                {
                    Utility.Assert(
                        lastPhysicalRecord == tailRecordAtStart,
                        "Last Physical Record {0} should be same as tail record at start {1}",
                        lastPhysicalRecord, tailRecordAtStart);

                    FabricEvents.Events.Api(tracer.Type, "OpenAsync: Skipping Recovery due to pending RemovingState");

                    this.IsRemovingStateAfterOpen = true;

                    return(new RecoveryInformation(shouldLocalStateBeRemoved));
                }
            }

            if (lastPhysicalRecord.RecordType == LogRecordType.TruncateHead)
            {
                recoveredLastTruncateHeadLogRecord = lastPhysicalRecord as TruncateHeadLogRecord;
            }
            else if (lastPhysicalRecord.RecordType == LogRecordType.EndCheckpoint)
            {
                this.RecoveredLastEndCheckpointRecord = lastPhysicalRecord as EndCheckpointLogRecord;
            }
            else if (lastPhysicalRecord.RecordType == LogRecordType.CompleteCheckpoint)
            {
                recoveredCompleteCheckpointRecord = lastPhysicalRecord as CompleteCheckpointLogRecord;
            }
            else
            {
                recoveredLinkedPhysicalRecord = await this.RecoveryLogsReader.GetLinkedPhysicalRecord(lastPhysicalRecord).ConfigureAwait(false);

                Utility.Assert(
                    (recoveredLinkedPhysicalRecord != null) &&
                    ((recoveredLinkedPhysicalRecord.RecordType == LogRecordType.TruncateHead) ||
                     (recoveredLinkedPhysicalRecord.RecordType == LogRecordType.EndCheckpoint) ||
                     (recoveredLinkedPhysicalRecord.RecordType == LogRecordType.CompleteCheckpoint)),
                    "Record type should be truncate head or end checkpoint or complete checkpoint. Record type is : {0}",
                    recoveredLinkedPhysicalRecord.RecordType);

                trace = "OpenAsync: RecoveredLinkedPhysicalRecord: " + recoveredLinkedPhysicalRecord.RecordType
                        + " LSN: " + recoveredLinkedPhysicalRecord.Lsn.LSN + " PSN: "
                        + recoveredLinkedPhysicalRecord.Psn.PSN + " Position: "
                        + recoveredLinkedPhysicalRecord.RecordPosition;

                FabricEvents.Events.Api(tracer.Type, trace);

                if (recoveredLinkedPhysicalRecord.RecordType == LogRecordType.TruncateHead)
                {
                    recoveredLastTruncateHeadLogRecord = recoveredLinkedPhysicalRecord as TruncateHeadLogRecord;
                }
                else if (recoveredLinkedPhysicalRecord.RecordType == LogRecordType.EndCheckpoint)
                {
                    this.RecoveredLastEndCheckpointRecord = recoveredLinkedPhysicalRecord as EndCheckpointLogRecord;
                }
                else
                {
                    recoveredCompleteCheckpointRecord = recoveredLinkedPhysicalRecord as CompleteCheckpointLogRecord;
                }
            }

            ulong logHeadPosition = 0;
            long  logHeadLsn      = 0;

            if (recoveredLastTruncateHeadLogRecord != null)
            {
                logHeadPosition = recoveredLastTruncateHeadLogRecord.LogHeadRecordPosition;
                logHeadLsn      = recoveredLastTruncateHeadLogRecord.LogHeadLsn.LSN;
                trace           = "OpenAsync: Recovered last truncate head record Type: "
                                  + recoveredLastTruncateHeadLogRecord.RecordType + " LSN: "
                                  + recoveredLastTruncateHeadLogRecord.Lsn.LSN + " PSN: "
                                  + recoveredLastTruncateHeadLogRecord.Psn.PSN + " Position: "
                                  + recoveredLastTruncateHeadLogRecord.RecordPosition + " LogHeadLSN: "
                                  + recoveredLastTruncateHeadLogRecord.LogHeadLsn.LSN + " LogHeadPosition: "
                                  + recoveredLastTruncateHeadLogRecord.LogHeadRecordPosition;

                FabricEvents.Events.Api(tracer.Type, trace);

                recoveredLinkedPhysicalRecord = recoveredLastTruncateHeadLogRecord;
                do
                {
                    recoveredLinkedPhysicalRecord = await this.RecoveryLogsReader.GetLinkedPhysicalRecord(recoveredLinkedPhysicalRecord).ConfigureAwait(false);

                    Utility.Assert(
                        (recoveredLinkedPhysicalRecord != null) &&
                        ((recoveredLinkedPhysicalRecord.RecordType == LogRecordType.TruncateHead) ||
                         (recoveredLinkedPhysicalRecord.RecordType == LogRecordType.EndCheckpoint) ||
                         (recoveredLinkedPhysicalRecord.RecordType == LogRecordType.CompleteCheckpoint)),
                        "Record type should be truncate head or end checkpoint or complete checkpoint. Record type is : {0}",
                        recoveredLinkedPhysicalRecord.RecordType);

                    this.RecoveredLastEndCheckpointRecord = recoveredLinkedPhysicalRecord as EndCheckpointLogRecord;

                    if (recoveredLinkedPhysicalRecord.RecordType == LogRecordType.CompleteCheckpoint)
                    {
                        recoveredCompleteCheckpointRecord = recoveredLinkedPhysicalRecord as CompleteCheckpointLogRecord;
                    }
                } while (this.RecoveredLastEndCheckpointRecord == null);
            }
            else if (recoveredCompleteCheckpointRecord != null)
            {
                logHeadPosition = recoveredCompleteCheckpointRecord.LogHeadRecordPosition;
                logHeadLsn      = recoveredCompleteCheckpointRecord.LogHeadLsn.LSN;

                trace = "OpenAsync: Recovered last complete checkpoint record Type: "
                        + recoveredCompleteCheckpointRecord.RecordType + " LSN: "
                        + recoveredCompleteCheckpointRecord.Lsn.LSN + " PSN: "
                        + recoveredCompleteCheckpointRecord.Psn.PSN + " Position: "
                        + recoveredCompleteCheckpointRecord.RecordPosition + " LogHeadLsn: "
                        + recoveredCompleteCheckpointRecord.LogHeadLsn.LSN + " LogHeadPosition: "
                        + recoveredCompleteCheckpointRecord.LogHeadRecordPosition;

                FabricEvents.Events.Api(tracer.Type, trace);
                recoveredLinkedPhysicalRecord = recoveredCompleteCheckpointRecord;

                do
                {
                    recoveredLinkedPhysicalRecord = await this.RecoveryLogsReader.GetLinkedPhysicalRecord(recoveredLinkedPhysicalRecord).ConfigureAwait(false);

                    Utility.Assert(
                        (recoveredLinkedPhysicalRecord != null) &&
                        ((recoveredLinkedPhysicalRecord.RecordType == LogRecordType.TruncateHead) ||
                         (recoveredLinkedPhysicalRecord.RecordType == LogRecordType.EndCheckpoint) ||
                         (recoveredLinkedPhysicalRecord.RecordType == LogRecordType.CompleteCheckpoint)),
                        "Record type should be truncate head or end checkpoint or complete checkpoint. Record type is : {0}",
                        recoveredLinkedPhysicalRecord.RecordType);

                    this.RecoveredLastEndCheckpointRecord = recoveredLinkedPhysicalRecord as EndCheckpointLogRecord;
                } while (this.RecoveredLastEndCheckpointRecord == null);
            }
            else
            {
                logHeadPosition = this.RecoveredLastEndCheckpointRecord.LogHeadRecordPosition;
                logHeadLsn      = this.RecoveredLastEndCheckpointRecord.LogHeadLsn.LSN;
            }

            trace = "OpenAsync: Recovered last end checkpoint record Type: "
                    + this.RecoveredLastEndCheckpointRecord.RecordType + " LSN: " + this.RecoveredLastEndCheckpointRecord.Lsn.LSN
                    + " PSN: " + this.RecoveredLastEndCheckpointRecord.Psn.PSN + " Position: "
                    + this.RecoveredLastEndCheckpointRecord.RecordPosition + " LogHeadLSN: "
                    + this.RecoveredLastEndCheckpointRecord.LogHeadLsn.LSN + " LogHeadPosition: "
                    + this.RecoveredLastEndCheckpointRecord.LogHeadRecordPosition;

            FabricEvents.Events.Api(tracer.Type, trace);
            if (recoveredCompleteCheckpointRecord != null)
            {
                this.logCompleteCheckpointAfterRecovery = false;

                // This is fine since both the begin and end records guarantee all the SP's have been renamed
                trace = "OpenAsync: " + " LogHeadPosition: " + this.RecoveredLastEndCheckpointRecord.LogHeadRecordPosition
                        + Environment.NewLine + " LogHeadLSN: " + this.RecoveredLastEndCheckpointRecord.LogHeadLsn.LSN
                        + Environment.NewLine + "           CompleteCheckpoint record found with LSN: "
                        + recoveredCompleteCheckpointRecord.Lsn.LSN + " PSN: "
                        + recoveredCompleteCheckpointRecord.Psn.PSN + " Position: "
                        + recoveredCompleteCheckpointRecord.RecordPosition;

                FabricEvents.Events.Api(tracer.Type, trace);
            }
            else
            {
                this.logCompleteCheckpointAfterRecovery = true;

                trace = "OpenAsync: " + " LogHeadPosition: " + this.RecoveredLastEndCheckpointRecord.LogHeadRecordPosition
                        + Environment.NewLine + " LogHeadLSN: " + this.RecoveredLastEndCheckpointRecord.LogHeadLsn.LSN
                        + Environment.NewLine + "           CompleteCheckpoint record missing";

                FabricEvents.Events.Api(tracer.Type, trace);
            }

            // For restore cases, logHeadPosition must be 0.
            if (isRestoring == true)
            {
                Utility.Assert(
                    logHeadPosition == 0,
                    "Full backup: LogHead Position ({0}) must be 0",
                    logHeadPosition);
            }

            this.RecoveryLogsReader.MoveStartingRecordPosition(
                logHeadLsn,
                logHeadPosition,
                "recovery",
                LogManager.LogReaderType.Recovery);

            logManager.SetLogHeadRecordPosition(logHeadPosition);

            return(new RecoveryInformation(
                       this.logCompleteCheckpointAfterRecovery,
                       shouldLocalStateBeRemoved));
        }
コード例 #5
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);
        }
コード例 #6
0
ファイル: LogRecord.cs プロジェクト: zmyer/service-fabric
        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);
        }