You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@zookeeper.apache.org by ak...@apache.org on 2008/07/24 23:46:31 UTC

svn commit: r679557 [1/3] - in /hadoop/zookeeper/trunk/src/c: ./ include/ src/ src/hashtable/ tests/

Author: akornev
Date: Thu Jul 24 14:46:30 2008
New Revision: 679557

URL: http://svn.apache.org/viewvc?rev=679557&view=rev
Log:
[ZOOKEEPER-39] Use Watcher objects rather than boolean on read operations

Added:
    hadoop/zookeeper/trunk/src/c/src/hashtable/
    hadoop/zookeeper/trunk/src/c/src/hashtable/LICENSE.txt   (with props)
    hadoop/zookeeper/trunk/src/c/src/hashtable/hashtable.c   (with props)
    hadoop/zookeeper/trunk/src/c/src/hashtable/hashtable.h   (with props)
    hadoop/zookeeper/trunk/src/c/src/hashtable/hashtable_itr.c   (with props)
    hadoop/zookeeper/trunk/src/c/src/hashtable/hashtable_itr.h   (with props)
    hadoop/zookeeper/trunk/src/c/src/hashtable/hashtable_private.h   (with props)
    hadoop/zookeeper/trunk/src/c/src/zk_hashtable.c   (with props)
    hadoop/zookeeper/trunk/src/c/src/zk_hashtable.h   (with props)
    hadoop/zookeeper/trunk/src/c/tests/CollectionUtil.h   (with props)
    hadoop/zookeeper/trunk/src/c/tests/TestHashtable.cc   (with props)
    hadoop/zookeeper/trunk/src/c/tests/TestWatchers.cc   (with props)
    hadoop/zookeeper/trunk/src/c/tests/Vector.h   (with props)
Modified:
    hadoop/zookeeper/trunk/src/c/Makefile.am
    hadoop/zookeeper/trunk/src/c/include/zookeeper.h
    hadoop/zookeeper/trunk/src/c/src/cli.c
    hadoop/zookeeper/trunk/src/c/src/load_gen.c
    hadoop/zookeeper/trunk/src/c/src/zk_adaptor.h
    hadoop/zookeeper/trunk/src/c/src/zookeeper.c
    hadoop/zookeeper/trunk/src/c/tests/TestOperations.cc
    hadoop/zookeeper/trunk/src/c/tests/TestZookeeperClose.cc
    hadoop/zookeeper/trunk/src/c/tests/TestZookeeperInit.cc
    hadoop/zookeeper/trunk/src/c/tests/ZKMocks.cc
    hadoop/zookeeper/trunk/src/c/tests/ZKMocks.h
    hadoop/zookeeper/trunk/src/c/tests/wrappers.opt

Modified: hadoop/zookeeper/trunk/src/c/Makefile.am
URL: http://svn.apache.org/viewvc/hadoop/zookeeper/trunk/src/c/Makefile.am?rev=679557&r1=679556&r2=679557&view=diff
==============================================================================
--- hadoop/zookeeper/trunk/src/c/Makefile.am (original)
+++ hadoop/zookeeper/trunk/src/c/Makefile.am Thu Jul 24 14:46:30 2008
@@ -10,29 +10,37 @@
 pkginclude_HEADERS = include/zookeeper.h include/recordio.h generated/zookeeper.jute.h
 EXTRA_DIST=LICENSE
 
+HASHTABLE_SRC = src/hashtable/hashtable_itr.h src/hashtable/hashtable_itr.c \
+    src/hashtable/hashtable_private.h src/hashtable/hashtable.h src/hashtable/hashtable.c
+
+noinst_LTLIBRARIES = libhashtable.la
+libhashtable_la_SOURCES = $(HASHTABLE_SRC)
+
 COMMON_SRC = src/zookeeper.c include/zookeeper.h \
     src/recordio.c include/recordio.h include/proto.h \
     src/zk_adaptor.h generated/zookeeper.jute.c \
-    src/zk_log.h src/zk_log.c
+    src/zk_log.h src/zk_log.c src/zk_hashtable.h src/zk_hashtable.c
 
-noinst_LTLIBRARIES = libzkst.la
+noinst_LTLIBRARIES += libzkst.la
 libzkst_la_SOURCES =$(COMMON_SRC) src/st_adaptor.c
+libzkst_la_LIBADD = -lm
 
 lib_LTLIBRARIES = libzookeeper_st.la
 libzookeeper_st_la_SOURCES =
-libzookeeper_st_la_LIBADD=libzkst.la
-libzookeeper_st_la_DEPENDENCIES=libzkst.la
+libzookeeper_st_la_LIBADD=libzkst.la libhashtable.la
+libzookeeper_st_la_DEPENDENCIES=libzkst.la libhashtable.la
 libzookeeper_st_la_LDFLAGS = $(LIB_LDFLAGS)
 
 if WANT_SYNCAPI
 noinst_LTLIBRARIES += libzkmt.la
 libzkmt_la_SOURCES =$(COMMON_SRC) src/mt_adaptor.c
 libzkmt_la_CFLAGS = -DTHREADED
+libzkmt_la_LIBADD = -lm
 
 lib_LTLIBRARIES += libzookeeper_mt.la
 libzookeeper_mt_la_SOURCES =
-libzookeeper_mt_la_LIBADD=libzkmt.la -lpthread
-libzookeeper_mt_la_DEPENDENCIES=libzkmt.la
+libzookeeper_mt_la_LIBADD=libzkmt.la libhashtable.la -lpthread
+libzookeeper_mt_la_DEPENDENCIES=libzkmt.la libhashtable.la
 libzookeeper_mt_la_LDFLAGS = $(LIB_LDFLAGS)
 endif
 
@@ -62,20 +70,21 @@
 
 TEST_SOURCES = tests/TestDriver.cc tests/LibCMocks.cc tests/LibCSymTable.cc \
     tests/MocksBase.cc  tests/ZKMocks.cc tests/Util.cc tests/ThreadingUtil.cc \
+    tests/TestWatchers.cc tests/TestHashtable.cc \
     tests/TestOperations.cc tests/TestZookeeperInit.cc tests/TestZookeeperClose.cc
 
 SYMBOL_WRAPPERS=$(shell cat tests/wrappers.opt)
 
 check_PROGRAMS = zktest-st
 nodist_zktest_st_SOURCES = $(TEST_SOURCES)
-zktest_st_LDADD = libzkst.la $(CPPUNIT_LIBS)
+zktest_st_LDADD = libzkst.la libhashtable.la $(CPPUNIT_LIBS)
 zktest_st_CXXFLAGS = -DUSE_STATIC_LIB $(CPPUNIT_CFLAGS)
 zktest_st_LDFLAGS = -static-libtool-libs $(SYMBOL_WRAPPERS)
 
 if WANT_SYNCAPI
   check_PROGRAMS += zktest-mt
   nodist_zktest_mt_SOURCES = $(TEST_SOURCES) tests/PthreadMocks.cc
-  zktest_mt_LDADD = libzkmt.la -lpthread $(CPPUNIT_LIBS)
+  zktest_mt_LDADD = libzkmt.la libhashtable.la -lpthread $(CPPUNIT_LIBS)
   zktest_mt_CXXFLAGS = -DUSE_STATIC_LIB -DTHREADED $(CPPUNIT_CFLAGS)
   SYMBOL_WRAPPERS_MT=$(SYMBOL_WRAPPERS) $(shell cat tests/wrappers-mt.opt)
   zktest_mt_LDFLAGS = -static-libtool-libs $(SYMBOL_WRAPPERS_MT)

Modified: hadoop/zookeeper/trunk/src/c/include/zookeeper.h
URL: http://svn.apache.org/viewvc/hadoop/zookeeper/trunk/src/c/include/zookeeper.h?rev=679557&r1=679556&r2=679557&view=diff
==============================================================================
--- hadoop/zookeeper/trunk/src/c/include/zookeeper.h (original)
+++ hadoop/zookeeper/trunk/src/c/include/zookeeper.h Thu Jul 24 14:46:30 2008
@@ -231,10 +231,32 @@
 /**
  * \brief signature of a watch function.
  * 
- * Programs wishing to receive events from ZooKeeper need to implement a function 
- * with this signature and pass a pointer to the function to \ref zookeeper_init.
+ * There are two ways to receive watch notifications: legacy and watcher object.
+ * <p>
+ * The legacy style, an application wishing to receive events from ZooKeeper must 
+ * first implement a function with this signature and pass a pointer to the function 
+ * to \ref zookeeper_init. Next, the application sets a watch by calling one of 
+ * the getter API that accept the watch integer flag (for example, \ref zoo_aexists, 
+ * \ref zoo_get, etc).
+ * <p>
+ * The watcher object style uses an instance of a "watcher object" which in 
+ * the C world is represented by a pair: a pointer to a function implementing this
+ * signature and a pointer to watcher context -- handback user-specific data. 
+ * When a watch is triggered this function will be called along with 
+ * the watcher context. An application wishing to use this style must use
+ * the getter API functions with the "w" prefix in their names (for example, \ref
+ * zoo_awexists, \ref zoo_wget, etc).
+ * 
+ * \param zh zookeeper handle
+ * \param type event type. This is one of the *_EVENT constants. 
+ * \param state connection state. If the type is SESSION_EVENT, the state value 
+ * will be one of the *_STATE constants, otherwise -1.
+ * \param path znode path for which the watcher is triggered. NULL if the event 
+ * type is SESSION_EVENT
+ * \param watcherCtx watcher context.
  */
-typedef void (*watcher_fn)(zhandle_t *, int type, int state, const char *path);
+typedef void (*watcher_fn)(zhandle_t *zh, int type, 
+        int state, const char *path,void *watcherCtx);
 
 /**
  * \brief create a handle to used communicate with zookeeper.
@@ -243,7 +265,7 @@
  * to that handle.
  * \param host the host name to connect to. This may be a comma separated list
  *   of different hosts.
- * \param fn the watcher callback function. When notifications are triggered
+ * \param fn the global watcher callback function. When notifications are triggered
  *   this function will be invoked.
  * \param clientid the id of a previously established session that this
  *   client will be reconnecting to. Pass 0 if not reconnecting to a previous
@@ -579,6 +601,39 @@
         stat_completion_t completion, const void *data);
 
 /**
+ * \brief checks the existence of a node in zookeeper.
+ * 
+ * This function is similar to \ref zoo_axists except it allows one specify 
+ * a watcher object - a function pointer and associated context. The function
+ * will be called once the watch has fired. The associated context data will be 
+ * passed to the function as the watcher context parameter. 
+ * 
+ * \param zh the zookeeper handle obtained by a call to \ref zookeeper_init
+ * \param path the name of the node. Expressed as a file name with slashes 
+ * separating ancestors of the node.
+ * \param watcher if non-null a watch will set on the specified znode on the server.
+ * The watch will be set even if the node does not exist. This allows clients 
+ * to watch for nodes to appear.
+ * \param watcherCtx user specific data, will be passed to the watcher callback.
+ * Unlike the global context set by \ref zookeeper_init, this watcher context
+ * is associated with the given instance of the watcher only.
+ * \param completion the routine to invoke when the request completes. The completion
+ * will be triggered with one of the following codes passed in as the rc argument:
+ * ZOK operation completed succesfully
+ * ZNONODE the node does not exist.
+ * ZNOAUTH the client does not have permission.
+ * \param data the data that will be passed to the completion routine when the 
+ * function completes.
+ * \return ZOK on success or one of the following errcodes on failure:
+ * ZBADARGUMENTS - invalid input parameters
+ * ZINVALIDSTATE - zhandle state is either SESSION_EXPIRED_STATE or AUTH_FAILED_STATE
+ * ZMARSHALLINGERROR - failed to marshall a request; possibly, out of memory
+ */
+ZOOAPI int zoo_awexists(zhandle_t *zh, const char *path, 
+        watcher_fn watcher, void* watcherCtx, 
+        stat_completion_t completion, const void *data);
+
+/**
  * \brief gets the data associated with a node.
  * 
  * \param zh the zookeeper handle obtained by a call to \ref zookeeper_init
@@ -602,6 +657,36 @@
         data_completion_t completion, const void *data);
 
 /**
+ * \brief gets the data associated with a node.
+ * 
+ * This function is similar to \ref zoo_aget except it allows one specify 
+ * a watcher object rather than a boolean watch flag. 
+ *
+ * \param zh the zookeeper handle obtained by a call to \ref zookeeper_init
+ * \param path the name of the node. Expressed as a file name with slashes 
+ * separating ancestors of the node.
+ * \param watcher if non-null, a watch will be set at the server to notify 
+ * the client if the node changes.
+ * \param watcherCtx user specific data, will be passed to the watcher callback.
+ * Unlike the global context set by \ref zookeeper_init, this watcher context
+ * is associated with the given instance of the watcher only.
+ * \param completion the routine to invoke when the request completes. The completion
+ * will be triggered with one of the following codes passed in as the rc argument:
+ * ZOK operation completed succesfully
+ * ZNONODE the node does not exist.
+ * ZNOAUTH the client does not have permission.
+ * \param data the data that will be passed to the completion routine when 
+ * the function completes.
+ * \return ZOK on success or one of the following errcodes on failure:
+ * ZBADARGUMENTS - invalid input parameters
+ * ZINVALIDSTATE - zhandle state is either in SESSION_EXPIRED_STATE or AUTH_FAILED_STATE
+ * ZMARSHALLINGERROR - failed to marshall a request; possibly, out of memory
+ */
+ZOOAPI int zoo_awget(zhandle_t *zh, const char *path, 
+        watcher_fn watcher, void* watcherCtx, 
+        data_completion_t completion, const void *data);
+
+/**
  * \brief sets the data associated with a node.
  * 
  * \param zh the zookeeper handle obtained by a call to \ref zookeeper_init
@@ -654,6 +739,36 @@
         strings_completion_t completion, const void *data);
 
 /**
+ * \brief lists the children of a node.
+ * 
+ * This function is similar to \ref zoo_aget_children except it allows one specify 
+ * a watcher object rather than a boolean watch flag.
+ *  
+ * \param zh the zookeeper handle obtained by a call to \ref zookeeper_init
+ * \param path the name of the node. Expressed as a file name with slashes 
+ * separating ancestors of the node.
+ * \param watcher if non-null, a watch will be set at the server to notify 
+ * the client if the node changes.
+ * \param watcherCtx user specific data, will be passed to the watcher callback.
+ * Unlike the global context set by \ref zookeeper_init, this watcher context
+ * is associated with the given instance of the watcher only.
+ * \param completion the routine to invoke when the request completes. The completion
+ * will be triggered with one of the following codes passed in as the rc argument:
+ * ZOK operation completed succesfully
+ * ZNONODE the node does not exist.
+ * ZNOAUTH the client does not have permission.
+ * \param data the data that will be passed to the completion routine when 
+ * the function completes.
+ * \return ZOK on success or one of the following errcodes on failure:
+ * ZBADARGUMENTS - invalid input parameters
+ * ZINVALIDSTATE - zhandle state is either SESSION_EXPIRED_STATE or AUTH_FAILED_STATE
+ * ZMARSHALLINGERROR - failed to marshall a request; possibly, out of memory
+ */
+ZOOAPI int zoo_awget_children(zhandle_t *zh, const char *path,
+        watcher_fn watcher, void* watcherCtx, 
+        strings_completion_t completion, const void *data);
+
+/**
  * \brief Flush leader channel.
  *
  * \param zh the zookeeper handle obtained by a call to \ref zookeeper_init
@@ -672,7 +787,8 @@
  * ZMARSHALLINGERROR - failed to marshall a request; possibly, out of memory
  */
 
-ZOOAPI int zoo_async(zhandle_t *zh, const char *path, string_completion_t completion, const void *data);
+ZOOAPI int zoo_async(zhandle_t *zh, const char *path, 
+        string_completion_t completion, const void *data);
 
 
 /**
@@ -825,7 +941,6 @@
  * ZINVALIDSTATE - zhandle state is either SESSION_EXPIRED_STATE or AUTH_FAILED_STATE
  * ZMARSHALLINGERROR - failed to marshall a request; possibly, out of memory
  */
-
 ZOOAPI int zoo_create(zhandle_t *zh, const char *path, const char *value,
         int valuelen, const struct ACL_vector *acl, int flags, char *realpath,	 
         int max_realpath_len);
@@ -849,7 +964,6 @@
  * ZINVALIDSTATE - zhandle state is either SESSION_EXPIRED_STATE or AUTH_FAILED_STATE
  * ZMARSHALLINGERROR - failed to marshall a request; possibly, out of memory
  */
-
 ZOOAPI int zoo_delete(zhandle_t *zh, const char *path, int version);
 
 
@@ -871,10 +985,36 @@
  * ZINVALIDSTATE - zhandle state is either SESSION_EXPIRED_STATE or AUTH_FAILED_STATE
  * ZMARSHALLINGERROR - failed to marshall a request; possibly, out of memory
  */
-
 ZOOAPI int zoo_exists(zhandle_t *zh, const char *path, int watch, struct Stat *stat);
 
 /**
+ * \brief checks the existence of a node in zookeeper synchronously.
+ * 
+ * This function is similar to \ref zoo_exists except it allows one specify 
+ * a watcher object rather than a boolean watch flag.
+ * 
+ * \param zh the zookeeper handle obtained by a call to \ref zookeeper_init
+ * \param path the name of the node. Expressed as a file name with slashes 
+ * separating ancestors of the node.
+ * \param watcher if non-null a watch will set on the specified znode on the server.
+ * The watch will be set even if the node does not exist. This allows clients 
+ * to watch for nodes to appear.
+ * \param watcherCtx user specific data, will be passed to the watcher callback.
+ * Unlike the global context set by \ref zookeeper_init, this watcher context
+ * is associated with the given instance of the watcher only.
+ * \param the return stat value of the node.
+ * \return  return code of the function call.
+ * ZOK operation completed succesfully
+ * ZNONODE the node does not exist.
+ * ZNOAUTH the client does not have permission.
+ * ZBADARGUMENTS - invalid input parameters
+ * ZINVALIDSTATE - zhandle state is either SESSION_EXPIRED_STATE or AUTH_FAILED_STATE
+ * ZMARSHALLINGERROR - failed to marshall a request; possibly, out of memory
+ */
+ZOOAPI int zoo_wexists(zhandle_t *zh, const char *path,
+        watcher_fn watcher, void* watcherCtx, struct Stat *stat);
+
+/**
  * \brief gets the data associated with a node synchronously.
  * 
  * \param zh the zookeeper handle obtained by a call to \ref zookeeper_init
@@ -894,10 +1034,38 @@
  * ZINVALIDSTATE - zhandle state is either in SESSION_EXPIRED_STATE or AUTH_FAILED_STATE
  * ZMARSHALLINGERROR - failed to marshall a request; possibly, out of memory
  */
-
 ZOOAPI int zoo_get(zhandle_t *zh, const char *path, int watch, char *buffer,   
                    int* buffer_len, struct Stat *stat);
 
+/**
+ * \brief gets the data associated with a node synchronously.
+ * 
+ * This function is similar to \ref zoo_get except it allows one specify 
+ * a watcher object rather than a boolean watch flag.
+ * 
+ * \param zh the zookeeper handle obtained by a call to \ref zookeeper_init
+ * \param path the name of the node. Expressed as a file name with slashes 
+ * separating ancestors of the node.
+ * \param watcher if non-null, a watch will be set at the server to notify 
+ * the client if the node changes.
+ * \param watcherCtx user specific data, will be passed to the watcher callback.
+ * Unlike the global context set by \ref zookeeper_init, this watcher context
+ * is associated with the given instance of the watcher only.
+ * \param buffer the buffer holding the node data returned by the server
+ * \param buffer_len is the size of the buffer pointed to by the buffer parameter.
+ * It'll be set to the actual data length upon return.
+ * \param stat if not NULL, will hold the value of stat for the path on return.
+ * \return return value of the function call.
+ * ZOK operation completed succesfully
+ * ZNONODE the node does not exist.
+ * ZNOAUTH the client does not have permission.
+ * ZBADARGUMENTS - invalid input parameters
+ * ZINVALIDSTATE - zhandle state is either in SESSION_EXPIRED_STATE or AUTH_FAILED_STATE
+ * ZMARSHALLINGERROR - failed to marshall a request; possibly, out of memory
+ */
+ZOOAPI int zoo_wget(zhandle_t *zh, const char *path, 
+        watcher_fn watcher, void* watcherCtx, 
+        char *buffer, int* buffer_len, struct Stat *stat);
 
 /**
  * \brief sets the data associated with a node.
@@ -919,7 +1087,6 @@
  * ZINVALIDSTATE - zhandle state is either SESSION_EXPIRED_STATE or AUTH_FAILED_STATE
  * ZMARSHALLINGERROR - failed to marshall a request; possibly, out of memory
  */
-
 ZOOAPI int zoo_set(zhandle_t *zh, const char *path, const char *buffer, int buflen,
                    int version);
 
@@ -941,9 +1108,36 @@
  * ZINVALIDSTATE - zhandle state is either SESSION_EXPIRED_STATE or AUTH_FAILED_STATE
  * ZMARSHALLINGERROR - failed to marshall a request; possibly, out of memory
  */
-
 ZOOAPI int zoo_get_children(zhandle_t *zh, const char *path, int watch,
                             struct String_vector *strings);
+
+/**
+ * \brief lists the children of a node synchronously.
+ * 
+ * This function is similar to \ref zoo_get_children except it allows one specify 
+ * a watcher object rather than a boolean watch flag.
+ * 
+ * \param zh the zookeeper handle obtained by a call to \ref zookeeper_init
+ * \param path the name of the node. Expressed as a file name with slashes 
+ * separating ancestors of the node.
+ * \param watcher if non-null, a watch will be set at the server to notify 
+ * the client if the node changes.
+ * \param watcherCtx user specific data, will be passed to the watcher callback.
+ * Unlike the global context set by \ref zookeeper_init, this watcher context
+ * is associated with the given instance of the watcher only.
+ * \param strings return value of children paths.
+ * \return the return code of the function.
+ * ZOK operation completed succesfully
+ * ZNONODE the node does not exist.
+ * ZNOAUTH the client does not have permission.
+ * ZBADARGUMENTS - invalid input parameters
+ * ZINVALIDSTATE - zhandle state is either SESSION_EXPIRED_STATE or AUTH_FAILED_STATE
+ * ZMARSHALLINGERROR - failed to marshall a request; possibly, out of memory
+ */
+ZOOAPI int zoo_wget_children(zhandle_t *zh, const char *path, 
+        watcher_fn watcher, void* watcherCtx,
+        struct String_vector *strings);
+
 /**
  * \brief gets the acl associated with a node synchronously.
  * 
@@ -960,7 +1154,6 @@
  * ZINVALIDSTATE - zhandle state is either SESSION_EXPIRED_STATE or AUTH_FAILED_STATE
  * ZMARSHALLINGERROR - failed to marshall a request; possibly, out of memory
  */
-
 ZOOAPI int zoo_get_acl(zhandle_t *zh, const char *path, struct ACL_vector *acl,
                        struct Stat *stat);
 
@@ -982,7 +1175,6 @@
  * ZINVALIDSTATE - zhandle state is either SESSION_EXPIRED_STATE or AUTH_FAILED_STATE
  * ZMARSHALLINGERROR - failed to marshall a request; possibly, out of memory
  */
-
 ZOOAPI int zoo_set_acl(zhandle_t *zh, const char *path, int version,
                            const struct ACL_vector *acl);
 

Modified: hadoop/zookeeper/trunk/src/c/src/cli.c
URL: http://svn.apache.org/viewvc/hadoop/zookeeper/trunk/src/c/src/cli.c?rev=679557&r1=679556&r2=679557&view=diff
==============================================================================
--- hadoop/zookeeper/trunk/src/c/src/cli.c (original)
+++ hadoop/zookeeper/trunk/src/c/src/cli.c Thu Jul 24 14:46:30 2008
@@ -55,7 +55,7 @@
     fprintf(stderr,"%s: execution time=%dms\n",msg,delay);
 }
 
-void watcher(zhandle_t *zzh, int type, int state, const char *path) {
+void watcher(zhandle_t *zzh, int type, int state, const char *path,void* context) {
     fprintf(stderr,"Watcher %d state = %d for %s\n", type, state, (path ? path: "null"));
     if (type == SESSION_EVENT) {
         if (state == CONNECTED_STATE) {

Added: hadoop/zookeeper/trunk/src/c/src/hashtable/LICENSE.txt
URL: http://svn.apache.org/viewvc/hadoop/zookeeper/trunk/src/c/src/hashtable/LICENSE.txt?rev=679557&view=auto
==============================================================================
--- hadoop/zookeeper/trunk/src/c/src/hashtable/LICENSE.txt (added)
+++ hadoop/zookeeper/trunk/src/c/src/hashtable/LICENSE.txt Thu Jul 24 14:46:30 2008
@@ -0,0 +1,30 @@
+Copyright (c) 2002, 2004, Christopher Clark
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+
+	* Redistributions of source code must retain the above copyright
+notice, this list of conditions and the following disclaimer.
+
+	* Redistributions in binary form must reproduce the above copyright
+notice, this list of conditions and the following disclaimer in the
+documentation and/or other materials provided with the distribution.
+
+	* Neither the name of the original author; nor the names of any contributors
+may be used to endorse or promote products derived from this software
+without specific prior written permission.
+
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

Propchange: hadoop/zookeeper/trunk/src/c/src/hashtable/LICENSE.txt
------------------------------------------------------------------------------
    svn:eol-style = native

Added: hadoop/zookeeper/trunk/src/c/src/hashtable/hashtable.c
URL: http://svn.apache.org/viewvc/hadoop/zookeeper/trunk/src/c/src/hashtable/hashtable.c?rev=679557&view=auto
==============================================================================
--- hadoop/zookeeper/trunk/src/c/src/hashtable/hashtable.c (added)
+++ hadoop/zookeeper/trunk/src/c/src/hashtable/hashtable.c Thu Jul 24 14:46:30 2008
@@ -0,0 +1,274 @@
+/* Copyright (C) 2004 Christopher Clark <fi...@cl.cam.ac.uk> */
+
+#include "hashtable.h"
+#include "hashtable_private.h"
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <math.h>
+
+/*
+Credit for primes table: Aaron Krowne
+ http://br.endernet.org/~akrowne/
+ http://planetmath.org/encyclopedia/GoodHashTablePrimes.html
+*/
+static const unsigned int primes[] = {
+53, 97, 193, 389,
+769, 1543, 3079, 6151,
+12289, 24593, 49157, 98317,
+196613, 393241, 786433, 1572869,
+3145739, 6291469, 12582917, 25165843,
+50331653, 100663319, 201326611, 402653189,
+805306457, 1610612741
+};
+const unsigned int prime_table_length = sizeof(primes)/sizeof(primes[0]);
+const float max_load_factor = 0.65;
+
+/*****************************************************************************/
+struct hashtable *
+create_hashtable(unsigned int minsize,
+                 unsigned int (*hashf) (void*),
+                 int (*eqf) (void*,void*))
+{
+    struct hashtable *h;
+    unsigned int pindex, size = primes[0];
+    /* Check requested hashtable isn't too large */
+    if (minsize > (1u << 30)) return NULL;
+    /* Enforce size as prime */
+    for (pindex=0; pindex < prime_table_length; pindex++) {
+        if (primes[pindex] > minsize) { size = primes[pindex]; break; }
+    }
+    h = (struct hashtable *)malloc(sizeof(struct hashtable));
+    if (NULL == h) return NULL; /*oom*/
+    h->table = (struct entry **)malloc(sizeof(struct entry*) * size);
+    if (NULL == h->table) { free(h); return NULL; } /*oom*/
+    memset(h->table, 0, size * sizeof(struct entry *));
+    h->tablelength  = size;
+    h->primeindex   = pindex;
+    h->entrycount   = 0;
+    h->hashfn       = hashf;
+    h->eqfn         = eqf;
+    h->loadlimit    = (unsigned int) ceil(size * max_load_factor);
+    return h;
+}
+
+/*****************************************************************************/
+unsigned int
+hash(struct hashtable *h, void *k)
+{
+    /* Aim to protect against poor hash functions by adding logic here
+     * - logic taken from java 1.4 hashtable source */
+    unsigned int i = h->hashfn(k);
+    i += ~(i << 9);
+    i ^=  ((i >> 14) | (i << 18)); /* >>> */
+    i +=  (i << 4);
+    i ^=  ((i >> 10) | (i << 22)); /* >>> */
+    return i;
+}
+
+/*****************************************************************************/
+static int
+hashtable_expand(struct hashtable *h)
+{
+    /* Double the size of the table to accomodate more entries */
+    struct entry **newtable;
+    struct entry *e;
+    struct entry **pE;
+    unsigned int newsize, i, index;
+    /* Check we're not hitting max capacity */
+    if (h->primeindex == (prime_table_length - 1)) return 0;
+    newsize = primes[++(h->primeindex)];
+
+    newtable = (struct entry **)malloc(sizeof(struct entry*) * newsize);
+    if (NULL != newtable)
+    {
+        memset(newtable, 0, newsize * sizeof(struct entry *));
+        /* This algorithm is not 'stable'. ie. it reverses the list
+         * when it transfers entries between the tables */
+        for (i = 0; i < h->tablelength; i++) {
+            while (NULL != (e = h->table[i])) {
+                h->table[i] = e->next;
+                index = indexFor(newsize,e->h);
+                e->next = newtable[index];
+                newtable[index] = e;
+            }
+        }
+        free(h->table);
+        h->table = newtable;
+    }
+    /* Plan B: realloc instead */
+    else 
+    {
+        newtable = (struct entry **)
+                   realloc(h->table, newsize * sizeof(struct entry *));
+        if (NULL == newtable) { (h->primeindex)--; return 0; }
+        h->table = newtable;
+        memset(newtable[h->tablelength], 0, newsize - h->tablelength);
+        for (i = 0; i < h->tablelength; i++) {
+            for (pE = &(newtable[i]), e = *pE; e != NULL; e = *pE) {
+                index = indexFor(newsize,e->h);
+                if (index == i)
+                {
+                    pE = &(e->next);
+                }
+                else
+                {
+                    *pE = e->next;
+                    e->next = newtable[index];
+                    newtable[index] = e;
+                }
+            }
+        }
+    }
+    h->tablelength = newsize;
+    h->loadlimit   = (unsigned int) ceil(newsize * max_load_factor);
+    return -1;
+}
+
+/*****************************************************************************/
+unsigned int
+hashtable_count(struct hashtable *h)
+{
+    return h->entrycount;
+}
+
+/*****************************************************************************/
+int
+hashtable_insert(struct hashtable *h, void *k, void *v)
+{
+    /* This method allows duplicate keys - but they shouldn't be used */
+    unsigned int index;
+    struct entry *e;
+    if (++(h->entrycount) > h->loadlimit)
+    {
+        /* Ignore the return value. If expand fails, we should
+         * still try cramming just this value into the existing table
+         * -- we may not have memory for a larger table, but one more
+         * element may be ok. Next time we insert, we'll try expanding again.*/
+        hashtable_expand(h);
+    }
+    e = (struct entry *)malloc(sizeof(struct entry));
+    if (NULL == e) { --(h->entrycount); return 0; } /*oom*/
+    e->h = hash(h,k);
+    index = indexFor(h->tablelength,e->h);
+    e->k = k;
+    e->v = v;
+    e->next = h->table[index];
+    h->table[index] = e;
+    return -1;
+}
+
+/*****************************************************************************/
+void * /* returns value associated with key */
+hashtable_search(struct hashtable *h, void *k)
+{
+    struct entry *e;
+    unsigned int hashvalue, index;
+    hashvalue = hash(h,k);
+    index = indexFor(h->tablelength,hashvalue);
+    e = h->table[index];
+    while (NULL != e)
+    {
+        /* Check hash value to short circuit heavier comparison */
+        if ((hashvalue == e->h) && (h->eqfn(k, e->k))) return e->v;
+        e = e->next;
+    }
+    return NULL;
+}
+
+/*****************************************************************************/
+void * /* returns value associated with key */
+hashtable_remove(struct hashtable *h, void *k)
+{
+    /* TODO: consider compacting the table when the load factor drops enough,
+     *       or provide a 'compact' method. */
+
+    struct entry *e;
+    struct entry **pE;
+    void *v;
+    unsigned int hashvalue, index;
+
+    hashvalue = hash(h,k);
+    index = indexFor(h->tablelength,hash(h,k));
+    pE = &(h->table[index]);
+    e = *pE;
+    while (NULL != e)
+    {
+        /* Check hash value to short circuit heavier comparison */
+        if ((hashvalue == e->h) && (h->eqfn(k, e->k)))
+        {
+            *pE = e->next;
+            h->entrycount--;
+            v = e->v;
+            freekey(e->k);
+            free(e);
+            return v;
+        }
+        pE = &(e->next);
+        e = e->next;
+    }
+    return NULL;
+}
+
+/*****************************************************************************/
+/* destroy */
+void
+hashtable_destroy(struct hashtable *h, int free_values)
+{
+    unsigned int i;
+    struct entry *e, *f;
+    struct entry **table = h->table;
+    if (free_values)
+    {
+        for (i = 0; i < h->tablelength; i++)
+        {
+            e = table[i];
+            while (NULL != e)
+            { f = e; e = e->next; freekey(f->k); free(f->v); free(f); }
+        }
+    }
+    else
+    {
+        for (i = 0; i < h->tablelength; i++)
+        {
+            e = table[i];
+            while (NULL != e)
+            { f = e; e = e->next; freekey(f->k); free(f); }
+        }
+    }
+    free(h->table);
+    free(h);
+}
+
+/*
+ * Copyright (c) 2002, Christopher Clark
+ * All rights reserved.
+ * 
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 
+ * * Neither the name of the original author; nor the names of any contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ * 
+ * 
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER
+ * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/

Propchange: hadoop/zookeeper/trunk/src/c/src/hashtable/hashtable.c
------------------------------------------------------------------------------
    svn:eol-style = native

Added: hadoop/zookeeper/trunk/src/c/src/hashtable/hashtable.h
URL: http://svn.apache.org/viewvc/hadoop/zookeeper/trunk/src/c/src/hashtable/hashtable.h?rev=679557&view=auto
==============================================================================
--- hadoop/zookeeper/trunk/src/c/src/hashtable/hashtable.h (added)
+++ hadoop/zookeeper/trunk/src/c/src/hashtable/hashtable.h Thu Jul 24 14:46:30 2008
@@ -0,0 +1,207 @@
+/* Copyright (C) 2002 Christopher Clark <fi...@cl.cam.ac.uk> */
+
+#ifndef __HASHTABLE_CWC22_H__
+#define __HASHTABLE_CWC22_H__
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+struct hashtable;
+
+/* Example of use:
+ *
+ *      struct hashtable  *h;
+ *      struct some_key   *k;
+ *      struct some_value *v;
+ *
+ *      static unsigned int         hash_from_key_fn( void *k );
+ *      static int                  keys_equal_fn ( void *key1, void *key2 );
+ *
+ *      h = create_hashtable(16, hash_from_key_fn, keys_equal_fn);
+ *      k = (struct some_key *)     malloc(sizeof(struct some_key));
+ *      v = (struct some_value *)   malloc(sizeof(struct some_value));
+ *
+ *      (initialise k and v to suitable values)
+ * 
+ *      if (! hashtable_insert(h,k,v) )
+ *      {     exit(-1);               }
+ *
+ *      if (NULL == (found = hashtable_search(h,k) ))
+ *      {    printf("not found!");                  }
+ *
+ *      if (NULL == (found = hashtable_remove(h,k) ))
+ *      {    printf("Not found\n");                 }
+ *
+ */
+
+/* Macros may be used to define type-safe(r) hashtable access functions, with
+ * methods specialized to take known key and value types as parameters.
+ * 
+ * Example:
+ *
+ * Insert this at the start of your file:
+ *
+ * DEFINE_HASHTABLE_INSERT(insert_some, struct some_key, struct some_value);
+ * DEFINE_HASHTABLE_SEARCH(search_some, struct some_key, struct some_value);
+ * DEFINE_HASHTABLE_REMOVE(remove_some, struct some_key, struct some_value);
+ *
+ * This defines the functions 'insert_some', 'search_some' and 'remove_some'.
+ * These operate just like hashtable_insert etc., with the same parameters,
+ * but their function signatures have 'struct some_key *' rather than
+ * 'void *', and hence can generate compile time errors if your program is
+ * supplying incorrect data as a key (and similarly for value).
+ *
+ * Note that the hash and key equality functions passed to create_hashtable
+ * still take 'void *' parameters instead of 'some key *'. This shouldn't be
+ * a difficult issue as they're only defined and passed once, and the other
+ * functions will ensure that only valid keys are supplied to them.
+ *
+ * The cost for this checking is increased code size and runtime overhead
+ * - if performance is important, it may be worth switching back to the
+ * unsafe methods once your program has been debugged with the safe methods.
+ * This just requires switching to some simple alternative defines - eg:
+ * #define insert_some hashtable_insert
+ *
+ */
+
+/*****************************************************************************
+ * create_hashtable
+   
+ * @name                    create_hashtable
+ * @param   minsize         minimum initial size of hashtable
+ * @param   hashfunction    function for hashing keys
+ * @param   key_eq_fn       function for determining key equality
+ * @return                  newly created hashtable or NULL on failure
+ */
+
+struct hashtable *
+create_hashtable(unsigned int minsize,
+                 unsigned int (*hashfunction) (void*),
+                 int (*key_eq_fn) (void*,void*));
+
+/*****************************************************************************
+ * hashtable_insert
+   
+ * @name        hashtable_insert
+ * @param   h   the hashtable to insert into
+ * @param   k   the key - hashtable claims ownership and will free on removal
+ * @param   v   the value - does not claim ownership
+ * @return      non-zero for successful insertion
+ *
+ * This function will cause the table to expand if the insertion would take
+ * the ratio of entries to table size over the maximum load factor.
+ *
+ * This function does not check for repeated insertions with a duplicate key.
+ * The value returned when using a duplicate key is undefined -- when
+ * the hashtable changes size, the order of retrieval of duplicate key
+ * entries is reversed.
+ * If in doubt, remove before insert.
+ */
+
+int 
+hashtable_insert(struct hashtable *h, void *k, void *v);
+
+#define DEFINE_HASHTABLE_INSERT(fnname, keytype, valuetype) \
+int fnname (struct hashtable *h, keytype *k, valuetype *v) \
+{ \
+    return hashtable_insert(h,k,v); \
+}
+
+/*****************************************************************************
+ * hashtable_search
+   
+ * @name        hashtable_search
+ * @param   h   the hashtable to search
+ * @param   k   the key to search for  - does not claim ownership
+ * @return      the value associated with the key, or NULL if none found
+ */
+
+void *
+hashtable_search(struct hashtable *h, void *k);
+
+#define DEFINE_HASHTABLE_SEARCH(fnname, keytype, valuetype) \
+valuetype * fnname (struct hashtable *h, keytype *k) \
+{ \
+    return (valuetype *) (hashtable_search(h,k)); \
+}
+
+/*****************************************************************************
+ * hashtable_remove
+   
+ * @name        hashtable_remove
+ * @param   h   the hashtable to remove the item from
+ * @param   k   the key to search for  - does not claim ownership
+ * @return      the value associated with the key, or NULL if none found
+ */
+
+void * /* returns value */
+hashtable_remove(struct hashtable *h, void *k);
+
+#define DEFINE_HASHTABLE_REMOVE(fnname, keytype, valuetype) \
+valuetype * fnname (struct hashtable *h, keytype *k) \
+{ \
+    return (valuetype *) (hashtable_remove(h,k)); \
+}
+
+
+/*****************************************************************************
+ * hashtable_count
+   
+ * @name        hashtable_count
+ * @param   h   the hashtable
+ * @return      the number of items stored in the hashtable
+ */
+unsigned int
+hashtable_count(struct hashtable *h);
+
+
+/*****************************************************************************
+ * hashtable_destroy
+   
+ * @name        hashtable_destroy
+ * @param   h   the hashtable
+ * @param       free_values     whether to call 'free' on the remaining values
+ */
+
+void
+hashtable_destroy(struct hashtable *h, int free_values);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* __HASHTABLE_CWC22_H__ */
+
+/*
+ * Copyright (c) 2002, Christopher Clark
+ * All rights reserved.
+ * 
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 
+ * * Neither the name of the original author; nor the names of any contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ * 
+ * 
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER
+ * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/

Propchange: hadoop/zookeeper/trunk/src/c/src/hashtable/hashtable.h
------------------------------------------------------------------------------
    svn:eol-style = native

Added: hadoop/zookeeper/trunk/src/c/src/hashtable/hashtable_itr.c
URL: http://svn.apache.org/viewvc/hadoop/zookeeper/trunk/src/c/src/hashtable/hashtable_itr.c?rev=679557&view=auto
==============================================================================
--- hadoop/zookeeper/trunk/src/c/src/hashtable/hashtable_itr.c (added)
+++ hadoop/zookeeper/trunk/src/c/src/hashtable/hashtable_itr.c Thu Jul 24 14:46:30 2008
@@ -0,0 +1,188 @@
+/* Copyright (C) 2002, 2004 Christopher Clark  <fi...@cl.cam.ac.uk> */
+
+#include "hashtable.h"
+#include "hashtable_private.h"
+#include "hashtable_itr.h"
+#include <stdlib.h> /* defines NULL */
+
+/*****************************************************************************/
+/* hashtable_iterator    - iterator constructor */
+
+struct hashtable_itr *
+hashtable_iterator(struct hashtable *h)
+{
+    unsigned int i, tablelength;
+    struct hashtable_itr *itr = (struct hashtable_itr *)
+        malloc(sizeof(struct hashtable_itr));
+    if (NULL == itr) return NULL;
+    itr->h = h;
+    itr->e = NULL;
+    itr->parent = NULL;
+    tablelength = h->tablelength;
+    itr->index = tablelength;
+    if (0 == h->entrycount) return itr;
+
+    for (i = 0; i < tablelength; i++)
+    {
+        if (NULL != h->table[i])
+        {
+            itr->e = h->table[i];
+            itr->index = i;
+            break;
+        }
+    }
+    return itr;
+}
+
+/*****************************************************************************/
+/* key      - return the key of the (key,value) pair at the current position */
+/* value    - return the value of the (key,value) pair at the current position */
+
+void *
+hashtable_iterator_key(struct hashtable_itr *i)
+{ return i->e->k; }
+
+void *
+hashtable_iterator_value(struct hashtable_itr *i)
+{ return i->e->v; }
+
+/*****************************************************************************/
+/* advance - advance the iterator to the next element
+ *           returns zero if advanced to end of table */
+
+int
+hashtable_iterator_advance(struct hashtable_itr *itr)
+{
+    unsigned int j,tablelength;
+    struct entry **table;
+    struct entry *next;
+    if (NULL == itr->e) return 0; /* stupidity check */
+
+    next = itr->e->next;
+    if (NULL != next)
+    {
+        itr->parent = itr->e;
+        itr->e = next;
+        return -1;
+    }
+    tablelength = itr->h->tablelength;
+    itr->parent = NULL;
+    if (tablelength <= (j = ++(itr->index)))
+    {
+        itr->e = NULL;
+        return 0;
+    }
+    table = itr->h->table;
+    while (NULL == (next = table[j]))
+    {
+        if (++j >= tablelength)
+        {
+            itr->index = tablelength;
+            itr->e = NULL;
+            return 0;
+        }
+    }
+    itr->index = j;
+    itr->e = next;
+    return -1;
+}
+
+/*****************************************************************************/
+/* remove - remove the entry at the current iterator position
+ *          and advance the iterator, if there is a successive
+ *          element.
+ *          If you want the value, read it before you remove:
+ *          beware memory leaks if you don't.
+ *          Returns zero if end of iteration. */
+
+int
+hashtable_iterator_remove(struct hashtable_itr *itr)
+{
+    struct entry *remember_e, *remember_parent;
+    int ret;
+
+    /* Do the removal */
+    if (NULL == (itr->parent))
+    {
+        /* element is head of a chain */
+        itr->h->table[itr->index] = itr->e->next;
+    } else {
+        /* element is mid-chain */
+        itr->parent->next = itr->e->next;
+    }
+    /* itr->e is now outside the hashtable */
+    remember_e = itr->e;
+    itr->h->entrycount--;
+    freekey(remember_e->k);
+
+    /* Advance the iterator, correcting the parent */
+    remember_parent = itr->parent;
+    ret = hashtable_iterator_advance(itr);
+    if (itr->parent == remember_e) { itr->parent = remember_parent; }
+    free(remember_e);
+    return ret;
+}
+
+/*****************************************************************************/
+int /* returns zero if not found */
+hashtable_iterator_search(struct hashtable_itr *itr,
+                          struct hashtable *h, void *k)
+{
+    struct entry *e, *parent;
+    unsigned int hashvalue, index;
+
+    hashvalue = hash(h,k);
+    index = indexFor(h->tablelength,hashvalue);
+
+    e = h->table[index];
+    parent = NULL;
+    while (NULL != e)
+    {
+        /* Check hash value to short circuit heavier comparison */
+        if ((hashvalue == e->h) && (h->eqfn(k, e->k)))
+        {
+            itr->index = index;
+            itr->e = e;
+            itr->parent = parent;
+            itr->h = h;
+            return -1;
+        }
+        parent = e;
+        e = e->next;
+    }
+    return 0;
+}
+
+
+/*
+ * Copyright (c) 2002, 2004, Christopher Clark
+ * All rights reserved.
+ * 
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 
+ * * Neither the name of the original author; nor the names of any contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ * 
+ * 
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER
+ * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/

Propchange: hadoop/zookeeper/trunk/src/c/src/hashtable/hashtable_itr.c
------------------------------------------------------------------------------
    svn:eol-style = native

Added: hadoop/zookeeper/trunk/src/c/src/hashtable/hashtable_itr.h
URL: http://svn.apache.org/viewvc/hadoop/zookeeper/trunk/src/c/src/hashtable/hashtable_itr.h?rev=679557&view=auto
==============================================================================
--- hadoop/zookeeper/trunk/src/c/src/hashtable/hashtable_itr.h (added)
+++ hadoop/zookeeper/trunk/src/c/src/hashtable/hashtable_itr.h Thu Jul 24 14:46:30 2008
@@ -0,0 +1,119 @@
+/* Copyright (C) 2002, 2004 Christopher Clark <fi...@cl.cam.ac.uk> */
+
+#ifndef __HASHTABLE_ITR_CWC22__
+#define __HASHTABLE_ITR_CWC22__
+#include "hashtable.h"
+#include "hashtable_private.h" /* needed to enable inlining */
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/*****************************************************************************/
+/* This struct is only concrete here to allow the inlining of two of the
+ * accessor functions. */
+struct hashtable_itr
+{
+    struct hashtable *h;
+    struct entry *e;
+    struct entry *parent;
+    unsigned int index;
+};
+
+
+/*****************************************************************************/
+/* hashtable_iterator
+ */
+
+struct hashtable_itr *
+hashtable_iterator(struct hashtable *h);
+
+/*****************************************************************************/
+/* hashtable_iterator_key
+ * - return the value of the (key,value) pair at the current position */
+
+extern inline void *
+hashtable_iterator_key(struct hashtable_itr *i)
+{
+    return i->e->k;
+}
+
+/*****************************************************************************/
+/* value - return the value of the (key,value) pair at the current position */
+
+extern inline void *
+hashtable_iterator_value(struct hashtable_itr *i)
+{
+    return i->e->v;
+}
+
+/*****************************************************************************/
+/* advance - advance the iterator to the next element
+ *           returns zero if advanced to end of table */
+
+int
+hashtable_iterator_advance(struct hashtable_itr *itr);
+
+/*****************************************************************************/
+/* remove - remove current element and advance the iterator to the next element
+ *          NB: if you need the value to free it, read it before
+ *          removing. ie: beware memory leaks!
+ *          returns zero if advanced to end of table */
+
+int
+hashtable_iterator_remove(struct hashtable_itr *itr);
+
+/*****************************************************************************/
+/* search - overwrite the supplied iterator, to point to the entry
+ *          matching the supplied key.
+            h points to the hashtable to be searched.
+ *          returns zero if not found. */
+int
+hashtable_iterator_search(struct hashtable_itr *itr,
+                          struct hashtable *h, void *k);
+
+#define DEFINE_HASHTABLE_ITERATOR_SEARCH(fnname, keytype) \
+int fnname (struct hashtable_itr *i, struct hashtable *h, keytype *k) \
+{ \
+    return (hashtable_iterator_search(i,h,k)); \
+}
+
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* __HASHTABLE_ITR_CWC22__*/
+
+/*
+ * Copyright (c) 2002, 2004, Christopher Clark
+ * All rights reserved.
+ * 
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 
+ * * Neither the name of the original author; nor the names of any contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ * 
+ * 
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER
+ * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/

Propchange: hadoop/zookeeper/trunk/src/c/src/hashtable/hashtable_itr.h
------------------------------------------------------------------------------
    svn:eol-style = native

Added: hadoop/zookeeper/trunk/src/c/src/hashtable/hashtable_private.h
URL: http://svn.apache.org/viewvc/hadoop/zookeeper/trunk/src/c/src/hashtable/hashtable_private.h?rev=679557&view=auto
==============================================================================
--- hadoop/zookeeper/trunk/src/c/src/hashtable/hashtable_private.h (added)
+++ hadoop/zookeeper/trunk/src/c/src/hashtable/hashtable_private.h Thu Jul 24 14:46:30 2008
@@ -0,0 +1,85 @@
+/* Copyright (C) 2002, 2004 Christopher Clark <fi...@cl.cam.ac.uk> */
+
+#ifndef __HASHTABLE_PRIVATE_CWC22_H__
+#define __HASHTABLE_PRIVATE_CWC22_H__
+
+#include "hashtable.h"
+
+/*****************************************************************************/
+struct entry
+{
+    void *k, *v;
+    unsigned int h;
+    struct entry *next;
+};
+
+struct hashtable {
+    unsigned int tablelength;
+    struct entry **table;
+    unsigned int entrycount;
+    unsigned int loadlimit;
+    unsigned int primeindex;
+    unsigned int (*hashfn) (void *k);
+    int (*eqfn) (void *k1, void *k2);
+};
+
+/*****************************************************************************/
+unsigned int
+hash(struct hashtable *h, void *k);
+
+/*****************************************************************************/
+/* indexFor */
+static inline unsigned int
+indexFor(unsigned int tablelength, unsigned int hashvalue) {
+    return (hashvalue % tablelength);
+};
+
+/* Only works if tablelength == 2^N */
+/*static inline unsigned int
+indexFor(unsigned int tablelength, unsigned int hashvalue)
+{
+    return (hashvalue & (tablelength - 1u));
+}
+*/
+
+/*****************************************************************************/
+#define freekey(X) free(X)
+/*define freekey(X) ; */
+
+
+/*****************************************************************************/
+
+#endif /* __HASHTABLE_PRIVATE_CWC22_H__*/
+
+/*
+ * Copyright (c) 2002, Christopher Clark
+ * All rights reserved.
+ * 
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 
+ * * Neither the name of the original author; nor the names of any contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ * 
+ * 
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER
+ * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/

Propchange: hadoop/zookeeper/trunk/src/c/src/hashtable/hashtable_private.h
------------------------------------------------------------------------------
    svn:eol-style = native

Modified: hadoop/zookeeper/trunk/src/c/src/load_gen.c
URL: http://svn.apache.org/viewvc/hadoop/zookeeper/trunk/src/c/src/load_gen.c?rev=679557&r1=679556&r2=679557&view=diff
==============================================================================
--- hadoop/zookeeper/trunk/src/c/src/load_gen.c (original)
+++ hadoop/zookeeper/trunk/src/c/src/load_gen.c Thu Jul 24 14:46:30 2008
@@ -68,7 +68,7 @@
     pthread_mutex_unlock(&counterLock);    
 }
 
-void listener(zhandle_t *zzh, int type, int state, const char *path) {
+void listener(zhandle_t *zzh, int type, int state, const char *path,void* ctx) {
     if(type == SESSION_EVENT){
         if(state == CONNECTED_STATE){
             pthread_mutex_lock(&lock);

Modified: hadoop/zookeeper/trunk/src/c/src/zk_adaptor.h
URL: http://svn.apache.org/viewvc/hadoop/zookeeper/trunk/src/c/src/zk_adaptor.h?rev=679557&r1=679556&r2=679557&view=diff
==============================================================================
--- hadoop/zookeeper/trunk/src/c/src/zk_adaptor.h (original)
+++ hadoop/zookeeper/trunk/src/c/src/zk_adaptor.h Thu Jul 24 14:46:30 2008
@@ -23,12 +23,28 @@
 #include <pthread.h>
 #endif
 #include "zookeeper.h"
+#include "zk_hashtable.h"
 
 /* predefined xid's values recognized as special by the server */
 #define WATCHER_EVENT_XID -1 
 #define PING_XID -2
 #define AUTH_XID -4
 
+/* zookeeper state constants */
+#define EXPIRED_SESSION_STATE_DEF -112
+#define AUTH_FAILED_STATE_DEF -113
+#define CONNECTING_STATE_DEF 1
+#define ASSOCIATING_STATE_DEF 2
+#define CONNECTED_STATE_DEF 3
+
+/* zookeeper event type constants */
+#define CREATED_EVENT_DEF 1
+#define DELETED_EVENT_DEF 2
+#define CHANGED_EVENT_DEF 3
+#define CHILD_EVENT_DEF 4
+#define SESSION_EVENT_DEF -1
+#define NOTWATCHING_EVENT_DEF -2
+
 #ifdef __cplusplus
 extern "C" {
 #endif
@@ -174,9 +190,12 @@
     volatile int close_requested;
     void *adaptor_priv;
     /* Used for debugging only: non-zero value indicates the time when the zookeeper_process
-     * call returned while there was at least one server response 
-     * unprocessed available in the socket recv buffer */
+     * call returned while there was at least one unprocessed server response 
+     * available in the socket recv buffer */
     struct timeval socket_readable;
+    
+    zk_hashtable* active_node_watchers;
+    zk_hashtable* active_child_watchers;
 };
 
 int adaptor_init(zhandle_t *zh);
@@ -209,7 +228,7 @@
 #define PROCESS_SESSION_EVENT(zh,newstate) queue_session_event(zh,newstate)
 #else
 // in single-threaded mode process session event immediately
-#define PROCESS_SESSION_EVENT(zh,newstate) zh->watcher(zh,SESSION_EVENT,newstate,0)
+#define PROCESS_SESSION_EVENT(zh,newstate) deliverWatchers(zh,SESSION_EVENT,newstate,0)
 #endif
 
 #ifdef __cplusplus

Added: hadoop/zookeeper/trunk/src/c/src/zk_hashtable.c
URL: http://svn.apache.org/viewvc/hadoop/zookeeper/trunk/src/c/src/zk_hashtable.c?rev=679557&view=auto
==============================================================================
--- hadoop/zookeeper/trunk/src/c/src/zk_hashtable.c (added)
+++ hadoop/zookeeper/trunk/src/c/src/zk_hashtable.c Thu Jul 24 14:46:30 2008
@@ -0,0 +1,444 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "zk_hashtable.h"
+#include "zk_adaptor.h"
+#include "hashtable/hashtable.h"
+#include "hashtable/hashtable_itr.h"
+#include <string.h>
+#include <stdlib.h>
+#include <assert.h>
+
+#ifdef THREADED
+#include <pthread.h>
+#endif
+
+struct _zk_hashtable {
+    struct hashtable* ht;
+#ifdef THREADED
+    pthread_mutex_t lock;
+#endif
+};
+
+hashtable_impl* getImpl(zk_hashtable* ht){
+    return ht->ht;
+}
+
+typedef struct _watcher_object_list_t {
+    watcher_object_t* head;
+} watcher_object_list_t;
+
+watcher_object_t* getFirstWatcher(zk_hashtable* ht,const char* path)
+{
+    watcher_object_list_t* wl=hashtable_search(ht->ht,(void*)path);
+    if(wl!=0)
+        return wl->head;
+    return 0;
+}
+
+watcher_object_t* clone_watcher_object(watcher_object_t* wo)
+{
+    watcher_object_t* res=calloc(1,sizeof(watcher_object_t));
+    res->watcher=wo->watcher;
+    res->context=wo->context;
+    return res;
+}
+
+static unsigned int string_hash_djb2(void *str) 
+{
+    unsigned int hash = 5381;
+    int c;
+
+    while ((c = *(const char*)str++))
+        hash = ((hash << 5) + hash) + c; /* hash * 33 + c */
+
+    return hash;
+}
+
+static int string_equal(void *key1,void *key2)
+{
+    return strcmp((const char*)key1,(const char*)key2)==0;
+}
+
+watcher_object_t* create_watcher_object(watcher_fn watcher,void* ctx)
+{
+    watcher_object_t* wo=calloc(1,sizeof(watcher_object_t));
+    wo->watcher=watcher;
+    wo->context=ctx;
+    return wo;
+}
+
+static watcher_object_list_t* create_watcher_object_list(watcher_object_t* head) 
+{
+    watcher_object_list_t* wl=calloc(1,sizeof(watcher_object_list_t));
+    wl->head=head;
+    return wl;
+}
+
+static void destroy_watcher_object_list(watcher_object_list_t* list)
+{
+    if(list==0)
+        return;
+    watcher_object_t* e=list->head;
+    while(e!=0){
+        watcher_object_t* this=e;
+        e=e->next;
+        free(this);
+    }
+    free(list);
+}
+
+zk_hashtable* create_zk_hashtable()
+{
+    struct _zk_hashtable *ht=calloc(1,sizeof(struct _zk_hashtable));
+#ifdef THREADED
+    pthread_mutex_init(&ht->lock, 0);
+#endif
+    ht->ht=create_hashtable(32,string_hash_djb2,string_equal);
+    return ht;
+}
+
+int get_element_count(zk_hashtable *ht)
+{
+    int res;
+#ifdef THREADED
+    pthread_mutex_lock(&ht->lock);
+#endif
+    res=hashtable_count(ht->ht);    
+#ifdef THREADED
+    pthread_mutex_unlock(&ht->lock);
+#endif
+    return res;
+}
+
+int get_watcher_count(zk_hashtable* ht,const char* path)
+{
+    int res=0;
+    watcher_object_list_t* wl;
+    watcher_object_t* wo;
+#ifdef THREADED
+    pthread_mutex_lock(&ht->lock);
+#endif
+    wl=hashtable_search(ht->ht,(void*)path);
+    if(wl==0)
+        goto done;
+    wo=wl->head;
+    while(wo!=0){
+        res++;
+        wo=wo->next;
+    }
+done:
+#ifdef THREADED
+    pthread_mutex_unlock(&ht->lock);
+#endif
+    return res;    
+}
+
+static void do_clean_hashtable(zk_hashtable* ht)
+{
+    struct hashtable_itr *it;
+    int hasMore;
+    if(hashtable_count(ht->ht)==0)
+        return;
+    it=hashtable_iterator(ht->ht);
+    do{
+        watcher_object_list_t* w=hashtable_iterator_value(it);
+        destroy_watcher_object_list(w);
+        hasMore=hashtable_iterator_remove(it);
+    }while(hasMore);
+    free(it);
+}
+
+void clean_zk_hashtable(zk_hashtable* ht)
+{
+#ifdef THREADED
+    pthread_mutex_lock(&ht->lock);
+#endif
+    do_clean_hashtable(ht);    
+#ifdef THREADED
+    pthread_mutex_unlock(&ht->lock);
+#endif    
+}
+
+void destroy_zk_hashtable(zk_hashtable* ht)
+{
+    if(ht!=0){
+        do_clean_hashtable(ht);
+        hashtable_destroy(ht->ht,0);
+#ifdef THREADED
+        pthread_mutex_destroy(&ht->lock);
+#endif
+        free(ht);
+    }
+}
+
+// searches for a watcher object instance in a watcher object list;
+// two watcher objects are equal if their watcher function and context pointers
+// are equal
+static watcher_object_t* search_watcher(watcher_object_list_t* wl,watcher_object_t* wo)
+{
+    watcher_object_t* wobj=wl->head;
+    while(wobj!=0){
+        if(wobj->watcher==wo->watcher && wobj->context==wo->context)
+            return wobj;
+        wobj=wobj->next;
+    }
+    return 0;
+}
+
+static int do_insert_watcher_object(zk_hashtable *ht, const char *path, watcher_object_t* wo)
+{
+    int res=1;
+    watcher_object_list_t* wl;
+    wl=hashtable_search(ht->ht,(void*)path);
+    if(wl==0){
+        int res;
+        /* inserting a new path element */
+        res=hashtable_insert(ht->ht,strdup(path),create_watcher_object_list(wo));
+        assert(res);
+    }else{
+        /* path already exists; check if the watcher already exists */
+        if(search_watcher(wl,wo)==0){
+            wo->next=wl->head;
+            wl->head=wo; // insert the new watcher at the head
+        }else
+            res=0; // the watcher already exists -- do not insert!
+    }
+    return res;    
+}
+
+int insert_watcher_object(zk_hashtable *ht, const char *path, watcher_object_t* wo)
+{
+    int res;
+#ifdef THREADED
+    pthread_mutex_lock(&ht->lock);
+#endif
+    res=do_insert_watcher_object(ht,path,wo);
+#ifdef THREADED
+    pthread_mutex_unlock(&ht->lock);
+#endif
+    return res;
+}
+
+static void copy_watchers(zk_hashtable* dst,const char* path,watcher_object_list_t* wl)
+{
+    if(wl==0)
+        return;
+    watcher_object_t* wo=wl->head;
+    while(wo!=0){
+        int res;
+        watcher_object_t* cloned=clone_watcher_object(wo);
+        res=do_insert_watcher_object(dst,path,cloned);
+        // was it a duplicate?
+        if(res==0)
+            free(cloned); // yes, didn't get inserted
+        wo=wo->next;
+    }
+}
+
+static void copy_table(zk_hashtable* dst,zk_hashtable* src)
+{
+    struct hashtable_itr *it;
+    int hasMore;
+    if(hashtable_count(src->ht)==0)
+        return;
+    it=hashtable_iterator(src->ht);
+    do{
+        copy_watchers(dst,hashtable_iterator_key(it),hashtable_iterator_value(it));
+        hasMore=hashtable_iterator_advance(it);
+    }while(hasMore);
+    free(it);
+}
+
+zk_hashtable* combine_hashtables(zk_hashtable *ht1,zk_hashtable *ht2)
+{
+    zk_hashtable* newht=create_zk_hashtable();
+#ifdef THREADED
+    pthread_mutex_lock(&ht1->lock);
+    pthread_mutex_lock(&ht2->lock);
+#endif
+    copy_table(newht,ht1);
+    copy_table(newht,ht2);
+#ifdef THREADED
+    pthread_mutex_unlock(&ht2->lock);
+    pthread_mutex_unlock(&ht1->lock);
+#endif    
+    return newht;
+}
+
+zk_hashtable* move_merge_watchers(zk_hashtable *ht1,zk_hashtable *ht2,const char *path)
+{
+    watcher_object_list_t* wl;
+    zk_hashtable* newht=create_zk_hashtable();
+#ifdef THREADED
+    pthread_mutex_lock(&ht1->lock);
+    pthread_mutex_lock(&ht2->lock);
+#endif
+    // copy watchers from table 1
+    wl=hashtable_remove(ht1->ht,(void*)path);
+    copy_watchers(newht,path,wl);
+    destroy_watcher_object_list(wl);
+    // merge all watchers from tabe 2
+    wl=hashtable_remove(ht2->ht,(void*)path);
+    copy_watchers(newht,path,wl);
+    destroy_watcher_object_list(wl);
+    
+#ifdef THREADED
+    pthread_mutex_unlock(&ht2->lock);
+    pthread_mutex_unlock(&ht1->lock);
+#endif    
+    return newht;
+}
+
+int contains_watcher(zk_hashtable *ht,watcher_object_t* wo)
+{
+    struct hashtable_itr *it=0;
+    int res=0;
+    int hasMore;
+#ifdef THREADED
+    pthread_mutex_lock(&ht->lock);
+#endif
+    if(hashtable_count(ht->ht)==0)
+        goto done;
+    it=hashtable_iterator(ht->ht);
+    do{
+        watcher_object_list_t* w=hashtable_iterator_value(it);
+        if(search_watcher(w,wo)!=0){
+            res=1;
+            goto done;
+        }
+        hasMore=hashtable_iterator_advance(it);
+    }while(hasMore);
+done:
+    if(it!=0)
+        free(it);
+#ifdef THREADED
+    pthread_mutex_unlock(&ht->lock);
+#endif
+    return res;
+}
+
+static void do_foreach_watcher(watcher_object_t* wo,zhandle_t* zh,
+        const char* path,int type,int state)
+{
+    while(wo!=0){
+        wo->watcher(zh,type,state,path,wo->context);
+        wo=wo->next;
+    }    
+}
+
+void deliver_session_event(zk_hashtable* ht,zhandle_t* zh,int type,int state)
+{
+    struct hashtable_itr *it;
+    int hasMore;
+#ifdef THREADED
+    pthread_mutex_lock(&ht->lock);
+#endif
+    if(hashtable_count(ht->ht)==0)
+        goto done;
+    it=hashtable_iterator(ht->ht);
+    do{
+        watcher_object_t* wo=((watcher_object_list_t*)hashtable_iterator_value(it))->head;
+        // session events are delivered with the path set to null
+        do_foreach_watcher(wo,zh,0,type,state);
+        hasMore=hashtable_iterator_advance(it);
+    }while(hasMore);
+    free(it);
+done:
+#ifdef THREADED
+    pthread_mutex_unlock(&ht->lock);
+#endif
+    return;
+}
+
+void deliver_znode_event(zk_hashtable* ht,zhandle_t* zh,const char* path,int type,int state)
+{
+    watcher_object_list_t* wl;
+#ifdef THREADED
+    pthread_mutex_lock(&ht->lock);
+#endif
+    wl=hashtable_remove(ht->ht,(void*)path);
+#ifdef THREADED
+    pthread_mutex_unlock(&ht->lock);
+#endif
+    if(wl!=0){
+        do_foreach_watcher(wl->head,zh,path,type,state);
+        destroy_watcher_object_list(wl);
+    }
+}
+
+void deliverWatchers(zhandle_t* zh,int type,int state, const char* path)
+{
+    zk_hashtable *ht;
+    if(type==SESSION_EVENT){
+        watcher_object_t defWatcher;
+        if(state==CONNECTED_STATE){
+            clean_zk_hashtable(zh->active_node_watchers);
+            clean_zk_hashtable(zh->active_child_watchers);
+            // unconditionally call back the default watcher only
+            zh->watcher(zh,type,state,0,zh->context);
+            return;
+        }
+        // process a disconnect/expiration
+        // must merge node and child watchers first
+        ht=combine_hashtables(zh->active_node_watchers,
+                zh->active_child_watchers);
+        // check if the default watcher is already present on the combined map 
+        defWatcher.watcher=zh->watcher;
+        defWatcher.context=zh->context;
+        if(contains_watcher(ht,&defWatcher)==0)
+            insert_watcher_object(ht,"",clone_watcher_object(&defWatcher));
+        // deliver watcher callback to all registered watchers
+        deliver_session_event(ht,zh,type,state);
+        destroy_zk_hashtable(ht);
+        // in anticipation of the watcher auto-reset feature we keep 
+        // the watcher maps intact. 
+        // (for now, we simply clean the maps on reconnect, see above)
+        return;
+    }
+    switch(type){
+    case CREATED_EVENT_DEF:
+    case CHANGED_EVENT_DEF:
+        // look up the watchers for the path and deliver them
+        deliver_znode_event(zh->active_node_watchers,zh,path,type,state);
+        break;
+    case CHILD_EVENT_DEF:
+        // look up the watchers for the path and deliver them
+        deliver_znode_event(zh->active_child_watchers,zh,path,type,state);
+        break;
+    case DELETED_EVENT_DEF:
+        // combine node and child watchers for the path and deliver them
+        ht=move_merge_watchers(zh->active_child_watchers,
+                zh->active_node_watchers,path);
+        deliver_znode_event(ht,zh,path,type,state);
+        destroy_zk_hashtable(ht);
+        break;
+    }
+}
+
+void activateWatcher(watcher_registration_t* reg, int rc)
+{
+    if(reg!=0){
+        /* in multithreaded lib, this code is executed 
+         * by the completion thread */
+        if(reg->checker(rc)){
+            insert_watcher_object(reg->activeMap,reg->path,
+                    create_watcher_object(reg->watcher,reg->context));
+        }
+    }    
+}

Propchange: hadoop/zookeeper/trunk/src/c/src/zk_hashtable.c
------------------------------------------------------------------------------
    svn:eol-style = native

Added: hadoop/zookeeper/trunk/src/c/src/zk_hashtable.h
URL: http://svn.apache.org/viewvc/hadoop/zookeeper/trunk/src/c/src/zk_hashtable.h?rev=679557&view=auto
==============================================================================
--- hadoop/zookeeper/trunk/src/c/src/zk_hashtable.h (added)
+++ hadoop/zookeeper/trunk/src/c/src/zk_hashtable.h Thu Jul 24 14:46:30 2008
@@ -0,0 +1,115 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef ZK_HASHTABLE_H_
+#define ZK_HASHTABLE_H_
+
+#include <zookeeper.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+typedef struct _zk_hashtable zk_hashtable;
+
+/**
+ * The function must return a non-zero value if the watcher object can be activated
+ * as a result of the server response. Normally, a watch can only be activated
+ * if the server returns a success code (ZOK). However in the case when zoo_exists() 
+ * returns a ZNONODE code the watcher should be activated nevertheless.
+ */
+typedef int (*result_checker_fn)(int rc);
+
+/**
+ * A watcher object gets temporarily stored with the completion entry until 
+ * the server response comes back at which moment the watcher object is moved
+ * to the active watchers map.
+ */
+typedef struct _watcher_registration {
+    watcher_fn watcher;
+    result_checker_fn checker;
+    void* context;
+    zk_hashtable* activeMap; // the map to add the watcher to upon activation
+    const char* path;
+} watcher_registration_t;
+
+
+typedef struct _watcher_object {
+    watcher_fn watcher;
+    void* context;
+    struct _watcher_object* next;
+} watcher_object_t;
+
+watcher_object_t* create_watcher_object(watcher_fn watcher,void* ctx);
+watcher_object_t* clone_watcher_object(watcher_object_t* wo);
+
+zk_hashtable* create_zk_hashtable();
+void clean_zk_hashtable(zk_hashtable* ht);
+void destroy_zk_hashtable(zk_hashtable* ht);
+zk_hashtable* combine_hashtables(zk_hashtable* ht1,zk_hashtable* ht2);
+/**
+ * \brief first, merges all watchers for path from ht1 and ht2 to a new hashtable and 
+ * then removes the path entries from ht1 and ht2 
+ */
+zk_hashtable* move_merge_watchers(zk_hashtable* ht1,zk_hashtable* ht2,const char* path);
+
+/**
+ * The hashtable takes ownership of the watcher object instance.
+ * 
+ * \return 1 if the watcher object was succesfully inserted, 0 otherwise
+ */
+int insert_watcher_object(zk_hashtable* ht, const char* path, watcher_object_t* wo);
+/**
+ * \brief searches the entire hashtable for the watcher object
+ * 
+ * \return 1 if the watcher object found in the table, 0 otherwise
+ */
+int contains_watcher(zk_hashtable* ht,watcher_object_t* wo);
+int get_element_count(zk_hashtable* ht);
+int get_watcher_count(zk_hashtable* ht,const char* path);
+/**
+ * \brief delivers all watchers in the hashtable
+ */
+void deliver_session_event(zk_hashtable* ht,zhandle_t* zh,int type,int state);
+/**
+ * \brief delivers all watchers for path and then removes the path entry 
+ * from the hashtable
+ */
+void deliver_znode_event(zk_hashtable* ht,zhandle_t* zh,const char* path,int type,int state);
+
+/**
+ * zookeeper uses this function to deliver watcher callbacks
+ */
+void deliverWatchers(zhandle_t* zh,int type,int state, const char* path);
+/**
+ * check if the completion has a watcher object associated
+ * with it. If it does, move the watcher object to the map of
+ * active watchers (only if the checker allows to do so)
+ */
+void activateWatcher(watcher_registration_t* reg, int rc);
+
+/* the following functions are for testing only */
+typedef struct hashtable hashtable_impl;
+hashtable_impl* getImpl(zk_hashtable* ht);
+watcher_object_t* getFirstWatcher(zk_hashtable* ht,const char* path);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /*ZK_HASHTABLE_H_*/

Propchange: hadoop/zookeeper/trunk/src/c/src/zk_hashtable.h
------------------------------------------------------------------------------
    svn:eol-style = native