/// <summary> /// Scan a term buffer for a block of messages from and offset up to a limit. /// </summary> /// <param name="termBuffer"> to scan for messages. </param> /// <param name="offset"> 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(DirectBuffer termBuffer, int offset, int limit) { 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); }
private long HandleEndOfLogCondition( DirectBuffer 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(Pack(termId, resultingOffset)); }
public static long Read( DirectBuffer termBuffer, int offset, OnAppendHandler handler, int fragmentsLimit, ErrorHandler errorHandler) { int fragmentsRead = 0; int capacity = (int)termBuffer.Length; try { do { int frameLength = FrameDescriptor.FrameLengthVolatile(termBuffer, offset); if (frameLength <= 0) { break; } int termOffset = offset; offset += BitUtil.Align(frameLength, FrameDescriptor.FRAME_ALIGNMENT); // TODO check for padding if (!FrameDescriptor.IsPaddingFrame(termBuffer, termOffset)) { var messageBuffer = new DirectBuffer(frameLength, termBuffer.Data + termOffset); handler?.Invoke(messageBuffer); ++fragmentsRead; } }while (fragmentsRead < fragmentsLimit && offset < capacity); } catch (Exception t) { errorHandler?.Invoke(t); } return(Pack(offset, fragmentsRead)); }
/// <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(DirectBuffer termBuffer, int offset, DirectBuffer packet, int length) { int firstFrameLength = packet.ReadInt32(0); packet.VolatileWriteInt32(0, 0); termBuffer.WriteBytes(offset, packet, 0, length); FrameDescriptor.FrameLengthOrdered(termBuffer, offset, firstFrameLength); }
private static void ResetHeader( DirectBuffer logMetaDataBuffer, DirectBuffer termBuffer, int termOffset, int termId, int frameLength) { LogBufferDescriptor.ApplyDefaultHeader(logMetaDataBuffer, termBuffer, termOffset); FrameDescriptor.FrameType(termBuffer, termOffset, HeaderFlyweight.HDR_TYPE_PAD); FrameDescriptor.FrameTermOffset(termBuffer, termOffset); FrameDescriptor.FrameTermId(termBuffer, termOffset, termId); FrameDescriptor.FrameLengthOrdered(termBuffer, termOffset, frameLength); }
/// <summary> /// Attempt to unblock the current term at the current offset. /// /// <ol> /// <li>Current position length is > 0, then return</li> /// <li>Current position length is 0, scan forward by frame alignment until, one of the following: /// <ol> /// <li>reach a non-0 length, unblock up to indicated position (check original frame length for non-0)</li> /// <li>reach end of term and tail position >= end of term, unblock up to end of term (check original /// frame length for non-0) /// </li> /// <li>reach tail position < end of term, do NOT unblock</li> /// </ol> /// </li> /// </ol> /// </summary> /// <param name="logMetaDataBuffer"> containing the default headers </param> /// <param name="termBuffer"> to unblock </param> /// <param name="blockedOffset"> to unblock at </param> /// <param name="tailOffset"> to unblock up to </param> /// <param name="termId"> for the current term. </param> /// <returns> whether unblocking was done, not done, or applied to end of term </returns> public static TermUnblockerStatus Unblock( DirectBuffer logMetaDataBuffer, DirectBuffer termBuffer, int blockedOffset, int tailOffset, int termId) { var status = TermUnblockerStatus.NO_ACTION; int frameLength = FrameDescriptor.FrameLengthVolatile(termBuffer, blockedOffset); if (frameLength < 0) { ResetHeader(logMetaDataBuffer, termBuffer, blockedOffset, termId, -frameLength); status = TermUnblockerStatus.UNBLOCKED; } else if (0 == frameLength) { int currentOffset = blockedOffset + FrameDescriptor.FRAME_ALIGNMENT; while (currentOffset < tailOffset) { frameLength = FrameDescriptor.FrameLengthVolatile(termBuffer, currentOffset); if (frameLength != 0) { if (ScanBackToConfirmZeroed(termBuffer, currentOffset, blockedOffset)) { int length = currentOffset - blockedOffset; ResetHeader(logMetaDataBuffer, termBuffer, blockedOffset, termId, length); status = TermUnblockerStatus.UNBLOCKED; } break; } currentOffset += FrameDescriptor.FRAME_ALIGNMENT; } if (currentOffset == termBuffer.Length) { if (0 == FrameDescriptor.FrameLengthVolatile(termBuffer, blockedOffset)) { int length = currentOffset - blockedOffset; ResetHeader(logMetaDataBuffer, termBuffer, blockedOffset, termId, length); status = TermUnblockerStatus.UNBLOCKED_TO_END; } } } return(status); }
private static bool ScanBackToConfirmZeroed(DirectBuffer buffer, int from, int limit) { int i = from - FrameDescriptor.FRAME_ALIGNMENT; bool allZeros = true; while (i >= limit) { if (0 != FrameDescriptor.FrameLengthVolatile(buffer, i)) { allZeros = false; break; } i -= FrameDescriptor.FRAME_ALIGNMENT; } return(allZeros); }
/// <summary> /// Reads data from a term in a log buffer. /// /// If a fragmentsLimit of 0 or less is passed then at least one read will be attempted. /// </summary> /// <param name="termBuffer"> to be read for fragments. </param> /// <param name="offset"> offset within the buffer that the read should begin. </param> /// <param name="handler"> the handler for data that has been read </param> /// <param name="fragmentsLimit"> limit the number of fragments read. </param> /// <param name="header"> to be used for mapping over the header for a given fragment. </param> /// <param name="errorHandler"> to be notified if an error occurs during the callback. </param> /// <returns> the number of fragments read </returns> public static long Read( DirectBuffer termBuffer, int offset, FragmentHandler handler, int fragmentsLimit, Header header, ErrorHandler errorHandler) { int fragmentsRead = 0; int capacity = (int)termBuffer.Length; 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.Buffer = termBuffer; header.Offset = termOffset; handler?.Invoke(termBuffer, termOffset + DataHeaderFlyweight.HEADER_LENGTH, frameLength - DataHeaderFlyweight.HEADER_LENGTH, header); ++fragmentsRead; } }while (fragmentsRead < fragmentsLimit && offset < capacity); } catch (Exception t) { errorHandler?.Invoke(t); } return(Pack(offset, fragmentsRead)); }
/** * Scan the term buffer for availability of new messages from a given offset up to a maxLength of bytes. * * @param termBuffer to be scanned for new messages * @param offset at which the scan should begin. * @param maxLength in bytes of how much should be scanned. * @return resulting status of the scan which packs the available bytes and padding into a long. */ public static long ScanForAvailability(DirectBuffer termBuffer, int offset, int maxLength) { checked { maxLength = Math.Min(maxLength, (int)termBuffer.Length - offset); int available = 0; int padding = 0; do { int termOffset = offset + available; int frameLength = FrameDescriptor.FrameLengthVolatile(termBuffer, termOffset); if (frameLength <= 0) { break; } int alignedFrameLength = BitUtil.Align(frameLength, FrameDescriptor.FRAME_ALIGNMENT); if (FrameDescriptor.IsPaddingFrame(termBuffer, termOffset)) { padding = alignedFrameLength - DataHeaderFlyweight.HEADER_LENGTH; alignedFrameLength = DataHeaderFlyweight.HEADER_LENGTH; } available += alignedFrameLength; if (available > maxLength) { available -= alignedFrameLength; padding = 0; break; } } while (0 == padding && available < maxLength); return(Pack(padding, available)); } }
/** * Scan for gaps from the rebuildOffset up to the high-water-mark. Each gap will be reported to the {@link GapHandler}. * * @param termBuffer to be scanned for a gap. * @param termId of the current term buffer. * @param rebuildOffset at which to start scanning. * @param hwmOffset at which to stop scanning. * @param handler to call if a gap is found. * @return offset of last contiguous frame */ public static int ScanForGap( DirectBuffer termBuffer, int termId, int rebuildOffset, int hwmOffset, GapHandler handler) { do { int frameLength = FrameDescriptor.FrameLengthVolatile(termBuffer, rebuildOffset); if (frameLength <= 0) { break; } rebuildOffset += BitUtil.Align(frameLength, FrameDescriptor.FRAME_ALIGNMENT); }while (rebuildOffset < hwmOffset); int gapBeginOffset = rebuildOffset; if (rebuildOffset < hwmOffset) { int limit = hwmOffset - ALIGNED_HEADER_LENGTH; while (rebuildOffset < limit) { rebuildOffset += FrameDescriptor.FRAME_ALIGNMENT; if (0 != termBuffer.VolatileReadInt32(rebuildOffset)) { rebuildOffset -= ALIGNED_HEADER_LENGTH; break; } } int gapLength = (rebuildOffset - gapBeginOffset) + ALIGNED_HEADER_LENGTH; handler?.Invoke(termId, termBuffer, gapBeginOffset, gapLength); } return(gapBeginOffset); }