Well

What can I say other then really great work.

I wish I wasn't working on this exact same piece of code at the moment
but it is what it is :)

I'll go ahead and merge this now and refix my changes.

Also what are you plans WRT xpathlite?  I noticed you added some types
in the confdb but don't see any api exported that uses it.

Regards
-steve



On Tue, 2008-08-05 at 14:00 +1200, angus salkeld wrote:
> 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);

_______________________________________________
Openais mailing list
[email protected]
https://lists.linux-foundation.org/mailman/listinfo/openais

Reply via email to