Buffer(uint blockMetadataSize, uint maxBlockSize, long streamLocation, long opNumber, Guid StreamId) { this._AllocationReportedToGC = maxBlockSize + (uint)KLogicalLogInformation.FixedMetadataSize; AddGCMemoryPressure(this._AllocationReportedToGC); this._MetadataSize = blockMetadataSize; NativeLog.CreateSimpleKIoBuffer((uint)KLogicalLogInformation.FixedMetadataSize, out this._MetadataKIoBuffer); // // Allocate the write KIoBuffer to be the full block size requested by the caller despite the fact that some // data will live in the metadata portion. Consider the fact that when the block is completely full, there will be some // amount of data in the metadata and then the data portion will be full as well except for a gap at the end of the block // which is the size of the data in the metadata portion. When rounding up we will need this last block despite it not being // completely full. // NativeLog.CreateSimpleKIoBuffer((uint)(maxBlockSize), out this._PageAlignedKIoBuffer); NativeLog.CreateEmptyKIoBuffer(out this._CombinedKIoBuffer); this._CombinedKIoBuffer.AddIoBufferReference(this._MetadataKIoBuffer, 0, (uint)KLogicalLogInformation.FixedMetadataSize); this._CombinedKIoBuffer.AddIoBufferReference( this._PageAlignedKIoBuffer, 0, (uint)(maxBlockSize - KLogicalLogInformation.FixedMetadataSize)); this._CombinedBufferStream = new KIoBufferStream(this._CombinedKIoBuffer, (uint)blockMetadataSize); NativeLog.CreateEmptyKIoBuffer(out this._PageAlignedKIoBufferView); unsafe { KLogicalLogInformation.MetadataBlockHeader *mdHdr = null; mdHdr = (KLogicalLogInformation.MetadataBlockHeader *) this._CombinedBufferStream.GetBufferPointer(); this._MetadataBlockHeader = mdHdr; ReleaseAssert.AssertIfNot( this._CombinedBufferStream.Skip((uint)sizeof(KLogicalLogInformation.MetadataBlockHeader)), "Unexpected Skip failure"); this._StreamBlockHeader = (KLogicalLogInformation.StreamBlockHeader *) this._CombinedBufferStream.GetBufferPointer(); mdHdr->OffsetToStreamHeader = this._CombinedBufferStream.GetPosition(); // Position the stream at 1st byte of user record ReleaseAssert.AssertIfNot( this._CombinedBufferStream.Skip((uint)sizeof(KLogicalLogInformation.StreamBlockHeader)), "Unexpected Skip failure"); this._StreamBlockHeader->Signature = KLogicalLogInformation.StreamBlockHeader.Sig; this._StreamBlockHeader->StreamOffsetPlusOne = streamLocation + 1; this._StreamBlockHeader->HighestOperationId = opNumber; this._StreamBlockHeader->StreamId = StreamId; this._StreamBlockHeader->HeaderCRC64 = 0; this._StreamBlockHeader->DataCRC64 = 0; this._StreamBlockHeader->DataSize = 0; this._StreamBlockHeader->Reserved = 0; this._OffsetToData = mdHdr->OffsetToStreamHeader + (uint)sizeof(KLogicalLogInformation.StreamBlockHeader); } }
Buffer( uint blockMetadataSize, long startingStreamPosition, NativeLog.IKIoBuffer metadataBuffer, NativeLog.IKIoBuffer pageAlignedKIoBuffer, string traceType) { this._MetadataSize = blockMetadataSize; this._MetadataKIoBuffer = metadataBuffer; this._PageAlignedKIoBuffer = pageAlignedKIoBuffer; unsafe { this._StreamBlockHeader = null; } this._PageAlignedKIoBufferView = null; this._OffsetToData = uint.MaxValue; NativeLog.CreateEmptyKIoBuffer(out this._CombinedKIoBuffer); this.OpenForRead(startingStreamPosition, traceType); }
Dispose(bool IsDisposing) { if (IsDisposing) { GC.SuppressFinalize(this); if (this._MetadataKIoBuffer != null) { this._MetadataKIoBuffer.Clear(); } if (this._PageAlignedKIoBuffer != null) { this._PageAlignedKIoBuffer.Clear(); } if (this._PageAlignedKIoBufferView != null) { this._PageAlignedKIoBufferView.Clear(); } if (this._CombinedKIoBuffer != null) { this._CombinedKIoBuffer.Clear(); } this._CombinedBufferStream.Reset(); unsafe { this._StreamBlockHeader = null; this._MetadataBlockHeader = null; } } if (this._AllocationReportedToGC > 0) { RemoveGCMemoryPressure(this._AllocationReportedToGC); this._AllocationReportedToGC = 0; } }
OpenForRead(long streamPosition, string traceType) { // Combine the metadata and page-align IoBuffers uint mdBufferSize; uint paBufferSize; this._MetadataKIoBuffer.QuerySize(out mdBufferSize); this._PageAlignedKIoBuffer.QuerySize(out paBufferSize); this._AllocationReportedToGC = mdBufferSize + paBufferSize; AddGCMemoryPressure(this._AllocationReportedToGC); this._CombinedKIoBuffer.Clear(); this._CombinedKIoBuffer.AddIoBufferReference(this._MetadataKIoBuffer, 0, mdBufferSize); this._CombinedKIoBuffer.AddIoBufferReference(this._PageAlignedKIoBuffer, 0, paBufferSize); this._CombinedBufferStream.Reuse(this._CombinedKIoBuffer, this._MetadataSize); // Parse the log stream physical record unsafe { KLogicalLogInformation.MetadataBlockHeader *mdHdr = null; mdHdr = (KLogicalLogInformation.MetadataBlockHeader *) this._CombinedBufferStream.GetBufferPointer(); ReleaseAssert.AssertIfNot( this._CombinedBufferStream.PositionTo(mdHdr->OffsetToStreamHeader), "Unexpected PositionTo failure"); this._StreamBlockHeader = (KLogicalLogInformation.StreamBlockHeader *) this._CombinedBufferStream.GetBufferPointer(); // Position the stream at 1st byte of user record ReleaseAssert.AssertIfNot( this._CombinedBufferStream.Skip((uint)sizeof(KLogicalLogInformation.StreamBlockHeader)), "Unexpected Skip failure"); this._OffsetToData = mdHdr->OffsetToStreamHeader + (uint)sizeof(KLogicalLogInformation.StreamBlockHeader); #if false // TODO: Start: DebugOnly UInt64 savedCrc = _StreamBlockHeader->HeaderCRC64; _StreamBlockHeader->HeaderCRC64 = 0; if (NativeLog.KCrc64(_StreamBlockHeader, (uint)sizeof(KLogicalLogInformation.StreamBlockHeader), 0) != savedCrc) { throw new InvalidDataException(); } _StreamBlockHeader->HeaderCRC64 = 0; // NOTE: Leave HeaderCRC64 0 - this is the unsealed condition if ((_OffsetToData + _StreamBlockHeader->DataSize) > mdBufferSize) { savedCrc = 0; KIoBufferStream.InterationCallback LocalHashFunc = (( byte *ioBufferFragment, ref UInt32 fragmentSize) => { savedCrc = NativeLog.KCrc64(ioBufferFragment, fragmentSize, savedCrc); return(0); }); ReleaseAssert.AssertIfNot( _CombinedBufferStream.Iterate(LocalHashFunc, _StreamBlockHeader->DataSize) == 0, "Unexpected Iterate failure"); if (_StreamBlockHeader->DataCRC64 != savedCrc) { throw new InvalidDataException(); } } // TODO: END: DebugOnly #endif // Compute position and limits of the KIoBufferStream System.Diagnostics.Debug.Assert(this._StreamBlockHeader->StreamOffsetPlusOne > 0); var recordOffsetToDesiredPosition = streamPosition - (this._StreamBlockHeader->StreamOffsetPlusOne - 1); if ((recordOffsetToDesiredPosition < 0) || (recordOffsetToDesiredPosition >= this._StreamBlockHeader->DataSize)) { var s = string.Format( CultureInfo.InvariantCulture, "OpenForRead: streamPosition {0}, StreamOffsetPlusOne {1}, DataSize {2}, recordOffsetToDesiredPosition {3}, HeadTruncationPoint {4}, HighestOperationId {5} ", streamPosition, this._StreamBlockHeader->StreamOffsetPlusOne, this._StreamBlockHeader->DataSize, recordOffsetToDesiredPosition, this._StreamBlockHeader->HeadTruncationPoint, this._StreamBlockHeader->HighestOperationId); AppTrace.TraceSource.WriteInfo( traceType, s ); } System.Diagnostics.Debug.Assert(recordOffsetToDesiredPosition <= uint.MaxValue); this._CombinedBufferStream.Reuse( this._CombinedKIoBuffer, (uint)recordOffsetToDesiredPosition + this._OffsetToData, this._OffsetToData + this._StreamBlockHeader->DataSize); } }