Example #1
0
  /**
   * Pass the VoltMessage to CI's handleRead() and inspect if the expected parameters are passed to
   * the initiator's createTranction() method. This is a convenient method if the caller expects the
   * result of handling this message is to create a new transaction.
   *
   * @param msg
   * @param procName
   * @param partitionParam null if it's a multi-part txn
   * @param isAdmin
   * @param isReadonly
   * @param isSinglePart
   * @param isEverySite
   * @return StoredProcedureInvocation object passed to createTransaction()
   * @throws IOException
   */
  private StoredProcedureInvocation readAndCheck(
      ByteBuffer msg,
      String procName,
      Object partitionParam,
      boolean isAdmin,
      boolean isReadonly,
      boolean isSinglePart,
      boolean isEverySite)
      throws IOException {
    ClientResponseImpl resp = m_ci.handleRead(msg, m_handler, m_cxn);
    assertNull(resp);

    ArgumentCaptor<Long> destinationCaptor = ArgumentCaptor.forClass(Long.class);
    ArgumentCaptor<Iv2InitiateTaskMessage> messageCaptor =
        ArgumentCaptor.forClass(Iv2InitiateTaskMessage.class);
    verify(m_messenger).send(destinationCaptor.capture(), messageCaptor.capture());

    Iv2InitiateTaskMessage message = messageCaptor.getValue();
    // assertEquals(isAdmin, message.); // is admin
    assertEquals(isReadonly, message.isReadOnly()); // readonly
    assertEquals(isSinglePart, message.isSinglePartition()); // single-part
    // assertEquals(isEverySite, message.g); // every site
    assertEquals(procName, message.getStoredProcedureName());
    if (isSinglePart) {
      int expected = TheHashinator.hashToPartition(partitionParam);
      assertEquals(
          new Long(m_cartographer.getHSIdForMaster(expected)), destinationCaptor.getValue());
    } else {
      assertEquals(
          new Long(m_cartographer.getHSIdForMultiPartitionInitiator()),
          destinationCaptor.getValue());
    }
    return message.getStoredProcedureInvocation();
  }
Example #2
0
 private boolean filter(TransactionInfoBaseMessage tibm) {
   // don't log sysproc fragments or iv2 intiiate task messages.
   // this is all jealously; should be refactored to ask tibm
   // if it wants to be filtered for rejoin and eliminate this
   // horrible introspection. This implementation mimics the
   // original live rejoin code for ExecutionSite...
   if (tibm instanceof FragmentTaskMessage && ((FragmentTaskMessage) tibm).isSysProcTask()) {
     return true;
   } else if (tibm instanceof Iv2InitiateTaskMessage) {
     Iv2InitiateTaskMessage itm = (Iv2InitiateTaskMessage) tibm;
     if ((itm.getStoredProcedureName().startsWith("@") == false)
         || (itm.getStoredProcedureName().startsWith("@AdHoc") == true)) {
       return false;
     } else {
       return true;
     }
   }
   return false;
 }
Example #3
0
  /** Fake an adhoc compiler result and return it to the CI, see if CI initiates the txn. */
  @Test
  public void testFinishedMPAdHocPlanning() throws Exception {
    // Need a batch and a statement
    AdHocPlannedStmtBatch plannedStmtBatch =
        new AdHocPlannedStmtBatch(
            "select * from a",
            null,
            0,
            0,
            "localhost",
            false,
            ProcedureInvocationType.ORIGINAL,
            0,
            0,
            null);
    AdHocPlannedStatement s =
        new AdHocPlannedStatement(
            "select * from a".getBytes(Constants.UTF8ENCODING),
            new CorePlan(
                new byte[0],
                new byte[0],
                new byte[20],
                new byte[20],
                false,
                false,
                true,
                new VoltType[0],
                0),
            ParameterSet.emptyParameterSet(),
            null,
            null,
            null);
    plannedStmtBatch.addStatement(s);
    m_ci.processFinishedCompilerWork(plannedStmtBatch).run();

    ArgumentCaptor<Long> destinationCaptor = ArgumentCaptor.forClass(Long.class);
    ArgumentCaptor<Iv2InitiateTaskMessage> messageCaptor =
        ArgumentCaptor.forClass(Iv2InitiateTaskMessage.class);
    verify(m_messenger).send(destinationCaptor.capture(), messageCaptor.capture());
    Iv2InitiateTaskMessage message = messageCaptor.getValue();

    // assertFalse(boolValues.get(0)); // is admin
    assertTrue(message.isReadOnly()); // readonly
    assertFalse(message.isSinglePartition()); // single-part
    // assertFalse(boolValues.get(3)); // every site
    assertEquals("@AdHoc_RO_MP", message.getStoredProcedureName());

    byte[] serializedData = (byte[]) message.getStoredProcedureInvocation().getParameterAtIndex(0);
    AdHocPlannedStatement[] statements =
        AdHocPlannedStmtBatch.planArrayFromBuffer(ByteBuffer.wrap(serializedData));
    assertEquals(1, statements.length);
    String sql = new String(statements[0].sql, Constants.UTF8ENCODING);
    assertEquals("select * from a", sql);
  }
Example #4
0
 /**
  * Do the work necessary to turn the Iv2InitiateTaskMessage 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 doLocalInitiateOffer(Iv2InitiateTaskMessage msg) {
   final String procedureName = msg.getStoredProcedureName();
   final SpProcedureTask task =
       new SpProcedureTask(m_mailbox, procedureName, m_pendingTasks, msg, m_drGateway);
   if (!msg.isReadOnly()) {
     if (!m_cl.log(msg, msg.getSpHandle(), m_durabilityListener, task)) {
       m_pendingTasks.offer(task);
     }
   } else {
     m_pendingTasks.offer(task);
   }
 }
Example #5
0
  @Test
  public void testFinishedSPAdHocPlanning() throws Exception {
    // Need a batch and a statement
    AdHocPlannedStmtBatch plannedStmtBatch =
        new AdHocPlannedStmtBatch(
            "select * from a where i = 3",
            3,
            0,
            0,
            "localhost",
            false,
            ProcedureInvocationType.ORIGINAL,
            0,
            0,
            null);
    AdHocPlannedStatement s =
        new AdHocPlannedStatement(
            "select * from a where i = 3".getBytes(Constants.UTF8ENCODING),
            new CorePlan(
                new byte[0], null, new byte[20], null, false, false, true, new VoltType[0], 0),
            ParameterSet.fromArrayNoCopy(new Object[0]),
            null,
            null,
            3);
    plannedStmtBatch.addStatement(s);
    m_ci.processFinishedCompilerWork(plannedStmtBatch).run();

    ArgumentCaptor<Long> destinationCaptor = ArgumentCaptor.forClass(Long.class);
    ArgumentCaptor<Iv2InitiateTaskMessage> messageCaptor =
        ArgumentCaptor.forClass(Iv2InitiateTaskMessage.class);
    verify(m_messenger).send(destinationCaptor.capture(), messageCaptor.capture());
    Iv2InitiateTaskMessage message = messageCaptor.getValue();

    assertTrue(message.isReadOnly()); // readonly
    assertTrue(message.isSinglePartition()); // single-part
    assertEquals("@AdHoc_RO_SP", message.getStoredProcedureName());

    // SP AdHoc should have partitioning parameter serialized in the parameter set
    Object partitionParam = message.getStoredProcedureInvocation().getParameterAtIndex(0);
    assertTrue(partitionParam instanceof byte[]);
    VoltType type =
        VoltType.get((Byte) message.getStoredProcedureInvocation().getParameterAtIndex(1));
    assertTrue(type.isInteger());
    byte[] serializedData = (byte[]) message.getStoredProcedureInvocation().getParameterAtIndex(2);
    AdHocPlannedStatement[] statements =
        AdHocPlannedStmtBatch.planArrayFromBuffer(ByteBuffer.wrap(serializedData));
    assertTrue(Arrays.equals(TheHashinator.valueToBytes(3), (byte[]) partitionParam));
    assertEquals(1, statements.length);
    String sql = new String(statements[0].sql, Constants.UTF8ENCODING);
    assertEquals("select * from a where i = 3", sql);
  }
Example #6
0
  /**
   * Fake a catalog diff compiler result and send it back to the CI, see if CI initiates a new txn.
   */
  @Test
  public void testFinishedCatalogDiffing() {
    CatalogChangeResult catalogResult = new CatalogChangeResult();
    catalogResult.clientData = null;
    catalogResult.clientHandle = 0;
    catalogResult.connectionId = 0;
    catalogResult.adminConnection = false;
    catalogResult.hostname = "localhost";
    // catalog change specific boiler plate
    catalogResult.catalogHash = "blah".getBytes();
    catalogResult.catalogBytes = "blah".getBytes();
    catalogResult.deploymentString = "blah";
    catalogResult.deploymentCRC = 1234l;
    catalogResult.expectedCatalogVersion = 3;
    catalogResult.encodedDiffCommands = "diff";
    catalogResult.invocationType = ProcedureInvocationType.REPLICATED;
    catalogResult.originalTxnId = 12345678l;
    catalogResult.originalUniqueId = 87654321l;
    m_ci.processFinishedCompilerWork(catalogResult).run();

    ArgumentCaptor<Long> destinationCaptor = ArgumentCaptor.forClass(Long.class);
    ArgumentCaptor<Iv2InitiateTaskMessage> messageCaptor =
        ArgumentCaptor.forClass(Iv2InitiateTaskMessage.class);
    verify(m_messenger).send(destinationCaptor.capture(), messageCaptor.capture());
    Iv2InitiateTaskMessage message = messageCaptor.getValue();
    // assertFalse(boolValues.get(0)); // is admin
    assertFalse(message.isReadOnly()); // readonly
    assertFalse(message.isSinglePartition()); // single-part
    // assertFalse(boolValues.get(3)); // every site
    assertEquals("@UpdateApplicationCatalog", message.getStoredProcedureName());
    assertEquals("diff", message.getStoredProcedureInvocation().getParameterAtIndex(0));
    assertTrue(
        Arrays.equals(
            "blah".getBytes(),
            (byte[]) message.getStoredProcedureInvocation().getParameterAtIndex(2)));
    assertEquals(3, message.getStoredProcedureInvocation().getParameterAtIndex(3));
    assertEquals("blah", message.getStoredProcedureInvocation().getParameterAtIndex(4));
    assertEquals(1234l, message.getStoredProcedureInvocation().getParameterAtIndex(5));
    assertEquals(
        ProcedureInvocationType.REPLICATED, message.getStoredProcedureInvocation().getType());
    assertEquals(12345678l, message.getStoredProcedureInvocation().getOriginalTxnId());
    assertEquals(87654321l, message.getStoredProcedureInvocation().getOriginalUniqueId());
  }
Example #7
0
  private void handleIv2InitiateTaskMessageRepair(
      List<Long> needsRepair, Iv2InitiateTaskMessage message) {
    if (!message.isSinglePartition()) {
      throw new RuntimeException(
          "SpScheduler.handleIv2InitiateTaskMessageRepair "
              + "should never receive multi-partition initiations.");
    }

    // set up duplicate counter. expect exactly the responses corresponding
    // to needsRepair. These may, or may not, include the local site.

    // We currently send the final response into the ether, since we don't
    // have the original ClientInterface HSID stored.  It would be more
    // useful to have the original ClienInterface HSId somewhere handy.

    List<Long> expectedHSIds = new ArrayList<Long>(needsRepair);
    DuplicateCounter counter =
        new DuplicateCounter(
            HostMessenger.VALHALLA,
            message.getTxnId(),
            expectedHSIds,
            message.getStoredProcedureName());
    m_duplicateCounters.put(
        new DuplicateCounterKey(message.getTxnId(), message.getSpHandle()), counter);

    m_uniqueIdGenerator.updateMostRecentlyGeneratedUniqueId(message.getUniqueId());
    // is local repair necessary?
    if (needsRepair.contains(m_mailbox.getHSId())) {
      needsRepair.remove(m_mailbox.getHSId());
      // make a copy because handleIv2 non-repair case does?
      Iv2InitiateTaskMessage localWork =
          new Iv2InitiateTaskMessage(
              message.getInitiatorHSId(), message.getCoordinatorHSId(), message);
      doLocalInitiateOffer(localWork);
    }

    // is remote repair necessary?
    if (!needsRepair.isEmpty()) {
      Iv2InitiateTaskMessage replmsg =
          new Iv2InitiateTaskMessage(m_mailbox.getHSId(), m_mailbox.getHSId(), message);
      m_mailbox.send(com.google.common.primitives.Longs.toArray(needsRepair), replmsg);
    }
  }
Example #8
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;
  }
Example #9
0
  void replayFromTaskLog() throws IOException {
    // not yet time to catch-up.
    if (m_rejoinState != kStateReplayingRejoin) {
      return;
    }

    // replay 10:1 in favor of replay
    for (int i = 0; i < 10; ++i) {
      if (m_rejoinTaskLog.isEmpty()) {
        break;
      }

      TransactionInfoBaseMessage tibm = m_rejoinTaskLog.getNextMessage();
      if (tibm == null) {
        break;
      }

      // Apply the readonly / sysproc filter. With Iv2 read optimizations,
      // reads should not reach here; the cost of post-filtering shouldn't
      // be particularly high (vs pre-filtering).
      if (filter(tibm)) {
        continue;
      }

      if (tibm instanceof Iv2InitiateTaskMessage) {
        Iv2InitiateTaskMessage m = (Iv2InitiateTaskMessage) tibm;
        SpProcedureTask t =
            new SpProcedureTask(m_initiatorMailbox, m.getStoredProcedureName(), null, m, null);
        t.runFromTaskLog(this);
      } else if (tibm instanceof FragmentTaskMessage) {
        FragmentTaskMessage m = (FragmentTaskMessage) tibm;
        if (global_replay_mpTxn == null) {
          global_replay_mpTxn = new ParticipantTransactionState(m.getTxnId(), m);
        } else if (global_replay_mpTxn.txnId != m.getTxnId()) {
          VoltDB.crashLocalVoltDB(
              "Started a MP transaction during replay before completing " + " open transaction.",
              false,
              null);
        }
        FragmentTask t = new FragmentTask(m_initiatorMailbox, m, global_replay_mpTxn);
        t.runFromTaskLog(this);
      } else if (tibm instanceof CompleteTransactionMessage) {
        // Needs improvement: completes for sysprocs aren't filterable as sysprocs.
        // Only complete transactions that are open...
        if (global_replay_mpTxn != null) {
          CompleteTransactionMessage m = (CompleteTransactionMessage) tibm;
          CompleteTransactionTask t =
              new CompleteTransactionTask(global_replay_mpTxn, null, m, null);
          if (!m.isRestart()) {
            global_replay_mpTxn = null;
          }
          t.runFromTaskLog(this);
        }
      } else {
        VoltDB.crashLocalVoltDB(
            "Can not replay message type " + tibm + " during live rejoin. Unexpected error.",
            false,
            null);
      }
    }

    // exit replay being careful not to exit in the middle of a multi-partititon
    // transaction. The SPScheduler doesn't have a valid transaction state for a
    // partially replayed MP txn and in case of rollback the scheduler's undo token
    // is wrong. Run MP txns fully kStateRejoining or fully kStateRunning.
    if (m_rejoinTaskLog.isEmpty() && global_replay_mpTxn == null) {
      setReplayRejoinComplete();
    }
  }