km_bdb_lib.c

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