Asterisk - The Open Source Telephony Project GIT-master-754dea3
All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Macros Modules Pages
Data Structures | Macros | Functions | Variables
res_sorcery_memory_cache.c File Reference

Sorcery Memory Cache Object Wizard. More...

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

Go to the source code of this file.

Data Structures

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

Macros

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

Functions

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

Variables

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

Detailed Description

Sorcery Memory Cache Object Wizard.

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

Definition in file res_sorcery_memory_cache.c.

Macro Definition Documentation

◆ CACHE_CONTAINER_BUCKET_SIZE

#define CACHE_CONTAINER_BUCKET_SIZE   53

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

Definition at line 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

◆ __init_passthru_update_id_storage()

static void __init_passthru_update_id_storage ( void  )
static

Definition at line 262 of file res_sorcery_memory_cache.c.

265{

◆ __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
Definition: pbx_realtime.c:77
static int schedule_cache_expiration(struct sorcery_memory_cache *cache)
Structure for stored a cached object.
struct timeval created
The time at which the object was created.

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

Referenced by object_add_to_cache_callback(), and sorcery_memory_cache_create().

◆ age_cmp()

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

Definition at line 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.

◆ 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:2317
Structure for storing a memory cache.
struct timeval ast_samp2tv(unsigned int _nsamp, unsigned int _rate)
Returns a timeval corresponding to the duration of n samples at rate r. Useful to convert samples to ...
Definition: time.h:282
struct timeval ast_tvadd(struct timeval a, struct timeval b)
Returns the sum of two timevals a + b.
Definition: extconf.c:2282
int64_t ast_tvdiff_ms(struct timeval end, struct timeval start)
Computes the difference (in milliseconds) between two struct timeval instances.
Definition: time.h:107
struct timeval ast_tvnow(void)
Returns current timeval. Meant to replace calls to gettimeofday().
Definition: time.h:159

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

Referenced by schedule_cache_expiration().

◆ is_passthru_update()

static int is_passthru_update ( void  )
static

Definition at line 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
static struct ast_threadstorage passthru_update_id_storage
void * ast_threadstorage_get(struct ast_threadstorage *ts, size_t init_size)
Retrieve thread storage.

References ast_threadstorage_get(), passthru_update_id_storage, and PASSTHRU_UPDATE_THREAD_ID.

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

◆ load_module()

static int load_module ( void  )
static

Definition at line 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:666

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

◆ mark_all_as_stale_in_cache()

static void mark_all_as_stale_in_cache ( struct sorcery_memory_cache cache)
static

Definition at line 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:739

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

Referenced by sorcery_memory_cache_ami_stale_object(), and sorcery_memory_cache_stale().

◆ memory_cache_full_update()

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

Definition at line 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[]
Definition: chan_ooh323.c:109
static struct ast_sorcery * sorcery
static void memory_cache_populate(const struct ast_sorcery *sorcery, const char *type, struct sorcery_memory_cache *cache)

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

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

◆ memory_cache_populate()

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

Definition at line 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:1897
Generic container type.
Full structure for sorcery.
Definition: sorcery.c:230

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

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

◆ memory_cache_stale_check()

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

Definition at line 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:2329
struct timeval ast_tvsub(struct timeval a, struct timeval b)
Returns the difference of two timevals a - b.
Definition: extconf.c:2297

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

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

◆ memory_cache_stale_update_full()

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

Definition at line 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:194
#define ast_mutex_lock(a)
Definition: lock.h:193
#define ast_cond_signal(cond)
Definition: lock.h:207
static int expire_objects_from_cache(const void *data)
#define MAX(a, b)
Definition: utils.h:233

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

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

◆ set_passthru_update()

static void set_passthru_update ( uint32_t  value)
static

Definition at line 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, passthru_update_id_storage, and value.

Referenced by end_passthru_update(), and start_passthru_update().

◆ sorcery_memory_cache_ami_expire()

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

Definition at line 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:1986
void astman_send_ack(struct mansession *s, const struct message *m, char *msg)
Send ack in manager transaction.
Definition: manager.c:2018
const char * astman_get_header(const struct message *m, char *var)
Get header from manager transaction.
Definition: manager.c:1647

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:2199

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

Referenced by load_module().

◆ sorcery_memory_cache_close()

static void sorcery_memory_cache_close ( void *  data)
static

Definition at line 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.
Definition: main/config.c:955
void ast_variables_destroy(struct ast_variable *var)
Free variable list.
Definition: extconf.c:1262
Structure for variables, used for configurations and for channel variables.
Structure used for fields comparison.
const char * prefix
Prefix for matching object id.
struct ao2_container * container
Optional container to put object into.
const size_t prefix_len
Prefix length in bytes for matching object id.
const struct ast_variable * fields
Pointer to the fields to check.
regex_t * regex
Regular expression for checking object id.
struct ast_variable * objectset
Cached objectset for field and regex retrieval.
#define RAII_VAR(vartype, varname, initval, dtor)
Declare a variable that will call a destructor function when it goes out of scope.
Definition: utils.h:941

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

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

◆ sorcery_memory_cache_hash()

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

Definition at line 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:2536

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

◆ sorcery_memory_cache_open()

static void * sorcery_memory_cache_open ( const char *  data)
static

Definition at line 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:1853

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:1853
#define ast_test_suite_event_notify(s, f,...)
Definition: test.h:189

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

Referenced by memory_cache_stale_update_object().

◆ stale_update_task_data_alloc()

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

Definition at line 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}
int ast_cli_unregister_multiple(struct ast_cli_entry *e, int len)
Unregister multiple commands.
Definition: clicompat.c:30
int ast_manager_unregister(const char *action)
Unregister a registered manager command.
Definition: manager.c:7697
void ast_sched_context_destroy(struct ast_sched_context *c)
destroys a schedule context
Definition: sched.c:271
int ast_sorcery_wizard_unregister(const struct ast_sorcery_wizard *interface)
Unregister a sorcery wizard.
Definition: sorcery.c:474
#define AST_TEST_UNREGISTER(cb)
Definition: test.h:128

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

Referenced by load_module().

Variable Documentation

◆ __mod_info

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

Definition at line 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.

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.

Referenced by load_module(), and unload_module().

◆ passthru_update_id_storage

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

Definition at line 262 of file res_sorcery_memory_cache.c.

Referenced by is_passthru_update(), and set_passthru_update().

◆ sched

struct ast_sched_context* sched
static

Scheduler for cache management.

Definition at line 259 of file res_sorcery_memory_cache.c.