[asterisk-commits] file: branch file/bucket r396897 - in /team/file/bucket: include/asterisk/ ma...
SVN commits to the Asterisk project
asterisk-commits at lists.digium.com
Sat Aug 17 10:26:51 CDT 2013
Author: file
Date: Sat Aug 17 10:26:49 2013
New Revision: 396897
URL: http://svnview.digium.com/svn/asterisk?view=rev&rev=396897
Log:
Make the scheme responsible for the life cycle of the underlying file.
Modified:
team/file/bucket/include/asterisk/bucket.h
team/file/bucket/main/bucket.c
team/file/bucket/tests/test_bucket.c
Modified: team/file/bucket/include/asterisk/bucket.h
URL: http://svnview.digium.com/svn/asterisk/team/file/bucket/include/asterisk/bucket.h?view=diff&rev=396897&r1=396896&r2=396897
==============================================================================
--- team/file/bucket/include/asterisk/bucket.h (original)
+++ team/file/bucket/include/asterisk/bucket.h Sat Aug 17 10:26:49 2013
@@ -39,6 +39,9 @@
#endif
#include "asterisk/sorcery.h"
+
+/*! \brief Opaque structure for internal details about a scheme */
+struct ast_bucket_scheme;
/*! \brief Bucket metadata structure, AO2 key value pair */
struct ast_bucket_metadata {
@@ -54,11 +57,13 @@
struct ast_bucket {
/*! \brief Sorcery object information */
SORCERY_OBJECT(details);
+ /*! \brief Scheme implementation in use */
+ struct ast_bucket_scheme *scheme_impl;
/*! \brief Stringfields */
AST_DECLARE_STRING_FIELDS(
/*! \brief Name of the bucket */
AST_STRING_FIELD(name);
- /*! \brief Scheme in use */
+ /*! \brief Name of scheme in use */
AST_STRING_FIELD(scheme);
);
/*! \brief When this bucket was created */
@@ -75,11 +80,13 @@
struct ast_bucket_file {
/*! \brief Sorcery object information */
SORCERY_OBJECT(details);
+ /*! \brief Scheme implementation in use */
+ struct ast_bucket_scheme *scheme_impl;
/*! \brief Stringfields */
AST_DECLARE_STRING_FIELDS(
/*! \brief Name of the file */
AST_STRING_FIELD(name);
- /*! \brief Scheme in use */
+ /*! \brief Name of scheme in use */
AST_STRING_FIELD(scheme);
);
/*! \brief When this file was created */
@@ -93,6 +100,23 @@
};
/*!
+ * \brief A callback function invoked when creating a file snapshot
+ *
+ * \param file Pointer to the file snapshot
+ *
+ * \retval 0 success
+ * \retval -1 failure
+ */
+typedef int (*bucket_file_create_cb)(struct ast_bucket_file *file);
+
+/*!
+ * \brief A callback function invoked when destroying a file snapshot
+ *
+ * \param file Pointer to the file snapshot
+ */
+typedef void (*bucket_file_destroy_cb)(struct ast_bucket_file *file);
+
+/*!
* \brief Initialize bucket support
*
* \retval 0 success
@@ -106,13 +130,15 @@
* \param name Name of the scheme, used to find based on scheme in URIs
* \param bucket Sorcery wizard used for buckets
* \param file Sorcery wizard used for files
+ * \param create_cb Required file snapshot creation callback
+ * \param destroy_cb Optional file snapshot destruction callback
*
* \retval 0 success
* \retval -1 failure
*
* \note Once a scheme has been registered it can not be unregistered
*/
-#define ast_bucket_scheme_register(name, bucket, file) __ast_bucket_scheme_register(name, bucket, file, ast_module_info ? ast_module_info->self : NULL)
+#define ast_bucket_scheme_register(name, bucket, file, create_cb, destroy_cb) __ast_bucket_scheme_register(name, bucket, file, create_cb, destroy_cb, ast_module_info ? ast_module_info->self : NULL)
/*!
* \brief Register support for a specific scheme
@@ -120,6 +146,8 @@
* \param name Name of the scheme, used to find based on scheme in URIs
* \param bucket Sorcery wizard used for buckets
* \param file Sorcery wizard used for files
+ * \param create_cb Required file snapshot creation callback
+ * \param destroy_cb Optional file snapshot destruction callback
* \param module The module which implements this scheme
*
* \retval 0 success
@@ -128,7 +156,8 @@
* \note Once a scheme has been registered it can not be unregistered
*/
int __ast_bucket_scheme_register(const char *name, struct ast_sorcery_wizard *bucket,
- struct ast_sorcery_wizard *file, struct ast_module *module);
+ struct ast_sorcery_wizard *file, bucket_file_create_cb create_cb,
+ bucket_file_destroy_cb destroy_cb, struct ast_module *module);
/*!
* \brief Set a metadata attribute on a file to a specific value
@@ -347,6 +376,23 @@
* \note The returned ast_json object must be unreferenced using ast_json_unref
*/
struct ast_json *ast_bucket_file_json(const struct ast_bucket_file *file);
+
+/*!
+ * \brief Common file snapshot creation callback for creating a temporary file
+ *
+ * \param file Pointer to the file snapshot
+ *
+ * \retval 0 success
+ * \retval -1 failure
+ */
+int ast_bucket_file_temporary_create(struct ast_bucket_file *file);
+
+/*!
+ * \brief Common file snapshot destruction callback for deleting a temporary file
+ *
+ * \param file Pointer to the file snapshot
+ */
+void ast_bucket_file_temporary_destroy(struct ast_bucket_file *file);
#if defined(__cplusplus) || defined(c_plusplus)
}
Modified: team/file/bucket/main/bucket.c
URL: http://svnview.digium.com/svn/asterisk/team/file/bucket/main/bucket.c?view=diff&rev=396897&r1=396896&r2=396897
==============================================================================
--- team/file/bucket/main/bucket.c (original)
+++ team/file/bucket/main/bucket.c Sat Aug 17 10:26:49 2013
@@ -50,12 +50,6 @@
/*! \brief Number of buckets for the container of schemes */
#define SCHEME_BUCKETS 53
-/*! \brief Number of buckets for the container of bucket URIs in a bucket */
-#define BUCKET_BUCKETS 53
-
-/*! \brief Number of buckets for the container of file URIs in a bucket */
-#define FILE_BUCKETS 53
-
/*! \brief Number of buckets for the container of metadata in a file */
#define METADATA_BUCKETS 53
@@ -66,11 +60,15 @@
static struct ao2_container *schemes;
/*! \brief Structure for available schemes */
-struct bucket_scheme {
+struct ast_bucket_scheme {
/*! \brief Wizard for buckets */
struct ast_sorcery_wizard *bucket;
/*! \brief Wizard for files */
struct ast_sorcery_wizard *file;
+ /*! \brief Pointer to the file snapshot creation callback */
+ bucket_file_create_cb create;
+ /*! \brief Pointer to the file snapshot destruction callback */
+ bucket_file_destroy_cb destroy;
/*! \brief Name of the scheme */
char name[0];
};
@@ -79,14 +77,8 @@
static int bucket_wizard_create(const struct ast_sorcery *sorcery, void *data, void *object)
{
struct ast_bucket *bucket = object;
- SCOPED_AO2RDLOCK(lock, schemes);
- RAII_VAR(struct bucket_scheme *, scheme, ao2_find(schemes, bucket->scheme, OBJ_KEY | OBJ_NOLOCK), ao2_cleanup);
-
- if (!scheme) {
- return -1;
- }
-
- return scheme->bucket->create(sorcery, data, object);
+
+ return bucket->scheme_impl->bucket->create(sorcery, data, object);
}
/*! \brief Callback function for retrieving a bucket */
@@ -98,7 +90,7 @@
SCOPED_AO2RDLOCK(lock, schemes);
size_t len;
char *uri_scheme;
- RAII_VAR(struct bucket_scheme *, scheme, NULL, ao2_cleanup);
+ RAII_VAR(struct ast_bucket_scheme *, scheme, NULL, ao2_cleanup);
state.uri = &uri;
if (uriParseUriA(&state, id) != URI_SUCCESS ||
@@ -126,14 +118,8 @@
static int bucket_wizard_delete(const struct ast_sorcery *sorcery, void *data, void *object)
{
struct ast_bucket *bucket = object;
- SCOPED_AO2RDLOCK(lock, schemes);
- RAII_VAR(struct bucket_scheme *, scheme, ao2_find(schemes, bucket->scheme, OBJ_KEY | OBJ_NOLOCK), ao2_cleanup);
-
- if (!scheme) {
- return -1;
- }
-
- return scheme->bucket->delete(sorcery, data, object);
+
+ return bucket->scheme_impl->bucket->delete(sorcery, data, object);
}
/*! \brief Intermediary bucket wizard */
@@ -148,14 +134,8 @@
static int bucket_file_wizard_create(const struct ast_sorcery *sorcery, void *data, void *object)
{
struct ast_bucket_file *file = object;
- SCOPED_AO2RDLOCK(lock, schemes);
- RAII_VAR(struct bucket_scheme *, scheme, ao2_find(schemes, file->scheme, OBJ_KEY | OBJ_NOLOCK), ao2_cleanup);
-
- if (!scheme) {
- return -1;
- }
-
- return scheme->file->create(sorcery, data, object);
+
+ return file->scheme_impl->file->create(sorcery, data, object);
}
/*! \brief Callback function for retrieving a bucket file */
@@ -167,7 +147,7 @@
size_t len;
char *uri_scheme;
SCOPED_AO2RDLOCK(lock, schemes);
- RAII_VAR(struct bucket_scheme *, scheme, NULL, ao2_cleanup);
+ RAII_VAR(struct ast_bucket_scheme *, scheme, NULL, ao2_cleanup);
state.uri = &uri;
if (uriParseUriA(&state, id) != URI_SUCCESS ||
@@ -195,28 +175,16 @@
static int bucket_file_wizard_update(const struct ast_sorcery *sorcery, void *data, void *object)
{
struct ast_bucket_file *file = object;
- SCOPED_AO2RDLOCK(lock, schemes);
- RAII_VAR(struct bucket_scheme *, scheme, ao2_find(schemes, file->scheme, OBJ_KEY | OBJ_NOLOCK), ao2_cleanup);
-
- if (!scheme) {
- return -1;
- }
-
- return scheme->file->update(sorcery, data, object);
+
+ return file->scheme_impl->file->update(sorcery, data, object);
}
/*! \brief Callback function for deleting a bucket file */
static int bucket_file_wizard_delete(const struct ast_sorcery *sorcery, void *data, void *object)
{
struct ast_bucket_file *file = object;
- SCOPED_AO2RDLOCK(lock, schemes);
- RAII_VAR(struct bucket_scheme *, scheme, ao2_find(schemes, file->scheme, OBJ_KEY), ao2_cleanup);
-
- if (!scheme) {
- return -1;
- }
-
- return scheme->file->delete(sorcery, data, object);
+
+ return file->scheme_impl->file->delete(sorcery, data, object);
}
/*! \brief Intermediary file wizard */
@@ -229,13 +197,15 @@
};
int __ast_bucket_scheme_register(const char *name, struct ast_sorcery_wizard *bucket,
- struct ast_sorcery_wizard *file, struct ast_module *module)
+ struct ast_sorcery_wizard *file, bucket_file_create_cb create_cb,
+ bucket_file_destroy_cb destroy_cb, struct ast_module *module)
{
SCOPED_AO2WRLOCK(lock, schemes);
- struct bucket_scheme *scheme;
+ struct ast_bucket_scheme *scheme;
if (ast_strlen_zero(name) || !bucket || !file ||
- !bucket->create || !bucket->delete || !bucket->retrieve_id) {
+ !bucket->create || !bucket->delete || !bucket->retrieve_id ||
+ !create_cb) {
return -1;
}
@@ -252,6 +222,8 @@
strcpy(scheme->name, name);
scheme->bucket = bucket;
scheme->file = file;
+ scheme->create = create_cb;
+ scheme->destroy = destroy_cb;
ao2_link_flags(schemes, scheme, OBJ_NOLOCK);
@@ -316,6 +288,7 @@
{
struct ast_bucket *bucket = obj;
+ ao2_cleanup(bucket->scheme_impl);
ast_string_field_free_memory(bucket);
ao2_cleanup(bucket->buckets);
ao2_cleanup(bucket->files);
@@ -377,6 +350,7 @@
UriUriA full_uri;
size_t len;
char *uri_scheme, *uri_name;
+ RAII_VAR(struct ast_bucket_scheme *, scheme, NULL, ao2_cleanup);
struct ast_bucket *bucket;
state.uri = &full_uri;
@@ -397,9 +371,18 @@
uriFreeUriMembersA(&full_uri);
- if (!(bucket = ast_sorcery_alloc(bucket_sorcery, "bucket", uri))) {
- return NULL;
- }
+ scheme = ao2_find(schemes, uri_scheme, OBJ_KEY);
+ if (!scheme) {
+ return NULL;
+ }
+
+ bucket = ast_sorcery_alloc(bucket_sorcery, "bucket", uri);
+ if (!bucket) {
+ return NULL;
+ }
+
+ ao2_ref(scheme, +1);
+ bucket->scheme_impl = scheme;
ast_string_field_set(bucket, name, uri_name);
ast_string_field_set(bucket, scheme, uri_scheme);
@@ -544,11 +527,12 @@
{
struct ast_bucket_file *file = obj;
+ if (file->scheme_impl->destroy) {
+ file->scheme_impl->destroy(file);
+ }
+
+ ao2_cleanup(file->scheme_impl);
ao2_cleanup(file->metadata);
-
- if (!ast_strlen_zero(file->path)) {
- unlink(file->path);
- }
}
/*! \brief Allocator for bucket files */
@@ -581,8 +565,8 @@
UriUriA full_uri;
size_t len;
char *uri_scheme, *uri_name;
+ RAII_VAR(struct ast_bucket_scheme *, scheme, NULL, ao2_cleanup);
struct ast_bucket_file *file;
- int fd;
state.uri = &full_uri;
if (uriParseUriA(&state, uri) != URI_SUCCESS ||
@@ -602,18 +586,24 @@
uriFreeUriMembersA(&full_uri);
- if (!(file = ast_sorcery_alloc(bucket_sorcery, "file", uri))) {
- return NULL;
- }
+ scheme = ao2_find(schemes, uri_scheme, OBJ_KEY);
+ if (!scheme) {
+ return NULL;
+ }
+
+ file = ast_sorcery_alloc(bucket_sorcery, "file", uri);
+ if (!file) {
+ return NULL;
+ }
+
+ ao2_ref(scheme, +1);
+ file->scheme_impl = scheme;
ast_string_field_set(file, name, uri_name);
ast_string_field_set(file, scheme, uri_scheme);
- snprintf(file->path, sizeof(file->path), "/tmp/bucket-file-XXXXXX");
-
- fd = mkstemp(file->path);
- if (fd == -1) {
- ao2_cleanup(file);
+ if (scheme->create(file)) {
+ ao2_ref(file, -1);
return NULL;
}
@@ -761,10 +751,32 @@
return json;
}
+int ast_bucket_file_temporary_create(struct ast_bucket_file *file)
+{
+ int fd;
+
+ ast_copy_string(file->path, "/tmp/bucket-XXXXXX", sizeof(file->path));
+
+ fd = mkstemp(file->path);
+ if (fd < 0) {
+ return -1;
+ }
+
+ close(fd);
+ return 0;
+}
+
+void ast_bucket_file_temporary_destroy(struct ast_bucket_file *file)
+{
+ if (!ast_strlen_zero(file->path)) {
+ unlink(file->path);
+ }
+}
+
/*! \brief Hashing function for scheme container */
static int bucket_scheme_hash(const void *obj, const int flags)
{
- const struct bucket_scheme *object;
+ const struct ast_bucket_scheme *object;
const char *key;
switch (flags & (OBJ_POINTER | OBJ_KEY | OBJ_PARTIAL_KEY)) {
@@ -784,7 +796,7 @@
/*! \brief Comparison function for scheme container */
static int bucket_scheme_cmp(void *obj, void *arg, int flags)
{
- struct bucket_scheme *scheme1 = obj, *scheme2 = arg;
+ struct ast_bucket_scheme *scheme1 = obj, *scheme2 = arg;
const char *name = arg;
return !strcmp(scheme1->name, flags & OBJ_KEY ? name : scheme2->name) ? CMP_MATCH | CMP_STOP : 0;
Modified: team/file/bucket/tests/test_bucket.c
URL: http://svnview.digium.com/svn/asterisk/team/file/bucket/tests/test_bucket.c?view=diff&rev=396897&r1=396896&r2=396897
==============================================================================
--- team/file/bucket/tests/test_bucket.c (original)
+++ team/file/bucket/tests/test_bucket.c Sat Aug 17 10:26:49 2013
@@ -136,12 +136,12 @@
break;
}
- if (!ast_bucket_scheme_register("", NULL, NULL)) {
+ if (!ast_bucket_scheme_register("", NULL, NULL, NULL, NULL)) {
ast_test_status_update(test, "Successfully registered a Bucket scheme without name or wizards\n");
return AST_TEST_FAIL;
}
- if (!ast_bucket_scheme_register("test", &bucket_test_wizard, &bucket_file_test_wizard)) {
+ if (!ast_bucket_scheme_register("test", &bucket_test_wizard, &bucket_file_test_wizard, NULL, NULL)) {
ast_test_status_update(test, "Successfully registered a Bucket scheme twice\n");
return AST_TEST_FAIL;
}
@@ -170,24 +170,24 @@
return AST_TEST_FAIL;
}
- if ((bucket = ast_bucket_alloc("goat://"))) {
+ if ((bucket = ast_bucket_alloc("test://"))) {
ast_test_status_update(test, "Allocated a bucket with no name\n");
return AST_TEST_FAIL;
}
- if (!(bucket = ast_bucket_alloc("goat:///tmp/bob"))) {
+ if (!(bucket = ast_bucket_alloc("test:///tmp/bob"))) {
ast_test_status_update(test, "Failed to allocate bucket\n");
return AST_TEST_FAIL;
}
- if (strcmp(ast_sorcery_object_get_id(bucket), "goat:///tmp/bob")) {
- ast_test_status_update(test, "URI within allocated bucket is '%s' and should be goat:///tmp/bob\n",
+ if (strcmp(ast_sorcery_object_get_id(bucket), "test:///tmp/bob")) {
+ ast_test_status_update(test, "URI within allocated bucket is '%s' and should be test:///tmp/bob\n",
ast_sorcery_object_get_id(bucket));
return AST_TEST_FAIL;
}
- if (strcmp(bucket->scheme, "goat")) {
- ast_test_status_update(test, "Scheme within allocated bucket is '%s' and should be goat\n",
+ if (strcmp(bucket->scheme, "test")) {
+ ast_test_status_update(test, "Scheme within allocated bucket is '%s' and should be test\n",
bucket->scheme);
return AST_TEST_FAIL;
}
@@ -383,29 +383,29 @@
return AST_TEST_FAIL;
}
- if ((file = ast_bucket_file_alloc("goat://"))) {
+ if ((file = ast_bucket_file_alloc("test://"))) {
ast_test_status_update(test, "Allocated a file with no name\n");
return AST_TEST_FAIL;
}
- if (!(file = ast_bucket_file_alloc("goat:///tmp/bob"))) {
+ if (!(file = ast_bucket_file_alloc("test:///tmp/bob"))) {
ast_test_status_update(test, "Failed to allocate file\n");
return AST_TEST_FAIL;
}
if (ast_strlen_zero(file->path)) {
- ast_test_status_update(test, "Expected path to temporary file in allocated file but have nothing\n");
- return AST_TEST_FAIL;
- }
-
- if (strcmp(ast_sorcery_object_get_id(file), "goat:///tmp/bob")) {
- ast_test_status_update(test, "URI within allocated file is '%s' and should be goat:///tmp/bob\n",
+ ast_test_status_update(test, "Expected temporary path in allocated file");
+ return AST_TEST_FAIL;
+ }
+
+ if (strcmp(ast_sorcery_object_get_id(file), "test:///tmp/bob")) {
+ ast_test_status_update(test, "URI within allocated file is '%s' and should be test:///tmp/bob\n",
ast_sorcery_object_get_id(file));
return AST_TEST_FAIL;
}
- if (strcmp(file->scheme, "goat")) {
- ast_test_status_update(test, "Scheme within allocated file is '%s' and should be goat\n",
+ if (strcmp(file->scheme, "test")) {
+ ast_test_status_update(test, "Scheme within allocated file is '%s' and should be test\n",
file->scheme);
return AST_TEST_FAIL;
}
@@ -413,59 +413,6 @@
if (strcmp(file->name, "bob")) {
ast_test_status_update(test, "File id is '%s' and should be bob\n",
ast_sorcery_object_get_id(file));
- return AST_TEST_FAIL;
- }
-
- return AST_TEST_PASS;
-}
-
-AST_TEST_DEFINE(bucket_file_temporary_deletion)
-{
- RAII_VAR(struct ast_bucket_file *, file, NULL, ao2_cleanup);
- FILE *temporary;
- struct stat st;
- char path[PATH_MAX];
-
- switch (cmd) {
- case TEST_INIT:
- info->name = "bucket_file_temporary_deletion";
- info->category = "/main/bucket/";
- info->summary = "bucket temporary file deletion unit test";
- info->description =
- "Test deletion of temporary bucket files";
- return AST_TEST_NOT_RUN;
- case TEST_EXECUTE:
- break;
- }
-
- if (!(file = ast_bucket_file_alloc("goat:///tmp/bob"))) {
- ast_test_status_update(test, "Failed to allocate file\n");
- return AST_TEST_FAIL;
- }
-
- if (!(temporary = fopen(file->path, "w"))) {
- ast_test_status_update(test, "Failed to open temporary file '%s'\n",
- file->path);
- return AST_TEST_FAIL;
- }
-
- fprintf(temporary, "bob");
- fclose(temporary);
-
- if (stat(file->path, &st)) {
- ast_test_status_update(test, "Temporary file '%s' did not exist after creating it\n",
- file->path);
- return AST_TEST_FAIL;
- }
-
- ast_copy_string(path, file->path, sizeof(path));
-
- ao2_cleanup(file);
- file = NULL;
-
- if (!stat(path, &st)) {
- ast_test_status_update(test, "Temporary file '%s' continued to exist after destroying it\n",
- path);
return AST_TEST_FAIL;
}
@@ -535,7 +482,7 @@
break;
}
- if (!(file = ast_bucket_file_alloc("goat:///tmp/bob"))) {
+ if (!(file = ast_bucket_file_alloc("test:///tmp/bob"))) {
ast_test_status_update(test, "Failed to allocate file\n");
return AST_TEST_FAIL;
}
@@ -550,8 +497,8 @@
fprintf(temporary, "bob");
fclose(temporary);
- if (!(copy = ast_bucket_file_copy(file, "goat:///tmp/bob2"))) {
- ast_test_status_update(test, "Failed to copy file '%s' to goat:///tmp/bob2\n",
+ if (!(copy = ast_bucket_file_copy(file, "test:///tmp/bob2"))) {
+ ast_test_status_update(test, "Failed to copy file '%s' to test:///tmp/bob2\n",
ast_sorcery_object_get_id(file));
return AST_TEST_FAIL;
}
@@ -906,7 +853,6 @@
AST_TEST_UNREGISTER(bucket_retrieve);
AST_TEST_UNREGISTER(bucket_json);
AST_TEST_UNREGISTER(bucket_file_alloc);
- AST_TEST_UNREGISTER(bucket_file_temporary_deletion);
AST_TEST_UNREGISTER(bucket_file_create);
AST_TEST_UNREGISTER(bucket_file_copy);
AST_TEST_UNREGISTER(bucket_file_retrieve);
@@ -921,7 +867,8 @@
static int load_module(void)
{
- if (ast_bucket_scheme_register("test", &bucket_test_wizard, &bucket_file_test_wizard)) {
+ if (ast_bucket_scheme_register("test", &bucket_test_wizard, &bucket_file_test_wizard,
+ ast_bucket_file_temporary_create, ast_bucket_file_temporary_destroy)) {
ast_log(LOG_ERROR, "Failed to register Bucket test wizard scheme implementation\n");
return AST_MODULE_LOAD_FAILURE;
}
@@ -933,7 +880,6 @@
AST_TEST_REGISTER(bucket_retrieve);
AST_TEST_REGISTER(bucket_json);
AST_TEST_REGISTER(bucket_file_alloc);
- AST_TEST_REGISTER(bucket_file_temporary_deletion);
AST_TEST_REGISTER(bucket_file_create);
AST_TEST_REGISTER(bucket_file_copy);
AST_TEST_REGISTER(bucket_file_retrieve);
More information about the asterisk-commits
mailing list