[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