Пример #1
0
  // 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);
  }
Пример #2
0
  /**
   * 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);
    }
  }
Пример #3
0
 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());
   }
 }