Skip to content

Commit

Permalink
dispatcher: add option to retain existing latency stats when reloadin…
Browse files Browse the repository at this point in the history
…g destinations

- also retain when adding/removing individual destinations via RPC
  • Loading branch information
charlesrchance authored and henningw committed Aug 14, 2023
1 parent 2fd5d88 commit 2a1a65d
Show file tree
Hide file tree
Showing 4 changed files with 106 additions and 9 deletions.
80 changes: 71 additions & 9 deletions src/modules/dispatcher/dispatch.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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;
Expand All @@ -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");
Expand Down Expand Up @@ -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");
Expand Down Expand Up @@ -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);
Expand Down Expand Up @@ -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;
Expand Down Expand Up @@ -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",
Expand Down Expand Up @@ -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);
Expand All @@ -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);
Expand Down Expand Up @@ -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);
Expand Down Expand Up @@ -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(
Expand Down Expand Up @@ -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;
Expand Down
1 change: 1 addition & 0 deletions src/modules/dispatcher/dispatch.h
Original file line number Diff line number Diff line change
Expand Up @@ -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 */
Expand Down
2 changes: 2 additions & 0 deletions src/modules/dispatcher/dispatcher.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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},
Expand Down
32 changes: 32 additions & 0 deletions src/modules/dispatcher/doc/dispatcher_admin.xml
Original file line number Diff line number Diff line change
Expand Up @@ -756,6 +756,38 @@ modparam("dispatcher", "ds_ping_latency_stats", 1)
</programlisting>
</example>
</section>


<section id="dispatcher.p.ds_retain_latency_stats">
<title><varname>ds_retain_latency_stats</varname> (int)</title>
<para>
Retain latency stats for existing destinations when reloading from file or database.
</para>

<itemizedlist>
<listitem>
<para>If set to 0, stats for all destinations will be reset on reload.</para>
</listitem>
<listitem>
<para>If set to 1, stats for existing destinations will persist across reloads.
</para>
</listitem>
</itemizedlist>
<para>
<emphasis>
Default value is <quote>0</quote>.
</emphasis>
</para>
<example>
<title>Set the <quote>ds_retain_latency_stats</quote> parameter</title>
<programlisting format="linespecific">
...
modparam("dispatcher", "ds_retain_latency_stats", 1)
...
</programlisting>
</example>
</section>

<section id="dispatcher.p.ds_latency_estimator_alpha">
<title><varname>ds_latency_estimator_alpha</varname> (int)</title>
<para>
Expand Down

0 comments on commit 2a1a65d

Please sign in to comment.