int 
HugoTransactions::pkUpdateRecords(Ndb* pNdb, 
				  int records,
				  int batch,
				  int doSleep){
  int updated = 0;
  int                  r = 0;
  int                  retryAttempt = 0;
  int                  check, b;

  allocRows(batch);

  g_info << "|- Updating records (batch=" << batch << ")..." << endl;
  int batch_no = 0;
  while (r < records){
    if(r + batch > records)
      batch = records - r;

    if (m_thr_count != 0 && m_thr_no != batch_no % m_thr_count)
    {
      r += batch;
      batch_no++;
      continue;
    }
    
    if (retryAttempt >= m_retryMax){
      g_info << "ERROR: has retried this operation " << retryAttempt 
	     << " times, failing!" << endl;
      return NDBT_FAILED;
    }
    
    if (doSleep > 0)
      NdbSleep_MilliSleep(doSleep);

    pTrans = pNdb->startTransaction();
    if (pTrans == NULL) {
      const NdbError err = pNdb->getNdbError();
      
      if (err.status == NdbError::TemporaryError){
	ERR(err);
	NdbSleep_MilliSleep(50);
	retryAttempt++;
	continue;
      }
      ERR(err);
      return NDBT_FAILED;
    }

    if(pkReadRecord(pNdb, r, batch, NdbOperation::LM_Exclusive) != NDBT_OK)
    {
      ERR(pTrans->getNdbError());
      closeTransaction(pNdb);
      return NDBT_FAILED;
    }
    
    check = pTrans->execute(NoCommit, AbortOnError);   
    if( check == -1 ) {
      const NdbError err = pTrans->getNdbError();
      
      if (err.status == NdbError::TemporaryError){
	ERR(err);
	closeTransaction(pNdb);
	NdbSleep_MilliSleep(50);
	retryAttempt++;
	continue;
      }
      ERR(err);
      closeTransaction(pNdb);
      return NDBT_FAILED;
    }

    MicroSecondTimer timer_start;
    MicroSecondTimer timer_stop;
    bool timer_active =
      m_stats_latency != 0 &&
      r >= batch &&             // first batch is "warmup"
      r + batch != records;     // last batch is usually partial

    if (timer_active)
      NdbTick_getMicroTimer(&timer_start);

    if(pIndexScanOp)
    {
      int rows_found = 0;
      while((check = pIndexScanOp->nextResult(true)) == 0)
      {
	do {
	  
	  if (calc.verifyRowValues(rows[0]) != 0){
	    closeTransaction(pNdb);
	    return NDBT_FAILED;
	  }
	  
	  int updates = calc.getUpdatesValue(rows[0]) + 1;
	  
	  if(pkUpdateRecord(pNdb, r+rows_found, 1, updates) != NDBT_OK)
	  {
	    ERR(pTrans->getNdbError());
	    closeTransaction(pNdb);
	    return NDBT_FAILED;
	  }
	  rows_found++;
	} while((check = pIndexScanOp->nextResult(false)) == 0);
	
	if(check != 2)
	  break;
	if((check = pTrans->execute(NoCommit, AbortOnError)) != 0)
	  break;
      }
      if(check != 1 || rows_found != batch)
      {
	closeTransaction(pNdb);
	return NDBT_FAILED;
      }
    }
    else
    {
      for(b = 0; b<batch && (b+r)<records; b++)
      {
	if (calc.verifyRowValues(rows[b]) != 0)
	{
	  closeTransaction(pNdb);
	  return NDBT_FAILED;
	}
	
	int updates = calc.getUpdatesValue(rows[b]) + 1;
	
	if(pkUpdateRecord(pNdb, r+b, 1, updates) != NDBT_OK)
	{
	  ERR(pTrans->getNdbError());
	  closeTransaction(pNdb);
	  return NDBT_FAILED;
	}
      }
      check = pTrans->execute(Commit, AbortOnError);   
    }
    if( check == -1 ) {
      const NdbError err = pTrans->getNdbError();

      if (err.status == NdbError::TemporaryError){
	ERR(err);
	closeTransaction(pNdb);
	NdbSleep_MilliSleep(50);
	retryAttempt++;
	continue;
      }
      ERR(err);
      ndbout << "r = " << r << endl;
      closeTransaction(pNdb);
      return NDBT_FAILED;
    }
    else{
      updated += batch;
      m_latest_gci = pTrans->getGCI();
    }
    
    closeTransaction(pNdb);

    if (timer_active) {
      NdbTick_getMicroTimer(&timer_stop);
      NDB_TICKS ticks = NdbTick_getMicrosPassed(timer_start, timer_stop);
      m_stats_latency->addObservation((double)ticks);
    }

    r += batch; // Read next record
    batch_no++;
  }
  
  deallocRows();
  g_info << "|- " << updated << " records updated" << endl;
  return NDBT_OK;
}
Exemplo n.º 2
0
void 
WatchDog::run()
{
  unsigned int anIPValue, sleep_time;
  unsigned int oldIPValue = 0;
  unsigned int theIntervalCheck = theInterval;
  struct MicroSecondTimer start_time, last_time, now;
  NdbTick_getMicroTimer(&start_time);
  last_time = start_time;

  // WatchDog for the single threaded NDB
  while (!theStop)
  {
    sleep_time= 100;

    NdbSleep_MilliSleep(sleep_time);
    if(theStop)
      break;

    NdbTick_getMicroTimer(&now);
    if (NdbTick_getMicrosPassed(last_time, now)/1000 > sleep_time*2)
    {
      struct tms my_tms;
      times(&my_tms);
      g_eventLogger.info("Watchdog: User time: %llu  System time: %llu",
                         (Uint64)my_tms.tms_utime,
                         (Uint64)my_tms.tms_stime);
      g_eventLogger.warning("Watchdog: Warning overslept %u ms, expected %u ms.",
                            NdbTick_getMicrosPassed(last_time, now)/1000,
                            sleep_time);
    }
    last_time = now;

    // Verify that the IP thread is not stuck in a loop
    anIPValue = *theIPValue;
    if (anIPValue != 0)
    {
      oldIPValue = anIPValue;
      globalData.incrementWatchDogCounter(0);
      NdbTick_getMicroTimer(&start_time);
      theIntervalCheck = theInterval;
    }
    else
    {
      int warn = 1;
      Uint32 elapsed = NdbTick_getMicrosPassed(start_time, now)/1000;
      /*
        oldIPValue == 9 indicates malloc going on, this can take some time
        so only warn if we pass the watchdog interval
      */
      if (oldIPValue == 9)
        if (elapsed < theIntervalCheck)
          warn = 0;
        else
          theIntervalCheck += theInterval;

      if (warn)
      {
        const char *last_stuck_action = get_action(oldIPValue);
        g_eventLogger.warning("Ndb kernel is stuck in: %s", last_stuck_action);
        {
          struct tms my_tms;
          times(&my_tms);
          g_eventLogger.info("Watchdog: User time: %llu  System time: %llu",
                             (Uint64)my_tms.tms_utime,
                             (Uint64)my_tms.tms_stime);
        }
        if (elapsed > 3 * theInterval)
        {
          shutdownSystem(last_stuck_action);
        }
      }
    }
  }
  return;
}
int 
HugoTransactions::pkReadRecords(Ndb* pNdb, 
				int records,
				int batch,
				NdbOperation::LockMode lm){
  int                  reads = 0;
  int                  r = 0;
  int                  retryAttempt = 0;
  int                  check;

  if (batch == 0) {
    g_info << "ERROR: Argument batch == 0 in pkReadRecords(). Not allowed." << endl;
    return NDBT_FAILED;
  }

  while (r < records){
    if(r + batch > records)
      batch = records - r;

    if (retryAttempt >= m_retryMax){
      g_info << "ERROR: has retried this operation " << retryAttempt 
	     << " times, failing!" << endl;
      return NDBT_FAILED;
    }
    
    pTrans = pNdb->startTransaction();
    if (pTrans == NULL) {
      const NdbError err = pNdb->getNdbError();
      
      if (err.status == NdbError::TemporaryError){
	ERR(err);
	NdbSleep_MilliSleep(50);
	retryAttempt++;
	continue;
      }
      ERR(err);
      return NDBT_FAILED;
    }

    MicroSecondTimer timer_start;
    MicroSecondTimer timer_stop;
    bool timer_active =
      m_stats_latency != 0 &&
      r >= batch &&             // first batch is "warmup"
      r + batch != records;     // last batch is usually partial

    if (timer_active)
      NdbTick_getMicroTimer(&timer_start);

    if(pkReadRecord(pNdb, r, batch, lm) != NDBT_OK)
    {
      ERR(pTrans->getNdbError());
      closeTransaction(pNdb);
      return NDBT_FAILED;
    }
    
    check = pTrans->execute(Commit, AbortOnError);   
    if( check == -1 ) {
      const NdbError err = pTrans->getNdbError();
      
      if (err.status == NdbError::TemporaryError){
	ERR(err);
	closeTransaction(pNdb);
	NdbSleep_MilliSleep(50);
	retryAttempt++;
	continue;
      }
      switch(err.code){
      case 626: // Tuple did not exist
	g_info << r << ": " << err.code << " " << err.message << endl;
	r++;
	break;

      default:
	ERR(err);
	closeTransaction(pNdb);
	return NDBT_FAILED;
      }
    } else {

      if(pIndexScanOp)
      {
	int rows_found = 0;
	while((check = pIndexScanOp->nextResult()) == 0)
	{
	  rows_found++;
	  if (calc.verifyRowValues(rows[0]) != 0){
	    closeTransaction(pNdb);
	    return NDBT_FAILED;
	  }
	}
	if(check != 1 || rows_found > batch)
	{
	  closeTransaction(pNdb);
	  return NDBT_FAILED;
	}
	else if(rows_found < batch)
	{
	  if(batch == 1){
	    g_info << r << ": not found" << endl; abort(); }
	  else
	    g_info << "Found " << rows_found << " of " 
		   << batch << " rows" << endl;
	}
	r += batch;
	reads += rows_found;
      }
      else 
      {
	for (int b=0; (b<batch) && (r+b<records); b++){ 
	  if (calc.verifyRowValues(rows[b]) != 0){
	    closeTransaction(pNdb);
	    return NDBT_FAILED;
	  }
	  reads++;
	  r++;
	}
      }
    }
    
    closeTransaction(pNdb);

    if (timer_active) {
      NdbTick_getMicroTimer(&timer_stop);
      NDB_TICKS ticks = NdbTick_getMicrosPassed(timer_start, timer_stop);
      m_stats_latency->addObservation((double)ticks);
    }
  }
  deallocRows();
  g_info << reads << " records read" << endl;
  return NDBT_OK;
}
int 
HugoTransactions::pkDelRecords(Ndb* pNdb, 
			       int records,
			       int batch,
			       bool allowConstraintViolation,
			       int doSleep){
  // TODO Batch is not implemented
  int deleted = 0;
  int                  r = 0;
  int                  retryAttempt = 0;
  int                  check;

  g_info << "|- Deleting records..." << endl;
  int batch_no = 0;
  while (r < records){
    if(r + batch > records)
      batch = records - r;

    if (m_thr_count != 0 && m_thr_no != batch_no % m_thr_count)
    {
      r += batch;
      batch_no++;
      continue;
    }

    if (retryAttempt >= m_retryMax){
      g_info << "ERROR: has retried this operation " << retryAttempt 
	     << " times, failing!" << endl;
      return NDBT_FAILED;
    }

    if (doSleep > 0)
      NdbSleep_MilliSleep(doSleep);

    pTrans = pNdb->startTransaction();
    if (pTrans == NULL) {
      const NdbError err = pNdb->getNdbError();

      if (err.status == NdbError::TemporaryError){
	ERR(err);
	NdbSleep_MilliSleep(50);
	retryAttempt++;
	continue;
      }
      ERR(err);
      return NDBT_FAILED;
    }

    MicroSecondTimer timer_start;
    MicroSecondTimer timer_stop;
    bool timer_active =
      m_stats_latency != 0 &&
      r >= batch &&             // first batch is "warmup"
      r + batch != records;     // last batch is usually partial

    if (timer_active)
      NdbTick_getMicroTimer(&timer_start);

    if(pkDeleteRecord(pNdb, r, batch) != NDBT_OK)
    {
      ERR(pTrans->getNdbError());
      closeTransaction(pNdb);
      return NDBT_FAILED;
    }

    check = pTrans->execute(Commit, AbortOnError);   
    if( check == -1) {
      const NdbError err = pTrans->getNdbError();
      
      switch(err.status){
      case NdbError::TemporaryError:
	ERR(err);
	closeTransaction(pNdb);
	NdbSleep_MilliSleep(50);
	retryAttempt++;
	continue;
	break;

      case NdbError::PermanentError:
	if (allowConstraintViolation == true){
	  switch (err.classification){
	  case NdbError::ConstraintViolation:
	    // Tuple did not exist, OK but should be reported
	    g_info << r << ": " << err.code << " " << err.message << endl;
	    continue;
	    break;
	  default:	    
	    break;
	  }
	}
	ERR(err);
	closeTransaction(pNdb);
	return NDBT_FAILED;
	break;
	
      default:
	ERR(err);
	closeTransaction(pNdb);
	return NDBT_FAILED;
      }
    }
    else {
      deleted += batch;
      m_latest_gci = pTrans->getGCI();
    }
    closeTransaction(pNdb);

    if (timer_active) {
      NdbTick_getMicroTimer(&timer_stop);
      NDB_TICKS ticks = NdbTick_getMicrosPassed(timer_start, timer_stop);
      m_stats_latency->addObservation((double)ticks);
    }

    r += batch; // Read next record
    batch_no++;
  }

  g_info << "|- " << deleted << " records deleted" << endl;
  return NDBT_OK;
}
Exemplo n.º 5
0
//--------------------------------------------------------------------
// ipControlLoop -- The main loop of ndb.
// Handles the scheduling of signal execution and input/output
// One lap in the loop should take approximately 10 milli seconds
// If the jobbuffer is empty and the laptime is less than 10 milliseconds
// at the end of the loop
// the TransporterRegistry is called in order to sleep on the IO ports
// waiting for another incoming signal to wake us up.
// The timeout value in this call is calculated as (10 ms - laptime)
// This would make ndb use less cpu while improving response time.
//--------------------------------------------------------------------
void ThreadConfig::ipControlLoop(NdbThread*, Uint32 thread_index)
{
  globalEmulatorData.theConfiguration->setAllLockCPU(true);

  Uint32 execute_loop_constant =
        globalEmulatorData.theConfiguration->schedulerExecutionTimer();
  Uint32 min_spin_time = 
    globalEmulatorData.theConfiguration->schedulerSpinTimer();
  struct MicroSecondTimer start_micro, end_micro, statistics_start_micro;
  struct MicroSecondTimer yield_micro;
  Uint32 no_exec_loops = 0;
  Uint32 no_extra_loops = 0;
  Uint32 tot_exec_time = 0;
  Uint32 tot_extra_time = 0;
  Uint32 timeOutMillis;
  Uint32 micros_passed;
  bool spinning;
  bool yield_flag= FALSE;
  int res1 = 0;
  int res2 = 0;
  int res3 = 0;
  Uint32 i = 0;
  Uint32 exec_again;

//--------------------------------------------------------------------
// initialise the counter that keeps track of the current millisecond
//--------------------------------------------------------------------
  globalData.internalMillisecCounter = NdbTick_CurrentMillisecond();

  Uint32 *watchCounter = globalData.getWatchDogPtr();
  globalEmulatorData.theWatchDog->registerWatchedThread(watchCounter, 0);

  res1 = NdbTick_getMicroTimer(&start_micro);
  yield_micro = statistics_start_micro = end_micro = start_micro;
  while (1)
  {
    timeOutMillis = 0;
//--------------------------------------------------------------------
// We send all messages buffered during execution of job buffers
//--------------------------------------------------------------------
    globalData.incrementWatchDogCounter(6);
    globalTransporterRegistry.performSend();

//--------------------------------------------------------------------
// Now it is time to check all interfaces. We will send all buffers
// plus checking for any received messages.
//--------------------------------------------------------------------
    if (i++ >= 20)
    {
      execute_loop_constant = 
        globalEmulatorData.theConfiguration->schedulerExecutionTimer();
      min_spin_time = 
        globalEmulatorData.theConfiguration->schedulerSpinTimer();
      globalData.incrementWatchDogCounter(5);
      globalTransporterRegistry.update_connections();
      i = 0;
    }
    spinning = false;
    do
    {
//--------------------------------------------------------------------
// We scan the time queue to see if there are any timed signals that
// is now ready to be executed.
//--------------------------------------------------------------------
      globalData.incrementWatchDogCounter(2);
      scanTimeQueue(); 

      if (LEVEL_IDLE == globalData.highestAvailablePrio)
      {
//--------------------------------------------------------------------
// The buffers are empty, we need to wait for a while until we continue.
// We cannot wait forever since we can also have timed events.
//--------------------------------------------------------------------
// We set the time to sleep on sockets before waking up to 10
// milliseconds unless we have set spin timer to be larger than 0. In
// this case we spin checking for events on the transporter until we
// have expired the spin time.
//--------------------------------------------------------------------
        timeOutMillis = 10;
        if (min_spin_time && !yield_flag)
        {
          if (spinning)
            res2 = NdbTick_getMicroTimer(&end_micro);
          if (!(res1 + res2))
          {
            micros_passed = 
              (Uint32)NdbTick_getMicrosPassed(start_micro, end_micro);
            if (micros_passed < min_spin_time)
              timeOutMillis = 0;
          }
        }
      }
      if (spinning && timeOutMillis > 0 && i++ >= 20)
      {
        globalData.incrementWatchDogCounter(5);
        globalTransporterRegistry.update_connections();
        i = 0;
      }

//--------------------------------------------------------------------
// Perform receive before entering execute loop
//--------------------------------------------------------------------
      globalData.incrementWatchDogCounter(7);
      {
        bool poll_flag;
        if (yield_flag)
        {
          globalEmulatorData.theConfiguration->yield_main(thread_index, TRUE);
          poll_flag= globalTransporterRegistry.pollReceive(timeOutMillis);
          globalEmulatorData.theConfiguration->yield_main(thread_index, FALSE);
          res3= NdbTick_getMicroTimer(&yield_micro);
        }
        else
          poll_flag= globalTransporterRegistry.pollReceive(timeOutMillis);
        if (poll_flag)
        {
          globalData.incrementWatchDogCounter(8);
          globalTransporterRegistry.performReceive();
        }
        yield_flag= FALSE;
      }
      spinning = true;
      globalScheduler.postPoll();
//--------------------------------------------------------------------
// In an idle system we will use this loop to wait either for external
// signal received or a message generated by the time queue.
//--------------------------------------------------------------------
    } while (LEVEL_IDLE == globalData.highestAvailablePrio);
//--------------------------------------------------------------------
// Get current microsecond to ensure we will continue executing
// signals for at least a configured time while there are more
// signals to receive.
//--------------------------------------------------------------------
    res1= NdbTick_getMicroTimer(&start_micro);
    if ((res1 + res3) || 
        ((Uint32)NdbTick_getMicrosPassed(start_micro, yield_micro) > 10000))
      yield_flag= TRUE;
    exec_again= 0;
    do
    {
//--------------------------------------------------------------------
// This is where the actual execution of signals occur. We execute
// until all buffers are empty or until we have executed 2048 signals.
//--------------------------------------------------------------------
      globalScheduler.doJob();
      if (unlikely(globalData.theRestartFlag == perform_stop))
        goto out;
//--------------------------------------------------------------------
// Get timer after executing this set of jobs. If we have passed the
// maximum execution time we will break out of the loop always
// otherwise we will check for new received signals before executing
// the send of the buffers.
// By setting exec_loop_constant to 0 we go back to the traditional
// algorithm of sending once per receive instance.
//--------------------------------------------------------------------
      if (!execute_loop_constant && !min_spin_time)
        break;
      res2= NdbTick_getMicroTimer(&end_micro);
      if (res2)
        break;
      micros_passed = (Uint32)NdbTick_getMicrosPassed(start_micro, end_micro);
      tot_exec_time += micros_passed;
      if (no_exec_loops++ >= 8192)
      {
        Uint32 expired_time = 
          (Uint32)NdbTick_getMicrosPassed(statistics_start_micro, end_micro);
        statistics_start_micro = end_micro;
        globalScheduler.reportThreadConfigLoop(expired_time,
                                               execute_loop_constant,
                                               &no_exec_loops,
                                               &tot_exec_time,
                                               &no_extra_loops,
                                               &tot_extra_time);
      }
      /*
        Continue our execution if micros_passed since last round is smaller
        than the configured constant. Given that we don't recall the
        actual start time of this loop we insert an extra check to ensure we
        don't enter an eternal loop here. We'll never execute more than
        3 times before sending.
      */
      if (micros_passed > execute_loop_constant || (exec_again > 1))
        break;
      exec_again++;
//--------------------------------------------------------------------
// There were still time for execution left, we check if there are
// signals newly received on the transporters and if so we execute one
// more round before sending the buffered signals.
//--------------------------------------------------------------------
      globalData.incrementWatchDogCounter(7);
      if (!globalTransporterRegistry.pollReceive(0))
        break;

      no_extra_loops++;
      tot_extra_time += micros_passed;
      start_micro = end_micro;
      globalData.incrementWatchDogCounter(8);
      globalTransporterRegistry.performReceive();
    } while (1);
  }
out:
  globalData.incrementWatchDogCounter(6);
  globalTransporterRegistry.performSend();

  globalEmulatorData.theWatchDog->unregisterWatchedThread(0);

}//ThreadConfig::ipControlLoop()
Exemplo n.º 6
0
void
Dbtup::buildIndex(Signal* signal, Uint32 buildPtrI)
{
    // get build record
    BuildIndexPtr buildPtr;
    buildPtr.i= buildPtrI;
    c_buildIndexList.getPtr(buildPtr);
    const BuildIndxImplReq* buildReq= &buildPtr.p->m_request;
    // get table
    TablerecPtr tablePtr;
    tablePtr.i= buildReq->tableId;
    ptrCheckGuard(tablePtr, cnoOfTablerec, tablerec);

    const Uint32 firstTupleNo = 0;
    const Uint32 tupheadsize = tablePtr.p->m_offsets[MM].m_fix_header_size;

#ifdef TIME_MEASUREMENT
    MicroSecondTimer start;
    MicroSecondTimer stop;
    NDB_TICKS time_passed;
#endif
    do {
        // get fragment
        FragrecordPtr fragPtr;
        if (buildPtr.p->m_fragNo == MAX_FRAG_PER_NODE) {
            jam();
            // build ready
            buildIndexReply(signal, buildPtr.p);
            c_buildIndexList.release(buildPtr);
            return;
        }
        ndbrequire(buildPtr.p->m_fragNo < MAX_FRAG_PER_NODE);
        fragPtr.i= tablePtr.p->fragrec[buildPtr.p->m_fragNo];
        if (fragPtr.i == RNIL) {
            jam();
            buildPtr.p->m_fragNo++;
            buildPtr.p->m_pageId= 0;
            buildPtr.p->m_tupleNo= firstTupleNo;
            break;
        }
        ptrCheckGuard(fragPtr, cnoOfFragrec, fragrecord);
        // get page
        PagePtr pagePtr;
        if (buildPtr.p->m_pageId >= fragPtr.p->m_max_page_no) {
            jam();
            buildPtr.p->m_fragNo++;
            buildPtr.p->m_pageId= 0;
            buildPtr.p->m_tupleNo= firstTupleNo;
            break;
        }
        Uint32 realPageId= getRealpidCheck(fragPtr.p, buildPtr.p->m_pageId);
        // skip empty page
        if (realPageId == RNIL)
        {
            jam();
            goto next_tuple;
        }

        c_page_pool.getPtr(pagePtr, realPageId);

next_tuple:
        // get tuple
        Uint32 pageIndex = ~0;
        const Tuple_header* tuple_ptr = 0;
        pageIndex = buildPtr.p->m_tupleNo * tupheadsize;
        if (pageIndex + tupheadsize > Fix_page::DATA_WORDS) {
            jam();
            buildPtr.p->m_pageId++;
            buildPtr.p->m_tupleNo= firstTupleNo;
            break;
        }

        if (realPageId == RNIL)
        {
            jam();
            buildPtr.p->m_tupleNo++;
            break;
        }

        tuple_ptr = (Tuple_header*)&pagePtr.p->m_data[pageIndex];
        // skip over free tuple
        if (tuple_ptr->m_header_bits & Tuple_header::FREE) {
            jam();
            buildPtr.p->m_tupleNo++;
            break;
        }
        Uint32 tupVersion= tuple_ptr->get_tuple_version();
        OperationrecPtr pageOperPtr;
        pageOperPtr.i= tuple_ptr->m_operation_ptr_i;
#ifdef TIME_MEASUREMENT
        NdbTick_getMicroTimer(&start);
#endif
        // add to index
        TuxMaintReq* const req = (TuxMaintReq*)signal->getDataPtrSend();
        req->errorCode = RNIL;
        req->tableId = tablePtr.i;
        req->indexId = buildPtr.p->m_indexId;
        req->fragId = tablePtr.p->fragid[buildPtr.p->m_fragNo];
        req->pageId = realPageId;
        req->tupVersion = tupVersion;
        req->opInfo = TuxMaintReq::OpAdd;
        req->tupFragPtrI = fragPtr.i;
        req->fragPageId = buildPtr.p->m_pageId;
        req->pageIndex = pageIndex;

        if (pageOperPtr.i == RNIL)
        {
            EXECUTE_DIRECT(buildPtr.p->m_buildRef, GSN_TUX_MAINT_REQ,
                           signal, TuxMaintReq::SignalLength+2);
        }
        else
        {
            /*
            If there is an ongoing operation on the tuple then it is either a
            copy tuple or an original tuple with an ongoing transaction. In
            both cases realPageId and pageOffset refer to the original tuple.
            The tuple address stored in TUX will always be the original tuple
            but with the tuple version of the tuple we found.

            This is necessary to avoid having to update TUX at abort of
            update. If an update aborts then the copy tuple is copied to
            the original tuple. The build will however have found that
            tuple as a copy tuple. The original tuple is stable and is thus
            preferrable to store in TUX.
            */
            jam();

            /**
             * Since copy tuples now can't be found on real pages.
             *   we will here build all copies of the tuple
             *
             * Note only "real" tupVersion's should be added
             *      i.e delete's shouldnt be added
             *      (unless it's the first op, when "original" should be added)
             */

            /*
             * Start from first operation.  This is only to make things more
             * clear.  It is not required by ordered index implementation.
             */
            c_operation_pool.getPtr(pageOperPtr);
            while (pageOperPtr.p->prevActiveOp != RNIL)
            {
                jam();
                pageOperPtr.i = pageOperPtr.p->prevActiveOp;
                c_operation_pool.getPtr(pageOperPtr);
            }
            /*
             * Do not use req->errorCode as global control.
             */
            bool ok = true;
            /*
             * If first operation is an update, add previous version.
             * This version does not appear as the version of any operation.
             * At commit this version is removed by executeTuxCommitTriggers.
             * At abort it is preserved by executeTuxAbortTriggers.
             */
            if (pageOperPtr.p->op_struct.op_type == ZUPDATE)
            {
                jam();
                req->errorCode = RNIL;
                req->tupVersion = decr_tup_version(pageOperPtr.p->tupVersion);
                EXECUTE_DIRECT(buildPtr.p->m_buildRef, GSN_TUX_MAINT_REQ,
                               signal, TuxMaintReq::SignalLength+2);
                ok = (req->errorCode == 0);
            }
            /*
             * Add versions from all operations.
             *
             * Each operation has a tuple version.  For insert and update it
             * is the newly created version.  For delete it is the version
             * deleted.  The existence of operation tuple version implies that
             * a corresponding tuple version exists for TUX to read.
             *
             * We could be in the middle of a commit.  The process here makes
             * no assumptions about operation commit order.  (It should be
             * first to last but this is not the place to assert it).
             *
             * Duplicate versions are possible e.g. a delete in the middle
             * may have same version as the previous operation.  TUX ignores
             * duplicate version errors during index build.
             */
            while (pageOperPtr.i != RNIL && ok)
            {
                jam();
                c_operation_pool.getPtr(pageOperPtr);
                req->errorCode = RNIL;
                req->tupVersion = pageOperPtr.p->tupVersion;
                EXECUTE_DIRECT(buildPtr.p->m_buildRef, GSN_TUX_MAINT_REQ,
                               signal, TuxMaintReq::SignalLength+2);
                pageOperPtr.i = pageOperPtr.p->nextActiveOp;
                ok = (req->errorCode == 0);
            }
        }

        jamEntry();
        if (req->errorCode != 0) {
            switch (req->errorCode) {
            case TuxMaintReq::NoMemError:
                jam();
                buildPtr.p->m_errorCode= BuildIndxImplRef::AllocationFailure;
                break;
            default:
                ndbrequire(false);
                break;
            }
            buildIndexReply(signal, buildPtr.p);
            c_buildIndexList.release(buildPtr);
            return;
        }
#ifdef TIME_MEASUREMENT
        NdbTick_getMicroTimer(&stop);
        time_passed= NdbTick_getMicrosPassed(start, stop);
        if (time_passed < 1000) {
            time_events++;
            tot_time_passed += time_passed;
            if (time_events == number_events) {
                NDB_TICKS mean_time_passed= tot_time_passed /
                                            (NDB_TICKS)number_events;
                ndbout << "Number of events= " << number_events;
                ndbout << " Mean time passed= " << mean_time_passed << endl;
                number_events <<= 1;
                tot_time_passed= (NDB_TICKS)0;
                time_events= 0;
            }
        }
#endif
        // next tuple
        buildPtr.p->m_tupleNo++;
        break;
    } while (0);
    signal->theData[0]= ZBUILD_INDEX;
    signal->theData[1]= buildPtr.i;
    sendSignal(reference(), GSN_CONTINUEB, signal, 2, JBB);
}
Exemplo n.º 7
0
void
Dbtup::buildIndex(Signal* signal, Uint32 buildPtrI)
{
  // get build record
  BuildIndexPtr buildPtr;
  buildPtr.i= buildPtrI;
  c_buildIndexList.getPtr(buildPtr);
  const BuildIndxReq* buildReq= (const BuildIndxReq*)buildPtr.p->m_request;
  // get table
  TablerecPtr tablePtr;
  tablePtr.i= buildReq->getTableId();
  ptrCheckGuard(tablePtr, cnoOfTablerec, tablerec);

  const Uint32 firstTupleNo = 0;
  const Uint32 tupheadsize = tablePtr.p->m_offsets[MM].m_fix_header_size;

#ifdef TIME_MEASUREMENT
  MicroSecondTimer start;
  MicroSecondTimer stop;
  NDB_TICKS time_passed;
#endif
  do {
    // get fragment
    FragrecordPtr fragPtr;
    if (buildPtr.p->m_fragNo == MAX_FRAG_PER_NODE) {
      jam();
      // build ready
      buildIndexReply(signal, buildPtr.p);
      c_buildIndexList.release(buildPtr);
      return;
    }
    ndbrequire(buildPtr.p->m_fragNo < MAX_FRAG_PER_NODE);
    fragPtr.i= tablePtr.p->fragrec[buildPtr.p->m_fragNo];
    if (fragPtr.i == RNIL) {
      jam();
      buildPtr.p->m_fragNo++;
      buildPtr.p->m_pageId= 0;
      buildPtr.p->m_tupleNo= firstTupleNo;
      break;
    }
    ptrCheckGuard(fragPtr, cnoOfFragrec, fragrecord);
    // get page
    PagePtr pagePtr;
    if (buildPtr.p->m_pageId >= fragPtr.p->noOfPages) {
      jam();
      buildPtr.p->m_fragNo++;
      buildPtr.p->m_pageId= 0;
      buildPtr.p->m_tupleNo= firstTupleNo;
      break;
    }
    Uint32 realPageId= getRealpid(fragPtr.p, buildPtr.p->m_pageId);
    c_page_pool.getPtr(pagePtr, realPageId);
    Uint32 pageState= pagePtr.p->page_state;
    // skip empty page
    if (pageState == ZEMPTY_MM) {
      jam();
      buildPtr.p->m_pageId++;
      buildPtr.p->m_tupleNo= firstTupleNo;
      break;
    }
    // get tuple
    Uint32 pageIndex = ~0;
    const Tuple_header* tuple_ptr = 0;
    pageIndex = buildPtr.p->m_tupleNo * tupheadsize;
    if (pageIndex + tupheadsize > Fix_page::DATA_WORDS) {
      jam();
      buildPtr.p->m_pageId++;
      buildPtr.p->m_tupleNo= firstTupleNo;
      break;
    }
    tuple_ptr = (Tuple_header*)&pagePtr.p->m_data[pageIndex];
    // skip over free tuple
    if (tuple_ptr->m_header_bits & Tuple_header::FREE) {
      jam();
      buildPtr.p->m_tupleNo++;
      break;
    }
    Uint32 tupVersion= tuple_ptr->get_tuple_version();
    OperationrecPtr pageOperPtr;
    pageOperPtr.i= tuple_ptr->m_operation_ptr_i;
#ifdef TIME_MEASUREMENT
    NdbTick_getMicroTimer(&start);
#endif
    // add to index
    TuxMaintReq* const req = (TuxMaintReq*)signal->getDataPtrSend();
    req->errorCode = RNIL;
    req->tableId = tablePtr.i;
    req->indexId = buildPtr.p->m_indexId;
    req->fragId = tablePtr.p->fragid[buildPtr.p->m_fragNo];
    req->pageId = realPageId;
    req->tupVersion = tupVersion;
    req->opInfo = TuxMaintReq::OpAdd;
    req->tupFragPtrI = fragPtr.i;
    req->fragPageId = buildPtr.p->m_pageId;
    req->pageIndex = pageIndex;

    if (pageOperPtr.i == RNIL)
    {
      EXECUTE_DIRECT(buildPtr.p->m_buildRef, GSN_TUX_MAINT_REQ,
		     signal, TuxMaintReq::SignalLength+2);
    }
    else
    {
      /*
      If there is an ongoing operation on the tuple then it is either a
      copy tuple or an original tuple with an ongoing transaction. In
      both cases realPageId and pageOffset refer to the original tuple.
      The tuple address stored in TUX will always be the original tuple
      but with the tuple version of the tuple we found.

      This is necessary to avoid having to update TUX at abort of
      update. If an update aborts then the copy tuple is copied to
      the original tuple. The build will however have found that
      tuple as a copy tuple. The original tuple is stable and is thus
      preferrable to store in TUX.
      */
      jam();

      /**
       * Since copy tuples now can't be found on real pages.
       *   we will here build all copies of the tuple
       *
       * Note only "real" tupVersion's should be added 
       *      i.e delete's shouldnt be added 
       *      (unless it's the first op, when "original" should be added)
       */
      do 
      {
	c_operation_pool.getPtr(pageOperPtr);
	if(pageOperPtr.p->op_struct.op_type != ZDELETE ||
	   pageOperPtr.p->is_first_operation())
	{
	  req->errorCode = RNIL;
	  req->tupVersion= pageOperPtr.p->tupVersion;
	  EXECUTE_DIRECT(buildPtr.p->m_buildRef, GSN_TUX_MAINT_REQ,
			 signal, TuxMaintReq::SignalLength+2);
	}
	else
	{
	  req->errorCode= 0;
	}
	pageOperPtr.i= pageOperPtr.p->prevActiveOp;
      } while(req->errorCode == 0 && pageOperPtr.i != RNIL);
    } 
    
    jamEntry();
    if (req->errorCode != 0) {
      switch (req->errorCode) {
      case TuxMaintReq::NoMemError:
        jam();
        buildPtr.p->m_errorCode= BuildIndxRef::AllocationFailure;
        break;
      default:
        ndbrequire(false);
        break;
      }
      buildIndexReply(signal, buildPtr.p);
      c_buildIndexList.release(buildPtr);
      return;
    }
#ifdef TIME_MEASUREMENT
    NdbTick_getMicroTimer(&stop);
    time_passed= NdbTick_getMicrosPassed(start, stop);
    if (time_passed < 1000) {
      time_events++;
      tot_time_passed += time_passed;
      if (time_events == number_events) {
        NDB_TICKS mean_time_passed= tot_time_passed /
                                     (NDB_TICKS)number_events;
        ndbout << "Number of events= " << number_events;
        ndbout << " Mean time passed= " << mean_time_passed << endl;
        number_events <<= 1;
        tot_time_passed= (NDB_TICKS)0;
        time_events= 0;
      }
    }
#endif
    // next tuple
    buildPtr.p->m_tupleNo++;
    break;
  } while (0);
  signal->theData[0]= ZBUILD_INDEX;
  signal->theData[1]= buildPtr.i;
  sendSignal(reference(), GSN_CONTINUEB, signal, 2, JBB);
}