mirror of https://github.com/sipwise/kamailio.git
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
520 lines
10 KiB
520 lines
10 KiB
/*
|
|
* 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 "../../mem/shm_mem.h"
|
|
#include "../../mem/mem.h"
|
|
#include "../../dprint.h"
|
|
#include "../../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 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_DBG("new db!\n");
|
|
|
|
_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(!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, !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;
|
|
|
|
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;
|
|
case DB1_DOUBLE:
|
|
break;
|
|
case DB1_STRING:
|
|
if(_t0==DB1_STR || _t0==DB1_BLOB)
|
|
return 0;
|
|
case DB1_STR:
|
|
if(_t0==DB1_STRING || _t0==DB1_BLOB)
|
|
return 0;
|
|
case DB1_BLOB:
|
|
if(_t0==DB1_STR || _t0==DB1_STRING)
|
|
return 0;
|
|
case DB1_BITMAP:
|
|
if (_t0==DB1_INT)
|
|
return 0;
|
|
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;
|
|
}
|