mirror of
https://github.com/asterisk/asterisk.git
synced 2025-09-04 11:58:52 +00:00
Added queue strategy "linear". This strategy is useful for those who always wish for their
phones to be rung in a specific order. (closes issue #7279, reported and initially patched by diLLec, patch reworked by me) git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@87154 65c4cc65-6c06-0410-ace0-fbb531ad65f3
This commit is contained in:
@@ -100,7 +100,8 @@ enum {
|
||||
QUEUE_STRATEGY_LEASTRECENT,
|
||||
QUEUE_STRATEGY_FEWESTCALLS,
|
||||
QUEUE_STRATEGY_RANDOM,
|
||||
QUEUE_STRATEGY_RRMEMORY
|
||||
QUEUE_STRATEGY_RRMEMORY,
|
||||
QUEUE_STRATEGY_LINEAR
|
||||
};
|
||||
|
||||
static struct strategy {
|
||||
@@ -112,6 +113,7 @@ static struct strategy {
|
||||
{ QUEUE_STRATEGY_FEWESTCALLS, "fewestcalls" },
|
||||
{ QUEUE_STRATEGY_RANDOM, "random" },
|
||||
{ QUEUE_STRATEGY_RRMEMORY, "rrmemory" },
|
||||
{ QUEUE_STRATEGY_LINEAR, "linear" },
|
||||
};
|
||||
|
||||
#define DEFAULT_RETRY 5
|
||||
@@ -324,6 +326,8 @@ struct queue_ent {
|
||||
int opos; /*!< Where we started in the queue */
|
||||
int handled; /*!< Whether our call was handled */
|
||||
int max_penalty; /*!< Limit the members that can take this call to this penalty or lower */
|
||||
int linpos; /*!< If using linear strategy, what position are we at? */
|
||||
int linwrapped; /*!< Is the linpos wrapped? */
|
||||
time_t start; /*!< When we started holding */
|
||||
time_t expire; /*!< When this entry should expire (time out of queue) */
|
||||
struct ast_channel *chan; /*!< Our channel */
|
||||
@@ -833,8 +837,13 @@ static void init_queue(struct call_queue *q)
|
||||
q->monfmt[0] = '\0';
|
||||
q->periodicannouncefrequency = 0;
|
||||
q->sound_callerannounce[0] = '\0'; /* Default, don't announce the caller that he has been answered */
|
||||
if(!q->members)
|
||||
q->members = ao2_container_alloc(37, member_hash_fn, member_cmp_fn);
|
||||
if(!q->members) {
|
||||
if(q->strategy == QUEUE_STRATEGY_LINEAR)
|
||||
/* linear strategy depends on order, so we have to place all members in a single bucket */
|
||||
q->members = ao2_container_alloc(1, member_hash_fn, member_cmp_fn);
|
||||
else
|
||||
q->members = ao2_container_alloc(37, member_hash_fn, member_cmp_fn);
|
||||
}
|
||||
q->membercount = 0;
|
||||
q->found = 1;
|
||||
ast_copy_string(q->sound_next, "queue-youarenext", sizeof(q->sound_next));
|
||||
@@ -1063,12 +1072,8 @@ static void queue_set_param(struct call_queue *q, const char *param, const char
|
||||
} else if (!strcasecmp(param, "servicelevel")) {
|
||||
q->servicelevel= atoi(val);
|
||||
} else if (!strcasecmp(param, "strategy")) {
|
||||
q->strategy = strat2int(val);
|
||||
if (q->strategy < 0) {
|
||||
ast_log(LOG_WARNING, "'%s' isn't a valid strategy for queue '%s', using ringall instead\n",
|
||||
val, q->name);
|
||||
q->strategy = QUEUE_STRATEGY_RINGALL;
|
||||
}
|
||||
/* We already have set this, no need to do it again */
|
||||
return;
|
||||
} else if (!strcasecmp(param, "joinempty")) {
|
||||
if (!strcasecmp(val, "loose"))
|
||||
q->joinempty = QUEUE_EMPTY_LOOSE;
|
||||
@@ -1914,8 +1919,10 @@ static int ring_entry(struct queue_ent *qe, struct callattempt *tmp, int *busies
|
||||
|
||||
ao2_lock(qe->parent);
|
||||
qe->parent->rrpos++;
|
||||
qe->linpos++;
|
||||
ao2_unlock(qe->parent);
|
||||
|
||||
|
||||
(*busies)++;
|
||||
return 0;
|
||||
} else if (status != tmp->oldstatus)
|
||||
@@ -2021,7 +2028,7 @@ static int ring_one(struct queue_ent *qe, struct callattempt *outgoing, int *bus
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int store_next(struct queue_ent *qe, struct callattempt *outgoing)
|
||||
static int store_next_rr(struct queue_ent *qe, struct callattempt *outgoing)
|
||||
{
|
||||
struct callattempt *best = find_best(outgoing);
|
||||
|
||||
@@ -2044,6 +2051,29 @@ static int store_next(struct queue_ent *qe, struct callattempt *outgoing)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int store_next_lin(struct queue_ent *qe, struct callattempt *outgoing)
|
||||
{
|
||||
struct callattempt *best = find_best(outgoing);
|
||||
|
||||
if (best) {
|
||||
/* Ring just the best channel */
|
||||
ast_debug(1, "Next is '%s' with metric %d\n", best->interface, best->metric);
|
||||
qe->linpos = best->metric % 1000;
|
||||
} else {
|
||||
/* Just increment rrpos */
|
||||
if (qe->linwrapped) {
|
||||
/* No more channels, start over */
|
||||
qe->linpos = 0;
|
||||
} else {
|
||||
/* Prioritize next entry */
|
||||
qe->linpos++;
|
||||
}
|
||||
}
|
||||
qe->linwrapped = 0;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int say_periodic_announcement(struct queue_ent *qe, int ringing)
|
||||
{
|
||||
int res = 0;
|
||||
@@ -2541,6 +2571,17 @@ static int calc_metric(struct call_queue *q, struct member *mem, int pos, struct
|
||||
/* Everyone equal, except for penalty */
|
||||
tmp->metric = mem->penalty * 1000000;
|
||||
break;
|
||||
case QUEUE_STRATEGY_LINEAR:
|
||||
if (pos < qe->linpos) {
|
||||
tmp->metric = 1000 + pos;
|
||||
} else {
|
||||
if (pos > qe->linpos)
|
||||
/* Indicate there is another priority */
|
||||
qe->linwrapped = 1;
|
||||
tmp->metric = pos;
|
||||
}
|
||||
tmp->metric += mem->penalty * 1000000;
|
||||
break;
|
||||
case QUEUE_STRATEGY_RRMEMORY:
|
||||
if (pos < q->rrpos) {
|
||||
tmp->metric = 1000 + pos;
|
||||
@@ -2689,7 +2730,7 @@ static int try_calling(struct queue_ent *qe, const char *options, char *announce
|
||||
ast_set_flag(&(bridge_config.features_caller), AST_FEATURE_PARKCALL);
|
||||
break;
|
||||
case 'n':
|
||||
if (qe->parent->strategy == QUEUE_STRATEGY_RRMEMORY)
|
||||
if (qe->parent->strategy == QUEUE_STRATEGY_RRMEMORY || qe->parent->strategy == QUEUE_STRATEGY_LINEAR)
|
||||
(*tries)++;
|
||||
else
|
||||
*tries = qe->parent->membercount;
|
||||
@@ -2757,7 +2798,10 @@ static int try_calling(struct queue_ent *qe, const char *options, char *announce
|
||||
lpeer = wait_for_answer(qe, outgoing, &to, &digit, numbusies, ast_test_flag(&(bridge_config.features_caller), AST_FEATURE_DISCONNECT), forwardsallowed);
|
||||
ao2_lock(qe->parent);
|
||||
if (qe->parent->strategy == QUEUE_STRATEGY_RRMEMORY) {
|
||||
store_next(qe, outgoing);
|
||||
store_next_rr(qe, outgoing);
|
||||
}
|
||||
if (qe->parent->strategy == QUEUE_STRATEGY_LINEAR) {
|
||||
store_next_lin(qe, outgoing);
|
||||
}
|
||||
ao2_unlock(qe->parent);
|
||||
peer = lpeer ? lpeer->chan : NULL;
|
||||
@@ -4214,6 +4258,7 @@ static int reload_queues(int reload)
|
||||
} else
|
||||
new = 0;
|
||||
if (q) {
|
||||
const char *tmpvar;
|
||||
if (!new)
|
||||
ao2_lock(q);
|
||||
/* Check if a queue with this name already exists */
|
||||
@@ -4223,6 +4268,20 @@ static int reload_queues(int reload)
|
||||
ao2_unlock(q);
|
||||
continue;
|
||||
}
|
||||
/* Due to the fact that the "linear" strategy will have a different allocation
|
||||
* scheme for queue members, we must devise the queue's strategy before other initializations
|
||||
*/
|
||||
if((tmpvar = ast_variable_retrieve(cfg, cat, "strategy"))) {
|
||||
ast_log(LOG_DEBUG, "Success!!\n");
|
||||
q->strategy = strat2int(tmpvar);
|
||||
ast_log(LOG_DEBUG, "Queue strategy set to '%s'\n", int2strat(q->strategy));
|
||||
if (q->strategy < 0) {
|
||||
ast_log(LOG_WARNING, "'%s' isn't a valid strategy for queue '%s', using ringall instead\n",
|
||||
tmpvar, q->name);
|
||||
q->strategy = QUEUE_STRATEGY_RINGALL;
|
||||
}
|
||||
} else
|
||||
q->strategy = QUEUE_STRATEGY_RINGALL;
|
||||
/* Re-initialize the queue, and clear statistics */
|
||||
init_queue(q);
|
||||
if (!queue_keep_stats)
|
||||
|
@@ -93,6 +93,9 @@ shared_lastcall=no
|
||||
; fewestcalls - ring the one with fewest completed calls from this queue
|
||||
; random - ring random interface
|
||||
; rrmemory - round robin with memory, remember where we left off last ring pass
|
||||
; linear - rings interfaces in the order specified in this configuration file.
|
||||
; If you use dynamic members, the members will be rung in the order in
|
||||
; which they were added
|
||||
;
|
||||
;strategy = ringall
|
||||
;
|
||||
|
Reference in New Issue
Block a user