public static void logIv2InitiateTaskMessage( Iv2InitiateTaskMessage itask, long localHSId, long txnid, long spHandle) { if (iv2log.isTraceEnabled()) { String logmsg = "rxInitMsg %s from %s ciHandle %s txnId %s spHandle %s trunc %s"; if (itask.getTxnId() != Long.MIN_VALUE && itask.getTxnId() != txnid) { iv2log.error( "Iv2InitiateTaskMessage TXN ID conflict. Message: " + itask.getTxnId() + ", locally held: " + txnid); } if (itask.getSpHandle() != Long.MIN_VALUE && itask.getSpHandle() != spHandle) { iv2log.error( "Iv2InitiateTaskMessage SP HANDLE conflict. Message: " + itask.getSpHandle() + ", locally held: " + spHandle); } iv2log.trace( String.format( logmsg, CoreUtils.hsIdToString(localHSId), CoreUtils.hsIdToString(itask.m_sourceHSId), ClientInterfaceHandleManager.handleToString(itask.getClientInterfaceHandle()), txnIdToString(txnid), txnIdToString(spHandle), txnIdToString(itask.getTruncationHandle()))); } }
@Override void completeInitiateTask(SiteProcedureConnection siteConnection) { CompleteTransactionMessage complete = new CompleteTransactionMessage( m_initiator.getHSId(), // who is the "initiator" now?? m_initiator.getHSId(), m_txnState.txnId, m_txnState.isReadOnly(), m_txnState.getHash(), m_txnState.needsRollback(), false, // really don't want to have ack the ack. false, m_msg.isForReplay()); complete.setTruncationHandle(m_msg.getTruncationHandle()); complete.setOriginalTxnId(m_msg.getOriginalTxnId()); m_initiator.send(com.google.common.primitives.Longs.toArray(m_initiatorHSIds), complete); m_txnState.setDone(); m_queue.flush(); }
@Test public void testTruncationHandleForwarding() throws IOException { long truncPt = 100L; Iv2InitiateTaskMessage taskmsg = new Iv2InitiateTaskMessage( 0, 0, truncPt, 101L, System.currentTimeMillis(), true, false, new StoredProcedureInvocation(), 0, 0, false); assertEquals(truncPt, taskmsg.getTruncationHandle()); FragmentTaskMessage localFrag = mock(FragmentTaskMessage.class); FragmentTaskMessage remoteFrag = mock(FragmentTaskMessage.class); when(remoteFrag.getFragmentCount()).thenReturn(1); buddyHSId = 0; Mailbox mailbox = mock(Mailbox.class); MpTransactionState dut = new MpTransactionState(mailbox, taskmsg, allHsids, buddyHSId, false); // create local work and verify the created localwork has the // expected truncation point. dut.createLocalFragmentWork(localFrag, false); verify(dut.m_localWork).setTruncationHandle(truncPt); // same with partcipating work. dut.createAllParticipatingFragmentWork(remoteFrag); verify(dut.m_remoteWork).setTruncationHandle(truncPt); }
/** Run is invoked by a run-loop to execute this transaction. */ @Override public void run(SiteProcedureConnection siteConnection) { hostLog.debug("STARTING: " + this); // Cast up. Could avoid ugliness with Iv2TransactionClass baseclass MpTransactionState txn = (MpTransactionState) m_txnState; // Check for restarting sysprocs String spName = txn.m_initiationMsg.getStoredProcedureName(); // certain system procs can and can't be restarted // Right now this is adhoc and catalog update. Since these are treated specially // in a few places (here, recovery, dr), maybe we should add another metadata // property the sysproc registry about whether a proc can be restarted/recovered/dr-ed if (m_isRestart && spName.startsWith("@") && !spName.startsWith("@AdHoc") && !spName.equals("@UpdateApplicationCatalog")) { InitiateResponseMessage errorResp = new InitiateResponseMessage(txn.m_initiationMsg); errorResp.setResults( new ClientResponseImpl( ClientResponse.UNEXPECTED_FAILURE, new VoltTable[] {}, "Failure while running system procedure " + txn.m_initiationMsg.getStoredProcedureName() + ", and system procedures can not be restarted.")); txn.setNeedsRollback(); completeInitiateTask(siteConnection); errorResp.m_sourceHSId = m_initiator.getHSId(); m_initiator.deliver(errorResp); hostLog.debug("SYSPROCFAIL: " + this); return; } // Let's ensure that we flush any previous attempts of this transaction // at the masters we're going to try to use this time around. if (m_isRestart) { CompleteTransactionMessage restart = new CompleteTransactionMessage( m_initiator.getHSId(), // who is the "initiator" now?? m_initiator.getHSId(), m_txnState.txnId, m_txnState.isReadOnly(), 0, true, false, // really don't want to have ack the ack. !m_txnState.isReadOnly(), m_msg.isForReplay()); restart.setTruncationHandle(m_msg.getTruncationHandle()); restart.setOriginalTxnId(m_msg.getOriginalTxnId()); m_initiator.send(com.google.common.primitives.Longs.toArray(m_initiatorHSIds), restart); } final InitiateResponseMessage response = processInitiateTask(txn.m_initiationMsg, siteConnection); // We currently don't want to restart read-only MP transactions because: // 1) We're not writing the Iv2InitiateTaskMessage to the first // FragmentTaskMessage in read-only case in the name of some unmeasured // performance impact, // 2) We don't want to perturb command logging and/or DR this close to the 3.0 release // 3) We don't guarantee the restarted results returned to the client // anyway, so not restarting the read is currently harmless. // We could actually restart this here, since we have the invocation, but let's be consistent? int status = response.getClientResponseData().getStatus(); if (status != ClientResponse.TXN_RESTART || (status == ClientResponse.TXN_RESTART && m_msg.isReadOnly())) { if (!response.shouldCommit()) { txn.setNeedsRollback(); } completeInitiateTask(siteConnection); // Set the source HSId (ugh) to ourselves so we track the message path correctly response.m_sourceHSId = m_initiator.getHSId(); m_initiator.deliver(response); execLog.l7dlog( Level.TRACE, LogKeys.org_voltdb_ExecutionSite_SendingCompletedWUToDtxn.name(), null); hostLog.debug("COMPLETE: " + this); } else { restartTransaction(); hostLog.debug("RESTART: " + this); } }
// Offer a new message to the repair log. This will truncate // the repairLog if the message includes a truncation hint. public void deliver(VoltMessage msg) { if (!m_isLeader && msg instanceof Iv2InitiateTaskMessage) { final Iv2InitiateTaskMessage m = (Iv2InitiateTaskMessage) msg; // We can't repair read only SP transactions. Just don't log them to the repair log. if (m.isReadOnly()) { return; } m_lastSpHandle = m.getSpHandle(); truncate(m.getTruncationHandle(), IS_SP); m_logSP.add(new Item(IS_SP, m, m.getSpHandle(), m.getTxnId())); } else if (msg instanceof FragmentTaskMessage) { final FragmentTaskMessage m = (FragmentTaskMessage) msg; // We can't repair read only SP transactions. Just don't log them to the repair log. if (m.isReadOnly()) { return; } truncate(m.getTruncationHandle(), IS_MP); // only log the first fragment of a procedure (and handle 1st case) if (m.getTxnId() > m_lastMpHandle || m_lastMpHandle == Long.MAX_VALUE) { m_logMP.add(new Item(IS_MP, m, m.getSpHandle(), m.getTxnId())); m_lastMpHandle = m.getTxnId(); m_lastSpHandle = m.getSpHandle(); } } else if (msg instanceof CompleteTransactionMessage) { // a CompleteTransactionMessage which indicates restart is not the end of the // transaction. We don't want to log it in the repair log. CompleteTransactionMessage ctm = (CompleteTransactionMessage) msg; // We can't repair read only SP transactions. Just don't log them to the repair log. // Restart transaction do not need to be repaired here, don't log them as well. if (ctm.isReadOnly() || ctm.isRestart()) { return; } truncate(ctm.getTruncationHandle(), IS_MP); m_logMP.add(new Item(IS_MP, ctm, ctm.getSpHandle(), ctm.getTxnId())); // Restore will send a complete transaction message with a lower mp transaction id because // the restore transaction precedes the loading of the right mp transaction id from the // snapshot // Hence Math.max m_lastMpHandle = Math.max(m_lastMpHandle, ctm.getTxnId()); m_lastSpHandle = ctm.getSpHandle(); } else if (msg instanceof DumpMessage) { String who = CoreUtils.hsIdToString(m_HSId); tmLog.warn( "Repair log dump for site: " + who + ", isLeader: " + m_isLeader + ", " + who + ": lastSpHandle: " + m_lastSpHandle + ", lastMpHandle: " + m_lastMpHandle); for (Iv2RepairLogResponseMessage il : contents(0l, false)) { tmLog.warn("[Repair log contents]" + who + ": msg: " + il); } } else if (msg instanceof RepairLogTruncationMessage) { final RepairLogTruncationMessage truncateMsg = (RepairLogTruncationMessage) msg; truncate(truncateMsg.getHandle(), IS_SP); } }