예제 #1
0
        private static void ProcessDuplicateRecord(LogRecord record)
        {
            record.CompletedFlush(null);
            record.CompletedApply(null);
            record.CompletedProcessing(null);

            return;
        }
예제 #2
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;
        }
예제 #3
0
        public async Task ImmediatelyProcessRecord(
            LogRecord record,
            Exception flushException,
            RecordProcessingMode processingMode)
        {
            Utility.Assert(
                processingMode > RecordProcessingMode.Normal,
                "processingMode ({0}) > RecordProcessingMode.Normal",
                processingMode);

            // TODO: Temporary double check.
            Utility.Assert(record.RecordType != LogRecordType.Backup, "record.RecordType != LogRecordType.Backup");

            Exception exception = null;

            if (flushException != null)
            {
                Utility.Assert(
                    this.logException != null,
                    "FlushException is {0} and this.logException is null",
                    flushException);
                exception = flushException;
            }

            // In case there was an apply failure, we should fault any further applies of any records.
            // Without this, we could end up assuming that all applies have succeeded and as a result, issue a checkpoint call
            if (exception == null)
            {
                exception = this.serviceException;
            }

            FabricEvents.Events.RecordProcessedImmediatelyNoise(
                this.tracer.Type,
                (int)this.roleContextDrainState.DrainingStream,
                record.Psn.PSN);

            var information = string.Empty;

            switch (record.RecordType)
            {
            case LogRecordType.TruncateHead:
                this.checkpointManager.ApplyLogHeadTruncationIfPermitted(exception, record);
                break;

            case LogRecordType.BeginCheckpoint:
                if (processingMode == RecordProcessingMode.ProcessImmediately)
                {
                    goto default;
                }

                await this.checkpointManager.ApplyCheckpointIfPermitted(exception, record).ConfigureAwait(false);

                break;

            case LogRecordType.Information:
                information = '-' + ((InformationLogRecord)record).InformationEvent.ToString();
                goto case LogRecordType.EndCheckpoint;

            case LogRecordType.EndCheckpoint:
            case LogRecordType.TruncateTail:
            case LogRecordType.Indexing:
            case LogRecordType.UpdateEpoch:
                goto default;

            default:
                record.CompletedApply(exception);
                break;
            }

            if (processingMode == RecordProcessingMode.ProcessImmediately)
            {
                FabricEvents.Events.RecordProcessedImmediately(
                    this.tracer.Type,
                    (int)this.roleContextDrainState.DrainingStream,
                    information,
                    record.Psn.PSN);

                record.CompletedProcessing(null);
            }

            return;
        }