// SpSchedulers will see FragmentTaskMessage for: // - The scatter fragment(s) of a multi-part transaction (normal or sysproc) // - Borrow tasks to do the local fragment work if this partition is the // buddy of the MPI. Borrow tasks may include input dependency tables for // aggregation fragments, or not, if it's a replicated table read. // For multi-batch MP transactions, we'll need to look up the transaction state // that gets created when the first batch arrives. // During command log replay a new SP handle is going to be generated, but it really // doesn't matter, it isn't going to be used for anything. void handleFragmentTaskMessage(FragmentTaskMessage message) { FragmentTaskMessage msg = message; long newSpHandle; if (m_isLeader) { // Quick hack to make progress...we need to copy the FragmentTaskMessage // before we start mucking with its state (SPHANDLE). We need to revisit // all the messaging mess at some point. msg = new FragmentTaskMessage( message.getInitiatorHSId(), message.getCoordinatorHSId(), message); // Not going to use the timestamp from the new Ego because the multi-part timestamp is what // should be used TxnEgo ego = advanceTxnEgo(); newSpHandle = ego.getTxnId(); msg.setSpHandle(newSpHandle); if (msg.getInitiateTask() != null) { msg.getInitiateTask().setSpHandle(newSpHandle); // set the handle msg.setInitiateTask( msg.getInitiateTask()); // Trigger reserialization so the new handle is used } /* * If there a replicas to send it to, forward it! * Unless... it's read only AND not a sysproc. Read only sysprocs may expect to be sent * everywhere. * In that case don't propagate it to avoid a determinism check and extra messaging overhead */ if (m_sendToHSIds.length > 0 && (!msg.isReadOnly() || msg.isSysProcTask())) { FragmentTaskMessage replmsg = new FragmentTaskMessage(m_mailbox.getHSId(), m_mailbox.getHSId(), msg); m_mailbox.send(m_sendToHSIds, replmsg); DuplicateCounter counter; /* * Non-determinism should be impossible to happen with MP fragments. * if you see "MP_DETERMINISM_ERROR" as procedure name in the crash logs * something has horribly gone wrong. */ if (message.getFragmentTaskType() != FragmentTaskMessage.SYS_PROC_PER_SITE) { counter = new DuplicateCounter( msg.getCoordinatorHSId(), msg.getTxnId(), m_replicaHSIds, "MP_DETERMINISM_ERROR"); } else { counter = new SysProcDuplicateCounter( msg.getCoordinatorHSId(), msg.getTxnId(), m_replicaHSIds, "MP_DETERMINISM_ERROR"); } m_duplicateCounters.put(new DuplicateCounterKey(msg.getTxnId(), newSpHandle), counter); } } else { newSpHandle = msg.getSpHandle(); setMaxSeenTxnId(newSpHandle); } Iv2Trace.logFragmentTaskMessage(message, m_mailbox.getHSId(), newSpHandle, false); doLocalFragmentOffer(msg); }
/** * Do the work necessary to turn the FragmentTaskMessage into a TransactionTask which can be * queued to the TransactionTaskQueue. This is reused by both the normal message handling path and * the repair path, and assumes that the caller has dealt with or ensured that the necessary ID, * SpHandles, and replication issues are resolved. */ private void doLocalFragmentOffer(FragmentTaskMessage msg) { TransactionState txn = m_outstandingTxns.get(msg.getTxnId()); boolean logThis = false; // bit of a hack...we will probably not want to create and // offer FragmentTasks for txn ids that don't match if we have // something in progress already if (txn == null) { txn = new ParticipantTransactionState(msg.getSpHandle(), msg); m_outstandingTxns.put(msg.getTxnId(), txn); // Only want to send things to the command log if it satisfies this predicate // AND we've never seen anything for this transaction before. We can't // actually log until we create a TransactionTask, though, so just keep track // of whether it needs to be done. logThis = (msg.getInitiateTask() != null && !msg.getInitiateTask().isReadOnly()); } // Check to see if this is the final task for this txn, and if so, if we can close it out early // Right now, this just means read-only. // NOTE: this overlaps slightly with CompleteTransactionMessage handling completion. It's so // tiny // that for now, meh, but if this scope grows then it should get refactored out if (msg.isFinalTask() && txn.isReadOnly()) { m_outstandingTxns.remove(msg.getTxnId()); } TransactionTask task; if (msg.isSysProcTask()) { task = new SysprocFragmentTask( m_mailbox, (ParticipantTransactionState) txn, m_pendingTasks, msg, null); } else { task = new FragmentTask(m_mailbox, (ParticipantTransactionState) txn, m_pendingTasks, msg, null); } if (logThis) { if (!m_cl.log(msg.getInitiateTask(), msg.getSpHandle(), m_durabilityListener, task)) { m_pendingTasks.offer(task); } else { /* Getting here means that the task is the first fragment of an MP txn and * synchronous command logging is on, so create a backlog for future tasks of * this MP arrived before it's marked durable. * * This is important for synchronous command logging and MP txn restart. Without * this, a restarted MP txn may not be gated by logging of the first fragment. */ assert !m_mpsPendingDurability.containsKey(task.getTxnId()); m_mpsPendingDurability.put(task.getTxnId(), new ArrayDeque<TransactionTask>()); } } else { queueOrOfferMPTask(task); } }
private void logToDR(PartitionDRGateway drGateway) { // Log invocation to DR if (drGateway != null && !m_txnState.isForReplay() && !m_txnState.isReadOnly() && !m_completeMsg.isRollback()) { FragmentTaskMessage fragment = (FragmentTaskMessage) m_txnState.getNotice(); Iv2InitiateTaskMessage initiateTask = fragment.getInitiateTask(); assert (initiateTask != null); if (initiateTask == null) { hostLog.error( "Unable to log MP transaction to DR because of missing InitiateTaskMessage, " + "fragment: " + fragment.toString()); } StoredProcedureInvocation invocation = initiateTask.getStoredProcedureInvocation().getShallowCopy(); drGateway.onSuccessfulMPCall( m_txnState.m_spHandle, m_txnState.txnId, m_txnState.uniqueId, m_completeMsg.getHash(), invocation, m_txnState.getResults()); } }