static int ki_ht_slot_xlock(sip_msg_t *msg, str *htname, str *skey, int lmode) { ht_t *ht; unsigned int hid; unsigned int idx; ht = ht_get_table(htname); if(ht==NULL) { LM_ERR("cannot get hash table by name [%.*s] (%d)\n", htname->len, htname->s, lmode); return -1; } hid = ht_compute_hash(skey); idx = ht_get_entry(hid, ht->htsize); if(lmode==0) { LM_DBG("locking slot %.*s[%u] for key %.*s\n", htname->len, htname->s, idx, skey->len, skey->s); ht_slot_lock(ht, idx); } else { LM_DBG("unlocking slot %.*s[%u] for key %.*s\n", htname->len, htname->s, idx, skey->len, skey->s); ht_slot_unlock(ht, idx); } return 1; }
ht_cell_t* ht_cell_pkg_copy(ht_t *ht, str *name, ht_cell_t *old) { unsigned int idx; unsigned int hid; ht_cell_t *it, *cell; if(ht==NULL || ht->entries==NULL) return NULL; hid = ht_compute_hash(name); idx = ht_get_entry(hid, ht->htsize); /* head test and return */ if(ht->entries[idx].first==NULL) return NULL; lock_get(&ht->entries[idx].lock); it = ht->entries[idx].first; while(it!=NULL && it->cellid < hid) it = it->next; while(it!=NULL && it->cellid == hid) { if(name->len==it->name.len && strncmp(name->s, it->name.s, name->len)==0) { /* found */ if(ht->htexpire>0 && it->expire!=0 && it->expire<time(NULL)) { /* entry has expired, delete it and return NULL */ if(it->prev==NULL) ht->entries[idx].first = it->next; else it->prev->next = it->next; if(it->next) it->next->prev = it->prev; ht->entries[idx].esize--; lock_release(&ht->entries[idx].lock); ht_cell_free(it); return NULL; } if(old!=NULL) { if(old->msize>=it->msize) { memcpy(old, it, it->msize); lock_release(&ht->entries[idx].lock); return old; } } cell = (ht_cell_t*)pkg_malloc(it->msize); if(cell!=NULL) memcpy(cell, it, it->msize); lock_release(&ht->entries[idx].lock); return cell; } it = it->next; } lock_release(&ht->entries[idx].lock); return NULL; }
int ht_add_table(str *name, int autoexp, str *dbtable, int size, int dbmode, int itype, int_str *ival, int updateexpire, int dmqreplicate) { unsigned int htid; ht_t *ht; htid = ht_compute_hash(name); /* does it exist */ ht = _ht_root; while(ht!=NULL) { if(htid == ht->htid && name->len==ht->name.len && strncmp(name->s, ht->name.s, name->len)==0) { LM_ERR("htable already configured [%.*s]\n", name->len, name->s); return -1; } ht = ht->next; } ht = (ht_t*)shm_malloc(sizeof(ht_t)); if(ht==NULL) { LM_ERR("no more shared memory\n"); return -1; } memset(ht, 0, sizeof(ht_t)); if(size<=1) ht->htsize = 8; else if(size>31) ht->htsize = 1<<14; else ht->htsize = 1<<size; ht->htid = htid; ht->htexpire = autoexp; ht->updateexpire = updateexpire; ht->name = *name; if(dbtable!=NULL && dbtable->len>0) ht->dbtable = *dbtable; ht->dbmode = dbmode; ht->flags = itype; if(ival!=NULL) ht->initval = *ival; ht->dmqreplicate = dmqreplicate; ht->next = _ht_root; _ht_root = ht; return 0; }
int ht_set_cell_expire(ht_t *ht, str *name, int type, int_str *val) { unsigned int idx; unsigned int hid; ht_cell_t *it; time_t now; if(ht==NULL || ht->entries==NULL) return -1; /* str value - ignore */ if(type&AVP_VAL_STR) return 0; /* not auto-expire htable */ if(ht->htexpire==0) return 0; hid = ht_compute_hash(name); idx = ht_get_entry(hid, ht->htsize); now = 0; if(val->n>0) now = time(NULL) + val->n; LM_DBG("set auto-expire to %u (%d)\n", (unsigned int)now, val->n); lock_get(&ht->entries[idx].lock); it = ht->entries[idx].first; while(it!=NULL && it->cellid < hid) it = it->next; while(it!=NULL && it->cellid == hid) { if(name->len==it->name.len && strncmp(name->s, it->name.s, name->len)==0) { /* update value */ it->expire = now; lock_release(&ht->entries[idx].lock); return 0; } it = it->next; } lock_release(&ht->entries[idx].lock); return 0; }
int ht_del_cell(ht_t *ht, str *name) { unsigned int idx; unsigned int hid; ht_cell_t *it; if(ht==NULL || ht->entries==NULL) return -1; hid = ht_compute_hash(name); idx = ht_get_entry(hid, ht->htsize); /* head test and return */ if(ht->entries[idx].first==NULL) return 0; lock_get(&ht->entries[idx].lock); it = ht->entries[idx].first; while(it!=NULL && it->cellid < hid) it = it->next; while(it!=NULL && it->cellid == hid) { if(name->len==it->name.len && strncmp(name->s, it->name.s, name->len)==0) { /* found */ if(it->prev==NULL) ht->entries[idx].first = it->next; else it->prev->next = it->next; if(it->next) it->next->prev = it->prev; ht->entries[idx].esize--; lock_release(&ht->entries[idx].lock); ht_cell_free(it); return 0; } it = it->next; } lock_release(&ht->entries[idx].lock); return 0; }
ht_t* ht_get_table(str *name) { unsigned int htid; ht_t *ht; htid = ht_compute_hash(name); /* does it exist */ ht = _ht_root; while(ht!=NULL) { if(htid == ht->htid && name->len==ht->name.len && strncmp(name->s, ht->name.s, name->len)==0) { LM_DBG("htable found [%.*s]\n", name->len, name->s); return ht; } ht = ht->next; } return NULL; }
int ht_get_cell_expire(ht_t *ht, str *name, unsigned int *val) { unsigned int idx; unsigned int hid; ht_cell_t *it; time_t now; if(ht==NULL || ht->entries==NULL) return -1; *val = 0; /* not auto-expire htable */ if(ht->htexpire==0) return 0; hid = ht_compute_hash(name); idx = ht_get_entry(hid, ht->htsize); now = time(NULL); lock_get(&ht->entries[idx].lock); it = ht->entries[idx].first; while(it!=NULL && it->cellid < hid) it = it->next; while(it!=NULL && it->cellid == hid) { if(name->len==it->name.len && strncmp(name->s, it->name.s, name->len)==0) { /* update value */ *val = (unsigned int)(it->expire - now); lock_release(&ht->entries[idx].lock); return 0; } it = it->next; } lock_release(&ht->entries[idx].lock); return 0; }
/** * unlock the slot for a given key in a hash table */ static int w_ht_slot_unlock(struct sip_msg* msg, char* key, char* foo) { ht_pv_t *hpv; str skey; pv_spec_t *sp; unsigned int hid; unsigned int idx; sp = (pv_spec_t*)key; hpv = (ht_pv_t*)sp->pvp.pvn.u.dname; if(hpv->ht==NULL) { hpv->ht = ht_get_table(&hpv->htname); if(hpv->ht==NULL) { LM_ERR("cannot get $sht root\n"); return -11; } } if(pv_printf_s(msg, hpv->pve, &skey)!=0) { LM_ERR("cannot get $sht key\n"); return -1; } hid = ht_compute_hash(&skey); idx = ht_get_entry(hid, hpv->ht->htsize); LM_DBG("unlocking slot %.*s[%u] for key %.*s\n", hpv->htname.len, hpv->htname.s, idx, skey.len, skey.s); ht_slot_unlock(hpv->ht, idx); return 1; }
ht_cell_t* ht_cell_value_add(ht_t *ht, str *name, int val, int mode, ht_cell_t *old) { unsigned int idx; unsigned int hid; ht_cell_t *it, *prev, *cell; time_t now; int_str isval; if(ht==NULL || ht->entries==NULL) return NULL; hid = ht_compute_hash(name); idx = ht_get_entry(hid, ht->htsize); now = 0; if(ht->htexpire>0) now = time(NULL); prev = NULL; if(mode) lock_get(&ht->entries[idx].lock); it = ht->entries[idx].first; while(it!=NULL && it->cellid < hid) { prev = it; it = it->next; } while(it!=NULL && it->cellid == hid) { if(name->len==it->name.len && strncmp(name->s, it->name.s, name->len)==0) { /* found */ if(now>0 && it->expire!=0 && it->expire<now) { /* entry has expired */ if(ht->flags==PV_VAL_INT) { /* initval is integer, use it to create a fresh entry */ it->flags &= ~AVP_VAL_STR; it->value.n = ht->initval.n; /* increment will be done below */ } else { /* delete expired entry */ if(it->prev==NULL) ht->entries[idx].first = it->next; else it->prev->next = it->next; if(it->next) it->next->prev = it->prev; ht->entries[idx].esize--; lock_release(&ht->entries[idx].lock); ht_cell_free(it); return NULL; } } /* update value */ if(it->flags&AVP_VAL_STR) { /* string value cannot be incremented */ if(mode) lock_release(&ht->entries[idx].lock); return NULL; } else { it->value.n += val; it->expire = now + ht->htexpire; if(old!=NULL) { if(old->msize>=it->msize) { memcpy(old, it, it->msize); lock_release(&ht->entries[idx].lock); return old; } } cell = (ht_cell_t*)pkg_malloc(it->msize); if(cell!=NULL) memcpy(cell, it, it->msize); if(mode) lock_release(&ht->entries[idx].lock); return cell; } } prev = it; it = it->next; } /* add val if htable has an integer init value */ if(ht->flags!=PV_VAL_INT) return NULL; isval.n = ht->initval.n + val; it = ht_cell_new(name, 0, &isval, hid); if(it == NULL) { LM_ERR("cannot create new cell.\n"); if(mode) lock_release(&ht->entries[idx].lock); return NULL; } it->expire = now + ht->htexpire; if(prev==NULL) { if(ht->entries[idx].first!=NULL) { it->next = ht->entries[idx].first; ht->entries[idx].first->prev = it; } ht->entries[idx].first = it; } else { it->next = prev->next; it->prev = prev; if(prev->next) prev->next->prev = it; prev->next = it; } ht->entries[idx].esize++; if(old!=NULL) { if(old->msize>=it->msize) { memcpy(old, it, it->msize); lock_release(&ht->entries[idx].lock); return old; } } cell = (ht_cell_t*)pkg_malloc(it->msize); if(cell!=NULL) memcpy(cell, it, it->msize); if(mode) lock_release(&ht->entries[idx].lock); return cell; }
int ht_set_cell(ht_t *ht, str *name, int type, int_str *val, int mode) { unsigned int idx; unsigned int hid; ht_cell_t *it, *prev, *cell; time_t now; if(ht==NULL || ht->entries==NULL) return -1; hid = ht_compute_hash(name); idx = ht_get_entry(hid, ht->htsize); now = 0; if(ht->htexpire>0) now = time(NULL); prev = NULL; if(mode) lock_get(&ht->entries[idx].lock); it = ht->entries[idx].first; while(it!=NULL && it->cellid < hid) { prev = it; it = it->next; } while(it!=NULL && it->cellid == hid) { if(name->len==it->name.len && strncmp(name->s, it->name.s, name->len)==0) { /* update value */ if(it->flags&AVP_VAL_STR) { if(type&AVP_VAL_STR) { if(it->value.s.len >= val->s.len) { /* copy */ it->value.s.len = val->s.len; memcpy(it->value.s.s, val->s.s, val->s.len); it->value.s.s[it->value.s.len] = '\0'; if(ht->updateexpire) it->expire = now + ht->htexpire; } else { /* new */ cell = ht_cell_new(name, type, val, hid); if(cell == NULL) { LM_ERR("cannot create new cell\n"); if(mode) lock_release(&ht->entries[idx].lock); return -1; } cell->next = it->next; cell->prev = it->prev; cell->expire = now + ht->htexpire; if(it->prev) it->prev->next = cell; else ht->entries[idx].first = cell; if(it->next) it->next->prev = cell; ht_cell_free(it); } } else { it->flags &= ~AVP_VAL_STR; it->value.n = val->n; if(ht->updateexpire) it->expire = now + ht->htexpire; } if(mode) lock_release(&ht->entries[idx].lock); return 0; } else { if(type&AVP_VAL_STR) { /* new */ cell = ht_cell_new(name, type, val, hid); if(cell == NULL) { LM_ERR("cannot create new cell.\n"); if(mode) lock_release(&ht->entries[idx].lock); return -1; } cell->expire = now + ht->htexpire; cell->next = it->next; cell->prev = it->prev; if(it->prev) it->prev->next = cell; else ht->entries[idx].first = cell; if(it->next) it->next->prev = cell; ht_cell_free(it); } else { it->value.n = val->n; if(ht->updateexpire) it->expire = now + ht->htexpire; } if(mode) lock_release(&ht->entries[idx].lock); return 0; } } prev = it; it = it->next; } /* add */ cell = ht_cell_new(name, type, val, hid); if(cell == NULL) { LM_ERR("cannot create new cell.\n"); if(mode) lock_release(&ht->entries[idx].lock); return -1; } cell->expire = now + ht->htexpire; if(prev==NULL) { if(ht->entries[idx].first!=NULL) { cell->next = ht->entries[idx].first; ht->entries[idx].first->prev = cell; } ht->entries[idx].first = cell; } else { cell->next = prev->next; cell->prev = prev; if(prev->next) prev->next->prev = cell; prev->next = cell; } ht->entries[idx].esize++; if(mode) lock_release(&ht->entries[idx].lock); return 0; }
int ht_add_table(str *name, int autoexp, str *dbtable, str *dbcols, int size, int dbmode, int itype, int_str *ival, int updateexpire, int dmqreplicate) { unsigned int htid; ht_t *ht; int c; int i; htid = ht_compute_hash(name); /* does it exist */ ht = _ht_root; while(ht!=NULL) { if(htid == ht->htid && name->len==ht->name.len && strncmp(name->s, ht->name.s, name->len)==0) { LM_ERR("htable already configured [%.*s]\n", name->len, name->s); return -1; } ht = ht->next; } ht = (ht_t*)shm_malloc(sizeof(ht_t)); if(ht==NULL) { LM_ERR("no more shared memory\n"); return -1; } memset(ht, 0, sizeof(ht_t)); if(size<=1) ht->htsize = 8; else if(size>31) ht->htsize = 1<<14; else ht->htsize = 1<<size; ht->htid = htid; ht->htexpire = autoexp; ht->updateexpire = updateexpire; ht->name = *name; if(dbtable!=NULL && dbtable->len>0) ht->dbtable = *dbtable; ht->dbmode = dbmode; ht->flags = itype; if(ival!=NULL) ht->initval = *ival; ht->dmqreplicate = dmqreplicate; if(dbcols!=NULL && dbcols->s!=NULL && dbcols->len>0) { ht->scols[0].s = (char*)shm_malloc((1+dbcols->len)*sizeof(char)); if(ht->scols[0].s==NULL) { LM_ERR("no more shm memory\n"); shm_free(ht); return -1; } memset(ht->scols[0].s, 0, (1+dbcols->len)*sizeof(char)); memcpy(ht->scols[0].s, dbcols->s, dbcols->len); ht->scols[0].len = dbcols->len; c = 0; for(i=0; i<dbcols->len; i++) { if(ht->scols[0].s[i]==',') { ht->scols[c].len = (ht->scols[0].s + i - ht->scols[c].s); LM_DBG("db table column[%d]='%.*s'\n", c, ht->scols[c].len, ht->scols[c].s); c++; if(c>=HT_MAX_COLS) { LM_ERR("too many columns %d\n", c); shm_free(ht->scols[0].s); shm_free(ht); return -1; } ht->scols[c].s = ht->scols[0].s + i + 1; ht->scols[c].len = ht->scols[0].s + dbcols->len - ht->scols[c].s; } } LM_DBG("db table column[%d]='%.*s'\n", c, ht->scols[c].len, ht->scols[c].s); if(c==0) { LM_ERR("there must be at least two columns (prefix, value)\n"); shm_free(ht->scols[0].s); shm_free(ht); return -1; } ht->ncols = c + 1; ht->pack[0] = 'l'; ht->pack[1] = ','; ht->pack[2] = '*'; } ht->next = _ht_root; _ht_root = ht; return 0; }