156 unsigned int cache_notify;
162 unsigned int cache_completed;
216 .
name =
"memory_cache",
232#define CACHES_CONTAINER_BUCKET_SIZE 53
235#define CACHE_CONTAINER_BUCKET_SIZE 53
238#define CACHE_HEAP_INIT_HEIGHT 5
246#define PASSTHRU_UPDATE_THREAD_ID 0x5EED1E55
251 uint32_t *passthru_update_thread_id;
254 sizeof(*passthru_update_thread_id));
255 if (!passthru_update_thread_id) {
264 uint32_t *passthru_update_thread_id;
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");
273 *passthru_update_thread_id =
value;
298 const char *
name = obj;
333 const char *right_name = arg;
339 right_name = right->
name;
342 cmp = strcmp(left->
name, right_name);
345 cmp = strncmp(left->
name, right_name, strlen(right_name));
363 const char *
name = obj;
398 const char *right_name = arg;
427 if (
cache->object_heap) {
485 if (reschedule && (oldest_object == heap_object)) {
511 if (
cache->del_expire) {
512 cache->expire_id = -1;
519 cache->expire_id = -1;
528 if (expiration > 0) {
562 cache->del_expire = 1;
564 cache->del_expire = 0;
653 if (!
cache->object_lifetime_maximum) {
657 cache->del_expire = 1;
659 cache->del_expire = 0;
665 cache->cache_completed = 1;
676 if (
cache->expire_id < 0) {
701 if (!heap_old_object) {
707 ast_assert(heap_old_object == hash_old_object);
748 if (
cache->expire_id == -1) {
780 if (
cache->full_backend_cache) {
825 ast_log(
LOG_ERROR,
"Unable to make room in cache for sorcery object '%s'.\n",
918 if (!backend_objects) {
919 task_data->cache->stale_update_sched_id = -1;
925 ast_log(
LOG_ERROR,
"The backend contains %d objects while the sorcery memory cache '%s' is explicitly configured to only allow %d\n",
927 task_data->cache->stale_update_sched_id = -1;
942 ast_log(
LOG_WARNING,
"The backend contains %d objects while only %d could be added to sorcery memory cache '%s'\n",
950 task_data->cache->stale_update_sched_id = -1;
1000 ast_debug(1,
"Backend no longer has object type '%s' ID '%s'. Removing from cache\n",
1006 ast_debug(1,
"Refreshing stale cache object type '%s' ID '%s'\n",
1042 if (!backend_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",
1061 ast_log(
LOG_WARNING,
"The backend contains %d objects while only %d could be added to sorcery memory cache '%s'\n",
1079 if (!
cache->full_backend_cache) {
1102 if (
cache->stale_update_sched_id == -1) {
1111 if (
cache->stale_update_sched_id < 0) {
1136 ast_debug(1,
"Cached sorcery object type '%s' ID '%s' is stale. Refreshing\n",
1143 ast_log(
LOG_ERROR,
"Unable to update stale cached object type '%s', ID '%s'.\n",
1161 struct timeval elapsed;
1163 if (!
cache->object_lifetime_stale) {
1170 if (elapsed.tv_sec <
cache->object_lifetime_stale) {
1174 if (
cache->full_backend_cache) {
1260 if (params->
regex) {
1266 }
else if (params->
prefix) {
1271 }
else if (params->
fields &&
1309 void *
object =
NULL;
1344 .container = objects,
1377 .container = objects,
1378 .regex = &expression,
1387 regfree(&expression);
1411 .container = objects,
1446 ast_debug(1,
"Memory cache '%s' associated with sorcery instance '%p' of module '%s' with object type '%s'\n",
1465 if (!
cache->expire_on_reload) {
1518 cache->expire_id = -1;
1519 cache->stale_update_sched_id = -1;
1527 if (!strcasecmp(
name,
"name")) {
1534 }
else if (!strcasecmp(
name,
"maximum_objects")) {
1536 ast_log(
LOG_ERROR,
"Unsupported maximum objects value of '%s' used for memory cache\n",
1540 }
else if (!strcasecmp(
name,
"object_lifetime_maximum")) {
1542 ast_log(
LOG_ERROR,
"Unsupported object maximum lifetime value of '%s' used for memory cache\n",
1546 }
else if (!strcasecmp(
name,
"object_lifetime_stale")) {
1548 ast_log(
LOG_ERROR,
"Unsupported object stale lifetime value of '%s' used for memory cache\n",
1552 }
else if (!strcasecmp(
name,
"expire_on_reload")) {
1554 }
else if (!strcasecmp(
name,
"full_backend_cache")) {
1565 if (!
cache->objects) {
1566 ast_log(
LOG_ERROR,
"Could not create a container to hold cached objects for memory cache\n");
1572 if (!
cache->object_heap) {
1629 if (
cache->object_lifetime_maximum) {
1639 if (
cache->full_backend_cache) {
1656 int wordlen = strlen(
word);
1662 if (!strncasecmp(
word,
cache->name, wordlen)
1663 && ++which >
state) {
1685 e->
command =
"sorcery memory cache show";
1687 "Usage: sorcery memory cache show <name>\n"
1688 " Show sorcery memory cache configuration and statistics.\n";
1704 ast_cli(
a->fd,
"Specified sorcery memory cache '%s' does not exist\n",
a->argv[4]);
1710 if (
cache->maximum_objects) {
1711 ast_cli(
a->fd,
"Maximum allowed objects: %d\n",
cache->maximum_objects);
1713 ast_cli(
a->fd,
"There is no limit on the maximum number of objects in the cache\n");
1715 if (
cache->object_lifetime_maximum) {
1716 ast_cli(
a->fd,
"Number of seconds before object expires: %d\n",
cache->object_lifetime_maximum);
1718 ast_cli(
a->fd,
"Object expiration is not enabled - cached objects will not expire\n");
1720 if (
cache->object_lifetime_stale) {
1721 ast_cli(
a->fd,
"Number of seconds before object becomes stale: %d\n",
cache->object_lifetime_stale);
1723 ast_cli(
a->fd,
"Object staleness is not enabled - cached objects will not go stale\n");
1746#define FORMAT "%-25.25s %-15u %-15u \n"
1749 int seconds_until_expire = 0, seconds_until_stale = 0;
1770#define FORMAT "%-25.25s %-15.15s %-15.15s \n"
1776 e->
command =
"sorcery memory cache dump";
1778 "Usage: sorcery memory cache dump <name>\n"
1779 " Dump a list of the objects within the cache, listed by object identifier.\n";
1795 ast_cli(
a->fd,
"Specified sorcery memory cache '%s' does not exist\n",
a->argv[4]);
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");
1806 if (!
cache->object_lifetime_maximum) {
1807 ast_cli(
a->fd,
" * Object lifetime is not enabled - objects will not expire\n");
1810 ast_cli(
a->fd,
FORMAT,
"-------------------------",
"---------------",
"---------------");
1812 ast_cli(
a->fd,
FORMAT,
"-------------------------",
"---------------",
"---------------");
1830 int wordlen = strlen(
word);
1842 && ++which >
state) {
1867 e->
command =
"sorcery memory cache expire";
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";
1875 }
else if (
a->pos == 5) {
1882 if (
a->argc < 5 ||
a->argc > 6) {
1888 ast_cli(
a->fd,
"Specified sorcery memory cache '%s' does not exist\n",
a->argv[4]);
1895 ast_cli(
a->fd,
"All objects have been removed from cache '%s'\n",
a->argv[4]);
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]);
1900 ast_cli(
a->fd,
"Successfully expired object '%s' from cache '%s'\n",
a->argv[5],
a->argv[4]);
1902 ast_cli(
a->fd,
"Object '%s' was not expired from cache '%s' as it was not found\n",
a->argv[5],
1924 e->
command =
"sorcery memory cache stale";
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";
1934 }
else if (
a->pos == 5) {
1936 }
else if (
a->pos == 6) {
1937 static const char *
const completions[] = {
"reload",
NULL };
1944 if (
a->argc < 5 ||
a->argc > 7) {
1949 if (!strcasecmp(
a->argv[6],
"reload")) {
1958 ast_cli(
a->fd,
"Specified sorcery memory cache '%s' does not exist\n",
a->argv[4]);
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]);
1971 ast_cli(
a->fd,
"Marked all objects in sorcery memory cache '%s' as stale\n",
a->argv[4]);
1974 ast_cli(
a->fd,
"Successfully marked object '%s' in memory cache '%s' as stale\n",
1975 a->argv[5],
a->argv[4]);
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]);
2007 e->
command =
"sorcery memory cache populate";
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";
2026 ast_cli(
a->fd,
"Specified sorcery memory cache '%s' does not exist\n",
a->argv[4]);
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]);
2037 if (!
cache->sorcery) {
2038 ast_cli(
a->fd,
"Specified sorcery memory cache '%s' is no longer active\n",
a->argv[4]);
2047 ast_cli(
a->fd,
"Specified sorcery memory cache '%s' has been populated with '%d' objects from the backend\n",
2077 astman_send_error(s, m,
"SorceryMemoryCacheExpireObject requires that a cache name be provided.\n");
2080 astman_send_error(s, m,
"SorceryMemoryCacheExpireObject requires that an object name be provided\n");
2091 if (
cache->full_backend_cache) {
2101 astman_send_error(s, m,
"Due to full backend caching per-object expiration is not available, consider using SorceryMemoryCachePopulate or SorceryMemoryCacheExpire instead\n");
2103 astman_send_ack(s, m,
"The provided object was expired from the cache\n");
2105 astman_send_error(s, m,
"The provided object could not be expired from the cache\n");
2121 astman_send_error(s, m,
"SorceryMemoryCacheExpire requires that a cache name be provided.\n");
2155 astman_send_error(s, m,
"SorceryMemoryCacheStaleObject requires that a cache name be provided.\n");
2158 astman_send_error(s, m,
"SorceryMemoryCacheStaleObject requires that an object name be provided\n");
2187 astman_send_ack(s, m,
"The provided object was marked as stale in the cache\n");
2189 astman_send_error(s, m,
"The provided object could not be marked as stale in the cache\n");
2205 astman_send_error(s, m,
"SorceryMemoryCacheStale requires that a cache name be provided.\n");
2221 astman_send_ack(s, m,
"All objects were marked as stale in the cache\n");
2236 astman_send_error(s, m,
"SorceryMemoryCachePopulate requires that a cache name be provided.\n");
2246 if (!
cache->full_backend_cache) {
2247 astman_send_error(s, m,
"The provided cache does not have full backend caching enabled\n");
2253 if (!
cache->sorcery) {
2272#ifdef TEST_FRAMEWORK
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";
2350 if (
cache->maximum_objects != 10) {
2352 cache->maximum_objects);
2362 if (
cache->object_lifetime_maximum != 60) {
2364 cache->object_lifetime_maximum);
2374 if (
cache->object_lifetime_stale != 90) {
2376 cache->object_lifetime_stale);
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";
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";
2522 if (!cached_object) {
2527 if (cached_object !=
object) {
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";
2591 if (!original_object) {
2599 if (!updated_object) {
2613 if (!cached_object) {
2618 if (cached_object == original_object) {
2621 }
else if (cached_object != updated_object) {
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";
2696 if (!cached_object) {
2702 cached_object =
NULL;
2707 if (cached_object) {
2726 const char **in_cache,
size_t num_in_cache,
const char **not_in_cache,
size_t num_not_in_cache)
2732 for (i = 0; i < num_in_cache; ++i) {
2734 if (!cached_object) {
2742 for (i = 0; i < num_not_in_cache; ++i) {
2744 if (cached_object) {
2764 const char *in_cache[2];
2765 const char *not_in_cache[2];
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";
2810 if (!alice || !bob || !charlie) {
2816 in_cache[0] =
"alice";
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)) {
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)) {
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)) {
2851 in_cache[0] =
"bob";
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)) {
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)) {
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";
2916 cache->cache_notify = 1;
2920 for (i = 0; i < 5; ++i) {
2936 while (!
cache->cache_completed) {
2938 struct timespec
end = {
2939 .tv_sec = start.tv_sec + 10,
2940 .tv_nsec = start.tv_usec * 1000,
2958 if (
cache->cache_notify) {
2974static struct backend_data {
2981} *real_backend_data;
3018 const char *
type,
const char *
id)
3022 if (!real_backend_data->exists) {
3031 b_data->salt = real_backend_data->salt;
3032 b_data->pepper = real_backend_data->pepper;
3058 for (i = 0; i < real_backend_data->exists; ++i) {
3067 b_data->salt = real_backend_data->salt;
3068 b_data->pepper = real_backend_data->pepper;
3081 .retrieve_multiple = mock_retrieve_multiple,
3100 void *previous_object,
struct test_data **new_object)
3108 if (
object != previous_object) {
3109 *new_object = 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 },
3128 struct backend_data initial = {
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";
3168 "object_lifetime_stale=3", 1);
3173 real_backend_data = &initial;
3176 if (!backend_object) {
3182 for (i = 0; i <
ARRAY_LEN(iterations); ++i) {
3187 real_backend_data = &iterations[i];
3197 if (cache_fresh->salt == iterations[i].salt || cache_fresh->pepper == iterations[i].pepper) {
3210 if (cache_stale != cache_fresh) {
3215 if (wait_for_cache_update(
sorcery, cache_stale, &cache_new)) {
3220 if (iterations[i].
exists) {
3224 }
else if (cache_new->salt != iterations[i].salt ||
3225 cache_new->pepper != iterations[i].pepper) {
3229 }
else if (cache_new) {
3249 struct backend_data initial = {
3257 struct timeval start;
3258 struct timespec
end;
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.";
3288 "object_lifetime_maximum=3,full_backend_cache=yes", 1);
3295 real_backend_data = &initial;
3327 end.tv_sec = start.tv_sec + 5;
3328 end.tv_nsec = start.tv_usec * 1000;
3367 struct backend_data initial = {
3375 struct timeval start;
3376 struct timespec
end;
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.";
3410 "object_lifetime_stale=1,full_backend_cache=yes", 1);
3417 real_backend_data = &initial;
3428 end.tv_sec = start.tv_sec + 5;
3429 end.tv_nsec = start.tv_usec * 1000;
3454 end.tv_sec = start.tv_sec + 5;
3455 end.tv_nsec = start.tv_usec * 1000;
3478 end.tv_sec = start.tv_sec + 5;
3479 end.tv_nsec = start.tv_usec * 1000;
3559 ast_log(
LOG_ERROR,
"Failed to create scheduler thread for cache management\n");
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.
Standard Command Line Interface.
int ast_cli_unregister_multiple(struct ast_cli_entry *e, int len)
Unregister multiple commands.
#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)
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]
char * strsep(char **str, const char *delims)
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.
static void * cleanup(void *unused)
struct ao2_container * cache
static struct ast_sorcery * sorcery
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 struct ast_threadstorage passthru_update_id_storage
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 void memory_cache_populate(const struct ast_sorcery *sorcery, const char *type, struct sorcery_memory_cache *cache)
static int sorcery_memory_cached_object_hash(const void *obj, int flags)
static void sorcery_memory_cache_close(void *data)
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 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)
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.
@ 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.
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.