|
@@ -88,6 +88,8 @@ int *next_idx = NULL;
|
|
|
static void ds_run_route(struct sip_msg *msg, str *uri, char *route);
|
|
|
|
|
|
void destroy_list(int);
|
|
|
+void shuffle_uint100array(unsigned int* arr);
|
|
|
+int ds_reinit_rweight_on_state_change(int old_state, int new_state, ds_set_t *dset);
|
|
|
|
|
|
/**
|
|
|
*
|
|
@@ -131,12 +133,13 @@ int ds_print_sets(void)
|
|
|
{
|
|
|
for(i=0; i<si->nr; i++)
|
|
|
{
|
|
|
- LM_DBG("dst>> %d %.*s %d %d (%.*s,%d,%d)\n", si->id,
|
|
|
+ LM_DBG("dst>> %d %.*s %d %d (%.*s,%d,%d,%d)\n", si->id,
|
|
|
si->dlist[i].uri.len, si->dlist[i].uri.s,
|
|
|
si->dlist[i].flags, si->dlist[i].priority,
|
|
|
si->dlist[i].attrs.duid.len, si->dlist[i].attrs.duid.s,
|
|
|
si->dlist[i].attrs.maxload,
|
|
|
- si->dlist[i].attrs.weight);
|
|
|
+ si->dlist[i].attrs.weight,
|
|
|
+ si->dlist[i].attrs.rweight);
|
|
|
}
|
|
|
si = si->next;
|
|
|
}
|
|
@@ -217,7 +220,18 @@ int ds_set_attrs(ds_dest_t *dest, str *attrs)
|
|
|
} else if(pit->name.len==6
|
|
|
&& strncasecmp(pit->name.s, "socket", 6)==0) {
|
|
|
dest->attrs.socket = pit->body;
|
|
|
+ }else if(pit->name.len==7
|
|
|
+ && strncasecmp(pit->name.s, "rweight", 7)==0) {
|
|
|
+ int tmp_rweight;
|
|
|
+ str2sint(&pit->body, &tmp_rweight);
|
|
|
+ if ( tmp_rweight>=1 && tmp_rweight<=100 ) {
|
|
|
+ dest->attrs.rweight = tmp_rweight;
|
|
|
+ }
|
|
|
+ else{
|
|
|
+ LM_ERR("rweight %d not in 1-100 range; skipped", tmp_rweight);
|
|
|
+ }
|
|
|
}
|
|
|
+
|
|
|
}
|
|
|
return 0;
|
|
|
}
|
|
@@ -397,6 +411,82 @@ err:
|
|
|
return -1;
|
|
|
}
|
|
|
|
|
|
+
|
|
|
+/* for internal usage; arr must be arr[100] */
|
|
|
+void shuffle_uint100array(unsigned int* arr){
|
|
|
+ if (arr == NULL)
|
|
|
+ return;
|
|
|
+ int k;
|
|
|
+ int j;
|
|
|
+ unsigned int t;
|
|
|
+ srand(time(0));
|
|
|
+ for (j=0; j<100; j++)
|
|
|
+ {
|
|
|
+ k = j + (rand() % (100-j));
|
|
|
+ t = arr[j];
|
|
|
+ arr[j] = arr[k];
|
|
|
+ arr[k] = t;
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+
|
|
|
+/**
|
|
|
+ * Initialize the relative weight distribution for a destination set
|
|
|
+ * - fill the array of 0..99 elements where to keep the index of the
|
|
|
+ * destination address to be used. The Nth call will use
|
|
|
+ * the address with the index at possition N%100
|
|
|
+ */
|
|
|
+int dp_init_relative_weights(ds_set_t *dset)
|
|
|
+{
|
|
|
+ int j;
|
|
|
+ int k;
|
|
|
+ int t;
|
|
|
+
|
|
|
+ if(dset==NULL || dset->dlist==NULL)
|
|
|
+ return -1;
|
|
|
+
|
|
|
+ int rw_sum = 0;
|
|
|
+ /* find the sum of relative weights*/
|
|
|
+ for(j=0; j<dset->nr; j++){
|
|
|
+ if( ds_skip_dst(dset->dlist[j].flags ) )
|
|
|
+ continue;
|
|
|
+ rw_sum += dset->dlist[j].attrs.rweight;
|
|
|
+ }
|
|
|
+
|
|
|
+ if (rw_sum == 0){
|
|
|
+ return 0;
|
|
|
+ }
|
|
|
+
|
|
|
+ /* fill the array based on the relative weight of each destination */
|
|
|
+ t = 0;
|
|
|
+ for(j=0; j<dset->nr; j++)
|
|
|
+ {
|
|
|
+ if( ds_skip_dst(dset->dlist[j].flags ) )
|
|
|
+ continue;
|
|
|
+
|
|
|
+ int current_slice = dset->dlist[j].attrs.rweight*100/rw_sum; //truncate here;
|
|
|
+ for(k=0; k<current_slice; k++)
|
|
|
+ {
|
|
|
+ dset->rwlist[t] = (unsigned int)j;
|
|
|
+ t++;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ /* if the array was not completely filled (i.e., the sum of rweights is
|
|
|
+ * less than 100 due to truncated), then use last address to fill the rest */
|
|
|
+ unsigned int last_insert = t>0? dset->rwlist[t-1] : (unsigned int)(dset->nr-1);
|
|
|
+ for(j=t; j<100; j++)
|
|
|
+ dset->rwlist[j] = last_insert;
|
|
|
+
|
|
|
+ /* shuffle the content of the array in order to mix the selection
|
|
|
+ * of the addresses (e.g., if first address has weight=20, avoid
|
|
|
+ * sending first 20 calls to it, but ensure that within a 100 calls,
|
|
|
+ * 20 go to first address */
|
|
|
+ shuffle_uint100array(dset->rwlist);
|
|
|
+
|
|
|
+ return 0;
|
|
|
+}
|
|
|
+
|
|
|
+
|
|
|
/**
|
|
|
* Initialize the weight distribution for a destination set
|
|
|
* - fill the array of 0..99 elements where to keep the index of the
|
|
@@ -441,14 +531,7 @@ randomize:
|
|
|
* of the addresses (e.g., if first address has weight=20, avoid
|
|
|
* sending first 20 calls to it, but ensure that within a 100 calls,
|
|
|
* 20 go to first address */
|
|
|
- srand(time(0));
|
|
|
- for (j=0; j<100; j++)
|
|
|
- {
|
|
|
- k = j + (rand() % (100-j));
|
|
|
- t = (int)dset->wlist[j];
|
|
|
- dset->wlist[j] = dset->wlist[k];
|
|
|
- dset->wlist[k] = (unsigned int)t;
|
|
|
- }
|
|
|
+ shuffle_uint100array(dset->wlist);
|
|
|
|
|
|
return 0;
|
|
|
}
|
|
@@ -488,6 +571,7 @@ int reindex_dests(int list_idx, int setn)
|
|
|
}
|
|
|
sp->dlist = dp0;
|
|
|
dp_init_weights(sp);
|
|
|
+ dp_init_relative_weights(sp);
|
|
|
}
|
|
|
|
|
|
LM_DBG("found [%d] dest sets\n", setn);
|
|
@@ -1799,6 +1883,10 @@ int ds_select_dst_limit(sip_msg_t *msg, int set, int alg, unsigned int limit, in
|
|
|
}
|
|
|
}
|
|
|
break;
|
|
|
+ case 11: /* relative weight based distribution */
|
|
|
+ hash = idx->rwlist[idx->rwlast];
|
|
|
+ idx->rwlast = (idx->rwlast+1) % 100;
|
|
|
+ break;
|
|
|
default:
|
|
|
LM_WARN("algo %d not implemented - using first entry...\n", alg);
|
|
|
hash = 0;
|
|
@@ -2292,6 +2380,8 @@ int ds_update_state(sip_msg_t *msg, int group, str *address, int state)
|
|
|
if(ds_skip_dst(old_state) && !ds_skip_dst(idx->dlist[i].flags))
|
|
|
ds_run_route(msg, address, "dispatcher:dst-up");
|
|
|
}
|
|
|
+ if (idx->dlist[i].attrs.rweight > 0)
|
|
|
+ ds_reinit_rweight_on_state_change(old_state, idx->dlist[i].flags, idx);
|
|
|
|
|
|
return 0;
|
|
|
}
|
|
@@ -2343,6 +2433,26 @@ static void ds_run_route(sip_msg_t *msg, str *uri, char *route)
|
|
|
set_route_type(backup_rt);
|
|
|
}
|
|
|
|
|
|
+
|
|
|
+/**
|
|
|
+ recalculate relative states if some destination state was changed
|
|
|
+ */
|
|
|
+int ds_reinit_rweight_on_state_change(int old_state, int new_state, ds_set_t *dset)
|
|
|
+{
|
|
|
+ if (dset == NULL){
|
|
|
+ LM_ERR("destination set is null\n");
|
|
|
+ return -1;
|
|
|
+ }
|
|
|
+ if ( (!ds_skip_dst(old_state) && ds_skip_dst(new_state)) ||
|
|
|
+ (ds_skip_dst(old_state) && !ds_skip_dst(new_state)) )
|
|
|
+ {
|
|
|
+ dp_init_relative_weights(dset);
|
|
|
+ }
|
|
|
+
|
|
|
+ return 0;
|
|
|
+}
|
|
|
+
|
|
|
+
|
|
|
/**
|
|
|
*
|
|
|
*/
|
|
@@ -2370,10 +2480,15 @@ int ds_reinit_state(int group, str *address, int state)
|
|
|
&& strncasecmp(idx->dlist[i].uri.s, address->s,
|
|
|
address->len)==0)
|
|
|
{
|
|
|
+ int old_state = idx->dlist[i].flags;
|
|
|
/* reset the bits used for states */
|
|
|
idx->dlist[i].flags &= ~(DS_STATES_ALL);
|
|
|
/* set the new states */
|
|
|
idx->dlist[i].flags |= state;
|
|
|
+ if (idx->dlist[i].attrs.rweight > 0){
|
|
|
+ ds_reinit_rweight_on_state_change(old_state, idx->dlist[i].flags, idx);
|
|
|
+ }
|
|
|
+
|
|
|
return 0;
|
|
|
}
|
|
|
}
|