public static boolean isNotDuplicateEndpoints(final ClusterMember[] members, final String memberEndpoints)
    {
        for (final ClusterMember member : members)
        {
            if (member.endpointsDetail().equals(memberEndpoints))
            {
                return false;
            }
        }

        return true;
    }

public static boolean isNotDuplicateEndpoints ( final ClusterMember [ ] members , final String memberEndpoints ) { for ( final ClusterMember member : members ) { if ( member . endpointsDetail ( ) . equals ( memberEndpoints ) ) { return false ; } } return true ; }

Is the string of member endpoints not duplicated in the members.

@param members         to check if the provided endpoints have a duplicate.
@param memberEndpoints to check for duplicates.
@return true if no duplicate is found otherwise false.

Is the string of member endpoints not duplicated in the members .


public static int findMemberIndex(final ClusterMember[] clusterMembers, final int memberId)
    {
        final int length = clusterMembers.length;
        int index = ArrayUtil.UNKNOWN_INDEX;

        for (int i = 0; i < length; i++)
        {
            if (clusterMembers[i].id() == memberId)
            {
                index = i;
            }
        }

        return index;
    }

public static int findMemberIndex ( final ClusterMember [ ] clusterMembers , final int memberId ) { final int length = clusterMembers . length ; int index = ArrayUtil . UNKNOWN_INDEX ; for ( int i = 0 ; i < length ; i ++ ) { if ( clusterMembers [ i ] . id ( ) == memberId ) { index = i ; } } return index ; }

Find the index at which a member id is present.

@param clusterMembers to be searched.
@param memberId       to search for.
@return the index at which the member id is found otherwise {@link ArrayUtil#UNKNOWN_INDEX}.

Find the index at which a member id is present .


public static ClusterMember[] removeMember(final ClusterMember[] oldMembers, final int memberId)
    {
        return ArrayUtil.remove(oldMembers, findMemberIndex(oldMembers, memberId));
    }

public static ClusterMember [ ] removeMember ( final ClusterMember [ ] oldMembers , final int memberId ) { return ArrayUtil . remove ( oldMembers , findMemberIndex ( oldMembers , memberId ) ) ; }

Remove a member from an array if found, otherwise return the array unmodified.

@param oldMembers to remove a member from.
@param memberId   of the member to remove.
@return a new array with the member removed or the existing array if not found.

Remove a member from an array if found otherwise return the array unmodified .


public static int highMemberId(final ClusterMember[] clusterMembers)
    {
        int highId = Aeron.NULL_VALUE;

        for (final ClusterMember member : clusterMembers)
        {
            highId = Math.max(highId, member.id());
        }

        return highId;
    }

public static int highMemberId ( final ClusterMember [ ] clusterMembers ) { int highId = Aeron . NULL_VALUE ; for ( final ClusterMember member : clusterMembers ) { highId = Math . max ( highId , member . id ( ) ) ; } return highId ; }

Find the highest member id in an array of members.

@param clusterMembers to search for the highest id.
@return the highest id otherwise {@link Aeron#NULL_VALUE} if empty.

Find the highest member id in an array of members .


public MappedByteBuffer mapExistingCncFile(final Consumer<String> logger)
    {
        final File cncFile = new File(aeronDirectory, CncFileDescriptor.CNC_FILE);

        if (cncFile.exists() && cncFile.length() > 0)
        {
            if (null != logger)
            {
                logger.accept("INFO: Aeron CnC file exists: " + cncFile);
            }

            return IoUtil.mapExistingFile(cncFile, CncFileDescriptor.CNC_FILE);
        }

        return null;
    }

public
MappedByteBuffer
mapExistingCncFile
(
final
Consumer
<
String
>
logger
)
{
final
File
cncFile
=
new
File
(
aeronDirectory
,
CncFileDescriptor
.
CNC_FILE
)
;
if
(
cncFile
.
exists
(
)
&&
cncFile
.
length
(
)
>
0
)
{
if
(
!=
logger
)
{
logger
.
accept
(
"INFO: Aeron CnC file exists: "
+
cncFile
)
;
}
return
IoUtil
.
mapExistingFile
(
cncFile
,
CncFileDescriptor
.
CNC_FILE
)
;
}
return
;
}

Map the CnC file if it exists.

@param logger for feedback
@return a new mapping for the file if it exists otherwise null;


public static boolean isDriverActive(
        final File directory, final long driverTimeoutMs, final Consumer<String> logger)
    {
        final File cncFile = new File(directory, CncFileDescriptor.CNC_FILE);

        if (cncFile.exists() && cncFile.length() > 0)
        {
            logger.accept("INFO: Aeron CnC file exists: " + cncFile);

            final MappedByteBuffer cncByteBuffer = IoUtil.mapExistingFile(cncFile, "CnC file");
            try
            {
                return isDriverActive(driverTimeoutMs, logger, cncByteBuffer);
            }
            finally
            {
                IoUtil.unmap(cncByteBuffer);
            }
        }

        return false;
    }

public
static
boolean
isDriverActive
(
final
File
directory
,
final
long
driverTimeoutMs
,
final
Consumer
<
String
>
logger
)
{
final
File
cncFile
=
new
File
(
directory
,
CncFileDescriptor
.
CNC_FILE
)
;
if
(
cncFile
.
exists
(
)
&&
cncFile
.
length
(
)
>
0
)
{
logger
.
accept
(
"INFO: Aeron CnC file exists: "
+
cncFile
)
;
final
MappedByteBuffer
cncByteBuffer
=
IoUtil
.
mapExistingFile
(
cncFile
,
"CnC file"
)
;
try
{
return
isDriverActive
(
driverTimeoutMs
,
logger
,
cncByteBuffer
)
;
}
finally
{
IoUtil
.
unmap
(
cncByteBuffer
)
;
}
}
return
false
;
}

Is a media driver active in the given directory?

@param directory       to check
@param driverTimeoutMs for the driver liveness check.
@param logger          for feedback as liveness checked.
@return true if a driver is active or false if not.


public boolean isDriverActive(final long driverTimeoutMs, final Consumer<String> logger)
    {
        final MappedByteBuffer cncByteBuffer = mapExistingCncFile(logger);
        try
        {
            return isDriverActive(driverTimeoutMs, logger, cncByteBuffer);
        }
        finally
        {
            IoUtil.unmap(cncByteBuffer);
        }
    }

public boolean isDriverActive ( final long driverTimeoutMs , final Consumer < String > logger ) { final MappedByteBuffer cncByteBuffer = mapExistingCncFile ( logger ) ; try { return isDriverActive ( driverTimeoutMs , logger , cncByteBuffer ) ; } finally { IoUtil . unmap ( cncByteBuffer ) ; } }

Is a media driver active in the current Aeron directory?

@param driverTimeoutMs for the driver liveness check.
@param logger          for feedback as liveness checked.
@return true if a driver is active or false if not.


public static boolean isDriverActive(
        final long driverTimeoutMs, final Consumer<String> logger, final ByteBuffer cncByteBuffer)
    {
        if (null == cncByteBuffer)
        {
            return false;
        }

        final UnsafeBuffer cncMetaDataBuffer = CncFileDescriptor.createMetaDataBuffer(cncByteBuffer);

        final long startTimeMs = System.currentTimeMillis();
        int cncVersion;
        while (0 == (cncVersion = cncMetaDataBuffer.getIntVolatile(CncFileDescriptor.cncVersionOffset(0))))
        {
            if (System.currentTimeMillis() > (startTimeMs + driverTimeoutMs))
            {
                throw new DriverTimeoutException("CnC file is created but not initialised.");
            }

            sleep(1);
        }

        if (CNC_VERSION != cncVersion)
        {
            throw new AeronException(
                "Aeron CnC version does not match: required=" + CNC_VERSION + " version=" + cncVersion);
        }

        final ManyToOneRingBuffer toDriverBuffer = new ManyToOneRingBuffer(
            CncFileDescriptor.createToDriverBuffer(cncByteBuffer, cncMetaDataBuffer));

        final long timestamp = toDriverBuffer.consumerHeartbeatTime();
        final long now = System.currentTimeMillis();
        final long timestampAge = now - timestamp;

        logger.accept("INFO: Aeron toDriver consumer heartbeat is (ms): " + timestampAge);

        return timestampAge <= driverTimeoutMs;
    }

Is a media driver active in the current mapped CnC buffer? If the driver is mid start then it will wait for
up to the driverTimeoutMs by checking for the cncVersion being set.

@param driverTimeoutMs for the driver liveness check.
@param logger          for feedback as liveness checked.
@param cncByteBuffer   for the existing CnC file.
@return true if a driver is active or false if not.

Is a media driver active in the current mapped CnC buffer? If the driver is mid start then it will wait for up to the driverTimeoutMs by checking for the cncVersion being set .


public static boolean requestDriverTermination(
        final File directory,
        final DirectBuffer tokenBuffer,
        final int tokenOffset,
        final int tokenLength)
    {
        final File cncFile = new File(directory, CncFileDescriptor.CNC_FILE);

        if (cncFile.exists() && cncFile.length() > 0)
        {
            final MappedByteBuffer cncByteBuffer = IoUtil.mapExistingFile(cncFile, "CnC file");
            try
            {
                final UnsafeBuffer cncMetaDataBuffer = CncFileDescriptor.createMetaDataBuffer(cncByteBuffer);
                final int cncVersion = cncMetaDataBuffer.getIntVolatile(cncVersionOffset(0));

                if (CncFileDescriptor.CNC_VERSION != cncVersion)
                {
                    throw new AeronException(
                        "Aeron CnC version does not match: required=" + CNC_VERSION + " version=" + cncVersion);
                }

                final ManyToOneRingBuffer toDriverBuffer = new ManyToOneRingBuffer(
                    CncFileDescriptor.createToDriverBuffer(cncByteBuffer, cncMetaDataBuffer));
                final long clientId = toDriverBuffer.nextCorrelationId();

                final DriverProxy driverProxy = new DriverProxy(toDriverBuffer, clientId);

                return driverProxy.terminateDriver(tokenBuffer, tokenOffset, tokenLength);
            }
            finally
            {
                IoUtil.unmap(cncByteBuffer);
            }
        }

        return false;
    }

Request a driver to run its termination hook.

@param directory for the driver.
@param tokenBuffer containing the optional token for the request.
@param tokenOffset within the tokenBuffer at which the token begins.
@param tokenLength of the token in the tokenBuffer.
@return true if request was sent or false if request could not be sent.

Request a driver to run its termination hook .


public static int frameLengthVolatile(final UnsafeBuffer buffer, final int termOffset)
    {
        int frameLength = buffer.getIntVolatile(termOffset);

        if (ByteOrder.nativeOrder() != LITTLE_ENDIAN)
        {
            frameLength = Integer.reverseBytes(frameLength);
        }

        return frameLength;
    }

public static int frameLengthVolatile ( final UnsafeBuffer buffer , final int termOffset ) { int frameLength = buffer . getIntVolatile ( termOffset ) ; if ( ByteOrder . nativeOrder ( ) != LITTLE_ENDIAN ) { frameLength = Integer . reverseBytes ( frameLength ) ; } return frameLength ; }

Get the length of a frame from the header as a volatile read.

@param buffer     containing the frame.
@param termOffset at which a frame begins.
@return the value for the frame length.

Get the length of a frame from the header as a volatile read .


public static void frameLengthOrdered(final UnsafeBuffer buffer, final int termOffset, final int frameLength)
    {
        int length = frameLength;
        if (ByteOrder.nativeOrder() != LITTLE_ENDIAN)
        {
            length = Integer.reverseBytes(frameLength);
        }

        buffer.putIntOrdered(termOffset, length);
    }

public static void frameLengthOrdered ( final UnsafeBuffer buffer , final int termOffset , final int frameLength ) { int length = frameLength ; if ( ByteOrder . nativeOrder ( ) != LITTLE_ENDIAN ) { length = Integer . reverseBytes ( frameLength ) ; } buffer . putIntOrdered ( termOffset , length ) ; }

Write the length header for a frame in a memory ordered fashion.

@param buffer      containing the frame.
@param termOffset  at which a frame begins.
@param frameLength field to be set for the frame.

Write the length header for a frame in a memory ordered fashion .


public static void frameType(final UnsafeBuffer buffer, final int termOffset, final int type)
    {
        buffer.putShort(typeOffset(termOffset), (short)type, LITTLE_ENDIAN);
    }

public static void frameType ( final UnsafeBuffer buffer , final int termOffset , final int type ) { buffer . putShort ( typeOffset ( termOffset ) , ( short ) type , LITTLE_ENDIAN ) ; }

Write the type field for a frame.

@param buffer     containing the frame.
@param termOffset at which a frame begins.
@param type       type value for the frame.


public static void frameFlags(final UnsafeBuffer buffer, final int termOffset, final byte flags)
    {
        buffer.putByte(flagsOffset(termOffset), flags);
    }

public static void frameFlags ( final UnsafeBuffer buffer , final int termOffset , final byte flags ) { buffer . putByte ( flagsOffset ( termOffset ) , flags ) ; }

Write the flags field for a frame.

@param buffer     containing the frame.
@param termOffset at which a frame begins.
@param flags      value for the frame.


public static void frameTermOffset(final UnsafeBuffer buffer, final int termOffset)
    {
        buffer.putInt(termOffsetOffset(termOffset), termOffset, LITTLE_ENDIAN);
    }

public static void frameTermOffset ( final UnsafeBuffer buffer , final int termOffset ) { buffer . putInt ( termOffsetOffset ( termOffset ) , termOffset , LITTLE_ENDIAN ) ; }

Write the term offset field for a frame.

@param buffer     containing the frame.
@param termOffset at which a frame begins.

Write the term offset field for a frame .


public static void frameTermId(final UnsafeBuffer buffer, final int termOffset, final int termId)
    {
        buffer.putInt(termIdOffset(termOffset), termId, LITTLE_ENDIAN);
    }

public static void frameTermId ( final UnsafeBuffer buffer , final int termOffset , final int termId ) { buffer . putInt ( termIdOffset ( termOffset ) , termId , LITTLE_ENDIAN ) ; }

Write the term id field for a frame.

@param buffer     containing the frame.
@param termOffset at which a frame begins.
@param termId     value for the frame.


public static int findCounterIdByRecording(final CountersReader countersReader, final long recordingId)
    {
        final DirectBuffer buffer = countersReader.metaDataBuffer();

        for (int i = 0, size = countersReader.maxCounterId(); i < size; i++)
        {
            if (countersReader.getCounterState(i) == RECORD_ALLOCATED)
            {
                final int recordOffset = CountersReader.metaDataOffset(i);

                if (buffer.getInt(recordOffset + TYPE_ID_OFFSET) == RECORDING_POSITION_TYPE_ID &&
                    buffer.getLong(recordOffset + KEY_OFFSET + RECORDING_ID_OFFSET) == recordingId)
                {
                    return i;
                }
            }
        }

        return NULL_COUNTER_ID;
    }

public static int findCounterIdByRecording ( final CountersReader countersReader , final long recordingId ) { final DirectBuffer buffer = countersReader . metaDataBuffer ( ) ; for ( int i = 0 , size = countersReader . maxCounterId ( ) ; i < size ; i ++ ) { if ( countersReader . getCounterState ( i ) == RECORD_ALLOCATED ) { final int recordOffset = CountersReader . metaDataOffset ( i ) ; if ( buffer . getInt ( recordOffset + TYPE_ID_OFFSET ) == RECORDING_POSITION_TYPE_ID && buffer . getLong ( recordOffset + KEY_OFFSET + RECORDING_ID_OFFSET ) == recordingId ) { return i ; } } } return NULL_COUNTER_ID ; }

Find the active counter id for a stream based on the recording id.

@param countersReader to search within.
@param recordingId    for the active recording.
@return the counter id if found otherwise {@link CountersReader#NULL_COUNTER_ID}.

Find the active counter id for a stream based on the recording id .


public static int findCounterIdBySession(final CountersReader countersReader, final int sessionId)
    {
        final DirectBuffer buffer = countersReader.metaDataBuffer();

        for (int i = 0, size = countersReader.maxCounterId(); i < size; i++)
        {
            if (countersReader.getCounterState(i) == RECORD_ALLOCATED)
            {
                final int recordOffset = CountersReader.metaDataOffset(i);

                if (buffer.getInt(recordOffset + TYPE_ID_OFFSET) == RECORDING_POSITION_TYPE_ID &&
                    buffer.getInt(recordOffset + KEY_OFFSET + SESSION_ID_OFFSET) == sessionId)
                {
                    return i;
                }
            }
        }

        return NULL_COUNTER_ID;
    }

public static int findCounterIdBySession ( final CountersReader countersReader , final int sessionId ) { final DirectBuffer buffer = countersReader . metaDataBuffer ( ) ; for ( int i = 0 , size = countersReader . maxCounterId ( ) ; i < size ; i ++ ) { if ( countersReader . getCounterState ( i ) == RECORD_ALLOCATED ) { final int recordOffset = CountersReader . metaDataOffset ( i ) ; if ( buffer . getInt ( recordOffset + TYPE_ID_OFFSET ) == RECORDING_POSITION_TYPE_ID && buffer . getInt ( recordOffset + KEY_OFFSET + SESSION_ID_OFFSET ) == sessionId ) { return i ; } } } return NULL_COUNTER_ID ; }

Find the active counter id for a stream based on the session id.

@param countersReader to search within.
@param sessionId      for the active recording.
@return the counter id if found otherwise {@link CountersReader#NULL_COUNTER_ID}.

Find the active counter id for a stream based on the session id .


public static long getRecordingId(final CountersReader countersReader, final int counterId)
    {
        final DirectBuffer buffer = countersReader.metaDataBuffer();

        if (countersReader.getCounterState(counterId) == RECORD_ALLOCATED)
        {
            final int recordOffset = CountersReader.metaDataOffset(counterId);

            if (buffer.getInt(recordOffset + TYPE_ID_OFFSET) == RECORDING_POSITION_TYPE_ID)
            {
                return buffer.getLong(recordOffset + KEY_OFFSET + RECORDING_ID_OFFSET);
            }
        }

        return NULL_RECORDING_ID;
    }

public static long getRecordingId ( final CountersReader countersReader , final int counterId ) { final DirectBuffer buffer = countersReader . metaDataBuffer ( ) ; if ( countersReader . getCounterState ( counterId ) == RECORD_ALLOCATED ) { final int recordOffset = CountersReader . metaDataOffset ( counterId ) ; if ( buffer . getInt ( recordOffset + TYPE_ID_OFFSET ) == RECORDING_POSITION_TYPE_ID ) { return buffer . getLong ( recordOffset + KEY_OFFSET + RECORDING_ID_OFFSET ) ; } } return NULL_RECORDING_ID ; }

Get the recording id for a given counter id.

@param countersReader to search within.
@param counterId      for the active recording.
@return the counter id if found otherwise {@link #NULL_RECORDING_ID}.

Get the recording id for a given counter id .


public static boolean isActive(final CountersReader countersReader, final int counterId, final long recordingId)
    {
        final DirectBuffer buffer = countersReader.metaDataBuffer();

        if (countersReader.getCounterState(counterId) == RECORD_ALLOCATED)
        {
            final int recordOffset = CountersReader.metaDataOffset(counterId);

            return
                buffer.getInt(recordOffset + TYPE_ID_OFFSET) == RECORDING_POSITION_TYPE_ID &&
                buffer.getLong(recordOffset + KEY_OFFSET + RECORDING_ID_OFFSET) == recordingId;
        }

        return false;
    }

public static boolean isActive ( final CountersReader countersReader , final int counterId , final long recordingId ) { final DirectBuffer buffer = countersReader . metaDataBuffer ( ) ; if ( countersReader . getCounterState ( counterId ) == RECORD_ALLOCATED ) { final int recordOffset = CountersReader . metaDataOffset ( counterId ) ; return buffer . getInt ( recordOffset + TYPE_ID_OFFSET ) == RECORDING_POSITION_TYPE_ID && buffer . getLong ( recordOffset + KEY_OFFSET + RECORDING_ID_OFFSET ) == recordingId ; } return false ; }

Is the recording counter still active.

@param countersReader to search within.
@param counterId      to search for.
@param recordingId    to confirm it is still the same value.
@return true if the counter is still active otherwise false.


public StatusMessageFlyweight applicationSpecificFeedback(final byte[] source, final int offset, final int length)
    {
        frameLength(HEADER_LENGTH + length);
        putBytes(APP_SPECIFIC_FEEDBACK_FIELD_OFFSET, source, offset, length);

        return this;
    }

public StatusMessageFlyweight applicationSpecificFeedback ( final byte [ ] source , final int offset , final int length ) { frameLength ( HEADER_LENGTH + length ) ; putBytes ( APP_SPECIFIC_FEEDBACK_FIELD_OFFSET , source , offset , length ) ; return this ; }

Set the Application Specific Feedback for the Status Message.

@param source of the feedback to set
@param offset of the feedback in the source
@param length of the feedback in bytes
@return flyweight

Set the Application Specific Feedback for the Status Message .


public void reload()
    {
        entries.clear();
        indexByLeadershipTermIdMap.clear();
        indexByLeadershipTermIdMap.compact();

        nextEntryIndex = 0;
        byteBuffer.clear();

        try
        {
            while (true)
            {
                final int bytes = fileChannel.read(byteBuffer);
                if (byteBuffer.remaining() == 0)
                {
                    byteBuffer.flip();
                    captureEntriesFromBuffer(byteBuffer, buffer, entries);
                    byteBuffer.clear();
                }

                if (-1 == bytes)
                {
                    if (byteBuffer.position() > 0)
                    {
                        byteBuffer.flip();
                        captureEntriesFromBuffer(byteBuffer, buffer, entries);
                        byteBuffer.clear();
                    }

                    break;
                }
            }
        }
        catch (final IOException ex)
        {
            LangUtil.rethrowUnchecked(ex);
        }
    }

public void reload ( ) { entries . clear ( ) ; indexByLeadershipTermIdMap . clear ( ) ; indexByLeadershipTermIdMap . compact ( ) ; nextEntryIndex = 0 ; byteBuffer . clear ( ) ; try { while ( true ) { final int bytes = fileChannel . read ( byteBuffer ) ; if ( byteBuffer . remaining ( ) == 0 ) { byteBuffer . flip ( ) ; captureEntriesFromBuffer ( byteBuffer , buffer , entries ) ; byteBuffer . clear ( ) ; } if ( - 1 == bytes ) { if ( byteBuffer . position ( ) > 0 ) { byteBuffer . flip ( ) ; captureEntriesFromBuffer ( byteBuffer , buffer , entries ) ; byteBuffer . clear ( ) ; } break ; } } } catch ( final IOException ex ) { LangUtil . rethrowUnchecked ( ex ) ; } }


public Entry findLastTerm()
    {
        for (int i = entries.size() - 1; i >= 0; i--)
        {
            final Entry entry = entries.get(i);
            if (ENTRY_TYPE_TERM == entry.type)
            {
                return entry;
            }
        }

        return null;
    }

public Entry findLastTerm ( ) { for ( int i = entries . size ( ) - 1 ; i >= 0 ; i -- ) { final Entry entry = entries . get ( i ) ; if ( ENTRY_TYPE_TERM == entry . type ) { return entry ; } } return null ; }

Find the last leadership term in the recording log.

@return the last leadership term in the recording log.

Find the last leadership term in the recording log .


public RecoveryPlan createRecoveryPlan(final AeronArchive archive, final int serviceCount)
    {
        final ArrayList<Snapshot> snapshots = new ArrayList<>();
        final ArrayList<Log> logs = new ArrayList<>();
        planRecovery(snapshots, logs, entries, archive, serviceCount);

        long lastLeadershipTermId = NULL_VALUE;
        long lastTermBaseLogPosition = 0;
        long committedLogPosition = -1;
        long appendedLogPosition = 0;

        final int snapshotStepsSize = snapshots.size();
        if (snapshotStepsSize > 0)
        {
            final Snapshot snapshot = snapshots.get(0);

            lastLeadershipTermId = snapshot.leadershipTermId;
            lastTermBaseLogPosition = snapshot.termBaseLogPosition;
            appendedLogPosition = snapshot.logPosition;
            committedLogPosition = snapshot.logPosition;
        }

        if (!logs.isEmpty())
        {
            final Log log = logs.get(0);

            lastLeadershipTermId = log.leadershipTermId;
            lastTermBaseLogPosition = log.termBaseLogPosition;
            appendedLogPosition = log.stopPosition;
            committedLogPosition = log.logPosition;
        }

        return new RecoveryPlan(
            lastLeadershipTermId,
            lastTermBaseLogPosition,
            appendedLogPosition,
            committedLogPosition,
            snapshots,
            logs);
    }

public RecoveryPlan createRecoveryPlan ( final AeronArchive archive , final int serviceCount ) { final ArrayList < Snapshot > snapshots = new ArrayList <> ( ) ; final ArrayList < Log > logs = new ArrayList <> ( ) ; planRecovery ( snapshots , logs , entries , archive , serviceCount ) ; long lastLeadershipTermId = NULL_VALUE ; long lastTermBaseLogPosition = 0 ; long committedLogPosition = - 1 ; long appendedLogPosition = 0 ; final int snapshotStepsSize = snapshots . size ( ) ; if ( snapshotStepsSize > 0 ) { final Snapshot snapshot = snapshots . get ( 0 ) ; lastLeadershipTermId = snapshot . leadershipTermId ; lastTermBaseLogPosition = snapshot . termBaseLogPosition ; appendedLogPosition = snapshot . logPosition ; committedLogPosition = snapshot . logPosition ; } if ( ! logs . isEmpty ( ) ) { final Log log = logs . get ( 0 ) ; lastLeadershipTermId = log . leadershipTermId ; lastTermBaseLogPosition = log . termBaseLogPosition ; appendedLogPosition = log . stopPosition ; committedLogPosition = log . logPosition ; } return new RecoveryPlan ( lastLeadershipTermId , lastTermBaseLogPosition , appendedLogPosition , committedLogPosition , snapshots , logs ) ; }

Create a recovery plan for the cluster that when the steps are replayed will bring the cluster back to the
latest stable state.

@param archive      to lookup recording descriptors.
@param serviceCount of services that may have snapshots.
@return a new {@link RecoveryPlan} for the cluster.

Create a recovery plan for the cluster that when the steps are replayed will bring the cluster back to the latest stable state .


public static RecoveryPlan createRecoveryPlan(final ArrayList<RecordingLog.Snapshot> snapshots)
    {
        long lastLeadershipTermId = NULL_VALUE;
        long lastTermBaseLogPosition = 0;
        long committedLogPosition = -1;
        long appendedLogPosition = 0;

        final int snapshotStepsSize = snapshots.size();
        if (snapshotStepsSize > 0)
        {
            final Snapshot snapshot = snapshots.get(0);

            lastLeadershipTermId = snapshot.leadershipTermId;
            lastTermBaseLogPosition = snapshot.termBaseLogPosition;
            appendedLogPosition = snapshot.logPosition;
            committedLogPosition = snapshot.logPosition;
        }

        return new RecoveryPlan(
            lastLeadershipTermId,
            lastTermBaseLogPosition,
            appendedLogPosition,
            committedLogPosition,
            snapshots,
            new ArrayList<>());
    }

public static RecoveryPlan createRecoveryPlan ( final ArrayList < RecordingLog . Snapshot > snapshots ) { long lastLeadershipTermId = NULL_VALUE ; long lastTermBaseLogPosition = 0 ; long committedLogPosition = - 1 ; long appendedLogPosition = 0 ; final int snapshotStepsSize = snapshots . size ( ) ; if ( snapshotStepsSize > 0 ) { final Snapshot snapshot = snapshots . get ( 0 ) ; lastLeadershipTermId = snapshot . leadershipTermId ; lastTermBaseLogPosition = snapshot . termBaseLogPosition ; appendedLogPosition = snapshot . logPosition ; committedLogPosition = snapshot . logPosition ; } return new RecoveryPlan ( lastLeadershipTermId , lastTermBaseLogPosition , appendedLogPosition , committedLogPosition , snapshots , new ArrayList <> ( ) ) ; }

Create a recovery plan that has only snapshots. Used for dynamicJoin snapshot load.

@param snapshots to construct plan from
@return a new {@link RecoveryPlan} for the cluster

Create a recovery plan that has only snapshots . Used for dynamicJoin snapshot load .


public void appendTerm(
        final long recordingId, final long leadershipTermId, final long termBaseLogPosition, final long timestamp)
    {
        final int size = entries.size();
        if (size > 0)
        {
            final Entry lastEntry = entries.get(size - 1);

            if (lastEntry.type != NULL_VALUE && lastEntry.leadershipTermId >= leadershipTermId)
            {
                throw new ClusterException("leadershipTermId out of sequence: previous " +
                    lastEntry.leadershipTermId + " this " + leadershipTermId);
            }
        }

        indexByLeadershipTermIdMap.put(leadershipTermId, nextEntryIndex);

        append(
            ENTRY_TYPE_TERM,
            recordingId,
            leadershipTermId,
            termBaseLogPosition,
            NULL_POSITION,
            timestamp,
            NULL_VALUE);
    }

Append a log entry for a leadership term.

@param recordingId         of the log.
@param leadershipTermId    for the current term.
@param termBaseLogPosition reached at the beginning of the term.
@param timestamp           at the beginning of the term.

Append a log entry for a leadership term .


public void appendSnapshot(
        final long recordingId,
        final long leadershipTermId,
        final long termBaseLogPosition,
        final long logPosition,
        final long timestamp,
        final int serviceId)
    {
        final int size = entries.size();
        if (size > 0)
        {
            final Entry entry = entries.get(size - 1);

            if (entry.type == ENTRY_TYPE_TERM && entry.leadershipTermId != leadershipTermId)
            {
                throw new ClusterException("leadershipTermId out of sequence: previous " +
                    entry.leadershipTermId + " this " + leadershipTermId);
            }
        }

        append(
            ENTRY_TYPE_SNAPSHOT,
            recordingId,
            leadershipTermId,
            termBaseLogPosition,
            logPosition,
            timestamp,
            serviceId);
    }

Append a log entry for a snapshot.

@param recordingId         in the archive for the snapshot.
@param leadershipTermId    for the current term
@param termBaseLogPosition at the beginning of the leadership term.
@param logPosition         for the position in the current term or length so far for that term.
@param timestamp           at which the snapshot was taken.
@param serviceId           for which the snapshot is recorded.


public void commitLogPosition(final long leadershipTermId, final long logPosition)
    {
        final int index = getLeadershipTermEntryIndex(leadershipTermId);
        commitEntryValue(index, logPosition, LOG_POSITION_OFFSET);

        final Entry entry = entries.get(index);
        entries.set(index, new Entry(
            entry.recordingId,
            entry.leadershipTermId,
            entry.termBaseLogPosition,
            logPosition,
            entry.timestamp,
            entry.serviceId,
            entry.type,
            entry.entryIndex));
    }

public void commitLogPosition ( final long leadershipTermId , final long logPosition ) { final int index = getLeadershipTermEntryIndex ( leadershipTermId ) ; commitEntryValue ( index , logPosition , LOG_POSITION_OFFSET ) ; final Entry entry = entries . get ( index ) ; entries . set ( index , new Entry ( entry . recordingId , entry . leadershipTermId , entry . termBaseLogPosition , logPosition , entry . timestamp , entry . serviceId , entry . type , entry . entryIndex ) ) ; }

Commit the position reached in a leadership term before a clean shutdown.

@param leadershipTermId for committing the term position reached.
@param logPosition      reached in the leadership term.

Commit the position reached in a leadership term before a clean shutdown .


public void tombstoneEntry(final long leadershipTermId, final int entryIndex)
    {
        int index = -1;
        for (int i = 0, size = entries.size(); i < size; i++)
        {
            final Entry entry = entries.get(i);
            if (entry.leadershipTermId == leadershipTermId && entry.entryIndex == entryIndex)
            {
                index = entry.entryIndex;

                if (ENTRY_TYPE_TERM == entry.type)
                {
                    indexByLeadershipTermIdMap.remove(leadershipTermId);
                }

                break;
            }
        }

        if (-1 == index)
        {
            throw new ClusterException("unknown entry index: " + entryIndex);
        }

        buffer.putInt(0, NULL_VALUE, LITTLE_ENDIAN);
        byteBuffer.limit(SIZE_OF_INT).position(0);
        final long filePosition = (index * (long)ENTRY_LENGTH) + ENTRY_TYPE_OFFSET;

        try
        {
            if (SIZE_OF_INT != fileChannel.write(byteBuffer, filePosition))
            {
                throw new ClusterException("failed to write field atomically");
            }
        }
        catch (final Exception ex)
        {
            LangUtil.rethrowUnchecked(ex);
        }
    }

public
void
tombstoneEntry
(
final
long
leadershipTermId
,
final
int
entryIndex
)
{
int
index
=
1
;
for
(
int
i
=
0
,
size
=
entries
.
size
(
)
;
i
<
size
;
i
++
)
{
final
Entry
entry
=
entries
.
get
(
i
)
;
if
(
entry
.
leadershipTermId
==
leadershipTermId
&&
entry
.
entryIndex
==
entryIndex
)
{
index
=
entry
.
entryIndex
;
if
(
ENTRY_TYPE_TERM
==
entry
.
type
)
{
indexByLeadershipTermIdMap
.
remove
(
leadershipTermId
)
;
}
break
;
}
}
if
(
1
==
index
)
{
throw
new
ClusterException
(
"unknown entry index: "
+
entryIndex
)
;
}
buffer
.
putInt
(
0
,
NULL_VALUE
,
LITTLE_ENDIAN
)
;
byteBuffer
.
limit
(
SIZE_OF_INT
)
.
position
(
0
)
;
final
long
filePosition
=
(
index
*
(
long
)
ENTRY_LENGTH
)
+
ENTRY_TYPE_OFFSET
;
try
{
if
(
SIZE_OF_INT
!=
fileChannel
.
write
(
byteBuffer
,
filePosition
)
)
{
throw
new
ClusterException
(
"failed to write field atomically"
)
;
}
}
catch
(
final
Exception
ex
)
{
LangUtil
.
rethrowUnchecked
(
ex
)
;
}
}

Tombstone an entry in the log so it is no longer valid.

@param leadershipTermId to match for validation.
@param entryIndex       reached in the leadership term.

Tombstone an entry in the log so it is no longer valid .


public void close()
    {
        if (null != publication && publication.isConnected())
        {
            closeSession();
        }

        if (!ctx.ownsAeronClient())
        {
            CloseHelper.close(subscription);
            CloseHelper.close(publication);
        }

        ctx.close();
    }

public void close ( ) { if ( null != publication && publication . isConnected ( ) ) { closeSession ( ) ; } if ( ! ctx . ownsAeronClient ( ) ) { CloseHelper . close ( subscription ) ; CloseHelper . close ( publication ) ; } ctx . close ( ) ; }

Close session and release associated resources.

Close session and release associated resources .


public long offer(final DirectBufferVector[] vectors)
    {
        if (headerVector != vectors[0])
        {
            vectors[0] = headerVector;
        }

        return publication.offer(vectors, null);
    }

public long offer ( final DirectBufferVector [ ] vectors ) { if ( headerVector != vectors [ 0 ] ) { vectors [ 0 ] = headerVector ; } return publication . offer ( vectors , null ) ; }

Non-blocking publish by gathering buffer vectors into a message. The first vector will be replaced by the cluster
ingress header so must be left unused.

@param vectors which make up the message.
@return the same as {@link Publication#offer(DirectBufferVector[])}.
@see Publication#offer(DirectBufferVector[])

Non - blocking publish by gathering buffer vectors into a message . The first vector will be replaced by the cluster ingress header so must be left unused .


public static boolean unblock(
        final UnsafeBuffer[] termBuffers,
        final UnsafeBuffer logMetaDataBuffer,
        final long blockedPosition,
        final int termLength)
    {
        final int positionBitsToShift = LogBufferDescriptor.positionBitsToShift(termLength);
        final int blockedTermCount = (int)(blockedPosition >> positionBitsToShift);
        final int blockedOffset = (int)blockedPosition & (termLength - 1);
        final int activeTermCount = activeTermCount(logMetaDataBuffer);

        if (activeTermCount == (blockedTermCount - 1) && blockedOffset == 0)
        {
            final int currentTermId = termId(rawTailVolatile(logMetaDataBuffer, indexByTermCount(activeTermCount)));
            return rotateLog(logMetaDataBuffer, activeTermCount, currentTermId);
        }

        final int blockedIndex = indexByTermCount(blockedTermCount);
        final long rawTail = rawTailVolatile(logMetaDataBuffer, blockedIndex);
        final int termId = termId(rawTail);
        final int tailOffset = termOffset(rawTail, termLength);
        final UnsafeBuffer termBuffer = termBuffers[blockedIndex];

        switch (TermUnblocker.unblock(logMetaDataBuffer, termBuffer, blockedOffset, tailOffset, termId))
        {
            case UNBLOCKED_TO_END:
                rotateLog(logMetaDataBuffer, blockedTermCount, termId);
                // fall through
            case UNBLOCKED:
                return true;
        }

        return false;
    }

public
static
boolean
unblock
(
final
UnsafeBuffer
[
]
termBuffers
,
final
UnsafeBuffer
logMetaDataBuffer
,
final
long
blockedPosition
,
final
int
termLength
)
{
final
int
positionBitsToShift
=
LogBufferDescriptor
.
positionBitsToShift
(
termLength
)
;
final
int
blockedTermCount
=
(
int
)
(
blockedPosition
>>
positionBitsToShift
)
;
final
int
blockedOffset
=
(
int
)
blockedPosition
&
(
termLength
1
)
;
final
int
activeTermCount
=
activeTermCount
(
logMetaDataBuffer
)
;
if
(
activeTermCount
==
(
blockedTermCount
1
)
&&
blockedOffset
==
0
)
{
final
int
currentTermId
=
termId
(
rawTailVolatile
(
logMetaDataBuffer
,
indexByTermCount
(
activeTermCount
)
)
)
;
return
rotateLog
(
logMetaDataBuffer
,
activeTermCount
,
currentTermId
)
;
}
final
int
blockedIndex
=
indexByTermCount
(
blockedTermCount
)
;
final
long
rawTail
=
rawTailVolatile
(
logMetaDataBuffer
,
blockedIndex
)
;
final
int
termId
=
termId
(
rawTail
)
;
final
int
tailOffset
=
termOffset
(
rawTail
,
termLength
)
;
final
UnsafeBuffer
termBuffer
=
termBuffers
[
blockedIndex
]
;
switch
(
TermUnblocker
.
unblock
(
logMetaDataBuffer
,
termBuffer
,
blockedOffset
,
tailOffset
,
termId
)
)
{
case
UNBLOCKED_TO_END
:
rotateLog
(
logMetaDataBuffer
,
blockedTermCount
,
termId
)
;
// fall through
case
UNBLOCKED
:
return
true
;
}
return
false
;
}

Attempt to unblock a log buffer at given position

@param termBuffers       for current blockedOffset
@param logMetaDataBuffer for log buffer
@param blockedPosition   to attempt to unblock
@param termLength        of the buffer for each term in the log
@return whether unblocked or not


public String channel()
    {
        final int length = buffer.getInt(offset + CHANNEL_OFFSET);
        lengthOfChannel = SIZE_OF_INT + length;

        return buffer.getStringAscii(offset + CHANNEL_OFFSET, length);
    }

public String channel ( ) { final int length = buffer . getInt ( offset + CHANNEL_OFFSET ) ; lengthOfChannel = SIZE_OF_INT + length ; return buffer . getStringAscii ( offset + CHANNEL_OFFSET , length ) ; }

Get the channel field as ASCII

@return channel field


public ImageMessageFlyweight channel(final String channel)
    {
        lengthOfChannel = buffer.putStringAscii(offset + CHANNEL_OFFSET, channel);

        return this;
    }

public ImageMessageFlyweight channel ( final String channel ) { lengthOfChannel = buffer . putStringAscii ( offset + CHANNEL_OFFSET , channel ) ; return this ; }

Set the channel field as ASCII

@param channel field value
@return flyweight


public static void checkTermLength(final int termLength)
    {
        if (termLength < TERM_MIN_LENGTH)
        {
            throw new IllegalStateException(
                "Term length less than min length of " + TERM_MIN_LENGTH + ": length=" + termLength);
        }

        if (termLength > TERM_MAX_LENGTH)
        {
            throw new IllegalStateException(
                "Term length more than max length of " + TERM_MAX_LENGTH + ": length=" + termLength);
        }

        if (!BitUtil.isPowerOfTwo(termLength))
        {
            throw new IllegalStateException("Term length not a power of 2: length=" + termLength);
        }
    }

public
static
void
checkTermLength
(
final
int
termLength
)
{
if
(
termLength
<
TERM_MIN_LENGTH
)
{
throw
new
IllegalStateException
(
"Term length less than min length of "
+
TERM_MIN_LENGTH
+
": length="
+
termLength
)
;
}
if
(
termLength
>
TERM_MAX_LENGTH
)
{
throw
new
IllegalStateException
(
"Term length more than max length of "
+
TERM_MAX_LENGTH
+
": length="
+
termLength
)
;
}
if
(
!
BitUtil
.
isPowerOfTwo
(
termLength
)
)
{
throw
new
IllegalStateException
(
"Term length not a power of 2: length="
+
termLength
)
;
}
}

Check that term length is valid and alignment is valid.

@param termLength to be checked.
@throws IllegalStateException if the length is not as expected.

Check that term length is valid and alignment is valid .


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

        if (pageSize > PAGE_MAX_SIZE)
        {
            throw new IllegalStateException(
                "Page size more than max size of " + PAGE_MAX_SIZE + ": page size=" + pageSize);
        }

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

Check that page size is valid and alignment is valid.

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

Check that page size is valid and alignment is valid .


public static boolean casActiveTermCount(
        final UnsafeBuffer metadataBuffer, final int expectedTermCount, final int updateTermCount)
    {
        return metadataBuffer.compareAndSetInt(LOG_ACTIVE_TERM_COUNT_OFFSET, expectedTermCount, updateTermCount);
    }

public static boolean casActiveTermCount ( final UnsafeBuffer metadataBuffer , final int expectedTermCount , final int updateTermCount ) { return metadataBuffer . compareAndSetInt ( LOG_ACTIVE_TERM_COUNT_OFFSET , expectedTermCount , updateTermCount ) ; }

Compare and set the value of the current active term count.

@param metadataBuffer    containing the meta data.
@param expectedTermCount value of the active term count expected in the log
@param updateTermCount   value of the active term count to be updated in the log
@return true if successful otherwise false.

Compare and set the value of the current active term count .


public static long computePosition(
        final int activeTermId, final int termOffset, final int positionBitsToShift, final int initialTermId)
    {
        final long termCount = activeTermId - initialTermId; // copes with negative activeTermId on rollover

        return (termCount << positionBitsToShift) + termOffset;
    }

Compute the current position in absolute number of bytes.

@param activeTermId        active term id.
@param termOffset          in the term.
@param positionBitsToShift number of times to left shift the term count
@param initialTermId       the initial term id that this stream started on
@return the absolute position in bytes

Compute the current position in absolute number of bytes .


public static long computeLogLength(final int termLength, final int filePageSize)
    {
        if (termLength < (1024 * 1024 * 1024))
        {
            return align((termLength * PARTITION_COUNT) + LOG_META_DATA_LENGTH, filePageSize);
        }

        return (PARTITION_COUNT * (long)termLength) + align(LOG_META_DATA_LENGTH, filePageSize);
    }

public static long computeLogLength ( final int termLength , final int filePageSize ) { if ( termLength < ( 1024 * 1024 * 1024 ) ) { return align ( ( termLength * PARTITION_COUNT ) + LOG_META_DATA_LENGTH , filePageSize ) ; } return ( PARTITION_COUNT * ( long ) termLength ) + align ( LOG_META_DATA_LENGTH , filePageSize ) ; }

Compute the total length of a log file given the term length.

Assumes {@link #TERM_MAX_LENGTH} is 1GB and that filePageSize is 1GB or less and a power of 2.

@param termLength   on which to base the calculation.
@param filePageSize to use for log.
@return the total length of the log file.

Compute the total length of a log file given the term length .


public static void storeDefaultFrameHeader(final UnsafeBuffer metadataBuffer, final DirectBuffer defaultHeader)
    {
        if (defaultHeader.capacity() != HEADER_LENGTH)
        {
            throw new IllegalArgumentException(
                "Default header length not equal to HEADER_LENGTH: length=" + defaultHeader.capacity());
        }

        metadataBuffer.putInt(LOG_DEFAULT_FRAME_HEADER_LENGTH_OFFSET, HEADER_LENGTH);
        metadataBuffer.putBytes(LOG_DEFAULT_FRAME_HEADER_OFFSET, defaultHeader, 0, HEADER_LENGTH);
    }

Store the default frame header to the log meta data buffer.

@param metadataBuffer into which the default headers should be stored.
@param defaultHeader  to be stored.
@throws IllegalArgumentException if the defaultHeader larger than {@link #LOG_DEFAULT_FRAME_HEADER_MAX_LENGTH}

Store the default frame header to the log meta data buffer .


public static void applyDefaultHeader(
        final UnsafeBuffer metadataBuffer, final UnsafeBuffer termBuffer, final int termOffset)
    {
        termBuffer.putBytes(termOffset, metadataBuffer, LOG_DEFAULT_FRAME_HEADER_OFFSET, HEADER_LENGTH);
    }

public static void applyDefaultHeader ( final UnsafeBuffer metadataBuffer , final UnsafeBuffer termBuffer , final int termOffset ) { termBuffer . putBytes ( termOffset , metadataBuffer , LOG_DEFAULT_FRAME_HEADER_OFFSET , HEADER_LENGTH ) ; }

Apply the default header for a message in a term.

@param metadataBuffer containing the default headers.
@param termBuffer     to which the default header should be applied.
@param termOffset     at which the default should be applied.

Apply the default header for a message in a term .


public static boolean rotateLog(final UnsafeBuffer metadataBuffer, final int termCount, final int termId)
    {
        final int nextTermId = termId + 1;
        final int nextTermCount = termCount + 1;
        final int nextIndex = indexByTermCount(nextTermCount);
        final int expectedTermId = nextTermId - PARTITION_COUNT;

        long rawTail;
        do
        {
            rawTail = rawTail(metadataBuffer, nextIndex);
            if (expectedTermId != termId(rawTail))
            {
                break;
            }
        }
        while (!casRawTail(metadataBuffer, nextIndex, rawTail, packTail(nextTermId, 0)));

        return casActiveTermCount(metadataBuffer, termCount, nextTermCount);
    }

public static boolean rotateLog ( final UnsafeBuffer metadataBuffer , final int termCount , final int termId ) { final int nextTermId = termId + 1 ; final int nextTermCount = termCount + 1 ; final int nextIndex = indexByTermCount ( nextTermCount ) ; final int expectedTermId = nextTermId - PARTITION_COUNT ; long rawTail ; do { rawTail = rawTail ( metadataBuffer , nextIndex ) ; if ( expectedTermId != termId ( rawTail ) ) { break ; } } while ( ! casRawTail ( metadataBuffer , nextIndex , rawTail , packTail ( nextTermId , 0 ) ) ) ; return casActiveTermCount ( metadataBuffer , termCount , nextTermCount ) ; }

Rotate the log and update the tail counter for the new term.

This method is safe for concurrent use.

@param metadataBuffer for the log.
@param termCount      from which to rotate.
@param termId         to be used in the default headers.
@return true if log was rotated.

Rotate the log and update the tail counter for the new term .


public static void initialiseTailWithTermId(
        final UnsafeBuffer metadataBuffer, final int partitionIndex, final int termId)
    {
        metadataBuffer.putLong(TERM_TAIL_COUNTERS_OFFSET + (partitionIndex * SIZE_OF_LONG), packTail(termId, 0));
    }

public static void initialiseTailWithTermId ( final UnsafeBuffer metadataBuffer , final int partitionIndex , final int termId ) { metadataBuffer . putLong ( TERM_TAIL_COUNTERS_OFFSET + ( partitionIndex * SIZE_OF_LONG ) , packTail ( termId , 0 ) ) ; }

Set the initial value for the termId in the upper bits of the tail counter.

@param metadataBuffer contain the tail counter.
@param partitionIndex to be initialised.
@param termId         to be set.

Set the initial value for the termId in the upper bits of the tail counter .


public static int termOffset(final long rawTail, final long termLength)
    {
        final long tail = rawTail & 0xFFFF_FFFFL;

        return (int)Math.min(tail, termLength);
    }

public static int termOffset ( final long rawTail , final long termLength ) { final long tail = rawTail & 0xFFFF_FFFF L ; return ( int ) Math . min ( tail , termLength ) ; }

Read the termOffset from a packed raw tail value.

@param rawTail    containing the termOffset.
@param termLength that the offset cannot exceed.
@return the termOffset value.

Read the termOffset from a packed raw tail value .


public static long rawTailVolatile(final UnsafeBuffer metadataBuffer)
    {
        final int partitionIndex = indexByTermCount(activeTermCount(metadataBuffer));
        return metadataBuffer.getLongVolatile(TERM_TAIL_COUNTERS_OFFSET + (SIZE_OF_LONG * partitionIndex));
    }

public static long rawTailVolatile ( final UnsafeBuffer metadataBuffer ) { final int partitionIndex = indexByTermCount ( activeTermCount ( metadataBuffer ) ) ; return metadataBuffer . getLongVolatile ( TERM_TAIL_COUNTERS_OFFSET + ( SIZE_OF_LONG * partitionIndex ) ) ; }

Get the raw value of the tail for the current active partition.

@param metadataBuffer containing the tail counters.
@return the raw value of the tail for the current active partition.

Get the raw value of the tail for the current active partition .


public static boolean casRawTail(
        final UnsafeBuffer metadataBuffer,
        final int partitionIndex,
        final long expectedRawTail,
        final long updateRawTail)
    {
        final int index = TERM_TAIL_COUNTERS_OFFSET + (SIZE_OF_LONG * partitionIndex);
        return metadataBuffer.compareAndSetLong(index, expectedRawTail, updateRawTail);
    }

public static boolean casRawTail ( final UnsafeBuffer metadataBuffer , final int partitionIndex , final long expectedRawTail , final long updateRawTail ) { final int index = TERM_TAIL_COUNTERS_OFFSET + ( SIZE_OF_LONG * partitionIndex ) ; return metadataBuffer . compareAndSetLong ( index , expectedRawTail , updateRawTail ) ; }

Compare and set the raw value of the tail for the given partition.

@param metadataBuffer  containing the tail counters.
@param partitionIndex  for the tail counter.
@param expectedRawTail expected current value.
@param updateRawTail   to be applied.
@return true if the update was successful otherwise false.

Compare and set the raw value of the tail for the given partition .


public TerminateDriverFlyweight tokenBuffer(
        final DirectBuffer tokenBuffer, final int tokenOffset, final int tokenLength)
    {
        buffer.putInt(TOKEN_LENGTH_OFFSET, tokenLength);
        if (null != tokenBuffer && tokenLength > 0)
        {
            buffer.putBytes(tokenBufferOffset(), tokenBuffer, tokenOffset, tokenLength);
        }

        return this;
    }

public TerminateDriverFlyweight tokenBuffer ( final DirectBuffer tokenBuffer , final int tokenOffset , final int tokenLength ) { buffer . putInt ( TOKEN_LENGTH_OFFSET , tokenLength ) ; if ( null != tokenBuffer && tokenLength > 0 ) { buffer . putBytes ( tokenBufferOffset ( ) , tokenBuffer , tokenOffset , tokenLength ) ; } return this ; }

Fill the token buffer.

@param tokenBuffer containing the optional token for the request.
@param tokenOffset within the tokenBuffer at which the token begins.
@param tokenLength of the token in the tokenBuffer.
@return flyweight


public static Counter allocate(
        final Aeron aeron,
        final MutableDirectBuffer tempBuffer,
        final long leadershipTermId,
        final long logPosition,
        final long timestamp,
        final boolean hasReplay,
        final long... snapshotRecordingIds)
    {
        tempBuffer.putLong(LEADERSHIP_TERM_ID_OFFSET, leadershipTermId);
        tempBuffer.putLong(LOG_POSITION_OFFSET, logPosition);
        tempBuffer.putLong(TIMESTAMP_OFFSET, timestamp);
        tempBuffer.putInt(REPLAY_FLAG_OFFSET, hasReplay ? 1 : 0);

        final int serviceCount = snapshotRecordingIds.length;
        tempBuffer.putInt(SERVICE_COUNT_OFFSET, serviceCount);

        final int keyLength = SNAPSHOT_RECORDING_IDS_OFFSET + (serviceCount * SIZE_OF_LONG);
        if (keyLength > MAX_KEY_LENGTH)
        {
            throw new ClusterException(keyLength + " exceeds max key length " + MAX_KEY_LENGTH);
        }

        for (int i = 0; i < serviceCount; i++)
        {
            tempBuffer.putLong(SNAPSHOT_RECORDING_IDS_OFFSET + (i * SIZE_OF_LONG), snapshotRecordingIds[i]);
        }

        final int labelOffset = BitUtil.align(keyLength, SIZE_OF_INT);
        int labelLength = 0;
        labelLength += tempBuffer.putStringWithoutLengthAscii(labelOffset + labelLength, NAME);
        labelLength += tempBuffer.putLongAscii(keyLength + labelLength, leadershipTermId);
        labelLength += tempBuffer.putStringWithoutLengthAscii(labelOffset + labelLength, " logPosition=");
        labelLength += tempBuffer.putLongAscii(labelOffset + labelLength, logPosition);
        labelLength += tempBuffer.putStringWithoutLengthAscii(labelOffset + labelLength, " hasReplay=" + hasReplay);

        return aeron.addCounter(RECOVERY_STATE_TYPE_ID, tempBuffer, 0, keyLength, tempBuffer, labelOffset, labelLength);
    }

public
static
Counter
allocate
(
final
Aeron
aeron
,
final
MutableDirectBuffer
tempBuffer
,
final
long
leadershipTermId
,
final
long
logPosition
,
final
long
timestamp
,
final
boolean
hasReplay
,
final
long
...
snapshotRecordingIds
)
{
tempBuffer
.
putLong
(
LEADERSHIP_TERM_ID_OFFSET
,
leadershipTermId
)
;
tempBuffer
.
putLong
(
LOG_POSITION_OFFSET
,
logPosition
)
;
tempBuffer
.
putLong
(
TIMESTAMP_OFFSET
,
timestamp
)
;
tempBuffer
.
putInt
(
REPLAY_FLAG_OFFSET
,
hasReplay
1
:
0
)
;
final
int
serviceCount
=
snapshotRecordingIds
.
length
;
tempBuffer
.
putInt
(
SERVICE_COUNT_OFFSET
,
serviceCount
)
;
final
int
keyLength
=
SNAPSHOT_RECORDING_IDS_OFFSET
+
(
serviceCount
*
SIZE_OF_LONG
)
;
if
(
keyLength
>
MAX_KEY_LENGTH
)
{
throw
new
ClusterException
(
keyLength
+
" exceeds max key length "
+
MAX_KEY_LENGTH
)
;
}
for
(
int
i
=
0
;
i
<
serviceCount
;
i
++
)
{
tempBuffer
.
putLong
(
SNAPSHOT_RECORDING_IDS_OFFSET
+
(
i
*
SIZE_OF_LONG
)
,
snapshotRecordingIds
[
i
]
)
;
}
final
int
labelOffset
=
BitUtil
.
align
(
keyLength
,
SIZE_OF_INT
)
;
int
labelLength
=
0
;
labelLength
+=
tempBuffer
.
putStringWithoutLengthAscii
(
labelOffset
+
labelLength
,
NAME
)
;
labelLength
+=
tempBuffer
.
putLongAscii
(
keyLength
+
labelLength
,
leadershipTermId
)
;
labelLength
+=
tempBuffer
.
putStringWithoutLengthAscii
(
labelOffset
+
labelLength
,
" logPosition="
)
;
labelLength
+=
tempBuffer
.
putLongAscii
(
labelOffset
+
labelLength
,
logPosition
)
;
labelLength
+=
tempBuffer
.
putStringWithoutLengthAscii
(
labelOffset
+
labelLength
,
" hasReplay="
+
hasReplay
)
;
return
aeron
.
addCounter
(
RECOVERY_STATE_TYPE_ID
,
tempBuffer
,
0
,
keyLength
,
tempBuffer
,
labelOffset
,
labelLength
)
;
}

Allocate a counter to represent the snapshot services should load on start.

@param aeron                to allocate the counter.
@param tempBuffer           to use for building the key and label without allocation.
@param leadershipTermId     at which the snapshot was taken.
@param logPosition          at which the snapshot was taken.
@param timestamp            the snapshot was taken.
@param hasReplay            flag is true if all or part of the log must be replayed.
@param snapshotRecordingIds for the services to use during recovery indexed by service id.
@return the {@link Counter} for the recovery state.

Allocate a counter to represent the snapshot services should load on start .


public static int findCounterId(final CountersReader counters)
    {
        final DirectBuffer buffer = counters.metaDataBuffer();

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

                if (buffer.getInt(recordOffset + TYPE_ID_OFFSET) == RECOVERY_STATE_TYPE_ID)
                {
                    return i;
                }
            }
        }

        return NULL_COUNTER_ID;
    }

public static int findCounterId ( final CountersReader counters ) { final DirectBuffer buffer = counters . metaDataBuffer ( ) ; for ( int i = 0 , size = counters . maxCounterId ( ) ; i < size ; i ++ ) { if ( counters . getCounterState ( i ) == RECORD_ALLOCATED ) { final int recordOffset = CountersReader . metaDataOffset ( i ) ; if ( buffer . getInt ( recordOffset + TYPE_ID_OFFSET ) == RECOVERY_STATE_TYPE_ID ) { return i ; } } } return NULL_COUNTER_ID ; }

Find the active counter id for recovery state.

@param counters to search within.
@return the counter id if found otherwise {@link CountersReader#NULL_COUNTER_ID}.

Find the active counter id for recovery state .


public static boolean hasReplay(final CountersReader counters, final int counterId)
    {
        final DirectBuffer buffer = counters.metaDataBuffer();

        if (counters.getCounterState(counterId) == RECORD_ALLOCATED)
        {
            final int recordOffset = CountersReader.metaDataOffset(counterId);

            if (buffer.getInt(recordOffset + TYPE_ID_OFFSET) == RECOVERY_STATE_TYPE_ID)
            {
                return buffer.getInt(recordOffset + KEY_OFFSET + REPLAY_FLAG_OFFSET) == 1;
            }
        }

        return false;
    }

public static boolean hasReplay ( final CountersReader counters , final int counterId ) { final DirectBuffer buffer = counters . metaDataBuffer ( ) ; if ( counters . getCounterState ( counterId ) == RECORD_ALLOCATED ) { final int recordOffset = CountersReader . metaDataOffset ( counterId ) ; if ( buffer . getInt ( recordOffset + TYPE_ID_OFFSET ) == RECOVERY_STATE_TYPE_ID ) { return buffer . getInt ( recordOffset + KEY_OFFSET + REPLAY_FLAG_OFFSET ) == 1 ; } } return false ; }

Has the recovery process got a log to replay?

@param counters  to search within.
@param counterId for the active recovery counter.
@return true if a replay is required.


public static long getSnapshotRecordingId(final CountersReader counters, final int counterId, final int serviceId)
    {
        final DirectBuffer buffer = counters.metaDataBuffer();

        if (counters.getCounterState(counterId) == RECORD_ALLOCATED)
        {
            final int recordOffset = CountersReader.metaDataOffset(counterId);

            if (buffer.getInt(recordOffset + TYPE_ID_OFFSET) == RECOVERY_STATE_TYPE_ID)
            {
                final int serviceCount = buffer.getInt(recordOffset + KEY_OFFSET + SERVICE_COUNT_OFFSET);
                if (serviceId < 0 || serviceId >= serviceCount)
                {
                    throw new ClusterException("invalid serviceId " + serviceId + " for count of " + serviceCount);
                }

                return buffer.getLong(
                    recordOffset + KEY_OFFSET + SNAPSHOT_RECORDING_IDS_OFFSET + (serviceId * SIZE_OF_LONG));
            }
        }

        throw new ClusterException("Active counter not found " + counterId);
    }

public
static
long
getSnapshotRecordingId
(
final
CountersReader
counters
,
final
int
counterId
,
final
int
serviceId
)
{
final
DirectBuffer
buffer
=
counters
.
metaDataBuffer
(
)
;
if
(
counters
.
getCounterState
(
counterId
)
==
RECORD_ALLOCATED
)
{
final
int
recordOffset
=
CountersReader
.
metaDataOffset
(
counterId
)
;
if
(
buffer
.
getInt
(
recordOffset
+
TYPE_ID_OFFSET
)
==
RECOVERY_STATE_TYPE_ID
)
{
final
int
serviceCount
=
buffer
.
getInt
(
recordOffset
+
KEY_OFFSET
+
SERVICE_COUNT_OFFSET
)
;
if
(
serviceId
<
0
||
serviceId
>=
serviceCount
)
{
throw
new
ClusterException
(
"invalid serviceId "
+
serviceId
+
" for count of "
+
serviceCount
)
;
}
return
buffer
.
getLong
(
recordOffset
+
KEY_OFFSET
+
SNAPSHOT_RECORDING_IDS_OFFSET
+
(
serviceId
*
SIZE_OF_LONG
)
)
;
}
}
throw
new
ClusterException
(
"Active counter not found "
+
counterId
)
;
}

Get the recording id of the snapshot for a service.

@param counters  to search within.
@param counterId for the active recovery counter.
@param serviceId for the snapshot required.
@return the count of replay terms if found otherwise {@link Aeron#NULL_VALUE}.

Get the recording id of the snapshot for a service .


public static char[] flagsToChars(final short flags)
    {
        final char[] chars = new char[]{ '0', '0', '0', '0', '0', '0', '0', '0' };
        final int length = chars.length;
        short mask = (short)(1 << (length - 1));

        for (int i = 0; i < length; i++)
        {
            if ((flags & mask) == mask)
            {
                chars[i] = '1';
            }

            mask >>= 1;
        }

        return chars;
    }

public static char [ ] flagsToChars ( final short flags ) { final char [ ] chars = new char [ ] { ' ' , ' ' , ' ' , ' ' , ' ' , ' ' , ' ' , ' ' } ; final int length = chars . length ; short mask = ( short ) ( 1 << ( length - 1 ) ) ; for ( int i = 0 ; i < length ; i ++ ) { if ( ( flags & mask ) == mask ) { chars [ i ] = ' ' ; } mask >>= 1 ; } return chars ; }

Convert header flags to an array of chars to be human readable.

@param flags to be converted.
@return header flags converted to an array of chars to be human readable.

Convert header flags to an array of chars to be human readable .


public PublicationMessageFlyweight channel(final String channel)
    {
        lengthOfChannel = buffer.putStringAscii(offset + CHANNEL_OFFSET, channel);

        return this;
    }

public PublicationMessageFlyweight channel ( final String channel ) { lengthOfChannel = buffer . putStringAscii ( offset + CHANNEL_OFFSET , channel ) ; return this ; }

Set the channel field in ASCII

@param channel field value
@return flyweight


public long offer(final DirectBuffer buffer, final int offset, final int length)
    {
        return cluster.offer(id, responsePublication, buffer, offset, length);
    }

public long offer ( final DirectBuffer buffer , final int offset , final int length ) { return cluster . offer ( id , responsePublication , buffer , offset , length ) ; }

Non-blocking publish of a partial buffer containing a message to a cluster.

@param buffer containing message.
@param offset offset in the buffer at which the encoded message begins.
@param length in bytes of the encoded message.
@return the same as {@link Publication#offer(DirectBuffer, int, int)} when in {@link Cluster.Role#LEADER}
otherwise {@link #MOCKED_OFFER}.

Non - blocking publish of a partial buffer containing a message to a cluster .


public final void wrap(final AtomicBuffer buffer, final int offset, final int length)
    {
        this.buffer.wrap(buffer, offset, length);
    }

public final void wrap ( final AtomicBuffer buffer , final int offset , final int length ) { this . buffer . wrap ( buffer , offset , length ) ; }

Wrap a region of an underlying log buffer so can can represent a claimed space for use by a publisher.

@param buffer to be wrapped.
@param offset at which the claimed region begins including space for the header.
@param length length of the underlying claimed region including space for the header.

Wrap a region of an underlying log buffer so can can represent a claimed space for use by a publisher .


public final void commit()
    {
        int frameLength = buffer.capacity();
        if (ByteOrder.nativeOrder() != LITTLE_ENDIAN)
        {
            frameLength = Integer.reverseBytes(frameLength);
        }

        buffer.putIntOrdered(FRAME_LENGTH_FIELD_OFFSET, frameLength);
    }

public final void commit ( ) { int frameLength = buffer . capacity ( ) ; if ( ByteOrder . nativeOrder ( ) != LITTLE_ENDIAN ) { frameLength = Integer . reverseBytes ( frameLength ) ; } buffer . putIntOrdered ( FRAME_LENGTH_FIELD_OFFSET , frameLength ) ; }

Commit the message to the log buffer so that is it available to subscribers.

Commit the message to the log buffer so that is it available to subscribers .


public final void abort()
    {
        int frameLength = buffer.capacity();
        if (ByteOrder.nativeOrder() != LITTLE_ENDIAN)
        {
            frameLength = Integer.reverseBytes(frameLength);
        }

        buffer.putShort(TYPE_FIELD_OFFSET, (short)HDR_TYPE_PAD, LITTLE_ENDIAN);
        buffer.putIntOrdered(FRAME_LENGTH_FIELD_OFFSET, frameLength);
    }

public final void abort ( ) { int frameLength = buffer . capacity ( ) ; if ( ByteOrder . nativeOrder ( ) != LITTLE_ENDIAN ) { frameLength = Integer . reverseBytes ( frameLength ) ; } buffer . putShort ( TYPE_FIELD_OFFSET , ( short ) HDR_TYPE_PAD , LITTLE_ENDIAN ) ; buffer . putIntOrdered ( FRAME_LENGTH_FIELD_OFFSET , frameLength ) ; }

Abort a claim of the message space to the log buffer so that the log can progress by ignoring this claim.

Abort a claim of the message space to the log buffer so that the log can progress by ignoring this claim .


public static void main(final String[] args)
    {
        loadPropertiesFiles(args);

        final ShutdownSignalBarrier barrier = new ShutdownSignalBarrier();
        final MediaDriver.Context ctx = new MediaDriver.Context();

        ctx.terminationHook(barrier::signal);

        try (MediaDriver ignore = MediaDriver.launch(ctx))
        {
            barrier.await();

            System.out.println("Shutdown Driver...");
        }
    }

public
static
void
main
(
final
String
[
]
args
)
{
loadPropertiesFiles
(
args
)
;
final
ShutdownSignalBarrier
barrier
=
new
ShutdownSignalBarrier
(
)
;
final
MediaDriver
.
Context
ctx
=
new
MediaDriver
.
Context
(
)
;
ctx
.
terminationHook
(
barrier
::
signal
)
;
try
(
MediaDriver
ignore
=
MediaDriver
.
launch
(
ctx
)
)
{
barrier
.
await
(
)
;
System
.
out
.
println
(
"Shutdown Driver..."
)
;
}
}

Start Media Driver as a stand-alone process.

@param args command line arguments

Start Media Driver as a stand - alone process .


public void close()
    {
        CloseHelper.close(sharedRunner);
        CloseHelper.close(sharedNetworkRunner);
        CloseHelper.close(receiverRunner);
        CloseHelper.close(senderRunner);
        CloseHelper.close(conductorRunner);
        CloseHelper.close(sharedInvoker);

        if (ctx.useWindowsHighResTimer() && SystemUtil.osName().startsWith("win"))
        {
            if (!wasHighResTimerEnabled)
            {
                HighResolutionTimer.disable();
            }
        }
    }

public void close ( ) { CloseHelper . close ( sharedRunner ) ; CloseHelper . close ( sharedNetworkRunner ) ; CloseHelper . close ( receiverRunner ) ; CloseHelper . close ( senderRunner ) ; CloseHelper . close ( conductorRunner ) ; CloseHelper . close ( sharedInvoker ) ; if ( ctx . useWindowsHighResTimer ( ) && SystemUtil . osName ( ) . startsWith ( "win" ) ) { if ( ! wasHighResTimerEnabled ) { HighResolutionTimer . disable ( ) ; } } }

Shutdown the media driver by stopping all threads and freeing resources.

Shutdown the media driver by stopping all threads and freeing resources .


public final long position()
    {
        final int resultingOffset = BitUtil.align(termOffset() + frameLength(), FRAME_ALIGNMENT);
        return computePosition(termId(), resultingOffset, positionBitsToShift, initialTermId);
    }

public final long position ( ) { final int resultingOffset = BitUtil . align ( termOffset ( ) + frameLength ( ) , FRAME_ALIGNMENT ) ; return computePosition ( termId ( ) , resultingOffset , positionBitsToShift , initialTermId ) ; }

Get the current position to which the image has advanced on reading this message.

@return the current position to which the image has advanced on reading this message.

Get the current position to which the image has advanced on reading this message .


public static Counter allocate(
        final Aeron aeron,
        final MutableDirectBuffer tempBuffer,
        final int serviceId)
    {
        tempBuffer.putInt(SERVICE_ID_OFFSET, serviceId);

        final int labelOffset = BitUtil.align(KEY_LENGTH, SIZE_OF_INT);
        int labelLength = 0;
        labelLength += tempBuffer.putStringWithoutLengthAscii(labelOffset + labelLength, NAME);
        labelLength += tempBuffer.putIntAscii(labelOffset + labelLength, serviceId);

        return aeron.addCounter(
            SERVICE_HEARTBEAT_TYPE_ID, tempBuffer, 0, KEY_LENGTH, tempBuffer, labelOffset, labelLength);
    }

public static Counter allocate ( final Aeron aeron , final MutableDirectBuffer tempBuffer , final int serviceId ) { tempBuffer . putInt ( SERVICE_ID_OFFSET , serviceId ) ; final int labelOffset = BitUtil . align ( KEY_LENGTH , SIZE_OF_INT ) ; int labelLength = 0 ; labelLength += tempBuffer . putStringWithoutLengthAscii ( labelOffset + labelLength , NAME ) ; labelLength += tempBuffer . putIntAscii ( labelOffset + labelLength , serviceId ) ; return aeron . addCounter ( SERVICE_HEARTBEAT_TYPE_ID , tempBuffer , 0 , KEY_LENGTH , tempBuffer , labelOffset , labelLength ) ; }

Allocate a counter to represent the heartbeat of a clustered service.

@param aeron           to allocate the counter.
@param tempBuffer      to use for building the key and label without allocation.
@param serviceId       of the service heartbeat.
@return the {@link Counter} for the commit position.

Allocate a counter to represent the heartbeat of a clustered service .


public static int findCounterId(final CountersReader counters, final int serviceId)
    {
        final DirectBuffer buffer = counters.metaDataBuffer();

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

                if (buffer.getInt(recordOffset + TYPE_ID_OFFSET) == SERVICE_HEARTBEAT_TYPE_ID &&
                    buffer.getInt(recordOffset + KEY_OFFSET + SERVICE_ID_OFFSET) == serviceId)
                {
                    return i;
                }
            }
        }

        return NULL_COUNTER_ID;
    }

public static int findCounterId ( final CountersReader counters , final int serviceId ) { final DirectBuffer buffer = counters . metaDataBuffer ( ) ; for ( int i = 0 , size = counters . maxCounterId ( ) ; i < size ; i ++ ) { if ( counters . getCounterState ( i ) == RECORD_ALLOCATED ) { final int recordOffset = CountersReader . metaDataOffset ( i ) ; if ( buffer . getInt ( recordOffset + TYPE_ID_OFFSET ) == SERVICE_HEARTBEAT_TYPE_ID && buffer . getInt ( recordOffset + KEY_OFFSET + SERVICE_ID_OFFSET ) == serviceId ) { return i ; } } } return NULL_COUNTER_ID ; }

Find the active counter id for heartbeat of a given service id.

@param counters  to search within.
@param serviceId to search for.
@return the counter id if found otherwise {@link CountersReader#NULL_COUNTER_ID}.

Find the active counter id for heartbeat of a given service id .


public Map<StreamCompositeKey, StreamBacklog> snapshot()
    {
        final Map<StreamCompositeKey, StreamBacklog> 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 StreamBacklog streamBacklog = streams.computeIfAbsent(key, (ignore) -> new StreamBacklog());
                    final long registrationId = keyBuffer.getLong(REGISTRATION_ID_OFFSET);
                    final long value = counters.getCounterValue(counterId);
                    switch (typeId)
                    {
                        case PublisherLimit.PUBLISHER_LIMIT_TYPE_ID:
                            streamBacklog.createPublisherIfAbsent().registrationId(registrationId);
                            streamBacklog.createPublisherIfAbsent().limit(value);
                            break;

                        case PublisherPos.PUBLISHER_POS_TYPE_ID:
                            streamBacklog.createPublisherIfAbsent().registrationId(registrationId);
                            streamBacklog.createPublisherIfAbsent().position(value);
                            break;

                        case SenderPos.SENDER_POSITION_TYPE_ID:
                            streamBacklog.createSenderIfAbsent().registrationId(registrationId);
                            streamBacklog.createSenderIfAbsent().position(value);
                            break;

                        case SenderLimit.SENDER_LIMIT_TYPE_ID:
                            streamBacklog.createSenderIfAbsent().registrationId(registrationId);
                            streamBacklog.createSenderIfAbsent().limit(value);
                            break;

                        case ReceiverHwm.RECEIVER_HWM_TYPE_ID:
                            streamBacklog.createReceiverIfAbsent().registrationId(registrationId);
                            streamBacklog.createReceiverIfAbsent().highWaterMark(value);
                            break;

                        case ReceiverPos.RECEIVER_POS_TYPE_ID:
                            streamBacklog.createReceiverIfAbsent().registrationId(registrationId);
                            streamBacklog.createReceiverIfAbsent().position(value);
                            break;

                        case SubscriberPos.SUBSCRIBER_POSITION_TYPE_ID:
                            streamBacklog.subscriberBacklogs().put(registrationId, new Subscriber(value));
                            break;
                    }
                }
            });

        return streams;
    }

public Map < StreamCompositeKey , StreamBacklog > snapshot ( ) { final Map < StreamCompositeKey , StreamBacklog > 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 StreamBacklog streamBacklog = streams . computeIfAbsent ( key , ( ignore ) - > new StreamBacklog ( ) ) ; final long registrationId = keyBuffer . getLong ( REGISTRATION_ID_OFFSET ) ; final long value = counters . getCounterValue ( counterId ) ; switch ( typeId ) { case PublisherLimit . PUBLISHER_LIMIT_TYPE_ID : streamBacklog . createPublisherIfAbsent ( ) . registrationId ( registrationId ) ; streamBacklog . createPublisherIfAbsent ( ) . limit ( value ) ; break ; case PublisherPos . PUBLISHER_POS_TYPE_ID : streamBacklog . createPublisherIfAbsent ( ) . registrationId ( registrationId ) ; streamBacklog . createPublisherIfAbsent ( ) . position ( value ) ; break ; case SenderPos . SENDER_POSITION_TYPE_ID : streamBacklog . createSenderIfAbsent ( ) . registrationId ( registrationId ) ; streamBacklog . createSenderIfAbsent ( ) . position ( value ) ; break ; case SenderLimit . SENDER_LIMIT_TYPE_ID : streamBacklog . createSenderIfAbsent ( ) . registrationId ( registrationId ) ; streamBacklog . createSenderIfAbsent ( ) . limit ( value ) ; break ; case ReceiverHwm . RECEIVER_HWM_TYPE_ID : streamBacklog . createReceiverIfAbsent ( ) . registrationId ( registrationId ) ; streamBacklog . createReceiverIfAbsent ( ) . highWaterMark ( value ) ; break ; case ReceiverPos . RECEIVER_POS_TYPE_ID : streamBacklog . createReceiverIfAbsent ( ) . registrationId ( registrationId ) ; streamBacklog . createReceiverIfAbsent ( ) . position ( value ) ; break ; case SubscriberPos . SUBSCRIBER_POSITION_TYPE_ID : streamBacklog . subscriberBacklogs ( ) . put ( registrationId , new Subscriber ( value ) ) ; break ; } } } ) ; return streams ; }

Take a snapshot of all the backlog information and group by stream.

@return a snapshot of all the backlog information and group by stream.

Take a snapshot of all the backlog information and group by stream .


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

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

Allocate a counter for tracking the last heartbeat of an entity.

@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.
@return a new {@link AtomicCounter} for tracking the last heartbeat.

Allocate a counter for tracking the last heartbeat of an entity .


public void close()
        {
            final MappedByteBuffer cncByteBuffer = this.cncByteBuffer;
            this.cncByteBuffer = null;
            IoUtil.unmap(cncByteBuffer);
            super.close();
        }

public void close ( ) { final MappedByteBuffer cncByteBuffer = this . cncByteBuffer ; this . cncByteBuffer = null ; IoUtil . unmap ( cncByteBuffer ) ; super . close ( ) ; }

Clean up all resources that the client uses to communicate with the Media Driver.

Clean up all resources that the client uses to communicate with the Media Driver .


public static void dispatchDescriptor(
        final RecordingDescriptorDecoder decoder, final RecordingDescriptorConsumer consumer)
    {
        consumer.onRecordingDescriptor(
            decoder.controlSessionId(),
            decoder.correlationId(),
            decoder.recordingId(),
            decoder.startTimestamp(),
            decoder.stopTimestamp(),
            decoder.startPosition(),
            decoder.stopPosition(),
            decoder.initialTermId(),
            decoder.segmentFileLength(),
            decoder.termBufferLength(),
            decoder.mtuLength(),
            decoder.sessionId(),
            decoder.streamId(),
            decoder.strippedChannel(),
            decoder.originalChannel(),
            decoder.sourceIdentity());
    }

public static void dispatchDescriptor ( final RecordingDescriptorDecoder decoder , final RecordingDescriptorConsumer consumer ) { consumer . onRecordingDescriptor ( decoder . controlSessionId ( ) , decoder . correlationId ( ) , decoder . recordingId ( ) , decoder . startTimestamp ( ) , decoder . stopTimestamp ( ) , decoder . startPosition ( ) , decoder . stopPosition ( ) , decoder . initialTermId ( ) , decoder . segmentFileLength ( ) , decoder . termBufferLength ( ) , decoder . mtuLength ( ) , decoder . sessionId ( ) , decoder . streamId ( ) , decoder . strippedChannel ( ) , decoder . originalChannel ( ) , decoder . sourceIdentity ( ) ) ; }

Dispatch a descriptor message to a consumer by reading the fields in the correct order.

@param decoder  which wraps the encoded message ready for reading.
@param consumer to which the decoded fields should be passed.

Dispatch a descriptor message to a consumer by reading the fields in the correct order .


private void addSlab(int minimumSize) {
    int nextSlabSize;

    if (bytesUsed == 0) {
      nextSlabSize = initialSlabSize;
    } else if (bytesUsed > maxCapacityHint / 5) {
      // to avoid an overhead of up to twice the needed size, we get linear when approaching target page size
      nextSlabSize = maxCapacityHint / 5;
    } else {
      // double the size every time
      nextSlabSize = bytesUsed;
    }

    if (nextSlabSize < minimumSize) {
      LOG.debug("slab size {} too small for value of size {}. Bumping up slab size", nextSlabSize, minimumSize);
      nextSlabSize = minimumSize;
    }

    LOG.debug("used {} slabs, adding new slab of size {}", slabs.size(), nextSlabSize);

    this.currentSlab = allocator.allocate(nextSlabSize);
    this.slabs.add(currentSlab);
    this.bytesAllocated += nextSlabSize;
    this.currentSlabIndex = 0;
  }

the new slab is guaranteed to be at least minimumSize
@param minimumSize the size of the data we want to copy in the new slab


public void setByte(long index, byte value) {
    checkArgument(index < bytesUsed, "Index: " + index + " is >= the current size of: " + bytesUsed);

    long seen = 0;
    for (int i = 0; i < slabs.size(); i++) {
      ByteBuffer slab = slabs.get(i);
      if (index < seen + slab.limit()) {
        // ok found index
        slab.put((int)(index-seen), value);
        break;
      }
      seen += slab.limit();
    }
  }

public
void
setByte
(
long
index
,
byte
value
)
{
checkArgument
(
index
<
bytesUsed
,
"Index: "
+
index
+
" is >= the current size of: "
+
bytesUsed
)
;
long
seen
=
0
;
for
(
int
i
=
0
;
i
<
slabs
.
size
(
)
;
i
++
)
{
ByteBuffer
slab
=
slabs
.
get
(
i
)
;
if
(
index
<
seen
+
slab
.
limit
(
)
)
{
// ok found index
slab
.
put
(
(
int
)
(
index
seen
)
,
value
)
;
break
;
}
seen
+=
slab
.
limit
(
)
;
}
}

Replace the byte stored at position index in this stream with value

@param index which byte to replace
@param value the value to replace it with


public void add(Statistics<?> stats) {
    if (stats.hasNonNullValue()) {
      nullPages.add(false);
      Object min = stats.genericGetMin();
      Object max = stats.genericGetMax();
      addMinMax(min, max);
      pageIndexes.add(nextPageIndex);
      minMaxSize += sizeOf(min);
      minMaxSize += sizeOf(max);
    } else {
      nullPages.add(true);
    }
    nullCounts.add(stats.getNumNulls());
    ++nextPageIndex;
  }

public void add ( Statistics < ? > stats ) { if ( stats . hasNonNullValue ( ) ) { nullPages . add ( false ) ; Object min = stats . genericGetMin ( ) ; Object max = stats . genericGetMax ( ) ; addMinMax ( min , max ) ; pageIndexes . add ( nextPageIndex ) ; minMaxSize += sizeOf ( min ) ; minMaxSize += sizeOf ( max ) ; } else { nullPages . add ( true ) ; } nullCounts . add ( stats . getNumNulls ( ) ) ; ++ nextPageIndex ; }

Adds the data from the specified statistics to this builder

@param stats
the statistics to be added


public static RowRanges calculateRowRanges(FilterCompat.Filter filter, ColumnIndexStore columnIndexStore,
      Set<ColumnPath> paths, long rowCount) {
    return filter.accept(new FilterCompat.Visitor<RowRanges>() {
      @Override
      public RowRanges visit(FilterPredicateCompat filterPredicateCompat) {
        try {
          return filterPredicateCompat.getFilterPredicate()
              .accept(new ColumnIndexFilter(columnIndexStore, paths, rowCount));
        } catch (MissingOffsetIndexException e) {
          LOGGER.info(e.getMessage());
          return RowRanges.createSingle(rowCount);
        }
      }

      @Override
      public RowRanges visit(UnboundRecordFilterCompat unboundRecordFilterCompat) {
        return RowRanges.createSingle(rowCount);
      }

      @Override
      public RowRanges visit(NoOpFilter noOpFilter) {
        return RowRanges.createSingle(rowCount);
      }
    });
  }

public static RowRanges calculateRowRanges ( FilterCompat . Filter filter , ColumnIndexStore columnIndexStore , Set < ColumnPath > paths , long rowCount ) { return filter . accept ( new FilterCompat . Visitor < RowRanges > ( ) { @ Override public RowRanges visit ( FilterPredicateCompat filterPredicateCompat ) { try { return filterPredicateCompat . getFilterPredicate ( ) . accept ( new ColumnIndexFilter ( columnIndexStore , paths , rowCount ) ) ; } catch ( MissingOffsetIndexException e ) { LOGGER . info ( e . getMessage ( ) ) ; return RowRanges . createSingle ( rowCount ) ; } } @ Override public RowRanges visit ( UnboundRecordFilterCompat unboundRecordFilterCompat ) { return RowRanges . createSingle ( rowCount ) ; } @ Override public RowRanges visit ( NoOpFilter noOpFilter ) { return RowRanges . createSingle ( rowCount ) ; } } ) ; }

Calculates the row ranges containing the indexes of the rows might match the specified filter.

@param filter
to be used for filtering the rows
@param columnIndexStore
the store for providing column/offset indexes
@param paths
the paths of the columns used in the actual projection; a column not being part of the projection will be
handled as containing {@code null} values only even if the column has values written in the file
@param rowCount
the total number of rows in the row-group
@return the ranges of the possible matching row indexes; the returned ranges will contain all the rows if any of
the required offset index is missing

Calculates the row ranges containing the indexes of the rows might match the specified filter .


private static GroupType convertArrayType(final String name, final ListTypeInfo typeInfo) {
    final TypeInfo subType = typeInfo.getListElementTypeInfo();
    return listWrapper(name, listType(), new GroupType(Repetition.REPEATED,
        ParquetHiveSerDe.ARRAY.toString(), convertType("array_element", subType)));
  }

private static GroupType convertArrayType ( final String name , final ListTypeInfo typeInfo ) { final TypeInfo subType = typeInfo . getListElementTypeInfo ( ) ; return listWrapper ( name , listType ( ) , new GroupType ( Repetition . REPEATED , ParquetHiveSerDe . ARRAY . toString ( ) , convertType ( "array_element" , subType ) ) ) ; }


private static GroupType convertStructType(final String name, final StructTypeInfo typeInfo) {
    final List<String> columnNames = typeInfo.getAllStructFieldNames();
    final List<TypeInfo> columnTypes = typeInfo.getAllStructFieldTypeInfos();
    return new GroupType(Repetition.OPTIONAL, name, convertTypes(columnNames, columnTypes));

  }

private static GroupType convertStructType ( final String name , final StructTypeInfo typeInfo ) { final List < String > columnNames = typeInfo . getAllStructFieldNames ( ) ; final List < TypeInfo > columnTypes = typeInfo . getAllStructFieldTypeInfos ( ) ; return new GroupType ( Repetition . OPTIONAL , name , convertTypes ( columnNames , columnTypes ) ) ; }

An optional group containing multiple elements


private static String annotateMessage(String message, int pos) {
    StringBuilder sb = new StringBuilder(message);
    sb.append('\n');
    for (int i = 0; i < pos; i++) {
      sb.append('-');
    }
    sb.append('^');
    return sb.toString();
  }

private static String annotateMessage ( String message , int pos ) { StringBuilder sb = new StringBuilder ( message ) ; sb . append ( ' ' ) ; for ( int i = 0 ; i < pos ; i ++ ) { sb . append ( ' ' ) ; } sb . append ( ' ' ) ; return sb . toString ( ) ; }

for pretty printing which character had the error


private void endPreviousBitPackedRun() {
    if (bitPackedRunHeaderPointer == -1) {
      // we're not currently in a bit-packed-run
      return;
    }

    // create bit-packed-header, which needs to fit in 1 byte
    byte bitPackHeader = (byte) ((bitPackedGroupCount << 1) | 1);

    // update this byte
    baos.setByte(bitPackedRunHeaderPointer, bitPackHeader);

    // mark that this run is over
    bitPackedRunHeaderPointer = -1;

    // reset the number of groups
    bitPackedGroupCount = 0;
  }

If we are currently writing a bit-packed-run, update the
bit-packed-header and consider this run to be over

does nothing if we're not currently writing a bit-packed run

If we are currently writing a bit - packed - run update the bit - packed - header and consider this run to be over


@Override
  public void readOne(TProtocol in, TProtocol out) throws TException {
    readOneStruct(in, out);
  }

@ Override public void readOne ( TProtocol in , TProtocol out ) throws TException { readOneStruct ( in , out ) ; }

reads one record from in and writes it to out
exceptions are not recoverable as record might be halfway written
@param in input protocol
@param out output protocol
@throws TException if there is an error while reading or writing


@Deprecated
  public static List<Footer> readFooters(Configuration configuration, FileStatus pathStatus) throws IOException {
    return readFooters(configuration, pathStatus, false);
  }

@ Deprecated public static List < Footer > readFooters ( Configuration configuration , FileStatus pathStatus ) throws IOException { return readFooters ( configuration , pathStatus , false ) ; }

this always returns the row groups
@param configuration a configuration
@param pathStatus a file status to read footers from
@return a list of footers
@throws IOException if an exception is thrown while reading the footers
@deprecated will be removed in 2.0.0;
use {@link ParquetFileReader#open(InputFile, ParquetReadOptions)}


@Deprecated
  public static List<Footer> readSummaryFile(Configuration configuration, FileStatus summaryStatus) throws IOException {
    final Path parent = summaryStatus.getPath().getParent();
    ParquetMetadata mergedFooters = readFooter(configuration, summaryStatus, filter(false));
    return footersFromSummaryFile(parent, mergedFooters);
  }

@ Deprecated public static List < Footer > readSummaryFile ( Configuration configuration , FileStatus summaryStatus ) throws IOException { final Path parent = summaryStatus . getPath ( ) . getParent ( ) ; ParquetMetadata mergedFooters = readFooter ( configuration , summaryStatus , filter ( false ) ) ; return footersFromSummaryFile ( parent , mergedFooters ) ; }

Specifically reads a given summary file
@param configuration a configuration
@param summaryStatus file status for a summary file
@return the metadata translated for each file
@throws IOException if an exception is thrown while reading the summary file
@deprecated metadata files are not recommended and will be removed in 2.0.0


@Deprecated
  public static final ParquetMetadata readFooter(InputFile file, MetadataFilter filter) throws IOException {
    ParquetReadOptions options;
    if (file instanceof HadoopInputFile) {
      options = HadoopReadOptions.builder(((HadoopInputFile) file).getConfiguration())
          .withMetadataFilter(filter).build();
    } else {
      options = ParquetReadOptions.builder().withMetadataFilter(filter).build();
    }

    try (SeekableInputStream in = file.newStream()) {
      return readFooter(file, options, in);
    }
  }

@ Deprecated public static final ParquetMetadata readFooter ( InputFile file , MetadataFilter filter ) throws IOException { ParquetReadOptions options ; if ( file instanceof HadoopInputFile ) { options = HadoopReadOptions . builder ( ( ( HadoopInputFile ) file ) . getConfiguration ( ) ) . withMetadataFilter ( filter ) . build ( ) ; } else { options = ParquetReadOptions . builder ( ) . withMetadataFilter ( filter ) . build ( ) ; } try ( SeekableInputStream in = file . newStream ( ) ) { return readFooter ( file , options , in ) ; } }

Reads the meta data block in the footer of the file using provided input stream
@param file a {@link InputFile} to read
@param filter the filter to apply to row groups
@return the metadata blocks in the footer
@throws IOException if an error occurs while reading the file
@deprecated will be removed in 2.0.0;
use {@link ParquetFileReader#open(InputFile, ParquetReadOptions)}


public PageReadStore readNextRowGroup() throws IOException {
    if (currentBlock == blocks.size()) {
      return null;
    }
    BlockMetaData block = blocks.get(currentBlock);
    if (block.getRowCount() == 0) {
      throw new RuntimeException("Illegal row group of 0 rows");
    }
    this.currentRowGroup = new ColumnChunkPageReadStore(block.getRowCount());
    // prepare the list of consecutive parts to read them in one scan
    List<ConsecutivePartList> allParts = new ArrayList<ConsecutivePartList>();
    ConsecutivePartList currentParts = null;
    for (ColumnChunkMetaData mc : block.getColumns()) {
      ColumnPath pathKey = mc.getPath();
      BenchmarkCounter.incrementTotalBytes(mc.getTotalSize());
      ColumnDescriptor columnDescriptor = paths.get(pathKey);
      if (columnDescriptor != null) {
        long startingPos = mc.getStartingPos();
        // first part or not consecutive => new list
        if (currentParts == null || currentParts.endPos() != startingPos) {
          currentParts = new ConsecutivePartList(startingPos);
          allParts.add(currentParts);
        }
        currentParts.addChunk(new ChunkDescriptor(columnDescriptor, mc, startingPos, (int)mc.getTotalSize()));
      }
    }
    // actually read all the chunks
    ChunkListBuilder builder = new ChunkListBuilder();
    for (ConsecutivePartList consecutiveChunks : allParts) {
      consecutiveChunks.readAll(f, builder);
    }
    for (Chunk chunk : builder.build()) {
      currentRowGroup.addColumn(chunk.descriptor.col, chunk.readAllPages());
    }

    // avoid re-reading bytes the dictionary reader is used after this call
    if (nextDictionaryReader != null) {
      nextDictionaryReader.setRowGroup(currentRowGroup);
    }

    advanceToNextBlock();

    return currentRowGroup;
  }

Reads all the columns requested from the row group at the current file position.
@throws IOException if an error occurs while reading
@return the PageReadStore which can provide PageReaders for each column.

Reads all the columns requested from the row group at the current file position .


public PageReadStore readNextFilteredRowGroup() throws IOException {
    if (currentBlock == blocks.size()) {
      return null;
    }
    if (!options.useColumnIndexFilter()) {
      return readNextRowGroup();
    }
    BlockMetaData block = blocks.get(currentBlock);
    if (block.getRowCount() == 0) {
      throw new RuntimeException("Illegal row group of 0 rows");
    }
    ColumnIndexStore ciStore = getColumnIndexStore(currentBlock);
    RowRanges rowRanges = getRowRanges(currentBlock);
    long rowCount = rowRanges.rowCount();
    if (rowCount == 0) {
      // There are no matching rows -> skipping this row-group
      advanceToNextBlock();
      return readNextFilteredRowGroup();
    }
    if (rowCount == block.getRowCount()) {
      // All rows are matching -> fall back to the non-filtering path
      return readNextRowGroup();
    }

    this.currentRowGroup = new ColumnChunkPageReadStore(rowRanges);
    // prepare the list of consecutive parts to read them in one scan
    ChunkListBuilder builder = new ChunkListBuilder();
    List<ConsecutivePartList> allParts = new ArrayList<ConsecutivePartList>();
    ConsecutivePartList currentParts = null;
    for (ColumnChunkMetaData mc : block.getColumns()) {
      ColumnPath pathKey = mc.getPath();
      ColumnDescriptor columnDescriptor = paths.get(pathKey);
      if (columnDescriptor != null) {
        OffsetIndex offsetIndex = ciStore.getOffsetIndex(mc.getPath());

        OffsetIndex filteredOffsetIndex = filterOffsetIndex(offsetIndex, rowRanges,
            block.getRowCount());
        for (OffsetRange range : calculateOffsetRanges(filteredOffsetIndex, mc, offsetIndex.getOffset(0))) {
          BenchmarkCounter.incrementTotalBytes(range.getLength());
          long startingPos = range.getOffset();
          // first part or not consecutive => new list
          if (currentParts == null || currentParts.endPos() != startingPos) {
            currentParts = new ConsecutivePartList(startingPos);
            allParts.add(currentParts);
          }
          ChunkDescriptor chunkDescriptor = new ChunkDescriptor(columnDescriptor, mc, startingPos,
              (int) range.getLength());
          currentParts.addChunk(chunkDescriptor);
          builder.setOffsetIndex(chunkDescriptor, filteredOffsetIndex);
        }
      }
    }
    // actually read all the chunks
    for (ConsecutivePartList consecutiveChunks : allParts) {
      consecutiveChunks.readAll(f, builder);
    }
    for (Chunk chunk : builder.build()) {
      currentRowGroup.addColumn(chunk.descriptor.col, chunk.readAllPages());
    }

    // avoid re-reading bytes the dictionary reader is used after this call
    if (nextDictionaryReader != null) {
      nextDictionaryReader.setRowGroup(currentRowGroup);
    }

    advanceToNextBlock();

    return currentRowGroup;
  }

Reads all the columns requested from the row group at the current file position. It may skip specific pages based
on the column indexes according to the actual filter. As the rows are not aligned among the pages of the different
columns row synchronization might be required. See the documentation of the class SynchronizingColumnReader for
details.

@return the PageReadStore which can provide PageReaders for each column
@throws IOException
if any I/O error occurs while reading

Reads all the columns requested from the row group at the current file position . It may skip specific pages based on the column indexes according to the actual filter . As the rows are not aligned among the pages of the different columns row synchronization might be required . See the documentation of the class SynchronizingColumnReader for details .