public int AppendFragmentedMessage(HeaderWriter header, IDirectBuffer srcBuffer, int srcOffset, int length, int maxPayloadLength, ReservedValueSupplier reservedValueSupplier, int activeTermId) { int numMaxPayloads = length / maxPayloadLength; int remainingPayload = length % maxPayloadLength; int lastFrameLength = remainingPayload > 0 ? BitUtil.Align(remainingPayload + DataHeaderFlyweight.HEADER_LENGTH, FrameDescriptor.FRAME_ALIGNMENT) : 0; int requiredLength = (numMaxPayloads * (maxPayloadLength + DataHeaderFlyweight.HEADER_LENGTH)) + lastFrameLength; long rawTail = GetAndAddRawTail(requiredLength); int termId = LogBufferDescriptor.TermId(rawTail); long termOffset = rawTail & 0xFFFFFFFFL; UnsafeBuffer termBuffer = _termBuffer; int termLength = termBuffer.Capacity; CheckTerm(activeTermId, termId); long resultingOffset = termOffset + requiredLength; if (resultingOffset > termLength) { resultingOffset = HandleEndOfLogCondition(termBuffer, termOffset, header, termLength, termId); } else { int frameOffset = (int)termOffset; byte flags = FrameDescriptor.BEGIN_FRAG_FLAG; int remaining = length; do { int bytesToWrite = Math.Min(remaining, maxPayloadLength); int frameLength = bytesToWrite + DataHeaderFlyweight.HEADER_LENGTH; int alignedLength = BitUtil.Align(frameLength, FrameDescriptor.FRAME_ALIGNMENT); header.Write(termBuffer, frameOffset, frameLength, termId); termBuffer.PutBytes(frameOffset + DataHeaderFlyweight.HEADER_LENGTH, srcBuffer, srcOffset + (length - remaining), bytesToWrite); if (remaining <= maxPayloadLength) { flags |= FrameDescriptor.END_FRAG_FLAG; } FrameDescriptor.FrameFlags(termBuffer, frameOffset, flags); if (null != reservedValueSupplier) { long reservedValue = reservedValueSupplier(termBuffer, frameOffset, frameLength); termBuffer.PutLong(frameOffset + DataHeaderFlyweight.RESERVED_VALUE_OFFSET, reservedValue, ByteOrder.LittleEndian); } FrameDescriptor.FrameLengthOrdered(termBuffer, frameOffset, frameLength); flags = 0; frameOffset += alignedLength; remaining -= bytesToWrite; } while (remaining > 0); } return((int)resultingOffset); }
public long AppendUnfragmentedMessage(HeaderWriter header, UnsafeBuffer srcBuffer, int srcOffset, int length, ReservedValueSupplier reservedValueSupplier) #endif { int frameLength = length + DataHeaderFlyweight.HEADER_LENGTH; int alignedLength = BitUtil.Align(frameLength, FrameDescriptor.FRAME_ALIGNMENT); long rawTail = GetAndAddRawTail(alignedLength); long termOffset = rawTail & 0xFFFFFFFFL; UnsafeBuffer termBuffer = _termBuffer; int termLength = termBuffer.Capacity; long resultingOffset = termOffset + alignedLength; if (resultingOffset > termLength) { resultingOffset = HandleEndOfLogCondition(termBuffer, termOffset, header, termLength, LogBufferDescriptor.TermId(rawTail)); } else { int offset = (int)termOffset; header.Write(termBuffer, offset, frameLength, LogBufferDescriptor.TermId(rawTail)); termBuffer.PutBytes(offset + DataHeaderFlyweight.HEADER_LENGTH, srcBuffer, srcOffset, length); if (null != reservedValueSupplier) { long reservedValue = reservedValueSupplier(termBuffer, offset, frameLength); termBuffer.PutLong(offset + DataHeaderFlyweight.RESERVED_VALUE_OFFSET, reservedValue); } FrameDescriptor.FrameLengthOrdered(termBuffer, offset, frameLength); } return(resultingOffset); }
/// <summary> /// Scan a term buffer for a block of message fragments from and offset up to a limitOffset. /// /// A scan will terminate if a padding frame is encountered. If first frame in a scan is padding then a block /// for the padding is notified. If the padding comes after the first frame in a scan then the scan terminates /// at the offset the padding frame begins. Padding frames are delivered singularly in a block. /// /// Padding frames may be for a greater range than the limit offset but only the header needs to be valid so /// relevant length of the frame is <see cref="DataHeaderFlyweight.HEADER_LENGTH"/> /// </summary> /// <param name="termBuffer"> to scan for message fragments. </param> /// <param name="termOffset"> at which the scan should begin. </param> /// <param name="limitOffset"> at which the scan should stop. </param> /// <returns> the offset at which the scan terminated. </returns> public static int Scan(IAtomicBuffer termBuffer, int termOffset, int limitOffset) { var offset = termOffset; while (offset < limitOffset) { int frameLength = FrameDescriptor.FrameLengthVolatile(termBuffer, offset); if (frameLength <= 0) { break; } int alignedFrameLength = BitUtil.Align(frameLength, FrameDescriptor.FRAME_ALIGNMENT); if (FrameDescriptor.IsPaddingFrame(termBuffer, offset)) { if (termOffset == offset) { offset += alignedFrameLength; } break; } if (offset + alignedFrameLength > limitOffset) { break; } offset += alignedFrameLength; } return(offset); }
public static long Read(UnsafeBuffer termBuffer, int offset, FragmentHandler handler, int fragmentsLimit, Header header, ErrorHandler errorHandler) { int fragmentsRead = 0; int capacity = termBuffer.Capacity; try { do { int frameLength = FrameDescriptor.FrameLengthVolatile(termBuffer, offset); if (frameLength <= 0) { break; } int termOffset = offset; offset += BitUtil.Align(frameLength, FrameDescriptor.FRAME_ALIGNMENT); if (!FrameDescriptor.IsPaddingFrame(termBuffer, termOffset)) { header.SetBuffer(termBuffer, termOffset); handler(termBuffer, termOffset + DataHeaderFlyweight.HEADER_LENGTH, frameLength - DataHeaderFlyweight.HEADER_LENGTH, header); ++fragmentsRead; } } while (fragmentsRead < fragmentsLimit && offset < capacity); } catch (Exception t) { errorHandler(t); } return(Pack(offset, fragmentsRead)); }
/// <summary> /// Pad a length of the term buffer with a padding record. /// </summary> /// <param name="termId"> for the current term.</param> /// <param name="termOffset"> in the term at which to append.</param> /// <param name="header"> for writing the default header.</param> /// <param name="length"> of the padding to be written.</param> /// <returns> the resulting offset of the term after success otherwise <see cref="FAILED"/>.</returns> public int AppendPadding( int termId, int termOffset, HeaderWriter header, int length) { int frameLength = length + DataHeaderFlyweight.HEADER_LENGTH; int alignedLength = BitUtil.Align(frameLength, FrameDescriptor.FRAME_ALIGNMENT); UnsafeBuffer termBuffer = _termBuffer; int termLength = termBuffer.Capacity; int resultingOffset = termOffset + alignedLength; PutRawTailOrdered(termId, resultingOffset); if (resultingOffset > termLength) { resultingOffset = HandleEndOfLogCondition(termBuffer, termOffset, header, termLength, termId); } else { header.Write(termBuffer, termOffset, frameLength, termId); FrameDescriptor.FrameType(termBuffer, termOffset, FrameDescriptor.PADDING_FRAME_TYPE); FrameDescriptor.FrameLengthOrdered(termBuffer, termOffset, frameLength); } return(resultingOffset); }
/// <summary> /// Append an unfragmented message to the the term buffer. /// </summary> /// <param name="header"> for writing the default header. </param> /// <param name="srcBuffer"> containing the message. </param> /// <param name="srcOffset"> at which the message begins. </param> /// <param name="length"> of the message in the source buffer. </param> /// <returns> the resulting offset of the term after the append on success otherwise <seealso cref="#TRIPPED"/> or <seealso cref="#FAILED"/> /// packed with the termId if a padding record was inserted at the end. </returns> public virtual long AppendUnfragmentedMessage(HeaderWriter header, IDirectBuffer srcBuffer, int srcOffset, int length) { int frameLength = length + DataHeaderFlyweight.HEADER_LENGTH; int alignedLength = BitUtil.Align(frameLength, FrameDescriptor.FRAME_ALIGNMENT); long rawTail = GetAndAddRawTail(alignedLength); long termOffset = rawTail & 0xFFFFFFFFL; IAtomicBuffer termBuffer = _termBuffer; int termLength = termBuffer.Capacity; long resultingOffset = termOffset + alignedLength; if (resultingOffset > termLength) { resultingOffset = HandleEndOfLogCondition(termBuffer, termOffset, header, termLength, TermId(rawTail)); } else { int offset = (int)termOffset; header.Write(termBuffer, offset, frameLength, TermId(rawTail)); termBuffer.PutBytes(offset + DataHeaderFlyweight.HEADER_LENGTH, srcBuffer, srcOffset, length); FrameDescriptor.FrameLengthOrdered(termBuffer, offset, frameLength); } return(resultingOffset); }
/// <summary> /// Scan a term buffer for a block of message fragments from and offset up to a limit. /// </summary> /// <param name="termBuffer"> to scan for message fragments. </param> /// <param name="termOffset"> at which the scan should begin. </param> /// <param name="limit"> at which the scan should stop. </param> /// <returns> the offset at which the scan terminated. </returns> public static int Scan(IAtomicBuffer termBuffer, int termOffset, int limit) { var offset = termOffset; do { int frameLength = FrameDescriptor.FrameLengthVolatile(termBuffer, offset); if (frameLength <= 0) { break; } int alignedFrameLength = BitUtil.Align(frameLength, FrameDescriptor.FRAME_ALIGNMENT); offset += alignedFrameLength; if (offset >= limit) { if (offset > limit) { offset -= alignedFrameLength; } break; } } while (true); return(offset); }
/// <summary> /// Insert a packet of frames into the log at the appropriate offset as indicated by the term offset header. /// </summary> /// <param name="termBuffer"> into which the packet should be inserted. </param> /// <param name="offset"> offset in the term at which the packet should be inserted. </param> /// <param name="packet"> containing a sequence of frames. </param> /// <param name="length"> of the sequence of frames in bytes. </param> public static void Insert(IAtomicBuffer termBuffer, int offset, UnsafeBuffer packet, int length) { var firstFrameLength = packet.GetInt(0); // LITTLE_ENDIAN packet.PutIntOrdered(0, 0); termBuffer.PutBytes(offset, packet, 0, length); FrameDescriptor.FrameLengthOrdered(termBuffer, offset, firstFrameLength); }
/// <summary> /// Insert a packet of frames into the log at the appropriate offset as indicated by the term termOffset header. /// </summary> /// <param name="termBuffer"> into which the packet should be inserted. </param> /// <param name="termOffset"> offset in the term at which the packet should be inserted. </param> /// <param name="packet"> containing a sequence of frames. </param> /// <param name="length"> of the sequence of frames in bytes. </param> public static void Insert(IAtomicBuffer termBuffer, int termOffset, UnsafeBuffer packet, int length) { var firstFrameLength = packet.GetInt(0); // LITTLE_ENDIAN packet.PutIntOrdered(0, 0); Thread.MemoryBarrier(); // UnsafeAccess.UNSAFE.storeFence(); termBuffer.PutBytes(termOffset, packet, 0, length); FrameDescriptor.FrameLengthOrdered(termBuffer, termOffset, firstFrameLength); }
/// <summary> /// Append a fragmented message to the the term buffer. /// The message will be split up into fragments of MTU length minus header. /// </summary> /// <param name="header"> for writing the default header. </param> /// <param name="srcBuffer"> containing the message. </param> /// <param name="srcOffset"> at which the message begins. </param> /// <param name="length"> of the message in the source buffer. </param> /// <param name="maxPayloadLength"> that the message will be fragmented into. </param> /// <returns> the resulting offset of the term after the append on success otherwise <seealso cref="#TRIPPED"/> or <seealso cref="#FAILED"/> /// packed with the termId if a padding record was inserted at the end. </returns> public long AppendFragmentedMessage(HeaderWriter header, IDirectBuffer srcBuffer, int srcOffset, int length, int maxPayloadLength) { int numMaxPayloads = length / maxPayloadLength; int remainingPayload = length % maxPayloadLength; int lastFrameLength = remainingPayload > 0 ? BitUtil.Align(remainingPayload + DataHeaderFlyweight.HEADER_LENGTH, FrameDescriptor.FRAME_ALIGNMENT) : 0; int requiredLength = (numMaxPayloads * (maxPayloadLength + DataHeaderFlyweight.HEADER_LENGTH)) + lastFrameLength; long rawTail = GetAndAddRawTail(requiredLength); int termId = TermId(rawTail); long termOffset = rawTail & 0xFFFFFFFFL; IAtomicBuffer termBuffer = _termBuffer; int termLength = termBuffer.Capacity; long resultingOffset = termOffset + requiredLength; if (resultingOffset > termLength) { resultingOffset = HandleEndOfLogCondition(termBuffer, termOffset, header, termLength, termId); } else { int offset = (int)termOffset; byte flags = FrameDescriptor.BEGIN_FRAG_FLAG; int remaining = length; do { int bytesToWrite = Math.Min(remaining, maxPayloadLength); int frameLength = bytesToWrite + DataHeaderFlyweight.HEADER_LENGTH; int alignedLength = BitUtil.Align(frameLength, FrameDescriptor.FRAME_ALIGNMENT); header.Write(termBuffer, offset, frameLength, termId); termBuffer.PutBytes(offset + DataHeaderFlyweight.HEADER_LENGTH, srcBuffer, srcOffset + (length - remaining), bytesToWrite); if (remaining <= maxPayloadLength) { flags |= FrameDescriptor.END_FRAG_FLAG; } FrameDescriptor.FrameFlags(termBuffer, offset, flags); FrameDescriptor.FrameLengthOrdered(termBuffer, offset, frameLength); flags = 0; offset += alignedLength; remaining -= bytesToWrite; } while (remaining > 0); } return(resultingOffset); }
public static int Read( UnsafeBuffer termBuffer, int termOffset, IFragmentHandler handler, int fragmentsLimit, Header header, ErrorHandler errorHandler, long currentPosition, IPosition subscriberPosition) { int fragmentsRead = 0; int offset = termOffset; int capacity = termBuffer.Capacity; header.Buffer = termBuffer; try { while (fragmentsRead < fragmentsLimit && offset < capacity) { int frameLength = FrameDescriptor.FrameLengthVolatile(termBuffer, offset); if (frameLength <= 0) { break; } int frameOffset = offset; offset += BitUtil.Align(frameLength, FrameDescriptor.FRAME_ALIGNMENT); if (!FrameDescriptor.IsPaddingFrame(termBuffer, frameOffset)) { header.Offset = frameOffset; handler.OnFragment(termBuffer, frameOffset + DataHeaderFlyweight.HEADER_LENGTH, frameLength - DataHeaderFlyweight.HEADER_LENGTH, header); ++fragmentsRead; } } } catch (Exception t) { errorHandler(t); } finally { long newPosition = currentPosition + (offset - termOffset); if (newPosition > currentPosition) { subscriberPosition.SetOrdered(newPosition); } } return(fragmentsRead); }
/// <summary> /// Append pre-formatted block of message fragments into the term buffer. /// <para> /// <em>WARNING: This is internal API used by {@code ExclusivePublication#offerBlock} method.</em> /// </para> /// </summary> /// <param name="termId"> for the current term. </param> /// <param name="termOffset"> in the term at which to append. </param> /// <param name="buffer"> which contains block of messages. </param> /// <param name="offset"> within the buffer at which the block begins. </param> /// <param name="length"> of the block in bytes (always aligned). </param> /// <returns> the resulting offset of the term after success otherwise <seealso cref="FAILED"/>. </returns> public int AppendBlock(int termId, int termOffset, IMutableDirectBuffer buffer, int offset, int length) { int resultingOffset = termOffset + length; int lengthOfFirstFrame = buffer.GetInt(offset, ByteOrder.LittleEndian); buffer.PutInt(offset, 0, ByteOrder.LittleEndian); _termBuffer.PutBytes(termOffset, buffer, offset, length); FrameDescriptor.FrameLengthOrdered(_termBuffer, termOffset, lengthOfFirstFrame); PutRawTailOrdered(termId, resultingOffset); return(resultingOffset); }
private long HandleEndOfLogCondition(UnsafeBuffer termBuffer, long termOffset, HeaderWriter header, int termLength, int termId) { if (termOffset < termLength) { int offset = (int)termOffset; int paddingLength = termLength - offset; header.Write(termBuffer, offset, paddingLength, termId); FrameDescriptor.FrameType(termBuffer, offset, FrameDescriptor.PADDING_FRAME_TYPE); FrameDescriptor.FrameLengthOrdered(termBuffer, offset, paddingLength); } return(FAILED); }
public int AppendUnfragmentedMessage( HeaderWriter header, DirectBufferVector[] vectors, int length, ReservedValueSupplier reservedValueSupplier, int activeTermId) { int frameLength = length + DataHeaderFlyweight.HEADER_LENGTH; int alignedLength = BitUtil.Align(frameLength, FrameDescriptor.FRAME_ALIGNMENT); UnsafeBuffer termBuffer = _termBuffer; int termLength = termBuffer.Capacity; long rawTail = GetAndAddRawTail(alignedLength); int termId = LogBufferDescriptor.TermId(rawTail); long termOffset = rawTail & 0xFFFFFFFFL; CheckTerm(activeTermId, termId); long resultingOffset = termOffset + alignedLength; if (resultingOffset > termLength) { resultingOffset = HandleEndOfLogCondition(termBuffer, termOffset, header, termLength, termId); } else { int frameOffset = (int)termOffset; header.Write(termBuffer, frameOffset, frameLength, LogBufferDescriptor.TermId(rawTail)); int offset = frameOffset + DataHeaderFlyweight.HEADER_LENGTH; foreach (var vector in vectors) { termBuffer.PutBytes(offset, vector.buffer, vector.offset, vector.length); offset += vector.length; } if (null != reservedValueSupplier) { long reservedValue = reservedValueSupplier(termBuffer, frameOffset, frameLength); termBuffer.PutLong(frameOffset + DataHeaderFlyweight.RESERVED_VALUE_OFFSET, reservedValue, ByteOrder.LittleEndian); } FrameDescriptor.FrameLengthOrdered(termBuffer, frameOffset, frameLength); } return((int)resultingOffset); }
public int AppendUnfragmentedMessage( int termId, int termOffset, HeaderWriter header, DirectBufferVector[] vectors, int length, ReservedValueSupplier reservedValueSupplier) #endif { int frameLength = length + DataHeaderFlyweight.HEADER_LENGTH; int alignedLength = BitUtil.Align(frameLength, FrameDescriptor.FRAME_ALIGNMENT); UnsafeBuffer termBuffer = _termBuffer; int termLength = termBuffer.Capacity; int resultingOffset = termOffset + alignedLength; PutRawTailOrdered(termId, resultingOffset); if (resultingOffset > termLength) { resultingOffset = HandleEndOfLogCondition(termBuffer, termOffset, header, termLength, termId); } else { header.Write(termBuffer, termOffset, frameLength, termId); var offset = termOffset + DataHeaderFlyweight.HEADER_LENGTH; foreach (var vector in vectors) { termBuffer.PutBytes(offset, vector.buffer, vector.offset, vector.length); offset += vector.length; } if (null != reservedValueSupplier) { long reservedValue = reservedValueSupplier(termBuffer, termOffset, frameLength); termBuffer.PutLong(termOffset + DataHeaderFlyweight.RESERVED_VALUE_OFFSET, reservedValue, ByteOrder.LittleEndian); } FrameDescriptor.FrameLengthOrdered(termBuffer, termOffset, frameLength); } return(resultingOffset); }
/// <summary> /// Append an unfragmented message to the the term buffer. /// </summary> /// <param name="termId"> for the current term. </param> /// <param name="termOffset"> in the term at which to append. </param> /// <param name="header"> for writing the default header. </param> /// <param name="bufferOne"> containing the first part of the message. </param> /// <param name="offsetOne"> at which the first part of the message begins. </param> /// <param name="lengthOne"> of the first part of the message. </param> /// <param name="bufferTwo"> containing the second part of the message. </param> /// <param name="offsetTwo"> at which the second part of the message begins. </param> /// <param name="lengthTwo"> of the second part of the message. </param> /// <param name="reservedValueSupplier"> <seealso cref="ReservedValueSupplier"/> for the frame. </param> /// <returns> the resulting offset of the term after the append on success otherwise <seealso cref="FAILED"/>. </returns> public int AppendUnfragmentedMessage( int termId, int termOffset, HeaderWriter header, IDirectBuffer bufferOne, int offsetOne, int lengthOne, IDirectBuffer bufferTwo, int offsetTwo, int lengthTwo, ReservedValueSupplier reservedValueSupplier) { int frameLength = lengthOne + lengthTwo + DataHeaderFlyweight.HEADER_LENGTH; int alignedLength = BitUtil.Align(frameLength, FrameDescriptor.FRAME_ALIGNMENT); UnsafeBuffer termBuffer = _termBuffer; int termLength = termBuffer.Capacity; int resultingOffset = termOffset + alignedLength; PutRawTailOrdered(termId, resultingOffset); if (resultingOffset > termLength) { resultingOffset = HandleEndOfLogCondition(termBuffer, termOffset, header, termLength, termId); } else { header.Write(termBuffer, termOffset, frameLength, termId); termBuffer.PutBytes(termOffset + DataHeaderFlyweight.HEADER_LENGTH, bufferOne, offsetOne, lengthOne); termBuffer.PutBytes(termOffset + DataHeaderFlyweight.HEADER_LENGTH + lengthOne, bufferTwo, offsetTwo, lengthTwo); if (null != reservedValueSupplier) { long reservedValue = reservedValueSupplier(termBuffer, termOffset, frameLength); termBuffer.PutLong(termOffset + DataHeaderFlyweight.RESERVED_VALUE_OFFSET, reservedValue, ByteOrder.LittleEndian); } FrameDescriptor.FrameLengthOrdered(termBuffer, termOffset, frameLength); } return(resultingOffset); }
private long HandleEndOfLogCondition(UnsafeBuffer termBuffer, long termOffset, HeaderWriter header, int termLength, int termId) { int resultingOffset = FAILED; if (termOffset <= termLength) { resultingOffset = TRIPPED; if (termOffset < termLength) { int offset = (int)termOffset; int paddingLength = termLength - offset; header.Write(termBuffer, offset, paddingLength, termId); FrameDescriptor.FrameType(termBuffer, offset, FrameDescriptor.PADDING_FRAME_TYPE); FrameDescriptor.FrameLengthOrdered(termBuffer, offset, paddingLength); } } return(LogBufferDescriptor.PackTail(termId, resultingOffset)); }
/// <summary> /// Try to gap fill the current term at a given offset if the gap contains no data. /// /// Note: the gap offset plus gap length must end on a <seealso cref="FrameDescriptor.FRAME_ALIGNMENT"/> boundary. /// </summary> /// <param name="logMetaDataBuffer"> containing the default headers </param> /// <param name="termBuffer"> to gap fill </param> /// <param name="termId"> for the current term. </param> /// <param name="gapOffset"> to fill from </param> /// <param name="gapLength"> to length of the gap. </param> /// <returns> true if the gap has been filled with a padding record or false if data found. </returns> public static bool TryFillGap(UnsafeBuffer logMetaDataBuffer, UnsafeBuffer termBuffer, int termId, int gapOffset, int gapLength) { int offset = gapOffset + gapLength - FrameDescriptor.FRAME_ALIGNMENT; while (offset >= gapOffset) { if (0 != termBuffer.GetInt(offset)) { return(false); } offset -= FrameDescriptor.FRAME_ALIGNMENT; } LogBufferDescriptor.ApplyDefaultHeader(logMetaDataBuffer, termBuffer, gapOffset); FrameDescriptor.FrameType(termBuffer, gapOffset, HeaderFlyweight.HDR_TYPE_PAD); FrameDescriptor.FrameTermOffset(termBuffer, gapOffset); FrameDescriptor.FrameTermId(termBuffer, gapOffset, termId); FrameDescriptor.FrameLengthOrdered(termBuffer, gapOffset, gapLength); return(true); }
public int AppendFragmentedMessage( int termId, int termOffset, HeaderWriter header, DirectBufferVector[] vectors, int length, int maxPayloadLength, ReservedValueSupplier reservedValueSupplier) { int numMaxPayloads = length / maxPayloadLength; int remainingPayload = length % maxPayloadLength; int lastFrameLength = remainingPayload > 0 ? BitUtil.Align(remainingPayload + DataHeaderFlyweight.HEADER_LENGTH, FrameDescriptor.FRAME_ALIGNMENT) : 0; int requiredLength = (numMaxPayloads * (maxPayloadLength + DataHeaderFlyweight.HEADER_LENGTH)) + lastFrameLength; UnsafeBuffer termBuffer = _termBuffer; int termLength = termBuffer.Capacity; int resultingOffset = termOffset + requiredLength; PutRawTailOrdered(termId, resultingOffset); if (resultingOffset > termLength) { resultingOffset = HandleEndOfLogCondition(termBuffer, termOffset, header, termLength, termId); } else { int frameOffset = termOffset; byte flags = FrameDescriptor.BEGIN_FRAG_FLAG; int remaining = length; int vectorIndex = 0; int vectorOffset = 0; do { int bytesToWrite = Math.Min(remaining, maxPayloadLength); int frameLength = bytesToWrite + DataHeaderFlyweight.HEADER_LENGTH; int alignedLength = BitUtil.Align(frameLength, FrameDescriptor.FRAME_ALIGNMENT); header.Write(termBuffer, frameOffset, frameLength, termId); int bytesWritten = 0; int payloadOffset = frameOffset + DataHeaderFlyweight.HEADER_LENGTH; do { var vector = vectors[vectorIndex]; int vectorRemaining = vector.length - vectorOffset; int numBytes = Math.Min(bytesToWrite - bytesWritten, vectorRemaining); termBuffer.PutBytes(payloadOffset, vector.buffer, vector.offset + vectorOffset, numBytes); bytesWritten += numBytes; payloadOffset += numBytes; vectorOffset += numBytes; if (vectorRemaining <= numBytes) { vectorIndex++; vectorOffset = 0; } } while (bytesWritten < bytesToWrite); if (remaining <= maxPayloadLength) { flags |= FrameDescriptor.END_FRAG_FLAG; } FrameDescriptor.FrameFlags(termBuffer, frameOffset, flags); if (null != reservedValueSupplier) { long reservedValue = reservedValueSupplier(termBuffer, frameOffset, frameLength); termBuffer.PutLong(frameOffset + DataHeaderFlyweight.RESERVED_VALUE_OFFSET, reservedValue, ByteOrder.LittleEndian); } FrameDescriptor.FrameLengthOrdered(termBuffer, frameOffset, frameLength); flags = 0; frameOffset += alignedLength; remaining -= bytesToWrite; } while (remaining > 0); } return(resultingOffset); }