From 2625ab3ccdafd8d474018516e6aa36ce48989db3 Mon Sep 17 00:00:00 2001 From: Stefan Mititelu Date: Thu, 5 Nov 2015 16:32:02 +0200 Subject: [PATCH 01/13] rtpengine: hash table to keep the selected nodes Shared memory hash table with global hashtable lock. Add state maintaining the selected rtp node, for a given callid. Hashtable entry expiration time configurable using hash_entry_tout modparam. The actual deletion happens on the fly while insert/remove/lookup are called. Updated doku. --- modules/rtpengine/doc/rtpengine_admin.xml | 26 ++ modules/rtpengine/rtpengine.c | 189 ++++++++++--- modules/rtpengine/rtpengine_hash.c | 314 ++++++++++++++++++++++ modules/rtpengine/rtpengine_hash.h | 30 +++ 4 files changed, 523 insertions(+), 36 deletions(-) create mode 100644 modules/rtpengine/rtpengine_hash.c create mode 100644 modules/rtpengine/rtpengine_hash.h diff --git a/modules/rtpengine/doc/rtpengine_admin.xml b/modules/rtpengine/doc/rtpengine_admin.xml index b447387dac2..bcb1c030ea4 100644 --- a/modules/rtpengine/doc/rtpengine_admin.xml +++ b/modules/rtpengine/doc/rtpengine_admin.xml @@ -356,6 +356,32 @@ modparam("rtpproxy", "rtp_inst_pvar", "$avp(RTP_INSTANCE)") +
+ <varname>hash_entry_tout</varname> (string) + + Number of seconds after an rtpengine hash table entry is marked for deletion. + By default, this parameter is set to 120 (seconds). + + + To maintain information about a selected rtp machine node, for a given call, entries are added in a hashtable of (callid, node) pairs. + When "offer" comes, insert new entry in the hastable. + When subsequent commands come, lookup callid and return chosen node. + When "delete" comes, remove old entry from hashtable. + + + NOTE: In the current implementation, the actual deletion happens on the fly, + while insert/remove/lookup the hastable, only for the entries in the insert/remove/lookup path. + + + Set <varname>hash_entry_tout</varname> parameter + +... +modparam("rtpproxy", "hash_entry_tout", "300") +... + + +
+
diff --git a/modules/rtpengine/rtpengine.c b/modules/rtpengine/rtpengine.c index 86211cc2211..e1ec46c8dca 100644 --- a/modules/rtpengine/rtpengine.c +++ b/modules/rtpengine/rtpengine.c @@ -78,6 +78,7 @@ #include "../../modules/tm/tm_load.h" #include "rtpengine.h" #include "rtpengine_funcs.h" +#include "rtpengine_hash.h" #include "bencode.h" MODULE_VERSION @@ -187,7 +188,9 @@ static int rtpengine_offer_answer(struct sip_msg *msg, const char *flags, int op static int fixup_set_id(void ** param, int param_no); static int set_rtpengine_set_f(struct sip_msg * msg, char * str1, char * str2); static struct rtpp_set * select_rtpp_set(int id_set); -static struct rtpp_node *select_rtpp_node(str, int); +static struct rtpp_node *select_rtpp_node_new(str, int, int); +static struct rtpp_node *select_rtpp_node_old(str, int, int); +static struct rtpp_node *select_rtpp_node(str, int, int); static char *send_rtpp_command(struct rtpp_node *, bencode_item_t *, int *); static int get_extra_id(struct sip_msg* msg, str *id_str); @@ -228,6 +231,7 @@ static pid_t mypid; static unsigned int myseqn = 0; static str extra_id_pv_param = {NULL, 0}; static char *setid_avp_param = NULL; +static int hash_entry_tout = 120; static char ** rtpp_strings=0; static int rtpp_sets=0; /*used in rtpengine_set_store()*/ @@ -336,6 +340,7 @@ static param_export_t params[] = { {"rtp_inst_pvar", PARAM_STR, &rtp_inst_pv_param }, {"write_sdp_pv", PARAM_STR, &write_sdp_pvar_str }, {"read_sdp_pv", PARAM_STR, &read_sdp_pvar_str }, + {"hash_entry_tout", INT_PARAM, &hash_entry_tout }, {0, 0, 0} }; @@ -1440,6 +1445,14 @@ mod_init(void) return -1; } + /* init the hastable which keeps the call-id <-> selected_node relation */ + if (!rtpengine_hash_table_init()) { + LM_ERR("rtpengine_hash_table_init() failed!\n"); + return -1; + } else { + LM_DBG("rtpengine_hash_table_init() success!\n"); + } + return 0; } @@ -1579,6 +1592,13 @@ static void mod_destroy(void) } shm_free(rtpp_set_list); + + /* destroy the hastable which keeps the call-id <-> selected_node relation */ + if (!rtpengine_hash_table_destroy()) { + LM_ERR("rtpengine_hash_table_destroy() failed!\n"); + } else { + LM_DBG("rtpengine_hash_table_destroy() success!\n"); + } } @@ -1923,16 +1943,17 @@ static bencode_item_t *rtpp_function_call(bencode_buffer_t *bencbuf, struct sip_ LM_ERR("queried nodes limit reached\n"); goto error; } - node = select_rtpp_node(callid, 1); + node = select_rtpp_node(callid, 1, op); if (!node) { LM_ERR("no available proxies\n"); goto error; } + cp = send_rtpp_command(node, ng_flags.dict, &ret); - if (cp == NULL) { - node->rn_disabled = 1; - node->rn_recheck_ticks = get_ticks() + rtpengine_disable_tout; - } + if (cp == NULL) { + node->rn_disabled = 1; + node->rn_recheck_ticks = get_ticks() + rtpengine_disable_tout; + } } while (cp == NULL); LM_DBG("proxy reply: %.*s\n", ret, cp); @@ -1944,12 +1965,13 @@ static bencode_item_t *rtpp_function_call(bencode_buffer_t *bencbuf, struct sip_ LM_ERR("failed to decode bencoded reply from proxy: %.*s\n", ret, cp); goto error; } + if (!bencode_dictionary_get_strcmp(resp, "result", "error")) { if (!bencode_dictionary_get_str(resp, "error-reason", &error)) { LM_ERR("proxy return error but didn't give an error reason: %.*s\n", ret, cp); } else { - if ((RTPENGINE_SESS_LIMIT_MSG_LEN == error.len) && + if ((RTPENGINE_SESS_LIMIT_MSG_LEN == error.len) && (strncmp(error.s, RTPENGINE_SESS_LIMIT_MSG, RTPENGINE_SESS_LIMIT_MSG_LEN) == 0)) { LM_WARN("proxy %.*s: %.*s", node->rn_url.len, node->rn_url.s , error.len, error.s); @@ -1957,12 +1979,23 @@ static bencode_item_t *rtpp_function_call(bencode_buffer_t *bencbuf, struct sip_ } LM_ERR("proxy replied with error: %.*s\n", error.len, error.s); } - goto error; + goto error; } if (body_out) *body_out = body; + if (op == OP_DELETE) { + /* Delete the key<->value from the hashtable */ + if (!rtpengine_hash_table_remove(&callid)) { + LM_ERR("rtpengine hash table failed to remove entry for callen=%d callid=%.*s\n", + callid.len, callid.len, callid.s); + } else { + LM_DBG("rtpengine hash table remove entry for callen=%d callid=%.*s\n", + callid.len, callid.len, callid.s); + } + } + return resp; error: @@ -2191,81 +2224,165 @@ static struct rtpp_set * select_rtpp_set(int id_set ){ return rtpp_list; } + /* - * Main balancing routine. This does not try to keep the same proxy for - * the call if some proxies were disabled or enabled; proxy death considered - * too rare. Otherwise we should implement "mature" HA clustering, which is - * too expensive here. + * run the selection algorithm and return the new selected node */ static struct rtpp_node * -select_rtpp_node(str callid, int do_test) +select_rtpp_node_new(str callid, int do_test, int op) { - unsigned sum, sumcut, weight_sum; struct rtpp_node* node; - int was_forced; - - if(!active_rtpp_set){ - LM_ERR("script error -no valid set selected\n"); - return NULL; - } - /* Most popular case: 1 proxy, nothing to calculate */ - if (active_rtpp_set->rtpp_node_count == 1) { - node = active_rtpp_set->rn_first; - if (node->rn_disabled && node->rn_recheck_ticks <= get_ticks()) - node->rn_disabled = rtpp_test(node, 1, 0); - return node->rn_disabled ? NULL : node; - } + unsigned i, sum, sumcut, weight_sum; + int was_forced = 0; /* XXX Use quick-and-dirty hashing algo */ - for(sum = 0; callid.len > 0; callid.len--) - sum += callid.s[callid.len - 1]; + for(i = 0; i < callid.len; i++) + sum += callid.s[i]; sum &= 0xff; - was_forced = 0; retry: weight_sum = 0; - for (node=active_rtpp_set->rn_first; node!=NULL; node=node->rn_next) { + for (node=active_rtpp_set->rn_first; node!=NULL; node=node->rn_next) { + /* Try to enable if it's time to try. */ if (node->rn_disabled && node->rn_recheck_ticks <= get_ticks()){ - /* Try to enable if it's time to try. */ node->rn_disabled = rtpp_test(node, 1, 0); } - if (!node->rn_disabled) + + /* Select only between enabled machines */ + if (!node->rn_disabled) { weight_sum += node->rn_weight; + } } + + /* No proxies? Force all to be redetected, if not yet */ if (weight_sum == 0) { - /* No proxies? Force all to be redetected, if not yet */ - if (was_forced) + if (was_forced) { return NULL; + } + was_forced = 1; + for(node=active_rtpp_set->rn_first; node!=NULL; node=node->rn_next) { node->rn_disabled = rtpp_test(node, 1, 1); } + goto retry; } + + /* sumcut here lays from 0 to weight_sum-1 */ sumcut = sum % weight_sum; + /* - * sumcut here lays from 0 to weight_sum-1. * Scan proxy list and decrease until appropriate proxy is found. */ for (node=active_rtpp_set->rn_first; node!=NULL; node=node->rn_next) { + /* Select only between enabled machines */ if (node->rn_disabled) continue; + + /* Found enabled machine */ if (sumcut < node->rn_weight) goto found; + + /* Update sumcut if enabled machine */ sumcut -= node->rn_weight; } + /* No node list */ return NULL; + found: if (do_test) { node->rn_disabled = rtpp_test(node, node->rn_disabled, 0); if (node->rn_disabled) goto retry; } + + /* build hash table entry */ + struct rtpengine_hash_entry *entry = shm_malloc(sizeof(struct rtpp_node)); + if (shm_str_dup(&entry->callid, &callid) < 0) { + LM_ERR("rtpengine hash table fail to duplicate calllen=%d callid=%.*s", + callid.len, callid.len, callid.s); + } + entry->node = node; + entry->next = NULL; + entry->tout = get_ticks() + hash_entry_tout; + + /* Insert the key<->entry from the hashtable */ + if (!rtpengine_hash_table_insert(&callid, entry)) { + LM_ERR("rtpengine hash table fail to insert node=%.*s for calllen=%d callid=%.*s", + node->rn_url.len, node->rn_url.s, callid.len, callid.len, callid.s); + } else { + LM_DBG("rtpengine hash table insert node=%.*s for calllen=%d callid=%.*s\n", + node->rn_url.len, node->rn_url.s, callid.len, callid.len, callid.s); + } + + /* Return selected node */ return node; } +/* + * lookup the hastable (key=callid value=node) and get the old node + */ +static struct rtpp_node * +select_rtpp_node_old(str callid, int do_test, int op) +{ + struct rtpp_node *node = NULL; + struct rtpengine_hash_entry *entry = NULL; + + entry = rtpengine_hash_table_lookup(&callid); + if (!entry) { + LM_ERR("rtpengine hash table lookup failed to find entry for calllen=%d callid=%.*s\n", + callid.len, callid.len, callid.s); + } else { + LM_DBG("rtpengine hash table lookup find entry for calllen=%d callid=%.*s\n", + callid.len, callid.len, callid.s); + node = entry->node; + } + + if (!node) { + LM_ERR("rtpengine hash table lookup failed to find node for calllen=%d callid=%.*s\n", + callid.len, callid.len, callid.s); + return NULL; + } else { + LM_DBG("rtpengine hash table lookup find node=%.*s for calllen=%d callid=%.*s\n", + node->rn_url.len, node->rn_url.s, callid.len, callid.len, callid.s); + } + + // if node broke, don't send any message + if (!node->rn_disabled) { + return node; + } else { + LM_DBG("rtpengine hash table lookup find node=%.*s for calllen=%d callid=%.*s, which is disabled!\n", + node->rn_url.len, node->rn_url.s, callid.len, callid.len, callid.s); + } + + return NULL; +} + +/* + * Main balancing routine. This DO try to keep the same proxy for + * the call if some proxies were disabled or enabled (e.g. kamctl command) + */ +static struct rtpp_node * +select_rtpp_node(str callid, int do_test, int op) +{ + if(!active_rtpp_set) { + LM_ERR("script error - no valid set selected\n"); + return NULL; + } + + // calculate and choose a node + if (op == OP_OFFER) { + // run the selection algorithm + return select_rtpp_node_new(callid, do_test, op); + } else { + // lookup the hastable (key=callid value=node) and get the old node + return select_rtpp_node_old(callid, do_test, op); + } +} + static int get_extra_id(struct sip_msg* msg, str *id_str) { if(msg==NULL || extra_id_pv==NULL || id_str==NULL) { diff --git a/modules/rtpengine/rtpengine_hash.c b/modules/rtpengine/rtpengine_hash.c new file mode 100644 index 00000000000..f23b45db48c --- /dev/null +++ b/modules/rtpengine/rtpengine_hash.c @@ -0,0 +1,314 @@ +#include "rtpengine_hash.h" + +#include "../../str.h" +#include "../../dprint.h" +#include "../../mem/shm_mem.h" +#include "../../locking.h" +#include "../../timer.h" + +static gen_lock_t *rtpengine_hash_lock; +static struct rtpengine_hash_table *rtpengine_hash_table; + +/* from sipwise rtpengine */ +static int str_cmp_str(const str *a, const str *b) { + if (a->len < b->len) + return -1; + if (a->len > b->len) + return 1; + if (a->len == 0 && b->len == 0) + return 0; + return memcmp(a->s, b->s, a->len); +} + +/* from sipwise rtpengine */ +static int str_equal(void *a, void *b) { + return (str_cmp_str((str *) a, (str *) b) == 0); +} + +/* from sipwise rtpengine */ +static unsigned int str_hash(void *ss) { + const str *s = (str*) ss; + unsigned int ret = 5381; + str it = *s; + + while (it.len > 0) { + ret = (ret << 5) + ret + *it.s; + it.s++; + it.len--; + } + + return ret % RTPENGINE_HASH_TABLE_SIZE; +} + +/* rtpengine glib hash API */ +int rtpengine_hash_table_init() { + int i; + + // init hashtable + rtpengine_hash_table = shm_malloc(sizeof(struct rtpengine_hash_table)); + if (!rtpengine_hash_table) { + LM_ERR("no shm left to create rtpengine_hash_table\n"); + return 0; + } + + // init hashtable entry_list heads (never filled) + for (i = 0; i < RTPENGINE_HASH_TABLE_SIZE; i++) { + rtpengine_hash_table->entry_list[i] = shm_malloc(sizeof(struct rtpengine_hash_entry)); + if (!rtpengine_hash_table->entry_list[i]) { + LM_ERR("no shm left to create rtpengine_hash_table->entry_list[%d]\n", i); + return 0; + } + + /* never expire the head of the hashtable index lists */ + rtpengine_hash_table->entry_list[i]->tout = -1; + rtpengine_hash_table->entry_list[i]->next = NULL; + } + + // init lock + rtpengine_hash_lock = lock_alloc(); + if (!rtpengine_hash_lock) { + LM_ERR("no shm left to init rtpengine_hash_table lock"); + return 0; + } + + return 1; +} + +int rtpengine_hash_table_destroy() { + int i; + struct rtpengine_hash_entry *entry, *last_entry; + + // check rtpengine hashtable + if (!rtpengine_hash_table) { + LM_ERR("NULL rtpengine_hash_table"); + return 0; + } + + // destroy hashtable entry_list content + lock_get(rtpengine_hash_lock); + for (i = 0; i < RTPENGINE_HASH_TABLE_SIZE; i++) { + entry = rtpengine_hash_table->entry_list[i]; + while (entry) { + last_entry = entry; + entry = entry->next; + shm_free(last_entry->callid.s); + shm_free(last_entry); + } + } + + // destroy hashtable + shm_free(rtpengine_hash_table); + rtpengine_hash_table = NULL; + lock_release(rtpengine_hash_lock); + + // destroy lock + if (!rtpengine_hash_lock) { + LM_ERR("NULL rtpengine_hash_lock"); + } else { + lock_dealloc(rtpengine_hash_lock); + rtpengine_hash_lock = NULL; + } + + return 1; +} + +int rtpengine_hash_table_insert(void *key, void *value) { + struct rtpengine_hash_entry *entry, *last_entry; + struct rtpengine_hash_entry *new_entry = (struct rtpengine_hash_entry *) value; + unsigned int hash_index; + + // check rtpengine hashtable + if (!rtpengine_hash_table) { + LM_ERR("NULL rtpengine_hash_table"); + return 0; + } + + // get entry list + hash_index = str_hash(key); + entry = rtpengine_hash_table->entry_list[hash_index]; + last_entry = entry; + + // lock + lock_get(rtpengine_hash_lock); + while (entry) { + // if key found, don't add new entry + if (str_equal(&entry->callid, &new_entry->callid)) { + // unlock + lock_release(rtpengine_hash_lock); + LM_ERR("Call id %.*s already in hashtable, ignore new value", entry->callid.len, entry->callid.s); + return 0; + } + + // if expired entry discovered, delete it + if (entry->tout < get_ticks()) { + // set pointers; exclude entry + last_entry->next = entry->next; + + // free current entry; entry points to unknown + shm_free(entry->callid.s); + shm_free(entry); + + // set pointers + entry = last_entry; + } + + // next entry in the list + last_entry = entry; + entry = entry->next; + } + + last_entry->next = new_entry; + + // unlock + lock_release(rtpengine_hash_lock); + + return 1; +} + +int rtpengine_hash_table_remove(void *key) { + struct rtpengine_hash_entry *entry, *last_entry; + unsigned int hash_index; + + // check rtpengine hashtable + if (!rtpengine_hash_table) { + LM_ERR("NULL rtpengine_hash_table"); + return 0; + } + + // get first entry from entry list; jump over unused list head + hash_index = str_hash(key); + entry = rtpengine_hash_table->entry_list[hash_index]; + last_entry = entry; + + // lock + lock_get(rtpengine_hash_lock); + while (entry) { + // if key found, delete entry + if (str_equal(&entry->callid, (str *)key)) { + // free entry + last_entry->next = entry->next; + shm_free(entry->callid.s); + shm_free(entry); + + // unlock + lock_release(rtpengine_hash_lock); + + return 1; + } + + // if expired entry discovered, delete it + if (entry->tout < get_ticks()) { + // set pointers; exclude entry + last_entry->next = entry->next; + + // free current entry; entry points to unknown + shm_free(entry->callid.s); + shm_free(entry); + + // set pointers + entry = last_entry; + } + + last_entry = entry; + entry = entry->next; + } + + // unlock + lock_release(rtpengine_hash_lock); + + return 0; +} + +void* rtpengine_hash_table_lookup(void *key) { + struct rtpengine_hash_entry *entry, *last_entry; + unsigned int hash_index; + + // check rtpengine hashtable + if (!rtpengine_hash_table) { + LM_ERR("NULL rtpengine_hash_table"); + return 0; + } + + // get first entry from entry list; jump over unused list head + hash_index = str_hash(key); + entry = rtpengine_hash_table->entry_list[hash_index]; + last_entry = entry; + + // lock + lock_get(rtpengine_hash_lock); + while (entry) { + // if key found, return entry + if (str_equal(&entry->callid, (str *)key)) { + // unlock + lock_release(rtpengine_hash_lock); + + return entry; + } + + // if expired entry discovered, delete it + if (entry->tout < get_ticks()) { + // set pointers; exclude entry + last_entry->next = entry->next; + + // free current entry; entry points to unknown + shm_free(entry->callid.s); + shm_free(entry); + + // set pointers + entry = last_entry; + } + + last_entry = entry; + entry = entry->next; + } + + // unlock + lock_release(rtpengine_hash_lock); + + return NULL; +} + +// print hash table entries while deleting expired entries +void rtpengine_hash_table_print() { + int i; + struct rtpengine_hash_entry *entry, *last_entry; + + // check rtpengine hashtable + if (!rtpengine_hash_table) { + LM_ERR("NULL rtpengine_hash_table"); + return ; + } + + // lock + lock_get(rtpengine_hash_lock); + + // print hashtable + for (i = 0; i < RTPENGINE_HASH_TABLE_SIZE; i++) { + entry = rtpengine_hash_table->entry_list[i]; + last_entry = entry; + + while (entry) { + // if expired entry discovered, delete it + if (entry->tout < get_ticks()) { + // set pointers; exclude entry + last_entry->next = entry->next; + + // free current entry; entry points to unknown + shm_free(entry->callid.s); + shm_free(entry); + + // set pointers + entry = last_entry; + } else { + LM_DBG("hash_index=%d callid=%.*s tout=%u\n", + i, entry->callid.len, entry->callid.s, entry->tout - get_ticks()); + } + + last_entry = entry; + entry = entry->next; + } + } + + // unlock + lock_release(rtpengine_hash_lock); +} diff --git a/modules/rtpengine/rtpengine_hash.h b/modules/rtpengine/rtpengine_hash.h new file mode 100644 index 00000000000..71a73b45b1e --- /dev/null +++ b/modules/rtpengine/rtpengine_hash.h @@ -0,0 +1,30 @@ +#ifndef _RTPENGINE_HASH_H +#define _RTPENGINE_HASH_H + +#include "../../str.h" + +#define RTPENGINE_HASH_TABLE_SIZE 512 + +/* table entry */ +struct rtpengine_hash_entry { + unsigned int tout; // call timeout + str callid; // call callid + struct rtpp_node *node; // call selected node + + struct rtpengine_hash_entry *next; // next +}; + +/* table */ +struct rtpengine_hash_table { + struct rtpengine_hash_entry *entry_list[RTPENGINE_HASH_TABLE_SIZE]; +}; + + +int rtpengine_hash_table_init(); +int rtpengine_hash_table_destroy(); +int rtpengine_hash_table_insert(void *key, void *value); +int rtpengine_hash_table_remove(void *key); +void* rtpengine_hash_table_lookup(void *key); +void rtpengine_hash_table_print() ; + +#endif From 02d8a62260fa1d1e98db4a9b5f4cdac8cab1ea4b Mon Sep 17 00:00:00 2001 From: Stefan Mititelu Date: Fri, 6 Nov 2015 17:12:23 +0200 Subject: [PATCH 02/13] rtpengine: Update doku for node enable/disable This is my understanding of the current shared memory node list implementation. Correct me if I'm wrong. --- modules/rtpengine/doc/rtpengine_admin.xml | 32 +++++++++++++++++++++++ 1 file changed, 32 insertions(+) diff --git a/modules/rtpengine/doc/rtpengine_admin.xml b/modules/rtpengine/doc/rtpengine_admin.xml index bcb1c030ea4..2454db2aa05 100644 --- a/modules/rtpengine/doc/rtpengine_admin.xml +++ b/modules/rtpengine/doc/rtpengine_admin.xml @@ -73,6 +73,38 @@ If the set was selected using setid_avp, the avp needs to be set only once before rtpengine_offer() or rtpengine_manage() call. + + From the current implementation point of view, the sets of rtpproxy nodes + are shared memory(shm), so all processes can see a common list of nodes. + There is no locking when setting the nodes enabled/disabled (to keep the + memory access as fast as possible). Thus, problems related to node state + might appear for concurent processes that might set the nodes + enabled/disabled(e.g. by fifo command). This robustness problems are overcomed as follows. + + + + If the current process sees the selected node as disabled, the node is + force tested before the current process actually + takes the disabled decision. If the test succeeds, the process will set + the node as enabled (but other concurrent process might still see it as disabled). +. + + + + If the current process sees the selected node as enabled, it does no additional checks + and sends the command which will fail in case the machine is actually broken. + The process will set the node as disabled (but other concurrent process might still see it as enabled). + + + + The 'kamctl fifo' commands (including rtpengin ones) are executed by an exclusive + process which operate on the same shared memory node list. + + + + All the nodes are pinged in the beginning by all the processes, + even if the node list is shared memory. +
From 7375d0b8f136c09d5f4597338aae2d50214a3293 Mon Sep 17 00:00:00 2001 From: Stefan Mititelu Date: Mon, 9 Nov 2015 12:54:47 +0200 Subject: [PATCH 03/13] rtpengine: Add hash_table_size modparam Allow configurable table size. Updated doku. --- modules/rtpengine/doc/rtpengine_admin.xml | 27 +++++++++++++++++--- modules/rtpengine/rtpengine.c | 14 +++++----- modules/rtpengine/rtpengine_hash.c | 31 +++++++++++++++++------ modules/rtpengine/rtpengine_hash.h | 7 +++-- 4 files changed, 57 insertions(+), 22 deletions(-) diff --git a/modules/rtpengine/doc/rtpengine_admin.xml b/modules/rtpengine/doc/rtpengine_admin.xml index 2454db2aa05..0c8a6477633 100644 --- a/modules/rtpengine/doc/rtpengine_admin.xml +++ b/modules/rtpengine/doc/rtpengine_admin.xml @@ -388,8 +388,26 @@ modparam("rtpproxy", "rtp_inst_pvar", "$avp(RTP_INSTANCE)")
-
- <varname>hash_entry_tout</varname> (string) +
+ <varname>hash_table_size</varname> (integer) + + Size of the hash table. Default value is 256. + + + NOTE: If configured size is less than 1, the size will be defaulted to 1. + + + Set <varname>hash_table_size</varname> parameter + +... +modparam("rtpproxy", "hash_table_size", "123") +... + + +
+ +
+ <varname>hash_table_tout</varname> (integer) Number of seconds after an rtpengine hash table entry is marked for deletion. By default, this parameter is set to 120 (seconds). @@ -405,15 +423,16 @@ modparam("rtpproxy", "rtp_inst_pvar", "$avp(RTP_INSTANCE)") while insert/remove/lookup the hastable, only for the entries in the insert/remove/lookup path. - Set <varname>hash_entry_tout</varname> parameter + Set <varname>hash_table_tout</varname> parameter ... -modparam("rtpproxy", "hash_entry_tout", "300") +modparam("rtpproxy", "hash_table_tout", "300") ...
+
diff --git a/modules/rtpengine/rtpengine.c b/modules/rtpengine/rtpengine.c index e1ec46c8dca..e48f31811e1 100644 --- a/modules/rtpengine/rtpengine.c +++ b/modules/rtpengine/rtpengine.c @@ -231,7 +231,8 @@ static pid_t mypid; static unsigned int myseqn = 0; static str extra_id_pv_param = {NULL, 0}; static char *setid_avp_param = NULL; -static int hash_entry_tout = 120; +static int hash_table_tout = 120; +static int hash_table_size = 256; static char ** rtpp_strings=0; static int rtpp_sets=0; /*used in rtpengine_set_store()*/ @@ -340,7 +341,8 @@ static param_export_t params[] = { {"rtp_inst_pvar", PARAM_STR, &rtp_inst_pv_param }, {"write_sdp_pv", PARAM_STR, &write_sdp_pvar_str }, {"read_sdp_pv", PARAM_STR, &read_sdp_pvar_str }, - {"hash_entry_tout", INT_PARAM, &hash_entry_tout }, + {"hash_table_tout", INT_PARAM, &hash_table_tout }, + {"hash_table_size", INT_PARAM, &hash_table_size }, {0, 0, 0} }; @@ -1446,11 +1448,11 @@ mod_init(void) } /* init the hastable which keeps the call-id <-> selected_node relation */ - if (!rtpengine_hash_table_init()) { - LM_ERR("rtpengine_hash_table_init() failed!\n"); + if (!rtpengine_hash_table_init(hash_table_size)) { + LM_ERR("rtpengine_hash_table_init(%d) failed!\n", hash_table_size); return -1; } else { - LM_DBG("rtpengine_hash_table_init() success!\n"); + LM_DBG("rtpengine_hash_table_init(%d) success!\n", hash_table_size); } return 0; @@ -2307,7 +2309,7 @@ select_rtpp_node_new(str callid, int do_test, int op) } entry->node = node; entry->next = NULL; - entry->tout = get_ticks() + hash_entry_tout; + entry->tout = get_ticks() + hash_table_tout; /* Insert the key<->entry from the hashtable */ if (!rtpengine_hash_table_insert(&callid, entry)) { diff --git a/modules/rtpengine/rtpengine_hash.c b/modules/rtpengine/rtpengine_hash.c index f23b45db48c..3cca5749f6e 100644 --- a/modules/rtpengine/rtpengine_hash.c +++ b/modules/rtpengine/rtpengine_hash.c @@ -8,6 +8,7 @@ static gen_lock_t *rtpengine_hash_lock; static struct rtpengine_hash_table *rtpengine_hash_table; +static int hash_table_size; /* from sipwise rtpengine */ static int str_cmp_str(const str *a, const str *b) { @@ -37,13 +38,21 @@ static unsigned int str_hash(void *ss) { it.len--; } - return ret % RTPENGINE_HASH_TABLE_SIZE; + return ret % hash_table_size; } /* rtpengine glib hash API */ -int rtpengine_hash_table_init() { +int rtpengine_hash_table_init(int size) { int i; + // init hash table size + if (size < 1) { + hash_table_size = 1; + } else { + hash_table_size = size; + } + LM_DBG("rtpengine_hash_table size = %d\n", hash_table_size); + // init hashtable rtpengine_hash_table = shm_malloc(sizeof(struct rtpengine_hash_table)); if (!rtpengine_hash_table) { @@ -51,15 +60,18 @@ int rtpengine_hash_table_init() { return 0; } - // init hashtable entry_list heads (never filled) - for (i = 0; i < RTPENGINE_HASH_TABLE_SIZE; i++) { + // init hashtable entry_list + rtpengine_hash_table->entry_list = shm_malloc(hash_table_size * sizeof(struct rtpengine_hash_entry)); + + // init hashtable entry_list[i] (head never filled) + for (i = 0; i < hash_table_size; i++) { rtpengine_hash_table->entry_list[i] = shm_malloc(sizeof(struct rtpengine_hash_entry)); if (!rtpengine_hash_table->entry_list[i]) { LM_ERR("no shm left to create rtpengine_hash_table->entry_list[%d]\n", i); return 0; } - /* never expire the head of the hashtable index lists */ + // never expire the head of the hashtable index lists rtpengine_hash_table->entry_list[i]->tout = -1; rtpengine_hash_table->entry_list[i]->next = NULL; } @@ -84,9 +96,9 @@ int rtpengine_hash_table_destroy() { return 0; } - // destroy hashtable entry_list content + // destroy hashtable entry_list[i] lock_get(rtpengine_hash_lock); - for (i = 0; i < RTPENGINE_HASH_TABLE_SIZE; i++) { + for (i = 0; i < hash_table_size; i++) { entry = rtpengine_hash_table->entry_list[i]; while (entry) { last_entry = entry; @@ -96,6 +108,9 @@ int rtpengine_hash_table_destroy() { } } + // destroy hashtable entry_list + shm_free(rtpengine_hash_table->entry_list); + // destroy hashtable shm_free(rtpengine_hash_table); rtpengine_hash_table = NULL; @@ -283,7 +298,7 @@ void rtpengine_hash_table_print() { lock_get(rtpengine_hash_lock); // print hashtable - for (i = 0; i < RTPENGINE_HASH_TABLE_SIZE; i++) { + for (i = 0; i < hash_table_size; i++) { entry = rtpengine_hash_table->entry_list[i]; last_entry = entry; diff --git a/modules/rtpengine/rtpengine_hash.h b/modules/rtpengine/rtpengine_hash.h index 71a73b45b1e..b0a8c739317 100644 --- a/modules/rtpengine/rtpengine_hash.h +++ b/modules/rtpengine/rtpengine_hash.h @@ -3,7 +3,6 @@ #include "../../str.h" -#define RTPENGINE_HASH_TABLE_SIZE 512 /* table entry */ struct rtpengine_hash_entry { @@ -11,16 +10,16 @@ struct rtpengine_hash_entry { str callid; // call callid struct rtpp_node *node; // call selected node - struct rtpengine_hash_entry *next; // next + struct rtpengine_hash_entry *next; // call next }; /* table */ struct rtpengine_hash_table { - struct rtpengine_hash_entry *entry_list[RTPENGINE_HASH_TABLE_SIZE]; + struct rtpengine_hash_entry **entry_list; }; -int rtpengine_hash_table_init(); +int rtpengine_hash_table_init(int size); int rtpengine_hash_table_destroy(); int rtpengine_hash_table_insert(void *key, void *value); int rtpengine_hash_table_remove(void *key); From 74fdbe2248ec79d70440bda255c2f21f801aa0f8 Mon Sep 17 00:00:00 2001 From: Stefan Mititelu Date: Mon, 9 Nov 2015 18:04:33 +0200 Subject: [PATCH 04/13] rtpengine: kamctl fifo nh_show_hash_total Print the total number of hash entries in the hash table, at the given moment. Updated doku. --- modules/rtpengine/doc/rtpengine_admin.xml | 17 ++++++ modules/rtpengine/rtpengine.c | 64 +++++++++++++++++++---- modules/rtpengine/rtpengine_hash.c | 30 +++++++++++ modules/rtpengine/rtpengine_hash.h | 6 ++- 4 files changed, 105 insertions(+), 12 deletions(-) diff --git a/modules/rtpengine/doc/rtpengine_admin.xml b/modules/rtpengine/doc/rtpengine_admin.xml index 0c8a6477633..96a490d2ad7 100644 --- a/modules/rtpengine/doc/rtpengine_admin.xml +++ b/modules/rtpengine/doc/rtpengine_admin.xml @@ -1041,6 +1041,23 @@ $ &ctltool; fifo nh_ping_rtpp all
+ +
+ <function moreinfo="none">nh_show_hash_total</function> + + Print the total number of hash entries in the hash table at a given moment. + + + + <function moreinfo="none">nh_show_hash_total</function> usage + +... +$ &ctltool; fifo nh_show_hash_total +... + + +
+ diff --git a/modules/rtpengine/rtpengine.c b/modules/rtpengine/rtpengine.c index e48f31811e1..b3ca0110b92 100644 --- a/modules/rtpengine/rtpengine.c +++ b/modules/rtpengine/rtpengine.c @@ -109,6 +109,7 @@ MODULE_VERSION #define MI_ENABLE_RTP_PROXY "nh_enable_rtpp" #define MI_SHOW_RTP_PROXIES "nh_show_rtpp" #define MI_PING_RTP_PROXY "nh_ping_rtpp" +#define MI_SHOW_HASH_TOTAL "nh_show_hash_total" #define MI_RTP_PROXY_NOT_FOUND "RTP proxy not found" #define MI_RTP_PROXY_NOT_FOUND_LEN (sizeof(MI_RTP_PROXY_NOT_FOUND)-1) @@ -143,6 +144,10 @@ MODULE_VERSION #define MI_SUCCESS_LEN (sizeof(MI_SUCCESS)-1) #define MI_FAIL "fail" #define MI_FAIL_LEN (sizeof(MI_FAIL)-1) +#define MI_HASH_ENTRIES "entries" +#define MI_HASH_ENTRIES_LEN (sizeof(MI_HASH_ENTRIES)-1) +#define MI_HASH_ENTRIES_FAIL "Fail to get entry details" +#define MI_HASH_ENTRIES_FAIL_LEN (sizeof(MI_HASH_ENTRIES_FAIL)-1) #define MI_FOUND_ALL 2 #define MI_FOUND_ONE 1 @@ -215,12 +220,10 @@ static int rtpp_test_ping(struct rtpp_node *node); static int pv_get_rtpstat_f(struct sip_msg *, pv_param_t *, pv_value_t *); /*mi commands*/ -static struct mi_root* mi_enable_rtp_proxy(struct mi_root* cmd_tree, - void* param ); -static struct mi_root* mi_show_rtp_proxy(struct mi_root* cmd_tree, - void* param); -static struct mi_root* mi_ping_rtp_proxy(struct mi_root* cmd_tree, - void* param); +static struct mi_root* mi_enable_rtp_proxy(struct mi_root* cmd_tree, void* param); +static struct mi_root* mi_show_rtp_proxy(struct mi_root* cmd_tree, void* param); +static struct mi_root* mi_ping_rtp_proxy(struct mi_root* cmd_tree, void* param); +static struct mi_root* mi_show_hash_total(struct mi_root* cmd_tree, void* param); static int rtpengine_disable_tout = 60; @@ -350,6 +353,7 @@ static mi_export_t mi_cmds[] = { {MI_ENABLE_RTP_PROXY, mi_enable_rtp_proxy, 0, 0, 0}, {MI_SHOW_RTP_PROXIES, mi_show_rtp_proxy, 0, 0, 0}, {MI_PING_RTP_PROXY, mi_ping_rtp_proxy, 0, 0, 0}, + {MI_SHOW_HASH_TOTAL, mi_show_hash_total, 0, 0, 0}, { 0, 0, 0, 0, 0} }; @@ -1106,8 +1110,7 @@ static int add_rtpp_node_info (struct mi_node *node, return -1; } -static struct mi_root* mi_show_rtp_proxy(struct mi_root* cmd_tree, - void* param) +static struct mi_root* mi_show_rtp_proxy(struct mi_root* cmd_tree, void* param) { struct mi_node *node; struct mi_root *root = NULL; @@ -1196,8 +1199,7 @@ static struct mi_root* mi_show_rtp_proxy(struct mi_root* cmd_tree, return init_mi_tree(404, MI_ERROR, MI_ERROR_LEN); } -static struct mi_root* mi_ping_rtp_proxy(struct mi_root* cmd_tree, - void* param) +static struct mi_root* mi_ping_rtp_proxy(struct mi_root* cmd_tree, void* param) { struct mi_node *node, *crt_node; struct mi_attr *attr; @@ -1322,6 +1324,48 @@ static struct mi_root* mi_ping_rtp_proxy(struct mi_root* cmd_tree, } +static struct mi_root* mi_show_hash_total(struct mi_root* cmd_tree, void* param) +{ + struct mi_node *node, *crt_node; + struct mi_attr *attr; + struct mi_root *root = NULL; + unsigned int total; + str total_str; + + // Init print tree + root = init_mi_tree(200, MI_OK_S, MI_OK_LEN); + if (!root) { + LM_ERR("the MI tree cannot be initialized!\n"); + return 0; + } + node = &root->node; + + // Create new node and add it to the roots's kids + if(!(crt_node = add_mi_node_child(node, MI_DUP_NAME, "total", strlen("total"), 0, 0))) { + LM_ERR("cannot add the child node to the tree\n"); + goto error; + } + + // Get total number of entries + total = rtpengine_hash_table_total(); + total_str.s = int2str(total, &total_str.len); + + // Add node attributes + if ((attr = add_mi_attr(crt_node, MI_DUP_VALUE, MI_HASH_ENTRIES, MI_HASH_ENTRIES_LEN, total_str.s, total_str.len)) == 0) { + LM_ERR("cannot add attributes to the node\n"); + goto error; + } + + return root; + +error: + if (root) { + free_mi_tree(root); + } + + return init_mi_tree(404, MI_HASH_ENTRIES_FAIL, MI_HASH_ENTRIES_FAIL_LEN); +} + static int mod_init(void) diff --git a/modules/rtpengine/rtpengine_hash.c b/modules/rtpengine/rtpengine_hash.c index 3cca5749f6e..76aa144cd50 100644 --- a/modules/rtpengine/rtpengine_hash.c +++ b/modules/rtpengine/rtpengine_hash.c @@ -74,6 +74,7 @@ int rtpengine_hash_table_init(int size) { // never expire the head of the hashtable index lists rtpengine_hash_table->entry_list[i]->tout = -1; rtpengine_hash_table->entry_list[i]->next = NULL; + rtpengine_hash_table->total = 0; } // init lock @@ -165,6 +166,9 @@ int rtpengine_hash_table_insert(void *key, void *value) { // set pointers entry = last_entry; + + // update total + rtpengine_hash_table->total--; } // next entry in the list @@ -174,6 +178,9 @@ int rtpengine_hash_table_insert(void *key, void *value) { last_entry->next = new_entry; + // update total + rtpengine_hash_table->total++; + // unlock lock_release(rtpengine_hash_lock); @@ -205,6 +212,9 @@ int rtpengine_hash_table_remove(void *key) { shm_free(entry->callid.s); shm_free(entry); + // update total + rtpengine_hash_table->total--; + // unlock lock_release(rtpengine_hash_lock); @@ -222,6 +232,9 @@ int rtpengine_hash_table_remove(void *key) { // set pointers entry = last_entry; + + // update total + rtpengine_hash_table->total--; } last_entry = entry; @@ -271,6 +284,9 @@ void* rtpengine_hash_table_lookup(void *key) { // set pointers entry = last_entry; + + // update total + rtpengine_hash_table->total--; } last_entry = entry; @@ -314,6 +330,9 @@ void rtpengine_hash_table_print() { // set pointers entry = last_entry; + + // update total + rtpengine_hash_table->total--; } else { LM_DBG("hash_index=%d callid=%.*s tout=%u\n", i, entry->callid.len, entry->callid.s, entry->tout - get_ticks()); @@ -327,3 +346,14 @@ void rtpengine_hash_table_print() { // unlock lock_release(rtpengine_hash_lock); } + +unsigned int rtpengine_hash_table_total() { + + // check rtpengine hashtable + if (!rtpengine_hash_table) { + LM_ERR("NULL rtpengine_hash_table"); + return 0; + } + + return rtpengine_hash_table->total; +} diff --git a/modules/rtpengine/rtpengine_hash.h b/modules/rtpengine/rtpengine_hash.h index b0a8c739317..c9957e92199 100644 --- a/modules/rtpengine/rtpengine_hash.h +++ b/modules/rtpengine/rtpengine_hash.h @@ -15,7 +15,8 @@ struct rtpengine_hash_entry { /* table */ struct rtpengine_hash_table { - struct rtpengine_hash_entry **entry_list; + struct rtpengine_hash_entry **entry_list; // hastable + unsigned int total; // total number of entries in the hashtable }; @@ -24,6 +25,7 @@ int rtpengine_hash_table_destroy(); int rtpengine_hash_table_insert(void *key, void *value); int rtpengine_hash_table_remove(void *key); void* rtpengine_hash_table_lookup(void *key); -void rtpengine_hash_table_print() ; +void rtpengine_hash_table_print(); +unsigned int rtpengine_hash_table_total(); #endif From d75bb85c4a03dedb33004fe04c447182fdf37f5c Mon Sep 17 00:00:00 2001 From: Stefan Mititelu Date: Tue, 10 Nov 2015 16:04:30 +0200 Subject: [PATCH 05/13] rtpengine: Add rtpengine_allow_op modparam When the param is enabled, allow current sessions to finish and deny new sessions for manually deactivated rtpengine nodes via kamctl i.e. "disabled(permanent)" nodes. This is useful when deactivating the nodes for maintenance. Default value is 0, so the current behaviour is maintained (e.g. don't send commands to any deactivated proxy). Updated doku. --- modules/rtpengine/doc/rtpengine_admin.xml | 24 +++++++++++++++++++++++ modules/rtpengine/rtpengine.c | 19 +++++++++++++++--- 2 files changed, 40 insertions(+), 3 deletions(-) diff --git a/modules/rtpengine/doc/rtpengine_admin.xml b/modules/rtpengine/doc/rtpengine_admin.xml index 96a490d2ad7..34e197fa2ce 100644 --- a/modules/rtpengine/doc/rtpengine_admin.xml +++ b/modules/rtpengine/doc/rtpengine_admin.xml @@ -207,6 +207,30 @@ modparam("rtpengine", "rtpengine_disable_tout", 20) ... modparam("rtpengine", "rtpengine_tout_ms", 2000) ... + + + +
+ <varname>rtpengine_allow_op</varname> (integer) + + Enable this to allow finishing the current sessions while denying new sessions for the + manually deactivated nodes via kamctl command i.e. "disabled(permanent)" nodes. + Probably the manually deactivated machine is still running(did not crash). + + + This is useful when deactivating a node for maintanance and reject new sessions but allow current ones to finish. + + + + Default value is 0 to keep the current behaviour. + + + + Set <varname>rtpengine_allow_op</varname> parameter + +... +modparam("rtpengine", "rtpengine_allow_op", 1) +...
diff --git a/modules/rtpengine/rtpengine.c b/modules/rtpengine/rtpengine.c index b3ca0110b92..042c477da14 100644 --- a/modules/rtpengine/rtpengine.c +++ b/modules/rtpengine/rtpengine.c @@ -227,6 +227,7 @@ static struct mi_root* mi_show_hash_total(struct mi_root* cmd_tree, void* param) static int rtpengine_disable_tout = 60; +static int rtpengine_allow_op = 0; static int rtpengine_retr = 5; static int rtpengine_tout_ms = 1000; static int queried_nodes_limit = MAX_RTPP_TRIED_NODES; @@ -334,6 +335,7 @@ static param_export_t params[] = { {"rtpengine_disable_tout",INT_PARAM, &rtpengine_disable_tout }, {"rtpengine_retr", INT_PARAM, &rtpengine_retr }, {"rtpengine_tout_ms", INT_PARAM, &rtpengine_tout_ms }, + {"rtpengine_allow_op", INT_PARAM, &rtpengine_allow_op }, {"queried_nodes_limit", INT_PARAM, &queried_nodes_limit }, {"db_url", PARAM_STR, &rtpp_db_url }, {"table_name", PARAM_STR, &rtpp_table_name }, @@ -2369,7 +2371,7 @@ select_rtpp_node_new(str callid, int do_test, int op) } /* - * lookup the hastable (key=callid value=node) and get the old node + * lookup the hastable (key=callid value=node) and get the old node (e.g. for answer/delete) */ static struct rtpp_node * select_rtpp_node_old(str callid, int do_test, int op) @@ -2396,11 +2398,22 @@ select_rtpp_node_old(str callid, int do_test, int op) node->rn_url.len, node->rn_url.s, callid.len, callid.len, callid.s); } - // if node broke, don't send any message + // if node enabled, return it if (!node->rn_disabled) { return node; + } + + // if node _manually_ disabled(e.g kamctl) and proper configuration, return it + if (node->rn_recheck_ticks == MI_MAX_RECHECK_TICKS) { + if (rtpengine_allow_op) { + LM_DBG("node=%.*s for calllen=%d callid=%.*s is disabled(permanent) (probably still UP)! Return it\n", + node->rn_url.len, node->rn_url.s, callid.len, callid.len, callid.s); + return node; + } + LM_DBG("node=%.*s for calllen=%d callid=%.*s is disabled(permanent) (probably still UP)! Return NULL\n", + node->rn_url.len, node->rn_url.s, callid.len, callid.len, callid.s); } else { - LM_DBG("rtpengine hash table lookup find node=%.*s for calllen=%d callid=%.*s, which is disabled!\n", + LM_DBG("node=%.*s for calllen=%d callid=%.*s is disabled (probably BROKE)! Return NULL\n", node->rn_url.len, node->rn_url.s, callid.len, callid.len, callid.s); } From 7ad4dadcab841d191d5edc028a74cea7fe411450 Mon Sep 17 00:00:00 2001 From: Stefan Mititelu Date: Thu, 12 Nov 2015 09:55:17 +0200 Subject: [PATCH 06/13] rtpengine: Fix comments for hastable - shm NULL checks and free already alloc'ed shm - default entry tout to 3600 sec - return node only, not the whole entry - zero shm hashtable parts - lookup and select new node if lookup fails; this is done for all commands and assures fallback behaviour - change void to struct specific - make set_rtp_inst_pvar() static -> used only in rtpengine.c - fix typos rtpproxy vs rtpengine --- modules/rtpengine/doc/rtpengine_admin.xml | 19 ++--- modules/rtpengine/rtpengine.c | 97 +++++++++++++---------- modules/rtpengine/rtpengine.h | 1 - modules/rtpengine/rtpengine_hash.c | 64 ++++++++++++--- modules/rtpengine/rtpengine_hash.h | 6 +- 5 files changed, 124 insertions(+), 63 deletions(-) diff --git a/modules/rtpengine/doc/rtpengine_admin.xml b/modules/rtpengine/doc/rtpengine_admin.xml index 34e197fa2ce..8b623c8c112 100644 --- a/modules/rtpengine/doc/rtpengine_admin.xml +++ b/modules/rtpengine/doc/rtpengine_admin.xml @@ -361,7 +361,7 @@ modparam("rtpengine", "read_sdp_pv", "$var(sdp)") route { ... $var(sdp) = $rb + "a=foo:bar\r\n"; - rtpproxy_manage(); + rtpengine_manage(); } @@ -386,7 +386,7 @@ modparam("rtpengine", "write_sdp_pv", "$avp(sdp)") ... route { ... - rtpproxy_manage(); + rtpengine_manage(); set_body("$avp(sdp)a=baz123\r\n", "application/sdp"); } @@ -406,7 +406,7 @@ route { Set <varname>rtp_inst_pvar</varname> parameter ... -modparam("rtpproxy", "rtp_inst_pvar", "$avp(RTP_INSTANCE)") +modparam("rtpengine", "rtp_inst_pvar", "$avp(RTP_INSTANCE)") ... @@ -424,7 +424,7 @@ modparam("rtpproxy", "rtp_inst_pvar", "$avp(RTP_INSTANCE)") Set <varname>hash_table_size</varname> parameter ... -modparam("rtpproxy", "hash_table_size", "123") +modparam("rtpengine", "hash_table_size", "123") ... @@ -434,23 +434,24 @@ modparam("rtpproxy", "hash_table_size", "123") <varname>hash_table_tout</varname> (integer) Number of seconds after an rtpengine hash table entry is marked for deletion. - By default, this parameter is set to 120 (seconds). + By default, this parameter is set to 3600 (seconds). To maintain information about a selected rtp machine node, for a given call, entries are added in a hashtable of (callid, node) pairs. - When "offer" comes, insert new entry in the hastable. - When subsequent commands come, lookup callid and return chosen node. - When "delete" comes, remove old entry from hashtable. + When command comes, lookup callid. If found, return chosen node. If not found, choose a new node, insert it in the hastable and return the chosen node. NOTE: In the current implementation, the actual deletion happens on the fly, while insert/remove/lookup the hastable, only for the entries in the insert/remove/lookup path. + + NOTE: When configuring this parameter, one should consider maximum call time VS share memory for unfinished calls. + Set <varname>hash_table_tout</varname> parameter ... -modparam("rtpproxy", "hash_table_tout", "300") +modparam("rtpengine", "hash_table_tout", "300") ... diff --git a/modules/rtpengine/rtpengine.c b/modules/rtpengine/rtpengine.c index 042c477da14..a11e38459bf 100644 --- a/modules/rtpengine/rtpengine.c +++ b/modules/rtpengine/rtpengine.c @@ -218,6 +218,7 @@ static int rtpp_test_ping(struct rtpp_node *node); /* Pseudo-Variables */ static int pv_get_rtpstat_f(struct sip_msg *, pv_param_t *, pv_value_t *); +static int set_rtp_inst_pvar(struct sip_msg *msg, const str * const uri); /*mi commands*/ static struct mi_root* mi_enable_rtp_proxy(struct mi_root* cmd_tree, void* param); @@ -235,7 +236,7 @@ static pid_t mypid; static unsigned int myseqn = 0; static str extra_id_pv_param = {NULL, 0}; static char *setid_avp_param = NULL; -static int hash_table_tout = 120; +static int hash_table_tout = 3600; static int hash_table_size = 256; static char ** rtpp_strings=0; @@ -2284,6 +2285,7 @@ select_rtpp_node_new(str callid, int do_test, int op) int was_forced = 0; /* XXX Use quick-and-dirty hashing algo */ + sum = 0; for(i = 0; i < callid.len; i++) sum += callid.s[i]; sum &= 0xff; @@ -2347,26 +2349,38 @@ select_rtpp_node_new(str callid, int do_test, int op) goto retry; } - /* build hash table entry */ + /* build the entry */ struct rtpengine_hash_entry *entry = shm_malloc(sizeof(struct rtpp_node)); + if (!entry) { + LM_ERR("rtpengine hash table fail to create entry for calllen=%d callid=%.*s\n", + callid.len, callid.len, callid.s); + return node; + } + + /* fill the entry */ if (shm_str_dup(&entry->callid, &callid) < 0) { - LM_ERR("rtpengine hash table fail to duplicate calllen=%d callid=%.*s", + LM_ERR("rtpengine hash table fail to duplicate calllen=%d callid=%.*s\n", callid.len, callid.len, callid.s); + shm_free(entry); + return node; } entry->node = node; entry->next = NULL; entry->tout = get_ticks() + hash_table_tout; - /* Insert the key<->entry from the hashtable */ + /* insert the key<->entry from the hashtable */ if (!rtpengine_hash_table_insert(&callid, entry)) { - LM_ERR("rtpengine hash table fail to insert node=%.*s for calllen=%d callid=%.*s", + LM_ERR("rtpengine hash table fail to insert node=%.*s for calllen=%d callid=%.*s\n", node->rn_url.len, node->rn_url.s, callid.len, callid.len, callid.s); + shm_free(entry->callid.s); + shm_free(entry); + return node; } else { LM_DBG("rtpengine hash table insert node=%.*s for calllen=%d callid=%.*s\n", node->rn_url.len, node->rn_url.s, callid.len, callid.len, callid.s); } - /* Return selected node */ + /* return selected node */ return node; } @@ -2377,20 +2391,11 @@ static struct rtpp_node * select_rtpp_node_old(str callid, int do_test, int op) { struct rtpp_node *node = NULL; - struct rtpengine_hash_entry *entry = NULL; - entry = rtpengine_hash_table_lookup(&callid); - if (!entry) { - LM_ERR("rtpengine hash table lookup failed to find entry for calllen=%d callid=%.*s\n", - callid.len, callid.len, callid.s); - } else { - LM_DBG("rtpengine hash table lookup find entry for calllen=%d callid=%.*s\n", - callid.len, callid.len, callid.s); - node = entry->node; - } + node = rtpengine_hash_table_lookup(&callid); if (!node) { - LM_ERR("rtpengine hash table lookup failed to find node for calllen=%d callid=%.*s\n", + LM_NOTICE("rtpengine hash table lookup failed to find node for calllen=%d callid=%.*s\n", callid.len, callid.len, callid.s); return NULL; } else { @@ -2398,6 +2403,39 @@ select_rtpp_node_old(str callid, int do_test, int op) node->rn_url.len, node->rn_url.s, callid.len, callid.len, callid.s); } + return node; +} + +/* + * Main balancing routine. This DO try to keep the same proxy for + * the call if some proxies were disabled or enabled (e.g. kamctl command) + */ +static struct rtpp_node * +select_rtpp_node(str callid, int do_test, int op) +{ + struct rtpp_node *node = NULL; + + if(!active_rtpp_set) { + LM_ERR("script error - no valid set selected\n"); + return NULL; + } + + // lookup node + node = select_rtpp_node_old(callid, do_test, op); + + // check node + if (!node) { + // run the selection algorithm + node = select_rtpp_node_new(callid, do_test, op); + + // check node + if (!node) { + LM_ERR("rtpengine failed to select new for calllen=%d callid=%.*s\n", + callid.len, callid.len, callid.s); + return NULL; + } + } + // if node enabled, return it if (!node->rn_disabled) { return node; @@ -2420,28 +2458,6 @@ select_rtpp_node_old(str callid, int do_test, int op) return NULL; } -/* - * Main balancing routine. This DO try to keep the same proxy for - * the call if some proxies were disabled or enabled (e.g. kamctl command) - */ -static struct rtpp_node * -select_rtpp_node(str callid, int do_test, int op) -{ - if(!active_rtpp_set) { - LM_ERR("script error - no valid set selected\n"); - return NULL; - } - - // calculate and choose a node - if (op == OP_OFFER) { - // run the selection algorithm - return select_rtpp_node_new(callid, do_test, op); - } else { - // lookup the hastable (key=callid value=node) and get the old node - return select_rtpp_node_old(callid, do_test, op); - } -} - static int get_extra_id(struct sip_msg* msg, str *id_str) { if(msg==NULL || extra_id_pv==NULL || id_str==NULL) { @@ -2858,7 +2874,8 @@ pv_get_rtpstat_f(struct sip_msg *msg, pv_param_t *param, return rtpengine_rtpp_set_wrap(msg, rtpengine_rtpstat_wrap, parms, 1); } -int set_rtp_inst_pvar(struct sip_msg *msg, const str * const uri) { +static int +set_rtp_inst_pvar(struct sip_msg *msg, const str * const uri) { pv_value_t val; if (rtp_inst_pvar == NULL) diff --git a/modules/rtpengine/rtpengine.h b/modules/rtpengine/rtpengine.h index af61701550d..71ce2645485 100644 --- a/modules/rtpengine/rtpengine.h +++ b/modules/rtpengine/rtpengine.h @@ -61,7 +61,6 @@ struct rtpp_set_head{ struct rtpp_set *get_rtpp_set(int set_id); int add_rtpengine_socks(struct rtpp_set * rtpp_list, char * rtpproxy); -int set_rtp_inst_pvar(struct sip_msg *msg, const str * const uri); int init_rtpproxy_db(void); diff --git a/modules/rtpengine/rtpengine_hash.c b/modules/rtpengine/rtpengine_hash.c index 76aa144cd50..566a9607eda 100644 --- a/modules/rtpengine/rtpengine_hash.c +++ b/modules/rtpengine/rtpengine_hash.c @@ -22,13 +22,12 @@ static int str_cmp_str(const str *a, const str *b) { } /* from sipwise rtpengine */ -static int str_equal(void *a, void *b) { - return (str_cmp_str((str *) a, (str *) b) == 0); +static int str_equal(str *a, str *b) { + return (str_cmp_str(a, b) == 0); } /* from sipwise rtpengine */ -static unsigned int str_hash(void *ss) { - const str *s = (str*) ss; +static unsigned int str_hash(str *s) { unsigned int ret = 5381; str it = *s; @@ -62,14 +61,22 @@ int rtpengine_hash_table_init(int size) { // init hashtable entry_list rtpengine_hash_table->entry_list = shm_malloc(hash_table_size * sizeof(struct rtpengine_hash_entry)); + if (!rtpengine_hash_table->entry_list) { + LM_ERR("no shm left to create rtpengine_hash_table->entry_list\n"); + rtpengine_hash_table_destroy(); + return 0; + } + memset(rtpengine_hash_table->entry_list, 0, hash_table_size * sizeof(struct rtpengine_hash_entry)); - // init hashtable entry_list[i] (head never filled) + // init hashtable entry_list[i] (head never filled); destroy table on error for (i = 0; i < hash_table_size; i++) { rtpengine_hash_table->entry_list[i] = shm_malloc(sizeof(struct rtpengine_hash_entry)); if (!rtpengine_hash_table->entry_list[i]) { LM_ERR("no shm left to create rtpengine_hash_table->entry_list[%d]\n", i); + rtpengine_hash_table_destroy(); return 0; } + memset(rtpengine_hash_table->entry_list[i], 0, sizeof(struct rtpengine_hash_entry)); // never expire the head of the hashtable index lists rtpengine_hash_table->entry_list[i]->tout = -1; @@ -81,6 +88,7 @@ int rtpengine_hash_table_init(int size) { rtpengine_hash_lock = lock_alloc(); if (!rtpengine_hash_lock) { LM_ERR("no shm left to init rtpengine_hash_table lock"); + rtpengine_hash_table_destroy(); return 0; } @@ -97,6 +105,14 @@ int rtpengine_hash_table_destroy() { return 0; } + // check rtpengine hashtable->entry_list + if (!rtpengine_hash_table->entry_list) { + LM_ERR("NULL rtpengine_hash_table->entry_list"); + shm_free(rtpengine_hash_table); + rtpengine_hash_table = NULL; + return 0; + } + // destroy hashtable entry_list[i] lock_get(rtpengine_hash_lock); for (i = 0; i < hash_table_size; i++) { @@ -111,6 +127,7 @@ int rtpengine_hash_table_destroy() { // destroy hashtable entry_list shm_free(rtpengine_hash_table->entry_list); + rtpengine_hash_table->entry_list = NULL; // destroy hashtable shm_free(rtpengine_hash_table); @@ -128,7 +145,7 @@ int rtpengine_hash_table_destroy() { return 1; } -int rtpengine_hash_table_insert(void *key, void *value) { +int rtpengine_hash_table_insert(str *key, struct rtpengine_hash_entry *value) { struct rtpengine_hash_entry *entry, *last_entry; struct rtpengine_hash_entry *new_entry = (struct rtpengine_hash_entry *) value; unsigned int hash_index; @@ -139,6 +156,12 @@ int rtpengine_hash_table_insert(void *key, void *value) { return 0; } + // check rtpengine hashtable->entry_list + if (!rtpengine_hash_table->entry_list) { + LM_ERR("NULL rtpengine_hash_table->entry_list"); + return 0; + } + // get entry list hash_index = str_hash(key); entry = rtpengine_hash_table->entry_list[hash_index]; @@ -187,7 +210,7 @@ int rtpengine_hash_table_insert(void *key, void *value) { return 1; } -int rtpengine_hash_table_remove(void *key) { +int rtpengine_hash_table_remove(str *key) { struct rtpengine_hash_entry *entry, *last_entry; unsigned int hash_index; @@ -197,6 +220,12 @@ int rtpengine_hash_table_remove(void *key) { return 0; } + // check rtpengine hashtable->entry_list + if (!rtpengine_hash_table->entry_list) { + LM_ERR("NULL rtpengine_hash_table->entry_list"); + return 0; + } + // get first entry from entry list; jump over unused list head hash_index = str_hash(key); entry = rtpengine_hash_table->entry_list[hash_index]; @@ -247,14 +276,21 @@ int rtpengine_hash_table_remove(void *key) { return 0; } -void* rtpengine_hash_table_lookup(void *key) { +struct rtpp_node *rtpengine_hash_table_lookup(str *key) { struct rtpengine_hash_entry *entry, *last_entry; unsigned int hash_index; + struct rtpp_node *node; // check rtpengine hashtable if (!rtpengine_hash_table) { LM_ERR("NULL rtpengine_hash_table"); - return 0; + return NULL; + } + + // check rtpengine hashtable->entry_list + if (!rtpengine_hash_table->entry_list) { + LM_ERR("NULL rtpengine_hash_table->entry_list"); + return NULL; } // get first entry from entry list; jump over unused list head @@ -267,10 +303,12 @@ void* rtpengine_hash_table_lookup(void *key) { while (entry) { // if key found, return entry if (str_equal(&entry->callid, (str *)key)) { + node = entry->node; + // unlock lock_release(rtpengine_hash_lock); - return entry; + return node; } // if expired entry discovered, delete it @@ -310,6 +348,12 @@ void rtpengine_hash_table_print() { return ; } + // check rtpengine hashtable->entry_list + if (!rtpengine_hash_table->entry_list) { + LM_ERR("NULL rtpengine_hash_table->entry_list"); + return ; + } + // lock lock_get(rtpengine_hash_lock); diff --git a/modules/rtpengine/rtpengine_hash.h b/modules/rtpengine/rtpengine_hash.h index c9957e92199..c0a9ed8c6bc 100644 --- a/modules/rtpengine/rtpengine_hash.h +++ b/modules/rtpengine/rtpengine_hash.h @@ -22,9 +22,9 @@ struct rtpengine_hash_table { int rtpengine_hash_table_init(int size); int rtpengine_hash_table_destroy(); -int rtpengine_hash_table_insert(void *key, void *value); -int rtpengine_hash_table_remove(void *key); -void* rtpengine_hash_table_lookup(void *key); +int rtpengine_hash_table_insert(str *key, struct rtpengine_hash_entry *value); +int rtpengine_hash_table_remove(str *key); +struct rtpp_node *rtpengine_hash_table_lookup(str *key); void rtpengine_hash_table_print(); unsigned int rtpengine_hash_table_total(); From 5f936a387fae32f4a4f7c11a9cbd5666b31ef9e7 Mon Sep 17 00:00:00 2001 From: Stefan Mititelu Date: Mon, 16 Nov 2015 10:49:36 +0200 Subject: [PATCH 07/13] rtpengine: Fix deletion for branching scenarios - hash table entry contains callid, viabranch - hash table lookup based on callid, viabranch (useful for branching scenarios); keep doing the hash table remove right away - remove op param when select_rtpp_node(); not needed --- modules/rtpengine/rtpengine.c | 69 +++++++++-------- modules/rtpengine/rtpengine_hash.c | 116 +++++++++++++++++++---------- modules/rtpengine/rtpengine_hash.h | 12 ++- 3 files changed, 121 insertions(+), 76 deletions(-) diff --git a/modules/rtpengine/rtpengine.c b/modules/rtpengine/rtpengine.c index a11e38459bf..7fa328365f8 100644 --- a/modules/rtpengine/rtpengine.c +++ b/modules/rtpengine/rtpengine.c @@ -193,9 +193,9 @@ static int rtpengine_offer_answer(struct sip_msg *msg, const char *flags, int op static int fixup_set_id(void ** param, int param_no); static int set_rtpengine_set_f(struct sip_msg * msg, char * str1, char * str2); static struct rtpp_set * select_rtpp_set(int id_set); -static struct rtpp_node *select_rtpp_node_new(str, int, int); -static struct rtpp_node *select_rtpp_node_old(str, int, int); -static struct rtpp_node *select_rtpp_node(str, int, int); +static struct rtpp_node *select_rtpp_node_new(str, str, int); +static struct rtpp_node *select_rtpp_node_old(str, str, int); +static struct rtpp_node *select_rtpp_node(str, str, int); static char *send_rtpp_command(struct rtpp_node *, bencode_item_t *, int *); static int get_extra_id(struct sip_msg* msg, str *id_str); @@ -1859,7 +1859,8 @@ static bencode_item_t *rtpp_function_call(bencode_buffer_t *bencbuf, struct sip_ { struct ng_flags_parse ng_flags; bencode_item_t *item, *resp; - str callid, from_tag, to_tag, body, viabranch, error; + str callid = STR_NULL, from_tag = STR_NULL, to_tag = STR_NULL, viabranch = STR_NULL; + str body = STR_NULL, error = STR_NULL; int ret, queried_nodes; struct rtpp_node *node; char *cp; @@ -1992,7 +1993,7 @@ static bencode_item_t *rtpp_function_call(bencode_buffer_t *bencbuf, struct sip_ LM_ERR("queried nodes limit reached\n"); goto error; } - node = select_rtpp_node(callid, 1, op); + node = select_rtpp_node(callid, viabranch, 1); if (!node) { LM_ERR("no available proxies\n"); goto error; @@ -2036,12 +2037,12 @@ static bencode_item_t *rtpp_function_call(bencode_buffer_t *bencbuf, struct sip_ if (op == OP_DELETE) { /* Delete the key<->value from the hashtable */ - if (!rtpengine_hash_table_remove(&callid)) { - LM_ERR("rtpengine hash table failed to remove entry for callen=%d callid=%.*s\n", - callid.len, callid.len, callid.s); + if (!rtpengine_hash_table_remove(callid, viabranch)) { + LM_ERR("rtpengine hash table failed to remove entry for callen=%d callid=%.*s viabranch=%.*s\n", + callid.len, callid.len, callid.s, viabranch.len, viabranch.s); } else { - LM_DBG("rtpengine hash table remove entry for callen=%d callid=%.*s\n", - callid.len, callid.len, callid.s); + LM_DBG("rtpengine hash table remove entry for callen=%d callid=%.*s viabranch=%.*s\n", + callid.len, callid.len, callid.s, viabranch.len, viabranch.s); } } @@ -2278,7 +2279,7 @@ static struct rtpp_set * select_rtpp_set(int id_set ){ * run the selection algorithm and return the new selected node */ static struct rtpp_node * -select_rtpp_node_new(str callid, int do_test, int op) +select_rtpp_node_new(str callid, str viabranch, int do_test) { struct rtpp_node* node; unsigned i, sum, sumcut, weight_sum; @@ -2350,18 +2351,25 @@ select_rtpp_node_new(str callid, int do_test, int op) } /* build the entry */ - struct rtpengine_hash_entry *entry = shm_malloc(sizeof(struct rtpp_node)); + struct rtpengine_hash_entry *entry = shm_malloc(sizeof(struct rtpengine_hash_entry)); if (!entry) { - LM_ERR("rtpengine hash table fail to create entry for calllen=%d callid=%.*s\n", - callid.len, callid.len, callid.s); + LM_ERR("rtpengine hash table fail to create entry for calllen=%d callid=%.*s viabranch=%.*s\n", + callid.len, callid.len, callid.s, viabranch.len, viabranch.s); return node; } + memset(entry, 0, sizeof(struct rtpengine_hash_entry)); /* fill the entry */ if (shm_str_dup(&entry->callid, &callid) < 0) { LM_ERR("rtpengine hash table fail to duplicate calllen=%d callid=%.*s\n", callid.len, callid.len, callid.s); - shm_free(entry); + rtpengine_hash_table_free_entry(entry); + return node; + } + if (shm_str_dup(&entry->viabranch, &viabranch) < 0) { + LM_ERR("rtpengine hash table fail to duplicate calllen=%d viabranch=%.*s\n", + callid.len, viabranch.len, viabranch.s); + rtpengine_hash_table_free_entry(entry); return node; } entry->node = node; @@ -2369,15 +2377,14 @@ select_rtpp_node_new(str callid, int do_test, int op) entry->tout = get_ticks() + hash_table_tout; /* insert the key<->entry from the hashtable */ - if (!rtpengine_hash_table_insert(&callid, entry)) { - LM_ERR("rtpengine hash table fail to insert node=%.*s for calllen=%d callid=%.*s\n", - node->rn_url.len, node->rn_url.s, callid.len, callid.len, callid.s); - shm_free(entry->callid.s); - shm_free(entry); + if (!rtpengine_hash_table_insert(callid, viabranch, entry)) { + LM_ERR("rtpengine hash table fail to insert node=%.*s for calllen=%d callid=%.*s viabranch=%.*s\n", + node->rn_url.len, node->rn_url.s, callid.len, callid.len, callid.s, viabranch.len, viabranch.s); + rtpengine_hash_table_free_entry(entry); return node; } else { - LM_DBG("rtpengine hash table insert node=%.*s for calllen=%d callid=%.*s\n", - node->rn_url.len, node->rn_url.s, callid.len, callid.len, callid.s); + LM_DBG("rtpengine hash table insert node=%.*s for calllen=%d callid=%.*s viabranch=%.*s\n", + node->rn_url.len, node->rn_url.s, callid.len, callid.len, callid.s, viabranch.len, viabranch.s); } /* return selected node */ @@ -2388,19 +2395,19 @@ select_rtpp_node_new(str callid, int do_test, int op) * lookup the hastable (key=callid value=node) and get the old node (e.g. for answer/delete) */ static struct rtpp_node * -select_rtpp_node_old(str callid, int do_test, int op) +select_rtpp_node_old(str callid, str viabranch, int do_test) { struct rtpp_node *node = NULL; - node = rtpengine_hash_table_lookup(&callid); + node = rtpengine_hash_table_lookup(callid, viabranch); if (!node) { - LM_NOTICE("rtpengine hash table lookup failed to find node for calllen=%d callid=%.*s\n", - callid.len, callid.len, callid.s); + LM_NOTICE("rtpengine hash table lookup failed to find node for calllen=%d callid=%.*s viabranch=%.*s\n", + callid.len, callid.len, callid.s, viabranch.len, viabranch.s); return NULL; } else { - LM_DBG("rtpengine hash table lookup find node=%.*s for calllen=%d callid=%.*s\n", - node->rn_url.len, node->rn_url.s, callid.len, callid.len, callid.s); + LM_DBG("rtpengine hash table lookup find node=%.*s for calllen=%d callid=%.*s viabranch=%.*s\n", + node->rn_url.len, node->rn_url.s, callid.len, callid.len, callid.s, viabranch.len, viabranch.s); } return node; @@ -2411,7 +2418,7 @@ select_rtpp_node_old(str callid, int do_test, int op) * the call if some proxies were disabled or enabled (e.g. kamctl command) */ static struct rtpp_node * -select_rtpp_node(str callid, int do_test, int op) +select_rtpp_node(str callid, str viabranch, int do_test) { struct rtpp_node *node = NULL; @@ -2421,12 +2428,12 @@ select_rtpp_node(str callid, int do_test, int op) } // lookup node - node = select_rtpp_node_old(callid, do_test, op); + node = select_rtpp_node_old(callid, viabranch, do_test); // check node if (!node) { // run the selection algorithm - node = select_rtpp_node_new(callid, do_test, op); + node = select_rtpp_node_new(callid, viabranch, do_test); // check node if (!node) { diff --git a/modules/rtpengine/rtpengine_hash.c b/modules/rtpengine/rtpengine_hash.c index 566a9607eda..027fd8a26f0 100644 --- a/modules/rtpengine/rtpengine_hash.c +++ b/modules/rtpengine/rtpengine_hash.c @@ -11,25 +11,25 @@ static struct rtpengine_hash_table *rtpengine_hash_table; static int hash_table_size; /* from sipwise rtpengine */ -static int str_cmp_str(const str *a, const str *b) { - if (a->len < b->len) +static int str_cmp_str(const str a, const str b) { + if (a.len < b.len) return -1; - if (a->len > b->len) + if (a.len > b.len) return 1; - if (a->len == 0 && b->len == 0) + if (a.len == 0 && b.len == 0) return 0; - return memcmp(a->s, b->s, a->len); + return memcmp(a.s, b.s, a.len); } /* from sipwise rtpengine */ -static int str_equal(str *a, str *b) { +static int str_equal(str a, str b) { return (str_cmp_str(a, b) == 0); } /* from sipwise rtpengine */ -static unsigned int str_hash(str *s) { +static unsigned int str_hash(str s) { unsigned int ret = 5381; - str it = *s; + str it = s; while (it.len > 0) { ret = (ret << 5) + ret + *it.s; @@ -40,7 +40,7 @@ static unsigned int str_hash(str *s) { return ret % hash_table_size; } -/* rtpengine glib hash API */ +/* rtpengine hash API */ int rtpengine_hash_table_init(int size) { int i; @@ -58,6 +58,7 @@ int rtpengine_hash_table_init(int size) { LM_ERR("no shm left to create rtpengine_hash_table\n"); return 0; } + memset(rtpengine_hash_table, 0, sizeof(struct rtpengine_hash_table)); // init hashtable entry_list rtpengine_hash_table->entry_list = shm_malloc(hash_table_size * sizeof(struct rtpengine_hash_entry)); @@ -97,7 +98,6 @@ int rtpengine_hash_table_init(int size) { int rtpengine_hash_table_destroy() { int i; - struct rtpengine_hash_entry *entry, *last_entry; // check rtpengine hashtable if (!rtpengine_hash_table) { @@ -113,16 +113,11 @@ int rtpengine_hash_table_destroy() { return 0; } - // destroy hashtable entry_list[i] lock_get(rtpengine_hash_lock); + + // destroy hashtable entry_list[i] for (i = 0; i < hash_table_size; i++) { - entry = rtpengine_hash_table->entry_list[i]; - while (entry) { - last_entry = entry; - entry = entry->next; - shm_free(last_entry->callid.s); - shm_free(last_entry); - } + rtpengine_hash_table_free_entry_list(rtpengine_hash_table->entry_list[i]); } // destroy hashtable entry_list @@ -132,6 +127,7 @@ int rtpengine_hash_table_destroy() { // destroy hashtable shm_free(rtpengine_hash_table); rtpengine_hash_table = NULL; + lock_release(rtpengine_hash_lock); // destroy lock @@ -145,7 +141,7 @@ int rtpengine_hash_table_destroy() { return 1; } -int rtpengine_hash_table_insert(str *key, struct rtpengine_hash_entry *value) { +int rtpengine_hash_table_insert(str callid, str viabranch, struct rtpengine_hash_entry *value) { struct rtpengine_hash_entry *entry, *last_entry; struct rtpengine_hash_entry *new_entry = (struct rtpengine_hash_entry *) value; unsigned int hash_index; @@ -163,18 +159,21 @@ int rtpengine_hash_table_insert(str *key, struct rtpengine_hash_entry *value) { } // get entry list - hash_index = str_hash(key); + hash_index = str_hash(callid); entry = rtpengine_hash_table->entry_list[hash_index]; last_entry = entry; // lock lock_get(rtpengine_hash_lock); while (entry) { - // if key found, don't add new entry - if (str_equal(&entry->callid, &new_entry->callid)) { + // if found, don't add new entry + if (str_equal(entry->callid, new_entry->callid) && + str_equal(entry->viabranch, new_entry->viabranch)) { // unlock lock_release(rtpengine_hash_lock); - LM_ERR("Call id %.*s already in hashtable, ignore new value", entry->callid.len, entry->callid.s); + LM_NOTICE("callid=%.*s, viabranch=%.*s already in hashtable, ignore new value", + entry->callid.len, entry->callid.s, + entry->viabranch.len, entry->viabranch.s); return 0; } @@ -184,8 +183,7 @@ int rtpengine_hash_table_insert(str *key, struct rtpengine_hash_entry *value) { last_entry->next = entry->next; // free current entry; entry points to unknown - shm_free(entry->callid.s); - shm_free(entry); + rtpengine_hash_table_free_entry(entry); // set pointers entry = last_entry; @@ -210,7 +208,7 @@ int rtpengine_hash_table_insert(str *key, struct rtpengine_hash_entry *value) { return 1; } -int rtpengine_hash_table_remove(str *key) { +int rtpengine_hash_table_remove(str callid, str viabranch) { struct rtpengine_hash_entry *entry, *last_entry; unsigned int hash_index; @@ -227,19 +225,19 @@ int rtpengine_hash_table_remove(str *key) { } // get first entry from entry list; jump over unused list head - hash_index = str_hash(key); + hash_index = str_hash(callid); entry = rtpengine_hash_table->entry_list[hash_index]; last_entry = entry; // lock lock_get(rtpengine_hash_lock); while (entry) { - // if key found, delete entry - if (str_equal(&entry->callid, (str *)key)) { + // if callid found, delete entry + if (str_equal(entry->callid, callid) && + str_equal(entry->viabranch, viabranch)) { // free entry last_entry->next = entry->next; - shm_free(entry->callid.s); - shm_free(entry); + rtpengine_hash_table_free_entry(entry); // update total rtpengine_hash_table->total--; @@ -256,8 +254,7 @@ int rtpengine_hash_table_remove(str *key) { last_entry->next = entry->next; // free current entry; entry points to unknown - shm_free(entry->callid.s); - shm_free(entry); + rtpengine_hash_table_free_entry(entry); // set pointers entry = last_entry; @@ -276,7 +273,7 @@ int rtpengine_hash_table_remove(str *key) { return 0; } -struct rtpp_node *rtpengine_hash_table_lookup(str *key) { +struct rtpp_node *rtpengine_hash_table_lookup(str callid, str viabranch) { struct rtpengine_hash_entry *entry, *last_entry; unsigned int hash_index; struct rtpp_node *node; @@ -294,15 +291,16 @@ struct rtpp_node *rtpengine_hash_table_lookup(str *key) { } // get first entry from entry list; jump over unused list head - hash_index = str_hash(key); + hash_index = str_hash(callid); entry = rtpengine_hash_table->entry_list[hash_index]; last_entry = entry; // lock lock_get(rtpengine_hash_lock); while (entry) { - // if key found, return entry - if (str_equal(&entry->callid, (str *)key)) { + // if callid found, return entry + if (str_equal(entry->callid, callid) && + str_equal(entry->viabranch, viabranch)) { node = entry->node; // unlock @@ -317,8 +315,7 @@ struct rtpp_node *rtpengine_hash_table_lookup(str *key) { last_entry->next = entry->next; // free current entry; entry points to unknown - shm_free(entry->callid.s); - shm_free(entry); + rtpengine_hash_table_free_entry(entry); // set pointers entry = last_entry; @@ -369,8 +366,7 @@ void rtpengine_hash_table_print() { last_entry->next = entry->next; // free current entry; entry points to unknown - shm_free(entry->callid.s); - shm_free(entry); + rtpengine_hash_table_free_entry(entry); // set pointers entry = last_entry; @@ -401,3 +397,41 @@ unsigned int rtpengine_hash_table_total() { return rtpengine_hash_table->total; } + +void rtpengine_hash_table_free_entry(struct rtpengine_hash_entry *entry) { + if (!entry) { + return ; + } + + // free callid + if (entry->callid.s) { + shm_free(entry->callid.s); + } + + // free viabranch + if (entry->viabranch.s) { + shm_free(entry->viabranch.s); + } + + // free entry + shm_free(entry); + + return ; +} + +void rtpengine_hash_table_free_entry_list(struct rtpengine_hash_entry *entry_list) { + struct rtpengine_hash_entry *entry, *last_entry; + + if (!entry_list) { + return ; + } + + entry = entry_list; + while (entry) { + last_entry = entry; + entry = entry->next; + rtpengine_hash_table_free_entry(last_entry); + } + + return ; +} diff --git a/modules/rtpengine/rtpengine_hash.h b/modules/rtpengine/rtpengine_hash.h index c0a9ed8c6bc..2d1ab4545f1 100644 --- a/modules/rtpengine/rtpengine_hash.h +++ b/modules/rtpengine/rtpengine_hash.h @@ -6,10 +6,11 @@ /* table entry */ struct rtpengine_hash_entry { - unsigned int tout; // call timeout str callid; // call callid + str viabranch; // call viabranch struct rtpp_node *node; // call selected node + unsigned int tout; // call timeout struct rtpengine_hash_entry *next; // call next }; @@ -22,10 +23,13 @@ struct rtpengine_hash_table { int rtpengine_hash_table_init(int size); int rtpengine_hash_table_destroy(); -int rtpengine_hash_table_insert(str *key, struct rtpengine_hash_entry *value); -int rtpengine_hash_table_remove(str *key); -struct rtpp_node *rtpengine_hash_table_lookup(str *key); +int rtpengine_hash_table_insert(str callid, str viabranch, struct rtpengine_hash_entry *value); +int rtpengine_hash_table_remove(str callid, str viabranch); +struct rtpp_node *rtpengine_hash_table_lookup(str callid, str viabranch); void rtpengine_hash_table_print(); unsigned int rtpengine_hash_table_total(); +void rtpengine_hash_table_free_entry(struct rtpengine_hash_entry *entry); +void rtpengine_hash_table_free_entry_list(struct rtpengine_hash_entry *entry_list); + #endif From 6390e8b35da0f8ad92430e40627d2c52e0b3ca52 Mon Sep 17 00:00:00 2001 From: Stefan Mititelu Date: Fri, 4 Dec 2015 13:08:11 +0200 Subject: [PATCH 08/13] rtpengine: Don't shm_str_dup() a NULL str->s Don't dup a NULL str->s to avoid warning message. This happened usually when viabranch is not used(default being NULL). --- modules/rtpengine/rtpengine.c | 24 ++++++++++++++---------- 1 file changed, 14 insertions(+), 10 deletions(-) diff --git a/modules/rtpengine/rtpengine.c b/modules/rtpengine/rtpengine.c index 7fa328365f8..893bc9dd67f 100644 --- a/modules/rtpengine/rtpengine.c +++ b/modules/rtpengine/rtpengine.c @@ -2360,17 +2360,21 @@ select_rtpp_node_new(str callid, str viabranch, int do_test) memset(entry, 0, sizeof(struct rtpengine_hash_entry)); /* fill the entry */ - if (shm_str_dup(&entry->callid, &callid) < 0) { - LM_ERR("rtpengine hash table fail to duplicate calllen=%d callid=%.*s\n", - callid.len, callid.len, callid.s); - rtpengine_hash_table_free_entry(entry); - return node; + if (callid.s && callid.len > 0) { + if (shm_str_dup(&entry->callid, &callid) < 0) { + LM_ERR("rtpengine hash table fail to duplicate calllen=%d callid=%.*s\n", + callid.len, callid.len, callid.s); + rtpengine_hash_table_free_entry(entry); + return node; + } } - if (shm_str_dup(&entry->viabranch, &viabranch) < 0) { - LM_ERR("rtpengine hash table fail to duplicate calllen=%d viabranch=%.*s\n", - callid.len, viabranch.len, viabranch.s); - rtpengine_hash_table_free_entry(entry); - return node; + if (viabranch.s && viabranch.len > 0) { + if (shm_str_dup(&entry->viabranch, &viabranch) < 0) { + LM_ERR("rtpengine hash table fail to duplicate calllen=%d viabranch=%.*s\n", + callid.len, viabranch.len, viabranch.s); + rtpengine_hash_table_free_entry(entry); + return node; + } } entry->node = node; entry->next = NULL; From 5a537506141027ca3d3ef87f49913ab628c30690 Mon Sep 17 00:00:00 2001 From: Stefan Mititelu Date: Mon, 7 Dec 2015 13:30:02 +0200 Subject: [PATCH 09/13] rtpengine: Allow op for all deactivated machines If allow_op modparam enabled, send commands to the disabled machines for the existing call. So far this was done only for manually deactivated machines. This is useful because there might be cases of proxy timeout, cases when you may want to still allow the operations for the existing calls. --- modules/rtpengine/rtpengine.c | 16 +++++++--------- 1 file changed, 7 insertions(+), 9 deletions(-) diff --git a/modules/rtpengine/rtpengine.c b/modules/rtpengine/rtpengine.c index 893bc9dd67f..bba10efc4b7 100644 --- a/modules/rtpengine/rtpengine.c +++ b/modules/rtpengine/rtpengine.c @@ -2452,18 +2452,16 @@ select_rtpp_node(str callid, str viabranch, int do_test) return node; } - // if node _manually_ disabled(e.g kamctl) and proper configuration, return it - if (node->rn_recheck_ticks == MI_MAX_RECHECK_TICKS) { - if (rtpengine_allow_op) { + // if proper configuration and node manually or timeout disabled, return it + if (rtpengine_allow_op) { + if (node->rn_recheck_ticks == MI_MAX_RECHECK_TICKS) { LM_DBG("node=%.*s for calllen=%d callid=%.*s is disabled(permanent) (probably still UP)! Return it\n", node->rn_url.len, node->rn_url.s, callid.len, callid.len, callid.s); - return node; + } else { + LM_DBG("node=%.*s for calllen=%d callid=%.*s is disabled, either broke or timeout disabled! Return it\n", + node->rn_url.len, node->rn_url.s, callid.len, callid.len, callid.s); } - LM_DBG("node=%.*s for calllen=%d callid=%.*s is disabled(permanent) (probably still UP)! Return NULL\n", - node->rn_url.len, node->rn_url.s, callid.len, callid.len, callid.s); - } else { - LM_DBG("node=%.*s for calllen=%d callid=%.*s is disabled (probably BROKE)! Return NULL\n", - node->rn_url.len, node->rn_url.s, callid.len, callid.len, callid.s); + return node; } return NULL; From a22b59fc802c1c1ee2a13ed772c515398f41e0a7 Mon Sep 17 00:00:00 2001 From: Stefan Mititelu Date: Tue, 8 Dec 2015 15:29:09 +0200 Subject: [PATCH 10/13] rtpengine: Add per rows hash table locks This will further increase rtpengine's hash table access. --- modules/rtpengine/rtpengine_hash.c | 139 ++++++++++++++++++++--------- modules/rtpengine/rtpengine_hash.h | 4 + 2 files changed, 100 insertions(+), 43 deletions(-) diff --git a/modules/rtpengine/rtpengine_hash.c b/modules/rtpengine/rtpengine_hash.c index 027fd8a26f0..e20b5643b5e 100644 --- a/modules/rtpengine/rtpengine_hash.c +++ b/modules/rtpengine/rtpengine_hash.c @@ -6,7 +6,6 @@ #include "../../locking.h" #include "../../timer.h" -static gen_lock_t *rtpengine_hash_lock; static struct rtpengine_hash_table *rtpengine_hash_table; static int hash_table_size; @@ -85,14 +84,24 @@ int rtpengine_hash_table_init(int size) { rtpengine_hash_table->total = 0; } - // init lock - rtpengine_hash_lock = lock_alloc(); - if (!rtpengine_hash_lock) { - LM_ERR("no shm left to init rtpengine_hash_table lock"); + // init hashtable row_locks + rtpengine_hash_table->row_locks = shm_malloc(hash_table_size * sizeof(gen_lock_t*)); + if (!rtpengine_hash_table->row_locks) { + LM_ERR("no shm left to create rtpengine_hash_table->row_locks\n"); rtpengine_hash_table_destroy(); return 0; } + // init hashtable row_locks[i] + for (i = 0; i < hash_table_size; i++) { + rtpengine_hash_table->row_locks[i] = lock_alloc(); + if (!rtpengine_hash_table->row_locks[i]) { + LM_ERR("no shm left to create rtpengine_hash_table->row_locks[%d]\n", i); + rtpengine_hash_table_destroy(); + return 0; + } + } + return 1; } @@ -101,43 +110,47 @@ int rtpengine_hash_table_destroy() { // check rtpengine hashtable if (!rtpengine_hash_table) { - LM_ERR("NULL rtpengine_hash_table"); + LM_ERR("NULL rtpengine_hash_table\n"); return 0; } // check rtpengine hashtable->entry_list if (!rtpengine_hash_table->entry_list) { - LM_ERR("NULL rtpengine_hash_table->entry_list"); + LM_ERR("NULL rtpengine_hash_table->entry_list\n"); shm_free(rtpengine_hash_table); rtpengine_hash_table = NULL; return 0; } - lock_get(rtpengine_hash_lock); - - // destroy hashtable entry_list[i] + // destroy hashtable content for (i = 0; i < hash_table_size; i++) { + // destroy hashtable entry_list[i] + if (rtpengine_hash_table->row_locks[i]) { + lock_get(rtpengine_hash_table->row_locks[i]); + } else { + LM_ERR("NULL rtpengine_hash_table->row_locks[%d]\n", i); + return 0; + } rtpengine_hash_table_free_entry_list(rtpengine_hash_table->entry_list[i]); + lock_release(rtpengine_hash_table->row_locks[i]); + + // destroy hashtable row_locks[i] + rtpengine_hash_table_free_row_lock(rtpengine_hash_table->row_locks[i]); + rtpengine_hash_table->row_locks[i] = NULL; } // destroy hashtable entry_list shm_free(rtpengine_hash_table->entry_list); rtpengine_hash_table->entry_list = NULL; + // destroy hashtable row_locks + shm_free(rtpengine_hash_table->row_locks); + rtpengine_hash_table->row_locks = NULL; + // destroy hashtable shm_free(rtpengine_hash_table); rtpengine_hash_table = NULL; - lock_release(rtpengine_hash_lock); - - // destroy lock - if (!rtpengine_hash_lock) { - LM_ERR("NULL rtpengine_hash_lock"); - } else { - lock_dealloc(rtpengine_hash_lock); - rtpengine_hash_lock = NULL; - } - return 1; } @@ -148,13 +161,19 @@ int rtpengine_hash_table_insert(str callid, str viabranch, struct rtpengine_hash // check rtpengine hashtable if (!rtpengine_hash_table) { - LM_ERR("NULL rtpengine_hash_table"); + LM_ERR("NULL rtpengine_hash_table\n"); return 0; } // check rtpengine hashtable->entry_list if (!rtpengine_hash_table->entry_list) { - LM_ERR("NULL rtpengine_hash_table->entry_list"); + LM_ERR("NULL rtpengine_hash_table->entry_list\n"); + return 0; + } + + // check rtpengine hashtable->row_locks + if (!rtpengine_hash_table->row_locks) { + LM_ERR("NULL rtpengine_hash_table->row_locks\n"); return 0; } @@ -163,15 +182,21 @@ int rtpengine_hash_table_insert(str callid, str viabranch, struct rtpengine_hash entry = rtpengine_hash_table->entry_list[hash_index]; last_entry = entry; + if (rtpengine_hash_table->row_locks[hash_index]) { + lock_get(rtpengine_hash_table->row_locks[hash_index]); + } else { + LM_ERR("NULL rtpengine_hash_table->row_locks[%d]\n", hash_index); + return 0; + } + // lock - lock_get(rtpengine_hash_lock); while (entry) { // if found, don't add new entry if (str_equal(entry->callid, new_entry->callid) && str_equal(entry->viabranch, new_entry->viabranch)) { // unlock - lock_release(rtpengine_hash_lock); - LM_NOTICE("callid=%.*s, viabranch=%.*s already in hashtable, ignore new value", + lock_release(rtpengine_hash_table->row_locks[hash_index]); + LM_NOTICE("callid=%.*s, viabranch=%.*s already in hashtable, ignore new value\n", entry->callid.len, entry->callid.s, entry->viabranch.len, entry->viabranch.s); return 0; @@ -203,7 +228,7 @@ int rtpengine_hash_table_insert(str callid, str viabranch, struct rtpengine_hash rtpengine_hash_table->total++; // unlock - lock_release(rtpengine_hash_lock); + lock_release(rtpengine_hash_table->row_locks[hash_index]); return 1; } @@ -214,13 +239,13 @@ int rtpengine_hash_table_remove(str callid, str viabranch) { // check rtpengine hashtable if (!rtpengine_hash_table) { - LM_ERR("NULL rtpengine_hash_table"); + LM_ERR("NULL rtpengine_hash_table\n"); return 0; } // check rtpengine hashtable->entry_list if (!rtpengine_hash_table->entry_list) { - LM_ERR("NULL rtpengine_hash_table->entry_list"); + LM_ERR("NULL rtpengine_hash_table->entry_list\n"); return 0; } @@ -230,7 +255,12 @@ int rtpengine_hash_table_remove(str callid, str viabranch) { last_entry = entry; // lock - lock_get(rtpengine_hash_lock); + if (rtpengine_hash_table->row_locks[hash_index]) { + lock_get(rtpengine_hash_table->row_locks[hash_index]); + } else { + LM_ERR("NULL rtpengine_hash_table->row_locks[%d]\n", hash_index); + return 0; + } while (entry) { // if callid found, delete entry if (str_equal(entry->callid, callid) && @@ -243,7 +273,7 @@ int rtpengine_hash_table_remove(str callid, str viabranch) { rtpengine_hash_table->total--; // unlock - lock_release(rtpengine_hash_lock); + lock_release(rtpengine_hash_table->row_locks[hash_index]); return 1; } @@ -268,7 +298,7 @@ int rtpengine_hash_table_remove(str callid, str viabranch) { } // unlock - lock_release(rtpengine_hash_lock); + lock_release(rtpengine_hash_table->row_locks[hash_index]); return 0; } @@ -280,13 +310,13 @@ struct rtpp_node *rtpengine_hash_table_lookup(str callid, str viabranch) { // check rtpengine hashtable if (!rtpengine_hash_table) { - LM_ERR("NULL rtpengine_hash_table"); + LM_ERR("NULL rtpengine_hash_table\n"); return NULL; } // check rtpengine hashtable->entry_list if (!rtpengine_hash_table->entry_list) { - LM_ERR("NULL rtpengine_hash_table->entry_list"); + LM_ERR("NULL rtpengine_hash_table->entry_list\n"); return NULL; } @@ -296,7 +326,12 @@ struct rtpp_node *rtpengine_hash_table_lookup(str callid, str viabranch) { last_entry = entry; // lock - lock_get(rtpengine_hash_lock); + if (rtpengine_hash_table->row_locks[hash_index]) { + lock_get(rtpengine_hash_table->row_locks[hash_index]); + } else { + LM_ERR("NULL rtpengine_hash_table->row_locks[%d]\n", hash_index); + return 0; + } while (entry) { // if callid found, return entry if (str_equal(entry->callid, callid) && @@ -304,7 +339,7 @@ struct rtpp_node *rtpengine_hash_table_lookup(str callid, str viabranch) { node = entry->node; // unlock - lock_release(rtpengine_hash_lock); + lock_release(rtpengine_hash_table->row_locks[hash_index]); return node; } @@ -329,7 +364,7 @@ struct rtpp_node *rtpengine_hash_table_lookup(str callid, str viabranch) { } // unlock - lock_release(rtpengine_hash_lock); + lock_release(rtpengine_hash_table->row_locks[hash_index]); return NULL; } @@ -341,21 +376,27 @@ void rtpengine_hash_table_print() { // check rtpengine hashtable if (!rtpengine_hash_table) { - LM_ERR("NULL rtpengine_hash_table"); + LM_ERR("NULL rtpengine_hash_table\n"); return ; } // check rtpengine hashtable->entry_list if (!rtpengine_hash_table->entry_list) { - LM_ERR("NULL rtpengine_hash_table->entry_list"); + LM_ERR("NULL rtpengine_hash_table->entry_list\n"); return ; } - // lock - lock_get(rtpengine_hash_lock); // print hashtable for (i = 0; i < hash_table_size; i++) { + // lock + if (rtpengine_hash_table->row_locks[i]) { + lock_get(rtpengine_hash_table->row_locks[i]); + } else { + LM_ERR("NULL rtpengine_hash_table->row_locks[%d]\n", i); + return ; + } + entry = rtpengine_hash_table->entry_list[i]; last_entry = entry; @@ -381,17 +422,18 @@ void rtpengine_hash_table_print() { last_entry = entry; entry = entry->next; } + + // unlock + lock_release(rtpengine_hash_table->row_locks[i]); } - // unlock - lock_release(rtpengine_hash_lock); } unsigned int rtpengine_hash_table_total() { // check rtpengine hashtable if (!rtpengine_hash_table) { - LM_ERR("NULL rtpengine_hash_table"); + LM_ERR("NULL rtpengine_hash_table\n"); return 0; } @@ -431,7 +473,18 @@ void rtpengine_hash_table_free_entry_list(struct rtpengine_hash_entry *entry_lis last_entry = entry; entry = entry->next; rtpengine_hash_table_free_entry(last_entry); + last_entry = NULL; + } + + return ; +} + +void rtpengine_hash_table_free_row_lock(gen_lock_t *row_lock) { + if (!row_lock) { + return ; } + lock_destroy(row_lock); + return ; } diff --git a/modules/rtpengine/rtpengine_hash.h b/modules/rtpengine/rtpengine_hash.h index 2d1ab4545f1..c4c67baa774 100644 --- a/modules/rtpengine/rtpengine_hash.h +++ b/modules/rtpengine/rtpengine_hash.h @@ -2,6 +2,7 @@ #define _RTPENGINE_HASH_H #include "../../str.h" +#include "../../locking.h" /* table entry */ @@ -17,6 +18,7 @@ struct rtpengine_hash_entry { /* table */ struct rtpengine_hash_table { struct rtpengine_hash_entry **entry_list; // hastable + gen_lock_t **row_locks; // hastable row locks unsigned int total; // total number of entries in the hashtable }; @@ -32,4 +34,6 @@ unsigned int rtpengine_hash_table_total(); void rtpengine_hash_table_free_entry(struct rtpengine_hash_entry *entry); void rtpengine_hash_table_free_entry_list(struct rtpengine_hash_entry *entry_list); +void rtpengine_hash_table_free_row_lock(gen_lock_t *lock); + #endif From c4f2b557682b3e7172b70550913711cccf68df56 Mon Sep 17 00:00:00 2001 From: Stefan Mititelu Date: Wed, 9 Dec 2015 11:00:15 +0200 Subject: [PATCH 11/13] rtpengine: Add per rows totals statistics For consistency with the per row locks, statistics should be also per row. --- modules/rtpengine/rtpengine_hash.c | 172 +++++++++++++++-------------- modules/rtpengine/rtpengine_hash.h | 7 +- 2 files changed, 96 insertions(+), 83 deletions(-) diff --git a/modules/rtpengine/rtpengine_hash.c b/modules/rtpengine/rtpengine_hash.c index e20b5643b5e..0062da888cc 100644 --- a/modules/rtpengine/rtpengine_hash.c +++ b/modules/rtpengine/rtpengine_hash.c @@ -68,8 +68,27 @@ int rtpengine_hash_table_init(int size) { } memset(rtpengine_hash_table->entry_list, 0, hash_table_size * sizeof(struct rtpengine_hash_entry)); - // init hashtable entry_list[i] (head never filled); destroy table on error + // init hashtable row_locks + rtpengine_hash_table->row_locks = shm_malloc(hash_table_size * sizeof(gen_lock_t*)); + if (!rtpengine_hash_table->row_locks) { + LM_ERR("no shm left to create rtpengine_hash_table->row_locks\n"); + rtpengine_hash_table_destroy(); + return 0; + } + memset(rtpengine_hash_table->row_locks, 0, hash_table_size * sizeof(gen_lock_t*)); + + // init hashtable row_totals + rtpengine_hash_table->row_totals = shm_malloc(hash_table_size * sizeof(unsigned int)); + if (!rtpengine_hash_table->row_totals) { + LM_ERR("no shm left to create rtpengine_hash_table->row_totals\n"); + rtpengine_hash_table_destroy(); + return 0; + } + memset(rtpengine_hash_table->row_totals, 0, hash_table_size * sizeof(unsigned int)); + + // init hashtable entry_list[i], row_locks[i] and row_totals[i] for (i = 0; i < hash_table_size; i++) { + // init hashtable row_entry_list[i] rtpengine_hash_table->entry_list[i] = shm_malloc(sizeof(struct rtpengine_hash_entry)); if (!rtpengine_hash_table->entry_list[i]) { LM_ERR("no shm left to create rtpengine_hash_table->entry_list[%d]\n", i); @@ -78,22 +97,10 @@ int rtpengine_hash_table_init(int size) { } memset(rtpengine_hash_table->entry_list[i], 0, sizeof(struct rtpengine_hash_entry)); - // never expire the head of the hashtable index lists rtpengine_hash_table->entry_list[i]->tout = -1; rtpengine_hash_table->entry_list[i]->next = NULL; - rtpengine_hash_table->total = 0; - } - - // init hashtable row_locks - rtpengine_hash_table->row_locks = shm_malloc(hash_table_size * sizeof(gen_lock_t*)); - if (!rtpengine_hash_table->row_locks) { - LM_ERR("no shm left to create rtpengine_hash_table->row_locks\n"); - rtpengine_hash_table_destroy(); - return 0; - } - // init hashtable row_locks[i] - for (i = 0; i < hash_table_size; i++) { + // init hashtable row_locks[i] rtpengine_hash_table->row_locks[i] = lock_alloc(); if (!rtpengine_hash_table->row_locks[i]) { LM_ERR("no shm left to create rtpengine_hash_table->row_locks[%d]\n", i); @@ -108,17 +115,9 @@ int rtpengine_hash_table_init(int size) { int rtpengine_hash_table_destroy() { int i; - // check rtpengine hashtable - if (!rtpengine_hash_table) { - LM_ERR("NULL rtpengine_hash_table\n"); - return 0; - } - - // check rtpengine hashtable->entry_list - if (!rtpengine_hash_table->entry_list) { - LM_ERR("NULL rtpengine_hash_table->entry_list\n"); - shm_free(rtpengine_hash_table); - rtpengine_hash_table = NULL; + // sanity checks + if (!rtpengine_hash_table_sanity_checks()) { + LM_ERR("sanity checks failed\n"); return 0; } @@ -132,6 +131,7 @@ int rtpengine_hash_table_destroy() { return 0; } rtpengine_hash_table_free_entry_list(rtpengine_hash_table->entry_list[i]); + rtpengine_hash_table->entry_list[i] = NULL; lock_release(rtpengine_hash_table->row_locks[i]); // destroy hashtable row_locks[i] @@ -147,6 +147,10 @@ int rtpengine_hash_table_destroy() { shm_free(rtpengine_hash_table->row_locks); rtpengine_hash_table->row_locks = NULL; + // destroy hashtable row_totals + shm_free(rtpengine_hash_table->row_totals); + rtpengine_hash_table->row_totals = NULL; + // destroy hashtable shm_free(rtpengine_hash_table); rtpengine_hash_table = NULL; @@ -159,21 +163,9 @@ int rtpengine_hash_table_insert(str callid, str viabranch, struct rtpengine_hash struct rtpengine_hash_entry *new_entry = (struct rtpengine_hash_entry *) value; unsigned int hash_index; - // check rtpengine hashtable - if (!rtpengine_hash_table) { - LM_ERR("NULL rtpengine_hash_table\n"); - return 0; - } - - // check rtpengine hashtable->entry_list - if (!rtpengine_hash_table->entry_list) { - LM_ERR("NULL rtpengine_hash_table->entry_list\n"); - return 0; - } - - // check rtpengine hashtable->row_locks - if (!rtpengine_hash_table->row_locks) { - LM_ERR("NULL rtpengine_hash_table->row_locks\n"); + // sanity checks + if (!rtpengine_hash_table_sanity_checks()) { + LM_ERR("sanity checks failed\n"); return 0; } @@ -182,6 +174,7 @@ int rtpengine_hash_table_insert(str callid, str viabranch, struct rtpengine_hash entry = rtpengine_hash_table->entry_list[hash_index]; last_entry = entry; + // lock if (rtpengine_hash_table->row_locks[hash_index]) { lock_get(rtpengine_hash_table->row_locks[hash_index]); } else { @@ -189,7 +182,6 @@ int rtpengine_hash_table_insert(str callid, str viabranch, struct rtpengine_hash return 0; } - // lock while (entry) { // if found, don't add new entry if (str_equal(entry->callid, new_entry->callid) && @@ -214,7 +206,7 @@ int rtpengine_hash_table_insert(str callid, str viabranch, struct rtpengine_hash entry = last_entry; // update total - rtpengine_hash_table->total--; + rtpengine_hash_table->row_totals[hash_index]--; } // next entry in the list @@ -225,7 +217,7 @@ int rtpengine_hash_table_insert(str callid, str viabranch, struct rtpengine_hash last_entry->next = new_entry; // update total - rtpengine_hash_table->total++; + rtpengine_hash_table->row_totals[hash_index]++; // unlock lock_release(rtpengine_hash_table->row_locks[hash_index]); @@ -237,15 +229,9 @@ int rtpengine_hash_table_remove(str callid, str viabranch) { struct rtpengine_hash_entry *entry, *last_entry; unsigned int hash_index; - // check rtpengine hashtable - if (!rtpengine_hash_table) { - LM_ERR("NULL rtpengine_hash_table\n"); - return 0; - } - - // check rtpengine hashtable->entry_list - if (!rtpengine_hash_table->entry_list) { - LM_ERR("NULL rtpengine_hash_table->entry_list\n"); + // sanity checks + if (!rtpengine_hash_table_sanity_checks()) { + LM_ERR("sanity checks failed\n"); return 0; } @@ -261,6 +247,7 @@ int rtpengine_hash_table_remove(str callid, str viabranch) { LM_ERR("NULL rtpengine_hash_table->row_locks[%d]\n", hash_index); return 0; } + while (entry) { // if callid found, delete entry if (str_equal(entry->callid, callid) && @@ -270,7 +257,7 @@ int rtpengine_hash_table_remove(str callid, str viabranch) { rtpengine_hash_table_free_entry(entry); // update total - rtpengine_hash_table->total--; + rtpengine_hash_table->row_totals[hash_index]--; // unlock lock_release(rtpengine_hash_table->row_locks[hash_index]); @@ -290,7 +277,7 @@ int rtpengine_hash_table_remove(str callid, str viabranch) { entry = last_entry; // update total - rtpengine_hash_table->total--; + rtpengine_hash_table->row_totals[hash_index]--; } last_entry = entry; @@ -308,16 +295,10 @@ struct rtpp_node *rtpengine_hash_table_lookup(str callid, str viabranch) { unsigned int hash_index; struct rtpp_node *node; - // check rtpengine hashtable - if (!rtpengine_hash_table) { - LM_ERR("NULL rtpengine_hash_table\n"); - return NULL; - } - - // check rtpengine hashtable->entry_list - if (!rtpengine_hash_table->entry_list) { - LM_ERR("NULL rtpengine_hash_table->entry_list\n"); - return NULL; + // sanity checks + if (!rtpengine_hash_table_sanity_checks()) { + LM_ERR("sanity checks failed\n"); + return 0; } // get first entry from entry list; jump over unused list head @@ -332,6 +313,7 @@ struct rtpp_node *rtpengine_hash_table_lookup(str callid, str viabranch) { LM_ERR("NULL rtpengine_hash_table->row_locks[%d]\n", hash_index); return 0; } + while (entry) { // if callid found, return entry if (str_equal(entry->callid, callid) && @@ -356,7 +338,7 @@ struct rtpp_node *rtpengine_hash_table_lookup(str callid, str viabranch) { entry = last_entry; // update total - rtpengine_hash_table->total--; + rtpengine_hash_table->row_totals[hash_index]--; } last_entry = entry; @@ -374,19 +356,12 @@ void rtpengine_hash_table_print() { int i; struct rtpengine_hash_entry *entry, *last_entry; - // check rtpengine hashtable - if (!rtpengine_hash_table) { - LM_ERR("NULL rtpengine_hash_table\n"); - return ; - } - - // check rtpengine hashtable->entry_list - if (!rtpengine_hash_table->entry_list) { - LM_ERR("NULL rtpengine_hash_table->entry_list\n"); + // sanity checks + if (!rtpengine_hash_table_sanity_checks()) { + LM_ERR("sanity checks failed\n"); return ; } - // print hashtable for (i = 0; i < hash_table_size; i++) { // lock @@ -413,7 +388,7 @@ void rtpengine_hash_table_print() { entry = last_entry; // update total - rtpengine_hash_table->total--; + rtpengine_hash_table->row_totals[i]--; } else { LM_DBG("hash_index=%d callid=%.*s tout=%u\n", i, entry->callid.len, entry->callid.s, entry->tout - get_ticks()); @@ -430,18 +405,25 @@ void rtpengine_hash_table_print() { } unsigned int rtpengine_hash_table_total() { + int i; + unsigned int total = 0; - // check rtpengine hashtable - if (!rtpengine_hash_table) { - LM_ERR("NULL rtpengine_hash_table\n"); + // sanity checks + if (!rtpengine_hash_table_sanity_checks()) { + LM_ERR("sanity checks failed\n"); return 0; } - return rtpengine_hash_table->total; + for (i = 0; i < hash_table_size; i++) { + total += rtpengine_hash_table->row_totals[i]; + } + + return total; } void rtpengine_hash_table_free_entry(struct rtpengine_hash_entry *entry) { if (!entry) { + LM_ERR("try to free a NULL entry\n"); return ; } @@ -465,6 +447,7 @@ void rtpengine_hash_table_free_entry_list(struct rtpengine_hash_entry *entry_lis struct rtpengine_hash_entry *entry, *last_entry; if (!entry_list) { + LM_ERR("try to free a NULL entry_list\n"); return ; } @@ -481,6 +464,7 @@ void rtpengine_hash_table_free_entry_list(struct rtpengine_hash_entry *entry_lis void rtpengine_hash_table_free_row_lock(gen_lock_t *row_lock) { if (!row_lock) { + LM_ERR("try to free a NULL lock\n"); return ; } @@ -488,3 +472,31 @@ void rtpengine_hash_table_free_row_lock(gen_lock_t *row_lock) { return ; } + +int rtpengine_hash_table_sanity_checks() { + // check rtpengine hashtable + if (!rtpengine_hash_table) { + LM_ERR("NULL rtpengine_hash_table\n"); + return 0; + } + + // check rtpengine hashtable->entry_list + if (!rtpengine_hash_table->entry_list) { + LM_ERR("NULL rtpengine_hash_table->entry_list\n"); + return 0; + } + + // check rtpengine hashtable->row_locks + if (!rtpengine_hash_table->row_locks) { + LM_ERR("NULL rtpengine_hash_table->row_locks\n"); + return 0; + } + + // check rtpengine hashtable->row_totals + if (!rtpengine_hash_table->row_totals) { + LM_ERR("NULL rtpengine_hash_table->row_totals\n"); + return 0; + } + + return 1; +} diff --git a/modules/rtpengine/rtpengine_hash.h b/modules/rtpengine/rtpengine_hash.h index c4c67baa774..31036ad93d9 100644 --- a/modules/rtpengine/rtpengine_hash.h +++ b/modules/rtpengine/rtpengine_hash.h @@ -17,9 +17,9 @@ struct rtpengine_hash_entry { /* table */ struct rtpengine_hash_table { - struct rtpengine_hash_entry **entry_list; // hastable - gen_lock_t **row_locks; // hastable row locks - unsigned int total; // total number of entries in the hashtable + struct rtpengine_hash_entry **entry_list; // hashtable + gen_lock_t **row_locks; // vector of pointers to locks + unsigned int *row_totals; // vector of numbers of entries in the hashtable rows }; @@ -35,5 +35,6 @@ void rtpengine_hash_table_free_entry(struct rtpengine_hash_entry *entry); void rtpengine_hash_table_free_entry_list(struct rtpengine_hash_entry *entry_list); void rtpengine_hash_table_free_row_lock(gen_lock_t *lock); +int rtpengine_hash_table_sanity_checks(); #endif From 5ad022a4f5e959b875e9f590eca4e7e1866836bb Mon Sep 17 00:00:00 2001 From: Stefan Mititelu Date: Wed, 9 Dec 2015 11:41:55 +0200 Subject: [PATCH 12/13] rtpengine: Move the size inside the hash table - struct rtpengine_hash_table now contains the table size. - rename the entry_list to row_entry_list --- modules/rtpengine/rtpengine_hash.c | 69 +++++++++++++++--------------- modules/rtpengine/rtpengine_hash.h | 9 ++-- 2 files changed, 40 insertions(+), 38 deletions(-) diff --git a/modules/rtpengine/rtpengine_hash.c b/modules/rtpengine/rtpengine_hash.c index 0062da888cc..821e2feea30 100644 --- a/modules/rtpengine/rtpengine_hash.c +++ b/modules/rtpengine/rtpengine_hash.c @@ -7,7 +7,6 @@ #include "../../timer.h" static struct rtpengine_hash_table *rtpengine_hash_table; -static int hash_table_size; /* from sipwise rtpengine */ static int str_cmp_str(const str a, const str b) { @@ -36,12 +35,13 @@ static unsigned int str_hash(str s) { it.len--; } - return ret % hash_table_size; + return ret % rtpengine_hash_table->size; } /* rtpengine hash API */ int rtpengine_hash_table_init(int size) { int i; + int hash_table_size; // init hash table size if (size < 1) { @@ -58,15 +58,16 @@ int rtpengine_hash_table_init(int size) { return 0; } memset(rtpengine_hash_table, 0, sizeof(struct rtpengine_hash_table)); + rtpengine_hash_table->size = hash_table_size; - // init hashtable entry_list - rtpengine_hash_table->entry_list = shm_malloc(hash_table_size * sizeof(struct rtpengine_hash_entry)); - if (!rtpengine_hash_table->entry_list) { - LM_ERR("no shm left to create rtpengine_hash_table->entry_list\n"); + // init hashtable row_entry_list + rtpengine_hash_table->row_entry_list = shm_malloc(rtpengine_hash_table->size * sizeof(struct rtpengine_hash_entry*)); + if (!rtpengine_hash_table->row_entry_list) { + LM_ERR("no shm left to create rtpengine_hash_table->row_entry_list\n"); rtpengine_hash_table_destroy(); return 0; } - memset(rtpengine_hash_table->entry_list, 0, hash_table_size * sizeof(struct rtpengine_hash_entry)); + memset(rtpengine_hash_table->row_entry_list, 0, rtpengine_hash_table->size * sizeof(struct rtpengine_hash_entry*)); // init hashtable row_locks rtpengine_hash_table->row_locks = shm_malloc(hash_table_size * sizeof(gen_lock_t*)); @@ -86,19 +87,19 @@ int rtpengine_hash_table_init(int size) { } memset(rtpengine_hash_table->row_totals, 0, hash_table_size * sizeof(unsigned int)); - // init hashtable entry_list[i], row_locks[i] and row_totals[i] + // init hashtable row_entry_list[i], row_locks[i] and row_totals[i] for (i = 0; i < hash_table_size; i++) { // init hashtable row_entry_list[i] - rtpengine_hash_table->entry_list[i] = shm_malloc(sizeof(struct rtpengine_hash_entry)); - if (!rtpengine_hash_table->entry_list[i]) { - LM_ERR("no shm left to create rtpengine_hash_table->entry_list[%d]\n", i); + rtpengine_hash_table->row_entry_list[i] = shm_malloc(sizeof(struct rtpengine_hash_entry)); + if (!rtpengine_hash_table->row_entry_list[i]) { + LM_ERR("no shm left to create rtpengine_hash_table->row_entry_list[%d]\n", i); rtpengine_hash_table_destroy(); return 0; } - memset(rtpengine_hash_table->entry_list[i], 0, sizeof(struct rtpengine_hash_entry)); + memset(rtpengine_hash_table->row_entry_list[i], 0, sizeof(struct rtpengine_hash_entry)); - rtpengine_hash_table->entry_list[i]->tout = -1; - rtpengine_hash_table->entry_list[i]->next = NULL; + rtpengine_hash_table->row_entry_list[i]->tout = -1; + rtpengine_hash_table->row_entry_list[i]->next = NULL; // init hashtable row_locks[i] rtpengine_hash_table->row_locks[i] = lock_alloc(); @@ -122,16 +123,16 @@ int rtpengine_hash_table_destroy() { } // destroy hashtable content - for (i = 0; i < hash_table_size; i++) { - // destroy hashtable entry_list[i] + for (i = 0; i < rtpengine_hash_table->size; i++) { + // destroy hashtable row_entry_list[i] if (rtpengine_hash_table->row_locks[i]) { lock_get(rtpengine_hash_table->row_locks[i]); } else { LM_ERR("NULL rtpengine_hash_table->row_locks[%d]\n", i); return 0; } - rtpengine_hash_table_free_entry_list(rtpengine_hash_table->entry_list[i]); - rtpengine_hash_table->entry_list[i] = NULL; + rtpengine_hash_table_free_row_entry_list(rtpengine_hash_table->row_entry_list[i]); + rtpengine_hash_table->row_entry_list[i] = NULL; lock_release(rtpengine_hash_table->row_locks[i]); // destroy hashtable row_locks[i] @@ -139,9 +140,9 @@ int rtpengine_hash_table_destroy() { rtpengine_hash_table->row_locks[i] = NULL; } - // destroy hashtable entry_list - shm_free(rtpengine_hash_table->entry_list); - rtpengine_hash_table->entry_list = NULL; + // destroy hashtable row_entry_list + shm_free(rtpengine_hash_table->row_entry_list); + rtpengine_hash_table->row_entry_list = NULL; // destroy hashtable row_locks shm_free(rtpengine_hash_table->row_locks); @@ -171,7 +172,7 @@ int rtpengine_hash_table_insert(str callid, str viabranch, struct rtpengine_hash // get entry list hash_index = str_hash(callid); - entry = rtpengine_hash_table->entry_list[hash_index]; + entry = rtpengine_hash_table->row_entry_list[hash_index]; last_entry = entry; // lock @@ -237,7 +238,7 @@ int rtpengine_hash_table_remove(str callid, str viabranch) { // get first entry from entry list; jump over unused list head hash_index = str_hash(callid); - entry = rtpengine_hash_table->entry_list[hash_index]; + entry = rtpengine_hash_table->row_entry_list[hash_index]; last_entry = entry; // lock @@ -303,7 +304,7 @@ struct rtpp_node *rtpengine_hash_table_lookup(str callid, str viabranch) { // get first entry from entry list; jump over unused list head hash_index = str_hash(callid); - entry = rtpengine_hash_table->entry_list[hash_index]; + entry = rtpengine_hash_table->row_entry_list[hash_index]; last_entry = entry; // lock @@ -363,7 +364,7 @@ void rtpengine_hash_table_print() { } // print hashtable - for (i = 0; i < hash_table_size; i++) { + for (i = 0; i < rtpengine_hash_table->size; i++) { // lock if (rtpengine_hash_table->row_locks[i]) { lock_get(rtpengine_hash_table->row_locks[i]); @@ -372,7 +373,7 @@ void rtpengine_hash_table_print() { return ; } - entry = rtpengine_hash_table->entry_list[i]; + entry = rtpengine_hash_table->row_entry_list[i]; last_entry = entry; while (entry) { @@ -414,7 +415,7 @@ unsigned int rtpengine_hash_table_total() { return 0; } - for (i = 0; i < hash_table_size; i++) { + for (i = 0; i < rtpengine_hash_table->size; i++) { total += rtpengine_hash_table->row_totals[i]; } @@ -443,15 +444,15 @@ void rtpengine_hash_table_free_entry(struct rtpengine_hash_entry *entry) { return ; } -void rtpengine_hash_table_free_entry_list(struct rtpengine_hash_entry *entry_list) { +void rtpengine_hash_table_free_row_entry_list(struct rtpengine_hash_entry *row_entry_list) { struct rtpengine_hash_entry *entry, *last_entry; - if (!entry_list) { - LM_ERR("try to free a NULL entry_list\n"); + if (!row_entry_list) { + LM_ERR("try to free a NULL row_entry_list\n"); return ; } - entry = entry_list; + entry = row_entry_list; while (entry) { last_entry = entry; entry = entry->next; @@ -480,9 +481,9 @@ int rtpengine_hash_table_sanity_checks() { return 0; } - // check rtpengine hashtable->entry_list - if (!rtpengine_hash_table->entry_list) { - LM_ERR("NULL rtpengine_hash_table->entry_list\n"); + // check rtpengine hashtable->row_entry_list + if (!rtpengine_hash_table->row_entry_list) { + LM_ERR("NULL rtpengine_hash_table->row_entry_list\n"); return 0; } diff --git a/modules/rtpengine/rtpengine_hash.h b/modules/rtpengine/rtpengine_hash.h index 31036ad93d9..bffb650cc74 100644 --- a/modules/rtpengine/rtpengine_hash.h +++ b/modules/rtpengine/rtpengine_hash.h @@ -17,9 +17,10 @@ struct rtpengine_hash_entry { /* table */ struct rtpengine_hash_table { - struct rtpengine_hash_entry **entry_list; // hashtable - gen_lock_t **row_locks; // vector of pointers to locks - unsigned int *row_totals; // vector of numbers of entries in the hashtable rows + struct rtpengine_hash_entry **row_entry_list; // vector of size pointers to entry + gen_lock_t **row_locks; // vector of size pointers to locks + unsigned int *row_totals; // vector of size numbers of entries in the hashtable rows + unsigned int size; // hash table size }; @@ -32,7 +33,7 @@ void rtpengine_hash_table_print(); unsigned int rtpengine_hash_table_total(); void rtpengine_hash_table_free_entry(struct rtpengine_hash_entry *entry); -void rtpengine_hash_table_free_entry_list(struct rtpengine_hash_entry *entry_list); +void rtpengine_hash_table_free_row_entry_list(struct rtpengine_hash_entry *row_entry_list); void rtpengine_hash_table_free_row_lock(gen_lock_t *lock); int rtpengine_hash_table_sanity_checks(); From 95cd1062a937568322665bacd019d21fc20d57c0 Mon Sep 17 00:00:00 2001 From: Stefan Mititelu Date: Thu, 10 Dec 2015 11:38:10 +0200 Subject: [PATCH 13/13] rtpengine: _destroy() sanity + memory free _destroy() sanity checking, with memory free, when possible: - alloc the locks first. - free the locks last. - consider content already hadled for a NULL lock (or NULL lock vector). - make _free_row_lock() static. --- modules/rtpengine/rtpengine_hash.c | 129 +++++++++++++++++++---------- modules/rtpengine/rtpengine_hash.h | 1 - 2 files changed, 85 insertions(+), 45 deletions(-) diff --git a/modules/rtpengine/rtpengine_hash.c b/modules/rtpengine/rtpengine_hash.c index 821e2feea30..f8e610d82d9 100644 --- a/modules/rtpengine/rtpengine_hash.c +++ b/modules/rtpengine/rtpengine_hash.c @@ -6,6 +6,9 @@ #include "../../locking.h" #include "../../timer.h" +static void rtpengine_hash_table_free_row_lock(gen_lock_t *row_lock); + + static struct rtpengine_hash_table *rtpengine_hash_table; /* from sipwise rtpengine */ @@ -60,15 +63,6 @@ int rtpengine_hash_table_init(int size) { memset(rtpengine_hash_table, 0, sizeof(struct rtpengine_hash_table)); rtpengine_hash_table->size = hash_table_size; - // init hashtable row_entry_list - rtpengine_hash_table->row_entry_list = shm_malloc(rtpengine_hash_table->size * sizeof(struct rtpengine_hash_entry*)); - if (!rtpengine_hash_table->row_entry_list) { - LM_ERR("no shm left to create rtpengine_hash_table->row_entry_list\n"); - rtpengine_hash_table_destroy(); - return 0; - } - memset(rtpengine_hash_table->row_entry_list, 0, rtpengine_hash_table->size * sizeof(struct rtpengine_hash_entry*)); - // init hashtable row_locks rtpengine_hash_table->row_locks = shm_malloc(hash_table_size * sizeof(gen_lock_t*)); if (!rtpengine_hash_table->row_locks) { @@ -78,6 +72,15 @@ int rtpengine_hash_table_init(int size) { } memset(rtpengine_hash_table->row_locks, 0, hash_table_size * sizeof(gen_lock_t*)); + // init hashtable row_entry_list + rtpengine_hash_table->row_entry_list = shm_malloc(rtpengine_hash_table->size * sizeof(struct rtpengine_hash_entry*)); + if (!rtpengine_hash_table->row_entry_list) { + LM_ERR("no shm left to create rtpengine_hash_table->row_entry_list\n"); + rtpengine_hash_table_destroy(); + return 0; + } + memset(rtpengine_hash_table->row_entry_list, 0, rtpengine_hash_table->size * sizeof(struct rtpengine_hash_entry*)); + // init hashtable row_totals rtpengine_hash_table->row_totals = shm_malloc(hash_table_size * sizeof(unsigned int)); if (!rtpengine_hash_table->row_totals) { @@ -87,8 +90,16 @@ int rtpengine_hash_table_init(int size) { } memset(rtpengine_hash_table->row_totals, 0, hash_table_size * sizeof(unsigned int)); - // init hashtable row_entry_list[i], row_locks[i] and row_totals[i] + // init hashtable row_locks[i], row_entry_list[i] and row_totals[i] for (i = 0; i < hash_table_size; i++) { + // init hashtable row_locks[i] + rtpengine_hash_table->row_locks[i] = lock_alloc(); + if (!rtpengine_hash_table->row_locks[i]) { + LM_ERR("no shm left to create rtpengine_hash_table->row_locks[%d]\n", i); + rtpengine_hash_table_destroy(); + return 0; + } + // init hashtable row_entry_list[i] rtpengine_hash_table->row_entry_list[i] = shm_malloc(sizeof(struct rtpengine_hash_entry)); if (!rtpengine_hash_table->row_entry_list[i]) { @@ -101,13 +112,8 @@ int rtpengine_hash_table_init(int size) { rtpengine_hash_table->row_entry_list[i]->tout = -1; rtpengine_hash_table->row_entry_list[i]->next = NULL; - // init hashtable row_locks[i] - rtpengine_hash_table->row_locks[i] = lock_alloc(); - if (!rtpengine_hash_table->row_locks[i]) { - LM_ERR("no shm left to create rtpengine_hash_table->row_locks[%d]\n", i); - rtpengine_hash_table_destroy(); - return 0; - } + // init hashtable row_totals[i] + rtpengine_hash_table->row_totals[i] = 0; } return 1; @@ -116,23 +122,40 @@ int rtpengine_hash_table_init(int size) { int rtpengine_hash_table_destroy() { int i; - // sanity checks - if (!rtpengine_hash_table_sanity_checks()) { - LM_ERR("sanity checks failed\n"); - return 0; + // check rtpengine hashtable + if (!rtpengine_hash_table) { + LM_ERR("NULL rtpengine_hash_table\n"); + return 1; + } + + // check rtpengine hashtable->row_locks + if (!rtpengine_hash_table->row_locks) { + LM_ERR("NULL rtpengine_hash_table->row_locks\n"); + shm_free(rtpengine_hash_table); + rtpengine_hash_table = NULL; + return 1; } // destroy hashtable content for (i = 0; i < rtpengine_hash_table->size; i++) { - // destroy hashtable row_entry_list[i] - if (rtpengine_hash_table->row_locks[i]) { + // lock + if (!rtpengine_hash_table->row_locks[i]) { + LM_ERR("NULL rtpengine_hash_table->row_locks[%d]\n", i); + continue; + } else { lock_get(rtpengine_hash_table->row_locks[i]); + } + + // check rtpengine hashtable->row_entry_list + if (!rtpengine_hash_table->row_entry_list) { + LM_ERR("NULL rtpengine_hash_table->row_entry_list\n"); } else { - LM_ERR("NULL rtpengine_hash_table->row_locks[%d]\n", i); - return 0; + // destroy hashtable row_entry_list[i] + rtpengine_hash_table_free_row_entry_list(rtpengine_hash_table->row_entry_list[i]); + rtpengine_hash_table->row_entry_list[i] = NULL; } - rtpengine_hash_table_free_row_entry_list(rtpengine_hash_table->row_entry_list[i]); - rtpengine_hash_table->row_entry_list[i] = NULL; + + // unlock lock_release(rtpengine_hash_table->row_locks[i]); // destroy hashtable row_locks[i] @@ -141,20 +164,38 @@ int rtpengine_hash_table_destroy() { } // destroy hashtable row_entry_list - shm_free(rtpengine_hash_table->row_entry_list); - rtpengine_hash_table->row_entry_list = NULL; - - // destroy hashtable row_locks - shm_free(rtpengine_hash_table->row_locks); - rtpengine_hash_table->row_locks = NULL; + if (!rtpengine_hash_table->row_entry_list) { + LM_ERR("NULL rtpengine_hash_table->row_entry_list\n"); + } else { + shm_free(rtpengine_hash_table->row_entry_list); + rtpengine_hash_table->row_entry_list = NULL; + } // destroy hashtable row_totals - shm_free(rtpengine_hash_table->row_totals); - rtpengine_hash_table->row_totals = NULL; + if (!rtpengine_hash_table->row_totals) { + LM_ERR("NULL rtpengine_hash_table->row_totals\n"); + } else { + shm_free(rtpengine_hash_table->row_totals); + rtpengine_hash_table->row_totals = NULL; + } + + // destroy hashtable row_locks + if (!rtpengine_hash_table->row_locks) { + // should not be the case; just for code symmetry + LM_ERR("NULL rtpengine_hash_table->row_locks\n"); + } else { + shm_free(rtpengine_hash_table->row_locks); + rtpengine_hash_table->row_locks = NULL; + } // destroy hashtable - shm_free(rtpengine_hash_table); - rtpengine_hash_table = NULL; + if (!rtpengine_hash_table) { + // should not be the case; just for code symmetry + LM_ERR("NULL rtpengine_hash_table\n"); + } else { + shm_free(rtpengine_hash_table); + rtpengine_hash_table = NULL; + } return 1; } @@ -463,7 +504,7 @@ void rtpengine_hash_table_free_row_entry_list(struct rtpengine_hash_entry *row_e return ; } -void rtpengine_hash_table_free_row_lock(gen_lock_t *row_lock) { +static void rtpengine_hash_table_free_row_lock(gen_lock_t *row_lock) { if (!row_lock) { LM_ERR("try to free a NULL lock\n"); return ; @@ -481,18 +522,18 @@ int rtpengine_hash_table_sanity_checks() { return 0; } - // check rtpengine hashtable->row_entry_list - if (!rtpengine_hash_table->row_entry_list) { - LM_ERR("NULL rtpengine_hash_table->row_entry_list\n"); - return 0; - } - // check rtpengine hashtable->row_locks if (!rtpengine_hash_table->row_locks) { LM_ERR("NULL rtpengine_hash_table->row_locks\n"); return 0; } + // check rtpengine hashtable->row_entry_list + if (!rtpengine_hash_table->row_entry_list) { + LM_ERR("NULL rtpengine_hash_table->row_entry_list\n"); + return 0; + } + // check rtpengine hashtable->row_totals if (!rtpengine_hash_table->row_totals) { LM_ERR("NULL rtpengine_hash_table->row_totals\n"); diff --git a/modules/rtpengine/rtpengine_hash.h b/modules/rtpengine/rtpengine_hash.h index bffb650cc74..dab6c714e81 100644 --- a/modules/rtpengine/rtpengine_hash.h +++ b/modules/rtpengine/rtpengine_hash.h @@ -35,7 +35,6 @@ unsigned int rtpengine_hash_table_total(); void rtpengine_hash_table_free_entry(struct rtpengine_hash_entry *entry); void rtpengine_hash_table_free_row_entry_list(struct rtpengine_hash_entry *row_entry_list); -void rtpengine_hash_table_free_row_lock(gen_lock_t *lock); int rtpengine_hash_table_sanity_checks(); #endif