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