use of org.voltdb.messaging.FragmentResponseMessage in project voltdb by VoltDB.
the class MpTransactionState method pollForResponses.
private FragmentResponseMessage pollForResponses() {
FragmentResponseMessage msg = null;
try {
final String snapShotRestoreProcName = "@SnapshotRestore";
while (msg == null) {
msg = m_newDeps.poll(60L * 5, TimeUnit.SECONDS);
if (msg == null && !snapShotRestoreProcName.equals(m_initiationMsg.getStoredProcedureName())) {
tmLog.warn("Possible multipartition transaction deadlock detected for: " + m_initiationMsg);
if (m_remoteWork == null) {
tmLog.warn("Waiting on local BorrowTask response from site: " + CoreUtils.hsIdToString(m_buddyHSId));
} else {
tmLog.warn("Waiting on remote dependencies: ");
for (Entry<Integer, Set<Long>> e : m_remoteDeps.entrySet()) {
tmLog.warn("Dep ID: " + e.getKey() + " waiting on: " + CoreUtils.hsIdCollectionToString(e.getValue()));
}
}
m_mbox.send(com.google_voltpatches.common.primitives.Longs.toArray(m_useHSIds), new DumpMessage());
}
}
} catch (InterruptedException e) {
// could retry; but this is unexpected. Crash.
throw new RuntimeException(e);
}
SerializableException se = msg.getException();
if (se != null && se instanceof TransactionRestartException) {
// If this is a restart exception, we don't need to match up the DependencyId
setNeedsRollback(true);
throw se;
}
return msg;
}
use of org.voltdb.messaging.FragmentResponseMessage 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.FragmentResponseMessage in project voltdb by VoltDB.
the class SpScheduler method handleFragmentResponseMessage.
// Eventually, the master for a partition set will need to be able to dedupe
// FragmentResponses from its replicas.
private void handleFragmentResponseMessage(FragmentResponseMessage message) {
final TransactionState txnState = m_outstandingTxns.get(message.getTxnId());
final VoltTrace.TraceEventBatch traceLog = VoltTrace.log(VoltTrace.Category.SPI);
// Send the message to the duplicate counter, if any
DuplicateCounter counter = m_duplicateCounters.get(new DuplicateCounterKey(message.getTxnId(), message.getSpHandle()));
final TransactionState txn = m_outstandingTxns.get(message.getTxnId());
if (counter != null) {
String traceName = "recvfragment";
if (message.m_sourceHSId != m_mailbox.getHSId()) {
traceName = "replicatefragment";
}
String finalTraceName = traceName;
if (traceLog != null) {
traceLog.add(() -> VoltTrace.endAsync(finalTraceName, MiscUtils.hsIdPairTxnIdToString(m_mailbox.getHSId(), message.m_sourceHSId, message.getSpHandle(), message.getTxnId()), "status", message.getStatusCode()));
}
int result = counter.offer(message);
if (result == DuplicateCounter.DONE) {
if (txn != null && txn.isDone()) {
setRepairLogTruncationHandle(txn.m_spHandle);
}
m_duplicateCounters.remove(new DuplicateCounterKey(message.getTxnId(), message.getSpHandle()));
FragmentResponseMessage resp = (FragmentResponseMessage) counter.getLastResponse();
// MPI is tracking deps per partition HSID. We need to make
// sure we write ours into the message getting sent to the MPI
resp.setExecutorSiteId(m_mailbox.getHSId());
m_mailbox.send(counter.m_destinationId, resp);
} else if (result == DuplicateCounter.MISMATCH) {
VoltDB.crashGlobalVoltDB("HASH MISMATCH running multi-part procedure.", true, null);
} else if (result == DuplicateCounter.ABORT) {
VoltDB.crashGlobalVoltDB("PARTIAL ROLLBACK/ABORT running multi-part procedure.", true, null);
}
// doing duplicate suppression: all done.
return;
}
// K-safety: read-only queries (on master) or write queries (on replica).
if (m_defaultConsistencyReadLevel == ReadLevel.SAFE && m_isLeader && m_sendToHSIds.length > 0 && message.getRespBufferable() && (txn == null || txn.isReadOnly())) {
// on k-safety leader with safe reads configuration: one shot reads + normal multi-fragments MP reads
// we will have to buffer these reads until previous writes acked in the cluster.
long readTxnId = txn == null ? message.getSpHandle() : txn.m_spHandle;
m_bufferedReadLog.offer(m_mailbox, message, readTxnId, m_repairLogTruncationHandle);
return;
}
// for complete writes txn, we will advance the transaction point
if (txn != null && !txn.isReadOnly() && txn.isDone()) {
setRepairLogTruncationHandle(txn.m_spHandle);
}
if (traceLog != null) {
traceLog.add(() -> VoltTrace.endAsync("recvfragment", MiscUtils.hsIdPairTxnIdToString(m_mailbox.getHSId(), message.m_sourceHSId, message.getSpHandle(), message.getTxnId()), "status", message.getStatusCode()));
}
m_mailbox.send(message.getDestinationSiteId(), message);
}
use of org.voltdb.messaging.FragmentResponseMessage in project voltdb by VoltDB.
the class SysprocFragmentTask method respondWithDummy.
/**
* Respond with a dummy fragment response.
*/
private void respondWithDummy() {
final FragmentResponseMessage response = new FragmentResponseMessage(m_fragmentMsg, m_initiator.getHSId());
response.m_sourceHSId = m_initiator.getHSId();
response.setRecovering(true);
response.setStatus(FragmentResponseMessage.SUCCESS, null);
// on elastic join, so the fragment response message is actually going to the MPI.
for (int frag = 0; frag < m_fragmentMsg.getFragmentCount(); frag++) {
final int outputDepId = m_fragmentMsg.getOutputDepId(frag);
response.addDependency(new DependencyPair.BufferDependencyPair(outputDepId, m_rawDummyResponse, 0, m_rawDummyResponse.length));
}
response.setRespBufferable(m_respBufferable);
m_initiator.deliver(response);
}
use of org.voltdb.messaging.FragmentResponseMessage in project voltdb by VoltDB.
the class TestMpTransactionState method testOneSitePartitionedReadWithRollback.
@Test
public void testOneSitePartitionedReadWithRollback() throws IOException {
long txnId = 1234l;
int batch_size = 3;
Iv2InitiateTaskMessage taskmsg = new Iv2InitiateTaskMessage(0, 0, (txnId - 1), txnId, System.currentTimeMillis(), true, false, new StoredProcedureInvocation(), 0, 0, false);
int hsids = 1;
buddyHSId = 0;
long[] non_local = configureHSIds(hsids);
MpTestPlan plan = createTestPlan(batch_size, true, false, true, non_local);
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 one message
verify(mailbox).send(eq(new long[] { 0 }), (VoltMessage) any());
// offer all the necessary fragment responses to satisfy deps
for (FragmentResponseMessage msg : plan.generatedResponses) {
System.out.println("Offering response: " + msg);
dut.offerReceivedFragmentResponse(msg);
}
// We're getting an error, so this should throw something
boolean threw = false;
try {
dut.recursableRun(siteConnection);
fail();
} catch (EEException eee) {
if (eee.getErrorCode() == 1234) {
threw = true;
}
}
assertTrue(threw);
}
Aggregations