class TransactionContextWrapper {

    void executePriorTransactionOperations(final TransactionContext localTransactionContext) {
        while (true) {
            // Access to queuedTxOperations and transactionContext must be protected and atomic
            // (ie synchronized) with respect to #addTxOperationOnComplete to handle timing
            // issues and ensure no TransactionOperation is missed and that they are processed
            // in the order they occurred.

            // We'll make a local copy of the queuedTxOperations list to handle re-entrancy
            // in case a TransactionOperation results in another transaction operation being
            // queued (eg a put operation from a client read Future callback that is notified
            // synchronously).
            final Collection<Entry<TransactionOperation, Boolean>> operationsBatch;
            synchronized (queuedTxOperations) {
                if (queuedTxOperations.isEmpty()) {
                    if (!pendingEnqueue) {
                        // We're done invoking the TransactionOperations so we can now publish the TransactionContext.
                        localTransactionContext.operationHandOffComplete();

                        // This is null-to-non-null transition after which we are releasing the lock and not doing
                        // any further processing.
                        transactionContext = localTransactionContext;
                    } else {
                        deferredTransactionContext = localTransactionContext;
                    }
                    return;
                }

                operationsBatch = new ArrayList<>(queuedTxOperations);
                queuedTxOperations.clear();
            }

            // Invoke TransactionOperations outside the sync block to avoid unnecessary blocking. A slight down-side is
            // that we need to re-acquire the lock below but this should be negligible.
            for (Entry<TransactionOperation, Boolean> oper : operationsBatch) {
                final Boolean permit = oper.getValue();
                if (permit.booleanValue() && !localTransactionContext.usesOperationLimiting()) {
                    // If the context is not using limiting we need to release operations as we are queueing them, so
                    // user threads are not charged for them.
                    limiter.release();
                }
                oper.getKey().invoke(localTransactionContext, permit);
            }
        }
    }

      TransactionContextWrapper(final TransactionIdentifier identifier, final ActorUtils actorUtils,
            final String shardName);

}