diff --git a/src/modules/dispatcher/dispatch.c b/src/modules/dispatcher/dispatch.c index e8d7886ec9b..9356fe65e1b 100644 --- a/src/modules/dispatcher/dispatch.c +++ b/src/modules/dispatcher/dispatch.c @@ -109,6 +109,7 @@ static int *_ds_ping_active = NULL; extern int ds_force_dst; extern str ds_event_callback; extern int ds_ping_latency_stats; +extern int ds_retain_latency_stats; extern float ds_latency_estimator_alpha; extern int ds_attrs_none; extern param_t *ds_db_extra_attrs_list; @@ -543,7 +544,7 @@ ds_dest_t *pack_dest(str iuri, int flags, int priority, str *attrs, int dload) * */ int add_dest2list(int id, str uri, int flags, int priority, str *attrs, - int list_idx, int *setn, int dload) + int list_idx, int *setn, int dload, ds_latency_stats_t *latency_stats) { ds_dest_t *dp = NULL; ds_set_t *sp = NULL; @@ -554,6 +555,17 @@ int add_dest2list(int id, str uri, int flags, int priority, str *attrs, if(!dp) goto err; + if(latency_stats != NULL) { + dp->latency_stats.stdev = latency_stats->stdev; + dp->latency_stats.m2 = latency_stats->m2; + dp->latency_stats.max = latency_stats->max; + dp->latency_stats.min = latency_stats->min; + dp->latency_stats.average = latency_stats->average; + dp->latency_stats.estimate = latency_stats->estimate; + dp->latency_stats.count = latency_stats->count; + dp->latency_stats.timeout = latency_stats->timeout; + } + sp = ds_avl_insert(&ds_lists[list_idx], id, setn); if(!sp) { LM_ERR("no more memory.\n"); @@ -811,6 +823,7 @@ int ds_load_list(char *lfile) int id, setn, flags, priority; str uri; str attrs; + ds_latency_stats_t *latency_stats; if((*ds_crt_idx) != (*ds_next_idx)) { LM_WARN("load command already generated, aborting reload...\n"); @@ -906,8 +919,12 @@ int ds_load_list(char *lfile) attrs.len = p - attrs.s; add_destination: - if(add_dest2list( - id, uri, flags, priority, &attrs, *ds_next_idx, &setn, 0) + latency_stats = NULL; + if(ds_ping_latency_stats && ds_retain_latency_stats) { + latency_stats = latency_stats_find(id, &uri); + } + if(add_dest2list(id, uri, flags, priority, &attrs, *ds_next_idx, &setn, + 0, latency_stats) != 0) { LM_WARN("unable to add destination %.*s to set %d -- skipping\n", uri.len, uri.s, id); @@ -1054,6 +1071,7 @@ int ds_load_db(void) int plen; #define DS_ATTRS_MAXSIZE 1024 char ds_attrs_buf[DS_ATTRS_MAXSIZE]; + ds_latency_stats_t *latency_stats; query_cols[0] = &ds_set_id_col; query_cols[1] = &ds_dest_uri_col; @@ -1161,8 +1179,12 @@ int ds_load_db(void) } LM_DBG("attributes string: [%.*s]\n", attrs.len, (attrs.s) ? attrs.s : ""); - if(add_dest2list( - id, uri, flags, priority, &attrs, *ds_next_idx, &setn, 0) + latency_stats = NULL; + if(ds_ping_latency_stats && ds_retain_latency_stats) { + latency_stats = latency_stats_find(id, &uri); + } + if(add_dest2list(id, uri, flags, priority, &attrs, *ds_next_idx, &setn, + 0, latency_stats) != 0) { dest_errs++; LM_WARN("unable to add destination %.*s to set %d -- skipping\n", @@ -2649,7 +2671,8 @@ void ds_add_dest_cb(ds_set_t *node, int i, void *arg) if(add_dest2list(node->id, node->dlist[i].uri, node->dlist[i].flags, node->dlist[i].priority, &node->dlist[i].attrs.body, - *ds_next_idx, &setn, node->dlist[i].dload) + *ds_next_idx, &setn, node->dlist[i].dload, + &node->dlist[i].latency_stats) != 0) { LM_WARN("failed to add destination in group %d - %.*s\n", node->id, node->dlist[i].uri.len, node->dlist[i].uri.s); @@ -2671,8 +2694,8 @@ int ds_add_dst(int group, str *address, int flags, int priority, str *attrs) ds_iter_set(_ds_list, &ds_add_dest_cb, NULL); // add new destination - if(add_dest2list( - group, *address, flags, priority, attrs, *ds_next_idx, &setn, 0) + if(add_dest2list(group, *address, flags, priority, attrs, *ds_next_idx, + &setn, 0, NULL) != 0) { LM_WARN("unable to add destination %.*s to set %d", address->len, address->s, group); @@ -2712,7 +2735,8 @@ void ds_filter_dest_cb(ds_set_t *node, int i, void *arg) if(add_dest2list(node->id, node->dlist[i].uri, node->dlist[i].flags, node->dlist[i].priority, &node->dlist[i].attrs.body, - *ds_next_idx, filter_arg->setn, node->dlist[i].dload) + *ds_next_idx, filter_arg->setn, node->dlist[i].dload, + &node->dlist[i].latency_stats) != 0) { LM_WARN("failed to add destination in group %d - %.*s\n", node->id, node->dlist[i].uri.len, node->dlist[i].uri.s); @@ -2825,6 +2849,36 @@ void latency_stats_init( latency_stats->count = count; } +ds_latency_stats_t *latency_stats_find(int group, str *address) +{ + + int i = 0; + ds_set_t *idx = NULL; + + if(_ds_list == NULL || _ds_list_nr <= 0) { + LM_DBG("the list is null\n"); + return NULL; + } + + /* get the index of the set */ + if(ds_get_index(group, *ds_crt_idx, &idx) != 0) { + LM_DBG("destination set [%d] not found\n", group); + return NULL; + } + + while(i < idx->nr) { + if(idx->dlist[i].uri.len == address->len + && strncasecmp(idx->dlist[i].uri.s, address->s, address->len) + == 0) { + /* destination address found - copy current stats */ + return &idx->dlist[i].latency_stats; + } + i++; + } + + return NULL; +} + #define _VOR1(v) ((v) ? (v) : 1) static inline void latency_stats_update( @@ -2946,6 +3000,14 @@ int ds_update_latency(int group, str *address, int code) } if(code == 408 && latency_stats->timeout < UINT32_MAX) latency_stats->timeout++; + + if(latency_stats->start.tv_sec == 0 + && latency_stats->start.tv_usec == 0) { + /* If we don't have a start time, we can't calculate latency */ + i++; + continue; + } + gettimeofday(&now, NULL); latency_ms = (now.tv_sec - latency_stats->start.tv_sec) * 1000 + (now.tv_usec - latency_stats->start.tv_usec) / 1000; diff --git a/src/modules/dispatcher/dispatch.h b/src/modules/dispatcher/dispatch.h index 0f897d1f87d..1add2d7000f 100644 --- a/src/modules/dispatcher/dispatch.h +++ b/src/modules/dispatcher/dispatch.h @@ -218,6 +218,7 @@ typedef struct _ds_latency_stats { } ds_latency_stats_t; void latency_stats_init(ds_latency_stats_t *latency_stats, int latency, int count); +ds_latency_stats_t *latency_stats_find(int group, str *address); typedef struct _ds_dest { str uri; /*!< address/uri */ diff --git a/src/modules/dispatcher/dispatcher.c b/src/modules/dispatcher/dispatcher.c index 84d743879d0..5ba70524359 100644 --- a/src/modules/dispatcher/dispatcher.c +++ b/src/modules/dispatcher/dispatcher.c @@ -101,6 +101,7 @@ str ds_ping_method = str_init("OPTIONS"); str ds_ping_from = str_init("sip:dispatcher@localhost"); static int ds_ping_interval = 0; int ds_ping_latency_stats = 0; +int ds_retain_latency_stats = 0; int ds_latency_estimator_alpha_i = 900; float ds_latency_estimator_alpha = 0.9f; int ds_probing_mode = DS_PROBE_NONE; @@ -283,6 +284,7 @@ static param_export_t params[]={ {"ds_ping_from", PARAM_STR, &ds_ping_from}, {"ds_ping_interval", INT_PARAM, &ds_ping_interval}, {"ds_ping_latency_stats", INT_PARAM, &ds_ping_latency_stats}, + {"ds_retain_latency_stats", INT_PARAM, &ds_retain_latency_stats}, {"ds_latency_estimator_alpha", INT_PARAM, &ds_latency_estimator_alpha_i}, {"ds_ping_reply_codes", PARAM_STR, &ds_ping_reply_codes_str}, {"ds_probing_mode", INT_PARAM, &ds_probing_mode}, diff --git a/src/modules/dispatcher/doc/dispatcher_admin.xml b/src/modules/dispatcher/doc/dispatcher_admin.xml index 86d93ca27ef..46148b03e4b 100644 --- a/src/modules/dispatcher/doc/dispatcher_admin.xml +++ b/src/modules/dispatcher/doc/dispatcher_admin.xml @@ -756,6 +756,38 @@ modparam("dispatcher", "ds_ping_latency_stats", 1) + + +
+ <varname>ds_retain_latency_stats</varname> (int) + + Retain latency stats for existing destinations when reloading from file or database. + + + + + If set to 0, stats for all destinations will be reset on reload. + + + If set to 1, stats for existing destinations will persist across reloads. + + + + + + Default value is 0. + + + + Set the <quote>ds_retain_latency_stats</quote> parameter + +... +modparam("dispatcher", "ds_retain_latency_stats", 1) +... + + +
+
<varname>ds_latency_estimator_alpha</varname> (int)