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)
+
+
+
+ ds_retain_latency_stats (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 ds_retain_latency_stats
parameter
+
+...
+modparam("dispatcher", "ds_retain_latency_stats", 1)
+...
+
+
+
+
ds_latency_estimator_alpha (int)