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);
     }
 }
示例#2
0
        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));
        }
示例#3
0
        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));
        }