package edu.brown.hstore.callbacks;
import org.apache.log4j.Logger;
import edu.brown.hstore.Hstoreservice.Status;
import edu.brown.hstore.Hstoreservice.TransactionMapResponse;
import edu.brown.logging.LoggerUtil;
import edu.brown.logging.LoggerUtil.LoggerBoolean;
import edu.brown.hstore.HStoreSite;
import edu.brown.hstore.txns.MapReduceTransaction;
/**
* This callback waits until all of the TransactionMapResponses have come
* back from all other partitions in the cluster. The unblockCallback will
* switch the MapReduceTransaction handle into the REDUCE phase and then requeue
* it at the local HStoreSite
* @author pavlo
*/
public class TransactionMapCallback extends AbstractTransactionCallback<MapReduceTransaction, TransactionMapResponse, TransactionMapResponse> {
private static final Logger LOG = Logger.getLogger(TransactionMapCallback.class);
private static final LoggerBoolean debug = new LoggerBoolean();
private static final LoggerBoolean trace = new LoggerBoolean();
static {
LoggerUtil.attachObserver(LOG, debug, trace);
}
/**
* Constructor
* @param hstore_site
*/
public TransactionMapCallback(HStoreSite hstore_site) {
super(hstore_site);
}
public void init(MapReduceTransaction ts) {
assert(this.isInitialized() == false) :
String.format("Trying to initialize %s twice! [origTs=%s, newTs=%s]",
this.getClass().getSimpleName(), this.ts, ts);
super.init(ts, ts.getPredictTouchedPartitions().size(), null);
}
/**
* This gets invoked after all of the partitions have finished
* executing the map phase for this txn
*/
@Override
protected void unblockTransactionCallback() {
if (debug.val)
LOG.debug(ts + " is ready to execute. Passing to HStoreSite " +
"<Switching to the 'reduce' phase>.......");
MapReduceTransaction mr_ts = (MapReduceTransaction)this.ts;
mr_ts.setReducePhase();
assert(mr_ts.isReducePhase());
mr_ts.resetTransaction();
if (hstore_site.getHStoreConf().site.mr_reduce_blocking){
if (debug.val)
LOG.debug(ts + ": $$$ normal reduce blocking execution way");
// calling this hstore_site.transactionStart function will block the executing engine on each partition
hstore_site.transactionStart(ts);
} else {
// throw reduce job to MapReduceHelperThread to do
if (debug.val)
LOG.debug(ts + ": $$$ non-blocking reduce execution by MapReduceHelperThread");
hstore_site.getMapReduceHelper().queue(mr_ts);
}
}
@Override
protected boolean abortTransactionCallback(Status status) {
assert(this.isInitialized()) : "ORIG TXN: " + this.getTransactionId();
return (true);
}
@Override
protected int runImpl(TransactionMapResponse response) {
if (debug.val)
LOG.debug(String.format("Got %s with status %s for %s [partitions=%s]",
response.getClass().getSimpleName(),
response.getStatus(),
this.ts,
response.getPartitionsList()));
assert(this.ts != null) :
String.format("Missing LocalTransaction handle for txn #%d [status=%s]",
response.getTransactionId(), response.getStatus());
// Otherwise, make sure it's legit
assert(this.ts.getTransactionId().longValue() == response.getTransactionId()) :
String.format("Unexpected %s for a different transaction %s != #%d [expected=#%d]",
response.getClass().getSimpleName(), this.ts, response.getTransactionId(), this.getTransactionId());
if (response.getStatus() != Status.OK || this.isAborted()) {
this.abort(response.getStatus());
}
return (response.getPartitionsCount());
}
}