use of org.voltdb.messaging.BorrowTaskMessage in project voltdb by VoltDB.
the class MpTransactionState method recursableRun.
@Override
public Map<Integer, List<VoltTable>> recursableRun(SiteProcedureConnection siteConnection) {
final VoltTrace.TraceEventBatch traceLog = VoltTrace.log(VoltTrace.Category.MPSITE);
// if we're restarting this transaction, and we only have local work, add some dummy
// remote work so that we can avoid injecting a borrow task into the local buddy site
// before the CompleteTransactionMessage with the restart flag reaches it.
// Right now, any read on a replicated table which has no distributed work will
// generate these null fragments in the restarted transaction.
boolean usedNullFragment = false;
if (m_isRestart && m_remoteWork == null) {
usedNullFragment = true;
m_remoteWork = new FragmentTaskMessage(m_localWork.getInitiatorHSId(), m_localWork.getCoordinatorHSId(), m_localWork.getTxnId(), m_localWork.getUniqueId(), m_localWork.isReadOnly(), false, false);
m_remoteWork.setEmptyForRestart(getNextDependencyId());
if (!m_haveDistributedInitTask && !isForReplay() && !isReadOnly()) {
m_haveDistributedInitTask = true;
m_remoteWork.setStateForDurability((Iv2InitiateTaskMessage) getNotice(), m_masterHSIds.keySet());
}
// Distribute fragments to remote destinations.
long[] non_local_hsids = new long[m_useHSIds.size()];
for (int i = 0; i < m_useHSIds.size(); i++) {
non_local_hsids[i] = m_useHSIds.get(i);
}
// send to all non-local sites
if (non_local_hsids.length > 0) {
m_mbox.send(non_local_hsids, m_remoteWork);
}
}
// Do distributed fragments, if any
if (m_remoteWork != null) {
// Create some record of expected dependencies for tracking
m_remoteDeps = createTrackedDependenciesFromTask(m_remoteWork, m_useHSIds);
// cause ProcedureRunner to do the right thing and cause rollback.
while (!checkDoneReceivingFragResponses()) {
FragmentResponseMessage msg = pollForResponses();
if (traceLog != null) {
final int batchIdx = m_remoteWork.getCurrentBatchIndex();
traceLog.add(() -> VoltTrace.endAsync("sendfragment", MiscUtils.hsIdPairTxnIdToString(m_mbox.getHSId(), msg.m_sourceHSId, txnId, batchIdx), "status", Byte.toString(msg.getStatusCode())));
}
boolean expectedMsg = handleReceivedFragResponse(msg);
if (expectedMsg) {
// Will roll-back and throw if this message has an exception
checkForException(msg);
}
}
}
// satisified. Clear this defensively. Procedure runner is sloppy with
// cleaning up if it decides new work is necessary that is local-only.
m_remoteWork = null;
BorrowTaskMessage borrowmsg = new BorrowTaskMessage(m_localWork);
m_localWork.setCoordinatorTask(true);
m_localWork.m_sourceHSId = m_mbox.getHSId();
// don't include the empty dependencies we got back in the borrow fragment.
if (!usedNullFragment) {
borrowmsg.addInputDepMap(m_remoteDepTables);
}
if (traceLog != null) {
final int batchIdx = m_localWork.getCurrentBatchIndex();
traceLog.add(() -> VoltTrace.beginAsync("sendborrow", MiscUtils.hsIdPairTxnIdToString(m_mbox.getHSId(), m_buddyHSId, txnId, batchIdx), "txnId", TxnEgo.txnIdToString(txnId), "dest", CoreUtils.hsIdToString(m_buddyHSId)));
}
m_mbox.send(m_buddyHSId, borrowmsg);
FragmentResponseMessage msg;
while (true) {
msg = pollForResponses();
final FragmentResponseMessage finalMsg = msg;
if (traceLog != null) {
final int batchIdx = m_localWork.getCurrentBatchIndex();
traceLog.add(() -> VoltTrace.endAsync("sendborrow", MiscUtils.hsIdPairTxnIdToString(m_mbox.getHSId(), m_buddyHSId, txnId, batchIdx), "status", Byte.toString(finalMsg.getStatusCode())));
}
assert (msg.getTableCount() > 0);
// If this is a restarted TXN, verify that this is not a stale message from a different Dependency
if (!m_isRestart || (msg.m_sourceHSId == m_buddyHSId && msg.getTableDependencyIdAtIndex(0) == m_localWork.getOutputDepId(0))) {
// Will roll-back and throw if this message has an exception
checkForException(msg);
break;
} else {
// ignore those
assert m_isRestart;
}
}
m_localWork = null;
// Build results from the FragmentResponseMessage
// This is similar to dependency tracking...maybe some
// sane way to merge it
Map<Integer, List<VoltTable>> results = new HashMap<Integer, List<VoltTable>>();
for (int i = 0; i < msg.getTableCount(); i++) {
int this_depId = msg.getTableDependencyIdAtIndex(i);
VoltTable this_dep = msg.getTableAtIndex(i);
List<VoltTable> tables = results.get(this_depId);
if (tables == null) {
tables = new ArrayList<VoltTable>();
results.put(this_depId, tables);
}
tables.add(this_dep);
}
// Need some sanity check that we got all of the expected output dependencies?
return results;
}
use of org.voltdb.messaging.BorrowTaskMessage in project voltdb by VoltDB.
the class TestMpTransactionState method testMPReadWithDummyResponse.
@Test
public void testMPReadWithDummyResponse() throws IOException {
long txnId = 1234l;
int batch_size = 3;
Iv2InitiateTaskMessage taskmsg = new Iv2InitiateTaskMessage(0, -1, (txnId - 1), txnId, System.currentTimeMillis(), true, false, new StoredProcedureInvocation(), 0, 0, false);
int hsids = 6;
buddyHSId = 0;
long[] non_local = configureHSIds(hsids);
MpTestPlan plan = createTestPlan(batch_size, true, false, false, non_local);
// replace the last remote fragment response with a dummy
for (FragmentResponseMessage dummy : plan.generatedResponses) {
if (dummy.getExecutorSiteId() == non_local[non_local.length - 1]) {
dummy.setRecovering(true);
for (int i = 0; i < dummy.getTableCount(); i++) {
VoltTable depTable = dummy.getTableAtIndex(i);
depTable.setStatusCode(VoltTableUtil.NULL_DEPENDENCY_STATUS);
depTable.clearRowData();
}
}
}
Mailbox mailbox = mock(Mailbox.class);
SiteProcedureConnection siteConnection = mock(SiteProcedureConnection.class);
MpTransactionState dut = new MpTransactionState(mailbox, taskmsg, allHsids, partMasters, buddyHSId, false);
// emulate ProcedureRunner's use for a single local fragment
dut.setupProcedureResume(true, plan.depsToResume);
dut.createLocalFragmentWork(plan.localWork, false);
// This will be passed a FragmentTaskMessage with no deps
dut.createAllParticipatingFragmentWork(plan.remoteWork);
// we should send 6 messages
verify(mailbox).send(eq(non_local), (VoltMessage) any());
// offer all the necessary fragment responses to satisfy deps
for (FragmentResponseMessage msg : plan.generatedResponses) {
dut.offerReceivedFragmentResponse(msg);
}
// if we've satisfied everything, this should run to completion
Map<Integer, List<VoltTable>> results = dut.recursableRun(siteConnection);
ArgumentCaptor<BorrowTaskMessage> borrowCaptor = ArgumentCaptor.forClass(BorrowTaskMessage.class);
verify(mailbox).send(eq(buddyHSId), borrowCaptor.capture());
// make sure that the borrow task message doesn't have any dummy dependency tables as input
BorrowTaskMessage borrowMsg = borrowCaptor.getValue();
Map<Integer, List<VoltTable>> inputDepMap = borrowMsg.getInputDepMap();
for (List<VoltTable> tables : inputDepMap.values()) {
for (VoltTable table : tables) {
assertNotSame(VoltTableUtil.NULL_DEPENDENCY_STATUS, table.getStatusCode());
}
}
// verify returned deps/tables
assertEquals(batch_size, results.size());
System.out.println(results);
}
Aggregations