@Override
 public void sendLocal(
     Long txn_id,
     TransactionPrepareRequest request,
     PartitionSet partitions,
     RpcCallback<TransactionPrepareResponse> callback) {
   // We don't care whether we actually updated anybody locally, so we don't need to
   // pass in a set to get the partitions that were updated here.
   LocalTransaction ts = this.hstore_site.getTransaction(txn_id);
   assert (ts != null) : "Unexpected null transaction handle for txn #" + txn_id;
   this.hstore_site.transactionPrepare(ts, partitions, ts.getPrepareCallback());
 }
  /**
   * Send a copy of a single message request to the partitions given as input If a partition is
   * managed by the local HStoreSite, then we will invoke the sendLocal() method. If it is on a
   * remote HStoreSite, then we will invoke sendRemote().
   *
   * @param ts
   * @param request
   * @param callback
   * @param partitions
   */
  public void sendMessages(
      LocalTransaction ts, T request, RpcCallback<U> callback, PartitionSet partitions) {
    // If this flag is true, then we'll invoke the local method
    // We want to do this *after* we send out all the messages to the remote sites
    // so that we don't have to wait as long for the responses to come back over the network
    boolean send_local = false;
    boolean site_sent[] = new boolean[this.num_sites];

    if (debug.val)
      LOG.debug(
          String.format(
              "Sending %s to %d partitions for %s",
              request.getClass().getSimpleName(), partitions.size(), ts));

    for (int partition : partitions.values()) {
      int dest_site_id = hstore_site.getCatalogContext().getSiteIdForPartitionId(partition);

      // Skip this HStoreSite if we're already sent it a message
      if (site_sent[dest_site_id]) continue;

      if (trace.val)
        LOG.trace(
            String.format(
                "Sending %s message to %s for %s",
                request.getClass().getSimpleName(),
                HStoreThreadManager.formatSiteName(dest_site_id),
                ts));

      // Local Partition
      if (this.local_site_id == dest_site_id) {
        send_local = true;
      }
      // Remote Partition
      else {
        HStoreService channel = coordinator.getChannel(dest_site_id);
        assert (channel != null) : "Invalid partition id '" + partition + "'";
        ProtoRpcController controller = this.getProtoRpcController(ts, dest_site_id);
        assert (controller != null)
            : "Invalid "
                + request.getClass().getSimpleName()
                + " ProtoRpcController for site #"
                + dest_site_id;
        this.sendRemote(channel, controller, request, callback);
      }
      site_sent[dest_site_id] = true;
    } // FOR
    // Optimization: We'll invoke sendLocal() after we have sent out
    // all of the messages to remote sites
    if (send_local) this.sendLocal(ts.getTransactionId(), request, partitions, callback);
  }
 @Override
 protected ProtoRpcController getProtoRpcController(LocalTransaction ts, int site_id) {
   return ts.getTransactionWorkController(site_id);
 }
  @Override
  public void remoteHandler(
      RpcController controller,
      TransactionPrefetchResult request,
      RpcCallback<TransactionPrefetchAcknowledgement> callback) {
    assert (request.hasTransactionId())
        : "Got " + request.getClass().getSimpleName() + " without a txn id!";
    Long txn_id = Long.valueOf(request.getTransactionId());
    if (debug.get())
      LOG.debug(
          String.format(
              "Got %s for txn #%d [remotePartition=%d]",
              request.getClass().getSimpleName(), txn_id, request.getSourcePartition()));

    // We should never a get a TransactionPrefetchResult for a transaction that
    // we don't know about.
    // XXX: No I think it's ok because we
    LocalTransaction ts = hstore_site.getTransaction(txn_id);
    if (ts == null) {
      String msg =
          String.format(
              "Unexpected transaction id %d for incoming %s",
              txn_id, request.getClass().getSimpleName());
      throw new ServerFaultException(msg, txn_id);
    }

    // We want to store this before sending back the acknowledgment so that the transaction can get
    // access to it right away
    PartitionExecutor executor = hstore_site.getPartitionExecutor(ts.getBasePartition());
    WorkResult result = request.getResult();

    if (result.getStatus() != Status.OK) {
      // TODO: Process error!
    } else {
      for (int i = 0, cnt = result.getDepIdCount(); i < cnt; i++) {
        int fragmentId = request.getFragmentId(i);
        int paramsHash = request.getParamHash(i);

        VoltTable vt = null;
        try {
          this.fds.setBuffer(result.getDepData(i).asReadOnlyByteBuffer());
          vt = this.fds.readObject(VoltTable.class);
        } catch (IOException ex) {
          throw new RuntimeException(ex);
        }

        executor.addPrefetchResult(
            txn_id, fragmentId, request.getSourcePartition(), paramsHash, vt);
      } // FOR
    }

    // I don't think we even need to bother wasting our time sending an acknowledgement
    // We would like to cancel but we can't do that on the "server" side
    // controller.startCancel();

    //        TransactionPrefetchAcknowledgement response =
    // TransactionPrefetchAcknowledgement.newBuilder()
    //
    // .setTransactionId(txn_id.longValue())
    //
    // .setTargetPartition(request.getSourcePartition())
    //                                                            .build();
    //        callback.run(response);
  }