From 1d2d771f99afb793115805a826521d67cee4b7d2 Mon Sep 17 00:00:00 2001 From: Christine Caulfield Date: Wed, 3 Sep 2008 07:58:08 +0000 Subject: [PATCH] This patch adds key_increment and key_decrement calls to the objdb and confdb subsystems. This is useful to provide atomic counters (ag handle numbers) for long-running (though not persistent) connections. It's not currently possible via confdb to atomically get a new number from objdb due to the lack of locking. Doing it via increment operations in the IPC thread provides enough atomicity to make it useful. Fabio has already identified a use for these calls. It could also provide some form of basic co-operative locking mechanism for IPC-using processes (not direct objdb calls). git-svn-id: http://svn.fedorahosted.org/svn/corosync/trunk@1662 fd59a12c-fef9-0310-b244-a6a79926bd2f --- Makefile | 10 +-- Makefile.inc | 2 +- exec/apidef.c | 2 + exec/objdb.c | 88 +++++++++++++++++++++++ include/corosync/confdb.h | 14 ++++ include/corosync/engine/coroapi.h | 12 ++++ include/corosync/engine/objdb.h | 12 ++++ include/corosync/ipc_confdb.h | 13 +++- lib/confdb.c | 115 ++++++++++++++++++++++++++++++ lib/sa-confdb.c | 28 ++++++++ services/confdb.c | 55 ++++++++++++++ test/testconfdb.c | 29 ++++++++ 12 files changed, 372 insertions(+), 8 deletions(-) diff --git a/Makefile b/Makefile index bae235ab..e2552341 100644 --- a/Makefile +++ b/Makefile @@ -98,11 +98,11 @@ help: @echo " doxygen - doxygen html docs" @echo @echo "Options: (* - default)" - @echo " OPENCOROSYNC [DEBUG/RELEASE*] - Enable/Disable debug symbols" - @echo " DESTDIR [directory] - Install prefix." - @echo " O [directory] - Locate all output files in \"dir\"." - @echo " BUILD_DYNAMIC [1*/0] - Enable/disable dynamic loading of service handler modules" - @echo " OPENCOROSYNC_PROFILE [1/0*] - Enable profiling" + @echo " COROSYNC_BUILD [DEBUG/RELEASE*] - Enable/Disable debug symbols" + @echo " DESTDIR [directory] - Install prefix." + @echo " O [directory] - Locate all output files in \"dir\"." + @echo " BUILD_DYNAMIC [1*/0] - Enable/disable dynamic loading of service handler modules" + @echo " COROSYNC_PROFILE [1/0*] - Enable profiling" @echo diff --git a/Makefile.inc b/Makefile.inc index 114cda22..b3d8f4cb 100644 --- a/Makefile.inc +++ b/Makefile.inc @@ -66,7 +66,7 @@ endif LDFLAGS += endif ifeq (${COROSYNC_BUILD}, DEBUG) - CFLAGS += -O0 -g -Wall -DDEBUG + CFLAGS += -O0 -g -Wall -DDEBUG --time LDFLAGS += -g ifeq (${COROSYNC_COMPAT}, SOLARIS) CFLAGS += -Werror -DTS_CLASS diff --git a/exec/apidef.c b/exec/apidef.c index 36423663..d24c3071 100644 --- a/exec/apidef.c +++ b/exec/apidef.c @@ -124,6 +124,8 @@ void apidef_init (struct objdb_iface_ver0 *objdb) { apidef_corosync_api_v1.object_track_stop = objdb->object_track_stop; apidef_corosync_api_v1.object_write_config = objdb->object_write_config; apidef_corosync_api_v1.object_reload_config = objdb->object_reload_config; + apidef_corosync_api_v1.object_key_increment = objdb->object_key_increment; + apidef_corosync_api_v1.object_key_decrement = objdb->object_key_decrement; } struct corosync_api_v1 *apidef_get (void) diff --git a/exec/objdb.c b/exec/objdb.c index b39d3343..28ec17f7 100644 --- a/exec/objdb.c +++ b/exec/objdb.c @@ -772,6 +772,92 @@ error_exit: return (-1); } +static int object_key_increment ( + unsigned int object_handle, + void *key_name, + int key_len, + unsigned int *value) +{ + unsigned int res = 0; + struct object_instance *instance; + struct object_key *object_key = NULL; + struct list_head *list; + int found = 0; + + res = hdb_handle_get (&object_instance_database, + object_handle, (void *)&instance); + if (res != 0) { + goto error_exit; + } + for (list = instance->key_head.next; + list != &instance->key_head; list = list->next) { + + object_key = list_entry (list, struct object_key, list); + + if ((object_key->key_len == key_len) && + (memcmp (object_key->key_name, key_name, key_len) == 0)) { + found = 1; + break; + } + } + if (found && object_key->value_len == sizeof(int)) { + (*(int *)object_key->value)++; + *value = *(int *)object_key->value; + } + else { + res = -1; + } + + hdb_handle_put (&object_instance_database, object_handle); + return (res); + +error_exit: + return (-1); +} + +static int object_key_decrement ( + unsigned int object_handle, + void *key_name, + int key_len, + unsigned int *value) +{ + unsigned int res = 0; + struct object_instance *instance; + struct object_key *object_key = NULL; + struct list_head *list; + int found = 0; + + res = hdb_handle_get (&object_instance_database, + object_handle, (void *)&instance); + if (res != 0) { + goto error_exit; + } + for (list = instance->key_head.next; + list != &instance->key_head; list = list->next) { + + object_key = list_entry (list, struct object_key, list); + + if ((object_key->key_len == key_len) && + (memcmp (object_key->key_name, key_name, key_len) == 0)) { + found = 1; + break; + } + } + if (found && object_key->value_len == sizeof(int)) { + (*(int *)object_key->value)--; + *value = *(int *)object_key->value; + } + else { + res = -1; + } + + hdb_handle_put (&object_instance_database, object_handle); + return (res); + +error_exit: + return (-1); +} + static int object_key_delete ( unsigned int object_handle, void *key_name, @@ -1306,6 +1392,8 @@ struct objdb_iface_ver0 objdb_iface = { .object_dump = object_dump, .object_write_config = object_write_config, .object_reload_config = object_reload_config, + .object_key_increment = object_key_increment, + .object_key_decrement = object_key_decrement, }; struct lcr_iface objdb_iface_ver0[1] = { diff --git a/include/corosync/confdb.h b/include/corosync/confdb.h index ea4baf48..a37f10f9 100644 --- a/include/corosync/confdb.h +++ b/include/corosync/confdb.h @@ -223,6 +223,20 @@ confdb_error_t confdb_key_replace ( void *new_value, int new_value_len); +confdb_error_t confdb_key_increment ( + confdb_handle_t handle, + unsigned int parent_object_handle, + void *key_name, + int key_name_len, + unsigned int *value); + +confdb_error_t confdb_key_decrement ( + confdb_handle_t handle, + unsigned int parent_object_handle, + void *key_name, + int key_name_len, + unsigned int *value); + /* * Object queries * "find" loops through all objects of a given name and is also diff --git a/include/corosync/engine/coroapi.h b/include/corosync/engine/coroapi.h index 9100c9db..35757eaf 100644 --- a/include/corosync/engine/coroapi.h +++ b/include/corosync/engine/coroapi.h @@ -281,6 +281,18 @@ struct corosync_api_v1 { int (*object_reload_config) (int flush, char **error_string); + int (*object_key_increment) ( + unsigned int object_handle, + void *key_name, + int key_len, + unsigned int *value); + + int (*object_key_decrement) ( + unsigned int object_handle, + void *key_name, + int key_len, + unsigned int *value); + /* * Time and timer APIs */ diff --git a/include/corosync/engine/objdb.h b/include/corosync/engine/objdb.h index 5a85d499..c2be7e32 100644 --- a/include/corosync/engine/objdb.h +++ b/include/corosync/engine/objdb.h @@ -211,6 +211,18 @@ struct objdb_iface_ver0 { int (*object_reload_config) ( int flush, char **error_string); + + int (*object_key_increment) ( + unsigned int object_handle, + void *key_name, + int key_len, + unsigned int *value); + + int (*object_key_decrement) ( + unsigned int object_handle, + void *key_name, + int key_len, + unsigned int *value); }; #endif /* OBJDB_H_DEFINED */ diff --git a/include/corosync/ipc_confdb.h b/include/corosync/ipc_confdb.h index 40a78c1d..9fea766a 100644 --- a/include/corosync/ipc_confdb.h +++ b/include/corosync/ipc_confdb.h @@ -53,7 +53,9 @@ enum req_confdb_types { MESSAGE_REQ_CONFDB_TRACK_STOP = 11, MESSAGE_REQ_CONFDB_WRITE = 12, MESSAGE_REQ_CONFDB_RELOAD = 13, - MESSAGE_REQ_CONFDB_OBJECT_FIND_DESTROY = 14 + MESSAGE_REQ_CONFDB_OBJECT_FIND_DESTROY = 14, + MESSAGE_REQ_CONFDB_KEY_INCREMENT = 15, + MESSAGE_REQ_CONFDB_KEY_DECREMENT = 16 }; enum res_confdb_types { @@ -74,7 +76,9 @@ enum res_confdb_types { MESSAGE_RES_CONFDB_OBJECT_DESTROY_CALLBACK = 14, MESSAGE_RES_CONFDB_WRITE = 15, MESSAGE_RES_CONFDB_RELOAD = 16, - MESSAGE_RES_CONFDB_OBJECT_FIND_DESTROY = 17 + MESSAGE_RES_CONFDB_OBJECT_FIND_DESTROY = 17, + MESSAGE_RES_CONFDB_KEY_INCREMENT = 18, + MESSAGE_RES_CONFDB_KEY_DECREMENT = 19 }; @@ -181,6 +185,11 @@ struct res_lib_confdb_key_get { mar_name_t value __attribute__((aligned(8))); }; +struct res_lib_confdb_key_incdec { + mar_res_header_t header __attribute__((aligned(8))); + mar_uint32_t value __attribute__((aligned(8))); +}; + struct res_lib_confdb_write { mar_res_header_t header __attribute__((aligned(8))); mar_name_t error __attribute__((aligned(8))); diff --git a/lib/confdb.c b/lib/confdb.c index dc04872e..905f0012 100644 --- a/lib/confdb.c +++ b/lib/confdb.c @@ -898,6 +898,121 @@ error_exit: return (error); } +confdb_error_t confdb_key_increment ( + confdb_handle_t handle, + unsigned int parent_object_handle, + void *key_name, + int key_name_len, + unsigned int *value) +{ + confdb_error_t error; + struct confdb_inst *confdb_inst; + struct iovec iov[2]; + struct req_lib_confdb_key_get req_lib_confdb_key_get; + struct res_lib_confdb_key_incdec res_lib_confdb_key_incdec; + + error = saHandleInstanceGet (&confdb_handle_t_db, handle, (void *)&confdb_inst); + if (error != SA_AIS_OK) { + return (error); + } + + if (confdb_inst->standalone) { + error = SA_AIS_OK; + + if (confdb_sa_key_increment(parent_object_handle, + key_name, key_name_len, + value)) + error = SA_AIS_ERR_ACCESS; + goto error_exit; + } + + req_lib_confdb_key_get.header.size = sizeof (struct req_lib_confdb_key_get); + req_lib_confdb_key_get.header.id = MESSAGE_REQ_CONFDB_KEY_INCREMENT; + req_lib_confdb_key_get.parent_object_handle = parent_object_handle; + memcpy(req_lib_confdb_key_get.key_name.value, key_name, key_name_len); + req_lib_confdb_key_get.key_name.length = key_name_len; + + iov[0].iov_base = (char *)&req_lib_confdb_key_get; + iov[0].iov_len = sizeof (struct req_lib_confdb_key_get); + + pthread_mutex_lock (&confdb_inst->response_mutex); + + error = saSendMsgReceiveReply (confdb_inst->response_fd, iov, 1, + &res_lib_confdb_key_incdec, sizeof (struct res_lib_confdb_key_incdec)); + + pthread_mutex_unlock (&confdb_inst->response_mutex); + if (error != SA_AIS_OK) { + goto error_exit; + } + + error = res_lib_confdb_key_incdec.header.error; + if (error == SA_AIS_OK) { + *value = res_lib_confdb_key_incdec.value; + } + +error_exit: + saHandleInstancePut (&confdb_handle_t_db, handle); + + return (error); +} + +confdb_error_t confdb_key_decrement ( + confdb_handle_t handle, + unsigned int parent_object_handle, + void *key_name, + int key_name_len, + unsigned int *value) +{ + confdb_error_t error; + struct confdb_inst *confdb_inst; + struct iovec iov[2]; + struct req_lib_confdb_key_get req_lib_confdb_key_get; + struct res_lib_confdb_key_incdec res_lib_confdb_key_incdec; + + error = saHandleInstanceGet (&confdb_handle_t_db, handle, (void *)&confdb_inst); + if (error != SA_AIS_OK) { + return (error); + } + + if (confdb_inst->standalone) { + error = SA_AIS_OK; + + if (confdb_sa_key_decrement(parent_object_handle, + key_name, key_name_len, + value)) + error = SA_AIS_ERR_ACCESS; + goto error_exit; + } + + req_lib_confdb_key_get.header.size = sizeof (struct req_lib_confdb_key_get); + req_lib_confdb_key_get.header.id = MESSAGE_REQ_CONFDB_KEY_DECREMENT; + req_lib_confdb_key_get.parent_object_handle = parent_object_handle; + memcpy(req_lib_confdb_key_get.key_name.value, key_name, key_name_len); + req_lib_confdb_key_get.key_name.length = key_name_len; + + iov[0].iov_base = (char *)&req_lib_confdb_key_get; + iov[0].iov_len = sizeof (struct req_lib_confdb_key_get); + + pthread_mutex_lock (&confdb_inst->response_mutex); + + error = saSendMsgReceiveReply (confdb_inst->response_fd, iov, 1, + &res_lib_confdb_key_incdec, sizeof (struct res_lib_confdb_key_incdec)); + + pthread_mutex_unlock (&confdb_inst->response_mutex); + if (error != SA_AIS_OK) { + goto error_exit; + } + + error = res_lib_confdb_key_incdec.header.error; + if (error == SA_AIS_OK) { + *value = res_lib_confdb_key_incdec.value; + } + +error_exit: + saHandleInstancePut (&confdb_handle_t_db, handle); + + return (error); +} confdb_error_t confdb_key_replace ( confdb_handle_t handle, diff --git a/lib/sa-confdb.c b/lib/sa-confdb.c index dac6f65a..1083c7cb 100644 --- a/lib/sa-confdb.c +++ b/lib/sa-confdb.c @@ -250,6 +250,34 @@ int confdb_sa_key_get ( return res; } +int confdb_sa_key_increment ( + unsigned int parent_object_handle, + void *key_name, + int key_name_len, + unsigned int *value) +{ + int res; + + res = objdb->object_key_increment(parent_object_handle, + key_name, key_name_len, + value); + return res; +} + +int confdb_sa_key_decrement ( + unsigned int parent_object_handle, + void *key_name, + int key_name_len, + unsigned int *value) +{ + int res; + + res = objdb->object_key_decrement(parent_object_handle, + key_name, key_name_len, + value); + return res; +} + int confdb_sa_key_replace ( unsigned int parent_object_handle, diff --git a/services/confdb.c b/services/confdb.c index 216b73ff..b517b18f 100644 --- a/services/confdb.c +++ b/services/confdb.c @@ -69,6 +69,9 @@ static void message_handler_req_lib_confdb_key_replace (void *conn, void *messag static void message_handler_req_lib_confdb_key_delete (void *conn, void *message); static void message_handler_req_lib_confdb_key_iter (void *conn, void *message); +static void message_handler_req_lib_confdb_key_increment (void *conn, void *message); +static void message_handler_req_lib_confdb_key_decrement (void *conn, void *message); + static void message_handler_req_lib_confdb_object_iter (void *conn, void *message); static void message_handler_req_lib_confdb_object_find (void *conn, void *message); @@ -189,6 +192,18 @@ static struct corosync_lib_handler confdb_lib_engine[] = .response_id = MESSAGE_RES_CONFDB_OBJECT_FIND_DESTROY, .flow_control = COROSYNC_LIB_FLOW_CONTROL_NOT_REQUIRED }, + { /* 15 */ + .lib_handler_fn = message_handler_req_lib_confdb_key_increment, + .response_size = sizeof (struct res_lib_confdb_key_incdec), + .response_id = MESSAGE_RES_CONFDB_KEY_INCREMENT, + .flow_control = COROSYNC_LIB_FLOW_CONTROL_NOT_REQUIRED + }, + { /* 16 */ + .lib_handler_fn = message_handler_req_lib_confdb_key_decrement, + .response_size = sizeof (struct res_lib_confdb_key_incdec), + .response_id = MESSAGE_RES_CONFDB_KEY_DECREMENT, + .flow_control = COROSYNC_LIB_FLOW_CONTROL_NOT_REQUIRED + }, }; @@ -365,6 +380,46 @@ static void message_handler_req_lib_confdb_key_get (void *conn, void *message) api->ipc_conn_send_response(conn, &res_lib_confdb_key_get, sizeof(res_lib_confdb_key_get)); } +static void message_handler_req_lib_confdb_key_increment (void *conn, void *message) +{ + struct req_lib_confdb_key_get *req_lib_confdb_key_get = (struct req_lib_confdb_key_get *)message; + struct res_lib_confdb_key_incdec res_lib_confdb_key_incdec; + int value_len; + void *value; + int ret = SA_AIS_OK; + + if (api->object_key_increment(req_lib_confdb_key_get->parent_object_handle, + req_lib_confdb_key_get->key_name.value, + req_lib_confdb_key_get->key_name.length, + &res_lib_confdb_key_incdec.value)) + ret = SA_AIS_ERR_ACCESS; + + res_lib_confdb_key_incdec.header.size = sizeof(res_lib_confdb_key_incdec); + res_lib_confdb_key_incdec.header.id = MESSAGE_RES_CONFDB_KEY_INCREMENT; + res_lib_confdb_key_incdec.header.error = ret; + api->ipc_conn_send_response(conn, &res_lib_confdb_key_incdec, sizeof(res_lib_confdb_key_incdec)); +} + +static void message_handler_req_lib_confdb_key_decrement (void *conn, void *message) +{ + struct req_lib_confdb_key_get *req_lib_confdb_key_get = (struct req_lib_confdb_key_get *)message; + struct res_lib_confdb_key_incdec res_lib_confdb_key_incdec; + int value_len; + void *value; + int ret = SA_AIS_OK; + + if (api->object_key_decrement(req_lib_confdb_key_get->parent_object_handle, + req_lib_confdb_key_get->key_name.value, + req_lib_confdb_key_get->key_name.length, + &res_lib_confdb_key_incdec.value)) + ret = SA_AIS_ERR_ACCESS; + + res_lib_confdb_key_incdec.header.size = sizeof(res_lib_confdb_key_incdec); + res_lib_confdb_key_incdec.header.id = MESSAGE_RES_CONFDB_KEY_DECREMENT; + res_lib_confdb_key_incdec.header.error = ret; + api->ipc_conn_send_response(conn, &res_lib_confdb_key_incdec, sizeof(res_lib_confdb_key_incdec)); +} + static void message_handler_req_lib_confdb_key_replace (void *conn, void *message) { struct req_lib_confdb_key_replace *req_lib_confdb_key_replace = (struct req_lib_confdb_key_replace *)message; diff --git a/test/testconfdb.c b/test/testconfdb.c index 09c1b3fe..be16718f 100644 --- a/test/testconfdb.c +++ b/test/testconfdb.c @@ -44,6 +44,7 @@ #include #include +#define INCDEC_VALUE 45 /* Callbacks are not supported yet */ confdb_callbacks_t callbacks = { @@ -109,6 +110,7 @@ static void print_config_tree(confdb_handle_t handle, unsigned int parent_object static void do_write_tests(confdb_handle_t handle) { int res; + unsigned int incdec_value; unsigned int object_handle; char error_string[1024]; @@ -147,6 +149,33 @@ static void do_write_tests(confdb_handle_t handle) /* Print it for verification */ print_config_tree(handle, object_handle, 0); + + incdec_value = INCDEC_VALUE; + res = confdb_key_create(handle, object_handle, "incdec", strlen("incdec"), &incdec_value, sizeof(incdec_value)); + if (res != SA_AIS_OK) { + printf( "error creating 'testconfdb' key 4: %d\n", res); + return; + } + res = confdb_key_increment(handle, object_handle, "incdec", strlen("incdec"), &incdec_value); + if (res != SA_AIS_OK) { + printf( "error incrementing 'testconfdb' key 4: %d\n", res); + return; + } + if (incdec_value == INCDEC_VALUE+1) + printf("incremented value = %d\n", incdec_value); + else + printf("ERROR: incremented value = %d (should be %d)\n", incdec_value, INCDEC_VALUE+1); + + res = confdb_key_decrement(handle, object_handle, "incdec", strlen("incdec"), &incdec_value); + if (res != SA_AIS_OK) { + printf( "error decrementing 'testconfdb' key 4: %d\n", res); + return; + } + if (incdec_value == INCDEC_VALUE) + printf("decremented value = %d\n", incdec_value); + else + printf("ERROR: decremented value = %d (should be %d)\n", incdec_value, INCDEC_VALUE); + printf("-------------------------\n"); /* Remove it.