Main Page | Alphabetical List | Data Structures | Directories | File List | Data Fields | Globals

dbpool.c

Go to the documentation of this file.
00001 /* ==================================================================== 
00002  * The Kannel Software License, Version 1.0 
00003  * 
00004  * Copyright (c) 2001-2008 Kannel Group  
00005  * Copyright (c) 1998-2001 WapIT Ltd.   
00006  * All rights reserved. 
00007  * 
00008  * Redistribution and use in source and binary forms, with or without 
00009  * modification, are permitted provided that the following conditions 
00010  * are met: 
00011  * 
00012  * 1. Redistributions of source code must retain the above copyright 
00013  *    notice, this list of conditions and the following disclaimer. 
00014  * 
00015  * 2. Redistributions in binary form must reproduce the above copyright 
00016  *    notice, this list of conditions and the following disclaimer in 
00017  *    the documentation and/or other materials provided with the 
00018  *    distribution. 
00019  * 
00020  * 3. The end-user documentation included with the redistribution, 
00021  *    if any, must include the following acknowledgment: 
00022  *       "This product includes software developed by the 
00023  *        Kannel Group (http://www.kannel.org/)." 
00024  *    Alternately, this acknowledgment may appear in the software itself, 
00025  *    if and wherever such third-party acknowledgments normally appear. 
00026  * 
00027  * 4. The names "Kannel" and "Kannel Group" must not be used to 
00028  *    endorse or promote products derived from this software without 
00029  *    prior written permission. For written permission, please  
00030  *    contact org@kannel.org. 
00031  * 
00032  * 5. Products derived from this software may not be called "Kannel", 
00033  *    nor may "Kannel" appear in their name, without prior written 
00034  *    permission of the Kannel Group. 
00035  * 
00036  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED 
00037  * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 
00038  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 
00039  * DISCLAIMED.  IN NO EVENT SHALL THE KANNEL GROUP OR ITS CONTRIBUTORS 
00040  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,  
00041  * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT  
00042  * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR  
00043  * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,  
00044  * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE  
00045  * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,  
00046  * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 
00047  * ==================================================================== 
00048  * 
00049  * This software consists of voluntary contributions made by many 
00050  * individuals on behalf of the Kannel Group.  For more information on  
00051  * the Kannel Group, please see <http://www.kannel.org/>. 
00052  * 
00053  * Portions of this software are based upon software originally written at  
00054  * WapIT Ltd., Helsinki, Finland for the Kannel project.  
00055  */ 
00056 
00057 /*
00058  * dbpool.c - implement generic database connection pool
00059  *
00060  * Stipe Tolj <stolj@wapme.de>
00061  *      2003 Initial version.
00062  * Alexander Malysh <a.malysh@centrium.de>
00063  *      2003 Made dbpool more generic.
00064  * Robert Gałach <robert.galach@my.tenbit.pl>
00065  *      2004 Added support for binding variables.
00066  */
00067 
00068 #include "gwlib.h"
00069 #include "dbpool.h"
00070 #include "dbpool_p.h"
00071 
00072 #ifdef HAVE_DBPOOL
00073 
00074 #include "dbpool_mysql.c"
00075 #include "dbpool_oracle.c"
00076 #include "dbpool_sqlite.c"
00077 #include "dbpool_sqlite3.c"
00078 #include "dbpool_sdb.c"
00079 #include "dbpool_pgsql.c"
00080 
00081 
00082 static void dbpool_conn_destroy(DBPoolConn *conn)
00083 {
00084     gw_assert(conn != NULL);
00085 
00086     if (conn->conn != NULL)
00087         conn->pool->db_ops->close(conn->conn);
00088 
00089     gw_free(conn);
00090 }
00091 
00092 
00093 /*************************************************************************
00094  * public functions
00095  */
00096 
00097 DBPool *dbpool_create(enum db_type db_type, DBConf *conf, unsigned int connections)
00098 {
00099     DBPool *p;
00100 
00101     if (conf == NULL)
00102         return NULL;
00103 
00104     p = gw_malloc(sizeof(DBPool));
00105     gw_assert(p != NULL);
00106     p->pool = gwlist_create();
00107     gwlist_add_producer(p->pool);
00108     p->max_size = connections;
00109     p->curr_size = 0;
00110     p->conf = conf;
00111     p->db_type = db_type;
00112 
00113     switch(db_type) {
00114 #ifdef HAVE_MYSQL
00115         case DBPOOL_MYSQL:
00116             p->db_ops = &mysql_ops;
00117             break;
00118 #endif
00119 #ifdef HAVE_ORACLE
00120         case DBPOOL_ORACLE:
00121             p->db_ops = &oracle_ops;
00122             break;
00123 #endif
00124 #ifdef HAVE_SQLITE
00125         case DBPOOL_SQLITE:
00126             p->db_ops = &sqlite_ops;
00127             break;
00128 #endif
00129 #ifdef HAVE_SQLITE3
00130         case DBPOOL_SQLITE3:
00131             p->db_ops = &sqlite3_ops;
00132             break;
00133 #endif
00134 #ifdef HAVE_SDB
00135         case DBPOOL_SDB:
00136             p->db_ops = &sdb_ops;
00137             break;
00138 #endif
00139 #ifdef HAVE_PGSQL
00140        case DBPOOL_PGSQL:
00141            p->db_ops = &pgsql_ops;
00142            break;
00143 #endif
00144         default:
00145             panic(0, "Unknown dbpool type defined.");
00146     }
00147 
00148     /*
00149      * XXX what is todo here if not all connections
00150      * where established ???
00151      */
00152     dbpool_increase(p, connections);
00153 
00154     return p;
00155 }
00156 
00157 
00158 void dbpool_destroy(DBPool *p)
00159 {
00160 
00161     if (p == NULL)
00162         return; /* nothing todo here */
00163 
00164     gw_assert(p->pool != NULL && p->db_ops != NULL);
00165 
00166     gwlist_remove_producer(p->pool);
00167     gwlist_destroy(p->pool, (void*) dbpool_conn_destroy);
00168 
00169     p->db_ops->conf_destroy(p->conf);
00170     gw_free(p);
00171 }
00172 
00173 
00174 unsigned int dbpool_increase(DBPool *p, unsigned int count)
00175 {
00176     unsigned int i, opened = 0;
00177 
00178     gw_assert(p != NULL && p->conf != NULL && p->db_ops != NULL && p->db_ops->open != NULL);
00179 
00180 
00181     /* lock dbpool for updates */
00182     gwlist_lock(p->pool);
00183 
00184     /* ensure we don't increase more items than the max_size border */
00185     for (i=0; i < count && p->curr_size < p->max_size; i++) {
00186         void *conn = p->db_ops->open(p->conf);
00187         if (conn != NULL) {
00188             DBPoolConn *pc = gw_malloc(sizeof(DBPoolConn));
00189             gw_assert(pc != NULL);
00190 
00191             pc->conn = conn;
00192             pc->pool = p;
00193 
00194             p->curr_size++;
00195             opened++;
00196             gwlist_produce(p->pool, pc);
00197         }
00198     }
00199 
00200     /* unlock dbpool for updates */
00201     gwlist_unlock(p->pool);
00202 
00203     return opened;
00204 }
00205 
00206 
00207 unsigned int dbpool_decrease(DBPool *p, unsigned int c)
00208 {
00209     unsigned int i;
00210 
00211     gw_assert(p != NULL && p->pool != NULL && p->db_ops != NULL && p->db_ops->close != NULL);
00212 
00213     /* lock dbpool for updates */
00214     gwlist_lock(p->pool);
00215 
00216     /*
00217      * Ensure we don't try to decrease more then available in pool.
00218      */
00219     for (i = 0; i < c; i++) {
00220         DBPoolConn *pc;
00221 
00222         /* gwlist_extract_first doesn't block even if no conn here */
00223         pc = gwlist_extract_first(p->pool);
00224 
00225         /* no conn availible anymore */
00226         if (pc == NULL)
00227             break;
00228 
00229         /* close connections and destroy pool connection */
00230         dbpool_conn_destroy(pc);
00231         p->curr_size--;
00232     }
00233 
00234     /* unlock dbpool for updates */
00235     gwlist_unlock(p->pool);
00236 
00237     return i;
00238 }
00239 
00240 
00241 long dbpool_conn_count(DBPool *p)
00242 {
00243     gw_assert(p != NULL && p->pool != NULL);
00244 
00245     return gwlist_len(p->pool);
00246 }
00247 
00248 
00249 DBPoolConn *dbpool_conn_consume(DBPool *p)
00250 {
00251     DBPoolConn *pc;
00252 
00253     gw_assert(p != NULL && p->pool != NULL);
00254     
00255     /* check for max connections and if 0 return NULL */
00256     if (p->max_size < 1)
00257         return NULL;
00258 
00259     /* check if we have any connection */
00260     while (p->curr_size < 1) {
00261         debug("dbpool", 0, "DBPool has no connections, reconnecting up to maximum...");
00262         /* dbpool_increase ensure max_size is not exceeded so don't lock */
00263         dbpool_increase(p, p->max_size - p->curr_size);
00264         if (p->curr_size < 1)
00265             gwthread_sleep(0.1);
00266     }
00267 
00268     /* garantee that you deliver a valid connection to the caller */
00269     while ((pc = gwlist_consume(p->pool)) != NULL) {
00270 
00271         /* 
00272          * XXX check that the connection is still existing.
00273          * Is this a performance bottle-neck?!
00274          */
00275         if (!pc->conn || (p->db_ops->check && p->db_ops->check(pc->conn) != 0)) {
00276             /* something was wrong, reinitialize the connection */
00277             /* lock dbpool for update */
00278             gwlist_lock(p->pool);
00279             dbpool_conn_destroy(pc);
00280             p->curr_size--;
00281             /* unlock dbpool for update */
00282             gwlist_unlock(p->pool);
00283             /*
00284              * maybe not needed, just try to get next connection, but it
00285              * can be dangeros if all connections where broken, then we will
00286              * block here for ever.
00287              */
00288             while (p->curr_size < 1) {
00289                 debug("dbpool", 0, "DBPool has too few connections, reconnecting up to maximum...");
00290                 /* dbpool_increase ensure max_size is not exceeded so don't lock */
00291                 dbpool_increase(p, p->max_size - p->curr_size);
00292                 if (p->curr_size < 1)
00293                     gwthread_sleep(0.1);
00294             }
00295 
00296         } else {
00297             break;
00298         }
00299     }
00300 
00301     return (pc->conn != NULL ? pc : NULL);
00302 }
00303 
00304 
00305 void dbpool_conn_produce(DBPoolConn *pc)
00306 {
00307     gw_assert(pc != NULL && pc->conn != NULL && pc->pool != NULL && pc->pool->pool != NULL);
00308 
00309     gwlist_produce(pc->pool->pool, pc);
00310 }
00311 
00312 
00313 unsigned int dbpool_check(DBPool *p)
00314 {
00315     long i, len, n = 0, reinit = 0;
00316 
00317     gw_assert(p != NULL && p->pool != NULL && p->db_ops != NULL);
00318 
00319     /*
00320      * First check if db_ops->check function pointer is here.
00321      * NOTE: db_ops->check is optional, so if it is not there, then
00322      * we have nothing todo and we simple return list length.
00323      */
00324     if (p->db_ops->check == NULL)
00325         return gwlist_len(p->pool);
00326 
00327     gwlist_lock(p->pool);
00328     len = gwlist_len(p->pool);
00329     for (i = 0; i < len; i++) {
00330         DBPoolConn *pconn;
00331 
00332         pconn = gwlist_get(p->pool, i);
00333         if (p->db_ops->check(pconn->conn) != 0) {
00334             /* something was wrong, reinitialize the connection */
00335             gwlist_delete(p->pool, i, 1);
00336             dbpool_conn_destroy(pconn);
00337             p->curr_size--;
00338             reinit++;
00339             len--;
00340             i--;
00341         } else {
00342             n++;
00343         }
00344     }
00345     gwlist_unlock(p->pool);
00346 
00347     /* reinitialize brocken connections */
00348     if (reinit > 0)
00349         n += dbpool_increase(p, reinit);
00350 
00351 
00352     return n;
00353 }
00354 
00355 
00356 int dbpool_conn_select(DBPoolConn *conn, const Octstr *sql, List *binds, List **result)
00357 {
00358     if (sql == NULL || conn == NULL)
00359         return -1;
00360 
00361     if (conn->pool->db_ops->select == NULL)
00362         return -1; /* may be panic here ??? */
00363 
00364     return conn->pool->db_ops->select(conn->conn, sql, binds, result);
00365 }
00366 
00367 
00368 int dbpool_conn_update(DBPoolConn *conn, const Octstr *sql, List *binds)
00369 {
00370     if (sql == NULL || conn == NULL)
00371         return -1;
00372 
00373     if (conn->pool->db_ops->update == NULL)
00374         return -1; /* may be panic here ??? */
00375 
00376     return conn->pool->db_ops->update(conn->conn, sql, binds);
00377 }
00378 
00379 #endif /* HAVE_DBPOOL */
See file LICENSE for details about the license agreement for using, modifying, copying or deriving work from this software.