/**
   * Do the commit. This is the 2nd phase of the 2-phase protocol.
   *
   * @param transactionState
   * @throws CommitUnsuccessfulException
   */
  void doCommit(final TransactionState transactionState) throws CommitUnsuccessfulException {
    try {
      LOG.trace("Commiting [" + transactionState.getTransactionId() + "]");

      transactionLogger.setStatusForTransaction(
          transactionState.getTransactionId(), TransactionLogger.TransactionStatus.COMMITTED);

      for (HRegionLocation location : transactionState.getParticipatingRegions()) {
        if (transactionState.getRegionsToIngore().contains(location)) {
          continue;
        }
        TransactionalRegionInterface transactionalRegionServer =
            (TransactionalRegionInterface)
                connection.getHRegionConnection(location.getServerAddress());
        transactionalRegionServer.commit(
            location.getRegionInfo().getRegionName(), transactionState.getTransactionId());
      }
    } catch (Exception e) {
      LOG.info(
          "Commit of transaction [" + transactionState.getTransactionId() + "] was unsucsessful",
          e);
      // This happens on a NSRE that is triggered by a split
      try {
        abort(transactionState);
      } catch (Exception abortException) {
        LOG.warn("Exeption durring abort", abortException);
      }
      throw new CommitUnsuccessfulException(e);
    }
    transactionLogger.forgetTransaction(transactionState.getTransactionId());
  }
  public static void testBeginEndEmpty(int numtx) throws IOException, CommitUnsuccessfulException {

    PrintWriter out = new PrintWriter(new File("TEmptyTest.txt"));
    out.println("\nTransactionEmptyTest ENTRY");

    double begin_latency = 0;
    double end_latency = 0;
    double abort_latency = 0;
    int newValue = 0;

    for (newValue = 0; newValue < numtx; newValue++) {
      // Begin
      long ts1 = System.nanoTime();
      TransactionState transactionState = transactionManager.beginTransaction();
      long ts2 = System.nanoTime();
      long latency = ts2 - ts1;
      double latency2 = (double) latency / 1000000000;

      begin_latency = begin_latency + latency2;

      // End
      ts1 = System.nanoTime();
      transactionManager.tryCommit(transactionState);
      ts2 = System.nanoTime();
      latency = ts2 - ts1;
      latency2 = (double) latency / 1000000000;

      end_latency = end_latency + latency2;

      transactionState = transactionManager.beginTransaction();

      // Abort
      ts1 = System.nanoTime();
      transactionManager.abort(transactionState);
      ts2 = System.nanoTime();
      latency = ts2 - ts1;
      latency2 = (double) latency / 1000000000;

      abort_latency = abort_latency + latency2;
    }

    out.println("\nAverage Begin latency : " + (double) (begin_latency / newValue));
    out.println("Average End latency  : " + (double) (end_latency / newValue));
    out.println("Average Abort latency  : " + (double) (abort_latency / newValue));
    out.println("newValue  : " + newValue);
    out.println("\ntestGetAfterPut EXIT");
    out.close();
  }
  /**
   * Prepare to commit a transaction.
   *
   * @param transactionState
   * @return commitStatusCode (see {@link TransactionalRegionInterface})
   * @throws IOException
   * @throws CommitUnsuccessfulException
   */
  public int prepareCommit(final TransactionState transactionState)
      throws CommitUnsuccessfulException, IOException {
    boolean allReadOnly = true;
    try {

      for (HRegionLocation location : transactionState.getParticipatingRegions()) {

        TransactionalRegionInterface transactionalRegionServer =
            (TransactionalRegionInterface)
                connection.getHRegionConnection(location.getServerAddress());
        int commitStatus =
            transactionalRegionServer.commitRequest(
                location.getRegionInfo().getRegionName(), transactionState.getTransactionId());
        boolean canCommit = true;
        switch (commitStatus) {
          case TransactionalRegionInterface.COMMIT_OK:
            allReadOnly = false;
            break;
          case TransactionalRegionInterface.COMMIT_OK_READ_ONLY:
            transactionState.addRegionToIgnore(location); // No need to doCommit for read-onlys
            break;
          case TransactionalRegionInterface.COMMIT_UNSUCESSFUL:
            canCommit = false;
            transactionState.addRegionToIgnore(location); // No need to re-abort.
            break;
          default:
            throw new CommitUnsuccessfulException(
                "Unexpected return code from prepareCommit: " + commitStatus);
        }

        if (LOG.isTraceEnabled()) {
          LOG.trace(
              "Region ["
                  + location.getRegionInfo().getRegionNameAsString()
                  + "] votes "
                  + (canCommit ? "to commit" : "to abort")
                  + " transaction "
                  + transactionState.getTransactionId());
        }

        if (!canCommit) {
          LOG.debug("Aborting [" + transactionState.getTransactionId() + "]");
          abort(transactionState);
          return TransactionalRegionInterface.COMMIT_UNSUCESSFUL;
        }
      }
    } catch (Exception e) {
      LOG.debug(
          "Commit of transaction [" + transactionState.getTransactionId() + "] was unsucsessful",
          e);
      // This happens on a NSRE that is triggered by a split
      try {
        abort(transactionState);
      } catch (Exception abortException) {
        LOG.warn("Exeption durring abort", abortException);
      }
      throw new CommitUnsuccessfulException(e);
    }
    return allReadOnly
        ? TransactionalRegionInterface.COMMIT_OK_READ_ONLY
        : TransactionalRegionInterface.COMMIT_OK;
  }
  public static void testGetAfterPut2(int numtx) throws IOException, CommitUnsuccessfulException {

    PrintWriter out = new PrintWriter(new File("TWorkTest.txt"));

    out.println("\nTransactionWithWorkTest ENTRY");

    double begin_latency = 0;
    double end_latency = 0;
    double put_latency = 0;
    double get_latency = 0;
    double delete_latency = 0;
    double abort_latency = 0;
    int newValue = 0;

    double hput_latency = 0;
    double hget_latency = 0;
    double hdelete_latency = 0;

    for (newValue = 0; newValue < numtx; newValue++) {
      // Begin
      long ts1 = System.nanoTime();
      TransactionState transactionState = transactionManager.beginTransaction();
      long ts2 = System.nanoTime();
      long latency = ts2 - ts1;
      double latency2 = (double) latency / 1000000000;

      begin_latency = begin_latency + latency2;

      // Put
      ts1 = System.nanoTime();
      table.put(transactionState, new Put(ROW1).add(FAMILY, QUAL_A, Bytes.toBytes(newValue)));
      ts2 = System.nanoTime();
      latency = ts2 - ts1;
      latency2 = (double) latency / 1000000000;

      put_latency = put_latency + latency2;

      // Abort
      System.nanoTime();
      transactionManager.abort(transactionState);
      try {
        transactionState.completeRequest();
      } catch (Exception e) {
        System.out.println("\nCAUGHT\n");
      }
      ts2 = System.nanoTime();
      latency = ts2 - ts1;
      latency2 = (double) latency / 1000000000;

      abort_latency = abort_latency + latency2;

      transactionState = transactionManager.beginTransaction();
      table.put(transactionState, new Put(ROW1).add(FAMILY, QUAL_A, Bytes.toBytes(newValue)));

      // End
      ts1 = System.nanoTime();
      transactionManager.tryCommit(transactionState);
      try {
        transactionState.completeRequest();
      } catch (Exception e) {
        System.out.println("\nCAUGHT\n");
      }
      ts2 = System.nanoTime();
      latency = ts2 - ts1;
      latency2 = (double) latency / 1000000000;

      end_latency = end_latency + latency2;

      transactionState = transactionManager.beginTransaction();
      table.put(transactionState, new Put(ROW1).add(FAMILY, QUAL_A, Bytes.toBytes(newValue)));

      // Get
      ts1 = System.nanoTime();
      Result row1_A = table.get(new Get(ROW1).addColumn(FAMILY, QUAL_A));
      ts2 = System.nanoTime();
      latency = ts2 - ts1;
      latency2 = (double) latency / 1000000000;

      get_latency = get_latency + latency2;

      transactionManager.tryCommit(transactionState);
      try {
        transactionState.completeRequest();
      } catch (Exception e) {
        System.out.println("\nCAUGHT\n");
      }

      int expected = Bytes.toInt(row1_A.getValue(FAMILY, QUAL_A));
      if (newValue != expected)
        System.out.println(
            "\ntestGetAfterPut : Assert 1 FAILED : expected "
                + expected
                + "newValue "
                + newValue
                + "\n");

      transactionState = transactionManager.beginTransaction();
      table.put(transactionState, new Put(ROW1).add(FAMILY, QUAL_A, Bytes.toBytes(newValue)));

      // Delete
      ts1 = System.nanoTime();
      table.delete(transactionState, new Delete(ROW1).deleteColumns(FAMILY, QUAL_A));
      ts2 = System.nanoTime();
      latency = ts2 - ts1;
      latency2 = (double) latency / 1000000000;

      delete_latency = delete_latency + latency2;

      transactionManager.tryCommit(transactionState);
      try {
        transactionState.completeRequest();
      } catch (Exception e) {
        System.out.println("\nCAUGHT\n");
      }
    }

    out.println("\nAverage Begin latency : " + (double) (begin_latency / newValue));
    out.println("Average End latency  : " + (double) (end_latency / newValue));
    out.println("Average Abort latency : " + (double) (abort_latency / newValue));
    out.println("Average Put latency  : " + (double) (put_latency / newValue));
    out.println("Average Get latency  : " + (double) (get_latency / newValue));
    out.println("Average Delete latency : " + (double) (delete_latency / newValue));
    out.println("Average HPut latency  : " + (double) (hput_latency / newValue));
    out.println("Average HGet latency  : " + (double) (hget_latency / newValue));
    out.println("\ntestGetAfterPut EXIT");
    out.close();
  }