private OperationData WriteRecord(LogRecord record, ulong bytesWritten) { // GopalK: The order of the following instructions is very important Utility.Assert( this.currentLogTailPosition + bytesWritten == (ulong)this.logicalLogStream.WritePosition, "this.currentLogTailPosition == (ulong) this.logicalLogStream.WritePosition"); // Update record position var recordPosition = this.currentLogTailPosition + bytesWritten; record.RecordPosition = recordPosition; // Write record return(LogRecord.WriteRecord(record, this.recordWriter, true, true, this.recomputeRecordOffsets)); }
/// <summary> /// Write the backup log file. /// </summary> /// <param name="stream">Backup log stream.</param> /// <param name="logRecords">The log records.</param> /// <param name="cancellationToken">Token used to signal cancellation.</param> /// <returns>Task that represents the asynchronous operation.</returns> private async Task WriteLogRecordsAsync( Stream stream, IncrementalBackupLogRecordAsyncEnumerator logRecords, CancellationToken cancellationToken) { using (var memoryStream = new MemoryStream(InitialSizeOfMemoryStream)) using (var binaryWriter = new BinaryWriter(memoryStream)) using (var recordWriter = new BinaryWriter(new MemoryStream())) { // Reserve an 'int' at the start to store the size of the block memoryStream.Position += sizeof(int); while (true == await logRecords.MoveNextAsync(cancellationToken).ConfigureAwait(false)) { var record = logRecords.Current; var operationData = LogRecord.WriteRecord(record, recordWriter, isPhysicalWrite: false, setRecordLength: false); // TODO: Fix this by using operationdata in this class foreach (var buffer in operationData) { binaryWriter.Write(buffer.Array, buffer.Offset, buffer.Count); } this.Count++; // Flush the block after it's large enough. if (memoryStream.Position >= MinimumIntermediateFlushSize) { await this.WriteLogRecordBlockAsync(stream, memoryStream, binaryWriter, cancellationToken).ConfigureAwait(false); } // Check for cancellation. cancellationToken.ThrowIfCancellationRequested(); } // Flush the block, if there's any remaining data (ignoring the block size 'int' at the start). if (memoryStream.Position > sizeof(int)) { await this.WriteLogRecordBlockAsync(stream, memoryStream, binaryWriter, cancellationToken).ConfigureAwait(false); } await stream.FlushAsync(cancellationToken).ConfigureAwait(false); } }
/// <summary> /// Write the backup log file. /// </summary> /// <param name="stream">Backup log stream.</param> /// <param name="logRecords">The log records.</param> /// <param name="cancellationToken">Token used to signal cancellation.</param> /// <returns>Task that represents the asynchronous operation.</returns> private async Task WriteLogRecordsAsync( Stream stream, IAsyncEnumerator <LogRecord> logRecords, CancellationToken cancellationToken) { var firstIndexingRecordProcessed = false; using (var memoryStream = new MemoryStream(InitialSizeOfMemoryStream)) using (var binaryWriter = new BinaryWriter(memoryStream)) using (var recordWriter = new BinaryWriter(new MemoryStream())) { // Reserve an 'int' at the start to store the size of the block memoryStream.Position += sizeof(int); while (true == await logRecords.MoveNextAsync(cancellationToken).ConfigureAwait(false)) { var record = logRecords.Current; var indexingLogRecord = record as IndexingLogRecord; if (indexingLogRecord != null) { if (false == firstIndexingRecordProcessed) { this.IndexingRecordEpoch = indexingLogRecord.CurrentEpoch; this.IndexingRecordLsn = indexingLogRecord.Lsn; firstIndexingRecordProcessed = true; } this.LastBackedUpEpoch = indexingLogRecord.CurrentEpoch; } var updateEpochLogRecord = record as UpdateEpochLogRecord; if (updateEpochLogRecord != null) { this.LastBackedUpEpoch = updateEpochLogRecord.Epoch; } this.LastBackedUpLsn = record.Lsn; var operationData = LogRecord.WriteRecord(record, recordWriter, isPhysicalWrite: false, setRecordLength: false); // TODO: Fix this by using operationdata in this class foreach (var buffer in operationData) { binaryWriter.Write(buffer.Array, buffer.Offset, buffer.Count); } this.Count++; // Flush the block after it's large enough. if (memoryStream.Position >= MinimumIntermediateFlushSize) { await this.WriteLogRecordBlockAsync(stream, memoryStream, binaryWriter, cancellationToken).ConfigureAwait(false); } // Check for cancellation. cancellationToken.ThrowIfCancellationRequested(); } // Flush the block, if there's any remaining data (ignoring the block size 'int' at the start). if (memoryStream.Position > sizeof(int)) { await this.WriteLogRecordBlockAsync(stream, memoryStream, binaryWriter, cancellationToken).ConfigureAwait(false); } await stream.FlushAsync(cancellationToken).ConfigureAwait(false); } // If no logical record is being backed up, lastBackedupLsn can be Invalid. if (this.LastBackedUpLsn == LogicalSequenceNumber.InvalidLsn) { this.LastBackedUpLsn = this.IndexingRecordLsn; } Utility.Assert(true == firstIndexingRecordProcessed, "Indexing log record must have been processed."); Utility.Assert( this.IndexingRecordEpoch.CompareTo(LoggingReplicator.InvalidEpoch) > 0, "Indexing record epoch has not been set."); Utility.Assert( this.LastBackedUpEpoch.CompareTo(LoggingReplicator.InvalidEpoch) > 0, "Ending epoch has not been set."); Utility.Assert( this.IndexingRecordLsn != LogicalSequenceNumber.InvalidLsn, "Indexing record lsn has not been set."); Utility.Assert(this.LastBackedUpLsn != LogicalSequenceNumber.InvalidLsn, "Ending lsn has not been set."); }