예제 #1
0
  @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();
  }
예제 #2
0
  // SpScheduler expects to see InitiateTaskMessages corresponding to single-partition
  // procedures only.
  public void handleIv2InitiateTaskMessage(Iv2InitiateTaskMessage message) {
    if (!message.isSinglePartition()) {
      throw new RuntimeException(
          "SpScheduler.handleIv2InitiateTaskMessage "
              + "should never receive multi-partition initiations.");
    }

    final String procedureName = message.getStoredProcedureName();
    long newSpHandle;
    long uniqueId = Long.MIN_VALUE;
    Iv2InitiateTaskMessage msg = message;
    if (m_isLeader || message.isReadOnly()) {
      /*
       * A short circuit read is a read where the client interface is local to
       * this node. The CI will let a replica perform a read in this case and
       * it does looser tracking of client handles since it can't be
       * partitioned from the local replica.
       */
      if (!m_isLeader
          && CoreUtils.getHostIdFromHSId(msg.getInitiatorHSId())
              != CoreUtils.getHostIdFromHSId(m_mailbox.getHSId())) {
        VoltDB.crashLocalVoltDB("Only allowed to do short circuit reads locally", true, null);
      }

      /*
       * If this is for CL replay or DR, update the unique ID generator
       */
      if (message.isForReplay()) {
        uniqueId = message.getUniqueId();
        try {
          m_uniqueIdGenerator.updateMostRecentlyGeneratedUniqueId(uniqueId);
        } catch (Exception e) {
          hostLog.fatal(e.getMessage());
          hostLog.fatal("Invocation: " + message);
          VoltDB.crashLocalVoltDB(e.getMessage(), true, e);
        }
      } else if (message.isForDR()) {
        uniqueId = message.getStoredProcedureInvocation().getOriginalUniqueId();
        // @LoadSinglepartitionTable does not have a valid uid
        if (UniqueIdGenerator.getPartitionIdFromUniqueId(uniqueId) == m_partitionId) {
          m_uniqueIdGenerator.updateMostRecentlyGeneratedUniqueId(uniqueId);
        }
      }

      /*
       * If this is CL replay use the txnid from the CL and also
       * update the txnid to match the one from the CL
       */
      if (message.isForReplay()) {
        newSpHandle = message.getTxnId();
        setMaxSeenTxnId(newSpHandle);
      } else if (m_isLeader) {
        TxnEgo ego = advanceTxnEgo();
        newSpHandle = ego.getTxnId();
        uniqueId = m_uniqueIdGenerator.getNextUniqueId();
      } else {
        /*
         * The short circuit read case. Since we are not a master
         * we can't create new transaction IDs, so reuse the last seen
         * txnid. For a timestamp, might as well give a reasonable one
         * for a read heavy workload so time isn't bursty.
         */
        uniqueId =
            UniqueIdGenerator.makeIdFromComponents(
                Math.max(System.currentTimeMillis(), m_uniqueIdGenerator.lastUsedTime),
                0,
                m_uniqueIdGenerator.partitionId);
        // Don't think it wise to make a new one for a short circuit read
        newSpHandle = getCurrentTxnId();
      }

      // Need to set the SP handle on the received message
      // Need to copy this or the other local sites handling
      // the same initiate task message will overwrite each
      // other's memory -- the message isn't copied on delivery
      // to other local mailboxes.
      msg =
          new Iv2InitiateTaskMessage(
              message.getInitiatorHSId(),
              message.getCoordinatorHSId(),
              m_repairLogTruncationHandle,
              message.getTxnId(),
              message.getUniqueId(),
              message.isReadOnly(),
              message.isSinglePartition(),
              message.getStoredProcedureInvocation(),
              message.getClientInterfaceHandle(),
              message.getConnectionId(),
              message.isForReplay());

      msg.setSpHandle(newSpHandle);

      // Also, if this is a vanilla single-part procedure, make the TXNID
      // be the SpHandle (for now)
      // Only system procedures are every-site, so we'll check through the SystemProcedureCatalog
      if (SystemProcedureCatalog.listing.get(procedureName) == null
          || !SystemProcedureCatalog.listing.get(procedureName).getEverysite()) {
        msg.setTxnId(newSpHandle);
        msg.setUniqueId(uniqueId);
      }

      // Don't replicate reads, this really assumes that DML validation
      // is going to be integrated soonish
      if (m_isLeader && !msg.isReadOnly() && m_sendToHSIds.length > 0) {
        Iv2InitiateTaskMessage replmsg =
            new Iv2InitiateTaskMessage(
                m_mailbox.getHSId(),
                m_mailbox.getHSId(),
                m_repairLogTruncationHandle,
                msg.getTxnId(),
                msg.getUniqueId(),
                msg.isReadOnly(),
                msg.isSinglePartition(),
                msg.getStoredProcedureInvocation(),
                msg.getClientInterfaceHandle(),
                msg.getConnectionId(),
                msg.isForReplay());
        // Update the handle in the copy since the constructor doesn't set it
        replmsg.setSpHandle(newSpHandle);
        m_mailbox.send(m_sendToHSIds, replmsg);
        DuplicateCounter counter =
            new DuplicateCounter(
                msg.getInitiatorHSId(),
                msg.getTxnId(),
                m_replicaHSIds,
                msg.getStoredProcedureName());
        m_duplicateCounters.put(new DuplicateCounterKey(msg.getTxnId(), newSpHandle), counter);
      }
    } else {
      setMaxSeenTxnId(msg.getSpHandle());
      newSpHandle = msg.getSpHandle();
      uniqueId = msg.getUniqueId();
    }
    Iv2Trace.logIv2InitiateTaskMessage(message, m_mailbox.getHSId(), msg.getTxnId(), newSpHandle);
    doLocalInitiateOffer(msg);
    return;
  }
예제 #3
0
  /** 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);
    }
  }