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