/* * 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.driver.status; import org.agrona.concurrent.status.CountersManager; import org.agrona.concurrent.status.CountersReader; import org.agrona.concurrent.UnsafeBuffer; import org.agrona.concurrent.status.UnsafeBufferPosition; import static org.agrona.BitUtil.SIZE_OF_INT; import static org.agrona.BitUtil.SIZE_OF_LONG; /** * Allocates {@link UnsafeBufferPosition} counters on a stream of messages. Positions tracked in bytes include: * <ul> * <li>{@link PublisherLimit}: Limit for flow controlling a {@link io.aeron.Publication} steam.</li> * <li>{@link SenderPos}: Highest position on a {@link io.aeron.Publication} stream sent to the media.</li> * <li>{@link SenderLimit}: Limit for flow controlling a {@link io.aeron.driver.Sender} of a stream.</li> * <li>{@link ReceiverHwm}: Highest position observed by the Receiver when rebuilding an {@link io.aeron.Image} of a stream.</li> * <li>{@link ReceiverPos}: Highest position rebuilt by the Receiver when rebuilding an {@link io.aeron.Image} of a stream.</li> * <li>{@link SubscriberPos}: Consumption position in an {@link io.aeron.Image} of a stream for each Subscriber.</li> * </ul> */ public class StreamPositionCounter { /** * Offset in the key meta data for the registration id of the counter. */ public static final int REGISTRATION_ID_OFFSET = 0; /** * Offset in the key meta data for the session id of the counter. */ public static final int SESSION_ID_OFFSET = REGISTRATION_ID_OFFSET + SIZE_OF_LONG; /** * Offset in the key meta data for the stream id of the counter. */ public static final int STREAM_ID_OFFSET = SESSION_ID_OFFSET + SIZE_OF_INT; /** * Offset in the key meta data for the channel of the counter. */ public static final int CHANNEL_OFFSET = STREAM_ID_OFFSET + SIZE_OF_INT; /** * The maximum length in bytes of the encoded channel identity. */ public static final int MAX_CHANNEL_LENGTH = CountersReader.MAX_KEY_LENGTH - (CHANNEL_OFFSET + SIZE_OF_INT); /** * Allocate a counter for tracking a position on a stream of messages. * * @param name of the counter for the label. * @param typeId of the counter for classification. * @param countersManager from which to allocated the underlying storage. * @param registrationId to be associated with the counter. * @param sessionId for the stream of messages. * @param streamId for the stream of messages. * @param channel for the stream of messages. * @return a new {@link UnsafeBufferPosition} for tracking the stream. */ public static UnsafeBufferPosition allocate( final String name, final int typeId, final CountersManager countersManager, final long registrationId, final int sessionId, final int streamId, final String channel) { return allocate(name, typeId, countersManager, registrationId, sessionId, streamId, channel, ""); } /** * Allocate a counter for tracking a position on a stream of messages. * * @param name of the counter for the label. * @param typeId of the counter for classification. * @param countersManager from which to allocated the underlying storage. * @param registrationId to be associated with the counter. * @param sessionId for the stream of messages. * @param streamId for the stream of messages. * @param channel for the stream of messages. * @param suffix for the label. * @return a new {@link UnsafeBufferPosition} for tracking the stream. */ public static UnsafeBufferPosition allocate( final String name, final int typeId, final CountersManager countersManager, final long registrationId, final int sessionId, final int streamId, final String channel, final String suffix) { final String label = name + ": " + registrationId + ' ' + sessionId + ' ' + streamId + ' ' + channel + ' ' + suffix; final int counterId = countersManager.allocate( label, typeId, (buffer) -> { buffer.putLong(REGISTRATION_ID_OFFSET, registrationId); buffer.putInt(SESSION_ID_OFFSET, sessionId); buffer.putInt(STREAM_ID_OFFSET, streamId); buffer.putStringAscii( CHANNEL_OFFSET, channel.length() > MAX_CHANNEL_LENGTH ? channel.substring(0, MAX_CHANNEL_LENGTH) : channel); } ); return new UnsafeBufferPosition((UnsafeBuffer)countersManager.valuesBuffer(), counterId, countersManager); } /** * Return the label name for a counter type identifier. * * @param typeId of the counter. * @return the label name as a String. */ public static String labelName(final int typeId) { switch (typeId) { case PublisherLimit.PUBLISHER_LIMIT_TYPE_ID: return PublisherLimit.NAME; case SenderPos.SENDER_POSITION_TYPE_ID: return SenderPos.NAME; case SenderLimit.SENDER_LIMIT_TYPE_ID: return SenderLimit.NAME; case ReceiverHwm.RECEIVER_HWM_TYPE_ID: return ReceiverHwm.NAME; case SubscriberPos.SUBSCRIBER_POSITION_TYPE_ID: return SubscriberPos.NAME; case ReceiverPos.RECEIVER_POS_TYPE_ID: return ReceiverPos.NAME; default: return "<unknown>"; } } }