diff options
author | Amitay Isaacs <amitay@gmail.com> | 2015-03-16 23:25:27 +1100 |
---|---|---|
committer | Amitay Isaacs <amitay@samba.org> | 2015-10-07 14:53:28 +0200 |
commit | 6272ef0d09930ffbff43c6223ea35858d13efffa (patch) | |
tree | 9488286f4ede7c78fcfe3561f58e55cf5f3dbbdd /ctdb | |
parent | e5592f9fc018b4b22fbdba4f45526210f5f41692 (diff) | |
download | samba-6272ef0d09930ffbff43c6223ea35858d13efffa.tar.gz |
ctdb-common: Add srvid abstraction
Attempt to make common code independent and free from ctdb_context.
Signed-off-by: Amitay Isaacs <amitay@gmail.com>
Reviewed-by: Martin Schwenke <martin@meltin.net>
Diffstat (limited to 'ctdb')
-rw-r--r-- | ctdb/common/srvid.c | 269 | ||||
-rw-r--r-- | ctdb/common/srvid.h | 115 | ||||
-rwxr-xr-x | ctdb/tests/cunit/srvid_test_001.sh | 7 | ||||
-rw-r--r-- | ctdb/tests/src/srvid_test.c | 78 | ||||
-rwxr-xr-x | ctdb/wscript | 3 |
5 files changed, 471 insertions, 1 deletions
diff --git a/ctdb/common/srvid.c b/ctdb/common/srvid.c new file mode 100644 index 00000000000..f9cd49b4ea3 --- /dev/null +++ b/ctdb/common/srvid.c @@ -0,0 +1,269 @@ +/* + Message handler database based on srvid + + Copyright (C) Amitay Isaacs 2015 + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, see <http://www.gnu.org/licenses/>. +*/ + +#include "replace.h" +#include "system/filesys.h" + +#include <tdb.h> + +#include "lib/util/dlinklist.h" +#include "common/db_hash.h" +#include "common/srvid.h" + +struct srvid_handler_list; + +struct srvid_context { + struct db_hash_context *dh; + struct srvid_handler_list *list; +}; + +struct srvid_handler { + struct srvid_handler *prev, *next; + struct srvid_handler_list *list; + srvid_handler_fn handler; + void *private_data; +}; + +struct srvid_handler_list { + struct srvid_handler_list *prev, *next; + struct srvid_context *srv; + uint64_t srvid; + struct srvid_handler *h; +}; + + +/* + * Initialise message srvid context and database + */ +int srvid_init(TALLOC_CTX *mem_ctx, struct srvid_context **result) +{ + struct srvid_context *srv; + int ret; + + srv = talloc_zero(mem_ctx, struct srvid_context); + if (srv == NULL) { + return ENOMEM; + } + + ret = db_hash_init(srv, "messagedb", 8192, DB_HASH_SIMPLE, &srv->dh); + if (ret != 0) { + talloc_free(srv); + return ret; + } + + *result = srv; + return 0; +} + +/* + * Wrapper functions to insert/delete/fetch srvid_hander_list + */ + +static int srvid_insert(struct srvid_context *srv, uint64_t srvid, + struct srvid_handler_list *list) +{ + return db_hash_insert(srv->dh, (uint8_t *)&srvid, sizeof(uint64_t), + (uint8_t *)&list, sizeof(list)); +} + +static int srvid_delete(struct srvid_context *srv, uint64_t srvid) +{ + return db_hash_delete(srv->dh, (uint8_t *)&srvid, sizeof(uint64_t)); +} + +static int srvid_fetch_parser(uint8_t *keybuf, size_t keylen, + uint8_t *databuf, size_t datalen, + void *private_data) +{ + struct srvid_handler_list **list = + (struct srvid_handler_list **)private_data; + + if (datalen != sizeof(*list)) { + return EIO; + } + + *list = *(struct srvid_handler_list **)databuf; + return 0; +} + +static int srvid_fetch(struct srvid_context *srv, uint64_t srvid, + struct srvid_handler_list **list) +{ + return db_hash_fetch(srv->dh, (uint8_t *)&srvid, sizeof(uint64_t), + srvid_fetch_parser, list); +} + +/* + * When a handler is freed, remove it from the list + */ +static int srvid_handler_destructor(struct srvid_handler *h) +{ + struct srvid_handler_list *list = h->list; + + DLIST_REMOVE(list->h, h); + if (list->h == NULL) { + talloc_free(list); + } + return 0; +} + +/* + * When a list is freed, remove all handlers and remove db entry + */ +static int srvid_handler_list_destructor(struct srvid_handler_list *list) +{ + struct srvid_handler *h; + + while (list->h != NULL) { + h = list->h; + DLIST_REMOVE(list->h, h); + TALLOC_FREE(h); + } + + srvid_delete(list->srv, list->srvid); + DLIST_REMOVE(list->srv->list, list); + return 0; +} + +/* + * Register a message handler + */ +int srvid_register(struct srvid_context *srv, TALLOC_CTX *mem_ctx, + uint64_t srvid, srvid_handler_fn handler, + void *private_data) +{ + struct srvid_handler_list *list; + struct srvid_handler *h; + int ret; + + if (srv == NULL) { + return EINVAL; + } + + h = talloc_zero(mem_ctx, struct srvid_handler); + if (h == NULL) { + return ENOMEM; + } + + h->handler = handler; + h->private_data = private_data; + + ret = srvid_fetch(srv, srvid, &list); + if (ret != 0) { + /* srvid not yet registered */ + list = talloc_zero(srv, struct srvid_handler_list); + if (list == NULL) { + talloc_free(h); + return ENOMEM; + } + + list->srv = srv; + list->srvid = srvid; + + ret = srvid_insert(srv, srvid, list); + if (ret != 0) { + talloc_free(h); + talloc_free(list); + return ret; + } + + DLIST_ADD(srv->list, list); + talloc_set_destructor(list, srvid_handler_list_destructor); + } + + h->list = list; + DLIST_ADD(list->h, h); + talloc_set_destructor(h, srvid_handler_destructor); + return 0; +} + +/* + * Deregister a message handler + */ +int srvid_deregister(struct srvid_context *srv, uint64_t srvid, + void *private_data) +{ + struct srvid_handler_list *list; + struct srvid_handler *h; + int ret; + + ret = srvid_fetch(srv, srvid, &list); + if (ret != 0) { + return ret; + } + + for (h = list->h; h != NULL; h = h->next) { + if (h->private_data == private_data) { + talloc_free(h); + return 0; + } + } + + return ENOENT; +} + +/* + * Check if a message handler exists + */ +int srvid_exists(struct srvid_context *srv, uint64_t srvid) +{ + struct srvid_handler_list *list; + int ret; + + ret = srvid_fetch(srv, srvid, &list); + if (ret != 0) { + return ret; + } + if (list->h == NULL) { + return ENOENT; + } + + return 0; +} + +/* + * Send a message to registered srvid and srvid_all + */ +int srvid_dispatch(struct srvid_context *srv, uint64_t srvid, + uint64_t srvid_all, TDB_DATA data) +{ + struct srvid_handler_list *list; + struct srvid_handler *h; + int ret; + + ret = srvid_fetch(srv, srvid, &list); + if (ret == 0) { + for (h = list->h; h != NULL; h = h->next) { + h->handler(srvid, data, h->private_data); + } + } + + if (srvid_all == 0) { + return ret; + } + + ret = srvid_fetch(srv, srvid_all, &list); + if (ret == 0) { + for (h = list->h; h != NULL; h = h->next) { + h->handler(srvid, data, h->private_data); + } + } + + return ret; +} diff --git a/ctdb/common/srvid.h b/ctdb/common/srvid.h new file mode 100644 index 00000000000..f048b5c6cbf --- /dev/null +++ b/ctdb/common/srvid.h @@ -0,0 +1,115 @@ +/* + Message handler database based on srvid + + Copyright (C) Amitay Isaacs 2015 + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, see <http://www.gnu.org/licenses/>. +*/ + +#ifndef __CTDB_SRVID_H__ +#define __CTDB_SRVID_H__ + +#include <talloc.h> +#include <tdb.h> + +/** + * @file srvid.h + * + * @brief Database of message handlers based on srvid + * + * CTDB can be used to send messages between clients across nodes using + * CTDB_REQ_MESSAGE. Clients register for mesages based on srvid. CTDB itself + * uses a small set of srvid messages. A large range (2^56) of srvid messages + * is reserved for Samba. + */ + +/** + * @brief Message handler function + * + * To receive messages for a specific srvid, register a message handler function + * for the srvid. + */ +typedef void (*srvid_handler_fn)(uint64_t srvid, TDB_DATA data, + void *private_data); + +/** + * @brief Abstract struct to store srvid message handler database + */ +struct srvid_context; + +/** + * @brief Initialize srvid message handler database + * + * This returns a new srvid message handler database context. Freeing + * this context will free all the memory associated with the hash table. + * + * @param[in] mem_ctx Talloc memory context + * @param[out] result The new db_hash_context structure + * @return 0 on success, errno on failure + */ +int srvid_init(TALLOC_CTX *mem_ctx, struct srvid_context **result); + +/** + * @brief Register a message handler for a srvid + * + * The message handler is allocated using the specified talloc context. Freeing + * this talloc context, removes the message handler. + * + * @param[in] srv The srvid message handler database context + * @param[in] mem_ctx Talloc memory context for message handler + * @param[in] srvid The srvid + * @param[in] handler The message handler function for srvid + * @param[in] private_data Private data for message handler function + * @return 0 on success, errno on failure + */ +int srvid_register(struct srvid_context *srv, TALLOC_CTX *mem_ctx, + uint64_t srvid, srvid_handler_fn handler, + void *private_data); + +/** + * @brief Unregister a message handler for a srvid + * + * @param[in] srv The srvid message handler database context + * @param[in] srvid The srvid + * @param[in] private_data Private data of message handler function + * @return 0 on success, errno on failure + */ +int srvid_deregister(struct srvid_context *srv, uint64_t srvid, + void *private_data); + +/** + * @brief Check if any message handler is registered for srvid + * + * @param[in] srv The srvid message handler database context + * @param[in] srvid The srvid + * @return 0 on success, errno on failure + */ +int srvid_exists(struct srvid_context *srv, uint64_t srvid); + +/** + * @brief Call message handlers for given srvid + * + * @param[in] srv The srvid message handler database context + * @param[in] srvid The srvid + * @param[in] srvid_all The srvid that gets all messages + * @param[in] data The data passed to each message handler + * @return 0 on success, errno on failure + * + * If srvid_all passed is 0, the message is not sent to message handlers + * registered with special srvid to receive all messages. + */ +int srvid_dispatch(struct srvid_context *srv, uint64_t srvid, + uint64_t srvid_all, TDB_DATA data); + +#endif /* __CTDB_SRVID_H__ */ diff --git a/ctdb/tests/cunit/srvid_test_001.sh b/ctdb/tests/cunit/srvid_test_001.sh new file mode 100755 index 00000000000..ed09535b1ee --- /dev/null +++ b/ctdb/tests/cunit/srvid_test_001.sh @@ -0,0 +1,7 @@ +#!/bin/sh + +. "${TEST_SCRIPTS_DIR}/unit.sh" + +ok_null + +unit_test srvid_test diff --git a/ctdb/tests/src/srvid_test.c b/ctdb/tests/src/srvid_test.c new file mode 100644 index 00000000000..f5e94ac3d03 --- /dev/null +++ b/ctdb/tests/src/srvid_test.c @@ -0,0 +1,78 @@ +/* + srvid tests + + Copyright (C) Amitay Isaacs 2015 + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, see <http://www.gnu.org/licenses/>. +*/ + +#include "replace.h" + +#include <assert.h> + +#include "common/db_hash.c" +#include "common/srvid.c" + +#define TEST_SRVID 0xFE11223344556677 + +static void test_handler(uint64_t srvid, TDB_DATA data, void *private_data) +{ + int *count = (int *)private_data; + (*count)++; +} + +int main(void) +{ + struct srvid_context *srv; + TALLOC_CTX *mem_ctx = talloc_new(NULL); + TALLOC_CTX *tmp_ctx = talloc_new(NULL); + int ret; + int count = 0; + + ret = srvid_init(mem_ctx, &srv); + assert(ret == 0); + + ret = srvid_register(srv, tmp_ctx, TEST_SRVID, test_handler, &count); + assert(ret == 0); + + ret = srvid_exists(srv, TEST_SRVID); + assert(ret == 0); + + ret = srvid_dispatch(srv, TEST_SRVID, 0, tdb_null); + assert(ret == 0); + assert(count == 1); + + ret = srvid_deregister(srv, TEST_SRVID, NULL); + assert(ret == ENOENT); + + ret = srvid_deregister(srv, TEST_SRVID, &count); + assert(ret == 0); + + ret = srvid_register(srv, tmp_ctx, TEST_SRVID, test_handler, &count); + assert(ret == 0); + + talloc_free(tmp_ctx); + ret = srvid_exists(srv, TEST_SRVID); + assert(ret == ENOENT); + + ret = srvid_dispatch(srv, TEST_SRVID, 0, tdb_null); + assert(ret == ENOENT); + + talloc_free(srv); + assert(talloc_get_size(mem_ctx) == 0); + + talloc_free(mem_ctx); + + return 0; +} diff --git a/ctdb/wscript b/ctdb/wscript index afd4d0e278c..aaefad3222a 100755 --- a/ctdb/wscript +++ b/ctdb/wscript @@ -333,7 +333,7 @@ def build(bld): bld.SAMBA_SUBSYSTEM('ctdb-util', source=bld.SUBDIR('common', - '''db_hash.c'''), + '''db_hash.c srvid.c'''), deps='replace talloc tevent tdb') bld.SAMBA_SUBSYSTEM('ctdb-client', @@ -573,6 +573,7 @@ def build(bld): # Unit tests ctdb_unit_tests = [ 'db_hash_test', + 'srvid_test', ] for target in ctdb_unit_tests: |