/* * Copyright 2014-2017 Real Logic Ltd. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package io.aeron.logbuffer; import org.agrona.concurrent.UnsafeBuffer; import static io.aeron.logbuffer.FrameDescriptor.FRAME_ALIGNMENT; import static io.aeron.logbuffer.FrameDescriptor.frameLengthVolatile; import static io.aeron.logbuffer.FrameDescriptor.isPaddingFrame; import static io.aeron.protocol.DataHeaderFlyweight.HEADER_LENGTH; import static org.agrona.BitUtil.align; /** * Scans a term buffer for an availability range of messages. * * This can be used to concurrently read a term buffer which is being appended to. */ public final class TermScanner { /** * 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(final UnsafeBuffer termBuffer, final int offset, final int maxLength) { final int limit = Math.min(maxLength, termBuffer.capacity() - offset); int available = 0; int padding = 0; do { final int termOffset = offset + available; final int frameLength = frameLengthVolatile(termBuffer, termOffset); if (frameLength <= 0) { break; } int alignedFrameLength = align(frameLength, FRAME_ALIGNMENT); if (isPaddingFrame(termBuffer, termOffset)) { padding = alignedFrameLength - HEADER_LENGTH; alignedFrameLength = HEADER_LENGTH; } available += alignedFrameLength; if (available > limit) { available -= alignedFrameLength; padding = 0; break; } } while (0 == padding && available < limit); return pack(padding, available); } /** * Pack the values for available and padding into a long for returning on the stack. * * @param padding value to be packed. * @param available value to be packed. * @return a long with both ints packed into it. */ public static long pack(final int padding, final int available) { return ((long)padding << 32) | available; } /** * The number of bytes that are available to be read after a scan. * * @param result into which the padding value has been packed. * @return the count of bytes that are available to be read. */ public static int available(final long result) { return (int)result; } /** * The count of bytes that should be added for padding to the position on top of what is available * * @param result into which the padding value has been packed. * @return the count of bytes that should be added for padding to the position on top of what is available. */ public static int padding(final long result) { return (int)(result >>> 32); } }