Kannel: Open Source WAP and SMS gateway  $Revision: 5037 $
dbpool.c
Go to the documentation of this file.
1 /* ====================================================================
2  * The Kannel Software License, Version 1.0
3  *
4  * Copyright (c) 2001-2016 Kannel Group
5  * Copyright (c) 1998-2001 WapIT Ltd.
6  * All rights reserved.
7  *
8  * Redistribution and use in source and binary forms, with or without
9  * modification, are permitted provided that the following conditions
10  * are met:
11  *
12  * 1. Redistributions of source code must retain the above copyright
13  * notice, this list of conditions and the following disclaimer.
14  *
15  * 2. Redistributions in binary form must reproduce the above copyright
16  * notice, this list of conditions and the following disclaimer in
17  * the documentation and/or other materials provided with the
18  * distribution.
19  *
20  * 3. The end-user documentation included with the redistribution,
21  * if any, must include the following acknowledgment:
22  * "This product includes software developed by the
23  * Kannel Group (http://www.kannel.org/)."
24  * Alternately, this acknowledgment may appear in the software itself,
25  * if and wherever such third-party acknowledgments normally appear.
26  *
27  * 4. The names "Kannel" and "Kannel Group" must not be used to
28  * endorse or promote products derived from this software without
29  * prior written permission. For written permission, please
30  * contact org@kannel.org.
31  *
32  * 5. Products derived from this software may not be called "Kannel",
33  * nor may "Kannel" appear in their name, without prior written
34  * permission of the Kannel Group.
35  *
36  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
37  * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
38  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
39  * DISCLAIMED. IN NO EVENT SHALL THE KANNEL GROUP OR ITS CONTRIBUTORS
40  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
41  * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
42  * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
43  * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
44  * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
45  * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
46  * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
47  * ====================================================================
48  *
49  * This software consists of voluntary contributions made by many
50  * individuals on behalf of the Kannel Group. For more information on
51  * the Kannel Group, please see <http://www.kannel.org/>.
52  *
53  * Portions of this software are based upon software originally written at
54  * WapIT Ltd., Helsinki, Finland for the Kannel project.
55  */
56 
57 /*
58  * dbpool.c - implement generic database connection pool
59  *
60  * Stipe Tolj <stolj@wapme.de>
61  * 2003 Initial version.
62  * Alexander Malysh <a.malysh@centrium.de>
63  * 2003 Made dbpool more generic.
64  * Robert Gałach <robert.galach@my.tenbit.pl>
65  * 2004 Added support for binding variables.
66  * Alejandro Guerrieri <aguerrieri at kannel dot org>
67  * 2009 Added support for MS-SQL using FreeTDS
68  */
69 
70 #include "gwlib.h"
71 #include "dbpool.h"
72 #include "dbpool_p.h"
73 
74 #ifdef HAVE_DBPOOL
75 
76 #include "dbpool_mysql.c"
77 #include "dbpool_oracle.c"
78 #include "dbpool_sqlite.c"
79 #include "dbpool_sqlite3.c"
80 #include "dbpool_sdb.c"
81 #include "dbpool_pgsql.c"
82 #include "dbpool_mssql.c"
83 #include "dbpool_redis.c"
84 #include "dbpool_cass.c"
85 
86 
87 static void dbpool_conn_destroy(DBPoolConn *conn)
88 {
89  gw_assert(conn != NULL);
90 
91  if (conn->conn != NULL)
92  conn->pool->db_ops->close(conn->conn);
93 
94  gw_free(conn);
95 }
96 
97 
98 /*************************************************************************
99  * public functions
100  */
101 
102 DBPool *dbpool_create(enum db_type db_type, DBConf *conf, unsigned int connections)
103 {
104  DBPool *p;
105 
106  if (conf == NULL)
107  return NULL;
108 
109  p = gw_malloc(sizeof(DBPool));
110  gw_assert(p != NULL);
111  p->pool = gwlist_create();
113  p->max_size = connections;
114  p->curr_size = 0;
115  p->conf = conf;
116  p->db_type = db_type;
117 
118  switch(db_type) {
119 #ifdef HAVE_MSSQL
120  case DBPOOL_MSSQL:
121  p->db_ops = &mssql_ops;
122  break;
123 #endif
124 #ifdef HAVE_MYSQL
125  case DBPOOL_MYSQL:
126  p->db_ops = &mysql_ops;
127  break;
128 #endif
129 #ifdef HAVE_ORACLE
130  case DBPOOL_ORACLE:
131  p->db_ops = &oracle_ops;
132  break;
133 #endif
134 #ifdef HAVE_SQLITE
135  case DBPOOL_SQLITE:
136  p->db_ops = &sqlite_ops;
137  break;
138 #endif
139 #ifdef HAVE_SQLITE3
140  case DBPOOL_SQLITE3:
141  p->db_ops = &sqlite3_ops;
142  break;
143 #endif
144 #ifdef HAVE_SDB
145  case DBPOOL_SDB:
146  p->db_ops = &sdb_ops;
147  break;
148 #endif
149 #ifdef HAVE_PGSQL
150  case DBPOOL_PGSQL:
151  p->db_ops = &pgsql_ops;
152  break;
153 #endif
154 #ifdef HAVE_REDIS
155  case DBPOOL_REDIS:
156  p->db_ops = &redis_ops;
157  break;
158 #endif
159 #ifdef HAVE_CASS
160  case DBPOOL_CASS:
161  p->db_ops = &cass_ops;
162  break;
163 #endif
164  default:
165  panic(0, "Unknown dbpool type defined.");
166  }
167 
168  /*
169  * XXX what is todo here if not all connections
170  * where established ???
171  */
172  dbpool_increase(p, connections);
173 
174  return p;
175 }
176 
177 
178 void dbpool_destroy(DBPool *p)
179 {
180 
181  if (p == NULL)
182  return; /* nothing todo here */
183 
184  gw_assert(p->pool != NULL && p->db_ops != NULL);
185 
187  gwlist_destroy(p->pool, (void*) dbpool_conn_destroy);
188 
189  p->db_ops->conf_destroy(p->conf);
190  gw_free(p);
191 }
192 
193 
194 unsigned int dbpool_increase(DBPool *p, unsigned int count)
195 {
196  unsigned int i, opened = 0;
197 
198  gw_assert(p != NULL && p->conf != NULL && p->db_ops != NULL && p->db_ops->open != NULL);
199 
200 
201  /* lock dbpool for updates */
202  gwlist_lock(p->pool);
203 
204  /* ensure we don't increase more items than the max_size border */
205  for (i=0; i < count && p->curr_size < p->max_size; i++) {
206  void *conn = p->db_ops->open(p->conf);
207  if (conn != NULL) {
208  DBPoolConn *pc = gw_malloc(sizeof(DBPoolConn));
209  gw_assert(pc != NULL);
210 
211  pc->conn = conn;
212  pc->pool = p;
213 
214  p->curr_size++;
215  opened++;
216  gwlist_produce(p->pool, pc);
217  }
218  }
219 
220  /* unlock dbpool for updates */
221  gwlist_unlock(p->pool);
222 
223  return opened;
224 }
225 
226 
227 unsigned int dbpool_decrease(DBPool *p, unsigned int c)
228 {
229  unsigned int i;
230 
231  gw_assert(p != NULL && p->pool != NULL && p->db_ops != NULL && p->db_ops->close != NULL);
232 
233  /* lock dbpool for updates */
234  gwlist_lock(p->pool);
235 
236  /*
237  * Ensure we don't try to decrease more then available in pool.
238  */
239  for (i = 0; i < c; i++) {
240  DBPoolConn *pc;
241 
242  /* gwlist_extract_first doesn't block even if no conn here */
243  pc = gwlist_extract_first(p->pool);
244 
245  /* no conn availible anymore */
246  if (pc == NULL)
247  break;
248 
249  /* close connections and destroy pool connection */
250  dbpool_conn_destroy(pc);
251  p->curr_size--;
252  }
253 
254  /* unlock dbpool for updates */
255  gwlist_unlock(p->pool);
256 
257  return i;
258 }
259 
260 
261 long dbpool_conn_count(DBPool *p)
262 {
263  gw_assert(p != NULL && p->pool != NULL);
264 
265  return gwlist_len(p->pool);
266 }
267 
268 
270 {
271  DBPoolConn *pc;
272 
273  gw_assert(p != NULL && p->pool != NULL);
274 
275  /* check for max connections and if 0 return NULL */
276  if (p->max_size < 1)
277  return NULL;
278 
279  /* check if we have any connection */
280  while (p->curr_size < 1) {
281  debug("dbpool", 0, "DBPool has no connections, reconnecting up to maximum...");
282  /* dbpool_increase ensure max_size is not exceeded so don't lock */
283  dbpool_increase(p, p->max_size - p->curr_size);
284  if (p->curr_size < 1)
285  gwthread_sleep(0.1);
286  }
287 
288  /* garantee that you deliver a valid connection to the caller */
289  while ((pc = gwlist_consume(p->pool)) != NULL) {
290 
291  /*
292  * XXX check that the connection is still existing.
293  * Is this a performance bottle-neck?!
294  */
295  if (!pc->conn || (p->db_ops->check && p->db_ops->check(pc->conn) != 0)) {
296  /* something was wrong, reinitialize the connection */
297  /* lock dbpool for update */
298  gwlist_lock(p->pool);
299  dbpool_conn_destroy(pc);
300  p->curr_size--;
301  /* unlock dbpool for update */
302  gwlist_unlock(p->pool);
303  /*
304  * maybe not needed, just try to get next connection, but it
305  * can be dangeros if all connections where broken, then we will
306  * block here for ever.
307  */
308  while (p->curr_size < 1) {
309  debug("dbpool", 0, "DBPool has too few connections, reconnecting up to maximum...");
310  /* dbpool_increase ensure max_size is not exceeded so don't lock */
311  dbpool_increase(p, p->max_size - p->curr_size);
312  if (p->curr_size < 1)
313  gwthread_sleep(0.1);
314  }
315 
316  } else {
317  break;
318  }
319  }
320 
321  return (pc->conn != NULL ? pc : NULL);
322 }
323 
324 
326 {
327  gw_assert(pc != NULL && pc->conn != NULL && pc->pool != NULL && pc->pool->pool != NULL);
328 
329  gwlist_produce(pc->pool->pool, pc);
330 }
331 
332 
333 unsigned int dbpool_check(DBPool *p)
334 {
335  long i, len, n = 0, reinit = 0;
336 
337  gw_assert(p != NULL && p->pool != NULL && p->db_ops != NULL);
338 
339  /*
340  * First check if db_ops->check function pointer is here.
341  * NOTE: db_ops->check is optional, so if it is not there, then
342  * we have nothing todo and we simple return list length.
343  */
344  if (p->db_ops->check == NULL)
345  return gwlist_len(p->pool);
346 
347  gwlist_lock(p->pool);
348  len = gwlist_len(p->pool);
349  for (i = 0; i < len; i++) {
350  DBPoolConn *pconn;
351 
352  pconn = gwlist_get(p->pool, i);
353  if (p->db_ops->check(pconn->conn) != 0) {
354  /* something was wrong, reinitialize the connection */
355  gwlist_delete(p->pool, i, 1);
356  dbpool_conn_destroy(pconn);
357  p->curr_size--;
358  reinit++;
359  len--;
360  i--;
361  } else {
362  n++;
363  }
364  }
365  gwlist_unlock(p->pool);
366 
367  /* reinitialize brocken connections */
368  if (reinit > 0)
369  n += dbpool_increase(p, reinit);
370 
371 
372  return n;
373 }
374 
375 
376 int dbpool_conn_select(DBPoolConn *conn, const Octstr *sql, List *binds, List **result)
377 {
378  if (sql == NULL || conn == NULL)
379  return -1;
380 
381  if (conn->pool->db_ops->select == NULL)
382  return -1; /* may be panic here ??? */
383 
384  return conn->pool->db_ops->select(conn->conn, sql, binds, result);
385 }
386 
387 
388 int dbpool_conn_update(DBPoolConn *conn, const Octstr *sql, List *binds)
389 {
390  if (sql == NULL || conn == NULL)
391  return -1;
392 
393  if (conn->pool->db_ops->update == NULL)
394  return -1; /* may be panic here ??? */
395 
396  return conn->pool->db_ops->update(conn->conn, sql, binds);
397 }
398 
399 #endif /* HAVE_DBPOOL */
db_type
Definition: dbpool.h:76
unsigned int dbpool_check(DBPool *p)
long dbpool_conn_count(DBPool *p)
DBPool * dbpool_create(enum db_type db_type, DBConf *conf, unsigned int connections)
List * pool
Definition: dbpool_p.h:111
int(* check)(void *conn)
Definition: dbpool_p.h:83
void gwlist_produce(List *list, void *item)
Definition: list.c:411
long gwlist_len(List *list)
Definition: list.c:166
void * gwlist_get(List *list, long pos)
Definition: list.c:292
int(* update)(void *conn, const Octstr *sql, List *binds)
Definition: dbpool_p.h:106
unsigned int dbpool_decrease(DBPool *p, unsigned int conn)
unsigned int dbpool_increase(DBPool *p, unsigned int conn)
void(* close)(void *conn)
Definition: dbpool_p.h:77
unsigned int max_size
Definition: dbpool_p.h:112
void dbpool_conn_produce(DBPoolConn *conn)
DBConf * conf
Definition: dbpool_p.h:114
void gwlist_unlock(List *list)
Definition: list.c:354
void * gwlist_extract_first(List *list)
Definition: list.c:305
void gwlist_delete(List *list, long pos, long count)
Definition: list.c:232
void(* conf_destroy)(DBConf *conf)
Definition: dbpool_p.h:87
void gwlist_remove_producer(List *list)
Definition: list.c:401
unsigned int curr_size
Definition: dbpool_p.h:113
gw_assert(wtls_machine->packet_to_send!=NULL)
void gwthread_sleep(double seconds)
void gwlist_lock(List *list)
Definition: list.c:347
Definition: dbpool.h:164
void dbpool_destroy(DBPool *p)
int dbpool_conn_update(DBPoolConn *conn, const Octstr *sql, List *binds)
Definition: octstr.c:118
void * gwlist_consume(List *list)
Definition: list.c:427
void debug(const char *place, int err, const char *fmt,...)
Definition: log.c:690
#define panic
Definition: log.h:87
int dbpool_conn_select(DBPoolConn *conn, const Octstr *sql, List *binds, List **result)
#define gwlist_create()
Definition: list.h:136
enum db_type db_type
Definition: dbpool_p.h:116
int(* select)(void *conn, const Octstr *sql, List *binds, List **result)
Definition: dbpool_p.h:99
DBPoolConn * dbpool_conn_consume(DBPool *p)
void * conn
Definition: dbpool.h:95
struct db_ops * db_ops
Definition: dbpool_p.h:115
void gwlist_add_producer(List *list)
Definition: list.c:383
Definition: list.c:102
void *(* open)(const DBConf *conf)
Definition: dbpool_p.h:73
DBPool * pool
Definition: dbpool.h:96
void gwlist_destroy(List *list, gwlist_item_destructor_t *destructor)
Definition: list.c:145
See file LICENSE for details about the license agreement for using, modifying, copying or deriving work from this software.