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_reset_content(ht_t *ht) { ht_cell_t *it; ht_cell_t *it0; int i; if(ht==NULL) return -1; for(i=0; i<ht->htsize; i++) { /* free entries */ ht_slot_lock(ht, i); it = ht->entries[i].first; while(it) { it0 = it->next; if(it->prev==NULL) ht->entries[i].first = it->next; else it->prev->next = it->next; if(it->next) it->next->prev = it->prev; ht->entries[i].esize--; ht_cell_free(it); it = it0; } ht_slot_unlock(ht, i); } return 0; }
int ht_rm_cell_re(str *sre, ht_t *ht, int mode) { ht_cell_t *it; ht_cell_t *it0; int i; regex_t re; int match; regmatch_t pmatch; if(sre==NULL || sre->len<=0 || ht==NULL) return -1; if (regcomp(&re, sre->s, REG_EXTENDED|REG_ICASE|REG_NEWLINE)) { LM_ERR("bad re %s\n", sre->s); return -1; } for(i=0; i<ht->htsize; i++) { /* free entries */ lock_get(&ht->entries[i].lock); it = ht->entries[i].first; while(it) { it0 = it->next; match = 0; if(mode==0) { if (regexec(&re, it->name.s, 1, &pmatch, 0)==0) match = 1; } else { if(it->flags&AVP_VAL_STR) if (regexec(&re, it->value.s.s, 1, &pmatch, 0)==0) match = 1; } if(match==1) { if(it->prev==NULL) ht->entries[i].first = it->next; else it->prev->next = it->next; if(it->next) it->next->prev = it->prev; ht->entries[i].esize--; ht_cell_free(it); } it = it0; } lock_release(&ht->entries[i].lock); } regfree(&re); return 0; }
void ht_timer(unsigned int ticks, void *param) { ht_t *ht; ht_cell_t *it; ht_cell_t *it0; time_t now; int i; int istart; int istep; if(_ht_root==NULL) return; now = time(NULL); istart = (int)(long)param; if(ht_timer_procs<=0) istep = 1; else istep = ht_timer_procs; ht = _ht_root; while(ht) { if(ht->htexpire>0) { for(i=istart; i<ht->htsize; i+=istep) { /* free entries */ ht_slot_lock(ht, i); it = ht->entries[i].first; while(it) { it0 = it->next; if(it->expire!=0 && it->expire<now) { /* expired */ ht_handle_expired_record(ht, it); if(it->prev==NULL) ht->entries[i].first = it->next; else it->prev->next = it->next; if(it->next) it->next->prev = it->prev; ht->entries[i].esize--; ht_cell_free(it); } it = it0; } ht_slot_unlock(ht, i); } } ht = ht->next; } return; }
int ht_rm_cell_op(str *sre, ht_t *ht, int mode, int op) { ht_cell_t *it; ht_cell_t *it0; int match; int i; if(sre==NULL || sre->len<=0 || ht==NULL) return -1; for(i=0; i<ht->htsize; i++) { /* free entries */ ht_slot_lock(ht, i); it = ht->entries[i].first; while(it) { it0 = it->next; match = 0; if(mode==0) { if(op==HT_RM_OP_SW) { if(sre->len<=it->name.len && strncmp(it->name.s, sre->s, sre->len)==0) { match = 1; } } } else { if(op==HT_RM_OP_SW) { if(it->flags&AVP_VAL_STR) { if(sre->len<=it->value.s.len && strncmp(it->value.s.s, sre->s, sre->len)==0) { match = 1; } } } } if(match==1) { if(it->prev==NULL) ht->entries[i].first = it->next; else it->prev->next = it->next; if(it->next) it->next->prev = it->prev; ht->entries[i].esize--; ht_cell_free(it); } it = it0; } ht_slot_unlock(ht, i); } return 0; }
void ht_timer(unsigned int ticks, void *param) { ht_t *ht; ht_cell_t *it; ht_cell_t *it0; time_t now; int i; if(_ht_root==NULL) return; now = time(NULL); ht = _ht_root; while(ht) { if(ht->htexpire>0) { for(i=0; i<ht->htsize; i++) { /* free entries */ lock_get(&ht->entries[i].lock); it = ht->entries[i].first; while(it) { it0 = it->next; if(it->expire!=0 && it->expire<now) { /* expired */ ht_handle_expired_record(ht, it); if(it->prev==NULL) ht->entries[i].first = it->next; else it->prev->next = it->next; if(it->next) it->next->prev = it->prev; ht->entries[i].esize--; ht_cell_free(it); } it = it0; } lock_release(&ht->entries[i].lock); } } ht = ht->next; } return; }
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; }
int ht_destroy(void) { int i; ht_cell_t *it, *it0; ht_t *ht; ht_t *ht0; if(_ht_root==NULL) return -1; ht = _ht_root; while(ht) { ht0 = ht->next; if(ht->entries!=NULL) { for(i=0; i<ht->htsize; i++) { /* free entries */ it = ht->entries[i].first; while(it) { it0 = it; it = it->next; ht_cell_free(it0); } /* free locks */ lock_destroy(&ht->entries[i].lock); } shm_free(ht->entries); } shm_free(ht); ht = ht0; } _ht_root = NULL; return 0; }
static struct mi_root* ht_mi_reload(struct mi_root* cmd_tree, void* param) { struct mi_node* node; str htname; ht_t *ht; ht_t nht; ht_cell_t *first; ht_cell_t *it; int i; if(ht_db_url.len<=0) return init_mi_tree(500, MI_ERR_RELOAD, MI_ERR_RELOAD_LEN); if(ht_db_init_con()!=0) return init_mi_tree(500, MI_ERR_RELOAD, MI_ERR_RELOAD_LEN); if(ht_db_open_con()!=0) return init_mi_tree(500, MI_ERR_RELOAD, MI_ERR_RELOAD_LEN); node = cmd_tree->node.kids; if(node == NULL) { ht_db_close_con(); return init_mi_tree( 400, MI_MISSING_PARM_S, MI_MISSING_PARM_LEN); } htname = node->value; if(htname.len<=0 || htname.s==NULL) { LM_ERR("bad hash table name\n"); ht_db_close_con(); return init_mi_tree( 500, "bad hash table name", 19); } ht = ht_get_table(&htname); if(ht==NULL || ht->dbtable.len<=0) { LM_ERR("bad hash table name\n"); ht_db_close_con(); return init_mi_tree( 500, "no such hash table", 18); } memcpy(&nht, ht, sizeof(ht_t)); /* it's temporary operation - use system malloc */ nht.entries = (ht_entry_t*)malloc(nht.htsize*sizeof(ht_entry_t)); if(nht.entries == NULL) { ht_db_close_con(); return init_mi_tree(500, MI_ERR_RELOAD, MI_ERR_RELOAD_LEN); } memset(nht.entries, 0, nht.htsize*sizeof(ht_entry_t)); if(ht_db_load_table(&nht, &ht->dbtable, 0)<0) { /* free any entry set if it was a partial load */ for(i=0; i<nht.htsize; i++) { first = nht.entries[i].first; while(first) { it = first; first = first->next; ht_cell_free(it); } } free(nht.entries); ht_db_close_con(); return init_mi_tree(500, MI_ERR_RELOAD, MI_ERR_RELOAD_LEN); } /* replace old entries */ for(i=0; i<nht.htsize; i++) { ht_slot_lock(ht, i); first = ht->entries[i].first; ht->entries[i].first = nht.entries[i].first; ht->entries[i].esize = nht.entries[i].esize; ht_slot_unlock(ht, i); nht.entries[i].first = first; } /* free old entries */ for(i=0; i<nht.htsize; i++) { first = nht.entries[i].first; while(first) { it = first; first = first->next; ht_cell_free(it); } } free(nht.entries); ht_db_close_con(); return init_mi_tree( 200, MI_OK_S, MI_OK_LEN); }
/*! \brief RPC htable.reload command to reload content of a hash table */ static void htable_rpc_reload(rpc_t* rpc, void* c) { str htname; ht_t *ht; ht_t nht; ht_cell_t *first; ht_cell_t *it; int i; if(ht_db_url.len<=0) { rpc->fault(c, 500, "No htable db_url"); return; } if(ht_db_init_con()!=0) { rpc->fault(c, 500, "Failed to init htable db connection"); return; } if(ht_db_open_con()!=0) { rpc->fault(c, 500, "Failed to open htable db connection"); return; } if (rpc->scan(c, "S", &htname) < 1) { rpc->fault(c, 500, "No htable name given"); return; } ht = ht_get_table(&htname); if(ht==NULL) { rpc->fault(c, 500, "No such htable"); return; } memcpy(&nht, ht, sizeof(ht_t)); /* it's temporary operation - use system malloc */ nht.entries = (ht_entry_t*)malloc(nht.htsize*sizeof(ht_entry_t)); if(nht.entries == NULL) { ht_db_close_con(); rpc->fault(c, 500, "Mtree reload failed"); return; } memset(nht.entries, 0, nht.htsize*sizeof(ht_entry_t)); if(ht_db_load_table(&nht, &ht->dbtable, 0)<0) { /* free any entry set if it was a partial load */ for(i=0; i<nht.htsize; i++) { first = nht.entries[i].first; while(first) { it = first; first = first->next; ht_cell_free(it); } } free(nht.entries); ht_db_close_con(); rpc->fault(c, 500, "Mtree reload failed"); return; } /* replace old entries */ for(i=0; i<nht.htsize; i++) { ht_slot_lock(ht, i); first = ht->entries[i].first; ht->entries[i].first = nht.entries[i].first; ht->entries[i].esize = nht.entries[i].esize; ht_slot_unlock(ht, i); nht.entries[i].first = first; } /* free old entries */ for(i=0; i<nht.htsize; i++) { first = nht.entries[i].first; while(first) { it = first; first = first->next; ht_cell_free(it); } } free(nht.entries); ht_db_close_con(); return; }
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; }