Coverage Report

Created: 2026-11-12 06:42

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/freeradius-server/src/lib/server/pool.c
Line
Count
Source
1
/*
2
 *   This program is free software; you can redistribute it and/or modify
3
 *   it under the terms of the GNU General Public License as published by
4
 *   the Free Software Foundation; either version 2 of the License, or
5
 *   (at your option) any later version.
6
 *
7
 *   This program is distributed in the hope that it will be useful,
8
 *   but WITHOUT ANY WARRANTY; without even the implied warranty of
9
 *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
10
 *   GNU General Public License for more details.
11
 *
12
 *   You should have received a copy of the GNU General Public License
13
 *   along with this program; if not, write to the Free Software
14
 *   Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
15
 */
16
17
/**
18
 * @file pool.c
19
 * @brief Handle pools of connections (threads, sockets, etc.)
20
 * @note This API must be used by all modules in the public distribution that
21
 * maintain pools of connections.
22
 *
23
 * @copyright 2012 The FreeRADIUS server project
24
 * @copyright 2012 Alan DeKok (aland@deployingradius.com)
25
 */
26
RCSID("$Id: dc3679204298804cd2fcd222838ddfd44dc6bc20 $")
27
28
0
#define LOG_PREFIX pool->log_prefix
29
30
#include <freeradius-devel/server/main_config.h>
31
#include <freeradius-devel/server/modpriv.h>
32
#include <freeradius-devel/server/trigger.h>
33
34
#include <freeradius-devel/util/debug.h>
35
36
#include <freeradius-devel/util/misc.h>
37
38
39
typedef struct fr_pool_connection_s fr_pool_connection_t;
40
41
static int connection_check(fr_pool_t *pool, request_t *request);
42
static int max_dflt(CONF_PAIR **out, void *parent, CONF_SECTION *cs, fr_token_t quote, conf_parser_t const *rule);
43
44
/** An individual connection within the connection pool
45
 *
46
 * Defines connection counters, timestamps, and holds a pointer to the
47
 * connection handle itself.
48
 *
49
 * @see fr_pool_t
50
 */
51
struct fr_pool_connection_s {
52
  fr_pool_connection_t  *prev;      //!< Previous connection in list.
53
  fr_pool_connection_t  *next;      //!< Next connection in list.
54
  fr_heap_index_t heap_id;      //!< For the next connection heap.
55
56
  fr_time_t created;    //!< Time connection was created.
57
  fr_time_t last_reserved;    //!< Last time the connection was reserved.
58
59
  fr_time_t last_released;    //!< Time the connection was released.
60
61
  uint32_t  num_uses;   //!< Number of times the connection has been reserved.
62
  uint64_t  number;     //!< Unique ID assigned when the connection is created,
63
            //!< these will monotonically increase over the
64
            //!< lifetime of the connection pool.
65
  void    *connection;    //!< Pointer to whatever the module uses for a connection
66
            //!< handle.
67
  bool    in_use;     //!< Whether the connection is currently reserved.
68
69
  bool    needs_reconnecting; //!< Reconnect this connection before use.
70
71
#ifdef PTHREAD_DEBUG
72
  pthread_t pthread_id;   //!< When 'in_use == true'.
73
#endif
74
};
75
76
/** A connection pool
77
 *
78
 * Defines the configuration of the connection pool, all the counters and
79
 * timestamps related to the connection pool, the mutex that stops multiple
80
 * threads leaving the pool in an inconsistent state, and the callbacks
81
 * required to open, close and check the status of connections within the pool.
82
 *
83
 * @see connection
84
 */
85
struct fr_pool_s {
86
  int   ref;      //!< Reference counter to prevent connection
87
            //!< pool being freed multiple times.
88
  uint32_t  start;      //!< Number of initial connections.
89
  uint32_t  min;      //!< Minimum number of concurrent connections to keep open.
90
  uint32_t  max;      //!< Maximum number of concurrent connections to allow.
91
  uint32_t  max_pending;    //!< Max number of pending connections to allow.
92
  uint32_t  spare;      //!< Number of spare connections to try.
93
  uint64_t  max_uses;   //!< Maximum number of times a connection can be used
94
            //!< before being closed.
95
  uint32_t  pending_window;   //!< Sliding window of pending connections.
96
97
  fr_time_delta_t retry_delay;    //!< seconds to delay re-open after a failed open.
98
  fr_time_delta_t cleanup_interval;   //!< Initial timer for how often we sweep the pool
99
            //!< for free connections. (0 is infinite).
100
  fr_time_delta_t delay_interval;   //!< When we next do a cleanup.  Initialized to
101
            //!< cleanup_interval, and increase from there based
102
            //!< on the delay.
103
  fr_time_delta_t lifetime;   //!< How long a connection can be open before being
104
            //!< closed (irrespective of whether it's idle or not).
105
  fr_time_delta_t idle_timeout;   //!< How long a connection can be idle before
106
            //!< being closed.
107
  fr_time_delta_t connect_timeout;  //!< New connection timeout, enforced by the create
108
            //!< callback.
109
110
  bool    spread;     //!< If true we spread requests over the connections,
111
            //!< using the connection released longest ago, first.
112
113
  fr_heap_t *heap;      //!< For the next connection heap
114
115
  fr_pool_connection_t  *head;    //!< Start of the connection list.
116
  fr_pool_connection_t  *tail;    //!< End of the connection list.
117
118
  pthread_mutex_t mutex;      //!< Mutex used to keep consistent state when making
119
            //!< modifications in threaded mode.
120
  pthread_cond_t  done_spawn;   //!< Threads that need to ensure no spawning is in progress,
121
            //!< should block on this condition if pending != 0.
122
  pthread_cond_t  done_reconnecting;  //!< Before calling the create callback, threads should
123
            //!< block on this condition if reconnecting == true.
124
125
  CONF_SECTION const *cs;     //!< Configuration section holding the section of parsed
126
            //!< config file that relates to this pool.
127
  void    *opaque;    //!< Pointer to context data that will be passed to callbacks.
128
129
  char const  *log_prefix;    //!< Log prefix to prepend to all log messages created
130
            //!< by the connection pool code.
131
132
  bool    triggers_enabled; //!< Whether we call the trigger functions.
133
134
  char const  *trigger_prefix;  //!< Prefix to prepend to names of all triggers
135
            //!< fired by the connection pool code.
136
  fr_pair_list_t  trigger_args;   //!< Arguments to make available in connection pool triggers.
137
138
  fr_time_delta_t held_trigger_min; //!< If a connection is held for less than the specified
139
            //!< period, fire a trigger.
140
  fr_time_delta_t held_trigger_max; //!< If a connection is held for longer than the specified
141
            //!< period, fire a trigger.
142
143
  fr_pool_connection_create_t create; //!< Function used to create new connections.
144
  fr_pool_connection_alive_t  alive;  //!< Function used to check status of connections.
145
146
  fr_pool_reconnect_t reconnect;  //!< Called during connection pool reconnect.
147
148
  fr_pool_state_t state;      //!< Stats and state of the connection pool.
149
};
150
151
static const conf_parser_t pool_config[] = {
152
  { FR_CONF_OFFSET("start", fr_pool_t, start), .dflt = "0" },
153
  { FR_CONF_OFFSET("min", fr_pool_t, min), .dflt = "0" },
154
  { FR_CONF_OFFSET("max", fr_pool_t, max), .dflt_func = max_dflt },
155
  { FR_CONF_OFFSET("max_pending", fr_pool_t, max_pending), .dflt = "0" },
156
  { FR_CONF_OFFSET("spare", fr_pool_t, spare), .dflt = "3" },
157
  { FR_CONF_OFFSET("uses", fr_pool_t, max_uses), .dflt = "0" },
158
  { FR_CONF_OFFSET("lifetime", fr_pool_t, lifetime), .dflt = "0" },
159
  { FR_CONF_OFFSET("cleanup_interval", fr_pool_t, cleanup_interval), .dflt = "30" },
160
  { FR_CONF_OFFSET("idle_timeout", fr_pool_t, idle_timeout), .dflt = "60" },
161
  { FR_CONF_OFFSET("connect_timeout", fr_pool_t, connect_timeout), .dflt = "3.0" },
162
  { FR_CONF_OFFSET("held_trigger_min", fr_pool_t, held_trigger_min), .dflt = "0.0" },
163
  { FR_CONF_OFFSET("held_trigger_max", fr_pool_t, held_trigger_max), .dflt = "0.5" },
164
  { FR_CONF_OFFSET("retry_delay", fr_pool_t, retry_delay), .dflt = "1" },
165
  { FR_CONF_OFFSET("spread", fr_pool_t, spread), .dflt = "no" },
166
  CONF_PARSER_TERMINATOR
167
};
168
169
static int max_dflt(CONF_PAIR **out, UNUSED void *parent, CONF_SECTION *cs, fr_token_t quote, conf_parser_t const *rule)
170
0
{
171
0
  char    *strvalue;
172
173
0
  strvalue = talloc_asprintf(NULL, "%u", main_config->max_workers);
174
0
  *out = cf_pair_alloc(cs, rule->name1, strvalue, T_OP_EQ, T_BARE_WORD, quote);
175
0
  talloc_free(strvalue);
176
177
0
  return 0;
178
0
}
179
180
/** Order connections by reserved most recently
181
 */
182
static fr_cmp_ret_t last_reserved_cmp(void const *one, void const *two)
183
0
{
184
0
  fr_pool_connection_t const *a = one, *b = two;
185
186
0
  return fr_time_cmp(a->last_reserved, b->last_reserved);
187
0
}
188
189
/** Order connections by released longest ago
190
 */
191
static fr_cmp_ret_t last_released_cmp(void const *one, void const *two)
192
0
{
193
0
  fr_pool_connection_t const *a = one, *b = two;
194
195
0
  return fr_time_cmp(a->last_released, b->last_released);
196
0
}
197
198
/** Removes a connection from the connection list
199
 *
200
 * @note Must be called with the mutex held.
201
 *
202
 * @param[in] pool  to modify.
203
 * @param[in] this  Connection to delete.
204
 */
205
static void connection_unlink(fr_pool_t *pool, fr_pool_connection_t *this)
206
0
{
207
0
  if (this->prev) {
208
0
    fr_assert(pool->head != this);
209
0
    this->prev->next = this->next;
210
0
  } else {
211
0
    fr_assert(pool->head == this);
212
0
    pool->head = this->next;
213
0
  }
214
0
  if (this->next) {
215
0
    fr_assert(pool->tail != this);
216
0
    this->next->prev = this->prev;
217
0
  } else {
218
0
    fr_assert(pool->tail == this);
219
0
    pool->tail = this->prev;
220
0
  }
221
222
0
  this->prev = this->next = NULL;
223
0
}
224
225
/** Adds a connection to the head of the connection list
226
 *
227
 * @note Must be called with the mutex held.
228
 *
229
 * @param[in] pool  to modify.
230
 * @param[in] this  Connection to add.
231
 */
232
static void connection_link_head(fr_pool_t *pool, fr_pool_connection_t *this)
233
0
{
234
0
  fr_assert(pool != NULL);
235
0
  fr_assert(this != NULL);
236
0
  fr_assert(pool->head != this);
237
0
  fr_assert(pool->tail != this);
238
239
0
  if (pool->head) {
240
0
    pool->head->prev = this;
241
0
  }
242
243
0
  this->next = pool->head;
244
0
  this->prev = NULL;
245
0
  pool->head = this;
246
0
  if (!pool->tail) {
247
0
    fr_assert(this->next == NULL);
248
0
    pool->tail = this;
249
0
  } else {
250
0
    fr_assert(this->next != NULL);
251
0
  }
252
0
}
253
254
/** Send a connection pool trigger.
255
 *
256
 * @param[in] pool  to send trigger for.
257
 * @param[in] event trigger name suffix.
258
 */
259
static inline void fr_pool_trigger(fr_pool_t *pool, char const *event)
260
0
{
261
0
  char  name[128];
262
263
0
  fr_assert(pool != NULL);
264
0
  fr_assert(event != NULL);
265
266
0
  if (!pool->triggers_enabled) return;
267
268
0
  snprintf(name, sizeof(name), "%s.%s", pool->trigger_prefix, event);
269
0
  trigger(unlang_interpret_get_thread_default(), pool->cs, NULL, name, true, &pool->trigger_args, pool);
270
0
}
271
272
/** Find a connection handle in the connection list
273
 *
274
 * Walks over the list of connections searching for a specified connection
275
 * handle and returns the first connection that contains that pointer.
276
 *
277
 * @note Must be called with the mutex held.
278
 *
279
 * @param[in] pool  to search in.
280
 * @param[in] conn  handle to search for.
281
 * @return
282
 *  - Connection containing the specified handle.
283
 *  - NULL if no such connection was found.
284
 */
285
static fr_pool_connection_t *connection_find(fr_pool_t *pool, void *conn)
286
0
{
287
0
  fr_pool_connection_t *this;
288
289
  /*
290
   *  FIXME: This loop could be avoided if we passed a 'void
291
   *  **connection' instead.  We could use "offsetof" in
292
   *  order to find top of the parent structure.
293
   */
294
0
  for (this = pool->head; this != NULL; this = this->next) {
295
0
    if (this->connection == conn) {
296
#ifdef PTHREAD_DEBUG
297
      pthread_t pthread_id;
298
299
      pthread_id = pthread_self();
300
      fr_assert(pthread_equal(this->pthread_id, pthread_id) != 0);
301
#endif
302
303
0
      fr_assert(this->in_use == true);
304
0
      return this;
305
0
    }
306
0
  }
307
308
0
  return NULL;
309
0
}
310
311
/** Spawns a new connection
312
 *
313
 * Spawns a new connection using the create callback, and returns it for
314
 * adding to the connection list.
315
 *
316
 * @note Will call the 'open' trigger.
317
 * @note Must be called with the mutex held.  Returns with the mutex held.
318
 *   The mutex is released while the create callback runs.
319
 *
320
 * @param[in] pool  to modify.
321
 * @param[in] request The current request.
322
 * @param[in] now Current time.
323
 * @param[in] in_use  whether the new connection should be "in_use" or not
324
 * @return
325
 *  - New connection struct.
326
 *  - NULL on error.
327
 */
328
static fr_pool_connection_t *connection_spawn(fr_pool_t *pool, request_t *request, fr_time_t now, bool in_use)
329
0
{
330
0
  uint64_t    number;
331
0
  uint32_t    pending_window;
332
0
  TALLOC_CTX    *ctx;
333
334
0
  fr_pool_connection_t  *this;
335
0
  void      *conn;
336
337
0
  fr_assert(pool != NULL);
338
0
  fr_assert(pool->state.num <= pool->max);
339
340
  /*
341
   *  If we have NO connections, and we've previously failed
342
   *  opening connections, don't open multiple connections until
343
   *  we successfully open at least one.
344
   */
345
0
  if ((pool->state.num == 0) &&
346
0
      pool->state.pending &&
347
0
      fr_time_gt(pool->state.last_failed, fr_time_wrap(0))) {
348
0
    return NULL;
349
0
  }
350
351
  /*
352
   *  Don't spawn too many connections at the same time.
353
   */
354
0
  if ((pool->state.num + pool->state.pending) >= pool->max) {
355
0
    ERROR("Cannot open new connection, already at max");
356
0
    return NULL;
357
0
  }
358
359
  /*
360
   *  If the last attempt failed, wait a bit before
361
   *  retrying.
362
   */
363
0
  if (fr_time_gt(pool->state.last_failed, fr_time_wrap(0)) &&
364
0
      fr_time_gt(fr_time_add(pool->state.last_failed, pool->retry_delay), now)) {
365
0
    bool complain = false;
366
0
    fr_time_delta_t retry_in = fr_time_sub(fr_time_add(pool->state.last_failed, pool->retry_delay), now);
367
368
0
    if (fr_time_delta_gteq(fr_time_sub(now, pool->state.last_throttled), fr_time_delta_from_sec(1))) {
369
0
      complain = true;
370
371
0
      pool->state.last_throttled = now;
372
0
    }
373
374
0
    if (!fr_rate_limit_enabled() || complain) {
375
0
      ERROR("Last connection attempt failed, waiting %pV seconds before retrying",
376
0
            fr_box_time_delta(retry_in));
377
0
    }
378
379
0
    return NULL;
380
0
  }
381
382
  /*
383
   *  We limit the rate of new connections after a failed attempt.
384
   */
385
0
  if (pool->state.pending > pool->pending_window) {
386
0
    RATE_LIMIT_GLOBAL_ROPTIONAL(RWARN, WARN,
387
0
              "Cannot open a new connection due to rate limit after failure");
388
389
0
    return NULL;
390
0
  }
391
392
0
  pool->state.pending++;
393
0
  number = pool->state.count++;
394
395
  /*
396
   *  Don't starve out the thread trying to reconnect
397
   *  the pool, by continuously opening new connections.
398
   */
399
0
  while (pool->state.reconnecting) pthread_cond_wait(&pool->done_reconnecting, &pool->mutex);
400
401
  /*
402
   *  The true value for pending_window is the smaller of
403
   *  free connection slots, or pool->pending_window.
404
   */
405
0
  pending_window = (pool->max - pool->state.num);
406
0
  if (pool->pending_window < pending_window) pending_window = pool->pending_window;
407
0
  ROPTIONAL(RDEBUG2, DEBUG2, "Opening additional connection (%" PRIu64 "), %u of %u pending slots used",
408
0
      number, pool->state.pending, pending_window);
409
410
  /*
411
   *  Unlock the mutex while we try to open a new
412
   *  connection.  If there are issues with the back-end,
413
   *  opening a new connection may take a LONG time.  In
414
   *  that case, we want the other connections to continue
415
   *  to be used.
416
   */
417
0
  pthread_mutex_unlock(&pool->mutex);
418
419
  /*
420
   *  Allocate a new top level ctx for the create callback
421
   *  to hang its memory off of.
422
   */
423
0
  MEM(ctx = talloc_init("connection_ctx"));
424
425
  /*
426
   *  This may take a long time, which prevents other
427
   *  threads from releasing connections.  We don't care
428
   *  about other threads opening new connections, as we
429
   *  already have no free connections.
430
   */
431
0
  conn = pool->create(ctx, pool->opaque, pool->connect_timeout);
432
0
  if (!conn) {
433
0
    ERROR("Opening connection failed (%" PRIu64 ")", number);
434
435
0
    pthread_mutex_lock(&pool->mutex);
436
0
    pool->state.last_failed = now;
437
0
    pool->pending_window = 1;
438
0
    pool->state.pending--;
439
440
    /*
441
     *  Must be done inside the mutex, reconnect callback
442
     *  may modify args.
443
     */
444
0
    fr_pool_trigger(pool, "fail");
445
0
    pthread_cond_broadcast(&pool->done_spawn);
446
447
0
    talloc_free(ctx);
448
449
0
    return NULL;
450
0
  }
451
452
  /*
453
   *  And lock the mutex again while we link the new
454
   *  connection back into the pool.
455
   */
456
0
  pthread_mutex_lock(&pool->mutex);
457
458
0
  this = talloc_zero(pool, fr_pool_connection_t);
459
0
  if (!this) {
460
0
    pool->state.last_failed = now;
461
0
    pool->state.pending--;
462
463
0
    pthread_cond_broadcast(&pool->done_spawn);
464
465
0
    ERROR("Memory allocation failed for new connection (%" PRIu64 ")", number);
466
467
0
    talloc_free(ctx);
468
469
0
    return NULL;
470
0
  }
471
0
  MEM(talloc_link_ctx(this, ctx) >= 0);
472
473
0
  this->created = now;
474
0
  this->connection = conn;
475
0
  this->in_use = in_use;
476
477
0
  this->number = number;
478
0
  this->last_reserved = fr_time();
479
0
  this->last_released = this->last_reserved;
480
481
  /*
482
   *  The connection pool is starting up.  Insert the
483
   *  connection into the heap.
484
   */
485
0
  if (!in_use) fr_heap_insert(&pool->heap, this);
486
487
0
  connection_link_head(pool, this);
488
489
  /*
490
   *  Do NOT insert the connection into the heap.  That's
491
   *  done when the connection is released.
492
   */
493
494
0
  pool->state.num++;
495
496
0
  fr_assert(pool->state.pending > 0);
497
0
  pool->state.pending--;
498
499
  /*
500
   *  We've successfully opened one more connection.  Allow
501
   *  more connections to open in parallel.
502
   */
503
0
  if ((pool->pending_window < pool->max) &&
504
0
      ((pool->max_pending == 0) || (pool->pending_window < pool->max_pending))) {
505
0
    pool->pending_window++;
506
0
  }
507
508
0
  pool->state.last_spawned = fr_time();
509
0
  pool->delay_interval = pool->cleanup_interval;
510
0
  pool->state.next_delay = pool->cleanup_interval;
511
0
  pool->state.last_failed = fr_time_wrap(0);
512
513
  /*
514
   *  Must be done inside the mutex, reconnect callback
515
   *  may modify args.
516
   */
517
0
  fr_pool_trigger(pool, "open");
518
519
0
  pthread_cond_broadcast(&pool->done_spawn);
520
521
0
  return this;
522
0
}
523
524
/** Close an existing connection.
525
 *
526
 * Removes the connection from the list, calls the delete callback to close
527
 * the connection, then frees memory allocated to the connection.
528
 *
529
 * @note Will call the 'close' trigger.
530
 * @note Must be called with the mutex held.
531
 *
532
 * @param[in] pool  to modify.
533
 * @param[in] this  Connection to delete.
534
 */
535
static void connection_close_internal(fr_pool_t *pool, fr_pool_connection_t *this)
536
0
{
537
  /*
538
   *  If it's in use, release it.
539
   */
540
0
  if (this->in_use) {
541
#ifdef PTHREAD_DEBUG
542
    pthread_t pthread_id = pthread_self();
543
    fr_assert(pthread_equal(this->pthread_id, pthread_id) != 0);
544
#endif
545
546
0
    this->in_use = false;
547
548
0
    fr_assert(pool->state.active != 0);
549
0
    pool->state.active--;
550
551
0
  } else {
552
    /*
553
     *  Connection isn't used, remove it from the heap.
554
     */
555
0
    fr_heap_extract(&pool->heap, this);
556
0
  }
557
558
0
  fr_pool_trigger(pool, "close");
559
560
0
  connection_unlink(pool, this);
561
562
0
  fr_assert(pool->state.num > 0);
563
0
  pool->state.num--;
564
0
  talloc_free(this);
565
0
}
566
567
/** Check whether a connection needs to be removed from the pool
568
 *
569
 * Will verify that the connection is within idle_timeout, max_uses, and
570
 * lifetime values. If it is not, the connection will be closed.
571
 *
572
 * @note Will only close connections not in use.
573
 * @note Must be called with the mutex held.
574
 *
575
 * @param[in] pool  to modify.
576
 * @param[in] request The current request.
577
 * @param[in] this  Connection to manage.
578
 * @param[in] now Current time.
579
 * @return
580
 *  - 0 if connection was closed.
581
 *  - 1 if connection handle was left open.
582
 */
583
static int connection_manage(fr_pool_t *pool, request_t *request, fr_pool_connection_t *this, fr_time_t now)
584
0
{
585
0
  fr_assert(pool != NULL);
586
0
  fr_assert(this != NULL);
587
588
  /*
589
   *  Don't terminated in-use connections
590
   */
591
0
  if (this->in_use) return 1;
592
593
0
  if (this->needs_reconnecting) {
594
0
    ROPTIONAL(RDEBUG2, DEBUG2, "Closing expired connection (%" PRIu64 "): Needs reconnecting",
595
0
        this->number);
596
0
  do_delete:
597
0
    if (pool->state.num <= pool->min) {
598
0
      ROPTIONAL(RDEBUG2, DEBUG2, "You probably need to lower \"min\"");
599
0
    }
600
0
    connection_close_internal(pool, this);
601
0
    return 0;
602
0
  }
603
604
0
  if ((pool->max_uses > 0) &&
605
0
      (this->num_uses >= pool->max_uses)) {
606
0
    ROPTIONAL(RDEBUG2, DEBUG2, "Closing expired connection (%" PRIu64 "): Hit max_uses limit",
607
0
        this->number);
608
0
    goto do_delete;
609
0
  }
610
611
0
  if (fr_time_delta_ispos(pool->lifetime) &&
612
0
      (fr_time_lt(fr_time_add(this->created, pool->lifetime), now))) {
613
0
    ROPTIONAL(RDEBUG2, DEBUG2, "Closing expired connection (%" PRIu64 "): Hit lifetime limit",
614
0
        this->number);
615
0
    goto do_delete;
616
0
  }
617
618
0
  if (fr_time_delta_ispos(pool->idle_timeout) &&
619
0
      (fr_time_lt(fr_time_add(this->last_released, pool->idle_timeout), now))) {
620
0
    ROPTIONAL(RINFO, INFO, "Closing connection (%" PRIu64 "): Hit idle_timeout, was idle for %pVs",
621
0
            this->number, fr_box_time_delta(fr_time_sub(now, this->last_released)));
622
0
    goto do_delete;
623
0
  }
624
625
0
  return 1;
626
0
}
627
628
629
/** Check whether any connections need to be removed from the pool
630
 *
631
 * Maintains the number of connections in the pool as per the configuration
632
 * parameters for the connection pool.
633
 *
634
 * @note Will only run checks the first time it's called in a given second,
635
 * to throttle connection spawning/closing.
636
 * @note Will only close connections not in use.
637
 * @note Must be called with the mutex held.  Returns with the mutex held.
638
 *
639
 * @param[in] pool  to manage.
640
 * @param[in] request The current request.
641
 * @return 1
642
 */
643
static int connection_check(fr_pool_t *pool, request_t *request)
644
0
{
645
0
  uint32_t    num, spare;
646
0
  fr_time_t   now = fr_time();
647
0
  fr_pool_connection_t  *this, *next;
648
649
0
  if (fr_time_delta_lt(fr_time_sub(now, pool->state.last_checked), fr_time_delta_from_sec(1))) return 1;
650
651
  /*
652
   *  Get "real" number of connections, and count pending
653
   *  connections as spare.
654
   */
655
0
  num = pool->state.num + pool->state.pending;
656
0
  spare = pool->state.pending + (pool->state.num - pool->state.active);
657
658
  /*
659
   *  The other end can close connections.  If so, we'll
660
   *  have fewer than "min".  When that happens, open more
661
   *  connections to enforce "min".
662
   *
663
   *  The code for spawning connections enforces that
664
   *  num + pending <= max.
665
   */
666
0
  if (num < pool->min) {
667
0
    ROPTIONAL(RINFO, INFO, "Need %" PRIu32 " more connections to reach min connections (%" PRIu32 ")", pool->min - num, pool->min);
668
0
    goto add_connection;
669
0
  }
670
671
  /*
672
   *  On the odd chance that we've opened too many
673
   *  connections, take care of that.
674
   */
675
0
  if (num > pool->max) {
676
    /*
677
     *  Pending connections don't get closed as "spare".
678
     */
679
0
    if (pool->state.pending > 0) goto manage_connections;
680
681
    /*
682
     *  Otherwise close one of the connections to
683
     *  bring us down to "max".
684
     */
685
0
    goto close_connection;
686
0
  }
687
688
  /*
689
   *  Now that we've enforced min/max connections, try to
690
   *  keep the "spare" connections at the correct number.
691
   */
692
693
  /*
694
   *  Nothing to do?  Go check all of the connections for
695
   *  timeouts, etc.
696
   */
697
0
  if (spare == pool->spare) goto manage_connections;
698
699
  /*
700
   *  Too many spare connections, delete some.
701
   */
702
0
  if (spare > pool->spare) {
703
0
    fr_pool_connection_t *found;
704
705
    /*
706
     *  Pending connections don't get closed as "spare".
707
     */
708
0
    if (pool->state.pending > 0) goto manage_connections;
709
710
    /*
711
     *  Don't close too many connections, even they
712
     *  are spare.
713
     */
714
0
    if (num <= pool->min) goto manage_connections;
715
716
    /*
717
     *  Too many spares, go close one.
718
     */
719
720
0
  close_connection:
721
    /*
722
     *  Don't close connections too often, in order to
723
     *  prevent flapping.
724
     */
725
0
    if (fr_time_lt(now, fr_time_add(pool->state.last_spawned, pool->delay_interval))) goto manage_connections;
726
727
    /*
728
     *  Find a connection to close.
729
     */
730
0
    found = NULL;
731
0
    for (this = pool->tail; this != NULL; this = this->prev) {
732
0
      if (this->in_use) continue;
733
734
0
      if (!found || (fr_time_lt(this->last_reserved, found->last_reserved))) found = this;
735
0
    }
736
737
0
    if (!fr_cond_assert(found)) goto done;
738
739
0
    ROPTIONAL(RDEBUG2, DEBUG2, "Closing connection (%" PRIu64 ") as we have too many unused connections",
740
0
        found->number);
741
0
    connection_close_internal(pool, found);
742
743
    /*
744
     *  Decrease the delay for the next time we clean
745
     *  up.
746
     */
747
0
    pool->state.next_delay = fr_time_delta_wrap(fr_time_delta_unwrap(pool->state.next_delay) >> 1);
748
0
    if (!fr_time_delta_ispos(pool->state.next_delay)) pool->state.next_delay = fr_time_delta_wrap(1);
749
0
    pool->delay_interval = fr_time_delta_add(pool->delay_interval, pool->state.next_delay);
750
751
0
    goto manage_connections;
752
0
  }
753
754
  /*
755
   *  Too few connections, open some more.
756
   */
757
0
  if (spare < pool->spare) {
758
    /*
759
     *  Don't open too many pending connections.
760
     */
761
0
    if (pool->state.pending >= pool->pending_window) goto manage_connections;
762
763
    /*
764
     *  Don't open too many connections, even if we
765
     *  need more spares.
766
     */
767
0
    if (num >= pool->max) goto manage_connections;
768
769
    /*
770
     *  Too few spares, go add one.
771
     */
772
0
    ROPTIONAL(RINFO, INFO, "Need %" PRIu32 " more connections to reach %" PRIu32 " spares", pool->spare - spare, pool->spare);
773
774
0
  add_connection:
775
    /*
776
     *  Only try to open spares if we're not already attempting to open
777
     *  a connection. Avoids spurious log messages.
778
     */
779
0
    (void) connection_spawn(pool, request, now, false);
780
0
    goto manage_connections;
781
0
  }
782
783
  /*
784
   *  Pass over all of the connections in the pool, limiting
785
   *  lifetime, idle time, max requests, etc.
786
   */
787
0
manage_connections:
788
0
  for (this = pool->head; this != NULL; this = next) {
789
0
    next = this->next;
790
0
    connection_manage(pool, request, this, now);
791
0
  }
792
793
0
  pool->state.last_checked = now;
794
795
0
done:
796
0
  return 1;
797
0
}
798
799
/** Get a connection from the connection pool
800
 *
801
 * @note Must be called with the mutex free.
802
 *
803
 * @param[in] pool  to reserve the connection from.
804
 * @param[in] request The current request.
805
 * @param[in] spawn whether to spawn a new connection
806
 * @return
807
 *  - A pointer to the connection handle.
808
 *  - NULL on error.
809
 */
810
static void *connection_get_internal(fr_pool_t *pool, request_t *request, bool spawn)
811
0
{
812
0
  fr_time_t now;
813
0
  fr_pool_connection_t *this;
814
815
0
  if (!pool) return NULL;
816
817
0
  pthread_mutex_lock(&pool->mutex);
818
819
0
  now = fr_time();
820
821
  /*
822
   *  Grab the link with the lowest latency, and check it
823
   *  for limits.  If "connection manage" says the link is
824
   *  no longer usable, go grab another one.
825
   */
826
0
  do {
827
0
    this = fr_heap_peek(pool->heap);
828
0
    if (!this) break;
829
0
  } while (!connection_manage(pool, request, this, now));
830
831
  /*
832
   *  We have a working connection.  Extract it from the
833
   *  heap and use it.
834
   */
835
0
  if (this) {
836
0
    fr_heap_extract(&pool->heap, this);
837
0
    goto do_return;
838
0
  }
839
840
0
  if (pool->state.num == pool->max) {
841
0
    bool complain = false;
842
843
    /*
844
     *  Rate-limit complaints.
845
     */
846
0
    if (fr_time_delta_gt(fr_time_sub(now, pool->state.last_at_max), fr_time_delta_from_sec(1))) {
847
0
      complain = true;
848
0
      pool->state.last_at_max = now;
849
0
    }
850
851
0
    if (!fr_rate_limit_enabled() || complain) {
852
0
      ERROR("No connections available and at max connection limit");
853
854
      /*
855
       *  Must be done inside the mutex, reconnect callback
856
       *  may modify args.
857
       */
858
0
      fr_pool_trigger(pool, "none");
859
0
    }
860
0
    pthread_mutex_unlock(&pool->mutex);
861
862
0
    return NULL;
863
0
  }
864
865
0
  if (!spawn) {
866
0
    pthread_mutex_unlock(&pool->mutex);
867
0
    return NULL;
868
0
  }
869
870
0
  ROPTIONAL(RDEBUG2, DEBUG2, "%" PRIu32 " of %u connections in use.  You may need to increase \"spare\"",
871
0
         pool->state.active, pool->state.num);
872
873
0
  this = connection_spawn(pool, request, now, true);
874
0
  if (!this) {
875
0
    pthread_mutex_unlock(&pool->mutex);
876
0
    return NULL;
877
0
  }
878
879
0
do_return:
880
0
  pool->state.active++;
881
0
  this->num_uses++;
882
0
  this->last_reserved = fr_time();
883
0
  this->in_use = true;
884
885
#ifdef PTHREAD_DEBUG
886
  this->pthread_id = pthread_self();
887
#endif
888
0
  pthread_mutex_unlock(&pool->mutex);
889
890
0
  ROPTIONAL(RDEBUG2, DEBUG2, "Reserved connection (%" PRIu64 ")", this->number);
891
892
0
  return this->connection;
893
0
}
894
895
/** Enable triggers for a connection pool
896
 *
897
 * @param[in] pool    to enable triggers for.
898
 * @param[in] trigger_prefix  prefix to prepend to all trigger names.  Usually a path
899
 *        to the module's trigger configuration e.g.
900
 *            @verbatim modules.<name>.pool @endverbatim
901
 *        @verbatim <trigger name> @endverbatim is appended to form
902
 *        the complete path.
903
 * @param[in] trigger_args  to make available in any triggers executed by the connection pool.
904
 *        These will usually be fr_pair_t (s) describing the host
905
 *        associated with the pool.
906
 *        Trigger args will be copied, input trigger_args should be freed
907
 *        if necessary.
908
 */
909
void fr_pool_enable_triggers(fr_pool_t *pool, char const *trigger_prefix, fr_pair_list_t *trigger_args)
910
{
911
  pool->triggers_enabled = true;
912
913
  talloc_const_free(pool->trigger_prefix);
914
  MEM(pool->trigger_prefix = trigger_prefix ? talloc_strdup(pool, trigger_prefix) : "");
915
916
  fr_pair_list_free(&pool->trigger_args);
917
918
  if (!trigger_args) return;
919
920
  MEM(fr_pair_list_copy(pool, &pool->trigger_args, trigger_args) >= 0);
921
}
922
923
/** Create a new connection pool
924
 *
925
 * Allocates structures used by the connection pool, initialises the various
926
 * configuration options and counters, and sets the callback functions.
927
 *
928
 * Will also spawn the number of connections specified by the 'start' configuration
929
 * option.
930
 *
931
 * @note Will call the 'start' trigger.
932
 *
933
 * @param[in] ctx   Context to link pool's destruction to.
934
 * @param[in] cs    pool section.
935
 * @param[in] opaque data pointer to pass to callbacks.
936
 * @param[in] c     Callback to create new connections.
937
 * @param[in] a     Callback to check the status of connections.
938
 * @param[in] log_prefix  prefix to prepend to all log messages.
939
 * @return
940
 *  - New connection pool.
941
 *  - NULL on error.
942
 */
943
fr_pool_t *fr_pool_init(TALLOC_CTX *ctx,
944
      CONF_SECTION const *cs,
945
      void *opaque,
946
      fr_pool_connection_create_t c, fr_pool_connection_alive_t a,
947
      char const *log_prefix)
948
0
{
949
0
  fr_pool_t   *pool = NULL;
950
951
0
  if (!cs || !opaque || !c) return NULL;
952
953
  /*
954
   *  Pool is allocated in the NULL context as
955
   *  threads are likely to allocate memory
956
   *  beneath the pool.
957
   */
958
0
  MEM(pool = talloc_zero(NULL, fr_pool_t));
959
0
  fr_pair_list_init(&pool->trigger_args);
960
961
  /*
962
   *  Ensure the pool is freed at the same time
963
   *  as its parent.
964
   */
965
0
  if (ctx && (talloc_link_ctx(ctx, pool) < 0)) {
966
0
    PERROR("%s: Failed linking pool ctx", __FUNCTION__);
967
0
    talloc_free(pool);
968
969
0
    return NULL;
970
0
  }
971
972
0
  pool->cs = cs;
973
0
  pool->opaque = opaque;
974
0
  pool->create = c;
975
0
  pool->alive = a;
976
977
0
  pool->head = pool->tail = NULL;
978
979
  /*
980
   *  We keep a heap of connections, sorted by the last time
981
   *  we STARTED using them.  Newly opened connections
982
   *  aren't in the heap.  They're only inserted in the list
983
   *  once they're released.
984
   *
985
   *  We do "most recently started" instead of "most
986
   *  recently used", because MRU is done as most recently
987
   *  *released*.  We want to order connections by
988
   *  responsiveness, and MRU prioritizes high latency
989
   *  connections.
990
   *
991
   *  We want most recently *started*, which gives
992
   *  preference to low latency links, and pushes high
993
   *  latency links down in the priority heap.
994
   *
995
   *  https://code.facebook.com/posts/1499322996995183/solving-the-mystery-of-link-imbalance-a-metastable-failure-state-at-scale/
996
   */
997
0
  if (!pool->spread) {
998
0
    pool->heap = fr_heap_talloc_alloc(pool, last_reserved_cmp, fr_pool_connection_t, heap_id, 0);
999
  /*
1000
   *  For some types of connections we need to used a different
1001
   *  algorithm, because load balancing benefits are secondary
1002
   *  to maintaining a cache of open connections.
1003
   *
1004
   *  With libcurl's multihandle, connections can only be reused
1005
   *  if all handles that make up the multihandle are done processing
1006
   *  their requests.
1007
   *
1008
   *  We can't tell when that's happened using libcurl, and even
1009
   *  if we could, blocking until all servers had responded
1010
   *  would have huge cost.
1011
   *
1012
   *  The solution is to order the heap so that the connection that
1013
   *  was released longest ago is at the top.
1014
   *
1015
   *  That way we maximise time between connection use.
1016
   */
1017
0
  } else {
1018
0
    pool->heap = fr_heap_talloc_alloc(pool, last_released_cmp, fr_pool_connection_t, heap_id, 0);
1019
0
  }
1020
0
  if (!pool->heap) {
1021
0
    ERROR("%s: Failed creating connection heap", __FUNCTION__);
1022
0
  error:
1023
0
    fr_pool_free(pool);
1024
0
    return NULL;
1025
0
  }
1026
1027
0
  pool->log_prefix = log_prefix ? talloc_strdup(pool, log_prefix) : "core";
1028
0
  pthread_mutex_init(&pool->mutex, NULL);
1029
0
  pthread_cond_init(&pool->done_spawn, NULL);
1030
0
  pthread_cond_init(&pool->done_reconnecting, NULL);
1031
1032
0
  DEBUG2("Initialising connection pool");
1033
1034
0
  if (cf_section_rules_push(UNCONST(CONF_SECTION *, cs), pool_config) < 0) goto error;
1035
0
  if (cf_section_parse(pool, pool, UNCONST(CONF_SECTION *, cs)) < 0) {
1036
0
    PERROR("Configuration parsing failed");
1037
0
    goto error;
1038
0
  }
1039
1040
  /*
1041
   *  Some simple limits
1042
   */
1043
0
  if (pool->max == 0) {
1044
0
    cf_log_err(cs, "Cannot set 'max' to zero");
1045
0
    goto error;
1046
0
  }
1047
1048
0
  pool->pending_window = (pool->max_pending > 0) ? pool->max_pending : pool->max;
1049
1050
0
  if (pool->min > pool->max) {
1051
0
    cf_log_err(cs, "Cannot set 'min' to more than 'max'");
1052
0
    goto error;
1053
0
  }
1054
1055
0
  FR_INTEGER_BOUND_CHECK("max", pool->max, <=, 1024);
1056
0
  FR_INTEGER_BOUND_CHECK("start", pool->start, <=, pool->max);
1057
0
  FR_INTEGER_BOUND_CHECK("spare", pool->spare, <=, (pool->max - pool->min));
1058
1059
0
  if (fr_time_delta_ispos(pool->lifetime)) {
1060
0
    FR_TIME_DELTA_COND_CHECK("idle_timeout", pool->idle_timeout,
1061
0
           fr_time_delta_lteq(pool->idle_timeout, pool->lifetime), fr_time_delta_wrap(0));
1062
0
  }
1063
1064
0
  if (fr_time_delta_ispos(pool->idle_timeout)) {
1065
0
    FR_TIME_DELTA_BOUND_CHECK("cleanup_interval", pool->cleanup_interval, <=, pool->idle_timeout);
1066
0
  }
1067
1068
  /*
1069
   *  Some libraries treat 0.0 as infinite timeout, others treat it
1070
   *  as instantaneous timeout.  Solve the inconsistency by making
1071
   *  the smallest allowable timeout 100ms.
1072
   */
1073
0
  FR_TIME_DELTA_BOUND_CHECK("connect_timeout", pool->connect_timeout, >=, fr_time_delta_from_msec(100));
1074
1075
  /*
1076
   *  Don't open any connections.  Instead, force the limits
1077
   *  to only 1 connection.
1078
   *
1079
   */
1080
0
  if (check_config) pool->start = pool->min = pool->max = 1;
1081
1082
0
  return pool;
1083
0
}
1084
1085
int fr_pool_start(fr_pool_t *pool)
1086
0
{
1087
0
  uint32_t    i;
1088
0
  fr_pool_connection_t  *this;
1089
1090
  /*
1091
   *  Don't spawn any connections
1092
   */
1093
0
  if (check_config) return 0;
1094
1095
  /*
1096
   *  Create all of the connections, unless the admin says
1097
   *  not to.
1098
   */
1099
0
  pthread_mutex_lock(&pool->mutex);
1100
0
  for (i = 0; i < pool->start; i++) {
1101
    /*
1102
     *  Call time() once for each spawn attempt as there
1103
     *  could be a significant delay.
1104
     */
1105
0
    this = connection_spawn(pool, NULL, fr_time(), false);
1106
0
    if (!this) {
1107
0
      pthread_mutex_unlock(&pool->mutex);
1108
0
      ERROR("Failed spawning initial connections");
1109
0
      return -1;
1110
0
    }
1111
0
  }
1112
0
  pthread_mutex_unlock(&pool->mutex);
1113
1114
0
  fr_pool_trigger(pool, "start");
1115
1116
0
  return 0;
1117
0
}
1118
1119
/** Allocate a new pool using an existing one as a template
1120
 *
1121
 * @param[in] ctx to allocate new pool in.
1122
 * @param[in] pool  to copy.
1123
 * @param[in] opaque  data to pass to connection function.
1124
 * @return
1125
 *  - New connection pool.
1126
 *  - NULL on error.
1127
 */
1128
fr_pool_t *fr_pool_copy(TALLOC_CTX *ctx, fr_pool_t *pool, void *opaque)
1129
0
{
1130
0
  fr_pool_t *copy;
1131
1132
0
  copy = fr_pool_init(ctx, pool->cs, opaque, pool->create, pool->alive, pool->log_prefix);
1133
0
  if (!copy) return NULL;
1134
1135
0
  if (pool->trigger_prefix) fr_pool_enable_triggers(copy, pool->trigger_prefix, &pool->trigger_args);
1136
1137
0
  return copy;
1138
0
}
1139
1140
/** Get the number of connections currently in the pool
1141
 *
1142
 * @param[in] pool to count connections for.
1143
 * @return the number of connections in the pool
1144
 */
1145
fr_pool_state_t const *fr_pool_state(fr_pool_t *pool)
1146
0
{
1147
0
  return &pool->state;
1148
0
}
1149
1150
/** Connection pool get timeout
1151
 *
1152
 * @param[in] pool to get connection timeout for.
1153
 * @return the connection timeout configured for the pool.
1154
 */
1155
fr_time_delta_t fr_pool_timeout(fr_pool_t *pool)
1156
0
{
1157
0
  return pool->connect_timeout;
1158
0
}
1159
1160
/** Connection pool get start
1161
 *
1162
 * @param[in] pool to get connection start for.
1163
 * @return the connection start value configured for the pool.
1164
 */
1165
int fr_pool_start_num(fr_pool_t *pool)
1166
0
{
1167
0
  return pool->start;
1168
0
}
1169
1170
/** Return the opaque data associated with a connection pool
1171
 *
1172
 * @param pool to return data for.
1173
 * @return opaque data associated with pool.
1174
 */
1175
void const *fr_pool_opaque(fr_pool_t *pool)
1176
0
{
1177
0
  return pool->opaque;
1178
0
}
1179
1180
/** Increment pool reference by one.
1181
 *
1182
 * @param[in] pool to increment reference counter for.
1183
 */
1184
void fr_pool_ref(fr_pool_t *pool)
1185
0
{
1186
0
  pool->ref++;
1187
0
}
1188
1189
/** Set a reconnection callback for the connection pool
1190
 *
1191
 * This can be called at any time during the pool's lifecycle.
1192
 *
1193
 * @param[in] pool to set reconnect callback for.
1194
 * @param reconnect callback to call when reconnecting pool's connections.
1195
 */
1196
void fr_pool_reconnect_func(fr_pool_t *pool, fr_pool_reconnect_t reconnect)
1197
0
{
1198
0
  pool->reconnect = reconnect;
1199
0
}
1200
1201
/** Mark connections for reconnection, and spawn at least 'start' connections
1202
 *
1203
 * @note This call may block whilst waiting for pending connection attempts to complete.
1204
 *
1205
 * This intended to be called on a connection pool that's in use, to have it reflect
1206
 * a configuration change, or because the administrator knows that all connections
1207
 * in the pool are inviable and need to be reconnected.
1208
 *
1209
 * @param[in] pool  to reconnect.
1210
 * @param[in] request The current request.
1211
 * @return
1212
 *  -  0 On success.
1213
 *  - -1 If we couldn't create start connections, this may be ignored
1214
 *       depending on the context in which this function is being called.
1215
 */
1216
int fr_pool_reconnect(fr_pool_t *pool, request_t *request)
1217
0
{
1218
0
  uint32_t    i;
1219
0
  fr_pool_connection_t  *this;
1220
0
  fr_time_t   now;
1221
1222
0
  pthread_mutex_lock(&pool->mutex);
1223
1224
  /*
1225
   *  Pause new spawn attempts (we release the mutex
1226
   *  during our cond wait).
1227
   */
1228
0
  pool->state.reconnecting = true;
1229
1230
  /*
1231
   *  When the loop exits, we'll hold the lock for the pool,
1232
   *  and we're guaranteed the connection create callback
1233
   *  will not be using the opaque data.
1234
   */
1235
0
  while (pool->state.pending) pthread_cond_wait(&pool->done_spawn, &pool->mutex);
1236
1237
  /*
1238
   *  We want to ensure at least 'start' connections
1239
   *  have been reconnected. We can't call reconnect
1240
   *  because, we might get the same connection each
1241
   *  time we reserve one, so we close 'start'
1242
   *  connections, and then attempt to spawn them again.
1243
   */
1244
0
  for (i = 0; i < pool->start; i++) {
1245
0
    this = fr_heap_peek(pool->heap);
1246
0
    if (!this) break; /* There wasn't 'start' connections available */
1247
1248
0
    connection_close_internal(pool, this);
1249
0
  }
1250
1251
  /*
1252
   *  Mark all remaining connections in the pool as
1253
   *  requiring reconnection.
1254
   */
1255
0
  for (this = pool->head; this; this = this->next) this->needs_reconnecting = true;
1256
1257
  /*
1258
   *  Call the reconnect callback (if one's set)
1259
   *  This may modify the opaque data associated
1260
   *  with the pool.
1261
   */
1262
0
  if (pool->reconnect) pool->reconnect(pool, pool->opaque);
1263
1264
  /*
1265
   *  Must be done inside the mutex, reconnect callback
1266
   *  may modify args.
1267
   */
1268
0
  fr_pool_trigger(pool, "reconnect");
1269
1270
  /*
1271
   *  Allow new spawn attempts, and wakeup any threads
1272
   *  waiting to spawn new connections.
1273
   */
1274
0
  pool->state.reconnecting = false;
1275
0
  pthread_cond_broadcast(&pool->done_reconnecting);
1276
1277
0
  now = fr_time();
1278
1279
  /*
1280
   *  Now attempt to spawn 'start' connections.
1281
   */
1282
0
  for (i = 0; i < pool->start; i++) {
1283
0
    this = connection_spawn(pool, request, now, false);
1284
0
    if (!this) {
1285
0
      pthread_mutex_unlock(&pool->mutex);
1286
0
      return -1;
1287
0
    }
1288
0
  }
1289
0
  pthread_mutex_unlock(&pool->mutex);
1290
1291
0
  return 0;
1292
0
}
1293
1294
/** Delete a connection pool
1295
 *
1296
 * Closes, unlinks and frees all connections in the connection pool, then frees
1297
 * all memory used by the connection pool.
1298
 *
1299
 * @note Will call the 'stop' trigger.
1300
 * @note Must be called with the mutex free.
1301
 *
1302
 * @param[in,out] pool to delete.
1303
 */
1304
void fr_pool_free(fr_pool_t *pool)
1305
0
{
1306
0
  fr_pool_connection_t *this;
1307
1308
0
  if (!pool) return;
1309
1310
  /*
1311
   *  More modules hold a reference to this pool, don't free
1312
   *  it yet.
1313
   */
1314
0
  if (pool->ref > 0) {
1315
0
    pool->ref--;
1316
0
    return;
1317
0
  }
1318
1319
0
  DEBUG2("Removing connection pool");
1320
1321
0
  pthread_mutex_lock(&pool->mutex);
1322
1323
  /*
1324
   *  Don't loop over the list.  Just keep removing the head
1325
   *  until they're all gone.
1326
   */
1327
0
  while ((this = pool->head) != NULL) {
1328
0
    INFO("Closing connection (%" PRIu64 ")", this->number);
1329
1330
0
    connection_close_internal(pool, this);
1331
0
  }
1332
1333
0
  fr_pool_trigger(pool, "stop");
1334
1335
0
  fr_assert(pool->head == NULL);
1336
0
  fr_assert(pool->tail == NULL);
1337
0
  fr_assert(pool->state.num == 0);
1338
1339
0
  pthread_mutex_unlock(&pool->mutex);
1340
0
  pthread_mutex_destroy(&pool->mutex);
1341
0
  pthread_cond_destroy(&pool->done_spawn);
1342
0
  pthread_cond_destroy(&pool->done_reconnecting);
1343
1344
0
  talloc_free(pool);
1345
0
}
1346
1347
/** Reserve a connection in the connection pool
1348
 *
1349
 * Will attempt to find an unused connection in the connection pool, if one is
1350
 * found, will mark it as in use, and increment the number of active connections
1351
 * and return the connection handle.
1352
 *
1353
 * If no free connections are found will attempt to spawn a new one, conditional
1354
 * on a connection spawning not already being in progress, and not being at the
1355
 * 'max' connection limit.
1356
 *
1357
 * @note fr_pool_connection_release must be called once the caller has finished
1358
 * using the connection.
1359
 *
1360
 * @see fr_pool_connection_release
1361
 * @param[in] pool  to reserve the connection from.
1362
 * @param[in] request The current request.
1363
 * @return
1364
 *  - A pointer to the connection handle.
1365
 *  - NULL on error.
1366
 */
1367
void *fr_pool_connection_get(fr_pool_t *pool, request_t *request)
1368
0
{
1369
0
  return connection_get_internal(pool, request, true);
1370
0
}
1371
1372
/** Release a connection
1373
 *
1374
 * Will mark a connection as unused and decrement the number of active
1375
 * connections.
1376
 *
1377
 * @see fr_pool_connection_get
1378
 * @param[in] pool  to release the connection in.
1379
 * @param[in] request The current request.
1380
 * @param[in] conn  to release.
1381
 */
1382
void fr_pool_connection_release(fr_pool_t *pool, request_t *request, void *conn)
1383
0
{
1384
0
  fr_pool_connection_t  *this;
1385
0
  fr_time_delta_t   held;
1386
0
  bool      trigger_min = false, trigger_max = false;
1387
1388
0
  if (!conn) return;
1389
1390
0
  pthread_mutex_lock(&pool->mutex);
1391
0
  this = connection_find(pool, conn);
1392
0
  if (!this) {
1393
0
    pthread_mutex_unlock(&pool->mutex);
1394
0
    return;
1395
0
  }
1396
1397
0
  this->in_use = false;
1398
1399
  /*
1400
   *  Record when the connection was last released
1401
   */
1402
0
  this->last_released = fr_time();
1403
0
  pool->state.last_released = this->last_released;
1404
1405
  /*
1406
   *  This is done inside the mutex to ensure
1407
   *  updates are atomic.
1408
   */
1409
0
  held = fr_time_sub(this->last_released, this->last_reserved);
1410
1411
  /*
1412
   *  Check we've not exceeded out trigger limits
1413
   *
1414
   *      These should only fire once per second.
1415
   */
1416
0
  if (fr_time_delta_ispos(pool->held_trigger_min) &&
1417
0
      (fr_time_delta_lt(held, pool->held_trigger_min)) &&
1418
0
      (fr_time_delta_gteq(fr_time_sub(this->last_released, pool->state.last_held_min), fr_time_delta_from_sec(1)))) {
1419
0
        trigger_min = true;
1420
0
        pool->state.last_held_min = this->last_released;
1421
0
  }
1422
1423
0
  if (fr_time_delta_ispos(pool->held_trigger_max) &&
1424
0
      (fr_time_delta_gt(held, pool->held_trigger_max)) &&
1425
0
      (fr_time_delta_gteq(fr_time_sub(this->last_released, pool->state.last_held_max), fr_time_delta_from_sec(1)))) {
1426
0
        trigger_max = true;
1427
0
        pool->state.last_held_max = this->last_released;
1428
0
  }
1429
1430
  /*
1431
   *  Insert the connection in the heap.
1432
   *
1433
   *  This will either be based on when we *started* using it
1434
   *  (allowing fast links to be re-used, and slow links to be
1435
   *  gradually expired), or when we released it (allowing
1436
   *  the maximum amount of time between connection use).
1437
   */
1438
0
  fr_heap_insert(&pool->heap, this);
1439
1440
0
  fr_assert(pool->state.active != 0);
1441
0
  pool->state.active--;
1442
1443
0
  ROPTIONAL(RDEBUG2, DEBUG2, "Released connection (%" PRIu64 ")", this->number);
1444
1445
  /*
1446
   *  We mirror the "spawn on get" functionality by having
1447
   *  "delete on release".  If there are too many spare
1448
   *  connections, go manage the pool && clean some up.
1449
   */
1450
0
  connection_check(pool, request);
1451
0
  pthread_mutex_unlock(&pool->mutex);
1452
1453
0
  if (trigger_min) fr_pool_trigger(pool, "min");
1454
0
  if (trigger_max) fr_pool_trigger(pool, "max");
1455
0
}
1456
1457
/** Reconnect a suspected inviable connection
1458
 *
1459
 * This should be called by the module if it suspects that a connection is
1460
 * not viable (e.g. the server has closed it).
1461
 *
1462
 * When implementing a module that uses the connection pool API, it is advisable
1463
 * to pass a pointer to the pointer to the handle (void **conn)
1464
 * to all functions which may call reconnect. This is so that if a new handle
1465
 * is created and returned, the handle pointer can be updated up the callstack,
1466
 * and a function higher up the stack doesn't attempt to use a now invalid
1467
 * connection handle.
1468
 *
1469
 * @note Will free any talloced memory hung off the context of the connection,
1470
 *  being reconnected.
1471
 *
1472
 * @warning After calling reconnect the caller *MUST NOT* attempt to use
1473
 *  the old handle in any other operations, as its memory will have been
1474
 *  freed.
1475
 *
1476
 * @see fr_pool_connection_get
1477
 * @param[in] pool  to reconnect the connection in.
1478
 * @param[in] request The current request.
1479
 * @param[in] conn  to reconnect.
1480
 * @return new connection handle if successful else NULL.
1481
 */
1482
void *fr_pool_connection_reconnect(fr_pool_t *pool, request_t *request, void *conn)
1483
0
{
1484
0
  fr_pool_connection_t  *this;
1485
1486
0
  if (!pool || !conn) return NULL;
1487
1488
0
  pthread_mutex_lock(&pool->mutex);
1489
0
  this = connection_find(pool, conn);
1490
0
  if (!this) {
1491
0
    pthread_mutex_unlock(&pool->mutex);
1492
0
    return NULL;
1493
0
  }
1494
1495
0
  ROPTIONAL(RINFO, INFO, "Deleting inviable connection (%" PRIu64 ")", this->number);
1496
1497
0
  connection_close_internal(pool, this);
1498
0
  connection_check(pool, request);
1499
0
  pthread_mutex_unlock(&pool->mutex);
1500
1501
  /*
1502
   *  Return an existing connection or spawn a new one.
1503
   */
1504
0
  return connection_get_internal(pool, request, true);
1505
0
}
1506
1507
/** Delete a connection from the connection pool.
1508
 *
1509
 * Resolves the connection handle to a connection, then (if found)
1510
 * closes, unlinks and frees that connection.
1511
 *
1512
 * @note Must be called with the mutex free.
1513
 *
1514
 * @param[in] pool  Connection pool to modify.
1515
 * @param[in] request The current request.
1516
 * @param[in] conn  to delete.
1517
 * @return
1518
 *  - 0 If the connection could not be found.
1519
 *  - 1 if the connection was deleted.
1520
 */
1521
int fr_pool_connection_close(fr_pool_t *pool, request_t *request, void *conn)
1522
0
{
1523
0
  fr_pool_connection_t *this;
1524
1525
0
  if (!conn) return 0;
1526
1527
0
  pthread_mutex_lock(&pool->mutex);
1528
0
  this = connection_find(pool, conn);
1529
0
  if (!this) {
1530
0
    pthread_mutex_unlock(&pool->mutex);
1531
0
    return 0;
1532
0
  }
1533
1534
  /*
1535
   *  Record the last time a connection was closed
1536
   */
1537
0
  pool->state.last_closed = fr_time();
1538
1539
0
  ROPTIONAL(RINFO, INFO, "Deleting connection (%" PRIu64 ")", this->number);
1540
1541
0
  connection_close_internal(pool, this);
1542
0
  connection_check(pool, request);
1543
0
  pthread_mutex_unlock(&pool->mutex);
1544
1545
0
  return 1;
1546
0
}