[Asterisk-code-review] sorcery: Add ast sorcery retrieve by prefix() (asterisk[13])
Sean Bright
asteriskteam at digium.com
Thu Nov 9 13:53:44 CST 2017
Sean Bright has uploaded this change for review. ( https://gerrit.asterisk.org/7162
Change subject: sorcery: Add ast_sorcery_retrieve_by_prefix()
......................................................................
sorcery: Add ast_sorcery_retrieve_by_prefix()
Some consumers of the sorcery API use ast_sorcery_retrieve_by_regex
only so that they can anchor the potential match as a prefix and not
because they truly need regular expressions.
Rather than using regular expressions for simple prefix lookups, add
a new operation - ast_sorcery_retrieve_by_prefix - that does them.
Change-Id: I56f4e20ba1154bd52281f995c27a429a854f6a79
---
M include/asterisk/sorcery.h
M main/sorcery.c
M res/res_sorcery_astdb.c
M res/res_sorcery_config.c
M res/res_sorcery_memory.c
M res/res_sorcery_memory_cache.c
M res/res_sorcery_realtime.c
7 files changed, 214 insertions(+), 0 deletions(-)
git pull ssh://gerrit.asterisk.org:29418/asterisk refs/changes/62/7162/1
diff --git a/include/asterisk/sorcery.h b/include/asterisk/sorcery.h
index 0cb4347..97597eb 100644
--- a/include/asterisk/sorcery.h
+++ b/include/asterisk/sorcery.h
@@ -312,6 +312,14 @@
/*! \brief Callback for closing a wizard */
void (*close)(void *data);
+
+ /*! \brief Optional callback for retrieving multiple objects by matching their id with a prefix */
+ void (*retrieve_prefix)(const struct ast_sorcery *sorcery,
+ void *data,
+ const char *type,
+ struct ao2_container *objects,
+ const char *prefix,
+ const size_t prefix_len);
};
/*! \brief Interface for a sorcery object type observer */
@@ -1218,6 +1226,22 @@
struct ao2_container *ast_sorcery_retrieve_by_regex(const struct ast_sorcery *sorcery, const char *type, const char *regex);
/*!
+ * \brief Retrieve multiple objects whose id begins with the specified prefix
+ * \since 13.19.0
+ *
+ * \param sorcery Pointer to a sorcery structure
+ * \param type Type of object to retrieve
+ * \param prefix Object id prefix
+ * \param prefix_len The length of prefix in bytes
+ *
+ * \retval non-NULL if error occurs
+ * \retval NULL success
+ *
+ * \note The prefix is matched in a case sensitive manner.
+ */
+struct ao2_container *ast_sorcery_retrieve_by_prefix(const struct ast_sorcery *sorcery, const char *type, const char *prefix, const size_t prefix_len);
+
+/*!
* \brief Update an object
*
* \param sorcery Pointer to a sorcery structure
diff --git a/main/sorcery.c b/main/sorcery.c
index 1bdf2c2..c715f60 100644
--- a/main/sorcery.c
+++ b/main/sorcery.c
@@ -1982,6 +1982,36 @@
return objects;
}
+struct ao2_container *ast_sorcery_retrieve_by_prefix(const struct ast_sorcery *sorcery, const char *type, const char *prefix, const size_t prefix_len)
+{
+ RAII_VAR(struct ast_sorcery_object_type *, object_type, ao2_find(sorcery->types, type, OBJ_KEY), ao2_cleanup);
+ struct ao2_container *objects;
+ int i;
+
+ if (!object_type || !(objects = ao2_container_alloc_options(AO2_ALLOC_OPT_LOCK_NOLOCK, 1, NULL, NULL))) {
+ return NULL;
+ }
+
+ AST_VECTOR_RW_RDLOCK(&object_type->wizards);
+ for (i = 0; i < AST_VECTOR_SIZE(&object_type->wizards); i++) {
+ struct ast_sorcery_object_wizard *wizard =
+ AST_VECTOR_GET(&object_type->wizards, i);
+
+ if (!wizard->wizard->callbacks.retrieve_prefix) {
+ continue;
+ }
+
+ wizard->wizard->callbacks.retrieve_prefix(sorcery, wizard->data, object_type->name, objects, prefix, prefix_len);
+
+ if (wizard->caching && ao2_container_count(objects)) {
+ break;
+ }
+ }
+ AST_VECTOR_RW_UNLOCK(&object_type->wizards);
+
+ return objects;
+}
+
/*! \brief Internal function which returns if the wizard has created the object */
static int sorcery_wizard_create(const struct ast_sorcery_object_wizard *object_wizard, const struct sorcery_details *details)
{
diff --git a/res/res_sorcery_astdb.c b/res/res_sorcery_astdb.c
index 1aec0be..998f1cc 100644
--- a/res/res_sorcery_astdb.c
+++ b/res/res_sorcery_astdb.c
@@ -46,6 +46,7 @@
static void sorcery_astdb_retrieve_multiple(const struct ast_sorcery *sorcery, void *data, const char *type, struct ao2_container *objects,
const struct ast_variable *fields);
static void sorcery_astdb_retrieve_regex(const struct ast_sorcery *sorcery, void *data, const char *type, struct ao2_container *objects, const char *regex);
+static void sorcery_astdb_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 int sorcery_astdb_update(const struct ast_sorcery *sorcery, void *data, void *object);
static int sorcery_astdb_delete(const struct ast_sorcery *sorcery, void *data, void *object);
static void sorcery_astdb_close(void *data);
@@ -58,6 +59,7 @@
.retrieve_fields = sorcery_astdb_retrieve_fields,
.retrieve_multiple = sorcery_astdb_retrieve_multiple,
.retrieve_regex = sorcery_astdb_retrieve_regex,
+ .retrieve_prefix = sorcery_astdb_retrieve_prefix,
.update = sorcery_astdb_update,
.delete = sorcery_astdb_delete,
.close = sorcery_astdb_close,
@@ -329,6 +331,42 @@
regfree(&expression);
}
+static void sorcery_astdb_retrieve_prefix(const struct ast_sorcery *sorcery, void *data, const char *type, struct ao2_container *objects, const char *prefix, const size_t prefix_len)
+{
+ const char *family_prefix = data;
+ size_t family_len = strlen(family_prefix) + strlen(type) + 1; /* +1 for slash delimiter */
+ char family[family_len + 1];
+ char tree[prefix_len + sizeof("%")];
+ RAII_VAR(struct ast_db_entry *, entries, NULL, ast_db_freetree);
+ struct ast_db_entry *entry;
+
+ snprintf(tree, sizeof(tree), "%s%%", prefix);
+ snprintf(family, sizeof(family), "%s/%s", family_prefix, type);
+
+ if (!(entries = ast_db_gettree(family, tree))) {
+ return;
+ }
+
+ for (entry = entries; entry; entry = entry->next) {
+ /* The key in the entry includes the family, so we need to strip it out */
+ const char *key = entry->key + family_len + 2;
+ RAII_VAR(struct ast_json *, json, NULL, ast_json_unref);
+ struct ast_json_error error;
+ RAII_VAR(void *, object, NULL, ao2_cleanup);
+ RAII_VAR(struct ast_variable *, objset, NULL, ast_variables_destroy);
+
+ if (!(json = ast_json_load_string(entry->data, &error))
+ || (ast_json_to_ast_variables(json, &objset) != AST_JSON_TO_AST_VARS_CODE_SUCCESS)
+ || !(objset = sorcery_astdb_filter_objectset(objset, sorcery, type))
+ || !(object = ast_sorcery_alloc(sorcery, type, key))
+ || ast_sorcery_objectset_apply(sorcery, object, objset)) {
+ return;
+ }
+
+ ao2_link(objects, object);
+ }
+}
+
static int sorcery_astdb_update(const struct ast_sorcery *sorcery, void *data, void *object)
{
const char *prefix = data;
diff --git a/res/res_sorcery_config.c b/res/res_sorcery_config.c
index 7fd7e76..b02000e 100644
--- a/res/res_sorcery_config.c
+++ b/res/res_sorcery_config.c
@@ -73,6 +73,12 @@
/*! \brief Regular expression for checking object id */
regex_t *regex;
+ /*! \brief Prefix for matching object id */
+ const char *prefix;
+
+ /*! \brief Prefix length in bytes for matching object id */
+ const size_t prefix_len;
+
/*! \brief Optional container to put object into */
struct ao2_container *container;
};
@@ -85,6 +91,7 @@
static void sorcery_config_retrieve_multiple(const struct ast_sorcery *sorcery, void *data, const char *type, struct ao2_container *objects,
const struct ast_variable *fields);
static void sorcery_config_retrieve_regex(const struct ast_sorcery *sorcery, void *data, const char *type, struct ao2_container *objects, const char *regex);
+static void sorcery_config_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_config_close(void *data);
static struct ast_sorcery_wizard config_object_wizard = {
@@ -96,6 +103,7 @@
.retrieve_fields = sorcery_config_retrieve_fields,
.retrieve_multiple = sorcery_config_retrieve_multiple,
.retrieve_regex = sorcery_config_retrieve_regex,
+ .retrieve_prefix = sorcery_config_retrieve_prefix,
.close = sorcery_config_close,
};
@@ -117,6 +125,11 @@
if (params->regex) {
/* If a regular expression has been provided see if it matches, otherwise move on */
if (!regexec(params->regex, ast_sorcery_object_get_id(obj), 0, NULL, 0)) {
+ ao2_link(params->container, obj);
+ }
+ return 0;
+ } else if (params->prefix) {
+ if (!strncmp(params->prefix, ast_sorcery_object_get_id(obj), params->prefix_len)) {
ao2_link(params->container, obj);
}
return 0;
@@ -208,6 +221,24 @@
regfree(&expression);
}
+static void sorcery_config_retrieve_prefix(const struct ast_sorcery *sorcery, void *data, const char *type, struct ao2_container *objects, const char *prefix, const size_t prefix_len)
+{
+ struct sorcery_config *config = data;
+ RAII_VAR(struct ao2_container *, config_objects, ao2_global_obj_ref(config->objects), ao2_cleanup);
+ struct sorcery_config_fields_cmp_params params = {
+ .sorcery = sorcery,
+ .container = objects,
+ .prefix = prefix,
+ .prefix_len = prefix_len,
+ };
+
+ if (!config_objects) {
+ return;
+ }
+
+ ao2_callback(config_objects, OBJ_NODATA | OBJ_MULTIPLE, sorcery_config_fields_cmp, ¶ms);
+}
+
/*! \brief Internal function which determines if criteria has been met for considering an object set applicable */
static int sorcery_is_criteria_met(struct ast_variable *objset, struct ast_variable *criteria)
{
diff --git a/res/res_sorcery_memory.c b/res/res_sorcery_memory.c
index b2f0559..a05f05d 100644
--- a/res/res_sorcery_memory.c
+++ b/res/res_sorcery_memory.c
@@ -48,6 +48,7 @@
static void sorcery_memory_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_retrieve_regex(const struct ast_sorcery *sorcery, void *data, const char *type, struct ao2_container *objects, const char *regex);
+static void sorcery_memory_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 int sorcery_memory_update(const struct ast_sorcery *sorcery, void *data, void *object);
static int sorcery_memory_delete(const struct ast_sorcery *sorcery, void *data, void *object);
static void sorcery_memory_close(void *data);
@@ -60,6 +61,7 @@
.retrieve_fields = sorcery_memory_retrieve_fields,
.retrieve_multiple = sorcery_memory_retrieve_multiple,
.retrieve_regex = sorcery_memory_retrieve_regex,
+ .retrieve_prefix = sorcery_memory_retrieve_prefix,
.update = sorcery_memory_update,
.delete = sorcery_memory_delete,
.close = sorcery_memory_close,
@@ -75,6 +77,12 @@
/*! \brief Regular expression for checking object id */
regex_t *regex;
+
+ /*! \brief Prefix for matching object id */
+ const char *prefix;
+
+ /*! \brief Prefix length in bytes for matching object id */
+ const size_t prefix_len;
/*! \brief Optional container to put object into */
struct ao2_container *container;
@@ -124,6 +132,11 @@
if (params->regex) {
/* If a regular expression has been provided see if it matches, otherwise move on */
if (!regexec(params->regex, ast_sorcery_object_get_id(obj), 0, NULL, 0)) {
+ ao2_link(params->container, obj);
+ }
+ return 0;
+ } else if (params->prefix) {
+ if (!strncmp(params->prefix, ast_sorcery_object_get_id(obj), params->prefix_len)) {
ao2_link(params->container, obj);
}
return 0;
@@ -200,6 +213,18 @@
regfree(&expression);
}
+static void sorcery_memory_retrieve_prefix(const struct ast_sorcery *sorcery, void *data, const char *type, struct ao2_container *objects, const char *prefix, const size_t prefix_len)
+{
+ struct sorcery_memory_fields_cmp_params params = {
+ .sorcery = sorcery,
+ .container = objects,
+ .prefix = prefix,
+ .prefix_len = prefix_len,
+ };
+
+ ao2_callback(data, 0, sorcery_memory_fields_cmp, ¶ms);
+}
+
static int sorcery_memory_update(const struct ast_sorcery *sorcery, void *data, void *object)
{
RAII_VAR(void *, existing, NULL, ao2_cleanup);
diff --git a/res/res_sorcery_memory_cache.c b/res/res_sorcery_memory_cache.c
index bf2347c..30e6ef0 100644
--- a/res/res_sorcery_memory_cache.c
+++ b/res/res_sorcery_memory_cache.c
@@ -185,6 +185,10 @@
const struct ast_variable *fields;
/*! \brief Regular expression for checking object id */
regex_t *regex;
+ /*! \brief Prefix for matching object id */
+ const char *prefix;
+ /*! \brief Prefix length in bytes for matching object id */
+ const size_t prefix_len;
/*! \brief Optional container to put object into */
struct ao2_container *container;
};
@@ -201,6 +205,8 @@
struct ao2_container *objects, const struct ast_variable *fields);
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_prefix(const struct ast_sorcery *sorcery, void *data, const char *type,
+ struct ao2_container *objects, const char *prefix, const size_t prefix_len);
static int sorcery_memory_cache_delete(const struct ast_sorcery *sorcery, void *data, void *object);
static void sorcery_memory_cache_close(void *data);
@@ -216,6 +222,7 @@
.retrieve_fields = sorcery_memory_cache_retrieve_fields,
.retrieve_multiple = sorcery_memory_cache_retrieve_multiple,
.retrieve_regex = sorcery_memory_cache_retrieve_regex,
+ .retrieve_prefix = sorcery_memory_cache_retrieve_prefix,
.close = sorcery_memory_cache_close,
};
@@ -1253,6 +1260,11 @@
ao2_link(params->container, cached->object);
}
return 0;
+ } else if (params->prefix) {
+ if (!strncmp(params->prefix, ast_sorcery_object_get_id(cached->object), params->prefix_len)) {
+ ao2_link(params->container, cached->object);
+ }
+ return 0;
} else if (params->fields &&
(!ast_variable_lists_match(cached->objectset, params->fields, 0))) {
/* If we can't turn the object into an object set OR if differences exist between the fields
@@ -1378,6 +1390,40 @@
/*!
* \internal
+ * \brief Callback function to retrieve multiple objects whose id matches a prefix
+ *
+ * \param sorcery The sorcery instance
+ * \param data The sorcery memory cache
+ * \param type The type of the object to retrieve
+ * \param objects Container to place the objects into
+ * \param prefix Prefix to match against the object id
+ */
+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)
+{
+ struct sorcery_memory_cache *cache = data;
+ struct sorcery_memory_cache_fields_cmp_params params = {
+ .sorcery = sorcery,
+ .cache = cache,
+ .container = objects,
+ .prefix = prefix,
+ .prefix_len = prefix_len,
+ };
+
+ if (is_passthru_update() || !cache->full_backend_cache) {
+ return;
+ }
+
+ memory_cache_full_update(sorcery, type, cache);
+ ao2_callback(cache->objects, 0, sorcery_memory_cache_fields_cmp, ¶ms);
+
+ if (ao2_container_count(objects)) {
+ memory_cache_stale_check(sorcery, cache);
+ }
+}
+
+/*!
+ * \internal
* \brief Callback function to finish configuring the memory cache
*
* \param data The sorcery memory cache
diff --git a/res/res_sorcery_realtime.c b/res/res_sorcery_realtime.c
index 138d6ea..b211abc 100644
--- a/res/res_sorcery_realtime.c
+++ b/res/res_sorcery_realtime.c
@@ -59,6 +59,8 @@
static void sorcery_realtime_retrieve_multiple(const struct ast_sorcery *sorcery, void *data, const char *type, struct ao2_container *objects,
const struct ast_variable *fields);
static void sorcery_realtime_retrieve_regex(const struct ast_sorcery *sorcery, void *data, const char *type, struct ao2_container *objects, const char *regex);
+static void sorcery_realtime_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 int sorcery_realtime_update(const struct ast_sorcery *sorcery, void *data, void *object);
static int sorcery_realtime_delete(const struct ast_sorcery *sorcery, void *data, void *object);
static void sorcery_realtime_close(void *data);
@@ -71,6 +73,7 @@
.retrieve_fields = sorcery_realtime_retrieve_fields,
.retrieve_multiple = sorcery_realtime_retrieve_multiple,
.retrieve_regex = sorcery_realtime_retrieve_regex,
+ .retrieve_prefix = sorcery_realtime_retrieve_prefix,
.update = sorcery_realtime_update,
.delete = sorcery_realtime_delete,
.close = sorcery_realtime_close,
@@ -262,6 +265,23 @@
sorcery_realtime_retrieve_multiple(sorcery, data, type, objects, fields);
}
+static void sorcery_realtime_retrieve_prefix(const struct ast_sorcery *sorcery, void *data, const char *type,
+ struct ao2_container *objects, const char *prefix, const size_t prefix_len)
+{
+ char field[strlen(UUID_FIELD) + 6], value[prefix_len + 2];
+ RAII_VAR(struct ast_variable *, fields, NULL, ast_variables_destroy);
+
+ if (!ast_strlen_zero(prefix)) {
+ snprintf(field, sizeof(field), "%s LIKE", UUID_FIELD);
+ snprintf(value, sizeof(value), "%s%%", prefix);
+ if (!(fields = ast_variable_new(field, value, ""))) {
+ return;
+ }
+ }
+
+ sorcery_realtime_retrieve_multiple(sorcery, data, type, objects, fields);
+}
+
static int sorcery_realtime_update(const struct ast_sorcery *sorcery, void *data, void *object)
{
struct sorcery_config *config = data;
--
To view, visit https://gerrit.asterisk.org/7162
To unsubscribe, visit https://gerrit.asterisk.org/settings
Gerrit-Project: asterisk
Gerrit-Branch: 13
Gerrit-MessageType: newchange
Gerrit-Change-Id: I56f4e20ba1154bd52281f995c27a429a854f6a79
Gerrit-Change-Number: 7162
Gerrit-PatchSet: 1
Gerrit-Owner: Sean Bright <sean.bright at gmail.com>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.digium.com/pipermail/asterisk-code-review/attachments/20171109/9440616f/attachment-0001.html>
More information about the asterisk-code-review
mailing list