diff --git a/include/asterisk/datastore.h b/include/asterisk/datastore.h index 8f59fd3cf7..85e9c6890a 100644 --- a/include/asterisk/datastore.h +++ b/include/asterisk/datastore.h @@ -92,6 +92,64 @@ struct ast_datastore * attribute_malloc __ast_datastore_alloc(const struct ast_d */ int ast_datastore_free(struct ast_datastore *datastore); +/*! + * \brief Allocate a specialized data stores container + * + * \return a container for storing data stores + * + * \since 14.0.0 + */ +struct ao2_container *ast_datastores_alloc(void); + +/*! + * \brief Add a data store to a container + * + * \param[in] datastores container to store datastore in + * \param[in] datastore datastore to add + * + * \retval 0 success + * \retval -1 failure + * + * \since 14.0.0 + */ +int ast_datastores_add(struct ao2_container *datastores, struct ast_datastore *datastore); + +/*! + * \brief Remove a data store from a container + * + * \param[in] datastores container to remove datastore from + * \param[in] name name of the data store to remove + * + * \since 14.0.0 + */ +void ast_datastores_remove(struct ao2_container *datastores, const char *name); + +/*! + * \brief Find a data store in a container + * + * \param[in] datastores container to find datastore in + * \param[in] name name of the data store to find + * + * \retval non-NULL success + * \retval NULL failure + * + * \since 14.0.0 + */ +struct ast_datastore *ast_datastores_find(struct ao2_container *datastores, const char *name); + +/*! + * \brief Allocate a datastore for use with the datastores container + * + * \param[in] info information about the datastore + * \param[in] uid unique identifier for the datastore + * + * \retval non-NULL success + * \retval NULL failure + * + * \since 14.0.0 + */ +struct ast_datastore *ast_datastores_alloc_datastore(const struct ast_datastore_info *info, const char *uid); + #if defined(__cplusplus) || defined(c_plusplus) } #endif diff --git a/main/datastore.c b/main/datastore.c index a9079e8375..c2bba41904 100644 --- a/main/datastore.c +++ b/main/datastore.c @@ -31,6 +31,11 @@ ASTERISK_REGISTER_FILE() #include "asterisk/datastore.h" #include "asterisk/utils.h" +#include "asterisk/astobj2.h" +#include "asterisk/uuid.h" + +/*! \brief Number of buckets for datastore container */ +#define DATASTORE_BUCKETS 53 struct ast_datastore *__ast_datastore_alloc(const struct ast_datastore_info *info, const char *uid, const char *file, int line, const char *function) @@ -83,3 +88,78 @@ int ast_datastore_free(struct ast_datastore *datastore) return res; } + +AO2_STRING_FIELD_HASH_FN(ast_datastore, uid); +AO2_STRING_FIELD_CMP_FN(ast_datastore, uid); + +struct ao2_container *ast_datastores_alloc(void) +{ + return ao2_container_alloc(DATASTORE_BUCKETS, ast_datastore_hash_fn, ast_datastore_cmp_fn); +} + +int ast_datastores_add(struct ao2_container *datastores, struct ast_datastore *datastore) +{ + ast_assert(datastore != NULL); + ast_assert(datastore->info != NULL); + ast_assert(!ast_strlen_zero(datastore->uid)); + + if (!ao2_link(datastores, datastore)) { + return -1; + } + + return 0; +} + +void ast_datastores_remove(struct ao2_container *datastores, const char *name) +{ + ao2_find(datastores, name, OBJ_SEARCH_KEY | OBJ_UNLINK | OBJ_NODATA); +} + +struct ast_datastore *ast_datastores_find(struct ao2_container *datastores, const char *name) +{ + return ao2_find(datastores, name, OBJ_SEARCH_KEY); +} + +static void datastore_destroy(void *obj) +{ + struct ast_datastore *datastore = obj; + + /* Using the destroy function (if present) destroy the data */ + if (datastore->info->destroy != NULL && datastore->data != NULL) { + datastore->info->destroy(datastore->data); + datastore->data = NULL; + } + + ast_free((void *) datastore->uid); + datastore->uid = NULL; +} + +struct ast_datastore *ast_datastores_alloc_datastore(const struct ast_datastore_info *info, const char *uid) +{ + struct ast_datastore *datastore; + char uuid_buf[AST_UUID_STR_LEN]; + const char *uid_ptr = uid; + + if (!info) { + return NULL; + } + + datastore = ao2_alloc(sizeof(*datastore), datastore_destroy); + if (!datastore) { + return NULL; + } + + datastore->info = info; + if (ast_strlen_zero(uid)) { + /* They didn't provide an ID so we'll provide one ourself */ + uid_ptr = ast_uuid_generate_str(uuid_buf, sizeof(uuid_buf)); + } + + datastore->uid = ast_strdup(uid_ptr); + if (!datastore->uid) { + ao2_ref(datastore, -1); + return NULL; + } + + return datastore; +}