mirror of
https://github.com/asterisk/asterisk.git
synced 2025-09-05 20:20:07 +00:00
Bug 5936 - Cannot AddQueueMember on realtime queue, if queue not yet loaded (different fix than 1.2)
git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@8402 65c4cc65-6c06-0410-ace0-fbb531ad65f3
This commit is contained in:
149
apps/app_queue.c
149
apps/app_queue.c
@@ -791,8 +791,7 @@ static void rt_handle_member_record(struct ast_call_queue *q, char *interface, c
|
|||||||
|
|
||||||
/*!\brief Reload a single queue via realtime.
|
/*!\brief Reload a single queue via realtime.
|
||||||
\return Return the queue, or NULL if it doesn't exist.
|
\return Return the queue, or NULL if it doesn't exist.
|
||||||
\note Should be called with the global qlock locked.
|
\note Should be called with the global qlock locked. */
|
||||||
When found, the queue is returned with q->lock locked. */
|
|
||||||
static struct ast_call_queue *find_queue_by_name_rt(const char *queuename, struct ast_variable *queue_vars, struct ast_config *member_config)
|
static struct ast_call_queue *find_queue_by_name_rt(const char *queuename, struct ast_variable *queue_vars, struct ast_config *member_config)
|
||||||
{
|
{
|
||||||
struct ast_variable *v;
|
struct ast_variable *v;
|
||||||
@@ -818,6 +817,7 @@ static struct ast_call_queue *find_queue_by_name_rt(const char *queuename, struc
|
|||||||
ast_mutex_unlock(&q->lock);
|
ast_mutex_unlock(&q->lock);
|
||||||
return NULL;
|
return NULL;
|
||||||
} else {
|
} else {
|
||||||
|
ast_mutex_unlock(&q->lock);
|
||||||
return q;
|
return q;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -911,13 +911,60 @@ static struct ast_call_queue *find_queue_by_name_rt(const char *queuename, struc
|
|||||||
m = next_m;
|
m = next_m;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ast_mutex_unlock(&q->lock);
|
||||||
|
|
||||||
|
return q;
|
||||||
|
}
|
||||||
|
|
||||||
|
static struct ast_call_queue *load_realtime_queue(char *queuename)
|
||||||
|
{
|
||||||
|
struct ast_variable *queue_vars = NULL;
|
||||||
|
struct ast_config *member_config = NULL;
|
||||||
|
struct ast_call_queue *q;
|
||||||
|
|
||||||
|
/* Find the queue in the in-core list first. */
|
||||||
|
ast_mutex_lock(&qlock);
|
||||||
|
for (q = queues; q; q = q->next) {
|
||||||
|
if (!strcasecmp(q->name, queuename)) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
ast_mutex_unlock(&qlock);
|
||||||
|
|
||||||
|
if (!q) {
|
||||||
|
/*! \note Load from realtime before taking the global qlock, to avoid blocking all
|
||||||
|
queue operations while waiting for the DB.
|
||||||
|
|
||||||
|
This will be two separate database transactions, so we might
|
||||||
|
see queue parameters as they were before another process
|
||||||
|
changed the queue and member list as it was after the change.
|
||||||
|
Thus we might see an empty member list when a queue is
|
||||||
|
deleted. In practise, this is unlikely to cause a problem. */
|
||||||
|
|
||||||
|
queue_vars = ast_load_realtime("queues", "name", queuename, NULL);
|
||||||
|
if (queue_vars) {
|
||||||
|
member_config = ast_load_realtime_multientry("queue_members", "interface LIKE", "%", "queue_name", queuename, NULL);
|
||||||
|
if (!member_config) {
|
||||||
|
ast_log(LOG_ERROR, "no queue_members defined in your config (extconfig.conf).\n");
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ast_mutex_lock(&qlock);
|
||||||
|
|
||||||
|
q = find_queue_by_name_rt(queuename, queue_vars, member_config);
|
||||||
|
if (member_config)
|
||||||
|
ast_config_destroy(member_config);
|
||||||
|
if (queue_vars)
|
||||||
|
ast_variables_destroy(queue_vars);
|
||||||
|
|
||||||
|
ast_mutex_unlock(&qlock);
|
||||||
|
}
|
||||||
return q;
|
return q;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int join_queue(char *queuename, struct queue_ent *qe, enum queue_result *reason)
|
static int join_queue(char *queuename, struct queue_ent *qe, enum queue_result *reason)
|
||||||
{
|
{
|
||||||
struct ast_variable *queue_vars = NULL;
|
|
||||||
struct ast_config *member_config = NULL;
|
|
||||||
struct ast_call_queue *q;
|
struct ast_call_queue *q;
|
||||||
struct queue_ent *cur, *prev = NULL;
|
struct queue_ent *cur, *prev = NULL;
|
||||||
int res = -1;
|
int res = -1;
|
||||||
@@ -925,35 +972,12 @@ static int join_queue(char *queuename, struct queue_ent *qe, enum queue_result *
|
|||||||
int inserted = 0;
|
int inserted = 0;
|
||||||
enum queue_member_status stat;
|
enum queue_member_status stat;
|
||||||
|
|
||||||
/*! \note Load from realtime before taking the global qlock, to avoid blocking all
|
q = load_realtime_queue(queuename);
|
||||||
queue operations while waiting for the DB.
|
if (!q)
|
||||||
|
return res;
|
||||||
This will be two separate database transactions, so we might
|
|
||||||
see queue parameters as they were before another process
|
|
||||||
changed the queue and member list as it was after the change.
|
|
||||||
Thus we might see an empty member list when a queue is
|
|
||||||
deleted. In practise, this is unlikely to cause a problem. */
|
|
||||||
queue_vars = ast_load_realtime("queues", "name", queuename, NULL);
|
|
||||||
if (queue_vars) {
|
|
||||||
member_config = ast_load_realtime_multientry("queue_members", "interface LIKE", "%", "queue_name", queuename, NULL);
|
|
||||||
if (!member_config) {
|
|
||||||
ast_log(LOG_ERROR, "no queue_members defined in your config (extconfig.conf).\n");
|
|
||||||
return res;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
ast_mutex_lock(&qlock);
|
ast_mutex_lock(&qlock);
|
||||||
q = find_queue_by_name_rt(queuename, queue_vars, member_config);
|
ast_mutex_lock(&q->lock);
|
||||||
/* Note: If found, find_queue_by_name_rt() returns with q->lock locked. */
|
|
||||||
if(member_config)
|
|
||||||
ast_config_destroy(member_config);
|
|
||||||
if(queue_vars)
|
|
||||||
ast_variables_destroy(queue_vars);
|
|
||||||
|
|
||||||
if (!q) {
|
|
||||||
ast_mutex_unlock(&qlock);
|
|
||||||
return res;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* This is our one */
|
/* This is our one */
|
||||||
stat = get_member_status(q, qe->max_penalty);
|
stat = get_member_status(q, qe->max_penalty);
|
||||||
@@ -2452,41 +2476,42 @@ static int add_to_queue(char *queuename, char *interface, int penalty, int pause
|
|||||||
struct member *new_member;
|
struct member *new_member;
|
||||||
int res = RES_NOSUCHQUEUE;
|
int res = RES_NOSUCHQUEUE;
|
||||||
|
|
||||||
|
/* \note Ensure the appropriate realtime queue is loaded. Note that this
|
||||||
|
* short-circuits if the queue is already in memory. */
|
||||||
|
q = load_realtime_queue(queuename);
|
||||||
|
|
||||||
ast_mutex_lock(&qlock);
|
ast_mutex_lock(&qlock);
|
||||||
for (q = queues ; q ; q = q->next) {
|
|
||||||
|
if (q) {
|
||||||
ast_mutex_lock(&q->lock);
|
ast_mutex_lock(&q->lock);
|
||||||
if (!strcmp(q->name, queuename)) {
|
if (interface_exists(q, interface) == NULL) {
|
||||||
if (interface_exists(q, interface) == NULL) {
|
new_member = create_queue_member(interface, penalty, paused);
|
||||||
new_member = create_queue_member(interface, penalty, paused);
|
|
||||||
|
|
||||||
if (new_member != NULL) {
|
if (new_member != NULL) {
|
||||||
new_member->dynamic = 1;
|
new_member->dynamic = 1;
|
||||||
new_member->next = q->members;
|
new_member->next = q->members;
|
||||||
q->members = new_member;
|
q->members = new_member;
|
||||||
manager_event(EVENT_FLAG_AGENT, "QueueMemberAdded",
|
manager_event(EVENT_FLAG_AGENT, "QueueMemberAdded",
|
||||||
"Queue: %s\r\n"
|
"Queue: %s\r\n"
|
||||||
"Location: %s\r\n"
|
"Location: %s\r\n"
|
||||||
"Membership: %s\r\n"
|
"Membership: %s\r\n"
|
||||||
"Penalty: %d\r\n"
|
"Penalty: %d\r\n"
|
||||||
"CallsTaken: %d\r\n"
|
"CallsTaken: %d\r\n"
|
||||||
"LastCall: %d\r\n"
|
"LastCall: %d\r\n"
|
||||||
"Status: %d\r\n"
|
"Status: %d\r\n"
|
||||||
"Paused: %d\r\n",
|
"Paused: %d\r\n",
|
||||||
q->name, new_member->interface, new_member->dynamic ? "dynamic" : "static",
|
q->name, new_member->interface, new_member->dynamic ? "dynamic" : "static",
|
||||||
new_member->penalty, new_member->calls, (int)new_member->lastcall, new_member->status, new_member->paused);
|
new_member->penalty, new_member->calls, (int)new_member->lastcall, new_member->status, new_member->paused);
|
||||||
|
|
||||||
if (dump)
|
if (dump)
|
||||||
dump_queue_members(q);
|
dump_queue_members(q);
|
||||||
|
|
||||||
res = RES_OKAY;
|
res = RES_OKAY;
|
||||||
} else {
|
|
||||||
res = RES_OUTOFMEMORY;
|
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
res = RES_EXISTS;
|
res = RES_OUTOFMEMORY;
|
||||||
}
|
}
|
||||||
ast_mutex_unlock(&q->lock);
|
} else {
|
||||||
break;
|
res = RES_EXISTS;
|
||||||
}
|
}
|
||||||
ast_mutex_unlock(&q->lock);
|
ast_mutex_unlock(&q->lock);
|
||||||
}
|
}
|
||||||
@@ -3411,7 +3436,13 @@ static int __queues_show(int manager, int fd, int argc, char **argv, int queue_s
|
|||||||
time(&now);
|
time(&now);
|
||||||
if ((!queue_show && argc != 2) || (queue_show && argc != 3))
|
if ((!queue_show && argc != 2) || (queue_show && argc != 3))
|
||||||
return RESULT_SHOWUSAGE;
|
return RESULT_SHOWUSAGE;
|
||||||
|
|
||||||
|
/* We only want to load realtime queues when a specific queue is asked for. */
|
||||||
|
if (queue_show)
|
||||||
|
load_realtime_queue(argv[2]);
|
||||||
|
|
||||||
ast_mutex_lock(&qlock);
|
ast_mutex_lock(&qlock);
|
||||||
|
|
||||||
q = queues;
|
q = queues;
|
||||||
if (!q) {
|
if (!q) {
|
||||||
ast_mutex_unlock(&qlock);
|
ast_mutex_unlock(&qlock);
|
||||||
|
Reference in New Issue
Block a user