Asterisk - The Open Source Telephony Project GIT-master-27fb039
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 void memory_cache_populate (const struct ast_sorcery *sorcery, const char *type, struct sorcery_memory_cache *cache)
 
static void memory_cache_stale_check (const struct ast_sorcery *sorcery, struct sorcery_memory_cache *cache)
 
static void memory_cache_stale_check_object (const struct ast_sorcery *sorcery, struct sorcery_memory_cache *cache, struct sorcery_memory_cached_object *cached)
 
static void memory_cache_stale_update_full (const struct ast_sorcery *sorcery, struct sorcery_memory_cache *cache, const char *type)
 
static void memory_cache_stale_update_object (const struct ast_sorcery *sorcery, struct sorcery_memory_cache *cache, struct sorcery_memory_cached_object *cached)
 
static int object_add_to_cache_callback (void *obj, void *arg, void *data, int flags)
 
static int object_stale_callback (void *obj, void *arg, int flags)
 
static void remove_all_from_cache (struct sorcery_memory_cache *cache)
 
static int remove_from_cache (struct sorcery_memory_cache *cache, const char *id, int reschedule)
 
static int remove_oldest_from_cache (struct sorcery_memory_cache *cache)
 
static int schedule_cache_expiration (struct sorcery_memory_cache *cache)
 
static void set_passthru_update (uint32_t value)
 
static int sorcery_memory_cache_ami_expire (struct mansession *s, const struct message *m)
 
static int sorcery_memory_cache_ami_expire_object (struct mansession *s, const struct message *m)
 
static int sorcery_memory_cache_ami_populate (struct mansession *s, const struct message *m)
 
static int sorcery_memory_cache_ami_stale (struct mansession *s, const struct message *m)
 
static int sorcery_memory_cache_ami_stale_object (struct mansession *s, const struct message *m)
 
static void sorcery_memory_cache_close (void *data)
 
static int sorcery_memory_cache_cmp (void *obj, void *arg, int flags)
 
static char * sorcery_memory_cache_complete_name (const char *word, int state)
 
static char * sorcery_memory_cache_complete_object_name (const char *cache_name, const char *word, int state)
 
static int sorcery_memory_cache_create (const struct ast_sorcery *sorcery, void *data, void *object)
 
static int sorcery_memory_cache_delete (const struct ast_sorcery *sorcery, void *data, void *object)
 
static void sorcery_memory_cache_destructor (void *obj)
 
static char * sorcery_memory_cache_dump (struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
 
static char * sorcery_memory_cache_expire (struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
 
static int sorcery_memory_cache_fields_cmp (void *obj, void *arg, int flags)
 
static int sorcery_memory_cache_hash (const void *obj, int flags)
 
static void sorcery_memory_cache_load (void *data, const struct ast_sorcery *sorcery, const char *type)
 
static void * sorcery_memory_cache_open (const char *data)
 
static char * sorcery_memory_cache_populate (struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
 
static int sorcery_memory_cache_print_object (void *obj, void *arg, int flags)
 
static void sorcery_memory_cache_reload (void *data, const struct ast_sorcery *sorcery, const char *type)
 
static void * sorcery_memory_cache_retrieve_fields (const struct ast_sorcery *sorcery, void *data, const char *type, const struct ast_variable *fields)
 
static void * sorcery_memory_cache_retrieve_id (const struct ast_sorcery *sorcery, void *data, const char *type, const char *id)
 
static void sorcery_memory_cache_retrieve_multiple (const struct ast_sorcery *sorcery, void *data, const char *type, struct ao2_container *objects, const struct ast_variable *fields)
 
static void sorcery_memory_cache_retrieve_prefix (const struct ast_sorcery *sorcery, void *data, const char *type, struct ao2_container *objects, const char *prefix, const size_t prefix_len)
 
static void sorcery_memory_cache_retrieve_regex (const struct ast_sorcery *sorcery, void *data, const char *type, struct ao2_container *objects, const char *regex)
 
static char * sorcery_memory_cache_show (struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
 
static char * sorcery_memory_cache_stale (struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
 
static struct sorcery_memory_cached_objectsorcery_memory_cached_object_alloc (const struct ast_sorcery *sorcery, const struct sorcery_memory_cache *cache, void *object)
 
static int sorcery_memory_cached_object_cmp (void *obj, void *arg, int flags)
 
static void sorcery_memory_cached_object_destructor (void *obj)
 
static int sorcery_memory_cached_object_hash (const void *obj, int flags)
 
static int stale_cache_update (const void *data)
 
static struct stale_cache_update_task_datastale_cache_update_task_data_alloc (struct ast_sorcery *sorcery, struct sorcery_memory_cache *cache, const char *type)
 
static void stale_cache_update_task_data_destructor (void *obj)
 
static int stale_item_update (const void *data)
 
static struct stale_update_task_datastale_update_task_data_alloc (struct ast_sorcery *sorcery, struct sorcery_memory_cache *cache, const char *type, void *object)
 
static void stale_update_task_data_destructor (void *obj)
 
static void start_passthru_update (void)
 
static int unload_module (void)
 

Variables

static struct ast_module_info __mod_info = { .name = AST_MODULE, .flags = AST_MODFLAG_GLOBAL_SYMBOLS | AST_MODFLAG_LOAD_ORDER , .description = "Sorcery Memory Cache Object Wizard" , .key = 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 250 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 253 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 247 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 261 of file res_sorcery_memory_cache.c.

Function Documentation

◆ __reg_module()

static void __reg_module ( void  )
static

Definition at line 3618 of file res_sorcery_memory_cache.c.

◆ __unreg_module()

static void __unreg_module ( void  )
static

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

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

◆ age_cmp()

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

Definition at line 1508 of file res_sorcery_memory_cache.c.

1509{
1510 return ast_tvcmp(((struct sorcery_memory_cached_object *) b)->created,
1511 ((struct sorcery_memory_cached_object *) a)->created);
1512}
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 3618 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 1499 of file res_sorcery_memory_cache.c.

1500{
1501 if (ast_strlen_zero(value) || !strncmp(value, "-", 1)) {
1502 return 0;
1503 }
1504
1505 return sscanf(value, "%30u", result);
1506}
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 296 of file res_sorcery_memory_cache.c.

297{
299}
static void set_passthru_update(uint32_t value)

References set_passthru_update().

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

◆ expire_objects_from_cache()

static int expire_objects_from_cache ( const void *  data)
static

Definition at line 513 of file res_sorcery_memory_cache.c.

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

265{
266 uint32_t *passthru_update_thread_id;
267
268 passthru_update_thread_id = ast_threadstorage_get(&passthru_update_id_storage,
269 sizeof(*passthru_update_thread_id));
270 if (!passthru_update_thread_id) {
271 return 0;
272 }
273
274 return *passthru_update_thread_id == PASSTHRU_UPDATE_THREAD_ID;
275}
#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 3553 of file res_sorcery_memory_cache.c.

3554{
3555 int res;
3556
3560 if (!caches) {
3561 ast_log(LOG_ERROR, "Failed to create container for configured caches\n");
3562 unload_module();
3564 }
3565
3567 if (!sched) {
3568 ast_log(LOG_ERROR, "Failed to create scheduler for cache management\n");
3569 unload_module();
3571 }
3572
3574 ast_log(LOG_ERROR, "Failed to create scheduler thread for cache management\n");
3575 unload_module();
3577 }
3578
3580 unload_module();
3582 }
3583
3590
3591 if (res) {
3592 unload_module();
3594 }
3595
3596 /* This causes the stale unit test to execute last, so if a sorcery instance persists
3597 * longer than expected subsequent unit tests don't fail when setting it up.
3598 */
3599 AST_TEST_REGISTER(stale);
3600 AST_TEST_REGISTER(open_with_valid_options);
3601 AST_TEST_REGISTER(open_with_invalid_options);
3602 AST_TEST_REGISTER(create_and_retrieve);
3604 AST_TEST_REGISTER(delete);
3605 AST_TEST_REGISTER(maximum_objects);
3606 AST_TEST_REGISTER(expiration);
3607 AST_TEST_REGISTER(full_backend_cache_expiration);
3608 AST_TEST_REGISTER(full_backend_cache_stale);
3609
3611}
#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 647 of file res_sorcery_memory_cache.c.

648{
650}
#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 620 of file res_sorcery_memory_cache.c.

621{
622 struct sorcery_memory_cached_object *cached;
623
624 cached = ao2_find(cache->objects, id, OBJ_SEARCH_KEY | OBJ_NOLOCK);
625 if (!cached) {
626 return -1;
627 }
628
629 ast_assert(!strcmp(ast_sorcery_object_get_id(cached->object), id));
630
631 object_stale_callback(cached, cache, 0);
632 ao2_ref(cached, -1);
633
634 return 0;
635}
@ 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 1092 of file res_sorcery_memory_cache.c.

1093{
1094 if (!cache->full_backend_cache) {
1095 return;
1096 }
1097
1098 ao2_wrlock(cache->objects);
1099 if (!ao2_container_count(cache->objects)) {
1101 }
1102 ao2_unlock(cache->objects);
1103}
#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(const struct ast_sorcery *sorcery, const char *type, struct sorcery_memory_cache *cache)

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

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

◆ memory_cache_populate()

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

Definition at line 1049 of file res_sorcery_memory_cache.c.

1050{
1051 struct ao2_container *backend_objects;
1052
1056
1057 if (!backend_objects) {
1058 /* This will occur in off-nominal memory allocation failure scenarios */
1059 return;
1060 }
1061
1062 if (cache->maximum_objects && ao2_container_count(backend_objects) >= cache->maximum_objects) {
1063 ast_log(LOG_ERROR, "The backend contains %d objects while the sorcery memory cache '%s' is explicitly configured to only allow %d\n",
1064 ao2_container_count(backend_objects), cache->name, cache->maximum_objects);
1065 return;
1066 }
1067
1069 (struct ast_sorcery*)sorcery, cache);
1070
1071 /* If the number of cached objects does not match the number of backend objects we encountered a memory allocation
1072 * failure and the cache is incomplete, so drop everything and fall back to querying the backend directly
1073 * as it may be able to provide what is wanted.
1074 */
1075 if (ao2_container_count(cache->objects) != ao2_container_count(backend_objects)) {
1076 ast_log(LOG_WARNING, "The backend contains %d objects while only %d could be added to sorcery memory cache '%s'\n",
1077 ao2_container_count(backend_objects), ao2_container_count(cache->objects), cache->name);
1079 }
1080
1081 ao2_ref(backend_objects, -1);
1082}
#define ao2_callback_data(container, flags, cb_fn, arg, data)
Definition astobj2.h:1723
#define LOG_WARNING
static void end_passthru_update(void)
static void start_passthru_update(void)
static int object_add_to_cache_callback(void *obj, void *arg, void *data, int flags)
static void remove_all_from_cache(struct sorcery_memory_cache *cache)
@ AST_RETRIEVE_FLAG_MULTIPLE
Return all matching objects.
Definition sorcery.h:120
@ AST_RETRIEVE_FLAG_ALL
Perform no matching, return all objects.
Definition sorcery.h:123
void * ast_sorcery_retrieve_by_fields(const struct ast_sorcery *sorcery, const char *type, unsigned int flags, struct ast_variable *fields)
Retrieve an object or multiple objects using specific fields.
Definition sorcery.c:1961
Generic container type.
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(), sorcery_memory_cache_ami_populate(), and sorcery_memory_cache_populate().

◆ memory_cache_stale_check()

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

Definition at line 1206 of file res_sorcery_memory_cache.c.

1207{
1208 struct sorcery_memory_cached_object *cached;
1209
1210 ao2_rdlock(cache->objects);
1211 cached = ao2_bump(ast_heap_peek(cache->object_heap, 1));
1212 ao2_unlock(cache->objects);
1213
1214 if (!cached) {
1215 return;
1216 }
1217
1219 ao2_ref(cached, -1);
1220}
#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 1173 of file res_sorcery_memory_cache.c.

1175{
1176 struct timeval elapsed;
1177
1178 if (!cache->object_lifetime_stale) {
1179 return;
1180 }
1181
1182 /* For a full cache as every object has the same expiration/staleness we can do the same check */
1183 elapsed = ast_tvsub(ast_tvnow(), cached->created);
1184
1185 if (elapsed.tv_sec < cache->object_lifetime_stale) {
1186 return;
1187 }
1188
1189 if (cache->full_backend_cache) {
1191 } else {
1193 }
1194
1195}
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 1113 of file res_sorcery_memory_cache.c.

1115{
1116 ao2_wrlock(cache->objects);
1117 if (cache->stale_update_sched_id == -1) {
1119
1121 cache, type);
1122 if (task_data) {
1123 cache->stale_update_sched_id = ast_sched_add(sched, 1,
1125 }
1126 if (cache->stale_update_sched_id < 0) {
1128 }
1129 }
1130 ao2_unlock(cache->objects);
1131}
#define ao2_cleanup(obj)
Definition astobj2.h:1934
static struct stale_cache_update_task_data * stale_cache_update_task_data_alloc(struct ast_sorcery *sorcery, struct sorcery_memory_cache *cache, const char *type)
static int stale_cache_update(const void *data)
int ast_sched_add(struct ast_sched_context *con, int when, ast_sched_cb callback, const void *data) attribute_warn_unused_result
Adds a scheduled event.
Definition sched.c:567
userdata associated with baseline taskprocessor test

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

Referenced by memory_cache_stale_check_object().

◆ memory_cache_stale_update_object()

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

Definition at line 1141 of file res_sorcery_memory_cache.c.

1143{
1144 ao2_lock(cached);
1145 if (cached->stale_update_sched_id == -1) {
1147
1149 cache, ast_sorcery_object_get_type(cached->object), cached->object);
1150 if (task_data) {
1151 ast_debug(1, "Cached sorcery object type '%s' ID '%s' is stale. Refreshing\n",
1155 }
1156 if (cached->stale_update_sched_id < 0) {
1158 ast_log(LOG_ERROR, "Unable to update stale cached object type '%s', ID '%s'.\n",
1160 }
1161 }
1162 ao2_unlock(cached);
1163}
#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 870 of file res_sorcery_memory_cache.c.

871{
872 struct sorcery_memory_cache *cache = data;
873 struct sorcery_memory_cached_object *cached;
874
875 cached = sorcery_memory_cached_object_alloc(arg, cache, obj);
876 if (!cached) {
877 return CMP_STOP;
878 }
879
880 add_to_cache(cache, cached);
881 ao2_ref(cached, -1);
882
883 return 0;
884}
@ CMP_STOP
Definition astobj2.h:1028
static struct sorcery_memory_cached_object * sorcery_memory_cached_object_alloc(const struct ast_sorcery *sorcery, const struct sorcery_memory_cache *cache, void *object)
static int add_to_cache(struct sorcery_memory_cache *cache, struct sorcery_memory_cached_object *cached_object)

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

Referenced by memory_cache_populate(), and stale_cache_update().

◆ object_stale_callback()

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

Definition at line 592 of file res_sorcery_memory_cache.c.

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

570{
571 while (ast_heap_pop(cache->object_heap)) {
572 }
573
575 NULL, NULL);
576
577 cache->del_expire = 1;
578 AST_SCHED_DEL_UNREF(sched, cache->expire_id, ao2_ref(cache, -1));
579 cache->del_expire = 0;
580}
void * ast_heap_pop(struct ast_heap *h)
Pop the max element off of the heap.
Definition heap.c:262
#define AST_SCHED_DEL_UNREF(sched, id, refcall)
schedule task to get deleted and call unref function
Definition sched.h:82

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

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

◆ remove_from_cache()

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

Definition at line 480 of file res_sorcery_memory_cache.c.

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

711{
712 struct sorcery_memory_cached_object *heap_old_object;
713 struct sorcery_memory_cached_object *hash_old_object;
714
715 heap_old_object = ast_heap_pop(cache->object_heap);
716 if (!heap_old_object) {
717 return -1;
718 }
719 hash_old_object = ao2_find(cache->objects, heap_old_object,
721
722 ast_assert(heap_old_object == hash_old_object);
723
724 ao2_ref(hash_old_object, -1);
725
727
728 return 0;
729}

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

664{
665 struct sorcery_memory_cached_object *cached;
666 int expiration = 0;
667
668 if (!cache->object_lifetime_maximum) {
669 return 0;
670 }
671
672 cache->del_expire = 1;
673 AST_SCHED_DEL_UNREF(sched, cache->expire_id, ao2_ref(cache, -1));
674 cache->del_expire = 0;
675
676 cached = ast_heap_peek(cache->object_heap, 1);
677 if (!cached) {
678#ifdef TEST_FRAMEWORK
679 ast_mutex_lock(&cache->lock);
680 cache->cache_completed = 1;
681 ast_cond_signal(&cache->cond);
682 ast_mutex_unlock(&cache->lock);
683#endif
684 return 0;
685 }
686
687 expiration = MAX(ast_tvdiff_ms(ast_tvadd(cached->created, ast_samp2tv(cache->object_lifetime_maximum, 1)), ast_tvnow()),
688 1);
689
691 if (cache->expire_id < 0) {
692 ao2_ref(cache, -1);
693 return -1;
694 }
695
696 return 0;
697}
#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 277 of file res_sorcery_memory_cache.c.

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

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

2131{
2132 const char *cache_name = astman_get_header(m, "Cache");
2134
2135 if (ast_strlen_zero(cache_name)) {
2136 astman_send_error(s, m, "SorceryMemoryCacheExpire requires that a cache name be provided.\n");
2137 return 0;
2138 }
2139
2140 cache = ao2_find(caches, cache_name, OBJ_SEARCH_KEY);
2141 if (!cache) {
2142 astman_send_error(s, m, "The provided cache does not exist\n");
2143 return 0;
2144 }
2145
2146 ao2_wrlock(cache->objects);
2148 ao2_unlock(cache->objects);
2149
2150 ao2_ref(cache, -1);
2151
2152 astman_send_ack(s, m, "All objects were expired from the cache\n");
2153
2154 return 0;
2155}
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 2084 of file res_sorcery_memory_cache.c.

2085{
2086 const char *cache_name = astman_get_header(m, "Cache");
2087 const char *object_name = astman_get_header(m, "Object");
2089 int res;
2090
2091 if (ast_strlen_zero(cache_name)) {
2092 astman_send_error(s, m, "SorceryMemoryCacheExpireObject requires that a cache name be provided.\n");
2093 return 0;
2094 } else if (ast_strlen_zero(object_name)) {
2095 astman_send_error(s, m, "SorceryMemoryCacheExpireObject requires that an object name be provided\n");
2096 return 0;
2097 }
2098
2099 cache = ao2_find(caches, cache_name, OBJ_SEARCH_KEY);
2100 if (!cache) {
2101 astman_send_error(s, m, "The provided cache does not exist\n");
2102 return 0;
2103 }
2104
2105 ao2_wrlock(cache->objects);
2106 if (cache->full_backend_cache) {
2107 res = 1;
2108 } else {
2109 res = remove_from_cache(cache, object_name, 1);
2110 }
2111 ao2_unlock(cache->objects);
2112
2113 ao2_ref(cache, -1);
2114
2115 if (res == 1) {
2116 astman_send_error(s, m, "Due to full backend caching per-object expiration is not available, consider using SorceryMemoryCachePopulate or SorceryMemoryCacheExpire instead\n");
2117 } else if (!res) {
2118 astman_send_ack(s, m, "The provided object was expired from the cache\n");
2119 } else {
2120 astman_send_error(s, m, "The provided object could not be expired from the cache\n");
2121 }
2122
2123 return 0;
2124}

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

2246{
2247 const char *cache_name = astman_get_header(m, "Cache");
2249
2250 if (ast_strlen_zero(cache_name)) {
2251 astman_send_error(s, m, "SorceryMemoryCachePopulate requires that a cache name be provided.\n");
2252 return 0;
2253 }
2254
2255 cache = ao2_find(caches, cache_name, OBJ_SEARCH_KEY);
2256 if (!cache) {
2257 astman_send_error(s, m, "The provided cache does not exist\n");
2258 return 0;
2259 }
2260
2261 if (!cache->full_backend_cache) {
2262 astman_send_error(s, m, "The provided cache does not have full backend caching enabled\n");
2263 ao2_ref(cache, -1);
2264 return 0;
2265 }
2266
2267 ao2_wrlock(cache->objects);
2268 if (!cache->sorcery) {
2269 astman_send_error(s, m, "The provided cache is no longer active\n");
2270 ao2_unlock(cache->objects);
2271 ao2_ref(cache, -1);
2272 return 0;
2273 }
2274
2276 memory_cache_populate(cache->sorcery, cache->object_type, cache);
2277
2278 ao2_unlock(cache->objects);
2279
2280 ao2_ref(cache, -1);
2281
2282 astman_send_ack(s, m, "Cache has been expired and populated\n");
2283
2284 return 0;
2285}

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

Referenced by load_module().

◆ sorcery_memory_cache_ami_stale()

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

Definition at line 2214 of file res_sorcery_memory_cache.c.

2215{
2216 const char *cache_name = astman_get_header(m, "Cache");
2218
2219 if (ast_strlen_zero(cache_name)) {
2220 astman_send_error(s, m, "SorceryMemoryCacheStale requires that a cache name be provided.\n");
2221 return 0;
2222 }
2223
2224 cache = ao2_find(caches, cache_name, OBJ_SEARCH_KEY);
2225 if (!cache) {
2226 astman_send_error(s, m, "The provided cache does not exist\n");
2227 return 0;
2228 }
2229
2230 ao2_rdlock(cache->objects);
2232 ao2_unlock(cache->objects);
2233
2234 ao2_ref(cache, -1);
2235
2236 astman_send_ack(s, m, "All objects were marked as stale in the cache\n");
2237
2238 return 0;
2239}
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 2161 of file res_sorcery_memory_cache.c.

2162{
2163 const char *cache_name = astman_get_header(m, "Cache");
2164 const char *object_name = astman_get_header(m, "Object");
2165 const char *reload = astman_get_header(m, "Reload");
2167 int res;
2168
2169 if (ast_strlen_zero(cache_name)) {
2170 astman_send_error(s, m, "SorceryMemoryCacheStaleObject requires that a cache name be provided.\n");
2171 return 0;
2172 } else if (ast_strlen_zero(object_name)) {
2173 astman_send_error(s, m, "SorceryMemoryCacheStaleObject requires that an object name be provided\n");
2174 return 0;
2175 }
2176
2177 cache = ao2_find(caches, cache_name, OBJ_SEARCH_KEY);
2178 if (!cache) {
2179 astman_send_error(s, m, "The provided cache does not exist\n");
2180 return 0;
2181 }
2182
2183 ao2_rdlock(cache->objects);
2184
2185 res = mark_object_as_stale_in_cache(cache, object_name);
2186
2187 if (ast_true(reload)) {
2188 struct sorcery_memory_cached_object *cached;
2189
2190 cached = ao2_find(cache->objects, object_name, OBJ_SEARCH_KEY | OBJ_NOLOCK);
2191 if (cached) {
2192 memory_cache_stale_update_object(cache->sorcery, cache, cached);
2193 ao2_ref(cached, -1);
2194 }
2195 }
2196
2197 ao2_unlock(cache->objects);
2198
2199 ao2_ref(cache, -1);
2200
2201 if (!res) {
2202 astman_send_ack(s, m, "The provided object was marked as stale in the cache\n");
2203 } else {
2204 astman_send_error(s, m, "The provided object could not be marked as stale in the cache\n");
2205 }
2206
2207 return 0;
2208}
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 1635 of file res_sorcery_memory_cache.c.

1636{
1637 struct sorcery_memory_cache *cache = data;
1638
1639 /* This can occur if a cache is created but never loaded */
1640 if (!ast_strlen_zero(cache->name)) {
1642 }
1643
1644 if (cache->object_lifetime_maximum) {
1645 /* If object lifetime support is enabled we need to explicitly drop all cached objects here
1646 * and stop the scheduled task. Failure to do so could potentially keep the cache around for
1647 * a prolonged period of time.
1648 */
1649 ao2_wrlock(cache->objects);
1651 ao2_unlock(cache->objects);
1652 }
1653
1654 if (cache->full_backend_cache) {
1655 ao2_wrlock(cache->objects);
1656 cache->sorcery = NULL;
1657 ao2_unlock(cache->objects);
1658 }
1659
1660 ao2_ref(cache, -1);
1661}
#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 344 of file res_sorcery_memory_cache.c.

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

1668{
1670 struct ao2_iterator it_caches;
1671 int wordlen = strlen(word);
1672 int which = 0;
1673 char *result = NULL;
1674
1675 it_caches = ao2_iterator_init(caches, 0);
1676 while ((cache = ao2_iterator_next(&it_caches))) {
1677 if (!strncasecmp(word, cache->name, wordlen)
1678 && ++which > state) {
1679 result = ast_strdup(cache->name);
1680 }
1681 ao2_ref(cache, -1);
1682 if (result) {
1683 break;
1684 }
1685 }
1686 ao2_iterator_destroy(&it_caches);
1687 return result;
1688}
#define ast_strdup(str)
A wrapper for strdup()
Definition astmm.h:241
#define ao2_iterator_next(iter)
Definition astobj2.h:1911
struct ao2_iterator ao2_iterator_init(struct ao2_container *c, int flags) attribute_warn_unused_result
Create an iterator for a container.
void ao2_iterator_destroy(struct ao2_iterator *iter)
Destroy a container iterator.
short word
When we need to walk through a container, we use an ao2_iterator to keep track of the current positio...
Definition astobj2.h:1821

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

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

◆ sorcery_memory_cache_complete_object_name()

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

Definition at line 1840 of file res_sorcery_memory_cache.c.

1841{
1843 struct sorcery_memory_cached_object *cached;
1844 struct ao2_iterator it_cached;
1845 int wordlen = strlen(word);
1846 int which = 0;
1847 char *result = NULL;
1848
1849 cache = ao2_find(caches, cache_name, OBJ_SEARCH_KEY);
1850 if (!cache) {
1851 return NULL;
1852 }
1853
1854 it_cached = ao2_iterator_init(cache->objects, 0);
1855 while ((cached = ao2_iterator_next(&it_cached))) {
1856 if (!strncasecmp(word, ast_sorcery_object_get_id(cached->object), wordlen)
1857 && ++which > state) {
1859 }
1860 ao2_ref(cached, -1);
1861 if (result) {
1862 break;
1863 }
1864 }
1865 ao2_iterator_destroy(&it_cached);
1866
1867 ao2_ref(cache, -1);
1868
1869 return result;
1870}

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

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

1614{
1615 struct sorcery_memory_cache *cache = data;
1616 int res;
1617
1618 ao2_wrlock(cache->objects);
1620 ao2_unlock(cache->objects);
1621
1622 if (res) {
1623 ast_debug(1, "Unable to delete object '%s' from sorcery cache\n", ast_sorcery_object_get_id(object));
1624 }
1625
1626 return res;
1627}

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

438{
439 struct sorcery_memory_cache *cache = obj;
440
441 ast_free(cache->name);
442 if (cache->object_heap) {
443 ast_heap_destroy(cache->object_heap);
444 }
445 ao2_cleanup(cache->objects);
446 ast_free(cache->object_type);
447}
#define ast_free(a)
Definition astmm.h:180
struct ast_heap * ast_heap_destroy(struct ast_heap *h)
Destroy a max heap.
Definition heap.c:146

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

Referenced by sorcery_memory_cache_open().

◆ sorcery_memory_cache_dump()

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

Definition at line 1783 of file res_sorcery_memory_cache.c.

1784{
1785#define FORMAT "%-25.25s %-15.15s %-15.15s \n"
1787 struct print_object_details details;
1788
1789 switch (cmd) {
1790 case CLI_INIT:
1791 e->command = "sorcery memory cache dump";
1792 e->usage =
1793 "Usage: sorcery memory cache dump <name>\n"
1794 " Dump a list of the objects within the cache, listed by object identifier.\n";
1795 return NULL;
1796 case CLI_GENERATE:
1797 if (a->pos == 4) {
1798 return sorcery_memory_cache_complete_name(a->word, a->n);
1799 } else {
1800 return NULL;
1801 }
1802 }
1803
1804 if (a->argc != 5) {
1805 return CLI_SHOWUSAGE;
1806 }
1807
1808 cache = ao2_find(caches, a->argv[4], OBJ_SEARCH_KEY);
1809 if (!cache) {
1810 ast_cli(a->fd, "Specified sorcery memory cache '%s' does not exist\n", a->argv[4]);
1811 return CLI_FAILURE;
1812 }
1813
1814 details.cache = cache;
1815 details.a = a;
1816
1817 ast_cli(a->fd, "Dumping sorcery memory cache '%s':\n", cache->name);
1818 if (!cache->object_lifetime_stale) {
1819 ast_cli(a->fd, " * Staleness is not enabled - objects will not go stale\n");
1820 }
1821 if (!cache->object_lifetime_maximum) {
1822 ast_cli(a->fd, " * Object lifetime is not enabled - objects will not expire\n");
1823 }
1824 ast_cli(a->fd, FORMAT, "Object Name", "Stale In", "Expires In");
1825 ast_cli(a->fd, FORMAT, "-------------------------", "---------------", "---------------");
1827 ast_cli(a->fd, FORMAT, "-------------------------", "---------------", "---------------");
1828 ast_cli(a->fd, "Total number of objects cached: %d\n", ao2_container_count(cache->objects));
1829
1830 ao2_ref(cache, -1);
1831
1832 return CLI_SUCCESS;
1833#undef FORMAT
1834}
#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 1876 of file res_sorcery_memory_cache.c.

1877{
1879
1880 switch (cmd) {
1881 case CLI_INIT:
1882 e->command = "sorcery memory cache expire";
1883 e->usage =
1884 "Usage: sorcery memory cache expire <cache name> [object name]\n"
1885 " Expire a specific object or ALL objects within a sorcery memory cache.\n";
1886 return NULL;
1887 case CLI_GENERATE:
1888 if (a->pos == 4) {
1889 return sorcery_memory_cache_complete_name(a->word, a->n);
1890 } else if (a->pos == 5) {
1891 return sorcery_memory_cache_complete_object_name(a->argv[4], a->word, a->n);
1892 } else {
1893 return NULL;
1894 }
1895 }
1896
1897 if (a->argc < 5 || a->argc > 6) {
1898 return CLI_SHOWUSAGE;
1899 }
1900
1901 cache = ao2_find(caches, a->argv[4], OBJ_SEARCH_KEY);
1902 if (!cache) {
1903 ast_cli(a->fd, "Specified sorcery memory cache '%s' does not exist\n", a->argv[4]);
1904 return CLI_FAILURE;
1905 }
1906
1907 ao2_wrlock(cache->objects);
1908 if (a->argc == 5) {
1910 ast_cli(a->fd, "All objects have been removed from cache '%s'\n", a->argv[4]);
1911 } else {
1912 if (cache->full_backend_cache) {
1913 ast_cli(a->fd, "Due to full backend caching per-object expiration is not available on cache '%s'\n", a->argv[4]);
1914 } else if (!remove_from_cache(cache, a->argv[5], 1)) {
1915 ast_cli(a->fd, "Successfully expired object '%s' from cache '%s'\n", a->argv[5], a->argv[4]);
1916 } else {
1917 ast_cli(a->fd, "Object '%s' was not expired from cache '%s' as it was not found\n", a->argv[5],
1918 a->argv[4]);
1919 }
1920 }
1921 ao2_unlock(cache->objects);
1922
1923 ao2_ref(cache, -1);
1924
1925 return CLI_SUCCESS;
1926}
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 1269 of file res_sorcery_memory_cache.c.

1270{
1271 struct sorcery_memory_cached_object *cached = obj;
1272 const struct sorcery_memory_cache_fields_cmp_params *params = arg;
1274
1275 if (params->regex) {
1276 /* If a regular expression has been provided see if it matches, otherwise move on */
1277 if (!regexec(params->regex, ast_sorcery_object_get_id(cached->object), 0, NULL, 0)) {
1278 ao2_link(params->container, cached->object);
1279 }
1280 return 0;
1281 } else if (params->prefix) {
1282 if (!strncmp(params->prefix, ast_sorcery_object_get_id(cached->object), params->prefix_len)) {
1283 ao2_link(params->container, cached->object);
1284 }
1285 return 0;
1286 } else if (params->fields &&
1287 (!ast_variable_lists_match(cached->objectset, params->fields, 0))) {
1288 /* If we can't turn the object into an object set OR if differences exist between the fields
1289 * passed in and what are present on the object they are not a match.
1290 */
1291 return 0;
1292 }
1293
1294 if (params->container) {
1295 ao2_link(params->container, cached->object);
1296
1297 /* As multiple objects are being returned keep going */
1298 return 0;
1299 } else {
1300 /* Immediately stop and return, we only want a single object */
1301 return CMP_MATCH | CMP_STOP;
1302 }
1303}
#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 310 of file res_sorcery_memory_cache.c.

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

1452{
1453 struct sorcery_memory_cache *cache = data;
1454
1455 /* If no name was explicitly specified generate one given the sorcery instance and object type */
1456 if (ast_strlen_zero(cache->name)) {
1458 }
1459
1461 ast_debug(1, "Memory cache '%s' associated with sorcery instance '%p' of module '%s' with object type '%s'\n",
1463
1464 cache->sorcery = sorcery;
1465 cache->object_type = ast_strdup(type);
1466}
#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 1523 of file res_sorcery_memory_cache.c.

1524{
1525 char *options = ast_strdupa(data), *option;
1527
1529 if (!cache) {
1530 return NULL;
1531 }
1532
1533 cache->expire_id = -1;
1534 cache->stale_update_sched_id = -1;
1535
1536 /* If no configuration options have been provided this memory cache will operate in a default
1537 * configuration.
1538 */
1539 while (!ast_strlen_zero(options) && (option = strsep(&options, ","))) {
1540 char *name = strsep(&option, "="), *value = option;
1541
1542 if (!strcasecmp(name, "name")) {
1543 if (ast_strlen_zero(value)) {
1544 ast_log(LOG_ERROR, "A name must be specified for the memory cache\n");
1545 return NULL;
1546 }
1547 ast_free(cache->name);
1548 cache->name = ast_strdup(value);
1549 } else if (!strcasecmp(name, "maximum_objects")) {
1550 if (configuration_parse_unsigned_integer(value, &cache->maximum_objects) != 1) {
1551 ast_log(LOG_ERROR, "Unsupported maximum objects value of '%s' used for memory cache\n",
1552 value);
1553 return NULL;
1554 }
1555 } else if (!strcasecmp(name, "object_lifetime_maximum")) {
1556 if (configuration_parse_unsigned_integer(value, &cache->object_lifetime_maximum) != 1) {
1557 ast_log(LOG_ERROR, "Unsupported object maximum lifetime value of '%s' used for memory cache\n",
1558 value);
1559 return NULL;
1560 }
1561 } else if (!strcasecmp(name, "object_lifetime_stale")) {
1562 if (configuration_parse_unsigned_integer(value, &cache->object_lifetime_stale) != 1) {
1563 ast_log(LOG_ERROR, "Unsupported object stale lifetime value of '%s' used for memory cache\n",
1564 value);
1565 return NULL;
1566 }
1567 } else if (!strcasecmp(name, "expire_on_reload")) {
1568 cache->expire_on_reload = ast_true(value);
1569 } else if (!strcasecmp(name, "full_backend_cache")) {
1570 cache->full_backend_cache = ast_true(value);
1571 } else {
1572 ast_log(LOG_ERROR, "Unsupported option '%s' used for memory cache\n", name);
1573 return NULL;
1574 }
1575 }
1576
1578 cache->maximum_objects ? cache->maximum_objects : CACHE_CONTAINER_BUCKET_SIZE,
1580 if (!cache->objects) {
1581 ast_log(LOG_ERROR, "Could not create a container to hold cached objects for memory cache\n");
1582 return NULL;
1583 }
1584
1586 offsetof(struct sorcery_memory_cached_object, __heap_index));
1587 if (!cache->object_heap) {
1588 ast_log(LOG_ERROR, "Could not create heap to hold cached objects\n");
1589 return NULL;
1590 }
1591
1592 /* The memory cache is not linked to the caches container until the load callback is invoked.
1593 * Linking occurs there so an intelligent cache name can be constructed using the module of
1594 * the sorcery instance and the specific object type if no cache name was specified as part
1595 * of the configuration.
1596 */
1597
1598 /* This is done as RAII_VAR will drop the reference */
1599 return ao2_bump(cache);
1600}
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
static int configuration_parse_unsigned_integer(const char *value, unsigned int *result)
static int sorcery_memory_cached_object_cmp(void *obj, void *arg, int flags)
static void sorcery_memory_cache_destructor(void *obj)
#define CACHE_HEAP_INIT_HEIGHT
Height of heap for cache object heap. Allows 31 initial objects.
static int age_cmp(void *a, void *b)
#define CACHE_CONTAINER_BUCKET_SIZE
The default bucket size for the container of objects in the cache.
static int sorcery_memory_cached_object_hash(const void *obj, int flags)
static struct test_options options

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

◆ sorcery_memory_cache_populate()

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

Definition at line 2016 of file res_sorcery_memory_cache.c.

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

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

◆ sorcery_memory_cache_print_object()

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

Definition at line 1759 of file res_sorcery_memory_cache.c.

1760{
1761#define FORMAT "%-25.25s %-15u %-15u \n"
1762 struct sorcery_memory_cached_object *cached = obj;
1763 struct print_object_details *details = arg;
1764 int seconds_until_expire = 0, seconds_until_stale = 0;
1765
1766 if (details->cache->object_lifetime_maximum) {
1767 seconds_until_expire = ast_tvdiff_ms(ast_tvadd(cached->created, ast_samp2tv(details->cache->object_lifetime_maximum, 1)), ast_tvnow()) / 1000;
1768 }
1769 if (details->cache->object_lifetime_stale) {
1770 seconds_until_stale = ast_tvdiff_ms(ast_tvadd(cached->created, ast_samp2tv(details->cache->object_lifetime_stale, 1)), ast_tvnow()) / 1000;
1771 }
1772
1773 ast_cli(details->a->fd, FORMAT, ast_sorcery_object_get_id(cached->object), MAX(seconds_until_stale, 0), MAX(seconds_until_expire, 0));
1774
1775 return CMP_MATCH;
1776#undef FORMAT
1777}
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 1476 of file res_sorcery_memory_cache.c.

1477{
1478 struct sorcery_memory_cache *cache = data;
1479
1480 if (!cache->expire_on_reload) {
1481 return;
1482 }
1483
1484 ao2_wrlock(cache->objects);
1486 ao2_unlock(cache->objects);
1487}

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

1316{
1317 struct sorcery_memory_cache *cache = data;
1319 .sorcery = sorcery,
1320 .cache = cache,
1321 .fields = fields,
1322 };
1323 struct sorcery_memory_cached_object *cached;
1324 void *object = NULL;
1325
1326 if (is_passthru_update() || !cache->full_backend_cache || !fields) {
1327 return NULL;
1328 }
1329
1330 cached = ao2_callback(cache->objects, 0, sorcery_memory_cache_fields_cmp, &params);
1331
1332 if (cached) {
1334 object = ao2_bump(cached->object);
1335 ao2_ref(cached, -1);
1336 }
1337
1338 return object;
1339}
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 1234 of file res_sorcery_memory_cache.c.

1235{
1236 struct sorcery_memory_cache *cache = data;
1237 struct sorcery_memory_cached_object *cached;
1238 void *object;
1239
1240 if (is_passthru_update()) {
1241 return NULL;
1242 }
1243
1245
1246 cached = ao2_find(cache->objects, id, OBJ_SEARCH_KEY);
1247 if (!cached) {
1248 return NULL;
1249 }
1250
1251 ast_assert(!strcmp(ast_sorcery_object_get_id(cached->object), id));
1252
1254
1255 object = ao2_bump(cached->object);
1256 ao2_ref(cached, -1);
1257
1258 return object;
1259}
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 1351 of file res_sorcery_memory_cache.c.

1353{
1354 struct sorcery_memory_cache *cache = data;
1356 .sorcery = sorcery,
1357 .cache = cache,
1358 .fields = fields,
1359 .container = objects,
1360 };
1361
1362 if (is_passthru_update() || !cache->full_backend_cache) {
1363 return;
1364 }
1365
1367 ao2_callback(cache->objects, 0, sorcery_memory_cache_fields_cmp, &params);
1368
1369 if (ao2_container_count(objects)) {
1371 }
1372}
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 1419 of file res_sorcery_memory_cache.c.

1421{
1422 struct sorcery_memory_cache *cache = data;
1424 .sorcery = sorcery,
1425 .cache = cache,
1426 .container = objects,
1427 .prefix = prefix,
1428 .prefix_len = prefix_len,
1429 };
1430
1431 if (is_passthru_update() || !cache->full_backend_cache) {
1432 return;
1433 }
1434
1436 ao2_callback(cache->objects, 0, sorcery_memory_cache_fields_cmp, &params);
1437
1438 if (ao2_container_count(objects)) {
1440 }
1441}
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 1384 of file res_sorcery_memory_cache.c.

1386{
1387 struct sorcery_memory_cache *cache = data;
1388 regex_t expression;
1390 .sorcery = sorcery,
1391 .cache = cache,
1392 .container = objects,
1393 .regex = &expression,
1394 };
1395
1396 if (is_passthru_update() || !cache->full_backend_cache || regcomp(&expression, regex, REG_EXTENDED | REG_NOSUB)) {
1397 return;
1398 }
1399
1401 ao2_callback(cache->objects, 0, sorcery_memory_cache_fields_cmp, &params);
1402 regfree(&expression);
1403
1404 if (ao2_container_count(objects)) {
1406 }
1407}
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 1694 of file res_sorcery_memory_cache.c.

1695{
1697
1698 switch (cmd) {
1699 case CLI_INIT:
1700 e->command = "sorcery memory cache show";
1701 e->usage =
1702 "Usage: sorcery memory cache show <name>\n"
1703 " Show sorcery memory cache configuration and statistics.\n";
1704 return NULL;
1705 case CLI_GENERATE:
1706 if (a->pos == 4) {
1707 return sorcery_memory_cache_complete_name(a->word, a->n);
1708 } else {
1709 return NULL;
1710 }
1711 }
1712
1713 if (a->argc != 5) {
1714 return CLI_SHOWUSAGE;
1715 }
1716
1717 cache = ao2_find(caches, a->argv[4], OBJ_SEARCH_KEY);
1718 if (!cache) {
1719 ast_cli(a->fd, "Specified sorcery memory cache '%s' does not exist\n", a->argv[4]);
1720 return CLI_FAILURE;
1721 }
1722
1723 ast_cli(a->fd, "Sorcery memory cache: %s\n", cache->name);
1724 ast_cli(a->fd, "Number of objects within cache: %d\n", ao2_container_count(cache->objects));
1725 if (cache->maximum_objects) {
1726 ast_cli(a->fd, "Maximum allowed objects: %d\n", cache->maximum_objects);
1727 } else {
1728 ast_cli(a->fd, "There is no limit on the maximum number of objects in the cache\n");
1729 }
1730 if (cache->object_lifetime_maximum) {
1731 ast_cli(a->fd, "Number of seconds before object expires: %d\n", cache->object_lifetime_maximum);
1732 } else {
1733 ast_cli(a->fd, "Object expiration is not enabled - cached objects will not expire\n");
1734 }
1735 if (cache->object_lifetime_stale) {
1736 ast_cli(a->fd, "Number of seconds before object becomes stale: %d\n", cache->object_lifetime_stale);
1737 } else {
1738 ast_cli(a->fd, "Object staleness is not enabled - cached objects will not go stale\n");
1739 }
1740 ast_cli(a->fd, "Expire all objects on reload: %s\n", AST_CLI_ONOFF(cache->expire_on_reload));
1741
1742 ao2_ref(cache, -1);
1743
1744 return CLI_SUCCESS;
1745}
#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 1932 of file res_sorcery_memory_cache.c.

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

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

783{
784 struct sorcery_memory_cached_object *cached;
785
786 cached = ao2_alloc(sizeof(*cached), sorcery_memory_cached_object_destructor);
787 if (!cached) {
788 return NULL;
789 }
790
791 cached->object = ao2_bump(object);
792 cached->created = ast_tvnow();
793 cached->stale_update_sched_id = -1;
794
795 if (cache->full_backend_cache) {
796 /* A cached objectset allows us to easily perform all retrieval operations in a
797 * minimal of time.
798 */
800 if (!cached->objectset) {
801 ao2_ref(cached, -1);
802 return NULL;
803 }
804 }
805
806 return cached;
807}
#define ao2_alloc(data_size, destructor_fn)
Definition astobj2.h:409
static void sorcery_memory_cached_object_destructor(void *obj)
#define ast_sorcery_objectset_create(sorcery, object)
Create an object set (KVP list) for an object.
Definition sorcery.h:1137

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

Referenced by object_add_to_cache_callback(), and sorcery_memory_cache_create().

◆ sorcery_memory_cached_object_cmp()

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

Definition at line 409 of file res_sorcery_memory_cache.c.

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

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

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

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

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

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

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

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

1005{
1007 void *object;
1008
1010
1011 object = ast_sorcery_retrieve_by_id(task_data->sorcery,
1014 if (!object) {
1015 ast_debug(1, "Backend no longer has object type '%s' ID '%s'. Removing from cache\n",
1019 task_data->object);
1020 } else {
1021 ast_debug(1, "Refreshing stale cache object type '%s' ID '%s'\n",
1025 object);
1026 ao2_ref(object, -1);
1027 }
1028
1029 ast_test_suite_event_notify("SORCERY_MEMORY_CACHE_REFRESHED", "Cache: %s\r\nType: %s\r\nName: %s\r\n",
1030 task_data->cache->name, ast_sorcery_object_get_type(task_data->object),
1032
1033 ao2_ref(task_data, -1);
1035
1036 return 0;
1037}
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 986 of file res_sorcery_memory_cache.c.

988{
990
993 if (!task_data) {
994 return NULL;
995 }
996
997 task_data->sorcery = ao2_bump(sorcery);
998 task_data->cache = ao2_bump(cache);
999 task_data->object = ao2_bump(object);
1000
1001 return task_data;
1002}
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 977 of file res_sorcery_memory_cache.c.

978{
979 struct stale_update_task_data *task_data = obj;
980
981 ao2_cleanup(task_data->cache);
982 ao2_cleanup(task_data->object);
984}

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

3516{
3517 AST_TEST_UNREGISTER(open_with_valid_options);
3518 AST_TEST_UNREGISTER(open_with_invalid_options);
3519 AST_TEST_UNREGISTER(create_and_retrieve);
3521 AST_TEST_UNREGISTER(delete);
3522 AST_TEST_UNREGISTER(maximum_objects);
3523 AST_TEST_UNREGISTER(expiration);
3524 AST_TEST_UNREGISTER(stale);
3525 AST_TEST_UNREGISTER(full_backend_cache_expiration);
3526 AST_TEST_UNREGISTER(full_backend_cache_stale);
3527
3528 ast_manager_unregister("SorceryMemoryCacheExpireObject");
3529 ast_manager_unregister("SorceryMemoryCacheExpire");
3530 ast_manager_unregister("SorceryMemoryCacheStaleObject");
3531 ast_manager_unregister("SorceryMemoryCacheStale");
3532 ast_manager_unregister("SorceryMemoryCachePopulate");
3533
3535
3537
3538 /*
3539 * XXX There is the potential to leak memory if there are pending
3540 * next-cache-expiration and stale-cache-update tasks in the scheduler.
3541 */
3542 if (sched) {
3544 sched = NULL;
3545 }
3546
3548 caches = NULL;
3549
3550 return 0;
3551}
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 3618 of file res_sorcery_memory_cache.c.

◆ ast_module_info

const struct ast_module_info* ast_module_info = &__mod_info
static

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

2072 {
2073 AST_CLI_DEFINE(sorcery_memory_cache_show, "Show sorcery memory cache information"),
2074 AST_CLI_DEFINE(sorcery_memory_cache_dump, "Dump all objects within a sorcery memory cache"),
2075 AST_CLI_DEFINE(sorcery_memory_cache_expire, "Expire a specific object or ALL objects within a sorcery memory cache"),
2076 AST_CLI_DEFINE(sorcery_memory_cache_stale, "Mark a specific object or ALL objects as stale within a sorcery memory cache"),
2077 AST_CLI_DEFINE(sorcery_memory_cache_populate, "Clear and populate the sorcery memory cache with objects from the backend"),
2078};
#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 230 of file res_sorcery_memory_cache.c.

230 {
231 .name = "memory_cache",
239 .retrieve_fields = sorcery_memory_cache_retrieve_fields,
240 .retrieve_multiple = sorcery_memory_cache_retrieve_multiple,
241 .retrieve_regex = sorcery_memory_cache_retrieve_regex,
242 .retrieve_prefix = sorcery_memory_cache_retrieve_prefix,
244};
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 259 of file res_sorcery_memory_cache.c.