Asterisk - The Open Source Telephony Project  18.5.0
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  backend_data
 Backend data that the mock sorcery wizard uses to create objects. More...
 
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
 
struct  test_data
 Sorcery object created based on backend data. More...
 
struct  test_sorcery_object
 Dummy sorcery object. More...
 

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)
 
static struct ast_sorceryalloc_and_initialize_sorcery (void)
 
struct ast_moduleAST_MODULE_SELF_SYM (void)
 
 AST_TEST_DEFINE (open_with_valid_options)
 
 AST_TEST_DEFINE (open_with_invalid_options)
 
 AST_TEST_DEFINE (create_and_retrieve)
 
 AST_TEST_DEFINE (update)
 
 AST_TEST_DEFINE (delete)
 
 AST_TEST_DEFINE (maximum_objects)
 
 AST_TEST_DEFINE (expiration)
 
 AST_TEST_DEFINE (stale)
 
 AST_TEST_DEFINE (full_backend_cache_expiration)
 
 AST_TEST_DEFINE (full_backend_cache_stale)
 
static int check_cache_content (struct ast_test *test, struct ast_sorcery *sorcery, struct sorcery_memory_cache *cache, const char **in_cache, size_t num_in_cache, const char **not_in_cache, size_t num_not_in_cache)
 
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 void * mock_retrieve_id (const struct ast_sorcery *sorcery, void *data, const char *type, const char *id)
 Callback for retrieving sorcery object by ID. More...
 
static void mock_retrieve_multiple (const struct ast_sorcery *sorcery, void *data, const char *type, struct ao2_container *objects, const struct ast_variable *fields)
 Callback for retrieving multiple sorcery objects. More...
 
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 void * test_data_alloc (const char *id)
 Allocation callback for test_data sorcery object. More...
 
static void * test_sorcery_object_alloc (const char *id)
 
static int unload_module (void)
 
static int wait_for_cache_update (const struct ast_sorcery *sorcery, void *previous_object, struct test_data **new_object)
 Wait for the cache to be updated after a stale object is retrieved. More...
 

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_sorcery_wizard mock_wizard
 A mock sorcery wizard used for the stale test. More...
 
static struct ast_threadstorage passthru_update_id_storage = { .once = PTHREAD_ONCE_INIT , .key_init = __init_passthru_update_id_storage , .custom_init = NULL , }
 
static struct backend_datareal_backend_data
 
static struct ast_sched_contextsched
 Scheduler for cache management. More...
 

Detailed Description

Sorcery Memory Cache Object Wizard.

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

Definition in file res_sorcery_memory_cache.c.

Macro Definition Documentation

◆ CACHE_CONTAINER_BUCKET_SIZE

#define CACHE_CONTAINER_BUCKET_SIZE   53

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

Definition at line 235 of file res_sorcery_memory_cache.c.

Referenced by sorcery_memory_cache_open().

◆ CACHE_HEAP_INIT_HEIGHT

#define CACHE_HEAP_INIT_HEIGHT   5

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

Definition at line 238 of file res_sorcery_memory_cache.c.

Referenced by sorcery_memory_cache_open().

◆ CACHES_CONTAINER_BUCKET_SIZE

#define CACHES_CONTAINER_BUCKET_SIZE   53

The bucket size for the container of caches.

Definition at line 232 of file res_sorcery_memory_cache.c.

Referenced by load_module().

◆ FORMAT [1/2]

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

◆ FORMAT [2/2]

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

◆ PASSTHRU_UPDATE_THREAD_ID

#define PASSTHRU_UPDATE_THREAD_ID   0x5EED1E55

Definition at line 246 of file res_sorcery_memory_cache.c.

Referenced by is_passthru_update(), and start_passthru_update().

Function Documentation

◆ __init_passthru_update_id_storage()

static void __init_passthru_update_id_storage ( void  )
static

Definition at line 247 of file res_sorcery_memory_cache.c.

250 {

◆ __reg_module()

static void __reg_module ( void  )
static

Definition at line 3603 of file res_sorcery_memory_cache.c.

◆ __unreg_module()

static void __unreg_module ( void  )
static

Definition at line 3603 of file res_sorcery_memory_cache.c.

◆ add_to_cache()

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

Definition at line 728 of file res_sorcery_memory_cache.c.

References ao2_find, ao2_link_flags, ast_heap_peek(), ast_heap_push, sorcery_memory_cached_object::created, sorcery_memory_cache::expire_id, sorcery_memory_cache::full_backend_cache, OBJ_NODATA, OBJ_NOLOCK, OBJ_SEARCH_OBJECT, OBJ_UNLINK, sorcery_memory_cache::object_heap, sorcery_memory_cache::objects, and schedule_cache_expiration().

Referenced by object_add_to_cache_callback(), and sorcery_memory_cache_create().

730 {
731  struct sorcery_memory_cached_object *front;
732 
733  if (!ao2_link_flags(cache->objects, cached_object, OBJ_NOLOCK)) {
734  return -1;
735  }
736 
737  if (cache->full_backend_cache && (front = ast_heap_peek(cache->object_heap, 1))) {
738  /* For a full backend cache all objects share the same lifetime */
739  cached_object->created = front->created;
740  }
741 
742  if (ast_heap_push(cache->object_heap, cached_object)) {
743  ao2_find(cache->objects, cached_object,
745  return -1;
746  }
747 
748  if (cache->expire_id == -1) {
750  }
751 
752  return 0;
753 }
static int schedule_cache_expiration(struct sorcery_memory_cache *cache)
Assume that the ao2_container is already locked.
Definition: astobj2.h:1067
struct timeval created
The time at which the object was created.
#define ao2_link_flags(container, obj, flags)
Definition: astobj2.h:1572
struct ast_heap * object_heap
Heap of cached objects. Oldest object is at the top.
#define ast_heap_push(h, elm)
Definition: heap.h:126
unsigned int full_backend_cache
Whether this is a cache of the entire backend, 0 if disabled.
Structure for stored a cached object.
int expire_id
Scheduler item for expiring oldest object.
#define ao2_find(container, arg, flags)
Definition: astobj2.h:1756
The arg parameter is an object of the same type.
Definition: astobj2.h:1091
struct ao2_container * objects
Objects in the cache.
void * ast_heap_peek(struct ast_heap *h, unsigned int index)
Peek at an element on a heap.
Definition: heap.c:267

◆ age_cmp()

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

Definition at line 1493 of file res_sorcery_memory_cache.c.

References ast_tvcmp().

Referenced by sorcery_memory_cache_open().

1494 {
1495  return ast_tvcmp(((struct sorcery_memory_cached_object *) b)->created,
1496  ((struct sorcery_memory_cached_object *) a)->created);
1497 }
struct timeval created
The time at which the object was created.
Structure for stored a cached object.
int ast_tvcmp(struct timeval _a, struct timeval _b)
Compres two struct timeval instances returning -1, 0, 1 if the first arg is smaller, equal or greater to the second.
Definition: time.h:128
static struct test_val b
static struct test_val a

◆ alloc_and_initialize_sorcery()

static struct ast_sorcery* alloc_and_initialize_sorcery ( void  )
static

Definition at line 2300 of file res_sorcery_memory_cache.c.

References ast_sorcery_apply_default, AST_SORCERY_APPLY_SUCCESS, ast_sorcery_internal_object_register, ast_sorcery_open, ast_sorcery_unref, NULL, sorcery_memory_cache::sorcery, and test_sorcery_object_alloc().

Referenced by AST_TEST_DEFINE().

2301 {
2302  struct ast_sorcery *sorcery;
2303 
2304  if (!(sorcery = ast_sorcery_open())) {
2305  return NULL;
2306  }
2307 
2308  if ((ast_sorcery_apply_default(sorcery, "test", "memory", NULL) != AST_SORCERY_APPLY_SUCCESS) ||
2310  ast_sorcery_unref(sorcery);
2311  return NULL;
2312  }
2313 
2314  return sorcery;
2315 }
Full structure for sorcery.
Definition: sorcery.c:230
static void * test_sorcery_object_alloc(const char *id)
#define NULL
Definition: resample.c:96
#define ast_sorcery_unref(sorcery)
Decrease the reference count of a sorcery structure.
Definition: sorcery.h:1502
#define ast_sorcery_internal_object_register(sorcery, type, alloc, transform, apply)
Register an internal, hidden object type.
Definition: sorcery.h:868
#define ast_sorcery_apply_default(sorcery, type, name, data)
Definition: sorcery.h:477
static struct ast_sorcery * sorcery
#define ast_sorcery_open()
Definition: sorcery.h:408

◆ AST_MODULE_SELF_SYM()

struct ast_module* AST_MODULE_SELF_SYM ( void  )

Definition at line 3603 of file res_sorcery_memory_cache.c.

◆ AST_TEST_DEFINE() [1/10]

AST_TEST_DEFINE ( open_with_valid_options  )

Definition at line 2317 of file res_sorcery_memory_cache.c.

References AST_TEST_FAIL, AST_TEST_NOT_RUN, AST_TEST_PASS, ast_test_status_update, cache, sip_to_pjsip::info(), sorcery_memory_cache::maximum_objects, sorcery_memory_cache::object_lifetime_maximum, sorcery_memory_cache::object_lifetime_stale, sorcery_memory_cache_close(), sorcery_memory_cache_open(), TEST_EXECUTE, and TEST_INIT.

2318 {
2319  int res = AST_TEST_PASS;
2320  struct sorcery_memory_cache *cache;
2321 
2322  switch (cmd) {
2323  case TEST_INIT:
2324  info->name = "open_with_valid_options";
2325  info->category = "/res/res_sorcery_memory_cache/";
2326  info->summary = "Attempt to create sorcery memory caches using valid options";
2327  info->description = "This test performs the following:\n"
2328  "\t* Creates a memory cache with default configuration\n"
2329  "\t* Creates a memory cache with a maximum object count of 10 and verifies it\n"
2330  "\t* Creates a memory cache with a maximum object lifetime of 60 and verifies it\n"
2331  "\t* Creates a memory cache with a stale object lifetime of 90 and verifies it";
2332  return AST_TEST_NOT_RUN;
2333  case TEST_EXECUTE:
2334  break;
2335  }
2336 
2337  cache = sorcery_memory_cache_open("");
2338  if (!cache) {
2339  ast_test_status_update(test, "Failed to create a sorcery memory cache using default configuration\n");
2340  res = AST_TEST_FAIL;
2341  } else {
2343  }
2344 
2345  cache = sorcery_memory_cache_open("maximum_objects=10");
2346  if (!cache) {
2347  ast_test_status_update(test, "Failed to create a sorcery memory cache with a maximum object count of 10\n");
2348  res = AST_TEST_FAIL;
2349  } else {
2350  if (cache->maximum_objects != 10) {
2351  ast_test_status_update(test, "Created a sorcery memory cache with a maximum object count of 10 but it has '%u'\n",
2352  cache->maximum_objects);
2353  }
2355  }
2356 
2357  cache = sorcery_memory_cache_open("object_lifetime_maximum=60");
2358  if (!cache) {
2359  ast_test_status_update(test, "Failed to create a sorcery memory cache with a maximum object lifetime of 60\n");
2360  res = AST_TEST_FAIL;
2361  } else {
2362  if (cache->object_lifetime_maximum != 60) {
2363  ast_test_status_update(test, "Created a sorcery memory cache with a maximum object lifetime of 60 but it has '%u'\n",
2364  cache->object_lifetime_maximum);
2365  }
2367  }
2368 
2369  cache = sorcery_memory_cache_open("object_lifetime_stale=90");
2370  if (!cache) {
2371  ast_test_status_update(test, "Failed to create a sorcery memory cache with a stale object lifetime of 90\n");
2372  res = AST_TEST_FAIL;
2373  } else {
2374  if (cache->object_lifetime_stale != 90) {
2375  ast_test_status_update(test, "Created a sorcery memory cache with a stale object lifetime of 90 but it has '%u'\n",
2376  cache->object_lifetime_stale);
2377  }
2379  }
2380 
2381 
2382  return res;
2383 }
unsigned int maximum_objects
The maximum number of objects permitted in the cache, 0 if no limit.
unsigned int object_lifetime_maximum
The maximum time (in seconds) an object will stay in the cache, 0 if no limit.
static void sorcery_memory_cache_close(void *data)
Structure for storing a memory cache.
#define ast_test_status_update(a, b, c...)
Definition: test.h:129
def info(msg)
struct ao2_container * cache
Definition: pbx_realtime.c:77
static void * sorcery_memory_cache_open(const char *data)
unsigned int object_lifetime_stale
The amount of time (in seconds) before an object is marked as stale, 0 if disabled.

◆ AST_TEST_DEFINE() [2/10]

AST_TEST_DEFINE ( open_with_invalid_options  )

Definition at line 2385 of file res_sorcery_memory_cache.c.

References AST_TEST_FAIL, AST_TEST_NOT_RUN, AST_TEST_PASS, ast_test_status_update, cache, sip_to_pjsip::info(), sorcery_memory_cache_close(), sorcery_memory_cache_open(), TEST_EXECUTE, and TEST_INIT.

2386 {
2387  int res = AST_TEST_PASS;
2388  struct sorcery_memory_cache *cache;
2389 
2390  switch (cmd) {
2391  case TEST_INIT:
2392  info->name = "open_with_invalid_options";
2393  info->category = "/res/res_sorcery_memory_cache/";
2394  info->summary = "Attempt to create sorcery memory caches using invalid options";
2395  info->description = "This test attempts to perform the following:\n"
2396  "\t* Create a memory cache with an empty name\n"
2397  "\t* Create a memory cache with a maximum object count of -1\n"
2398  "\t* Create a memory cache with a maximum object count of toast\n"
2399  "\t* Create a memory cache with a maximum object lifetime of -1\n"
2400  "\t* Create a memory cache with a maximum object lifetime of toast\n"
2401  "\t* Create a memory cache with a stale object lifetime of -1\n"
2402  "\t* Create a memory cache with a stale object lifetime of toast";
2403  return AST_TEST_NOT_RUN;
2404  case TEST_EXECUTE:
2405  break;
2406  }
2407 
2408  cache = sorcery_memory_cache_open("name=");
2409  if (cache) {
2410  ast_test_status_update(test, "Created a sorcery memory cache with an empty name\n");
2412  res = AST_TEST_FAIL;
2413  }
2414 
2415  cache = sorcery_memory_cache_open("maximum_objects=-1");
2416  if (cache) {
2417  ast_test_status_update(test, "Created a sorcery memory cache with a maximum object count of -1\n");
2419  res = AST_TEST_FAIL;
2420  }
2421 
2422  cache = sorcery_memory_cache_open("maximum_objects=toast");
2423  if (cache) {
2424  ast_test_status_update(test, "Created a sorcery memory cache with a maximum object count of toast\n");
2426  res = AST_TEST_FAIL;
2427  }
2428 
2429  cache = sorcery_memory_cache_open("object_lifetime_maximum=-1");
2430  if (cache) {
2431  ast_test_status_update(test, "Created a sorcery memory cache with an object lifetime maximum of -1\n");
2433  res = AST_TEST_FAIL;
2434  }
2435 
2436  cache = sorcery_memory_cache_open("object_lifetime_maximum=toast");
2437  if (cache) {
2438  ast_test_status_update(test, "Created a sorcery memory cache with an object lifetime maximum of toast\n");
2440  res = AST_TEST_FAIL;
2441  }
2442 
2443  cache = sorcery_memory_cache_open("object_lifetime_stale=-1");
2444  if (cache) {
2445  ast_test_status_update(test, "Created a sorcery memory cache with a stale object lifetime of -1\n");
2447  res = AST_TEST_FAIL;
2448  }
2449 
2450  cache = sorcery_memory_cache_open("object_lifetime_stale=toast");
2451  if (cache) {
2452  ast_test_status_update(test, "Created a sorcery memory cache with a stale object lifetime of toast\n");
2454  res = AST_TEST_FAIL;
2455  }
2456 
2457  cache = sorcery_memory_cache_open("tacos");
2458  if (cache) {
2459  ast_test_status_update(test, "Created a sorcery memory cache with an invalid configuration option 'tacos'\n");
2461  res = AST_TEST_FAIL;
2462  }
2463 
2464  return res;
2465 }
static void sorcery_memory_cache_close(void *data)
Structure for storing a memory cache.
#define ast_test_status_update(a, b, c...)
Definition: test.h:129
def info(msg)
struct ao2_container * cache
Definition: pbx_realtime.c:77
static void * sorcery_memory_cache_open(const char *data)

◆ AST_TEST_DEFINE() [3/10]

AST_TEST_DEFINE ( create_and_retrieve  )

Definition at line 2467 of file res_sorcery_memory_cache.c.

References alloc_and_initialize_sorcery(), ao2_cleanup, ao2_container_count(), ast_sorcery_alloc(), ast_sorcery_unref, AST_TEST_FAIL, AST_TEST_NOT_RUN, AST_TEST_PASS, ast_test_status_update, cleanup(), sip_to_pjsip::info(), NULL, sorcery_memory_cache::objects, RAII_VAR, sorcery_memory_cache::sorcery, sorcery_memory_cache_close(), sorcery_memory_cache_create(), sorcery_memory_cache_open(), sorcery_memory_cache_retrieve_id(), TEST_EXECUTE, and TEST_INIT.

2468 {
2469  int res = AST_TEST_FAIL;
2470  struct ast_sorcery *sorcery = NULL;
2471  struct sorcery_memory_cache *cache = NULL;
2472  RAII_VAR(void *, object, NULL, ao2_cleanup);
2473  RAII_VAR(void *, cached_object, NULL, ao2_cleanup);
2474 
2475  switch (cmd) {
2476  case TEST_INIT:
2477  info->name = "create";
2478  info->category = "/res/res_sorcery_memory_cache/";
2479  info->summary = "Attempt to create an object in the cache";
2480  info->description = "This test performs the following:\n"
2481  "\t* Creates a memory cache with default options\n"
2482  "\t* Creates a sorcery instance with a test object\n"
2483  "\t* Creates a test object with an id of test\n"
2484  "\t* Pushes the test object into the memory cache\n"
2485  "\t* Confirms that the test object is in the cache";
2486  return AST_TEST_NOT_RUN;
2487  case TEST_EXECUTE:
2488  break;
2489  }
2490 
2491  cache = sorcery_memory_cache_open("");
2492  if (!cache) {
2493  ast_test_status_update(test, "Failed to create a sorcery memory cache using default options\n");
2494  goto cleanup;
2495  }
2496 
2497  if (ao2_container_count(cache->objects)) {
2498  ast_test_status_update(test, "Memory cache contains cached objects before we added one\n");
2499  goto cleanup;
2500  }
2501 
2502  sorcery = alloc_and_initialize_sorcery();
2503  if (!sorcery) {
2504  ast_test_status_update(test, "Failed to create a test sorcery instance\n");
2505  goto cleanup;
2506  }
2507 
2508  object = ast_sorcery_alloc(sorcery, "test", "test");
2509  if (!object) {
2510  ast_test_status_update(test, "Failed to allocate a test object\n");
2511  goto cleanup;
2512  }
2513 
2514  sorcery_memory_cache_create(sorcery, cache, object);
2515 
2516  if (!ao2_container_count(cache->objects)) {
2517  ast_test_status_update(test, "Added test object to memory cache but cache remains empty\n");
2518  goto cleanup;
2519  }
2520 
2521  cached_object = sorcery_memory_cache_retrieve_id(sorcery, cache, "test", "test");
2522  if (!cached_object) {
2523  ast_test_status_update(test, "Object placed into memory cache could not be retrieved\n");
2524  goto cleanup;
2525  }
2526 
2527  if (cached_object != object) {
2528  ast_test_status_update(test, "Object retrieved from memory cached is not the one we cached\n");
2529  goto cleanup;
2530  }
2531 
2532  res = AST_TEST_PASS;
2533 
2534 cleanup:
2535  if (cache) {
2537  }
2538  if (sorcery) {
2539  ast_sorcery_unref(sorcery);
2540  }
2541 
2542  return res;
2543 }
static void * sorcery_memory_cache_retrieve_id(const struct ast_sorcery *sorcery, void *data, const char *type, const char *id)
int ao2_container_count(struct ao2_container *c)
Returns the number of elements in a container.
Full structure for sorcery.
Definition: sorcery.c:230
#define NULL
Definition: resample.c:96
static void sorcery_memory_cache_close(void *data)
static int sorcery_memory_cache_create(const struct ast_sorcery *sorcery, void *data, void *object)
#define ast_sorcery_unref(sorcery)
Decrease the reference count of a sorcery structure.
Definition: sorcery.h:1502
Structure for storing a memory cache.
#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:911
#define ast_test_status_update(a, b, c...)
Definition: test.h:129
def info(msg)
void * ast_sorcery_alloc(const struct ast_sorcery *sorcery, const char *type, const char *id)
Allocate an object.
Definition: sorcery.c:1744
static void * cleanup(void *unused)
Definition: pbx_realtime.c:124
struct ao2_container * cache
Definition: pbx_realtime.c:77
static struct ast_sorcery * sorcery
#define ao2_cleanup(obj)
Definition: astobj2.h:1958
static struct ast_sorcery * alloc_and_initialize_sorcery(void)
struct ao2_container * objects
Objects in the cache.
static void * sorcery_memory_cache_open(const char *data)

◆ AST_TEST_DEFINE() [4/10]

AST_TEST_DEFINE ( update  )

Definition at line 2545 of file res_sorcery_memory_cache.c.

References alloc_and_initialize_sorcery(), ao2_cleanup, ao2_container_count(), ast_sorcery_alloc(), ast_sorcery_unref, AST_TEST_FAIL, AST_TEST_NOT_RUN, AST_TEST_PASS, ast_test_status_update, cleanup(), sip_to_pjsip::info(), NULL, sorcery_memory_cache::objects, RAII_VAR, sorcery_memory_cache::sorcery, sorcery_memory_cache_close(), sorcery_memory_cache_create(), sorcery_memory_cache_open(), sorcery_memory_cache_retrieve_id(), TEST_EXECUTE, and TEST_INIT.

2546 {
2547  int res = AST_TEST_FAIL;
2548  struct ast_sorcery *sorcery = NULL;
2549  struct sorcery_memory_cache *cache = NULL;
2550  RAII_VAR(void *, original_object, NULL, ao2_cleanup);
2551  RAII_VAR(void *, updated_object, NULL, ao2_cleanup);
2552  RAII_VAR(void *, cached_object, NULL, ao2_cleanup);
2553 
2554  switch (cmd) {
2555  case TEST_INIT:
2556  info->name = "create";
2557  info->category = "/res/res_sorcery_memory_cache/";
2558  info->summary = "Attempt to create and then update an object in the cache";
2559  info->description = "This test performs the following:\n"
2560  "\t* Creates a memory cache with default options\n"
2561  "\t* Creates a sorcery instance with a test object\n"
2562  "\t* Creates a test object with an id of test\n"
2563  "\t* Pushes the test object into the memory cache\n"
2564  "\t* Confirms that the test object is in the cache\n"
2565  "\t* Creates a new test object with the same id of test\n"
2566  "\t* Pushes the new test object into the memory cache\n"
2567  "\t* Confirms that the new test object has replaced the old one";
2568  return AST_TEST_NOT_RUN;
2569  case TEST_EXECUTE:
2570  break;
2571  }
2572 
2573  cache = sorcery_memory_cache_open("");
2574  if (!cache) {
2575  ast_test_status_update(test, "Failed to create a sorcery memory cache using default options\n");
2576  goto cleanup;
2577  }
2578 
2579  if (ao2_container_count(cache->objects)) {
2580  ast_test_status_update(test, "Memory cache contains cached objects before we added one\n");
2581  goto cleanup;
2582  }
2583 
2584  sorcery = alloc_and_initialize_sorcery();
2585  if (!sorcery) {
2586  ast_test_status_update(test, "Failed to create a test sorcery instance\n");
2587  goto cleanup;
2588  }
2589 
2590  original_object = ast_sorcery_alloc(sorcery, "test", "test");
2591  if (!original_object) {
2592  ast_test_status_update(test, "Failed to allocate a test object\n");
2593  goto cleanup;
2594  }
2595 
2596  sorcery_memory_cache_create(sorcery, cache, original_object);
2597 
2598  updated_object = ast_sorcery_alloc(sorcery, "test", "test");
2599  if (!updated_object) {
2600  ast_test_status_update(test, "Failed to allocate an updated test object\n");
2601  goto cleanup;
2602  }
2603 
2604  sorcery_memory_cache_create(sorcery, cache, updated_object);
2605 
2606  if (ao2_container_count(cache->objects) != 1) {
2607  ast_test_status_update(test, "Added updated test object to memory cache but cache now contains %d objects instead of 1\n",
2608  ao2_container_count(cache->objects));
2609  goto cleanup;
2610  }
2611 
2612  cached_object = sorcery_memory_cache_retrieve_id(sorcery, cache, "test", "test");
2613  if (!cached_object) {
2614  ast_test_status_update(test, "Updated object placed into memory cache could not be retrieved\n");
2615  goto cleanup;
2616  }
2617 
2618  if (cached_object == original_object) {
2619  ast_test_status_update(test, "Updated object placed into memory cache but old one is being retrieved\n");
2620  goto cleanup;
2621  } else if (cached_object != updated_object) {
2622  ast_test_status_update(test, "Updated object placed into memory cache but different one is being retrieved\n");
2623  goto cleanup;
2624  }
2625 
2626  res = AST_TEST_PASS;
2627 
2628 cleanup:
2629  if (cache) {
2631  }
2632  if (sorcery) {
2633  ast_sorcery_unref(sorcery);
2634  }
2635 
2636  return res;
2637 }
static void * sorcery_memory_cache_retrieve_id(const struct ast_sorcery *sorcery, void *data, const char *type, const char *id)
int ao2_container_count(struct ao2_container *c)
Returns the number of elements in a container.
Full structure for sorcery.
Definition: sorcery.c:230
#define NULL
Definition: resample.c:96
static void sorcery_memory_cache_close(void *data)
static int sorcery_memory_cache_create(const struct ast_sorcery *sorcery, void *data, void *object)
#define ast_sorcery_unref(sorcery)
Decrease the reference count of a sorcery structure.
Definition: sorcery.h:1502
Structure for storing a memory cache.
#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:911
#define ast_test_status_update(a, b, c...)
Definition: test.h:129
def info(msg)
void * ast_sorcery_alloc(const struct ast_sorcery *sorcery, const char *type, const char *id)
Allocate an object.
Definition: sorcery.c:1744
static void * cleanup(void *unused)
Definition: pbx_realtime.c:124
struct ao2_container * cache
Definition: pbx_realtime.c:77
static struct ast_sorcery * sorcery
#define ao2_cleanup(obj)
Definition: astobj2.h:1958
static struct ast_sorcery * alloc_and_initialize_sorcery(void)
struct ao2_container * objects
Objects in the cache.
static void * sorcery_memory_cache_open(const char *data)

◆ AST_TEST_DEFINE() [5/10]

AST_TEST_DEFINE ( delete  )

Definition at line 2639 of file res_sorcery_memory_cache.c.

References alloc_and_initialize_sorcery(), ao2_cleanup, ao2_container_count(), ao2_ref, ast_sorcery_alloc(), ast_sorcery_unref, AST_TEST_FAIL, AST_TEST_NOT_RUN, AST_TEST_PASS, ast_test_status_update, cleanup(), sip_to_pjsip::info(), NULL, sorcery_memory_cache::objects, RAII_VAR, sorcery_memory_cache::sorcery, sorcery_memory_cache_close(), sorcery_memory_cache_create(), sorcery_memory_cache_delete(), sorcery_memory_cache_open(), sorcery_memory_cache_retrieve_id(), TEST_EXECUTE, and TEST_INIT.

2640 {
2641  int res = AST_TEST_FAIL;
2642  struct ast_sorcery *sorcery = NULL;
2643  struct sorcery_memory_cache *cache = NULL;
2644  RAII_VAR(void *, object, NULL, ao2_cleanup);
2645  RAII_VAR(void *, cached_object, NULL, ao2_cleanup);
2646 
2647  switch (cmd) {
2648  case TEST_INIT:
2649  info->name = "delete";
2650  info->category = "/res/res_sorcery_memory_cache/";
2651  info->summary = "Attempt to create and then delete an object in the cache";
2652  info->description = "This test performs the following:\n"
2653  "\t* Creates a memory cache with default options\n"
2654  "\t* Creates a sorcery instance with a test object\n"
2655  "\t* Creates a test object with an id of test\n"
2656  "\t* Pushes the test object into the memory cache\n"
2657  "\t* Confirms that the test object is in the cache\n"
2658  "\t* Deletes the test object from the cache\n"
2659  "\t* Confirms that the test object is no longer in the cache";
2660  return AST_TEST_NOT_RUN;
2661  case TEST_EXECUTE:
2662  break;
2663  }
2664 
2665  cache = sorcery_memory_cache_open("");
2666  if (!cache) {
2667  ast_test_status_update(test, "Failed to create a sorcery memory cache using default options\n");
2668  goto cleanup;
2669  }
2670 
2671  if (ao2_container_count(cache->objects)) {
2672  ast_test_status_update(test, "Memory cache contains cached objects before we added one\n");
2673  goto cleanup;
2674  }
2675 
2676  sorcery = alloc_and_initialize_sorcery();
2677  if (!sorcery) {
2678  ast_test_status_update(test, "Failed to create a test sorcery instance\n");
2679  goto cleanup;
2680  }
2681 
2682  object = ast_sorcery_alloc(sorcery, "test", "test");
2683  if (!object) {
2684  ast_test_status_update(test, "Failed to allocate a test object\n");
2685  goto cleanup;
2686  }
2687 
2688  sorcery_memory_cache_create(sorcery, cache, object);
2689 
2690  if (!ao2_container_count(cache->objects)) {
2691  ast_test_status_update(test, "Added test object to memory cache but cache contains no objects\n");
2692  goto cleanup;
2693  }
2694 
2695  cached_object = sorcery_memory_cache_retrieve_id(sorcery, cache, "test", "test");
2696  if (!cached_object) {
2697  ast_test_status_update(test, "Test object placed into memory cache could not be retrieved\n");
2698  goto cleanup;
2699  }
2700 
2701  ao2_ref(cached_object, -1);
2702  cached_object = NULL;
2703 
2704  sorcery_memory_cache_delete(sorcery, cache, object);
2705 
2706  cached_object = sorcery_memory_cache_retrieve_id(sorcery, cache, "test", "test");
2707  if (cached_object) {
2708  ast_test_status_update(test, "Test object deleted from memory cache can still be retrieved\n");
2709  goto cleanup;
2710  }
2711 
2712  res = AST_TEST_PASS;
2713 
2714 cleanup:
2715  if (cache) {
2717  }
2718  if (sorcery) {
2719  ast_sorcery_unref(sorcery);
2720  }
2721 
2722  return res;
2723 }
static void * sorcery_memory_cache_retrieve_id(const struct ast_sorcery *sorcery, void *data, const char *type, const char *id)
static int sorcery_memory_cache_delete(const struct ast_sorcery *sorcery, void *data, void *object)
int ao2_container_count(struct ao2_container *c)
Returns the number of elements in a container.
Full structure for sorcery.
Definition: sorcery.c:230
#define NULL
Definition: resample.c:96
static void sorcery_memory_cache_close(void *data)
static int sorcery_memory_cache_create(const struct ast_sorcery *sorcery, void *data, void *object)
#define ast_sorcery_unref(sorcery)
Decrease the reference count of a sorcery structure.
Definition: sorcery.h:1502
Structure for storing a memory cache.
#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:911
#define ast_test_status_update(a, b, c...)
Definition: test.h:129
#define ao2_ref(o, delta)
Definition: astobj2.h:464
def info(msg)
void * ast_sorcery_alloc(const struct ast_sorcery *sorcery, const char *type, const char *id)
Allocate an object.
Definition: sorcery.c:1744
static void * cleanup(void *unused)
Definition: pbx_realtime.c:124
struct ao2_container * cache
Definition: pbx_realtime.c:77
static struct ast_sorcery * sorcery
#define ao2_cleanup(obj)
Definition: astobj2.h:1958
static struct ast_sorcery * alloc_and_initialize_sorcery(void)
struct ao2_container * objects
Objects in the cache.
static void * sorcery_memory_cache_open(const char *data)

◆ AST_TEST_DEFINE() [6/10]

AST_TEST_DEFINE ( maximum_objects  )

Definition at line 2755 of file res_sorcery_memory_cache.c.

References alloc_and_initialize_sorcery(), ao2_cleanup, ao2_container_count(), ast_sorcery_alloc(), ast_sorcery_unref, AST_TEST_FAIL, AST_TEST_NOT_RUN, AST_TEST_PASS, ast_test_status_update, check_cache_content(), cleanup(), sip_to_pjsip::info(), NULL, sorcery_memory_cache::objects, RAII_VAR, sorcery_memory_cache::sorcery, sorcery_memory_cache_close(), sorcery_memory_cache_create(), sorcery_memory_cache_delete(), sorcery_memory_cache_open(), TEST_EXECUTE, and TEST_INIT.

2756 {
2757  int res = AST_TEST_FAIL;
2758  struct ast_sorcery *sorcery = NULL;
2759  struct sorcery_memory_cache *cache = NULL;
2760  RAII_VAR(void *, alice, NULL, ao2_cleanup);
2761  RAII_VAR(void *, bob, NULL, ao2_cleanup);
2762  RAII_VAR(void *, charlie, NULL, ao2_cleanup);
2763  RAII_VAR(void *, cached_object, NULL, ao2_cleanup);
2764  const char *in_cache[2];
2765  const char *not_in_cache[2];
2766 
2767  switch (cmd) {
2768  case TEST_INIT:
2769  info->name = "maximum_objects";
2770  info->category = "/res/res_sorcery_memory_cache/";
2771  info->summary = "Ensure that the 'maximum_objects' option works as expected";
2772  info->description = "This test performs the following:\n"
2773  "\t* Creates a memory cache with maximum_objects=2\n"
2774  "\t* Creates a sorcery instance\n"
2775  "\t* Creates a three test objects: alice, bob, charlie, and david\n"
2776  "\t* Pushes alice and bob into the memory cache\n"
2777  "\t* Confirms that alice and bob are in the memory cache\n"
2778  "\t* Pushes charlie into the memory cache\n"
2779  "\t* Confirms that bob and charlie are in the memory cache\n"
2780  "\t* Deletes charlie from the memory cache\n"
2781  "\t* Confirms that only bob is in the memory cache\n"
2782  "\t* Pushes alice into the memory cache\n"
2783  "\t* Confirms that bob and alice are in the memory cache";
2784  return AST_TEST_NOT_RUN;
2785  case TEST_EXECUTE:
2786  break;
2787  }
2788 
2789  cache = sorcery_memory_cache_open("maximum_objects=2");
2790  if (!cache) {
2791  ast_test_status_update(test, "Failed to create a sorcery memory cache with maximum_objects=2\n");
2792  goto cleanup;
2793  }
2794 
2795  if (ao2_container_count(cache->objects)) {
2796  ast_test_status_update(test, "Memory cache contains cached objects before we added one\n");
2797  goto cleanup;
2798  }
2799 
2800  sorcery = alloc_and_initialize_sorcery();
2801  if (!sorcery) {
2802  ast_test_status_update(test, "Failed to create a test sorcery instance\n");
2803  goto cleanup;
2804  }
2805 
2806  alice = ast_sorcery_alloc(sorcery, "test", "alice");
2807  bob = ast_sorcery_alloc(sorcery, "test", "bob");
2808  charlie = ast_sorcery_alloc(sorcery, "test", "charlie");
2809 
2810  if (!alice || !bob || !charlie) {
2811  ast_test_status_update(test, "Failed to allocate sorcery object(s)\n");
2812  goto cleanup;
2813  }
2814 
2815  sorcery_memory_cache_create(sorcery, cache, alice);
2816  in_cache[0] = "alice";
2817  in_cache[1] = NULL;
2818  not_in_cache[0] = "bob";
2819  not_in_cache[1] = "charlie";
2820  if (check_cache_content(test, sorcery, cache, in_cache, 1, not_in_cache, 2)) {
2821  goto cleanup;
2822  }
2823 
2824  /* Delays are added to ensure that we are not adding cache entries within the
2825  * same microsecond
2826  */
2827  usleep(1000);
2828 
2829  sorcery_memory_cache_create(sorcery, cache, bob);
2830  in_cache[0] = "alice";
2831  in_cache[1] = "bob";
2832  not_in_cache[0] = "charlie";
2833  not_in_cache[1] = NULL;
2834  if (check_cache_content(test, sorcery, cache, in_cache, 2, not_in_cache, 1)) {
2835  goto cleanup;
2836  }
2837 
2838  usleep(1000);
2839 
2840  sorcery_memory_cache_create(sorcery, cache, charlie);
2841  in_cache[0] = "bob";
2842  in_cache[1] = "charlie";
2843  not_in_cache[0] = "alice";
2844  not_in_cache[1] = NULL;
2845  if (check_cache_content(test, sorcery, cache, in_cache, 2, not_in_cache, 1)) {
2846  goto cleanup;
2847  }
2848  usleep(1000);
2849 
2850  sorcery_memory_cache_delete(sorcery, cache, charlie);
2851  in_cache[0] = "bob";
2852  in_cache[1] = NULL;
2853  not_in_cache[0] = "alice";
2854  not_in_cache[1] = "charlie";
2855  if (check_cache_content(test, sorcery, cache, in_cache, 1, not_in_cache, 2)) {
2856  goto cleanup;
2857  }
2858  usleep(1000);
2859 
2860  sorcery_memory_cache_create(sorcery, cache, alice);
2861  in_cache[0] = "bob";
2862  in_cache[1] = "alice";
2863  not_in_cache[0] = "charlie";
2864  not_in_cache[1] = NULL;
2865  if (check_cache_content(test, sorcery, cache, in_cache, 2, not_in_cache, 1)) {
2866  goto cleanup;
2867  }
2868 
2869  res = AST_TEST_PASS;
2870 
2871 cleanup:
2872  if (cache) {
2874  }
2875  if (sorcery) {
2876  ast_sorcery_unref(sorcery);
2877  }
2878 
2879  return res;
2880 }
static int sorcery_memory_cache_delete(const struct ast_sorcery *sorcery, void *data, void *object)
int ao2_container_count(struct ao2_container *c)
Returns the number of elements in a container.
Full structure for sorcery.
Definition: sorcery.c:230
#define NULL
Definition: resample.c:96
static void sorcery_memory_cache_close(void *data)
static int sorcery_memory_cache_create(const struct ast_sorcery *sorcery, void *data, void *object)
#define ast_sorcery_unref(sorcery)
Decrease the reference count of a sorcery structure.
Definition: sorcery.h:1502
Structure for storing a memory cache.
#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:911
#define ast_test_status_update(a, b, c...)
Definition: test.h:129
static int check_cache_content(struct ast_test *test, struct ast_sorcery *sorcery, struct sorcery_memory_cache *cache, const char **in_cache, size_t num_in_cache, const char **not_in_cache, size_t num_not_in_cache)
def info(msg)
void * ast_sorcery_alloc(const struct ast_sorcery *sorcery, const char *type, const char *id)
Allocate an object.
Definition: sorcery.c:1744
static void * cleanup(void *unused)
Definition: pbx_realtime.c:124
struct ao2_container * cache
Definition: pbx_realtime.c:77
static struct ast_sorcery * sorcery
#define ao2_cleanup(obj)
Definition: astobj2.h:1958
static struct ast_sorcery * alloc_and_initialize_sorcery(void)
struct ao2_container * objects
Objects in the cache.
static void * sorcery_memory_cache_open(const char *data)

◆ AST_TEST_DEFINE() [7/10]

AST_TEST_DEFINE ( expiration  )

Definition at line 2882 of file res_sorcery_memory_cache.c.

References alloc_and_initialize_sorcery(), ao2_container_count(), ao2_ref, ast_cond_destroy, ast_cond_init, ast_cond_timedwait, ast_mutex_destroy, ast_mutex_init, ast_mutex_lock, ast_mutex_unlock, ast_sorcery_alloc(), ast_sorcery_unref, AST_TEST_FAIL, AST_TEST_NOT_RUN, AST_TEST_PASS, ast_test_status_update, ast_tvnow(), ast_uuid_generate_str(), AST_UUID_STR_LEN, sorcery_memory_cache::cache_completed, sorcery_memory_cache::cache_notify, cleanup(), sorcery_memory_cache::cond, sip_to_pjsip::info(), sorcery_memory_cache::lock, NULL, sorcery_memory_cache::objects, sorcery_memory_cache::sorcery, sorcery_memory_cache_close(), sorcery_memory_cache_create(), sorcery_memory_cache_open(), TEST_EXECUTE, and TEST_INIT.

2883 {
2884  int res = AST_TEST_FAIL;
2885  struct ast_sorcery *sorcery = NULL;
2886  struct sorcery_memory_cache *cache = NULL;
2887  int i;
2888 
2889  switch (cmd) {
2890  case TEST_INIT:
2891  info->name = "expiration";
2892  info->category = "/res/res_sorcery_memory_cache/";
2893  info->summary = "Add objects to a cache configured with maximum lifetime, confirm they are removed";
2894  info->description = "This test performs the following:\n"
2895  "\t* Creates a memory cache with a maximum object lifetime of 5 seconds\n"
2896  "\t* Pushes 10 objects into the memory cache\n"
2897  "\t* Waits (up to) 10 seconds for expiration to occur\n"
2898  "\t* Confirms that the objects have been removed from the cache";
2899  return AST_TEST_NOT_RUN;
2900  case TEST_EXECUTE:
2901  break;
2902  }
2903 
2904  cache = sorcery_memory_cache_open("object_lifetime_maximum=5");
2905  if (!cache) {
2906  ast_test_status_update(test, "Failed to create a sorcery memory cache using default options\n");
2907  goto cleanup;
2908  }
2909 
2910  sorcery = alloc_and_initialize_sorcery();
2911  if (!sorcery) {
2912  ast_test_status_update(test, "Failed to create a test sorcery instance\n");
2913  goto cleanup;
2914  }
2915 
2916  cache->cache_notify = 1;
2917  ast_mutex_init(&cache->lock);
2918  ast_cond_init(&cache->cond, NULL);
2919 
2920  for (i = 0; i < 5; ++i) {
2921  char uuid[AST_UUID_STR_LEN];
2922  void *object;
2923 
2924  object = ast_sorcery_alloc(sorcery, "test", ast_uuid_generate_str(uuid, sizeof(uuid)));
2925  if (!object) {
2926  ast_test_status_update(test, "Failed to allocate test object for expiration\n");
2927  goto cleanup;
2928  }
2929 
2930  sorcery_memory_cache_create(sorcery, cache, object);
2931 
2932  ao2_ref(object, -1);
2933  }
2934 
2935  ast_mutex_lock(&cache->lock);
2936  while (!cache->cache_completed) {
2937  struct timeval start = ast_tvnow();
2938  struct timespec end = {
2939  .tv_sec = start.tv_sec + 10,
2940  .tv_nsec = start.tv_usec * 1000,
2941  };
2942 
2943  if (ast_cond_timedwait(&cache->cond, &cache->lock, &end) == ETIMEDOUT) {
2944  break;
2945  }
2946  }
2947  ast_mutex_unlock(&cache->lock);
2948 
2949  if (ao2_container_count(cache->objects)) {
2950  ast_test_status_update(test, "Objects placed into the memory cache did not expire and get removed\n");
2951  goto cleanup;
2952  }
2953 
2954  res = AST_TEST_PASS;
2955 
2956 cleanup:
2957  if (cache) {
2958  if (cache->cache_notify) {
2959  ast_cond_destroy(&cache->cond);
2960  ast_mutex_destroy(&cache->lock);
2961  }
2963  }
2964  if (sorcery) {
2965  ast_sorcery_unref(sorcery);
2966  }
2967 
2968  return res;
2969 }
int ao2_container_count(struct ao2_container *c)
Returns the number of elements in a container.
#define AST_UUID_STR_LEN
Definition: uuid.h:27
Full structure for sorcery.
Definition: sorcery.c:230
#define ast_cond_init(cond, attr)
Definition: lock.h:199
struct timeval ast_tvnow(void)
Returns current timeval. Meant to replace calls to gettimeofday().
Definition: time.h:150
#define ast_mutex_lock(a)
Definition: lock.h:187
ast_mutex_t lock
Mutex lock used for signaling when the cache has reached empty.
#define NULL
Definition: resample.c:96
char * end
Definition: eagi_proxy.c:73
static void sorcery_memory_cache_close(void *data)
static int sorcery_memory_cache_create(const struct ast_sorcery *sorcery, void *data, void *object)
#define ast_sorcery_unref(sorcery)
Decrease the reference count of a sorcery structure.
Definition: sorcery.h:1502
Structure for storing a memory cache.
#define ast_test_status_update(a, b, c...)
Definition: test.h:129
#define ao2_ref(o, delta)
Definition: astobj2.h:464
def info(msg)
#define ast_cond_destroy(cond)
Definition: lock.h:200
void * ast_sorcery_alloc(const struct ast_sorcery *sorcery, const char *type, const char *id)
Allocate an object.
Definition: sorcery.c:1744
char * ast_uuid_generate_str(char *buf, size_t size)
Generate a UUID string.
Definition: uuid.c:143
static void * cleanup(void *unused)
Definition: pbx_realtime.c:124
struct ao2_container * cache
Definition: pbx_realtime.c:77
static struct ast_sorcery * sorcery
static struct ast_sorcery * alloc_and_initialize_sorcery(void)
struct ao2_container * objects
Objects in the cache.
unsigned int cache_notify
Variable used to indicate we should notify a test when we reach empty.
#define ast_mutex_init(pmutex)
Definition: lock.h:184
#define ast_mutex_destroy(a)
Definition: lock.h:186
static void * sorcery_memory_cache_open(const char *data)
ast_cond_t cond
Condition used for signaling when the cache has reached empty.
#define ast_cond_timedwait(cond, mutex, time)
Definition: lock.h:204
#define ast_mutex_unlock(a)
Definition: lock.h:188
unsigned int cache_completed
Variable that is set when the cache has reached empty.

◆ AST_TEST_DEFINE() [8/10]

AST_TEST_DEFINE ( stale  )

Definition at line 3118 of file res_sorcery_memory_cache.c.

References ao2_cleanup, ao2_ref, ARRAY_LEN, ast_sorcery_apply_wizard_mapping, ast_sorcery_internal_object_register, ast_sorcery_open, ast_sorcery_retrieve_by_id(), ast_sorcery_unref, ast_sorcery_wizard_register, ast_sorcery_wizard_unregister(), AST_TEST_FAIL, AST_TEST_NOT_RUN, AST_TEST_PASS, ast_test_status_update, cleanup(), exists(), sip_to_pjsip::info(), NULL, backend_data::pepper, RAII_VAR, real_backend_data, backend_data::salt, sorcery_memory_cache::sorcery, test_data_alloc(), TEST_EXECUTE, TEST_INIT, and wait_for_cache_update().

3119 {
3120  int res = AST_TEST_FAIL;
3121  struct ast_sorcery *sorcery = NULL;
3122  struct test_data *backend_object;
3123  struct backend_data iterations[] = {
3124  { .salt = 1, .pepper = 2, .exists = 1 },
3125  { .salt = 568729, .pepper = -234123, .exists = 1 },
3126  { .salt = 0, .pepper = 0, .exists = 0 },
3127  };
3128  struct backend_data initial = {
3129  .salt = 0,
3130  .pepper = 0,
3131  .exists = 1,
3132  };
3133  int i;
3134 
3135  switch (cmd) {
3136  case TEST_INIT:
3137  info->name = "stale";
3138  info->category = "/res/res_sorcery_memory_cache/";
3139  info->summary = "Ensure that stale objects are replaced with updated objects";
3140  info->description = "This test performs the following:\n"
3141  "\t* Create a sorcery instance with two wizards"
3142  "\t\t* The first is a memory cache that marks items stale after 3 seconds\n"
3143  "\t\t* The second is a mock of a back-end\n"
3144  "\t* Pre-populates the cache by retrieving some initial data from the backend.\n"
3145  "\t* Performs iterations of the following:\n"
3146  "\t\t* Update backend data with new values\n"
3147  "\t\t* Retrieve item from the cache\n"
3148  "\t\t* Ensure the retrieved item does not have the new backend values\n"
3149  "\t\t* Wait for cached object to become stale\n"
3150  "\t\t* Retrieve the stale cached object\n"
3151  "\t\t* Ensure that the stale object retrieved is the same as the fresh one from earlier\n"
3152  "\t\t* Wait for the cache to update with new data\n"
3153  "\t\t* Ensure that new data in the cache matches backend data";
3154  return AST_TEST_NOT_RUN;
3155  case TEST_EXECUTE:
3156  break;
3157  }
3158 
3160 
3161  sorcery = ast_sorcery_open();
3162  if (!sorcery) {
3163  ast_test_status_update(test, "Failed to create sorcery instance\n");
3164  goto cleanup;
3165  }
3166 
3167  ast_sorcery_apply_wizard_mapping(sorcery, "test", "memory_cache",
3168  "object_lifetime_stale=3", 1);
3169  ast_sorcery_apply_wizard_mapping(sorcery, "test", "mock", NULL, 0);
3171 
3172  /* Prepopulate the cache */
3173  real_backend_data = &initial;
3174 
3175  backend_object = ast_sorcery_retrieve_by_id(sorcery, "test", "test");
3176  if (!backend_object) {
3177  ast_test_status_update(test, "Unable to retrieve backend data and populate the cache\n");
3178  goto cleanup;
3179  }
3180  ao2_ref(backend_object, -1);
3181 
3182  for (i = 0; i < ARRAY_LEN(iterations); ++i) {
3183  RAII_VAR(struct test_data *, cache_fresh, NULL, ao2_cleanup);
3184  RAII_VAR(struct test_data *, cache_stale, NULL, ao2_cleanup);
3185  RAII_VAR(struct test_data *, cache_new, NULL, ao2_cleanup);
3186 
3187  real_backend_data = &iterations[i];
3188 
3189  ast_test_status_update(test, "Begininning iteration %d\n", i);
3190 
3191  cache_fresh = ast_sorcery_retrieve_by_id(sorcery, "test", "test");
3192  if (!cache_fresh) {
3193  ast_test_status_update(test, "Unable to retrieve fresh cached object\n");
3194  goto cleanup;
3195  }
3196 
3197  if (cache_fresh->salt == iterations[i].salt || cache_fresh->pepper == iterations[i].pepper) {
3198  ast_test_status_update(test, "Fresh cached object has unexpected values. Did we hit the backend?\n");
3199  goto cleanup;
3200  }
3201 
3202  sleep(5);
3203 
3204  cache_stale = ast_sorcery_retrieve_by_id(sorcery, "test", "test");
3205  if (!cache_stale) {
3206  ast_test_status_update(test, "Unable to retrieve stale cached object\n");
3207  goto cleanup;
3208  }
3209 
3210  if (cache_stale != cache_fresh) {
3211  ast_test_status_update(test, "Stale cache hit retrieved different object than fresh cache hit\n");
3212  goto cleanup;
3213  }
3214 
3215  if (wait_for_cache_update(sorcery, cache_stale, &cache_new)) {
3216  ast_test_status_update(test, "Cache was not updated\n");
3217  goto cleanup;
3218  }
3219 
3220  if (iterations[i].exists) {
3221  if (!cache_new) {
3222  ast_test_status_update(test, "Failed to retrieve item from cache when there should be one present\n");
3223  goto cleanup;
3224  } else if (cache_new->salt != iterations[i].salt ||
3225  cache_new->pepper != iterations[i].pepper) {
3226  ast_test_status_update(test, "New cached item has unexpected values\n");
3227  goto cleanup;
3228  }
3229  } else if (cache_new) {
3230  ast_test_status_update(test, "Retrieved a cached item when there should not have been one present\n");
3231  goto cleanup;
3232  }
3233  }
3234 
3235  res = AST_TEST_PASS;
3236 
3237 cleanup:
3238  if (sorcery) {
3239  ast_sorcery_unref(sorcery);
3240  }
3242  return res;
3243 }
#define ARRAY_LEN(a)
Definition: isdn_lib.c:42
#define ast_sorcery_apply_wizard_mapping(sorcery, type, name, data, caching)
Apply additional object wizard mappings.
Definition: sorcery.h:511
static int exists(struct ast_channel *chan, const char *cmd, char *data, char *buf, size_t len)
Definition: func_logic.c:124
Full structure for sorcery.
Definition: sorcery.c:230
#define NULL
Definition: resample.c:96
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_sorcery_unref(sorcery)
Decrease the reference count of a sorcery structure.
Definition: sorcery.h:1502
#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:911
#define ast_test_status_update(a, b, c...)
Definition: test.h:129
#define ao2_ref(o, delta)
Definition: astobj2.h:464
#define ast_sorcery_wizard_register(interface)
See __ast_sorcery_wizard_register()
Definition: sorcery.h:383
#define ast_sorcery_internal_object_register(sorcery, type, alloc, transform, apply)
Register an internal, hidden object type.
Definition: sorcery.h:868
static void * test_data_alloc(const char *id)
Allocation callback for test_data sorcery object.
int ast_sorcery_wizard_unregister(const struct ast_sorcery_wizard *interface)
Unregister a sorcery wizard.
Definition: sorcery.c:474
def info(msg)
Sorcery object created based on backend data.
Backend data that the mock sorcery wizard uses to create objects.
static int wait_for_cache_update(const struct ast_sorcery *sorcery, void *previous_object, struct test_data **new_object)
Wait for the cache to be updated after a stale object is retrieved.
static void * cleanup(void *unused)
Definition: pbx_realtime.c:124
static struct ast_sorcery * sorcery
#define ao2_cleanup(obj)
Definition: astobj2.h:1958
static struct backend_data * real_backend_data
static struct ast_sorcery_wizard mock_wizard
A mock sorcery wizard used for the stale test.
#define ast_sorcery_open()
Definition: sorcery.h:408

◆ AST_TEST_DEFINE() [9/10]

AST_TEST_DEFINE ( full_backend_cache_expiration  )

Definition at line 3245 of file res_sorcery_memory_cache.c.

References ao2_container_count(), ao2_ref, ast_cond_destroy, ast_cond_init, ast_cond_timedwait, ast_mutex_destroy, ast_mutex_init, ast_mutex_lock, ast_mutex_unlock, AST_RETRIEVE_FLAG_ALL, AST_RETRIEVE_FLAG_MULTIPLE, ast_sorcery_apply_wizard_mapping, ast_sorcery_internal_object_register, ast_sorcery_object_field_register_nodoc, ast_sorcery_open, ast_sorcery_retrieve_by_fields(), ast_sorcery_unref, ast_sorcery_wizard_register, ast_sorcery_wizard_unregister(), AST_TEST_FAIL, AST_TEST_NOT_RUN, AST_TEST_PASS, ast_test_status_update, ast_tvnow(), cleanup(), sorcery_memory_cache::cond, backend_data::exists, FLDSET, sip_to_pjsip::info(), sorcery_memory_cache::lock, NULL, sorcery_memory_cache::objects, OPT_UINT_T, real_backend_data, backend_data::salt, sorcery_memory_cache::sorcery, test_data_alloc(), TEST_EXECUTE, and TEST_INIT.

3246 {
3247  int res = AST_TEST_FAIL;
3248  struct ast_sorcery *sorcery = NULL;
3249  struct backend_data initial = {
3250  .salt = 0,
3251  .pepper = 0,
3252  .exists = 4,
3253  };
3254  struct ao2_container *objects;
3255  ast_mutex_t lock;
3256  ast_cond_t cond;
3257  struct timeval start;
3258  struct timespec end;
3259 
3260  switch (cmd) {
3261  case TEST_INIT:
3262  info->name = "full_backend_cache_expiration";
3263  info->category = "/res/res_sorcery_memory_cache/";
3264  info->summary = "Ensure that the full backend cache actually caches the backend";
3265  info->description = "This test performs the following:\n"
3266  "\t* Create a sorcery instance with two wizards"
3267  "\t\t* The first is a memory cache that expires objects after 3 seconds and does full backend caching\n"
3268  "\t\t* The second is a mock of a back-end\n"
3269  "\t* Populates the cache by requesting all objects which returns 4.\n"
3270  "\t* Updates the backend to contain a different number of objects, 8.\n"
3271  "\t* Requests all objects and confirms the number returned is only 4.\n"
3272  "\t* Wait for cached objects to expire.\n"
3273  "\t* Requests all objects and confirms the number returned is 8.";
3274  return AST_TEST_NOT_RUN;
3275  case TEST_EXECUTE:
3276  break;
3277  }
3278 
3280 
3281  sorcery = ast_sorcery_open();
3282  if (!sorcery) {
3283  ast_test_status_update(test, "Failed to create sorcery instance\n");
3284  goto cleanup;
3285  }
3286 
3287  ast_sorcery_apply_wizard_mapping(sorcery, "test", "memory_cache",
3288  "object_lifetime_maximum=3,full_backend_cache=yes", 1);
3289  ast_sorcery_apply_wizard_mapping(sorcery, "test", "mock", NULL, 0);
3291  ast_sorcery_object_field_register_nodoc(sorcery, "test", "salt", "0", OPT_UINT_T, 0, FLDSET(struct test_data, salt));
3292  ast_sorcery_object_field_register_nodoc(sorcery, "test", "pepper", "0", OPT_UINT_T, 0, FLDSET(struct test_data, pepper));
3293 
3294  /* Prepopulate the cache */
3295  real_backend_data = &initial;
3296 
3297  /* Get all current objects in the backend */
3299  if (!objects) {
3300  ast_test_status_update(test, "Unable to retrieve all objects in backend and populate cache\n");
3301  goto cleanup;
3302  }
3303  ao2_ref(objects, -1);
3304 
3305  /* Update the backend to have a different number of objects */
3306  initial.exists = 8;
3307 
3308  /* Get all current objects in the backend */
3310  if (!objects) {
3311  ast_test_status_update(test, "Unable to retrieve all objects in backend and populate cache\n");
3312  goto cleanup;
3313  }
3314 
3315  if (ao2_container_count(objects) == initial.exists) {
3316  ast_test_status_update(test, "Number of objects returned is of the current backend and not the cache\n");
3317  ao2_ref(objects, -1);
3318  goto cleanup;
3319  }
3320 
3321  ao2_ref(objects, -1);
3322 
3323  ast_mutex_init(&lock);
3324  ast_cond_init(&cond, NULL);
3325 
3326  start = ast_tvnow();
3327  end.tv_sec = start.tv_sec + 5;
3328  end.tv_nsec = start.tv_usec * 1000;
3329 
3330  ast_mutex_lock(&lock);
3331  while (ast_cond_timedwait(&cond, &lock, &end) != ETIMEDOUT) {
3332  }
3333  ast_mutex_unlock(&lock);
3334 
3335  ast_mutex_destroy(&lock);
3336  ast_cond_destroy(&cond);
3337 
3338  /* Get all current objects in the backend */
3340  if (!objects) {
3341  ast_test_status_update(test, "Unable to retrieve all objects in backend and populate cache\n");
3342  goto cleanup;
3343  }
3344 
3345  if (ao2_container_count(objects) != initial.exists) {
3346  ast_test_status_update(test, "Number of objects returned is NOT of the current backend when it should be\n");
3347  ao2_ref(objects, -1);
3348  goto cleanup;
3349  }
3350 
3351  ao2_ref(objects, -1);
3352 
3353  res = AST_TEST_PASS;
3354 
3355 cleanup:
3356  if (sorcery) {
3357  ast_sorcery_unref(sorcery);
3358  }
3360  return res;
3361 }
#define ast_sorcery_object_field_register_nodoc(sorcery, type, name, default_val, opt_type, flags,...)
Register a field within an object without documentation.
Definition: sorcery.h:987
int ao2_container_count(struct ao2_container *c)
Returns the number of elements in a container.
#define ast_sorcery_apply_wizard_mapping(sorcery, type, name, data, caching)
Apply additional object wizard mappings.
Definition: sorcery.h:511
Perform no matching, return all objects.
Definition: sorcery.h:123
Full structure for sorcery.
Definition: sorcery.c:230
#define ast_cond_init(cond, attr)
Definition: lock.h:199
struct timeval ast_tvnow(void)
Returns current timeval. Meant to replace calls to gettimeofday().
Definition: time.h:150
Return all matching objects.
Definition: sorcery.h:120
#define ast_mutex_lock(a)
Definition: lock.h:187
#define NULL
Definition: resample.c:96
char * end
Definition: eagi_proxy.c:73
pthread_cond_t ast_cond_t
Definition: lock.h:176
#define ast_sorcery_unref(sorcery)
Decrease the reference count of a sorcery structure.
Definition: sorcery.h:1502
#define FLDSET(type,...)
Convert a struct and list of fields to an argument list of field offsets.
Type for default option handler for unsigned integers.
#define ast_test_status_update(a, b, c...)
Definition: test.h:129
ast_mutex_t lock
Definition: app_meetme.c:1091
ast_cond_t cond
Definition: app_meetme.c:1090
#define ao2_ref(o, delta)
Definition: astobj2.h:464
#define ast_sorcery_wizard_register(interface)
See __ast_sorcery_wizard_register()
Definition: sorcery.h:383
#define ast_sorcery_internal_object_register(sorcery, type, alloc, transform, apply)
Register an internal, hidden object type.
Definition: sorcery.h:868
static void * test_data_alloc(const char *id)
Allocation callback for test_data sorcery object.
int ast_sorcery_wizard_unregister(const struct ast_sorcery_wizard *interface)
Unregister a sorcery wizard.
Definition: sorcery.c:474
def info(msg)
Sorcery object created based on backend data.
#define ast_cond_destroy(cond)
Definition: lock.h:200
Backend data that the mock sorcery wizard uses to create objects.
static void * cleanup(void *unused)
Definition: pbx_realtime.c:124
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
static struct ast_sorcery * sorcery
static struct backend_data * real_backend_data
static struct ast_sorcery_wizard mock_wizard
A mock sorcery wizard used for the stale test.
#define ast_sorcery_open()
Definition: sorcery.h:408
#define ast_mutex_init(pmutex)
Definition: lock.h:184
Generic container type.
#define ast_mutex_destroy(a)
Definition: lock.h:186
#define ast_cond_timedwait(cond, mutex, time)
Definition: lock.h:204
Structure for mutex and tracking information.
Definition: lock.h:135
#define ast_mutex_unlock(a)
Definition: lock.h:188

◆ AST_TEST_DEFINE() [10/10]

AST_TEST_DEFINE ( full_backend_cache_stale  )

Definition at line 3363 of file res_sorcery_memory_cache.c.

References ao2_container_count(), ao2_ref, ast_cond_destroy, ast_cond_init, ast_cond_timedwait, ast_mutex_destroy, ast_mutex_init, ast_mutex_lock, ast_mutex_unlock, AST_RETRIEVE_FLAG_ALL, AST_RETRIEVE_FLAG_MULTIPLE, ast_sorcery_apply_wizard_mapping, ast_sorcery_internal_object_register, ast_sorcery_object_field_register_nodoc, ast_sorcery_open, ast_sorcery_retrieve_by_fields(), ast_sorcery_unref, ast_sorcery_wizard_register, ast_sorcery_wizard_unregister(), AST_TEST_FAIL, AST_TEST_NOT_RUN, AST_TEST_PASS, ast_test_status_update, ast_tvnow(), cleanup(), sorcery_memory_cache::cond, backend_data::exists, FLDSET, sip_to_pjsip::info(), sorcery_memory_cache::lock, NULL, sorcery_memory_cache::objects, OPT_UINT_T, real_backend_data, backend_data::salt, sorcery_memory_cache::sorcery, test_data_alloc(), TEST_EXECUTE, and TEST_INIT.

3364 {
3365  int res = AST_TEST_FAIL;
3366  struct ast_sorcery *sorcery = NULL;
3367  struct backend_data initial = {
3368  .salt = 0,
3369  .pepper = 0,
3370  .exists = 4,
3371  };
3372  struct ao2_container *objects;
3373  ast_mutex_t lock;
3374  ast_cond_t cond;
3375  struct timeval start;
3376  struct timespec end;
3377 
3378  switch (cmd) {
3379  case TEST_INIT:
3380  info->name = "full_backend_cache_stale";
3381  info->category = "/res/res_sorcery_memory_cache/";
3382  info->summary = "Ensure that the full backend cache works with staleness";
3383  info->description = "This test performs the following:\n"
3384  "\t* Create a sorcery instance with two wizards"
3385  "\t\t* The first is a memory cache that stales objects after 1 second and does full backend caching\n"
3386  "\t\t* The second is a mock of a back-end\n"
3387  "\t* Populates the cache by requesting all objects which returns 4.\n"
3388  "\t* Wait for objects to go stale.\n"
3389  "\t* Updates the backend to contain a different number of objects, 8.\""
3390  "\t* Requests all objects and confirms the number returned is only 4.\n"
3391  "\t* Wait for objects to be refreshed from backend.\n"
3392  "\t* Requests all objects and confirms the number returned is 8.";
3393  return AST_TEST_NOT_RUN;
3394  case TEST_EXECUTE:
3395  break;
3396  }
3397 
3399 
3400  ast_mutex_init(&lock);
3401  ast_cond_init(&cond, NULL);
3402 
3403  sorcery = ast_sorcery_open();
3404  if (!sorcery) {
3405  ast_test_status_update(test, "Failed to create sorcery instance\n");
3406  goto cleanup;
3407  }
3408 
3409  ast_sorcery_apply_wizard_mapping(sorcery, "test", "memory_cache",
3410  "object_lifetime_stale=1,full_backend_cache=yes", 1);
3411  ast_sorcery_apply_wizard_mapping(sorcery, "test", "mock", NULL, 0);
3413  ast_sorcery_object_field_register_nodoc(sorcery, "test", "salt", "0", OPT_UINT_T, 0, FLDSET(struct test_data, salt));
3414  ast_sorcery_object_field_register_nodoc(sorcery, "test", "pepper", "0", OPT_UINT_T, 0, FLDSET(struct test_data, pepper));
3415 
3416  /* Prepopulate the cache */
3417  real_backend_data = &initial;
3418 
3419  /* Get all current objects in the backend */
3421  if (!objects) {
3422  ast_test_status_update(test, "Unable to retrieve all objects in backend and populate cache\n");
3423  goto cleanup;
3424  }
3425  ao2_ref(objects, -1);
3426 
3427  start = ast_tvnow();
3428  end.tv_sec = start.tv_sec + 5;
3429  end.tv_nsec = start.tv_usec * 1000;
3430 
3431  ast_mutex_lock(&lock);
3432  while (ast_cond_timedwait(&cond, &lock, &end) != ETIMEDOUT) {
3433  }
3434  ast_mutex_unlock(&lock);
3435 
3436  initial.exists = 8;
3437 
3438  /* Get all current objects in the backend */
3440  if (!objects) {
3441  ast_test_status_update(test, "Unable to retrieve all objects in backend and populate cache\n");
3442  goto cleanup;
3443  }
3444 
3445  if (ao2_container_count(objects) == initial.exists) {
3446  ast_test_status_update(test, "Number of objects returned is of the backend and not the cache\n");
3447  ao2_ref(objects, -1);
3448  goto cleanup;
3449  }
3450 
3451  ao2_ref(objects, -1);
3452 
3453  start = ast_tvnow();
3454  end.tv_sec = start.tv_sec + 5;
3455  end.tv_nsec = start.tv_usec * 1000;
3456 
3457  ast_mutex_lock(&lock);
3458  while (ast_cond_timedwait(&cond, &lock, &end) != ETIMEDOUT) {
3459  }
3460  ast_mutex_unlock(&lock);
3461 
3462  /* Get all current objects in the backend */
3464  if (!objects) {
3465  ast_test_status_update(test, "Unable to retrieve all objects in backend and populate cache\n");
3466  goto cleanup;
3467  }
3468 
3469  if (ao2_container_count(objects) != initial.exists) {
3470  ast_test_status_update(test, "Number of objects returned is not of backend\n");
3471  ao2_ref(objects, -1);
3472  goto cleanup;
3473  }
3474 
3475  ao2_ref(objects, -1);
3476 
3477  start = ast_tvnow();
3478  end.tv_sec = start.tv_sec + 5;
3479  end.tv_nsec = start.tv_usec * 1000;
3480 
3481  ast_mutex_lock(&lock);
3482  while (ast_cond_timedwait(&cond, &lock, &end) != ETIMEDOUT) {
3483  }
3484  ast_mutex_unlock(&lock);
3485 
3486  res = AST_TEST_PASS;
3487 
3488 cleanup:
3489  if (sorcery) {
3490  ast_sorcery_unref(sorcery);
3491  }
3493  ast_mutex_destroy(&lock);
3494  ast_cond_destroy(&cond);
3495  return res;
3496 }
#define ast_sorcery_object_field_register_nodoc(sorcery, type, name, default_val, opt_type, flags,...)
Register a field within an object without documentation.
Definition: sorcery.h:987
int ao2_container_count(struct ao2_container *c)
Returns the number of elements in a container.
#define ast_sorcery_apply_wizard_mapping(sorcery, type, name, data, caching)
Apply additional object wizard mappings.
Definition: sorcery.h:511
Perform no matching, return all objects.
Definition: sorcery.h:123
Full structure for sorcery.
Definition: sorcery.c:230
#define ast_cond_init(cond, attr)
Definition: lock.h:199
struct timeval ast_tvnow(void)
Returns current timeval. Meant to replace calls to gettimeofday().
Definition: time.h:150
Return all matching objects.
Definition: sorcery.h:120
#define ast_mutex_lock(a)
Definition: lock.h:187
#define NULL
Definition: resample.c:96
char * end
Definition: eagi_proxy.c:73
pthread_cond_t ast_cond_t
Definition: lock.h:176
#define ast_sorcery_unref(sorcery)
Decrease the reference count of a sorcery structure.
Definition: sorcery.h:1502
#define FLDSET(type,...)
Convert a struct and list of fields to an argument list of field offsets.
Type for default option handler for unsigned integers.
#define ast_test_status_update(a, b, c...)
Definition: test.h:129
ast_mutex_t lock
Definition: app_meetme.c:1091
ast_cond_t cond
Definition: app_meetme.c:1090
#define ao2_ref(o, delta)
Definition: astobj2.h:464
#define ast_sorcery_wizard_register(interface)
See __ast_sorcery_wizard_register()
Definition: sorcery.h:383
#define ast_sorcery_internal_object_register(sorcery, type, alloc, transform, apply)
Register an internal, hidden object type.
Definition: sorcery.h:868
static void * test_data_alloc(const char *id)
Allocation callback for test_data sorcery object.
int ast_sorcery_wizard_unregister(const struct ast_sorcery_wizard *interface)
Unregister a sorcery wizard.
Definition: sorcery.c:474
def info(msg)
Sorcery object created based on backend data.
#define ast_cond_destroy(cond)
Definition: lock.h:200
Backend data that the mock sorcery wizard uses to create objects.
static void * cleanup(void *unused)
Definition: pbx_realtime.c:124
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
static struct ast_sorcery * sorcery
static struct backend_data * real_backend_data
static struct ast_sorcery_wizard mock_wizard
A mock sorcery wizard used for the stale test.
#define ast_sorcery_open()
Definition: sorcery.h:408
#define ast_mutex_init(pmutex)
Definition: lock.h:184
Generic container type.
#define ast_mutex_destroy(a)
Definition: lock.h:186
#define ast_cond_timedwait(cond, mutex, time)
Definition: lock.h:204
Structure for mutex and tracking information.
Definition: lock.h:135
#define ast_mutex_unlock(a)
Definition: lock.h:188

◆ check_cache_content()

static int check_cache_content ( struct ast_test test,
struct ast_sorcery sorcery,
struct sorcery_memory_cache cache,
const char **  in_cache,
size_t  num_in_cache,
const char **  not_in_cache,
size_t  num_not_in_cache 
)
static

Definition at line 2725 of file res_sorcery_memory_cache.c.

References ao2_cleanup, ao2_ref, ast_test_status_update, NULL, RAII_VAR, and sorcery_memory_cache_retrieve_id().

Referenced by AST_TEST_DEFINE().

2727 {
2728  int i;
2729  int res = 0;
2730  RAII_VAR(void *, cached_object, NULL, ao2_cleanup);
2731 
2732  for (i = 0; i < num_in_cache; ++i) {
2733  cached_object = sorcery_memory_cache_retrieve_id(sorcery, cache, "test", in_cache[i]);
2734  if (!cached_object) {
2735  ast_test_status_update(test, "Failed to retrieve '%s' object from the cache\n",
2736  in_cache[i]);
2737  res = -1;
2738  }
2739  ao2_ref(cached_object, -1);
2740  }
2741 
2742  for (i = 0; i < num_not_in_cache; ++i) {
2743  cached_object = sorcery_memory_cache_retrieve_id(sorcery, cache, "test", not_in_cache[i]);
2744  if (cached_object) {
2745  ast_test_status_update(test, "Retrieved '%s' object from the cache unexpectedly\n",
2746  not_in_cache[i]);
2747  ao2_ref(cached_object, -1);
2748  res = -1;
2749  }
2750  }
2751 
2752  return res;
2753 }
static void * sorcery_memory_cache_retrieve_id(const struct ast_sorcery *sorcery, void *data, const char *type, const char *id)
#define NULL
Definition: resample.c:96
#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:911
#define ast_test_status_update(a, b, c...)
Definition: test.h:129
#define ao2_ref(o, delta)
Definition: astobj2.h:464
#define ao2_cleanup(obj)
Definition: astobj2.h:1958

◆ configuration_parse_unsigned_integer()

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

Definition at line 1484 of file res_sorcery_memory_cache.c.

References ast_strlen_zero.

Referenced by sorcery_memory_cache_open().

1485 {
1486  if (ast_strlen_zero(value) || !strncmp(value, "-", 1)) {
1487  return 0;
1488  }
1489 
1490  return sscanf(value, "%30u", result);
1491 }
int value
Definition: syslog.c:37
#define ast_strlen_zero(foo)
Definition: strings.h:52
static PGresult * result
Definition: cel_pgsql.c:88

◆ end_passthru_update()

static void end_passthru_update ( void  )
static

Definition at line 281 of file res_sorcery_memory_cache.c.

References set_passthru_update().

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

282 {
284 }
static void set_passthru_update(uint32_t value)

◆ expire_objects_from_cache()

static int expire_objects_from_cache ( const void *  data)
static

Definition at line 498 of file res_sorcery_memory_cache.c.

References ao2_ref, ao2_trywrlock, ao2_unlock, ast_heap_peek(), ast_samp2tv(), ast_sorcery_object_get_id(), ast_tvadd(), ast_tvdiff_ms(), ast_tvnow(), sorcery_memory_cached_object::created, sorcery_memory_cache::del_expire, sorcery_memory_cache::expire_id, sorcery_memory_cached_object::object, sorcery_memory_cache::object_heap, sorcery_memory_cache::object_lifetime_maximum, sorcery_memory_cache::objects, remove_from_cache(), and schedule_cache_expiration().

Referenced by schedule_cache_expiration().

499 {
500  struct sorcery_memory_cache *cache = (struct sorcery_memory_cache *)data;
501  struct sorcery_memory_cached_object *cached;
502 
503  /*
504  * We need to do deadlock avoidance between a non-scheduler thread
505  * blocking when trying to delete the scheduled entry for this
506  * callback because the scheduler thread is running this callback
507  * and this callback waiting for the cache->objects container lock
508  * that the blocked non-scheduler thread already holds.
509  */
510  while (ao2_trywrlock(cache->objects)) {
511  if (cache->del_expire) {
512  cache->expire_id = -1;
513  ao2_ref(cache, -1);
514  return 0;
515  }
516  sched_yield();
517  }
518 
519  cache->expire_id = -1;
520 
521  /* This is an optimization for objects which have been cached close to each other */
522  while ((cached = ast_heap_peek(cache->object_heap, 1))) {
523  int expiration;
524 
525  expiration = ast_tvdiff_ms(ast_tvadd(cached->created, ast_samp2tv(cache->object_lifetime_maximum, 1)), ast_tvnow());
526 
527  /* If the current oldest object has not yet expired stop and reschedule for it */
528  if (expiration > 0) {
529  break;
530  }
531 
533  }
534 
536 
537  ao2_unlock(cache->objects);
538 
539  ao2_ref(cache, -1);
540 
541  return 0;
542 }
static int schedule_cache_expiration(struct sorcery_memory_cache *cache)
#define ao2_trywrlock(a)
Definition: astobj2.h:742
struct timeval ast_tvnow(void)
Returns current timeval. Meant to replace calls to gettimeofday().
Definition: time.h:150
struct timeval created
The time at which the object was created.
unsigned int object_lifetime_maximum
The maximum time (in seconds) an object will stay in the cache, 0 if no limit.
#define ao2_unlock(a)
Definition: astobj2.h:730
int64_t ast_tvdiff_ms(struct timeval end, struct timeval start)
Computes the difference (in milliseconds) between two struct timeval instances.
Definition: time.h:98
struct ast_heap * object_heap
Heap of cached objects. Oldest object is at the top.
Structure for storing a memory cache.
#define ao2_ref(o, delta)
Definition: astobj2.h:464
Structure for stored a cached object.
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:238
const char * ast_sorcery_object_get_id(const void *object)
Get the unique identifier of a sorcery object.
Definition: sorcery.c:2312
static int remove_from_cache(struct sorcery_memory_cache *cache, const char *id, int reschedule)
int expire_id
Scheduler item for expiring oldest object.
struct timeval ast_tvadd(struct timeval a, struct timeval b)
Returns the sum of two timevals a + b.
Definition: extconf.c:2283
void * object
The cached object.
struct ao2_container * cache
Definition: pbx_realtime.c:77
struct ao2_container * objects
Objects in the cache.
void * ast_heap_peek(struct ast_heap *h, unsigned int index)
Peek at an element on a heap.
Definition: heap.c:267

◆ is_passthru_update()

static int is_passthru_update ( void  )
static

Definition at line 249 of file res_sorcery_memory_cache.c.

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

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

◆ load_module()

static int load_module ( void  )
static

Definition at line 3538 of file res_sorcery_memory_cache.c.

References AO2_ALLOC_OPT_LOCK_MUTEX, ao2_container_alloc_hash, ARRAY_LEN, ast_cli_register_multiple, ast_log, ast_manager_register_xml, AST_MODFLAG_GLOBAL_SYMBOLS, AST_MODFLAG_LOAD_ORDER, AST_MODPRI_REALTIME_DRIVER, AST_MODULE_INFO(), AST_MODULE_LOAD_DECLINE, AST_MODULE_LOAD_SUCCESS, AST_MODULE_SUPPORT_CORE, ast_sched_context_create(), ast_sched_start_thread(), ast_sorcery_wizard_register, AST_TEST_REGISTER, ASTERISK_GPL_KEY, CACHES_CONTAINER_BUCKET_SIZE, EVENT_FLAG_SYSTEM, LOG_ERROR, sorcery_memory_cache::maximum_objects, 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().

3539 {
3540  int res;
3541 
3545  if (!caches) {
3546  ast_log(LOG_ERROR, "Failed to create container for configured caches\n");
3547  unload_module();
3548  return AST_MODULE_LOAD_DECLINE;
3549  }
3550 
3552  if (!sched) {
3553  ast_log(LOG_ERROR, "Failed to create scheduler for cache management\n");
3554  unload_module();
3555  return AST_MODULE_LOAD_DECLINE;
3556  }
3557 
3559  ast_log(LOG_ERROR, "Failed to create scheduler thread for cache management\n");
3560  unload_module();
3561  return AST_MODULE_LOAD_DECLINE;
3562  }
3563 
3565  unload_module();
3566  return AST_MODULE_LOAD_DECLINE;
3567  }
3568 
3570  res |= ast_manager_register_xml("SorceryMemoryCacheExpireObject", EVENT_FLAG_SYSTEM, sorcery_memory_cache_ami_expire_object);
3571  res |= ast_manager_register_xml("SorceryMemoryCacheExpire", EVENT_FLAG_SYSTEM, sorcery_memory_cache_ami_expire);
3572  res |= ast_manager_register_xml("SorceryMemoryCacheStaleObject", EVENT_FLAG_SYSTEM, sorcery_memory_cache_ami_stale_object);
3574  res |= ast_manager_register_xml("SorceryMemoryCachePopulate", EVENT_FLAG_SYSTEM, sorcery_memory_cache_ami_populate);
3575 
3576  if (res) {
3577  unload_module();
3578  return AST_MODULE_LOAD_DECLINE;
3579  }
3580 
3581  /* This causes the stale unit test to execute last, so if a sorcery instance persists
3582  * longer than expected subsequent unit tests don't fail when setting it up.
3583  */
3584  AST_TEST_REGISTER(stale);
3585  AST_TEST_REGISTER(open_with_valid_options);
3586  AST_TEST_REGISTER(open_with_invalid_options);
3587  AST_TEST_REGISTER(create_and_retrieve);
3589  AST_TEST_REGISTER(delete);
3590  AST_TEST_REGISTER(maximum_objects);
3591  AST_TEST_REGISTER(expiration);
3592  AST_TEST_REGISTER(full_backend_cache_expiration);
3593  AST_TEST_REGISTER(full_backend_cache_stale);
3594 
3595  return AST_MODULE_LOAD_SUCCESS;
3596 }
int ast_sched_start_thread(struct ast_sched_context *con)
Start a thread for processing scheduler entries.
Definition: sched.c:195
#define ARRAY_LEN(a)
Definition: isdn_lib.c:42
static int sorcery_memory_cache_ami_expire_object(struct mansession *s, const struct message *m)
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
static struct ast_sorcery_wizard memory_cache_object_wizard
Definition: sched.c:76
#define AST_TEST_REGISTER(cb)
Definition: test.h:127
#define ast_cli_register_multiple(e, len)
Register multiple commands.
Definition: cli.h:265
#define NULL
Definition: resample.c:96
static int sorcery_memory_cache_hash(const void *obj, int flags)
static int unload_module(void)
static int sorcery_memory_cache_cmp(void *obj, void *arg, int flags)
static int sorcery_memory_cache_ami_populate(struct mansession *s, const struct message *m)
#define EVENT_FLAG_SYSTEM
Definition: manager.h:71
#define ast_log
Definition: astobj2.c:42
static int sorcery_memory_cache_ami_expire(struct mansession *s, const struct message *m)
struct ast_sched_context * ast_sched_context_create(void)
Create a scheduler context.
Definition: sched.c:236
#define ast_sorcery_wizard_register(interface)
See __ast_sorcery_wizard_register()
Definition: sorcery.h:383
#define LOG_ERROR
Definition: logger.h:285
#define ao2_container_alloc_hash(ao2_options, container_options, n_buckets, hash_fn, sort_fn, cmp_fn)
Definition: astobj2.h:1310
static struct ao2_container * caches
Container of created caches.
Module has failed to load, may be in an inconsistent state.
Definition: module.h:78
static struct ast_cli_entry cli_memory_cache[]
#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 int sorcery_memory_cache_ami_stale_object(struct mansession *s, const struct message *m)
#define ast_manager_register_xml(action, authority, func)
Register a manager callback using XML documentation to describe the manager.
Definition: manager.h:186

◆ mark_all_as_stale_in_cache()

static void mark_all_as_stale_in_cache ( struct sorcery_memory_cache cache)
static

Definition at line 632 of file res_sorcery_memory_cache.c.

References ao2_callback, OBJ_MULTIPLE, OBJ_NODATA, OBJ_NOLOCK, object_stale_callback(), and sorcery_memory_cache::objects.

Referenced by sorcery_memory_cache_ami_stale(), and sorcery_memory_cache_stale().

633 {
635 }
static int object_stale_callback(void *obj, void *arg, int flags)
#define ao2_callback(c, flags, cb_fn, arg)
Definition: astobj2.h:1716
Assume that the ao2_container is already locked.
Definition: astobj2.h:1067
struct ao2_container * objects
Objects in the cache.

◆ mark_object_as_stale_in_cache()

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

Definition at line 605 of file res_sorcery_memory_cache.c.

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

Referenced by sorcery_memory_cache_ami_stale_object(), and sorcery_memory_cache_stale().

606 {
607  struct sorcery_memory_cached_object *cached;
608 
609  cached = ao2_find(cache->objects, id, OBJ_SEARCH_KEY | OBJ_NOLOCK);
610  if (!cached) {
611  return -1;
612  }
613 
614  ast_assert(!strcmp(ast_sorcery_object_get_id(cached->object), id));
615 
616  object_stale_callback(cached, cache, 0);
617  ao2_ref(cached, -1);
618 
619  return 0;
620 }
static int object_stale_callback(void *obj, void *arg, int flags)
The arg parameter is a search key, but is not an object.
Definition: astobj2.h:1105
Assume that the ao2_container is already locked.
Definition: astobj2.h:1067
#define ast_assert(a)
Definition: utils.h:695
#define ao2_ref(o, delta)
Definition: astobj2.h:464
Structure for stored a cached object.
const char * ast_sorcery_object_get_id(const void *object)
Get the unique identifier of a sorcery object.
Definition: sorcery.c:2312
void * object
The cached object.
#define ao2_find(container, arg, flags)
Definition: astobj2.h:1756
struct ao2_container * objects
Objects in the cache.

◆ memory_cache_full_update()

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

Definition at line 1077 of file res_sorcery_memory_cache.c.

References ao2_container_count(), ao2_unlock, ao2_wrlock, sorcery_memory_cache::full_backend_cache, memory_cache_populate(), and sorcery_memory_cache::objects.

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

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

◆ memory_cache_populate()

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

Definition at line 1034 of file res_sorcery_memory_cache.c.

References ao2_callback_data, ao2_container_count(), ao2_ref, ast_log, AST_RETRIEVE_FLAG_ALL, AST_RETRIEVE_FLAG_MULTIPLE, ast_sorcery_retrieve_by_fields(), end_passthru_update(), LOG_ERROR, LOG_WARNING, sorcery_memory_cache::maximum_objects, sorcery_memory_cache::name, NULL, OBJ_MULTIPLE, OBJ_NODATA, OBJ_NOLOCK, object_add_to_cache_callback(), sorcery_memory_cache::objects, remove_all_from_cache(), and start_passthru_update().

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

1035 {
1036  struct ao2_container *backend_objects;
1037 
1041 
1042  if (!backend_objects) {
1043  /* This will occur in off-nominal memory allocation failure scenarios */
1044  return;
1045  }
1046 
1047  if (cache->maximum_objects && ao2_container_count(backend_objects) >= cache->maximum_objects) {
1048  ast_log(LOG_ERROR, "The backend contains %d objects while the sorcery memory cache '%s' is explicitly configured to only allow %d\n",
1049  ao2_container_count(backend_objects), cache->name, cache->maximum_objects);
1050  return;
1051  }
1052 
1054  (struct ast_sorcery*)sorcery, cache);
1055 
1056  /* If the number of cached objects does not match the number of backend objects we encountered a memory allocation
1057  * failure and the cache is incomplete, so drop everything and fall back to querying the backend directly
1058  * as it may be able to provide what is wanted.
1059  */
1060  if (ao2_container_count(cache->objects) != ao2_container_count(backend_objects)) {
1061  ast_log(LOG_WARNING, "The backend contains %d objects while only %d could be added to sorcery memory cache '%s'\n",
1062  ao2_container_count(backend_objects), ao2_container_count(cache->objects), cache->name);
1063  remove_all_from_cache(cache);
1064  }
1065 
1066  ao2_ref(backend_objects, -1);
1067 }
static const char type[]
Definition: chan_ooh323.c:109
unsigned int maximum_objects
The maximum number of objects permitted in the cache, 0 if no limit.
int ao2_container_count(struct ao2_container *c)
Returns the number of elements in a container.
static void start_passthru_update(void)
#define LOG_WARNING
Definition: logger.h:274
Perform no matching, return all objects.
Definition: sorcery.h:123
Assume that the ao2_container is already locked.
Definition: astobj2.h:1067
Full structure for sorcery.
Definition: sorcery.c:230
Return all matching objects.
Definition: sorcery.h:120
#define NULL
Definition: resample.c:96
#define ast_log
Definition: astobj2.c:42
#define ao2_ref(o, delta)
Definition: astobj2.h:464
#define LOG_ERROR
Definition: logger.h:285
static void remove_all_from_cache(struct sorcery_memory_cache *cache)
#define ao2_callback_data(container, flags, cb_fn, arg, data)
Definition: astobj2.h:1743
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
struct ao2_container * objects
Objects in the cache.
static int object_add_to_cache_callback(void *obj, void *arg, void *data, int flags)
Generic container type.
static void end_passthru_update(void)
char * name
The name of the memory cache.

◆ memory_cache_stale_check()

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

Definition at line 1191 of file res_sorcery_memory_cache.c.

References ao2_bump, ao2_rdlock, ao2_ref, ao2_unlock, ast_heap_peek(), memory_cache_stale_check_object(), sorcery_memory_cache::object_heap, and sorcery_memory_cache::objects.

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

1192 {
1193  struct sorcery_memory_cached_object *cached;
1194 
1195  ao2_rdlock(cache->objects);
1196  cached = ao2_bump(ast_heap_peek(cache->object_heap, 1));
1197  ao2_unlock(cache->objects);
1198 
1199  if (!cached) {
1200  return;
1201  }
1202 
1203  memory_cache_stale_check_object(sorcery, cache, cached);
1204  ao2_ref(cached, -1);
1205 }
#define ao2_unlock(a)
Definition: astobj2.h:730
struct ast_heap * object_heap
Heap of cached objects. Oldest object is at the top.
#define ao2_bump(obj)
Definition: astobj2.h:491
#define ao2_ref(o, delta)
Definition: astobj2.h:464
Structure for stored a cached object.
static void memory_cache_stale_check_object(const struct ast_sorcery *sorcery, struct sorcery_memory_cache *cache, struct sorcery_memory_cached_object *cached)
#define ao2_rdlock(a)
Definition: astobj2.h:719
struct ao2_container * objects
Objects in the cache.
void * ast_heap_peek(struct ast_heap *h, unsigned int index)
Peek at an element on a heap.
Definition: heap.c:267

◆ memory_cache_stale_check_object()

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

Definition at line 1158 of file res_sorcery_memory_cache.c.

References ast_sorcery_object_get_type(), ast_tvnow(), ast_tvsub(), sorcery_memory_cached_object::created, sorcery_memory_cache::full_backend_cache, memory_cache_stale_update_full(), memory_cache_stale_update_object(), sorcery_memory_cached_object::object, and sorcery_memory_cache::object_lifetime_stale.

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

1160 {
1161  struct timeval elapsed;
1162 
1163  if (!cache->object_lifetime_stale) {
1164  return;
1165  }
1166 
1167  /* For a full cache as every object has the same expiration/staleness we can do the same check */
1168  elapsed = ast_tvsub(ast_tvnow(), cached->created);
1169 
1170  if (elapsed.tv_sec < cache->object_lifetime_stale) {
1171  return;
1172  }
1173 
1174  if (cache->full_backend_cache) {
1176  } else {
1177  memory_cache_stale_update_object(sorcery, cache, cached);
1178  }
1179 
1180 }
struct timeval ast_tvnow(void)
Returns current timeval. Meant to replace calls to gettimeofday().
Definition: time.h:150
struct timeval created
The time at which the object was created.
const char * ast_sorcery_object_get_type(const void *object)
Get the type of a sorcery object.
Definition: sorcery.c:2324
static void memory_cache_stale_update_object(const struct ast_sorcery *sorcery, struct sorcery_memory_cache *cache, struct sorcery_memory_cached_object *cached)
unsigned int full_backend_cache
Whether this is a cache of the entire backend, 0 if disabled.
void * object
The cached object.
static void memory_cache_stale_update_full(const struct ast_sorcery *sorcery, struct sorcery_memory_cache *cache, const char *type)
struct timeval ast_tvsub(struct timeval a, struct timeval b)
Returns the difference of two timevals a - b.
Definition: extconf.c:2298
unsigned int object_lifetime_stale
The amount of time (in seconds) before an object is marked as stale, 0 if disabled.

◆ memory_cache_stale_update_full()

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

Definition at line 1098 of file res_sorcery_memory_cache.c.

References ao2_cleanup, ao2_unlock, ao2_wrlock, ast_sched_add(), sorcery_memory_cache::objects, stale_cache_update(), stale_cache_update_task_data_alloc(), and sorcery_memory_cache::stale_update_sched_id.

Referenced by memory_cache_stale_check_object().

1100 {
1101  ao2_wrlock(cache->objects);
1102  if (cache->stale_update_sched_id == -1) {
1104 
1105  task_data = stale_cache_update_task_data_alloc((struct ast_sorcery *) sorcery,
1106  cache, type);
1107  if (task_data) {
1109  stale_cache_update, task_data);
1110  }
1111  if (cache->stale_update_sched_id < 0) {
1112  ao2_cleanup(task_data);
1113  }
1114  }
1115  ao2_unlock(cache->objects);
1116 }
static const char type[]
Definition: chan_ooh323.c:109
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)
Definition: sched.c:76
Full structure for sorcery.
Definition: sorcery.c:230
#define ao2_unlock(a)
Definition: astobj2.h:730
#define ao2_wrlock(a)
Definition: astobj2.h:720
int stale_update_sched_id
scheduler id of stale update task
userdata associated with baseline taskprocessor test
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:565
#define ao2_cleanup(obj)
Definition: astobj2.h:1958
struct ao2_container * objects
Objects in the cache.

◆ memory_cache_stale_update_object()

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

Definition at line 1126 of file res_sorcery_memory_cache.c.

References ao2_cleanup, ao2_lock, ao2_unlock, ast_debug, ast_log, ast_sched_add(), ast_sorcery_object_get_id(), ast_sorcery_object_get_type(), LOG_ERROR, sorcery_memory_cached_object::object, 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().

1128 {
1129  ao2_lock(cached);
1130  if (cached->stale_update_sched_id == -1) {
1132 
1133  task_data = stale_update_task_data_alloc((struct ast_sorcery *) sorcery,
1134  cache, ast_sorcery_object_get_type(cached->object), cached->object);
1135  if (task_data) {
1136  ast_debug(1, "Cached sorcery object type '%s' ID '%s' is stale. Refreshing\n",
1139  stale_item_update, task_data);
1140  }
1141  if (cached->stale_update_sched_id < 0) {
1142  ao2_cleanup(task_data);
1143  ast_log(LOG_ERROR, "Unable to update stale cached object type '%s', ID '%s'.\n",
1145  }
1146  }
1147  ao2_unlock(cached);
1148 }
Definition: sched.c:76
Full structure for sorcery.
Definition: sorcery.c:230
#define ao2_unlock(a)
Definition: astobj2.h:730
const char * ast_sorcery_object_get_type(const void *object)
Get the type of a sorcery object.
Definition: sorcery.c:2324
#define ast_debug(level,...)
Log a DEBUG message.
Definition: logger.h:452
#define ast_log
Definition: astobj2.c:42
#define ao2_lock(a)
Definition: astobj2.h:718
const char * ast_sorcery_object_get_id(const void *object)
Get the unique identifier of a sorcery object.
Definition: sorcery.c:2312
#define LOG_ERROR
Definition: logger.h:285
userdata associated with baseline taskprocessor test
void * object
The cached object.
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:565
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)
#define ao2_cleanup(obj)
Definition: astobj2.h:1958
static int stale_item_update(const void *data)
int stale_update_sched_id
scheduler id of stale update task

◆ mock_retrieve_id()

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

Callback for retrieving sorcery object by ID.

The mock wizard uses the real_backend_data in order to construct objects. If the backend data is "nonexisent" then no object is returned. Otherwise, an object is created that has the backend data's salt and pepper values copied.

Parameters
sorceryThe sorcery instance
dataUnused
typeThe object type. Will always be "test".
idThe object id. Will always be "test".
Return values
NULLBackend data does not exist
non-NULLAn object representing the backend data

Definition at line 3017 of file res_sorcery_memory_cache.c.

References ast_sorcery_alloc(), backend_data::exists, NULL, backend_data::pepper, test_data::pepper, real_backend_data, backend_data::salt, and test_data::salt.

3019 {
3020  struct test_data *b_data;
3021 
3022  if (!real_backend_data->exists) {
3023  return NULL;
3024  }
3025 
3026  b_data = ast_sorcery_alloc(sorcery, type, id);
3027  if (!b_data) {
3028  return NULL;
3029  }
3030 
3031  b_data->salt = real_backend_data->salt;
3032  b_data->pepper = real_backend_data->pepper;
3033  return b_data;
3034 }
static const char type[]
Definition: chan_ooh323.c:109
#define NULL
Definition: resample.c:96
Sorcery object created based on backend data.
void * ast_sorcery_alloc(const struct ast_sorcery *sorcery, const char *type, const char *id)
Allocate an object.
Definition: sorcery.c:1744
static struct backend_data * real_backend_data

◆ mock_retrieve_multiple()

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

Callback for retrieving multiple sorcery objects.

The mock wizard uses the real_backend_data in order to construct objects. If the backend data is "nonexisent" then no object is returned. Otherwise, the number of objects matching the exists value will be returned.

Parameters
sorceryThe sorcery instance
dataUnused
typeThe object type. Will always be "test".
objectsContainer to place objects into.
fieldsFields to search for.

Definition at line 3049 of file res_sorcery_memory_cache.c.

References ao2_link, ao2_ref, ast_sorcery_alloc(), ast_uuid_generate_str(), AST_UUID_STR_LEN, backend_data::exists, backend_data::pepper, test_data::pepper, real_backend_data, backend_data::salt, and test_data::salt.

3051 {
3052  int i;
3053 
3054  if (fields) {
3055  return;
3056  }
3057 
3058  for (i = 0; i < real_backend_data->exists; ++i) {
3059  char uuid[AST_UUID_STR_LEN];
3060  struct test_data *b_data;
3061 
3062  b_data = ast_sorcery_alloc(sorcery, type, ast_uuid_generate_str(uuid, sizeof(uuid)));
3063  if (!b_data) {
3064  continue;
3065  }
3066 
3067  b_data->salt = real_backend_data->salt;
3068  b_data->pepper = real_backend_data->pepper;
3069 
3070  ao2_link(objects, b_data);
3071  ao2_ref(b_data, -1);
3072  }
3073 }
static const char type[]
Definition: chan_ooh323.c:109
#define AST_UUID_STR_LEN
Definition: uuid.h:27
#define ao2_ref(o, delta)
Definition: astobj2.h:464
Sorcery object created based on backend data.
void * ast_sorcery_alloc(const struct ast_sorcery *sorcery, const char *type, const char *id)
Allocate an object.
Definition: sorcery.c:1744
char * ast_uuid_generate_str(char *buf, size_t size)
Generate a UUID string.
Definition: uuid.c:143
static struct backend_data * real_backend_data
#define ao2_link(container, obj)
Definition: astobj2.h:1549

◆ object_add_to_cache_callback()

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

Definition at line 855 of file res_sorcery_memory_cache.c.

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

Referenced by memory_cache_populate(), and stale_cache_update().

856 {
857  struct sorcery_memory_cache *cache = data;
858  struct sorcery_memory_cached_object *cached;
859 
860  cached = sorcery_memory_cached_object_alloc(arg, cache, obj);
861  if (!cached) {
862  return CMP_STOP;
863  }
864 
865  add_to_cache(cache, cached);
866  ao2_ref(cached, -1);
867 
868  return 0;
869 }
Structure for storing a memory cache.
#define ao2_ref(o, delta)
Definition: astobj2.h:464
Structure for stored a cached object.
struct ao2_container * cache
Definition: pbx_realtime.c:77
static int add_to_cache(struct sorcery_memory_cache *cache, struct sorcery_memory_cached_object *cached_object)
static struct sorcery_memory_cached_object * sorcery_memory_cached_object_alloc(const struct ast_sorcery *sorcery, const struct sorcery_memory_cache *cache, void *object)

◆ object_stale_callback()

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

Definition at line 577 of file res_sorcery_memory_cache.c.

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

Referenced by mark_all_as_stale_in_cache(), and mark_object_as_stale_in_cache().

578 {
579  struct sorcery_memory_cached_object *cached = obj;
580  struct sorcery_memory_cache *cache = arg;
581 
582  /* Since our granularity is seconds it's possible for something to retrieve us within a window
583  * where we wouldn't be treated as stale. To ensure that doesn't happen we use the configured stale
584  * time plus a second.
585  */
586  cached->created = ast_tvsub(cached->created, ast_samp2tv(cache->object_lifetime_stale + 1, 1));
587 
588  return CMP_MATCH;
589 }
struct timeval created
The time at which the object was created.
Structure for storing a memory cache.
Structure for stored a cached object.
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:238
struct ao2_container * cache
Definition: pbx_realtime.c:77
struct timeval ast_tvsub(struct timeval a, struct timeval b)
Returns the difference of two timevals a - b.
Definition: extconf.c:2298
unsigned int object_lifetime_stale
The amount of time (in seconds) before an object is marked as stale, 0 if disabled.

◆ remove_all_from_cache()

static void remove_all_from_cache ( struct sorcery_memory_cache cache)
static

Definition at line 554 of file res_sorcery_memory_cache.c.

References ao2_callback, ao2_ref, ast_heap_pop(), AST_SCHED_DEL_UNREF, sorcery_memory_cache::del_expire, sorcery_memory_cache::expire_id, NULL, OBJ_MULTIPLE, OBJ_NODATA, OBJ_NOLOCK, OBJ_UNLINK, sorcery_memory_cache::object_heap, and sorcery_memory_cache::objects.

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

555 {
556  while (ast_heap_pop(cache->object_heap)) {
557  }
558 
560  NULL, NULL);
561 
562  cache->del_expire = 1;
563  AST_SCHED_DEL_UNREF(sched, cache->expire_id, ao2_ref(cache, -1));
564  cache->del_expire = 0;
565 }
#define ao2_callback(c, flags, cb_fn, arg)
Definition: astobj2.h:1716
Definition: sched.c:76
Assume that the ao2_container is already locked.
Definition: astobj2.h:1067
#define AST_SCHED_DEL_UNREF(sched, id, refcall)
schedule task to get deleted and call unref function
Definition: sched.h:80
#define NULL
Definition: resample.c:96
void * ast_heap_pop(struct ast_heap *h)
Pop the max element off of the heap.
Definition: heap.c:262
struct ast_heap * object_heap
Heap of cached objects. Oldest object is at the top.
#define ao2_ref(o, delta)
Definition: astobj2.h:464
int expire_id
Scheduler item for expiring oldest object.
struct ao2_container * objects
Objects in the cache.

◆ remove_from_cache()

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

Definition at line 465 of file res_sorcery_memory_cache.c.

References ao2_find, ao2_ref, ast_assert, ast_heap_peek(), ast_heap_remove(), ast_sorcery_object_get_id(), OBJ_NOLOCK, OBJ_SEARCH_KEY, OBJ_UNLINK, sorcery_memory_cached_object::object, sorcery_memory_cache::object_heap, sorcery_memory_cache::objects, 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().

466 {
467  struct sorcery_memory_cached_object *hash_object;
468  struct sorcery_memory_cached_object *oldest_object;
469  struct sorcery_memory_cached_object *heap_object;
470 
471  hash_object = ao2_find(cache->objects, id, OBJ_SEARCH_KEY | OBJ_UNLINK | OBJ_NOLOCK);
472  if (!hash_object) {
473  return -1;
474  }
475 
476  ast_assert(!strcmp(ast_sorcery_object_get_id(hash_object->object), id));
477 
478  oldest_object = ast_heap_peek(cache->object_heap, 1);
479  heap_object = ast_heap_remove(cache->object_heap, hash_object);
480 
481  ast_assert(heap_object == hash_object);
482 
483  ao2_ref(hash_object, -1);
484 
485  if (reschedule && (oldest_object == heap_object)) {
487  }
488 
489  return 0;
490 }
static int schedule_cache_expiration(struct sorcery_memory_cache *cache)
The arg parameter is a search key, but is not an object.
Definition: astobj2.h:1105
Assume that the ao2_container is already locked.
Definition: astobj2.h:1067
#define ast_assert(a)
Definition: utils.h:695
struct ast_heap * object_heap
Heap of cached objects. Oldest object is at the top.
#define ao2_ref(o, delta)
Definition: astobj2.h:464
Structure for stored a cached object.
const char * ast_sorcery_object_get_id(const void *object)
Get the unique identifier of a sorcery object.
Definition: sorcery.c:2312
void * object
The cached object.
#define ao2_find(container, arg, flags)
Definition: astobj2.h:1756
void * ast_heap_remove(struct ast_heap *h, void *elm)
Remove a specific element from a heap.
Definition: heap.c:251
struct ao2_container * objects
Objects in the cache.
void * ast_heap_peek(struct ast_heap *h, unsigned int index)
Peek at an element on a heap.
Definition: heap.c:267

◆ remove_oldest_from_cache()

static int remove_oldest_from_cache ( struct sorcery_memory_cache cache)
static

Definition at line 695 of file res_sorcery_memory_cache.c.

References ao2_find, ao2_ref, ast_assert, ast_heap_pop(), OBJ_NOLOCK, OBJ_SEARCH_OBJECT, OBJ_UNLINK, sorcery_memory_cache::object_heap, sorcery_memory_cache::objects, and schedule_cache_expiration().

Referenced by sorcery_memory_cache_create().

696 {
697  struct sorcery_memory_cached_object *heap_old_object;
698  struct sorcery_memory_cached_object *hash_old_object;
699 
700  heap_old_object = ast_heap_pop(cache->object_heap);
701  if (!heap_old_object) {
702  return -1;
703  }
704  hash_old_object = ao2_find(cache->objects, heap_old_object,
706 
707  ast_assert(heap_old_object == hash_old_object);
708 
709  ao2_ref(hash_old_object, -1);
710 
712 
713  return 0;
714 }
static int schedule_cache_expiration(struct sorcery_memory_cache *cache)
Assume that the ao2_container is already locked.
Definition: astobj2.h:1067
#define ast_assert(a)
Definition: utils.h:695
void * ast_heap_pop(struct ast_heap *h)
Pop the max element off of the heap.
Definition: heap.c:262
struct ast_heap * object_heap
Heap of cached objects. Oldest object is at the top.
#define ao2_ref(o, delta)
Definition: astobj2.h:464
Structure for stored a cached object.
#define ao2_find(container, arg, flags)
Definition: astobj2.h:1756
The arg parameter is an object of the same type.
Definition: astobj2.h:1091
struct ao2_container * objects
Objects in the cache.

◆ schedule_cache_expiration()

static int schedule_cache_expiration ( struct sorcery_memory_cache cache)
static

Definition at line 648 of file res_sorcery_memory_cache.c.

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(), sorcery_memory_cache::cache_completed, sorcery_memory_cache::cond, sorcery_memory_cached_object::created, sorcery_memory_cache::del_expire, sorcery_memory_cache::expire_id, expire_objects_from_cache(), sorcery_memory_cache::lock, MAX, sorcery_memory_cache::object_heap, and sorcery_memory_cache::object_lifetime_maximum.

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

649 {
650  struct sorcery_memory_cached_object *cached;
651  int expiration = 0;
652 
653  if (!cache->object_lifetime_maximum) {
654  return 0;
655  }
656 
657  cache->del_expire = 1;
658  AST_SCHED_DEL_UNREF(sched, cache->expire_id, ao2_ref(cache, -1));
659  cache->del_expire = 0;
660 
661  cached = ast_heap_peek(cache->object_heap, 1);
662  if (!cached) {
663 #ifdef TEST_FRAMEWORK
664  ast_mutex_lock(&cache->lock);
665  cache->cache_completed = 1;
666  ast_cond_signal(&cache->cond);
667  ast_mutex_unlock(&cache->lock);
668 #endif
669  return 0;
670  }
671 
672  expiration = MAX(ast_tvdiff_ms(ast_tvadd(cached->created, ast_samp2tv(cache->object_lifetime_maximum, 1)), ast_tvnow()),
673  1);
674 
675  cache->expire_id = ast_sched_add(sched, expiration, expire_objects_from_cache, ao2_bump(cache));
676  if (cache->expire_id < 0) {
677  ao2_ref(cache, -1);
678  return -1;
679  }
680 
681  return 0;
682 }
Definition: sched.c:76
#define AST_SCHED_DEL_UNREF(sched, id, refcall)
schedule task to get deleted and call unref function
Definition: sched.h:80
struct timeval ast_tvnow(void)
Returns current timeval. Meant to replace calls to gettimeofday().
Definition: time.h:150
struct timeval created
The time at which the object was created.
#define ast_mutex_lock(a)
Definition: lock.h:187
unsigned int object_lifetime_maximum
The maximum time (in seconds) an object will stay in the cache, 0 if no limit.
int64_t ast_tvdiff_ms(struct timeval end, struct timeval start)
Computes the difference (in milliseconds) between two struct timeval instances.
Definition: time.h:98
ast_mutex_t lock
Mutex lock used for signaling when the cache has reached empty.
#define ast_cond_signal(cond)
Definition: lock.h:201
struct ast_heap * object_heap
Heap of cached objects. Oldest object is at the top.
#define ao2_bump(obj)
Definition: astobj2.h:491
#define MAX(a, b)
Definition: utils.h:228
#define ao2_ref(o, delta)
Definition: astobj2.h:464
Structure for stored a cached object.
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:238
int expire_id
Scheduler item for expiring oldest object.
struct timeval ast_tvadd(struct timeval a, struct timeval b)
Returns the sum of two timevals a + b.
Definition: extconf.c:2283
static int expire_objects_from_cache(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:565
void * ast_heap_peek(struct ast_heap *h, unsigned int index)
Peek at an element on a heap.
Definition: heap.c:267
ast_cond_t cond
Condition used for signaling when the cache has reached empty.
#define ast_mutex_unlock(a)
Definition: lock.h:188
unsigned int cache_completed
Variable that is set when the cache has reached empty.

◆ set_passthru_update()

static void set_passthru_update ( uint32_t  value)
static

Definition at line 262 of file res_sorcery_memory_cache.c.

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

Referenced by end_passthru_update(), and start_passthru_update().

263 {
264  uint32_t *passthru_update_thread_id;
265 
266  passthru_update_thread_id = ast_threadstorage_get(&passthru_update_id_storage,
267  sizeof(*passthru_update_thread_id));
268  if (!passthru_update_thread_id) {
269  ast_log(LOG_ERROR, "Could not set passthru update ID for sorcery memory cache thread\n");
270  return;
271  }
272 
273  *passthru_update_thread_id = value;
274 }
void * ast_threadstorage_get(struct ast_threadstorage *ts, size_t init_size)
Retrieve thread storage.
int value
Definition: syslog.c:37
#define ast_log
Definition: astobj2.c:42
#define LOG_ERROR
Definition: logger.h:285
static struct ast_threadstorage passthru_update_id_storage

◆ sorcery_memory_cache_ami_expire()

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

Definition at line 2115 of file res_sorcery_memory_cache.c.

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

Referenced by load_module().

2116 {
2117  const char *cache_name = astman_get_header(m, "Cache");
2118  struct sorcery_memory_cache *cache;
2119 
2120  if (ast_strlen_zero(cache_name)) {
2121  astman_send_error(s, m, "SorceryMemoryCacheExpire requires that a cache name be provided.\n");
2122  return 0;
2123  }
2124 
2125  cache = ao2_find(caches, cache_name, OBJ_SEARCH_KEY);
2126  if (!cache) {
2127  astman_send_error(s, m, "The provided cache does not exist\n");
2128  return 0;
2129  }
2130 
2131  ao2_wrlock(cache->objects);
2132  remove_all_from_cache(cache);
2133  ao2_unlock(cache->objects);
2134 
2135  ao2_ref(cache, -1);
2136 
2137  astman_send_ack(s, m, "All objects were expired from the cache\n");
2138 
2139  return 0;
2140 }
The arg parameter is a search key, but is not an object.
Definition: astobj2.h:1105
void astman_send_ack(struct mansession *s, const struct message *m, char *msg)
Send ack in manager transaction.
Definition: manager.c:3191
#define ao2_unlock(a)
Definition: astobj2.h:730
#define ao2_wrlock(a)
Definition: astobj2.h:720
const char * astman_get_header(const struct message *m, char *var)
Get header from mananger transaction.
Definition: manager.c:2820
#define ast_strlen_zero(foo)
Definition: strings.h:52
Structure for storing a memory cache.
#define ao2_ref(o, delta)
Definition: astobj2.h:464
static void remove_all_from_cache(struct sorcery_memory_cache *cache)
static struct ao2_container * caches
Container of created caches.
#define ao2_find(container, arg, flags)
Definition: astobj2.h:1756
struct ao2_container * cache
Definition: pbx_realtime.c:77
struct ao2_container * objects
Objects in the cache.
void astman_send_error(struct mansession *s, const struct message *m, char *error)
Send error in manager transaction.
Definition: manager.c:3159

◆ sorcery_memory_cache_ami_expire_object()

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

Definition at line 2069 of file res_sorcery_memory_cache.c.

References ao2_find, ao2_ref, ao2_unlock, ao2_wrlock, ast_strlen_zero, astman_get_header(), astman_send_ack(), astman_send_error(), cache, sorcery_memory_cache::full_backend_cache, OBJ_SEARCH_KEY, sorcery_memory_cache::objects, and remove_from_cache().

Referenced by load_module().

2070 {
2071  const char *cache_name = astman_get_header(m, "Cache");
2072  const char *object_name = astman_get_header(m, "Object");
2073  struct sorcery_memory_cache *cache;
2074  int res;
2075 
2076  if (ast_strlen_zero(cache_name)) {
2077  astman_send_error(s, m, "SorceryMemoryCacheExpireObject requires that a cache name be provided.\n");
2078  return 0;
2079  } else if (ast_strlen_zero(object_name)) {
2080  astman_send_error(s, m, "SorceryMemoryCacheExpireObject requires that an object name be provided\n");
2081  return 0;
2082  }
2083 
2084  cache = ao2_find(caches, cache_name, OBJ_SEARCH_KEY);
2085  if (!cache) {
2086  astman_send_error(s, m, "The provided cache does not exist\n");
2087  return 0;
2088  }
2089 
2090  ao2_wrlock(cache->objects);
2091  if (cache->full_backend_cache) {
2092  res = 1;
2093  } else {
2094  res = remove_from_cache(cache, object_name, 1);
2095  }
2096  ao2_unlock(cache->objects);
2097 
2098  ao2_ref(cache, -1);
2099 
2100  if (res == 1) {
2101  astman_send_error(s, m, "Due to full backend caching per-object expiration is not available, consider using SorceryMemoryCachePopulate or SorceryMemoryCacheExpire instead\n");
2102  } else if (!res) {
2103  astman_send_ack(s, m, "The provided object was expired from the cache\n");
2104  } else {
2105  astman_send_error(s, m, "The provided object could not be expired from the cache\n");
2106  }
2107 
2108  return 0;
2109 }
The arg parameter is a search key, but is not an object.
Definition: astobj2.h:1105
void astman_send_ack(struct mansession *s, const struct message *m, char *msg)
Send ack in manager transaction.
Definition: manager.c:3191
#define ao2_unlock(a)
Definition: astobj2.h:730
#define ao2_wrlock(a)
Definition: astobj2.h:720
const char * astman_get_header(const struct message *m, char *var)
Get header from mananger transaction.
Definition: manager.c:2820
#define ast_strlen_zero(foo)
Definition: strings.h:52
Structure for storing a memory cache.
unsigned int full_backend_cache
Whether this is a cache of the entire backend, 0 if disabled.
#define ao2_ref(o, delta)
Definition: astobj2.h:464
static int remove_from_cache(struct sorcery_memory_cache *cache, const char *id, int reschedule)
static struct ao2_container * caches
Container of created caches.
#define ao2_find(container, arg, flags)
Definition: astobj2.h:1756
struct ao2_container * cache
Definition: pbx_realtime.c:77
struct ao2_container * objects
Objects in the cache.
void astman_send_error(struct mansession *s, const struct message *m, char *error)
Send error in manager transaction.
Definition: manager.c:3159

◆ sorcery_memory_cache_ami_populate()

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

Definition at line 2230 of file res_sorcery_memory_cache.c.

References ao2_find, ao2_ref, ao2_unlock, ao2_wrlock, ast_strlen_zero, astman_get_header(), astman_send_ack(), astman_send_error(), cache, sorcery_memory_cache::full_backend_cache, memory_cache_populate(), OBJ_SEARCH_KEY, sorcery_memory_cache::object_type, sorcery_memory_cache::objects, remove_all_from_cache(), and sorcery_memory_cache::sorcery.

Referenced by load_module().

2231 {
2232  const char *cache_name = astman_get_header(m, "Cache");
2233  struct sorcery_memory_cache *cache;
2234 
2235  if (ast_strlen_zero(cache_name)) {
2236  astman_send_error(s, m, "SorceryMemoryCachePopulate requires that a cache name be provided.\n");
2237  return 0;
2238  }
2239 
2240  cache = ao2_find(caches, cache_name, OBJ_SEARCH_KEY);
2241  if (!cache) {
2242  astman_send_error(s, m, "The provided cache does not exist\n");
2243  return 0;
2244  }
2245 
2246  if (!cache->full_backend_cache) {
2247  astman_send_error(s, m, "The provided cache does not have full backend caching enabled\n");
2248  ao2_ref(cache, -1);
2249  return 0;
2250  }
2251 
2252  ao2_wrlock(cache->objects);
2253  if (!cache->sorcery) {
2254  astman_send_error(s, m, "The provided cache is no longer active\n");
2255  ao2_unlock(cache->objects);
2256  ao2_ref(cache, -1);
2257  return 0;
2258  }
2259 
2260  remove_all_from_cache(cache);
2261  memory_cache_populate(cache->sorcery, cache->object_type, cache);
2262 
2263  ao2_unlock(cache->objects);
2264 
2265  ao2_ref(cache, -1);
2266 
2267  astman_send_ack(s, m, "Cache has been expired and populated\n");
2268 
2269  return 0;
2270 }
The arg parameter is a search key, but is not an object.
Definition: astobj2.h:1105
const struct ast_sorcery * sorcery
An unreffed pointer to the sorcery instance, accessible only with lock held.
void astman_send_ack(struct mansession *s, const struct message *m, char *msg)
Send ack in manager transaction.
Definition: manager.c:3191
#define ao2_unlock(a)
Definition: astobj2.h:730
#define ao2_wrlock(a)
Definition: astobj2.h:720
const char * astman_get_header(const struct message *m, char *var)
Get header from mananger transaction.
Definition: manager.c:2820
#define ast_strlen_zero(foo)
Definition: strings.h:52
Structure for storing a memory cache.
unsigned int full_backend_cache
Whether this is a cache of the entire backend, 0 if disabled.
#define ao2_ref(o, delta)
Definition: astobj2.h:464
static void memory_cache_populate(const struct ast_sorcery *sorcery, const char *type, struct sorcery_memory_cache *cache)
static void remove_all_from_cache(struct sorcery_memory_cache *cache)
static struct ao2_container * caches
Container of created caches.
#define ao2_find(container, arg, flags)
Definition: astobj2.h:1756
struct ao2_container * cache
Definition: pbx_realtime.c:77
char * object_type
The type of object we are caching.
struct ao2_container * objects
Objects in the cache.
void astman_send_error(struct mansession *s, const struct message *m, char *error)
Send error in manager transaction.
Definition: manager.c:3159

◆ sorcery_memory_cache_ami_stale()

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

Definition at line 2199 of file res_sorcery_memory_cache.c.

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

Referenced by load_module().

2200 {
2201  const char *cache_name = astman_get_header(m, "Cache");
2202  struct sorcery_memory_cache *cache;
2203 
2204  if (ast_strlen_zero(cache_name)) {
2205  astman_send_error(s, m, "SorceryMemoryCacheStale requires that a cache name be provided.\n");
2206  return 0;
2207  }
2208 
2209  cache = ao2_find(caches, cache_name, OBJ_SEARCH_KEY);
2210  if (!cache) {
2211  astman_send_error(s, m, "The provided cache does not exist\n");
2212  return 0;
2213  }
2214 
2215  ao2_rdlock(cache->objects);
2217  ao2_unlock(cache->objects);
2218 
2219  ao2_ref(cache, -1);
2220 
2221  astman_send_ack(s, m, "All objects were marked as stale in the cache\n");
2222 
2223  return 0;
2224 }
The arg parameter is a search key, but is not an object.
Definition: astobj2.h:1105
void astman_send_ack(struct mansession *s, const struct message *m, char *msg)
Send ack in manager transaction.
Definition: manager.c:3191
#define ao2_unlock(a)
Definition: astobj2.h:730
const char * astman_get_header(const struct message *m, char *var)
Get header from mananger transaction.
Definition: manager.c:2820
#define ast_strlen_zero(foo)
Definition: strings.h:52
Structure for storing a memory cache.
#define ao2_ref(o, delta)
Definition: astobj2.h:464
static struct ao2_container * caches
Container of created caches.
#define ao2_rdlock(a)
Definition: astobj2.h:719
#define ao2_find(container, arg, flags)
Definition: astobj2.h:1756
struct ao2_container * cache
Definition: pbx_realtime.c:77
struct ao2_container * objects
Objects in the cache.
static void mark_all_as_stale_in_cache(struct sorcery_memory_cache *cache)
void astman_send_error(struct mansession *s, const struct message *m, char *error)
Send error in manager transaction.
Definition: manager.c:3159

◆ sorcery_memory_cache_ami_stale_object()

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

Definition at line 2146 of file res_sorcery_memory_cache.c.

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

Referenced by load_module().

2147 {
2148  const char *cache_name = astman_get_header(m, "Cache");
2149  const char *object_name = astman_get_header(m, "Object");
2150  const char *reload = astman_get_header(m, "Reload");
2151  struct sorcery_memory_cache *cache;
2152  int res;
2153 
2154  if (ast_strlen_zero(cache_name)) {
2155  astman_send_error(s, m, "SorceryMemoryCacheStaleObject requires that a cache name be provided.\n");
2156  return 0;
2157  } else if (ast_strlen_zero(object_name)) {
2158  astman_send_error(s, m, "SorceryMemoryCacheStaleObject requires that an object name be provided\n");
2159  return 0;
2160  }
2161 
2162  cache = ao2_find(caches, cache_name, OBJ_SEARCH_KEY);
2163  if (!cache) {
2164  astman_send_error(s, m, "The provided cache does not exist\n");
2165  return 0;
2166  }
2167 
2168  ao2_rdlock(cache->objects);
2169 
2170  res = mark_object_as_stale_in_cache(cache, object_name);
2171 
2172  if (ast_true(reload)) {
2173  struct sorcery_memory_cached_object *cached;
2174 
2175  cached = ao2_find(cache->objects, object_name, OBJ_SEARCH_KEY | OBJ_NOLOCK);
2176  if (cached) {
2177  memory_cache_stale_update_object(cache->sorcery, cache, cached);
2178  ao2_ref(cached, -1);
2179  }
2180  }
2181 
2182  ao2_unlock(cache->objects);
2183 
2184  ao2_ref(cache, -1);
2185 
2186  if (!res) {
2187  astman_send_ack(s, m, "The provided object was marked as stale in the cache\n");
2188  } else {
2189  astman_send_error(s, m, "The provided object could not be marked as stale in the cache\n");
2190  }
2191 
2192  return 0;
2193 }
The arg parameter is a search key, but is not an object.
Definition: astobj2.h:1105
const struct ast_sorcery * sorcery
An unreffed pointer to the sorcery instance, accessible only with lock held.
Assume that the ao2_container is already locked.
Definition: astobj2.h:1067
void astman_send_ack(struct mansession *s, const struct message *m, char *msg)
Send ack in manager transaction.
Definition: manager.c:3191
#define ao2_unlock(a)
Definition: astobj2.h:730
const char * astman_get_header(const struct message *m, char *var)
Get header from mananger transaction.
Definition: manager.c:2820
#define ast_strlen_zero(foo)
Definition: strings.h:52
static void memory_cache_stale_update_object(const struct ast_sorcery *sorcery, struct sorcery_memory_cache *cache, struct sorcery_memory_cached_object *cached)
Structure for storing a memory cache.
#define ao2_ref(o, delta)
Definition: astobj2.h:464
Structure for stored a cached object.
int attribute_pure ast_true(const char *val)
Make sure something is true. Determine if a string containing a boolean value is "true". This function checks to see whether a string passed to it is an indication of an "true" value. It checks to see if the string is "yes", "true", "y", "t", "on" or "1".
Definition: main/utils.c:1951
static struct ao2_container * caches
Container of created caches.
#define ao2_rdlock(a)
Definition: astobj2.h:719
static int reload(void)
Definition: cdr_mysql.c:741
#define ao2_find(container, arg, flags)
Definition: astobj2.h:1756
struct ao2_container * cache
Definition: pbx_realtime.c:77
struct ao2_container * objects
Objects in the cache.
static int mark_object_as_stale_in_cache(struct sorcery_memory_cache *cache, const char *id)
void astman_send_error(struct mansession *s, const struct message *m, char *error)
Send error in manager transaction.
Definition: manager.c:3159

◆ sorcery_memory_cache_close()

static void sorcery_memory_cache_close ( void *  data)
static

Definition at line 1620 of file res_sorcery_memory_cache.c.

References ao2_ref, ao2_unlink, ao2_unlock, ao2_wrlock, ast_strlen_zero, sorcery_memory_cache::full_backend_cache, sorcery_memory_cache::name, NULL, sorcery_memory_cache::object_lifetime_maximum, sorcery_memory_cache::objects, remove_all_from_cache(), and sorcery_memory_cache::sorcery.

Referenced by AST_TEST_DEFINE().

1621 {
1622  struct sorcery_memory_cache *cache = data;
1623 
1624  /* This can occur if a cache is created but never loaded */
1625  if (!ast_strlen_zero(cache->name)) {
1626  ao2_unlink(caches, cache);
1627  }
1628 
1629  if (cache->object_lifetime_maximum) {
1630  /* If object lifetime support is enabled we need to explicitly drop all cached objects here
1631  * and stop the scheduled task. Failure to do so could potentially keep the cache around for
1632  * a prolonged period of time.
1633  */
1634  ao2_wrlock(cache->objects);
1635  remove_all_from_cache(cache);
1636  ao2_unlock(cache->objects);
1637  }
1638 
1639  if (cache->full_backend_cache) {
1640  ao2_wrlock(cache->objects);
1641  cache->sorcery = NULL;
1642  ao2_unlock(cache->objects);
1643  }
1644 
1645  ao2_ref(cache, -1);
1646 }
const struct ast_sorcery * sorcery
An unreffed pointer to the sorcery instance, accessible only with lock held.
unsigned int object_lifetime_maximum
The maximum time (in seconds) an object will stay in the cache, 0 if no limit.
#define ao2_unlock(a)
Definition: astobj2.h:730
#define NULL
Definition: resample.c:96
#define ao2_wrlock(a)
Definition: astobj2.h:720
#define ast_strlen_zero(foo)
Definition: strings.h:52
Structure for storing a memory cache.
unsigned int full_backend_cache
Whether this is a cache of the entire backend, 0 if disabled.
#define ao2_ref(o, delta)
Definition: astobj2.h:464
static void remove_all_from_cache(struct sorcery_memory_cache *cache)
#define ao2_unlink(container, obj)
Definition: astobj2.h:1598
static struct ao2_container * caches
Container of created caches.
struct ao2_container * cache
Definition: pbx_realtime.c:77
struct ao2_container * objects
Objects in the cache.
char * name
The name of the memory cache.

◆ sorcery_memory_cache_cmp()

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

Definition at line 329 of file res_sorcery_memory_cache.c.

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

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

◆ sorcery_memory_cache_complete_name()

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

Definition at line 1652 of file res_sorcery_memory_cache.c.

References ao2_iterator_destroy(), ao2_iterator_init(), ao2_iterator_next, ao2_ref, ast_strdup, cache, sorcery_memory_cache::name, 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().

1653 {
1654  struct sorcery_memory_cache *cache;
1655  struct ao2_iterator it_caches;
1656  int wordlen = strlen(word);
1657  int which = 0;
1658  char *result = NULL;
1659 
1660  it_caches = ao2_iterator_init(caches, 0);
1661  while ((cache = ao2_iterator_next(&it_caches))) {
1662  if (!strncasecmp(word, cache->name, wordlen)
1663  && ++which > state) {
1664  result = ast_strdup(cache->name);
1665  }
1666  ao2_ref(cache, -1);
1667  if (result) {
1668  break;
1669  }
1670  }
1671  ao2_iterator_destroy(&it_caches);
1672  return result;
1673 }
void ao2_iterator_destroy(struct ao2_iterator *iter)
Destroy a container iterator.
#define ast_strdup(str)
A wrapper for strdup()
Definition: astmm.h:243
#define NULL
Definition: resample.c:96
Structure for storing a memory cache.
#define ao2_ref(o, delta)
Definition: astobj2.h:464
static struct ao2_container * caches
Container of created caches.
#define ao2_iterator_next(iter)
Definition: astobj2.h:1933
struct ao2_container * cache
Definition: pbx_realtime.c:77
When we need to walk through a container, we use an ao2_iterator to keep track of the current positio...
Definition: astobj2.h:1841
static PGresult * result
Definition: cel_pgsql.c:88
struct ao2_iterator ao2_iterator_init(struct ao2_container *c, int flags) attribute_warn_unused_result
Create an iterator for a container.
char * name
The name of the memory cache.
short word

◆ sorcery_memory_cache_complete_object_name()

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

Definition at line 1825 of file res_sorcery_memory_cache.c.

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

Referenced by sorcery_memory_cache_expire(), and sorcery_memory_cache_stale().

1826 {
1827  struct sorcery_memory_cache *cache;
1828  struct sorcery_memory_cached_object *cached;
1829  struct ao2_iterator it_cached;
1830  int wordlen = strlen(word);
1831  int which = 0;
1832  char *result = NULL;
1833 
1834  cache = ao2_find(caches, cache_name, OBJ_SEARCH_KEY);
1835  if (!cache) {
1836  return NULL;
1837  }
1838 
1839  it_cached = ao2_iterator_init(cache->objects, 0);
1840  while ((cached = ao2_iterator_next(&it_cached))) {
1841  if (!strncasecmp(word, ast_sorcery_object_get_id(cached->object), wordlen)
1842  && ++which > state) {
1843  result = ast_strdup(ast_sorcery_object_get_id(cached->object));
1844  }
1845  ao2_ref(cached, -1);
1846  if (result) {
1847  break;
1848  }
1849  }
1850  ao2_iterator_destroy(&it_cached);
1851 
1852  ao2_ref(cache, -1);
1853 
1854  return result;
1855 }
The arg parameter is a search key, but is not an object.
Definition: astobj2.h:1105
void ao2_iterator_destroy(struct ao2_iterator *iter)
Destroy a container iterator.
#define ast_strdup(str)
A wrapper for strdup()
Definition: astmm.h:243
#define NULL
Definition: resample.c:96
Structure for storing a memory cache.
#define ao2_ref(o, delta)
Definition: astobj2.h:464
Structure for stored a cached object.
const char * ast_sorcery_object_get_id(const void *object)
Get the unique identifier of a sorcery object.
Definition: sorcery.c:2312
static struct ao2_container * caches
Container of created caches.
#define ao2_iterator_next(iter)
Definition: astobj2.h:1933
void * object
The cached object.
#define ao2_find(container, arg, flags)
Definition: astobj2.h:1756
struct ao2_container * cache
Definition: pbx_realtime.c:77
When we need to walk through a container, we use an ao2_iterator to keep track of the current positio...
Definition: astobj2.h:1841
struct ao2_container * objects
Objects in the cache.
static PGresult * result
Definition: cel_pgsql.c:88
struct ao2_iterator ao2_iterator_init(struct ao2_container *c, int flags) attribute_warn_unused_result
Create an iterator for a container.
short word

◆ sorcery_memory_cache_create()

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

Definition at line 805 of file res_sorcery_memory_cache.c.

References add_to_cache(), ao2_container_count(), ao2_ref, ao2_unlock, ao2_wrlock, ast_assert, ast_log, ast_sorcery_object_get_id(), LOG_ERROR, sorcery_memory_cache::maximum_objects, sorcery_memory_cache::objects, remove_from_cache(), remove_oldest_from_cache(), and sorcery_memory_cached_object_alloc().

Referenced by AST_TEST_DEFINE(), and stale_item_update().

806 {
807  struct sorcery_memory_cache *cache = data;
808  struct sorcery_memory_cached_object *cached;
809 
810  cached = sorcery_memory_cached_object_alloc(sorcery, cache, object);
811  if (!cached) {
812  return -1;
813  }
814 
815  /* As there is no guarantee that this won't be called by multiple threads wanting to cache
816  * the same object we remove any old ones, which turns this into a create/update function
817  * in reality. As well since there's no guarantee that the object in the cache is the same
818  * one here we remove any old objects using the object identifier.
819  */
820 
821  ao2_wrlock(cache->objects);
822  remove_from_cache(cache, ast_sorcery_object_get_id(object), 1);
823  if (cache->maximum_objects && ao2_container_count(cache->objects) >= cache->maximum_objects) {
824  if (remove_oldest_from_cache(cache)) {
825  ast_log(LOG_ERROR, "Unable to make room in cache for sorcery object '%s'.\n",
826  ast_sorcery_object_get_id(object));
827  ao2_unlock(cache->objects);
828  ao2_ref(cached, -1);
829  return -1;
830  }
832  }
833  if (add_to_cache(cache, cached)) {
834  ast_log(LOG_ERROR, "Unable to add object '%s' to the cache\n",
835  ast_sorcery_object_get_id(object));
836  ao2_unlock(cache->objects);
837  ao2_ref(cached, -1);
838  return -1;
839  }
840  ao2_unlock(cache->objects);
841 
842  ao2_ref(cached, -1);
843  return 0;
844 }
unsigned int maximum_objects
The maximum number of objects permitted in the cache, 0 if no limit.
int ao2_container_count(struct ao2_container *c)
Returns the number of elements in a container.
#define ast_assert(a)
Definition: utils.h:695
#define ao2_unlock(a)
Definition: astobj2.h:730
#define ao2_wrlock(a)
Definition: astobj2.h:720
#define ast_log
Definition: astobj2.c:42
Structure for storing a memory cache.
#define ao2_ref(o, delta)
Definition: astobj2.h:464
Structure for stored a cached object.
const char * ast_sorcery_object_get_id(const void *object)
Get the unique identifier of a sorcery object.
Definition: sorcery.c:2312
static int remove_from_cache(struct sorcery_memory_cache *cache, const char *id, int reschedule)
#define LOG_ERROR
Definition: logger.h:285
static int remove_oldest_from_cache(struct sorcery_memory_cache *cache)
struct ao2_container * cache
Definition: pbx_realtime.c:77
struct ao2_container * objects
Objects in the cache.
static int add_to_cache(struct sorcery_memory_cache *cache, struct sorcery_memory_cached_object *cached_object)
static struct sorcery_memory_cached_object * sorcery_memory_cached_object_alloc(const struct ast_sorcery *sorcery, const struct sorcery_memory_cache *cache, void *object)

◆ sorcery_memory_cache_delete()

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

Definition at line 1598 of file res_sorcery_memory_cache.c.

References ao2_unlock, ao2_wrlock, ast_debug, ast_sorcery_object_get_id(), sorcery_memory_cache::objects, and remove_from_cache().

Referenced by AST_TEST_DEFINE(), and stale_item_update().

1599 {
1600  struct sorcery_memory_cache *cache = data;
1601  int res;
1602 
1603  ao2_wrlock(cache->objects);
1604  res = remove_from_cache(cache, ast_sorcery_object_get_id(object), 1);
1605  ao2_unlock(cache->objects);
1606 
1607  if (res) {
1608  ast_debug(1, "Unable to delete object '%s' from sorcery cache\n", ast_sorcery_object_get_id(object));
1609  }
1610 
1611  return res;
1612 }
#define ao2_unlock(a)
Definition: astobj2.h:730
#define ao2_wrlock(a)
Definition: astobj2.h:720
#define ast_debug(level,...)
Log a DEBUG message.
Definition: logger.h:452
Structure for storing a memory cache.
const char * ast_sorcery_object_get_id(const void *object)
Get the unique identifier of a sorcery object.
Definition: sorcery.c:2312
static int remove_from_cache(struct sorcery_memory_cache *cache, const char *id, int reschedule)
struct ao2_container * cache
Definition: pbx_realtime.c:77
struct ao2_container * objects
Objects in the cache.

◆ sorcery_memory_cache_destructor()

static void sorcery_memory_cache_destructor ( void *  obj)
static

Definition at line 422 of file res_sorcery_memory_cache.c.

References ao2_cleanup, ast_free, ast_heap_destroy(), cache, sorcery_memory_cache::name, sorcery_memory_cache::object_heap, sorcery_memory_cache::object_type, and sorcery_memory_cache::objects.

Referenced by sorcery_memory_cache_open().

423 {
424  struct sorcery_memory_cache *cache = obj;
425 
426  ast_free(cache->name);
427  if (cache->object_heap) {
429  }
430  ao2_cleanup(cache->objects);
431  ast_free(cache->object_type);
432 }
struct ast_heap * ast_heap_destroy(struct ast_heap *h)
Destroy a max heap.
Definition: heap.c:146
struct ast_heap * object_heap
Heap of cached objects. Oldest object is at the top.
Structure for storing a memory cache.
#define ast_free(a)
Definition: astmm.h:182
struct ao2_container * cache
Definition: pbx_realtime.c:77
#define ao2_cleanup(obj)
Definition: astobj2.h:1958
char * object_type
The type of object we are caching.
struct ao2_container * objects
Objects in the cache.
char * name
The name of the memory cache.

◆ sorcery_memory_cache_dump()

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

Definition at line 1768 of file res_sorcery_memory_cache.c.

References print_object_details::a, a, ao2_callback, ao2_container_count(), ao2_find, ao2_ref, ast_cli_args::argc, ast_cli_args::argv, ast_cli(), cache, print_object_details::cache, CLI_FAILURE, CLI_GENERATE, CLI_INIT, CLI_SHOWUSAGE, CLI_SUCCESS, ast_cli_entry::command, ast_cli_args::fd, FORMAT, ast_cli_args::n, sorcery_memory_cache::name, NULL, OBJ_MULTIPLE, OBJ_NODATA, OBJ_SEARCH_KEY, sorcery_memory_cache::object_lifetime_maximum, sorcery_memory_cache::object_lifetime_stale, sorcery_memory_cache::objects, ast_cli_args::pos, sorcery_memory_cache_complete_name(), sorcery_memory_cache_print_object(), ast_cli_entry::usage, and ast_cli_args::word.

1769 {
1770 #define FORMAT "%-25.25s %-15.15s %-15.15s \n"
1771  struct sorcery_memory_cache *cache;
1772  struct print_object_details details;
1773 
1774  switch (cmd) {
1775  case CLI_INIT:
1776  e->command = "sorcery memory cache dump";
1777  e->usage =
1778  "Usage: sorcery memory cache dump <name>\n"
1779  " Dump a list of the objects within the cache, listed by object identifier.\n";
1780  return NULL;
1781  case CLI_GENERATE:
1782  if (a->pos == 4) {
1783  return sorcery_memory_cache_complete_name(a->word, a->n);
1784  } else {
1785  return NULL;
1786  }
1787  }
1788 
1789  if (a->argc != 5) {
1790  return CLI_SHOWUSAGE;
1791  }
1792 
1793  cache = ao2_find(caches, a->argv[4], OBJ_SEARCH_KEY);
1794  if (!cache) {
1795  ast_cli(a->fd, "Specified sorcery memory cache '%s' does not exist\n", a->argv[4]);
1796  return CLI_FAILURE;
1797  }
1798 
1799  details.cache = cache;
1800  details.a = a;
1801 
1802  ast_cli(a->fd, "Dumping sorcery memory cache '%s':\n", cache->name);
1803  if (!cache->object_lifetime_stale) {
1804  ast_cli(a->fd, " * Staleness is not enabled - objects will not go stale\n");
1805  }
1806  if (!cache->object_lifetime_maximum) {
1807  ast_cli(a->fd, " * Object lifetime is not enabled - objects will not expire\n");
1808  }
1809  ast_cli(a->fd, FORMAT, "Object Name", "Stale In", "Expires In");
1810  ast_cli(a->fd, FORMAT, "-------------------------", "---------------", "---------------");
1812  ast_cli(a->fd, FORMAT, "-------------------------", "---------------", "---------------");
1813  ast_cli(a->fd, "Total number of objects cached: %d\n", ao2_container_count(cache->objects));
1814 
1815  ao2_ref(cache, -1);
1816 
1817  return CLI_SUCCESS;
1818 #undef FORMAT
1819 }
int ao2_container_count(struct ao2_container *c)
Returns the number of elements in a container.
The arg parameter is a search key, but is not an object.
Definition: astobj2.h:1105
const int argc
Definition: cli.h:160
#define FORMAT
#define ao2_callback(c, flags, cb_fn, arg)
Definition: astobj2.h:1716
Definition: cli.h:152
static int sorcery_memory_cache_print_object(void *obj, void *arg, int flags)
unsigned int object_lifetime_maximum
The maximum time (in seconds) an object will stay in the cache, 0 if no limit.
#define NULL
Definition: resample.c:96
void ast_cli(int fd, const char *fmt,...)
Definition: clicompat.c:6
Structure for storing a memory cache.
const int fd
Definition: cli.h:159
const int n
Definition: cli.h:165
#define ao2_ref(o, delta)
Definition: astobj2.h:464
const char *const * argv
Definition: cli.h:161
Structure used to pass data for printing cached object information.
static struct ao2_container * caches
Container of created caches.
#define CLI_SHOWUSAGE
Definition: cli.h:45
#define CLI_FAILURE
Definition: cli.h:46
char * command
Definition: cli.h:186
const char * word
Definition: cli.h:163
#define ao2_find(container, arg, flags)
Definition: astobj2.h:1756
struct ao2_container * cache
Definition: pbx_realtime.c:77
const char * usage
Definition: cli.h:177
#define CLI_SUCCESS
Definition: cli.h:44
const int pos
Definition: cli.h:164
struct ao2_container * objects
Objects in the cache.
unsigned int object_lifetime_stale
The amount of time (in seconds) before an object is marked as stale, 0 if disabled.
char * name
The name of the memory cache.
static char * sorcery_memory_cache_complete_name(const char *word, int state)
static struct test_val a

◆ sorcery_memory_cache_expire()

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

Definition at line 1861 of file res_sorcery_memory_cache.c.

References ao2_find, ao2_ref, ao2_unlock, ao2_wrlock, ast_cli_args::argc, ast_cli_args::argv, ast_cli(), cache, CLI_FAILURE, CLI_GENERATE, CLI_INIT, CLI_SHOWUSAGE, CLI_SUCCESS, ast_cli_entry::command, ast_cli_args::fd, sorcery_memory_cache::full_backend_cache, ast_cli_args::n, NULL, OBJ_SEARCH_KEY, sorcery_memory_cache::objects, ast_cli_args::pos, remove_all_from_cache(), remove_from_cache(), sorcery_memory_cache_complete_name(), sorcery_memory_cache_complete_object_name(), ast_cli_entry::usage, and ast_cli_args::word.

1862 {
1863  struct sorcery_memory_cache *cache;
1864 
1865  switch (cmd) {
1866  case CLI_INIT:
1867  e->command = "sorcery memory cache expire";
1868  e->usage =
1869  "Usage: sorcery memory cache expire <cache name> [object name]\n"
1870  " Expire a specific object or ALL objects within a sorcery memory cache.\n";
1871  return NULL;
1872  case CLI_GENERATE:
1873  if (a->pos == 4) {
1874  return sorcery_memory_cache_complete_name(a->word, a->n);
1875  } else if (a->pos == 5) {
1876  return sorcery_memory_cache_complete_object_name(a->argv[4], a->word, a->n);
1877  } else {
1878  return NULL;
1879  }
1880  }
1881 
1882  if (a->argc < 5 || a->argc > 6) {
1883  return CLI_SHOWUSAGE;
1884  }
1885 
1886  cache = ao2_find(caches, a->argv[4], OBJ_SEARCH_KEY);
1887  if (!cache) {
1888  ast_cli(a->fd, "Specified sorcery memory cache '%s' does not exist\n", a->argv[4]);
1889  return CLI_FAILURE;
1890  }
1891 
1892  ao2_wrlock(cache->objects);
1893  if (a->argc == 5) {
1894  remove_all_from_cache(cache);
1895  ast_cli(a->fd, "All objects have been removed from cache '%s'\n", a->argv[4]);
1896  } else {
1897  if (cache->full_backend_cache) {
1898  ast_cli(a->fd, "Due to full backend caching per-object expiration is not available on cache '%s'\n", a->argv[4]);
1899  } else if (!remove_from_cache(cache, a->argv[5], 1)) {
1900  ast_cli(a->fd, "Successfully expired object '%s' from cache '%s'\n", a->argv[5], a->argv[4]);
1901  } else {
1902  ast_cli(a->fd, "Object '%s' was not expired from cache '%s' as it was not found\n", a->argv[5],
1903  a->argv[4]);
1904  }
1905  }
1906  ao2_unlock(cache->objects);
1907 
1908  ao2_ref(cache, -1);
1909 
1910  return CLI_SUCCESS;
1911 }
The arg parameter is a search key, but is not an object.
Definition: astobj2.h:1105
static char * sorcery_memory_cache_complete_object_name(const char *cache_name, const char *word, int state)
const int argc
Definition: cli.h:160
Definition: cli.h:152
#define ao2_unlock(a)
Definition: astobj2.h:730
#define NULL
Definition: resample.c:96
#define ao2_wrlock(a)
Definition: astobj2.h:720
void ast_cli(int fd, const char *fmt,...)
Definition: clicompat.c:6
Structure for storing a memory cache.
const int fd
Definition: cli.h:159
const int n
Definition: cli.h:165
unsigned int full_backend_cache
Whether this is a cache of the entire backend, 0 if disabled.
#define ao2_ref(o, delta)
Definition: astobj2.h:464
static int remove_from_cache(struct sorcery_memory_cache *cache, const char *id, int reschedule)
const char *const * argv
Definition: cli.h:161
static void remove_all_from_cache(struct sorcery_memory_cache *cache)
static struct ao2_container * caches
Container of created caches.
#define CLI_SHOWUSAGE
Definition: cli.h:45
#define CLI_FAILURE
Definition: cli.h:46
char * command
Definition: cli.h:186
const char * word
Definition: cli.h:163
#define ao2_find(container, arg, flags)
Definition: astobj2.h:1756
struct ao2_container * cache
Definition: pbx_realtime.c:77
const char * usage
Definition: cli.h:177
#define CLI_SUCCESS
Definition: cli.h:44
const int pos
Definition: cli.h:164
struct ao2_container * objects
Objects in the cache.
static char * sorcery_memory_cache_complete_name(const char *word, int state)

◆ sorcery_memory_cache_fields_cmp()

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

Definition at line 1254 of file res_sorcery_memory_cache.c.

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

1255 {
1256  struct sorcery_memory_cached_object *cached = obj;
1257  const struct sorcery_memory_cache_fields_cmp_params *params = arg;
1258  RAII_VAR(struct ast_variable *, diff, NULL, ast_variables_destroy);
1259 
1260  if (params->regex) {
1261  /* If a regular expression has been provided see if it matches, otherwise move on */
1262  if (!regexec(params->regex, ast_sorcery_object_get_id(cached->object), 0, NULL, 0)) {
1263  ao2_link(params->container, cached->object);
1264  }
1265  return 0;
1266  } else if (params->prefix) {
1267  if (!strncmp(params->prefix, ast_sorcery_object_get_id(cached->object), params->prefix_len)) {
1268  ao2_link(params->container, cached->object);
1269  }
1270  return 0;
1271  } else if (params->fields &&
1272  (!ast_variable_lists_match(cached->objectset, params->fields, 0))) {
1273  /* If we can't turn the object into an object set OR if differences exist between the fields
1274  * passed in and what are present on the object they are not a match.
1275  */
1276  return 0;
1277  }
1278 
1279  if (params->container) {
1280  ao2_link(params->container, cached->object);
1281 
1282  /* As multiple objects are being returned keep going */
1283  return 0;
1284  } else {
1285  /* Immediately stop and return, we only want a single object */
1286  return CMP_MATCH | CMP_STOP;
1287  }
1288 }
const struct ast_variable * fields
Pointer to the fields to check.
void ast_variables_destroy(struct ast_variable *var)
Free variable list.
Definition: extconf.c:1263
struct ao2_container * container
Optional container to put object into.
Structure for variables, used for configurations and for channel variables.
#define NULL
Definition: resample.c:96
const char * prefix
Prefix for matching object id.
#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:911
regex_t * regex
Regular expression for checking object id.
const size_t prefix_len
Prefix length in bytes for matching object id.
Structure for stored a cached object.
const char * ast_sorcery_object_get_id(const void *object)
Get the unique identifier of a sorcery object.
Definition: sorcery.c:2312
void * object
The cached object.
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:772
struct ast_variable * objectset
Cached objectset for field and regex retrieval.
Structure used for fields comparison.
#define ao2_link(container, obj)
Definition: astobj2.h:1549

◆ sorcery_memory_cache_hash()

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

Definition at line 295 of file res_sorcery_memory_cache.c.

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

Referenced by load_module().

296 {
297  const struct sorcery_memory_cache *cache = obj;
298  const char *name = obj;
299  int hash;
300 
301  switch (flags & OBJ_SEARCH_MASK) {
302  default:
303  case OBJ_SEARCH_OBJECT:
304  name = cache->name;
305  /* Fall through */
306  case OBJ_SEARCH_KEY:
307  hash = ast_str_hash(name);
308  break;
310  /* Should never happen in hash callback. */
311  ast_assert(0);
312  hash = 0;
313  break;
314  }
315  return hash;
316 }
The arg parameter is a search key, but is not an object.
Definition: astobj2.h:1105
#define ast_assert(a)
Definition: utils.h:695
The arg parameter is a partial search key similar to OBJ_SEARCH_KEY.
Definition: astobj2.h:1120
Structure for storing a memory cache.
static const char name[]
Definition: cdr_mysql.c:74
struct ao2_container * cache
Definition: pbx_realtime.c:77
The arg parameter is an object of the same type.
Definition: astobj2.h:1091
Search option field mask.
Definition: astobj2.h:1076
char * name
The name of the memory cache.
static force_inline int attribute_pure ast_str_hash(const char *str)
Compute a hash value on a string.
Definition: strings.h:1206

◆ sorcery_memory_cache_load()

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

Definition at line 1436 of file res_sorcery_memory_cache.c.

References ao2_link, ast_asprintf, ast_debug, ast_sorcery_get_module(), ast_strdup, ast_strlen_zero, sorcery_memory_cache::name, sorcery_memory_cache::object_type, and sorcery_memory_cache::sorcery.

1437 {
1438  struct sorcery_memory_cache *cache = data;
1439 
1440  /* If no name was explicitly specified generate one given the sorcery instance and object type */
1441  if (ast_strlen_zero(cache->name)) {
1442  ast_asprintf(&cache->name, "%s/%s", ast_sorcery_get_module(sorcery), type);
1443  }
1444 
1445  ao2_link(caches, cache);
1446  ast_debug(1, "Memory cache '%s' associated with sorcery instance '%p' of module '%s' with object type '%s'\n",
1447  cache->name, sorcery, ast_sorcery_get_module(sorcery), type);
1448 
1449  cache->sorcery = sorcery;
1450  cache->object_type = ast_strdup(type);
1451 }
static const char type[]
Definition: chan_ooh323.c:109
const struct ast_sorcery * sorcery
An unreffed pointer to the sorcery instance, accessible only with lock held.
#define ast_strdup(str)
A wrapper for strdup()
Definition: astmm.h:243
#define ast_asprintf(ret, fmt,...)
A wrapper for asprintf()
Definition: astmm.h:269
#define ast_strlen_zero(foo)
Definition: strings.h:52
const char * ast_sorcery_get_module(const struct ast_sorcery *sorcery)
Get the module that has opened the provided sorcery instance.
Definition: sorcery.c:2531
#define ast_debug(level,...)
Log a DEBUG message.
Definition: logger.h:452
Structure for storing a memory cache.
static struct ao2_container * caches
Container of created caches.
struct ao2_container * cache
Definition: pbx_realtime.c:77
static struct ast_sorcery * sorcery
char * object_type
The type of object we are caching.
char * name
The name of the memory cache.
#define ao2_link(container, obj)
Definition: astobj2.h:1549

◆ sorcery_memory_cache_open()

static void * sorcery_memory_cache_open ( const char *  data)
static

Definition at line 1508 of file res_sorcery_memory_cache.c.

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_strlen_zero, ast_true(), CACHE_CONTAINER_BUCKET_SIZE, CACHE_HEAP_INIT_HEIGHT, configuration_parse_unsigned_integer(), sorcery_memory_cache::expire_id, sorcery_memory_cache::expire_on_reload, sorcery_memory_cache::full_backend_cache, LOG_ERROR, sorcery_memory_cache::maximum_objects, sorcery_memory_cache::name, NULL, sorcery_memory_cache::object_heap, sorcery_memory_cache::object_lifetime_maximum, sorcery_memory_cache::object_lifetime_stale, sorcery_memory_cache::objects, options, RAII_VAR, sorcery_memory_cache_destructor(), sorcery_memory_cached_object_cmp(), sorcery_memory_cached_object_hash(), sorcery_memory_cache::stale_update_sched_id, strsep(), and value.

Referenced by AST_TEST_DEFINE().

1509 {
1510  char *options = ast_strdup(data), *option;
1512 
1514  if (!cache) {
1515  return NULL;
1516  }
1517 
1518  cache->expire_id = -1;
1519  cache->stale_update_sched_id = -1;
1520 
1521  /* If no configuration options have been provided this memory cache will operate in a default
1522  * configuration.
1523  */
1524  while (!ast_strlen_zero(options) && (option = strsep(&options, ","))) {
1525  char *name = strsep(&option, "="), *value = option;
1526 
1527  if (!strcasecmp(name, "name")) {
1528  if (ast_strlen_zero(value)) {
1529  ast_log(LOG_ERROR, "A name must be specified for the memory cache\n");
1530  return NULL;
1531  }
1532  ast_free(cache->name);
1533  cache->name = ast_strdup(value);
1534  } else if (!strcasecmp(name, "maximum_objects")) {
1535  if (configuration_parse_unsigned_integer(value, &cache->maximum_objects) != 1) {
1536  ast_log(LOG_ERROR, "Unsupported maximum objects value of '%s' used for memory cache\n",
1537  value);
1538  return NULL;
1539  }
1540  } else if (!strcasecmp(name, "object_lifetime_maximum")) {
1541  if (configuration_parse_unsigned_integer(value, &cache->object_lifetime_maximum) != 1) {
1542  ast_log(LOG_ERROR, "Unsupported object maximum lifetime value of '%s' used for memory cache\n",
1543  value);
1544  return NULL;
1545  }
1546  } else if (!strcasecmp(name, "object_lifetime_stale")) {
1547  if (configuration_parse_unsigned_integer(value, &cache->object_lifetime_stale) != 1) {
1548  ast_log(LOG_ERROR, "Unsupported object stale lifetime value of '%s' used for memory cache\n",
1549  value);
1550  return NULL;
1551  }
1552  } else if (!strcasecmp(name, "expire_on_reload")) {
1553  cache->expire_on_reload = ast_true(value);
1554  } else if (!strcasecmp(name, "full_backend_cache")) {
1555  cache->full_backend_cache = ast_true(value);
1556  } else {
1557  ast_log(LOG_ERROR, "Unsupported option '%s' used for memory cache\n", name);
1558  return NULL;
1559  }
1560  }
1561 
1563  cache->maximum_objects ? cache->maximum_objects : CACHE_CONTAINER_BUCKET_SIZE,
1565  if (!cache->objects) {
1566  ast_log(LOG_ERROR, "Could not create a container to hold cached objects for memory cache\n");
1567  return NULL;
1568  }
1569 
1571  offsetof(struct sorcery_memory_cached_object, __heap_index));
1572  if (!cache->object_heap) {
1573  ast_log(LOG_ERROR, "Could not create heap to hold cached objects\n");
1574  return NULL;
1575  }
1576 
1577  /* The memory cache is not linked to the caches container until the load callback is invoked.
1578  * Linking occurs there so an intelligent cache name can be constructed using the module of
1579  * the sorcery instance and the specific object type if no cache name was specified as part
1580  * of the configuration.
1581  */
1582 
1583  /* This is done as RAII_VAR will drop the reference */
1584  return ao2_bump(cache);
1585 }
#define 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 int sorcery_memory_cached_object_cmp(void *obj, void *arg, int flags)
#define ao2_alloc_options(data_size, destructor_fn, options)
Definition: astobj2.h:406
#define ast_strdup(str)
A wrapper for strdup()
Definition: astmm.h:243
#define NULL
Definition: resample.c:96
int value
Definition: syslog.c:37
#define ast_strlen_zero(foo)
Definition: strings.h:52
#define ao2_bump(obj)
Definition: astobj2.h:491
#define ast_log
Definition: astobj2.c:42
Structure for storing a memory cache.
#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:911
Structure for stored a cached object.
#define LOG_ERROR
Definition: logger.h:285
#define ao2_container_alloc_hash(ao2_options, container_options, n_buckets, hash_fn, sort_fn, cmp_fn)
Definition: astobj2.h:1310
int attribute_pure ast_true(const char *val)
Make sure something is true. Determine if a string containing a boolean value is "true". This function checks to see whether a string passed to it is an indication of an "true" value. It checks to see if the string is "yes", "true", "y", "t", "on" or "1".
Definition: main/utils.c:1951
static const char name[]
Definition: cdr_mysql.c:74
#define ast_free(a)
Definition: astmm.h:182
#define ast_heap_create(init_height, cmp_fn, index_offset)
Definition: heap.h:102
struct ao2_container * cache
Definition: pbx_realtime.c:77
char * strsep(char **str, const char *delims)
static void sorcery_memory_cache_destructor(void *obj)
#define ao2_cleanup(obj)
Definition: astobj2.h:1958
#define CACHE_HEAP_INIT_HEIGHT
Height of heap for cache object heap. Allows 31 initial objects.
static struct test_options options
static int configuration_parse_unsigned_integer(const char *value, unsigned int *result)
static int age_cmp(void *a, void *b)

◆ sorcery_memory_cache_populate()

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

Definition at line 2001 of file res_sorcery_memory_cache.c.

References ao2_container_count(), ao2_find, ao2_ref, ao2_unlock, ao2_wrlock, ast_cli_args::argc, ast_cli_args::argv, ast_cli(), cache, CLI_FAILURE, CLI_GENERATE, CLI_INIT, CLI_SHOWUSAGE, CLI_SUCCESS, ast_cli_entry::command, ast_cli_args::fd, sorcery_memory_cache::full_backend_cache, memory_cache_populate(), ast_cli_args::n, NULL, OBJ_SEARCH_KEY, sorcery_memory_cache::object_type, sorcery_memory_cache::objects, ast_cli_args::pos, remove_all_from_cache(), sorcery_memory_cache::sorcery, sorcery_memory_cache_complete_name(), ast_cli_entry::usage, and ast_cli_args::word.

2002 {
2003  struct sorcery_memory_cache *cache;
2004 
2005  switch (cmd) {
2006  case CLI_INIT:
2007  e->command = "sorcery memory cache populate";
2008  e->usage =
2009  "Usage: sorcery memory cache populate <cache name>\n"
2010  " Expire all objects in the cache and populate it with ALL objects from backend.\n";
2011  return NULL;
2012  case CLI_GENERATE:
2013  if (a->pos == 4) {
2014  return sorcery_memory_cache_complete_name(a->word, a->n);
2015  } else {
2016  return NULL;
2017  }
2018  }
2019 
2020  if (a->argc != 5) {
2021  return CLI_SHOWUSAGE;
2022  }
2023 
2024  cache = ao2_find(caches, a->argv[4], OBJ_SEARCH_KEY);
2025  if (!cache) {
2026  ast_cli(a->fd, "Specified sorcery memory cache '%s' does not exist\n", a->argv[4]);
2027  return CLI_FAILURE;
2028  }
2029 
2030  if (!cache->full_backend_cache) {
2031  ast_cli(a->fd, "Specified sorcery memory cache '%s' does not have full backend caching enabled\n", a->argv[4]);
2032  ao2_ref(cache, -1);
2033  return CLI_FAILURE;
2034  }
2035 
2036  ao2_wrlock(cache->objects);
2037  if (!cache->sorcery) {
2038  ast_cli(a->fd, "Specified sorcery memory cache '%s' is no longer active\n", a->argv[4]);
2039  ao2_unlock(cache->objects);
2040  ao2_ref(cache, -1);
2041  return CLI_FAILURE;
2042  }
2043 
2044  remove_all_from_cache(cache);
2045  memory_cache_populate(cache->sorcery, cache->object_type, cache);
2046 
2047  ast_cli(a->fd, "Specified sorcery memory cache '%s' has been populated with '%d' objects from the backend\n",
2048  a->argv[4], ao2_container_count(cache->objects));
2049 
2050  ao2_unlock(cache->objects);
2051 
2052  ao2_ref(cache, -1);
2053 
2054  return CLI_SUCCESS;
2055 }
int ao2_container_count(struct ao2_container *c)
Returns the number of elements in a container.
The arg parameter is a search key, but is not an object.
Definition: astobj2.h:1105
const struct ast_sorcery * sorcery
An unreffed pointer to the sorcery instance, accessible only with lock held.
const int argc
Definition: cli.h:160
Definition: cli.h:152
#define ao2_unlock(a)
Definition: astobj2.h:730
#define NULL
Definition: resample.c:96
#define ao2_wrlock(a)
Definition: astobj2.h:720
void ast_cli(int fd, const char *fmt,...)
Definition: clicompat.c:6
Structure for storing a memory cache.
const int fd
Definition: cli.h:159
const int n
Definition: cli.h:165
unsigned int full_backend_cache
Whether this is a cache of the entire backend, 0 if disabled.
#define ao2_ref(o, delta)
Definition: astobj2.h:464
static void memory_cache_populate(const struct ast_sorcery *sorcery, const char *type, struct sorcery_memory_cache *cache)
const char *const * argv
Definition: cli.h:161
static void remove_all_from_cache(struct sorcery_memory_cache *cache)
static struct ao2_container * caches
Container of created caches.
#define CLI_SHOWUSAGE
Definition: cli.h:45
#define CLI_FAILURE
Definition: cli.h:46
char * command
Definition: cli.h:186
const char * word
Definition: cli.h:163
#define ao2_find(container, arg, flags)
Definition: astobj2.h:1756
struct ao2_container * cache
Definition: pbx_realtime.c:77
const char * usage
Definition: cli.h:177
#define CLI_SUCCESS
Definition: cli.h:44
const int pos
Definition: cli.h:164
char * object_type
The type of object we are caching.
struct ao2_container * objects
Objects in the cache.
static char * sorcery_memory_cache_complete_name(const char *word, int state)

◆ sorcery_memory_cache_print_object()

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

Definition at line 1744 of file res_sorcery_memory_cache.c.

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

1745 {
1746 #define FORMAT "%-25.25s %-15u %-15u \n"
1747  struct sorcery_memory_cached_object *cached = obj;
1748  struct print_object_details *details = arg;
1749  int seconds_until_expire = 0, seconds_until_stale = 0;
1750 
1751  if (details->cache->object_lifetime_maximum) {
1752  seconds_until_expire = ast_tvdiff_ms(ast_tvadd(cached->created, ast_samp2tv(details->cache->object_lifetime_maximum, 1)), ast_tvnow()) / 1000;
1753  }
1754  if (details->cache->object_lifetime_stale) {
1755  seconds_until_stale = ast_tvdiff_ms(ast_tvadd(cached->created, ast_samp2tv(details->cache->object_lifetime_stale, 1)), ast_tvnow()) / 1000;
1756  }
1757 
1758  ast_cli(details->a->fd, FORMAT, ast_sorcery_object_get_id(cached->object), MAX(seconds_until_stale, 0), MAX(seconds_until_expire, 0));
1759 
1760  return CMP_MATCH;
1761 #undef FORMAT
1762 }
#define FORMAT
struct timeval ast_tvnow(void)
Returns current timeval. Meant to replace calls to gettimeofday().
Definition: time.h:150
struct timeval created
The time at which the object was created.
unsigned int object_lifetime_maximum
The maximum time (in seconds) an object will stay in the cache, 0 if no limit.
int64_t ast_tvdiff_ms(struct timeval end, struct timeval start)
Computes the difference (in milliseconds) between two struct timeval instances.
Definition: time.h:98
void ast_cli(int fd, const char *fmt,...)
Definition: clicompat.c:6
#define MAX(a, b)
Definition: utils.h:228
const int fd
Definition: cli.h:159
Structure for stored a cached object.
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:238
const char * ast_sorcery_object_get_id(const void *object)
Get the unique identifier of a sorcery object.
Definition: sorcery.c:2312
Structure used to pass data for printing cached object information.
struct timeval ast_tvadd(struct timeval a, struct timeval b)
Returns the sum of two timevals a + b.
Definition: extconf.c:2283
void * object
The cached object.
struct ast_cli_args * a
The CLI arguments.
unsigned int object_lifetime_stale
The amount of time (in seconds) before an object is marked as stale, 0 if disabled.
struct sorcery_memory_cache * cache
The sorcery memory cache.

◆ sorcery_memory_cache_reload()

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

Definition at line 1461 of file res_sorcery_memory_cache.c.

References ao2_unlock, ao2_wrlock, sorcery_memory_cache::expire_on_reload, sorcery_memory_cache::objects, and remove_all_from_cache().

1462 {
1463  struct sorcery_memory_cache *cache = data;
1464 
1465  if (!cache->expire_on_reload) {
1466  return;
1467  }
1468 
1469  ao2_wrlock(cache->objects);
1470  remove_all_from_cache(cache);
1471  ao2_unlock(cache->objects);
1472 }
#define ao2_unlock(a)
Definition: astobj2.h:730
#define ao2_wrlock(a)
Definition: astobj2.h:720
Structure for storing a memory cache.
unsigned int expire_on_reload
Whether all objects are expired when the object type is reloaded, 0 if disabled.
static void remove_all_from_cache(struct sorcery_memory_cache *cache)
struct ao2_container * cache
Definition: pbx_realtime.c:77
struct ao2_container * objects
Objects in the cache.

◆ sorcery_memory_cache_retrieve_fields()

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

Definition at line 1299 of file res_sorcery_memory_cache.c.

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

1301 {
1302  struct sorcery_memory_cache *cache = data;
1303  struct sorcery_memory_cache_fields_cmp_params params = {
1304  .sorcery = sorcery,
1305  .cache = cache,
1306  .fields = fields,
1307  };
1308  struct sorcery_memory_cached_object *cached;
1309  void *object = NULL;
1310 
1311  if (is_passthru_update() || !cache->full_backend_cache || !fields) {
1312  return NULL;
1313  }
1314 
1315  cached = ao2_callback(cache->objects, 0, sorcery_memory_cache_fields_cmp, &params);
1316 
1317  if (cached) {
1318  memory_cache_stale_check_object(sorcery, cache, cached);
1319  object = ao2_bump(cached->object);
1320  ao2_ref(cached, -1);
1321  }
1322 
1323  return object;
1324 }
const struct ast_variable * fields
Pointer to the fields to check.
static int is_passthru_update(void)
#define ao2_callback(c, flags, cb_fn, arg)
Definition: astobj2.h:1716
#define NULL
Definition: resample.c:96
#define ao2_bump(obj)
Definition: astobj2.h:491
Structure for storing a memory cache.
unsigned int full_backend_cache
Whether this is a cache of the entire backend, 0 if disabled.
const struct ast_sorcery * sorcery
Pointer to the sorcery structure.
#define ao2_ref(o, delta)
Definition: astobj2.h:464
Structure for stored a cached 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 int sorcery_memory_cache_fields_cmp(void *obj, void *arg, int flags)
void * object
The cached object.
struct ao2_container * cache
Definition: pbx_realtime.c:77
static struct ast_sorcery * sorcery
struct ao2_container * objects
Objects in the cache.
Structure used for fields comparison.

◆ sorcery_memory_cache_retrieve_id()

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

Definition at line 1219 of file res_sorcery_memory_cache.c.

References ao2_bump, ao2_find, ao2_ref, ast_assert, ast_sorcery_object_get_id(), is_passthru_update(), memory_cache_full_update(), memory_cache_stale_check_object(), NULL, OBJ_SEARCH_KEY, sorcery_memory_cached_object::object, and sorcery_memory_cache::objects.

Referenced by AST_TEST_DEFINE(), and check_cache_content().

1220 {
1221  struct sorcery_memory_cache *cache = data;
1222  struct sorcery_memory_cached_object *cached;
1223  void *object;
1224 
1225  if (is_passthru_update()) {
1226  return NULL;
1227  }
1228 
1229  memory_cache_full_update(sorcery, type, cache);
1230 
1231  cached = ao2_find(cache->objects, id, OBJ_SEARCH_KEY);
1232  if (!cached) {
1233  return NULL;
1234  }
1235 
1236  ast_assert(!strcmp(ast_sorcery_object_get_id(cached->object), id));
1237 
1238  memory_cache_stale_check_object(sorcery, cache, cached);
1239 
1240  object = ao2_bump(cached->object);
1241  ao2_ref(cached, -1);
1242 
1243  return object;
1244 }
static const char type[]
Definition: chan_ooh323.c:109
static int is_passthru_update(void)
The arg parameter is a search key, but is not an object.
Definition: astobj2.h:1105
#define ast_assert(a)
Definition: utils.h:695
#define NULL
Definition: resample.c:96
#define ao2_bump(obj)
Definition: astobj2.h:491
Structure for storing a memory cache.
#define ao2_ref(o, delta)
Definition: astobj2.h:464
Structure for stored a cached object.
const char * ast_sorcery_object_get_id(const void *object)
Get the unique identifier of a sorcery object.
Definition: sorcery.c:2312
static void memory_cache_stale_check_object(const struct ast_sorcery *sorcery, struct sorcery_memory_cache *cache, struct sorcery_memory_cached_object *cached)
void * object
The cached object.
static void memory_cache_full_update(const struct ast_sorcery *sorcery, const char *type, struct sorcery_memory_cache *cache)
#define ao2_find(container, arg, flags)
Definition: astobj2.h:1756
struct ao2_container * cache
Definition: pbx_realtime.c:77
struct ao2_container * objects
Objects in the cache.

◆ sorcery_memory_cache_retrieve_multiple()

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

Definition at line 1336 of file res_sorcery_memory_cache.c.

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

1338 {
1339  struct sorcery_memory_cache *cache = data;
1340  struct sorcery_memory_cache_fields_cmp_params params = {
1341  .sorcery = sorcery,
1342  .cache = cache,
1343  .fields = fields,
1344  .container = objects,
1345  };
1346 
1347  if (is_passthru_update() || !cache->full_backend_cache) {
1348  return;
1349  }
1350 
1351  memory_cache_full_update(sorcery, type, cache);
1353 
1354  if (ao2_container_count(objects)) {
1355  memory_cache_stale_check(sorcery, cache);
1356  }
1357 }
static const char type[]
Definition: chan_ooh323.c:109
const struct ast_variable * fields
Pointer to the fields to check.
static int is_passthru_update(void)
int ao2_container_count(struct ao2_container *c)
Returns the number of elements in a container.
#define ao2_callback(c, flags, cb_fn, arg)
Definition: astobj2.h:1716
Structure for storing a memory cache.
unsigned int full_backend_cache
Whether this is a cache of the entire backend, 0 if disabled.
const struct ast_sorcery * sorcery
Pointer to the sorcery structure.
static int sorcery_memory_cache_fields_cmp(void *obj, void *arg, int flags)
static void memory_cache_full_update(const struct ast_sorcery *sorcery, const char *type, struct sorcery_memory_cache *cache)
struct ao2_container * cache
Definition: pbx_realtime.c:77
static struct ast_sorcery * sorcery
struct ao2_container * objects
Objects in the cache.
Structure used for fields comparison.
static void memory_cache_stale_check(const struct ast_sorcery *sorcery, struct sorcery_memory_cache *cache)

◆ sorcery_memory_cache_retrieve_prefix()

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

Definition at line 1404 of file res_sorcery_memory_cache.c.

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

1406 {
1407  struct sorcery_memory_cache *cache = data;
1408  struct sorcery_memory_cache_fields_cmp_params params = {
1409  .sorcery = sorcery,
1410  .cache = cache,
1411  .container = objects,
1412  .prefix = prefix,
1413  .prefix_len = prefix_len,
1414  };
1415 
1416  if (is_passthru_update() || !cache->full_backend_cache) {
1417  return;
1418  }
1419 
1420  memory_cache_full_update(sorcery, type, cache);
1422 
1423  if (ao2_container_count(objects)) {
1424  memory_cache_stale_check(sorcery, cache);
1425  }
1426 }
static const char type[]
Definition: chan_ooh323.c:109
static int is_passthru_update(void)
int ao2_container_count(struct ao2_container *c)
Returns the number of elements in a container.
#define ao2_callback(c, flags, cb_fn, arg)
Definition: astobj2.h:1716
Structure for storing a memory cache.
unsigned int full_backend_cache
Whether this is a cache of the entire backend, 0 if disabled.
const size_t prefix_len
Prefix length in bytes for matching object id.
const struct ast_sorcery * sorcery
Pointer to the sorcery structure.
static int sorcery_memory_cache_fields_cmp(void *obj, void *arg, int flags)
static void memory_cache_full_update(const struct ast_sorcery *sorcery, const char *type, struct sorcery_memory_cache *cache)
struct ao2_container * cache
Definition: pbx_realtime.c:77
static struct ast_sorcery * sorcery
struct ao2_container * objects
Objects in the cache.
Structure used for fields comparison.
static void memory_cache_stale_check(const struct ast_sorcery *sorcery, struct sorcery_memory_cache *cache)
static char prefix[MAX_PREFIX]
Definition: http.c:141

◆ sorcery_memory_cache_retrieve_regex()

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

Definition at line 1369 of file res_sorcery_memory_cache.c.

References ao2_callback, ao2_container_count(), cache, sorcery_memory_cache::full_backend_cache, is_passthru_update(), memory_cache_full_update(), memory_cache_stale_check(), sorcery_memory_cache::objects, sorcery_memory_cache::sorcery, sorcery_memory_cache_fields_cmp_params::sorcery, and sorcery_memory_cache_fields_cmp().

1371 {
1372  struct sorcery_memory_cache *cache = data;
1373  regex_t expression;
1374  struct sorcery_memory_cache_fields_cmp_params params = {
1375  .sorcery = sorcery,
1376  .cache = cache,
1377  .container = objects,
1378  .regex = &expression,
1379  };
1380 
1381  if (is_passthru_update() || !cache->full_backend_cache || regcomp(&expression, regex, REG_EXTENDED | REG_NOSUB)) {
1382  return;
1383  }
1384 
1385  memory_cache_full_update(sorcery, type, cache);
1387  regfree(&expression);
1388 
1389  if (ao2_container_count(objects)) {
1390  memory_cache_stale_check(sorcery, cache);
1391  }
1392 }
static const char type[]
Definition: chan_ooh323.c:109
static int is_passthru_update(void)
int ao2_container_count(struct ao2_container *c)
Returns the number of elements in a container.
#define ao2_callback(c, flags, cb_fn, arg)
Definition: astobj2.h:1716
Structure for storing a memory cache.
unsigned int full_backend_cache
Whether this is a cache of the entire backend, 0 if disabled.
const struct ast_sorcery * sorcery
Pointer to the sorcery structure.
static int sorcery_memory_cache_fields_cmp(void *obj, void *arg, int flags)
static int regex(struct ast_channel *chan, const char *cmd, char *parse, char *buf, size_t len)
Definition: func_strings.c:948
static void memory_cache_full_update(const struct ast_sorcery *sorcery, const char *type, struct sorcery_memory_cache *cache)
struct ao2_container * cache
Definition: pbx_realtime.c:77
static struct ast_sorcery * sorcery
struct ao2_container * objects
Objects in the cache.
Structure used for fields comparison.
static void memory_cache_stale_check(const struct ast_sorcery *sorcery, struct sorcery_memory_cache *cache)

◆ sorcery_memory_cache_show()

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

Definition at line 1679 of file res_sorcery_memory_cache.c.

References ao2_container_count(), ao2_find, ao2_ref, ast_cli_args::argc, ast_cli_args::argv, ast_cli(), AST_CLI_ONOFF, cache, CLI_FAILURE, CLI_GENERATE, CLI_INIT, CLI_SHOWUSAGE, CLI_SUCCESS, ast_cli_entry::command, sorcery_memory_cache::expire_on_reload, ast_cli_args::fd, sorcery_memory_cache::maximum_objects, ast_cli_args::n, sorcery_memory_cache::name, NULL, OBJ_SEARCH_KEY, sorcery_memory_cache::object_lifetime_maximum, sorcery_memory_cache::object_lifetime_stale, sorcery_memory_cache::objects, ast_cli_args::pos, sorcery_memory_cache_complete_name(), ast_cli_entry::usage, and ast_cli_args::word.

1680 {
1681  struct sorcery_memory_cache *cache;
1682 
1683  switch (cmd) {
1684  case CLI_INIT:
1685  e->command = "sorcery memory cache show";
1686  e->usage =
1687  "Usage: sorcery memory cache show <name>\n"
1688  " Show sorcery memory cache configuration and statistics.\n";
1689  return NULL;
1690  case CLI_GENERATE:
1691  if (a->pos == 4) {
1692  return sorcery_memory_cache_complete_name(a->word, a->n);
1693  } else {
1694  return NULL;
1695  }
1696  }
1697 
1698  if (a->argc != 5) {
1699  return CLI_SHOWUSAGE;
1700  }
1701 
1702  cache = ao2_find(caches, a->argv[4], OBJ_SEARCH_KEY);
1703  if (!cache) {
1704  ast_cli(a->fd, "Specified sorcery memory cache '%s' does not exist\n", a->argv[4]);
1705  return CLI_FAILURE;
1706  }
1707 
1708  ast_cli(a->fd, "Sorcery memory cache: %s\n", cache->name);
1709  ast_cli(a->fd, "Number of objects within cache: %d\n", ao2_container_count(cache->objects));
1710  if (cache->maximum_objects) {
1711  ast_cli(a->fd, "Maximum allowed objects: %d\n", cache->maximum_objects);
1712  } else {
1713  ast_cli(a->fd, "There is no limit on the maximum number of objects in the cache\n");
1714  }
1715  if (cache->object_lifetime_maximum) {
1716  ast_cli(a->fd, "Number of seconds before object expires: %d\n", cache->object_lifetime_maximum);
1717  } else {
1718  ast_cli(a->fd, "Object expiration is not enabled - cached objects will not expire\n");
1719  }
1720  if (cache->object_lifetime_stale) {
1721  ast_cli(a->fd, "Number of seconds before object becomes stale: %d\n", cache->object_lifetime_stale);
1722  } else {
1723  ast_cli(a->fd, "Object staleness is not enabled - cached objects will not go stale\n");
1724  }
1725  ast_cli(a->fd, "Expire all objects on reload: %s\n", AST_CLI_ONOFF(cache->expire_on_reload));
1726 
1727  ao2_ref(cache, -1);
1728 
1729  return CLI_SUCCESS;
1730 }
unsigned int maximum_objects
The maximum number of objects permitted in the cache, 0 if no limit.
int ao2_container_count(struct ao2_container *c)
Returns the number of elements in a container.
The arg parameter is a search key, but is not an object.
Definition: astobj2.h:1105
const int argc
Definition: cli.h:160
Definition: cli.h:152
unsigned int object_lifetime_maximum
The maximum time (in seconds) an object will stay in the cache, 0 if no limit.
#define NULL
Definition: resample.c:96
void ast_cli(int fd, const char *fmt,...)
Definition: clicompat.c:6
#define AST_CLI_ONOFF(x)
return On or Off depending on the argument. This is used in many places in CLI command, having a function to generate this helps maintaining a consistent output (and possibly emitting the output in other languages, at some point).
Definition: cli.h:78
Structure for storing a memory cache.
const int fd
Definition: cli.h:159
const int n
Definition: cli.h:165
#define ao2_ref(o, delta)
Definition: astobj2.h:464
unsigned int expire_on_reload
Whether all objects are expired when the object type is reloaded, 0 if disabled.
const char *const * argv
Definition: cli.h:161
static struct ao2_container * caches
Container of created caches.
#define CLI_SHOWUSAGE
Definition: cli.h:45
#define CLI_FAILURE
Definition: cli.h:46
char * command
Definition: cli.h:186
const char * word
Definition: cli.h:163
#define ao2_find(container, arg, flags)
Definition: astobj2.h:1756
struct ao2_container * cache
Definition: pbx_realtime.c:77
const char * usage
Definition: cli.h:177
#define CLI_SUCCESS
Definition: cli.h:44
const int pos
Definition: cli.h:164
struct ao2_container * objects
Objects in the cache.
unsigned int object_lifetime_stale
The amount of time (in seconds) before an object is marked as stale, 0 if disabled.
char * name
The name of the memory cache.
static char * sorcery_memory_cache_complete_name(const char *word, int state)

◆ sorcery_memory_cache_stale()

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

Definition at line 1917 of file res_sorcery_memory_cache.c.

References ao2_find, ao2_rdlock, ao2_ref, ao2_unlock, ast_cli_args::argc, ast_cli_args::argv, ast_cli(), ast_cli_complete(), cache, CLI_FAILURE, CLI_GENERATE, CLI_INIT, CLI_SHOWUSAGE, CLI_SUCCESS, ast_cli_entry::command, ast_cli_args::fd, mark_all_as_stale_in_cache(), mark_object_as_stale_in_cache(), memory_cache_stale_update_object(), ast_cli_args::n, NULL, OBJ_NOLOCK, OBJ_SEARCH_KEY, sorcery_memory_cache::object_lifetime_stale, sorcery_memory_cache::objects, ast_cli_args::pos, reload(), sorcery_memory_cache::sorcery, sorcery_memory_cache_complete_name(), sorcery_memory_cache_complete_object_name(), ast_cli_entry::usage, and ast_cli_args::word.

1918 {
1919  struct sorcery_memory_cache *cache;
1920  int reload = 0;
1921 
1922  switch (cmd) {
1923  case CLI_INIT:
1924  e->command = "sorcery memory cache stale";
1925  e->usage =
1926  "Usage: sorcery memory cache stale <cache name> [object name [reload]]\n"
1927  " Mark a specific object or ALL objects as stale in a sorcery memory cache.\n"
1928  " If \"reload\" is specified, then the object is marked stale and immediately\n"
1929  " retrieved from backend storage to repopulate the cache\n";
1930  return NULL;
1931  case CLI_GENERATE:
1932  if (a->pos == 4) {
1933  return sorcery_memory_cache_complete_name(a->word, a->n);
1934  } else if (a->pos == 5) {
1935  return sorcery_memory_cache_complete_object_name(a->argv[4], a->word, a->n);
1936  } else if (a->pos == 6) {
1937  static const char * const completions[] = { "reload", NULL };
1938  return ast_cli_complete(a->word, completions, a->n);
1939  } else {
1940  return NULL;
1941  }
1942  }
1943 
1944  if (a->argc < 5 || a->argc > 7) {
1945  return CLI_SHOWUSAGE;
1946  }
1947 
1948  if (a->argc == 7) {
1949  if (!strcasecmp(a->argv[6], "reload")) {
1950  reload = 1;
1951  } else {
1952  return CLI_SHOWUSAGE;
1953  }
1954  }
1955 
1956  cache = ao2_find(caches, a->argv[4], OBJ_SEARCH_KEY);
1957  if (!cache) {
1958  ast_cli(a->fd, "Specified sorcery memory cache '%s' does not exist\n", a->argv[4]);
1959  return CLI_FAILURE;
1960  }
1961 
1962  if (!cache->object_lifetime_stale) {
1963  ast_cli(a->fd, "Specified sorcery memory cache '%s' does not have staleness enabled\n", a->argv[4]);
1964  ao2_ref(cache, -1);
1965  return CLI_FAILURE;
1966  }
1967 
1968  ao2_rdlock(cache->objects);
1969  if (a->argc == 5) {
1971  ast_cli(a->fd, "Marked all objects in sorcery memory cache '%s' as stale\n", a->argv[4]);
1972  } else {
1973  if (!mark_object_as_stale_in_cache(cache, a->argv[5])) {
1974  ast_cli(a->fd, "Successfully marked object '%s' in memory cache '%s' as stale\n",
1975  a->argv[5], a->argv[4]);
1976  if (reload) {
1977  struct sorcery_memory_cached_object *cached;
1978 
1979  cached = ao2_find(cache->objects, a->argv[5], OBJ_SEARCH_KEY | OBJ_NOLOCK);
1980  if (cached) {
1981  memory_cache_stale_update_object(cache->sorcery, cache, cached);
1982  ao2_ref(cached, -1);
1983  }
1984  }
1985  } else {
1986  ast_cli(a->fd, "Object '%s' in sorcery memory cache '%s' could not be marked as stale as it was not found\n",
1987  a->argv[5], a->argv[4]);
1988  }
1989  }
1990  ao2_unlock(cache->objects);
1991 
1992  ao2_ref(cache, -1);
1993 
1994  return CLI_SUCCESS;
1995 }
The arg parameter is a search key, but is not an object.
Definition: astobj2.h:1105
const struct ast_sorcery * sorcery
An unreffed pointer to the sorcery instance, accessible only with lock held.
static char * sorcery_memory_cache_complete_object_name(const char *cache_name, const char *word, int state)
const int argc
Definition: cli.h:160
Definition: cli.h:152
Assume that the ao2_container is already locked.
Definition: astobj2.h:1067
#define ao2_unlock(a)
Definition: astobj2.h:730
#define NULL
Definition: resample.c:96
void ast_cli(int fd, const char *fmt,...)
Definition: clicompat.c:6
char * ast_cli_complete(const char *word, const char *const choices[], int pos)
Definition: main/cli.c:1811
static void memory_cache_stale_update_object(const struct ast_sorcery *sorcery, struct sorcery_memory_cache *cache, struct sorcery_memory_cached_object *cached)
Structure for storing a memory cache.
const int fd
Definition: cli.h:159
const int n
Definition: cli.h:165
#define ao2_ref(o, delta)
Definition: astobj2.h:464
Structure for stored a cached object.
const char *const * argv
Definition: cli.h:161
static struct ao2_container * caches
Container of created caches.
#define CLI_SHOWUSAGE
Definition: cli.h:45
#define ao2_rdlock(a)
Definition: astobj2.h:719
#define CLI_FAILURE
Definition: cli.h:46
char * command
Definition: cli.h:186
static int reload(void)
Definition: cdr_mysql.c:741
const char * word
Definition: cli.h:163
#define ao2_find(container, arg, flags)
Definition: astobj2.h:1756
struct ao2_container * cache
Definition: pbx_realtime.c:77
const char * usage
Definition: cli.h:177
#define CLI_SUCCESS
Definition: cli.h:44
const int pos
Definition: cli.h:164
struct ao2_container * objects
Objects in the cache.
static int mark_object_as_stale_in_cache(struct sorcery_memory_cache *cache, const char *id)
static void mark_all_as_stale_in_cache(struct sorcery_memory_cache *cache)
unsigned int object_lifetime_stale
The amount of time (in seconds) before an object is marked as stale, 0 if disabled.
static char * sorcery_memory_cache_complete_name(const char *word, int state)

◆ sorcery_memory_cached_object_alloc()

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

Definition at line 766 of file res_sorcery_memory_cache.c.

References ao2_alloc, ao2_bump, ao2_ref, ast_sorcery_objectset_create, ast_tvnow(), sorcery_memory_cached_object::created, sorcery_memory_cache::full_backend_cache, NULL, sorcery_memory_cached_object::object, sorcery_memory_cached_object::objectset, 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().

768 {
769  struct sorcery_memory_cached_object *cached;
770 
771  cached = ao2_alloc(sizeof(*cached), sorcery_memory_cached_object_destructor);
772  if (!cached) {
773  return NULL;
774  }
775 
776  cached->object = ao2_bump(object);
777  cached->created = ast_tvnow();
778  cached->stale_update_sched_id = -1;
779 
780  if (cache->full_backend_cache) {
781  /* A cached objectset allows us to easily perform all retrieval operations in a
782  * minimal of time.
783  */
784  cached->objectset = ast_sorcery_objectset_create(sorcery, object);
785  if (!cached->objectset) {
786  ao2_ref(cached, -1);
787  return NULL;
788  }
789  }
790 
791  return cached;
792 }
struct timeval ast_tvnow(void)
Returns current timeval. Meant to replace calls to gettimeofday().
Definition: time.h:150
struct timeval created
The time at which the object was created.
#define NULL
Definition: resample.c:96
#define ao2_bump(obj)
Definition: astobj2.h:491
unsigned int full_backend_cache
Whether this is a cache of the entire backend, 0 if disabled.
#define ao2_ref(o, delta)
Definition: astobj2.h:464
Structure for stored a cached object.
static void sorcery_memory_cached_object_destructor(void *obj)
#define ao2_alloc(data_size, destructor_fn)
Definition: astobj2.h:411
#define ast_sorcery_objectset_create(sorcery, object)
Create an object set (KVP list) for an object.
Definition: sorcery.h:1136
void * object
The cached object.
struct ast_variable * objectset
Cached objectset for field and regex retrieval.
int stale_update_sched_id
scheduler id of stale update task

◆ sorcery_memory_cached_object_cmp()

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

Definition at line 394 of file res_sorcery_memory_cache.c.

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

395 {
396  struct sorcery_memory_cached_object *left = obj;
397  struct sorcery_memory_cached_object *right = arg;
398  const char *right_name = arg;
399  int cmp;
400 
401  switch (flags & OBJ_SEARCH_MASK) {
402  default:
403  case OBJ_SEARCH_OBJECT:
404  right_name = ast_sorcery_object_get_id(right->object);
405  /* Fall through */
406  case OBJ_SEARCH_KEY:
407  cmp = strcmp(ast_sorcery_object_get_id(left->object), right_name);
408  break;
410  cmp = strncmp(ast_sorcery_object_get_id(left->object), right_name, strlen(right_name));
411  break;
412  }
413  return cmp ? 0 : CMP_MATCH;
414 }
The arg parameter is a search key, but is not an object.
Definition: astobj2.h:1105
The arg parameter is a partial search key similar to OBJ_SEARCH_KEY.
Definition: astobj2.h:1120
Structure for stored a cached object.
const char * ast_sorcery_object_get_id(const void *object)
Get the unique identifier of a sorcery object.
Definition: sorcery.c:2312
void * object
The cached object.
The arg parameter is an object of the same type.
Definition: astobj2.h:1091
Search option field mask.
Definition: astobj2.h:1076

◆ sorcery_memory_cached_object_destructor()

static void sorcery_memory_cached_object_destructor ( void *  obj)
static

Definition at line 440 of file res_sorcery_memory_cache.c.

References ao2_cleanup, ast_variables_destroy(), cache, sorcery_memory_cached_object::object, sorcery_memory_cached_object::objectset, and schedule_cache_expiration().

Referenced by sorcery_memory_cached_object_alloc().

441 {
442  struct sorcery_memory_cached_object *cached = obj;
443 
444  ao2_cleanup(cached->object);
446 }
void ast_variables_destroy(struct ast_variable *var)
Free variable list.
Definition: extconf.c:1263
Structure for stored a cached object.
void * object
The cached object.
#define ao2_cleanup(obj)
Definition: astobj2.h:1958
struct ast_variable * objectset
Cached objectset for field and regex retrieval.

◆ sorcery_memory_cached_object_hash()

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

Definition at line 360 of file res_sorcery_memory_cache.c.

References ast_assert, ast_sorcery_object_get_id(), ast_str_hash(), sorcery_memory_cache::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().

361 {
362  const struct sorcery_memory_cached_object *cached = obj;
363  const char *name = obj;
364  int hash;
365 
366  switch (flags & OBJ_SEARCH_MASK) {
367  default:
368  case OBJ_SEARCH_OBJECT:
369  name = ast_sorcery_object_get_id(cached->object);
370  /* Fall through */
371  case OBJ_SEARCH_KEY:
372  hash = ast_str_hash(name);
373  break;
375  /* Should never happen in hash callback. */
376  ast_assert(0);
377  hash = 0;
378  break;
379  }
380  return hash;
381 }
The arg parameter is a search key, but is not an object.
Definition: astobj2.h:1105
#define ast_assert(a)
Definition: utils.h:695
The arg parameter is a partial search key similar to OBJ_SEARCH_KEY.
Definition: astobj2.h:1120
Structure for stored a cached object.
const char * ast_sorcery_object_get_id(const void *object)
Get the unique identifier of a sorcery object.
Definition: sorcery.c:2312
static const char name[]
Definition: cdr_mysql.c:74
void * object
The cached object.
The arg parameter is an object of the same type.
Definition: astobj2.h:1091
Search option field mask.
Definition: astobj2.h:1076
static force_inline int attribute_pure ast_str_hash(const char *str)
Compute a hash value on a string.
Definition: strings.h:1206

◆ stale_cache_update()

static int stale_cache_update ( const void *  data)
static

Definition at line 908 of file res_sorcery_memory_cache.c.

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(), stale_cache_update_task_data::cache, end_passthru_update(), LOG_ERROR, LOG_WARNING, sorcery_memory_cache::maximum_objects, sorcery_memory_cache::name, NULL, OBJ_MULTIPLE, OBJ_NODATA, OBJ_NOLOCK, object_add_to_cache_callback(), sorcery_memory_cache::objects, remove_all_from_cache(), stale_cache_update_task_data::sorcery, sorcery_memory_cache::stale_update_sched_id, start_passthru_update(), and stale_cache_update_task_data::type.

Referenced by memory_cache_stale_update_full().

909 {
911  struct ao2_container *backend_objects;
912 
914  backend_objects = ast_sorcery_retrieve_by_fields(task_data->sorcery, task_data->type,
917 
918  if (!backend_objects) {
919  task_data->cache->stale_update_sched_id = -1;
920  ao2_ref(task_data, -1);
921  return 0;
922  }
923 
924  if (task_data->cache->maximum_objects && ao2_container_count(backend_objects) >= task_data->cache->maximum_objects) {
925  ast_log(LOG_ERROR, "The backend contains %d objects while the sorcery memory cache '%s' is explicitly configured to only allow %d\n",
926  ao2_container_count(backend_objects), task_data->cache->name, task_data->cache->maximum_objects);
927  task_data->cache->stale_update_sched_id = -1;
928  ao2_ref(task_data, -1);
929  return 0;
930  }
931 
932  ao2_wrlock(task_data->cache->objects);
933  remove_all_from_cache(task_data->cache);
935  task_data->sorcery, task_data->cache);
936 
937  /* If the number of cached objects does not match the number of backend objects we encountered a memory allocation
938  * failure and the cache is incomplete, so drop everything and fall back to querying the backend directly
939  * as it may be able to provide what is wanted.
940  */
941  if (ao2_container_count(task_data->cache->objects) != ao2_container_count(backend_objects)) {
942  ast_log(LOG_WARNING, "The backend contains %d objects while only %d could be added to sorcery memory cache '%s'\n",
943  ao2_container_count(backend_objects), ao2_container_count(task_data->cache->objects), task_data->cache->name);
944  remove_all_from_cache(task_data->cache);
945  }
946 
947  ao2_unlock(task_data->cache->objects);
948  ao2_ref(backend_objects, -1);
949 
950  task_data->cache->stale_update_sched_id = -1;
951  ao2_ref(task_data, -1);
952 
953  return 0;
954 }
unsigned int maximum_objects
The maximum number of objects permitted in the cache, 0 if no limit.
int ao2_container_count(struct ao2_container *c)
Returns the number of elements in a container.
static void start_passthru_update(void)
#define LOG_WARNING
Definition: logger.h:274
Perform no matching, return all objects.
Definition: sorcery.h:123
Assume that the ao2_container is already locked.
Definition: astobj2.h:1067
Return all matching objects.
Definition: sorcery.h:120
#define ao2_unlock(a)
Definition: astobj2.h:730
#define NULL
Definition: resample.c:96
#define ao2_wrlock(a)
Definition: astobj2.h:720
#define ast_log
Definition: astobj2.c:42
#define ao2_ref(o, delta)
Definition: astobj2.h:464
int stale_update_sched_id
scheduler id of stale update task
#define LOG_ERROR
Definition: logger.h:285
static void remove_all_from_cache(struct sorcery_memory_cache *cache)
#define ao2_callback_data(container, flags, cb_fn, arg, data)
Definition: astobj2.h:1743
userdata associated with baseline taskprocessor test
struct sorcery_memory_cache * cache
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
struct ao2_container * objects
Objects in the cache.
static int object_add_to_cache_callback(void *obj, void *arg, void *data, int flags)
Generic container type.
static void end_passthru_update(void)
char * name
The name of the memory cache.

◆ stale_cache_update_task_data_alloc()

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

Definition at line 886 of file res_sorcery_memory_cache.c.

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

Referenced by memory_cache_stale_update_full().

888 {
890 
891  task_data = ao2_alloc_options(sizeof(*task_data), stale_cache_update_task_data_destructor,
893  if (!task_data) {
894  return NULL;
895  }
896 
897  task_data->sorcery = ao2_bump(sorcery);
898  task_data->cache = ao2_bump(cache);
899  task_data->type = ast_strdup(type);
900  if (!task_data->type) {
901  ao2_ref(task_data, -1);
902  return NULL;
903  }
904 
905  return task_data;
906 }
static const char type[]
Definition: chan_ooh323.c:109
#define ao2_alloc_options(data_size, destructor_fn, options)
Definition: astobj2.h:406
#define ast_strdup(str)
A wrapper for strdup()
Definition: astmm.h:243
#define NULL
Definition: resample.c:96
#define ao2_bump(obj)
Definition: astobj2.h:491
#define ao2_ref(o, delta)
Definition: astobj2.h:464
static void stale_cache_update_task_data_destructor(void *obj)
userdata associated with baseline taskprocessor test
struct sorcery_memory_cache * cache

◆ stale_cache_update_task_data_destructor()

static void stale_cache_update_task_data_destructor ( void *  obj)
static

Definition at line 877 of file res_sorcery_memory_cache.c.

References ao2_cleanup, ast_free, ast_sorcery_unref, stale_cache_update_task_data::cache, stale_cache_update_task_data::sorcery, and stale_cache_update_task_data::type.

Referenced by stale_cache_update_task_data_alloc().

878 {
880 
881  ao2_cleanup(task_data->cache);
882  ast_sorcery_unref(task_data->sorcery);
883  ast_free(task_data->type);
884 }
#define ast_sorcery_unref(sorcery)
Decrease the reference count of a sorcery structure.
Definition: sorcery.h:1502
userdata associated with baseline taskprocessor test
#define ast_free(a)
Definition: astmm.h:182
struct sorcery_memory_cache * cache
#define ao2_cleanup(obj)
Definition: astobj2.h:1958

◆ stale_item_update()

static int stale_item_update ( const void *  data)
static

Definition at line 989 of file res_sorcery_memory_cache.c.

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, stale_update_task_data::cache, end_passthru_update(), sorcery_memory_cache::name, stale_update_task_data::object, stale_update_task_data::sorcery, sorcery_memory_cache_create(), sorcery_memory_cache_delete(), and start_passthru_update().

Referenced by memory_cache_stale_update_object().

990 {
991  struct stale_update_task_data *task_data = (struct stale_update_task_data *) data;
992  void *object;
993 
995 
996  object = ast_sorcery_retrieve_by_id(task_data->sorcery,
998  ast_sorcery_object_get_id(task_data->object));
999  if (!object) {
1000  ast_debug(1, "Backend no longer has object type '%s' ID '%s'. Removing from cache\n",
1001  ast_sorcery_object_get_type(task_data->object),
1002  ast_sorcery_object_get_id(task_data->object));
1003  sorcery_memory_cache_delete(task_data->sorcery, task_data->cache,
1004  task_data->object);
1005  } else {
1006  ast_debug(1, "Refreshing stale cache object type '%s' ID '%s'\n",
1007  ast_sorcery_object_get_type(task_data->object),
1008  ast_sorcery_object_get_id(task_data->object));
1009  sorcery_memory_cache_create(task_data->sorcery, task_data->cache,
1010  object);
1011  ao2_ref(object, -1);
1012  }
1013 
1014  ast_test_suite_event_notify("SORCERY_MEMORY_CACHE_REFRESHED", "Cache: %s\r\nType: %s\r\nName: %s\r\n",
1015  task_data->cache->name, ast_sorcery_object_get_type(task_data->object),
1016  ast_sorcery_object_get_id(task_data->object));
1017 
1018  ao2_ref(task_data, -1);
1020 
1021  return 0;
1022 }
static int sorcery_memory_cache_delete(const struct ast_sorcery *sorcery, void *data, void *object)
static void start_passthru_update(void)
static int sorcery_memory_cache_create(const struct ast_sorcery *sorcery, void *data, void *object)
const char * ast_sorcery_object_get_type(const void *object)
Get the type of a sorcery object.
Definition: sorcery.c:2324
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_debug(level,...)
Log a DEBUG message.
Definition: logger.h:452
#define ao2_ref(o, delta)
Definition: astobj2.h:464
const char * ast_sorcery_object_get_id(const void *object)
Get the unique identifier of a sorcery object.
Definition: sorcery.c:2312
#define ast_test_suite_event_notify(s, f,...)
Definition: test.h:196
userdata associated with baseline taskprocessor test
struct sorcery_memory_cache * cache
static void end_passthru_update(void)
char * name
The name of the memory cache.

◆ stale_update_task_data_alloc()

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

Definition at line 971 of file res_sorcery_memory_cache.c.

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

Referenced by memory_cache_stale_update_object().

973 {
975 
976  task_data = ao2_alloc_options(sizeof(*task_data), stale_update_task_data_destructor,
978  if (!task_data) {
979  return NULL;
980  }
981 
982  task_data->sorcery = ao2_bump(sorcery);
983  task_data->cache = ao2_bump(cache);
984  task_data->object = ao2_bump(object);
985 
986  return task_data;
987 }
#define ao2_alloc_options(data_size, destructor_fn, options)
Definition: astobj2.h:406
#define NULL
Definition: resample.c:96
#define ao2_bump(obj)
Definition: astobj2.h:491
userdata associated with baseline taskprocessor test
struct sorcery_memory_cache * cache
static void stale_update_task_data_destructor(void *obj)

◆ stale_update_task_data_destructor()

static void stale_update_task_data_destructor ( void *  obj)
static

Definition at line 962 of file res_sorcery_memory_cache.c.

References ao2_cleanup, ast_sorcery_unref, stale_update_task_data::cache, stale_update_task_data::object, and stale_update_task_data::sorcery.

Referenced by stale_update_task_data_alloc().

963 {
964  struct stale_update_task_data *task_data = obj;
965 
966  ao2_cleanup(task_data->cache);
967  ao2_cleanup(task_data->object);
968  ast_sorcery_unref(task_data->sorcery);
969 }
#define ast_sorcery_unref(sorcery)
Decrease the reference count of a sorcery structure.
Definition: sorcery.h:1502
userdata associated with baseline taskprocessor test
struct sorcery_memory_cache * cache
#define ao2_cleanup(obj)
Definition: astobj2.h:1958

◆ start_passthru_update()

static void start_passthru_update ( void  )
static

Definition at line 276 of file res_sorcery_memory_cache.c.

References PASSTHRU_UPDATE_THREAD_ID, and set_passthru_update().

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

277 {
279 }
#define PASSTHRU_UPDATE_THREAD_ID
static void set_passthru_update(uint32_t value)

◆ test_data_alloc()

static void* test_data_alloc ( const char *  id)
static

Allocation callback for test_data sorcery object.

Definition at line 2997 of file res_sorcery_memory_cache.c.

References ast_sorcery_generic_alloc(), and NULL.

Referenced by AST_TEST_DEFINE().

2997  {
2998  return ast_sorcery_generic_alloc(sizeof(struct test_data), NULL);
2999 }
#define NULL
Definition: resample.c:96
Sorcery object created based on backend data.
void * ast_sorcery_generic_alloc(size_t size, ao2_destructor_fn destructor)
Allocate a generic sorcery capable object.
Definition: sorcery.c:1728

◆ test_sorcery_object_alloc()

static void* test_sorcery_object_alloc ( const char *  id)
static

Definition at line 2288 of file res_sorcery_memory_cache.c.

References ast_sorcery_generic_alloc(), and NULL.

Referenced by alloc_and_initialize_sorcery().

2289 {
2290  return ast_sorcery_generic_alloc(sizeof(struct test_sorcery_object), NULL);
2291 }
Dummy sorcery object.
#define NULL
Definition: resample.c:96
void * ast_sorcery_generic_alloc(size_t size, ao2_destructor_fn destructor)
Allocate a generic sorcery capable object.
Definition: sorcery.c:1728

◆ unload_module()

static int unload_module ( void  )
static

Definition at line 3500 of file res_sorcery_memory_cache.c.

References ao2_cleanup, ARRAY_LEN, ast_cli_unregister_multiple(), ast_manager_unregister(), ast_sched_context_destroy(), ast_sorcery_wizard_unregister(), AST_TEST_UNREGISTER, sorcery_memory_cache::maximum_objects, NULL, and update().

Referenced by load_module().

3501 {
3502  AST_TEST_UNREGISTER(open_with_valid_options);
3503  AST_TEST_UNREGISTER(open_with_invalid_options);
3504  AST_TEST_UNREGISTER(create_and_retrieve);
3506  AST_TEST_UNREGISTER(delete);
3507  AST_TEST_UNREGISTER(maximum_objects);
3508  AST_TEST_UNREGISTER(expiration);
3509  AST_TEST_UNREGISTER(stale);
3510  AST_TEST_UNREGISTER(full_backend_cache_expiration);
3511  AST_TEST_UNREGISTER(full_backend_cache_stale);
3512 
3513  ast_manager_unregister("SorceryMemoryCacheExpireObject");
3514  ast_manager_unregister("SorceryMemoryCacheExpire");
3515  ast_manager_unregister("SorceryMemoryCacheStaleObject");
3516  ast_manager_unregister("SorceryMemoryCacheStale");
3517  ast_manager_unregister("SorceryMemoryCachePopulate");
3518 
3520 
3522 
3523  /*
3524  * XXX There is the potential to leak memory if there are pending
3525  * next-cache-expiration and stale-cache-update tasks in the scheduler.
3526  */
3527  if (sched) {
3529  sched = NULL;
3530  }
3531 
3533  caches = NULL;
3534 
3535  return 0;
3536 }
#define ARRAY_LEN(a)
Definition: isdn_lib.c:42
int ast_cli_unregister_multiple(struct ast_cli_entry *e, int len)
Unregister multiple commands.
Definition: clicompat.c:30
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
static struct ast_sorcery_wizard memory_cache_object_wizard
Definition: sched.c:76
#define NULL
Definition: resample.c:96
int ast_manager_unregister(const char *action)
Unregister a registered manager command.
Definition: manager.c:7258
static struct ao2_container * caches
Container of created caches.
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
static struct ast_cli_entry cli_memory_cache[]
#define ao2_cleanup(obj)
Definition: astobj2.h:1958
void ast_sched_context_destroy(struct ast_sched_context *c)
destroys a schedule context
Definition: sched.c:269

◆ wait_for_cache_update()

static int wait_for_cache_update ( const struct ast_sorcery sorcery,
void *  previous_object,
struct test_data **  new_object 
)
static

Wait for the cache to be updated after a stale object is retrieved.

Since the cache does not know what type of objects it is dealing with, and since we do not have the internals of the cache, the only way to make this determination is to continuously retrieve an object from the cache until we retrieve a different object than we had previously retrieved.

Parameters
sorceryThe sorcery instance
previous_objectThe object we had previously retrieved from the cache
[out]new_objectThe new object we retrieve from the cache
Return values
0Successfully retrieved a new object from the cache
non-zeroFailed to retrieve a new object from the cache

Definition at line 3099 of file res_sorcery_memory_cache.c.

References ao2_cleanup, ast_remaining_ms(), ast_sorcery_retrieve_by_id(), and ast_tvnow().

Referenced by AST_TEST_DEFINE().

3101 {
3102  struct timeval start = ast_tvnow();
3103 
3104  while (ast_remaining_ms(start, 5000) > 0) {
3105  void *object;
3106 
3107  object = ast_sorcery_retrieve_by_id(sorcery, "test", "test");
3108  if (object != previous_object) {
3109  *new_object = object;
3110  return 0;
3111  }
3112  ao2_cleanup(object);
3113  }
3114 
3115  return -1;
3116 }
struct timeval ast_tvnow(void)
Returns current timeval. Meant to replace calls to gettimeofday().
Definition: time.h:150
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
int ast_remaining_ms(struct timeval start, int max_ms)
Calculate remaining milliseconds given a starting timestamp and upper bound.
Definition: main/utils.c:2033
#define ao2_cleanup(obj)
Definition: astobj2.h:1958

Variable Documentation

◆ __mod_info

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

Definition at line 3603 of file res_sorcery_memory_cache.c.

◆ ast_module_info

const struct ast_module_info* ast_module_info = &__mod_info
static

Definition at line 3603 of file res_sorcery_memory_cache.c.

◆ caches

struct ao2_container* caches
static

Container of created caches.

Definition at line 241 of file res_sorcery_memory_cache.c.

◆ cli_memory_cache

struct ast_cli_entry cli_memory_cache[]
static

Definition at line 2057 of file res_sorcery_memory_cache.c.

◆ memory_cache_object_wizard

struct ast_sorcery_wizard memory_cache_object_wizard
static

Definition at line 215 of file res_sorcery_memory_cache.c.

◆ mock_wizard

struct ast_sorcery_wizard mock_wizard
static
Initial value:
= {
.name = "mock",
.retrieve_id = mock_retrieve_id,
.retrieve_multiple = mock_retrieve_multiple,
}
static void * mock_retrieve_id(const struct ast_sorcery *sorcery, void *data, const char *type, const char *id)
Callback for retrieving sorcery object by ID.
static void mock_retrieve_multiple(const struct ast_sorcery *sorcery, void *data, const char *type, struct ao2_container *objects, const struct ast_variable *fields)
Callback for retrieving multiple sorcery objects.

A mock sorcery wizard used for the stale test.

Definition at line 3078 of file res_sorcery_memory_cache.c.

◆ passthru_update_id_storage

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

Definition at line 247 of file res_sorcery_memory_cache.c.

Referenced by is_passthru_update(), and set_passthru_update().

◆ real_backend_data

struct backend_data * real_backend_data
static

◆ sched

struct ast_sched_context* sched
static

Scheduler for cache management.

Definition at line 244 of file res_sorcery_memory_cache.c.