package edu.brown.hstore.handlers;
import java.io.IOException;
import org.apache.log4j.Logger;
import org.voltdb.VoltTable;
import org.voltdb.exceptions.ServerFaultException;
import org.voltdb.messaging.FastDeserializer;
import com.google.protobuf.RpcCallback;
import com.google.protobuf.RpcController;
import edu.brown.hstore.HStoreCoordinator;
import edu.brown.hstore.HStoreSite;
import edu.brown.hstore.Hstoreservice.HStoreService;
import edu.brown.hstore.Hstoreservice.Status;
import edu.brown.hstore.Hstoreservice.TransactionPrefetchAcknowledgement;
import edu.brown.hstore.Hstoreservice.TransactionPrefetchResult;
import edu.brown.hstore.Hstoreservice.WorkResult;
import edu.brown.hstore.PartitionExecutor;
import edu.brown.hstore.txns.LocalTransaction;
import edu.brown.logging.LoggerUtil;
import edu.brown.logging.LoggerUtil.LoggerBoolean;
import edu.brown.protorpc.ProtoRpcController;
import edu.brown.utils.PartitionSet;
/**
* Process TransactionPrefetchResult sent from remote sites for prefetched queries
* @author pavlo
*/
public class TransactionPrefetchHandler extends AbstractTransactionHandler<TransactionPrefetchResult, TransactionPrefetchAcknowledgement> {
private static final Logger LOG = Logger.getLogger(TransactionWorkHandler.class);
private static final LoggerBoolean debug = new LoggerBoolean();
private static final LoggerBoolean trace = new LoggerBoolean();
static {
LoggerUtil.attachObserver(LOG, debug, trace);
}
private final FastDeserializer fds = new FastDeserializer();
public TransactionPrefetchHandler(HStoreSite hstore_site, HStoreCoordinator hstore_coord) {
super(hstore_site, hstore_coord);
}
@Override
public void sendLocal(Long txn_id, TransactionPrefetchResult request, PartitionSet partitions, RpcCallback<TransactionPrefetchAcknowledgement> callback) {
// TODO
}
@Override
public void sendRemote(HStoreService channel, ProtoRpcController controller, TransactionPrefetchResult request, RpcCallback<TransactionPrefetchAcknowledgement> callback) {
channel.transactionPrefetch(controller, request, callback);
}
@Override
public void remoteQueue(RpcController controller, TransactionPrefetchResult request, RpcCallback<TransactionPrefetchAcknowledgement> callback) {
if (debug.val)
LOG.debug(String.format("Executing %s using remote handler for txn #%d",
request.getClass().getSimpleName(), request.getTransactionId()));
this.remoteHandler(controller, request, callback);
}
@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.val)
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.
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 stmtCounter = request.getStmtCounter(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(ts, stmtCounter, 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
TransactionPrefetchAcknowledgement response = TransactionPrefetchAcknowledgement.newBuilder()
.setTransactionId(txn_id.longValue())
.setTargetPartition(request.getSourcePartition())
.build();
callback.run(response);
}
@Override
protected ProtoRpcController getProtoRpcController(LocalTransaction ts, int site_id) {
return ts.getTransactionWorkController(site_id);
}
}