예제 #1
0
  /**
   * Dedupe initiate task messages. Check if the initiate task message is seen before.
   *
   * @param inTxnId The txnId of the message
   * @param in The initiate task message
   * @return A client response to return if it's a duplicate, otherwise null.
   */
  public InitiateResponseMessage dedupe(long inTxnId, TransactionInfoBaseMessage in) {
    if (in instanceof Iv2InitiateTaskMessage) {
      final Iv2InitiateTaskMessage init = (Iv2InitiateTaskMessage) in;
      final StoredProcedureInvocation invocation = init.getStoredProcedureInvocation();
      final String procName = invocation.getProcName();

      /*
       * Ning - @LoadSinglepartTable and @LoadMultipartTable always have the same txnId
       * which is the txnId of the snapshot.
       */
      if (!(procName.equalsIgnoreCase("@LoadSinglepartitionTable")
              || procName.equalsIgnoreCase("@LoadMultipartitionTable"))
          && inTxnId <= m_lastSeenTxnId) {
        // already sequenced
        final InitiateResponseMessage resp = new InitiateResponseMessage(init);
        resp.setResults(
            new ClientResponseImpl(
                ClientResponseImpl.UNEXPECTED_FAILURE,
                new VoltTable[0],
                ClientResponseImpl.IGNORED_TRANSACTION));
        return resp;
      }
    }
    return null;
  }
예제 #2
0
 /*
  * The timestamp field is no longer really a timestamp, it is a unique id that is time based
  * and is similar to a pre-IV2 transaction ID except the less significant bits are set
  * to allow matching partition counts with IV2. It's OK, still can do 512k txns/second per
  * partition so plenty of headroom.
  */
 public long getUniqueId() {
   StoredProcedureInvocation invocation = m_txnState.getInvocation();
   if (invocation != null && invocation.getType() == ProcedureInvocationType.REPLICATED) {
     return invocation.getOriginalUniqueId();
   } else {
     return m_txnState.uniqueId;
   }
 }
예제 #3
0
 /*
  * Extract the timestamp from the timestamp field we have been passing around
  * that is now a unique id with a timestamp encoded in the most significant bits ala
  * a pre-IV2 transaction id.
  */
 public Date getTransactionTime() {
   StoredProcedureInvocation invocation = m_txnState.getInvocation();
   if (invocation != null && invocation.getType() == ProcedureInvocationType.REPLICATED) {
     return new Date(UniqueIdGenerator.getTimestampFromUniqueId(invocation.getOriginalUniqueId()));
   } else {
     return new Date(UniqueIdGenerator.getTimestampFromUniqueId(m_txnState.uniqueId));
   }
 }
예제 #4
0
 /**
  * Note this fails for Sysprocs that use it in non-coordinating fragment work. Don't.
  *
  * @return The transaction id for determinism, not for ordering.
  */
 long getTransactionId() {
   StoredProcedureInvocation invocation = m_txnState.getInvocation();
   if (invocation != null && invocation.getType() == ProcedureInvocationType.REPLICATED) {
     return invocation.getOriginalTxnId();
   } else {
     return m_txnState.txnId;
   }
 }
예제 #5
0
 /**
  * Create a VoltMessage that can be fed into CI's handleRead() method.
  *
  * @param origTxnId The original txnId if it's a replicated transaction
  * @param name The procedure name
  * @param params Procedure parameters
  * @return
  * @throws IOException
  */
 private static ByteBuffer createMsg(Long origTxnId, String name, final Object... params)
     throws IOException {
   FastSerializer fs = new FastSerializer();
   StoredProcedureInvocation proc = new StoredProcedureInvocation();
   proc.setProcName(name);
   if (origTxnId != null) proc.setOriginalTxnId(origTxnId);
   proc.setParams(params);
   fs.writeObject(proc);
   return fs.getBuffer();
 }
예제 #6
0
  @Override
  public ClientResponseImpl shouldAccept(
      AuthUser user, StoredProcedureInvocation invocation, Config sysProc) {

    if (!invocation.procName.equals("@AdHoc")) {
      return null;
    }

    ParameterSet params = invocation.getParams();
    // note the second secret param
    if (params.toArray().length > 2) {
      return new ClientResponseImpl(
          ClientResponseImpl.GRACEFUL_FAILURE,
          new VoltTable[0],
          "Adhoc system procedure requires exactly one or two parameters, "
              + "the SQL statement to execute with an optional partitioning value.",
          invocation.clientHandle);
    }
    // check the types are both strings
    if ((params.toArray()[0] instanceof String) == false) {
      return new ClientResponseImpl(
          ClientResponseImpl.GRACEFUL_FAILURE,
          new VoltTable[0],
          "Adhoc system procedure requires sql in the String type only.",
          invocation.clientHandle);
    }

    return null;
  }
  public StoredProcedureInvocation getShallowCopy() {
    StoredProcedureInvocation copy = new StoredProcedureInvocation();
    copy.type = type;
    copy.clientHandle = clientHandle;
    copy.params = params;
    copy.procName = procName;
    copy.originalTxnId = originalTxnId;
    copy.originalUniqueId = originalUniqueId;
    if (serializedParams != null) {
      copy.serializedParams = serializedParams.duplicate();
    } else {
      copy.serializedParams = null;
    }

    copy.batchTimeout = batchTimeout;

    return copy;
  }
예제 #8
0
 @Test
 public void testUserProc() throws IOException {
   ByteBuffer msg = createMsg("hello", 1);
   StoredProcedureInvocation invocation = readAndCheck(msg, "hello", 1, false, true, true, false);
   assertEquals(1, invocation.getParameterAtIndex(0));
 }
  public MultiPartitionParticipantTxnState(
      Mailbox mbox, ExecutionSite site, TransactionInfoBaseMessage notice) {
    super(mbox, site, notice);
    m_hsId = site.getSiteId();
    m_nonCoordinatingSites = null;
    m_isCoordinator = false;
    m_context = site.m_context;

    // Check to make sure we are the coordinator, it is possible to get an intiate task
    // where we aren't the coordinator because we are a replica of the coordinator.
    if (notice instanceof InitiateTaskMessage) {
      // keep this around for DR purposes
      m_invocation = ((InitiateTaskMessage) notice).getStoredProcedureInvocation();

      // Determine if mismatched results are okay.
      if (m_invocation != null) {
        String procName = m_invocation.getProcName();
        if (procName.startsWith("@AdHoc")) {
          // For now the best we can do with ad hoc is to always allow mismatched results.
          // We don't know if it's non-deterministic or not. But the main use case for
          // being lenient is "SELECT * FROM TABLE LIMIT n", typically run as ad hoc.
          m_allowMismatchedResults = true;
        } else {
          // Walk through the statements to see if any are non-deterministic.
          if (m_context != null && m_context.procedures != null) {
            Procedure proc = m_context.procedures.get(procName);
            if (proc != null) {
              CatalogMap<Statement> stmts = proc.getStatements();
              if (stmts != null) {
                for (Statement stmt : stmts) {
                  if (!stmt.getIscontentdeterministic() || !stmt.getIsorderdeterministic()) {
                    m_allowMismatchedResults = true;
                    break;
                  }
                }
              }
            }
          }
        }
      }

      if (notice.getCoordinatorHSId() == m_hsId) {
        m_isCoordinator = true;
        m_task = (InitiateTaskMessage) notice;
        m_durabilityFlag = m_task.getDurabilityFlagIfItExists();
        SiteTracker tracker = site.getSiteTracker();
        m_readyWorkUnits.add(
            new WorkUnit(tracker, m_task, null, m_hsId, null, false, m_allowMismatchedResults));

        /*
         * ENG-3374: Use the same set of non-coordinator sites the
         * initiator sent out the participant notices to, so that when
         * the coordinator send out the fragment works all participants
         * will get them.
         *
         * During rejoin, the initiator's site tracker and the
         * coordinator's site tracker may not be consistent for a brief
         * period of time. So can't rely on the site tracker to tell the
         * coordinator which sites to send work to.
         */
        m_nonCoordinatingSites = m_task.getNonCoordinatorSites();
      } else {
        m_durabilityFlag = ((InitiateTaskMessage) notice).getDurabilityFlagIfItExists();
        m_task = null;
      }
    } else {
      m_task = null;
      m_durabilityFlag = null;
      m_invocation = null;
    }
  }
예제 #10
0
 public long getClientHandle() {
   return StoredProcedureInvocation.getClientHandle(this.serializedRequest);
 }
예제 #11
0
 /** Write an SPI using it's ByteBuffer serialization code. */
 public void writeInvocation(StoredProcedureInvocation invocation) throws IOException {
   int len = invocation.getSerializedSize();
   growIfNeeded(len);
   invocation.flattenToBuffer(buffer.b());
 }
예제 #12
0
  public ClientResponseImpl call(Object... paramListIn) {
    // verify per-txn state has been reset
    assert (m_statusCode == ClientResponse.UNINITIALIZED_APP_STATUS_CODE);
    assert (m_statusString == null);
    assert (m_cachedRNG == null);

    // reset the hash of results
    m_inputCRC.reset();

    // use local var to avoid warnings about reassigning method argument
    Object[] paramList = paramListIn;

    ClientResponseImpl retval = null;
    // assert no sql is queued
    assert (m_batch.size() == 0);

    try {
      m_statsCollector.beginProcedure();

      byte status = ClientResponse.SUCCESS;
      VoltTable[] results = null;

      // inject sysproc execution context as the first parameter.
      if (isSystemProcedure()) {
        final Object[] combinedParams = new Object[paramList.length + 1];
        combinedParams[0] = m_systemProcedureContext;
        for (int i = 0; i < paramList.length; ++i) combinedParams[i + 1] = paramList[i];
        // swap the lists.
        paramList = combinedParams;
      }

      if (paramList.length != m_paramTypes.length) {
        m_statsCollector.endProcedure(false, true, null, null);
        String msg =
            "PROCEDURE "
                + m_procedureName
                + " EXPECTS "
                + String.valueOf(m_paramTypes.length)
                + " PARAMS, BUT RECEIVED "
                + String.valueOf(paramList.length);
        status = ClientResponse.GRACEFUL_FAILURE;
        return getErrorResponse(status, msg, null);
      }

      for (int i = 0; i < m_paramTypes.length; i++) {
        try {
          paramList[i] =
              ParameterConverter.tryToMakeCompatible(
                  m_paramTypeIsPrimitive[i],
                  m_paramTypeIsArray[i],
                  m_paramTypes[i],
                  m_paramTypeComponentType[i],
                  paramList[i]);
        } catch (Exception e) {
          m_statsCollector.endProcedure(false, true, null, null);
          String msg =
              "PROCEDURE "
                  + m_procedureName
                  + " TYPE ERROR FOR PARAMETER "
                  + i
                  + ": "
                  + e.toString();
          status = ClientResponse.GRACEFUL_FAILURE;
          return getErrorResponse(status, msg, null);
        }
      }

      boolean error = false;
      boolean abort = false;
      // run a regular java class
      if (m_catProc.getHasjava()) {
        try {
          if (log.isTraceEnabled()) {
            log.trace(
                "invoking... procMethod="
                    + m_procMethod.getName()
                    + ", class="
                    + getClass().getName());
          }
          try {
            Object rawResult = m_procMethod.invoke(m_procedure, paramList);
            results = getResultsFromRawResults(rawResult);
          } catch (IllegalAccessException e) {
            // If reflection fails, invoke the same error handling that other exceptions do
            throw new InvocationTargetException(e);
          }
          log.trace("invoked");
        } catch (InvocationTargetException itex) {
          // itex.printStackTrace();
          Throwable ex = itex.getCause();
          if (ex instanceof VoltAbortException && !(ex instanceof EEException)) {
            abort = true;
          } else {
            error = true;
          }
          if (ex instanceof Error) {
            m_statsCollector.endProcedure(false, true, null, null);
            throw (Error) ex;
          }

          retval = getErrorResponse(ex);
        }
      }
      // single statement only work
      // (this could be made faster, but with less code re-use)
      else {
        assert (m_catProc.getStatements().size() == 1);
        try {
          m_cachedSingleStmt.params = getCleanParams(m_cachedSingleStmt.stmt, paramList);
          if (getHsqlBackendIfExists() != null) {
            // HSQL handling
            CatalogMap<StmtParameter> sparamsMap = m_cachedSingleStmt.stmt.catStmt.getParameters();
            List<StmtParameter> sparams = CatalogUtil.getSortedCatalogItems(sparamsMap, "index");
            VoltTable table =
                getHsqlBackendIfExists()
                    .runSQLWithSubstitutions(
                        m_cachedSingleStmt.stmt, m_cachedSingleStmt.params, sparams);
            results = new VoltTable[] {table};
          } else {
            m_batch.add(m_cachedSingleStmt);
            results = voltExecuteSQL(true);
          }
        } catch (SerializableException ex) {
          retval = getErrorResponse(ex);
        }
      }

      // Record statistics for procedure call.
      StoredProcedureInvocation invoc = (m_txnState != null ? m_txnState.getInvocation() : null);
      ParameterSet paramSet = (invoc != null ? invoc.getParams() : null);
      m_statsCollector.endProcedure(abort, error, results, paramSet);

      // don't leave empty handed
      if (results == null) results = new VoltTable[0];

      if (retval == null)
        retval = new ClientResponseImpl(status, m_statusCode, m_statusString, results, null);

      int hash = (int) m_inputCRC.getValue();
      if ((retval.getStatus() == ClientResponse.SUCCESS) && (hash != 0)) {
        retval.setHash(hash);
      }
      if ((m_txnState != null)
          && // may be null for tests
          (m_txnState.getInvocation() != null)
          && (m_txnState.getInvocation().getType() == ProcedureInvocationType.REPLICATED)) {
        retval.convertResultsToHashForDeterminism();
      }
    } finally {
      // finally at the call(..) scope to ensure params can be
      // garbage collected and that the queue will be empty for
      // the next call
      m_batch.clear();

      // reset other per-txn state
      m_txnState = null;
      m_statusCode = ClientResponse.UNINITIALIZED_APP_STATUS_CODE;
      m_statusString = null;
      m_cachedRNG = null;
      m_cachedSingleStmt.params = null;
      m_cachedSingleStmt.expectation = null;
      m_seenFinalBatch = false;
    }

    return retval;
  }