Asterisk - The Open Source Telephony Project GIT-master-7e7a603
Data Structures | Macros | Functions | Variables
res_sorcery_memory_cache.c File Reference

Sorcery Memory Cache Object Wizard. More...

#include "asterisk.h"
#include "asterisk/module.h"
#include "asterisk/sorcery.h"
#include "asterisk/astobj2.h"
#include "asterisk/sched.h"
#include "asterisk/test.h"
#include "asterisk/heap.h"
#include "asterisk/cli.h"
#include "asterisk/manager.h"
Include dependency graph for res_sorcery_memory_cache.c:

Go to the source code of this file.

Data Structures

struct  print_object_details
 Structure used to pass data for printing cached object information. More...
 
struct  sorcery_memory_cache
 Structure for storing a memory cache. More...
 
struct  sorcery_memory_cache_fields_cmp_params
 Structure used for fields comparison. More...
 
struct  sorcery_memory_cached_object
 Structure for stored a cached object. More...
 
struct  stale_cache_update_task_data
 
struct  stale_update_task_data
 

Macros

#define CACHE_CONTAINER_BUCKET_SIZE   53
 The default bucket size for the container of objects in the cache. More...
 
#define CACHE_HEAP_INIT_HEIGHT   5
 Height of heap for cache object heap. Allows 31 initial objects. More...
 
#define CACHES_CONTAINER_BUCKET_SIZE   53
 The bucket size for the container of caches. More...
 
#define FORMAT   "%-25.25s %-15u %-15u \n"
 
#define FORMAT   "%-25.25s %-15.15s %-15.15s \n"
 
#define PASSTHRU_UPDATE_THREAD_ID   0x5EED1E55
 

Functions

static void __init_passthru_update_id_storage (void)
 
static void __reg_module (void)
 
static void __unreg_module (void)
 
static int add_to_cache (struct sorcery_memory_cache *cache, struct sorcery_memory_cached_object *cached_object)
 
static int age_cmp (void *a, void *b)
 
struct ast_moduleAST_MODULE_SELF_SYM (void)
 
static int configuration_parse_unsigned_integer (const char *value, unsigned int *result)
 
static void end_passthru_update (void)
 
static int expire_objects_from_cache (const void *data)
 
static int is_passthru_update (void)
 
static int load_module (void)
 
static void mark_all_as_stale_in_cache (struct sorcery_memory_cache *cache)
 
static int mark_object_as_stale_in_cache (struct sorcery_memory_cache *cache, const char *id)
 
static void memory_cache_full_update (const struct ast_sorcery *sorcery, const char *type, struct sorcery_memory_cache *cache)
 
static void memory_cache_populate (const struct ast_sorcery *sorcery, const char *type, struct sorcery_memory_cache *cache)
 
static void memory_cache_stale_check (const struct ast_sorcery *sorcery, struct sorcery_memory_cache *cache)
 
static void memory_cache_stale_check_object (const struct ast_sorcery *sorcery, struct sorcery_memory_cache *cache, struct sorcery_memory_cached_object *cached)
 
static void memory_cache_stale_update_full (const struct ast_sorcery *sorcery, struct sorcery_memory_cache *cache, const char *type)
 
static void memory_cache_stale_update_object (const struct ast_sorcery *sorcery, struct sorcery_memory_cache *cache, struct sorcery_memory_cached_object *cached)
 
static int object_add_to_cache_callback (void *obj, void *arg, void *data, int flags)
 
static int object_stale_callback (void *obj, void *arg, int flags)
 
static void remove_all_from_cache (struct sorcery_memory_cache *cache)
 
static int remove_from_cache (struct sorcery_memory_cache *cache, const char *id, int reschedule)
 
static int remove_oldest_from_cache (struct sorcery_memory_cache *cache)
 
static int schedule_cache_expiration (struct sorcery_memory_cache *cache)
 
static void set_passthru_update (uint32_t value)
 
static int sorcery_memory_cache_ami_expire (struct mansession *s, const struct message *m)
 
static int sorcery_memory_cache_ami_expire_object (struct mansession *s, const struct message *m)
 
static int sorcery_memory_cache_ami_populate (struct mansession *s, const struct message *m)
 
static int sorcery_memory_cache_ami_stale (struct mansession *s, const struct message *m)
 
static int sorcery_memory_cache_ami_stale_object (struct mansession *s, const struct message *m)
 
static void sorcery_memory_cache_close (void *data)
 
static int sorcery_memory_cache_cmp (void *obj, void *arg, int flags)
 
static char * sorcery_memory_cache_complete_name (const char *word, int state)
 
static char * sorcery_memory_cache_complete_object_name (const char *cache_name, const char *word, int state)
 
static int sorcery_memory_cache_create (const struct ast_sorcery *sorcery, void *data, void *object)
 
static int sorcery_memory_cache_delete (const struct ast_sorcery *sorcery, void *data, void *object)
 
static void sorcery_memory_cache_destructor (void *obj)
 
static char * sorcery_memory_cache_dump (struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
 
static char * sorcery_memory_cache_expire (struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
 
static int sorcery_memory_cache_fields_cmp (void *obj, void *arg, int flags)
 
static int sorcery_memory_cache_hash (const void *obj, int flags)
 
static void sorcery_memory_cache_load (void *data, const struct ast_sorcery *sorcery, const char *type)
 
static void * sorcery_memory_cache_open (const char *data)
 
static char * sorcery_memory_cache_populate (struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
 
static int sorcery_memory_cache_print_object (void *obj, void *arg, int flags)
 
static void sorcery_memory_cache_reload (void *data, const struct ast_sorcery *sorcery, const char *type)
 
static void * sorcery_memory_cache_retrieve_fields (const struct ast_sorcery *sorcery, void *data, const char *type, const struct ast_variable *fields)
 
static void * sorcery_memory_cache_retrieve_id (const struct ast_sorcery *sorcery, void *data, const char *type, const char *id)
 
static void sorcery_memory_cache_retrieve_multiple (const struct ast_sorcery *sorcery, void *data, const char *type, struct ao2_container *objects, const struct ast_variable *fields)
 
static void sorcery_memory_cache_retrieve_prefix (const struct ast_sorcery *sorcery, void *data, const char *type, struct ao2_container *objects, const char *prefix, const size_t prefix_len)
 
static void sorcery_memory_cache_retrieve_regex (const struct ast_sorcery *sorcery, void *data, const char *type, struct ao2_container *objects, const char *regex)
 
static char * sorcery_memory_cache_show (struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
 
static char * sorcery_memory_cache_stale (struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
 
static struct sorcery_memory_cached_objectsorcery_memory_cached_object_alloc (const struct ast_sorcery *sorcery, const struct sorcery_memory_cache *cache, void *object)
 
static int sorcery_memory_cached_object_cmp (void *obj, void *arg, int flags)
 
static void sorcery_memory_cached_object_destructor (void *obj)
 
static int sorcery_memory_cached_object_hash (const void *obj, int flags)
 
static int stale_cache_update (const void *data)
 
static struct stale_cache_update_task_datastale_cache_update_task_data_alloc (struct ast_sorcery *sorcery, struct sorcery_memory_cache *cache, const char *type)
 
static void stale_cache_update_task_data_destructor (void *obj)
 
static int stale_item_update (const void *data)
 
static struct stale_update_task_datastale_update_task_data_alloc (struct ast_sorcery *sorcery, struct sorcery_memory_cache *cache, const char *type, void *object)
 
static void stale_update_task_data_destructor (void *obj)
 
static void start_passthru_update (void)
 
static int unload_module (void)
 

Variables

static struct ast_module_info __mod_info = { .name = AST_MODULE, .flags = AST_MODFLAG_GLOBAL_SYMBOLS | AST_MODFLAG_LOAD_ORDER , .description = "Sorcery Memory Cache Object Wizard" , .key = "This paragraph is copyright (c) 2006 by Digium, Inc. \In order for your module to load, it must return this \key via a function called \"key\". Any code which \includes this paragraph must be licensed under the GNU \General Public License version 2 or later (at your \option). In addition to Digium's general reservations \of rights, Digium expressly reserves the right to \allow other parties to license this paragraph under \different terms. Any use of Digium, Inc. trademarks or \logos (including \"Asterisk\" or \"Digium\") without \express written permission of Digium, Inc. is prohibited.\n" , .buildopt_sum = AST_BUILDOPT_SUM, .support_level = AST_MODULE_SUPPORT_CORE, .load = load_module, .unload = unload_module, .load_pri = AST_MODPRI_REALTIME_DRIVER, }
 
static const struct ast_module_infoast_module_info = &__mod_info
 
static struct ao2_containercaches
 Container of created caches. More...
 
static struct ast_cli_entry cli_memory_cache []
 
static struct ast_sorcery_wizard memory_cache_object_wizard
 
static struct ast_threadstorage passthru_update_id_storage = { .once = PTHREAD_ONCE_INIT , .key_init = __init_passthru_update_id_storage , .custom_init = NULL , }
 
static struct ast_sched_contextsched
 Scheduler for cache management. More...
 

Detailed Description

Sorcery Memory Cache Object Wizard.

Author
Joshua Colp jcolp.nosp@m.@dig.nosp@m.ium.c.nosp@m.om

Definition in file res_sorcery_memory_cache.c.

Macro Definition Documentation

◆ CACHE_CONTAINER_BUCKET_SIZE

#define CACHE_CONTAINER_BUCKET_SIZE   53

The default bucket size for the container of objects in the cache.

Definition at line 235 of file res_sorcery_memory_cache.c.

◆ CACHE_HEAP_INIT_HEIGHT

#define CACHE_HEAP_INIT_HEIGHT   5

Height of heap for cache object heap. Allows 31 initial objects.

Definition at line 238 of file res_sorcery_memory_cache.c.

◆ CACHES_CONTAINER_BUCKET_SIZE

#define CACHES_CONTAINER_BUCKET_SIZE   53

The bucket size for the container of caches.

Definition at line 232 of file res_sorcery_memory_cache.c.

◆ FORMAT [1/2]

#define FORMAT   "%-25.25s %-15u %-15u \n"

◆ FORMAT [2/2]

#define FORMAT   "%-25.25s %-15.15s %-15.15s \n"

◆ PASSTHRU_UPDATE_THREAD_ID

#define PASSTHRU_UPDATE_THREAD_ID   0x5EED1E55

Definition at line 246 of file res_sorcery_memory_cache.c.

Function Documentation

◆ __init_passthru_update_id_storage()

static void __init_passthru_update_id_storage ( void  )
static

Definition at line 247 of file res_sorcery_memory_cache.c.

250{

◆ __reg_module()

static void __reg_module ( void  )
static

Definition at line 3603 of file res_sorcery_memory_cache.c.

◆ __unreg_module()

static void __unreg_module ( void  )
static

Definition at line 3603 of file res_sorcery_memory_cache.c.

◆ add_to_cache()

static int add_to_cache ( struct sorcery_memory_cache cache,
struct sorcery_memory_cached_object cached_object 
)
static

Definition at line 728 of file res_sorcery_memory_cache.c.

730{
731 struct sorcery_memory_cached_object *front;
732
733 if (!ao2_link_flags(cache->objects, cached_object, OBJ_NOLOCK)) {
734 return -1;
735 }
736
737 if (cache->full_backend_cache && (front = ast_heap_peek(cache->object_heap, 1))) {
738 /* For a full backend cache all objects share the same lifetime */
739 cached_object->created = front->created;
740 }
741
742 if (ast_heap_push(cache->object_heap, cached_object)) {
743 ao2_find(cache->objects, cached_object,
745 return -1;
746 }
747
748 if (cache->expire_id == -1) {
750 }
751
752 return 0;
753}
#define ao2_link_flags(container, obj, flags)
Add an object to a container.
Definition: astobj2.h:1554
#define ao2_find(container, arg, flags)
Definition: astobj2.h:1736
@ OBJ_SEARCH_OBJECT
The arg parameter is an object of the same type.
Definition: astobj2.h:1087
@ OBJ_NOLOCK
Assume that the ao2_container is already locked.
Definition: astobj2.h:1063
@ OBJ_NODATA
Definition: astobj2.h:1044
@ OBJ_UNLINK
Definition: astobj2.h:1039
#define ast_heap_push(h, elm)
Push an element on to a heap.
Definition: heap.h:125
void * ast_heap_peek(struct ast_heap *h, unsigned int index)
Peek at an element on a heap.
Definition: heap.c:267
struct ao2_container * cache
Definition: pbx_realtime.c:77
static int schedule_cache_expiration(struct sorcery_memory_cache *cache)
Structure for stored a cached object.
struct timeval created
The time at which the object was created.

References ao2_find, ao2_link_flags, ast_heap_peek(), ast_heap_push, cache, sorcery_memory_cached_object::created, OBJ_NODATA, OBJ_NOLOCK, OBJ_SEARCH_OBJECT, OBJ_UNLINK, and schedule_cache_expiration().

Referenced by object_add_to_cache_callback(), and sorcery_memory_cache_create().

◆ age_cmp()

static int age_cmp ( void *  a,
void *  b 
)
static

Definition at line 1493 of file res_sorcery_memory_cache.c.

1494{
1495 return ast_tvcmp(((struct sorcery_memory_cached_object *) b)->created,
1496 ((struct sorcery_memory_cached_object *) a)->created);
1497}
static struct test_val b
static struct test_val a
int ast_tvcmp(struct timeval _a, struct timeval _b)
Compress two struct timeval instances returning -1, 0, 1 if the first arg is smaller,...
Definition: time.h:137

References a, ast_tvcmp(), and b.

Referenced by sorcery_memory_cache_open().

◆ AST_MODULE_SELF_SYM()

struct ast_module * AST_MODULE_SELF_SYM ( void  )

Definition at line 3603 of file res_sorcery_memory_cache.c.

◆ configuration_parse_unsigned_integer()

static int configuration_parse_unsigned_integer ( const char *  value,
unsigned int *  result 
)
static

Definition at line 1484 of file res_sorcery_memory_cache.c.

1485{
1486 if (ast_strlen_zero(value) || !strncmp(value, "-", 1)) {
1487 return 0;
1488 }
1489
1490 return sscanf(value, "%30u", result);
1491}
static PGresult * result
Definition: cel_pgsql.c:84
static force_inline int attribute_pure ast_strlen_zero(const char *s)
Definition: strings.h:65
int value
Definition: syslog.c:37

References ast_strlen_zero(), result, and value.

Referenced by sorcery_memory_cache_open().

◆ end_passthru_update()

static void end_passthru_update ( void  )
static

Definition at line 281 of file res_sorcery_memory_cache.c.

282{
284}
static void set_passthru_update(uint32_t value)

References set_passthru_update().

Referenced by memory_cache_populate(), stale_cache_update(), and stale_item_update().

◆ expire_objects_from_cache()

static int expire_objects_from_cache ( const void *  data)
static

Definition at line 498 of file res_sorcery_memory_cache.c.

499{
500 struct sorcery_memory_cache *cache = (struct sorcery_memory_cache *)data;
501 struct sorcery_memory_cached_object *cached;
502
503 /*
504 * We need to do deadlock avoidance between a non-scheduler thread
505 * blocking when trying to delete the scheduled entry for this
506 * callback because the scheduler thread is running this callback
507 * and this callback waiting for the cache->objects container lock
508 * that the blocked non-scheduler thread already holds.
509 */
510 while (ao2_trywrlock(cache->objects)) {
511 if (cache->del_expire) {
512 cache->expire_id = -1;
513 ao2_ref(cache, -1);
514 return 0;
515 }
516 sched_yield();
517 }
518
519 cache->expire_id = -1;
520
521 /* This is an optimization for objects which have been cached close to each other */
522 while ((cached = ast_heap_peek(cache->object_heap, 1))) {
523 int expiration;
524
525 expiration = ast_tvdiff_ms(ast_tvadd(cached->created, ast_samp2tv(cache->object_lifetime_maximum, 1)), ast_tvnow());
526
527 /* If the current oldest object has not yet expired stop and reschedule for it */
528 if (expiration > 0) {
529 break;
530 }
531
533 }
534
536
537 ao2_unlock(cache->objects);
538
539 ao2_ref(cache, -1);
540
541 return 0;
542}
#define ao2_trywrlock(a)
Definition: astobj2.h:741
#define ao2_unlock(a)
Definition: astobj2.h:729
#define ao2_ref(o, delta)
Reference/unreference an object and return the old refcount.
Definition: astobj2.h:459
static int remove_from_cache(struct sorcery_memory_cache *cache, const char *id, int reschedule)
const char * ast_sorcery_object_get_id(const void *object)
Get the unique identifier of a sorcery object.
Definition: sorcery.c:2317
Structure for storing a memory cache.
struct timeval ast_samp2tv(unsigned int _nsamp, unsigned int _rate)
Returns a timeval corresponding to the duration of n samples at rate r. Useful to convert samples to ...
Definition: time.h:282
struct timeval ast_tvadd(struct timeval a, struct timeval b)
Returns the sum of two timevals a + b.
Definition: extconf.c:2282
int64_t ast_tvdiff_ms(struct timeval end, struct timeval start)
Computes the difference (in milliseconds) between two struct timeval instances.
Definition: time.h:107
struct timeval ast_tvnow(void)
Returns current timeval. Meant to replace calls to gettimeofday().
Definition: time.h:159

References ao2_ref, ao2_trywrlock, ao2_unlock, ast_heap_peek(), ast_samp2tv(), ast_sorcery_object_get_id(), ast_tvadd(), ast_tvdiff_ms(), ast_tvnow(), cache, sorcery_memory_cached_object::created, sorcery_memory_cached_object::object, remove_from_cache(), and schedule_cache_expiration().

Referenced by schedule_cache_expiration().

◆ is_passthru_update()

static int is_passthru_update ( void  )
static

Definition at line 249 of file res_sorcery_memory_cache.c.

250{
251 uint32_t *passthru_update_thread_id;
252
253 passthru_update_thread_id = ast_threadstorage_get(&passthru_update_id_storage,
254 sizeof(*passthru_update_thread_id));
255 if (!passthru_update_thread_id) {
256 return 0;
257 }
258
259 return *passthru_update_thread_id == PASSTHRU_UPDATE_THREAD_ID;
260}
#define PASSTHRU_UPDATE_THREAD_ID
static struct ast_threadstorage passthru_update_id_storage
void * ast_threadstorage_get(struct ast_threadstorage *ts, size_t init_size)
Retrieve thread storage.

References ast_threadstorage_get(), passthru_update_id_storage, and PASSTHRU_UPDATE_THREAD_ID.

Referenced by sorcery_memory_cache_retrieve_fields(), sorcery_memory_cache_retrieve_id(), sorcery_memory_cache_retrieve_multiple(), sorcery_memory_cache_retrieve_prefix(), and sorcery_memory_cache_retrieve_regex().

◆ load_module()

static int load_module ( void  )
static

Definition at line 3538 of file res_sorcery_memory_cache.c.

3539{
3540 int res;
3541
3545 if (!caches) {
3546 ast_log(LOG_ERROR, "Failed to create container for configured caches\n");
3547 unload_module();
3549 }
3550
3552 if (!sched) {
3553 ast_log(LOG_ERROR, "Failed to create scheduler for cache management\n");
3554 unload_module();
3556 }
3557
3559 ast_log(LOG_ERROR, "Failed to create scheduler thread for cache management\n");
3560 unload_module();
3562 }
3563
3565 unload_module();
3567 }
3568
3575
3576 if (res) {
3577 unload_module();
3579 }
3580
3581 /* This causes the stale unit test to execute last, so if a sorcery instance persists
3582 * longer than expected subsequent unit tests don't fail when setting it up.
3583 */
3584 AST_TEST_REGISTER(stale);
3585 AST_TEST_REGISTER(open_with_valid_options);
3586 AST_TEST_REGISTER(open_with_invalid_options);
3587 AST_TEST_REGISTER(create_and_retrieve);
3589 AST_TEST_REGISTER(delete);
3590 AST_TEST_REGISTER(maximum_objects);
3591 AST_TEST_REGISTER(expiration);
3592 AST_TEST_REGISTER(full_backend_cache_expiration);
3593 AST_TEST_REGISTER(full_backend_cache_stale);
3594
3596}
#define ast_log
Definition: astobj2.c:42
@ AO2_ALLOC_OPT_LOCK_MUTEX
Definition: astobj2.h:363
#define ao2_container_alloc_hash(ao2_options, container_options, n_buckets, hash_fn, sort_fn, cmp_fn)
Allocate and initialize a hash container with the desired number of buckets.
Definition: astobj2.h:1303
#define ast_cli_register_multiple(e, len)
Register multiple commands.
Definition: cli.h:265
static void update(int code_size, int y, int wi, int fi, int dq, int sr, int dqsez, struct g726_state *state_ptr)
Definition: codec_g726.c:367
#define LOG_ERROR
#define EVENT_FLAG_SYSTEM
Definition: manager.h:75
#define ast_manager_register_xml(action, authority, func)
Register a manager callback using XML documentation to describe the manager.
Definition: manager.h:191
@ AST_MODULE_LOAD_SUCCESS
Definition: module.h:70
@ AST_MODULE_LOAD_DECLINE
Module has failed to load, may be in an inconsistent state.
Definition: module.h:78
static int sorcery_memory_cache_ami_stale_object(struct mansession *s, const struct message *m)
#define CACHES_CONTAINER_BUCKET_SIZE
The bucket size for the container of caches.
static int sorcery_memory_cache_ami_stale(struct mansession *s, const struct message *m)
static struct ast_cli_entry cli_memory_cache[]
static int sorcery_memory_cache_cmp(void *obj, void *arg, int flags)
static int sorcery_memory_cache_hash(const void *obj, int flags)
static int sorcery_memory_cache_ami_expire(struct mansession *s, const struct message *m)
static struct ast_sorcery_wizard memory_cache_object_wizard
static int sorcery_memory_cache_ami_populate(struct mansession *s, const struct message *m)
static int unload_module(void)
static struct ao2_container * caches
Container of created caches.
static int sorcery_memory_cache_ami_expire_object(struct mansession *s, const struct message *m)
#define NULL
Definition: resample.c:96
int ast_sched_start_thread(struct ast_sched_context *con)
Start a thread for processing scheduler entries.
Definition: sched.c:197
struct ast_sched_context * ast_sched_context_create(void)
Create a scheduler context.
Definition: sched.c:238
#define ast_sorcery_wizard_register(interface)
See __ast_sorcery_wizard_register()
Definition: sorcery.h:383
Definition: sched.c:76
#define AST_TEST_REGISTER(cb)
Definition: test.h:127
#define ARRAY_LEN(a)
Definition: utils.h:666

References AO2_ALLOC_OPT_LOCK_MUTEX, ao2_container_alloc_hash, ARRAY_LEN, ast_cli_register_multiple, ast_log, ast_manager_register_xml, AST_MODULE_LOAD_DECLINE, AST_MODULE_LOAD_SUCCESS, ast_sched_context_create(), ast_sched_start_thread(), ast_sorcery_wizard_register, AST_TEST_REGISTER, caches, CACHES_CONTAINER_BUCKET_SIZE, cli_memory_cache, EVENT_FLAG_SYSTEM, LOG_ERROR, memory_cache_object_wizard, NULL, sorcery_memory_cache_ami_expire(), sorcery_memory_cache_ami_expire_object(), sorcery_memory_cache_ami_populate(), sorcery_memory_cache_ami_stale(), sorcery_memory_cache_ami_stale_object(), sorcery_memory_cache_cmp(), sorcery_memory_cache_hash(), unload_module(), and update().

◆ mark_all_as_stale_in_cache()

static void mark_all_as_stale_in_cache ( struct sorcery_memory_cache cache)
static

Definition at line 632 of file res_sorcery_memory_cache.c.

633{
635}
#define ao2_callback(c, flags, cb_fn, arg)
ao2_callback() is a generic function that applies cb_fn() to all objects in a container,...
Definition: astobj2.h:1693
@ OBJ_MULTIPLE
Definition: astobj2.h:1049
static int object_stale_callback(void *obj, void *arg, int flags)

References ao2_callback, cache, OBJ_MULTIPLE, OBJ_NODATA, OBJ_NOLOCK, and object_stale_callback().

Referenced by sorcery_memory_cache_ami_stale(), and sorcery_memory_cache_stale().

◆ mark_object_as_stale_in_cache()

static int mark_object_as_stale_in_cache ( struct sorcery_memory_cache cache,
const char *  id 
)
static

Definition at line 605 of file res_sorcery_memory_cache.c.

606{
607 struct sorcery_memory_cached_object *cached;
608
609 cached = ao2_find(cache->objects, id, OBJ_SEARCH_KEY | OBJ_NOLOCK);
610 if (!cached) {
611 return -1;
612 }
613
614 ast_assert(!strcmp(ast_sorcery_object_get_id(cached->object), id));
615
616 object_stale_callback(cached, cache, 0);
617 ao2_ref(cached, -1);
618
619 return 0;
620}
@ OBJ_SEARCH_KEY
The arg parameter is a search key, but is not an object.
Definition: astobj2.h:1101
#define ast_assert(a)
Definition: utils.h:739

References ao2_find, ao2_ref, ast_assert, ast_sorcery_object_get_id(), cache, OBJ_NOLOCK, OBJ_SEARCH_KEY, sorcery_memory_cached_object::object, and object_stale_callback().

Referenced by sorcery_memory_cache_ami_stale_object(), and sorcery_memory_cache_stale().

◆ memory_cache_full_update()

static void memory_cache_full_update ( const struct ast_sorcery sorcery,
const char *  type,
struct sorcery_memory_cache cache 
)
static

Definition at line 1077 of file res_sorcery_memory_cache.c.

1078{
1079 if (!cache->full_backend_cache) {
1080 return;
1081 }
1082
1083 ao2_wrlock(cache->objects);
1084 if (!ao2_container_count(cache->objects)) {
1086 }
1087 ao2_unlock(cache->objects);
1088}
#define ao2_wrlock(a)
Definition: astobj2.h:719
int ao2_container_count(struct ao2_container *c)
Returns the number of elements in a container.
static const char type[]
Definition: chan_ooh323.c:109
static struct ast_sorcery * sorcery
static void memory_cache_populate(const struct ast_sorcery *sorcery, const char *type, struct sorcery_memory_cache *cache)

References ao2_container_count(), ao2_unlock, ao2_wrlock, cache, memory_cache_populate(), sorcery, and type.

Referenced by sorcery_memory_cache_retrieve_id(), sorcery_memory_cache_retrieve_multiple(), sorcery_memory_cache_retrieve_prefix(), and sorcery_memory_cache_retrieve_regex().

◆ memory_cache_populate()

static void memory_cache_populate ( const struct ast_sorcery sorcery,
const char *  type,
struct sorcery_memory_cache cache 
)
static

Definition at line 1034 of file res_sorcery_memory_cache.c.

1035{
1036 struct ao2_container *backend_objects;
1037
1041
1042 if (!backend_objects) {
1043 /* This will occur in off-nominal memory allocation failure scenarios */
1044 return;
1045 }
1046
1047 if (cache->maximum_objects && ao2_container_count(backend_objects) >= cache->maximum_objects) {
1048 ast_log(LOG_ERROR, "The backend contains %d objects while the sorcery memory cache '%s' is explicitly configured to only allow %d\n",
1049 ao2_container_count(backend_objects), cache->name, cache->maximum_objects);
1050 return;
1051 }
1052
1054 (struct ast_sorcery*)sorcery, cache);
1055
1056 /* If the number of cached objects does not match the number of backend objects we encountered a memory allocation
1057 * failure and the cache is incomplete, so drop everything and fall back to querying the backend directly
1058 * as it may be able to provide what is wanted.
1059 */
1060 if (ao2_container_count(cache->objects) != ao2_container_count(backend_objects)) {
1061 ast_log(LOG_WARNING, "The backend contains %d objects while only %d could be added to sorcery memory cache '%s'\n",
1062 ao2_container_count(backend_objects), ao2_container_count(cache->objects), cache->name);
1064 }
1065
1066 ao2_ref(backend_objects, -1);
1067}
#define ao2_callback_data(container, flags, cb_fn, arg, data)
Definition: astobj2.h:1723
#define LOG_WARNING
static void end_passthru_update(void)
static void start_passthru_update(void)
static int object_add_to_cache_callback(void *obj, void *arg, void *data, int flags)
static void remove_all_from_cache(struct sorcery_memory_cache *cache)
@ AST_RETRIEVE_FLAG_MULTIPLE
Return all matching objects.
Definition: sorcery.h:120
@ AST_RETRIEVE_FLAG_ALL
Perform no matching, return all objects.
Definition: sorcery.h:123
void * ast_sorcery_retrieve_by_fields(const struct ast_sorcery *sorcery, const char *type, unsigned int flags, struct ast_variable *fields)
Retrieve an object or multiple objects using specific fields.
Definition: sorcery.c:1897
Generic container type.
Full structure for sorcery.
Definition: sorcery.c:230

References ao2_callback_data, ao2_container_count(), ao2_ref, ast_log, AST_RETRIEVE_FLAG_ALL, AST_RETRIEVE_FLAG_MULTIPLE, ast_sorcery_retrieve_by_fields(), cache, end_passthru_update(), LOG_ERROR, LOG_WARNING, NULL, OBJ_MULTIPLE, OBJ_NODATA, OBJ_NOLOCK, object_add_to_cache_callback(), remove_all_from_cache(), sorcery, start_passthru_update(), and type.

Referenced by memory_cache_full_update(), sorcery_memory_cache_ami_populate(), and sorcery_memory_cache_populate().

◆ memory_cache_stale_check()

static void memory_cache_stale_check ( const struct ast_sorcery sorcery,
struct sorcery_memory_cache cache 
)
static

Definition at line 1191 of file res_sorcery_memory_cache.c.

1192{
1193 struct sorcery_memory_cached_object *cached;
1194
1195 ao2_rdlock(cache->objects);
1196 cached = ao2_bump(ast_heap_peek(cache->object_heap, 1));
1197 ao2_unlock(cache->objects);
1198
1199 if (!cached) {
1200 return;
1201 }
1202
1204 ao2_ref(cached, -1);
1205}
#define ao2_rdlock(a)
Definition: astobj2.h:718
#define ao2_bump(obj)
Bump refcount on an AO2 object by one, returning the object.
Definition: astobj2.h:480
static void memory_cache_stale_check_object(const struct ast_sorcery *sorcery, struct sorcery_memory_cache *cache, struct sorcery_memory_cached_object *cached)

References ao2_bump, ao2_rdlock, ao2_ref, ao2_unlock, ast_heap_peek(), cache, memory_cache_stale_check_object(), and sorcery.

Referenced by sorcery_memory_cache_retrieve_multiple(), sorcery_memory_cache_retrieve_prefix(), and sorcery_memory_cache_retrieve_regex().

◆ memory_cache_stale_check_object()

static void memory_cache_stale_check_object ( const struct ast_sorcery sorcery,
struct sorcery_memory_cache cache,
struct sorcery_memory_cached_object cached 
)
static

Definition at line 1158 of file res_sorcery_memory_cache.c.

1160{
1161 struct timeval elapsed;
1162
1163 if (!cache->object_lifetime_stale) {
1164 return;
1165 }
1166
1167 /* For a full cache as every object has the same expiration/staleness we can do the same check */
1168 elapsed = ast_tvsub(ast_tvnow(), cached->created);
1169
1170 if (elapsed.tv_sec < cache->object_lifetime_stale) {
1171 return;
1172 }
1173
1174 if (cache->full_backend_cache) {
1176 } else {
1178 }
1179
1180}
static void memory_cache_stale_update_object(const struct ast_sorcery *sorcery, struct sorcery_memory_cache *cache, struct sorcery_memory_cached_object *cached)
static void memory_cache_stale_update_full(const struct ast_sorcery *sorcery, struct sorcery_memory_cache *cache, const char *type)
const char * ast_sorcery_object_get_type(const void *object)
Get the type of a sorcery object.
Definition: sorcery.c:2329
struct timeval ast_tvsub(struct timeval a, struct timeval b)
Returns the difference of two timevals a - b.
Definition: extconf.c:2297

References ast_sorcery_object_get_type(), ast_tvnow(), ast_tvsub(), cache, sorcery_memory_cached_object::created, memory_cache_stale_update_full(), memory_cache_stale_update_object(), sorcery_memory_cached_object::object, and sorcery.

Referenced by memory_cache_stale_check(), sorcery_memory_cache_retrieve_fields(), and sorcery_memory_cache_retrieve_id().

◆ memory_cache_stale_update_full()

static void memory_cache_stale_update_full ( const struct ast_sorcery sorcery,
struct sorcery_memory_cache cache,
const char *  type 
)
static

Definition at line 1098 of file res_sorcery_memory_cache.c.

1100{
1101 ao2_wrlock(cache->objects);
1102 if (cache->stale_update_sched_id == -1) {
1104
1106 cache, type);
1107 if (task_data) {
1108 cache->stale_update_sched_id = ast_sched_add(sched, 1,
1110 }
1111 if (cache->stale_update_sched_id < 0) {
1113 }
1114 }
1115 ao2_unlock(cache->objects);
1116}
#define ao2_cleanup(obj)
Definition: astobj2.h:1934
static struct stale_cache_update_task_data * stale_cache_update_task_data_alloc(struct ast_sorcery *sorcery, struct sorcery_memory_cache *cache, const char *type)
static int stale_cache_update(const void *data)
int ast_sched_add(struct ast_sched_context *con, int when, ast_sched_cb callback, const void *data) attribute_warn_unused_result
Adds a scheduled event.
Definition: sched.c:567
userdata associated with baseline taskprocessor test

References ao2_cleanup, ao2_unlock, ao2_wrlock, ast_sched_add(), cache, sorcery, stale_cache_update(), stale_cache_update_task_data_alloc(), and type.

Referenced by memory_cache_stale_check_object().

◆ memory_cache_stale_update_object()

static void memory_cache_stale_update_object ( const struct ast_sorcery sorcery,
struct sorcery_memory_cache cache,
struct sorcery_memory_cached_object cached 
)
static

Definition at line 1126 of file res_sorcery_memory_cache.c.

1128{
1129 ao2_lock(cached);
1130 if (cached->stale_update_sched_id == -1) {
1132
1134 cache, ast_sorcery_object_get_type(cached->object), cached->object);
1135 if (task_data) {
1136 ast_debug(1, "Cached sorcery object type '%s' ID '%s' is stale. Refreshing\n",
1140 }
1141 if (cached->stale_update_sched_id < 0) {
1143 ast_log(LOG_ERROR, "Unable to update stale cached object type '%s', ID '%s'.\n",
1145 }
1146 }
1147 ao2_unlock(cached);
1148}
#define ao2_lock(a)
Definition: astobj2.h:717
#define ast_debug(level,...)
Log a DEBUG message.
static struct stale_update_task_data * stale_update_task_data_alloc(struct ast_sorcery *sorcery, struct sorcery_memory_cache *cache, const char *type, void *object)
static int stale_item_update(const void *data)
int stale_update_sched_id
scheduler id of stale update task

References ao2_cleanup, ao2_lock, ao2_unlock, ast_debug, ast_log, ast_sched_add(), ast_sorcery_object_get_id(), ast_sorcery_object_get_type(), cache, LOG_ERROR, sorcery_memory_cached_object::object, sorcery, stale_item_update(), sorcery_memory_cached_object::stale_update_sched_id, and stale_update_task_data_alloc().

Referenced by memory_cache_stale_check_object(), sorcery_memory_cache_ami_stale_object(), and sorcery_memory_cache_stale().

◆ object_add_to_cache_callback()

static int object_add_to_cache_callback ( void *  obj,
void *  arg,
void *  data,
int  flags 
)
static

Definition at line 855 of file res_sorcery_memory_cache.c.

856{
857 struct sorcery_memory_cache *cache = data;
858 struct sorcery_memory_cached_object *cached;
859
860 cached = sorcery_memory_cached_object_alloc(arg, cache, obj);
861 if (!cached) {
862 return CMP_STOP;
863 }
864
865 add_to_cache(cache, cached);
866 ao2_ref(cached, -1);
867
868 return 0;
869}
@ CMP_STOP
Definition: astobj2.h:1028
static struct sorcery_memory_cached_object * sorcery_memory_cached_object_alloc(const struct ast_sorcery *sorcery, const struct sorcery_memory_cache *cache, void *object)
static int add_to_cache(struct sorcery_memory_cache *cache, struct sorcery_memory_cached_object *cached_object)

References add_to_cache(), ao2_ref, cache, CMP_STOP, and sorcery_memory_cached_object_alloc().

Referenced by memory_cache_populate(), and stale_cache_update().

◆ object_stale_callback()

static int object_stale_callback ( void *  obj,
void *  arg,
int  flags 
)
static

Definition at line 577 of file res_sorcery_memory_cache.c.

578{
579 struct sorcery_memory_cached_object *cached = obj;
580 struct sorcery_memory_cache *cache = arg;
581
582 /* Since our granularity is seconds it's possible for something to retrieve us within a window
583 * where we wouldn't be treated as stale. To ensure that doesn't happen we use the configured stale
584 * time plus a second.
585 */
586 cached->created = ast_tvsub(cached->created, ast_samp2tv(cache->object_lifetime_stale + 1, 1));
587
588 return CMP_MATCH;
589}
@ CMP_MATCH
Definition: astobj2.h:1027

References ast_samp2tv(), ast_tvsub(), cache, CMP_MATCH, and sorcery_memory_cached_object::created.

Referenced by mark_all_as_stale_in_cache(), and mark_object_as_stale_in_cache().

◆ remove_all_from_cache()

static void remove_all_from_cache ( struct sorcery_memory_cache cache)
static

Definition at line 554 of file res_sorcery_memory_cache.c.

555{
556 while (ast_heap_pop(cache->object_heap)) {
557 }
558
560 NULL, NULL);
561
562 cache->del_expire = 1;
563 AST_SCHED_DEL_UNREF(sched, cache->expire_id, ao2_ref(cache, -1));
564 cache->del_expire = 0;
565}
void * ast_heap_pop(struct ast_heap *h)
Pop the max element off of the heap.
Definition: heap.c:262
#define AST_SCHED_DEL_UNREF(sched, id, refcall)
schedule task to get deleted and call unref function
Definition: sched.h:82

References ao2_callback, ao2_ref, ast_heap_pop(), AST_SCHED_DEL_UNREF, cache, NULL, OBJ_MULTIPLE, OBJ_NODATA, OBJ_NOLOCK, and OBJ_UNLINK.

Referenced by memory_cache_populate(), sorcery_memory_cache_ami_expire(), sorcery_memory_cache_ami_populate(), sorcery_memory_cache_close(), sorcery_memory_cache_expire(), sorcery_memory_cache_populate(), sorcery_memory_cache_reload(), and stale_cache_update().

◆ remove_from_cache()

static int remove_from_cache ( struct sorcery_memory_cache cache,
const char *  id,
int  reschedule 
)
static

Definition at line 465 of file res_sorcery_memory_cache.c.

466{
467 struct sorcery_memory_cached_object *hash_object;
468 struct sorcery_memory_cached_object *oldest_object;
469 struct sorcery_memory_cached_object *heap_object;
470
471 hash_object = ao2_find(cache->objects, id, OBJ_SEARCH_KEY | OBJ_UNLINK | OBJ_NOLOCK);
472 if (!hash_object) {
473 return -1;
474 }
475
476 ast_assert(!strcmp(ast_sorcery_object_get_id(hash_object->object), id));
477
478 oldest_object = ast_heap_peek(cache->object_heap, 1);
479 heap_object = ast_heap_remove(cache->object_heap, hash_object);
480
481 ast_assert(heap_object == hash_object);
482
483 ao2_ref(hash_object, -1);
484
485 if (reschedule && (oldest_object == heap_object)) {
487 }
488
489 return 0;
490}
void * ast_heap_remove(struct ast_heap *h, void *elm)
Remove a specific element from a heap.
Definition: heap.c:251

References ao2_find, ao2_ref, ast_assert, ast_heap_peek(), ast_heap_remove(), ast_sorcery_object_get_id(), cache, OBJ_NOLOCK, OBJ_SEARCH_KEY, OBJ_UNLINK, sorcery_memory_cached_object::object, and schedule_cache_expiration().

Referenced by expire_objects_from_cache(), sorcery_memory_cache_ami_expire_object(), sorcery_memory_cache_create(), sorcery_memory_cache_delete(), and sorcery_memory_cache_expire().

◆ remove_oldest_from_cache()

static int remove_oldest_from_cache ( struct sorcery_memory_cache cache)
static

Definition at line 695 of file res_sorcery_memory_cache.c.

696{
697 struct sorcery_memory_cached_object *heap_old_object;
698 struct sorcery_memory_cached_object *hash_old_object;
699
700 heap_old_object = ast_heap_pop(cache->object_heap);
701 if (!heap_old_object) {
702 return -1;
703 }
704 hash_old_object = ao2_find(cache->objects, heap_old_object,
706
707 ast_assert(heap_old_object == hash_old_object);
708
709 ao2_ref(hash_old_object, -1);
710
712
713 return 0;
714}

References ao2_find, ao2_ref, ast_assert, ast_heap_pop(), cache, OBJ_NOLOCK, OBJ_SEARCH_OBJECT, OBJ_UNLINK, and schedule_cache_expiration().

Referenced by sorcery_memory_cache_create().

◆ schedule_cache_expiration()

static int schedule_cache_expiration ( struct sorcery_memory_cache cache)
static

Definition at line 648 of file res_sorcery_memory_cache.c.

649{
650 struct sorcery_memory_cached_object *cached;
651 int expiration = 0;
652
653 if (!cache->object_lifetime_maximum) {
654 return 0;
655 }
656
657 cache->del_expire = 1;
658 AST_SCHED_DEL_UNREF(sched, cache->expire_id, ao2_ref(cache, -1));
659 cache->del_expire = 0;
660
661 cached = ast_heap_peek(cache->object_heap, 1);
662 if (!cached) {
663#ifdef TEST_FRAMEWORK
664 ast_mutex_lock(&cache->lock);
665 cache->cache_completed = 1;
666 ast_cond_signal(&cache->cond);
667 ast_mutex_unlock(&cache->lock);
668#endif
669 return 0;
670 }
671
672 expiration = MAX(ast_tvdiff_ms(ast_tvadd(cached->created, ast_samp2tv(cache->object_lifetime_maximum, 1)), ast_tvnow()),
673 1);
674
676 if (cache->expire_id < 0) {
677 ao2_ref(cache, -1);
678 return -1;
679 }
680
681 return 0;
682}
#define ast_mutex_unlock(a)
Definition: lock.h:190
#define ast_mutex_lock(a)
Definition: lock.h:189
#define ast_cond_signal(cond)
Definition: lock.h:203
static int expire_objects_from_cache(const void *data)
#define MAX(a, b)
Definition: utils.h:233

References ao2_bump, ao2_ref, ast_cond_signal, ast_heap_peek(), ast_mutex_lock, ast_mutex_unlock, ast_samp2tv(), ast_sched_add(), AST_SCHED_DEL_UNREF, ast_tvadd(), ast_tvdiff_ms(), ast_tvnow(), cache, sorcery_memory_cached_object::created, expire_objects_from_cache(), and MAX.

Referenced by add_to_cache(), expire_objects_from_cache(), remove_from_cache(), and remove_oldest_from_cache().

◆ set_passthru_update()

static void set_passthru_update ( uint32_t  value)
static

Definition at line 262 of file res_sorcery_memory_cache.c.

263{
264 uint32_t *passthru_update_thread_id;
265
266 passthru_update_thread_id = ast_threadstorage_get(&passthru_update_id_storage,
267 sizeof(*passthru_update_thread_id));
268 if (!passthru_update_thread_id) {
269 ast_log(LOG_ERROR, "Could not set passthru update ID for sorcery memory cache thread\n");
270 return;
271 }
272
273 *passthru_update_thread_id = value;
274}

References ast_log, ast_threadstorage_get(), LOG_ERROR, passthru_update_id_storage, and value.

Referenced by end_passthru_update(), and start_passthru_update().

◆ sorcery_memory_cache_ami_expire()

static int sorcery_memory_cache_ami_expire ( struct mansession s,
const struct message m 
)
static

Definition at line 2115 of file res_sorcery_memory_cache.c.

2116{
2117 const char *cache_name = astman_get_header(m, "Cache");
2119
2120 if (ast_strlen_zero(cache_name)) {
2121 astman_send_error(s, m, "SorceryMemoryCacheExpire requires that a cache name be provided.\n");
2122 return 0;
2123 }
2124
2125 cache = ao2_find(caches, cache_name, OBJ_SEARCH_KEY);
2126 if (!cache) {
2127 astman_send_error(s, m, "The provided cache does not exist\n");
2128 return 0;
2129 }
2130
2131 ao2_wrlock(cache->objects);
2133 ao2_unlock(cache->objects);
2134
2135 ao2_ref(cache, -1);
2136
2137 astman_send_ack(s, m, "All objects were expired from the cache\n");
2138
2139 return 0;
2140}
void astman_send_error(struct mansession *s, const struct message *m, char *error)
Send error in manager transaction.
Definition: manager.c:3381
void astman_send_ack(struct mansession *s, const struct message *m, char *msg)
Send ack in manager transaction.
Definition: manager.c:3413
const char * astman_get_header(const struct message *m, char *var)
Get header from manager transaction.
Definition: manager.c:3042

References ao2_find, ao2_ref, ao2_unlock, ao2_wrlock, ast_strlen_zero(), astman_get_header(), astman_send_ack(), astman_send_error(), cache, caches, OBJ_SEARCH_KEY, and remove_all_from_cache().

Referenced by load_module().

◆ sorcery_memory_cache_ami_expire_object()

static int sorcery_memory_cache_ami_expire_object ( struct mansession s,
const struct message m 
)
static

Definition at line 2069 of file res_sorcery_memory_cache.c.

2070{
2071 const char *cache_name = astman_get_header(m, "Cache");
2072 const char *object_name = astman_get_header(m, "Object");
2074 int res;
2075
2076 if (ast_strlen_zero(cache_name)) {
2077 astman_send_error(s, m, "SorceryMemoryCacheExpireObject requires that a cache name be provided.\n");
2078 return 0;
2079 } else if (ast_strlen_zero(object_name)) {
2080 astman_send_error(s, m, "SorceryMemoryCacheExpireObject requires that an object name be provided\n");
2081 return 0;
2082 }
2083
2084 cache = ao2_find(caches, cache_name, OBJ_SEARCH_KEY);
2085 if (!cache) {
2086 astman_send_error(s, m, "The provided cache does not exist\n");
2087 return 0;
2088 }
2089
2090 ao2_wrlock(cache->objects);
2091 if (cache->full_backend_cache) {
2092 res = 1;
2093 } else {
2094 res = remove_from_cache(cache, object_name, 1);
2095 }
2096 ao2_unlock(cache->objects);
2097
2098 ao2_ref(cache, -1);
2099
2100 if (res == 1) {
2101 astman_send_error(s, m, "Due to full backend caching per-object expiration is not available, consider using SorceryMemoryCachePopulate or SorceryMemoryCacheExpire instead\n");
2102 } else if (!res) {
2103 astman_send_ack(s, m, "The provided object was expired from the cache\n");
2104 } else {
2105 astman_send_error(s, m, "The provided object could not be expired from the cache\n");
2106 }
2107
2108 return 0;
2109}

References ao2_find, ao2_ref, ao2_unlock, ao2_wrlock, ast_strlen_zero(), astman_get_header(), astman_send_ack(), astman_send_error(), cache, caches, OBJ_SEARCH_KEY, and remove_from_cache().

Referenced by load_module().

◆ sorcery_memory_cache_ami_populate()

static int sorcery_memory_cache_ami_populate ( struct mansession s,
const struct message m 
)
static

Definition at line 2230 of file res_sorcery_memory_cache.c.

2231{
2232 const char *cache_name = astman_get_header(m, "Cache");
2234
2235 if (ast_strlen_zero(cache_name)) {
2236 astman_send_error(s, m, "SorceryMemoryCachePopulate requires that a cache name be provided.\n");
2237 return 0;
2238 }
2239
2240 cache = ao2_find(caches, cache_name, OBJ_SEARCH_KEY);
2241 if (!cache) {
2242 astman_send_error(s, m, "The provided cache does not exist\n");
2243 return 0;
2244 }
2245
2246 if (!cache->full_backend_cache) {
2247 astman_send_error(s, m, "The provided cache does not have full backend caching enabled\n");
2248 ao2_ref(cache, -1);
2249 return 0;
2250 }
2251
2252 ao2_wrlock(cache->objects);
2253 if (!cache->sorcery) {
2254 astman_send_error(s, m, "The provided cache is no longer active\n");
2255 ao2_unlock(cache->objects);
2256 ao2_ref(cache, -1);
2257 return 0;
2258 }
2259
2261 memory_cache_populate(cache->sorcery, cache->object_type, cache);
2262
2263 ao2_unlock(cache->objects);
2264
2265 ao2_ref(cache, -1);
2266
2267 astman_send_ack(s, m, "Cache has been expired and populated\n");
2268
2269 return 0;
2270}

References ao2_find, ao2_ref, ao2_unlock, ao2_wrlock, ast_strlen_zero(), astman_get_header(), astman_send_ack(), astman_send_error(), cache, caches, memory_cache_populate(), OBJ_SEARCH_KEY, and remove_all_from_cache().

Referenced by load_module().

◆ sorcery_memory_cache_ami_stale()

static int sorcery_memory_cache_ami_stale ( struct mansession s,
const struct message m 
)
static

Definition at line 2199 of file res_sorcery_memory_cache.c.

2200{
2201 const char *cache_name = astman_get_header(m, "Cache");
2203
2204 if (ast_strlen_zero(cache_name)) {
2205 astman_send_error(s, m, "SorceryMemoryCacheStale requires that a cache name be provided.\n");
2206 return 0;
2207 }
2208
2209 cache = ao2_find(caches, cache_name, OBJ_SEARCH_KEY);
2210 if (!cache) {
2211 astman_send_error(s, m, "The provided cache does not exist\n");
2212 return 0;
2213 }
2214
2215 ao2_rdlock(cache->objects);
2217 ao2_unlock(cache->objects);
2218
2219 ao2_ref(cache, -1);
2220
2221 astman_send_ack(s, m, "All objects were marked as stale in the cache\n");
2222
2223 return 0;
2224}
static void mark_all_as_stale_in_cache(struct sorcery_memory_cache *cache)

References ao2_find, ao2_rdlock, ao2_ref, ao2_unlock, ast_strlen_zero(), astman_get_header(), astman_send_ack(), astman_send_error(), cache, caches, mark_all_as_stale_in_cache(), and OBJ_SEARCH_KEY.

Referenced by load_module().

◆ sorcery_memory_cache_ami_stale_object()

static int sorcery_memory_cache_ami_stale_object ( struct mansession s,
const struct message m 
)
static

Definition at line 2146 of file res_sorcery_memory_cache.c.

2147{
2148 const char *cache_name = astman_get_header(m, "Cache");
2149 const char *object_name = astman_get_header(m, "Object");
2150 const char *reload = astman_get_header(m, "Reload");
2152 int res;
2153
2154 if (ast_strlen_zero(cache_name)) {
2155 astman_send_error(s, m, "SorceryMemoryCacheStaleObject requires that a cache name be provided.\n");
2156 return 0;
2157 } else if (ast_strlen_zero(object_name)) {
2158 astman_send_error(s, m, "SorceryMemoryCacheStaleObject requires that an object name be provided\n");
2159 return 0;
2160 }
2161
2162 cache = ao2_find(caches, cache_name, OBJ_SEARCH_KEY);
2163 if (!cache) {
2164 astman_send_error(s, m, "The provided cache does not exist\n");
2165 return 0;
2166 }
2167
2168 ao2_rdlock(cache->objects);
2169
2170 res = mark_object_as_stale_in_cache(cache, object_name);
2171
2172 if (ast_true(reload)) {
2173 struct sorcery_memory_cached_object *cached;
2174
2175 cached = ao2_find(cache->objects, object_name, OBJ_SEARCH_KEY | OBJ_NOLOCK);
2176 if (cached) {
2177 memory_cache_stale_update_object(cache->sorcery, cache, cached);
2178 ao2_ref(cached, -1);
2179 }
2180 }
2181
2182 ao2_unlock(cache->objects);
2183
2184 ao2_ref(cache, -1);
2185
2186 if (!res) {
2187 astman_send_ack(s, m, "The provided object was marked as stale in the cache\n");
2188 } else {
2189 astman_send_error(s, m, "The provided object could not be marked as stale in the cache\n");
2190 }
2191
2192 return 0;
2193}
static int reload(void)
static int mark_object_as_stale_in_cache(struct sorcery_memory_cache *cache, const char *id)
int attribute_pure ast_true(const char *val)
Make sure something is true. Determine if a string containing a boolean value is "true"....
Definition: utils.c:2199

References ao2_find, ao2_rdlock, ao2_ref, ao2_unlock, ast_strlen_zero(), ast_true(), astman_get_header(), astman_send_ack(), astman_send_error(), cache, caches, mark_object_as_stale_in_cache(), memory_cache_stale_update_object(), OBJ_NOLOCK, OBJ_SEARCH_KEY, and reload().

Referenced by load_module().

◆ sorcery_memory_cache_close()

static void sorcery_memory_cache_close ( void *  data)
static

Definition at line 1620 of file res_sorcery_memory_cache.c.

1621{
1622 struct sorcery_memory_cache *cache = data;
1623
1624 /* This can occur if a cache is created but never loaded */
1625 if (!ast_strlen_zero(cache->name)) {
1627 }
1628
1629 if (cache->object_lifetime_maximum) {
1630 /* If object lifetime support is enabled we need to explicitly drop all cached objects here
1631 * and stop the scheduled task. Failure to do so could potentially keep the cache around for
1632 * a prolonged period of time.
1633 */
1634 ao2_wrlock(cache->objects);
1636 ao2_unlock(cache->objects);
1637 }
1638
1639 if (cache->full_backend_cache) {
1640 ao2_wrlock(cache->objects);
1641 cache->sorcery = NULL;
1642 ao2_unlock(cache->objects);
1643 }
1644
1645 ao2_ref(cache, -1);
1646}
#define ao2_unlink(container, obj)
Remove an object from a container.
Definition: astobj2.h:1578

References ao2_ref, ao2_unlink, ao2_unlock, ao2_wrlock, ast_strlen_zero(), cache, caches, NULL, and remove_all_from_cache().

◆ sorcery_memory_cache_cmp()

static int sorcery_memory_cache_cmp ( void *  obj,
void *  arg,
int  flags 
)
static

Definition at line 329 of file res_sorcery_memory_cache.c.

330{
331 const struct sorcery_memory_cache *left = obj;
332 const struct sorcery_memory_cache *right = arg;
333 const char *right_name = arg;
334 int cmp;
335
336 switch (flags & OBJ_SEARCH_MASK) {
337 default:
339 right_name = right->name;
340 /* Fall through */
341 case OBJ_SEARCH_KEY:
342 cmp = strcmp(left->name, right_name);
343 break;
345 cmp = strncmp(left->name, right_name, strlen(right_name));
346 break;
347 }
348 return cmp ? 0 : CMP_MATCH;
349}
@ OBJ_SEARCH_PARTIAL_KEY
The arg parameter is a partial search key similar to OBJ_SEARCH_KEY.
Definition: astobj2.h:1116
@ OBJ_SEARCH_MASK
Search option field mask.
Definition: astobj2.h:1072
char * name
The name of the memory cache.

References CMP_MATCH, sorcery_memory_cache::name, OBJ_SEARCH_KEY, OBJ_SEARCH_MASK, OBJ_SEARCH_OBJECT, and OBJ_SEARCH_PARTIAL_KEY.

Referenced by load_module().

◆ sorcery_memory_cache_complete_name()

static char * sorcery_memory_cache_complete_name ( const char *  word,
int  state 
)
static

Definition at line 1652 of file res_sorcery_memory_cache.c.

1653{
1655 struct ao2_iterator it_caches;
1656 int wordlen = strlen(word);
1657 int which = 0;
1658 char *result = NULL;
1659
1660 it_caches = ao2_iterator_init(caches, 0);
1661 while ((cache = ao2_iterator_next(&it_caches))) {
1662 if (!strncasecmp(word, cache->name, wordlen)
1663 && ++which > state) {
1664 result = ast_strdup(cache->name);
1665 }
1666 ao2_ref(cache, -1);
1667 if (result) {
1668 break;
1669 }
1670 }
1671 ao2_iterator_destroy(&it_caches);
1672 return result;
1673}
#define ast_strdup(str)
A wrapper for strdup()
Definition: astmm.h:241
#define ao2_iterator_next(iter)
Definition: astobj2.h:1911
struct ao2_iterator ao2_iterator_init(struct ao2_container *c, int flags) attribute_warn_unused_result
Create an iterator for a container.
void ao2_iterator_destroy(struct ao2_iterator *iter)
Destroy a container iterator.
short word
When we need to walk through a container, we use an ao2_iterator to keep track of the current positio...
Definition: astobj2.h:1821

References ao2_iterator_destroy(), ao2_iterator_init(), ao2_iterator_next, ao2_ref, ast_strdup, cache, caches, NULL, and result.

Referenced by sorcery_memory_cache_dump(), sorcery_memory_cache_expire(), sorcery_memory_cache_populate(), sorcery_memory_cache_show(), and sorcery_memory_cache_stale().

◆ sorcery_memory_cache_complete_object_name()

static char * sorcery_memory_cache_complete_object_name ( const char *  cache_name,
const char *  word,
int  state 
)
static

Definition at line 1825 of file res_sorcery_memory_cache.c.

1826{
1828 struct sorcery_memory_cached_object *cached;
1829 struct ao2_iterator it_cached;
1830 int wordlen = strlen(word);
1831 int which = 0;
1832 char *result = NULL;
1833
1834 cache = ao2_find(caches, cache_name, OBJ_SEARCH_KEY);
1835 if (!cache) {
1836 return NULL;
1837 }
1838
1839 it_cached = ao2_iterator_init(cache->objects, 0);
1840 while ((cached = ao2_iterator_next(&it_cached))) {
1841 if (!strncasecmp(word, ast_sorcery_object_get_id(cached->object), wordlen)
1842 && ++which > state) {
1844 }
1845 ao2_ref(cached, -1);
1846 if (result) {
1847 break;
1848 }
1849 }
1850 ao2_iterator_destroy(&it_cached);
1851
1852 ao2_ref(cache, -1);
1853
1854 return result;
1855}

References ao2_find, ao2_iterator_destroy(), ao2_iterator_init(), ao2_iterator_next, ao2_ref, ast_sorcery_object_get_id(), ast_strdup, cache, caches, NULL, OBJ_SEARCH_KEY, sorcery_memory_cached_object::object, and result.

Referenced by sorcery_memory_cache_expire(), and sorcery_memory_cache_stale().

◆ sorcery_memory_cache_create()

static int sorcery_memory_cache_create ( const struct ast_sorcery sorcery,
void *  data,
void *  object 
)
static

Definition at line 805 of file res_sorcery_memory_cache.c.

806{
807 struct sorcery_memory_cache *cache = data;
808 struct sorcery_memory_cached_object *cached;
809
811 if (!cached) {
812 return -1;
813 }
814
815 /* As there is no guarantee that this won't be called by multiple threads wanting to cache
816 * the same object we remove any old ones, which turns this into a create/update function
817 * in reality. As well since there's no guarantee that the object in the cache is the same
818 * one here we remove any old objects using the object identifier.
819 */
820
821 ao2_wrlock(cache->objects);
823 if (cache->maximum_objects && ao2_container_count(cache->objects) >= cache->maximum_objects) {
825 ast_log(LOG_ERROR, "Unable to make room in cache for sorcery object '%s'.\n",
827 ao2_unlock(cache->objects);
828 ao2_ref(cached, -1);
829 return -1;
830 }
831 ast_assert(ao2_container_count(cache->objects) != cache->maximum_objects);
832 }
833 if (add_to_cache(cache, cached)) {
834 ast_log(LOG_ERROR, "Unable to add object '%s' to the cache\n",
836 ao2_unlock(cache->objects);
837 ao2_ref(cached, -1);
838 return -1;
839 }
840 ao2_unlock(cache->objects);
841
842 ao2_ref(cached, -1);
843 return 0;
844}
static int remove_oldest_from_cache(struct sorcery_memory_cache *cache)

References add_to_cache(), ao2_container_count(), ao2_ref, ao2_unlock, ao2_wrlock, ast_assert, ast_log, ast_sorcery_object_get_id(), cache, LOG_ERROR, remove_from_cache(), remove_oldest_from_cache(), sorcery, and sorcery_memory_cached_object_alloc().

Referenced by stale_item_update().

◆ sorcery_memory_cache_delete()

static int sorcery_memory_cache_delete ( const struct ast_sorcery sorcery,
void *  data,
void *  object 
)
static

Definition at line 1598 of file res_sorcery_memory_cache.c.

1599{
1600 struct sorcery_memory_cache *cache = data;
1601 int res;
1602
1603 ao2_wrlock(cache->objects);
1605 ao2_unlock(cache->objects);
1606
1607 if (res) {
1608 ast_debug(1, "Unable to delete object '%s' from sorcery cache\n", ast_sorcery_object_get_id(object));
1609 }
1610
1611 return res;
1612}

References ao2_unlock, ao2_wrlock, ast_debug, ast_sorcery_object_get_id(), cache, and remove_from_cache().

Referenced by stale_item_update().

◆ sorcery_memory_cache_destructor()

static void sorcery_memory_cache_destructor ( void *  obj)
static

Definition at line 422 of file res_sorcery_memory_cache.c.

423{
424 struct sorcery_memory_cache *cache = obj;
425
426 ast_free(cache->name);
427 if (cache->object_heap) {
428 ast_heap_destroy(cache->object_heap);
429 }
430 ao2_cleanup(cache->objects);
431 ast_free(cache->object_type);
432}
#define ast_free(a)
Definition: astmm.h:180
struct ast_heap * ast_heap_destroy(struct ast_heap *h)
Destroy a max heap.
Definition: heap.c:146

References ao2_cleanup, ast_free, ast_heap_destroy(), and cache.

Referenced by sorcery_memory_cache_open().

◆ sorcery_memory_cache_dump()

static char * sorcery_memory_cache_dump ( struct ast_cli_entry e,
int  cmd,
struct ast_cli_args a 
)
static

Definition at line 1768 of file res_sorcery_memory_cache.c.

1769{
1770#define FORMAT "%-25.25s %-15.15s %-15.15s \n"
1772 struct print_object_details details;
1773
1774 switch (cmd) {
1775 case CLI_INIT:
1776 e->command = "sorcery memory cache dump";
1777 e->usage =
1778 "Usage: sorcery memory cache dump <name>\n"
1779 " Dump a list of the objects within the cache, listed by object identifier.\n";
1780 return NULL;
1781 case CLI_GENERATE:
1782 if (a->pos == 4) {
1783 return sorcery_memory_cache_complete_name(a->word, a->n);
1784 } else {
1785 return NULL;
1786 }
1787 }
1788
1789 if (a->argc != 5) {
1790 return CLI_SHOWUSAGE;
1791 }
1792
1793 cache = ao2_find(caches, a->argv[4], OBJ_SEARCH_KEY);
1794 if (!cache) {
1795 ast_cli(a->fd, "Specified sorcery memory cache '%s' does not exist\n", a->argv[4]);
1796 return CLI_FAILURE;
1797 }
1798
1799 details.cache = cache;
1800 details.a = a;
1801
1802 ast_cli(a->fd, "Dumping sorcery memory cache '%s':\n", cache->name);
1803 if (!cache->object_lifetime_stale) {
1804 ast_cli(a->fd, " * Staleness is not enabled - objects will not go stale\n");
1805 }
1806 if (!cache->object_lifetime_maximum) {
1807 ast_cli(a->fd, " * Object lifetime is not enabled - objects will not expire\n");
1808 }
1809 ast_cli(a->fd, FORMAT, "Object Name", "Stale In", "Expires In");
1810 ast_cli(a->fd, FORMAT, "-------------------------", "---------------", "---------------");
1812 ast_cli(a->fd, FORMAT, "-------------------------", "---------------", "---------------");
1813 ast_cli(a->fd, "Total number of objects cached: %d\n", ao2_container_count(cache->objects));
1814
1815 ao2_ref(cache, -1);
1816
1817 return CLI_SUCCESS;
1818#undef FORMAT
1819}
#define CLI_SHOWUSAGE
Definition: cli.h:45
#define CLI_SUCCESS
Definition: cli.h:44
void ast_cli(int fd, const char *fmt,...)
Definition: clicompat.c:6
@ CLI_INIT
Definition: cli.h:152
@ CLI_GENERATE
Definition: cli.h:153
#define CLI_FAILURE
Definition: cli.h:46
static int sorcery_memory_cache_print_object(void *obj, void *arg, int flags)
#define FORMAT
static char * sorcery_memory_cache_complete_name(const char *word, int state)
char * command
Definition: cli.h:186
const char * usage
Definition: cli.h:177
Structure used to pass data for printing cached object information.

References print_object_details::a, a, ao2_callback, ao2_container_count(), ao2_find, ao2_ref, ast_cli(), cache, print_object_details::cache, caches, CLI_FAILURE, CLI_GENERATE, CLI_INIT, CLI_SHOWUSAGE, CLI_SUCCESS, ast_cli_entry::command, FORMAT, NULL, OBJ_MULTIPLE, OBJ_NODATA, OBJ_SEARCH_KEY, sorcery_memory_cache_complete_name(), sorcery_memory_cache_print_object(), and ast_cli_entry::usage.

◆ sorcery_memory_cache_expire()

static char * sorcery_memory_cache_expire ( struct ast_cli_entry e,
int  cmd,
struct ast_cli_args a 
)
static

Definition at line 1861 of file res_sorcery_memory_cache.c.

1862{
1864
1865 switch (cmd) {
1866 case CLI_INIT:
1867 e->command = "sorcery memory cache expire";
1868 e->usage =
1869 "Usage: sorcery memory cache expire <cache name> [object name]\n"
1870 " Expire a specific object or ALL objects within a sorcery memory cache.\n";
1871 return NULL;
1872 case CLI_GENERATE:
1873 if (a->pos == 4) {
1874 return sorcery_memory_cache_complete_name(a->word, a->n);
1875 } else if (a->pos == 5) {
1876 return sorcery_memory_cache_complete_object_name(a->argv[4], a->word, a->n);
1877 } else {
1878 return NULL;
1879 }
1880 }
1881
1882 if (a->argc < 5 || a->argc > 6) {
1883 return CLI_SHOWUSAGE;
1884 }
1885
1886 cache = ao2_find(caches, a->argv[4], OBJ_SEARCH_KEY);
1887 if (!cache) {
1888 ast_cli(a->fd, "Specified sorcery memory cache '%s' does not exist\n", a->argv[4]);
1889 return CLI_FAILURE;
1890 }
1891
1892 ao2_wrlock(cache->objects);
1893 if (a->argc == 5) {
1895 ast_cli(a->fd, "All objects have been removed from cache '%s'\n", a->argv[4]);
1896 } else {
1897 if (cache->full_backend_cache) {
1898 ast_cli(a->fd, "Due to full backend caching per-object expiration is not available on cache '%s'\n", a->argv[4]);
1899 } else if (!remove_from_cache(cache, a->argv[5], 1)) {
1900 ast_cli(a->fd, "Successfully expired object '%s' from cache '%s'\n", a->argv[5], a->argv[4]);
1901 } else {
1902 ast_cli(a->fd, "Object '%s' was not expired from cache '%s' as it was not found\n", a->argv[5],
1903 a->argv[4]);
1904 }
1905 }
1906 ao2_unlock(cache->objects);
1907
1908 ao2_ref(cache, -1);
1909
1910 return CLI_SUCCESS;
1911}
static char * sorcery_memory_cache_complete_object_name(const char *cache_name, const char *word, int state)

References a, ao2_find, ao2_ref, ao2_unlock, ao2_wrlock, ast_cli(), cache, caches, CLI_FAILURE, CLI_GENERATE, CLI_INIT, CLI_SHOWUSAGE, CLI_SUCCESS, ast_cli_entry::command, NULL, OBJ_SEARCH_KEY, remove_all_from_cache(), remove_from_cache(), sorcery_memory_cache_complete_name(), sorcery_memory_cache_complete_object_name(), and ast_cli_entry::usage.

◆ sorcery_memory_cache_fields_cmp()

static int sorcery_memory_cache_fields_cmp ( void *  obj,
void *  arg,
int  flags 
)
static

Definition at line 1254 of file res_sorcery_memory_cache.c.

1255{
1256 struct sorcery_memory_cached_object *cached = obj;
1257 const struct sorcery_memory_cache_fields_cmp_params *params = arg;
1259
1260 if (params->regex) {
1261 /* If a regular expression has been provided see if it matches, otherwise move on */
1262 if (!regexec(params->regex, ast_sorcery_object_get_id(cached->object), 0, NULL, 0)) {
1263 ao2_link(params->container, cached->object);
1264 }
1265 return 0;
1266 } else if (params->prefix) {
1267 if (!strncmp(params->prefix, ast_sorcery_object_get_id(cached->object), params->prefix_len)) {
1268 ao2_link(params->container, cached->object);
1269 }
1270 return 0;
1271 } else if (params->fields &&
1272 (!ast_variable_lists_match(cached->objectset, params->fields, 0))) {
1273 /* If we can't turn the object into an object set OR if differences exist between the fields
1274 * passed in and what are present on the object they are not a match.
1275 */
1276 return 0;
1277 }
1278
1279 if (params->container) {
1280 ao2_link(params->container, cached->object);
1281
1282 /* As multiple objects are being returned keep going */
1283 return 0;
1284 } else {
1285 /* Immediately stop and return, we only want a single object */
1286 return CMP_MATCH | CMP_STOP;
1287 }
1288}
#define ao2_link(container, obj)
Add an object to a container.
Definition: astobj2.h:1532
int ast_variable_lists_match(const struct ast_variable *left, const struct ast_variable *right, int exact_match)
Tests 2 variable lists to see if they match.
Definition: main/config.c:861
void ast_variables_destroy(struct ast_variable *var)
Free variable list.
Definition: extconf.c:1262
Structure for variables, used for configurations and for channel variables.
Structure used for fields comparison.
const char * prefix
Prefix for matching object id.
struct ao2_container * container
Optional container to put object into.
const size_t prefix_len
Prefix length in bytes for matching object id.
const struct ast_variable * fields
Pointer to the fields to check.
regex_t * regex
Regular expression for checking object id.
struct ast_variable * objectset
Cached objectset for field and regex retrieval.
#define RAII_VAR(vartype, varname, initval, dtor)
Declare a variable that will call a destructor function when it goes out of scope.
Definition: utils.h:941

References ao2_link, ast_sorcery_object_get_id(), ast_variable_lists_match(), ast_variables_destroy(), CMP_MATCH, CMP_STOP, sorcery_memory_cache_fields_cmp_params::container, sorcery_memory_cache_fields_cmp_params::fields, NULL, sorcery_memory_cached_object::object, sorcery_memory_cached_object::objectset, sorcery_memory_cache_fields_cmp_params::prefix, sorcery_memory_cache_fields_cmp_params::prefix_len, RAII_VAR, and sorcery_memory_cache_fields_cmp_params::regex.

Referenced by sorcery_memory_cache_retrieve_fields(), sorcery_memory_cache_retrieve_multiple(), sorcery_memory_cache_retrieve_prefix(), and sorcery_memory_cache_retrieve_regex().

◆ sorcery_memory_cache_hash()

static int sorcery_memory_cache_hash ( const void *  obj,
int  flags 
)
static

Definition at line 295 of file res_sorcery_memory_cache.c.

296{
297 const struct sorcery_memory_cache *cache = obj;
298 const char *name = obj;
299 int hash;
300
301 switch (flags & OBJ_SEARCH_MASK) {
302 default:
304 name = cache->name;
305 /* Fall through */
306 case OBJ_SEARCH_KEY:
307 hash = ast_str_hash(name);
308 break;
310 /* Should never happen in hash callback. */
311 ast_assert(0);
312 hash = 0;
313 break;
314 }
315 return hash;
316}
static const char name[]
Definition: format_mp3.c:68
static force_inline int attribute_pure ast_str_hash(const char *str)
Compute a hash value on a string.
Definition: strings.h:1259

References ast_assert, ast_str_hash(), cache, name, OBJ_SEARCH_KEY, OBJ_SEARCH_MASK, OBJ_SEARCH_OBJECT, and OBJ_SEARCH_PARTIAL_KEY.

Referenced by load_module().

◆ sorcery_memory_cache_load()

static void sorcery_memory_cache_load ( void *  data,
const struct ast_sorcery sorcery,
const char *  type 
)
static

Definition at line 1436 of file res_sorcery_memory_cache.c.

1437{
1438 struct sorcery_memory_cache *cache = data;
1439
1440 /* If no name was explicitly specified generate one given the sorcery instance and object type */
1441 if (ast_strlen_zero(cache->name)) {
1443 }
1444
1446 ast_debug(1, "Memory cache '%s' associated with sorcery instance '%p' of module '%s' with object type '%s'\n",
1448
1449 cache->sorcery = sorcery;
1450 cache->object_type = ast_strdup(type);
1451}
#define ast_asprintf(ret, fmt,...)
A wrapper for asprintf()
Definition: astmm.h:267
const char * ast_sorcery_get_module(const struct ast_sorcery *sorcery)
Get the module that has opened the provided sorcery instance.
Definition: sorcery.c:2536

References ao2_link, ast_asprintf, ast_debug, ast_sorcery_get_module(), ast_strdup, ast_strlen_zero(), cache, caches, sorcery, and type.

◆ sorcery_memory_cache_open()

static void * sorcery_memory_cache_open ( const char *  data)
static

Definition at line 1508 of file res_sorcery_memory_cache.c.

1509{
1510 char *options = ast_strdupa(data), *option;
1512
1514 if (!cache) {
1515 return NULL;
1516 }
1517
1518 cache->expire_id = -1;
1519 cache->stale_update_sched_id = -1;
1520
1521 /* If no configuration options have been provided this memory cache will operate in a default
1522 * configuration.
1523 */
1524 while (!ast_strlen_zero(options) && (option = strsep(&options, ","))) {
1525 char *name = strsep(&option, "="), *value = option;
1526
1527 if (!strcasecmp(name, "name")) {
1528 if (ast_strlen_zero(value)) {
1529 ast_log(LOG_ERROR, "A name must be specified for the memory cache\n");
1530 return NULL;
1531 }
1532 ast_free(cache->name);
1533 cache->name = ast_strdup(value);
1534 } else if (!strcasecmp(name, "maximum_objects")) {
1535 if (configuration_parse_unsigned_integer(value, &cache->maximum_objects) != 1) {
1536 ast_log(LOG_ERROR, "Unsupported maximum objects value of '%s' used for memory cache\n",
1537 value);
1538 return NULL;
1539 }
1540 } else if (!strcasecmp(name, "object_lifetime_maximum")) {
1541 if (configuration_parse_unsigned_integer(value, &cache->object_lifetime_maximum) != 1) {
1542 ast_log(LOG_ERROR, "Unsupported object maximum lifetime value of '%s' used for memory cache\n",
1543 value);
1544 return NULL;
1545 }
1546 } else if (!strcasecmp(name, "object_lifetime_stale")) {
1547 if (configuration_parse_unsigned_integer(value, &cache->object_lifetime_stale) != 1) {
1548 ast_log(LOG_ERROR, "Unsupported object stale lifetime value of '%s' used for memory cache\n",
1549 value);
1550 return NULL;
1551 }
1552 } else if (!strcasecmp(name, "expire_on_reload")) {
1553 cache->expire_on_reload = ast_true(value);
1554 } else if (!strcasecmp(name, "full_backend_cache")) {
1555 cache->full_backend_cache = ast_true(value);
1556 } else {
1557 ast_log(LOG_ERROR, "Unsupported option '%s' used for memory cache\n", name);
1558 return NULL;
1559 }
1560 }
1561
1563 cache->maximum_objects ? cache->maximum_objects : CACHE_CONTAINER_BUCKET_SIZE,
1565 if (!cache->objects) {
1566 ast_log(LOG_ERROR, "Could not create a container to hold cached objects for memory cache\n");
1567 return NULL;
1568 }
1569
1571 offsetof(struct sorcery_memory_cached_object, __heap_index));
1572 if (!cache->object_heap) {
1573 ast_log(LOG_ERROR, "Could not create heap to hold cached objects\n");
1574 return NULL;
1575 }
1576
1577 /* The memory cache is not linked to the caches container until the load callback is invoked.
1578 * Linking occurs there so an intelligent cache name can be constructed using the module of
1579 * the sorcery instance and the specific object type if no cache name was specified as part
1580 * of the configuration.
1581 */
1582
1583 /* This is done as RAII_VAR will drop the reference */
1584 return ao2_bump(cache);
1585}
#define ast_strdupa(s)
duplicate a string in memory from the stack
Definition: astmm.h:298
@ AO2_ALLOC_OPT_LOCK_NOLOCK
Definition: astobj2.h:367
@ AO2_ALLOC_OPT_LOCK_RWLOCK
Definition: astobj2.h:365
#define ao2_alloc_options(data_size, destructor_fn, options)
Definition: astobj2.h:404
#define ast_heap_create(init_height, cmp_fn, index_offset)
Create a max heap.
Definition: heap.h:100
char * strsep(char **str, const char *delims)
static int configuration_parse_unsigned_integer(const char *value, unsigned int *result)
static int sorcery_memory_cached_object_cmp(void *obj, void *arg, int flags)
static void sorcery_memory_cache_destructor(void *obj)
#define CACHE_HEAP_INIT_HEIGHT
Height of heap for cache object heap. Allows 31 initial objects.
static int age_cmp(void *a, void *b)
#define CACHE_CONTAINER_BUCKET_SIZE
The default bucket size for the container of objects in the cache.
static int sorcery_memory_cached_object_hash(const void *obj, int flags)
static struct test_options options

References age_cmp(), AO2_ALLOC_OPT_LOCK_NOLOCK, AO2_ALLOC_OPT_LOCK_RWLOCK, ao2_alloc_options, ao2_bump, ao2_cleanup, ao2_container_alloc_hash, ast_free, ast_heap_create, ast_log, ast_strdup, ast_strdupa, ast_strlen_zero(), ast_true(), cache, CACHE_CONTAINER_BUCKET_SIZE, CACHE_HEAP_INIT_HEIGHT, configuration_parse_unsigned_integer(), LOG_ERROR, name, NULL, options, RAII_VAR, sorcery_memory_cache_destructor(), sorcery_memory_cached_object_cmp(), sorcery_memory_cached_object_hash(), strsep(), and value.

◆ sorcery_memory_cache_populate()

static char * sorcery_memory_cache_populate ( struct ast_cli_entry e,
int  cmd,
struct ast_cli_args a 
)
static

Definition at line 2001 of file res_sorcery_memory_cache.c.

2002{
2004
2005 switch (cmd) {
2006 case CLI_INIT:
2007 e->command = "sorcery memory cache populate";
2008 e->usage =
2009 "Usage: sorcery memory cache populate <cache name>\n"
2010 " Expire all objects in the cache and populate it with ALL objects from backend.\n";
2011 return NULL;
2012 case CLI_GENERATE:
2013 if (a->pos == 4) {
2014 return sorcery_memory_cache_complete_name(a->word, a->n);
2015 } else {
2016 return NULL;
2017 }
2018 }
2019
2020 if (a->argc != 5) {
2021 return CLI_SHOWUSAGE;
2022 }
2023
2024 cache = ao2_find(caches, a->argv[4], OBJ_SEARCH_KEY);
2025 if (!cache) {
2026 ast_cli(a->fd, "Specified sorcery memory cache '%s' does not exist\n", a->argv[4]);
2027 return CLI_FAILURE;
2028 }
2029
2030 if (!cache->full_backend_cache) {
2031 ast_cli(a->fd, "Specified sorcery memory cache '%s' does not have full backend caching enabled\n", a->argv[4]);
2032 ao2_ref(cache, -1);
2033 return CLI_FAILURE;
2034 }
2035
2036 ao2_wrlock(cache->objects);
2037 if (!cache->sorcery) {
2038 ast_cli(a->fd, "Specified sorcery memory cache '%s' is no longer active\n", a->argv[4]);
2039 ao2_unlock(cache->objects);
2040 ao2_ref(cache, -1);
2041 return CLI_FAILURE;
2042 }
2043
2045 memory_cache_populate(cache->sorcery, cache->object_type, cache);
2046
2047 ast_cli(a->fd, "Specified sorcery memory cache '%s' has been populated with '%d' objects from the backend\n",
2048 a->argv[4], ao2_container_count(cache->objects));
2049
2050 ao2_unlock(cache->objects);
2051
2052 ao2_ref(cache, -1);
2053
2054 return CLI_SUCCESS;
2055}

References a, ao2_container_count(), ao2_find, ao2_ref, ao2_unlock, ao2_wrlock, ast_cli(), cache, caches, CLI_FAILURE, CLI_GENERATE, CLI_INIT, CLI_SHOWUSAGE, CLI_SUCCESS, ast_cli_entry::command, memory_cache_populate(), NULL, OBJ_SEARCH_KEY, remove_all_from_cache(), sorcery_memory_cache_complete_name(), and ast_cli_entry::usage.

◆ sorcery_memory_cache_print_object()

static int sorcery_memory_cache_print_object ( void *  obj,
void *  arg,
int  flags 
)
static

Definition at line 1744 of file res_sorcery_memory_cache.c.

1745{
1746#define FORMAT "%-25.25s %-15u %-15u \n"
1747 struct sorcery_memory_cached_object *cached = obj;
1748 struct print_object_details *details = arg;
1749 int seconds_until_expire = 0, seconds_until_stale = 0;
1750
1751 if (details->cache->object_lifetime_maximum) {
1752 seconds_until_expire = ast_tvdiff_ms(ast_tvadd(cached->created, ast_samp2tv(details->cache->object_lifetime_maximum, 1)), ast_tvnow()) / 1000;
1753 }
1754 if (details->cache->object_lifetime_stale) {
1755 seconds_until_stale = ast_tvdiff_ms(ast_tvadd(cached->created, ast_samp2tv(details->cache->object_lifetime_stale, 1)), ast_tvnow()) / 1000;
1756 }
1757
1758 ast_cli(details->a->fd, FORMAT, ast_sorcery_object_get_id(cached->object), MAX(seconds_until_stale, 0), MAX(seconds_until_expire, 0));
1759
1760 return CMP_MATCH;
1761#undef FORMAT
1762}
const int fd
Definition: cli.h:159
struct sorcery_memory_cache * cache
The sorcery memory cache.
struct ast_cli_args * a
The CLI arguments.
unsigned int object_lifetime_maximum
The maximum time (in seconds) an object will stay in the cache, 0 if no limit.
unsigned int object_lifetime_stale
The amount of time (in seconds) before an object is marked as stale, 0 if disabled.

References print_object_details::a, ast_cli(), ast_samp2tv(), ast_sorcery_object_get_id(), ast_tvadd(), ast_tvdiff_ms(), ast_tvnow(), print_object_details::cache, CMP_MATCH, sorcery_memory_cached_object::created, ast_cli_args::fd, FORMAT, MAX, sorcery_memory_cached_object::object, sorcery_memory_cache::object_lifetime_maximum, and sorcery_memory_cache::object_lifetime_stale.

Referenced by sorcery_memory_cache_dump().

◆ sorcery_memory_cache_reload()

static void sorcery_memory_cache_reload ( void *  data,
const struct ast_sorcery sorcery,
const char *  type 
)
static

Definition at line 1461 of file res_sorcery_memory_cache.c.

1462{
1463 struct sorcery_memory_cache *cache = data;
1464
1465 if (!cache->expire_on_reload) {
1466 return;
1467 }
1468
1469 ao2_wrlock(cache->objects);
1471 ao2_unlock(cache->objects);
1472}

References ao2_unlock, ao2_wrlock, cache, and remove_all_from_cache().

◆ sorcery_memory_cache_retrieve_fields()

static void * sorcery_memory_cache_retrieve_fields ( const struct ast_sorcery sorcery,
void *  data,
const char *  type,
const struct ast_variable fields 
)
static

Definition at line 1299 of file res_sorcery_memory_cache.c.

1301{
1302 struct sorcery_memory_cache *cache = data;
1304 .sorcery = sorcery,
1305 .cache = cache,
1306 .fields = fields,
1307 };
1308 struct sorcery_memory_cached_object *cached;
1309 void *object = NULL;
1310
1311 if (is_passthru_update() || !cache->full_backend_cache || !fields) {
1312 return NULL;
1313 }
1314
1315 cached = ao2_callback(cache->objects, 0, sorcery_memory_cache_fields_cmp, &params);
1316
1317 if (cached) {
1319 object = ao2_bump(cached->object);
1320 ao2_ref(cached, -1);
1321 }
1322
1323 return object;
1324}
static int sorcery_memory_cache_fields_cmp(void *obj, void *arg, int flags)
static int is_passthru_update(void)
const struct ast_sorcery * sorcery
Pointer to the sorcery structure.

References ao2_bump, ao2_callback, ao2_ref, cache, sorcery_memory_cache_fields_cmp_params::fields, is_passthru_update(), memory_cache_stale_check_object(), NULL, sorcery_memory_cached_object::object, sorcery, sorcery_memory_cache_fields_cmp_params::sorcery, and sorcery_memory_cache_fields_cmp().

◆ sorcery_memory_cache_retrieve_id()

static void * sorcery_memory_cache_retrieve_id ( const struct ast_sorcery sorcery,
void *  data,
const char *  type,
const char *  id 
)
static

Definition at line 1219 of file res_sorcery_memory_cache.c.

1220{
1221 struct sorcery_memory_cache *cache = data;
1222 struct sorcery_memory_cached_object *cached;
1223 void *object;
1224
1225 if (is_passthru_update()) {
1226 return NULL;
1227 }
1228
1230
1231 cached = ao2_find(cache->objects, id, OBJ_SEARCH_KEY);
1232 if (!cached) {
1233 return NULL;
1234 }
1235
1236 ast_assert(!strcmp(ast_sorcery_object_get_id(cached->object), id));
1237
1239
1240 object = ao2_bump(cached->object);
1241 ao2_ref(cached, -1);
1242
1243 return object;
1244}
static void memory_cache_full_update(const struct ast_sorcery *sorcery, const char *type, struct sorcery_memory_cache *cache)

References ao2_bump, ao2_find, ao2_ref, ast_assert, ast_sorcery_object_get_id(), cache, is_passthru_update(), memory_cache_full_update(), memory_cache_stale_check_object(), NULL, OBJ_SEARCH_KEY, sorcery_memory_cached_object::object, sorcery, and type.

◆ sorcery_memory_cache_retrieve_multiple()

static void sorcery_memory_cache_retrieve_multiple ( const struct ast_sorcery sorcery,
void *  data,
const char *  type,
struct ao2_container objects,
const struct ast_variable fields 
)
static

Definition at line 1336 of file res_sorcery_memory_cache.c.

1338{
1339 struct sorcery_memory_cache *cache = data;
1341 .sorcery = sorcery,
1342 .cache = cache,
1343 .fields = fields,
1344 .container = objects,
1345 };
1346
1347 if (is_passthru_update() || !cache->full_backend_cache) {
1348 return;
1349 }
1350
1352 ao2_callback(cache->objects, 0, sorcery_memory_cache_fields_cmp, &params);
1353
1354 if (ao2_container_count(objects)) {
1356 }
1357}
static void memory_cache_stale_check(const struct ast_sorcery *sorcery, struct sorcery_memory_cache *cache)

References ao2_callback, ao2_container_count(), cache, sorcery_memory_cache_fields_cmp_params::fields, is_passthru_update(), memory_cache_full_update(), memory_cache_stale_check(), sorcery, sorcery_memory_cache_fields_cmp_params::sorcery, sorcery_memory_cache_fields_cmp(), and type.

◆ sorcery_memory_cache_retrieve_prefix()

static void sorcery_memory_cache_retrieve_prefix ( const struct ast_sorcery sorcery,
void *  data,
const char *  type,
struct ao2_container objects,
const char *  prefix,
const size_t  prefix_len 
)
static

Definition at line 1404 of file res_sorcery_memory_cache.c.

1406{
1407 struct sorcery_memory_cache *cache = data;
1409 .sorcery = sorcery,
1410 .cache = cache,
1411 .container = objects,
1412 .prefix = prefix,
1413 .prefix_len = prefix_len,
1414 };
1415
1416 if (is_passthru_update() || !cache->full_backend_cache) {
1417 return;
1418 }
1419
1421 ao2_callback(cache->objects, 0, sorcery_memory_cache_fields_cmp, &params);
1422
1423 if (ao2_container_count(objects)) {
1425 }
1426}
static char prefix[MAX_PREFIX]
Definition: http.c:144

References ao2_callback, ao2_container_count(), cache, is_passthru_update(), memory_cache_full_update(), memory_cache_stale_check(), prefix, sorcery_memory_cache_fields_cmp_params::prefix_len, sorcery, sorcery_memory_cache_fields_cmp_params::sorcery, sorcery_memory_cache_fields_cmp(), and type.

◆ sorcery_memory_cache_retrieve_regex()

static void sorcery_memory_cache_retrieve_regex ( const struct ast_sorcery sorcery,
void *  data,
const char *  type,
struct ao2_container objects,
const char *  regex 
)
static

Definition at line 1369 of file res_sorcery_memory_cache.c.

1371{
1372 struct sorcery_memory_cache *cache = data;
1373 regex_t expression;
1375 .sorcery = sorcery,
1376 .cache = cache,
1377 .container = objects,
1378 .regex = &expression,
1379 };
1380
1381 if (is_passthru_update() || !cache->full_backend_cache || regcomp(&expression, regex, REG_EXTENDED | REG_NOSUB)) {
1382 return;
1383 }
1384
1386 ao2_callback(cache->objects, 0, sorcery_memory_cache_fields_cmp, &params);
1387 regfree(&expression);
1388
1389 if (ao2_container_count(objects)) {
1391 }
1392}
static int regex(struct ast_channel *chan, const char *cmd, char *parse, char *buf, size_t len)

References ao2_callback, ao2_container_count(), cache, is_passthru_update(), memory_cache_full_update(), memory_cache_stale_check(), regex(), sorcery, sorcery_memory_cache_fields_cmp_params::sorcery, sorcery_memory_cache_fields_cmp(), and type.

◆ sorcery_memory_cache_show()

static char * sorcery_memory_cache_show ( struct ast_cli_entry e,
int  cmd,
struct ast_cli_args a 
)
static

Definition at line 1679 of file res_sorcery_memory_cache.c.

1680{
1682
1683 switch (cmd) {
1684 case CLI_INIT:
1685 e->command = "sorcery memory cache show";
1686 e->usage =
1687 "Usage: sorcery memory cache show <name>\n"
1688 " Show sorcery memory cache configuration and statistics.\n";
1689 return NULL;
1690 case CLI_GENERATE:
1691 if (a->pos == 4) {
1692 return sorcery_memory_cache_complete_name(a->word, a->n);
1693 } else {
1694 return NULL;
1695 }
1696 }
1697
1698 if (a->argc != 5) {
1699 return CLI_SHOWUSAGE;
1700 }
1701
1702 cache = ao2_find(caches, a->argv[4], OBJ_SEARCH_KEY);
1703 if (!cache) {
1704 ast_cli(a->fd, "Specified sorcery memory cache '%s' does not exist\n", a->argv[4]);
1705 return CLI_FAILURE;
1706 }
1707
1708 ast_cli(a->fd, "Sorcery memory cache: %s\n", cache->name);
1709 ast_cli(a->fd, "Number of objects within cache: %d\n", ao2_container_count(cache->objects));
1710 if (cache->maximum_objects) {
1711 ast_cli(a->fd, "Maximum allowed objects: %d\n", cache->maximum_objects);
1712 } else {
1713 ast_cli(a->fd, "There is no limit on the maximum number of objects in the cache\n");
1714 }
1715 if (cache->object_lifetime_maximum) {
1716 ast_cli(a->fd, "Number of seconds before object expires: %d\n", cache->object_lifetime_maximum);
1717 } else {
1718 ast_cli(a->fd, "Object expiration is not enabled - cached objects will not expire\n");
1719 }
1720 if (cache->object_lifetime_stale) {
1721 ast_cli(a->fd, "Number of seconds before object becomes stale: %d\n", cache->object_lifetime_stale);
1722 } else {
1723 ast_cli(a->fd, "Object staleness is not enabled - cached objects will not go stale\n");
1724 }
1725 ast_cli(a->fd, "Expire all objects on reload: %s\n", AST_CLI_ONOFF(cache->expire_on_reload));
1726
1727 ao2_ref(cache, -1);
1728
1729 return CLI_SUCCESS;
1730}
#define AST_CLI_ONOFF(x)
return On or Off depending on the argument. This is used in many places in CLI command,...
Definition: cli.h:78

References a, ao2_container_count(), ao2_find, ao2_ref, ast_cli(), AST_CLI_ONOFF, cache, caches, CLI_FAILURE, CLI_GENERATE, CLI_INIT, CLI_SHOWUSAGE, CLI_SUCCESS, ast_cli_entry::command, NULL, OBJ_SEARCH_KEY, sorcery_memory_cache_complete_name(), and ast_cli_entry::usage.

◆ sorcery_memory_cache_stale()

static char * sorcery_memory_cache_stale ( struct ast_cli_entry e,
int  cmd,
struct ast_cli_args a 
)
static

Definition at line 1917 of file res_sorcery_memory_cache.c.

1918{
1920 int reload = 0;
1921
1922 switch (cmd) {
1923 case CLI_INIT:
1924 e->command = "sorcery memory cache stale";
1925 e->usage =
1926 "Usage: sorcery memory cache stale <cache name> [object name [reload]]\n"
1927 " Mark a specific object or ALL objects as stale in a sorcery memory cache.\n"
1928 " If \"reload\" is specified, then the object is marked stale and immediately\n"
1929 " retrieved from backend storage to repopulate the cache\n";
1930 return NULL;
1931 case CLI_GENERATE:
1932 if (a->pos == 4) {
1933 return sorcery_memory_cache_complete_name(a->word, a->n);
1934 } else if (a->pos == 5) {
1935 return sorcery_memory_cache_complete_object_name(a->argv[4], a->word, a->n);
1936 } else if (a->pos == 6) {
1937 static const char * const completions[] = { "reload", NULL };
1938 return ast_cli_complete(a->word, completions, a->n);
1939 } else {
1940 return NULL;
1941 }
1942 }
1943
1944 if (a->argc < 5 || a->argc > 7) {
1945 return CLI_SHOWUSAGE;
1946 }
1947
1948 if (a->argc == 7) {
1949 if (!strcasecmp(a->argv[6], "reload")) {
1950 reload = 1;
1951 } else {
1952 return CLI_SHOWUSAGE;
1953 }
1954 }
1955
1956 cache = ao2_find(caches, a->argv[4], OBJ_SEARCH_KEY);
1957 if (!cache) {
1958 ast_cli(a->fd, "Specified sorcery memory cache '%s' does not exist\n", a->argv[4]);
1959 return CLI_FAILURE;
1960 }
1961
1962 if (!cache->object_lifetime_stale) {
1963 ast_cli(a->fd, "Specified sorcery memory cache '%s' does not have staleness enabled\n", a->argv[4]);
1964 ao2_ref(cache, -1);
1965 return CLI_FAILURE;
1966 }
1967
1968 ao2_rdlock(cache->objects);
1969 if (a->argc == 5) {
1971 ast_cli(a->fd, "Marked all objects in sorcery memory cache '%s' as stale\n", a->argv[4]);
1972 } else {
1973 if (!mark_object_as_stale_in_cache(cache, a->argv[5])) {
1974 ast_cli(a->fd, "Successfully marked object '%s' in memory cache '%s' as stale\n",
1975 a->argv[5], a->argv[4]);
1976 if (reload) {
1977 struct sorcery_memory_cached_object *cached;
1978
1979 cached = ao2_find(cache->objects, a->argv[5], OBJ_SEARCH_KEY | OBJ_NOLOCK);
1980 if (cached) {
1981 memory_cache_stale_update_object(cache->sorcery, cache, cached);
1982 ao2_ref(cached, -1);
1983 }
1984 }
1985 } else {
1986 ast_cli(a->fd, "Object '%s' in sorcery memory cache '%s' could not be marked as stale as it was not found\n",
1987 a->argv[5], a->argv[4]);
1988 }
1989 }
1990 ao2_unlock(cache->objects);
1991
1992 ao2_ref(cache, -1);
1993
1994 return CLI_SUCCESS;
1995}
char * ast_cli_complete(const char *word, const char *const choices[], int pos)
Definition: main/cli.c:1841

References a, ao2_find, ao2_rdlock, ao2_ref, ao2_unlock, ast_cli(), ast_cli_complete(), cache, caches, CLI_FAILURE, CLI_GENERATE, CLI_INIT, CLI_SHOWUSAGE, CLI_SUCCESS, ast_cli_entry::command, mark_all_as_stale_in_cache(), mark_object_as_stale_in_cache(), memory_cache_stale_update_object(), NULL, OBJ_NOLOCK, OBJ_SEARCH_KEY, reload(), sorcery_memory_cache_complete_name(), sorcery_memory_cache_complete_object_name(), and ast_cli_entry::usage.

◆ sorcery_memory_cached_object_alloc()

static struct sorcery_memory_cached_object * sorcery_memory_cached_object_alloc ( const struct ast_sorcery sorcery,
const struct sorcery_memory_cache cache,
void *  object 
)
static

Definition at line 766 of file res_sorcery_memory_cache.c.

768{
769 struct sorcery_memory_cached_object *cached;
770
771 cached = ao2_alloc(sizeof(*cached), sorcery_memory_cached_object_destructor);
772 if (!cached) {
773 return NULL;
774 }
775
776 cached->object = ao2_bump(object);
777 cached->created = ast_tvnow();
778 cached->stale_update_sched_id = -1;
779
780 if (cache->full_backend_cache) {
781 /* A cached objectset allows us to easily perform all retrieval operations in a
782 * minimal of time.
783 */
785 if (!cached->objectset) {
786 ao2_ref(cached, -1);
787 return NULL;
788 }
789 }
790
791 return cached;
792}
#define ao2_alloc(data_size, destructor_fn)
Definition: astobj2.h:409
static void sorcery_memory_cached_object_destructor(void *obj)
#define ast_sorcery_objectset_create(sorcery, object)
Create an object set (KVP list) for an object.
Definition: sorcery.h:1137

References ao2_alloc, ao2_bump, ao2_ref, ast_sorcery_objectset_create, ast_tvnow(), cache, sorcery_memory_cached_object::created, NULL, sorcery_memory_cached_object::object, sorcery_memory_cached_object::objectset, sorcery, sorcery_memory_cached_object_destructor(), and sorcery_memory_cached_object::stale_update_sched_id.

Referenced by object_add_to_cache_callback(), and sorcery_memory_cache_create().

◆ sorcery_memory_cached_object_cmp()

static int sorcery_memory_cached_object_cmp ( void *  obj,
void *  arg,
int  flags 
)
static

Definition at line 394 of file res_sorcery_memory_cache.c.

395{
396 struct sorcery_memory_cached_object *left = obj;
397 struct sorcery_memory_cached_object *right = arg;
398 const char *right_name = arg;
399 int cmp;
400
401 switch (flags & OBJ_SEARCH_MASK) {
402 default:
404 right_name = ast_sorcery_object_get_id(right->object);
405 /* Fall through */
406 case OBJ_SEARCH_KEY:
407 cmp = strcmp(ast_sorcery_object_get_id(left->object), right_name);
408 break;
410 cmp = strncmp(ast_sorcery_object_get_id(left->object), right_name, strlen(right_name));
411 break;
412 }
413 return cmp ? 0 : CMP_MATCH;
414}

References ast_sorcery_object_get_id(), CMP_MATCH, OBJ_SEARCH_KEY, OBJ_SEARCH_MASK, OBJ_SEARCH_OBJECT, OBJ_SEARCH_PARTIAL_KEY, and sorcery_memory_cached_object::object.

Referenced by sorcery_memory_cache_open().

◆ sorcery_memory_cached_object_destructor()

static void sorcery_memory_cached_object_destructor ( void *  obj)
static

◆ sorcery_memory_cached_object_hash()

static int sorcery_memory_cached_object_hash ( const void *  obj,
int  flags 
)
static

Definition at line 360 of file res_sorcery_memory_cache.c.

361{
362 const struct sorcery_memory_cached_object *cached = obj;
363 const char *name = obj;
364 int hash;
365
366 switch (flags & OBJ_SEARCH_MASK) {
367 default:
370 /* Fall through */
371 case OBJ_SEARCH_KEY:
372 hash = ast_str_hash(name);
373 break;
375 /* Should never happen in hash callback. */
376 ast_assert(0);
377 hash = 0;
378 break;
379 }
380 return hash;
381}

References ast_assert, ast_sorcery_object_get_id(), ast_str_hash(), name, OBJ_SEARCH_KEY, OBJ_SEARCH_MASK, OBJ_SEARCH_OBJECT, OBJ_SEARCH_PARTIAL_KEY, and sorcery_memory_cached_object::object.

Referenced by sorcery_memory_cache_open().

◆ stale_cache_update()

static int stale_cache_update ( const void *  data)
static

Definition at line 908 of file res_sorcery_memory_cache.c.

909{
911 struct ao2_container *backend_objects;
912
914 backend_objects = ast_sorcery_retrieve_by_fields(task_data->sorcery, task_data->type,
917
918 if (!backend_objects) {
919 task_data->cache->stale_update_sched_id = -1;
920 ao2_ref(task_data, -1);
921 return 0;
922 }
923
924 if (task_data->cache->maximum_objects && ao2_container_count(backend_objects) >= task_data->cache->maximum_objects) {
925 ast_log(LOG_ERROR, "The backend contains %d objects while the sorcery memory cache '%s' is explicitly configured to only allow %d\n",
926 ao2_container_count(backend_objects), task_data->cache->name, task_data->cache->maximum_objects);
927 task_data->cache->stale_update_sched_id = -1;
928 ao2_ref(task_data, -1);
929 return 0;
930 }
931
932 ao2_wrlock(task_data->cache->objects);
935 task_data->sorcery, task_data->cache);
936
937 /* If the number of cached objects does not match the number of backend objects we encountered a memory allocation
938 * failure and the cache is incomplete, so drop everything and fall back to querying the backend directly
939 * as it may be able to provide what is wanted.
940 */
941 if (ao2_container_count(task_data->cache->objects) != ao2_container_count(backend_objects)) {
942 ast_log(LOG_WARNING, "The backend contains %d objects while only %d could be added to sorcery memory cache '%s'\n",
943 ao2_container_count(backend_objects), ao2_container_count(task_data->cache->objects), task_data->cache->name);
945 }
946
947 ao2_unlock(task_data->cache->objects);
948 ao2_ref(backend_objects, -1);
949
950 task_data->cache->stale_update_sched_id = -1;
951 ao2_ref(task_data, -1);
952
953 return 0;
954}

References ao2_callback_data, ao2_container_count(), ao2_ref, ao2_unlock, ao2_wrlock, ast_log, AST_RETRIEVE_FLAG_ALL, AST_RETRIEVE_FLAG_MULTIPLE, ast_sorcery_retrieve_by_fields(), end_passthru_update(), LOG_ERROR, LOG_WARNING, NULL, OBJ_MULTIPLE, OBJ_NODATA, OBJ_NOLOCK, object_add_to_cache_callback(), remove_all_from_cache(), and start_passthru_update().

Referenced by memory_cache_stale_update_full().

◆ stale_cache_update_task_data_alloc()

static struct stale_cache_update_task_data * stale_cache_update_task_data_alloc ( struct ast_sorcery sorcery,
struct sorcery_memory_cache cache,
const char *  type 
)
static

Definition at line 886 of file res_sorcery_memory_cache.c.

888{
890
893 if (!task_data) {
894 return NULL;
895 }
896
897 task_data->sorcery = ao2_bump(sorcery);
898 task_data->cache = ao2_bump(cache);
899 task_data->type = ast_strdup(type);
900 if (!task_data->type) {
901 ao2_ref(task_data, -1);
902 return NULL;
903 }
904
905 return task_data;
906}
static void stale_cache_update_task_data_destructor(void *obj)

References AO2_ALLOC_OPT_LOCK_NOLOCK, ao2_alloc_options, ao2_bump, ao2_ref, ast_strdup, cache, NULL, sorcery, stale_cache_update_task_data_destructor(), and type.

Referenced by memory_cache_stale_update_full().

◆ stale_cache_update_task_data_destructor()

static void stale_cache_update_task_data_destructor ( void *  obj)
static

Definition at line 877 of file res_sorcery_memory_cache.c.

878{
880
881 ao2_cleanup(task_data->cache);
883 ast_free(task_data->type);
884}
#define ast_sorcery_unref(sorcery)
Decrease the reference count of a sorcery structure.
Definition: sorcery.h:1500

References ao2_cleanup, ast_free, and ast_sorcery_unref.

Referenced by stale_cache_update_task_data_alloc().

◆ stale_item_update()

static int stale_item_update ( const void *  data)
static

Definition at line 989 of file res_sorcery_memory_cache.c.

990{
992 void *object;
993
995
996 object = ast_sorcery_retrieve_by_id(task_data->sorcery,
999 if (!object) {
1000 ast_debug(1, "Backend no longer has object type '%s' ID '%s'. Removing from cache\n",
1004 task_data->object);
1005 } else {
1006 ast_debug(1, "Refreshing stale cache object type '%s' ID '%s'\n",
1010 object);
1011 ao2_ref(object, -1);
1012 }
1013
1014 ast_test_suite_event_notify("SORCERY_MEMORY_CACHE_REFRESHED", "Cache: %s\r\nType: %s\r\nName: %s\r\n",
1015 task_data->cache->name, ast_sorcery_object_get_type(task_data->object),
1017
1018 ao2_ref(task_data, -1);
1020
1021 return 0;
1022}
static int sorcery_memory_cache_create(const struct ast_sorcery *sorcery, void *data, void *object)
static int sorcery_memory_cache_delete(const struct ast_sorcery *sorcery, void *data, void *object)
void * ast_sorcery_retrieve_by_id(const struct ast_sorcery *sorcery, const char *type, const char *id)
Retrieve an object using its unique identifier.
Definition: sorcery.c:1853
#define ast_test_suite_event_notify(s, f,...)
Definition: test.h:189

References ao2_ref, ast_debug, ast_sorcery_object_get_id(), ast_sorcery_object_get_type(), ast_sorcery_retrieve_by_id(), ast_test_suite_event_notify, end_passthru_update(), stale_update_task_data::object, sorcery_memory_cache_create(), sorcery_memory_cache_delete(), and start_passthru_update().

Referenced by memory_cache_stale_update_object().

◆ stale_update_task_data_alloc()

static struct stale_update_task_data * stale_update_task_data_alloc ( struct ast_sorcery sorcery,
struct sorcery_memory_cache cache,
const char *  type,
void *  object 
)
static

Definition at line 971 of file res_sorcery_memory_cache.c.

973{
975
978 if (!task_data) {
979 return NULL;
980 }
981
982 task_data->sorcery = ao2_bump(sorcery);
983 task_data->cache = ao2_bump(cache);
984 task_data->object = ao2_bump(object);
985
986 return task_data;
987}
static void stale_update_task_data_destructor(void *obj)

References AO2_ALLOC_OPT_LOCK_NOLOCK, ao2_alloc_options, ao2_bump, cache, NULL, sorcery, and stale_update_task_data_destructor().

Referenced by memory_cache_stale_update_object().

◆ stale_update_task_data_destructor()

static void stale_update_task_data_destructor ( void *  obj)
static

Definition at line 962 of file res_sorcery_memory_cache.c.

963{
964 struct stale_update_task_data *task_data = obj;
965
966 ao2_cleanup(task_data->cache);
967 ao2_cleanup(task_data->object);
969}

References ao2_cleanup, and ast_sorcery_unref.

Referenced by stale_update_task_data_alloc().

◆ start_passthru_update()

static void start_passthru_update ( void  )
static

◆ unload_module()

static int unload_module ( void  )
static

Definition at line 3500 of file res_sorcery_memory_cache.c.

3501{
3502 AST_TEST_UNREGISTER(open_with_valid_options);
3503 AST_TEST_UNREGISTER(open_with_invalid_options);
3504 AST_TEST_UNREGISTER(create_and_retrieve);
3506 AST_TEST_UNREGISTER(delete);
3507 AST_TEST_UNREGISTER(maximum_objects);
3508 AST_TEST_UNREGISTER(expiration);
3509 AST_TEST_UNREGISTER(stale);
3510 AST_TEST_UNREGISTER(full_backend_cache_expiration);
3511 AST_TEST_UNREGISTER(full_backend_cache_stale);
3512
3513 ast_manager_unregister("SorceryMemoryCacheExpireObject");
3514 ast_manager_unregister("SorceryMemoryCacheExpire");
3515 ast_manager_unregister("SorceryMemoryCacheStaleObject");
3516 ast_manager_unregister("SorceryMemoryCacheStale");
3517 ast_manager_unregister("SorceryMemoryCachePopulate");
3518
3520
3522
3523 /*
3524 * XXX There is the potential to leak memory if there are pending
3525 * next-cache-expiration and stale-cache-update tasks in the scheduler.
3526 */
3527 if (sched) {
3529 sched = NULL;
3530 }
3531
3533 caches = NULL;
3534
3535 return 0;
3536}
int ast_cli_unregister_multiple(struct ast_cli_entry *e, int len)
Unregister multiple commands.
Definition: clicompat.c:30
int ast_manager_unregister(const char *action)
Unregister a registered manager command.
Definition: manager.c:8041
void ast_sched_context_destroy(struct ast_sched_context *c)
destroys a schedule context
Definition: sched.c:271
int ast_sorcery_wizard_unregister(const struct ast_sorcery_wizard *interface)
Unregister a sorcery wizard.
Definition: sorcery.c:474
#define AST_TEST_UNREGISTER(cb)
Definition: test.h:128

References ao2_cleanup, ARRAY_LEN, ast_cli_unregister_multiple(), ast_manager_unregister(), ast_sched_context_destroy(), ast_sorcery_wizard_unregister(), AST_TEST_UNREGISTER, caches, cli_memory_cache, memory_cache_object_wizard, NULL, and update().

Referenced by load_module().

Variable Documentation

◆ __mod_info

struct ast_module_info __mod_info = { .name = AST_MODULE, .flags = AST_MODFLAG_GLOBAL_SYMBOLS | AST_MODFLAG_LOAD_ORDER , .description = "Sorcery Memory Cache Object Wizard" , .key = "This paragraph is copyright (c) 2006 by Digium, Inc. \In order for your module to load, it must return this \key via a function called \"key\". Any code which \includes this paragraph must be licensed under the GNU \General Public License version 2 or later (at your \option). In addition to Digium's general reservations \of rights, Digium expressly reserves the right to \allow other parties to license this paragraph under \different terms. Any use of Digium, Inc. trademarks or \logos (including \"Asterisk\" or \"Digium\") without \express written permission of Digium, Inc. is prohibited.\n" , .buildopt_sum = AST_BUILDOPT_SUM, .support_level = AST_MODULE_SUPPORT_CORE, .load = load_module, .unload = unload_module, .load_pri = AST_MODPRI_REALTIME_DRIVER, }
static

Definition at line 3603 of file res_sorcery_memory_cache.c.

◆ ast_module_info

const struct ast_module_info* ast_module_info = &__mod_info
static

Definition at line 3603 of file res_sorcery_memory_cache.c.

◆ caches

struct ao2_container* caches
static

◆ cli_memory_cache

struct ast_cli_entry cli_memory_cache[]
static

Definition at line 2057 of file res_sorcery_memory_cache.c.

Referenced by load_module(), and unload_module().

◆ memory_cache_object_wizard

struct ast_sorcery_wizard memory_cache_object_wizard
static

Definition at line 215 of file res_sorcery_memory_cache.c.

Referenced by load_module(), and unload_module().

◆ passthru_update_id_storage

struct ast_threadstorage passthru_update_id_storage = { .once = PTHREAD_ONCE_INIT , .key_init = __init_passthru_update_id_storage , .custom_init = NULL , }
static

Definition at line 247 of file res_sorcery_memory_cache.c.

Referenced by is_passthru_update(), and set_passthru_update().

◆ sched

struct ast_sched_context* sched
static

Scheduler for cache management.

Definition at line 244 of file res_sorcery_memory_cache.c.