1 /*
2 BAREOS® - Backup Archiving REcovery Open Sourced
3
4 Copyright (C) 2010-2012 Free Software Foundation Europe e.V.
5 Copyright (C) 2011-2016 Planets Communications B.V.
6 Copyright (C) 2013-2016 Bareos GmbH & Co. KG
7
8 This program is Free Software; you can redistribute it and/or
9 modify it under the terms of version three of the GNU Affero General Public
10 License as published by the Free Software Foundation and included
11 in the file LICENSE.
12
13 This program is distributed in the hope that it will be useful, but
14 WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 Affero General Public License for more details.
17
18 You should have received a copy of the GNU Affero General Public License
19 along with this program; if not, write to the Free Software
20 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
21 02110-1301, USA.
22 */
23 /*
24 * Written by Marco van Wieringen, March 2010
25 */
26 /**
27 * @file
28 * BAREOS sql pooling code that manages the database connection pools.
29 */
30
31 #include "include/bareos.h"
32
33 #if HAVE_SQLITE3 || HAVE_MYSQL || HAVE_POSTGRESQL || HAVE_INGRES || HAVE_DBI
34
35 #include "cats.h"
36 #include "cats_backends.h"
37
38 /**
39 * Get a non-pooled connection used when either sql pooling is
40 * runtime disabled or at compile time. Or when we run out of
41 * pooled connections and need more database connections.
42 */
DbSqlGetNonPooledConnection(JobControlRecord * jcr,const char * db_drivername,const char * db_name,const char * db_user,const char * db_password,const char * db_address,int db_port,const char * db_socket,bool mult_db_connections,bool disable_batch_insert,bool try_reconnect,bool exit_on_fatal,bool need_private)43 BareosDb *DbSqlGetNonPooledConnection(JobControlRecord *jcr,
44 const char *db_drivername,
45 const char *db_name,
46 const char *db_user,
47 const char *db_password,
48 const char *db_address,
49 int db_port,
50 const char *db_socket,
51 bool mult_db_connections,
52 bool disable_batch_insert,
53 bool try_reconnect,
54 bool exit_on_fatal,
55 bool need_private)
56 {
57 BareosDb *mdb;
58
59 #if defined(HAVE_DYNAMIC_CATS_BACKENDS)
60 Dmsg2(100, "DbSqlGetNonPooledConnection allocating 1 new non pooled database connection to database %s, backend type %s\n",
61 db_name, db_drivername);
62 #else
63 Dmsg1(100, "DbSqlGetNonPooledConnection allocating 1 new non pooled database connection to database %s\n",
64 db_name);
65 #endif
66 mdb = db_init_database(jcr,
67 db_drivername,
68 db_name,
69 db_user,
70 db_password,
71 db_address,
72 db_port,
73 db_socket,
74 mult_db_connections,
75 disable_batch_insert,
76 try_reconnect,
77 exit_on_fatal,
78 need_private);
79 if (mdb == NULL) {
80 return NULL;
81 }
82
83 if (!mdb->OpenDatabase(jcr)) {
84 Jmsg(jcr, M_FATAL, 0, "%s", mdb->strerror());
85 mdb->CloseDatabase(jcr);
86 return NULL;
87 }
88
89 return mdb;
90 }
91
92 #ifdef HAVE_SQL_POOLING
93
94 static dlist *db_pooling_descriptors = NULL;
95
96 static pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
97
DestroyPoolDescriptor(SqlPoolDescriptor * spd,bool flush_only)98 static void DestroyPoolDescriptor(SqlPoolDescriptor *spd, bool flush_only)
99 {
100 SqlPoolEntry *spe, *spe_next;
101
102 spe = (SqlPoolEntry *)spd->pool_entries->first();
103 while (spe) {
104 spe_next = (SqlPoolEntry *)spd->pool_entries->get_next(spe);
105 if (!flush_only || spe->reference_count == 0) {
106 Dmsg3(100, "DbSqlPoolDestroy destroy db pool connection %d to %s, backend type %s\n",
107 spe->id, spe->db_handle->get_db_name(), spe->db_handle->GetType());
108 spe->db_handle->CloseDatabase(NULL);
109 if (flush_only) {
110 spd->pool_entries->remove(spe);
111 free(spe);
112 }
113 spd->nr_connections--;
114 }
115 spe = spe_next;
116 }
117
118 /*
119 * See if there is anything left on this pool and we are flushing the pool.
120 */
121 if (flush_only && spd->nr_connections == 0) {
122 db_pooling_descriptors->remove(spd);
123 delete spd->pool_entries;
124 free(spd);
125 }
126 }
127
128 /**
129 * Initialize the sql connection pool.
130 */
db_sql_pool_initialize(const char * db_drivername,const char * db_name,const char * db_user,const char * db_password,const char * db_address,int db_port,const char * db_socket,bool disable_batch_insert,bool try_reconnect,bool exit_on_fatal,int min_connections,int max_connections,int increment_connections,int idle_timeout,int validate_timeout)131 bool db_sql_pool_initialize(const char *db_drivername,
132 const char *db_name,
133 const char *db_user,
134 const char *db_password,
135 const char *db_address,
136 int db_port,
137 const char *db_socket,
138 bool disable_batch_insert,
139 bool try_reconnect,
140 bool exit_on_fatal,
141 int min_connections,
142 int max_connections,
143 int increment_connections,
144 int idle_timeout,
145 int validate_timeout)
146 {
147 int cnt;
148 BareosDb *mdb;
149 time_t now;
150 SqlPoolDescriptor *spd = NULL;
151 SqlPoolEntry *spe = NULL;
152 bool retval = false;
153
154 /*
155 * See if pooling is runtime disabled.
156 */
157 if (max_connections == 0) {
158 Dmsg0(100, "db_sql_pool_initialize pooling disabled as max_connections == 0\n");
159 return true;
160 }
161
162 /*
163 * First make sure the values make any sense.
164 */
165 if (min_connections <= 0 ||
166 max_connections <= 0 ||
167 increment_connections <= 0 ||
168 min_connections > max_connections) {
169 Jmsg(NULL, M_FATAL, 0,
170 _("Illegal values for sql pool initialization, min_connections = %d, max_connections = %d, increment_connections = %d"),
171 min_connections, max_connections, increment_connections);
172 return false;
173 }
174
175 P(mutex);
176 time(&now);
177
178 if (db_pooling_descriptors == NULL) {
179 db_pooling_descriptors = New(dlist(spd, &spd->link));
180 }
181
182 /*
183 * Create a new pool descriptor.
184 */
185 spd = (SqlPoolDescriptor *)malloc(sizeof(SqlPoolDescriptor));
186 memset(spd, 0, sizeof(SqlPoolDescriptor));
187 spd->pool_entries = New(dlist(spe, &spe->link));
188 spd->min_connections = min_connections;
189 spd->max_connections = max_connections;
190 spd->increment_connections = increment_connections;
191 spd->idle_timeout = idle_timeout;
192 spd->validate_timeout = validate_timeout;
193 spd->last_update = now;
194 spd->active = true;
195
196 /*
197 * Create a number of database connections.
198 */
199 for (cnt = 0; cnt < min_connections; cnt++) {
200 mdb = db_init_database(NULL,
201 db_drivername,
202 db_name,
203 db_user,
204 db_password,
205 db_address,
206 db_port,
207 db_socket,
208 true,
209 disable_batch_insert,
210 try_reconnect,
211 exit_on_fatal);
212 if (mdb == NULL) {
213 Jmsg(NULL, M_FATAL, 0, "%s", _("Could not init database connection"));
214 goto bail_out;
215 }
216
217 if (!mdb->OpenDatabase(NULL)) {
218 Jmsg(NULL, M_FATAL, 0, "%s", mdb->strerror());
219 mdb->CloseDatabase(NULL);
220 goto bail_out;
221 }
222
223 /*
224 * Push this new connection onto the connection pool.
225 */
226 spe = (SqlPoolEntry *)malloc(sizeof(SqlPoolEntry));
227 memset(spe, 0, sizeof(SqlPoolEntry));
228 spe->id = spd->nr_connections++;
229 spe->last_update = now;
230 spe->db_handle = mdb;
231 spd->pool_entries->append(spe);
232 spe = NULL;
233 }
234
235 #if defined(HAVE_DYNAMIC_CATS_BACKENDS)
236 Dmsg3(100, "db_sql_pool_initialize created %d connections to database %s, backend type %s\n",
237 cnt, db_name, db_drivername);
238 #else
239 Dmsg2(100, "db_sql_pool_initialize created %d connections to database %s\n",
240 cnt, db_name);
241 #endif
242 db_pooling_descriptors->append(spd);
243 retval = true;
244 goto ok_out;
245
246 bail_out:
247 if (spe) {
248 free(spe);
249 }
250
251 if (spd) {
252 DestroyPoolDescriptor(spd, false);
253 }
254
255 ok_out:
256 V(mutex);
257 return retval;
258 }
259
260 /**
261 * Cleanup the sql connection pools.
262 * This gets called on shutdown.
263 */
DbSqlPoolDestroy(void)264 void DbSqlPoolDestroy(void)
265 {
266 SqlPoolDescriptor *spd, *spd_next;
267
268 /*
269 * See if pooling is enabled.
270 */
271 if (!db_pooling_descriptors) {
272 return;
273 }
274
275 P(mutex);
276 spd = (SqlPoolDescriptor *)db_pooling_descriptors->first();
277 while (spd) {
278 spd_next = (SqlPoolDescriptor *)db_pooling_descriptors->get_next(spd);
279 DestroyPoolDescriptor(spd, false);
280 spd = spd_next;
281 }
282 delete db_pooling_descriptors;
283 db_pooling_descriptors = NULL;
284 V(mutex);
285 }
286
287 /**
288 * Flush the sql connection pools.
289 * This gets called on config reload. We close all unreferenced connections.
290 */
DbSqlPoolFlush(void)291 void DbSqlPoolFlush(void)
292 {
293 SqlPoolEntry *spe;
294 SqlPoolDescriptor *spd, *spd_next;
295
296 /*
297 * See if pooling is enabled.
298 */
299 if (!db_pooling_descriptors) {
300 return;
301 }
302
303 P(mutex);
304 spd = (SqlPoolDescriptor *)db_pooling_descriptors->first();
305 while (spd) {
306 spd_next = (SqlPoolDescriptor *)db_pooling_descriptors->get_next(spd);
307 if (spd->active) {
308 /*
309 * On a flush all current available pools are invalidated.
310 */
311 spd->active = false;
312 DestroyPoolDescriptor(spd, true);
313 }
314 spd = spd_next;
315 }
316 V(mutex);
317 }
318
319 /**
320 * Grow the sql connection pool.
321 * This function should be called with the mutex held.
322 */
SqlPoolGrow(SqlPoolDescriptor * spd)323 static inline void SqlPoolGrow(SqlPoolDescriptor *spd)
324 {
325 int cnt, next_id;
326 BareosDb *mdb;
327 time_t now;
328 SqlPoolEntry *spe;
329 BareosDb *db_handle;
330
331 /*
332 * Get the first entry from the list to be able to clone it.
333 * If the pool is empty its not initialized ok so we cannot really
334 * grow its size.
335 */
336 spe = (SqlPoolEntry *)spd->pool_entries->first();
337 if (spe != NULL) {
338 /*
339 * Save the handle of the first entry so we can clone it later on.
340 */
341 db_handle = spe->db_handle;
342
343 /*
344 * Now that the pool is about to be grown give each entry a new id.
345 */
346 cnt = 0;
347 foreach_dlist(spe, spd->pool_entries) {
348 spe->id = cnt++;
349 }
350
351 /*
352 * Remember the next available id to use.
353 */
354 next_id = cnt;
355
356 /*
357 * Create a number of database connections.
358 */
359 time(&now);
360 for (cnt = 0; cnt < spd->increment_connections; cnt++) {
361 /*
362 * Get a new non-pooled connection to the database.
363 * We want to add a non pooled connection to the pool as otherwise
364 * we are creating a deadlock as CloneDatabaseConnection will
365 * call sql_pool_get_connection which means a recursive enter into
366 * the pooling code and as such the mutex will deadlock.
367 */
368 mdb = db_handle->CloneDatabaseConnection(NULL, true, false);
369 if (mdb == NULL) {
370 Jmsg(NULL, M_FATAL, 0, "%s", _("Could not init database connection"));
371 break;
372 }
373
374 /*
375 * Push this new connection onto the connection pool.
376 */
377 spe = (SqlPoolEntry *)malloc(sizeof(SqlPoolEntry));
378 memset(spe, 0, sizeof(SqlPoolEntry));
379 spe->id = next_id++;
380 spe->last_update = now;
381 spe->db_handle = mdb;
382 spd->pool_entries->append(spe);
383 }
384 Dmsg3(100, "SqlPoolGrow created %d connections to database %s, backend type %s\n",
385 cnt, spe->db_handle->get_db_name(), spe->db_handle->GetType());
386 spd->last_update = now;
387 } else {
388 Dmsg0(100, "SqlPoolGrow unable to determine first entry on pool list\n");
389 }
390 }
391
392 /**
393 * Shrink the sql connection pool.
394 * This function should be called with the mutex held.
395 */
SqlPoolShrink(SqlPoolDescriptor * spd)396 static inline void SqlPoolShrink(SqlPoolDescriptor *spd)
397 {
398 int cnt;
399 time_t now;
400 SqlPoolEntry *spe, *spe_next;
401
402 time(&now);
403 spd->last_update = now;
404
405 /*
406 * See if we want to shrink.
407 */
408 if (spd->min_connections && spd->nr_connections <= spd->min_connections) {
409 Dmsg0(100, "SqlPoolShrink cannot shrink connection pool already minimum size\n");
410 return;
411 }
412
413 /*
414 * See how much we should shrink.
415 * No need to shrink under min_connections, and when things are greater
416 * shrink with increment_connections per shrink run.
417 */
418 cnt = spd->nr_connections - spd->min_connections;
419 if (cnt > spd->increment_connections) {
420 cnt = spd->increment_connections;
421 }
422
423 /*
424 * Sanity check.
425 */
426 if (cnt <= 0) {
427 return;
428 }
429
430 /*
431 * For debugging purposes get the first entry on the connection pool.
432 */
433 spe = (SqlPoolEntry *)spd->pool_entries->first();
434 if (spe) {
435 Dmsg3(100, "SqlPoolShrink shrinking connection pool with %d connections to database %s, backend type %s\n",
436 cnt, spe->db_handle->get_db_name(), spe->db_handle->GetType());
437 }
438
439 /*
440 * Loop over all entries on the pool and see if the can be removed.
441 */
442 spe = (SqlPoolEntry *)spd->pool_entries->first();
443 while (spe) {
444 spe_next = (SqlPoolEntry *)spd->pool_entries->get_next(spe);
445
446 /*
447 * See if this is a unreferenced connection.
448 * And its been idle for more then idle_timeout seconds.
449 */
450 if (spe->reference_count == 0 && ((now - spe->last_update) >= spd->idle_timeout)) {
451 spd->pool_entries->remove(spe);
452 spe->db_handle->CloseDatabase(NULL);
453 free(spe);
454 spd->nr_connections--;
455 cnt--;
456 /*
457 * See if we have freed enough.
458 */
459 if (cnt <= 0) {
460 break;
461 }
462 }
463
464 spe = spe_next;
465 }
466
467 /*
468 * Now that the pool has shrunk give each entry a new id.
469 */
470 cnt = 0;
471 foreach_dlist(spe, spd->pool_entries) {
472 spe->id = cnt++;
473 }
474 }
475
476 /**
477 * Find the connection pool with the correct connections.
478 * This function should be called with the mutex held.
479 */
sql_find_pool_descriptor(const char * db_drivername,const char * db_name,const char * db_address,int db_port)480 static inline SqlPoolDescriptor *sql_find_pool_descriptor(const char *db_drivername,
481 const char *db_name,
482 const char *db_address,
483 int db_port)
484 {
485 SqlPoolDescriptor *spd;
486 SqlPoolEntry *spe;
487
488 foreach_dlist(spd, db_pooling_descriptors) {
489 if (spd->active) {
490 foreach_dlist(spe, spd->pool_entries) {
491 if (spe->db_handle->MatchDatabase(db_drivername, db_name, db_address, db_port)) {
492 return spd;
493 }
494 }
495 }
496 }
497 return NULL;
498 }
499
500 /**
501 * Find a free connection in a certain connection pool.
502 * This function should be called with the mutex held.
503 */
sql_find_free_connection(SqlPoolDescriptor * spd)504 static inline SqlPoolEntry *sql_find_free_connection(SqlPoolDescriptor *spd)
505 {
506 SqlPoolEntry *spe;
507
508 foreach_dlist(spe, spd->pool_entries) {
509 if (spe->reference_count == 0) {
510 return spe;
511 }
512 }
513 return NULL;
514 }
515
516 /**
517 * Find a connection in a certain connection pool.
518 * This function should be called with the mutex held.
519 */
sql_find_first_connection(SqlPoolDescriptor * spd)520 static inline SqlPoolEntry *sql_find_first_connection(SqlPoolDescriptor *spd)
521 {
522 SqlPoolEntry *spe;
523
524 foreach_dlist(spe, spd->pool_entries) {
525 return spe;
526 }
527 return NULL;
528 }
529
530 /**
531 * Get a new connection from the pool.
532 */
DbSqlGetPooledConnection(JobControlRecord * jcr,const char * db_drivername,const char * db_name,const char * db_user,const char * db_password,const char * db_address,int db_port,const char * db_socket,bool mult_db_connections,bool disable_batch_insert,bool try_reconnect,bool exit_on_fatal,bool need_private)533 BareosDb *DbSqlGetPooledConnection(JobControlRecord *jcr,
534 const char *db_drivername,
535 const char *db_name,
536 const char *db_user,
537 const char *db_password,
538 const char *db_address,
539 int db_port,
540 const char *db_socket,
541 bool mult_db_connections,
542 bool disable_batch_insert,
543 bool try_reconnect,
544 bool exit_on_fatal,
545 bool need_private)
546 {
547 int cnt = 0;
548 SqlPoolDescriptor *wanted_pool;
549 SqlPoolEntry *use_connection = NULL;
550 BareosDb *db_handle = NULL;
551 time_t now;
552
553 now = time(NULL);
554 #if defined(HAVE_DYNAMIC_CATS_BACKENDS)
555 Dmsg2(100, "DbSqlGetPooledConnection get new connection for connection to database %s, backend type %s\n",
556 db_name, db_drivername);
557 #else
558 Dmsg1(100, "DbSqlGetPooledConnection get new connection for connection to database %s\n",
559 db_name);
560 #endif
561
562 /*
563 * See if pooling is enabled.
564 */
565 if (!db_pooling_descriptors) {
566 return DbSqlGetNonPooledConnection(jcr,
567 db_drivername,
568 db_name,
569 db_user,
570 db_password,
571 db_address,
572 db_port,
573 db_socket,
574 mult_db_connections,
575 disable_batch_insert,
576 try_reconnect,
577 exit_on_fatal,
578 need_private);
579 }
580
581 P(mutex);
582 /*
583 * Try to lookup the pool.
584 */
585 wanted_pool = sql_find_pool_descriptor(db_drivername, db_name, db_address, db_port);
586 if (wanted_pool) {
587 /*
588 * Loop while trying to find a connection.
589 */
590 while (1) {
591 /*
592 * If we can return a shared connection and when need_private is not
593 * explicitly set try to match an existing connection. Otherwise we
594 * want a free connection.
595 */
596 if (!mult_db_connections && !need_private) {
597 use_connection = sql_find_first_connection(wanted_pool);
598 } else {
599 use_connection = sql_find_free_connection(wanted_pool);
600 }
601 if (use_connection) {
602 /*
603 * See if the connection match needs validation.
604 */
605 if ((now - use_connection->last_update) >= wanted_pool->validate_timeout) {
606 if (!use_connection->db_handle->ValidateConnection()) {
607 /*
608 * Connection seems to be dead kill it from the pool.
609 */
610 wanted_pool->pool_entries->remove(use_connection);
611 use_connection->db_handle->CloseDatabase(jcr);
612 free(use_connection);
613 wanted_pool->nr_connections--;
614 continue;
615 }
616 }
617 goto ok_out;
618 } else {
619 if (mult_db_connections || need_private) {
620 /*
621 * Cannot find an already open connection that is unused.
622 * See if there is still room to grow the pool if not this is it.
623 * We just give back a non pooled connection which gets a proper cleanup
624 * anyhow when it discarded using DbSqlClosePooledConnection.
625 */
626 if (wanted_pool->nr_connections >= wanted_pool->max_connections) {
627 db_handle = DbSqlGetNonPooledConnection(jcr,
628 db_drivername,
629 db_name,
630 db_user,
631 db_password,
632 db_address,
633 db_port,
634 db_socket,
635 mult_db_connections,
636 disable_batch_insert,
637 try_reconnect,
638 exit_on_fatal,
639 need_private);
640 goto bail_out;
641 }
642
643 Dmsg0(100, "DbSqlGetPooledConnection trying to grow connection pool for getting free connection\n");
644 SqlPoolGrow(wanted_pool);
645 } else {
646 /*
647 * Request for a shared connection and no connection gets through the validation.
648 * e.g. all connections in the pool have failed.
649 * This should never happen so lets abort things and let the upper layer handle this.
650 */
651 goto bail_out;
652 }
653 }
654 }
655 } else {
656 /*
657 * Pooling not enabled for this connection use non pooling.
658 */
659 db_handle = DbSqlGetNonPooledConnection(jcr,
660 db_drivername,
661 db_name,
662 db_user,
663 db_password,
664 db_address,
665 db_port,
666 db_socket,
667 mult_db_connections,
668 disable_batch_insert,
669 try_reconnect,
670 exit_on_fatal,
671 need_private);
672 goto bail_out;
673 }
674
675 ok_out:
676 use_connection->reference_count++;
677 use_connection->last_update = now;
678 db_handle = use_connection->db_handle;
679
680 /*
681 * Set the IsPrivate flag of this database connection to the wanted state.
682 */
683 db_handle->SetPrivate(need_private);
684
685 bail_out:
686 V(mutex);
687 return db_handle;
688 }
689
690 /**
691 * Put a connection back onto the pool for reuse.
692 *
693 * The abort flag is set when we encounter a dead or misbehaving connection
694 * which needs to be closed right away and should not be reused.
695 */
DbSqlClosePooledConnection(JobControlRecord * jcr,BareosDb * mdb,bool abort)696 void DbSqlClosePooledConnection(JobControlRecord *jcr, BareosDb *mdb, bool abort)
697 {
698 SqlPoolEntry *spe, *spe_next;
699 SqlPoolDescriptor *spd, *spd_next;
700 bool found = false;
701 time_t now;
702
703 /*
704 * See if pooling is enabled.
705 */
706 if (!db_pooling_descriptors) {
707 mdb->CloseDatabase(jcr);
708 return;
709 }
710
711 P(mutex);
712
713 /*
714 * See what connection is freed.
715 */
716 now = time(NULL);
717
718 spd = (SqlPoolDescriptor *)db_pooling_descriptors->first();
719 while (spd) {
720 spd_next = (SqlPoolDescriptor *)db_pooling_descriptors->get_next(spd);
721
722 if (!spd->pool_entries) {
723 spd = spd_next;
724 continue;
725 }
726
727 spe = (SqlPoolEntry *)spd->pool_entries->first();
728 while (spe) {
729 spe_next = (SqlPoolEntry *)spd->pool_entries->get_next(spe);
730
731 if (spe->db_handle == mdb) {
732 found = true;
733 if (!abort) {
734 /*
735 * End any active transactions.
736 */
737 mdb->EndTransaction(jcr);
738
739 /*
740 * Decrement reference count and update last update field.
741 */
742 spe->reference_count--;
743 time(&spe->last_update);
744
745 Dmsg3(100, "DbSqlClosePooledConnection decrementing reference count of connection %d now %d, backend type %s\n",
746 spe->id, spe->reference_count, spe->db_handle->GetType());
747
748 /*
749 * Clear the IsPrivate flag if this is a free connection again.
750 */
751 if (spe->reference_count == 0) {
752 mdb->SetPrivate(false);
753 }
754
755 /*
756 * See if this is a free on an inactive pool and this was the last reference.
757 */
758 if (!spd->active && spe->reference_count == 0) {
759 spd->pool_entries->remove(spe);
760 spe->db_handle->CloseDatabase(jcr);
761 free(spe);
762 spd->nr_connections--;
763 }
764 } else {
765 Dmsg3(100, "DbSqlClosePooledConnection aborting connection to database %s reference count %d, backend type %s\n",
766 spe->db_handle->get_db_name(), spe->reference_count, spe->db_handle->GetType());
767 spd->pool_entries->remove(spe);
768 spe->db_handle->CloseDatabase(jcr);
769 free(spe);
770 spd->nr_connections--;
771 }
772
773 /*
774 * No need to search further if we found the item we were looking for.
775 */
776 break;
777 }
778
779 spe = spe_next;
780 }
781
782 /*
783 * See if this is an inactive pool and it has no connections on it anymore.
784 */
785 if (!spd->active && spd->nr_connections == 0) {
786 db_pooling_descriptors->remove(spd);
787 delete spd->pool_entries;
788 free(spd);
789 } else {
790 /*
791 * See if we can shrink the connection pool.
792 * Only try to shrink when the last update on the pool was more than the validate time ago.
793 */
794 if ((now - spd->last_update) >= spd->validate_timeout) {
795 Dmsg0(100, "DbSqlClosePooledConnection trying to shrink connection pool\n");
796 SqlPoolShrink(spd);
797 }
798 }
799
800 /*
801 * No need to search further if we found the item we were looking for.
802 */
803 if (found) {
804 break;
805 }
806
807 spd = spd_next;
808 }
809
810 /*
811 * If we didn't find this mdb on any pooling chain we are not pooling
812 * this connection and we just close the connection.
813 */
814 if (!found) {
815 mdb->CloseDatabase(jcr);
816 }
817
818 V(mutex);
819 }
820
821 #else /* HAVE_SQL_POOLING */
822
823 /**
824 * Initialize the sql connection pool.
825 * For non pooling this is a no-op.
826 */
db_sql_pool_initialize(const char * db_drivername,const char * db_name,const char * db_user,const char * db_password,const char * db_address,int db_port,const char * db_socket,bool disable_batch_insert,bool try_reconnect,bool exit_on_fatal,int min_connections,int max_connections,int increment_connections,int idle_timeout,int validate_timeout)827 bool db_sql_pool_initialize(const char *db_drivername,
828 const char *db_name,
829 const char *db_user,
830 const char *db_password,
831 const char *db_address,
832 int db_port,
833 const char *db_socket,
834 bool disable_batch_insert,
835 bool try_reconnect,
836 bool exit_on_fatal,
837 int min_connections,
838 int max_connections,
839 int increment_connections,
840 int idle_timeout,
841 int validate_timeout)
842 {
843 return true;
844 }
845
846 /**
847 * Cleanup the sql connection pools.
848 * For non pooling this is a no-op.
849 */
DbSqlPoolDestroy(void)850 void DbSqlPoolDestroy(void)
851 {
852 }
853
854 /**
855 * Flush the sql connection pools.
856 * For non pooling this is a no-op.
857 */
DbSqlPoolFlush(void)858 void DbSqlPoolFlush(void)
859 {
860 }
861
862 /**
863 * Get a new connection from the pool.
864 * For non pooling we just call DbSqlGetNonPooledConnection.
865 */
DbSqlGetPooledConnection(JobControlRecord * jcr,const char * db_drivername,const char * db_name,const char * db_user,const char * db_password,const char * db_address,int db_port,const char * db_socket,bool mult_db_connections,bool disable_batch_insert,bool try_reconnect,bool exit_on_fatal,bool need_private)866 BareosDb *DbSqlGetPooledConnection(JobControlRecord *jcr,
867 const char *db_drivername,
868 const char *db_name,
869 const char *db_user,
870 const char *db_password,
871 const char *db_address,
872 int db_port,
873 const char *db_socket,
874 bool mult_db_connections,
875 bool disable_batch_insert,
876 bool try_reconnect,
877 bool exit_on_fatal,
878 bool need_private)
879 {
880 return DbSqlGetNonPooledConnection(jcr,
881 db_drivername,
882 db_name,
883 db_user,
884 db_password,
885 db_address,
886 db_port,
887 db_socket,
888 mult_db_connections,
889 disable_batch_insert,
890 try_reconnect,
891 exit_on_fatal,
892 need_private);
893 }
894
895 /**
896 * Put a connection back onto the pool for reuse.
897 * For non pooling we just do a CloseDatabase.
898 */
DbSqlClosePooledConnection(JobControlRecord * jcr,BareosDb * mdb,bool abort)899 void DbSqlClosePooledConnection(JobControlRecord *jcr, BareosDb *mdb, bool abort)
900 {
901 mdb->CloseDatabase(jcr);
902 }
903
904 #endif /* HAVE_SQL_POOLING */
905 #endif /* HAVE_SQLITE3 || HAVE_MYSQL || HAVE_POSTGRESQL || HAVE_INGRES || HAVE_DBI */
906