173 unsigned int cache_notify;
179 unsigned int cache_completed;
233 .
name =
"memory_cache",
249#define CACHES_CONTAINER_BUCKET_SIZE 53
252#define CACHE_CONTAINER_BUCKET_SIZE 53
255#define CACHE_HEAP_INIT_HEIGHT 5
263#define PASSTHRU_UPDATE_THREAD_ID 0x5EED1E55
268 uint32_t *passthru_update_thread_id;
271 sizeof(*passthru_update_thread_id));
272 if (!passthru_update_thread_id) {
281 uint32_t *passthru_update_thread_id;
284 sizeof(*passthru_update_thread_id));
285 if (!passthru_update_thread_id) {
286 ast_log(
LOG_ERROR,
"Could not set passthru update ID for sorcery memory cache thread\n");
290 *passthru_update_thread_id =
value;
315 const char *
name = obj;
350 const char *right_name = arg;
356 right_name = right->
name;
359 cmp = strcmp(left->
name, right_name);
362 cmp = strncmp(left->
name, right_name, strlen(right_name));
380 const char *
name = obj;
415 const char *right_name = arg;
444 if (
cache->object_heap) {
503 if (reschedule && (oldest_object == heap_object)) {
529 if (
cache->del_expire) {
530 cache->expire_id = -1;
537 cache->expire_id = -1;
546 if (expiration > 0) {
580 cache->del_expire = 1;
582 cache->del_expire = 0;
671 if (!
cache->object_lifetime_maximum) {
675 cache->del_expire = 1;
677 cache->del_expire = 0;
683 cache->cache_completed = 1;
694 if (
cache->expire_id < 0) {
719 if (!heap_old_object) {
725 ast_assert(heap_old_object == hash_old_object);
766 if (
cache->expire_id == -1) {
798 if (
cache->full_backend_cache) {
843 ast_log(
LOG_ERROR,
"Unable to make room in cache for sorcery object '%s'.\n",
936 if (!backend_objects) {
937 task_data->cache->stale_update_sched_id = -1;
943 ast_log(
LOG_ERROR,
"The backend contains %d objects while the sorcery memory cache '%s' is explicitly configured to only allow %d\n",
945 task_data->cache->stale_update_sched_id = -1;
960 ast_log(
LOG_WARNING,
"The backend contains %d objects while only %d could be added to sorcery memory cache '%s'\n",
968 task_data->cache->stale_update_sched_id = -1;
1018 ast_debug(1,
"Backend no longer has object type '%s' ID '%s'. Removing from cache\n",
1024 ast_debug(1,
"Refreshing stale cache object type '%s' ID '%s'\n",
1063 if (!backend_objects) {
1069 ast_log(
LOG_ERROR,
"The backend contains %d objects while the sorcery memory cache '%s' is explicitly configured to only allow %d\n",
1083 ast_log(
LOG_WARNING,
"The backend contains %d objects while only %d could be added to sorcery memory cache '%s'\n",
1120 if (!backend_objects) {
1126 ast_log(
LOG_ERROR,
"The backend contains %d objects while the sorcery memory cache '%s' is explicitly configured to only allow %d\n",
1134 ast_log(
LOG_ERROR,
"Could not allocate vector for cached objects for sorcery memory cache '%s'\n",
1173 for (i = 0; i < num_cached; i++) {
1184 for (i = 0; i < num_cached; i++) {
1203 if (!
cache->full_backend_cache) {
1226 if (
cache->stale_update_sched_id == -1) {
1235 if (
cache->stale_update_sched_id < 0) {
1260 ast_debug(1,
"Cached sorcery object type '%s' ID '%s' is stale. Refreshing\n",
1267 ast_log(
LOG_ERROR,
"Unable to update stale cached object type '%s', ID '%s'.\n",
1285 struct timeval elapsed;
1287 if (!
cache->object_lifetime_stale) {
1294 if (elapsed.tv_sec <
cache->object_lifetime_stale) {
1298 if (
cache->full_backend_cache) {
1384 if (params->
regex) {
1390 }
else if (params->
prefix) {
1395 }
else if (params->
fields &&
1433 void *
object =
NULL;
1468 .container = objects,
1501 .container = objects,
1502 .regex = &expression,
1511 regfree(&expression);
1535 .container = objects,
1570 ast_debug(1,
"Memory cache '%s' associated with sorcery instance '%p' of module '%s' with object type '%s'\n",
1589 if (!
cache->expire_on_reload) {
1642 cache->expire_id = -1;
1643 cache->stale_update_sched_id = -1;
1651 if (!strcasecmp(
name,
"name")) {
1658 }
else if (!strcasecmp(
name,
"maximum_objects")) {
1660 ast_log(
LOG_ERROR,
"Unsupported maximum objects value of '%s' used for memory cache\n",
1664 }
else if (!strcasecmp(
name,
"object_lifetime_maximum")) {
1666 ast_log(
LOG_ERROR,
"Unsupported object maximum lifetime value of '%s' used for memory cache\n",
1670 }
else if (!strcasecmp(
name,
"object_lifetime_stale")) {
1672 ast_log(
LOG_ERROR,
"Unsupported object stale lifetime value of '%s' used for memory cache\n",
1676 }
else if (!strcasecmp(
name,
"expire_on_reload")) {
1678 }
else if (!strcasecmp(
name,
"full_backend_cache")) {
1689 if (!
cache->objects) {
1690 ast_log(
LOG_ERROR,
"Could not create a container to hold cached objects for memory cache\n");
1696 if (!
cache->object_heap) {
1758 if (
cache->object_lifetime_maximum) {
1768 if (
cache->full_backend_cache) {
1785 int wordlen = strlen(
word);
1791 if (!strncasecmp(
word,
cache->name, wordlen)
1792 && ++which >
state) {
1814 e->
command =
"sorcery memory cache show";
1816 "Usage: sorcery memory cache show <name>\n"
1817 " Show sorcery memory cache configuration and statistics.\n";
1833 ast_cli(
a->fd,
"Specified sorcery memory cache '%s' does not exist\n",
a->argv[4]);
1839 if (
cache->maximum_objects) {
1840 ast_cli(
a->fd,
"Maximum allowed objects: %d\n",
cache->maximum_objects);
1842 ast_cli(
a->fd,
"There is no limit on the maximum number of objects in the cache\n");
1844 if (
cache->object_lifetime_maximum) {
1845 ast_cli(
a->fd,
"Number of seconds before object expires: %d\n",
cache->object_lifetime_maximum);
1847 ast_cli(
a->fd,
"Object expiration is not enabled - cached objects will not expire\n");
1849 if (
cache->object_lifetime_stale) {
1850 ast_cli(
a->fd,
"Number of seconds before object becomes stale: %d\n",
cache->object_lifetime_stale);
1852 ast_cli(
a->fd,
"Object staleness is not enabled - cached objects will not go stale\n");
1875#define FORMAT "%-25.25s %-15u %-15u \n"
1878 int seconds_until_expire = 0, seconds_until_stale = 0;
1899#define FORMAT "%-25.25s %-15.15s %-15.15s \n"
1905 e->
command =
"sorcery memory cache dump";
1907 "Usage: sorcery memory cache dump <name>\n"
1908 " Dump a list of the objects within the cache, listed by object identifier.\n";
1924 ast_cli(
a->fd,
"Specified sorcery memory cache '%s' does not exist\n",
a->argv[4]);
1931 ast_cli(
a->fd,
"Dumping sorcery memory cache '%s':\n",
cache->name);
1932 if (!
cache->object_lifetime_stale) {
1933 ast_cli(
a->fd,
" * Staleness is not enabled - objects will not go stale\n");
1935 if (!
cache->object_lifetime_maximum) {
1936 ast_cli(
a->fd,
" * Object lifetime is not enabled - objects will not expire\n");
1939 ast_cli(
a->fd,
FORMAT,
"-------------------------",
"---------------",
"---------------");
1941 ast_cli(
a->fd,
FORMAT,
"-------------------------",
"---------------",
"---------------");
1959 int wordlen = strlen(
word);
1971 && ++which >
state) {
1996 e->
command =
"sorcery memory cache expire";
1998 "Usage: sorcery memory cache expire <cache name> [object name]\n"
1999 " Expire a specific object or ALL objects within a sorcery memory cache.\n";
2004 }
else if (
a->pos == 5) {
2011 if (
a->argc < 5 ||
a->argc > 6) {
2017 ast_cli(
a->fd,
"Specified sorcery memory cache '%s' does not exist\n",
a->argv[4]);
2024 ast_cli(
a->fd,
"All objects have been removed from cache '%s'\n",
a->argv[4]);
2026 if (
cache->full_backend_cache) {
2027 ast_cli(
a->fd,
"Due to full backend caching per-object expiration is not available on cache '%s'\n",
a->argv[4]);
2029 ast_cli(
a->fd,
"Successfully expired object '%s' from cache '%s'\n",
a->argv[5],
a->argv[4]);
2031 ast_cli(
a->fd,
"Object '%s' was not expired from cache '%s' as it was not found\n",
a->argv[5],
2053 e->
command =
"sorcery memory cache stale";
2055 "Usage: sorcery memory cache stale <cache name> [object name [reload]]\n"
2056 " Mark a specific object or ALL objects as stale in a sorcery memory cache.\n"
2057 " If \"reload\" is specified, then the object is marked stale and immediately\n"
2058 " retrieved from backend storage to repopulate the cache\n";
2063 }
else if (
a->pos == 5) {
2065 }
else if (
a->pos == 6) {
2066 static const char *
const completions[] = {
"reload",
NULL };
2073 if (
a->argc < 5 ||
a->argc > 7) {
2078 if (!strcasecmp(
a->argv[6],
"reload")) {
2087 ast_cli(
a->fd,
"Specified sorcery memory cache '%s' does not exist\n",
a->argv[4]);
2091 if (!
cache->object_lifetime_stale) {
2092 ast_cli(
a->fd,
"Specified sorcery memory cache '%s' does not have staleness enabled\n",
a->argv[4]);
2100 ast_cli(
a->fd,
"Marked all objects in sorcery memory cache '%s' as stale\n",
a->argv[4]);
2103 ast_cli(
a->fd,
"Successfully marked object '%s' in memory cache '%s' as stale\n",
2104 a->argv[5],
a->argv[4]);
2115 ast_cli(
a->fd,
"Object '%s' in sorcery memory cache '%s' could not be marked as stale as it was not found\n",
2116 a->argv[5],
a->argv[4]);
2134 const char *object_type;
2139 e->
command =
"sorcery memory cache populate";
2141 "Usage: sorcery memory cache populate <cache name>\n"
2142 " Expire all objects in the cache and populate it with ALL objects from backend.\n";
2158 ast_cli(
a->fd,
"Specified sorcery memory cache '%s' does not exist\n",
a->argv[4]);
2162 if (!
cache->full_backend_cache) {
2163 ast_cli(
a->fd,
"Specified sorcery memory cache '%s' does not have full backend caching enabled\n",
a->argv[4]);
2173 if (!
cache->sorcery) {
2174 ast_cli(
a->fd,
"Specified sorcery memory cache '%s' is no longer active\n",
a->argv[4]);
2183 object_type =
cache->object_type;
2193 if (num_cached < 0) {
2194 ast_cli(
a->fd,
"An error occurred while populating sorcery memory cache '%s'\n",
a->argv[4]);
2196 ast_cli(
a->fd,
"Specified sorcery memory cache '%s' has been populated with '%d' objects from the backend\n",
2197 a->argv[4], num_cached);
2223 astman_send_error(s, m,
"SorceryMemoryCacheExpireObject requires that a cache name be provided.\n");
2226 astman_send_error(s, m,
"SorceryMemoryCacheExpireObject requires that an object name be provided\n");
2237 if (
cache->full_backend_cache) {
2247 astman_send_error(s, m,
"Due to full backend caching per-object expiration is not available, consider using SorceryMemoryCachePopulate or SorceryMemoryCacheExpire instead\n");
2249 astman_send_ack(s, m,
"The provided object was expired from the cache\n");
2251 astman_send_error(s, m,
"The provided object could not be expired from the cache\n");
2267 astman_send_error(s, m,
"SorceryMemoryCacheExpire requires that a cache name be provided.\n");
2301 astman_send_error(s, m,
"SorceryMemoryCacheStaleObject requires that a cache name be provided.\n");
2304 astman_send_error(s, m,
"SorceryMemoryCacheStaleObject requires that an object name be provided\n");
2333 astman_send_ack(s, m,
"The provided object was marked as stale in the cache\n");
2335 astman_send_error(s, m,
"The provided object could not be marked as stale in the cache\n");
2351 astman_send_error(s, m,
"SorceryMemoryCacheStale requires that a cache name be provided.\n");
2367 astman_send_ack(s, m,
"All objects were marked as stale in the cache\n");
2381 const char *object_type;
2382 int cache_population_result;
2385 astman_send_error(s, m,
"SorceryMemoryCachePopulate requires that a cache name be provided.\n");
2395 if (!
cache->full_backend_cache) {
2396 astman_send_error(s, m,
"The provided cache does not have full backend caching enabled\n");
2406 if (!
cache->sorcery) {
2416 object_type =
cache->object_type;
2426 if (cache_population_result < 0) {
2435#ifdef TEST_FRAMEWORK
2487 info->name =
"open_with_valid_options";
2488 info->category =
"/res/res_sorcery_memory_cache/";
2489 info->summary =
"Attempt to create sorcery memory caches using valid options";
2490 info->description =
"This test performs the following:\n"
2491 "\t* Creates a memory cache with default configuration\n"
2492 "\t* Creates a memory cache with a maximum object count of 10 and verifies it\n"
2493 "\t* Creates a memory cache with a maximum object lifetime of 60 and verifies it\n"
2494 "\t* Creates a memory cache with a stale object lifetime of 90 and verifies it";
2513 if (
cache->maximum_objects != 10) {
2515 cache->maximum_objects);
2525 if (
cache->object_lifetime_maximum != 60) {
2527 cache->object_lifetime_maximum);
2537 if (
cache->object_lifetime_stale != 90) {
2539 cache->object_lifetime_stale);
2555 info->name =
"open_with_invalid_options";
2556 info->category =
"/res/res_sorcery_memory_cache/";
2557 info->summary =
"Attempt to create sorcery memory caches using invalid options";
2558 info->description =
"This test attempts to perform the following:\n"
2559 "\t* Create a memory cache with an empty name\n"
2560 "\t* Create a memory cache with a maximum object count of -1\n"
2561 "\t* Create a memory cache with a maximum object count of toast\n"
2562 "\t* Create a memory cache with a maximum object lifetime of -1\n"
2563 "\t* Create a memory cache with a maximum object lifetime of toast\n"
2564 "\t* Create a memory cache with a stale object lifetime of -1\n"
2565 "\t* Create a memory cache with a stale object lifetime of toast";
2640 info->name =
"create";
2641 info->category =
"/res/res_sorcery_memory_cache/";
2642 info->summary =
"Attempt to create an object in the cache";
2643 info->description =
"This test performs the following:\n"
2644 "\t* Creates a memory cache with default options\n"
2645 "\t* Creates a sorcery instance with a test object\n"
2646 "\t* Creates a test object with an id of test\n"
2647 "\t* Pushes the test object into the memory cache\n"
2648 "\t* Confirms that the test object is in the cache";
2685 if (!cached_object) {
2690 if (cached_object !=
object) {
2719 info->name =
"create";
2720 info->category =
"/res/res_sorcery_memory_cache/";
2721 info->summary =
"Attempt to create and then update an object in the cache";
2722 info->description =
"This test performs the following:\n"
2723 "\t* Creates a memory cache with default options\n"
2724 "\t* Creates a sorcery instance with a test object\n"
2725 "\t* Creates a test object with an id of test\n"
2726 "\t* Pushes the test object into the memory cache\n"
2727 "\t* Confirms that the test object is in the cache\n"
2728 "\t* Creates a new test object with the same id of test\n"
2729 "\t* Pushes the new test object into the memory cache\n"
2730 "\t* Confirms that the new test object has replaced the old one";
2754 if (!original_object) {
2762 if (!updated_object) {
2776 if (!cached_object) {
2781 if (cached_object == original_object) {
2784 }
else if (cached_object != updated_object) {
2812 info->name =
"delete";
2813 info->category =
"/res/res_sorcery_memory_cache/";
2814 info->summary =
"Attempt to create and then delete an object in the cache";
2815 info->description =
"This test performs the following:\n"
2816 "\t* Creates a memory cache with default options\n"
2817 "\t* Creates a sorcery instance with a test object\n"
2818 "\t* Creates a test object with an id of test\n"
2819 "\t* Pushes the test object into the memory cache\n"
2820 "\t* Confirms that the test object is in the cache\n"
2821 "\t* Deletes the test object from the cache\n"
2822 "\t* Confirms that the test object is no longer in the cache";
2859 if (!cached_object) {
2865 cached_object =
NULL;
2870 if (cached_object) {
2889 const char **in_cache,
size_t num_in_cache,
const char **not_in_cache,
size_t num_not_in_cache)
2895 for (i = 0; i < num_in_cache; ++i) {
2897 if (!cached_object) {
2905 for (i = 0; i < num_not_in_cache; ++i) {
2907 if (cached_object) {
2927 const char *in_cache[2];
2928 const char *not_in_cache[2];
2932 info->name =
"maximum_objects";
2933 info->category =
"/res/res_sorcery_memory_cache/";
2934 info->summary =
"Ensure that the 'maximum_objects' option works as expected";
2935 info->description =
"This test performs the following:\n"
2936 "\t* Creates a memory cache with maximum_objects=2\n"
2937 "\t* Creates a sorcery instance\n"
2938 "\t* Creates a three test objects: alice, bob, charlie, and david\n"
2939 "\t* Pushes alice and bob into the memory cache\n"
2940 "\t* Confirms that alice and bob are in the memory cache\n"
2941 "\t* Pushes charlie into the memory cache\n"
2942 "\t* Confirms that bob and charlie are in the memory cache\n"
2943 "\t* Deletes charlie from the memory cache\n"
2944 "\t* Confirms that only bob is in the memory cache\n"
2945 "\t* Pushes alice into the memory cache\n"
2946 "\t* Confirms that bob and alice are in the memory cache";
2973 if (!alice || !bob || !charlie) {
2979 in_cache[0] =
"alice";
2981 not_in_cache[0] =
"bob";
2982 not_in_cache[1] =
"charlie";
2983 if (check_cache_content(
test,
sorcery,
cache, in_cache, 1, not_in_cache, 2)) {
2993 in_cache[0] =
"alice";
2994 in_cache[1] =
"bob";
2995 not_in_cache[0] =
"charlie";
2996 not_in_cache[1] =
NULL;
2997 if (check_cache_content(
test,
sorcery,
cache, in_cache, 2, not_in_cache, 1)) {
3004 in_cache[0] =
"bob";
3005 in_cache[1] =
"charlie";
3006 not_in_cache[0] =
"alice";
3007 not_in_cache[1] =
NULL;
3008 if (check_cache_content(
test,
sorcery,
cache, in_cache, 2, not_in_cache, 1)) {
3014 in_cache[0] =
"bob";
3016 not_in_cache[0] =
"alice";
3017 not_in_cache[1] =
"charlie";
3018 if (check_cache_content(
test,
sorcery,
cache, in_cache, 1, not_in_cache, 2)) {
3024 in_cache[0] =
"bob";
3025 in_cache[1] =
"alice";
3026 not_in_cache[0] =
"charlie";
3027 not_in_cache[1] =
NULL;
3028 if (check_cache_content(
test,
sorcery,
cache, in_cache, 2, not_in_cache, 1)) {
3054 info->name =
"expiration";
3055 info->category =
"/res/res_sorcery_memory_cache/";
3056 info->summary =
"Add objects to a cache configured with maximum lifetime, confirm they are removed";
3057 info->description =
"This test performs the following:\n"
3058 "\t* Creates a memory cache with a maximum object lifetime of 5 seconds\n"
3059 "\t* Pushes 10 objects into the memory cache\n"
3060 "\t* Waits (up to) 10 seconds for expiration to occur\n"
3061 "\t* Confirms that the objects have been removed from the cache";
3079 cache->cache_notify = 1;
3083 for (i = 0; i < 5; ++i) {
3099 while (!
cache->cache_completed) {
3101 struct timespec
end = {
3102 .tv_sec = start.tv_sec + 10,
3103 .tv_nsec = start.tv_usec * 1000,
3121 if (
cache->cache_notify) {
3137static struct backend_data {
3144} *real_backend_data;
3181 const char *
type,
const char *
id)
3185 if (!real_backend_data->exists) {
3194 b_data->salt = real_backend_data->salt;
3195 b_data->pepper = real_backend_data->pepper;
3221 for (i = 0; i < real_backend_data->exists; ++i) {
3230 b_data->salt = real_backend_data->salt;
3231 b_data->pepper = real_backend_data->pepper;
3244 .retrieve_multiple = mock_retrieve_multiple,
3263 void *previous_object,
struct test_data **new_object)
3271 if (
object != previous_object) {
3272 *new_object = object;
3286 struct backend_data iterations[] = {
3287 { .salt = 1, .pepper = 2, .exists = 1 },
3288 { .salt = 568729, .pepper = -234123, .exists = 1 },
3289 { .salt = 0, .pepper = 0, .exists = 0 },
3291 struct backend_data initial = {
3300 info->name =
"stale";
3301 info->category =
"/res/res_sorcery_memory_cache/";
3302 info->summary =
"Ensure that stale objects are replaced with updated objects";
3303 info->description =
"This test performs the following:\n"
3304 "\t* Create a sorcery instance with two wizards"
3305 "\t\t* The first is a memory cache that marks items stale after 3 seconds\n"
3306 "\t\t* The second is a mock of a back-end\n"
3307 "\t* Pre-populates the cache by retrieving some initial data from the backend.\n"
3308 "\t* Performs iterations of the following:\n"
3309 "\t\t* Update backend data with new values\n"
3310 "\t\t* Retrieve item from the cache\n"
3311 "\t\t* Ensure the retrieved item does not have the new backend values\n"
3312 "\t\t* Wait for cached object to become stale\n"
3313 "\t\t* Retrieve the stale cached object\n"
3314 "\t\t* Ensure that the stale object retrieved is the same as the fresh one from earlier\n"
3315 "\t\t* Wait for the cache to update with new data\n"
3316 "\t\t* Ensure that new data in the cache matches backend data";
3331 "object_lifetime_stale=3", 1);
3336 real_backend_data = &initial;
3339 if (!backend_object) {
3345 for (i = 0; i <
ARRAY_LEN(iterations); ++i) {
3350 real_backend_data = &iterations[i];
3360 if (cache_fresh->salt == iterations[i].salt || cache_fresh->pepper == iterations[i].pepper) {
3373 if (cache_stale != cache_fresh) {
3378 if (wait_for_cache_update(
sorcery, cache_stale, &cache_new)) {
3383 if (iterations[i].
exists) {
3387 }
else if (cache_new->salt != iterations[i].salt ||
3388 cache_new->pepper != iterations[i].pepper) {
3392 }
else if (cache_new) {
3412 struct backend_data initial = {
3420 struct timeval start;
3421 struct timespec
end;
3425 info->name =
"full_backend_cache_expiration";
3426 info->category =
"/res/res_sorcery_memory_cache/";
3427 info->summary =
"Ensure that the full backend cache actually caches the backend";
3428 info->description =
"This test performs the following:\n"
3429 "\t* Create a sorcery instance with two wizards"
3430 "\t\t* The first is a memory cache that expires objects after 3 seconds and does full backend caching\n"
3431 "\t\t* The second is a mock of a back-end\n"
3432 "\t* Populates the cache by requesting all objects which returns 4.\n"
3433 "\t* Updates the backend to contain a different number of objects, 8.\n"
3434 "\t* Requests all objects and confirms the number returned is only 4.\n"
3435 "\t* Wait for cached objects to expire.\n"
3436 "\t* Requests all objects and confirms the number returned is 8.";
3451 "object_lifetime_maximum=3,full_backend_cache=yes", 1);
3458 real_backend_data = &initial;
3490 end.tv_sec = start.tv_sec + 5;
3491 end.tv_nsec = start.tv_usec * 1000;
3530 struct backend_data initial = {
3538 struct timeval start;
3539 struct timespec
end;
3543 info->name =
"full_backend_cache_stale";
3544 info->category =
"/res/res_sorcery_memory_cache/";
3545 info->summary =
"Ensure that the full backend cache works with staleness";
3546 info->description =
"This test performs the following:\n"
3547 "\t* Create a sorcery instance with two wizards"
3548 "\t\t* The first is a memory cache that stales objects after 1 second and does full backend caching\n"
3549 "\t\t* The second is a mock of a back-end\n"
3550 "\t* Populates the cache by requesting all objects which returns 4.\n"
3551 "\t* Wait for objects to go stale.\n"
3552 "\t* Updates the backend to contain a different number of objects, 8.\""
3553 "\t* Requests all objects and confirms the number returned is only 4.\n"
3554 "\t* Wait for objects to be refreshed from backend.\n"
3555 "\t* Requests all objects and confirms the number returned is 8.";
3573 "object_lifetime_stale=1,full_backend_cache=yes", 1);
3580 real_backend_data = &initial;
3591 end.tv_sec = start.tv_sec + 5;
3592 end.tv_nsec = start.tv_usec * 1000;
3617 end.tv_sec = start.tv_sec + 5;
3618 end.tv_nsec = start.tv_usec * 1000;
3641 end.tv_sec = start.tv_sec + 5;
3642 end.tv_nsec = start.tv_usec * 1000;
3722 ast_log(
LOG_ERROR,
"Failed to create scheduler thread for cache management\n");
void ast_cli_unregister_multiple(void)
char * strsep(char **str, const char *delims)
Asterisk main include file. File version handling, generic pbx functions.
#define ast_strdup(str)
A wrapper for strdup()
#define ast_strdupa(s)
duplicate a string in memory from the stack
#define ast_asprintf(ret, fmt,...)
A wrapper for asprintf()
#define ao2_iterator_next(iter)
#define ao2_link(container, obj)
Add an object to a container.
@ AO2_ALLOC_OPT_LOCK_NOLOCK
@ AO2_ALLOC_OPT_LOCK_RWLOCK
@ AO2_ALLOC_OPT_LOCK_MUTEX
#define ao2_callback(c, flags, cb_fn, arg)
ao2_callback() is a generic function that applies cb_fn() to all objects in a container,...
int ao2_container_count(struct ao2_container *c)
Returns the number of elements in a container.
#define ao2_callback_data(container, flags, cb_fn, arg, data)
#define ao2_unlink(container, obj)
Remove an object from a container.
#define ao2_link_flags(container, obj, flags)
Add an object to a container.
#define ao2_find(container, arg, flags)
struct ao2_iterator ao2_iterator_init(struct ao2_container *c, int flags) attribute_warn_unused_result
Create an iterator for a container.
#define ao2_ref(o, delta)
Reference/unreference an object and return the old refcount.
#define ao2_alloc_options(data_size, destructor_fn, options)
#define ao2_bump(obj)
Bump refcount on an AO2 object by one, returning the object.
void ao2_iterator_destroy(struct ao2_iterator *iter)
Destroy a container iterator.
@ OBJ_SEARCH_PARTIAL_KEY
The arg parameter is a partial search key similar to OBJ_SEARCH_KEY.
@ OBJ_SEARCH_OBJECT
The arg parameter is an object of the same type.
@ OBJ_NOLOCK
Assume that the ao2_container is already locked.
@ OBJ_SEARCH_MASK
Search option field mask.
@ OBJ_SEARCH_KEY
The arg parameter is a search key, but is not an object.
#define ao2_alloc(data_size, destructor_fn)
#define ao2_container_alloc_hash(ao2_options, container_options, n_buckets, hash_fn, sort_fn, cmp_fn)
Allocate and initialize a hash container with the desired number of buckets.
static struct ast_sorcery * sorcery
Standard Command Line Interface.
#define AST_CLI_DEFINE(fn, txt,...)
void ast_cli(int fd, const char *fmt,...)
char * ast_cli_complete(const char *word, const char *const choices[], int pos)
#define AST_CLI_ONOFF(x)
return On or Off depending on the argument. This is used in many places in CLI command,...
#define ast_cli_register_multiple(e, len)
Register multiple commands.
static void update(int code_size, int y, int wi, int fi, int dq, int sr, int dqsez, struct g726_state *state_ptr)
#define FLDSET(type,...)
Convert a struct and list of fields to an argument list of field offsets.
@ OPT_UINT_T
Type for default option handler for unsigned integers.
static int exists(struct ast_channel *chan, const char *cmd, char *data, char *buf, size_t len)
static int regex(struct ast_channel *chan, const char *cmd, char *parse, char *buf, size_t len)
static int uuid(struct ast_channel *chan, const char *cmd, char *data, char *buf, size_t len)
void astman_send_error(struct mansession *s, const struct message *m, char *error)
Send error in manager transaction.
void astman_send_ack(struct mansession *s, const struct message *m, char *msg)
Send ack in manager transaction.
const char * astman_get_header(const struct message *m, char *var)
Get header from manager transaction.
int ast_manager_unregister(const char *action)
Unregister a registered manager command.
struct ast_heap * ast_heap_destroy(struct ast_heap *h)
Destroy a max heap.
#define ast_heap_create(init_height, cmp_fn, index_offset)
Create a max heap.
void * ast_heap_pop(struct ast_heap *h)
Pop the max element off of the heap.
void * ast_heap_remove(struct ast_heap *h, void *elm)
Remove a specific element from a heap.
#define ast_heap_push(h, elm)
Push an element on to a heap.
void * ast_heap_peek(struct ast_heap *h, unsigned int index)
Peek at an element on a heap.
static char prefix[MAX_PREFIX]
int ast_variable_lists_match(const struct ast_variable *left, const struct ast_variable *right, int exact_match)
Tests 2 variable lists to see if they match.
void ast_variables_destroy(struct ast_variable *var)
Free variable list.
#define ast_debug(level,...)
Log a DEBUG message.
#define ast_cond_destroy(cond)
#define ast_cond_init(cond, attr)
#define ast_cond_timedwait(cond, mutex, time)
#define ast_mutex_init(pmutex)
#define ast_mutex_unlock(a)
pthread_cond_t ast_cond_t
#define ast_mutex_destroy(a)
#define ast_mutex_lock(a)
#define ast_cond_signal(cond)
The AMI - Asterisk Manager Interface - is a TCP protocol created to manage Asterisk with third-party ...
#define EVENT_FLAG_SYSTEM
#define ast_manager_register_xml(action, authority, func)
Register a manager callback using XML documentation to describe the manager.
Asterisk module definitions.
@ AST_MODFLAG_GLOBAL_SYMBOLS
#define AST_MODULE_INFO(keystr, flags_to_set, desc, fields...)
@ AST_MODPRI_REALTIME_DRIVER
@ AST_MODULE_SUPPORT_CORE
#define ASTERISK_GPL_KEY
The text the key() function should return.
@ AST_MODULE_LOAD_SUCCESS
@ AST_MODULE_LOAD_DECLINE
Module has failed to load, may be in an inconsistent state.
struct ao2_container * cache
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 char * sorcery_memory_cache_dump(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
static int object_stale_callback(void *obj, void *arg, int flags)
static int stale_item_update(const void *data)
static int sorcery_memory_cache_ami_stale_object(struct mansession *s, const struct message *m)
static void * sorcery_memory_cache_retrieve_id(const struct ast_sorcery *sorcery, void *data, const char *type, const char *id)
static char * sorcery_memory_cache_stale(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
static void stale_cache_update_task_data_destructor(void *obj)
static char * sorcery_memory_cache_show(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
#define PASSTHRU_UPDATE_THREAD_ID
static int configuration_parse_unsigned_integer(const char *value, unsigned int *result)
static int sorcery_memory_cache_print_object(void *obj, void *arg, int flags)
#define CACHES_CONTAINER_BUCKET_SIZE
The bucket size for the container of caches.
static struct ast_sched_context * sched
Scheduler for cache management.
static int sorcery_memory_cached_object_cmp(void *obj, void *arg, int flags)
static void sorcery_memory_cache_destructor(void *obj)
static void end_passthru_update(void)
static int sorcery_memory_cache_ami_stale(struct mansession *s, const struct message *m)
static void set_passthru_update(uint32_t value)
#define CACHE_HEAP_INIT_HEIGHT
Height of heap for cache object heap. Allows 31 initial objects.
static void sorcery_memory_cache_retrieve_regex(const struct ast_sorcery *sorcery, void *data, const char *type, struct ao2_container *objects, const char *regex)
static void * sorcery_memory_cache_retrieve_fields(const struct ast_sorcery *sorcery, void *data, const char *type, const struct ast_variable *fields)
static char * sorcery_memory_cache_complete_object_name(const char *cache_name, const char *word, int state)
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)
static void stale_update_task_data_destructor(void *obj)
static int remove_from_cache(struct sorcery_memory_cache *cache, const char *id, int reschedule)
static struct ast_cli_entry cli_memory_cache[]
static void sorcery_memory_cache_reload(void *data, const struct ast_sorcery *sorcery, const char *type)
static int sorcery_memory_cache_cmp(void *obj, void *arg, int flags)
static void sorcery_memory_cache_load(void *data, const struct ast_sorcery *sorcery, const char *type)
static int sorcery_memory_cache_hash(const void *obj, int flags)
static void * sorcery_memory_cache_open(const char *data)
static int sorcery_memory_cache_create(const struct ast_sorcery *sorcery, void *data, void *object)
static int sorcery_memory_cache_ami_expire(struct mansession *s, const struct message *m)
static struct ast_sorcery_wizard memory_cache_object_wizard
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 void start_passthru_update(void)
static int expire_objects_from_cache(const void *data)
static struct sorcery_memory_cached_object * sorcery_memory_cached_object_alloc(const struct ast_sorcery *sorcery, const struct sorcery_memory_cache *cache, void *object)
static int sorcery_memory_cache_delete(const struct ast_sorcery *sorcery, void *data, void *object)
static void memory_cache_full_update(const struct ast_sorcery *sorcery, const char *type, struct sorcery_memory_cache *cache)
static int is_passthru_update(void)
static int age_cmp(void *a, void *b)
#define CACHE_CONTAINER_BUCKET_SIZE
The default bucket size for the container of objects in the cache.
static int sorcery_memory_cached_object_hash(const void *obj, int flags)
static void sorcery_memory_cache_close(void *data)
static int memory_cache_populate_external(const struct ast_sorcery *sorcery, const char *type, struct sorcery_memory_cache *cache)
static int sorcery_memory_cache_ami_populate(struct mansession *s, const struct message *m)
static char * sorcery_memory_cache_expire(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
static int object_add_to_cache_callback(void *obj, void *arg, void *data, int flags)
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 remove_all_from_cache(struct sorcery_memory_cache *cache)
static int stale_cache_update(const void *data)
static void mark_all_as_stale_in_cache(struct sorcery_memory_cache *cache)
static void memory_cache_stale_check(const struct ast_sorcery *sorcery, struct sorcery_memory_cache *cache)
static int remove_oldest_from_cache(struct sorcery_memory_cache *cache)
static int load_module(void)
static void memory_cache_stale_update_full(const struct ast_sorcery *sorcery, struct sorcery_memory_cache *cache, const char *type)
static int schedule_cache_expiration(struct sorcery_memory_cache *cache)
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 int unload_module(void)
static int add_to_cache(struct sorcery_memory_cache *cache, struct sorcery_memory_cached_object *cached_object)
static char * sorcery_memory_cache_complete_name(const char *word, int state)
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 memory_cache_populate_internal(const struct ast_sorcery *sorcery, const char *type, struct sorcery_memory_cache *cache)
static char * sorcery_memory_cache_populate(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
static struct ao2_container * caches
Container of created caches.
static int sorcery_memory_cache_ami_expire_object(struct mansession *s, const struct message *m)
static int mark_object_as_stale_in_cache(struct sorcery_memory_cache *cache, const char *id)
static void sorcery_memory_cached_object_destructor(void *obj)
static void cleanup(void)
Clean up any old apps that we don't need any more.
Scheduler Routines (derived from cheops)
#define AST_SCHED_DEL_UNREF(sched, id, refcall)
schedule task to get deleted and call unref function
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.
void ast_sched_context_destroy(struct ast_sched_context *c)
destroys a schedule context
int ast_sched_start_thread(struct ast_sched_context *con)
Start a thread for processing scheduler entries.
struct ast_sched_context * ast_sched_context_create(void)
Create a scheduler context.
Sorcery Data Access Layer API.
#define ast_sorcery_apply_wizard_mapping(sorcery, type, name, data, caching)
Apply additional object wizard mappings.
#define ast_sorcery_unref(sorcery)
Decrease the reference count of a sorcery structure.
const char * ast_sorcery_object_get_id(const void *object)
Get the unique identifier of a sorcery object.
#define ast_sorcery_object_field_register_nodoc(sorcery, type, name, default_val, opt_type, flags,...)
Register a field within an object without documentation.
int ast_sorcery_wizard_unregister(const struct ast_sorcery_wizard *interface)
Unregister a sorcery wizard.
#define ast_sorcery_objectset_create(sorcery, object)
Create an object set (KVP list) for an object.
#define SORCERY_OBJECT(details)
Macro which must be used at the beginning of each sorcery capable object.
@ AST_RETRIEVE_FLAG_MULTIPLE
Return all matching objects.
@ AST_RETRIEVE_FLAG_ALL
Perform no matching, return all objects.
const char * ast_sorcery_get_module(const struct ast_sorcery *sorcery)
Get the module that has opened the provided sorcery instance.
const char * ast_sorcery_object_get_type(const void *object)
Get the type of a sorcery object.
void * ast_sorcery_retrieve_by_id(const struct ast_sorcery *sorcery, const char *type, const char *id)
Retrieve an object using its unique identifier.
#define ast_sorcery_internal_object_register(sorcery, type, alloc, transform, apply)
Register an internal, hidden object type.
void * ast_sorcery_generic_alloc(size_t size, ao2_destructor_fn destructor)
Allocate a generic sorcery capable object.
#define ast_sorcery_wizard_register(interface)
See __ast_sorcery_wizard_register()
void * ast_sorcery_alloc(const struct ast_sorcery *sorcery, const char *type, const char *id)
Allocate an object.
#define ast_sorcery_apply_default(sorcery, type, name, data)
#define ast_sorcery_open()
Open a new sorcery structure.
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.
@ AST_SORCERY_APPLY_SUCCESS
static force_inline int attribute_pure ast_str_hash(const char *str)
Compute a hash value on a string.
int attribute_pure ast_true(const char *val)
Make sure something is true. Determine if a string containing a boolean value is "true"....
static force_inline int attribute_pure ast_strlen_zero(const char *s)
When we need to walk through a container, we use an ao2_iterator to keep track of the current positio...
descriptor for a cli entry.
Structure for mutex and tracking information.
Interface for a sorcery wizard.
const char * name
Name of the wizard.
Full structure for sorcery.
Structure for variables, used for configurations and for channel variables.
In case you didn't read that giant block of text above the mansession_session struct,...
Structure used to pass data for printing cached object information.
struct sorcery_memory_cache * cache
The sorcery memory cache.
struct ast_cli_args * a
The CLI arguments.
Structure used for fields comparison.
const char * prefix
Prefix for matching object id.
struct ao2_container * container
Optional container to put object into.
struct sorcery_memory_cache * cache
The sorcery memory cache.
const size_t prefix_len
Prefix length in bytes for matching object id.
const struct ast_sorcery * sorcery
Pointer to the sorcery structure.
const struct ast_variable * fields
Pointer to the fields to check.
regex_t * regex
Regular expression for checking object id.
Structure for storing a memory cache.
ast_mutex_t populate_lock
Lock to serialize full cache population operations.
int stale_update_sched_id
scheduler id of stale update task
char * name
The name of the memory cache.
unsigned int maximum_objects
The maximum number of objects permitted in the cache, 0 if no limit.
unsigned int expire_on_reload
Whether all objects are expired when the object type is reloaded, 0 if disabled.
unsigned int object_lifetime_maximum
The maximum time (in seconds) an object will stay in the cache, 0 if no limit.
unsigned int object_lifetime_stale
The amount of time (in seconds) before an object is marked as stale, 0 if disabled.
struct ao2_container * objects
Objects in the cache.
char * object_type
The type of object we are caching.
struct ast_heap * object_heap
Heap of cached objects. Oldest object is at the top.
unsigned int full_backend_cache
Whether this is a cache of the entire backend, 0 if disabled.
int expire_id
Scheduler item for expiring oldest object.
const struct ast_sorcery * sorcery
An unreffed pointer to the sorcery instance, accessible only with lock held.
Structure for stored a cached object.
void * object
The cached object.
struct ast_variable * objectset
Cached objectset for field and regex retrieval.
ssize_t __heap_index
index required by heap
struct timeval created
The time at which the object was created.
int stale_update_sched_id
scheduler id of stale update task
struct ast_sorcery * sorcery
struct sorcery_memory_cache * cache
struct ast_sorcery * sorcery
struct sorcery_memory_cache * cache
userdata associated with baseline taskprocessor test
Sorcery object created based on backend data.
#define AST_TEST_REGISTER(cb)
#define ast_test_status_update(a, b, c...)
#define AST_TEST_UNREGISTER(cb)
#define ast_test_suite_event_notify(s, f,...)
#define AST_TEST_DEFINE(hdr)
static struct ast_sorcery * alloc_and_initialize_sorcery(void)
static void * test_sorcery_object_alloc(const char *id)
Internal function to allocate a test object.
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 struct ast_sorcery_wizard mock_wizard
A mock sorcery wizard used for the stale test.
static void * test_data_alloc(const char *id)
Allocation callback for test_data sorcery object.
void * ast_threadstorage_get(struct ast_threadstorage *ts, size_t init_size)
Retrieve thread storage.
#define AST_THREADSTORAGE(name)
Define a thread storage variable.
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 ...
int ast_tvcmp(struct timeval _a, struct timeval _b)
Compress two struct timeval instances returning -1, 0, 1 if the first arg is smaller,...
int ast_remaining_ms(struct timeval start, int max_ms)
Calculate remaining milliseconds given a starting timestamp and upper bound.
struct timeval ast_tvadd(struct timeval a, struct timeval b)
Returns the sum of two timevals a + b.
struct timeval ast_tvsub(struct timeval a, struct timeval b)
Returns the difference of two timevals a - b.
int64_t ast_tvdiff_ms(struct timeval end, struct timeval start)
Computes the difference (in milliseconds) between two struct timeval instances.
struct timeval ast_tvnow(void)
Returns current timeval. Meant to replace calls to gettimeofday().
#define RAII_VAR(vartype, varname, initval, dtor)
Declare a variable that will call a destructor function when it goes out of scope.
char * ast_uuid_generate_str(char *buf, size_t size)
Generate a UUID string.
#define AST_VECTOR_SIZE(vec)
Get the number of elements in a vector.
#define AST_VECTOR_FREE(vec)
Deallocates this vector.
#define AST_VECTOR_INIT(vec, size)
Initialize a vector.
#define AST_VECTOR_APPEND(vec, elem)
Append an element to a vector, growing the vector if needed.
#define AST_VECTOR(name, type)
Define a vector structure.
#define AST_VECTOR_GET(vec, idx)
Get an element from a vector.