Exemplo n.º 1
0
void ConnectionPool::quiesce_connections()
{
  for (int ii = 0; ii < _num_connections; ii++)
  {
    quiesce_connection(ii);
  }
}
Exemplo n.º 2
0
void ConnectionPool::recycle_connections()
{
  // The recycler periodically recycles the connections so that any new nodes
  // in the upstream proxy cluster get used reasonably soon after they are
  // active.  To avoid mucking around with variable length waits, the
  // algorithm waits for a fixed period (one second) then recycles connections
  // that are due to be recycled.

  while (!_terminated)
  {
#ifdef UNIT_TEST
    // A smaller pause here is much faster
    sleep(0.1);
#else
    sleep(1);
#endif

    int now = time(NULL);

    // Walk the vector of connections.  This is safe to do without the lock
    // because the vector is immutable.
    for (size_t ii = 0; ii < _tp_hash.size(); ++ii)
    {
      if (_tp_hash[ii].tp == NULL)
      {
        // This slot is empty, so try to populate it now.
        create_connection(ii);
      }
      else if ((_tp_hash[ii].connected) &&
               (_tp_hash[ii].recycle_time != 0) &&
               (now >= _tp_hash[ii].recycle_time))
      {
        // This slot is due to be recycled, so quiesce the existing
        // connection and create a new one.
        TRC_STATUS("Recycle TCP connection slot %d", ii);
        quiesce_connection(ii);
        create_connection(ii);
      }
    }
  }
}
Exemplo n.º 3
0
void ConnectionPool::recycle_connections()
{
  // The recycler periodically recycles the connections so that any new nodes
  // in the upstream proxy cluster get used reasonably soon after they are
  // active.  To avoid mucking around with variable length waits, the
  // algorithm waits for a fixed period (one second) then recycles a 
  // number of connections.
  //
  // Logically the algorithm runs an independent trial for each hash slot
  // with a success probability of (1/_recycle_period).  For efficiency this
  // is implemented by using a binomially distributed random number to find
  // the number of successful trials, then selecting that number of hash slots
  // at random.
  //
  // Currently the selection is done with replacement which raises the possibility
  // that one connection may be recycled twice in the same schedule, but this
  // should only introduce a small error in the recycling rate.

  std::default_random_engine rand;
  std::binomial_distribution<int> rbinomial(_num_connections, 1.0/_recycle_period);

  while (!_terminated) 
  {
    sleep(1);

    int recycle = rbinomial(rand);

    LOG_INFO("Recycling %d connections to %.*s:%d", recycle, _target.host.slen, _target.host.ptr, _target.port);

    for (int ii = 0; ii < recycle; ++ii) 
    {
      // Pick a hash slot at random, and quiesce the connection (if active).
      int hash_slot = rand() % _num_connections;
      quiesce_connection(hash_slot);

      // Create a new connection for this hash slot. 
      create_connection(hash_slot);
    }

    int index = 0;

    // Walk the hash table, attempting to fill in any gaps caused by transports failing.
    //
    // It is safe to walk the vector without the lock since:
    //
    //  * The vector never changes size
    //  * We only care about the value of the entry being NULL (atomic check)
    //  * Only we can change a NULL value to a non-NULL value
    //  * If we just miss a change from non-NULL to NULL (a transport suddenly dies), we'll catch it in a second.
    for (std::vector<tp_hash_slot>::iterator it = _tp_hash.begin();
         it != _tp_hash.end();
         ++it)
    {
      if (it->tp == NULL)
      {
        create_connection(index);
      }
      index++;
    }
  }
}