public Map<StreamCompositeKey, List<StreamPosition>> snapshot()
    {
        final Map<StreamCompositeKey, List<StreamPosition>> streams = new HashMap<>();

        counters.forEach(
            (counterId, typeId, keyBuffer, label) ->
            {
                if ((typeId >= PUBLISHER_LIMIT_TYPE_ID && typeId <= RECEIVER_POS_TYPE_ID) ||
                    typeId == SENDER_LIMIT_TYPE_ID || typeId == PER_IMAGE_TYPE_ID || typeId == PUBLISHER_POS_TYPE_ID)
                {
                    final StreamCompositeKey key = new StreamCompositeKey(
                        keyBuffer.getInt(SESSION_ID_OFFSET),
                        keyBuffer.getInt(STREAM_ID_OFFSET),
                        keyBuffer.getStringAscii(CHANNEL_OFFSET));

                    final StreamPosition position = new StreamPosition(
                        keyBuffer.getLong(REGISTRATION_ID_OFFSET),
                        counters.getCounterValue(counterId),
                        typeId);

                    streams
                        .computeIfAbsent(key, (ignore) -> new ArrayList<>())
                        .add(position);
                }
            });

        return streams;
    }

public Map < StreamCompositeKey , List < StreamPosition > > snapshot ( ) { final Map < StreamCompositeKey , List < StreamPosition > > streams = new HashMap <> ( ) ; counters . forEach ( ( counterId , typeId , keyBuffer , label ) -> { if ( ( typeId >= PUBLISHER_LIMIT_TYPE_ID && typeId <= RECEIVER_POS_TYPE_ID ) || typeId == SENDER_LIMIT_TYPE_ID || typeId == PER_IMAGE_TYPE_ID || typeId == PUBLISHER_POS_TYPE_ID ) { final StreamCompositeKey key = new StreamCompositeKey ( keyBuffer . getInt ( SESSION_ID_OFFSET ) , keyBuffer . getInt ( STREAM_ID_OFFSET ) , keyBuffer . getStringAscii ( CHANNEL_OFFSET ) ) ; final StreamPosition position = new StreamPosition ( keyBuffer . getLong ( REGISTRATION_ID_OFFSET ) , counters . getCounterValue ( counterId ) , typeId ) ; streams . computeIfAbsent ( key , ( ignore ) - > new ArrayList <> ( ) ) . add ( position ) ; } } ) ; return streams ; }

Take a snapshot of all the counters and group them by streams.

@return a snapshot of all the counters and group them by streams.

Take a snapshot of all the counters and group them by streams .


public static UnsafeBuffer createDefaultHeader(final int sessionId, final int streamId, final int termId)
    {
        final UnsafeBuffer buffer = new UnsafeBuffer(
            BufferUtil.allocateDirectAligned(HEADER_LENGTH, CACHE_LINE_LENGTH));

        buffer.putByte(VERSION_FIELD_OFFSET, CURRENT_VERSION);
        buffer.putByte(FLAGS_FIELD_OFFSET, (byte)BEGIN_AND_END_FLAGS);
        buffer.putShort(TYPE_FIELD_OFFSET, (short)HDR_TYPE_DATA, LITTLE_ENDIAN);
        buffer.putInt(SESSION_ID_FIELD_OFFSET, sessionId, LITTLE_ENDIAN);
        buffer.putInt(STREAM_ID_FIELD_OFFSET, streamId, LITTLE_ENDIAN);
        buffer.putInt(TERM_ID_FIELD_OFFSET, termId, LITTLE_ENDIAN);
        buffer.putLong(RESERVED_VALUE_OFFSET, DEFAULT_RESERVE_VALUE);

        return buffer;
    }

public static UnsafeBuffer createDefaultHeader ( final int sessionId , final int streamId , final int termId ) { final UnsafeBuffer buffer = new UnsafeBuffer ( BufferUtil . allocateDirectAligned ( HEADER_LENGTH , CACHE_LINE_LENGTH ) ) ; buffer . putByte ( VERSION_FIELD_OFFSET , CURRENT_VERSION ) ; buffer . putByte ( FLAGS_FIELD_OFFSET , ( byte ) BEGIN_AND_END_FLAGS ) ; buffer . putShort ( TYPE_FIELD_OFFSET , ( short ) HDR_TYPE_DATA , LITTLE_ENDIAN ) ; buffer . putInt ( SESSION_ID_FIELD_OFFSET , sessionId , LITTLE_ENDIAN ) ; buffer . putInt ( STREAM_ID_FIELD_OFFSET , streamId , LITTLE_ENDIAN ) ; buffer . putInt ( TERM_ID_FIELD_OFFSET , termId , LITTLE_ENDIAN ) ; buffer . putLong ( RESERVED_VALUE_OFFSET , DEFAULT_RESERVE_VALUE ) ; return buffer ; }

Return an initialised default Data Frame Header.

@param sessionId for the header
@param streamId  for the header
@param termId    for the header
@return byte array containing the header

Return an initialised default Data Frame Header .


public CounterMessageFlyweight keyBuffer(final DirectBuffer keyBuffer, final int keyOffset, final int keyLength)
    {
        buffer.putInt(KEY_LENGTH_OFFSET, keyLength);
        if (null != keyBuffer && keyLength > 0)
        {
            buffer.putBytes(keyBufferOffset(), keyBuffer, keyOffset, keyLength);
        }

        return this;
    }

public CounterMessageFlyweight keyBuffer ( final DirectBuffer keyBuffer , final int keyOffset , final int keyLength ) { buffer . putInt ( KEY_LENGTH_OFFSET , keyLength ) ; if ( null != keyBuffer && keyLength > 0 ) { buffer . putBytes ( keyBufferOffset ( ) , keyBuffer , keyOffset , keyLength ) ; } return this ; }

Fill the key buffer.

@param keyBuffer containing the optional key for the counter.
@param keyOffset within the keyBuffer at which the key begins.
@param keyLength of the key in the keyBuffer.
@return flyweight


public CounterMessageFlyweight labelBuffer(
        final DirectBuffer labelBuffer, final int labelOffset, final int labelLength)
    {
        buffer.putInt(labelOffset(), labelLength);
        buffer.putBytes(labelBufferOffset(), labelBuffer, labelOffset, labelLength);

        return this;
    }

public CounterMessageFlyweight labelBuffer ( final DirectBuffer labelBuffer , final int labelOffset , final int labelLength ) { buffer . putInt ( labelOffset ( ) , labelLength ) ; buffer . putBytes ( labelBufferOffset ( ) , labelBuffer , labelOffset , labelLength ) ; return this ; }

Fill the label buffer.

@param labelBuffer containing the mandatory label for the counter.
@param labelOffset within the labelBuffer at which the label begins.
@param labelLength of the label in the labelBuffer.
@return flyweight


public boolean connect(final String responseChannel, final int responseStreamId, final long correlationId)
    {
        connectRequestEncoder
            .wrapAndApplyHeader(buffer, 0, messageHeaderEncoder)
            .correlationId(correlationId)
            .responseStreamId(responseStreamId)
            .version(AeronArchive.Configuration.SEMANTIC_VERSION)
            .responseChannel(responseChannel);

        return offerWithTimeout(connectRequestEncoder.encodedLength(), null);
    }

public boolean connect ( final String responseChannel , final int responseStreamId , final long correlationId ) { connectRequestEncoder . wrapAndApplyHeader ( buffer , 0 , messageHeaderEncoder ) . correlationId ( correlationId ) . responseStreamId ( responseStreamId ) . version ( AeronArchive . Configuration . SEMANTIC_VERSION ) . responseChannel ( responseChannel ) ; return offerWithTimeout ( connectRequestEncoder . encodedLength ( ) , null ) ; }

Connect to an archive on its control interface providing the response stream details.

@param responseChannel  for the control message responses.
@param responseStreamId for the control message responses.
@param correlationId    for this request.
@return true if successfully offered otherwise false.

Connect to an archive on its control interface providing the response stream details .


public boolean tryConnect(final String responseChannel, final int responseStreamId, final long correlationId)
    {
        connectRequestEncoder
            .wrapAndApplyHeader(buffer, 0, messageHeaderEncoder)
            .correlationId(correlationId)
            .responseStreamId(responseStreamId)
            .version(AeronArchive.Configuration.SEMANTIC_VERSION)
            .responseChannel(responseChannel);

        final int length = MessageHeaderEncoder.ENCODED_LENGTH + connectRequestEncoder.encodedLength();

        return publication.offer(buffer, 0, length) > 0;
    }

public boolean tryConnect ( final String responseChannel , final int responseStreamId , final long correlationId ) { connectRequestEncoder . wrapAndApplyHeader ( buffer , 0 , messageHeaderEncoder ) . correlationId ( correlationId ) . responseStreamId ( responseStreamId ) . version ( AeronArchive . Configuration . SEMANTIC_VERSION ) . responseChannel ( responseChannel ) ; final int length = MessageHeaderEncoder . ENCODED_LENGTH + connectRequestEncoder . encodedLength ( ) ; return publication . offer ( buffer , 0 , length ) > 0 ; }

Try Connect to an archive on its control interface providing the response stream details. Only one attempt will
be made to offer the request.

@param responseChannel  for the control message responses.
@param responseStreamId for the control message responses.
@param correlationId    for this request.
@return true if successfully offered otherwise false.

Try Connect to an archive on its control interface providing the response stream details . Only one attempt will be made to offer the request .


public boolean closeSession(final long controlSessionId)
    {
        closeSessionRequestEncoder
            .wrapAndApplyHeader(buffer, 0, messageHeaderEncoder)
            .controlSessionId(controlSessionId);

        return offer(closeSessionRequestEncoder.encodedLength());
    }

public boolean closeSession ( final long controlSessionId ) { closeSessionRequestEncoder . wrapAndApplyHeader ( buffer , 0 , messageHeaderEncoder ) . controlSessionId ( controlSessionId ) ; return offer ( closeSessionRequestEncoder . encodedLength ( ) ) ; }

Close this control session with the archive.

@param controlSessionId with the archive.
@return true if successfully offered otherwise false.

Close this control session with the archive .


public boolean startRecording(
        final String channel,
        final int streamId,
        final SourceLocation sourceLocation,
        final long correlationId,
        final long controlSessionId)
    {
        startRecordingRequestEncoder
            .wrapAndApplyHeader(buffer, 0, messageHeaderEncoder)
            .controlSessionId(controlSessionId)
            .correlationId(correlationId)
            .streamId(streamId)
            .sourceLocation(sourceLocation)
            .channel(channel);

        return offer(startRecordingRequestEncoder.encodedLength());
    }

public boolean startRecording ( final String channel , final int streamId , final SourceLocation sourceLocation , final long correlationId , final long controlSessionId ) { startRecordingRequestEncoder . wrapAndApplyHeader ( buffer , 0 , messageHeaderEncoder ) . controlSessionId ( controlSessionId ) . correlationId ( correlationId ) . streamId ( streamId ) . sourceLocation ( sourceLocation ) . channel ( channel ) ; return offer ( startRecordingRequestEncoder . encodedLength ( ) ) ; }

Start recording streams for a given channel and stream id pairing.

@param channel          to be recorded.
@param streamId         to be recorded.
@param sourceLocation   of the publication to be recorded.
@param correlationId    for this request.
@param controlSessionId for this request.
@return true if successfully offered otherwise false.

Start recording streams for a given channel and stream id pairing .


public boolean stopRecording(
        final String channel,
        final int streamId,
        final long correlationId,
        final long controlSessionId)
    {
        stopRecordingRequestEncoder
            .wrapAndApplyHeader(buffer, 0, messageHeaderEncoder)
            .controlSessionId(controlSessionId)
            .correlationId(correlationId)
            .streamId(streamId)
            .channel(channel);

        return offer(stopRecordingRequestEncoder.encodedLength());
    }

public boolean stopRecording ( final String channel , final int streamId , final long correlationId , final long controlSessionId ) { stopRecordingRequestEncoder . wrapAndApplyHeader ( buffer , 0 , messageHeaderEncoder ) . controlSessionId ( controlSessionId ) . correlationId ( correlationId ) . streamId ( streamId ) . channel ( channel ) ; return offer ( stopRecordingRequestEncoder . encodedLength ( ) ) ; }

Stop an active recording.

@param channel          to be stopped.
@param streamId         to be stopped.
@param correlationId    for this request.
@param controlSessionId for this request.
@return true if successfully offered otherwise false.


public boolean replay(
        final long recordingId,
        final long position,
        final long length,
        final String replayChannel,
        final int replayStreamId,
        final long correlationId,
        final long controlSessionId)
    {
        replayRequestEncoder
            .wrapAndApplyHeader(buffer, 0, messageHeaderEncoder)
            .controlSessionId(controlSessionId)
            .correlationId(correlationId)
            .recordingId(recordingId)
            .position(position)
            .length(length)
            .replayStreamId(replayStreamId)
            .replayChannel(replayChannel);

        return offer(replayRequestEncoder.encodedLength());
    }

public boolean replay ( final long recordingId , final long position , final long length , final String replayChannel , final int replayStreamId , final long correlationId , final long controlSessionId ) { replayRequestEncoder . wrapAndApplyHeader ( buffer , 0 , messageHeaderEncoder ) . controlSessionId ( controlSessionId ) . correlationId ( correlationId ) . recordingId ( recordingId ) . position ( position ) . length ( length ) . replayStreamId ( replayStreamId ) . replayChannel ( replayChannel ) ; return offer ( replayRequestEncoder . encodedLength ( ) ) ; }

Replay a recording from a given position.

@param recordingId      to be replayed.
@param position         from which the replay should be started.
@param length           of the stream to be replayed. Use {@link Long#MAX_VALUE} to follow a live stream.
@param replayChannel    to which the replay should be sent.
@param replayStreamId   to which the replay should be sent.
@param correlationId    for this request.
@param controlSessionId for this request.
@return true if successfully offered otherwise false.

Replay a recording from a given position .


public boolean stopReplay(final long replaySessionId, final long correlationId, final long controlSessionId)
    {
        stopReplayRequestEncoder
            .wrapAndApplyHeader(buffer, 0, messageHeaderEncoder)
            .controlSessionId(controlSessionId)
            .correlationId(correlationId)
            .replaySessionId(replaySessionId);

        return offer(replayRequestEncoder.encodedLength());
    }

public boolean stopReplay ( final long replaySessionId , final long correlationId , final long controlSessionId ) { stopReplayRequestEncoder . wrapAndApplyHeader ( buffer , 0 , messageHeaderEncoder ) . controlSessionId ( controlSessionId ) . correlationId ( correlationId ) . replaySessionId ( replaySessionId ) ; return offer ( replayRequestEncoder . encodedLength ( ) ) ; }

Stop an existing replay session.

@param replaySessionId  that should be stopped.
@param correlationId    for this request.
@param controlSessionId for this request.
@return true if successfully offered otherwise false.


public boolean listRecordings(
        final long fromRecordingId, final int recordCount, final long correlationId, final long controlSessionId)
    {
        listRecordingsRequestEncoder
            .wrapAndApplyHeader(buffer, 0, messageHeaderEncoder)
            .controlSessionId(controlSessionId)
            .correlationId(correlationId)
            .fromRecordingId(fromRecordingId)
            .recordCount(recordCount);

        return offer(listRecordingsRequestEncoder.encodedLength());
    }

public boolean listRecordings ( final long fromRecordingId , final int recordCount , final long correlationId , final long controlSessionId ) { listRecordingsRequestEncoder . wrapAndApplyHeader ( buffer , 0 , messageHeaderEncoder ) . controlSessionId ( controlSessionId ) . correlationId ( correlationId ) . fromRecordingId ( fromRecordingId ) . recordCount ( recordCount ) ; return offer ( listRecordingsRequestEncoder . encodedLength ( ) ) ; }

List a range of recording descriptors.

@param fromRecordingId  at which to begin listing.
@param recordCount      for the number of descriptors to be listed.
@param correlationId    for this request.
@param controlSessionId for this request.
@return true if successfully offered otherwise false.


public boolean listRecordingsForUri(
        final long fromRecordingId,
        final int recordCount,
        final String channelFragment,
        final int streamId,
        final long correlationId,
        final long controlSessionId)
    {
        listRecordingsForUriRequestEncoder
            .wrapAndApplyHeader(buffer, 0, messageHeaderEncoder)
            .controlSessionId(controlSessionId)
            .correlationId(correlationId)
            .fromRecordingId(fromRecordingId)
            .recordCount(recordCount)
            .streamId(streamId)
            .channel(channelFragment);

        return offer(listRecordingsForUriRequestEncoder.encodedLength());
    }

public boolean listRecordingsForUri ( final long fromRecordingId , final int recordCount , final String channelFragment , final int streamId , final long correlationId , final long controlSessionId ) { listRecordingsForUriRequestEncoder . wrapAndApplyHeader ( buffer , 0 , messageHeaderEncoder ) . controlSessionId ( controlSessionId ) . correlationId ( correlationId ) . fromRecordingId ( fromRecordingId ) . recordCount ( recordCount ) . streamId ( streamId ) . channel ( channelFragment ) ; return offer ( listRecordingsForUriRequestEncoder . encodedLength ( ) ) ; }

List a range of recording descriptors which match a channel URI fragment and stream id.

@param fromRecordingId  at which to begin listing.
@param recordCount      for the number of descriptors to be listed.
@param channelFragment  to match recordings on from the original channel URI in the archive descriptor.
@param streamId         to match recordings on.
@param correlationId    for this request.
@param controlSessionId for this request.
@return true if successfully offered otherwise false.

List a range of recording descriptors which match a channel URI fragment and stream id .


public boolean listRecording(final long recordingId, final long correlationId, final long controlSessionId)
    {
        listRecordingRequestEncoder
            .wrapAndApplyHeader(buffer, 0, messageHeaderEncoder)
            .controlSessionId(controlSessionId)
            .correlationId(correlationId)
            .recordingId(recordingId);

        return offer(listRecordingRequestEncoder.encodedLength());
    }

public boolean listRecording ( final long recordingId , final long correlationId , final long controlSessionId ) { listRecordingRequestEncoder . wrapAndApplyHeader ( buffer , 0 , messageHeaderEncoder ) . controlSessionId ( controlSessionId ) . correlationId ( correlationId ) . recordingId ( recordingId ) ; return offer ( listRecordingRequestEncoder . encodedLength ( ) ) ; }

List a recording descriptor for a given recording id.

@param recordingId      at which to begin listing.
@param correlationId    for this request.
@param controlSessionId for this request.
@return true if successfully offered otherwise false.

List a recording descriptor for a given recording id .


public boolean extendRecording(
        final String channel,
        final int streamId,
        final SourceLocation sourceLocation,
        final long recordingId,
        final long correlationId,
        final long controlSessionId)
    {
        extendRecordingRequestEncoder
            .wrapAndApplyHeader(buffer, 0, messageHeaderEncoder)
            .controlSessionId(controlSessionId)
            .correlationId(correlationId)
            .recordingId(recordingId)
            .streamId(streamId)
            .sourceLocation(sourceLocation)
            .channel(channel);

        return offer(extendRecordingRequestEncoder.encodedLength());
    }

public boolean extendRecording ( final String channel , final int streamId , final SourceLocation sourceLocation , final long recordingId , final long correlationId , final long controlSessionId ) { extendRecordingRequestEncoder . wrapAndApplyHeader ( buffer , 0 , messageHeaderEncoder ) . controlSessionId ( controlSessionId ) . correlationId ( correlationId ) . recordingId ( recordingId ) . streamId ( streamId ) . sourceLocation ( sourceLocation ) . channel ( channel ) ; return offer ( extendRecordingRequestEncoder . encodedLength ( ) ) ; }

Extend an existing, non-active, recorded stream for a the same channel and stream id.

The channel must be configured for the initial position from which it will be extended. This can be done
with {@link ChannelUriStringBuilder#initialPosition(long, int, int)}. The details required to initialise can
be found by calling {@link #listRecording(long, long, long)}.

@param channel          to be recorded.
@param streamId         to be recorded.
@param sourceLocation   of the publication to be recorded.
@param recordingId      to be extended.
@param correlationId    for this request.
@param controlSessionId for this request.
@return true if successfully offered otherwise false.

Extend an existing non - active recorded stream for a the same channel and stream id .


public boolean getRecordingPosition(final long recordingId, final long correlationId, final long controlSessionId)
    {
        recordingPositionRequestEncoder
            .wrapAndApplyHeader(buffer, 0, messageHeaderEncoder)
            .controlSessionId(controlSessionId)
            .correlationId(correlationId)
            .recordingId(recordingId);

        return offer(recordingPositionRequestEncoder.encodedLength());
    }

public boolean getRecordingPosition ( final long recordingId , final long correlationId , final long controlSessionId ) { recordingPositionRequestEncoder . wrapAndApplyHeader ( buffer , 0 , messageHeaderEncoder ) . controlSessionId ( controlSessionId ) . correlationId ( correlationId ) . recordingId ( recordingId ) ; return offer ( recordingPositionRequestEncoder . encodedLength ( ) ) ; }

Get the recorded position of an active recording.

@param recordingId      of the active recording that the position is being requested for.
@param correlationId    for this request.
@param controlSessionId for this request.
@return true if successfully offered otherwise false.

Get the recorded position of an active recording .


public boolean getStopPosition(final long recordingId, final long correlationId, final long controlSessionId)
    {
        stopPositionRequestEncoder
            .wrapAndApplyHeader(buffer, 0, messageHeaderEncoder)
            .controlSessionId(controlSessionId)
            .correlationId(correlationId)
            .recordingId(recordingId);

        return offer(stopPositionRequestEncoder.encodedLength());
    }

public boolean getStopPosition ( final long recordingId , final long correlationId , final long controlSessionId ) { stopPositionRequestEncoder . wrapAndApplyHeader ( buffer , 0 , messageHeaderEncoder ) . controlSessionId ( controlSessionId ) . correlationId ( correlationId ) . recordingId ( recordingId ) ; return offer ( stopPositionRequestEncoder . encodedLength ( ) ) ; }

Get the stop position of a recording.

@param recordingId      of the recording that the stop position is being requested for.
@param correlationId    for this request.
@param controlSessionId for this request.
@return true if successfully offered otherwise false.


public boolean listRecordingSubscriptions(
        final int pseudoIndex,
        final int subscriptionCount,
        final String channelFragment,
        final int streamId,
        final boolean applyStreamId,
        final long correlationId,
        final long controlSessionId)
    {
        listRecordingSubscriptionsRequestEncoder
            .wrapAndApplyHeader(buffer, 0, messageHeaderEncoder)
            .controlSessionId(controlSessionId)
            .correlationId(correlationId)
            .pseudoIndex(pseudoIndex)
            .subscriptionCount(subscriptionCount)
            .applyStreamId(applyStreamId ? BooleanType.TRUE : BooleanType.FALSE)
            .streamId(streamId)
            .channel(channelFragment);

        return offer(listRecordingSubscriptionsRequestEncoder.encodedLength());
    }

List registered subscriptions in the archive which have been used to record streams.

@param pseudoIndex       in the list of active recording subscriptions.
@param subscriptionCount for the number of descriptors to be listed.
@param channelFragment   for a contains match on the stripped channel used with the registered subscription.
@param streamId          for the subscription.
@param applyStreamId     when matching.
@param correlationId     for this request.
@param controlSessionId  for this request.
@return true if successfully offered otherwise false.

List registered subscriptions in the archive which have been used to record streams .


public boolean matchesTag(final UdpChannel udpChannel)
    {
        if (!hasTag || !udpChannel.hasTag() || tag != udpChannel.tag())
        {
            return false;
        }

        if (udpChannel.remoteData().getAddress().isAnyLocalAddress() &&
            udpChannel.remoteData().getPort() == 0 &&
            udpChannel.localData().getAddress().isAnyLocalAddress() &&
            udpChannel.localData().getPort() == 0)
        {
            return true;
        }

        throw new IllegalArgumentException("matching tag has set endpoint or control address");
    }

Does this channel have a tag match to another channel including endpoints.

@param udpChannel to match against.
@return true if there is a match otherwise false.

Does this channel have a tag match to another channel including endpoints .


public static InetSocketAddress destinationAddress(final ChannelUri uri)
    {
        try
        {
            validateConfiguration(uri);
            return getEndpointAddress(uri);
        }
        catch (final Exception ex)
        {
            throw new InvalidChannelException(ErrorCode.INVALID_CHANNEL, ex);
        }
    }

public static InetSocketAddress destinationAddress ( final ChannelUri uri ) { try { validateConfiguration ( uri ) ; return getEndpointAddress ( uri ) ; } catch ( final Exception ex ) { throw new InvalidChannelException ( ErrorCode . INVALID_CHANNEL , ex ) ; } }

Get the endpoint address from the URI.

@param uri to check
@return endpoint address for URI


public String description()
    {
        final StringBuilder builder = new StringBuilder("UdpChannel - ");
        if (null != localInterface)
        {
            builder
                .append("interface: ")
                .append(localInterface.getDisplayName())
                .append(", ");
        }

        builder
            .append("localData: ").append(localData)
            .append(", remoteData: ").append(remoteData)
            .append(", ttl: ").append(multicastTtl);

        return builder.toString();
    }

public
String
description
(
)
{
final
StringBuilder
builder
=
new
StringBuilder
(
"UdpChannel - "
)
;
if
(
!=
localInterface
)
{
builder
.
append
(
"interface: "
)
.
append
(
localInterface
.
getDisplayName
(
)
)
.
append
(
", "
)
;
}
builder
.
append
(
"localData: "
)
.
append
(
localData
)
.
append
(
", remoteData: "
)
.
append
(
remoteData
)
.
append
(
", ttl: "
)
.
append
(
multicastTtl
)
;
return
builder
.
toString
(
)
;
}

Used for debugging to get a human readable description of the channel.

@return a human readable description of the channel.

Used for debugging to get a human readable description of the channel .


void addDestination(final int transportIndex, final ReceiveDestinationUdpTransport transport)
    {
        imageConnections = ArrayUtil.ensureCapacity(imageConnections, transportIndex + 1);

        if (transport.isMulticast())
        {
            imageConnections[transportIndex] = new ImageConnection(
                cachedNanoClock.nanoTime(), transport.udpChannel().remoteControl());
        }
        else if (transport.hasExplicitControl())
        {
            imageConnections[transportIndex] = new ImageConnection(
                cachedNanoClock.nanoTime(), transport.explicitControlAddress());
        }
    }

void addDestination ( final int transportIndex , final ReceiveDestinationUdpTransport transport ) { imageConnections = ArrayUtil . ensureCapacity ( imageConnections , transportIndex + 1 ) ; if ( transport . isMulticast ( ) ) { imageConnections [ transportIndex ] = new ImageConnection ( cachedNanoClock . nanoTime ( ) , transport . udpChannel ( ) . remoteControl ( ) ) ; } else if ( transport . hasExplicitControl ( ) ) { imageConnections [ transportIndex ] = new ImageConnection ( cachedNanoClock . nanoTime ( ) , transport . explicitControlAddress ( ) ) ; } }

Add a destination to this image so it can merge streams.

@param transportIndex from which packets will arrive.
@param transport      from which packets will arrive.

Add a destination to this image so it can merge streams .


int insertPacket(
        final int termId,
        final int termOffset,
        final UnsafeBuffer buffer,
        final int length,
        final int transportIndex,
        final InetSocketAddress srcAddress)
    {
        final boolean isHeartbeat = DataHeaderFlyweight.isHeartbeat(buffer, length);
        final long packetPosition = computePosition(termId, termOffset, positionBitsToShift, initialTermId);
        final long proposedPosition = isHeartbeat ? packetPosition : packetPosition + length;

        if (!isFlowControlUnderRun(packetPosition) && !isFlowControlOverRun(proposedPosition))
        {
            trackConnection(transportIndex, srcAddress, lastPacketTimestampNs);

            if (isHeartbeat)
            {
                if (DataHeaderFlyweight.isEndOfStream(buffer) && !isEndOfStream && allEos(transportIndex))
                {
                    LogBufferDescriptor.endOfStreamPosition(rawLog.metaData(), proposedPosition);
                    isEndOfStream = true;
                }

                heartbeatsReceived.incrementOrdered();
            }
            else
            {
                final UnsafeBuffer termBuffer = termBuffers[indexByPosition(packetPosition, positionBitsToShift)];
                TermRebuilder.insert(termBuffer, termOffset, buffer, length);
            }

            lastPacketTimestampNs = cachedNanoClock.nanoTime();
            hwmPosition.proposeMaxOrdered(proposedPosition);
        }

        return length;
    }

int insertPacket ( final int termId , final int termOffset , final UnsafeBuffer buffer , final int length , final int transportIndex , final InetSocketAddress srcAddress ) { final boolean isHeartbeat = DataHeaderFlyweight . isHeartbeat ( buffer , length ) ; final long packetPosition = computePosition ( termId , termOffset , positionBitsToShift , initialTermId ) ; final long proposedPosition = isHeartbeat ? packetPosition : packetPosition + length ; if ( ! isFlowControlUnderRun ( packetPosition ) && ! isFlowControlOverRun ( proposedPosition ) ) { trackConnection ( transportIndex , srcAddress , lastPacketTimestampNs ) ; if ( isHeartbeat ) { if ( DataHeaderFlyweight . isEndOfStream ( buffer ) && ! isEndOfStream && allEos ( transportIndex ) ) { LogBufferDescriptor . endOfStreamPosition ( rawLog . metaData ( ) , proposedPosition ) ; isEndOfStream = true ; } heartbeatsReceived . incrementOrdered ( ) ; } else { final UnsafeBuffer termBuffer = termBuffers [ indexByPosition ( packetPosition , positionBitsToShift ) ] ; TermRebuilder . insert ( termBuffer , termOffset , buffer , length ) ; } lastPacketTimestampNs = cachedNanoClock . nanoTime ( ) ; hwmPosition . proposeMaxOrdered ( proposedPosition ) ; } return length ; }

Insert frame into term buffer.

@param termId         for the data packet to insert into the appropriate term.
@param termOffset     for the start of the packet in the term.
@param buffer         for the data packet to insert into the appropriate term.
@param length         of the data packet
@param transportIndex which the packet came from.
@param srcAddress     which the packet came from.
@return number of bytes applied as a result of this insertion.


public static AtomicCounter findControlToggle(final CountersReader counters)
    {
        final AtomicBuffer buffer = counters.metaDataBuffer();

        for (int i = 0, size = counters.maxCounterId(); i < size; i++)
        {
            final int recordOffset = CountersReader.metaDataOffset(i);

            if (counters.getCounterState(i) == RECORD_ALLOCATED &&
                buffer.getInt(recordOffset + TYPE_ID_OFFSET) == CONTROL_TOGGLE_TYPE_ID)
            {
                return new AtomicCounter(counters.valuesBuffer(), i, null);
            }
        }

        return null;
    }

public static AtomicCounter findControlToggle ( final CountersReader counters ) { final AtomicBuffer buffer = counters . metaDataBuffer ( ) ; for ( int i = 0 , size = counters . maxCounterId ( ) ; i < size ; i ++ ) { final int recordOffset = CountersReader . metaDataOffset ( i ) ; if ( counters . getCounterState ( i ) == RECORD_ALLOCATED && buffer . getInt ( recordOffset + TYPE_ID_OFFSET ) == CONTROL_TOGGLE_TYPE_ID ) { return new AtomicCounter ( counters . valuesBuffer ( ) , i , null ) ; } } return null ; }

Find the control toggle counter or return null if not found.

@param counters to search for the control toggle.
@return the control toggle counter or return null if not found.

Find the control toggle counter or return null if not found .


public String put(final String key, final String value)
    {
        return params.put(key, value);
    }

public String put ( final String key , final String value ) { return params . put ( key , value ) ; }

Put a key and value pair in the map of params.

@param key   of the param to be put.
@param value of the param to be put.
@return the existing value otherwise null.

Put a key and value pair in the map of params .


public String channelTag()
    {
        return (null != tags && tags.length > CHANNEL_TAG_INDEX) ? tags[CHANNEL_TAG_INDEX] : null;
    }

public String channelTag ( ) { return ( null != tags && tags . length > CHANNEL_TAG_INDEX ) ? tags [ CHANNEL_TAG_INDEX ] : null ; }

Get the channel tag, if it exists, that refers to an another channel.

@return channel tag if it exists or null if not in this URI.
@see CommonContext#TAGS_PARAM_NAME
@see CommonContext#TAG_PREFIX

Get the channel tag if it exists that refers to an another channel .


public String entityTag()
    {
        return (null != tags && tags.length > ENTITY_TAG_INDEX) ? tags[ENTITY_TAG_INDEX] : null;
    }

public String entityTag ( ) { return ( null != tags && tags . length > ENTITY_TAG_INDEX ) ? tags [ ENTITY_TAG_INDEX ] : null ; }

Get the entity tag, if it exists, that refers to an entity such as subscription or publication.

@return entity tag if it exists or null if not in this URI.
@see CommonContext#TAGS_PARAM_NAME
@see CommonContext#TAG_PREFIX

Get the entity tag if it exists that refers to an entity such as subscription or publication .


public static String addSessionId(final String channel, final int sessionId)
    {
        final ChannelUri channelUri = ChannelUri.parse(channel);
        channelUri.put(CommonContext.SESSION_ID_PARAM_NAME, Integer.toString(sessionId));

        return channelUri.toString();
    }

public static String addSessionId ( final String channel , final int sessionId ) { final ChannelUri channelUri = ChannelUri . parse ( channel ) ; channelUri . put ( CommonContext . SESSION_ID_PARAM_NAME , Integer . toString ( sessionId ) ) ; return channelUri . toString ( ) ; }

Add a sessionId to a given channel.

@param channel   to add sessionId to.
@param sessionId to add to channel.
@return new string that represents channel with sessionId added.


public static long getTag(final String paramValue)
    {
        return isTagged(paramValue) ?
            AsciiEncoding.parseLongAscii(paramValue, 4, paramValue.length() - 4) : INVALID_TAG;
    }

public static long getTag ( final String paramValue ) { return isTagged ( paramValue ) ? AsciiEncoding . parseLongAscii ( paramValue , 4 , paramValue . length ( ) - 4 ) : INVALID_TAG ; }

Get the value of the tag from a given parameter value.

@param paramValue to extract the tag value from.
@return the value of the tag or {@link #INVALID_TAG} if not tagged.
@see CommonContext#TAGS_PARAM_NAME
@see CommonContext#TAG_PREFIX

Get the value of the tag from a given parameter value .


public int appendPadding(
        final int termId,
        final int termOffset,
        final HeaderWriter header,
        final int length)
    {
        final int frameLength = length + HEADER_LENGTH;
        final int alignedLength = align(frameLength, FRAME_ALIGNMENT);
        final UnsafeBuffer termBuffer = this.termBuffer;
        final 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);
            frameType(termBuffer, termOffset, PADDING_FRAME_TYPE);
            frameLengthOrdered(termBuffer, termOffset, frameLength);
        }

        return resultingOffset;
    }

public int appendPadding ( final int termId , final int termOffset , final HeaderWriter header , final int length ) { final int frameLength = length + HEADER_LENGTH ; final int alignedLength = align ( frameLength , FRAME_ALIGNMENT ) ; final UnsafeBuffer termBuffer = this . termBuffer ; final 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 ) ; frameType ( termBuffer , termOffset , PADDING_FRAME_TYPE ) ; frameLengthOrdered ( termBuffer , termOffset , frameLength ) ; } return resultingOffset ; }

Pad a length of the term buffer with a padding record.

@param termId     for the current term.
@param termOffset in the term at which to append.
@param header     for writing the default header.
@param length     of the padding to be written.
@return the resulting offset of the term after success otherwise {@link #FAILED}.

Pad a length of the term buffer with a padding record .


final int updatePublisherLimit()
    {
        int workCount = 0;

        final long senderPosition = this.senderPosition.getVolatile();
        if (hasReceivers || (spiesSimulateConnection && spyPositions.length > 0))
        {
            long minConsumerPosition = senderPosition;
            for (final ReadablePosition spyPosition : spyPositions)
            {
                minConsumerPosition = Math.min(minConsumerPosition, spyPosition.getVolatile());
            }

            final long proposedPublisherLimit = minConsumerPosition + termWindowLength;
            if (publisherLimit.proposeMaxOrdered(proposedPublisherLimit))
            {
                cleanBuffer(proposedPublisherLimit);
                workCount = 1;
            }
        }
        else if (publisherLimit.get() > senderPosition)
        {
            publisherLimit.setOrdered(senderPosition);
        }

        return workCount;
    }

final int updatePublisherLimit ( ) { int workCount = 0 ; final long senderPosition = this . senderPosition . getVolatile ( ) ; if ( hasReceivers || ( spiesSimulateConnection && spyPositions . length > 0 ) ) { long minConsumerPosition = senderPosition ; for ( final ReadablePosition spyPosition : spyPositions ) { minConsumerPosition = Math . min ( minConsumerPosition , spyPosition . getVolatile ( ) ) ; } final long proposedPublisherLimit = minConsumerPosition + termWindowLength ; if ( publisherLimit . proposeMaxOrdered ( proposedPublisherLimit ) ) { cleanBuffer ( proposedPublisherLimit ) ; workCount = 1 ; } } else if ( publisherLimit . get ( ) > senderPosition ) { publisherLimit . setOrdered ( senderPosition ) ; } return workCount ; }

Update the publishers limit for flow control as part of the conductor duty cycle.

@return 1 if the limit has been updated otherwise 0.

Update the publishers limit for flow control as part of the conductor duty cycle .


public static UnsafeBufferPosition allocate(
        final MutableDirectBuffer tempBuffer,
        final String name,
        final int typeId,
        final CountersManager countersManager,
        final long registrationId,
        final int sessionId,
        final int streamId,
        final String channel)
    {
        return new UnsafeBufferPosition(
            (UnsafeBuffer)countersManager.valuesBuffer(),
            allocateCounterId(tempBuffer, name, typeId, countersManager, registrationId, sessionId, streamId, channel),
            countersManager);
    }

public static UnsafeBufferPosition allocate ( final MutableDirectBuffer tempBuffer , final String name , final int typeId , final CountersManager countersManager , final long registrationId , final int sessionId , final int streamId , final String channel ) { return new UnsafeBufferPosition ( ( UnsafeBuffer ) countersManager . valuesBuffer ( ) , allocateCounterId ( tempBuffer , name , typeId , countersManager , registrationId , sessionId , streamId , channel ) , countersManager ) ; }

Allocate a counter for tracking a position on a stream of messages.

@param tempBuffer      to be used for labels and key.
@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.

Allocate a counter for tracking a position on a stream of messages .


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 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;

            case SenderLimit.SENDER_LIMIT_TYPE_ID:
                return SenderLimit.NAME;

            case PublisherPos.PUBLISHER_POS_TYPE_ID:
                return PublisherPos.NAME;

            case SenderBpe.SENDER_BPE_TYPE_ID:
                return SenderBpe.NAME;

            default:
                return "<unknown>";
        }
    }

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 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 ; case SenderLimit . SENDER_LIMIT_TYPE_ID : return SenderLimit . NAME ; case PublisherPos . PUBLISHER_POS_TYPE_ID : return PublisherPos . NAME ; case SenderBpe . SENDER_BPE_TYPE_ID : return SenderBpe . NAME ; default : return "<unknown>" ; } }

Return the label name for a counter type identifier.

@param typeId of the counter.
@return the label name as a String.

Return the label name for a counter type identifier .


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);
    }

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 ) ; }

Scan the term buffer for availability of new message fragments from a given offset up to a maxLength of bytes.

@param termBuffer to be scanned for new message fragments.
@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.

Scan the term buffer for availability of new message fragments from a given offset up to a maxLength of bytes .


public ChannelUriStringBuilder clear()
    {
        prefix = null;
        media = null;
        endpoint = null;
        networkInterface = null;
        controlEndpoint = null;
        controlMode = null;
        tags = null;
        alias = null;
        reliable = null;
        ttl = null;
        mtu = null;
        termLength = null;
        initialTermId = null;
        termId = null;
        termOffset = null;
        sessionId = null;
        linger = null;
        sparse = null;
        eos = null;
        tether = null;
        isSessionIdTagged = false;

        return this;
    }

public ChannelUriStringBuilder clear ( ) { prefix = null ; media = null ; endpoint = null ; networkInterface = null ; controlEndpoint = null ; controlMode = null ; tags = null ; alias = null ; reliable = null ; ttl = null ; mtu = null ; termLength = null ; initialTermId = null ; termId = null ; termOffset = null ; sessionId = null ; linger = null ; sparse = null ; eos = null ; tether = null ; isSessionIdTagged = false ; return this ; }

Clear out all the values thus setting back to the initial state.

@return this for a fluent API.

Clear out all the values thus setting back to the initial state .


public ChannelUriStringBuilder validate()
    {
        if (null == media)
        {
            throw new IllegalStateException("media type is mandatory");
        }

        if (CommonContext.UDP_MEDIA.equals(media) && (null == endpoint && null == controlEndpoint))
        {
            throw new IllegalStateException("either 'endpoint' or 'control' must be specified for UDP.");
        }

        int count = 0;
        count += null == initialTermId ? 0 : 1;
        count += null == termId ? 0 : 1;
        count += null == termOffset ? 0 : 1;

        if (count > 0)
        {
            if (count < 3)
            {
                throw new IllegalStateException(
                    "if any of then a complete set of 'initialTermId', 'termId', and 'termOffset' must be provided");
            }

            if (termId - initialTermId < 0) // lgtm [java/dereferenced-value-may-be-null]
            {
                throw new IllegalStateException(
                    "difference greater than 2^31 - 1: termId=" + termId + " - initialTermId=" + initialTermId);
            }

            if (null != termLength && termOffset > termLength) // lgtm [java/dereferenced-value-may-be-null]
            {
                throw new IllegalStateException("termOffset=" + termOffset + " > termLength=" + termLength);
            }
        }

        return this;
    }

Validates that the collection of set parameters are valid together.

@return this for a fluent API.
@throws IllegalStateException if the combination of params is invalid.

Validates that the collection of set parameters are valid together .


public ChannelUriStringBuilder prefix(final String prefix)
    {
        if (null != prefix && !prefix.equals("") && !prefix.equals(SPY_QUALIFIER))
        {
            throw new IllegalArgumentException("invalid prefix: " + prefix);
        }

        this.prefix = prefix;
        return this;
    }

public
ChannelUriStringBuilder
prefix
(
final
String
prefix
)
{
if
(
!=
prefix
&&
!
prefix
.
equals
(
""
)
&&
!
prefix
.
equals
(
SPY_QUALIFIER
)
)
{
throw
new
IllegalArgumentException
(
"invalid prefix: "
+
prefix
)
;
}
this
.
prefix
=
prefix
;
return
this
;
}

Set the prefix for taking an addition action such as spying on an outgoing publication with "aeron-spy".

@param prefix to be applied to the URI before the the scheme.
@return this for a fluent API.
@see ChannelUri#SPY_QUALIFIER

Set the prefix for taking an addition action such as spying on an outgoing publication with aeron - spy .


public ChannelUriStringBuilder media(final String media)
    {
        switch (media)
        {
            case CommonContext.UDP_MEDIA:
            case CommonContext.IPC_MEDIA:
                break;

            default:
                throw new IllegalArgumentException("invalid media: " + media);
        }

        this.media = media;
        return this;
    }

public
ChannelUriStringBuilder
media
(
final
String
media
)
{
switch
(
media
)
{
case
CommonContext
.
UDP_MEDIA
:
case
CommonContext
.
IPC_MEDIA
:
break
;
default
:
throw
new
IllegalArgumentException
(
"invalid media: "
+
media
)
;
}
this
.
media
=
media
;
return
this
;
}

Set the media for this channel. Valid values are "udp" and "ipc".

@param media for this channel.
@return this for a fluent API.

Set the media for this channel . Valid values are udp and ipc .


public ChannelUriStringBuilder controlMode(final String controlMode)
    {
        if (null != controlMode &&
            !controlMode.equals(CommonContext.MDC_CONTROL_MODE_MANUAL) &&
            !controlMode.equals(CommonContext.MDC_CONTROL_MODE_DYNAMIC))
        {
            throw new IllegalArgumentException("invalid control mode: " + controlMode);
        }

        this.controlMode = controlMode;
        return this;
    }

public
ChannelUriStringBuilder
controlMode
(
final
String
controlMode
)
{
if
(
!=
controlMode
&&
!
controlMode
.
equals
(
CommonContext
.
MDC_CONTROL_MODE_MANUAL
)
&&
!
controlMode
.
equals
(
CommonContext
.
MDC_CONTROL_MODE_DYNAMIC
)
)
{
throw
new
IllegalArgumentException
(
"invalid control mode: "
+
controlMode
)
;
}
this
.
controlMode
=
controlMode
;
return
this
;
}

Set the control mode for multi-destination-cast. Set to "manual" for allowing control from the publication API.

@param controlMode for taking control of MDC.
@return this for a fluent API.
@see Publication#addDestination(String)
@see Publication#removeDestination(String)
@see CommonContext#MDC_CONTROL_MODE_PARAM_NAME
@see CommonContext#MDC_CONTROL_MODE_MANUAL
@see CommonContext#MDC_CONTROL_MODE_DYNAMIC

Set the control mode for multi - destination - cast . Set to manual for allowing control from the publication API .


public ChannelUriStringBuilder termLength(final Integer termLength)
    {
        if (null != termLength)
        {
            LogBufferDescriptor.checkTermLength(termLength);
        }

        this.termLength = termLength;
        return this;
    }

public ChannelUriStringBuilder termLength ( final Integer termLength ) { if ( null != termLength ) { LogBufferDescriptor . checkTermLength ( termLength ) ; } this . termLength = termLength ; return this ; }

Set the length of buffer used for each term of the log. Valid values are powers of 2 in the 64K - 1G range.

@param termLength of the buffer used for each term of the log.
@return this for a fluent API.
@see CommonContext#TERM_LENGTH_PARAM_NAME

Set the length of buffer used for each term of the log . Valid values are powers of 2 in the 64K - 1G range .


public ChannelUriStringBuilder termOffset(final Integer termOffset)
    {
        if (null != termOffset)
        {
            if ((termOffset < 0 || termOffset > LogBufferDescriptor.TERM_MAX_LENGTH))
            {
                throw new IllegalArgumentException("term offset not in range 0-1g: " + termOffset);
            }

            if (0 != (termOffset & (FRAME_ALIGNMENT - 1)))
            {
                throw new IllegalArgumentException("term offset not multiple of FRAME_ALIGNMENT: " + termOffset);
            }
        }

        this.termOffset = termOffset;
        return this;
    }

Set the offset within a term at which a publication will start. This when combined with the term id can establish
a starting position.

@param termOffset within a term at which a publication will start.
@return this for a fluent API.
@see CommonContext#TERM_OFFSET_PARAM_NAME

Set the offset within a term at which a publication will start . This when combined with the term id can establish a starting position .


public ChannelUriStringBuilder linger(final Long lingerNs)
    {
        if (null != lingerNs && lingerNs < 0)
        {
            throw new IllegalArgumentException("linger value cannot be negative: " + lingerNs);
        }

        this.linger = lingerNs;
        return this;
    }

public
ChannelUriStringBuilder
linger
(
final
Long
lingerNs
)
{
if
(
!=
lingerNs
&&
lingerNs
<
0
)
{
throw
new
IllegalArgumentException
(
"linger value cannot be negative: "
+
lingerNs
)
;
}
this
.
linger
=
lingerNs
;
return
this
;
}

Set the time a network publication will linger in nanoseconds after being drained. This time is so that tail loss
can be recovered.

@param lingerNs time for the publication after it is drained.
@return this for a fluent API.
@see CommonContext#LINGER_PARAM_NAME

Set the time a network publication will linger in nanoseconds after being drained . This time is so that tail loss can be recovered .


public void openDatagramChannel(final AtomicCounter statusIndicator)
    {
        try
        {
            sendDatagramChannel = DatagramChannel.open(udpChannel.protocolFamily());
            receiveDatagramChannel = sendDatagramChannel;

            if (udpChannel.isMulticast())
            {
                if (null != connectAddress)
                {
                    receiveDatagramChannel = DatagramChannel.open(udpChannel.protocolFamily());
                }

                receiveDatagramChannel.setOption(StandardSocketOptions.SO_REUSEADDR, true);
                receiveDatagramChannel.bind(new InetSocketAddress(endPointAddress.getPort()));
                receiveDatagramChannel.join(endPointAddress.getAddress(), udpChannel.localInterface());
                sendDatagramChannel.setOption(StandardSocketOptions.IP_MULTICAST_IF, udpChannel.localInterface());

                if (udpChannel.isHasMulticastTtl())
                {
                    sendDatagramChannel.setOption(StandardSocketOptions.IP_MULTICAST_TTL, udpChannel.multicastTtl());
                    multicastTtl = sendDatagramChannel.getOption(StandardSocketOptions.IP_MULTICAST_TTL);
                }
                else if (context.socketMulticastTtl() != 0)
                {
                    sendDatagramChannel.setOption(StandardSocketOptions.IP_MULTICAST_TTL, context.socketMulticastTtl());
                    multicastTtl = sendDatagramChannel.getOption(StandardSocketOptions.IP_MULTICAST_TTL);
                }
            }
            else
            {
                sendDatagramChannel.bind(bindAddress);
            }

            if (null != connectAddress)
            {
                sendDatagramChannel.connect(connectAddress);
            }

            if (0 != context.socketSndbufLength())
            {
                sendDatagramChannel.setOption(SO_SNDBUF, context.socketSndbufLength());
            }

            if (0 != context.socketRcvbufLength())
            {
                receiveDatagramChannel.setOption(SO_RCVBUF, context.socketRcvbufLength());
            }

            sendDatagramChannel.configureBlocking(false);
            receiveDatagramChannel.configureBlocking(false);
        }
        catch (final IOException ex)
        {
            if (null != statusIndicator)
            {
                statusIndicator.setOrdered(ChannelEndpointStatus.ERRORED);
            }

            CloseHelper.quietClose(sendDatagramChannel);
            if (receiveDatagramChannel != sendDatagramChannel)
            {
                CloseHelper.quietClose(receiveDatagramChannel);
            }

            sendDatagramChannel = null;
            receiveDatagramChannel = null;

            throw new AeronException(
                "channel error - " + ex.getMessage() +
                " (at " + ex.getStackTrace()[0].toString() + "): " +
                udpChannel.originalUriString(), ex);
        }
    }

public
void
openDatagramChannel
(
final
AtomicCounter
statusIndicator
)
{
try
{
sendDatagramChannel
=
DatagramChannel
.
open
(
udpChannel
.
protocolFamily
(
)
)
;
receiveDatagramChannel
=
sendDatagramChannel
;
if
(
udpChannel
.
isMulticast
(
)
)
{
if
(
!=
connectAddress
)
{
receiveDatagramChannel
=
DatagramChannel
.
open
(
udpChannel
.
protocolFamily
(
)
)
;
}
receiveDatagramChannel
.
setOption
(
StandardSocketOptions
.
SO_REUSEADDR
,
true
)
;
receiveDatagramChannel
.
bind
(
new
InetSocketAddress
(
endPointAddress
.
getPort
(
)
)
)
;
receiveDatagramChannel
.
join
(
endPointAddress
.
getAddress
(
)
,
udpChannel
.
localInterface
(
)
)
;
sendDatagramChannel
.
setOption
(
StandardSocketOptions
.
IP_MULTICAST_IF
,
udpChannel
.
localInterface
(
)
)
;
if
(
udpChannel
.
isHasMulticastTtl
(
)
)
{
sendDatagramChannel
.
setOption
(
StandardSocketOptions
.
IP_MULTICAST_TTL
,
udpChannel
.
multicastTtl
(
)
)
;
multicastTtl
=
sendDatagramChannel
.
getOption
(
StandardSocketOptions
.
IP_MULTICAST_TTL
)
;
}
else
if
(
context
.
socketMulticastTtl
(
)
!=
0
)
{
sendDatagramChannel
.
setOption
(
StandardSocketOptions
.
IP_MULTICAST_TTL
,
context
.
socketMulticastTtl
(
)
)
;
multicastTtl
=
sendDatagramChannel
.
getOption
(
StandardSocketOptions
.
IP_MULTICAST_TTL
)
;
}
}
else
{
sendDatagramChannel
.
bind
(
bindAddress
)
;
}
if
(
!=
connectAddress
)
{
sendDatagramChannel
.
connect
(
connectAddress
)
;
}
if
(
0
!=
context
.
socketSndbufLength
(
)
)
{
sendDatagramChannel
.
setOption
(
SO_SNDBUF
,
context
.
socketSndbufLength
(
)
)
;
}
if
(
0
!=
context
.
socketRcvbufLength
(
)
)
{
receiveDatagramChannel
.
setOption
(
SO_RCVBUF
,
context
.
socketRcvbufLength
(
)
)
;
}
sendDatagramChannel
.
configureBlocking
(
false
)
;
receiveDatagramChannel
.
configureBlocking
(
false
)
;
}
catch
(
final
IOException
ex
)
{
if
(
!=
statusIndicator
)
{
statusIndicator
.
setOrdered
(
ChannelEndpointStatus
.
ERRORED
)
;
}
CloseHelper
.
quietClose
(
sendDatagramChannel
)
;
if
(
receiveDatagramChannel
!=
sendDatagramChannel
)
{
CloseHelper
.
quietClose
(
receiveDatagramChannel
)
;
}
sendDatagramChannel
=
;
receiveDatagramChannel
=
;
throw
new
AeronException
(
"channel error - "
+
ex
.
getMessage
(
)
+
" (at "
+
ex
.
getStackTrace
(
)
[
0
]
.
toString
(
)
+
"): "
+
udpChannel
.
originalUriString
(
)
,
ex
)
;
}
}

Create the underlying channel for reading and writing.

@param statusIndicator to set for error status

Create the underlying channel for reading and writing .


public void close()
    {
        if (!isClosed)
        {
            isClosed = true;
            try
            {
                if (null != selectionKey)
                {
                    selectionKey.cancel();
                }

                if (null != transportPoller)
                {
                    transportPoller.cancelRead(this);
                    transportPoller.selectNowWithoutProcessing();
                }

                if (null != sendDatagramChannel)
                {
                    sendDatagramChannel.close();
                }

                if (receiveDatagramChannel != sendDatagramChannel && null != receiveDatagramChannel)
                {
                    receiveDatagramChannel.close();
                }

                if (null != transportPoller)
                {
                    transportPoller.selectNowWithoutProcessing();
                }
            }
            catch (final IOException ex)
            {
                errorLog.record(ex);
            }
        }
    }

public void close ( ) { if ( ! isClosed ) { isClosed = true ; try { if ( null != selectionKey ) { selectionKey . cancel ( ) ; } if ( null != transportPoller ) { transportPoller . cancelRead ( this ) ; transportPoller . selectNowWithoutProcessing ( ) ; } if ( null != sendDatagramChannel ) { sendDatagramChannel . close ( ) ; } if ( receiveDatagramChannel != sendDatagramChannel && null != receiveDatagramChannel ) { receiveDatagramChannel . close ( ) ; } if ( null != transportPoller ) { transportPoller . selectNowWithoutProcessing ( ) ; } } catch ( final IOException ex ) { errorLog . record ( ex ) ; } } }

Close transport, canceling any pending read operations and closing channel

Close transport canceling any pending read operations and closing channel


public boolean isValidFrame(final UnsafeBuffer buffer, final int length)
    {
        boolean isFrameValid = true;

        if (frameVersion(buffer, 0) != HeaderFlyweight.CURRENT_VERSION)
        {
            isFrameValid = false;
            invalidPackets.increment();
        }
        else if (length < HeaderFlyweight.MIN_HEADER_LENGTH)
        {
            isFrameValid = false;
            invalidPackets.increment();
        }

        return isFrameValid;
    }

public boolean isValidFrame ( final UnsafeBuffer buffer , final int length ) { boolean isFrameValid = true ; if ( frameVersion ( buffer , 0 ) != HeaderFlyweight . CURRENT_VERSION ) { isFrameValid = false ; invalidPackets . increment ( ) ; } else if ( length < HeaderFlyweight . MIN_HEADER_LENGTH ) { isFrameValid = false ; invalidPackets . increment ( ) ; } return isFrameValid ; }

Is the received frame valid. This method will do some basic checks on the header and can be
overridden in a subclass for further validation.

@param buffer containing the frame.
@param length of the frame.
@return true if the frame is believed valid otherwise false.

Is the received frame valid . This method will do some basic checks on the header and can be overridden in a subclass for further validation .


public InetSocketAddress receive(final ByteBuffer buffer)
    {
        buffer.clear();

        InetSocketAddress address = null;
        try
        {
            if (receiveDatagramChannel.isOpen())
            {
                address = (InetSocketAddress)receiveDatagramChannel.receive(buffer);
            }
        }
        catch (final PortUnreachableException ignored)
        {
        }
        catch (final Exception ex)
        {
            LangUtil.rethrowUnchecked(ex);
        }

        return address;
    }

public InetSocketAddress receive ( final ByteBuffer buffer ) { buffer . clear ( ) ; InetSocketAddress address = null ; try { if ( receiveDatagramChannel . isOpen ( ) ) { address = ( InetSocketAddress ) receiveDatagramChannel . receive ( buffer ) ; } } catch ( final PortUnreachableException ignored ) { } catch ( final Exception ex ) { LangUtil . rethrowUnchecked ( ex ) ; } return address ; }

Receive a datagram from the media layer.

@param buffer into which the datagram will be received.
@return the source address of the datagram if one is available otherwise false.

Receive a datagram from the media layer .


public void onNak(
        final int termId,
        final int termOffset,
        final int length,
        final int termLength,
        final RetransmitSender retransmitSender)
    {
        if (!isInvalid(termOffset, termLength))
        {
            if (null == activeRetransmitsMap.get(termId, termOffset) &&
                activeRetransmitsMap.size() < MAX_RETRANSMITS_DEFAULT)
            {
                final RetransmitAction action = assignRetransmitAction();
                action.termId = termId;
                action.termOffset = termOffset;
                action.length = Math.min(length, termLength - termOffset);

                final long delay = delayGenerator.generateDelay();
                if (0 == delay)
                {
                    retransmitSender.resend(termId, termOffset, action.length);
                    action.linger(lingerTimeoutGenerator.generateDelay(), nanoClock.nanoTime());
                }
                else
                {
                    action.delay(delay, nanoClock.nanoTime());
                }

                activeRetransmitsMap.put(termId, termOffset, action);
            }
        }
    }

public void onNak ( final int termId , final int termOffset , final int length , final int termLength , final RetransmitSender retransmitSender ) { if ( ! isInvalid ( termOffset , termLength ) ) { if ( null == activeRetransmitsMap . get ( termId , termOffset ) && activeRetransmitsMap . size ( ) < MAX_RETRANSMITS_DEFAULT ) { final RetransmitAction action = assignRetransmitAction ( ) ; action . termId = termId ; action . termOffset = termOffset ; action . length = Math . min ( length , termLength - termOffset ) ; final long delay = delayGenerator . generateDelay ( ) ; if ( 0 == delay ) { retransmitSender . resend ( termId , termOffset , action . length ) ; action . linger ( lingerTimeoutGenerator . generateDelay ( ) , nanoClock . nanoTime ( ) ) ; } else { action . delay ( delay , nanoClock . nanoTime ( ) ) ; } activeRetransmitsMap . put ( termId , termOffset , action ) ; } } }

Called on reception of a NAK to start retransmits handling.

@param termId           from the NAK and the term id of the buffer to retransmit from
@param termOffset       from the NAK and the offset of the data to retransmit
@param length           of the missing data
@param termLength       of the term buffer.
@param retransmitSender to call if an immediate retransmit is required

Called on reception of a NAK to start retransmits handling .


public void processTimeouts(final long nowNs, final RetransmitSender retransmitSender)
    {
        if (activeRetransmitsMap.size() > 0)
        {
            for (final RetransmitAction action : retransmitActionPool)
            {
                if (DELAYED == action.state && (action.expireNs - nowNs < 0))
                {
                    retransmitSender.resend(action.termId, action.termOffset, action.length);
                    action.linger(lingerTimeoutGenerator.generateDelay(), nanoClock.nanoTime());
                }
                else if (LINGERING == action.state && (action.expireNs - nowNs < 0))
                {
                    action.cancel();
                    activeRetransmitsMap.remove(action.termId, action.termOffset);
                }
            }
        }
    }

public void processTimeouts ( final long nowNs , final RetransmitSender retransmitSender ) { if ( activeRetransmitsMap . size ( ) > 0 ) { for ( final RetransmitAction action : retransmitActionPool ) { if ( DELAYED == action . state && ( action . expireNs - nowNs < 0 ) ) { retransmitSender . resend ( action . termId , action . termOffset , action . length ) ; action . linger ( lingerTimeoutGenerator . generateDelay ( ) , nanoClock . nanoTime ( ) ) ; } else if ( LINGERING == action . state && ( action . expireNs - nowNs < 0 ) ) { action . cancel ( ) ; activeRetransmitsMap . remove ( action . termId , action . termOffset ) ; } } } }

Called to process any outstanding timeouts.

@param nowNs            time in nanoseconds
@param retransmitSender to call on retransmissions

Called to process any outstanding timeouts .


public static String status(final long status)
    {
        if (INITIALIZING == status)
        {
            return "INITIALIZING";
        }

        if (ERRORED == status)
        {
            return "ERRORED";
        }

        if (ACTIVE == status)
        {
            return "ACTIVE";
        }

        if (CLOSING == status)
        {
            return "CLOSING";
        }

        return "unknown id=" + status;
    }

public
static
String
status
(
final
long
status
)
{
if
(
INITIALIZING
==
status
)
{
return
"INITIALIZING"
;
}
if
(
ERRORED
==
status
)
{
return
"ERRORED"
;
}
if
(
ACTIVE
==
status
)
{
return
"ACTIVE"
;
}
if
(
CLOSING
==
status
)
{
return
"CLOSING"
;
}
return
"unknown id="
+
status
;
}

String representation of the channel status.

@param status to be converted.
@return representation of the channel status.

String representation of the channel status .


public static AtomicCounter allocate(
        final MutableDirectBuffer tempBuffer,
        final String name,
        final int typeId,
        final CountersManager countersManager,
        final String channel)
    {
        final int keyLength = tempBuffer.putStringWithoutLengthAscii(
            CHANNEL_OFFSET + SIZE_OF_INT, channel, 0, MAX_CHANNEL_LENGTH);
        tempBuffer.putInt(CHANNEL_OFFSET, keyLength);

        int labelLength = 0;
        labelLength += tempBuffer.putStringWithoutLengthAscii(keyLength + labelLength, name);
        labelLength += tempBuffer.putStringWithoutLengthAscii(keyLength + labelLength, ": ");
        labelLength += tempBuffer.putStringWithoutLengthAscii(
            keyLength + labelLength, channel, 0, MAX_LABEL_LENGTH - labelLength);

        return countersManager.newCounter(typeId, tempBuffer, 0, keyLength, tempBuffer, keyLength, labelLength);
    }

public
static
AtomicCounter
allocate
(
final
MutableDirectBuffer
tempBuffer
,
final
String
name
,
final
int
typeId
,
final
CountersManager
countersManager
,
final
String
channel
)
{
final
int
keyLength
=
tempBuffer
.
putStringWithoutLengthAscii
(
CHANNEL_OFFSET
+
SIZE_OF_INT
,
channel
,
0
,
MAX_CHANNEL_LENGTH
)
;
tempBuffer
.
putInt
(
CHANNEL_OFFSET
,
keyLength
)
;
int
labelLength
=
0
;
labelLength
+=
tempBuffer
.
putStringWithoutLengthAscii
(
keyLength
+
labelLength
,
name
)
;
labelLength
+=
tempBuffer
.
putStringWithoutLengthAscii
(
keyLength
+
labelLength
,
": "
)
;
labelLength
+=
tempBuffer
.
putStringWithoutLengthAscii
(
keyLength
+
labelLength
,
channel
,
0
,
MAX_LABEL_LENGTH
labelLength
)
;
return
countersManager
.
newCounter
(
typeId
,
tempBuffer
,
0
,
keyLength
,
tempBuffer
,
keyLength
,
labelLength
)
;
}

Allocate an indicator for tracking the status of a channel endpoint.

@param tempBuffer      to be used for labels and metadata.
@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 channel         for the stream of messages.
@return a new {@link AtomicCounter} for tracking the status.

Allocate an indicator for tracking the status of a channel endpoint .


public DirectBufferVector reset(final DirectBuffer buffer, final int offset, final int length)
    {
        this.buffer = buffer;
        this.offset = offset;
        this.length = length;

        return this;
    }

public DirectBufferVector reset ( final DirectBuffer buffer , final int offset , final int length ) { this . buffer = buffer ; this . offset = offset ; this . length = length ; return this ; }

Reset the values.

@param buffer which is the super set.
@param offset at which the vector begins.
@param length of the vector.
@return this for a fluent API.


public DirectBufferVector validate()
    {
        final int capacity = buffer.capacity();
        if (offset < 0 || offset >= capacity)
        {
            throw new IllegalArgumentException("offset=" + offset + " capacity=" + capacity);
        }

        if (length < 0 || length > (capacity - offset))
        {
            throw new IllegalArgumentException("offset=" + offset + " capacity=" + capacity + " length=" + length);
        }

        return this;
    }

public
DirectBufferVector
validate
(
)
{
final
int
capacity
=
buffer
.
capacity
(
)
;
if
(
offset
<
0
||
offset
>=
capacity
)
{
throw
new
IllegalArgumentException
(
"offset="
+
offset
+
" capacity="
+
capacity
)
;
}
if
(
length
<
0
||
length
>
(
capacity
offset
)
)
{
throw
new
IllegalArgumentException
(
"offset="
+
offset
+
" capacity="
+
capacity
+
" length="
+
length
)
;
}
return
this
;
}

Ensure the vector is valid for the buffer.

@throws NullPointerException if the buffer is null.
@throws IllegalArgumentException if the offset is out of range for the buffer.
@throws IllegalArgumentException if the length is out of range for the buffer.
@return this for a fluent API.

Ensure the vector is valid for the buffer .


public static int validateAndComputeLength(final DirectBufferVector[] vectors)
    {
        int messageLength = 0;
        for (final DirectBufferVector vector : vectors)
        {
            vector.validate();
            messageLength += vector.length;

            if (messageLength < 0)
            {
                throw new IllegalStateException("length overflow: " + Arrays.toString(vectors));
            }
        }

        return messageLength;
    }

public
static
int
validateAndComputeLength
(
final
DirectBufferVector
[
]
vectors
)
{
int
messageLength
=
0
;
for
(
final
DirectBufferVector
vector
:
vectors
)
{
vector
.
validate
(
)
;
messageLength
+=
vector
.
length
;
if
(
messageLength
<
0
)
{
throw
new
IllegalStateException
(
"length overflow: "
+
Arrays
.
toString
(
vectors
)
)
;
}
}
return
messageLength
;
}

Validate an array of vectors to make up a message and compute the total length.

@param vectors to be validated summed.
@return the sum of the vector lengths.

Validate an array of vectors to make up a message and compute the total length .


public static int producerWindowLength(final int termBufferLength, final int defaultTermWindowLength)
    {
        int termWindowLength = termBufferLength / 2;

        if (0 != defaultTermWindowLength)
        {
            termWindowLength = Math.min(defaultTermWindowLength, termWindowLength);
        }

        return termWindowLength;
    }

public static int producerWindowLength ( final int termBufferLength , final int defaultTermWindowLength ) { int termWindowLength = termBufferLength / 2 ; if ( 0 != defaultTermWindowLength ) { termWindowLength = Math . min ( defaultTermWindowLength , termWindowLength ) ; } return termWindowLength ; }

How far ahead a producer can get from a consumer position.

@param termBufferLength        for when default is not set and considering an appropriate minimum.
@param defaultTermWindowLength to take priority.
@return the length to be used for the producer window.

How far ahead a producer can get from a consumer position .


public static void validateSocketBufferLengths(final MediaDriver.Context ctx)
    {
        try (DatagramChannel probe = DatagramChannel.open())
        {
            final int defaultSoSndBuf = probe.getOption(StandardSocketOptions.SO_SNDBUF);

            probe.setOption(StandardSocketOptions.SO_SNDBUF, Integer.MAX_VALUE);
            final int maxSoSndBuf = probe.getOption(StandardSocketOptions.SO_SNDBUF);

            if (maxSoSndBuf < ctx.socketSndbufLength())
            {
                System.err.format(
                    "WARNING: Could not get desired SO_SNDBUF, adjust OS to allow %s: attempted=%d, actual=%d%n",
                    SOCKET_SNDBUF_LENGTH_PROP_NAME,
                    ctx.socketSndbufLength(),
                    maxSoSndBuf);
            }

            probe.setOption(StandardSocketOptions.SO_RCVBUF, Integer.MAX_VALUE);
            final int maxSoRcvBuf = probe.getOption(StandardSocketOptions.SO_RCVBUF);

            if (maxSoRcvBuf < ctx.socketRcvbufLength())
            {
                System.err.format(
                    "WARNING: Could not get desired SO_RCVBUF, adjust OS to allow %s: attempted=%d, actual=%d%n",
                    SOCKET_RCVBUF_LENGTH_PROP_NAME,
                    ctx.socketRcvbufLength(),
                    maxSoRcvBuf);
            }

            final int soSndBuf = 0 == ctx.socketSndbufLength() ? defaultSoSndBuf : ctx.socketSndbufLength();

            if (ctx.mtuLength() > soSndBuf)
            {
                throw new ConfigurationException(String.format(
                    "MTU greater than socket SO_SNDBUF, adjust %s to match MTU: mtuLength=%d, SO_SNDBUF=%d",
                    SOCKET_SNDBUF_LENGTH_PROP_NAME,
                    ctx.mtuLength(),
                    soSndBuf));
            }

            if (ctx.initialWindowLength() > maxSoRcvBuf)
            {
                throw new ConfigurationException("window length greater than socket SO_RCVBUF, increase '" +
                    Configuration.INITIAL_WINDOW_LENGTH_PROP_NAME +
                    "' to match window: windowLength=" + ctx.initialWindowLength() + ", SO_RCVBUF=" + maxSoRcvBuf);
            }
        }
        catch (final IOException ex)
        {
            throw new AeronException("probe socket: " + ex.toString(), ex);
        }
    }

Validate that the socket buffer lengths are sufficient for the media driver configuration.

@param ctx to be validated.

Validate that the socket buffer lengths are sufficient for the media driver configuration .


public static void validatePageSize(final int pageSize)
    {
        if (pageSize < PAGE_MIN_SIZE)
        {
            throw new ConfigurationException(
                "page size less than min size of " + PAGE_MIN_SIZE + ": " + pageSize);
        }

        if (pageSize > PAGE_MAX_SIZE)
        {
            throw new ConfigurationException(
                "page size greater than max size of " + PAGE_MAX_SIZE + ": " + pageSize);
        }

        if (!BitUtil.isPowerOfTwo(pageSize))
        {
            throw new ConfigurationException("page size not a power of 2: " + pageSize);
        }
    }

public
static
void
validatePageSize
(
final
int
pageSize
)
{
if
(
pageSize
<
PAGE_MIN_SIZE
)
{
throw
new
ConfigurationException
(
"page size less than min size of "
+
PAGE_MIN_SIZE
+
": "
+
pageSize
)
;
}
if
(
pageSize
>
PAGE_MAX_SIZE
)
{
throw
new
ConfigurationException
(
"page size greater than max size of "
+
PAGE_MAX_SIZE
+
": "
+
pageSize
)
;
}
if
(
!
BitUtil
.
isPowerOfTwo
(
pageSize
)
)
{
throw
new
ConfigurationException
(
"page size not a power of 2: "
+
pageSize
)
;
}
}

Validate that page size is valid and alignment is valid.

@param pageSize to be checked.
@throws ConfigurationException if the size is not as expected.

Validate that page size is valid and alignment is valid .


public static void validateSessionIdRange(final int low, final int high)
    {
        if (low > high)
        {
            throw new ConfigurationException("low session id value " + low + " must be <= high value " + high);
        }

        if (Math.abs((long)high - low) > Integer.MAX_VALUE)
        {
            throw new ConfigurationException("reserved range to too large");
        }
    }

public
static
void
validateSessionIdRange
(
final
int
low
,
final
int
high
)
{
if
(
low
>
high
)
{
throw
new
ConfigurationException
(
"low session id value "
+
low
+
" must be <= high value "
+
high
)
;
}
if
(
Math
.
abs
(
(
long
)
high
low
)
>
Integer
.
MAX_VALUE
)
{
throw
new
ConfigurationException
(
"reserved range to too large"
)
;
}
}

Validate the range of session ids based on a high and low value provided which accounts for the values wrapping.

@param low  value in the range.
@param high value in the range.
@throws ConfigurationException if the values are not valid.

Validate the range of session ids based on a high and low value provided which accounts for the values wrapping .


public static void validateUnblockTimeout(
        final long publicationUnblockTimeoutNs, final long clientLivenessTimeoutNs, final long timerIntervalNs)
    {
        if (publicationUnblockTimeoutNs <= clientLivenessTimeoutNs)
        {
            throw new ConfigurationException(
                "publicationUnblockTimeoutNs=" + publicationUnblockTimeoutNs +
                " <= clientLivenessTimeoutNs=" + clientLivenessTimeoutNs);
        }

        if (clientLivenessTimeoutNs <= timerIntervalNs)
        {
            throw new ConfigurationException(
                "clientLivenessTimeoutNs=" + clientLivenessTimeoutNs +
                " <= timerIntervalNs=" + timerIntervalNs);
        }
    }

public
static
void
validateUnblockTimeout
(
final
long
publicationUnblockTimeoutNs
,
final
long
clientLivenessTimeoutNs
,
final
long
timerIntervalNs
)
{
if
(
publicationUnblockTimeoutNs
<=
clientLivenessTimeoutNs
)
{
throw
new
ConfigurationException
(
"publicationUnblockTimeoutNs="
+
publicationUnblockTimeoutNs
+
" <= clientLivenessTimeoutNs="
+
clientLivenessTimeoutNs
)
;
}
if
(
clientLivenessTimeoutNs
<=
timerIntervalNs
)
{
throw
new
ConfigurationException
(
"clientLivenessTimeoutNs="
+
clientLivenessTimeoutNs
+
" <= timerIntervalNs="
+
timerIntervalNs
)
;
}
}

Validate that the timeouts for unblocking publications from a client are valid.

@param publicationUnblockTimeoutNs after which an uncommitted publication will be unblocked.
@param clientLivenessTimeoutNs     after which a client will be considered not alive.
@param timerIntervalNs             interval at which the driver will check timeouts.
@throws ConfigurationException if the values are not valid.

Validate that the timeouts for unblocking publications from a client are valid .


public ErrorResponseFlyweight errorCode(final ErrorCode code)
    {
        buffer.putInt(offset + ERROR_CODE_OFFSET, code.value());
        return this;
    }

public ErrorResponseFlyweight errorCode ( final ErrorCode code ) { buffer . putInt ( offset + ERROR_CODE_OFFSET , code . value ( ) ) ; return this ; }

Set the error code for the command.

@param code for the error
@return flyweight


public void reset()
    {
        isBallotSent = false;
        isLeader = false;
        hasRequestedJoin = false;
        hasSentTerminationAck = false;
        vote = null;
        candidateTermId = Aeron.NULL_VALUE;
        leadershipTermId = Aeron.NULL_VALUE;
        logPosition = NULL_POSITION;
    }

public void reset ( ) { isBallotSent = false ; isLeader = false ; hasRequestedJoin = false ; hasSentTerminationAck = false ; vote = null ; candidateTermId = Aeron . NULL_VALUE ; leadershipTermId = Aeron . NULL_VALUE ; logPosition = NULL_POSITION ; }

Reset the state of a cluster member so it can be canvassed and reestablished.

Reset the state of a cluster member so it can be canvassed and reestablished .


public static String encodeAsString(final ClusterMember[] clusterMembers)
    {
        final StringBuilder builder = new StringBuilder();

        for (int i = 0, length = clusterMembers.length; i < length; i++)
        {
            final ClusterMember member = clusterMembers[i];

            builder
                .append(member.id())
                .append(',')
                .append(member.endpointsDetail());

            if ((length - 1) != i)
            {
                builder.append('|');
            }
        }

        return builder.toString();
    }

public static String encodeAsString ( final ClusterMember [ ] clusterMembers ) { final StringBuilder builder = new StringBuilder ( ) ; for ( int i = 0 , length = clusterMembers . length ; i < length ; i ++ ) { final ClusterMember member = clusterMembers [ i ] ; builder . append ( member . id ( ) ) . append ( ' ' ) . append ( member . endpointsDetail ( ) ) ; if ( ( length - 1 ) != i ) { builder . append ( ' ' ) ; } } return builder . toString ( ) ; }

Encode member details from a cluster members array to a string.

@param clusterMembers to fill the details from
@return String representation suitable for use with {@link ClusterMember#parse}

Encode member details from a cluster members array to a string .


public static void addMemberStatusPublications(
        final ClusterMember[] members,
        final ClusterMember exclude,
        final ChannelUri channelUri,
        final int streamId,
        final Aeron aeron)
    {
        for (final ClusterMember member : members)
        {
            if (member != exclude)
            {
                channelUri.put(ENDPOINT_PARAM_NAME, member.memberFacingEndpoint());
                member.publication = aeron.addExclusivePublication(channelUri.toString(), streamId);
            }
        }
    }

public static void addMemberStatusPublications ( final ClusterMember [ ] members , final ClusterMember exclude , final ChannelUri channelUri , final int streamId , final Aeron aeron ) { for ( final ClusterMember member : members ) { if ( member != exclude ) { channelUri . put ( ENDPOINT_PARAM_NAME , member . memberFacingEndpoint ( ) ) ; member . publication = aeron . addExclusivePublication ( channelUri . toString ( ) , streamId ) ; } } }

Add the publications for sending status messages to the other members of the cluster.

@param members    of the cluster.
@param exclude    this member when adding publications.
@param channelUri for the publication.
@param streamId   for the publication.
@param aeron      to add the publications to.

Add the publications for sending status messages to the other members of the cluster .


public static void closeMemberPublications(final ClusterMember[] clusterMembers)
    {
        for (final ClusterMember member : clusterMembers)
        {
            CloseHelper.close(member.publication);
        }
    }

public static void closeMemberPublications ( final ClusterMember [ ] clusterMembers ) { for ( final ClusterMember member : clusterMembers ) { CloseHelper . close ( member . publication ) ; } }

Close the publications associated with members of the cluster.

@param clusterMembers to close the publications for.

Close the publications associated with members of the cluster .


public static boolean hasActiveQuorum(
        final ClusterMember[] clusterMembers, final long nowMs, final long timeoutMs)
    {
        int threshold = quorumThreshold(clusterMembers.length);

        for (final ClusterMember member : clusterMembers)
        {
            if (member.isLeader() || nowMs <= (member.timeOfLastAppendPositionMs() + timeoutMs))
            {
                if (--threshold <= 0)
                {
                    return true;
                }
            }
        }

        return false;
    }

public static boolean hasActiveQuorum ( final ClusterMember [ ] clusterMembers , final long nowMs , final long timeoutMs ) { int threshold = quorumThreshold ( clusterMembers . length ) ; for ( final ClusterMember member : clusterMembers ) { if ( member . isLeader ( ) || nowMs <= ( member . timeOfLastAppendPositionMs ( ) + timeoutMs ) ) { if ( -- threshold <= 0 ) { return true ; } } } return false ; }

Check if the cluster leader has an active quorum of cluster followers.

@param clusterMembers for the current cluster.
@param nowMs          for the current time.
@param timeoutMs      after which a follower is not considered active.
@return true if quorum of cluster members are considered active.

Check if the cluster leader has an active quorum of cluster followers .


public static long quorumPosition(final ClusterMember[] members, final long[] rankedPositions)
    {
        final int length = rankedPositions.length;
        for (int i = 0; i < length; i++)
        {
            rankedPositions[i] = 0;
        }

        for (final ClusterMember member : members)
        {
            long newPosition = member.logPosition;

            for (int i = 0; i < length; i++)
            {
                final long rankedPosition = rankedPositions[i];

                if (newPosition > rankedPosition)
                {
                    rankedPositions[i] = newPosition;
                    newPosition = rankedPosition;
                }
            }
        }

        return rankedPositions[length - 1];
    }

public static long quorumPosition ( final ClusterMember [ ] members , final long [ ] rankedPositions ) { final int length = rankedPositions . length ; for ( int i = 0 ; i < length ; i ++ ) { rankedPositions [ i ] = 0 ; } for ( final ClusterMember member : members ) { long newPosition = member . logPosition ; for ( int i = 0 ; i < length ; i ++ ) { final long rankedPosition = rankedPositions [ i ] ; if ( newPosition > rankedPosition ) { rankedPositions [ i ] = newPosition ; newPosition = rankedPosition ; } } } return rankedPositions [ length - 1 ] ; }

Calculate the position reached by a quorum of cluster members.

@param members         of the cluster.
@param rankedPositions temp array to be used for sorting the positions to avoid allocation.
@return the position reached by a quorum of cluster members.

Calculate the position reached by a quorum of cluster members .


public static void resetLogPositions(final ClusterMember[] clusterMembers, final long logPosition)
    {
        for (final ClusterMember member : clusterMembers)
        {
            member.logPosition(logPosition);
        }
    }

public static void resetLogPositions ( final ClusterMember [ ] clusterMembers , final long logPosition ) { for ( final ClusterMember member : clusterMembers ) { member . logPosition ( logPosition ) ; } }

Reset the log position of all the members to the provided value.

@param clusterMembers to be reset.
@param logPosition    to set for them all.

Reset the log position of all the members to the provided value .


public static boolean haveVotersReachedPosition(
        final ClusterMember[] clusterMembers, final long position, final long leadershipTermId)
    {
        for (final ClusterMember member : clusterMembers)
        {
            if (member.vote != null && (member.logPosition < position || member.leadershipTermId != leadershipTermId))
            {
                return false;
            }
        }

        return true;
    }

public static boolean haveVotersReachedPosition ( final ClusterMember [ ] clusterMembers , final long position , final long leadershipTermId ) { for ( final ClusterMember member : clusterMembers ) { if ( member . vote != null && ( member . logPosition < position || member . leadershipTermId != leadershipTermId ) ) { return false ; } } return true ; }

Has the members of the cluster the voted reached the provided position in their log.

@param clusterMembers   to check.
@param position         to compare the {@link #logPosition()} against.
@param leadershipTermId expected of the members.
@return true if all members have reached this position otherwise false.

Has the members of the cluster the voted reached the provided position in their log .


public static boolean hasWonVoteOnFullCount(final ClusterMember[] members, final long candidateTermId)
    {
        int votes = 0;

        for (final ClusterMember member : members)
        {
            if (null == member.vote || member.candidateTermId != candidateTermId)
            {
                return false;
            }

            votes += member.vote ? 1 : 0;
        }

        return votes >= ClusterMember.quorumThreshold(members.length);
    }

public static boolean hasWonVoteOnFullCount ( final ClusterMember [ ] members , final long candidateTermId ) { int votes = 0 ; for ( final ClusterMember member : members ) { if ( null == member . vote || member . candidateTermId != candidateTermId ) { return false ; } votes += member . vote ? 1 : 0 ; } return votes >= ClusterMember . quorumThreshold ( members . length ) ; }

Has the candidate got unanimous support of the cluster?

@param members         to check for votes.
@param candidateTermId for the vote.
@return false if any member has not voted for the candidate.


public static boolean hasMajorityVote(final ClusterMember[] clusterMembers, final long candidateTermId)
    {
        int votes = 0;
        for (final ClusterMember member : clusterMembers)
        {
            if (Boolean.TRUE.equals(member.vote) && member.candidateTermId == candidateTermId)
            {
                ++votes;
            }
        }

        return votes >= ClusterMember.quorumThreshold(clusterMembers.length);
    }

public static boolean hasMajorityVote ( final ClusterMember [ ] clusterMembers , final long candidateTermId ) { int votes = 0 ; for ( final ClusterMember member : clusterMembers ) { if ( Boolean . TRUE . equals ( member . vote ) && member . candidateTermId == candidateTermId ) { ++ votes ; } } return votes >= ClusterMember . quorumThreshold ( clusterMembers . length ) ; }

Has sufficient votes being counted for a majority?

@param clusterMembers  to check for votes.
@param candidateTermId for the vote.
@return true if a majority of positive votes.


public static ClusterMember determineMember(
        final ClusterMember[] clusterMembers, final int memberId, final String memberEndpoints)
    {
        ClusterMember member = NULL_VALUE != memberId ? ClusterMember.findMember(clusterMembers, memberId) : null;

        if ((null == clusterMembers || 0 == clusterMembers.length) && null == member)
        {
            member = ClusterMember.parseEndpoints(NULL_VALUE, memberEndpoints);
        }
        else
        {
            if (null == member)
            {
                throw new ClusterException("memberId=" + memberId + " not found in clusterMembers");
            }

            if (!"".equals(memberEndpoints))
            {
                ClusterMember.validateMemberEndpoints(member, memberEndpoints);
            }
        }

        return member;
    }

public
static
ClusterMember
determineMember
(
final
ClusterMember
[
]
clusterMembers
,
final
int
memberId
,
final
String
memberEndpoints
)
{
ClusterMember
member
=
NULL_VALUE
!=
memberId
ClusterMember
.
findMember
(
clusterMembers
,
memberId
)
:
;
if
(
(
==
clusterMembers
||
0
==
clusterMembers
.
length
)
&&
==
member
)
{
member
=
ClusterMember
.
parseEndpoints
(
NULL_VALUE
,
memberEndpoints
)
;
}
else
{
if
(
==
member
)
{
throw
new
ClusterException
(
"memberId="
+
memberId
+
" not found in clusterMembers"
)
;
}
if
(
!
""
.
equals
(
memberEndpoints
)
)
{
ClusterMember
.
validateMemberEndpoints
(
member
,
memberEndpoints
)
;
}
}
return
member
;
}

Determine which member of a cluster this is and check endpoints.

@param clusterMembers  for the current cluster which can be null.
@param memberId        for this member.
@param memberEndpoints for this member.
@return the {@link ClusterMember} determined.

Determine which member of a cluster this is and check endpoints .


public static void validateMemberEndpoints(final ClusterMember member, final String memberEndpoints)
    {
        final ClusterMember endpointMember = ClusterMember.parseEndpoints(Aeron.NULL_VALUE, memberEndpoints);

        if (!areSameEndpoints(member, endpointMember))
        {
            throw new ClusterException(
                "clusterMembers and memberEndpoints differ: " + member.endpointsDetail() + " != " + memberEndpoints);
        }
    }

Check the member with the memberEndpoints

@param member          to check memberEndpoints against
@param memberEndpoints to check member against
@see ConsensusModule.Context#memberEndpoints()
@see ConsensusModule.Context#clusterMembers()


public static boolean areSameEndpoints(final ClusterMember lhs, final ClusterMember rhs)
    {
        return lhs.clientFacingEndpoint().equals(rhs.clientFacingEndpoint()) &&
            lhs.memberFacingEndpoint().equals(rhs.memberFacingEndpoint()) &&
            lhs.logEndpoint().equals(rhs.logEndpoint()) &&
            lhs.transferEndpoint().equals(rhs.transferEndpoint()) &&
            lhs.archiveEndpoint().equals(rhs.archiveEndpoint());
    }

public static boolean areSameEndpoints ( final ClusterMember lhs , final ClusterMember rhs ) { return lhs . clientFacingEndpoint ( ) . equals ( rhs . clientFacingEndpoint ( ) ) && lhs . memberFacingEndpoint ( ) . equals ( rhs . memberFacingEndpoint ( ) ) && lhs . logEndpoint ( ) . equals ( rhs . logEndpoint ( ) ) && lhs . transferEndpoint ( ) . equals ( rhs . transferEndpoint ( ) ) && lhs . archiveEndpoint ( ) . equals ( rhs . archiveEndpoint ( ) ) ; }

Are two cluster members using the same endpoints?

@param lhs to check
@param rhs to check
@return true if both are using the same endpoints or false if not.


public static boolean isUnanimousCandidate(final ClusterMember[] clusterMembers, final ClusterMember candidate)
    {
        for (final ClusterMember member : clusterMembers)
        {
            if (NULL_POSITION == member.logPosition || compareLog(candidate, member) < 0)
            {
                return false;
            }
        }

        return true;
    }

public static boolean isUnanimousCandidate ( final ClusterMember [ ] clusterMembers , final ClusterMember candidate ) { for ( final ClusterMember member : clusterMembers ) { if ( NULL_POSITION == member . logPosition || compareLog ( candidate , member ) < 0 ) { return false ; } } return true ; }

Has the member achieved a unanimous view to be a suitable candidate in an election.

@param clusterMembers to compare the candidate against.
@param candidate      for leadership.
@return true if the candidate is suitable otherwise false.

Has the member achieved a unanimous view to be a suitable candidate in an election .


public static boolean isQuorumCandidate(final ClusterMember[] clusterMembers, final ClusterMember candidate)
    {
        int possibleVotes = 0;
        for (final ClusterMember member : clusterMembers)
        {
            if (NULL_POSITION == member.logPosition || compareLog(candidate, member) < 0)
            {
                continue;
            }

            ++possibleVotes;
        }

        return possibleVotes >= ClusterMember.quorumThreshold(clusterMembers.length);
    }

public static boolean isQuorumCandidate ( final ClusterMember [ ] clusterMembers , final ClusterMember candidate ) { int possibleVotes = 0 ; for ( final ClusterMember member : clusterMembers ) { if ( NULL_POSITION == member . logPosition || compareLog ( candidate , member ) < 0 ) { continue ; } ++ possibleVotes ; } return possibleVotes >= ClusterMember . quorumThreshold ( clusterMembers . length ) ; }

Has the member achieved a quorum view to be a suitable candidate in an election.

@param clusterMembers to compare the candidate against.
@param candidate      for leadership.
@return true if the candidate is suitable otherwise false.

Has the member achieved a quorum view to be a suitable candidate in an election .