Asterisk - The Open Source Telephony Project GIT-master-4f2b068
Loading...
Searching...
No Matches
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.
 
#define CACHE_HEAP_INIT_HEIGHT   5
 Height of heap for cache object heap. Allows 31 initial objects.
 
#define CACHES_CONTAINER_BUCKET_SIZE   53
 The bucket size for the container of caches.
 
#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 __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)
 
 AST_THREADSTORAGE_CUSTOM_SCOPE (passthru_update_id_storage, NULL, ast_free_ptr, static)
 
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 int memory_cache_populate_external (const struct ast_sorcery *sorcery, const char *type, struct sorcery_memory_cache *cache)
 
static void memory_cache_populate_internal (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 = ASTERISK_GPL_KEY , .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.
 
static struct ast_cli_entry cli_memory_cache []
 
static struct ast_sorcery_wizard memory_cache_object_wizard
 
static struct ast_sched_contextsched
 Scheduler for cache management.
 

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 252 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 255 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 249 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 263 of file res_sorcery_memory_cache.c.

Function Documentation

◆ __reg_module()

static void __reg_module ( void  )
static

Definition at line 3766 of file res_sorcery_memory_cache.c.

◆ __unreg_module()

static void __unreg_module ( void  )
static

Definition at line 3766 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 746 of file res_sorcery_memory_cache.c.

748{
749 struct sorcery_memory_cached_object *front;
750
751 if (!ao2_link_flags(cache->objects, cached_object, OBJ_NOLOCK)) {
752 return -1;
753 }
754
755 if (cache->full_backend_cache && (front = ast_heap_peek(cache->object_heap, 1))) {
756 /* For a full backend cache all objects share the same lifetime */
757 cached_object->created = front->created;
758 }
759
760 if (ast_heap_push(cache->object_heap, cached_object)) {
761 ao2_find(cache->objects, cached_object,
763 return -1;
764 }
765
766 if (cache->expire_id == -1) {
768 }
769
770 return 0;
771}
#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
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 memory_cache_populate_external(), object_add_to_cache_callback(), and sorcery_memory_cache_create().

◆ age_cmp()

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

Definition at line 1617 of file res_sorcery_memory_cache.c.

1618{
1619 return ast_tvcmp(((struct sorcery_memory_cached_object *) b)->created,
1620 ((struct sorcery_memory_cached_object *) a)->created);
1621}
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 3766 of file res_sorcery_memory_cache.c.

◆ AST_THREADSTORAGE_CUSTOM_SCOPE()

AST_THREADSTORAGE_CUSTOM_SCOPE ( passthru_update_id_storage  ,
NULL  ,
ast_free_ptr  ,
static   
)

◆ configuration_parse_unsigned_integer()

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

Definition at line 1608 of file res_sorcery_memory_cache.c.

1609{
1610 if (ast_strlen_zero(value) || !strncmp(value, "-", 1)) {
1611 return 0;
1612 }
1613
1614 return sscanf(value, "%30u", result);
1615}
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 298 of file res_sorcery_memory_cache.c.

299{
301}
static void set_passthru_update(uint32_t value)

References set_passthru_update().

Referenced by memory_cache_populate_external(), memory_cache_populate_internal(), stale_cache_update(), and stale_item_update().

◆ expire_objects_from_cache()

static int expire_objects_from_cache ( const void *  data)
static

Definition at line 516 of file res_sorcery_memory_cache.c.

517{
518 struct sorcery_memory_cache *cache = (struct sorcery_memory_cache *)data;
519 struct sorcery_memory_cached_object *cached;
520
521 /*
522 * We need to do deadlock avoidance between a non-scheduler thread
523 * blocking when trying to delete the scheduled entry for this
524 * callback because the scheduler thread is running this callback
525 * and this callback waiting for the cache->objects container lock
526 * that the blocked non-scheduler thread already holds.
527 */
528 while (ao2_trywrlock(cache->objects)) {
529 if (cache->del_expire) {
530 cache->expire_id = -1;
531 ao2_ref(cache, -1);
532 return 0;
533 }
534 sched_yield();
535 }
536
537 cache->expire_id = -1;
538
539 /* This is an optimization for objects which have been cached close to each other */
540 while ((cached = ast_heap_peek(cache->object_heap, 1))) {
541 int expiration;
542
543 expiration = ast_tvdiff_ms(ast_tvadd(cached->created, ast_samp2tv(cache->object_lifetime_maximum, 1)), ast_tvnow());
544
545 /* If the current oldest object has not yet expired stop and reschedule for it */
546 if (expiration > 0) {
547 break;
548 }
549
551 }
552
554
555 ao2_unlock(cache->objects);
556
557 ao2_ref(cache, -1);
558
559 return 0;
560}
#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:2381
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:2280
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 266 of file res_sorcery_memory_cache.c.

267{
268 uint32_t *passthru_update_thread_id;
269
270 passthru_update_thread_id = ast_threadstorage_get(&passthru_update_id_storage,
271 sizeof(*passthru_update_thread_id));
272 if (!passthru_update_thread_id) {
273 return 0;
274 }
275
276 return *passthru_update_thread_id == PASSTHRU_UPDATE_THREAD_ID;
277}
#define PASSTHRU_UPDATE_THREAD_ID
void * ast_threadstorage_get(struct ast_threadstorage *ts, size_t init_size)
Retrieve thread storage.

References ast_threadstorage_get(), 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 3701 of file res_sorcery_memory_cache.c.

3702{
3703 int res;
3704
3708 if (!caches) {
3709 ast_log(LOG_ERROR, "Failed to create container for configured caches\n");
3710 unload_module();
3712 }
3713
3715 if (!sched) {
3716 ast_log(LOG_ERROR, "Failed to create scheduler for cache management\n");
3717 unload_module();
3719 }
3720
3722 ast_log(LOG_ERROR, "Failed to create scheduler thread for cache management\n");
3723 unload_module();
3725 }
3726
3728 unload_module();
3730 }
3731
3738
3739 if (res) {
3740 unload_module();
3742 }
3743
3744 /* This causes the stale unit test to execute last, so if a sorcery instance persists
3745 * longer than expected subsequent unit tests don't fail when setting it up.
3746 */
3747 AST_TEST_REGISTER(stale);
3748 AST_TEST_REGISTER(open_with_valid_options);
3749 AST_TEST_REGISTER(open_with_invalid_options);
3750 AST_TEST_REGISTER(create_and_retrieve);
3752 AST_TEST_REGISTER(delete);
3753 AST_TEST_REGISTER(maximum_objects);
3754 AST_TEST_REGISTER(expiration);
3755 AST_TEST_REGISTER(full_backend_cache_expiration);
3756 AST_TEST_REGISTER(full_backend_cache_stale);
3757
3759}
#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:192
@ 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:706

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 650 of file res_sorcery_memory_cache.c.

651{
653}
#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 623 of file res_sorcery_memory_cache.c.

624{
625 struct sorcery_memory_cached_object *cached;
626
627 cached = ao2_find(cache->objects, id, OBJ_SEARCH_KEY | OBJ_NOLOCK);
628 if (!cached) {
629 return -1;
630 }
631
632 ast_assert(!strcmp(ast_sorcery_object_get_id(cached->object), id));
633
634 object_stale_callback(cached, cache, 0);
635 ao2_ref(cached, -1);
636
637 return 0;
638}
@ 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:779

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 1201 of file res_sorcery_memory_cache.c.

1202{
1203 if (!cache->full_backend_cache) {
1204 return;
1205 }
1206
1207 ao2_wrlock(cache->objects);
1208 if (!ao2_container_count(cache->objects)) {
1210 }
1211 ao2_unlock(cache->objects);
1212}
#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[]
static struct ast_sorcery * sorcery
static void memory_cache_populate_internal(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_internal(), 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_external()

static int memory_cache_populate_external ( const struct ast_sorcery sorcery,
const char *  type,
struct sorcery_memory_cache cache 
)
static

Definition at line 1107 of file res_sorcery_memory_cache.c.

1108{
1109 struct ao2_container *backend_objects;
1110 struct ao2_iterator it_backend;
1111 void *object;
1112 AST_VECTOR(, struct sorcery_memory_cached_object *) cached_objects;
1113 int i, num_cached;
1114
1115 /* Retrieve all backend objects without holding the cache lock */
1119
1120 if (!backend_objects) {
1121 /* This will occur in off-nominal memory allocation failure scenarios */
1122 return -1;
1123 }
1124
1125 if (cache->maximum_objects && ao2_container_count(backend_objects) >= cache->maximum_objects) {
1126 ast_log(LOG_ERROR, "The backend contains %d objects while the sorcery memory cache '%s' is explicitly configured to only allow %d\n",
1127 ao2_container_count(backend_objects), cache->name, cache->maximum_objects);
1128 ao2_ref(backend_objects, -1);
1129 return -1;
1130 }
1131
1132 /* Allocate vector to hold cached objects - do this before any locking */
1133 if (AST_VECTOR_INIT(&cached_objects, ao2_container_count(backend_objects))) {
1134 ast_log(LOG_ERROR, "Could not allocate vector for cached objects for sorcery memory cache '%s'\n",
1135 cache->name);
1136 ao2_ref(backend_objects, -1);
1137 return -1;
1138 }
1139
1140 /* Iterate all backend objects, creating cached objects for each */
1141 it_backend = ao2_iterator_init(backend_objects, 0);
1142
1143 while ((object = ao2_iterator_next(&it_backend))) {
1144 struct sorcery_memory_cached_object *cached;
1145
1147 ao2_ref(object, -1);
1148
1149 if (!cached || AST_VECTOR_APPEND(&cached_objects, cached)) {
1150 ao2_cleanup(cached);
1151 ao2_iterator_destroy(&it_backend);
1152 ao2_ref(backend_objects, -1);
1153 /* Clean up any cached objects we already created */
1154 for (i = 0; i < AST_VECTOR_SIZE(&cached_objects); i++) {
1155 ao2_ref(AST_VECTOR_GET(&cached_objects, i), -1);
1156 }
1157 AST_VECTOR_FREE(&cached_objects);
1158 return -1;
1159 }
1160 }
1161
1162 ao2_iterator_destroy(&it_backend);
1163
1164 /* Now we have all cached objects ready - quickly swap them into the cache */
1165 ao2_wrlock(cache->objects);
1166
1167 /* Remove all existing objects from cache */
1169
1170 num_cached = AST_VECTOR_SIZE(&cached_objects);
1171
1172 /* Add all new objects to cache */
1173 for (i = 0; i < num_cached; i++) {
1174 struct sorcery_memory_cached_object *cached = AST_VECTOR_GET(&cached_objects, i);
1175 add_to_cache(cache, cached);
1176 }
1177
1178 ao2_unlock(cache->objects);
1179
1180 /* Cleanup - release all our references to cached objects.
1181 * Done in a separate loop to avoid holding the cache lock while destroying objects,
1182 * which reduces lock contention and potential blocking.
1183 */
1184 for (i = 0; i < num_cached; i++) {
1185 ao2_ref(AST_VECTOR_GET(&cached_objects, i), -1);
1186 }
1187 AST_VECTOR_FREE(&cached_objects);
1188
1189 ao2_ref(backend_objects, -1);
1190 return num_cached;
1191}
#define ao2_iterator_next(iter)
Definition astobj2.h:1911
#define ao2_cleanup(obj)
Definition astobj2.h:1934
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.
static void end_passthru_update(void)
static void start_passthru_update(void)
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 void remove_all_from_cache(struct sorcery_memory_cache *cache)
static int add_to_cache(struct sorcery_memory_cache *cache, struct sorcery_memory_cached_object *cached_object)
@ 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:1961
Generic container type.
When we need to walk through a container, we use an ao2_iterator to keep track of the current positio...
Definition astobj2.h:1821
#define AST_VECTOR_SIZE(vec)
Get the number of elements in a vector.
Definition vector.h:620
#define AST_VECTOR_FREE(vec)
Deallocates this vector.
Definition vector.h:185
#define AST_VECTOR_INIT(vec, size)
Initialize a vector.
Definition vector.h:124
#define AST_VECTOR_APPEND(vec, elem)
Append an element to a vector, growing the vector if needed.
Definition vector.h:267
#define AST_VECTOR(name, type)
Define a vector structure.
Definition vector.h:44
#define AST_VECTOR_GET(vec, idx)
Get an element from a vector.
Definition vector.h:691

References add_to_cache(), ao2_cleanup, ao2_container_count(), ao2_iterator_destroy(), ao2_iterator_init(), ao2_iterator_next, ao2_ref, ao2_unlock, ao2_wrlock, ast_log, AST_RETRIEVE_FLAG_ALL, AST_RETRIEVE_FLAG_MULTIPLE, ast_sorcery_retrieve_by_fields(), AST_VECTOR, AST_VECTOR_APPEND, AST_VECTOR_FREE, AST_VECTOR_GET, AST_VECTOR_INIT, AST_VECTOR_SIZE, cache, end_passthru_update(), LOG_ERROR, NULL, remove_all_from_cache(), sorcery, sorcery_memory_cached_object_alloc(), start_passthru_update(), and type.

Referenced by sorcery_memory_cache_ami_populate(), and sorcery_memory_cache_populate().

◆ memory_cache_populate_internal()

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

Definition at line 1055 of file res_sorcery_memory_cache.c.

1056{
1057 struct ao2_container *backend_objects;
1058
1062
1063 if (!backend_objects) {
1064 /* This will occur in off-nominal memory allocation failure scenarios */
1065 return;
1066 }
1067
1068 if (cache->maximum_objects && ao2_container_count(backend_objects) >= cache->maximum_objects) {
1069 ast_log(LOG_ERROR, "The backend contains %d objects while the sorcery memory cache '%s' is explicitly configured to only allow %d\n",
1070 ao2_container_count(backend_objects), cache->name, cache->maximum_objects);
1071 ao2_ref(backend_objects, -1);
1072 return;
1073 }
1074
1076 (struct ast_sorcery*)sorcery, cache);
1077
1078 /* If the number of cached objects does not match the number of backend objects we encountered a memory allocation
1079 * failure and the cache is incomplete, so drop everything and fall back to querying the backend directly
1080 * as it may be able to provide what is wanted.
1081 */
1082 if (ao2_container_count(cache->objects) != ao2_container_count(backend_objects)) {
1083 ast_log(LOG_WARNING, "The backend contains %d objects while only %d could be added to sorcery memory cache '%s'\n",
1084 ao2_container_count(backend_objects), ao2_container_count(cache->objects), cache->name);
1086 }
1087
1088 ao2_ref(backend_objects, -1);
1089}
#define ao2_callback_data(container, flags, cb_fn, arg, data)
Definition astobj2.h:1723
#define LOG_WARNING
static int object_add_to_cache_callback(void *obj, void *arg, void *data, int flags)
Full structure for sorcery.
Definition sorcery.c:231

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().

◆ memory_cache_stale_check()

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

Definition at line 1315 of file res_sorcery_memory_cache.c.

1316{
1317 struct sorcery_memory_cached_object *cached;
1318
1319 ao2_rdlock(cache->objects);
1320 cached = ao2_bump(ast_heap_peek(cache->object_heap, 1));
1321 ao2_unlock(cache->objects);
1322
1323 if (!cached) {
1324 return;
1325 }
1326
1328 ao2_ref(cached, -1);
1329}
#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 1282 of file res_sorcery_memory_cache.c.

1284{
1285 struct timeval elapsed;
1286
1287 if (!cache->object_lifetime_stale) {
1288 return;
1289 }
1290
1291 /* For a full cache as every object has the same expiration/staleness we can do the same check */
1292 elapsed = ast_tvsub(ast_tvnow(), cached->created);
1293
1294 if (elapsed.tv_sec < cache->object_lifetime_stale) {
1295 return;
1296 }
1297
1298 if (cache->full_backend_cache) {
1300 } else {
1302 }
1303
1304}
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:2393
struct timeval ast_tvsub(struct timeval a, struct timeval b)
Returns the difference of two timevals a - b.
Definition extconf.c:2295

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 1222 of file res_sorcery_memory_cache.c.

1224{
1225 ao2_wrlock(cache->objects);
1226 if (cache->stale_update_sched_id == -1) {
1228
1230 cache, type);
1231 if (task_data) {
1232 cache->stale_update_sched_id = ast_sched_add(sched, 1,
1234 }
1235 if (cache->stale_update_sched_id < 0) {
1237 }
1238 }
1239 ao2_unlock(cache->objects);
1240}
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 1250 of file res_sorcery_memory_cache.c.

1252{
1253 ao2_lock(cached);
1254 if (cached->stale_update_sched_id == -1) {
1256
1258 cache, ast_sorcery_object_get_type(cached->object), cached->object);
1259 if (task_data) {
1260 ast_debug(1, "Cached sorcery object type '%s' ID '%s' is stale. Refreshing\n",
1264 }
1265 if (cached->stale_update_sched_id < 0) {
1267 ast_log(LOG_ERROR, "Unable to update stale cached object type '%s', ID '%s'.\n",
1269 }
1270 }
1271 ao2_unlock(cached);
1272}
#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 873 of file res_sorcery_memory_cache.c.

874{
875 struct sorcery_memory_cache *cache = data;
876 struct sorcery_memory_cached_object *cached;
877
878 cached = sorcery_memory_cached_object_alloc(arg, cache, obj);
879 if (!cached) {
880 return CMP_STOP;
881 }
882
883 add_to_cache(cache, cached);
884 ao2_ref(cached, -1);
885
886 return 0;
887}
@ CMP_STOP
Definition astobj2.h:1028

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

Referenced by memory_cache_populate_internal(), and stale_cache_update().

◆ object_stale_callback()

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

Definition at line 595 of file res_sorcery_memory_cache.c.

596{
597 struct sorcery_memory_cached_object *cached = obj;
598 struct sorcery_memory_cache *cache = arg;
599
600 /* Since our granularity is seconds it's possible for something to retrieve us within a window
601 * where we wouldn't be treated as stale. To ensure that doesn't happen we use the configured stale
602 * time plus a second.
603 */
604 cached->created = ast_tvsub(cached->created, ast_samp2tv(cache->object_lifetime_stale + 1, 1));
605
606 return CMP_MATCH;
607}
@ 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 572 of file res_sorcery_memory_cache.c.

573{
574 while (ast_heap_pop(cache->object_heap)) {
575 }
576
578 NULL, NULL);
579
580 cache->del_expire = 1;
581 AST_SCHED_DEL_UNREF(sched, cache->expire_id, ao2_ref(cache, -1));
582 cache->del_expire = 0;
583}
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_external(), memory_cache_populate_internal(), sorcery_memory_cache_ami_expire(), sorcery_memory_cache_close(), sorcery_memory_cache_expire(), 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 483 of file res_sorcery_memory_cache.c.

484{
485 struct sorcery_memory_cached_object *hash_object;
486 struct sorcery_memory_cached_object *oldest_object;
487 struct sorcery_memory_cached_object *heap_object;
488
489 hash_object = ao2_find(cache->objects, id, OBJ_SEARCH_KEY | OBJ_UNLINK | OBJ_NOLOCK);
490 if (!hash_object) {
491 return -1;
492 }
493
494 ast_assert(!strcmp(ast_sorcery_object_get_id(hash_object->object), id));
495
496 oldest_object = ast_heap_peek(cache->object_heap, 1);
497 heap_object = ast_heap_remove(cache->object_heap, hash_object);
498
499 ast_assert(heap_object == hash_object);
500
501 ao2_ref(hash_object, -1);
502
503 if (reschedule && (oldest_object == heap_object)) {
505 }
506
507 return 0;
508}
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 713 of file res_sorcery_memory_cache.c.

714{
715 struct sorcery_memory_cached_object *heap_old_object;
716 struct sorcery_memory_cached_object *hash_old_object;
717
718 heap_old_object = ast_heap_pop(cache->object_heap);
719 if (!heap_old_object) {
720 return -1;
721 }
722 hash_old_object = ao2_find(cache->objects, heap_old_object,
724
725 ast_assert(heap_old_object == hash_old_object);
726
727 ao2_ref(hash_old_object, -1);
728
730
731 return 0;
732}

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 666 of file res_sorcery_memory_cache.c.

667{
668 struct sorcery_memory_cached_object *cached;
669 int expiration = 0;
670
671 if (!cache->object_lifetime_maximum) {
672 return 0;
673 }
674
675 cache->del_expire = 1;
676 AST_SCHED_DEL_UNREF(sched, cache->expire_id, ao2_ref(cache, -1));
677 cache->del_expire = 0;
678
679 cached = ast_heap_peek(cache->object_heap, 1);
680 if (!cached) {
681#ifdef TEST_FRAMEWORK
682 ast_mutex_lock(&cache->lock);
683 cache->cache_completed = 1;
684 ast_cond_signal(&cache->cond);
685 ast_mutex_unlock(&cache->lock);
686#endif
687 return 0;
688 }
689
690 expiration = MAX(ast_tvdiff_ms(ast_tvadd(cached->created, ast_samp2tv(cache->object_lifetime_maximum, 1)), ast_tvnow()),
691 1);
692
694 if (cache->expire_id < 0) {
695 ao2_ref(cache, -1);
696 return -1;
697 }
698
699 return 0;
700}
#define ast_mutex_unlock(a)
Definition lock.h:197
#define ast_mutex_lock(a)
Definition lock.h:196
#define ast_cond_signal(cond)
Definition lock.h:210
static int expire_objects_from_cache(const void *data)
#define MAX(a, b)
Definition utils.h:254

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 279 of file res_sorcery_memory_cache.c.

280{
281 uint32_t *passthru_update_thread_id;
282
283 passthru_update_thread_id = ast_threadstorage_get(&passthru_update_id_storage,
284 sizeof(*passthru_update_thread_id));
285 if (!passthru_update_thread_id) {
286 ast_log(LOG_ERROR, "Could not set passthru update ID for sorcery memory cache thread\n");
287 return;
288 }
289
290 *passthru_update_thread_id = value;
291}

References ast_log, ast_threadstorage_get(), LOG_ERROR, 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 2261 of file res_sorcery_memory_cache.c.

2262{
2263 const char *cache_name = astman_get_header(m, "Cache");
2265
2266 if (ast_strlen_zero(cache_name)) {
2267 astman_send_error(s, m, "SorceryMemoryCacheExpire requires that a cache name be provided.\n");
2268 return 0;
2269 }
2270
2271 cache = ao2_find(caches, cache_name, OBJ_SEARCH_KEY);
2272 if (!cache) {
2273 astman_send_error(s, m, "The provided cache does not exist\n");
2274 return 0;
2275 }
2276
2277 ao2_wrlock(cache->objects);
2279 ao2_unlock(cache->objects);
2280
2281 ao2_ref(cache, -1);
2282
2283 astman_send_ack(s, m, "All objects were expired from the cache\n");
2284
2285 return 0;
2286}
void astman_send_error(struct mansession *s, const struct message *m, char *error)
Send error in manager transaction.
Definition manager.c:1982
void astman_send_ack(struct mansession *s, const struct message *m, char *msg)
Send ack in manager transaction.
Definition manager.c:2014
const char * astman_get_header(const struct message *m, char *var)
Get header from manager transaction.
Definition manager.c:1643

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 2215 of file res_sorcery_memory_cache.c.

2216{
2217 const char *cache_name = astman_get_header(m, "Cache");
2218 const char *object_name = astman_get_header(m, "Object");
2220 int res;
2221
2222 if (ast_strlen_zero(cache_name)) {
2223 astman_send_error(s, m, "SorceryMemoryCacheExpireObject requires that a cache name be provided.\n");
2224 return 0;
2225 } else if (ast_strlen_zero(object_name)) {
2226 astman_send_error(s, m, "SorceryMemoryCacheExpireObject requires that an object name be provided\n");
2227 return 0;
2228 }
2229
2230 cache = ao2_find(caches, cache_name, OBJ_SEARCH_KEY);
2231 if (!cache) {
2232 astman_send_error(s, m, "The provided cache does not exist\n");
2233 return 0;
2234 }
2235
2236 ao2_wrlock(cache->objects);
2237 if (cache->full_backend_cache) {
2238 res = 1;
2239 } else {
2240 res = remove_from_cache(cache, object_name, 1);
2241 }
2242 ao2_unlock(cache->objects);
2243
2244 ao2_ref(cache, -1);
2245
2246 if (res == 1) {
2247 astman_send_error(s, m, "Due to full backend caching per-object expiration is not available, consider using SorceryMemoryCachePopulate or SorceryMemoryCacheExpire instead\n");
2248 } else if (!res) {
2249 astman_send_ack(s, m, "The provided object was expired from the cache\n");
2250 } else {
2251 astman_send_error(s, m, "The provided object could not be expired from the cache\n");
2252 }
2253
2254 return 0;
2255}

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 2376 of file res_sorcery_memory_cache.c.

2377{
2378 const char *cache_name = astman_get_header(m, "Cache");
2380 struct ast_sorcery *sorcery;
2381 const char *object_type;
2382 int cache_population_result;
2383
2384 if (ast_strlen_zero(cache_name)) {
2385 astman_send_error(s, m, "SorceryMemoryCachePopulate requires that a cache name be provided.\n");
2386 return 0;
2387 }
2388
2389 cache = ao2_find(caches, cache_name, OBJ_SEARCH_KEY);
2390 if (!cache) {
2391 astman_send_error(s, m, "The provided cache does not exist\n");
2392 return 0;
2393 }
2394
2395 if (!cache->full_backend_cache) {
2396 astman_send_error(s, m, "The provided cache does not have full backend caching enabled\n");
2397 ao2_ref(cache, -1);
2398 return 0;
2399 }
2400
2401 /* Acquire the populate lock to ensure only one population at a time */
2402 ast_mutex_lock(&cache->populate_lock);
2403
2404 /* Quick check with read lock to see if cache is still active */
2405 ao2_rdlock(cache->objects);
2406 if (!cache->sorcery) {
2407 astman_send_error(s, m, "The provided cache is no longer active\n");
2408 ao2_unlock(cache->objects);
2409 ast_mutex_unlock(&cache->populate_lock);
2410 ao2_ref(cache, -1);
2411 return 0;
2412 }
2413
2414 /* Get sorcery reference while we have the lock, safe to un-const as the ao2 ref change is allowed and safe */
2415 sorcery = ao2_bump((struct ast_sorcery *)cache->sorcery);
2416 object_type = cache->object_type;
2417
2418 /* Unlock and populate the cache - memory_cache_populate_external will handle locking internally */
2419 ao2_unlock(cache->objects);
2420 cache_population_result = memory_cache_populate_external(sorcery, object_type, cache);
2421
2422 ao2_ref(sorcery, -1);
2423 ast_mutex_unlock(&cache->populate_lock);
2424 ao2_ref(cache, -1);
2425
2426 if (cache_population_result < 0) {
2427 astman_send_error(s, m, "An error occurred while populating the cache\n");
2428 } else {
2429 astman_send_ack(s, m, "Cache has been expired and populated\n");
2430 }
2431
2432 return 0;
2433}
static int memory_cache_populate_external(const struct ast_sorcery *sorcery, const char *type, struct sorcery_memory_cache *cache)

References ao2_bump, ao2_find, ao2_rdlock, ao2_ref, ao2_unlock, ast_mutex_lock, ast_mutex_unlock, ast_strlen_zero(), astman_get_header(), astman_send_ack(), astman_send_error(), cache, caches, memory_cache_populate_external(), OBJ_SEARCH_KEY, and sorcery.

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 2345 of file res_sorcery_memory_cache.c.

2346{
2347 const char *cache_name = astman_get_header(m, "Cache");
2349
2350 if (ast_strlen_zero(cache_name)) {
2351 astman_send_error(s, m, "SorceryMemoryCacheStale requires that a cache name be provided.\n");
2352 return 0;
2353 }
2354
2355 cache = ao2_find(caches, cache_name, OBJ_SEARCH_KEY);
2356 if (!cache) {
2357 astman_send_error(s, m, "The provided cache does not exist\n");
2358 return 0;
2359 }
2360
2361 ao2_rdlock(cache->objects);
2363 ao2_unlock(cache->objects);
2364
2365 ao2_ref(cache, -1);
2366
2367 astman_send_ack(s, m, "All objects were marked as stale in the cache\n");
2368
2369 return 0;
2370}
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 2292 of file res_sorcery_memory_cache.c.

2293{
2294 const char *cache_name = astman_get_header(m, "Cache");
2295 const char *object_name = astman_get_header(m, "Object");
2296 const char *reload = astman_get_header(m, "Reload");
2298 int res;
2299
2300 if (ast_strlen_zero(cache_name)) {
2301 astman_send_error(s, m, "SorceryMemoryCacheStaleObject requires that a cache name be provided.\n");
2302 return 0;
2303 } else if (ast_strlen_zero(object_name)) {
2304 astman_send_error(s, m, "SorceryMemoryCacheStaleObject requires that an object name be provided\n");
2305 return 0;
2306 }
2307
2308 cache = ao2_find(caches, cache_name, OBJ_SEARCH_KEY);
2309 if (!cache) {
2310 astman_send_error(s, m, "The provided cache does not exist\n");
2311 return 0;
2312 }
2313
2314 ao2_rdlock(cache->objects);
2315
2316 res = mark_object_as_stale_in_cache(cache, object_name);
2317
2318 if (ast_true(reload)) {
2319 struct sorcery_memory_cached_object *cached;
2320
2321 cached = ao2_find(cache->objects, object_name, OBJ_SEARCH_KEY | OBJ_NOLOCK);
2322 if (cached) {
2323 memory_cache_stale_update_object(cache->sorcery, cache, cached);
2324 ao2_ref(cached, -1);
2325 }
2326 }
2327
2328 ao2_unlock(cache->objects);
2329
2330 ao2_ref(cache, -1);
2331
2332 if (!res) {
2333 astman_send_ack(s, m, "The provided object was marked as stale in the cache\n");
2334 } else {
2335 astman_send_error(s, m, "The provided object could not be marked as stale in the cache\n");
2336 }
2337
2338 return 0;
2339}
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:2235

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 1749 of file res_sorcery_memory_cache.c.

1750{
1751 struct sorcery_memory_cache *cache = data;
1752
1753 /* This can occur if a cache is created but never loaded */
1754 if (!ast_strlen_zero(cache->name)) {
1756 }
1757
1758 if (cache->object_lifetime_maximum) {
1759 /* If object lifetime support is enabled we need to explicitly drop all cached objects here
1760 * and stop the scheduled task. Failure to do so could potentially keep the cache around for
1761 * a prolonged period of time.
1762 */
1763 ao2_wrlock(cache->objects);
1765 ao2_unlock(cache->objects);
1766 }
1767
1768 if (cache->full_backend_cache) {
1769 ao2_wrlock(cache->objects);
1770 cache->sorcery = NULL;
1771 ao2_unlock(cache->objects);
1772 }
1773
1774 ao2_ref(cache, -1);
1775}
#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 346 of file res_sorcery_memory_cache.c.

347{
348 const struct sorcery_memory_cache *left = obj;
349 const struct sorcery_memory_cache *right = arg;
350 const char *right_name = arg;
351 int cmp;
352
353 switch (flags & OBJ_SEARCH_MASK) {
354 default:
356 right_name = right->name;
357 /* Fall through */
358 case OBJ_SEARCH_KEY:
359 cmp = strcmp(left->name, right_name);
360 break;
362 cmp = strncmp(left->name, right_name, strlen(right_name));
363 break;
364 }
365 return cmp ? 0 : CMP_MATCH;
366}
@ 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 1781 of file res_sorcery_memory_cache.c.

1782{
1784 struct ao2_iterator it_caches;
1785 int wordlen = strlen(word);
1786 int which = 0;
1787 char *result = NULL;
1788
1789 it_caches = ao2_iterator_init(caches, 0);
1790 while ((cache = ao2_iterator_next(&it_caches))) {
1791 if (!strncasecmp(word, cache->name, wordlen)
1792 && ++which > state) {
1793 result = ast_strdup(cache->name);
1794 }
1795 ao2_ref(cache, -1);
1796 if (result) {
1797 break;
1798 }
1799 }
1800 ao2_iterator_destroy(&it_caches);
1801 return result;
1802}
#define ast_strdup(str)
A wrapper for strdup()
Definition astmm.h:241
short word

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 1954 of file res_sorcery_memory_cache.c.

1955{
1957 struct sorcery_memory_cached_object *cached;
1958 struct ao2_iterator it_cached;
1959 int wordlen = strlen(word);
1960 int which = 0;
1961 char *result = NULL;
1962
1963 cache = ao2_find(caches, cache_name, OBJ_SEARCH_KEY);
1964 if (!cache) {
1965 return NULL;
1966 }
1967
1968 it_cached = ao2_iterator_init(cache->objects, 0);
1969 while ((cached = ao2_iterator_next(&it_cached))) {
1970 if (!strncasecmp(word, ast_sorcery_object_get_id(cached->object), wordlen)
1971 && ++which > state) {
1973 }
1974 ao2_ref(cached, -1);
1975 if (result) {
1976 break;
1977 }
1978 }
1979 ao2_iterator_destroy(&it_cached);
1980
1981 ao2_ref(cache, -1);
1982
1983 return result;
1984}

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 823 of file res_sorcery_memory_cache.c.

824{
825 struct sorcery_memory_cache *cache = data;
826 struct sorcery_memory_cached_object *cached;
827
829 if (!cached) {
830 return -1;
831 }
832
833 /* As there is no guarantee that this won't be called by multiple threads wanting to cache
834 * the same object we remove any old ones, which turns this into a create/update function
835 * in reality. As well since there's no guarantee that the object in the cache is the same
836 * one here we remove any old objects using the object identifier.
837 */
838
839 ao2_wrlock(cache->objects);
841 if (cache->maximum_objects && ao2_container_count(cache->objects) >= cache->maximum_objects) {
843 ast_log(LOG_ERROR, "Unable to make room in cache for sorcery object '%s'.\n",
845 ao2_unlock(cache->objects);
846 ao2_ref(cached, -1);
847 return -1;
848 }
849 ast_assert(ao2_container_count(cache->objects) != cache->maximum_objects);
850 }
851 if (add_to_cache(cache, cached)) {
852 ast_log(LOG_ERROR, "Unable to add object '%s' to the cache\n",
854 ao2_unlock(cache->objects);
855 ao2_ref(cached, -1);
856 return -1;
857 }
858 ao2_unlock(cache->objects);
859
860 ao2_ref(cached, -1);
861 return 0;
862}
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 1727 of file res_sorcery_memory_cache.c.

1728{
1729 struct sorcery_memory_cache *cache = data;
1730 int res;
1731
1732 ao2_wrlock(cache->objects);
1734 ao2_unlock(cache->objects);
1735
1736 if (res) {
1737 ast_debug(1, "Unable to delete object '%s' from sorcery cache\n", ast_sorcery_object_get_id(object));
1738 }
1739
1740 return res;
1741}

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 439 of file res_sorcery_memory_cache.c.

440{
441 struct sorcery_memory_cache *cache = obj;
442
443 ast_free(cache->name);
444 if (cache->object_heap) {
445 ast_heap_destroy(cache->object_heap);
446 }
447 ao2_cleanup(cache->objects);
448 ast_free(cache->object_type);
449 ast_mutex_destroy(&cache->populate_lock);
450}
#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
#define ast_mutex_destroy(a)
Definition lock.h:195

References ao2_cleanup, ast_free, ast_heap_destroy(), ast_mutex_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 1897 of file res_sorcery_memory_cache.c.

1898{
1899#define FORMAT "%-25.25s %-15.15s %-15.15s \n"
1901 struct print_object_details details;
1902
1903 switch (cmd) {
1904 case CLI_INIT:
1905 e->command = "sorcery memory cache dump";
1906 e->usage =
1907 "Usage: sorcery memory cache dump <name>\n"
1908 " Dump a list of the objects within the cache, listed by object identifier.\n";
1909 return NULL;
1910 case CLI_GENERATE:
1911 if (a->pos == 4) {
1912 return sorcery_memory_cache_complete_name(a->word, a->n);
1913 } else {
1914 return NULL;
1915 }
1916 }
1917
1918 if (a->argc != 5) {
1919 return CLI_SHOWUSAGE;
1920 }
1921
1922 cache = ao2_find(caches, a->argv[4], OBJ_SEARCH_KEY);
1923 if (!cache) {
1924 ast_cli(a->fd, "Specified sorcery memory cache '%s' does not exist\n", a->argv[4]);
1925 return CLI_FAILURE;
1926 }
1927
1928 details.cache = cache;
1929 details.a = a;
1930
1931 ast_cli(a->fd, "Dumping sorcery memory cache '%s':\n", cache->name);
1932 if (!cache->object_lifetime_stale) {
1933 ast_cli(a->fd, " * Staleness is not enabled - objects will not go stale\n");
1934 }
1935 if (!cache->object_lifetime_maximum) {
1936 ast_cli(a->fd, " * Object lifetime is not enabled - objects will not expire\n");
1937 }
1938 ast_cli(a->fd, FORMAT, "Object Name", "Stale In", "Expires In");
1939 ast_cli(a->fd, FORMAT, "-------------------------", "---------------", "---------------");
1941 ast_cli(a->fd, FORMAT, "-------------------------", "---------------", "---------------");
1942 ast_cli(a->fd, "Total number of objects cached: %d\n", ao2_container_count(cache->objects));
1943
1944 ao2_ref(cache, -1);
1945
1946 return CLI_SUCCESS;
1947#undef FORMAT
1948}
#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 1990 of file res_sorcery_memory_cache.c.

1991{
1993
1994 switch (cmd) {
1995 case CLI_INIT:
1996 e->command = "sorcery memory cache expire";
1997 e->usage =
1998 "Usage: sorcery memory cache expire <cache name> [object name]\n"
1999 " Expire a specific object or ALL objects within a sorcery memory cache.\n";
2000 return NULL;
2001 case CLI_GENERATE:
2002 if (a->pos == 4) {
2003 return sorcery_memory_cache_complete_name(a->word, a->n);
2004 } else if (a->pos == 5) {
2005 return sorcery_memory_cache_complete_object_name(a->argv[4], a->word, a->n);
2006 } else {
2007 return NULL;
2008 }
2009 }
2010
2011 if (a->argc < 5 || a->argc > 6) {
2012 return CLI_SHOWUSAGE;
2013 }
2014
2015 cache = ao2_find(caches, a->argv[4], OBJ_SEARCH_KEY);
2016 if (!cache) {
2017 ast_cli(a->fd, "Specified sorcery memory cache '%s' does not exist\n", a->argv[4]);
2018 return CLI_FAILURE;
2019 }
2020
2021 ao2_wrlock(cache->objects);
2022 if (a->argc == 5) {
2024 ast_cli(a->fd, "All objects have been removed from cache '%s'\n", a->argv[4]);
2025 } else {
2026 if (cache->full_backend_cache) {
2027 ast_cli(a->fd, "Due to full backend caching per-object expiration is not available on cache '%s'\n", a->argv[4]);
2028 } else if (!remove_from_cache(cache, a->argv[5], 1)) {
2029 ast_cli(a->fd, "Successfully expired object '%s' from cache '%s'\n", a->argv[5], a->argv[4]);
2030 } else {
2031 ast_cli(a->fd, "Object '%s' was not expired from cache '%s' as it was not found\n", a->argv[5],
2032 a->argv[4]);
2033 }
2034 }
2035 ao2_unlock(cache->objects);
2036
2037 ao2_ref(cache, -1);
2038
2039 return CLI_SUCCESS;
2040}
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 1378 of file res_sorcery_memory_cache.c.

1379{
1380 struct sorcery_memory_cached_object *cached = obj;
1381 const struct sorcery_memory_cache_fields_cmp_params *params = arg;
1383
1384 if (params->regex) {
1385 /* If a regular expression has been provided see if it matches, otherwise move on */
1386 if (!regexec(params->regex, ast_sorcery_object_get_id(cached->object), 0, NULL, 0)) {
1387 ao2_link(params->container, cached->object);
1388 }
1389 return 0;
1390 } else if (params->prefix) {
1391 if (!strncmp(params->prefix, ast_sorcery_object_get_id(cached->object), params->prefix_len)) {
1392 ao2_link(params->container, cached->object);
1393 }
1394 return 0;
1395 } else if (params->fields &&
1396 (!ast_variable_lists_match(cached->objectset, params->fields, 0))) {
1397 /* If we can't turn the object into an object set OR if differences exist between the fields
1398 * passed in and what are present on the object they are not a match.
1399 */
1400 return 0;
1401 }
1402
1403 if (params->container) {
1404 ao2_link(params->container, cached->object);
1405
1406 /* As multiple objects are being returned keep going */
1407 return 0;
1408 } else {
1409 /* Immediately stop and return, we only want a single object */
1410 return CMP_MATCH | CMP_STOP;
1411 }
1412}
#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.
void ast_variables_destroy(struct ast_variable *var)
Free variable list.
Definition extconf.c:1260
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:981

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 312 of file res_sorcery_memory_cache.c.

313{
314 const struct sorcery_memory_cache *cache = obj;
315 const char *name = obj;
316 int hash;
317
318 switch (flags & OBJ_SEARCH_MASK) {
319 default:
321 name = cache->name;
322 /* Fall through */
323 case OBJ_SEARCH_KEY:
324 hash = ast_str_hash(name);
325 break;
327 /* Should never happen in hash callback. */
328 ast_assert(0);
329 hash = 0;
330 break;
331 }
332 return hash;
333}
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 1560 of file res_sorcery_memory_cache.c.

1561{
1562 struct sorcery_memory_cache *cache = data;
1563
1564 /* If no name was explicitly specified generate one given the sorcery instance and object type */
1565 if (ast_strlen_zero(cache->name)) {
1567 }
1568
1570 ast_debug(1, "Memory cache '%s' associated with sorcery instance '%p' of module '%s' with object type '%s'\n",
1572
1573 cache->sorcery = sorcery;
1574 cache->object_type = ast_strdup(type);
1575}
#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:2600

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 1632 of file res_sorcery_memory_cache.c.

1633{
1634 char *options = ast_strdupa(data), *option;
1636
1638 if (!cache) {
1639 return NULL;
1640 }
1641
1642 cache->expire_id = -1;
1643 cache->stale_update_sched_id = -1;
1644
1645 /* If no configuration options have been provided this memory cache will operate in a default
1646 * configuration.
1647 */
1648 while (!ast_strlen_zero(options) && (option = strsep(&options, ","))) {
1649 char *name = strsep(&option, "="), *value = option;
1650
1651 if (!strcasecmp(name, "name")) {
1652 if (ast_strlen_zero(value)) {
1653 ast_log(LOG_ERROR, "A name must be specified for the memory cache\n");
1654 return NULL;
1655 }
1656 ast_free(cache->name);
1657 cache->name = ast_strdup(value);
1658 } else if (!strcasecmp(name, "maximum_objects")) {
1659 if (configuration_parse_unsigned_integer(value, &cache->maximum_objects) != 1) {
1660 ast_log(LOG_ERROR, "Unsupported maximum objects value of '%s' used for memory cache\n",
1661 value);
1662 return NULL;
1663 }
1664 } else if (!strcasecmp(name, "object_lifetime_maximum")) {
1665 if (configuration_parse_unsigned_integer(value, &cache->object_lifetime_maximum) != 1) {
1666 ast_log(LOG_ERROR, "Unsupported object maximum lifetime value of '%s' used for memory cache\n",
1667 value);
1668 return NULL;
1669 }
1670 } else if (!strcasecmp(name, "object_lifetime_stale")) {
1671 if (configuration_parse_unsigned_integer(value, &cache->object_lifetime_stale) != 1) {
1672 ast_log(LOG_ERROR, "Unsupported object stale lifetime value of '%s' used for memory cache\n",
1673 value);
1674 return NULL;
1675 }
1676 } else if (!strcasecmp(name, "expire_on_reload")) {
1677 cache->expire_on_reload = ast_true(value);
1678 } else if (!strcasecmp(name, "full_backend_cache")) {
1679 cache->full_backend_cache = ast_true(value);
1680 } else {
1681 ast_log(LOG_ERROR, "Unsupported option '%s' used for memory cache\n", name);
1682 return NULL;
1683 }
1684 }
1685
1687 cache->maximum_objects ? cache->maximum_objects : CACHE_CONTAINER_BUCKET_SIZE,
1689 if (!cache->objects) {
1690 ast_log(LOG_ERROR, "Could not create a container to hold cached objects for memory cache\n");
1691 return NULL;
1692 }
1693
1695 offsetof(struct sorcery_memory_cached_object, __heap_index));
1696 if (!cache->object_heap) {
1697 ast_log(LOG_ERROR, "Could not create heap to hold cached objects\n");
1698 return NULL;
1699 }
1700
1701 if (ast_mutex_init(&cache->populate_lock)) {
1702 ast_log(LOG_ERROR, "Could not create populate lock for cache\n");
1703 return NULL;
1704 }
1705
1706 /* The memory cache is not linked to the caches container until the load callback is invoked.
1707 * Linking occurs there so an intelligent cache name can be constructed using the module of
1708 * the sorcery instance and the specific object type if no cache name was specified as part
1709 * of the configuration.
1710 */
1711
1712 /* This is done as RAII_VAR will drop the reference */
1713 return ao2_bump(cache);
1714}
char * strsep(char **str, const char *delims)
#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
#define ast_mutex_init(pmutex)
Definition lock.h:193
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_mutex_init, 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 2130 of file res_sorcery_memory_cache.c.

2131{
2133 struct ast_sorcery *sorcery;
2134 const char *object_type;
2135 int num_cached;
2136
2137 switch (cmd) {
2138 case CLI_INIT:
2139 e->command = "sorcery memory cache populate";
2140 e->usage =
2141 "Usage: sorcery memory cache populate <cache name>\n"
2142 " Expire all objects in the cache and populate it with ALL objects from backend.\n";
2143 return NULL;
2144 case CLI_GENERATE:
2145 if (a->pos == 4) {
2146 return sorcery_memory_cache_complete_name(a->word, a->n);
2147 } else {
2148 return NULL;
2149 }
2150 }
2151
2152 if (a->argc != 5) {
2153 return CLI_SHOWUSAGE;
2154 }
2155
2156 cache = ao2_find(caches, a->argv[4], OBJ_SEARCH_KEY);
2157 if (!cache) {
2158 ast_cli(a->fd, "Specified sorcery memory cache '%s' does not exist\n", a->argv[4]);
2159 return CLI_FAILURE;
2160 }
2161
2162 if (!cache->full_backend_cache) {
2163 ast_cli(a->fd, "Specified sorcery memory cache '%s' does not have full backend caching enabled\n", a->argv[4]);
2164 ao2_ref(cache, -1);
2165 return CLI_FAILURE;
2166 }
2167
2168 /* Acquire the populate lock to ensure only one population at a time */
2169 ast_mutex_lock(&cache->populate_lock);
2170
2171 /* Quick check with read lock to see if cache is still active */
2172 ao2_rdlock(cache->objects);
2173 if (!cache->sorcery) {
2174 ast_cli(a->fd, "Specified sorcery memory cache '%s' is no longer active\n", a->argv[4]);
2175 ao2_unlock(cache->objects);
2176 ast_mutex_unlock(&cache->populate_lock);
2177 ao2_ref(cache, -1);
2178 return CLI_FAILURE;
2179 }
2180
2181 /* Get sorcery reference while we have the lock, safe to un-const as the ao2 ref change is allowed and safe */
2182 sorcery = ao2_bump((struct ast_sorcery *)cache->sorcery);
2183 object_type = cache->object_type;
2184
2185 /* Unlock and populate the cache - memory_cache_populate_external will handle locking internally */
2186 ao2_unlock(cache->objects);
2187 num_cached = memory_cache_populate_external(sorcery, object_type, cache);
2188
2189 ao2_ref(sorcery, -1);
2190 ast_mutex_unlock(&cache->populate_lock);
2191 ao2_ref(cache, -1);
2192
2193 if (num_cached < 0) {
2194 ast_cli(a->fd, "An error occurred while populating sorcery memory cache '%s'\n", a->argv[4]);
2195 } else {
2196 ast_cli(a->fd, "Specified sorcery memory cache '%s' has been populated with '%d' objects from the backend\n",
2197 a->argv[4], num_cached);
2198 }
2199
2200 return CLI_SUCCESS;
2201}

References a, ao2_bump, ao2_find, ao2_rdlock, ao2_ref, ao2_unlock, ast_cli(), ast_mutex_lock, ast_mutex_unlock, cache, caches, CLI_FAILURE, CLI_GENERATE, CLI_INIT, CLI_SHOWUSAGE, CLI_SUCCESS, ast_cli_entry::command, memory_cache_populate_external(), NULL, OBJ_SEARCH_KEY, sorcery, 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 1873 of file res_sorcery_memory_cache.c.

1874{
1875#define FORMAT "%-25.25s %-15u %-15u \n"
1876 struct sorcery_memory_cached_object *cached = obj;
1877 struct print_object_details *details = arg;
1878 int seconds_until_expire = 0, seconds_until_stale = 0;
1879
1880 if (details->cache->object_lifetime_maximum) {
1881 seconds_until_expire = ast_tvdiff_ms(ast_tvadd(cached->created, ast_samp2tv(details->cache->object_lifetime_maximum, 1)), ast_tvnow()) / 1000;
1882 }
1883 if (details->cache->object_lifetime_stale) {
1884 seconds_until_stale = ast_tvdiff_ms(ast_tvadd(cached->created, ast_samp2tv(details->cache->object_lifetime_stale, 1)), ast_tvnow()) / 1000;
1885 }
1886
1887 ast_cli(details->a->fd, FORMAT, ast_sorcery_object_get_id(cached->object), MAX(seconds_until_stale, 0), MAX(seconds_until_expire, 0));
1888
1889 return CMP_MATCH;
1890#undef FORMAT
1891}
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 1585 of file res_sorcery_memory_cache.c.

1586{
1587 struct sorcery_memory_cache *cache = data;
1588
1589 if (!cache->expire_on_reload) {
1590 return;
1591 }
1592
1593 ao2_wrlock(cache->objects);
1595 ao2_unlock(cache->objects);
1596}

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 1423 of file res_sorcery_memory_cache.c.

1425{
1426 struct sorcery_memory_cache *cache = data;
1428 .sorcery = sorcery,
1429 .cache = cache,
1430 .fields = fields,
1431 };
1432 struct sorcery_memory_cached_object *cached;
1433 void *object = NULL;
1434
1435 if (is_passthru_update() || !cache->full_backend_cache || !fields) {
1436 return NULL;
1437 }
1438
1439 cached = ao2_callback(cache->objects, 0, sorcery_memory_cache_fields_cmp, &params);
1440
1441 if (cached) {
1443 object = ao2_bump(cached->object);
1444 ao2_ref(cached, -1);
1445 }
1446
1447 return object;
1448}
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 1343 of file res_sorcery_memory_cache.c.

1344{
1345 struct sorcery_memory_cache *cache = data;
1346 struct sorcery_memory_cached_object *cached;
1347 void *object;
1348
1349 if (is_passthru_update()) {
1350 return NULL;
1351 }
1352
1354
1355 cached = ao2_find(cache->objects, id, OBJ_SEARCH_KEY);
1356 if (!cached) {
1357 return NULL;
1358 }
1359
1360 ast_assert(!strcmp(ast_sorcery_object_get_id(cached->object), id));
1361
1363
1364 object = ao2_bump(cached->object);
1365 ao2_ref(cached, -1);
1366
1367 return object;
1368}
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 1460 of file res_sorcery_memory_cache.c.

1462{
1463 struct sorcery_memory_cache *cache = data;
1465 .sorcery = sorcery,
1466 .cache = cache,
1467 .fields = fields,
1468 .container = objects,
1469 };
1470
1471 if (is_passthru_update() || !cache->full_backend_cache) {
1472 return;
1473 }
1474
1476 ao2_callback(cache->objects, 0, sorcery_memory_cache_fields_cmp, &params);
1477
1478 if (ao2_container_count(objects)) {
1480 }
1481}
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 1528 of file res_sorcery_memory_cache.c.

1530{
1531 struct sorcery_memory_cache *cache = data;
1533 .sorcery = sorcery,
1534 .cache = cache,
1535 .container = objects,
1536 .prefix = prefix,
1537 .prefix_len = prefix_len,
1538 };
1539
1540 if (is_passthru_update() || !cache->full_backend_cache) {
1541 return;
1542 }
1543
1545 ao2_callback(cache->objects, 0, sorcery_memory_cache_fields_cmp, &params);
1546
1547 if (ao2_container_count(objects)) {
1549 }
1550}
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 1493 of file res_sorcery_memory_cache.c.

1495{
1496 struct sorcery_memory_cache *cache = data;
1497 regex_t expression;
1499 .sorcery = sorcery,
1500 .cache = cache,
1501 .container = objects,
1502 .regex = &expression,
1503 };
1504
1505 if (is_passthru_update() || !cache->full_backend_cache || regcomp(&expression, regex, REG_EXTENDED | REG_NOSUB)) {
1506 return;
1507 }
1508
1510 ao2_callback(cache->objects, 0, sorcery_memory_cache_fields_cmp, &params);
1511 regfree(&expression);
1512
1513 if (ao2_container_count(objects)) {
1515 }
1516}
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 1808 of file res_sorcery_memory_cache.c.

1809{
1811
1812 switch (cmd) {
1813 case CLI_INIT:
1814 e->command = "sorcery memory cache show";
1815 e->usage =
1816 "Usage: sorcery memory cache show <name>\n"
1817 " Show sorcery memory cache configuration and statistics.\n";
1818 return NULL;
1819 case CLI_GENERATE:
1820 if (a->pos == 4) {
1821 return sorcery_memory_cache_complete_name(a->word, a->n);
1822 } else {
1823 return NULL;
1824 }
1825 }
1826
1827 if (a->argc != 5) {
1828 return CLI_SHOWUSAGE;
1829 }
1830
1831 cache = ao2_find(caches, a->argv[4], OBJ_SEARCH_KEY);
1832 if (!cache) {
1833 ast_cli(a->fd, "Specified sorcery memory cache '%s' does not exist\n", a->argv[4]);
1834 return CLI_FAILURE;
1835 }
1836
1837 ast_cli(a->fd, "Sorcery memory cache: %s\n", cache->name);
1838 ast_cli(a->fd, "Number of objects within cache: %d\n", ao2_container_count(cache->objects));
1839 if (cache->maximum_objects) {
1840 ast_cli(a->fd, "Maximum allowed objects: %d\n", cache->maximum_objects);
1841 } else {
1842 ast_cli(a->fd, "There is no limit on the maximum number of objects in the cache\n");
1843 }
1844 if (cache->object_lifetime_maximum) {
1845 ast_cli(a->fd, "Number of seconds before object expires: %d\n", cache->object_lifetime_maximum);
1846 } else {
1847 ast_cli(a->fd, "Object expiration is not enabled - cached objects will not expire\n");
1848 }
1849 if (cache->object_lifetime_stale) {
1850 ast_cli(a->fd, "Number of seconds before object becomes stale: %d\n", cache->object_lifetime_stale);
1851 } else {
1852 ast_cli(a->fd, "Object staleness is not enabled - cached objects will not go stale\n");
1853 }
1854 ast_cli(a->fd, "Expire all objects on reload: %s\n", AST_CLI_ONOFF(cache->expire_on_reload));
1855
1856 ao2_ref(cache, -1);
1857
1858 return CLI_SUCCESS;
1859}
#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 2046 of file res_sorcery_memory_cache.c.

2047{
2049 int reload = 0;
2050
2051 switch (cmd) {
2052 case CLI_INIT:
2053 e->command = "sorcery memory cache stale";
2054 e->usage =
2055 "Usage: sorcery memory cache stale <cache name> [object name [reload]]\n"
2056 " Mark a specific object or ALL objects as stale in a sorcery memory cache.\n"
2057 " If \"reload\" is specified, then the object is marked stale and immediately\n"
2058 " retrieved from backend storage to repopulate the cache\n";
2059 return NULL;
2060 case CLI_GENERATE:
2061 if (a->pos == 4) {
2062 return sorcery_memory_cache_complete_name(a->word, a->n);
2063 } else if (a->pos == 5) {
2064 return sorcery_memory_cache_complete_object_name(a->argv[4], a->word, a->n);
2065 } else if (a->pos == 6) {
2066 static const char * const completions[] = { "reload", NULL };
2067 return ast_cli_complete(a->word, completions, a->n);
2068 } else {
2069 return NULL;
2070 }
2071 }
2072
2073 if (a->argc < 5 || a->argc > 7) {
2074 return CLI_SHOWUSAGE;
2075 }
2076
2077 if (a->argc == 7) {
2078 if (!strcasecmp(a->argv[6], "reload")) {
2079 reload = 1;
2080 } else {
2081 return CLI_SHOWUSAGE;
2082 }
2083 }
2084
2085 cache = ao2_find(caches, a->argv[4], OBJ_SEARCH_KEY);
2086 if (!cache) {
2087 ast_cli(a->fd, "Specified sorcery memory cache '%s' does not exist\n", a->argv[4]);
2088 return CLI_FAILURE;
2089 }
2090
2091 if (!cache->object_lifetime_stale) {
2092 ast_cli(a->fd, "Specified sorcery memory cache '%s' does not have staleness enabled\n", a->argv[4]);
2093 ao2_ref(cache, -1);
2094 return CLI_FAILURE;
2095 }
2096
2097 ao2_rdlock(cache->objects);
2098 if (a->argc == 5) {
2100 ast_cli(a->fd, "Marked all objects in sorcery memory cache '%s' as stale\n", a->argv[4]);
2101 } else {
2102 if (!mark_object_as_stale_in_cache(cache, a->argv[5])) {
2103 ast_cli(a->fd, "Successfully marked object '%s' in memory cache '%s' as stale\n",
2104 a->argv[5], a->argv[4]);
2105 if (reload) {
2106 struct sorcery_memory_cached_object *cached;
2107
2108 cached = ao2_find(cache->objects, a->argv[5], OBJ_SEARCH_KEY | OBJ_NOLOCK);
2109 if (cached) {
2110 memory_cache_stale_update_object(cache->sorcery, cache, cached);
2111 ao2_ref(cached, -1);
2112 }
2113 }
2114 } else {
2115 ast_cli(a->fd, "Object '%s' in sorcery memory cache '%s' could not be marked as stale as it was not found\n",
2116 a->argv[5], a->argv[4]);
2117 }
2118 }
2119 ao2_unlock(cache->objects);
2120
2121 ao2_ref(cache, -1);
2122
2123 return CLI_SUCCESS;
2124}
char * ast_cli_complete(const char *word, const char *const choices[], int pos)
Definition main/cli.c:1931

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 784 of file res_sorcery_memory_cache.c.

786{
787 struct sorcery_memory_cached_object *cached;
788
789 cached = ao2_alloc(sizeof(*cached), sorcery_memory_cached_object_destructor);
790 if (!cached) {
791 return NULL;
792 }
793
794 cached->object = ao2_bump(object);
795 cached->created = ast_tvnow();
796 cached->stale_update_sched_id = -1;
797
798 if (cache->full_backend_cache) {
799 /* A cached objectset allows us to easily perform all retrieval operations in a
800 * minimal of time.
801 */
803 if (!cached->objectset) {
804 ao2_ref(cached, -1);
805 return NULL;
806 }
807 }
808
809 return cached;
810}
#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 memory_cache_populate_external(), 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 411 of file res_sorcery_memory_cache.c.

412{
413 struct sorcery_memory_cached_object *left = obj;
414 struct sorcery_memory_cached_object *right = arg;
415 const char *right_name = arg;
416 int cmp;
417
418 switch (flags & OBJ_SEARCH_MASK) {
419 default:
421 right_name = ast_sorcery_object_get_id(right->object);
422 /* Fall through */
423 case OBJ_SEARCH_KEY:
424 cmp = strcmp(ast_sorcery_object_get_id(left->object), right_name);
425 break;
427 cmp = strncmp(ast_sorcery_object_get_id(left->object), right_name, strlen(right_name));
428 break;
429 }
430 return cmp ? 0 : CMP_MATCH;
431}

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 377 of file res_sorcery_memory_cache.c.

378{
379 const struct sorcery_memory_cached_object *cached = obj;
380 const char *name = obj;
381 int hash;
382
383 switch (flags & OBJ_SEARCH_MASK) {
384 default:
387 /* Fall through */
388 case OBJ_SEARCH_KEY:
389 hash = ast_str_hash(name);
390 break;
392 /* Should never happen in hash callback. */
393 ast_assert(0);
394 hash = 0;
395 break;
396 }
397 return hash;
398}

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 926 of file res_sorcery_memory_cache.c.

927{
929 struct ao2_container *backend_objects;
930
932 backend_objects = ast_sorcery_retrieve_by_fields(task_data->sorcery, task_data->type,
935
936 if (!backend_objects) {
937 task_data->cache->stale_update_sched_id = -1;
938 ao2_ref(task_data, -1);
939 return 0;
940 }
941
942 if (task_data->cache->maximum_objects && ao2_container_count(backend_objects) >= task_data->cache->maximum_objects) {
943 ast_log(LOG_ERROR, "The backend contains %d objects while the sorcery memory cache '%s' is explicitly configured to only allow %d\n",
944 ao2_container_count(backend_objects), task_data->cache->name, task_data->cache->maximum_objects);
945 task_data->cache->stale_update_sched_id = -1;
946 ao2_ref(task_data, -1);
947 return 0;
948 }
949
950 ao2_wrlock(task_data->cache->objects);
953 task_data->sorcery, task_data->cache);
954
955 /* If the number of cached objects does not match the number of backend objects we encountered a memory allocation
956 * failure and the cache is incomplete, so drop everything and fall back to querying the backend directly
957 * as it may be able to provide what is wanted.
958 */
959 if (ao2_container_count(task_data->cache->objects) != ao2_container_count(backend_objects)) {
960 ast_log(LOG_WARNING, "The backend contains %d objects while only %d could be added to sorcery memory cache '%s'\n",
961 ao2_container_count(backend_objects), ao2_container_count(task_data->cache->objects), task_data->cache->name);
963 }
964
965 ao2_unlock(task_data->cache->objects);
966 ao2_ref(backend_objects, -1);
967
968 task_data->cache->stale_update_sched_id = -1;
969 ao2_ref(task_data, -1);
970
971 return 0;
972}

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 904 of file res_sorcery_memory_cache.c.

906{
908
911 if (!task_data) {
912 return NULL;
913 }
914
915 task_data->sorcery = ao2_bump(sorcery);
916 task_data->cache = ao2_bump(cache);
917 task_data->type = ast_strdup(type);
918 if (!task_data->type) {
919 ao2_ref(task_data, -1);
920 return NULL;
921 }
922
923 return task_data;
924}
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 895 of file res_sorcery_memory_cache.c.

896{
898
899 ao2_cleanup(task_data->cache);
901 ast_free(task_data->type);
902}
#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 1007 of file res_sorcery_memory_cache.c.

1008{
1010 void *object;
1011
1013
1014 object = ast_sorcery_retrieve_by_id(task_data->sorcery,
1017 if (!object) {
1018 ast_debug(1, "Backend no longer has object type '%s' ID '%s'. Removing from cache\n",
1022 task_data->object);
1023 } else {
1024 ast_debug(1, "Refreshing stale cache object type '%s' ID '%s'\n",
1028 object);
1029 ao2_ref(object, -1);
1030 }
1031
1032 ast_test_suite_event_notify("SORCERY_MEMORY_CACHE_REFRESHED", "Cache: %s\r\nType: %s\r\nName: %s\r\n",
1033 task_data->cache->name, ast_sorcery_object_get_type(task_data->object),
1035
1036 ao2_ref(task_data, -1);
1038
1039 return 0;
1040}
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:1917
#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 989 of file res_sorcery_memory_cache.c.

991{
993
996 if (!task_data) {
997 return NULL;
998 }
999
1000 task_data->sorcery = ao2_bump(sorcery);
1001 task_data->cache = ao2_bump(cache);
1002 task_data->object = ao2_bump(object);
1003
1004 return task_data;
1005}
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 980 of file res_sorcery_memory_cache.c.

981{
982 struct stale_update_task_data *task_data = obj;
983
984 ao2_cleanup(task_data->cache);
985 ao2_cleanup(task_data->object);
987}

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 3663 of file res_sorcery_memory_cache.c.

3664{
3665 AST_TEST_UNREGISTER(open_with_valid_options);
3666 AST_TEST_UNREGISTER(open_with_invalid_options);
3667 AST_TEST_UNREGISTER(create_and_retrieve);
3669 AST_TEST_UNREGISTER(delete);
3670 AST_TEST_UNREGISTER(maximum_objects);
3671 AST_TEST_UNREGISTER(expiration);
3672 AST_TEST_UNREGISTER(stale);
3673 AST_TEST_UNREGISTER(full_backend_cache_expiration);
3674 AST_TEST_UNREGISTER(full_backend_cache_stale);
3675
3676 ast_manager_unregister("SorceryMemoryCacheExpireObject");
3677 ast_manager_unregister("SorceryMemoryCacheExpire");
3678 ast_manager_unregister("SorceryMemoryCacheStaleObject");
3679 ast_manager_unregister("SorceryMemoryCacheStale");
3680 ast_manager_unregister("SorceryMemoryCachePopulate");
3681
3683
3685
3686 /*
3687 * XXX There is the potential to leak memory if there are pending
3688 * next-cache-expiration and stale-cache-update tasks in the scheduler.
3689 */
3690 if (sched) {
3692 sched = NULL;
3693 }
3694
3696 caches = NULL;
3697
3698 return 0;
3699}
void ast_cli_unregister_multiple(void)
Definition ael_main.c:408
int ast_manager_unregister(const char *action)
Unregister a registered manager command.
Definition manager.c:7698
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:538
#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 = ASTERISK_GPL_KEY , .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 3766 of file res_sorcery_memory_cache.c.

◆ ast_module_info

const struct ast_module_info* ast_module_info = &__mod_info
static

Definition at line 3766 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 2203 of file res_sorcery_memory_cache.c.

2203 {
2204 AST_CLI_DEFINE(sorcery_memory_cache_show, "Show sorcery memory cache information"),
2205 AST_CLI_DEFINE(sorcery_memory_cache_dump, "Dump all objects within a sorcery memory cache"),
2206 AST_CLI_DEFINE(sorcery_memory_cache_expire, "Expire a specific object or ALL objects within a sorcery memory cache"),
2207 AST_CLI_DEFINE(sorcery_memory_cache_stale, "Mark a specific object or ALL objects as stale within a sorcery memory cache"),
2208 AST_CLI_DEFINE(sorcery_memory_cache_populate, "Clear and populate the sorcery memory cache with objects from the backend"),
2209};
#define AST_CLI_DEFINE(fn, txt,...)
Definition cli.h:197
static char * sorcery_memory_cache_dump(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 char * sorcery_memory_cache_show(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 char * sorcery_memory_cache_populate(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)

Referenced by load_module(), and unload_module().

◆ memory_cache_object_wizard

struct ast_sorcery_wizard memory_cache_object_wizard
static

Definition at line 232 of file res_sorcery_memory_cache.c.

232 {
233 .name = "memory_cache",
241 .retrieve_fields = sorcery_memory_cache_retrieve_fields,
242 .retrieve_multiple = sorcery_memory_cache_retrieve_multiple,
243 .retrieve_regex = sorcery_memory_cache_retrieve_regex,
244 .retrieve_prefix = sorcery_memory_cache_retrieve_prefix,
246};
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_regex(const struct ast_sorcery *sorcery, void *data, const char *type, struct ao2_container *objects, const char *regex)
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_reload(void *data, const struct ast_sorcery *sorcery, const char *type)
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 void sorcery_memory_cache_close(void *data)
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)

Referenced by load_module(), and unload_module().

◆ sched

struct ast_sched_context* sched
static

Scheduler for cache management.

Definition at line 261 of file res_sorcery_memory_cache.c.