class RaftLogShipper {

    public synchronized void onNewEntries( long prevLogIndex, long prevLogTerm, RaftLogEntry[] newLogEntries,
                                           LeaderContext leaderContext )
    {
        if ( mode == Mode.PIPELINE )
        {
            while ( lastSentIndex <= prevLogIndex )
            {
                if ( prevLogIndex - matchIndex <= maxAllowedShippingLag )
                {
                    // all sending functions update lastSentIndex
                    sendNewEntries( prevLogIndex, prevLogTerm, newLogEntries, leaderContext );
                }
                else
                {
                    /* The timer is still set at this point. Either we will send the next batch
                     * as soon as the follower has caught up with the last pipelined entry,
                     * or when we timeout and resend. */
                    log.info( "%s: follower has fallen behind (target prevLogIndex was %d, maxAllowedShippingLag " +
                              "is %d), moving to CATCHUP mode", statusAsString(), prevLogIndex,
                            maxAllowedShippingLag );
                    mode = Mode.CATCHUP;
                    break;
                }
            }
        }

        lastLeaderContext = leaderContext;
    }

      RaftLogShipper( Outbound<MemberId, RaftMessages.RaftMessage> outbound, LogProvider logProvider,
                    ReadableRaftLog raftLog, Clock clock, TimerService timerService,
                    MemberId leader, MemberId follower, long leaderTerm, long leaderCommit, long retryTimeMillis,
                    int catchupBatchSize, int maxAllowedShippingLag, InFlightCache inFlightCache );

}