bdb_lib.c

Go to the documentation of this file.
00001 /*
00002  * $Id: bdb_lib.c 5759 2009-03-23 13:11:05Z henningw $
00003  *
00004  * db_berkeley module, portions of this code were templated using
00005  * the dbtext and postgres modules.
00006 
00007  * Copyright (C) 2007 Cisco Systems
00008  *
00009  * This file is part of Kamailio, a free SIP server.
00010  *
00011  * Kamailio is free software; you can redistribute it and/or modify
00012  * it under the terms of the GNU General Public License as published by
00013  * the Free Software Foundation; either version 2 of the License, or
00014  * (at your option) any later version
00015  *
00016  * Kamailio is distributed in the hope that it will be useful,
00017  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00018  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00019  * GNU General Public License for more details.
00020  *
00021  * You should have received a copy of the GNU General Public License 
00022  * along with this program; if not, write to the Free Software 
00023  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
00024  * 
00025  * History:
00026  * --------
00027  * 2007-09-19  genesis (wiquan)
00028  */
00029 
00030 #include <stdio.h>
00031 #include <string.h>
00032 #include <time.h>
00033 #include <sys/types.h>
00034 #include <dirent.h>
00035 #include "../../ut.h"
00036 #include "../../mem/mem.h"
00037 #include "../../dprint.h"
00038 
00039 #include "bdb_util.h"
00040 #include "bdb_lib.h"
00041 #include "bdb_val.h"
00042 
00043 static database_p *_cachedb = NULL;
00044 static db_parms_p _db_parms = NULL;
00045 
00046 /**
00047  *
00048  */
00049 int bdblib_init(db_parms_p _p) 
00050 {
00051    if (!_cachedb)
00052    {
00053       _cachedb = pkg_malloc( sizeof(database_p) );
00054       if (!_cachedb) 
00055       {  LM_CRIT("not enough private memory\n");
00056          return -1;
00057       }
00058       
00059       *_cachedb = NULL;
00060       
00061       /*create default parms*/
00062       db_parms_p dp = (db_parms_p) pkg_malloc( sizeof(db_parms_t) );
00063       if (!dp) 
00064       {  LM_CRIT("not enough private memory\n");
00065          return -1;
00066       }
00067       
00068       if(_p)
00069       {
00070          dp->cache_size  = _p->cache_size;
00071          dp->auto_reload = _p->auto_reload;
00072          dp->log_enable  = _p->log_enable;
00073          dp->journal_roll_interval = _p->journal_roll_interval;
00074       }
00075       else
00076       {
00077          dp->cache_size = (4 * 1024 * 1024); //4Mb
00078          dp->auto_reload = 0;
00079          dp->log_enable = 0;
00080          dp->journal_roll_interval = 3600;
00081       }
00082       
00083       _db_parms = dp;
00084    }
00085    return 0;
00086 }
00087 
00088 
00089 /**
00090  * close all DBs and then the DBENV; free all memory
00091  */
00092 int bdblib_destroy(void)
00093 {
00094    if (_cachedb)  db_free(*_cachedb);
00095    if(_db_parms)  pkg_free(_db_parms);
00096    return 0;
00097 }
00098 
00099 
00100 /** closes the underlying Berkeley DB.
00101   assumes the lib data-structures are already initialzed;
00102   used to sync and reload the db file.
00103 */
00104 int bdblib_close(char* _n)
00105 {
00106    str s;
00107    int rc;
00108    tbl_cache_p _tbc;
00109    DB* _db = NULL;
00110    DB_ENV* _env = NULL;
00111    database_p _db_p = *_cachedb;
00112    
00113    if (!_cachedb || !_n)
00114       return -1;
00115    
00116    rc = 0;
00117    s.s = (char*)_n;
00118    s.len = strlen(_n);
00119    
00120    if (_db_p)
00121    {  
00122       _env = _db_p->dbenv;
00123       _tbc = _db_p->tables;
00124 LM_DBG("ENV %.*s \n"
00125    , _db_p->name.len
00126    , _db_p->name.s);
00127       if(s.len == _db_p->name.len && 
00128       !strncasecmp(s.s, _db_p->name.s, _db_p->name.len))
00129       {
00130          //close the whole dbenv
00131          LM_DBG("ENV %.*s \n", s.len, s.s);
00132          while(_tbc)
00133          {
00134             if(_tbc->dtp)
00135             {
00136                lock_get(&_tbc->dtp->sem);
00137                _db = _tbc->dtp->db;
00138                if(_db)
00139                   rc = _db->close(_db, 0);
00140                if(rc != 0)
00141                   LM_CRIT("error closing %s\n", _tbc->dtp->name.s);
00142                _tbc->dtp->db = NULL;
00143                
00144                lock_release(&_tbc->dtp->sem);
00145             }
00146             _tbc = _tbc->next;
00147          }
00148          _env->close(_env, 0);
00149          _db_p->dbenv = NULL;
00150          return 0;
00151       }
00152       
00153       //close a particular db
00154       while(_tbc)
00155       {
00156          if(_tbc->dtp)
00157          {
00158    LM_DBG("checking DB %.*s \n"
00159       , _tbc->dtp->name.len
00160       , _tbc->dtp->name.s);
00161             
00162             if(_tbc->dtp->name.len == s.len && 
00163             !strncasecmp(_tbc->dtp->name.s, s.s, s.len ))
00164             {
00165                LM_DBG("DB %.*s \n", s.len, s.s);
00166                lock_get(&_tbc->dtp->sem);
00167                _db = _tbc->dtp->db;
00168                if(_db)
00169                   rc = _db->close(_db, 0);
00170                if(rc != 0)
00171                   LM_CRIT("error closing %s\n", _tbc->dtp->name.s);
00172                _tbc->dtp->db = NULL;
00173                lock_release(&_tbc->dtp->sem);
00174                return 0;
00175             }
00176          }
00177          _tbc = _tbc->next;
00178       }
00179    }
00180    LM_DBG("DB not found %.*s \n", s.len, s.s);
00181    return 1; /*table not found*/
00182 }
00183 
00184 /** opens the underlying Berkeley DB.
00185   assumes the lib data-structures are already initialzed;
00186   used to sync and reload the db file.
00187 */
00188 int bdblib_reopen(char* _n)
00189 {
00190    str s;
00191    int rc, flags;
00192    tbl_cache_p _tbc;
00193    DB* _db = NULL;
00194    DB_ENV* _env = NULL;
00195    database_p _db_p = *_cachedb;
00196    rc = flags = 0;
00197    _tbc = NULL;
00198    
00199    if (!_cachedb || !_n)
00200       return -1;
00201 
00202    s.s = (char*)_n;
00203    s.len = strlen(_n);
00204    
00205    if (_db_p)
00206    {
00207       _env = _db_p->dbenv;
00208       _tbc = _db_p->tables;
00209       
00210       if(s.len ==_db_p->name.len && 
00211       !strncasecmp(s.s, _db_p->name.s,_db_p->name.len))
00212       {
00213          //open the whole dbenv
00214          LM_DBG("-- bdblib_reopen ENV %.*s \n", s.len, s.s);
00215          if(!_db_p->dbenv)
00216          {  rc = bdblib_create_dbenv(&_env, _n);
00217             _db_p->dbenv = _env;
00218          }
00219          
00220          if(rc!=0) return rc;
00221          _env = _db_p->dbenv;
00222          _tbc = _db_p->tables;
00223 
00224          while(_tbc)
00225          {
00226             if(_tbc->dtp)
00227             {
00228                lock_get(&_tbc->dtp->sem);
00229                if(!_tbc->dtp->db)
00230                {
00231                   if ((rc = db_create(&_db, _env, 0)) != 0)
00232                   {  _env->err(_env, rc, "db_create");
00233                      LM_CRIT("error in db_create, db error: %s.\n",db_strerror(rc));
00234                      bdblib_recover(_tbc->dtp, rc);
00235                   }
00236                }
00237                
00238                if ((rc = _db->open(_db, NULL, _n, NULL, DB_HASH, DB_CREATE, 0664)) != 0)
00239                {  _db->dbenv->err(_env, rc, "DB->open: %s", _n);
00240                   LM_CRIT("error in db_open: %s.\n",db_strerror(rc));
00241                   bdblib_recover(_tbc->dtp, rc);
00242                }
00243                
00244                _tbc->dtp->db = _db;
00245                lock_release(&_tbc->dtp->sem);
00246             }
00247             _tbc = _tbc->next;
00248          }
00249          _env->close(_env, 0);
00250          return rc;
00251       }
00252       
00253       //open a particular db
00254       while(_tbc)
00255       {
00256          if(_tbc->dtp)
00257          {
00258    LM_DBG("checking DB %.*s \n"
00259       , _tbc->dtp->name.len
00260       , _tbc->dtp->name.s);
00261             
00262             if(_tbc->dtp->name.len == s.len && 
00263             !strncasecmp(_tbc->dtp->name.s, s.s, s.len ))
00264             {
00265                LM_DBG("DB %.*s \n", s.len, s.s);
00266                lock_get(&_tbc->dtp->sem);
00267                if(!_tbc->dtp->db) 
00268                {
00269                   if ((rc = db_create(&_db, _env, 0)) != 0)
00270                   {  _env->err(_env, rc, "db_create");
00271                      LM_CRIT("error in db_create, db error: %s.\n",db_strerror(rc));
00272                      bdblib_recover(_tbc->dtp, rc);
00273                   }
00274                }
00275                
00276                if ((rc = _db->open(_db, NULL, _n, NULL, DB_HASH, DB_CREATE, 0664)) != 0)
00277                {  _db->dbenv->err(_env, rc, "DB->open: %s", _n);
00278                   LM_CRIT("bdb open: %s.\n",db_strerror(rc));
00279                   bdblib_recover(_tbc->dtp, rc);
00280                }
00281                _tbc->dtp->db = _db;
00282                lock_release(&_tbc->dtp->sem);
00283                return rc;
00284             }
00285          }
00286          _tbc = _tbc->next;
00287       }
00288       
00289    }
00290    LM_DBG("DB not found %.*s \n", s.len, s.s);
00291    return 1; /*table not found*/
00292 }
00293 
00294 
00295 /**
00296  *
00297  */
00298 int bdblib_create_dbenv(DB_ENV **_dbenv, char* _home)
00299 {
00300    DB_ENV *env;
00301    char *progname;
00302    int rc, flags;
00303    
00304    progname = "openser";
00305    
00306    /* Create an environment and initialize it for additional error * reporting. */ 
00307    if ((rc = db_env_create(&env, 0)) != 0) 
00308    {
00309       LM_ERR("db_env_create failed! bdb error: %s.\n", db_strerror(rc)); 
00310       return (rc);
00311    }
00312  
00313    env->set_errpfx(env, progname);
00314 
00315    /*  Specify the shared memory buffer pool cachesize */ 
00316    if ((rc = env->set_cachesize(env, 0, _db_parms->cache_size, 0)) != 0) 
00317    {
00318       LM_ERR("dbenv set_cachsize failed! bdb error: %s.\n", db_strerror(rc));
00319       env->err(env, rc, "set_cachesize"); 
00320       goto err; 
00321    }
00322 
00323    /* Concurrent Data Store flags */
00324    flags = DB_CREATE |
00325       DB_INIT_CDB |
00326       DB_INIT_MPOOL |
00327       DB_THREAD;
00328    
00329    /* Transaction Data Store flags ; not supported yet */
00330    /*
00331    flags = DB_CREATE |
00332       DB_RECOVER |
00333       DB_INIT_LOG | 
00334       DB_INIT_LOCK |
00335       DB_INIT_MPOOL |
00336       DB_THREAD |
00337       DB_INIT_TXN;
00338    */
00339    
00340    /* Open the environment */ 
00341    if ((rc = env->open(env, _home, flags, 0)) != 0) 
00342    { 
00343       LM_ERR("dbenv is not initialized! bdb error: %s.\n",db_strerror(rc));
00344       env->err(env, rc, "environment open: %s", _home); 
00345       goto err; 
00346    }
00347    
00348    *_dbenv = env;
00349    return (0);
00350 
00351 err: (void)env->close(env, 0);
00352    return (rc);
00353 }
00354 
00355 
00356 /**
00357  */
00358 database_p bdblib_get_db(str *_s)
00359 {
00360    int rc;
00361    database_p _db_p=NULL;
00362    char name[512];
00363 
00364    if(!_s || !_s->s || _s->len<=0 || _s->len > 512)
00365       return NULL;
00366 
00367    if( !_cachedb)
00368    {
00369       LM_ERR("db_berkeley cache is not initialized! Check if you loaded db_berkeley "
00370          "before any other module that uses it.\n");
00371       return NULL;
00372    }
00373 
00374    _db_p = *_cachedb;
00375    if(_db_p)
00376    {
00377       LM_DBG("db already cached!\n");
00378       return _db_p;
00379    }
00380 
00381    if(!bdb_is_database(_s))
00382    {  
00383       LM_ERR("database [%.*s] does not exists!\n" ,_s->len , _s->s);
00384       return NULL;
00385    }
00386 
00387    _db_p = (database_p)pkg_malloc(sizeof(database_t));
00388    if(!_db_p)
00389    {
00390       LM_ERR("no private memory for dbenv_t.\n");
00391       pkg_free(_db_p);
00392       return NULL;
00393    }
00394 
00395    _db_p->name.s = (char*)pkg_malloc(_s->len*sizeof(char));
00396    memcpy(_db_p->name.s, _s->s, _s->len);
00397    _db_p->name.len = _s->len;
00398 
00399    strncpy(name, _s->s, _s->len);
00400    name[_s->len] = 0;
00401 
00402    if ((rc = bdblib_create_dbenv(&(_db_p->dbenv), name)) != 0)
00403    {
00404       LM_ERR("bdblib_create_dbenv failed");
00405       pkg_free(_db_p->name.s);
00406       pkg_free(_db_p);
00407       return NULL;
00408    }
00409 
00410    _db_p->tables=NULL;
00411    *_cachedb = _db_p;
00412 
00413    return _db_p;
00414 }
00415 
00416 
00417 /**
00418  * look thru a linked list for the table. if dne, create a new one
00419  * and add to the list
00420 */
00421 tbl_cache_p bdblib_get_table(database_p _db, str *_s)
00422 {
00423    tbl_cache_p _tbc = NULL;
00424    table_p _tp = NULL;
00425 
00426    if(!_db || !_s || !_s->s || _s->len<=0)
00427       return NULL;
00428 
00429    if(!_db->dbenv)
00430    {
00431       return NULL;
00432    }
00433 
00434    _tbc = _db->tables;
00435    while(_tbc)
00436    {
00437       if(_tbc->dtp)
00438       {
00439 
00440          if(_tbc->dtp->name.len == _s->len 
00441             && !strncasecmp(_tbc->dtp->name.s, _s->s, _s->len ))
00442          {
00443             return _tbc;
00444          }
00445       }
00446       _tbc = _tbc->next;
00447    }
00448 
00449    _tbc = (tbl_cache_p)pkg_malloc(sizeof(tbl_cache_t));
00450    if(!_tbc)
00451       return NULL;
00452 
00453    if(!lock_init(&_tbc->sem))
00454    {
00455       pkg_free(_tbc);
00456       return NULL;
00457    }
00458 
00459    _tp = bdblib_create_table(_db, _s);
00460 
00461 #ifdef BDB_EXTRA_DEBUG
00462    LM_DBG("table: %.*s\n", _s->len, _s->s);
00463 #endif
00464 
00465    if(!_tp)
00466    {
00467       LM_ERR("failed to create table.\n");
00468       pkg_free(_tbc);
00469       return NULL;
00470    }
00471 
00472    lock_get(&_tbc->sem);
00473    _tbc->dtp = _tp;
00474 
00475    if(_db->tables)
00476       (_db->tables)->prev = _tbc;
00477    
00478    _tbc->next = _db->tables;
00479    _db->tables = _tbc;
00480    lock_release(&_tbc->sem);
00481 
00482    return _tbc;
00483 }
00484 
00485 
00486 void bdblib_log(int op, table_p _tp, char* _msg, int len)
00487 {
00488    if(!_tp || !len)     return;
00489    if(! _db_parms->log_enable)   return;
00490    if (_tp->logflags == JLOG_NONE)  return;
00491    
00492    if ((_tp->logflags & op) == op)
00493    {  int op_len=7;
00494       char buf[MAX_ROW_SIZE + op_len];
00495       char *c;
00496       time_t now = time(NULL);
00497       
00498       if( _db_parms->journal_roll_interval)
00499       {
00500          if((_tp->t) && (now - _tp->t) > _db_parms->journal_roll_interval)
00501          {  /*try to roll logfile*/
00502             if(bdblib_create_journal(_tp))
00503             {
00504                LM_ERR("Journaling has FAILED !\n");
00505                return;
00506             }
00507          }
00508       }
00509       
00510       c = buf;
00511       switch (op)
00512       {
00513       case JLOG_INSERT:
00514          strncpy(c, "INSERT|", op_len);
00515          break;
00516       case JLOG_UPDATE:
00517          strncpy(c, "UPDATE|", op_len);
00518          break;
00519       case JLOG_DELETE:
00520          strncpy(c, "DELETE|", op_len);
00521          break;
00522       }
00523       
00524       c += op_len;
00525       strncpy(c, _msg, len);
00526       c +=len;
00527       *c = '\n';
00528       c++;
00529       *c = '\0';
00530       
00531       if ((_tp->logflags & JLOG_STDOUT) == JLOG_STDOUT)
00532          puts(buf);
00533       
00534       if ((_tp->logflags & JLOG_SYSLOG) == JLOG_SYSLOG)
00535          syslog(LOG_LOCAL6, buf);
00536       
00537       if(_tp->fp) 
00538       {
00539          if(!fputs(buf, _tp->fp) )
00540             fflush(_tp->fp);
00541       }
00542    }
00543 }
00544 
00545 /**
00546  * The function is called to create a handle to a db table.
00547  * 
00548  * On startup, we do not create any of the db handles.
00549  * Instead it is done on first-use (lazy-initialized) to only create handles to 
00550  * files (db) that we require.
00551  * 
00552  * There is one db file per openser table (eg. acc), and they should exist
00553  * in your DB_PATH (refer to kamctlrc) directory.
00554  *
00555  * This function does _not_ create the underlying binary db tables.
00556  * Creating the tables MUST be manually performed before 
00557  * openser startup by 'kamdbctl create'
00558  *
00559  * Function returns NULL on error, which will cause openser to exit.
00560  *
00561  */
00562 table_p bdblib_create_table(database_p _db, str *_s)
00563 {
00564 
00565    int rc,i,flags;
00566    DB *bdb = NULL;
00567    table_p tp = NULL;
00568    char tblname[MAX_TABLENAME_SIZE]; 
00569 
00570    if(!_db || !_db->dbenv)
00571    {
00572       LM_ERR("no database_p or dbenv.\n");
00573       return NULL;
00574    }
00575 
00576    tp = (table_p)pkg_malloc(sizeof(table_t));
00577    if(!tp)
00578    {
00579       LM_ERR("no private memory for table_t.\n");
00580       return NULL;
00581    }
00582 
00583    if ((rc = db_create(&bdb, _db->dbenv, 0)) != 0)
00584    { 
00585       _db->dbenv->err(_db->dbenv, rc, "database create");
00586       LM_ERR("error in db_create, bdb error: %s.\n",db_strerror(rc));
00587       pkg_free(tp);
00588       return NULL;
00589    }
00590 
00591    memset(tblname, 0, MAX_TABLENAME_SIZE);
00592    strncpy(tblname, _s->s, _s->len);
00593 
00594 #ifdef BDB_EXTRA_DEBUG
00595    LM_DBG("CREATE TABLE = %s\n", tblname);
00596 #endif
00597 
00598    flags = DB_THREAD;
00599 
00600    if ((rc = bdb->open(bdb, NULL, tblname, NULL, DB_HASH, flags, 0664)) != 0)
00601    { 
00602       _db->dbenv->err(_db->dbenv, rc, "DB->open: %s", tblname);
00603       LM_ERR("bdb open failed: %s.\n",db_strerror(rc));
00604       pkg_free(tp);
00605       return NULL;
00606    }
00607 
00608    if(!lock_init(&tp->sem))
00609    {
00610       goto error;
00611    }
00612    
00613    tp->name.s = (char*)pkg_malloc(_s->len*sizeof(char));
00614    memcpy(tp->name.s, _s->s, _s->len);
00615    tp->name.len = _s->len;
00616    tp->db=bdb;
00617    tp->ncols=0;
00618    tp->nkeys=0;
00619    tp->ro=0;    /*0=ReadWrite ; 1=ReadOnly*/
00620    tp->ino=0;   /*inode*/
00621    tp->logflags=0; /*bitmap; 4=Delete, 2=Update, 1=Insert, 0=None*/
00622    tp->fp=0;
00623    tp->t=0;
00624    
00625    for(i=0;i<MAX_NUM_COLS;i++)
00626       tp->colp[i] = NULL;
00627 
00628    /*load metadata; seeded\db_loaded when database are created*/
00629    
00630    /*initialize columns with metadata*/
00631    rc = load_metadata_columns(tp);
00632    if(rc!=0)
00633    {
00634       LM_ERR("FAILED to load METADATA COLS in table: %s.\n", tblname);
00635       goto error;
00636    }
00637    
00638    /*initialize columns default values from metadata*/
00639    rc = load_metadata_defaults(tp);
00640    if(rc!=0)
00641    {
00642       LM_ERR("FAILED to load METADATA DEFAULTS in table: %s.\n", tblname);
00643       goto error;
00644    }
00645    
00646    rc = load_metadata_keys(tp);
00647    if(rc!=0)
00648    {
00649       LM_ERR("FAILED to load METADATA KEYS in table: %s.\n", tblname);
00650       /*will have problems later figuring column types*/
00651       goto error;
00652    }
00653 
00654    /*opened RW by default; Query to set the RO flag */
00655    rc = load_metadata_readonly(tp);
00656    if(rc!=0)
00657    {
00658       LM_INFO("No METADATA_READONLY in table: %s.\n", tblname);
00659       /*non-critical; table will default to READWRITE*/
00660    }
00661 
00662    if(tp->ro)
00663    {  
00664       /*schema defines this table RO readonly*/
00665 #ifdef BDB_EXTRA_DEBUG
00666       LM_DBG("TABLE %.*s is changing to READONLY mode\n"
00667          , tp->name.len, tp->name.s);
00668 #endif
00669       
00670       if ((rc = bdb->close(bdb,0)) != 0)
00671       { 
00672          _db->dbenv->err(_db->dbenv, rc, "DB->close: %s", tblname);
00673          LM_ERR("bdb close: %s.\n",db_strerror(rc));
00674          goto error;
00675       }
00676       
00677       bdb = NULL;
00678       if ((rc = db_create(&bdb, _db->dbenv, 0)) != 0)
00679       { 
00680          _db->dbenv->err(_db->dbenv, rc, "database create");
00681          LM_ERR("error in db_create.\n");
00682          goto error;
00683       }
00684       
00685       flags = DB_THREAD | DB_RDONLY;
00686       if ((rc = bdb->open(bdb, NULL, tblname, NULL, DB_HASH, flags, 0664)) != 0)
00687       { 
00688          _db->dbenv->err(_db->dbenv, rc, "DB->open: %s", tblname);
00689          LM_ERR("bdb open: %s.\n",db_strerror(rc));
00690          goto error;
00691       }
00692       tp->db=bdb;
00693    }
00694    
00695    /* set the journaling flags; flags indicate which operations
00696       need to be journalled. (e.g possible to only journal INSERT.)
00697    */
00698    rc = load_metadata_logflags(tp);
00699    if(rc!=0)
00700       LM_INFO("No METADATA_LOGFLAGS in table: %s.\n", tblname);
00701    
00702    if ((tp->logflags & JLOG_FILE) == JLOG_FILE)
00703       bdblib_create_journal(tp);
00704    
00705    return tp;
00706    
00707 error:
00708    if(tp) 
00709    {
00710       pkg_free(tp->name.s);
00711       pkg_free(tp);
00712    }
00713    return NULL;
00714 }
00715 
00716 int bdblib_create_journal(table_p _tp)
00717 {
00718    char *s;
00719    char fn[1024];
00720    char d[64];
00721    FILE *fp = NULL;
00722    struct tm *t;
00723    int bl;
00724    database_p _db_p = *_cachedb;
00725    time_t tim = time(NULL);
00726    
00727    if(! _db_p || ! _tp) return -1;
00728    if(! _db_parms->log_enable) return 0;
00729    /* journal filename ; e.g. '/var/kamailio/db/location-YYYYMMDDhhmmss.jnl' */
00730    s=fn;
00731    strncpy(s, _db_p->name.s, _db_p->name.len);
00732    s+=_db_p->name.len;
00733    
00734    *s = '/';
00735    s++;
00736    
00737    strncpy(s, _tp->name.s, _tp->name.len);
00738    s+=_tp->name.len;
00739    
00740    t = localtime( &tim );
00741    bl=strftime(d,128,"-%Y%m%d%H%M%S.jnl",t);
00742    strncpy(s, d, bl);
00743    s+= bl;
00744    *s = 0;
00745    
00746    if(_tp->fp)
00747    {  /* must be rolling. */
00748       if( fclose(_tp->fp) )
00749       {  LM_ERR("Failed to Close Log in table: %.*s .\n", _tp->name.len,
00750           _tp->name.s);
00751          return -1;
00752       }
00753    }
00754    
00755    if( (fp = fopen(fn, "w")) != NULL )
00756    {
00757       _tp->fp = fp;
00758    }
00759    else
00760    {
00761       LM_ERR("Failed to Open Log in table: %.*s .\n",_tp->name.len, _tp->name.s);
00762       return -1;
00763    }
00764    
00765    _tp->t = tim;
00766    return 0;
00767 
00768 }
00769 
00770 int load_metadata_columns(table_p _tp)
00771 {
00772    int ret,n,len;
00773    char dbuf[MAX_ROW_SIZE];
00774    char *s = NULL;
00775    char cn[64], ct[16];
00776    DB *db = NULL;
00777    DBT key, data;
00778    column_p col;
00779    ret = n = len = 0;
00780    
00781    if(!_tp || !_tp->db)
00782       return -1;
00783    
00784    if(_tp->ncols!=0)
00785       return 0;
00786    
00787    db = _tp->db;
00788    memset(&key, 0, sizeof(DBT));
00789    memset(&data, 0, sizeof(DBT));
00790    memset(dbuf, 0, MAX_ROW_SIZE);
00791 
00792    key.data = METADATA_COLUMNS;
00793    key.size = strlen(METADATA_COLUMNS);
00794 
00795    /*memory for the result*/
00796    data.data = dbuf;
00797    data.ulen = MAX_ROW_SIZE;
00798    data.flags = DB_DBT_USERMEM;
00799    
00800    if ((ret = db->get(db, NULL, &key, &data, 0)) != 0) 
00801    {
00802       db->err(db, ret, "load_metadata_columns DB->get failed");
00803       LM_ERR("FAILED to find METADATA_COLUMNS in DB \n");
00804       return -1;
00805    }
00806 
00807    /* eg: dbuf = "table_name(str) table_version(int)" */
00808    s = strtok(dbuf, " ");
00809    while(s!=NULL && n<MAX_NUM_COLS) 
00810    {
00811       /* eg: meta[0]=table_name  meta[1]=str */
00812       if (sscanf(s,"%20[^(](%10[^)])[^\n]", cn, ct) < 0) {
00813          LM_ERR("could not parse meta data\n");
00814          return -1;
00815       }
00816 
00817       /* create column*/
00818       col = (column_p) pkg_malloc(sizeof(column_t));
00819       if(!col)
00820       {  LM_ERR("out of private memory \n");
00821          return -1;
00822       }
00823       
00824       /* set name*/
00825       len = strlen( cn );
00826       col->name.s = (char*)pkg_malloc(len * sizeof(char));
00827       memcpy(col->name.s, cn, len );
00828       col->name.len = len;
00829       
00830       /*set column type*/
00831       if(strncmp(ct, "str", 3)==0)
00832       {  col->type = DB_STRING;
00833       }
00834       else if(strncmp(ct, "int", 3)==0)
00835       {  col->type = DB_INT;
00836       }
00837       else if(strncmp(ct, "double", 6)==0)
00838       {  col->type = DB_DOUBLE;
00839       }
00840       else if(strncmp(ct, "datetime", 8)==0)
00841       {  col->type = DB_DATETIME;
00842       }
00843       else
00844       {  col->type = DB_STRING;
00845       }
00846       
00847       col->flag = 0;
00848       _tp->colp[n] = col;
00849       n++;
00850       _tp->ncols++;
00851       s=strtok(NULL, " ");
00852    }
00853 
00854    return 0;
00855 }
00856 
00857 int load_metadata_keys(table_p _tp)
00858 {
00859    int ret,n,ci;
00860    char dbuf[MAX_ROW_SIZE];
00861    char *s = NULL;
00862    DB *db = NULL;
00863    DBT key, data;
00864    ret = n = ci = 0;
00865    
00866    if(!_tp || !_tp->db)
00867       return -1;
00868    
00869    db = _tp->db;
00870    memset(&key, 0, sizeof(DBT));
00871    memset(&data, 0, sizeof(DBT));
00872    memset(dbuf, 0, MAX_ROW_SIZE);
00873    key.data = METADATA_KEY;
00874    key.size = strlen(METADATA_KEY);
00875    data.data = dbuf;
00876    data.ulen = MAX_ROW_SIZE;
00877    data.flags = DB_DBT_USERMEM;
00878    
00879    if ((ret = db->get(db, NULL, &key, &data, 0)) != 0) 
00880    {
00881       db->err(db, ret, "load_metadata_keys DB->get failed");
00882       LM_ERR("FAILED to find METADATA in table \n");
00883       return ret;
00884    }
00885    
00886    s = strtok(dbuf, " ");
00887    while(s!=NULL && n< _tp->ncols) 
00888    {  ret = sscanf(s,"%i", &ci);
00889       if(ret != 1) return -1;
00890       if( _tp->colp[ci] ) 
00891       {  _tp->colp[ci]->flag = 1;
00892          _tp->nkeys++;
00893       }
00894       n++;
00895       s=strtok(NULL, " ");
00896    }
00897 
00898    return 0;
00899 }
00900 
00901 
00902 int load_metadata_readonly(table_p _tp)
00903 {
00904    int i, ret;
00905    char dbuf[MAX_ROW_SIZE];
00906 
00907    DB *db = NULL;
00908    DBT key, data;
00909    i = 0;
00910    
00911    if(!_tp || !_tp->db)
00912       return -1;
00913    
00914    db = _tp->db;
00915    memset(&key, 0, sizeof(DBT));
00916    memset(&data, 0, sizeof(DBT));
00917    memset(dbuf, 0, MAX_ROW_SIZE);
00918    key.data = METADATA_READONLY;
00919    key.size = strlen(METADATA_READONLY);
00920    data.data = dbuf;
00921    data.ulen = MAX_ROW_SIZE;
00922    data.flags = DB_DBT_USERMEM;
00923    
00924    if ((ret = db->get(db, NULL, &key, &data, 0)) != 0) 
00925    {  return ret;
00926    }
00927    
00928    if( 1 == sscanf(dbuf,"%i", &i) )
00929       _tp->ro=(i>0)?1:0;
00930    
00931    return 0;
00932 }
00933 
00934 int load_metadata_logflags(table_p _tp)
00935 {
00936    int i, ret;
00937    char dbuf[MAX_ROW_SIZE];
00938 
00939    DB *db = NULL;
00940    DBT key, data;
00941    i = 0;
00942    
00943    if(!_tp || !_tp->db)
00944       return -1;
00945    
00946    db = _tp->db;
00947    memset(&key, 0, sizeof(DBT));
00948    memset(&data, 0, sizeof(DBT));
00949    memset(dbuf, 0, MAX_ROW_SIZE);
00950    key.data = METADATA_LOGFLAGS;
00951    key.size = strlen(METADATA_LOGFLAGS);
00952    data.data = dbuf;
00953    data.ulen = MAX_ROW_SIZE;
00954    data.flags = DB_DBT_USERMEM;
00955    
00956    if ((ret = db->get(db, NULL, &key, &data, 0)) != 0) 
00957    {  return ret;
00958    }
00959    
00960    if( 1 == sscanf(dbuf,"%i", &i) )
00961       _tp->logflags=i;
00962    
00963    return 0;
00964 }
00965 
00966 int load_metadata_defaults(table_p _tp)
00967 {
00968    int ret,n,len;
00969    char dbuf[MAX_ROW_SIZE];
00970    char *s = NULL;
00971    char cv[64];
00972    DB *db = NULL;
00973    DBT key, data;
00974    column_p col;
00975    ret = n = len = 0;
00976    
00977    if(!_tp || !_tp->db)
00978       return -1;
00979    
00980    db = _tp->db;
00981    memset(&key, 0, sizeof(DBT));
00982    memset(&data, 0, sizeof(DBT));
00983    memset(dbuf, 0, MAX_ROW_SIZE);
00984 
00985    key.data = METADATA_DEFAULTS;
00986    key.size = strlen(METADATA_DEFAULTS);
00987 
00988    /*memory for the result*/
00989    data.data = dbuf;
00990    data.ulen = MAX_ROW_SIZE;
00991    data.flags = DB_DBT_USERMEM;
00992    
00993    if ((ret = db->get(db, NULL, &key, &data, 0)) != 0) 
00994    {
00995 #ifdef BDB_EXTRA_DEBUG
00996       LM_DBG("NO DEFAULTS ; SETTING ALL columns to NULL! \n" );
00997 #endif
00998 
00999       /*no defaults in DB; make some up.*/
01000       for(n=0; n<_tp->ncols; n++)
01001       {
01002          col = _tp->colp[n];
01003          if( col ) 
01004          {  /*set all columns default value to 'NULL' */
01005             len = strlen("NULL");
01006             col->dv.s = (char*)pkg_malloc(len * sizeof(char));
01007             memcpy(col->dv.s, "NULL", len);
01008             col->dv.len = len;
01009          }
01010       }
01011       return 0;
01012    }
01013    
01014    /* use the defaults provided*/
01015    s = strtok(dbuf, DELIM);
01016    while(s!=NULL && n< _tp->ncols) 
01017    {  ret = sscanf(s,"%s", cv);
01018       if(ret != 1) return -1;
01019       col = _tp->colp[n];
01020       if( col ) 
01021       {  /*set column default*/
01022          len = strlen(s);
01023          col->dv.s = (char*)pkg_malloc(len * sizeof(char));
01024          memcpy(col->dv.s, cv, len);
01025          col->dv.len = len;
01026 #ifdef BDB_EXTRA_DEBUG
01027       LM_DBG("COLUMN DEFAULT is %.*s for column[%.*s] \n"
01028          , col->dv.len , ZSW(col->dv.s)
01029          , col->name.len , ZSW(col->name.s)
01030          );
01031 #endif
01032 
01033       }
01034       n++;
01035       s=strtok(NULL, DELIM);
01036    }
01037    
01038    return 0;
01039 }
01040 
01041 
01042 /*creates a composite key _k of length _klen from n values of _v;
01043   provide your own initialized memory for target _k and _klen;
01044   resulting value: _k = "KEY1 | KEY2"
01045   ko = key only
01046 */
01047 int bdblib_valtochar(table_p _tp, int* _lres, char* _k, int* _klen, db_val_t* _v, int _n, int _ko)
01048 {
01049    char *p; 
01050    char sk[MAX_ROW_SIZE]; // subkey(sk) val
01051    char* delim = DELIM;
01052    char* cNULL = "NULL";
01053    int  len, total, sum;
01054    int i, j, k;
01055    p =  _k;
01056    len = sum = total = 0;
01057    i = j = k = 0;
01058    
01059    if(!_tp) return -1;
01060    if(!_v || (_n<1) ) return -1;
01061    if(!_k || !_klen ) return -1;
01062    if( *_klen < 1)    return -1;
01063    
01064    memset(sk, 0, MAX_ROW_SIZE);
01065    total = *_klen;
01066    *_klen = 0; //sum
01067    
01068    if(! _lres)
01069    {  
01070 #ifdef BDB_EXTRA_DEBUG
01071       LM_DBG("schema has NOT specified any keys! \n");
01072 #endif
01073 
01074       /* schema has not specified keys
01075          just use the provided data in order provided
01076       */
01077       for(i=0;i<_n;i++)
01078       {  len = total - sum;
01079          if ( bdb_val2str(&_v[i], sk, &len) != 0 ) 
01080          {  LM_ERR("error building composite key \n");
01081             return -2;
01082          }
01083 
01084          sum += len;
01085          if(sum > total)
01086          {  LM_ERR("Destination buffer too short for subval %s\n",sk);
01087             return -2;
01088          } 
01089 
01090          /* write sk */
01091          strncpy(p, sk, len);
01092          p += len;
01093          *_klen = sum;
01094 
01095          sum += DELIM_LEN;
01096          if(sum > total)
01097          {  LM_ERR("Destination buffer too short for delim \n");
01098             return -3;
01099          }
01100          
01101          /* write delim */
01102          strncpy(p, delim, DELIM_LEN);
01103          p += DELIM_LEN;
01104          *_klen = sum;;
01105       }
01106       return 0;
01107    }
01108 
01109 
01110    /*
01111      schema has specified keys
01112      verify all schema keys are provided
01113      use 'NULL' for those that are missing.
01114    */
01115    for(i=0; i<_tp->ncols; i++)
01116    {  /* i indexes columns in schema order */
01117       if( _ko)
01118       {  /* keymode; skip over non-key columns */
01119          if( ! _tp->colp[i]->flag) 
01120             continue; 
01121       }
01122       
01123       for(j=0; j<_n; j++)
01124       {  
01125          /*
01126            j indexes the columns provided in _k
01127            which may be less than the total required by
01128            the schema. the app does not know the order
01129            of the columns in our schema!
01130           */
01131          k = (_lres) ? _lres[j] : j;
01132          
01133          /*
01134           * k index will remap back to our schema order; like i
01135           */
01136          if(i == k)
01137          {
01138             /*
01139              KEY was provided; append to buffer;
01140              _k[j] contains a key, but its a key that 
01141              corresponds to column k of our schema.
01142              now we know its a match, and we dont need
01143              index k for anything else
01144             */
01145 #ifdef BDB_EXTRA_DEBUG
01146             LM_DBG("KEY PROVIDED[%i]: %.*s.%.*s \n", i 
01147                , _tp->name.len , ZSW(_tp->name.s) 
01148                , _tp->colp[i]->name.len, ZSW(_tp->colp[i]->name.s)
01149                );
01150 #endif
01151 
01152             len = total - sum;
01153             if ( bdb_val2str(&_v[j], sk, &len) != 0)
01154             {  LM_ERR("Destination buffer too short for subval %s\n",sk);
01155                return -4;
01156             }
01157             
01158             sum += len;
01159             if(sum > total)
01160             {  LM_ERR("Destination buffer too short for subval %s\n",sk);
01161                return -5;
01162             }
01163 
01164             strncpy(p, sk, len);
01165             p += len;
01166             *_klen = sum;
01167 
01168             sum += DELIM_LEN;
01169             if(sum > total)
01170             {  LM_ERR("Destination buffer too short for delim \n");
01171                return -5;
01172             } 
01173             
01174             /* append delim */
01175             strncpy(p, delim, DELIM_LEN);
01176             p += DELIM_LEN;
01177             *_klen = sum;
01178             
01179             
01180             /* take us out of inner for loop
01181                and at the end of the outer loop
01182                to look for our next schema key
01183             */
01184             goto next;
01185          }
01186          
01187       }
01188 
01189       /*
01190        NO KEY provided; use the column default value (dv)
01191            i.e _tp->colp[i]->dv
01192       */
01193 #ifdef BDB_EXTRA_DEBUG
01194       LM_DBG("Missing KEY[%i]: %.*s.%.*s using default [%.*s] \n", i
01195          , _tp->name.len , ZSW(_tp->name.s) 
01196          , _tp->colp[i]->name.len, ZSW(_tp->colp[i]->name.s)
01197          , _tp->colp[i]->dv.len , ZSW(_tp->colp[i]->dv.s)
01198          );
01199 #endif
01200       len = _tp->colp[i]->dv.len;
01201       sum += len;
01202       if(sum > total)
01203       {  LM_ERR("Destination buffer too short for subval %s\n",cNULL);
01204          return -5;
01205       }
01206       
01207       strncpy(p, _tp->colp[i]->dv.s, len);
01208       p += len;
01209       *_klen = sum;
01210       
01211       sum += DELIM_LEN;
01212       if(sum > total)
01213       {  LM_ERR("Destination buffer too short for delim \n");
01214          return -5;
01215       } 
01216       
01217       strncpy(p, delim, DELIM_LEN);
01218       p += DELIM_LEN;
01219       *_klen = sum;
01220 next:
01221       continue;
01222    }
01223 
01224 
01225 
01226    return 0;
01227 }
01228 
01229 
01230 /**
01231  *
01232  */
01233 int db_free(database_p _dbp)
01234 {
01235    tbl_cache_p _tbc = NULL, _tbc0=NULL;
01236    if(!_dbp)
01237       return -1;
01238 
01239    _tbc = _dbp->tables;
01240 
01241    while(_tbc)
01242    {
01243       _tbc0 = _tbc->next;
01244       tbl_cache_free(_tbc);
01245       _tbc = _tbc0;
01246    }
01247    
01248    if(_dbp->dbenv)
01249       _dbp->dbenv->close(_dbp->dbenv, 0);
01250    
01251    if(_dbp->name.s)
01252       pkg_free(_dbp->name.s);
01253    
01254    pkg_free(_dbp);
01255 
01256    return 0;
01257 }
01258 
01259 
01260 /**
01261  *
01262  */
01263 int tbl_cache_free(tbl_cache_p _tbc)
01264 {
01265    if(!_tbc)
01266       return -1;
01267    
01268    lock_get(&_tbc->sem);
01269    
01270    if(_tbc->dtp)
01271       tbl_free(_tbc->dtp);
01272    
01273    lock_destroy(&_tbc->sem);
01274    pkg_free(_tbc);
01275 
01276    return 0;
01277 }
01278 
01279 
01280 /**
01281  * close DB (sync data to disk) and free mem
01282  */
01283 int tbl_free(table_p _tp)
01284 {  int i;
01285    if(!_tp)
01286       return -1;
01287 
01288    if(_tp->db)
01289       _tp->db->close(_tp->db, 0);
01290    
01291    if(_tp->fp)
01292       fclose(_tp->fp);
01293 
01294    if(_tp->name.s)
01295       pkg_free(_tp->name.s);
01296    
01297    for(i=0;i<_tp->ncols;i++)
01298    {  if(_tp->colp[i])
01299       {  pkg_free(_tp->colp[i]->name.s);
01300          pkg_free(_tp->colp[i]->dv.s);
01301          pkg_free(_tp->colp[i]);
01302       }
01303    }
01304 
01305    pkg_free(_tp);
01306    return 0;
01307 }
01308 
01309 int bdblib_recover(table_p _tp, int _rc)
01310 {
01311    switch(_rc)
01312    {
01313       case DB_LOCK_DEADLOCK:
01314       LM_ERR("DB_LOCK_DEADLOCK detected !!\n");
01315       
01316       case DB_RUNRECOVERY:
01317       LM_ERR("DB_RUNRECOVERY detected !! \n");
01318       bdblib_destroy();
01319       exit(1);
01320       break;
01321    }
01322    
01323    return 0;
01324 }

Generated on Thu May 17 12:00:25 2012 for Kamailio - The Open Source SIP Server by  doxygen 1.5.6