res_odbc: cache_size option to limit the cached connections.

UserNote: New cache_size option for res_odbc to on a per class basis limit the
number of cached connections. Please reference the sample configuration
for details.

Signed-off-by: Jaco Kroon <jaco@uls.co.za>
Jaco Kroon 5 months ago
parent a841d09ee8
commit 955ea1e5f0

@ -88,6 +88,13 @@ pre-connect => yes
; compatible, setting this value to any of rr, roundrobin or queue will result
; in a round-robin queue being used.
;cache_type => roundrobin
;
; Limit the number of connections to cache. On extremely spiky loads this could be
; useful to limit the overall number of connections that's kept open. The default is
; to not limit the cache size (thus effectively limit to max_connections). When a returned
; connection would result in the cache size being exceeded, the longest idle connection
; in the cache shall be dropped.
;cache_size => 10
[mysql2]
enabled => no

@ -101,6 +101,10 @@ struct odbc_class
char *sql_text;
/*! Slow query limit (in milliseconds) */
unsigned int slowquerylimit;
/*! Maximum number of cached connections, default is maxconnections */
unsigned int max_cache_size;
/*! Current cached connection count, when cache_size will exceed max_cache_size, longest-idle connection will be dropped from the cache */
unsigned int cur_cache;
};
static struct ao2_container *class_container;
@ -564,6 +568,7 @@ static int load_odbc_config(void)
struct timeval ncache = { 0, 0 };
int preconnect = 0, res = 0, cache_is_queue = 0;
struct ast_flags config_flags = { 0 };
unsigned int max_cache_size;
struct odbc_class *new;
@ -591,6 +596,7 @@ static int load_odbc_config(void)
logging = 0;
slowquerylimit = 5000;
cache_is_queue = 0;
max_cache_size = UINT_MAX;
for (v = ast_variable_browse(config, cat); v; v = v->next) {
if (!strcasecmp(v->name, "pooling") ||
!strncasecmp(v->name, "share", 5) ||
@ -650,6 +656,10 @@ static int load_odbc_config(void)
cache_is_queue = !strcasecmp(v->value, "rr") ||
!strcasecmp(v->value, "roundrobin") ||
!strcasecmp(v->value, "queue");
} else if (!strcasecmp(v->name, "cache_size")) {
if (sscanf(v->value, "%u", &max_cache_size) != 1) {
ast_log(LOG_WARNING, "cache_size must be a non-negative integer\n");
}
}
}
@ -679,6 +689,8 @@ static int load_odbc_config(void)
new->logging = logging;
new->slowquerylimit = slowquerylimit;
new->cache_is_queue = cache_is_queue;
new->max_cache_size = max_cache_size;
new->cur_cache = 0;
if (cat)
ast_copy_string(new->name, cat, sizeof(new->name));
@ -766,6 +778,8 @@ static char *handle_cli_odbc_show(struct ast_cli_entry *e, int cmd, struct ast_c
ast_cli(a->fd, " Number of active connections: %zd (out of %d)\n", class->connection_cnt, class->maxconnections);
ast_cli(a->fd, " Cache Type: %s\n", class->cache_is_queue ? "round-robin queue" : "stack (last release, first re-use)");
ast_cli(a->fd, " Cache Usage: %u cached out of %u\n", class->cur_cache,
class->max_cache_size < class->maxconnections ? class->max_cache_size : class->maxconnections);
ast_cli(a->fd, " Logging: %s\n", class->logging ? "Enabled" : "Disabled");
if (class->logging) {
ast_cli(a->fd, " Number of prepares executed: %d\n", class->prepares_executed);
@ -836,6 +850,28 @@ void ast_odbc_release_obj(struct odbc_obj *obj)
} else {
AST_LIST_INSERT_HEAD(&class->connections, obj, list);
}
if (class->cur_cache >= class->max_cache_size) {
/* cache is full */
if (class->cache_is_queue) {
/* HEAD will be oldest */
obj = AST_LIST_REMOVE_HEAD(&class->connections, list);
} else {
/* TAIL will be oldest */
obj = AST_LIST_LAST(&class->connections);
AST_LIST_REMOVE(&class->connections, obj, list);
}
--class->connection_cnt;
ast_mutex_unlock(&class->lock);
ast_debug(2, "ODBC Pool '%s' exceeded cache size, dropping '%p', connection count is %zd (%u cached)\n",
class->name, obj, class->connection_cnt, class->cur_cache);
ao2_ref(obj, -1);
ast_mutex_lock(&class->lock);
} else
++class->cur_cache;
ast_cond_signal(&class->cond);
ast_mutex_unlock(&class->lock);
@ -931,6 +967,8 @@ struct odbc_obj *_ast_odbc_request_obj2(const char *name, struct ast_flags flags
ast_mutex_lock(&class->lock);
obj = AST_LIST_REMOVE_HEAD(&class->connections, list);
if (obj)
--class->cur_cache;
ast_mutex_unlock(&class->lock);

Loading…
Cancel
Save