package org.voltdb.regressionsuites.specexecprocs;
import java.util.concurrent.Semaphore;
import org.apache.log4j.Logger;
import org.voltdb.ProcInfo;
import org.voltdb.VoltTable;
import edu.brown.benchmark.smallbank.procedures.SendPayment;
import edu.brown.profilers.ProfileMeasurement;
/**
* Special version of SmallBank's SendPayment that is blockable
* @author pavlo
*/
@ProcInfo(
partitionParam = 0,
singlePartition = false
)
public class BlockingSendPayment extends SendPayment {
private static final Logger LOG = Logger.getLogger(BlockingSendPayment.class);
public final Semaphore LOCK_BEFORE = new Semaphore(0);
public final Semaphore NOTIFY_BEFORE = new Semaphore(0);
public final Semaphore LOCK_AFTER = new Semaphore(0);
public final Semaphore NOTIFY_AFTER = new Semaphore(0);
public VoltTable[] run(long sendAcct, long destAcct, double amount) {
try {
return _run(sendAcct, destAcct, amount);
} finally {
LOCK_BEFORE.drainPermits();
LOCK_AFTER.drainPermits();
NOTIFY_BEFORE.drainPermits();
NOTIFY_AFTER.drainPermits();
}
}
private VoltTable[] _run(long sendAcct, long destAcct, double amount) {
// If this is the second time that we are running (i.e., this
// txn has been restarted before), then we don't want to block on
// any of the locks.
boolean takeLocks = (this.getTransactionState().getRestartCounter() == 0);
// -------------------- LOCK BEFORE QUERY --------------------
ProfileMeasurement pm_before = new ProfileMeasurement("BEFORE");
LOG.info(this.getTransactionState() + " - Blocking until LOCK_BEFORE is released");
pm_before.start();
try {
// Notify others before we lock
NOTIFY_BEFORE.release();
if (takeLocks) LOCK_BEFORE.acquire();
} catch (InterruptedException ex) {
ex.printStackTrace();
throw new VoltAbortException(ex.getMessage());
} finally {
NOTIFY_BEFORE.drainPermits();
pm_before.stop();
LOG.info("AWAKE - " + pm_before.debug());
}
// BATCH #1
voltQueueSQL(GetAccount, sendAcct);
voltQueueSQL(GetAccount, destAcct);
final VoltTable acctResults[] = voltExecuteSQL();
assert(acctResults != null);
// BATCH #2
voltQueueSQL(GetCheckingBalance, sendAcct);
final VoltTable balResults[] = voltExecuteSQL();
assert(balResults != null);
// BATCH #3
voltQueueSQL(UpdateCheckingBalance, amount*-1d, sendAcct);
voltQueueSQL(UpdateCheckingBalance, amount, destAcct);
final VoltTable updateResults[] = voltExecuteSQL();
// -------------------- LOCK AFTER QUERY --------------------
ProfileMeasurement pm_after = new ProfileMeasurement("AFTER");
LOG.info(this.getTransactionState() + " - Blocking until LOCK_AFTER is released");
pm_after.start();
try {
// Notify others before we lock
NOTIFY_AFTER.release();
if (takeLocks) LOCK_AFTER.acquire();
} catch (InterruptedException ex) {
ex.printStackTrace();
throw new VoltAbortException(ex.getMessage());
} finally {
NOTIFY_AFTER.drainPermits();
pm_after.stop();
LOG.info("AWAKE - " + pm_after.debug());
}
return (updateResults);
}
}