All Downloads are FREE. Search and download functionalities are using the official Maven repository.

io.aeron.logbuffer.TermScanner Maven / Gradle / Ivy

There is a newer version: 1.46.7
Show newest version
/*
 * 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);
    }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy