/* * DBText library * * Copyright (C) 2001-2003 FhG Fokus * * This file is part of Kamailio, a free SIP server. * * Kamailio is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version * * Kamailio is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA * */ #include <stdio.h> #include <string.h> #include <time.h> #include <sys/types.h> #include <dirent.h> #include "../../core/mem/shm_mem.h" #include "../../core/mem/mem.h" #include "../../core/dprint.h" #include "../../core/hashes.h" #include "dbt_util.h" #include "dbt_lib.h" static dbt_cache_p *_dbt_cachedb = NULL; static gen_lock_t *_dbt_cachesem = NULL; static dbt_tbl_cachel_p _dbt_cachetbl = NULL; extern int _ksr_is_main; #define DBT_CACHETBL_SIZE 16 /** * */ int dbt_init_cache(void) { int i, j; if(!_dbt_cachesem) { /* init locks */ _dbt_cachesem = lock_alloc(); if(!_dbt_cachesem) { LM_CRIT("could not alloc a lock\n"); return -1; } if (lock_init(_dbt_cachesem)==0) { LM_CRIT("could not initialize a lock\n"); lock_dealloc(_dbt_cachesem); return -1; } } /* init pointer to caches list */ if (!_dbt_cachedb) { _dbt_cachedb = shm_malloc( sizeof(dbt_cache_p) ); if (!_dbt_cachedb) { LM_CRIT("no enough shm mem\n"); lock_dealloc(_dbt_cachesem); return -1; } *_dbt_cachedb = NULL; } /* init tables' hash table */ if (!_dbt_cachetbl) { _dbt_cachetbl = (dbt_tbl_cachel_p)shm_malloc(DBT_CACHETBL_SIZE* sizeof(dbt_tbl_cachel_t)); if(_dbt_cachetbl==NULL) { LM_CRIT("no enough shm mem\n"); lock_dealloc(_dbt_cachesem); shm_free(_dbt_cachedb); return -1; } memset(_dbt_cachetbl, 0, DBT_CACHETBL_SIZE*sizeof(dbt_tbl_cachel_t)); for(i=0; i<DBT_CACHETBL_SIZE; i++) { if (lock_init(&_dbt_cachetbl[i].sem)==0) { LM_CRIT("cannot init tables' sem's\n"); for(j=i-1; j>=0; j--) lock_destroy(&_dbt_cachetbl[j].sem); lock_dealloc(_dbt_cachesem); shm_free(_dbt_cachedb); return -1; } } } return 0; } /** * */ dbt_cache_p dbt_cache_get_db(str *_s) { dbt_cache_p _dcache=NULL;; if(!_dbt_cachesem || !_dbt_cachedb) { LM_ERR("dbtext cache is not initialized! Check if you loaded" " dbtext before any other module that uses it\n"); return NULL; } if(!_s || !_s->s || _s->len<=0) return NULL; LM_DBG("looking for db %.*s!\n",_s->len,_s->s); lock_get(_dbt_cachesem); _dcache = *_dbt_cachedb; while(_dcache) { if(_dcache->name.len==_s->len && !strncasecmp(_dcache->name.s, _s->s, _s->len)) { LM_DBG("db already cached!\n"); goto done; } _dcache = _dcache->next; } if(!dbt_is_database(_s)) { LM_ERR("database [%.*s] does not exists!\n", _s->len, _s->s); goto done; } LM_INFO("using database at: %.*s\n", _s->len, _s->s); _dcache = (dbt_cache_p)shm_malloc(sizeof(dbt_cache_t)); if(!_dcache) { LM_ERR(" no shm memory for dbt_cache_t.\n"); goto done; } memset(_dcache, 0, sizeof(dbt_cache_t)); _dcache->name.s = (char*)shm_malloc((_s->len+1)*sizeof(char)); if(!_dcache->name.s) { LM_ERR(" no shm memory for s!!\n"); shm_free(_dcache); _dcache = NULL; goto done; } memcpy(_dcache->name.s, _s->s, _s->len); _dcache->name.s[_s->len] = '\0'; _dcache->name.len = _s->len; if(*_dbt_cachedb) _dcache->next = *_dbt_cachedb; *_dbt_cachedb = _dcache; done: lock_release(_dbt_cachesem); return _dcache; } /** * */ int dbt_cache_check_db(str *_s) { dbt_cache_p _dcache=NULL;; if(!_dbt_cachesem || !(*_dbt_cachedb) || !_s || !_s->s || _s->len<=0) return -1; lock_get(_dbt_cachesem); _dcache = *_dbt_cachedb; while(_dcache) { if(_dcache->name.len == _s->len && strncasecmp(_dcache->name.s, _s->s, _s->len)) { lock_release(_dbt_cachesem); return 0; } _dcache = _dcache->next; } lock_release(_dbt_cachesem); return -1; } /** * */ int dbt_db_del_table(dbt_cache_p _dc, const str *_s, int sync) { dbt_table_p _tbc = NULL; int hash; int hashidx; if(!_dbt_cachetbl || !_dc || !_s || !_s->s || _s->len<=0) return -1; hash = core_hash(&_dc->name, _s, DBT_CACHETBL_SIZE); hashidx = hash % DBT_CACHETBL_SIZE; if(sync) lock_get(&_dbt_cachetbl[hashidx].sem); _tbc = _dbt_cachetbl[hashidx].dtp; while(_tbc) { if(_tbc->hash==hash && _tbc->dbname.len == _dc->name.len && _tbc->name.len == _s->len && !strncasecmp(_tbc->dbname.s, _dc->name.s, _dc->name.len) && !strncasecmp(_tbc->name.s, _s->s, _s->len)) { if(_tbc->prev) (_tbc->prev)->next = _tbc->next; else _dbt_cachetbl[hashidx].dtp = _tbc->next; if(_tbc->next) (_tbc->next)->prev = _tbc->prev; break; } _tbc = _tbc->next; } if(sync) lock_release(&_dbt_cachetbl[hashidx].sem); dbt_table_free(_tbc); return 0; } /** * */ dbt_table_p dbt_db_get_table(dbt_cache_p _dc, const str *_s) { dbt_table_p _tbc = NULL; int hash; int hashidx; if(!_dbt_cachetbl || !_dc || !_s || !_s->s || _s->len<=0) { LM_ERR("invalid parameter\n"); return NULL; } hash = core_hash(&_dc->name, _s, DBT_CACHETBL_SIZE); hashidx = hash % DBT_CACHETBL_SIZE; if(!_ksr_is_main) lock_get(&_dbt_cachetbl[hashidx].sem); _tbc = _dbt_cachetbl[hashidx].dtp; while(_tbc) { if(_tbc->hash==hash && _tbc->dbname.len == _dc->name.len && _tbc->name.len == _s->len && !strncasecmp(_tbc->dbname.s, _dc->name.s, _dc->name.len) && !strncasecmp(_tbc->name.s, _s->s, _s->len)) { /* found - if cache mode or no-change, return */ if(db_mode==0 || dbt_check_mtime(_s, &(_dc->name), &(_tbc->mt))!=1) { LM_DBG("cache or mtime succeeded for [%.*s]\n", _tbc->name.len, _tbc->name.s); return _tbc; } break; } _tbc = _tbc->next; } /* new table */ if(_tbc) /* free old one */ { dbt_db_del_table(_dc, _s, 0); } _tbc = dbt_load_file(_s, &(_dc->name)); if(!_tbc) { LM_ERR("could not load database from file [%.*s]\n", _s->len, _s->s); lock_release(&_dbt_cachetbl[hashidx].sem); return NULL; } _tbc->hash = hash; _tbc->next = _dbt_cachetbl[hashidx].dtp; if(_dbt_cachetbl[hashidx].dtp) _dbt_cachetbl[hashidx].dtp->prev = _tbc; _dbt_cachetbl[hashidx].dtp = _tbc; /* table is locked */ return _tbc; } int dbt_release_table(dbt_cache_p _dc, const str *_s) { int hash; int hashidx; if(!_dbt_cachetbl || !_dc || !_s || !_s->s || _s->len<=0) return -1; hash = core_hash(&_dc->name, _s, DBT_CACHETBL_SIZE); hashidx = hash % DBT_CACHETBL_SIZE; lock_release(&_dbt_cachetbl[hashidx].sem); return 0; } /** * */ int dbt_cache_destroy(void) { int i; dbt_cache_p _dc=NULL, _dc0=NULL; dbt_table_p _tbc = NULL; dbt_table_p _tbc0 = NULL; if(!_dbt_cachesem) return -1; lock_get(_dbt_cachesem); if( _dbt_cachedb!=NULL ) { _dc = *_dbt_cachedb; while(_dc) { _dc0 = _dc; _dc = _dc->next; shm_free(_dc0->name.s); shm_free(_dc0); } shm_free(_dbt_cachedb); } lock_destroy(_dbt_cachesem); lock_dealloc(_dbt_cachesem); /* destroy tables' hash table*/ if(_dbt_cachetbl==0) return 0; for(i=0; i<DBT_CACHETBL_SIZE; i++) { lock_destroy(&_dbt_cachetbl[i].sem); _tbc = _dbt_cachetbl[i].dtp; while(_tbc) { _tbc0 = _tbc; _tbc = _tbc->next; dbt_table_free(_tbc0); } } shm_free(_dbt_cachetbl); return 0; } /** * */ int dbt_cache_print2(int _f, int _lock) { int i; dbt_table_p _tbc; if(!_dbt_cachetbl) return -1; for(i=0; i< DBT_CACHETBL_SIZE; i++) { if(_lock) lock_get(&_dbt_cachetbl[i].sem); _tbc = _dbt_cachetbl[i].dtp; while(_tbc) { if(! (_tbc->flag & DBT_TBFL_TEMP)) { if(_f) fprintf(stdout, "\n--- Database [%.*s]\n", _tbc->dbname.len, _tbc->dbname.s); if(_f) { fprintf(stdout, "\n----- Table [%.*s]\n", _tbc->name.len, _tbc->name.s); fprintf(stdout, "------- LA=<%d> FL=<%x> AC=<%d>" " AV=<%d>\n", _tbc->mark, _tbc->flag, _tbc->auto_col, _tbc->auto_val); dbt_print_table(_tbc, NULL); } else { if(_tbc->flag & DBT_TBFL_MODI) { dbt_print_table(_tbc, &(_tbc->dbname)); dbt_table_update_flags(_tbc,DBT_TBFL_MODI, DBT_FL_UNSET, 0); } } } _tbc = _tbc->next; } if(_lock) lock_release(&_dbt_cachetbl[i].sem); } return 0; } int dbt_cache_print(int _f) { return dbt_cache_print2(_f, !_ksr_is_main); } int dbt_is_neq_type(db_type_t _t0, db_type_t _t1) { // LM_DBG("t0=%d t1=%d!\n", _t0, _t1); if(_t0 == _t1) return 0; switch(_t1) { case DB1_INT: if(_t0==DB1_DATETIME || _t0==DB1_BITMAP) return 0; break; case DB1_BIGINT: LM_ERR("BIGINT not supported\n"); return 0; case DB1_DATETIME: if(_t0==DB1_INT) return 0; if(_t0==DB1_BITMAP) return 0; break; case DB1_DOUBLE: break; case DB1_STRING: if(_t0==DB1_STR || _t0==DB1_BLOB) return 0; break; case DB1_STR: if(_t0==DB1_STRING || _t0==DB1_BLOB) return 0; break; case DB1_BLOB: if(_t0==DB1_STR || _t0==DB1_STRING) return 0; break; case DB1_BITMAP: if (_t0==DB1_INT) return 0; break; default: LM_ERR("invalid datatype %d\n", _t1); return 1; } return 1; } static int tmp_table_number = 0; dbt_table_p dbt_db_get_temp_table(dbt_cache_p _dc) { dbt_table_p _tbc = NULL; str _s; char buf[30]; int hash; int hashidx; if(!_dbt_cachetbl || !_dc) { LM_ERR("invalid parameter\n"); return NULL; } sprintf(buf, "tmp-%i-%i", my_pid(), ++tmp_table_number); _s.s = buf; _s.len = strlen(buf); hash = core_hash(&_dc->name, &_s, DBT_CACHETBL_SIZE); hashidx = hash % DBT_CACHETBL_SIZE; lock_get(&_dbt_cachetbl[hashidx].sem); _tbc = _dbt_cachetbl[hashidx].dtp; _tbc = dbt_table_new(&_s, &(_dc->name), NULL); _tbc->hash = hash; _tbc->next = _dbt_cachetbl[hashidx].dtp; if(_dbt_cachetbl[hashidx].dtp) _dbt_cachetbl[hashidx].dtp->prev = _tbc; _dbt_cachetbl[hashidx].dtp = _tbc; dbt_table_update_flags(_tbc, DBT_TBFL_TEMP, DBT_FL_SET, 0); lock_release(&_dbt_cachetbl[hashidx].sem); return _tbc; }