class AbstractProxyTransaction implements Identifiable<TransactionIdentifier> {

    final ListenableFuture<Boolean> directCommit() {
        checkReadWrite();
        checkSealed();

        // Precludes startReconnect() from interfering with the fast path
        synchronized (this) {
            if (STATE_UPDATER.compareAndSet(this, SEALED, FLUSHED)) {
                final SettableFuture<Boolean> ret = SettableFuture.create();
                sendRequest(verifyNotNull(commitRequest(false)), t -> {
                    if (t instanceof TransactionCommitSuccess) {
                        ret.set(Boolean.TRUE);
                    } else if (t instanceof RequestFailure) {
                        final Throwable cause = ((RequestFailure<?, ?>) t).getCause().unwrap();
                        if (cause instanceof ClosedTransactionException) {
                            // This is okay, as it indicates the transaction has been completed. It can happen
                            // when we lose connectivity with the backend after it has received the request.
                            ret.set(Boolean.TRUE);
                        } else {
                            ret.setException(cause);
                        }
                    } else {
                        ret.setException(unhandledResponseException(t));
                    }

                    // This is a terminal request, hence we do not need to record it
                    LOG.debug("Transaction {} directCommit completed", this);
                    enqueuePurge();
                });

                return ret;
            }
        }

        // We have had some interference with successor injection, wait for it to complete and defer to the successor.
        return awaitSuccessor().directCommit();
    }

      AbstractProxyTransaction(final ProxyHistory parent, final boolean isDone);

}