public static void WriteWithLengthPrefixAndSuffixTo(this ILogRecord record, BinaryWriter writer) { using (var memoryStream = new MemoryStream()) { record.WriteTo(new BinaryWriter(memoryStream)); var length = (int)memoryStream.Length; writer.Write(length); writer.Write(memoryStream.GetBuffer(), 0, (int)memoryStream.Length); writer.Write(length); } }
public RecordWriteResult TryAppend(ILogRecord record) { if (_isReadOnly) { throw new InvalidOperationException("Cannot write to a read-only block."); } var workItem = _writerWorkItem; var buffer = workItem.Buffer; var bufferWriter = workItem.BufferWriter; buffer.SetLength(4); buffer.Position = 4; record.WriteTo(bufferWriter); var length = (int)buffer.Length - 4; bufferWriter.Write(length); // length suffix buffer.Position = 0; bufferWriter.Write(length); // length prefix if (workItem.StreamPosition + length + 2 * sizeof(int) > ChunkHeader.Size + _chunkHeader.ChunkSize) { return(RecordWriteResult.Failed(GetDataPosition(workItem))); } var oldPosition = WriteRawData(workItem, buffer); _physicalDataSize = (int)GetDataPosition(workItem); // should fit 32 bits _logicalDataSize = ChunkHeader.GetLocalLogPosition(record.LogPosition + length + 2 * sizeof(int)); // for non-scavenged chunk _physicalDataSize should be the same as _logicalDataSize // for scavenged chunk _logicalDataSize should be at least the same as _physicalDataSize if ((!ChunkHeader.IsScavenged && _logicalDataSize != _physicalDataSize) || (ChunkHeader.IsScavenged && _logicalDataSize < _physicalDataSize)) { throw new Exception(string.Format( "Data sizes violation. Chunk: {0}, IsScavenged: {1}, LogicalDataSize: {2}, PhysicalDataSize: {3}.", FileName, ChunkHeader.IsScavenged, _logicalDataSize, _physicalDataSize)); } return(RecordWriteResult.Successful(oldPosition, _physicalDataSize)); }
public RecordWriteResult TryAppend(ILogRecord record) { if (_isCompleted) { throw new ChunkWriteException(this.ToString(), string.Format("Cannot write to a read-only chunk, isMemoryChunk: {0}, _dataPosition: {1}", _isMemoryChunk, _dataPosition)); } _lastActiveTime = DateTime.Now; var writerWorkItem = _writerWorkItem; var bufferStream = writerWorkItem.BufferStream; var bufferWriter = writerWorkItem.BufferWriter; var recordBuffer = default(byte[]); if (IsFixedDataSize()) { if (writerWorkItem.WorkingStream.Position + _chunkConfig.ChunkDataUnitSize > ChunkHeader.Size + _chunkHeader.ChunkDataTotalSize) { return(RecordWriteResult.NotEnoughSpace()); } bufferStream.Position = 0; record.WriteTo(GlobalDataPosition, bufferWriter); var recordLength = (int)bufferStream.Length; if (recordLength != _chunkConfig.ChunkDataUnitSize) { throw new ChunkWriteException(this.ToString(), string.Format("Invalid fixed data length, expected length {0}, but was {1}", _chunkConfig.ChunkDataUnitSize, recordLength)); } if (_cacheItems != null) { recordBuffer = new byte[recordLength]; Buffer.BlockCopy(bufferStream.GetBuffer(), 0, recordBuffer, 0, recordLength); } } else { bufferStream.SetLength(4); bufferStream.Position = 4; record.WriteTo(GlobalDataPosition, bufferWriter); var recordLength = (int)bufferStream.Length - 4; bufferWriter.Write(recordLength); // write record length suffix bufferStream.Position = 0; bufferWriter.Write(recordLength); // write record length prefix if (recordLength > _chunkConfig.MaxLogRecordSize) { throw new ChunkWriteException(this.ToString(), string.Format("Log record at data position {0} has too large length: {1} bytes, while limit is {2} bytes", _dataPosition, recordLength, _chunkConfig.MaxLogRecordSize)); } if (writerWorkItem.WorkingStream.Position + recordLength + 2 * sizeof(int) > ChunkHeader.Size + _chunkHeader.ChunkDataTotalSize) { return(RecordWriteResult.NotEnoughSpace()); } if (_cacheItems != null) { recordBuffer = new byte[recordLength]; Buffer.BlockCopy(bufferStream.GetBuffer(), 4, recordBuffer, 0, recordLength); } } var writtenPosition = _dataPosition; var buffer = bufferStream.GetBuffer(); lock (_writeSyncObj) { writerWorkItem.AppendData(buffer, 0, (int)bufferStream.Length); } _dataPosition = (int)writerWorkItem.WorkingStream.Position - ChunkHeader.Size; var position = ChunkHeader.ChunkDataStartPosition + writtenPosition; if (_chunkConfig.EnableCache) { if (_memoryChunk != null) { var result = _memoryChunk.TryAppend(record); if (!result.Success) { throw new ChunkWriteException(this.ToString(), "Append record to file chunk success, but append to memory chunk failed as memory space not enough, this should not be happened."); } else if (result.Position != position) { throw new ChunkWriteException(this.ToString(), string.Format("Append record to file chunk success, and append to memory chunk success, but the position is not equal, memory chunk write position: {0}, file chunk write position: {1}.", result.Position, position)); } } else if (_cacheItems != null && recordBuffer != null) { var index = writtenPosition % _chunkConfig.ChunkLocalCacheSize; _cacheItems[index] = new CacheItem { RecordPosition = writtenPosition, RecordBuffer = recordBuffer }; } } else if (_cacheItems != null && recordBuffer != null) { var index = writtenPosition % _chunkConfig.ChunkLocalCacheSize; _cacheItems[index] = new CacheItem { RecordPosition = writtenPosition, RecordBuffer = recordBuffer }; } if (!_isMemoryChunk && _chunkConfig.EnableChunkWriteStatistic) { _chunkStatisticService.AddWriteBytes(ChunkHeader.ChunkNumber, (int)bufferStream.Length); } return(RecordWriteResult.Successful(position)); }