diff options
Diffstat (limited to 'ctdb/common/srvid.c')
-rw-r--r-- | ctdb/common/srvid.c | 280 |
1 files changed, 280 insertions, 0 deletions
diff --git a/ctdb/common/srvid.c b/ctdb/common/srvid.c new file mode 100644 index 0000000..3304994 --- /dev/null +++ b/ctdb/common/srvid.c @@ -0,0 +1,280 @@ +/* + 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, 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; + } + if (list->h == NULL) { + return ENOENT; + } + + if (private_data != NULL) { + for (h = list->h; h != NULL; h = h->next) { + if (h->private_data == private_data) { + return 0; + } + } + + 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; +} |