use of org.voltdb.messaging.CompleteTransactionMessage in project voltdb by VoltDB.
the class InitiatorMailbox method repairReplicasWithInternal.
private void repairReplicasWithInternal(List<Long> needsRepair, VoltMessage repairWork) {
assert (lockingVows());
if (repairWork instanceof Iv2InitiateTaskMessage) {
Iv2InitiateTaskMessage m = (Iv2InitiateTaskMessage) repairWork;
Iv2InitiateTaskMessage work = new Iv2InitiateTaskMessage(m.getInitiatorHSId(), getHSId(), m);
m_scheduler.handleMessageRepair(needsRepair, work);
} else if (repairWork instanceof FragmentTaskMessage) {
// We need to get this into the repair log in case we've never seen it before. Adding fragment
// tasks to the repair log is safe; we'll never overwrite the first fragment if we've already seen it.
m_repairLog.deliver(repairWork);
m_scheduler.handleMessageRepair(needsRepair, repairWork);
} else if (repairWork instanceof CompleteTransactionMessage) {
// CompleteTransactionMessages should always be safe to handle. Either the work was done, and we'll
// ignore it, or we need to clean up, or we'll be restarting and it doesn't matter. Make sure they
// get into the repair log and then let them run their course.
m_repairLog.deliver(repairWork);
m_scheduler.handleMessageRepair(needsRepair, repairWork);
} else {
throw new RuntimeException("Invalid repair message type: " + repairWork);
}
}
use of org.voltdb.messaging.CompleteTransactionMessage in project voltdb by VoltDB.
the class MpProcedureTask method completeInitiateTask.
@Override
void completeInitiateTask(SiteProcedureConnection siteConnection) {
final VoltTrace.TraceEventBatch traceLog = VoltTrace.log(VoltTrace.Category.MPSITE);
if (traceLog != null) {
traceLog.add(() -> VoltTrace.instant("sendcomplete", "txnId", TxnEgo.txnIdToString(getTxnId()), "commit", Boolean.toString(!m_txnState.needsRollback()), "dest", CoreUtils.hsIdCollectionToString(m_initiatorHSIds)));
}
CompleteTransactionMessage complete = new CompleteTransactionMessage(// who is the "initiator" now??
m_initiator.getHSId(), m_initiator.getHSId(), m_txnState.txnId, m_txnState.isReadOnly(), m_txnState.getHash(), m_txnState.needsRollback(), // really don't want to have ack the ack.
false, false, m_msg.isForReplay());
complete.setTruncationHandle(m_msg.getTruncationHandle());
m_initiator.send(com.google_voltpatches.common.primitives.Longs.toArray(m_initiatorHSIds), complete);
m_txnState.setDone();
m_queue.flush(getTxnId());
}
use of org.voltdb.messaging.CompleteTransactionMessage in project voltdb by VoltDB.
the class SpScheduler method handleCompleteTransactionMessage.
private void handleCompleteTransactionMessage(CompleteTransactionMessage message) {
CompleteTransactionMessage msg = message;
if (m_isLeader) {
msg = new CompleteTransactionMessage(m_mailbox.getHSId(), m_mailbox.getHSId(), message);
// Set the spHandle so that on repair the new master will set the max seen spHandle
// correctly
advanceTxnEgo();
msg.setSpHandle(getCurrentTxnId());
if (m_sendToHSIds.length > 0 && !msg.isReadOnly()) {
m_mailbox.send(m_sendToHSIds, msg);
}
} else {
setMaxSeenTxnId(msg.getSpHandle());
}
logRepair(msg);
TransactionState txn = m_outstandingTxns.get(msg.getTxnId());
// now, fix that later.
if (txn != null) {
CompleteTransactionMessage finalMsg = msg;
final VoltTrace.TraceEventBatch traceLog = VoltTrace.log(VoltTrace.Category.SPI);
if (traceLog != null) {
traceLog.add(() -> VoltTrace.instant("recvCompleteTxn", "txnId", TxnEgo.txnIdToString(finalMsg.getTxnId()), "partition", Integer.toString(m_partitionId), "hsId", CoreUtils.hsIdToString(m_mailbox.getHSId())));
}
final boolean isSysproc = ((FragmentTaskMessage) txn.getNotice()).isSysProcTask();
if (m_sendToHSIds.length > 0 && !msg.isRestart() && (!msg.isReadOnly() || isSysproc)) {
DuplicateCounter counter;
counter = new DuplicateCounter(msg.getCoordinatorHSId(), msg.getTxnId(), m_replicaHSIds, msg);
safeAddToDuplicateCounterMap(new DuplicateCounterKey(msg.getTxnId(), msg.getSpHandle()), counter);
}
Iv2Trace.logCompleteTransactionMessage(msg, m_mailbox.getHSId());
final CompleteTransactionTask task = new CompleteTransactionTask(m_mailbox, txn, m_pendingTasks, msg);
queueOrOfferMPTask(task);
} else {
// Generate a dummy response message when this site has not seen previous FragmentTaskMessage,
// the leader may have started to wait for replicas' response messages.
// This can happen in the early phase of site rejoin before replica receiving the snapshot initiation,
// it also means this CompleteTransactionMessage message will be dropped because it's after snapshot.
final CompleteTransactionResponseMessage resp = new CompleteTransactionResponseMessage(msg);
resp.m_sourceHSId = m_mailbox.getHSId();
handleCompleteTransactionResponseMessage(resp);
}
}
use of org.voltdb.messaging.CompleteTransactionMessage in project voltdb by VoltDB.
the class MpScheduler method handleInitiateResponseMessage.
// The MpScheduler will see InitiateResponseMessages from the Partition masters when
// performing an every-partition system procedure. A consequence of this deduping
// is that the MpScheduler will also need to forward the final InitiateResponseMessage
// for a normal multipartition procedure back to the client interface since it must
// see all of these messages and control their transmission.
public void handleInitiateResponseMessage(InitiateResponseMessage message) {
final VoltTrace.TraceEventBatch traceLog = VoltTrace.log(VoltTrace.Category.MPI);
if (traceLog != null) {
traceLog.add(() -> VoltTrace.endAsync("initmp", message.getTxnId()));
}
DuplicateCounter counter = m_duplicateCounters.get(message.getTxnId());
if (counter != null) {
int result = counter.offer(message);
if (result == DuplicateCounter.DONE) {
m_duplicateCounters.remove(message.getTxnId());
// Only advance the truncation point on committed transactions. See ENG-4211
if (message.shouldCommit()) {
m_repairLogTruncationHandle = m_repairLogAwaitingCommit;
m_repairLogAwaitingCommit = message.getTxnId();
}
m_outstandingTxns.remove(message.getTxnId());
m_mailbox.send(counter.m_destinationId, message);
} else if (result == DuplicateCounter.MISMATCH) {
VoltDB.crashLocalVoltDB("HASH MISMATCH running every-site system procedure.", true, null);
} else if (result == DuplicateCounter.ABORT) {
VoltDB.crashLocalVoltDB("PARTIAL ROLLBACK/ABORT running every-site system procedure.", true, null);
}
// doing duplicate suppresion: all done.
} else {
// Only advance the truncation point on committed transactions.
if (message.shouldCommit()) {
m_repairLogTruncationHandle = m_repairLogAwaitingCommit;
m_repairLogAwaitingCommit = message.getTxnId();
}
m_outstandingTxns.remove(message.getTxnId());
// the initiatorHSId is the ClientInterface mailbox. Yeah. I know.
m_mailbox.send(message.getInitiatorHSId(), message);
// We actually completed this MP transaction. Create a fake CompleteTransactionMessage
// to send to our local repair log so that the fate of this transaction is never forgotten
// even if all the masters somehow die before forwarding Complete on to their replicas.
CompleteTransactionMessage ctm = new CompleteTransactionMessage(m_mailbox.getHSId(), message.m_sourceHSId, message.getTxnId(), message.isReadOnly(), 0, !message.shouldCommit(), false, false, false);
ctm.setTruncationHandle(m_repairLogTruncationHandle);
// dump it in the repair log
// hacky castage
((MpInitiatorMailbox) m_mailbox).deliverToRepairLog(ctm);
}
}
use of org.voltdb.messaging.CompleteTransactionMessage in project voltdb by VoltDB.
the class TestSpPromoteAlgo method testFuzz.
@Test
public void testFuzz() throws Exception {
InitiatorMailbox mbox = mock(InitiatorMailbox.class);
Map<Long, List<TransactionInfoBaseMessage>> finalStreams = new HashMap<Long, List<TransactionInfoBaseMessage>>();
Random rand = new Random(System.currentTimeMillis());
// Generate a random message stream to several "replicas", interrupted
// at random points to all but one. Validate that promotion repair
// results in identical, correct, repair streams to all replicas.
TxnEgo sphandle = TxnEgo.makeZero(0);
UniqueIdGenerator spbuig = new UniqueIdGenerator(0, 0);
UniqueIdGenerator mpbuig = new UniqueIdGenerator(0, 0);
sphandle = sphandle.makeNext();
RandomMsgGenerator msgGen = new RandomMsgGenerator();
boolean[] stops = new boolean[3];
RepairLog[] logs = new RepairLog[3];
for (int i = 0; i < 3; i++) {
logs[i] = new RepairLog();
stops[i] = false;
finalStreams.put((long) i, new ArrayList<TransactionInfoBaseMessage>());
}
long maxBinaryLogSpUniqueId = Long.MIN_VALUE;
for (int i = 0; i < 4000; i++) {
// get next message, update the sphandle according to SpScheduler rules,
// but only submit messages that would have been forwarded by the master
// to the repair log.
TransactionInfoBaseMessage msg = msgGen.generateRandomMessageInStream();
msg.setSpHandle(sphandle.getTxnId());
if (msg instanceof Iv2InitiateTaskMessage) {
Pair<Long, Long> uids = TestRepairLog.setBinaryLogUniqueId(msg, spbuig, mpbuig);
maxBinaryLogSpUniqueId = Math.max(maxBinaryLogSpUniqueId, uids.getFirst());
}
sphandle = sphandle.makeNext();
if (!msg.isReadOnly() || msg instanceof CompleteTransactionMessage) {
if (!stops[0]) {
logs[0].deliver(msg);
}
if (!stops[1]) {
logs[1].deliver(msg);
}
logs[2].deliver(msg);
// be fed any transactions
for (int j = 0; j < 2; j++) {
// Hacky way to get spaced failures
if (rand.nextDouble() < (.01 / ((j + 1) * 5))) {
stops[j] = true;
}
}
}
}
List<Long> survivors = new ArrayList<Long>();
survivors.add(0l);
survivors.add(1l);
survivors.add(2l);
SpPromoteAlgo dut = new SpPromoteAlgo(survivors, mbox, "bleh ", 0);
Future<RepairResult> result = dut.start();
for (int i = 0; i < 3; i++) {
List<Iv2RepairLogResponseMessage> stuff = logs[i].contents(dut.getRequestId(), false);
System.out.println("Repair log size from: " + i + ": " + stuff.size());
for (Iv2RepairLogResponseMessage msg : stuff) {
msg.m_sourceHSId = i;
dut.deliver(msg);
// First message is metadata only, skip it in validation stream
if (msg.getSequence() > 0) {
//System.out.println("finalstreams: " + finalStreams);
//System.out.println("get(i): " + i + ": " + finalStreams.get((long)i));
//System.out.println("msg: " + msg);
finalStreams.get((long) i).add((TransactionInfoBaseMessage) msg.getPayload());
}
}
}
assertFalse(result.isCancelled());
assertTrue(result.isDone());
// of repairSurvivors()
for (Iv2RepairLogResponseMessage li : dut.m_repairLogUnion) {
for (Entry<Long, SpPromoteAlgo.ReplicaRepairStruct> entry : dut.m_replicaRepairStructs.entrySet()) {
if (entry.getValue().needs(li.getHandle())) {
// append the missing message for this 'node' to the list of messages that node has seen
finalStreams.get(entry.getKey()).add((TransactionInfoBaseMessage) li.getPayload());
}
}
}
// check that all the lists for all the nodes are identical after repair
int longest = Integer.MIN_VALUE;
for (Entry<Long, List<TransactionInfoBaseMessage>> entry : finalStreams.entrySet()) {
System.out.println("SIZE: " + entry.getValue().size());
if (entry.getValue().size() > longest) {
if (longest == Integer.MIN_VALUE) {
longest = entry.getValue().size();
} else {
fail("Mismatch in repair stream size!");
}
}
}
for (int i = 0; i < longest; i++) {
TransactionInfoBaseMessage current = null;
for (Entry<Long, List<TransactionInfoBaseMessage>> entry : finalStreams.entrySet()) {
TransactionInfoBaseMessage msg = entry.getValue().get(i);
if (current == null) {
current = msg;
} else {
assertEquals(current.getSpHandle(), msg.getSpHandle());
assertEquals(current.getClass(), msg.getClass());
}
}
}
}
Aggregations