class BatchingTransactionAppender extends LifecycleAdapter implements TransactionAppender {

    @Override
    public long append( TransactionToApply batch, LogAppendEvent logAppendEvent ) throws IOException
    {
        // Assigned base tx id just to make compiler happy
        long lastTransactionId = TransactionIdStore.BASE_TX_ID;
        // Synchronized with logFile to get absolute control over concurrent rotations happening
        synchronized ( logFile )
        {
            // Assert that kernel is healthy before making any changes
            databaseHealth.assertHealthy( IOException.class );
            try ( SerializeTransactionEvent serialiseEvent = logAppendEvent.beginSerializeTransaction() )
            {
                // Append all transactions in this batch to the log under the same logFile monitor
                TransactionToApply tx = batch;
                while ( tx != null )
                {
                    long transactionId = transactionIdStore.nextCommittingTransactionId();

                    // If we're in a scenario where we're merely replicating transactions, i.e. transaction
                    // id have already been generated by another entity we simply check that our id
                    // that we generated match that id. If it doesn't we've run into a problem we can't ´
                    // really recover from and would point to a bug somewhere.
                    matchAgainstExpectedTransactionIdIfAny( transactionId, tx );

                    TransactionCommitment commitment = appendToLog( tx.transactionRepresentation(), transactionId );
                    tx.commitment( commitment, transactionId );
                    tx.logPosition( commitment.logPosition() );
                    tx = tx.next();
                    lastTransactionId = transactionId;
                }
            }
        }

        // At this point we've appended all transactions in this batch, but we can't mark any of them
        // as committed since they haven't been forced to disk yet. So here we force, or potentially
        // piggy-back on another force, but anyway after this call below we can be sure that all our transactions
        // in this batch exist durably on disk.
        if ( forceAfterAppend( logAppendEvent ) )
        {
            // We got lucky and were the one forcing the log. It's enough if ones of all doing concurrent committers
            // checks the need for log rotation.
            boolean logRotated = logRotation.rotateLogIfNeeded( logAppendEvent );
            logAppendEvent.setLogRotated( logRotated );
        }

        // Mark all transactions as committed
        publishAsCommitted( batch );

        return lastTransactionId;
    }

    public  BatchingTransactionAppender( LogFiles logFiles, LogRotation logRotation,
            TransactionMetadataCache transactionMetadataCache, TransactionIdStore transactionIdStore,
            IdOrderingQueue explicitIndexTransactionOrdering, DatabaseHealth databaseHealth );

}