package edu.brown.hstore.handlers;
import org.apache.log4j.Logger;
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.TransactionFinishRequest;
import edu.brown.hstore.Hstoreservice.TransactionFinishResponse;
import edu.brown.hstore.callbacks.PartitionCountingCallback;
import edu.brown.hstore.dispatchers.AbstractDispatcher;
import edu.brown.hstore.txns.AbstractTransaction;
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;
public class TransactionFinishHandler extends AbstractTransactionHandler<TransactionFinishRequest, TransactionFinishResponse> {
private static final Logger LOG = Logger.getLogger(TransactionFinishHandler.class);
private static final LoggerBoolean debug = new LoggerBoolean();
static {
LoggerUtil.attachObserver(LOG, debug);
}
final AbstractDispatcher<Object[]> finishDispatcher;
// Reusable container for the partitions that we need to
// use to tell the HStoreSite that we're finished with
// This is thread-safe
final PartitionSet finishPartitions = new PartitionSet();
public TransactionFinishHandler(HStoreSite hstore_site, HStoreCoordinator hstore_coord, AbstractDispatcher<Object[]> finishDispatcher) {
super(hstore_site, hstore_coord);
this.finishDispatcher = finishDispatcher;
}
@Override
public void sendLocal(Long txn_id, TransactionFinishRequest request, PartitionSet partitions,
RpcCallback<TransactionFinishResponse> callback) {
this.hstore_site.transactionFinish(txn_id, request.getStatus(), partitions);
}
@Override
public void sendRemote(HStoreService channel, ProtoRpcController controller, TransactionFinishRequest request,
RpcCallback<TransactionFinishResponse> callback) {
channel.transactionFinish(controller, request, callback);
}
@Override
public void remoteQueue(RpcController controller, TransactionFinishRequest request,
RpcCallback<TransactionFinishResponse> callback) {
if (this.finishDispatcher != null && request.getStatus() == Status.ABORT_RESTART) {
if (debug.val)
LOG.debug(String.format("Queuing %s for txn #%d [status=%s]",
request.getClass().getSimpleName(), request.getTransactionId(), request.getStatus()));
Object o[] = { controller, request, callback };
this.finishDispatcher.queue(o);
} else {
if (debug.val)
LOG.debug(String.format("Sending %s to remote handler for txn #%d [status=%s]",
request.getClass().getSimpleName(), request.getTransactionId(), request.getStatus()));
this.remoteHandler(controller, request, callback);
}
}
@Override
public void remoteHandler(RpcController controller, TransactionFinishRequest request,
RpcCallback<TransactionFinishResponse> 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 [status=%s]",
request.getClass().getSimpleName(), txn_id, request.getStatus()));
// Cancel the InitCallback if it hasn't been invoked yet
AbstractTransaction ts = this.hstore_site.getTransaction(txn_id);
if (ts != null) {
PartitionCountingCallback<AbstractTransaction> initCallback = ts.getInitCallback();
if (initCallback.isUnblocked() == false && initCallback.isAborted() == false) {
initCallback.cancel();
}
}
this.finishPartitions.clear();
this.finishPartitions.addAll(request.getPartitionsList());
this.hstore_site.transactionFinish(txn_id, request.getStatus(), this.finishPartitions);
// Send back a FinishResponse to let them know we're cool with everything...
TransactionFinishResponse.Builder builder = TransactionFinishResponse.newBuilder()
.setTransactionId(txn_id);
for (int p : request.getPartitionsList()) {
if (hstore_site.isLocalPartition(p)) builder.addPartitions(p);
} // FOR
if (debug.val)
LOG.debug(String.format("Sending back %s for txn #%d [status=%s, partitions=%s]",
TransactionFinishResponse.class.getSimpleName(), txn_id,
request.getStatus(), builder.getPartitionsList()));
callback.run(builder.build());
}
@Override
protected ProtoRpcController getProtoRpcController(LocalTransaction ts, int site_id) {
return ts.getTransactionFinishController(site_id);
}
}