/// <summary>
        /// Initializes a new instance of the BeginCheckpointLogRecord class.
        /// </summary>
        /// <remarks>Only used for generating invalid BeginCheckpointLogRecord.</remarks>
        private BeginCheckpointLogRecord()
        {
            this.IsFirstCheckpointOnFullCopy = false;
            this.progressVector = null;
            this.earliestPendingTransactionOffset = LogicalLogRecord.InvalidLogicalRecordOffset;
            this.earliestPendingTransaction       = BeginTransactionOperationLogRecord.InvalidBeginTransactionLogRecord;
            this.checkpointState = CheckpointState.Invalid;
            this.lastStableLsn   = LogicalSequenceNumber.InvalidLsn;
            this.epoch           = LogicalSequenceNumber.InvalidEpoch;

            // Initializes the backup information to invalid.
            this.highestBackedUpEpoch = new Epoch(
                LogicalSequenceNumber.InvalidLsn.LSN,
                LogicalSequenceNumber.InvalidLsn.LSN);
            this.highestBackedUpLsn = LogicalSequenceNumber.InvalidLsn;

            // Uint.MaxValue is used to indicate invalid. 4,294,967,295 log records, 4.294967295 TB.
            this.backupLogRecordCount = uint.MaxValue;
            this.backupLogSize        = uint.MaxValue;

            this.earliestPendingTransactionInvalidated = 0;

            this.lastPeriodicCheckpointTimeTicks = 0;
            this.lastPeriodicTruncationTimeTicks = 0;
        }
Example #2
0
        private static LogRecord ReadFromOperationData(OperationData operationData)
        {
            LogRecord     record;
            long          lsn;
            const ulong   RecordPosition = InvalidRecordPosition;
            LogRecordType recordType;
            var           index = -1;

            using (var reader = new BinaryReader(IncrementIndexAndGetMemoryStreamAt(operationData, ref index)))
            {
                // Logical metadata section.
                var startingPosition = reader.BaseStream.Position;
                var sizeOfSection    = reader.ReadInt32();
                var endPosition      = startingPosition + sizeOfSection;

                // Logical metadata read.
                recordType = (LogRecordType)reader.ReadUInt32();
                lsn        = reader.ReadInt64();

                // Jump to the end of the section ignoring fields that are not understood.
                Utility.Assert(endPosition >= reader.BaseStream.Position, "Could not have read more than section size.");
                reader.BaseStream.Position = endPosition;
            }

            switch (recordType)
            {
            case LogRecordType.BeginTransaction:
                record = new BeginTransactionOperationLogRecord(recordType, RecordPosition, lsn);
                break;

            case LogRecordType.Operation:
                record = new OperationLogRecord(recordType, RecordPosition, lsn);
                break;

            case LogRecordType.EndTransaction:
                record = new EndTransactionLogRecord(recordType, RecordPosition, lsn);
                break;

            case LogRecordType.Barrier:
                record = new BarrierLogRecord(recordType, RecordPosition, lsn);
                break;

            case LogRecordType.UpdateEpoch:
                record = new UpdateEpochLogRecord(recordType, RecordPosition, lsn);
                break;

            case LogRecordType.Backup:
                record = new BackupLogRecord(recordType, RecordPosition, lsn);
                break;

            default:
                Utility.CodingError(
                    "Unexpected record type received during replication/copy processing {0}",
                    recordType);
                return(null);
            }

            record.ReadLogical(operationData, ref index);
            return(record);
        }
        internal BeginCheckpointLogRecord(LogRecordType recordType, ulong recordPosition, long lsn)
            : base(recordType, recordPosition, lsn)
        {
            Utility.Assert(
                recordType == LogRecordType.BeginCheckpoint,
                "Record type is expected to be begin checkpoint  but the record type is : {0}",
                recordType);
            this.IsFirstCheckpointOnFullCopy = false;
            this.progressVector = null;
            this.earliestPendingTransactionOffset = LogicalLogRecord.InvalidLogicalRecordOffset;
            this.earliestPendingTransaction       = BeginTransactionOperationLogRecord.InvalidBeginTransactionLogRecord;
            this.checkpointState = CheckpointState.Invalid;
            this.lastStableLsn   = LogicalSequenceNumber.InvalidLsn;
            this.epoch           = LogicalSequenceNumber.InvalidEpoch;

            // Initializes the backup information to invalid.
            this.backupId             = BackupLogRecord.InvalidBackupId;
            this.highestBackedUpEpoch = new Epoch(
                LogicalSequenceNumber.InvalidLsn.LSN,
                LogicalSequenceNumber.InvalidLsn.LSN);
            this.highestBackedUpLsn = LogicalSequenceNumber.InvalidLsn;

            // Uint.MaxValue is used to indicate invalid. 4,294,967,295 log records, 4.294967295 TB.
            this.backupLogRecordCount = uint.MaxValue;
            this.backupLogSize        = uint.MaxValue;

            this.earliestPendingTransactionInvalidated = 0;

            this.lastPeriodicCheckpointTimeTicks = 0;
            this.lastPeriodicTruncationTimeTicks = 0;
        }
Example #4
0
        public void BeginTransaction(Transaction transaction, OperationData metaData, OperationData undo, OperationData redo, object operationContext)
        {
            var record = new BeginTransactionOperationLogRecord(
                transaction,
                metaData,
                undo,
                redo,
                operationContext,
                isSingleOperationTransaction: false);

            this.ProcessLogicalRecordOnPrimary(record);
        }
Example #5
0
        /// <summary>
        /// Process the begin transaction log record.
        /// </summary>
        /// <param name="beginTransactionRecord">The begin transaction record to be processed.</param>
        /// <param name="isRecoverableRecord">Is this a recoverable record.</param>
        private void ProcessLogRecord(
            BeginTransactionOperationLogRecord beginTransactionRecord,
            out bool isRecoverableRecord)
        {
            isRecoverableRecord = true;

            this.LastLogicalSequenceNumber++;
            Utility.Assert(
                beginTransactionRecord.Lsn == this.LastLogicalSequenceNumber,
                "beginTransactionRecord.LastLogicalSequenceNumber == lsn");
            beginTransactionRecord.RecordEpoch = this.CurrentLogTailEpoch;
            this.TransactionsMap.CreateTransaction(beginTransactionRecord);
        }
Example #6
0
        public async Task <long> BeginTransactionAsync(Transaction transaction, OperationData metaData, OperationData undo, OperationData redo, object operationContext)
        {
            var record = new BeginTransactionOperationLogRecord(
                transaction,
                metaData,
                undo,
                redo,
                operationContext,
                isSingleOperationTransaction: true);

            await this.ProcessLogicalRecordOnPrimaryAsync(record).ConfigureAwait(false);

            return(record.Lsn.LSN);
        }
        internal override bool FreePreviousLinksLowerThanPsn(PhysicalSequenceNumber newHeadPsn)
        {
            bool ret = base.FreePreviousLinksLowerThanPsn(newHeadPsn);

            if (this.earliestPendingTransaction != null &&
                this.earliestPendingTransaction.Psn < newHeadPsn)
            {
                Utility.Assert(
                    this.earliestPendingTransactionOffset != LogicalLogRecord.InvalidLogicalRecordOffset,
                    "FreePreviousLinksLowerThanPsn: Earliest pending transaction offset cannot be invalid for checkpoint record lsn: {0}, psn: {1}",
                    Lsn,
                    Psn);

                this.earliestPendingTransaction = BeginTransactionOperationLogRecord.InvalidBeginTransactionLogRecord;
                Interlocked.Increment(ref this.earliestPendingTransactionInvalidated);
                return(true);
            }

            return(ret);
        }
Example #8
0
        internal void CompleteTransaction(EndTransactionLogRecord record)
        {
            Utility.Assert(
                record.Transaction.IsAtomicOperation == false,
                "record.Transaction.IsAtomicOperation == false");

            lock (this.txmapLock)
            {
                if (this.latestRecords.ContainsKey(record.Transaction.Id))
                {
                    record.IsEnlistedTransaction   = this.latestRecords[record.Transaction.Id].IsEnlistedTransaction;
                    record.ParentTransactionRecord = this.latestRecords[record.Transaction.Id];
                    record.ParentTransactionRecord.ChildTransactionRecord = record;
                    this.latestRecords.Remove(record.Transaction.Id);
                }
                else
                {
                    Utility.Assert(record.IsEnlistedTransaction == false, "record.IsEnlistedTransaction == false");
                    record.ParentTransactionRecord = null;
                }

                BeginTransactionOperationLogRecord beginTransactionRecord = null;
                if (this.transactionIdPendingTransactionsPair.ContainsKey(record.Transaction.Id))
                {
                    beginTransactionRecord = this.transactionIdPendingTransactionsPair[record.Transaction.Id];
                    this.lsnPendingTransactionsPair.Remove(
                        this.transactionIdPendingTransactionsPair[record.Transaction.Id].Lsn.LSN);
                    this.transactionIdPendingTransactionsPair.Remove(record.Transaction.Id);
                }

                Utility.Assert(
                    (record.IsEnlistedTransaction == true) == (beginTransactionRecord != null),
                    "(record.IsEnlistedTransaction == true) == (beginTransactionRecord != null)");
                if (beginTransactionRecord != null)
                {
                    this.AddUnstableTransactionCallerHoldsLock(beginTransactionRecord, record);
                }
            }
        }
Example #9
0
        private void AddUnstableTransactionCallerHoldsLock(
            BeginTransactionOperationLogRecord beginTransactionRecord,
            EndTransactionLogRecord endTransactionRecord)
        {
            Utility.Assert(
                beginTransactionRecord.IsSingleOperationTransaction == false,
                "beginTransactionRecord.IsSingleOperationTransaction == false");

            // Transactions tend to complete in order
            int i;

            for (i = this.completedTransactions.Count - 1; i >= 0; i--)
            {
                if (this.completedTransactions[i].Lsn < beginTransactionRecord.Lsn)
                {
                    this.completedTransactions.Insert(i + 1, beginTransactionRecord);
                    break;
                }
            }

            if (i == -1)
            {
                this.completedTransactions.Insert(0, beginTransactionRecord);
            }

            for (i = this.unstableTransactions.Count - 1; i >= 0; i--)
            {
                if (this.unstableTransactions[i].Lsn < endTransactionRecord.Lsn)
                {
                    this.unstableTransactions.Insert(i + 1, endTransactionRecord);
                    break;
                }
            }

            if (i == -1)
            {
                this.unstableTransactions.Insert(0, endTransactionRecord);
            }
        }
Example #10
0
        internal BeginTransactionOperationLogRecord DeleteTransaction(BeginTransactionOperationLogRecord record)
        {
            Utility.Assert(
                record.Transaction.IsAtomicOperation == false,
                "record.Transaction.IsAtomicOperation == false");
            Utility.Assert(record.ParentTransactionRecord == null, "record.ParentTransactionRecord == null");

            if (record.IsSingleOperationTransaction)
            {
                Utility.Assert(record.ParentTransactionRecord == null, "record.ParentTransactionRecord == null");
            }
            else
            {
                lock (this.txmapLock)
                {
                    Utility.Assert(
                        this.latestRecords.ContainsKey(record.Transaction.Id),
                        "transaction log record not found in latest records");
                    Utility.Assert(
                        this.transactionIdPendingTransactionsPair.ContainsKey(record.Transaction.Id),
                        "transaction log record not found in penging records");

                    record = (BeginTransactionOperationLogRecord)this.latestRecords[record.Transaction.Id];

                    Utility.Assert(
                        record == this.transactionIdPendingTransactionsPair[record.Transaction.Id],
                        "pendingTransactions_[id] == record");

                    this.latestRecords.Remove(record.Transaction.Id);
                    record.IsEnlistedTransaction = false;

                    this.lsnPendingTransactionsPair.Remove(
                        this.transactionIdPendingTransactionsPair[record.Transaction.Id].Lsn.LSN);
                    this.transactionIdPendingTransactionsPair.Remove(record.Transaction.Id);
                }
            }

            return(record);
        }
Example #11
0
        internal void CreateTransaction(BeginTransactionOperationLogRecord record)
        {
            Utility.Assert(
                record.Transaction.IsAtomicOperation == false,
                "record.Transaction.IsAtomicOperation == false");
            Utility.Assert(record.ParentTransactionRecord == null, "record.ParentTransactionRecord == null");

            if (record.IsSingleOperationTransaction)
            {
                record.IsEnlistedTransaction = true;
            }
            else
            {
                lock (this.txmapLock)
                {
                    this.latestRecords[record.Transaction.Id] = record;
                    record.IsEnlistedTransaction = true;
                    this.transactionIdPendingTransactionsPair[record.Transaction.Id] = record;
                    this.lsnPendingTransactionsPair[record.Lsn.LSN] = record;
                }
            }
        }
        /// <summary>
        /// Initializes a new instance of the BeginCheckpointLogRecord class.
        /// </summary>
        /// <param name="dummy">Used to indicate that this is not an Invalid BeginCheckpointLogRecord.</param>
        private BeginCheckpointLogRecord(bool dummy)
            : base(LogRecordType.BeginCheckpoint, LogicalSequenceNumber.ZeroLsn, null)
        {
            this.IsFirstCheckpointOnFullCopy = false;
            this.progressVector = ProgressVector.Clone(ProgressVector.ZeroProgressVector, 0, LogicalSequenceNumber.ZeroEpoch, LogicalSequenceNumber.ZeroEpoch);
            this.earliestPendingTransactionOffset = 0;
            this.earliestPendingTransaction       = null;
            this.checkpointState = CheckpointState.Completed;
            this.lastStableLsn   = LogicalSequenceNumber.ZeroLsn;
            this.epoch           = LogicalSequenceNumber.ZeroEpoch;

            // Indicates that a full backup has not been taken yet.
            this.highestBackedUpEpoch = LogicalSequenceNumber.ZeroEpoch;
            this.highestBackedUpLsn   = LogicalSequenceNumber.ZeroLsn;

            // Indicates that the current backup stream has zero logs and hence 0 KB size.
            this.backupLogRecordCount = (uint)0;
            this.backupLogSize        = (uint)0;

            this.earliestPendingTransactionInvalidated = 0;
            this.lastPeriodicCheckpointTimeTicks       = DateTime.Now.Ticks;
            this.lastPeriodicTruncationTimeTicks       = this.lastPeriodicCheckpointTimeTicks;
        }
Example #13
0
        internal BeginTransactionOperationLogRecord FindTransaction(BeginTransactionOperationLogRecord record)
        {
            Utility.Assert(
                record.Transaction.IsAtomicOperation == false,
                "record.Transaction.IsAtomicOperation == false");
            Utility.Assert(record.ParentTransactionRecord == null, "record.ParentTransactionRecord == null");

            if (record.IsSingleOperationTransaction)
            {
                Utility.Assert(record.ParentTransactionRecord == null, "record.ParentTransactionRecord == null");
            }
            else
            {
                lock (this.txmapLock)
                {
                    Utility.Assert(
                        this.latestRecords.ContainsKey(record.Transaction.Id),
                        "Begin transaction log record was not found in latest records");
                    record = (BeginTransactionOperationLogRecord)this.latestRecords[record.Transaction.Id];
                }
            }

            return(record);
        }
        /// <summary>
        /// Initializes a new instance of the BeginCheckpointLogRecord class.
        /// </summary>
        /// <remarks>Called when the replicator decides to checkpoint.</remarks>
        internal BeginCheckpointLogRecord(
            bool isFirstCheckpointOnFullCopy,
            ProgressVector progressVector,
            BeginTransactionOperationLogRecord earliestPendingTransaction,
            Epoch headEpoch,
            Epoch epoch,
            LogicalSequenceNumber lsn,
            PhysicalLogRecord lastLinkedPhysicalRecord,
            BackupLogRecord lastCompletedBackupLogRecord,
            uint progressVectorMaxEntries,
            long periodicCheckpointTimeTicks,
            long periodicTruncationTimeTicks)
            : base(LogRecordType.BeginCheckpoint, lsn, lastLinkedPhysicalRecord)
        {
            this.IsFirstCheckpointOnFullCopy = isFirstCheckpointOnFullCopy;
            this.progressVector = ProgressVector.Clone(progressVector, progressVectorMaxEntries, lastCompletedBackupLogRecord.HighestBackedUpEpoch, headEpoch);

            this.earliestPendingTransactionOffset = LogicalLogRecord.InvalidLogicalRecordOffset;
            this.earliestPendingTransaction       = earliestPendingTransaction;
            this.checkpointState = CheckpointState.Invalid;
            this.lastStableLsn   = LogicalSequenceNumber.InvalidLsn;
            this.epoch           = (earliestPendingTransaction != null) ? earliestPendingTransaction.RecordEpoch : epoch;

            // Initialize backup log record fields.
            this.highestBackedUpEpoch = lastCompletedBackupLogRecord.HighestBackedUpEpoch;
            this.highestBackedUpLsn   = lastCompletedBackupLogRecord.HighestBackedUpLsn;

            this.backupLogRecordCount = lastCompletedBackupLogRecord.BackupLogRecordCount;
            this.backupLogSize        = lastCompletedBackupLogRecord.BackupLogSizeInKB;

            this.earliestPendingTransactionInvalidated = 0;

            this.lastPeriodicCheckpointTimeTicks = periodicCheckpointTimeTicks;
            this.lastPeriodicTruncationTimeTicks = periodicTruncationTimeTicks;
            this.UpdateApproximateDiskSize();
        }
Example #15
0
        private async Task ApplyCallback(LogRecord record)
        {
            Utility.Assert(
                this.roleContextDrainState.DrainingStream != DrainingStream.Invalid && this.roleContextDrainState.DrainingStream != DrainingStream.StateStream,
                "ApplyCallback: this.roleContextDrainState.DrainingStream != DrainingStream.Invalid && this.roleContextDrainState.DrainingStream != DrainingStream.StateStream. It is {0} for log record lsn: {1} and psn: {2}",
                this.roleContextDrainState.DrainingStream, record.Lsn, record.Psn);

            var serviceException = this.serviceException;

            if (serviceException != null)
            {
                record.CompletedApply(serviceException);
                return;
            }

            try
            {
                OperationLogRecord operationRecord;
                var callbackRedoContext = this.roleContextDrainState.ApplyRedoContext;
                switch (record.RecordType)
                {
                case LogRecordType.BeginTransaction:
                    var beginTransactionRecordExtra =
                        (BeginTransactionOperationLogRecord)record;

                    FabricEvents.Events.ApplyCallbackTransactionRecordNoise(
                        this.tracer.Type,
                        (int)this.roleContextDrainState.DrainingStream,
                        (uint)beginTransactionRecordExtra.RecordType,
                        beginTransactionRecordExtra.Lsn.LSN,
                        beginTransactionRecordExtra.Psn.PSN,
                        beginTransactionRecordExtra.RecordPosition,
                        beginTransactionRecordExtra.Transaction.Id);

                    if (beginTransactionRecordExtra.IsSingleOperationTransaction)
                    {
                        if (beginTransactionRecordExtra.Lsn > this.recoveredOrCopiedCheckpointLsn.Value)
                        {
                            beginTransactionRecordExtra.Transaction.CommitSequenceNumber =
                                beginTransactionRecordExtra.Lsn.LSN;

                            var operationContext =
                                await
                                this.stateManager.OnApplyAsync(
                                    beginTransactionRecordExtra.Lsn.LSN,
                                    beginTransactionRecordExtra.Transaction,
                                    beginTransactionRecordExtra.MetaData,
                                    beginTransactionRecordExtra.Redo,
                                    callbackRedoContext).ConfigureAwait(false);

                            if (operationContext != null)
                            {
                                beginTransactionRecordExtra.OperationContext = operationContext;
                            }

                            FabricEvents.Events.ApplyCallbackSingleOperationTransaction(
                                this.tracer.Type,
                                (int)this.roleContextDrainState.DrainingStream,
                                beginTransactionRecordExtra.Lsn.LSN,
                                beginTransactionRecordExtra.Psn.PSN,
                                beginTransactionRecordExtra.RecordPosition,
                                beginTransactionRecordExtra.Transaction.Id);
                        }
                    }

                    break;

                case LogRecordType.Operation:
                    operationRecord = (OperationLogRecord)record;
                    if (operationRecord.Transaction.IsAtomicOperation == true)
                    {
                        if (operationRecord.Lsn > this.recoveredOrCopiedCheckpointLsn.Value)
                        {
                            // For atomic operations create lsn equals commit lsn.
                            operationRecord.Transaction.CommitSequenceNumber = operationRecord.Lsn.LSN;

                            var operationContext =
                                await
                                this.stateManager.OnApplyAsync(
                                    operationRecord.Lsn.LSN,
                                    operationRecord.Transaction,
                                    operationRecord.MetaData,
                                    operationRecord.Redo,
                                    callbackRedoContext).ConfigureAwait(false);

                            if (operationContext != null)
                            {
                                operationRecord.OperationContext = operationContext;
                            }

                            FabricEvents.Events.ApplyCallbackAtomicOperationRecord(
                                this.tracer.Type,
                                (int)this.roleContextDrainState.DrainingStream,
                                operationRecord.Lsn.LSN,
                                operationRecord.Psn.PSN,
                                operationRecord.RecordPosition,
                                operationRecord.Transaction.Id,
                                operationRecord.IsRedoOnly);
                        }
                    }
                    else
                    {
                        FabricEvents.Events.ApplyCallbackTransactionRecordNoise(
                            this.tracer.Type,
                            (int)this.roleContextDrainState.DrainingStream,
                            (uint)operationRecord.RecordType,
                            operationRecord.Lsn.LSN,
                            operationRecord.Psn.PSN,
                            operationRecord.RecordPosition,
                            operationRecord.Transaction.Id);
                    }

                    break;

                case LogRecordType.EndTransaction:
                    var endTransactionRecord = (EndTransactionLogRecord)record;
                    if ((endTransactionRecord.IsCommitted == true) &&
                        (endTransactionRecord.Lsn > this.recoveredOrCopiedCheckpointLsn.Value))
                    {
                        // GopalK: I am currently adopting the approach of only applying updates that do not
                        // belong to any transaction in the update switch above and
                        // applying the updates that belong to a transaction only when if it commits.
                        // The other approach is to immediately apply updates of all
                        // transactions in the update switch case above and then undoing updates of
                        // aborted transactions here.
                        // Both approaches have their pros and cons and we may want to look into
                        // making this a replicator option that the service developer can choose.

                        // If on Primary, Transaction object is shared.
                        endTransactionRecord.Transaction.CommitSequenceNumber = endTransactionRecord.Lsn.LSN;

                        BeginTransactionOperationLogRecord beginTransactionRecord = null;
                        TransactionLogRecord transactionRecord = endTransactionRecord;
                        do
                        {
                            transactionRecord      = transactionRecord.ParentTransactionRecord;
                            beginTransactionRecord = transactionRecord as BeginTransactionOperationLogRecord;
                        } while (beginTransactionRecord == null);

                        {
                            Utility.Assert(
                                LogRecord.IsInvalidRecord(beginTransactionRecord) == false,
                                "TransactionLogRecord.IsInvalidRecord(beginTransactionRecord) == false");

                            Utility.Assert(
                                beginTransactionRecord.IsSingleOperationTransaction == false,
                                "beginTransactionRecord.IsSingleOperationTransaction must be false when endTxRecord is being processed");

                            // If on not Primary, Transaction object is shared.
                            if (callbackRedoContext.HasFlag(ApplyContext.PRIMARY) == false)
                            {
                                beginTransactionRecord.Transaction.CommitSequenceNumber =
                                    endTransactionRecord.Lsn.LSN;
                            }
                            else
                            {
                                // TODO: Temporary assert. Should be removed later.
                                Utility.Assert(
                                    beginTransactionRecord.Transaction.CommitSequenceNumber
                                    == endTransactionRecord.Lsn.LSN,
                                    "Transaction's commit sequence number must have already been set. Expected: {0} Actual: {1}",
                                    transactionRecord.Transaction.CommitSequenceNumber,
                                    endTransactionRecord.Lsn.LSN);
                            }

                            var operationContext =
                                await
                                this.stateManager.OnApplyAsync(
                                    beginTransactionRecord.Lsn.LSN,
                                    beginTransactionRecord.Transaction,
                                    beginTransactionRecord.MetaData,
                                    beginTransactionRecord.Redo,
                                    callbackRedoContext).ConfigureAwait(false);

                            if (operationContext != null)
                            {
                                beginTransactionRecord.OperationContext = operationContext;
                            }

                            FabricEvents.Events.ApplyCallbackTransactionRecordNoise(
                                this.tracer.Type,
                                (int)this.roleContextDrainState.DrainingStream,
                                (uint)beginTransactionRecord.RecordType,
                                beginTransactionRecord.Lsn.LSN,
                                beginTransactionRecord.Psn.PSN,
                                beginTransactionRecord.RecordPosition,
                                beginTransactionRecord.Transaction.Id);
                        }

                        do
                        {
                            transactionRecord = transactionRecord.ChildTransactionRecord;
                            Utility.Assert(
                                (transactionRecord != null) &&
                                (LogRecord.IsInvalidRecord(transactionRecord) == false),
                                "(transactionRecord != null) && (TransactionLogRecord.IsInvalidRecord(transactionRecord) == false");

                            if (transactionRecord == endTransactionRecord)
                            {
                                break;
                            }

                            operationRecord = (OperationLogRecord)transactionRecord;

                            // If on Primary, Transaction object is shared.
                            if (callbackRedoContext.HasFlag(ApplyContext.PRIMARY) == false)
                            {
                                operationRecord.Transaction.CommitSequenceNumber = endTransactionRecord.Lsn.LSN;
                            }
                            else
                            {
                                // TODO: Temporary assert. Should be removed later.
                                Utility.Assert(
                                    operationRecord.Transaction.CommitSequenceNumber == endTransactionRecord.Lsn.LSN,
                                    "Transaction's commit sequence number must have already been set. Expected: {0} Actual: {1}",
                                    transactionRecord.Transaction.CommitSequenceNumber,
                                    endTransactionRecord.Lsn.LSN);
                            }

                            var operationContext =
                                await
                                this.stateManager.OnApplyAsync(
                                    operationRecord.Lsn.LSN,
                                    operationRecord.Transaction,
                                    operationRecord.MetaData,
                                    operationRecord.Redo,
                                    callbackRedoContext).ConfigureAwait(false);

                            if (operationContext != null)
                            {
                                operationRecord.OperationContext = operationContext;
                            }

                            FabricEvents.Events.ApplyCallbackTransactionRecordNoise(
                                this.tracer.Type,
                                (int)this.roleContextDrainState.DrainingStream,
                                (uint)operationRecord.RecordType,
                                operationRecord.Lsn.LSN,
                                operationRecord.Psn.PSN,
                                operationRecord.RecordPosition,
                                operationRecord.Transaction.Id);
                        } while (true);

                        FabricEvents.Events.ApplyCallbackTransactionRecord(
                            this.tracer.Type,
                            (int)this.roleContextDrainState.DrainingStream,
                            endTransactionRecord.Psn.PSN,
                            endTransactionRecord.Transaction.Id);
                    }

                    break;

                case LogRecordType.Barrier:
                    this.LastAppliedBarrierRecord = (BarrierLogRecord)record;

                    FabricEvents.Events.ApplyCallbackBarrierRecord(
                        this.tracer.Type,
                        (int)this.roleContextDrainState.DrainingStream,
                        record.Lsn.LSN,
                        record.Psn.PSN,
                        record.RecordPosition);

                    break;

                case LogRecordType.Backup:

                    // TODO: Trace.
                    break;

                default:
                    Utility.CodingError("Unexpected record type {0}", record.RecordType);
                    break;
                }
            }
            catch (Exception e)
            {
                this.ProcessServiceException("OnApply", record, e);
                serviceException = e;
            }

            record.CompletedApply(serviceException);
            return;
        }
Example #16
0
        internal EndTransactionLogRecord ReifyTransaction(EndTransactionLogRecord record)
        {
            Utility.Assert(
                record.Transaction.IsAtomicOperation == false,
                "record.Transaction.IsAtomicOperation == false");
            Utility.Assert(
                LogRecord.IsInvalidRecord(record.ParentTransactionRecord) == true,
                "LogRecord.IsInvalidRecord(record.ParentTransactionRecord) == true");

            BeginTransactionOperationLogRecord reifiedBeginTransactionRecord = null;
            EndTransactionLogRecord            reifiedEndTransactionRecord   = null;

            int i;

            lock (this.txmapLock)
            {
                for (i = this.completedTransactions.Count - 1; i >= 0; i--)
                {
                    if (this.completedTransactions[i].Transaction == record.Transaction)
                    {
                        reifiedBeginTransactionRecord = this.completedTransactions[i];
                        Utility.Assert(
                            reifiedBeginTransactionRecord.IsSingleOperationTransaction == false,
                            "reifiedBeginTransactionRecord.IsSingleOperationTransaction == false");
                        this.completedTransactions.RemoveAt(i);
                        break;
                    }
                }

                Utility.Assert(i > -1, "Begin transaction record is not present in completed transactions");

                for (i = this.unstableTransactions.Count - 1; i >= 0; i--)
                {
                    if (this.unstableTransactions[i].Transaction == record.Transaction)
                    {
                        reifiedEndTransactionRecord = this.unstableTransactions[i];
                        this.unstableTransactions.RemoveAt(i);
                        break;
                    }
                }

                Utility.Assert(i > -1, "End transaction record is not present in unstable transactions");

                this.latestRecords[record.Transaction.Id] = reifiedEndTransactionRecord.ParentTransactionRecord;
                reifiedEndTransactionRecord.ParentTransactionRecord.ChildTransactionRecord =
                    TransactionLogRecord.InvalidTransactionLogRecord;

                TransactionLogRecord parentRecord = reifiedEndTransactionRecord;
                BeginTransactionOperationLogRecord chainedBeginTransactionRecord;
                do
                {
                    parentRecord = parentRecord.ParentTransactionRecord;
                    chainedBeginTransactionRecord = parentRecord as BeginTransactionOperationLogRecord;
                } while (chainedBeginTransactionRecord == null);

                Utility.Assert(
                    reifiedBeginTransactionRecord == chainedBeginTransactionRecord,
                    "reifiedBeginTransactionRecord == chainedBeginTransactionRecord");
                Utility.Assert(
                    reifiedBeginTransactionRecord.IsEnlistedTransaction,
                    "reifiedBeginTransactionRecord.IsEnlistedTransaction == true");
                this.transactionIdPendingTransactionsPair[reifiedBeginTransactionRecord.Transaction.Id] =
                    reifiedBeginTransactionRecord;
                this.lsnPendingTransactionsPair[reifiedBeginTransactionRecord.Lsn.LSN] = reifiedBeginTransactionRecord;
            }

            return(reifiedEndTransactionRecord);
        }
Example #17
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);
        }