[Openais] [PATCH] Add object tracking to the objdb and confdb
angus salkeld
angus.salkeld at alliedtelesis.co.nz
Mon Aug 4 19:00:10 PDT 2008
Hi
Here is an implementation of object tracking.
I have slightly extended the tracking API already defined to include
an object create & destroy notification.
Regards
Angus
---
corosync/Makefile | 2 +-
corosync/exec/apidef.c | 2 +
corosync/exec/objdb.c | 268 +++++++++++++++++++++++++++++++++++++-
corosync/exec/objdb.h | 44 ++++++-
corosync/include/confdb.h | 33 ++++-
corosync/include/coroapi.h | 49 +++++++-
corosync/include/ipc_confdb.h | 30 ++++-
corosync/include/mar_gen.h | 2 +-
corosync/lib/confdb.c | 148 ++++++++++++++++++---
corosync/man/corosync-objctl.8 | 10 +-
corosync/services/confdb.c | 106 ++++++++++++++-
corosync/test/testconfdb.c | 4 +-
corosync/tools/corosync-objctl.c | 147 ++++++++++++++++++++-
13 files changed, 799 insertions(+), 46 deletions(-)
diff --git a/corosync/Makefile b/corosync/Makefile
index 17758c7..445fcac 100644
--- a/corosync/Makefile
+++ b/corosync/Makefile
@@ -173,7 +173,7 @@ install: all
install -m 755 $(builddir)exec/*lcrso $(DESTDIR)$(LCRSODIR)
install -m 755 $(builddir)services/*lcrso $(DESTDIR)$(LCRSODIR)
install -m 755 $(builddir)exec/corosync $(DESTDIR)$(SBINDIR)
- install -m 755 $(builddir)tools/objctl $(DESTDIR)$(SBINDIR)
+ install -m 755 $(builddir)tools/corosync-objctl $(DESTDIR)$(SBINDIR)
install -m 700 $(builddir)tools/keygen $(DESTDIR)$(SBINDIR)/ais-keygen
if [ ! -f $(DESTDIR)$(ETCDIR)/penais.conf ] ; then \
diff --git a/corosync/exec/apidef.c b/corosync/exec/apidef.c
index 8105a51..c04c586 100644
--- a/corosync/exec/apidef.c
+++ b/corosync/exec/apidef.c
@@ -101,6 +101,8 @@ void apidef_init (struct objdb_iface_ver0 *objdb) {
apidef_corosync_api_v1.object_find_from = objdb->object_find_from;
apidef_corosync_api_v1.object_iter_from = objdb->object_iter_from;
apidef_corosync_api_v1.object_key_iter_from = objdb->object_key_iter_from;
+ apidef_corosync_api_v1.object_track_start = objdb->object_track_start;
+ apidef_corosync_api_v1.object_track_stop = objdb->object_track_stop;
apidef_corosync_api_v1.object_write_config = objdb->object_write_config;
}
diff --git a/corosync/exec/objdb.c b/corosync/exec/objdb.c
index 785aff9..a2cc888 100644
--- a/corosync/exec/objdb.c
+++ b/corosync/exec/objdb.c
@@ -50,6 +50,17 @@ struct object_key {
struct list_head list;
};
+struct object_tracker {
+ unsigned int object_handle;
+ void * data_pt;
+ object_track_depth_t depth;
+ object_key_change_notify_fn_t key_change_notify_fn;
+ object_create_notify_fn_t object_create_notify_fn;
+ object_destroy_notify_fn_t object_destroy_notify_fn;
+ struct list_head tracker_list;
+ struct list_head object_list;
+};
+
struct object_instance {
void *object_name;
int object_name_len;
@@ -66,6 +77,7 @@ struct object_instance {
int object_valid_list_entries;
struct object_key_valid *object_key_valid_list;
int object_key_valid_list_entries;
+ struct list_head track_head;
};
struct object_find_instance {
@@ -76,6 +88,7 @@ struct object_find_instance {
};
struct objdb_iface_ver0 objdb_iface;
+struct list_head objdb_trackers_head;
static struct hdb_handle_database object_instance_database = {
.handle_count = 0,
@@ -118,6 +131,8 @@ static int objdb_init (void)
list_init (&instance->key_head);
list_init (&instance->child_head);
list_init (&instance->child_list);
+ list_init (&instance->track_head);
+ list_init (&objdb_trackers_head);
hdb_handle_put (&object_instance_database, handle);
return (0);
@@ -129,6 +144,153 @@ error_exit:
return (-1);
}
+static int _object_notify_deleted_children(struct object_instance *parent_pt)
+{
+ struct list_head *list;
+ struct list_head *notify_list;
+ int res;
+ struct object_instance *obj_pt = NULL;
+ struct object_tracker * tracker_pt;
+
+ for (list = parent_pt->child_head.next;
+ list != &parent_pt->child_head; list = list->next) {
+
+ obj_pt = list_entry(list, struct object_instance,
+ child_list);
+ res = _object_notify_deleted_children(obj_pt);
+ if (res)
+ return res;
+
+ for (notify_list = obj_pt->track_head.next;
+ notify_list != &obj_pt->track_head;
+ notify_list = notify_list->next) {
+
+ tracker_pt = list_entry (notify_list, struct object_tracker, object_list);
+
+ if ((tracker_pt != NULL) &&
+ (tracker_pt->object_destroy_notify_fn != NULL))
+ tracker_pt->object_destroy_notify_fn(parent_pt->object_handle,
+ obj_pt->object_name,
+ obj_pt->object_name_len,
+ tracker_pt->data_pt);
+ }
+ }
+
+ return 0;
+}
+
+static void object_created_notification(unsigned int object_handle,
+ unsigned int parent_object_handle,
+ void *name_pt, int name_len)
+{
+ struct list_head * list;
+ struct object_instance * obj_pt;
+ struct object_tracker * tracker_pt;
+ unsigned int obj_handle = object_handle;
+ unsigned int res;
+
+ do {
+ res = hdb_handle_get (&object_instance_database,
+ obj_handle, (void *)&obj_pt);
+
+ for (list = obj_pt->track_head.next;
+ list != &obj_pt->track_head; list = list->next) {
+
+ tracker_pt = list_entry (list, struct object_tracker, object_list);
+
+ if (((obj_handle == parent_object_handle) ||
+ (tracker_pt->depth == OBJECT_TRACK_DEPTH_RECURSIVE)) &&
+ (tracker_pt->object_create_notify_fn != NULL)) {
+ tracker_pt->object_create_notify_fn(object_handle, parent_object_handle,
+ name_pt, name_len,
+ tracker_pt->data_pt);
+ }
+ }
+
+ hdb_handle_put (&object_instance_database, obj_handle);
+ obj_handle = obj_pt->parent_handle;
+
+ } while (obj_pt->object_handle != OBJECT_PARENT_HANDLE);
+
+}
+
+static void object_pre_deletion_notification(unsigned int object_handle,
+ unsigned int parent_object_handle,
+ void *name_pt, int name_len)
+{
+ struct list_head * list;
+ struct object_instance * obj_pt;
+ struct object_tracker * tracker_pt;
+ unsigned int obj_handle = object_handle;
+ unsigned int res;
+
+ do {
+ res = hdb_handle_get (&object_instance_database,
+ obj_handle, (void *)&obj_pt);
+
+ for (list = obj_pt->track_head.next;
+ list != &obj_pt->track_head; list = list->next) {
+
+ tracker_pt = list_entry (list, struct object_tracker, object_list);
+
+ if (((obj_handle == parent_object_handle) ||
+ (tracker_pt->depth == OBJECT_TRACK_DEPTH_RECURSIVE)) &&
+ (tracker_pt->object_destroy_notify_fn != NULL)) {
+ tracker_pt->object_destroy_notify_fn(parent_object_handle,
+ name_pt, name_len,
+ tracker_pt->data_pt);
+ }
+ }
+ /* notify child object listeners */
+ if (obj_handle == object_handle)
+ _object_notify_deleted_children(obj_pt);
+
+ hdb_handle_put (&object_instance_database, obj_handle);
+ obj_handle = obj_pt->parent_handle;
+
+ } while (obj_pt->object_handle != OBJECT_PARENT_HANDLE);
+
+}
+
+static void object_key_changed_notification(unsigned int object_handle,
+ void *name_pt, int name_len,
+ void *value_pt, int value_len,
+ object_change_type_t type)
+{
+ struct list_head * list;
+ struct object_instance * obj_pt;
+ struct object_instance * owner_pt = NULL;
+ struct object_tracker * tracker_pt;
+ unsigned int obj_handle = object_handle;
+ unsigned int res;
+
+ do {
+ res = hdb_handle_get (&object_instance_database,
+ obj_handle, (void *)&obj_pt);
+ if (owner_pt == NULL)
+ owner_pt = obj_pt;
+
+ for (list = obj_pt->track_head.next;
+ list != &obj_pt->track_head; list = list->next) {
+
+ tracker_pt = list_entry (list, struct object_tracker, object_list);
+
+ if (((obj_handle == object_handle) ||
+ (tracker_pt->depth == OBJECT_TRACK_DEPTH_RECURSIVE)) &&
+ (tracker_pt->key_change_notify_fn != NULL))
+ tracker_pt->key_change_notify_fn(type, obj_pt->parent_handle, object_handle,
+ owner_pt->object_name, owner_pt->object_name_len,
+ name_pt, name_len,
+ value_pt, value_len,
+ tracker_pt->data_pt);
+ }
+
+ hdb_handle_put (&object_instance_database, obj_handle);
+ obj_handle = obj_pt->parent_handle;
+
+ } while (obj_pt->object_handle != OBJECT_PARENT_HANDLE);
+}
+
/*
* object db create/destroy/set
*/
@@ -189,6 +351,7 @@ static int object_create (
list_init (&object_instance->key_head);
list_init (&object_instance->child_head);
list_init (&object_instance->child_list);
+ list_init (&object_instance->track_head);
object_instance->object_name = malloc (object_name_len);
if (object_instance->object_name == 0) {
goto error_put_destroy;
@@ -211,6 +374,10 @@ static int object_create (
hdb_handle_put (&object_instance_database, *object_handle);
hdb_handle_put (&object_instance_database, parent_object_handle);
+ object_created_notification(object_instance->object_handle,
+ object_instance->parent_handle,
+ object_instance->object_name,
+ object_instance->object_name_len);
return (0);
@@ -322,6 +489,8 @@ static int object_key_create (
list_init (&object_key->list);
list_add (&object_key->list, &instance->key_head);
+ object_key_changed_notification(object_handle, key_name, key_len,
+ value, value_len, OBJECT_KEY_CREATED);
return (0);
@@ -338,7 +507,6 @@ error_exit:
return (-1);
}
-
static int _clear_object(struct object_instance *instance)
{
struct list_head *list;
@@ -390,6 +558,11 @@ static int object_destroy (
return (res);
}
+ object_pre_deletion_notification(object_handle,
+ instance->parent_handle,
+ instance->object_name,
+ instance->object_name_len);
+
/* Recursively clear sub-objects & keys */
res = _clear_object(instance);
@@ -641,6 +814,9 @@ static int object_key_delete (
}
hdb_handle_put (&object_instance_database, object_handle);
+ if (ret == 0)
+ object_key_changed_notification(object_handle, key_name, key_len,
+ value, value_len, OBJECT_KEY_DELETED);
return (ret);
error_exit:
@@ -735,6 +911,9 @@ static int object_key_replace (
}
hdb_handle_put (&object_instance_database, object_handle);
+ if (ret == 0)
+ object_key_changed_notification(object_handle, key_name, key_len,
+ new_value, new_value_len, OBJECT_KEY_REPLACED);
return (ret);
error_put:
@@ -1093,8 +1272,6 @@ error_exit:
}
-
-
static int object_parent_get(unsigned int object_handle,
unsigned int *parent_handle)
{
@@ -1118,6 +1295,89 @@ static int object_parent_get(unsigned int object_handle,
}
+static int object_track_start(unsigned int object_handle,
+ object_track_depth_t depth,
+ object_key_change_notify_fn_t key_change_notify_fn,
+ object_create_notify_fn_t object_create_notify_fn,
+ object_destroy_notify_fn_t object_destroy_notify_fn,
+ void * priv_data_pt)
+{
+ struct object_instance *instance;
+ unsigned int res;
+ struct object_tracker * tracker_pt;
+
+ res = hdb_handle_get (&object_instance_database,
+ object_handle, (void *)&instance);
+ if (res != 0) {
+ return (res);
+ }
+ tracker_pt = malloc(sizeof(struct object_tracker));
+
+ tracker_pt->depth = depth;
+ tracker_pt->object_handle = object_handle;
+ tracker_pt->key_change_notify_fn = key_change_notify_fn;
+ tracker_pt->object_create_notify_fn = object_create_notify_fn;
+ tracker_pt->object_destroy_notify_fn = object_destroy_notify_fn;
+ tracker_pt->data_pt = priv_data_pt;
+
+ list_init(&tracker_pt->object_list);
+ list_init(&tracker_pt->tracker_list);
+
+ list_add(&tracker_pt->object_list, &instance->track_head);
+ list_add(&tracker_pt->tracker_list, &objdb_trackers_head);
+
+ hdb_handle_put (&object_instance_database, object_handle);
+
+ return (res);
+}
+
+static void object_track_stop(object_key_change_notify_fn_t key_change_notify_fn,
+ object_create_notify_fn_t object_create_notify_fn,
+ object_destroy_notify_fn_t object_destroy_notify_fn,
+ void * priv_data_pt)
+{
+ struct object_instance *instance;
+ struct object_tracker * tracker_pt = NULL;
+ struct object_tracker * obj_tracker_pt = NULL;
+ struct list_head *list, *tmp_list;
+ struct list_head *obj_list, *tmp_obj_list;
+ unsigned int res;
+
+ /* go through the global list and find all the trackers to stop */
+ for (list = objdb_trackers_head.next, tmp_list = list->next;
+ list != &objdb_trackers_head; list = tmp_list, tmp_list = tmp_list->next) {
+
+ tracker_pt = list_entry (list, struct object_tracker, tracker_list);
+
+ if (tracker_pt && (tracker_pt->data_pt == priv_data_pt) &&
+ (tracker_pt->object_create_notify_fn == object_create_notify_fn) &&
+ (tracker_pt->object_destroy_notify_fn == object_destroy_notify_fn) &&
+ (tracker_pt->key_change_notify_fn == key_change_notify_fn)) {
+
+ /* get the object & take this tracker off of it's list. */
+
+ res = hdb_handle_get (&object_instance_database,
+ tracker_pt->object_handle, (void *)&instance);
+ if (res != 0) continue;
+
+ for (obj_list = instance->track_head.next, tmp_obj_list = obj_list->next;
+ obj_list != &instance->track_head; obj_list = tmp_obj_list, tmp_obj_list = tmp_obj_list->next) {
+
+ obj_tracker_pt = list_entry (obj_list, struct object_tracker, object_list);
+ if (obj_tracker_pt == tracker_pt) {
+ /* this is the tracker we are after. */
+ list_del(obj_list);
+ }
+ }
+ hdb_handle_put (&object_instance_database, tracker_pt->object_handle);
+
+ /* remove the tracker off of the global list */
+ list_del(list);
+ free(tracker_pt);
+ }
+ }
+}
+
static int object_dump(unsigned int object_handle,
FILE *file)
{
@@ -1178,6 +1438,8 @@ struct objdb_iface_ver0 objdb_iface = {
.object_iter_from = object_iter_from,
.object_priv_get = object_priv_get,
.object_parent_get = object_parent_get,
+ .object_track_start = object_track_start,
+ .object_track_stop = object_track_stop,
.object_dump = object_dump,
.object_write_config = object_write_config,
};
diff --git a/corosync/exec/objdb.h b/corosync/exec/objdb.h
index 9656eaa..608bd42 100644
--- a/corosync/exec/objdb.h
+++ b/corosync/exec/objdb.h
@@ -40,11 +40,39 @@
#include <stdio.h>
+typedef enum {
+ OBJECT_TRACK_DEPTH_ONE,
+ OBJECT_TRACK_DEPTH_RECURSIVE
+} object_track_depth_t;
+
+typedef enum {
+ OBJECT_KEY_CREATED,
+ OBJECT_KEY_REPLACED,
+ OBJECT_KEY_DELETED
+} object_change_type_t;
+
+typedef void (*object_key_change_notify_fn_t)(object_change_type_t change_type,
+ unsigned int parent_object_handle,
+ unsigned int object_handle,
+ void *object_name_pt, int object_name_len,
+ void *key_name_pt, int key_len,
+ void *key_value_pt, int key_value_len,
+ void *priv_data_pt);
+
+typedef void (*object_create_notify_fn_t) (unsigned int parent_object_handle,
+ unsigned int object_handle,
+ void *name_pt, int name_len,
+ void *priv_data_pt);
+
+typedef void (*object_destroy_notify_fn_t) (unsigned int parent_object_handle,
+ void *name_pt, int name_len,
+ void *priv_data_pt);
+
struct object_valid {
char *object_name;
int object_len;
};
-
+
struct object_key_valid {
char *key_name;
int key_len;
@@ -174,6 +202,20 @@ struct objdb_iface_ver0 {
void **value,
int *value_len);
+ int (*object_track_start) (
+ unsigned int object_handle,
+ object_track_depth_t depth,
+ object_key_change_notify_fn_t key_change_notify_fn,
+ object_create_notify_fn_t object_create_notify_fn,
+ object_destroy_notify_fn_t object_destroy_notify_fn,
+ void * priv_data_pt);
+
+ void (*object_track_stop) (
+ object_key_change_notify_fn_t key_change_notify_fn,
+ object_create_notify_fn_t object_create_notify_fn,
+ object_destroy_notify_fn_t object_destroy_notify_fn,
+ void * priv_data_pt);
+
int (*object_write_config) (char **error_string);
};
diff --git a/corosync/include/confdb.h b/corosync/include/confdb.h
index 831d982..7e1b9ee 100644
--- a/corosync/include/confdb.h
+++ b/corosync/include/confdb.h
@@ -50,6 +50,11 @@ typedef enum {
} confdb_dispatch_t;
typedef enum {
+ CONFDB_TRACK_DEPTH_ONE,
+ CONFDB_TRACK_DEPTH_RECURSIVE
+} confdb_track_depth_t;
+
+typedef enum {
CONFDB_OK = 1,
CONFDB_ERR_LIBRARY = 2,
CONFDB_ERR_TIMEOUT = 5,
@@ -65,9 +70,15 @@ typedef enum {
CONFDB_ERR_SECURITY = 29,
} confdb_error_t;
+typedef enum {
+ OBJECT_KEY_CREATED,
+ OBJECT_KEY_REPLACED,
+ OBJECT_KEY_DELETED
+} confdb_change_type_t;
-typedef void (*confdb_change_notify_fn_t) (
+typedef void (*confdb_key_change_notify_fn_t) (
confdb_handle_t handle,
+ confdb_change_type_t change_type,
unsigned int parent_object_handle,
unsigned int object_handle,
void *object_name,
@@ -77,8 +88,23 @@ typedef void (*confdb_change_notify_fn_t) (
void *key_value,
int key_value_len);
+typedef void (*confdb_object_create_notify_fn_t) (
+ confdb_handle_t handle,
+ unsigned int parent_object_handle,
+ unsigned int object_handle,
+ uint8_t *name_pt,
+ int name_len);
+
+typedef void (*confdb_object_delete_notify_fn_t) (
+ confdb_handle_t handle,
+ unsigned int parent_object_handle,
+ uint8_t *name_pt,
+ int name_len);
+
typedef struct {
- confdb_change_notify_fn_t confdb_change_notify_fn;
+ confdb_object_create_notify_fn_t confdb_object_create_change_notify_fn;
+ confdb_object_delete_notify_fn_t confdb_object_delete_change_notify_fn;
+ confdb_key_change_notify_fn_t confdb_key_change_notify_fn;
} confdb_callbacks_t;
/** @} */
@@ -119,7 +145,6 @@ confdb_error_t confdb_dispatch (
confdb_handle_t handle,
confdb_dispatch_t dispatch_types);
-
/*
* Change notification
*/
@@ -194,7 +219,7 @@ confdb_error_t confdb_key_replace (
* Object queries
* "find" loops through all objects of a given name and is also
* a quick way of finding a specific object,
- * "iter" returns ech object in sequence.
+ * "iter" returns each object in sequence.
*/
confdb_error_t confdb_object_find_start (
confdb_handle_t handle,
diff --git a/corosync/include/coroapi.h b/corosync/include/coroapi.h
index 0cd2335..aa9baa8 100644
--- a/corosync/include/coroapi.h
+++ b/corosync/include/coroapi.h
@@ -90,13 +90,46 @@ struct object_valid {
char *object_name;
int object_len;
};
-
+
struct object_key_valid {
char *key_name;
int key_len;
int (*validate_callback) (void *key, int key_len, void *value, int value_len);
};
+typedef enum {
+ OBJECT_TRACK_DEPTH_ONE,
+ OBJECT_TRACK_DEPTH_RECURSIVE
+} object_track_depth_t;
+
+typedef enum {
+ OBJECT_KEY_CREATED,
+ OBJECT_KEY_REPLACED,
+ OBJECT_KEY_DELETED
+} object_change_type_t;
+
+typedef void (*object_key_change_notify_fn_t)(object_change_type_t change_type,
+ unsigned int parent_object_handle,
+ unsigned int object_handle,
+ void *object_name_pt, int object_name_len,
+ void *key_name_pt, int key_len,
+ void *key_value_pt, int key_value_len,
+ void *priv_data_pt);
+
+typedef void (*object_create_notify_fn_t) (unsigned int parent_object_handle,
+ unsigned int object_handle,
+ uint8_t *name_pt, int name_len,
+ void *priv_data_pt);
+
+typedef void (*object_destroy_notify_fn_t) (unsigned int parent_object_handle,
+ uint8_t *name_pt, int name_len,
+ void *priv_data_pt);
+typedef void (*object_notify_callback_fn_t)(unsigned int object_handle,
+ void *key_name, int key_len,
+ void *value, int value_len,
+ object_change_type_t type,
+ void * priv_data_pt);
+
#endif /* OBJECT_PARENT_HANDLE_DEFINED */
struct corosync_api_v1 {
@@ -222,6 +255,20 @@ struct corosync_api_v1 {
void **value,
int *value_len);
+ int (*object_track_start) (
+ unsigned int object_handle,
+ object_track_depth_t depth,
+ object_key_change_notify_fn_t key_change_notify_fn,
+ object_create_notify_fn_t object_create_notify_fn,
+ object_destroy_notify_fn_t object_destroy_notify_fn,
+ void * priv_data_pt);
+
+ void (*object_track_stop) (
+ object_key_change_notify_fn_t key_change_notify_fn,
+ object_create_notify_fn_t object_create_notify_fn,
+ object_destroy_notify_fn_t object_destroy_notify_fn,
+ void * priv_data_pt);
+
int (*object_write_config) (char **error_string);
/*
diff --git a/corosync/include/ipc_confdb.h b/corosync/include/ipc_confdb.h
index acc0871..ab01a6f 100644
--- a/corosync/include/ipc_confdb.h
+++ b/corosync/include/ipc_confdb.h
@@ -51,7 +51,8 @@ enum req_confdb_types {
MESSAGE_REQ_CONFDB_KEY_ITER = 9,
MESSAGE_REQ_CONFDB_TRACK_START = 10,
MESSAGE_REQ_CONFDB_TRACK_STOP = 11,
- MESSAGE_REQ_CONFDB_WRITE = 12
+ MESSAGE_REQ_CONFDB_XPATH_EVAL_EXPRESSION = 12,
+ MESSAGE_REQ_CONFDB_WRITE = 13
};
enum res_confdb_types {
@@ -67,8 +68,10 @@ enum res_confdb_types {
MESSAGE_RES_CONFDB_KEY_ITER = 9,
MESSAGE_RES_CONFDB_TRACK_START = 10,
MESSAGE_RES_CONFDB_TRACK_STOP = 11,
- MESSAGE_RES_CONFDB_CHANGE_CALLBACK = 12,
- MESSAGE_RES_CONFDB_WRITE = 13
+ MESSAGE_RES_CONFDB_KEY_CHANGE_CALLBACK = 12,
+ MESSAGE_RES_CONFDB_OBJECT_CREATE_CALLBACK = 13,
+ MESSAGE_RES_CONFDB_OBJECT_DESTROY_CALLBACK = 14,
+ MESSAGE_RES_CONFDB_WRITE = 15
};
@@ -174,8 +177,9 @@ struct res_lib_confdb_write {
mar_name_t error __attribute__((aligned(8)));
};
-struct res_lib_confdb_change_callback {
+struct res_lib_confdb_key_change_callback {
mar_res_header_t header __attribute__((aligned(8)));
+ mar_uint32_t change_type __attribute__((aligned(8)));
mar_uint32_t parent_object_handle __attribute__((aligned(8)));
mar_uint32_t object_handle __attribute__((aligned(8)));
mar_name_t object_name __attribute__((aligned(8)));
@@ -183,5 +187,23 @@ struct res_lib_confdb_change_callback {
mar_name_t key_value __attribute__((aligned(8)));
};
+struct res_lib_confdb_object_create_callback {
+ mar_res_header_t header __attribute__((aligned(8)));
+ mar_uint32_t parent_object_handle __attribute__((aligned(8)));
+ mar_uint32_t object_handle __attribute__((aligned(8)));
+ mar_name_t name __attribute__((aligned(8)));
+};
+
+struct res_lib_confdb_object_destroy_callback {
+ mar_res_header_t header __attribute__((aligned(8)));
+ mar_uint32_t parent_object_handle __attribute__((aligned(8)));
+ mar_name_t name __attribute__((aligned(8)));
+};
+
+struct req_lib_confdb_object_track_start {
+ mar_req_header_t header __attribute__((aligned(8)));
+ mar_uint32_t object_handle __attribute__((aligned(8)));
+ mar_uint32_t flags __attribute__((aligned(8)));
+};
#endif /* IPC_CONFDB_H_DEFINED */
diff --git a/corosync/include/mar_gen.h b/corosync/include/mar_gen.h
index 09a839d..af343e5 100644
--- a/corosync/include/mar_gen.h
+++ b/corosync/include/mar_gen.h
@@ -109,7 +109,7 @@ static inline char *get_mar_name_t (mar_name_t *name) {
return ((char *)name->value);
}
-static int mar_name_match(mar_name_t *name1, mar_name_t *name2)
+static inline int mar_name_match(mar_name_t *name1, mar_name_t *name2)
{
if (name1->length == name2->length) {
return ((strncmp ((char *)name1->value, (char *)name2->value,
diff --git a/corosync/lib/confdb.c b/corosync/lib/confdb.c
index 7e22c03..8ff8cb2 100644
--- a/corosync/lib/confdb.c
+++ b/corosync/lib/confdb.c
@@ -304,8 +304,10 @@ confdb_error_t confdb_dispatch (
int cont = 1; /* always continue do loop except when set to 0 */
int dispatch_avail;
struct confdb_inst *confdb_inst;
- struct res_lib_confdb_change_callback *res_confdb_change_callback;
confdb_callbacks_t callbacks;
+ struct res_lib_confdb_key_change_callback *res_key_changed_pt;
+ struct res_lib_confdb_object_create_callback *res_object_created_pt;
+ struct res_lib_confdb_object_destroy_callback *res_object_destroyed_pt;
struct res_overlay dispatch_data;
int ignore_dispatch = 0;
@@ -400,24 +402,44 @@ confdb_error_t confdb_dispatch (
* Dispatch incoming message
*/
switch (dispatch_data.header.id) {
- case MESSAGE_RES_CONFDB_CHANGE_CALLBACK:
- res_confdb_change_callback = (struct res_lib_confdb_change_callback *)&dispatch_data;
-
- callbacks.confdb_change_notify_fn (handle,
- res_confdb_change_callback->parent_object_handle,
- res_confdb_change_callback->object_handle,
- res_confdb_change_callback->object_name.value,
- res_confdb_change_callback->object_name.length,
- res_confdb_change_callback->key_name.value,
- res_confdb_change_callback->key_name.length,
- res_confdb_change_callback->key_value.value,
- res_confdb_change_callback->key_value.length);
- break;
-
- default:
- error = SA_AIS_ERR_LIBRARY;
- goto error_nounlock;
- break;
+ case MESSAGE_RES_CONFDB_KEY_CHANGE_CALLBACK:
+ res_key_changed_pt = (struct res_lib_confdb_key_change_callback *)&dispatch_data;
+
+ callbacks.confdb_key_change_notify_fn(handle,
+ res_key_changed_pt->change_type,
+ res_key_changed_pt->object_handle,
+ res_key_changed_pt->parent_object_handle,
+ res_key_changed_pt->object_name.value,
+ res_key_changed_pt->object_name.length,
+ res_key_changed_pt->key_name.value,
+ res_key_changed_pt->key_name.length,
+ res_key_changed_pt->key_value.value,
+ res_key_changed_pt->key_value.length);
+ break;
+
+ case MESSAGE_RES_CONFDB_OBJECT_CREATE_CALLBACK:
+ res_object_created_pt = (struct res_lib_confdb_object_create_callback *)&dispatch_data;
+
+ callbacks.confdb_object_create_change_notify_fn(handle,
+ res_object_created_pt->object_handle,
+ res_object_created_pt->parent_object_handle,
+ res_object_created_pt->name.value,
+ res_object_created_pt->name.length);
+ break;
+
+ case MESSAGE_RES_CONFDB_OBJECT_DESTROY_CALLBACK:
+ res_object_destroyed_pt = (struct res_lib_confdb_object_destroy_callback *)&dispatch_data;
+
+ callbacks.confdb_object_delete_change_notify_fn(handle,
+ res_object_destroyed_pt->parent_object_handle,
+ res_object_destroyed_pt->name.value,
+ res_object_destroyed_pt->name.length);
+ break;
+
+ default:
+ error = SA_AIS_ERR_LIBRARY;
+ goto error_nounlock;
+ break;
}
/*
@@ -1197,4 +1219,92 @@ error_exit:
return (error);
}
+confdb_error_t confdb_track_changes (
+ confdb_handle_t handle,
+ unsigned int object_handle,
+ unsigned int flags)
+{
+ confdb_error_t error;
+ struct confdb_inst *confdb_inst;
+ struct iovec iov[2];
+ struct req_lib_confdb_object_track_start req;
+ mar_res_header_t res;
+
+ error = saHandleInstanceGet (&confdb_handle_t_db, handle, (void *)&confdb_inst);
+ if (error != SA_AIS_OK) {
+ return (error);
+ }
+
+ if (confdb_inst->standalone) {
+ error = CONFDB_ERR_NOT_SUPPORTED;
+ goto error_exit;
+ }
+
+ req.header.size = sizeof (struct req_lib_confdb_object_track_start);
+ req.header.id = MESSAGE_REQ_CONFDB_TRACK_START;
+ req.object_handle = object_handle;
+ req.flags = flags;
+
+ iov[0].iov_base = (char *)&req;
+ iov[0].iov_len = sizeof (struct req_lib_confdb_object_track_start);
+
+ pthread_mutex_lock (&confdb_inst->response_mutex);
+
+ error = saSendMsgReceiveReply (confdb_inst->response_fd, iov, 1,
+ &res, sizeof ( mar_res_header_t));
+
+ pthread_mutex_unlock (&confdb_inst->response_mutex);
+ if (error != SA_AIS_OK) {
+ goto error_exit;
+ }
+
+ error = res.error;
+
+error_exit:
+ saHandleInstancePut (&confdb_handle_t_db, handle);
+
+ return (error);
+}
+
+confdb_error_t confdb_stop_track_changes (confdb_handle_t handle)
+{
+ confdb_error_t error;
+ struct confdb_inst *confdb_inst;
+ struct iovec iov[2];
+ mar_req_header_t req;
+ mar_res_header_t res;
+
+ error = saHandleInstanceGet (&confdb_handle_t_db, handle, (void *)&confdb_inst);
+ if (error != SA_AIS_OK) {
+ return (error);
+ }
+
+ if (confdb_inst->standalone) {
+ error = CONFDB_ERR_NOT_SUPPORTED;
+ goto error_exit;
+ }
+
+ req.size = sizeof (mar_req_header_t);
+ req.id = MESSAGE_REQ_CONFDB_TRACK_STOP;
+
+ iov[0].iov_base = (char *)&req;
+ iov[0].iov_len = sizeof (mar_req_header_t);
+
+ pthread_mutex_lock (&confdb_inst->response_mutex);
+
+ error = saSendMsgReceiveReply (confdb_inst->response_fd, iov, 1,
+ &res, sizeof ( mar_res_header_t));
+
+ pthread_mutex_unlock (&confdb_inst->response_mutex);
+ if (error != SA_AIS_OK) {
+ goto error_exit;
+ }
+
+ error = res.error;
+
+error_exit:
+ saHandleInstancePut (&confdb_handle_t_db, handle);
+
+ return (error);
+}
diff --git a/corosync/man/corosync-objctl.8 b/corosync/man/corosync-objctl.8
index f230008..250a99c 100644
--- a/corosync/man/corosync-objctl.8
+++ b/corosync/man/corosync-objctl.8
@@ -35,7 +35,7 @@
.SH NAME
corosync-objctl \- Configure objects in the Object Database
.SH SYNOPSIS
-.B "corosync-objctl [\-c|\-w|\-d|\-a|\-h] <OBJECT-SPEC>..."
+.B "corosync-objctl [\-c|\-w|\-d|\-a|\-t\-h] <OBJECT-SPEC>..."
.SH DESCRIPTION
.B corosync-objctl
is used to configure objects within the object database at runtime.
@@ -62,12 +62,16 @@ Create a new object.
.B -d
Delete an existing object.
.TP
-.B "-w"
+.B -w
Use this option when you want to write a new value to a key.
.TP
-.B "-a"
+.B -a
Display all values currently available.
.TP
+.B -t
+Track changes to an object and it's children. As changes are made to the object
+they are printed out. this is kind of like a "tail -f" for the object database.
+.TP
.B -h
Print basic usage.
.SH EXAMPLES
diff --git a/corosync/services/confdb.c b/corosync/services/confdb.c
index 2b56b00..440e44b 100644
--- a/corosync/services/confdb.c
+++ b/corosync/services/confdb.c
@@ -46,7 +46,7 @@
#include "../exec/logsys.h"
#include "../include/coroapi.h"
-LOGSYS_DECLARE_SUBSYS ("CONFDB", LOG_INFO);
+LOGSYS_DECLARE_SUBSYS ("CONFDB", LOG_DEBUG);
static struct corosync_api_v1 *api;
@@ -74,7 +74,21 @@ static void message_handler_req_lib_confdb_write (void *conn, void *message);
static void message_handler_req_lib_confdb_track_start (void *conn, void *message);
static void message_handler_req_lib_confdb_track_stop (void *conn, void *message);
-
+static void confdb_notify_lib_of_key_change(object_change_type_t change_type,
+ unsigned int parent_object_handle,
+ unsigned int object_handle,
+ void *object_name_pt, int object_name_len,
+ void *key_name_pt, int key_name_len,
+ void *key_value_pt, int key_value_len,
+ void *priv_data_pt);
+
+static void confdb_notify_lib_of_new_object(unsigned int parent_object_handle,
+ unsigned int object_handle,
+ uint8_t *name_pt, int name_len,
+ void *priv_data_pt);
+static void confdb_notify_lib_of_destroyed_object(unsigned int parent_object_handle,
+ uint8_t *name_pt, int name_len,
+ void *priv_data_pt);
/*
* Library Handler Definition
*/
@@ -149,7 +163,7 @@ static struct corosync_lib_handler confdb_lib_engine[] =
{ /* 11 */
.lib_handler_fn = message_handler_req_lib_confdb_track_stop,
.response_size = sizeof (mar_res_header_t),
- .response_id = MESSAGE_RES_CONFDB_TRACK_START,
+ .response_id = MESSAGE_RES_CONFDB_TRACK_STOP,
.flow_control = COROSYNC_LIB_FLOW_CONTROL_NOT_REQUIRED
},
{ /* 12 */
@@ -230,6 +244,11 @@ static int confdb_lib_exit_fn (void *conn)
{
log_printf(LOG_LEVEL_DEBUG, "exit_fn for conn=%p\n", conn);
+ /* cleanup the object trackers for this client. */
+ api->object_track_stop(confdb_notify_lib_of_key_change,
+ confdb_notify_lib_of_new_object,
+ confdb_notify_lib_of_destroyed_object,
+ api->ipc_conn_partner_get (conn));
return (0);
}
@@ -469,14 +488,84 @@ static void message_handler_req_lib_confdb_write (void *conn, void *message)
api->ipc_conn_send_response(conn, &res_lib_confdb_write, sizeof(res_lib_confdb_write));
}
-/* TODO: when we have notification in the objdb. */
+static void confdb_notify_lib_of_key_change(object_change_type_t change_type,
+ unsigned int parent_object_handle,
+ unsigned int object_handle,
+ void *object_name_pt, int object_name_len,
+ void *key_name_pt, int key_name_len,
+ void *key_value_pt, int key_value_len,
+ void *priv_data_pt)
+{
+ struct res_lib_confdb_key_change_callback res;
+
+ res.header.size = sizeof(res);
+ res.header.id = MESSAGE_RES_CONFDB_KEY_CHANGE_CALLBACK;
+ res.header.error = SA_AIS_OK;
+// handle & type
+ res.change_type = change_type;
+ res.parent_object_handle = parent_object_handle;
+ res.object_handle = object_handle;
+//object
+ memcpy(res.object_name.value, object_name_pt, object_name_len);
+ res.object_name.length = object_name_len;
+//key name
+ memcpy(res.key_name.value, key_name_pt, key_name_len);
+ res.key_name.length = key_name_len;
+//key value
+ memcpy(res.key_value.value, key_value_pt, key_value_len);
+ res.key_value.length = key_value_len;
+
+ api->ipc_conn_send_response(priv_data_pt, &res, sizeof(res));
+}
+
+static void confdb_notify_lib_of_new_object(unsigned int parent_object_handle,
+ unsigned int object_handle,
+ uint8_t *name_pt, int name_len,
+ void *priv_data_pt)
+{
+ struct res_lib_confdb_object_create_callback res;
+
+ res.header.size = sizeof(res);
+ res.header.id = MESSAGE_RES_CONFDB_OBJECT_CREATE_CALLBACK;
+ res.header.error = SA_AIS_OK;
+ res.parent_object_handle = parent_object_handle;
+ res.object_handle = object_handle;
+ memcpy(res.name.value, name_pt, name_len);
+ res.name.length = name_len;
+
+ api->ipc_conn_send_response(priv_data_pt, &res, sizeof(res));
+}
+
+static void confdb_notify_lib_of_destroyed_object(unsigned int parent_object_handle,
+ uint8_t *name_pt, int name_len,
+ void *priv_data_pt)
+{
+ struct res_lib_confdb_object_destroy_callback res;
+
+ res.header.size = sizeof(res);
+ res.header.id = MESSAGE_RES_CONFDB_OBJECT_DESTROY_CALLBACK;
+ res.header.error = SA_AIS_OK;
+ res.parent_object_handle = parent_object_handle;
+ memcpy(res.name.value, name_pt, name_len);
+ res.name.length = name_len;
+
+ api->ipc_conn_send_response(priv_data_pt, &res, sizeof(res));
+}
+
+
static void message_handler_req_lib_confdb_track_start (void *conn, void *message)
{
+ struct req_lib_confdb_object_track_start *req = (struct req_lib_confdb_object_track_start *)message;
mar_res_header_t res;
+ api->object_track_start(req->object_handle, req->flags,
+ confdb_notify_lib_of_key_change,
+ confdb_notify_lib_of_new_object,
+ confdb_notify_lib_of_destroyed_object,
+ api->ipc_conn_partner_get (conn));
res.size = sizeof(res);
res.id = MESSAGE_RES_CONFDB_TRACK_START;
- res.error = SA_AIS_ERR_NOT_SUPPORTED;
+ res.error = SA_AIS_OK;
api->ipc_conn_send_response(conn, &res, sizeof(res));
}
@@ -484,9 +573,14 @@ static void message_handler_req_lib_confdb_track_stop (void *conn, void *message
{
mar_res_header_t res;
+ api->object_track_stop(confdb_notify_lib_of_key_change,
+ confdb_notify_lib_of_new_object,
+ confdb_notify_lib_of_destroyed_object,
+ api->ipc_conn_partner_get (conn));
+
res.size = sizeof(res);
res.id = MESSAGE_RES_CONFDB_TRACK_STOP;
- res.error = SA_AIS_ERR_NOT_SUPPORTED;
+ res.error = SA_AIS_OK;
api->ipc_conn_send_response(conn, &res, sizeof(res));
}
diff --git a/corosync/test/testconfdb.c b/corosync/test/testconfdb.c
index 8ecbf46..90ab3c5 100644
--- a/corosync/test/testconfdb.c
+++ b/corosync/test/testconfdb.c
@@ -47,7 +47,9 @@
/* Callbacks are not supported yet */
confdb_callbacks_t callbacks = {
- .confdb_change_notify_fn = NULL,
+ .confdb_key_change_notify_fn = NULL,
+ .confdb_object_create_change_notify_fn = NULL,
+ .confdb_object_delete_change_notify_fn = NULL
};
/* Recursively dump the object tree */
diff --git a/corosync/tools/corosync-objctl.c b/corosync/tools/corosync-objctl.c
index 84f356c..d59c2f6 100644
--- a/corosync/tools/corosync-objctl.c
+++ b/corosync/tools/corosync-objctl.c
@@ -54,6 +54,7 @@ typedef enum {
ACTION_DELETE,
ACTION_PRINT_ALL,
ACTION_PRINT_DEFAULT,
+ ACTION_TRACK,
} action_types_t;
typedef enum {
@@ -62,8 +63,32 @@ typedef enum {
FIND_KEY_ONLY
} find_object_of_type_t;
+static void tail_key_changed(confdb_handle_t handle,
+ confdb_change_type_t change_type,
+ unsigned int parent_object_handle,
+ unsigned int object_handle,
+ void *object_name,
+ int object_name_len,
+ void *key_name,
+ int key_name_len,
+ void *key_value,
+ int key_value_len);
+
+static void tail_object_created(confdb_handle_t handle,
+ unsigned int parent_object_handle,
+ unsigned int object_handle,
+ uint8_t *name_pt,
+ int name_len);
+
+static void tail_object_deleted(confdb_handle_t handle,
+ unsigned int parent_object_handle,
+ uint8_t *name_pt,
+ int name_len);
+
confdb_callbacks_t callbacks = {
- .confdb_change_notify_fn = NULL,
+ .confdb_key_change_notify_fn = tail_key_changed,
+ .confdb_object_create_change_notify_fn = tail_object_created,
+ .confdb_object_delete_change_notify_fn = tail_object_deleted,
};
static int action;
@@ -377,6 +402,113 @@ static void create_object(confdb_handle_t handle, char * name_pt)
}
}
+static void tail_key_changed(confdb_handle_t handle,
+ confdb_change_type_t change_type,
+ unsigned int parent_object_handle,
+ unsigned int object_handle,
+ void *object_name_pt,
+ int object_name_len,
+ void *key_name_pt,
+ int key_name_len,
+ void *key_value_pt,
+ int key_value_len)
+{
+ char * on = (char*)object_name_pt;
+ char * kn = (char*)key_name_pt;
+ char * kv = (char*)key_value_pt;
+
+ on[object_name_len] = '\0';
+ kv[key_value_len] = '\0';
+ kn[key_name_len] = '\0';
+ printf("key_changed> %s.%s=%s\n", on, kn, kv);
+}
+
+static void tail_object_created(confdb_handle_t handle,
+ unsigned int parent_object_handle,
+ unsigned int object_handle,
+ uint8_t *name_pt,
+ int name_len)
+{
+ name_pt[name_len] = '\0';
+ printf("object_created> %s\n", name_pt);
+}
+
+static void tail_object_deleted(confdb_handle_t handle,
+ unsigned int parent_object_handle,
+ uint8_t *name_pt,
+ int name_len)
+{
+ name_pt[name_len] = '\0';
+
+ printf("object_deleted> %s\n", name_pt);
+}
+
+static void listen_for_object_changes(confdb_handle_t handle)
+{
+ int result;
+ fd_set read_fds;
+ int select_fd;
+ SaBoolT quit = SA_FALSE;
+
+ FD_ZERO (&read_fds);
+ confdb_fd_get(handle, &select_fd);
+ printf ("Type \"q\" to finish\n");
+ do {
+ FD_SET (select_fd, &read_fds);
+ FD_SET (STDIN_FILENO, &read_fds);
+ result = select (select_fd + 1, &read_fds, 0, 0, 0);
+ if (result == -1) {
+ perror ("select\n");
+ }
+ if (FD_ISSET (STDIN_FILENO, &read_fds)) {
+ char inbuf[3];
+
+ fgets(inbuf, sizeof(inbuf), stdin);
+ if (strncmp(inbuf, "q", 1) == 0)
+ quit = SA_TRUE;
+ }
+ if (FD_ISSET (select_fd, &read_fds)) {
+ if (confdb_dispatch (handle, CONFDB_DISPATCH_ALL) != CONFDB_OK)
+ exit(1);
+ }
+ } while (result && quit == SA_FALSE);
+
+ confdb_stop_track_changes(handle);
+
+}
+
+static void track_object(confdb_handle_t handle, char * name_pt)
+{
+ confdb_error_t res;
+ uint32_t obj_handle;
+
+ res = find_object (handle, name_pt, FIND_OBJECT_ONLY, &obj_handle);
+
+ if (res != CONFDB_OK) {
+ fprintf (stderr, "Could not find object \"%s\". Error %d\n",
+ name_pt, res);
+ return;
+ }
+
+ res = confdb_track_changes (handle, obj_handle, CONFDB_TRACK_DEPTH_RECURSIVE);
+ if (res != CONFDB_OK) {
+ fprintf (stderr, "Could not enable tracking on object \"%s\". Error %d\n",
+ name_pt, res);
+ return;
+ }
+}
+
+static void stop_tracking(confdb_handle_t handle)
+{
+ confdb_error_t res;
+
+ res = confdb_stop_track_changes (handle);
+ if (res != CONFDB_OK) {
+ fprintf (stderr, "Could not stop tracking. Error %d\n", res);
+ return;
+ }
+}
+
static void delete_object(confdb_handle_t handle, char * name_pt)
{
confdb_error_t res;
@@ -425,7 +557,7 @@ int main (int argc, char *argv[]) {
action = ACTION_READ;
for (;;){
- c = getopt (argc,argv,"hawcdp:");
+ c = getopt (argc,argv,"hawcdtp:");
if (c==-1) {
break;
}
@@ -450,6 +582,9 @@ int main (int argc, char *argv[]) {
case 'w':
action = ACTION_WRITE;
break;
+ case 't':
+ action = ACTION_TRACK;
+ break;
default :
action = ACTION_READ;
break;
@@ -485,9 +620,17 @@ int main (int argc, char *argv[]) {
case ACTION_DELETE:
delete_object(handle, argv[optind++]);
break;
+ case ACTION_TRACK:
+ track_object(handle, argv[optind++]);
+ break;
}
}
+ if (action == ACTION_TRACK) {
+ listen_for_object_changes(handle);
+ stop_tracking(handle);
+ }
+
result = confdb_finalize (handle);
if (result != CONFDB_OK) {
fprintf (stderr, "Error finalizing objdb API. Error %d\n", result);
--
1.5.6
More information about the Openais
mailing list