bool
SocketServer::stopSessions(bool wait, unsigned wait_timeout){
  int i;
  m_session_mutex.lock();
  for(i = m_sessions.size() - 1; i>=0; i--)
  {
    m_sessions[i].m_session->stopSession();
  }
  m_session_mutex.unlock();
  
  for(i = m_services.size() - 1; i>=0; i--)
    m_services[i].m_service->stopSessions();
  
  if(!wait)
    return false; // No wait

  const NDB_TICKS start = NdbTick_getCurrentTicks();
  m_session_mutex.lock();
  while(m_sessions.size() > 0){
    checkSessionsImpl();
    m_session_mutex.unlock();

    if (wait_timeout > 0 &&
        NdbTick_Elapsed(start,NdbTick_getCurrentTicks()).milliSec() > wait_timeout)
      return false; // Wait abandoned

    NdbSleep_MilliSleep(100);
    m_session_mutex.lock();
  }
  m_session_mutex.unlock();
  return true; // All sessions gone
}
double userGetTimeSync(void)
{
  double timeValue = 0;

  if ( !NdbTick_IsValid(initTicks)) {
    initTicks = NdbTick_getCurrentTicks();
    timeValue = 0.0;
  } else {
    const NDB_TICKS now = NdbTick_getCurrentTicks();
    const Uint64 elapsedMicro =
      NdbTick_Elapsed(initTicks,now).microSec();

    timeValue = ((double)elapsedMicro) / 1000000.0;
  }
  return timeValue;
}
bool
WatchDog::registerWatchedThread(Uint32 *counter, Uint32 threadId)
{
  bool ret;

  NdbMutex_Lock(m_mutex);

  if (m_watchedCount >= MAX_WATCHED_THREADS)
  {
    ret = false;
  }
  else
  {
    m_watchedList[m_watchedCount].m_watchCounter = counter;
    m_watchedList[m_watchedCount].m_threadId = threadId;
    m_watchedList[m_watchedCount].m_startTicks = NdbTick_getCurrentTicks();
    m_watchedList[m_watchedCount].m_slowWarnDelay = theInterval;
    m_watchedList[m_watchedCount].m_lastCounterValue = 0;
    ++m_watchedCount;
    ret = true;
  }

  NdbMutex_Unlock(m_mutex);
  return ret;
}
void*
thread_main(void * _t)
{
  const NDB_TICKS now = NdbTick_getCurrentTicks(); 
  unsigned seed =
    (unsigned)now.getUint64() +
    (unsigned)(unsigned long long)_t;

  Thread * self = (Thread*) _t;
  for (unsigned i = 0; i < cnt_inner_loops; i++)
  {
    test.wait_started();
    for (unsigned j = 0; j < cnt_signals_per_inner_loop;)
    {
      for (unsigned k = 0; k < cnt_signals_before_consume; k++)
      {
        /**
         * Produce a signal to destination D
         */
        unsigned D = unsigned(ndb_rand_r(&seed)) % cnt_transporters;
        self->p.produce(D);
      }

      j += cnt_signals_before_consume;

      /**
       * This is the equivalent of do_send()
       */
      bool force = unsigned(ndb_rand_r(&seed) % 100) < pct_force;
      self->p.consume(force);
    }
    test.wait_completed();
  }
  return 0;
}
Example #5
0
SimpleSignal *
SignalSender::waitFor(Uint32 timeOutMillis, T & t)
{
    SimpleSignal * s = t.check(m_jobBuffer);
    if(s != 0) {
        if (m_usedBuffer.push_back(s))
        {
            return 0;
        }
        assert(s->header.theLength > 0);
        return s;
    }

    /* Remove old signals from usedBuffer */
    for (unsigned i= 0; i < m_usedBuffer.size(); i++)
        delete m_usedBuffer[i];
    m_usedBuffer.clear();

    const NDB_TICKS start = NdbTick_getCurrentTicks();
    Uint32 waited = 0; //ms waited since 'start'
    do {
        const Uint32 wait = (timeOutMillis == 0 ? 10
                             : timeOutMillis-waited);
        do_poll(wait);

        SimpleSignal * s = t.check(m_jobBuffer);
        if(s != 0) {
            if (m_usedBuffer.push_back(s))
            {
                return 0;
            }
            assert(s->header.theLength > 0);
            return s;
        }

        // Calculate total wait(ms) since 'start'
        const NDB_TICKS now = NdbTick_getCurrentTicks();
        waited = (Uint32)NdbTick_Elapsed(start,now).milliSec();

    } while(timeOutMillis == 0 || waited < timeOutMillis);

    return 0;
}
inline
void
Consumer::consume(unsigned D)
{
  /**
   * This is the equivalent of do_send(must_send = 1)
   */
  m_force_send = 1;

  do
  {
    if (trylock(&m_send_lock) != 0)
    {
      /* Other thread will send for us as we set m_force_send. */
      return;
    }

    /**
     * Now clear the flag, and start sending all data available to this node.
     *
     * Put a memory barrier here, so that if another thread tries to grab
     * the send lock but fails due to us holding it here, we either
     * 1) Will see m_force_send[nodeId] set to 1 at the end of the loop, or
     * 2) We clear here the flag just set by the other thread, but then we
     * will (thanks to mb()) be able to see and send all of the data already
     * in the first send iteration.
     */
    m_force_send = 0;
    mb();

    /**
     * This is the equivalent of link_thread_send_buffers
     */
    for (unsigned i = 0; i < cnt_threads; i++)
    {
      val[i] = rep.t[i].t.p.val[D];
    }

    /**
     * Do a syscall...which could have affect on barriers...etc
     */
    if (DO_SYSCALL)
    {
      NdbTick_getCurrentTicks();
    }

    unlock(&m_send_lock);

#if BUGGY_VERSION
#else
    mb();
#endif
  }
  while (m_force_send != 0);
}
Example #7
0
/**
 * For each millisecond that has passed since this function was last called:
 *   Scan the job buffer and increment the internalTicksCounter 
 *      with 1ms to keep track of where we are
 */
inline
void 
ThreadConfig::scanTimeQueue()
{
  unsigned int maxCounter = 0;
  const NDB_TICKS currTicks = NdbTick_getCurrentTicks();

  if (NdbTick_Compare(currTicks, globalData.internalTicksCounter) < 0) {
//--------------------------------------------------------------------
// This could occur around 2036 or if the operator decides to change
// time backwards. We cannot know how long time has past since last
// time and we make a best try with 0 milliseconds.
//--------------------------------------------------------------------
    const Uint64 backward = 
      NdbTick_Elapsed(currTicks, globalData.internalTicksCounter).milliSec();

    // Silently ignore sub millisecond backticks.
    // Such 'noise' is unfortunately common even for monotonic timers.
    if (backward > 0)
    {
      g_eventLogger->warning("Time moved backwards with %llu ms", backward);
      globalData.internalTicksCounter = currTicks;
      assert(backward < 100 || !NdbTick_IsMonotonic()); 
    }
    return;
  }//if

  Uint64 elapsed = 
    NdbTick_Elapsed(globalData.internalTicksCounter,currTicks).milliSec();
  if (elapsed > 1500) {
//--------------------------------------------------------------------
// Time has moved forward more than a second. Either it could happen
// if operator changed the time or if the OS has misbehaved badly.
// We set the new time to one second from the past.
//--------------------------------------------------------------------
    g_eventLogger->warning("Time moved forward with %llu ms", elapsed);
    elapsed -= 1000;
    globalData.internalTicksCounter = 
      NdbTick_AddMilliseconds(globalData.internalTicksCounter,elapsed);
  }//if
  while ((elapsed > 0) &&
         (maxCounter < 20)){
    globalData.internalTicksCounter = 
      NdbTick_AddMilliseconds(globalData.internalTicksCounter,1);
    elapsed--;
    maxCounter++;
    globalTimeQueue.scanTable();
  }//while
}//ThreadConfig::scanTimeQueue()
Example #8
0
void
Thrman::execSTTOR(Signal *signal)
{
  jamEntry();

  const Uint32 startPhase  = signal->theData[1];

  switch (startPhase) {
  case 1:
    Ndb_GetRUsage(&last_rusage);
    prev_cpu_usage_check = NdbTick_getCurrentTicks();
    sendNextCONTINUEB(signal);
    break;
  default:
    ndbrequire(false);
  }
  sendSTTORRY(signal);
}
inline
void
Consumer::forceConsume(unsigned D)
{
  /**
   * This is the equivalent of forceSend()
   */

  do
  {
    /**
     * NOTE: since we unconditionally lock m_send_lock
     *   we don't need a mb() after the clearing of m_force_send here.
     */
    m_force_send = 0;

    lock(&m_send_lock);

    /**
     * This is the equivalent of link_thread_send_buffers
     */
    for (unsigned i = 0; i < cnt_threads; i++)
    {
      val[i] = rep.t[i].t.p.val[D];
    }

    /**
     * Do a syscall...which could have affect on barriers...etc
     */
    if (DO_SYSCALL)
    {
      NdbTick_getCurrentTicks();
    }

    unlock(&m_send_lock);

#if BUGGY_VERSION
#else
    mb();
#endif
  }
  while (m_force_send != 0);
}
int
Ndb_move_data::move_data(Ndb* ndb)
{
  int ret = 0;
  Op& op = m_op;
  Stat& stat = m_stat;
  stat.rows_moved = 0; // keep rows_total
  do
  {
    const NDB_TICKS now = NdbTick_getCurrentTicks(); 
    ndb_srand((unsigned)now.getUint64());
    reset_error();

    CHK2(m_source != 0 && m_target != 0,
        (Error::InvalidState, "source / target not defined"));

    op.ndb = ndb;
    CHK1(m_error.code == 0);
    CHK1(check_tables() == 0);
    CHK1(start_scan() == 0);
    while (1)
    {
      CHK1(move_batch() == 0);
      stat.rows_moved += op.rows_in_batch;
      stat.rows_total += op.rows_in_batch;
      stat.truncated += op.truncated_in_batch;

      require(op.end_of_scan == (op.rows_in_batch == 0));
      if (op.end_of_scan)
        break;
    }
    CHK1(ret == 0);
  }
  while (0);
  close_op(ndb, ret);
  return ret;
}
Example #11
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
  NDB_TICKS start;
  NDB_TICKS stop;
  Uint64 time_passed;
#endif
  do {
    // get fragment
    FragrecordPtr fragPtr;
    if (buildPtr.p->m_fragNo == NDB_ARRAY_SIZE(tablePtr.p->fragrec)) {
      jam();
      // build ready
      buildIndexReply(signal, buildPtr.p);
      c_buildIndexList.release(buildPtr);
      return;
    }
    ndbrequire(buildPtr.p->m_fragNo < NDB_ARRAY_SIZE(tablePtr.p->fragrec));
    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_cnt)
    {
      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
    start = NdbTick_getCurrentTicks();
#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_type == ZUPDATE)
      {
        jam();
        req->errorCode = RNIL;
        req->tupVersion =
          decr_tup_version(pageOperPtr.p->op_struct.bit_field.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->op_struct.bit_field.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
    stop = NdbTick_getCurrentTicks();
    time_passed= NdbTick_Elapsed(start, stop).microSec();
    if (time_passed < 1000) {
      time_events++;
      tot_time_passed += time_passed;
      if (time_events == number_events) {
        Uint64 mean_time_passed= tot_time_passed /
                                     (Uint64)number_events;
        ndbout << "Number of events= " << number_events;
        ndbout << " Mean time passed= " << mean_time_passed << endl;
        number_events <<= 1;
        tot_time_passed= 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);
}
Example #12
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* pThis)
{
  Uint32 thread_index = globalEmulatorData.theConfiguration->addThread(pThis,
                                                                 BlockThread);
  globalEmulatorData.theConfiguration->setAllLockCPU(true);

  Uint32 execute_loop_constant =
        globalEmulatorData.theConfiguration->schedulerExecutionTimer();
  Uint32 min_spin_time = 
    globalEmulatorData.theConfiguration->schedulerSpinTimer();
  NDB_TICKS start_ticks, end_ticks, statistics_start_ticks;
  NDB_TICKS yield_ticks;
  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;
  Uint32 i = 0;
  Uint32 exec_again;

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

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

  start_ticks = NdbTick_getCurrentTicks();
  yield_ticks = statistics_start_ticks = end_ticks = start_ticks;
  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);
      scanZeroTimeQueue(); 
      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)
            end_ticks = NdbTick_getCurrentTicks();

          micros_passed = 
            (Uint32)NdbTick_Elapsed(start_ticks, end_ticks).microSec();
          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);
          yield_ticks = NdbTick_getCurrentTicks();
        }
        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.
//--------------------------------------------------------------------
    start_ticks = NdbTick_getCurrentTicks();
    if ((NdbTick_Elapsed(yield_ticks, start_ticks).microSec() > 10000))
      yield_flag= TRUE;
    exec_again= 0;
    Uint32 loopStartCount = 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.
//--------------------------------------------------------------------
      loopStartCount = globalScheduler.doJob(loopStartCount);
      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;

      end_ticks = NdbTick_getCurrentTicks();
      micros_passed = (Uint32)NdbTick_Elapsed(start_ticks, end_ticks).microSec();
      tot_exec_time += micros_passed;
      if (no_exec_loops++ >= 8192)
      {
        Uint32 expired_time = 
          (Uint32)NdbTick_Elapsed(statistics_start_ticks, end_ticks).microSec();
        statistics_start_ticks = end_ticks;
        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_ticks = end_ticks;
      globalData.incrementWatchDogCounter(8);
      globalTransporterRegistry.performReceive();
    } while (1);
  }
out:
  globalData.incrementWatchDogCounter(6);
  globalTransporterRegistry.performSend();

  globalEmulatorData.theWatchDog->unregisterWatchedThread(0);
  globalEmulatorData.theConfiguration->removeThread(pThis);
}//ThreadConfig::ipControlLoop()
Example #13
0
void
Thrman::measure_cpu_usage(void)
{
  struct ndb_rusage curr_rusage;
  Uint64 elapsed_micros;

  Uint64 user_micros;
  Uint64 kernel_micros;
  Uint64 total_micros;

  /**
   * Start by making a new CPU usage measurement. After that we will
   * measure how much time has passed since last measurement and from
   * this we can calculate a percentage of CPU usage that this thread
   * has had for the last second or so.
   */
  int res = Ndb_GetRUsage(&curr_rusage);
  if (res != 0)
  {
#ifdef DEBUG_CPU_USAGE
    ndbout << "res = " << -res << endl;
#endif
  }
  NDB_TICKS curr_time = NdbTick_getCurrentTicks();
  if ((curr_rusage.ru_utime == 0 && curr_rusage.ru_stime == 0) ||
      (last_rusage.ru_utime == 0 && last_rusage.ru_stime == 0))
  {
    /**
     * We lack at least one valid measurement to make any conclusions.
     * We set CPU usage to 90 as the default value.
     */
    current_cpu_load = default_cpu_load;
  }
  else
  {

    elapsed_micros = NdbTick_Elapsed(prev_cpu_usage_check,
                                     curr_time).microSec();

    user_micros = curr_rusage.ru_utime - last_rusage.ru_utime;
    kernel_micros = curr_rusage.ru_stime - last_rusage.ru_stime;
    total_micros = user_micros + kernel_micros;

    if (elapsed_micros != 0)
    {
      /* Handle errors in time measurements */
      current_cpu_load = (total_micros * 100) / elapsed_micros;
    }
    if (current_cpu_load > 100)
    {
      /* Handle errors in time measurements */
      current_cpu_load = 100;
    }
  }
#ifdef DEBUG_CPU_USAGE
  if (current_cpu_load != 0)
  {
    ndbout << "CPU usage is now " << current_cpu_load << "%";
    ndbout << " in instance " << instance() << endl;
  }
#endif
  last_rusage = curr_rusage;
  prev_cpu_usage_check = curr_time;
}
int
main(int argc, char ** argv)
{
  plan(1);
  ndb_init();
  test.init();
  rep.init();

  if (argc == 1)
  {
    printf("No arguments supplied...\n"
           "assuming we're being run from MTR or similar.\n"
           "decreasing loop counts to ridiculously small values...\n");
    cnt_seconds = 10;
    cnt_inner_loops = 3000;
    cnt_threads = 4;
  }
  else
  {
    printf("Arguments supplied...\n");
    for (int i = 1; i < argc; i++)
    {
      if (match(argv[i], "cnt_seconds=", &cnt_seconds))
        continue;
      else if (match(argv[i], "cnt_threads=", &cnt_threads))
        continue;
      else if (match(argv[i], "cnt_transporters=", &cnt_transporters))
        continue;
      else if (match(argv[i], "cnt_inner_loops=", &cnt_inner_loops))
        continue;
      else if (match(argv[i], "cnt_signals_before_consume=",
                     &cnt_signals_before_consume))
        continue;
      else if (match(argv[i], "cnt_signals_per_inner_loop=",
                     &cnt_signals_per_inner_loop))
        continue;
      else if (match(argv[i], "pct_force=",
                     &pct_force))
        continue;
      else
      {
        printf("ignoreing unknown argument: %s\n", argv[i]);
      }
    }
  }

  printf("%s"
         " cnt_seconds=%u"
         " cnt_threads=%u"
         " cnt_transporters=%u"
         " cnt_inner_loops=%u"
         " cnt_signals_before_consume=%u"
         " cnt_signals_per_inner_loop=%u"
         " pct_force=%u"
         "\n",
         argv[0],
         cnt_seconds,
         cnt_threads,
         cnt_transporters,
         cnt_inner_loops,
         cnt_signals_before_consume,
         cnt_signals_per_inner_loop,
         pct_force);

  Uint32 loop = 0;
  const NDB_TICKS start = NdbTick_getCurrentTicks();
  while (NdbTick_Elapsed(start,NdbTick_getCurrentTicks()).seconds() <= cnt_seconds)
  {
    printf("%u ", loop++); fflush(stdout);
    if ((loop < 100 && (loop % 25) == 0) ||
        (loop >= 100 && (loop % 20) == 0))
      printf("\n");

    for (unsigned t = 0; t < cnt_threads; t++)
    {
      rep.t[t].t.thread = NdbThread_Create(thread_main,
                                           (void**)&rep.t[t].t,
                                           1024*1024,
                                           "execute thread",
                                           NDB_THREAD_PRIO_MEAN);
    }

    for (unsigned t = 0; t < cnt_threads; t++)
    {
      void * ret;
      NdbThread_WaitFor(rep.t[t].t.thread, &ret);
    }
  }
  printf("\n"); fflush(stdout);

  ok(true, "ok");
  return 0;
}
Example #15
0
void
ClusterMgr::threadMain()
{
    startup();

    NdbApiSignal signal(numberToRef(API_CLUSTERMGR, theFacade.ownId()));

    signal.theVerId_signalNumber   = GSN_API_REGREQ;
    signal.theTrace                = 0;
    signal.theLength               = ApiRegReq::SignalLength;

    ApiRegReq * req = CAST_PTR(ApiRegReq, signal.getDataPtrSend());
    req->ref = numberToRef(API_CLUSTERMGR, theFacade.ownId());
    req->version = NDB_VERSION;
    req->mysql_version = NDB_MYSQL_VERSION_D;

    NdbApiSignal nodeFail_signal(numberToRef(API_CLUSTERMGR, getOwnNodeId()));
    nodeFail_signal.theVerId_signalNumber = GSN_NODE_FAILREP;
    nodeFail_signal.theReceiversBlockNumber = API_CLUSTERMGR;
    nodeFail_signal.theTrace  = 0;
    nodeFail_signal.theLength = NodeFailRep::SignalLengthLong;

    NDB_TICKS now = NdbTick_getCurrentTicks();

    while(!theStop)
    {
        /* Sleep 1/5 of minHeartBeatInterval between each check */
        const NDB_TICKS before = now;
        for (Uint32 i = 0; i<5; i++)
        {
            NdbSleep_MilliSleep(minHeartBeatInterval/5);
            {
                /**
                 * start_poll does lock the trp_client and complete_poll
                 * releases this lock. This means that this protects
                 * against concurrent calls to send signals in ArbitMgr.
                 * We do however need to protect also against concurrent
                 * close in doStop, so to avoid this problem we need to
                 * also lock clusterMgrThreadMutex before we start the
                 * poll.
                 */
                Guard g(clusterMgrThreadMutex);
                start_poll();
                do_poll(0);
                complete_poll();
            }
        }
        now = NdbTick_getCurrentTicks();
        const Uint32 timeSlept = (Uint32)NdbTick_Elapsed(before, now).milliSec();

        lock();
        if (m_cluster_state == CS_waiting_for_clean_cache &&
                theFacade.m_globalDictCache)
        {
            if (!global_flag_skip_waiting_for_clean_cache)
            {
                theFacade.m_globalDictCache->lock();
                unsigned sz= theFacade.m_globalDictCache->get_size();
                theFacade.m_globalDictCache->unlock();
                if (sz)
                {
                    unlock();
                    continue;
                }
            }
            m_cluster_state = CS_waiting_for_first_connect;
        }

        NodeFailRep * nodeFailRep = CAST_PTR(NodeFailRep,
                                             nodeFail_signal.getDataPtrSend());
        nodeFailRep->noOfNodes = 0;
        NodeBitmask::clear(nodeFailRep->theAllNodes);

        for (int i = 1; i < MAX_NODES; i++)
        {
            /**
             * Send register request (heartbeat) to all available nodes
             * at specified timing intervals
             */
            const NodeId nodeId = i;
            // Check array bounds + don't allow node 0 to be touched
            assert(nodeId > 0 && nodeId < MAX_NODES);
            Node & cm_node = theNodes[nodeId];
            trp_node & theNode = cm_node;

            if (!theNode.defined)
                continue;

            if (theNode.is_connected() == false) {
                theFacade.doConnect(nodeId);
                continue;
            }

            if (!theNode.compatible) {
                continue;
            }

            if (nodeId == getOwnNodeId())
            {
                /**
                 * Don't send HB to self more than once
                 * (once needed to avoid weird special cases in e.g ConfigManager)
                 */
                if (m_sent_API_REGREQ_to_myself)
                {
                    continue;
                }
            }

            cm_node.hbCounter += timeSlept;
            if (cm_node.hbCounter >= m_max_api_reg_req_interval ||
                    cm_node.hbCounter >= cm_node.hbFrequency)
            {
                /**
                 * It is now time to send a new Heartbeat
                 */
                if (cm_node.hbCounter >= cm_node.hbFrequency)
                {
                    cm_node.hbMissed++;
                    cm_node.hbCounter = 0;
                }

                if (theNode.m_info.m_type != NodeInfo::DB)
                    signal.theReceiversBlockNumber = API_CLUSTERMGR;
                else
                    signal.theReceiversBlockNumber = QMGR;

#ifdef DEBUG_REG
                ndbout_c("ClusterMgr: Sending API_REGREQ to node %d", (int)nodeId);
#endif
                if (nodeId == getOwnNodeId())
                {
                    /* Set flag to ensure we only send once to ourself */
                    m_sent_API_REGREQ_to_myself = true;
                }
                raw_sendSignal(&signal, nodeId);
            }//if

            if (cm_node.hbMissed == 4 && cm_node.hbFrequency > 0)
            {
                nodeFailRep->noOfNodes++;
                NodeBitmask::set(nodeFailRep->theAllNodes, nodeId);
            }
        }
        flush_send_buffers();
        unlock();

        if (nodeFailRep->noOfNodes)
        {
            lock();
            raw_sendSignal(&nodeFail_signal, getOwnNodeId());
            flush_send_buffers();
            unlock();
        }
    }
}
int MultiNdbWakeupHandler::waitForInput(Ndb** _objs,
                                        int _cnt,
                                        int min_req,
                                        int timeout_millis,
                                        int *nready)
{
  /**
    Initialise object for waiting.

    numNdbsWithCompletedTrans: 
    Keeps track of number of transactions completed and is protected by
    localWakeupMutexPtr-mutex. It can be set to 0 without mutex protection
    since the poll owner thread will not access it until we have registered
    at least one NDB object.

    minNdbsToWake:
    This is used by both notifyWakeup and notifyTransactionsCompleted to
    see whether we're currently waiting to be woken up. We always access
    it protected by the Ndb mutex on the waiter object.

    objs:
    This is a local array set when waitForInput is called. It is only
    manipulated by the thread calling waitForInput. So it doesn't need
    any protection when used.

    cnt:
    This is a local counter of how many objects we're waiting for, only
    used by the thread calling waitForInput, so no need to protect it.

    woken:
    This is set by notifyWakeup to indicate we should wake up even if no
    NDB objects are done. This is protected by the Ndb mutex on the waiter
    object.
  */

  numNdbsWithCompletedTrans = 0;
  cnt = (Uint32)_cnt;
  objs = _objs;

  NdbMutex_Lock(wakeNdb->theImpl->m_mutex);
  ignore_wakeups();
  NdbMutex_Unlock(wakeNdb->theImpl->m_mutex);

  /*
    Before sleeping, we register each Ndb, and check whether it already
    has any completed transactions.
  */
  for (Uint32 i = 0; i < cnt; i++)
  {
    /* Register the Ndb's */
    registerNdb(objs[i], i);
  }

  int ret = -1;
  bool first = true;
  const NDB_TICKS start = NdbTick_getCurrentTicks();
  const int maxTime = timeout_millis;
  {
    PollGuard pg(*wakeNdb->theImpl);
    do
    {
      if (first)
      {
        set_wakeup(min_req);
        if (isReadyToWake())  // already enough
        {
          pg.wait_for_input(0);
          ignore_wakeups();
          ret = 0;
          break;
        }
        wakeNdb->theImpl->theWaiter.set_node(0);
        wakeNdb->theImpl->theWaiter.set_state(WAIT_TRANS);
        first = false;
      }
      /* PollGuard will put us to sleep until something relevant happens */
      pg.wait_for_input(timeout_millis > 10 ? 10 : timeout_millis);
      wakeNdb->theImpl->incClientStat(Ndb::WaitExecCompleteCount, 1);
 
      if (isReadyToWake())
      {
        ignore_wakeups();
        ret = 0;
        break;
      }
      const NDB_TICKS now = NdbTick_getCurrentTicks();
      timeout_millis = (maxTime - (int)NdbTick_Elapsed(start,now).milliSec());
      if (timeout_millis <= 0)
      {
        ignore_wakeups();
        break;
      }
    } while (1);
  }
  finalize_wait(nready);
  return ret;
}
void
AsyncIoThread::run()
{
  bool first_flag = true;
  Request *request;
  NDB_TICKS last_yield_ticks;

  // Create theMemoryChannel in the thread that will wait for it
  NdbMutex_Lock(theStartMutexPtr);
  theStartFlag = true;
  NdbMutex_Unlock(theStartMutexPtr);
  NdbCondition_Signal(theStartConditionPtr);

  EmulatedJamBuffer jamBuffer;
  jamBuffer.theEmulatedJamIndex = 0;
  // This key is needed by jamNoBlock().
  NdbThread_SetTlsKey(NDB_THREAD_TLS_JAM, &jamBuffer);

  while (1)
  {
    if (m_real_time)
    {
      /**
       * If we are running in real-time we'll simply insert a break every
       * so often to ensure that low-prio threads aren't blocked from the
       * CPU, this is especially important if we're using a compressed
       * file system where lots of CPU is used by this thread.
       */
      bool yield_flag = false;
      const NDB_TICKS current_ticks = NdbTick_getCurrentTicks();

      if (first_flag)
      {
        first_flag = false;
        yield_flag = true;
      }
      else
      {
        Uint64 micros_passed =
          NdbTick_Elapsed(last_yield_ticks, current_ticks).microSec();
        if (micros_passed > 10000)
        {
          yield_flag = true;
        }
      }
      if (yield_flag)
      {
        if (NdbThread_yield_rt(theThreadPtr, TRUE))
        {
          m_real_time = false;
        }
        last_yield_ticks = current_ticks;
      }
    }
    request = theMemoryChannelPtr->readChannel();
    if (!request || request->action == Request::end)
    {
      DEBUG(ndbout_c("Nothing read from Memory Channel in AsyncFile"));
      theStartFlag = false;
      return;
    }//if

    AsyncFile * file = request->file;
    m_current_request= request;
    switch (request->action) {
    case Request::open:
      file->openReq(request);
      if (request->error == 0 && request->m_do_bind)
        attach(file);
      break;
    case Request::close:
      file->closeReq(request);
      detach(file);
      break;
    case Request::closeRemove:
      file->closeReq(request);
      file->removeReq(request);
      detach(file);
      break;
    case Request::readPartial:
    case Request::read:
      file->readReq(request);
      break;
    case Request::readv:
      file->readvReq(request);
      break;
    case Request::write:
      file->writeReq(request);
      break;
    case Request::writev:
      file->writevReq(request);
      break;
    case Request::writeSync:
      file->writeReq(request);
      file->syncReq(request);
      break;
    case Request::writevSync:
      file->writevReq(request);
      file->syncReq(request);
      break;
    case Request::sync:
      file->syncReq(request);
      break;
    case Request::append:
      file->appendReq(request);
      break;
    case Request::append_synch:
      file->appendReq(request);
      file->syncReq(request);
      break;
    case Request::rmrf:
      file->rmrfReq(request, file->theFileName.c_str(),
                    request->par.rmrf.own_directory);
      break;
    case Request::end:
      theStartFlag = false;
      return;
    case Request::allocmem:
    {
      allocMemReq(request);
      break;
    }
    case Request::buildindx:
      buildIndxReq(request);
      break;
    case Request::suspend:
      if (request->par.suspend.milliseconds)
      {
        g_eventLogger->debug("Suspend %s %u ms",
                             file->theFileName.c_str(),
                             request->par.suspend.milliseconds);
        NdbSleep_MilliSleep(request->par.suspend.milliseconds);
        continue;
      }
      else
      {
        g_eventLogger->debug("Suspend %s",
                             file->theFileName.c_str());
        theStartFlag = false;
        return;
      }
    default:
      DEBUG(ndbout_c("Invalid Request"));
      abort();
      break;
    }//switch
    m_last_request = request;
    m_current_request = 0;

    // No need to signal as ndbfs only uses tryRead
    theReportTo->writeChannelNoSignal(request);
    m_fs.wakeup();
  }
}
void Qmgr::initData() 
{
  creadyDistCom = ZFALSE;

  // Records with constant sizes
  nodeRec = new NodeRec[MAX_NODES];
  for (Uint32 i = 0; i<MAX_NODES; i++)
  {
    nodeRec[i].m_secret = 0;
  }

  c_maxDynamicId = 0;
  c_clusterNodes.clear();
  c_stopReq.senderRef = 0;

  /**
   * Check sanity for NodeVersion
   */
  ndbrequire((Uint32)NodeInfo::DB == 0);
  ndbrequire((Uint32)NodeInfo::API == 1);
  ndbrequire((Uint32)NodeInfo::MGM == 2); 

  m_micro_gcp_enabled = false;
  m_hb_order_config_used = false;

  NodeRecPtr nodePtr;
  nodePtr.i = getOwnNodeId();
  ptrAss(nodePtr, nodeRec);
  nodePtr.p->blockRef = reference();
  ndbrequire(getNodeInfo(getOwnNodeId()).m_type == NodeInfo::DB);

  c_connectedNodes.set(getOwnNodeId());
  setNodeInfo(getOwnNodeId()).m_version = NDB_VERSION;


  /**
   * Timeouts
   */
  const ndb_mgm_configuration_iterator * p = 
    m_ctx.m_config.getOwnConfigIterator();
  ndbrequire(p != 0);
  
  Uint32 hbDBAPI = 1500;
  ndb_mgm_get_int_parameter(p, CFG_DB_API_HEARTBEAT_INTERVAL, &hbDBAPI);
  
  setHbApiDelay(hbDBAPI);

  const NDB_TICKS now = NdbTick_getCurrentTicks(); //OJA bug#17757895
  interface_check_timer.setDelay(1000);
  interface_check_timer.reset(now);

#ifdef ERROR_INSERT
  nodeFailCount = 0;
#endif

  cfailureNr = 1;
  ccommitFailureNr = 1;
  cprepareFailureNr = 1;
  cfailedNodes.clear();
  cprepFailedNodes.clear();
  ccommitFailedNodes.clear();
  creadyDistCom = ZFALSE;
  cpresident = ZNIL;
  c_start.m_president_candidate = ZNIL;
  c_start.m_president_candidate_gci = 0;
  cpdistref = 0;
  cneighbourh = ZNIL;
  cneighbourl = ZNIL;
  cdelayRegreq = ZDELAY_REGREQ;
  c_allow_api_connect = 0;
  ctoStatus = Q_NOT_ACTIVE;

  for (nodePtr.i = 1; nodePtr.i < MAX_NODES; nodePtr.i++)
  {
    ptrAss(nodePtr, nodeRec);
    nodePtr.p->ndynamicId = 0;
    nodePtr.p->hbOrder = 0;
    Uint32 cnt = 0;
    Uint32 type = getNodeInfo(nodePtr.i).m_type;
    switch(type){
    case NodeInfo::DB:
      jam();
      nodePtr.p->phase = ZINIT;
      c_definedNodes.set(nodePtr.i);
      break;
    case NodeInfo::API:
      jam();
      nodePtr.p->phase = ZAPI_INACTIVE;
      break;
    case NodeInfo::MGM:
      jam();
      /**
       * cmvmi allows ndb_mgmd to connect directly
       */
      nodePtr.p->phase = ZAPI_INACTIVE;
      break;
    default:
      jam();
      nodePtr.p->phase = ZAPI_INACTIVE;
    }

    set_hb_count(nodePtr.i) = cnt;
    nodePtr.p->sendPrepFailReqStatus = Q_NOT_ACTIVE;
    nodePtr.p->sendCommitFailReqStatus = Q_NOT_ACTIVE;
    nodePtr.p->sendPresToStatus = Q_NOT_ACTIVE;
    nodePtr.p->failState = NORMAL;
  }//for
}//Qmgr::initData()
void 
WatchDog::run()
{
  unsigned int sleep_time;
  NDB_TICKS last_ticks, now;
  Uint32 numThreads;
  Uint32 counterValue[MAX_WATCHED_THREADS];
  Uint32 oldCounterValue[MAX_WATCHED_THREADS];
  Uint32 threadId[MAX_WATCHED_THREADS];
  NDB_TICKS start_ticks[MAX_WATCHED_THREADS];
  Uint32 theIntervalCheck[MAX_WATCHED_THREADS];
  Uint32 elapsed[MAX_WATCHED_THREADS];

  if (!NdbTick_IsMonotonic())
  {
    g_eventLogger->warning("A monotonic timer was not available on this platform.");
    g_eventLogger->warning("Adjusting system time manually, or otherwise (e.g. NTP), "
              "may cause false watchdog alarms, temporary freeze, or node shutdown.");
  }

  last_ticks = NdbTick_getCurrentTicks();

  while (!theStop)
  {
    sleep_time= 100;

    NdbSleep_MilliSleep(sleep_time);
    if(theStop)
      break;

    now = NdbTick_getCurrentTicks();

    if (NdbTick_Compare(now, last_ticks) < 0)
    {
      g_eventLogger->warning("Watchdog: Time ticked backwards %llu ms.",
                             NdbTick_Elapsed(now, last_ticks).milliSec());
      /**
       * A backtick after sleeping 100ms, is considdered a
       * fatal error if monotonic timers are used.
       */
      assert(!NdbTick_IsMonotonic());
    }
    // Print warnings if sleeping much longer than expected
    else if (NdbTick_Elapsed(last_ticks, now).milliSec() > sleep_time*2)
    {
      struct tms my_tms;
      if (times(&my_tms) != (clock_t)-1)
      {
        g_eventLogger->info("Watchdog: User time: %llu  System time: %llu",
                          (Uint64)my_tms.tms_utime,
                          (Uint64)my_tms.tms_stime);
      }
      else
      {
        g_eventLogger->info("Watchdog: User time: %llu System time: %llu (errno=%d)",
                          (Uint64)my_tms.tms_utime,
                          (Uint64)my_tms.tms_stime,
                          errno);
      }
      g_eventLogger->warning("Watchdog: Warning overslept %llu ms, expected %u ms.",
                             NdbTick_Elapsed(last_ticks, now).milliSec(),
                             sleep_time);
    }
    last_ticks = now;

    /*
      Copy out all active counters under locked mutex, then check them
      afterwards without holding the mutex.
    */
    NdbMutex_Lock(m_mutex);
    numThreads = m_watchedCount;
    for (Uint32 i = 0; i < numThreads; i++)
    {
#ifdef NDB_HAVE_XCNG
      /* atomically read and clear watchdog counter */
      counterValue[i] = xcng(m_watchedList[i].m_watchCounter, 0);
#else
      counterValue[i] = *(m_watchedList[i].m_watchCounter);
#endif
      if (likely(counterValue[i] != 0))
      {
        /*
          The thread responded since last check, so just update state until
          next check.
         */
#ifndef NDB_HAVE_XCNG
        /*
          There is a small race here. If the thread changes the counter
          in-between the read and setting to zero here in the watchdog
          thread, then gets stuck immediately after, we may report the
          wrong action that it got stuck on.
          But there will be no reporting of non-stuck thread because of
          this race, nor will there be missed reporting.
        */
        *(m_watchedList[i].m_watchCounter) = 0;
#endif
        m_watchedList[i].m_startTicks = now;
        m_watchedList[i].m_slowWarnDelay = theInterval;
        m_watchedList[i].m_lastCounterValue = counterValue[i];
      }
      else
      {
        start_ticks[i] = m_watchedList[i].m_startTicks;
        threadId[i] = m_watchedList[i].m_threadId;
        oldCounterValue[i] = m_watchedList[i].m_lastCounterValue;
        theIntervalCheck[i] = m_watchedList[i].m_slowWarnDelay;
        elapsed[i] = (Uint32)NdbTick_Elapsed(start_ticks[i], now).milliSec();
        if (oldCounterValue[i] == 9 && elapsed[i] >= theIntervalCheck[i])
          m_watchedList[i].m_slowWarnDelay += theInterval;
      }
    }
    NdbMutex_Unlock(m_mutex);

    /*
      Now check each watched thread if it has reported progress since previous
      check. Warn about any stuck threads, and eventually force shutdown the
      server.
    */
    for (Uint32 i = 0; i < numThreads; i++)
    {
      if (counterValue[i] != 0)
        continue;

      /*
        Counter value == 9 indicates malloc going on, this can take some time
        so only warn if we pass the watchdog interval
      */
      if (oldCounterValue[i] != 9 || elapsed[i] >= theIntervalCheck[i])
      {
        const char *last_stuck_action = get_action(oldCounterValue[i]);
        if (last_stuck_action != NULL)
        {
          g_eventLogger->warning("Ndb kernel thread %u is stuck in: %s "
                                 "elapsed=%u",
                                 threadId[i], last_stuck_action, elapsed[i]);
        }
        else
        {
          g_eventLogger->warning("Ndb kernel thread %u is stuck in: Unknown place %u "
                                 "elapsed=%u",
                                 threadId[i],  oldCounterValue[i], elapsed[i]);
        }
        {
          struct tms my_tms;
          if (times(&my_tms) != (clock_t)-1)
          {
            g_eventLogger->info("Watchdog: User time: %llu  System time: %llu",
                              (Uint64)my_tms.tms_utime,
                              (Uint64)my_tms.tms_stime);
          }
          else
          {
            g_eventLogger->info("Watchdog: User time: %llu System time: %llu (errno=%d)",
                              (Uint64)my_tms.tms_utime,
                              (Uint64)my_tms.tms_stime,
                              errno);
          }
        }
        if (elapsed[i] > 3 * theInterval)
        {
          shutdownSystem(last_stuck_action);
        }
      }
    }
  }
  return;
}