public CompletedTransactionStatus getTransactionStatus(GlobalTransaction gtx) {
      CompletedTransactionInfo completedTx = completedTransactions.get(gtx);
      if (completedTx != null) {
        return completedTx.successful
            ? CompletedTransactionStatus.COMMITTED
            : CompletedTransactionStatus.ABORTED;
      }

      // Transaction ids are allocated in sequence, so any transaction with a smaller id must have
      // been started
      // before a transaction that was already removed from the completed transactions map because
      // it was too old.
      // We assume that the transaction was either committed, or it was rolled back (e.g. because
      // the prepare
      // RPC timed out.
      // Note: We must check the id *after* verifying that the tx doesn't exist in the map.
      if (gtx.getId() > globalMaxPrunedTxId) return CompletedTransactionStatus.NOT_COMPLETED;
      Long nodeMaxPrunedTxId = nodeMaxPrunedTxIds.get(gtx.getAddress());
      if (nodeMaxPrunedTxId == null) {
        // We haven't removed any transaction for this node
        return CompletedTransactionStatus.NOT_COMPLETED;
      } else if (gtx.getId() > nodeMaxPrunedTxId) {
        // We haven't removed this particular transaction yet
        return CompletedTransactionStatus.NOT_COMPLETED;
      } else {
        // We already removed the status of this transaction from the completed transactions map
        return CompletedTransactionStatus.EXPIRED;
      }
    }
    /** @see #markTransactionCompleted(GlobalTransaction, boolean) */
    public boolean isTransactionCompleted(GlobalTransaction gtx) {
      if (completedTransactions.containsKey(gtx)) return true;

      // Transaction ids are allocated in sequence, so any transaction with a smaller id must have
      // been started
      // before a transaction that was already removed from the completed transactions map because
      // it was too old.
      // We assume that the transaction was either committed, or it was rolled back (e.g. because
      // the prepare
      // RPC timed out.
      // Note: We must check the id *after* verifying that the tx doesn't exist in the map.
      if (gtx.getId() > globalMaxPrunedTxId) return false;
      Long nodeMaxPrunedTxId = nodeMaxPrunedTxIds.get(gtx.getAddress());
      return nodeMaxPrunedTxId != null && gtx.getId() <= nodeMaxPrunedTxId;
    }