Skip to content
Snippets Groups Projects
Commit 05a1ec8a authored by Tilghman Lesher's avatar Tilghman Lesher
Browse files

Cache query results for one second.

Queries from the PBX core come in 3's.  Caching avoids the additional
performance penalty from those two additional queries hitting the database.

(closes issue #16521)
 Reported by: tilghman
 Patches: 
       20091229__issue16521.diff.txt uploaded by tilghman (license 14)
 Tested by: Hubguru, tilghman


git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@266238 65c4cc65-6c06-0410-ace0-fbb531ad65f3
parent fb80119b
No related branches found
No related tags found
No related merge requests found
......@@ -446,6 +446,8 @@ Miscellaneous
of dynamic parkinglots.
* chan_dahdi now supports reporting alarms over AMI either by channel or span via
the reportalarms config option.
* The Realtime dialplan switch now caches entries for 1 second. This provides a
significant increase in performance (about 3X) for installations using this switchtype.
CLI Changes
-----------
......
......@@ -27,6 +27,8 @@
ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
#include <signal.h>
#include "asterisk/file.h"
#include "asterisk/logger.h"
#include "asterisk/channel.h"
......@@ -47,6 +49,7 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
#include "asterisk/crypto.h"
#include "asterisk/astdb.h"
#include "asterisk/app.h"
#include "asterisk/astobj2.h"
#define MODE_MATCH 0
#define MODE_MATCHMORE 1
......@@ -62,6 +65,80 @@ AST_APP_OPTIONS(switch_opts, {
AST_APP_OPTION('p', OPTION_PATTERNS_DISABLED),
});
struct cache_entry {
struct timeval when;
struct ast_variable *var;
int priority;
char *context;
char exten[2];
};
struct ao2_container *cache;
pthread_t cleanup_thread = 0;
static int cache_hash(const void *obj, const int flags)
{
const struct cache_entry *e = obj;
return ast_str_case_hash(e->exten) + e->priority;
}
static int cache_cmp(void *obj, void *arg, int flags)
{
struct cache_entry *e = obj, *f = arg;
return e->priority != f->priority ? 0 :
strcmp(e->exten, f->exten) ? 0 :
strcmp(e->context, f->context) ? 0 :
CMP_MATCH;
}
static struct ast_variable *dup_vars(struct ast_variable *v)
{
struct ast_variable *new, *list = NULL;
for (; v; v = v->next) {
if (!(new = ast_variable_new(v->name, v->value, v->file))) {
ast_variables_destroy(list);
return NULL;
}
/* Reversed list in cache, but when we duplicate out of the cache,
* it's back to correct order. */
new->next = list;
list = new;
}
return list;
}
static void free_entry(void *obj)
{
struct cache_entry *e = obj;
ast_variables_destroy(e->var);
}
static int purge_old_fn(void *obj, void *arg, int flags)
{
struct cache_entry *e = obj;
struct timeval *now = arg;
return ast_tvdiff_ms(*now, e->when) >= 1000 ? CMP_MATCH : 0;
}
static void *cleanup(void *unused)
{
struct timespec forever = { 999999999, 0 }, one_second = { 1, 0 };
struct timeval now;
for (;;) {
pthread_testcancel();
if (ao2_container_count(cache) == 0) {
nanosleep(&forever, NULL);
}
pthread_testcancel();
now = ast_tvnow();
ao2_callback(cache, OBJ_MULTIPLE | OBJ_UNLINK | OBJ_NODATA, purge_old_fn, &now);
pthread_testcancel();
nanosleep(&one_second, NULL);
}
}
/* Realtime switch looks up extensions in the supplied realtime table.
[context@][realtimetable][/options]
......@@ -141,6 +218,11 @@ static struct ast_variable *realtime_common(const char *context, const char *ext
char *table;
struct ast_variable *var=NULL;
struct ast_flags flags = { 0, };
struct cache_entry *ce;
struct {
struct cache_entry ce;
char exten[AST_MAX_EXTENSION];
} cache_search = { { .priority = priority, .context = (char *) context }, };
char *buf = ast_strdupa(data);
if (buf) {
/* "Realtime" prefix is stripped off in the parent engine. The
......@@ -158,7 +240,36 @@ static struct ast_variable *realtime_common(const char *context, const char *ext
if (!ast_strlen_zero(opts)) {
ast_app_parse_options(switch_opts, &flags, NULL, opts);
}
var = realtime_switch_common(table, ctx, exten, priority, mode, flags);
ast_copy_string(cache_search.exten, exten, sizeof(cache_search.exten));
if (mode == MODE_MATCH && (ce = ao2_find(cache, &cache_search, OBJ_POINTER))) {
var = dup_vars(ce->var);
ao2_ref(ce, -1);
} else {
var = realtime_switch_common(table, ctx, exten, priority, mode, flags);
do {
struct ast_variable *new;
/* Only cache matches */
if (mode != MODE_MATCH) {
break;
}
if (!(new = dup_vars(var))) {
break;
}
if (!(ce = ao2_alloc(sizeof(*ce) + strlen(exten) + strlen(context), free_entry))) {
ast_variables_destroy(new);
break;
}
ce->context = ce->exten + strlen(exten) + 1;
strcpy(ce->exten, exten); /* SAFE */
strcpy(ce->context, context); /* SAFE */
ce->priority = priority;
ce->var = new;
ce->when = ast_tvnow();
ao2_link(cache, ce);
pthread_kill(cleanup_thread, SIGURG);
ao2_ref(ce, -1);
} while (0);
}
}
return var;
}
......@@ -283,11 +394,24 @@ static struct ast_switch realtime_switch =
static int unload_module(void)
{
ast_unregister_switch(&realtime_switch);
pthread_cancel(cleanup_thread);
pthread_kill(cleanup_thread, SIGURG);
pthread_join(cleanup_thread, NULL);
/* Destroy all remaining entries */
ao2_ref(cache, -1);
return 0;
}
static int load_module(void)
{
if (!(cache = ao2_container_alloc(573, cache_hash, cache_cmp))) {
return AST_MODULE_LOAD_FAILURE;
}
if (ast_pthread_create(&cleanup_thread, NULL, cleanup, NULL)) {
return AST_MODULE_LOAD_FAILURE;
}
if (ast_register_switch(&realtime_switch))
return AST_MODULE_LOAD_FAILURE;
return AST_MODULE_LOAD_SUCCESS;
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment