uint32_t max; //!< Maximum number of concurrent
//!< connections to allow.
uint32_t spare; //!< Number of spare connections to try
+ uint32_t pending; //!< Number of pending open connections
uint32_t retry_delay; //!< seconds to delay re-open
//!< after a failed open.
uint32_t cleanup_interval; //!< Initial timer for how
fr_connection_t *head; //!< Start of the connection list.
fr_connection_t *tail; //!< End of the connection list.
- bool spawning; //!< Whether we are currently attempting
- //!< to spawn a new connection.
-
#ifdef HAVE_PTHREAD_H
pthread_mutex_t mutex; //!< Mutex used to keep consistent state
//!< when making modifications in
* Prevent all threads from blocking if the resource
* were managing connections for appears to be unavailable.
*/
- if ((pool->num == 0) && pool->spawning) {
+ if (pool->num == 0) {
return NULL;
}
rad_assert(pool->num <= pool->max);
/*
- * Don't spawn multiple connections at the same time.
+ * Don't spawn too many connections at the same time.
*/
- if (pool->spawning) {
+ if ((pool->num + pool->pending) >= pool->max) {
pthread_mutex_unlock(&pool->mutex);
- ERROR("%s: Cannot open new connection, connection spawning already in progress", pool->log_prefix);
+ ERROR("%s: Cannot open new connection, already at max", pool->log_prefix);
return NULL;
}
return NULL;
}
- pool->spawning = true;
+ pool->pending++;
/*
* Unlock the mutex while we try to open a new
ERROR("%s: Opening connection failed (%" PRIu64 ")", pool->log_prefix, pool->count);
pool->last_failed = now;
- pool->spawning = false; /* atomic, so no lock is needed */
+ pthread_mutex_lock(&pool->mutex);
+ pool->pending--;
+ pthread_mutex_unlock(&pool->mutex);
+
return NULL;
}
this->last_used = now;
fr_connection_link_head(pool, this);
pool->num++;
- pool->spawning = false;
+
+ rad_assert(pool->pending > 0);
+ pool->pending--;
pool->last_spawned = time(NULL);
pool->delay_interval = pool->cleanup_interval;
pool->next_delay = pool->cleanup_interval;
* connections to enforce "min".
*/
if (pool->num <= pool->min) {
- if (pool->spawning) {
- spawn = 0;
+ /*
+ * We're already opening sockets, don't open too many.
+ */
+ if (pool->pending) {
+ if ((pool->num + pool->pending) >= pool->min) {
+ spawn = 0;
+ } else {
+ spawn = pool->min - (pool->num + pool->pending);
+ }
} else {
spawn = pool->min - pool->num;
}
* Only try to open spares if we're not already attempting to open
* a connection. Avoids spurious log messages.
*/
- if (spawn && !pool->spawning) {
+ if (spawn) {
INFO("%s: %i of %u connections in use. Need more spares", pool->log_prefix, pool->active, pool->num);
pthread_mutex_unlock(&pool->mutex);
fr_connection_spawn(pool, now, false); /* ignore return code */