@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); }