@Override
  public void remoteHandler(
      RpcController controller,
      TransactionPrepareRequest request,
      RpcCallback<TransactionPrepareResponse> callback) {
    assert (request.hasTransactionId())
        : "Got " + request.getClass().getSimpleName() + " without a txn id!";
    Long txn_id = Long.valueOf(request.getTransactionId());
    if (debug.val)
      LOG.debug(String.format("Got %s for txn #%d", request.getClass().getSimpleName(), txn_id));

    // HACK
    // Use a TransactionPrepareWrapperCallback to ensure that we only send back
    // the prepare response once all of the PartitionExecutors have successfully
    // acknowledged that we're ready to commit
    PartitionSet partitions = new PartitionSet(request.getPartitionsList());
    assert (partitions.isEmpty() == false)
        : "Unexpected empty list of updated partitions for txn #" + txn_id;
    partitions.retainAll(hstore_site.getLocalPartitionIds());

    RemoteTransaction ts = this.hstore_site.getTransaction(txn_id);
    assert (ts != null) : "Unexpected null transaction handle for txn #" + txn_id;

    // Always create a new prepare callback because we may get multiple messages
    // to prepare this txn for commit.
    RemotePrepareCallback wrapper = ts.getPrepareCallback();
    assert (wrapper.isInitialized() == false);
    wrapper.init(ts, partitions, callback);

    this.hstore_site.transactionPrepare(ts, partitions, wrapper);
  }
  public void init(
      RemoteTransaction ts,
      PartitionSet partitions,
      RpcCallback<TransactionPrepareResponse> origCallback) {
    this.builder =
        TransactionPrepareResponse.newBuilder()
            .setTransactionId(ts.getTransactionId().longValue())
            .setStatus(Status.OK);
    this.origCallback = origCallback;

    // Remove non-local partitions
    this.localPartitions.clear();
    this.localPartitions.addAll(partitions);
    this.localPartitions.retainAll(this.hstore_site.getLocalPartitionIds());
    super.init(ts, this.localPartitions);
  }