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); } }
SealForWrite( long currentHeadTruncationPoint, bool IsBarrier, out NativeLog.IKIoBuffer metadataBuffer, out uint metadataSize, out NativeLog.IKIoBuffer pageAlignedBuffer, out long userSizeOfStreamData, out long AsnOfRecord, out long OpOfRecord) { unsafe { uint trimSize = 0; uint dataResidingOutsideMetadata = 0; UInt64 dataCrc = 0; this._MetadataBlockHeader->Flags = IsBarrier ? (uint)KLogicalLogInformation.MetadatBlockHeaderFlags.IsEndOfLogicalRecord : 0; this._StreamBlockHeader->DataSize = this._CombinedBufferStream.GetPosition() - this._OffsetToData; this._StreamBlockHeader->HeadTruncationPoint = currentHeadTruncationPoint; this._PageAlignedKIoBufferView.Clear(); // Compute CRC64 for record data if ((this._OffsetToData < KLogicalLogInformation.FixedMetadataSize) && ((this._OffsetToData + this._StreamBlockHeader->DataSize) <= KLogicalLogInformation.FixedMetadataSize)) { // no data outside the metadata buffer metadataSize = this._OffsetToData + this._StreamBlockHeader->DataSize; } else { // // Compute how much of the metadata is being used. It should be the entire 4K block minus the // space reserved by the physical logger // metadataSize = (uint)KLogicalLogInformation.FixedMetadataSize - this._MetadataSize; ReleaseAssert.AssertIfNot(this._CombinedBufferStream.PositionTo(this._OffsetToData), "Unexpected PositionTo failure"); KIoBufferStream.InterationCallback LocalHashFunc = (( byte *ioBufferFragment, ref UInt32 fragmentSize) => { dataCrc = NativeLog.KCrc64(ioBufferFragment, fragmentSize, dataCrc); return(0); }); ReleaseAssert.AssertIfNot( this._CombinedBufferStream.Iterate(LocalHashFunc, this._StreamBlockHeader->DataSize) == 0, "Unexpected Iterate failure"); // // Compute the number of data blocks that are needed to hold the data that is within the payload // data buffer. This excludes the payload data in the metadata portion // ReleaseAssert.AssertIf(this._OffsetToData > MetadataBlockSize, "Unexpected size for _OffsetToData"); dataResidingOutsideMetadata = this._StreamBlockHeader->DataSize - (MetadataBlockSize - this._OffsetToData); trimSize = ((((dataResidingOutsideMetadata) + (MetadataBlockSize - 1)) / MetadataBlockSize) * MetadataBlockSize); this._PageAlignedKIoBufferView.AddIoBufferReference( this._PageAlignedKIoBuffer, 0, (uint)trimSize); } this._StreamBlockHeader->DataCRC64 = dataCrc; // Now compute block header CRC this._StreamBlockHeader->HeaderCRC64 = NativeLog.KCrc64( this._StreamBlockHeader, (uint)sizeof(KLogicalLogInformation.StreamBlockHeader), 0); // Build results metadataBuffer = this._MetadataKIoBuffer; pageAlignedBuffer = this._PageAlignedKIoBufferView; userSizeOfStreamData = this._StreamBlockHeader->DataSize; AsnOfRecord = this._StreamBlockHeader->StreamOffsetPlusOne; OpOfRecord = this._StreamBlockHeader->HighestOperationId; } }