private static void ProcessDuplicateRecord(LogRecord record) { record.CompletedFlush(null); record.CompletedApply(null); record.CompletedProcessing(null); return; }
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; }
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; }