The FreeRADIUS server $Id: a4e7f8c94e8038b7627bcf52356b7ed15955c1d7 $
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: dc3679204298804cd2fcd222838ddfd44dc6bc20 $")
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/misc.h>
37
38
40
42static 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 */
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 */
85struct 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
151static 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" },
167};
168
169static int max_dflt(CONF_PAIR **out, UNUSED void *parent, CONF_SECTION *cs, fr_token_t quote, conf_parser_t const *rule)
170{
171 char *strvalue;
172
173 strvalue = talloc_asprintf(NULL, "%u", main_config->max_workers);
174 *out = cf_pair_alloc(cs, rule->name1, strvalue, T_OP_EQ, T_BARE_WORD, quote);
175 talloc_free(strvalue);
176
177 return 0;
178}
179
180/** Order connections by reserved most recently
181 */
182static fr_cmp_ret_t last_reserved_cmp(void const *one, void const *two)
183{
184 fr_pool_connection_t const *a = one, *b = two;
185
186 return fr_time_cmp(a->last_reserved, b->last_reserved);
187}
188
189/** Order connections by released longest ago
190 */
191static fr_cmp_ret_t last_released_cmp(void const *one, void const *two)
192{
193 fr_pool_connection_t const *a = one, *b = two;
194
195 return fr_time_cmp(a->last_released, b->last_released);
196}
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 */
206{
207 if (this->prev) {
208 fr_assert(pool->head != this);
209 this->prev->next = this->next;
210 } else {
211 fr_assert(pool->head == this);
212 pool->head = this->next;
213 }
214 if (this->next) {
215 fr_assert(pool->tail != this);
216 this->next->prev = this->prev;
217 } else {
218 fr_assert(pool->tail == this);
219 pool->tail = this->prev;
220 }
221
222 this->prev = this->next = NULL;
223}
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 */
233{
234 fr_assert(pool != NULL);
235 fr_assert(this != NULL);
236 fr_assert(pool->head != this);
237 fr_assert(pool->tail != this);
238
239 if (pool->head) {
240 pool->head->prev = this;
241 }
242
243 this->next = pool->head;
244 this->prev = NULL;
245 pool->head = this;
246 if (!pool->tail) {
247 fr_assert(this->next == NULL);
248 pool->tail = this;
249 } else {
250 fr_assert(this->next != NULL);
251 }
252}
253
254/** Send a connection pool trigger.
255 *
256 * @param[in] pool to send trigger for.
257 * @param[in] event trigger name suffix.
258 */
259static inline void fr_pool_trigger(fr_pool_t *pool, char const *event)
260{
261 char name[128];
262
263 fr_assert(pool != NULL);
264 fr_assert(event != NULL);
265
266 if (!pool->triggers_enabled) return;
267
268 snprintf(name, sizeof(name), "%s.%s", pool->trigger_prefix, event);
269 trigger(unlang_interpret_get_thread_default(), pool->cs, NULL, name, true, &pool->trigger_args, pool);
270}
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 */
286{
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 for (this = pool->head; this != NULL; this = this->next) {
295 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 fr_assert(this->in_use == true);
304 return this;
305 }
306 }
307
308 return NULL;
309}
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 */
329{
330 uint64_t number;
331 uint32_t pending_window;
332 TALLOC_CTX *ctx;
333
335 void *conn;
336
337 fr_assert(pool != NULL);
338 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 if ((pool->state.num == 0) &&
346 pool->state.pending &&
348 return NULL;
349 }
350
351 /*
352 * Don't spawn too many connections at the same time.
353 */
354 if ((pool->state.num + pool->state.pending) >= pool->max) {
355 ERROR("Cannot open new connection, already at max");
356 return NULL;
357 }
358
359 /*
360 * If the last attempt failed, wait a bit before
361 * retrying.
362 */
363 if (fr_time_gt(pool->state.last_failed, fr_time_wrap(0)) &&
364 fr_time_gt(fr_time_add(pool->state.last_failed, pool->retry_delay), now)) {
365 bool complain = false;
367
369 complain = true;
370
371 pool->state.last_throttled = now;
372 }
373
374 if (!fr_rate_limit_enabled() || complain) {
375 ERROR("Last connection attempt failed, waiting %pV seconds before retrying",
376 fr_box_time_delta(retry_in));
377 }
378
379 return NULL;
380 }
381
382 /*
383 * We limit the rate of new connections after a failed attempt.
384 */
385 if (pool->state.pending > pool->pending_window) {
387 "Cannot open a new connection due to rate limit after failure");
388
389 return NULL;
390 }
391
392 pool->state.pending++;
393 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 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 pending_window = (pool->max - pool->state.num);
406 if (pool->pending_window < pending_window) pending_window = pool->pending_window;
407 ROPTIONAL(RDEBUG2, DEBUG2, "Opening additional connection (%" PRIu64 "), %u of %u pending slots used",
408 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 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 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 conn = pool->create(ctx, pool->opaque, pool->connect_timeout);
432 if (!conn) {
433 ERROR("Opening connection failed (%" PRIu64 ")", number);
434
435 pthread_mutex_lock(&pool->mutex);
436 pool->state.last_failed = now;
437 pool->pending_window = 1;
438 pool->state.pending--;
439
440 /*
441 * Must be done inside the mutex, reconnect callback
442 * may modify args.
443 */
444 fr_pool_trigger(pool, "fail");
445 pthread_cond_broadcast(&pool->done_spawn);
446
447 talloc_free(ctx);
448
449 return NULL;
450 }
451
452 /*
453 * And lock the mutex again while we link the new
454 * connection back into the pool.
455 */
456 pthread_mutex_lock(&pool->mutex);
457
458 this = talloc_zero(pool, fr_pool_connection_t);
459 if (!this) {
460 pool->state.last_failed = now;
461 pool->state.pending--;
462
463 pthread_cond_broadcast(&pool->done_spawn);
464
465 ERROR("Memory allocation failed for new connection (%" PRIu64 ")", number);
466
467 talloc_free(ctx);
468
469 return NULL;
470 }
471 MEM(talloc_link_ctx(this, ctx) >= 0);
472
473 this->created = now;
474 this->connection = conn;
475 this->in_use = in_use;
476
477 this->number = number;
478 this->last_reserved = fr_time();
479 this->last_released = this->last_reserved;
480
481 /*
482 * The connection pool is starting up. Insert the
483 * connection into the heap.
484 */
485 if (!in_use) fr_heap_insert(&pool->heap, this);
486
487 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 pool->state.num++;
495
496 fr_assert(pool->state.pending > 0);
497 pool->state.pending--;
498
499 /*
500 * We've successfully opened one more connection. Allow
501 * more connections to open in parallel.
502 */
503 if ((pool->pending_window < pool->max) &&
504 ((pool->max_pending == 0) || (pool->pending_window < pool->max_pending))) {
505 pool->pending_window++;
506 }
507
508 pool->state.last_spawned = fr_time();
509 pool->delay_interval = pool->cleanup_interval;
510 pool->state.next_delay = pool->cleanup_interval;
511 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 fr_pool_trigger(pool, "open");
518
519 pthread_cond_broadcast(&pool->done_spawn);
520
521 return this;
522}
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 */
536{
537 /*
538 * If it's in use, release it.
539 */
540 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 this->in_use = false;
547
548 fr_assert(pool->state.active != 0);
549 pool->state.active--;
550
551 } else {
552 /*
553 * Connection isn't used, remove it from the heap.
554 */
555 fr_heap_extract(&pool->heap, this);
556 }
557
558 fr_pool_trigger(pool, "close");
559
560 connection_unlink(pool, this);
561
562 fr_assert(pool->state.num > 0);
563 pool->state.num--;
564 talloc_free(this);
565}
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 */
584{
585 fr_assert(pool != NULL);
586 fr_assert(this != NULL);
587
588 /*
589 * Don't terminated in-use connections
590 */
591 if (this->in_use) return 1;
592
593 if (this->needs_reconnecting) {
594 ROPTIONAL(RDEBUG2, DEBUG2, "Closing expired connection (%" PRIu64 "): Needs reconnecting",
595 this->number);
596 do_delete:
597 if (pool->state.num <= pool->min) {
598 ROPTIONAL(RDEBUG2, DEBUG2, "You probably need to lower \"min\"");
599 }
600 connection_close_internal(pool, this);
601 return 0;
602 }
603
604 if ((pool->max_uses > 0) &&
605 (this->num_uses >= pool->max_uses)) {
606 ROPTIONAL(RDEBUG2, DEBUG2, "Closing expired connection (%" PRIu64 "): Hit max_uses limit",
607 this->number);
608 goto do_delete;
609 }
610
611 if (fr_time_delta_ispos(pool->lifetime) &&
612 (fr_time_lt(fr_time_add(this->created, pool->lifetime), now))) {
613 ROPTIONAL(RDEBUG2, DEBUG2, "Closing expired connection (%" PRIu64 "): Hit lifetime limit",
614 this->number);
615 goto do_delete;
616 }
617
619 (fr_time_lt(fr_time_add(this->last_released, pool->idle_timeout), now))) {
620 ROPTIONAL(RINFO, INFO, "Closing connection (%" PRIu64 "): Hit idle_timeout, was idle for %pVs",
621 this->number, fr_box_time_delta(fr_time_sub(now, this->last_released)));
622 goto do_delete;
623 }
624
625 return 1;
626}
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 */
644{
645 uint32_t num, spare;
646 fr_time_t now = fr_time();
647 fr_pool_connection_t *this, *next;
648
650
651 /*
652 * Get "real" number of connections, and count pending
653 * connections as spare.
654 */
655 num = pool->state.num + pool->state.pending;
656 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 if (num < pool->min) {
667 ROPTIONAL(RINFO, INFO, "Need %" PRIu32 " more connections to reach min connections (%" PRIu32 ")", pool->min - num, pool->min);
668 goto add_connection;
669 }
670
671 /*
672 * On the odd chance that we've opened too many
673 * connections, take care of that.
674 */
675 if (num > pool->max) {
676 /*
677 * Pending connections don't get closed as "spare".
678 */
679 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 goto close_connection;
686 }
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 if (spare == pool->spare) goto manage_connections;
698
699 /*
700 * Too many spare connections, delete some.
701 */
702 if (spare > pool->spare) {
704
705 /*
706 * Pending connections don't get closed as "spare".
707 */
708 if (pool->state.pending > 0) goto manage_connections;
709
710 /*
711 * Don't close too many connections, even they
712 * are spare.
713 */
714 if (num <= pool->min) goto manage_connections;
715
716 /*
717 * Too many spares, go close one.
718 */
719
720 close_connection:
721 /*
722 * Don't close connections too often, in order to
723 * prevent flapping.
724 */
725 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 found = NULL;
731 for (this = pool->tail; this != NULL; this = this->prev) {
732 if (this->in_use) continue;
733
734 if (!found || (fr_time_lt(this->last_reserved, found->last_reserved))) found = this;
735 }
736
737 if (!fr_cond_assert(found)) goto done;
738
739 ROPTIONAL(RDEBUG2, DEBUG2, "Closing connection (%" PRIu64 ") as we have too many unused connections",
740 found->number);
741 connection_close_internal(pool, found);
742
743 /*
744 * Decrease the delay for the next time we clean
745 * up.
746 */
750
751 goto manage_connections;
752 }
753
754 /*
755 * Too few connections, open some more.
756 */
757 if (spare < pool->spare) {
758 /*
759 * Don't open too many pending connections.
760 */
761 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 if (num >= pool->max) goto manage_connections;
768
769 /*
770 * Too few spares, go add one.
771 */
772 ROPTIONAL(RINFO, INFO, "Need %" PRIu32 " more connections to reach %" PRIu32 " spares", pool->spare - spare, pool->spare);
773
774 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 (void) connection_spawn(pool, request, now, false);
780 goto manage_connections;
781 }
782
783 /*
784 * Pass over all of the connections in the pool, limiting
785 * lifetime, idle time, max requests, etc.
786 */
787manage_connections:
788 for (this = pool->head; this != NULL; this = next) {
789 next = this->next;
790 connection_manage(pool, request, this, now);
791 }
792
793 pool->state.last_checked = now;
794
795done:
796 return 1;
797}
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 */
810static void *connection_get_internal(fr_pool_t *pool, request_t *request, bool spawn)
811{
812 fr_time_t now;
814
815 if (!pool) return NULL;
816
817 pthread_mutex_lock(&pool->mutex);
818
819 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 do {
827 this = fr_heap_peek(pool->heap);
828 if (!this) break;
829 } 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 if (this) {
836 fr_heap_extract(&pool->heap, this);
837 goto do_return;
838 }
839
840 if (pool->state.num == pool->max) {
841 bool complain = false;
842
843 /*
844 * Rate-limit complaints.
845 */
847 complain = true;
848 pool->state.last_at_max = now;
849 }
850
851 if (!fr_rate_limit_enabled() || complain) {
852 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 fr_pool_trigger(pool, "none");
859 }
860 pthread_mutex_unlock(&pool->mutex);
861
862 return NULL;
863 }
864
865 if (!spawn) {
866 pthread_mutex_unlock(&pool->mutex);
867 return NULL;
868 }
869
870 ROPTIONAL(RDEBUG2, DEBUG2, "%" PRIu32 " of %u connections in use. You may need to increase \"spare\"",
871 pool->state.active, pool->state.num);
872
873 this = connection_spawn(pool, request, now, true);
874 if (!this) {
875 pthread_mutex_unlock(&pool->mutex);
876 return NULL;
877 }
878
879do_return:
880 pool->state.active++;
881 this->num_uses++;
882 this->last_reserved = fr_time();
883 this->in_use = true;
884
885#ifdef PTHREAD_DEBUG
886 this->pthread_id = pthread_self();
887#endif
888 pthread_mutex_unlock(&pool->mutex);
889
890 ROPTIONAL(RDEBUG2, DEBUG2, "Reserved connection (%" PRIu64 ")", this->number);
891
892 return this->connection;
893}
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 */
909void 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
914 MEM(pool->trigger_prefix = trigger_prefix ? talloc_strdup(pool, trigger_prefix) : "");
915
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 */
943fr_pool_t *fr_pool_init(TALLOC_CTX *ctx,
944 CONF_SECTION const *cs,
945 void *opaque,
947 char const *log_prefix)
948{
949 fr_pool_t *pool = NULL;
950
951 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 MEM(pool = talloc_zero(NULL, fr_pool_t));
960
961 /*
962 * Ensure the pool is freed at the same time
963 * as its parent.
964 */
965 if (ctx && (talloc_link_ctx(ctx, pool) < 0)) {
966 PERROR("%s: Failed linking pool ctx", __FUNCTION__);
967 talloc_free(pool);
968
969 return NULL;
970 }
971
972 pool->cs = cs;
973 pool->opaque = opaque;
974 pool->create = c;
975 pool->alive = a;
976
977 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 if (!pool->spread) {
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 } else {
1019 }
1020 if (!pool->heap) {
1021 ERROR("%s: Failed creating connection heap", __FUNCTION__);
1022 error:
1023 fr_pool_free(pool);
1024 return NULL;
1025 }
1026
1027 pool->log_prefix = log_prefix ? talloc_strdup(pool, log_prefix) : "core";
1028 pthread_mutex_init(&pool->mutex, NULL);
1029 pthread_cond_init(&pool->done_spawn, NULL);
1030 pthread_cond_init(&pool->done_reconnecting, NULL);
1031
1032 DEBUG2("Initialising connection pool");
1033
1034 if (cf_section_rules_push(UNCONST(CONF_SECTION *, cs), pool_config) < 0) goto error;
1035 if (cf_section_parse(pool, pool, UNCONST(CONF_SECTION *, cs)) < 0) {
1036 PERROR("Configuration parsing failed");
1037 goto error;
1038 }
1039
1040 /*
1041 * Some simple limits
1042 */
1043 if (pool->max == 0) {
1044 cf_log_err(cs, "Cannot set 'max' to zero");
1045 goto error;
1046 }
1047
1048 pool->pending_window = (pool->max_pending > 0) ? pool->max_pending : pool->max;
1049
1050 if (pool->min > pool->max) {
1051 cf_log_err(cs, "Cannot set 'min' to more than 'max'");
1052 goto error;
1053 }
1054
1055 FR_INTEGER_BOUND_CHECK("max", pool->max, <=, 1024);
1056 FR_INTEGER_BOUND_CHECK("start", pool->start, <=, pool->max);
1057 FR_INTEGER_BOUND_CHECK("spare", pool->spare, <=, (pool->max - pool->min));
1058
1059 if (fr_time_delta_ispos(pool->lifetime)) {
1060 FR_TIME_DELTA_COND_CHECK("idle_timeout", pool->idle_timeout,
1062 }
1063
1064 if (fr_time_delta_ispos(pool->idle_timeout)) {
1065 FR_TIME_DELTA_BOUND_CHECK("cleanup_interval", pool->cleanup_interval, <=, pool->idle_timeout);
1066 }
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 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 if (check_config) pool->start = pool->min = pool->max = 1;
1081
1082 return pool;
1083}
1084
1086{
1087 uint32_t i;
1089
1090 /*
1091 * Don't spawn any connections
1092 */
1093 if (check_config) return 0;
1094
1095 /*
1096 * Create all of the connections, unless the admin says
1097 * not to.
1098 */
1099 pthread_mutex_lock(&pool->mutex);
1100 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 this = connection_spawn(pool, NULL, fr_time(), false);
1106 if (!this) {
1107 pthread_mutex_unlock(&pool->mutex);
1108 ERROR("Failed spawning initial connections");
1109 return -1;
1110 }
1111 }
1112 pthread_mutex_unlock(&pool->mutex);
1113
1114 fr_pool_trigger(pool, "start");
1115
1116 return 0;
1117}
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 */
1128fr_pool_t *fr_pool_copy(TALLOC_CTX *ctx, fr_pool_t *pool, void *opaque)
1129{
1130 fr_pool_t *copy;
1131
1132 copy = fr_pool_init(ctx, pool->cs, opaque, pool->create, pool->alive, pool->log_prefix);
1133 if (!copy) return NULL;
1134
1135 if (pool->trigger_prefix) fr_pool_enable_triggers(copy, pool->trigger_prefix, &pool->trigger_args);
1136
1137 return copy;
1138}
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 */
1146{
1147 return &pool->state;
1148}
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 */
1156{
1157 return pool->connect_timeout;
1158}
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 */
1166{
1167 return pool->start;
1168}
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 */
1175void const *fr_pool_opaque(fr_pool_t *pool)
1176{
1177 return pool->opaque;
1178}
1179
1180/** Increment pool reference by one.
1181 *
1182 * @param[in] pool to increment reference counter for.
1183 */
1185{
1186 pool->ref++;
1187}
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 */
1197{
1198 pool->reconnect = reconnect;
1199}
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 */
1217{
1218 uint32_t i;
1220 fr_time_t now;
1221
1222 pthread_mutex_lock(&pool->mutex);
1223
1224 /*
1225 * Pause new spawn attempts (we release the mutex
1226 * during our cond wait).
1227 */
1228 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 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 for (i = 0; i < pool->start; i++) {
1245 this = fr_heap_peek(pool->heap);
1246 if (!this) break; /* There wasn't 'start' connections available */
1247
1248 connection_close_internal(pool, this);
1249 }
1250
1251 /*
1252 * Mark all remaining connections in the pool as
1253 * requiring reconnection.
1254 */
1255 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 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 fr_pool_trigger(pool, "reconnect");
1269
1270 /*
1271 * Allow new spawn attempts, and wakeup any threads
1272 * waiting to spawn new connections.
1273 */
1274 pool->state.reconnecting = false;
1275 pthread_cond_broadcast(&pool->done_reconnecting);
1276
1277 now = fr_time();
1278
1279 /*
1280 * Now attempt to spawn 'start' connections.
1281 */
1282 for (i = 0; i < pool->start; i++) {
1283 this = connection_spawn(pool, request, now, false);
1284 if (!this) {
1285 pthread_mutex_unlock(&pool->mutex);
1286 return -1;
1287 }
1288 }
1289 pthread_mutex_unlock(&pool->mutex);
1290
1291 return 0;
1292}
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 */
1305{
1307
1308 if (!pool) return;
1309
1310 /*
1311 * More modules hold a reference to this pool, don't free
1312 * it yet.
1313 */
1314 if (pool->ref > 0) {
1315 pool->ref--;
1316 return;
1317 }
1318
1319 DEBUG2("Removing connection pool");
1320
1321 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 while ((this = pool->head) != NULL) {
1328 INFO("Closing connection (%" PRIu64 ")", this->number);
1329
1330 connection_close_internal(pool, this);
1331 }
1332
1333 fr_pool_trigger(pool, "stop");
1334
1335 fr_assert(pool->head == NULL);
1336 fr_assert(pool->tail == NULL);
1337 fr_assert(pool->state.num == 0);
1338
1339 pthread_mutex_unlock(&pool->mutex);
1340 pthread_mutex_destroy(&pool->mutex);
1341 pthread_cond_destroy(&pool->done_spawn);
1342 pthread_cond_destroy(&pool->done_reconnecting);
1343
1344 talloc_free(pool);
1345}
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 */
1368{
1369 return connection_get_internal(pool, request, true);
1370}
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 */
1383{
1385 fr_time_delta_t held;
1386 bool trigger_min = false, trigger_max = false;
1387
1388 if (!conn) return;
1389
1390 pthread_mutex_lock(&pool->mutex);
1391 this = connection_find(pool, conn);
1392 if (!this) {
1393 pthread_mutex_unlock(&pool->mutex);
1394 return;
1395 }
1396
1397 this->in_use = false;
1398
1399 /*
1400 * Record when the connection was last released
1401 */
1402 this->last_released = fr_time();
1403 pool->state.last_released = this->last_released;
1404
1405 /*
1406 * This is done inside the mutex to ensure
1407 * updates are atomic.
1408 */
1409 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 */
1417 (fr_time_delta_lt(held, pool->held_trigger_min)) &&
1418 (fr_time_delta_gteq(fr_time_sub(this->last_released, pool->state.last_held_min), fr_time_delta_from_sec(1)))) {
1419 trigger_min = true;
1420 pool->state.last_held_min = this->last_released;
1421 }
1422
1424 (fr_time_delta_gt(held, pool->held_trigger_max)) &&
1425 (fr_time_delta_gteq(fr_time_sub(this->last_released, pool->state.last_held_max), fr_time_delta_from_sec(1)))) {
1426 trigger_max = true;
1427 pool->state.last_held_max = this->last_released;
1428 }
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 fr_heap_insert(&pool->heap, this);
1439
1440 fr_assert(pool->state.active != 0);
1441 pool->state.active--;
1442
1443 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 */
1451 pthread_mutex_unlock(&pool->mutex);
1452
1453 if (trigger_min) fr_pool_trigger(pool, "min");
1454 if (trigger_max) fr_pool_trigger(pool, "max");
1455}
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 */
1483{
1485
1486 if (!pool || !conn) return NULL;
1487
1488 pthread_mutex_lock(&pool->mutex);
1489 this = connection_find(pool, conn);
1490 if (!this) {
1491 pthread_mutex_unlock(&pool->mutex);
1492 return NULL;
1493 }
1494
1495 ROPTIONAL(RINFO, INFO, "Deleting inviable connection (%" PRIu64 ")", this->number);
1496
1497 connection_close_internal(pool, this);
1499 pthread_mutex_unlock(&pool->mutex);
1500
1501 /*
1502 * Return an existing connection or spawn a new one.
1503 */
1504 return connection_get_internal(pool, request, true);
1505}
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 */
1522{
1524
1525 if (!conn) return 0;
1526
1527 pthread_mutex_lock(&pool->mutex);
1528 this = connection_find(pool, conn);
1529 if (!this) {
1530 pthread_mutex_unlock(&pool->mutex);
1531 return 0;
1532 }
1533
1534 /*
1535 * Record the last time a connection was closed
1536 */
1537 pool->state.last_closed = fr_time();
1538
1539 ROPTIONAL(RINFO, INFO, "Deleting connection (%" PRIu64 ")", this->number);
1540
1541 connection_close_internal(pool, this);
1543 pthread_mutex_unlock(&pool->mutex);
1544
1545 return 1;
1546}
static uint8_t request[4]
#define UNCONST(_type, _ptr)
Remove const qualification from a pointer.
Definition build.h:203
#define RCSID(id)
Definition build.h:603
#define UNUSED
Definition build.h:415
fr_cmp_ret_t
Result of an ordering comparison.
Definition build.h:113
bool check_config
Definition cf_file.c:61
int cf_section_parse(TALLOC_CTX *ctx, void *base, CONF_SECTION *cs)
Parse a configuration section into user-supplied variables.
Definition cf_parse.c:1360
#define CONF_PARSER_TERMINATOR
Definition cf_parse.h:712
#define FR_INTEGER_BOUND_CHECK(_name, _var, _op, _bound)
Definition cf_parse.h:572
#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:280
#define FR_TIME_DELTA_COND_CHECK(_name, _var, _cond, _new)
Definition cf_parse.h:574
#define cf_section_rules_push(_cs, _rule)
Definition cf_parse.h:744
char const * name1
Name of the CONF_ITEM to parse.
Definition cf_parse.h:650
#define FR_TIME_DELTA_BOUND_CHECK(_name, _var, _op, _bound)
Definition cf_parse.h:583
Defines a CONF_PAIR to C data type mapping.
Definition cf_parse.h:649
Configuration AVP similar to a fr_pair_t.
Definition cf_priv.h:77
A section grouping multiple CONF_PAIR.
Definition cf_priv.h:106
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:1487
#define cf_log_err(_cf, _fmt,...)
Definition cf_util.h:340
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:177
#define MEM(x)
Definition debug.h:38
#define ERROR(fmt,...)
Definition dhcpclient.c:40
int fr_heap_insert(fr_heap_t **hp, void *data)
Insert a new element into the heap.
Definition heap.c:149
int fr_heap_extract(fr_heap_t **hp, void *data)
Remove a node from the heap.
Definition heap.c:259
unsigned int fr_heap_index_t
Definition heap.h:82
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:138
#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:117
The main heap structure.
Definition heap.h:68
talloc_free(hp)
unlang_interpret_t * unlang_interpret_get_thread_default(void)
Get the default interpreter for this thread.
Definition interpret.c:2561
#define PERROR(_fmt,...)
Definition log.h:233
#define ROPTIONAL(_l_request, _l_global, _fmt,...)
Use different logging functions depending on whether request is NULL or not.
Definition log.h:545
#define RWARN(fmt,...)
Definition log.h:314
#define RINFO(fmt,...)
Definition log.h:313
#define RATE_LIMIT_GLOBAL_ROPTIONAL(_l_request, _l_global, _fmt,...)
Rate limit messages using a global limiting entry.
Definition log.h:680
#define fr_time()
Definition event.c:58
static bool fr_rate_limit_enabled(void)
Whether rate limiting is enabled.
Definition log.h:145
main_config_t const * main_config
Main server configuration.
Definition main_config.c:56
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:2303
void fr_pair_list_init(fr_pair_list_t *list)
Initialise a pair list header.
Definition pair.c:47
fr_pool_reconnect_t reconnect
Called during connection pool reconnect.
Definition pool.c:146
fr_time_delta_t fr_pool_timeout(fr_pool_t *pool)
Connection pool get timeout.
Definition pool.c:1155
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:232
int fr_pool_start(fr_pool_t *pool)
Definition pool.c:1085
bool spread
If true we spread requests over the connections, using the connection released longest ago,...
Definition pool.c:110
uint32_t max_pending
Max number of pending connections to allow.
Definition pool.c:91
fr_time_delta_t delay_interval
When we next do a cleanup.
Definition pool.c:100
fr_time_t last_reserved
Last time the connection was reserved.
Definition pool.c:57
fr_heap_t * heap
For the next connection heap.
Definition pool.c:113
fr_time_delta_t held_trigger_min
If a connection is held for less than the specified period, fire a trigger.
Definition pool.c:138
fr_pool_connection_create_t create
Function used to create new connections.
Definition pool.c:143
uint32_t start
Number of initial connections.
Definition pool.c:88
fr_time_delta_t idle_timeout
How long a connection can be idle before being closed.
Definition pool.c:105
static void connection_unlink(fr_pool_t *pool, fr_pool_connection_t *this)
Removes a connection from the connection list.
Definition pool.c:205
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:643
static fr_cmp_ret_t last_reserved_cmp(void const *one, void const *two)
Order connections by reserved most recently.
Definition pool.c:182
void fr_pool_connection_release(fr_pool_t *pool, request_t *request, void *conn)
Release a connection.
Definition pool.c:1382
uint32_t min
Minimum number of concurrent connections to keep open.
Definition pool.c:89
static fr_cmp_ret_t last_released_cmp(void const *one, void const *two)
Order connections by released longest ago.
Definition pool.c:191
fr_heap_index_t heap_id
For the next connection heap.
Definition pool.c:54
uint64_t number
Unique ID assigned when the connection is created, these will monotonically increase over the lifetim...
Definition pool.c:62
CONF_SECTION const * cs
Configuration section holding the section of parsed config file that relates to this pool.
Definition pool.c:125
void fr_pool_free(fr_pool_t *pool)
Delete a connection pool.
Definition pool.c:1304
static fr_pool_connection_t * connection_find(fr_pool_t *pool, void *conn)
Find a connection handle in the connection list.
Definition pool.c:285
fr_pool_state_t const * fr_pool_state(fr_pool_t *pool)
Get the number of connections currently in the pool.
Definition pool.c:1145
static void fr_pool_trigger(fr_pool_t *pool, char const *event)
Send a connection pool trigger.
Definition pool.c:259
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:1184
uint32_t pending_window
Sliding window of pending connections.
Definition pool.c:95
static void connection_close_internal(fr_pool_t *pool, fr_pool_connection_t *this)
Close an existing connection.
Definition pool.c:535
char const * trigger_prefix
Prefix to prepend to names of all triggers fired by the connection pool code.
Definition pool.c:134
fr_time_delta_t cleanup_interval
Initial timer for how often we sweep the pool for free connections.
Definition pool.c:98
void * connection
Pointer to whatever the module uses for a connection handle.
Definition pool.c:65
int fr_pool_reconnect(fr_pool_t *pool, request_t *request)
Mark connections for reconnection, and spawn at least 'start' connections.
Definition pool.c:1216
fr_pool_connection_t * tail
End of the connection list.
Definition pool.c:116
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:943
bool needs_reconnecting
Reconnect this connection before use.
Definition pool.c:69
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:1128
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:583
fr_time_delta_t held_trigger_max
If a connection is held for longer than the specified period, fire a trigger.
Definition pool.c:140
fr_pool_connection_alive_t alive
Function used to check status of connections.
Definition pool.c:144
uint32_t num_uses
Number of times the connection has been reserved.
Definition pool.c:61
bool triggers_enabled
Whether we call the trigger functions.
Definition pool.c:132
fr_time_delta_t connect_timeout
New connection timeout, enforced by the create callback.
Definition pool.c:107
static fr_pool_connection_t * connection_spawn(fr_pool_t *pool, request_t *request, fr_time_t now, bool in_use)
Spawns a new connection.
Definition pool.c:328
int fr_pool_connection_close(fr_pool_t *pool, request_t *request, void *conn)
Delete a connection from the connection pool.
Definition pool.c:1521
uint32_t spare
Number of spare connections to try.
Definition pool.c:92
uint64_t max_uses
Maximum number of times a connection can be used before being closed.
Definition pool.c:93
void * fr_pool_connection_get(fr_pool_t *pool, request_t *request)
Reserve a connection in the connection pool.
Definition pool.c:1367
void const * fr_pool_opaque(fr_pool_t *pool)
Return the opaque data associated with a connection pool.
Definition pool.c:1175
pthread_cond_t done_reconnecting
Before calling the create callback, threads should block on this condition if reconnecting == true.
Definition pool.c:122
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:103
pthread_mutex_t mutex
Mutex used to keep consistent state when making modifications in threaded mode.
Definition pool.c:118
uint32_t max
Maximum number of concurrent connections to allow.
Definition pool.c:90
fr_pool_connection_t * head
Start of the connection list.
Definition pool.c:115
int ref
Reference counter to prevent connection pool being freed multiple times.
Definition pool.c:86
int fr_pool_start_num(fr_pool_t *pool)
Connection pool get start.
Definition pool.c:1165
fr_pool_state_t state
Stats and state of the connection pool.
Definition pool.c:148
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:909
fr_pair_list_t trigger_args
Arguments to make available in connection pool triggers.
Definition pool.c:136
fr_time_t created
Time connection was created.
Definition pool.c:56
bool in_use
Whether the connection is currently reserved.
Definition pool.c:67
fr_time_delta_t retry_delay
seconds to delay re-open after a failed open.
Definition pool.c:97
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:120
static void * connection_get_internal(fr_pool_t *pool, request_t *request, bool spawn)
Get a connection from the connection pool.
Definition pool.c:810
fr_pool_connection_t * prev
Previous connection in list.
Definition pool.c:52
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:1196
static const conf_parser_t pool_config[]
Definition pool.c:151
fr_pool_connection_t * next
Next connection in list.
Definition pool.c:53
void * opaque
Pointer to context data that will be passed to callbacks.
Definition pool.c:127
fr_time_t last_released
Time the connection was released.
Definition pool.c:59
void * fr_pool_connection_reconnect(fr_pool_t *pool, request_t *request, void *conn)
Reconnect a suspected inviable connection.
Definition pool.c:1482
char const * log_prefix
Log prefix to prepend to all log messages created by the connection pool code.
Definition pool.c:129
An individual connection within the connection pool.
Definition pool.c:51
A connection pool.
Definition pool.c:85
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:37
#define RDEBUG2(fmt,...)
#define DEBUG2(fmt,...)
#define WARN(fmt,...)
static bool done
Definition radclient.c:80
#define INFO(fmt,...)
Definition radict.c:67
static char const * name
PUBLIC int snprintf(char *string, size_t length, char *format, va_alist)
Definition snprintf.c:689
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:168
static int talloc_const_free(void const *ptr)
Free const'd memory.
Definition talloc.h:289
#define talloc_asprintf
Definition talloc.h:151
#define talloc_strdup(_ctx, _str)
Definition talloc.h:149
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
static fr_cmp_ret_t fr_time_cmp(fr_time_t a, fr_time_t b)
Compare two fr_time_t values.
Definition time.h:916
#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
A time delta, a difference in time measured in nanoseconds.
Definition time.h:80
"server local" time.
Definition time.h:69
@ T_BARE_WORD
Definition token.h:118
@ T_OP_EQ
Definition token.h:81
enum fr_token fr_token_t
int trigger(unlang_interpret_t *intp, CONF_SECTION const *cs, CONF_PAIR **trigger_cp, char const *name, bool rate_limit, fr_pair_list_t *args, void const *uctx)
Execute a trigger - call an executable to process an event.
Definition trigger.c:160
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:864
static fr_sbuff_err_t char size_t fr_sbuff_t size_t max
Definition value.h:1061
static fr_sbuff_err_t char ** out
Definition value.h:1061
#define fr_box_time_delta(_val)
Definition value.h:397