You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@zookeeper.apache.org by br...@apache.org on 2010/01/12 23:02:28 UTC

svn commit: r898542 [1/2] - in /hadoop/zookeeper/trunk: ./ src/contrib/zktreeutil/ src/contrib/zktreeutil/src/ src/contrib/zktreeutil/tests/

Author: breed
Date: Tue Jan 12 22:02:27 2010
New Revision: 898542

URL: http://svn.apache.org/viewvc?rev=898542&view=rev
Log:
ZOOKEEPER-496. zookeeper-tree utility for export, import and incremental updates


Added:
    hadoop/zookeeper/trunk/src/contrib/zktreeutil/
    hadoop/zookeeper/trunk/src/contrib/zktreeutil/Makefile.am
    hadoop/zookeeper/trunk/src/contrib/zktreeutil/README.txt
    hadoop/zookeeper/trunk/src/contrib/zktreeutil/build.xml
    hadoop/zookeeper/trunk/src/contrib/zktreeutil/configure.ac
    hadoop/zookeeper/trunk/src/contrib/zktreeutil/src/
    hadoop/zookeeper/trunk/src/contrib/zktreeutil/src/Makefile.am
    hadoop/zookeeper/trunk/src/contrib/zktreeutil/src/SimpleTree.h
    hadoop/zookeeper/trunk/src/contrib/zktreeutil/src/ZkAdaptor.cc
    hadoop/zookeeper/trunk/src/contrib/zktreeutil/src/ZkAdaptor.h
    hadoop/zookeeper/trunk/src/contrib/zktreeutil/src/ZkTreeUtil.cc
    hadoop/zookeeper/trunk/src/contrib/zktreeutil/src/ZkTreeUtil.h
    hadoop/zookeeper/trunk/src/contrib/zktreeutil/src/ZkTreeUtilMain.cc
    hadoop/zookeeper/trunk/src/contrib/zktreeutil/tests/
    hadoop/zookeeper/trunk/src/contrib/zktreeutil/tests/zk_sample.xml
Modified:
    hadoop/zookeeper/trunk/CHANGES.txt

Modified: hadoop/zookeeper/trunk/CHANGES.txt
URL: http://svn.apache.org/viewvc/hadoop/zookeeper/trunk/CHANGES.txt?rev=898542&r1=898541&r2=898542&view=diff
==============================================================================
--- hadoop/zookeeper/trunk/CHANGES.txt (original)
+++ hadoop/zookeeper/trunk/CHANGES.txt Tue Jan 12 22:02:27 2010
@@ -237,6 +237,8 @@
 
   ZOOKEEPER-368. Observers: core functionality (henry robinson via mahadev)
 
+  ZOOKEEPER-496. zookeeper-tree utility for export, import and incremental updates (anirban roy via breed)
+
 Release 3.2.0 - 2009-06-30
 
 Non-backward compatible changes:

Added: hadoop/zookeeper/trunk/src/contrib/zktreeutil/Makefile.am
URL: http://svn.apache.org/viewvc/hadoop/zookeeper/trunk/src/contrib/zktreeutil/Makefile.am?rev=898542&view=auto
==============================================================================
--- hadoop/zookeeper/trunk/src/contrib/zktreeutil/Makefile.am (added)
+++ hadoop/zookeeper/trunk/src/contrib/zktreeutil/Makefile.am Tue Jan 12 22:02:27 2010
@@ -0,0 +1,4 @@
+## Process this file with automake to produce Makefile.in
+
+SUBDIRS = src
+

Added: hadoop/zookeeper/trunk/src/contrib/zktreeutil/README.txt
URL: http://svn.apache.org/viewvc/hadoop/zookeeper/trunk/src/contrib/zktreeutil/README.txt?rev=898542&view=auto
==============================================================================
--- hadoop/zookeeper/trunk/src/contrib/zktreeutil/README.txt (added)
+++ hadoop/zookeeper/trunk/src/contrib/zktreeutil/README.txt Tue Jan 12 22:02:27 2010
@@ -0,0 +1,74 @@
+==========================================
+zktreeutil - Zookeeper Tree Data Utility
+Author: Anirban Roy
+Organization: Yahoo Inc.
+==========================================
+
+zktreeutil program is intended to manage and manipulate zk-tree data quickly, effi-
+ciently and with ease. The utility operates on free-form ZK-tree and hence can be used
+for any cluster managed by Zookeeper. Here are the basic functionalities -
+
+EXPORT: The whole/partial ZK-tree is exported into a XML file. This helps in
+capturing a current snapshot of the data for backup/analysis. For a subtree
+export, one need to specify the path to the ZK-subtree with proper option.
+
+IMPORT: The ZK-tree can be imported from XML into ZK cluster. This helps in priming
+the new ZK cluster with static configuration. The import can be non-intrusive by
+making only the additions in the existing data. The import of subtree is also
+possible by optionally providing the path to the ZK-subtree.
+
+DIFF: Creates a diff between live ZK data vs data saved in XML file. Diff can ignore
+some ZK-tree branches (possibly dynamic data) on reading the optional ignore flag
+from XML file. Diffing on a ZK-subtree achieved by providing path to ZK-subtree with
+diff command.
+
+UPDATE: Make the incremental changes into the live ZK-tree from saved XML, essentia-
+lly after running the diff.
+
+DUMP: Dumps the ZK-tree on the standard output device reading either from live ZK
+server or XML file. Like export, ZK-subtree can be dumped with optionaly
+providing the path to the ZK-subtree, and till a certain depth of the (sub)tree.
+
+The exported ZK data into XML file can be shortened by only keeping the static ZK
+nodes which are required to prime a cluster. The dynamic zk nodes (created on-the-
+fly) can be ignored by setting a 'ignore' attribute at the root node of the dynamic
+subtree (see tests/zk_sample.xml), possibly deleting all inner ZK nodes under that.
+Once ignored, the whole subtree is ignored during DIFF, UPDATE and WRITE.
+
+Pre-requisites
+--------------
+1. Linux system with 2.6.X kernel.
+2. Zookeeper C client library (locally built at ../../c/.libs) >= 3.X.X
+3. Development build libraries (rpm packages):
+  a. boost-devel >= 1.32.0
+  b. libxml2-devel >= 2.7.3
+  c. log4cxx0100-devel >= 0.10.0
+
+Build instructions
+------------------
+1. cd into this directory
+2. autoreconf -if
+3. ./configure
+4. make
+5. 'zktreeutil' binary created under src directory
+
+Limitations
+-----------
+Current version works with text data only, binary data will be supported in future
+versions.
+
+Testing  and usage of zktreeutil
+--------------------------------
+1.  Run Zookeeper server locally on port 2181
+2.  export LD_LIBRARY_PATH=../../c/.libs/:/usr/local/lib/
+3.  ./src/zktreeutil --help # show help
+4.  ./src/zktreeutil --zookeeper=localhost:2181 --import --xmlfile=tests/zk_sample.xml 2>/dev/null                 # import sample ZK tree
+5.  ./src/zktreeutil --zookeeper=localhost:2181 --dump --path=/myapp/version-1.0 2>/dev/null                         # dump Zk subtree 
+5.  ./src/zktreeutil --zookeeper=localhost:2181 --dump --depth=3 2>/dev/null                                                 # dump Zk tree till certain depth
+6.  ./src/zktreeutil --xmlfile=zk_sample.xml -D 2>/dev/null                                                                     # dump the xml data
+7.  Change zk_sample.xml with adding/deleting/chaging some nodes 
+8.  ./src/zktreeutil -z localhost:2181 -F -x zk_sample.xml -p /myapp/version-1.0/configuration 2>/dev/null          # take a diff of changes
+9.  ./src/zktreeutil -z localhost:2181 -E 2>/dev/null > zk_sample2.xml                                                         # export the mofied ZK tree
+10. ./src/zktreeutil -z localhost:2181 -U -x zk_sample.xml -p /myapp/version-1.0/distributions 2>/dev/null        # update with incr. changes
+11. ./src/zktreeutil --zookeeper=localhost:2181 --import --force --xmlfile=zk_sample2.xml 2>/dev/null             # re-prime the ZK tree
+

Added: hadoop/zookeeper/trunk/src/contrib/zktreeutil/build.xml
URL: http://svn.apache.org/viewvc/hadoop/zookeeper/trunk/src/contrib/zktreeutil/build.xml?rev=898542&view=auto
==============================================================================
--- hadoop/zookeeper/trunk/src/contrib/zktreeutil/build.xml (added)
+++ hadoop/zookeeper/trunk/src/contrib/zktreeutil/build.xml Tue Jan 12 22:02:27 2010
@@ -0,0 +1,61 @@
+<?xml version="1.0"?>
+
+<!--
+   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.
+-->
+
+<project name="zktreeutil" default="compile">
+  <import file="../build-contrib.xml"/>
+
+  <target name="init" depends="check-contrib" unless="skip.contrib">
+    <echo message="contrib: ${name}"/>
+    <mkdir dir="${build.dir}"/>
+    <antcall target="init-contrib"/>
+  </target>
+
+  <target name="compile" depends="init" unless="skip.contrib">
+    <echo message="contrib: ${name}"/>
+
+    <mkdir dir="${build.dir}"/>
+    <copy todir="${build.dir}">
+      <fileset dir="${basedir}">
+        <exclude name="**/VERSION"/>
+      </fileset>
+    </copy>
+    <exec executable="echo" output="${build.dir}/VERSION">
+      <arg line="${version}" />
+    </exec>
+  </target>
+
+    <target name="jar" depends="compile" >
+        <echo message="No jar target defined for this package"/>
+    </target>
+
+     <target name="test">
+        <echo message="No test target defined for this package" />
+    </target>
+
+
+  <target name="package" depends="compile" unless="skip.contrib">
+    <echo message="contrib: ${name}"/>
+
+    <mkdir dir="${dist.dir}/contrib/${name}"/>
+    <copy todir="${dist.dir}/contrib/${name}">
+      <fileset dir="${build.dir}"/>
+    </copy>
+  </target>
+
+</project>

Added: hadoop/zookeeper/trunk/src/contrib/zktreeutil/configure.ac
URL: http://svn.apache.org/viewvc/hadoop/zookeeper/trunk/src/contrib/zktreeutil/configure.ac?rev=898542&view=auto
==============================================================================
--- hadoop/zookeeper/trunk/src/contrib/zktreeutil/configure.ac (added)
+++ hadoop/zookeeper/trunk/src/contrib/zktreeutil/configure.ac Tue Jan 12 22:02:27 2010
@@ -0,0 +1,66 @@
+#                                               -*- Autoconf -*-
+# Process this file with autoconf to produce a configure script.
+
+AC_PREREQ(2.59)
+
+AC_INIT([zktreeutil], [1.0.0])
+AM_INIT_AUTOMAKE(foreign)
+
+AC_CONFIG_SRCDIR([src])
+AM_CONFIG_HEADER([config.h])
+
+PACKAGE=zktreeutil
+VERSION=1.0.0
+
+AC_SUBST(PACKAGE)
+AC_SUBST(VERSION)
+BUILD_PATH="`pwd`"
+
+# Checks for programs.
+AC_LANG_CPLUSPLUS
+AC_PROG_CXX
+
+# Checks for libxm2.
+AM_PATH_XML2(2.7.3)
+XML2_INCLUDE="/usr/include/libxml2"
+AC_SUBST(XML2_INCLUDE)
+
+# Zookeeper C client
+ZOOKEEPER_PATH=${BUILD_PATH}/../../c
+AC_CHECK_LIB(zookeeper_mt, main, [ZOOKEEPER="-L${ZOOKEEPER_PATH}/.libs -lzookeeper_mt"],,["-L${ZOOKEEPER_PATH}/.libs"])
+if test -z "${ZOOKEEPER}"; then
+      AC_ERROR("... zookeeper C client not found!")
+fi
+
+AC_SUBST(ZOOKEEPER)
+AC_SUBST(ZOOKEEPER_PATH)
+
+### log4cxx ###
+
+LOG4CXX_VERSION="0.10.0"
+LOG4CXX_INCLUDE="/usr/local/include"
+LOG4CXX_LIB_PATH="/usr/local/lib"
+AC_CHECK_LIB(log4cxx, main, [LOG4CXX="-L${LOG4CXX_LIB_PATH} -llog4cxx"],,["-L${LOG4CXX_LIB_PATH}"])
+if test -z "${LOG4CXX}"; then
+      AC_ERROR("... log4cxx not found!")
+fi
+
+AC_SUBST(LOG4CXX)
+AC_SUBST(LOG4CXX_VERSION)
+AC_SUBST(LOG4CXX_INCLUDE)
+
+# Checks for header files.
+AC_HEADER_DIRENT
+AC_HEADER_STDC
+AC_CHECK_HEADERS([stdlib.h string.h stdio.h unistd.h boost/shared_ptr.hpp boost/algorithm/string.hpp boost/algorithm/string/split.hpp])
+
+# Checks for typedefs, structures, and compiler characteristics.
+AC_HEADER_STDBOOL
+AC_C_CONST
+AC_C_INLINE
+AC_TYPE_SIZE_T
+AC_C_VOLATILE
+
+AC_CONFIG_FILES([Makefile])
+AC_CONFIG_FILES([src/Makefile])
+AC_OUTPUT

Added: hadoop/zookeeper/trunk/src/contrib/zktreeutil/src/Makefile.am
URL: http://svn.apache.org/viewvc/hadoop/zookeeper/trunk/src/contrib/zktreeutil/src/Makefile.am?rev=898542&view=auto
==============================================================================
--- hadoop/zookeeper/trunk/src/contrib/zktreeutil/src/Makefile.am (added)
+++ hadoop/zookeeper/trunk/src/contrib/zktreeutil/src/Makefile.am Tue Jan 12 22:02:27 2010
@@ -0,0 +1,24 @@
+# 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.
+
+AM_CXXFLAGS = -I${ZOOKEEPER_PATH}/include -I${ZOOKEEPER_PATH}/generated \
+    -I$(top_srcdir)/include -I${LOG4CXX_INCLUDE} -I/usr/include \
+      -I${XML2_INCLUDE}
+
+bin_PROGRAMS = zktreeutil
+
+zktreeutil_SOURCES = ZkAdaptor.cc ZkTreeUtil.cc ZkTreeUtilMain.cc
+zktreeutil_LDADD = ${ZOOKEEPER} ${XML_LIBS} ${LOG4CXX}

Added: hadoop/zookeeper/trunk/src/contrib/zktreeutil/src/SimpleTree.h
URL: http://svn.apache.org/viewvc/hadoop/zookeeper/trunk/src/contrib/zktreeutil/src/SimpleTree.h?rev=898542&view=auto
==============================================================================
--- hadoop/zookeeper/trunk/src/contrib/zktreeutil/src/SimpleTree.h (added)
+++ hadoop/zookeeper/trunk/src/contrib/zktreeutil/src/SimpleTree.h Tue Jan 12 22:02:27 2010
@@ -0,0 +1,150 @@
+/**
+ * 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 __SIMPLE_TREE_H__
+#define __SIMPLE_TREE_H__
+
+#include <vector>
+#include <boost/shared_ptr.hpp>
+
+namespace zktreeutil
+{
+   using std::vector;
+
+   /**
+    * \brief A simple tree data-structure template.
+    */
+   template < class KeyType, class DataType > class SimpleTreeNode
+   {
+      private:
+         /**
+          * \brief The type representing simple-tree node smart-pointer.
+          */
+         typedef boost::shared_ptr< SimpleTreeNode< KeyType, DataType > > SimpleTreeNodeSptr;
+
+      public:
+         /**
+          * \brief Constructor.
+          * 
+          * @param isRoot the flag indicating whether the node is root.
+          */
+         SimpleTreeNode (bool isRoot=false) : isRoot_(isRoot)
+         {
+         }
+
+         /**
+          * \brief Constructor.
+          * 
+          * @param key the key stored at the tree node
+          * @param isRoot the flag indicating whether the node is root
+          */
+         SimpleTreeNode (const KeyType& key, bool isRoot=false) :
+            isRoot_(isRoot), key_(key)
+         {
+         }
+
+         /**
+          * \brief Constructor.
+          * 
+          * @param key the key stored at the tree node
+          * @param val the value stored at the tree node
+          * @param isRoot the flag indicating whether the node is root
+          */
+         SimpleTreeNode (const KeyType& key, const DataType& val, bool isRoot=false) :
+            isRoot_(isRoot), key_(key), val_(val)
+         {
+         }
+
+         /**
+          * \brief Destructor.
+          */
+         ~SimpleTreeNode () throw() {}
+
+         /**
+          * \brief Add a child node to this node.
+          *
+          * @param node the child node to be added
+          */
+         void addChild (const SimpleTreeNodeSptr node) { children_.push_back (node); }
+
+         /**
+          * \brief Sets the key of this node.
+          *
+          * @param key the key to be set
+          */
+         void setKey (const KeyType& key) { key_ = key; }
+
+         /**
+          * \brief Sets the data of this node.
+          *
+          * @param val the value to be set
+          */
+         void setData (const DataType& val) { val_ = val; }
+
+         /**
+          * \brief Gets the key of this node.
+          *
+          * @return the key of this node 
+          */
+         KeyType getKey () const { return key_; }
+
+         /**
+          * \brief Gets the data of this node.
+          *
+          * @return the value of this node 
+          */
+         DataType getData () const { return val_; }
+
+         /**
+          * \brief Gets the i'th of this node.
+          *
+          * @param idx the index of the child node
+          * @return the child node
+          */
+         SimpleTreeNodeSptr getChild (unsigned idx) const { return children_[idx]; }
+
+         /**
+          * \brief Gets the number of children of this node.
+          *
+          * @return the number of children
+          */
+         unsigned numChildren () const { return children_.size(); }
+
+         /**
+          * \brief Indicates whether this node is root.
+          *
+          * @return 'true' if this node is root, 'false' otherwise
+          */
+         bool isRoot () const { return isRoot_; }
+
+         /**
+          * \brief Indicates whether this node is leaf node.
+          *
+          * @return 'true' if this node is leaf node, 'false' otherwise
+          */
+         bool isLeaf () const { return !numChildren(); }
+
+      private:
+         bool isRoot_;                                        // Flag indicates if the node is root
+         KeyType key_;                                        // Key of this node
+         DataType val_;                                        // Value of this node
+         vector< SimpleTreeNodeSptr > children_;    // List of children of this node
+   };
+}
+
+#endif // __SIMPLE_TREE_H__

Added: hadoop/zookeeper/trunk/src/contrib/zktreeutil/src/ZkAdaptor.cc
URL: http://svn.apache.org/viewvc/hadoop/zookeeper/trunk/src/contrib/zktreeutil/src/ZkAdaptor.cc?rev=898542&view=auto
==============================================================================
--- hadoop/zookeeper/trunk/src/contrib/zktreeutil/src/ZkAdaptor.cc (added)
+++ hadoop/zookeeper/trunk/src/contrib/zktreeutil/src/ZkAdaptor.cc Tue Jan 12 22:02:27 2010
@@ -0,0 +1,513 @@
+/**
+ * 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 "ZkAdaptor.h"
+#include <string.h>
+#include <sstream>
+#include <iostream>
+#include <algorithm>
+#include <log4cxx/logger.h>
+
+// Logger
+static log4cxx::LoggerPtr zkLoggerPtr = log4cxx::Logger::getLogger ("zookeeper.core");
+
+namespace zktreeutil
+{
+    /**
+     * \brief This class provides logic for checking if a request can be retried.
+     */
+    class RetryHandler
+    {
+        public:
+            RetryHandler(const ZooKeeperConfig &zkConfig) : m_zkConfig(zkConfig)
+            {
+                if (zkConfig.getAutoReconnect())
+                    retries = 2;
+                else
+                    retries = 0;
+            }
+
+            /**
+             * \brief Attempts to fix a side effect of the given RC.
+             * 
+             * @param rc the ZK error code
+             * @return whether the error code has been handled and the caller should 
+             *         retry an operation the caused this error
+             */
+            bool handleRC(int rc)
+            {
+                //check if the given error code is recoverable
+                if (!retryOnError(rc))
+                    return false;
+
+                std::cerr << "[zktreeuti] Number of retries left: " << retries << std::endl;
+                if (retries-- > 0)
+                    return true;
+                else
+                    return false;
+            }
+
+        private:
+            /**
+             * The ZK config.
+             */
+            const ZooKeeperConfig &m_zkConfig;
+
+            /**
+             * The number of outstanding retries.
+             */
+            int retries;    
+
+            /**
+             * Checks whether the given error entitles this adapter
+             * to retry the previous operation.
+             * 
+             * @param zkErrorCode one of the ZK error code
+             */
+            static bool retryOnError(int zkErrorCode)
+            {
+                return (zkErrorCode == ZCONNECTIONLOSS || zkErrorCode == ZOPERATIONTIMEOUT);
+            }
+    };
+
+
+    // =======================================================================
+
+    ZooKeeperAdapter::ZooKeeperAdapter(ZooKeeperConfig config) throw(ZooKeeperException) :
+        m_zkConfig(config),
+        mp_zkHandle(NULL)
+    {
+        // Enforce setting up appropriate ZK log level
+        if (zkLoggerPtr->isDebugEnabled()
+#ifdef LOG4CXX_TRACE
+                || zkLoggerPtr->isTraceEnabled()
+#endif
+            ) 
+        {
+            zoo_set_debug_level( ZOO_LOG_LEVEL_DEBUG );
+        } else if (zkLoggerPtr->isInfoEnabled()) {
+            zoo_set_debug_level( ZOO_LOG_LEVEL_INFO );
+        } else if (zkLoggerPtr->isWarnEnabled()) {
+            zoo_set_debug_level( ZOO_LOG_LEVEL_WARN );
+        } else {
+            zoo_set_debug_level( ZOO_LOG_LEVEL_ERROR );
+        }
+
+        // Establish the connection
+        reconnect();
+    }
+
+    ZooKeeperAdapter::~ZooKeeperAdapter()
+    {
+        try
+        {
+            disconnect();
+        }
+        catch (std::exception &e)
+        {
+            std::cerr << "[zktreeutil] An exception while disconnecting from ZK: "
+                << e.what()
+                << std::endl;
+        }
+    }
+
+    void ZooKeeperAdapter::validatePath(const string &path) throw(ZooKeeperException)
+    {
+        if (path.find ("/") != 0)
+        {
+            std::ostringstream oss;
+            oss << "Node path must start with '/' but" "it was '"
+                << path
+                << "'";
+            throw ZooKeeperException (oss.str());
+        }
+        if (path.length() > 1)
+        {
+            if (path.rfind ("/") == path.length() - 1)
+            {
+                std::ostringstream oss;
+                oss << "Node path must not end with '/' but it was '"
+                    << path
+                    << "'";
+                throw ZooKeeperException (oss.str());
+            }
+            if (path.find( "//" ) != string::npos)
+            {
+                std::ostringstream oss;
+                oss << "Node path must not contain '//' but it was '"
+                    << path
+                    << "'";
+                throw ZooKeeperException (oss.str());
+            }
+        }
+    }
+
+    void ZooKeeperAdapter::disconnect()
+    {
+        if (mp_zkHandle != NULL)
+        {
+            zookeeper_close (mp_zkHandle);
+            mp_zkHandle = NULL;
+        }
+    }
+
+    void ZooKeeperAdapter::reconnect() throw(ZooKeeperException)
+    {
+        // Clear the connection state
+        disconnect();
+
+        // Establish a new connection to ZooKeeper
+        mp_zkHandle = zookeeper_init( m_zkConfig.getHosts().c_str(), 
+                NULL, 
+                m_zkConfig.getLeaseTimeout(),
+                0,
+                NULL,
+                0);
+        if (mp_zkHandle == NULL)
+        {
+            // Invalid handle returned
+            std::ostringstream oss;
+            oss << "Unable to connect to ZK running at '"
+                << m_zkConfig.getHosts()
+                << "'";
+            throw ZooKeeperException (oss.str());
+        }
+
+        // Enter into connect loop
+        int64_t connWaitTime = m_zkConfig.getConnectTimeout();
+        while (1)
+        {
+            int state = zoo_state (mp_zkHandle);
+            if (state == ZOO_CONNECTED_STATE)
+            {
+                // connected
+                std::cerr << "[zktreeutil] Connected! mp_zkHandle: "
+                    << mp_zkHandle
+                    << std::endl; 
+                return;
+            }
+            else if ( state && state != ZOO_CONNECTING_STATE)
+            {
+                // Not connecting any more... some other issue
+                std::ostringstream oss;
+                oss << "Unable to connect to ZK running at '"
+                    << m_zkConfig.getHosts()
+                    << "'; state="
+                    << state;
+                throw ZooKeeperException (oss.str());
+            }
+
+            // Still connecting, wait and come back
+            struct timeval now;
+            gettimeofday( &now, NULL );
+            int64_t milliSecs = -(now.tv_sec * 1000LL + now.tv_usec / 1000);
+            std::cerr << "[zktreeutil] About to wait 1 sec" << std::endl;
+            sleep (1);
+            gettimeofday( &now, NULL );
+            milliSecs += now.tv_sec * 1000LL + now.tv_usec / 1000;
+            connWaitTime -= milliSecs;
+            // Timed out !!!
+            if (connWaitTime <= 0)
+                break;
+        }
+
+        // Timed out while connecting
+        std::ostringstream oss;
+        oss << "Timed out while connecting to ZK running at '"
+            << m_zkConfig.getHosts()
+            << "'";
+        throw ZooKeeperException (oss.str());
+    }
+
+    void ZooKeeperAdapter::verifyConnection() throw(ZooKeeperException)
+    {
+        // Check connection state
+        int state = zoo_state (mp_zkHandle);
+        if (state != ZOO_CONNECTED_STATE)
+        {
+            if (m_zkConfig.getAutoReconnect())
+            {
+                // Trying to reconnect
+                std::cerr << "[zktreeutil] Trying to reconnect..." << std::endl;
+                reconnect();
+            }
+            else
+            {
+                std::ostringstream oss;
+                oss << "Disconnected from ZK running at '"
+                    << m_zkConfig.getHosts()
+                    << "'; state="
+                    << state;
+                throw ZooKeeperException (oss.str());
+            }
+        }
+    }
+
+    bool ZooKeeperAdapter::createNode(const string &path, 
+            const string &value, 
+            int flags, 
+            bool createAncestors) throw(ZooKeeperException) 
+    {
+        const int MAX_PATH_LENGTH = 1024;
+        char realPath[MAX_PATH_LENGTH];
+        realPath[0] = 0;
+
+        int rc;
+        RetryHandler rh(m_zkConfig);
+        do
+        {
+            verifyConnection();
+            rc = zoo_create( mp_zkHandle, 
+                    path.c_str(), 
+                    value.c_str(),
+                    value.length(),
+                    &ZOO_OPEN_ACL_UNSAFE,
+                    flags,
+                    realPath,
+                    MAX_PATH_LENGTH );
+        } while (rc != ZOK && rh.handleRC(rc));
+        if (rc != ZOK) // check return status
+        {
+            if (rc == ZNODEEXISTS)
+            {
+                //the node already exists
+                std::cerr << "[zktreeutil] ZK node " << path << " already exists" << std::endl;
+                return false;
+            }
+            else if (rc == ZNONODE && createAncestors)
+            {
+                std::cerr << "[zktreeutil] Intermediate ZK node missing in path " << path << std::endl;
+                //one of the ancestors doesn't exist so lets start from the root 
+                //and make sure the whole path exists, creating missing nodes if
+                //necessary
+                for (string::size_type pos = 1; pos != string::npos; )
+                {
+                    pos = path.find( "/", pos );
+                    if (pos != string::npos)
+                    {
+                        try
+                        {
+                            createNode( path.substr( 0, pos ), "", 0, true );
+                        }
+                        catch (ZooKeeperException &e)
+                        {
+                            throw ZooKeeperException( string("Unable to create " "node ") + path, rc );
+                        }
+                        pos++;
+                    }
+                    else
+                    {
+                        // No more path components
+                        return createNode( path, value, flags, false );
+                    }
+                }
+            }
+
+            // Unexpected error during create
+            std::cerr << "[zktreeutil] Error in creating ZK node " << path << std::endl;
+            throw ZooKeeperException( string("Unable to create node ") + path, rc );
+        }
+
+        // Success
+        std::cerr << "[zktreeutil] " << realPath << " has been created" << std::endl;
+        return true;
+    }
+
+    bool ZooKeeperAdapter::deleteNode(const string &path,
+            bool recursive,
+            int version) throw(ZooKeeperException)
+    {
+        // Validate the zk path
+        validatePath( path );
+
+        int rc;
+        RetryHandler rh(m_zkConfig);
+        do
+        {
+            verifyConnection();
+            rc = zoo_delete( mp_zkHandle, path.c_str(), version );
+        } while (rc != ZOK && rh.handleRC(rc));
+        if (rc != ZOK) //check return status
+        {
+            if (rc == ZNONODE)
+            {
+                std::cerr << "[zktreeutil] ZK Node "
+                    << path
+                    << " does not exist"
+                    << std::endl;
+                return false;
+            }
+            if (rc == ZNOTEMPTY && recursive)
+            {
+                std::cerr << "[zktreeutil] ZK Node "
+                    << path
+                    << " not empty; deleting..."
+                    << std::endl;
+                //get all children and delete them recursively...
+                vector<string> nodeList = getNodeChildren (path);
+                for (vector<string>::const_iterator i = nodeList.begin();
+                        i != nodeList.end();
+                        ++i) {
+                    deleteNode( *i, true );
+                }
+                //...and finally attempt to delete the node again
+                return deleteNode( path, false ); 
+            }
+
+            // Unexpected return without success
+            std::cerr << "[zktreeutil] Unable to delete ZK node " << path << std::endl;
+            throw ZooKeeperException( string("Unable to delete node ") + path, rc );
+        }
+
+        // success
+        std::cerr << "[zktreeutil] " << path << " has been deleted" << std::endl;
+        return true;
+    }
+
+    vector< string > ZooKeeperAdapter::getNodeChildren (const string &path) throw (ZooKeeperException)
+    {
+        // Validate the zk path
+        validatePath( path );
+
+        String_vector children;
+        memset( &children, 0, sizeof(children) );
+        int rc;
+        RetryHandler rh(m_zkConfig);
+        do
+        {
+            verifyConnection();
+            rc = zoo_get_children( mp_zkHandle,
+                    path.c_str(), 
+                    0,
+                    &children );
+        } while (rc != ZOK && rh.handleRC(rc));
+        if (rc != ZOK) // check return code
+        {
+            std::cerr << "[zktreeutil] Error in fetching children of " << path << std::endl;
+            throw ZooKeeperException( string("Unable to get children of node ") + path, rc );
+        }
+        else
+        {
+            vector< string > nodeList;
+            for (int i = 0; i < children.count; ++i)
+            {
+                //convert each child's path from relative to absolute 
+                string absPath(path);
+                if (path != "/")
+                {
+                    absPath.append( "/" );
+                } 
+                absPath.append( children.data[i] ); 
+                nodeList.push_back( absPath );
+            }
+
+            //make sure the order is always deterministic
+            sort( nodeList.begin(), nodeList.end() );
+            return nodeList;
+        }
+    }
+
+    bool ZooKeeperAdapter::nodeExists(const string &path) throw(ZooKeeperException)
+    {
+        // Validate the zk path
+        validatePath( path );
+
+        struct Stat tmpStat;
+        struct Stat* stat = &tmpStat;
+        memset( stat, 0, sizeof(Stat) );
+
+        int rc;
+        RetryHandler rh(m_zkConfig);
+        do {
+            verifyConnection();
+            rc = zoo_exists( mp_zkHandle,
+                    path.c_str(),
+                    0,
+                    stat );
+        } while (rc != ZOK && rh.handleRC(rc));
+        if (rc != ZOK)
+        {
+            if (rc == ZNONODE)
+                return false;
+            // Some error
+            std::cerr << "[zktreeutil] Error in checking existance of " << path << std::endl;
+            throw ZooKeeperException( string("Unable to check existence of node ") + path, rc );
+        } else {
+            return true;        
+        }
+    }
+
+    string ZooKeeperAdapter::getNodeData(const string &path) throw(ZooKeeperException)
+    {
+        // Validate the zk path
+        validatePath( path );
+
+        const int MAX_DATA_LENGTH = 128 * 1024;
+        char buffer[MAX_DATA_LENGTH];
+        memset( buffer, 0, MAX_DATA_LENGTH );
+        struct Stat tmpStat;
+        struct Stat* stat = &tmpStat;
+        memset( stat, 0, sizeof(Stat) );
+
+        int rc;
+        int len;
+        RetryHandler rh(m_zkConfig);
+        do {
+            verifyConnection();
+            len = MAX_DATA_LENGTH - 1;
+            rc = zoo_get( mp_zkHandle,
+                    path.c_str(),
+                    0,
+                    buffer, &len, stat );
+        } while (rc != ZOK && rh.handleRC(rc));
+        if (rc != ZOK) // checl return code
+        {
+            std::cerr << "[zktreeutil] Error in fetching value of " << path << std::endl;
+            throw ZooKeeperException( string("Unable to get data of node ") + path, rc );
+        }
+
+        // return data
+        return string( buffer, buffer + len );
+    }
+
+    void ZooKeeperAdapter::setNodeData(const string &path,
+            const string &value,
+            int version) throw(ZooKeeperException)
+    {
+        // Validate the zk path
+        validatePath( path );
+
+        int rc;
+        RetryHandler rh(m_zkConfig);
+        do {
+            verifyConnection();
+            rc = zoo_set( mp_zkHandle,
+                    path.c_str(),
+                    value.c_str(),
+                    value.length(),
+                    version);
+        } while (rc != ZOK && rh.handleRC(rc));
+        if (rc != ZOK) // check return code
+        {
+            std::cerr << "[zktreeutil] Error in setting value of " << path << std::endl;
+            throw ZooKeeperException( string("Unable to set data for node ") + path, rc );
+        }
+        // success
+    }
+
+}   /* end of 'namespace zktreeutil' */

Added: hadoop/zookeeper/trunk/src/contrib/zktreeutil/src/ZkAdaptor.h
URL: http://svn.apache.org/viewvc/hadoop/zookeeper/trunk/src/contrib/zktreeutil/src/ZkAdaptor.h?rev=898542&view=auto
==============================================================================
--- hadoop/zookeeper/trunk/src/contrib/zktreeutil/src/ZkAdaptor.h (added)
+++ hadoop/zookeeper/trunk/src/contrib/zktreeutil/src/ZkAdaptor.h Tue Jan 12 22:02:27 2010
@@ -0,0 +1,327 @@
+/**
+ * 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_ADAPTER_H__
+#define __ZK_ADAPTER_H__
+
+#include <string>
+#include <vector>
+
+extern "C" {
+#include "zookeeper.h"
+}
+
+namespace zktreeutil
+{
+    using std::string;
+    using std::vector;
+
+    /**
+     * \brief A cluster related exception.
+     */
+    class ZooKeeperException : public std::exception
+    {
+        public:
+
+            /**
+             * \brief Constructor.
+             * 
+             * @param msg the detailed message associated with this exception
+             */
+            ZooKeeperException(const string& msg) :
+                m_message(msg),
+                m_zkErrorCode(0) {}
+
+            /**
+             * \brief Constructor.
+             * 
+             * @param msg the detailed message associated with this exception
+             * @param errorCode the ZK error code associated with this exception
+             */
+            ZooKeeperException(const string &msg, int errorCode) : 
+                m_zkErrorCode(errorCode) 
+            {
+                char tmp[100];
+                sprintf( tmp, " (ZK error code: %d)", errorCode );
+                m_message = msg + tmp;
+            }
+
+            /**
+             * \brief Destructor.
+             */
+            ~ZooKeeperException() throw() {}
+
+            /**
+             * \brief Returns detailed description of the exception.
+             */
+            const char *what() const throw()
+            {
+                return m_message.c_str();
+            }
+
+            /**
+             * \brief Returns the ZK error code.
+             */
+            int getZKErrorCode() const
+            {
+                return m_zkErrorCode;
+            }
+
+        private:
+
+            /**
+             * The detailed message associated with this exception.
+             */
+            string m_message;
+
+            /**
+             * The optional error code received from ZK.
+             */
+            int m_zkErrorCode;
+
+    };
+
+    /**
+     * \brief This class encapsulates configuration of a ZK client.
+     */
+    class ZooKeeperConfig
+    {
+        public:
+
+            /**
+             * \brief Constructor.
+             * 
+             * @param hosts the comma separated list of host and port pairs of ZK nodes
+             * @param leaseTimeout the lease timeout (heartbeat)
+             * @param autoReconnect whether to allow for auto-reconnect
+             * @param connectTimeout the connect timeout, in milliseconds;
+             */
+            ZooKeeperConfig(const string &hosts, 
+                    int leaseTimeout, 
+                    bool autoReconnect = true, 
+                    long long int connectTimeout = 15000)
+                : m_hosts(hosts),
+                m_leaseTimeout(leaseTimeout), 
+                m_autoReconnect(autoReconnect),
+                m_connectTimeout(connectTimeout) {}
+
+            /**
+             * \brief Returns the list of ZK hosts to connect to.
+             */
+            string getHosts() const { return m_hosts; }
+
+            /**
+             * \brief Returns the lease timeout.
+             */
+            int getLeaseTimeout() const { return m_leaseTimeout; }
+
+            /**
+             * \brief Returns whether {@link ZooKeeperAdapter} should attempt 
+             * \brief to automatically reconnect in case of a connection failure.
+             */
+            bool getAutoReconnect() const { return m_autoReconnect; }
+
+            /**
+             * \brief Gets the connect timeout.
+             * 
+             * @return the connect timeout
+             */
+            long long int getConnectTimeout() const { return m_connectTimeout; }
+
+        private:
+
+            /**
+             * The host addresses of ZK nodes.
+             */
+            const string m_hosts;
+
+            /**
+             * The ZK lease timeout.
+             */
+            const int m_leaseTimeout;
+
+            /**
+             * True if this adapater should attempt to autoreconnect in case 
+             * the current session has been dropped.
+             */
+            const bool m_autoReconnect;
+
+            /**
+             * How long to wait, in milliseconds, before a connection 
+             * is established to ZK.
+             */
+            const long long int m_connectTimeout;
+    };
+
+    /**
+     * \brief This is a wrapper around ZK C synchrounous API.
+     */
+    class ZooKeeperAdapter
+    {
+        public:
+            /**
+             * \brief Constructor.
+             * Attempts to create a ZK adapter, optionally connecting
+             * to the ZK. Note, that if the connection is to be established
+             * and the given listener is NULL, some events may be lost, 
+             * as they may arrive asynchronously before this method finishes.
+             * 
+             * @param config the ZK configuration
+             * @throw ZooKeeperException if cannot establish connection to the given ZK
+             */
+            ZooKeeperAdapter(ZooKeeperConfig config) throw(ZooKeeperException);
+
+            /**
+             * \brief Destructor.
+             */
+            ~ZooKeeperAdapter(); 
+
+            /**
+             * \brief Returns the current config.
+             */
+            const ZooKeeperConfig &getZooKeeperConfig() const { return m_zkConfig; }
+
+            /**
+             * \brief Restablishes connection to the ZK. 
+             * If this adapter is already connected, the current connection 
+             * will be dropped and a new connection will be established.
+             * 
+             * @throw ZooKeeperException if cannot establish connection to the ZK
+             */
+            void reconnect() throw(ZooKeeperException);
+
+            /**
+             * \brief Disconnects from the ZK and unregisters {@link #mp_zkHandle}.
+             */
+            void disconnect();
+
+            /**
+             * \brief Creates a new node identified by the given path. 
+             * This method will optionally attempt to create all missing ancestors.
+             * 
+             * @param path the absolute path name of the node to be created
+             * @param value the initial value to be associated with the node
+             * @param flags the ZK flags of the node to be created
+             * @param createAncestors if true and there are some missing ancestor nodes, 
+             *        this method will attempt to create them
+             * 
+             * @return true if the node has been successfully created; false otherwise
+             * @throw ZooKeeperException if the operation has failed
+             */ 
+            bool createNode(const string &path, 
+                    const string &value = "", 
+                    int flags = 0, 
+                    bool createAncestors = true) throw(ZooKeeperException);
+
+            /**
+             * \brief Deletes a node identified by the given path.
+             * 
+             * @param path the absolute path name of the node to be deleted
+             * @param recursive if true this method will attempt to remove 
+             *                  all children of the given node if any exist
+             * @param version the expected version of the node. The function will 
+             *                fail if the actual version of the node does not match 
+             *                the expected version
+             * 
+             * @return true if the node has been deleted; false otherwise
+             * @throw ZooKeeperException if the operation has failed
+             */
+            bool deleteNode(const string &path,
+                    bool recursive = false,
+                    int version = -1) throw(ZooKeeperException);
+
+            /**
+             * \brief Retrieves list of all children of the given node.
+             * 
+             * @param path the absolute path name of the node for which to get children
+             * @return the list of absolute paths of child nodes, possibly empty
+             * @throw ZooKeeperException if the operation has failed
+             */
+            vector<string> getNodeChildren( const string &path) throw(ZooKeeperException);
+
+            /**
+             * \brief Check the existance of path to a znode.
+             * 
+             * @param path the absolute path name of the znode
+             * @return TRUE if the znode exists; FALSE otherwise
+             * @throw ZooKeeperException if the operation has failed
+             */
+            bool nodeExists(const string &path) throw(ZooKeeperException);
+
+            /**
+             * \brief Gets the given node's data.
+             * 
+             * @param path the absolute path name of the node to get data from
+             * 
+             * @return the node's data
+             * @throw ZooKeeperException if the operation has failed
+             */
+            string getNodeData(const string &path) throw(ZooKeeperException);
+
+            /**
+             * \brief Sets the given node's data.
+             * 
+             * @param path the absolute path name of the node to get data from
+             * @param value the node's data to be set
+             * @param version the expected version of the node. The function will 
+             *                fail if the actual version of the node does not match 
+             *                the expected version
+             * 
+             * @throw ZooKeeperException if the operation has failed
+             */
+            void setNodeData(const string &path,
+                    const string &value,
+                    int version = -1) throw(ZooKeeperException);
+
+            /**
+             * \brief Validates the given path to a node in ZK.
+             * 
+             * @param the path to be validated
+             * 
+             * @throw ZooKeeperException if the given path is not valid
+             *        (for instance it doesn't start with "/")
+             */
+            static void validatePath(const string &path) throw(ZooKeeperException);
+
+        private:
+
+            /**
+             * Verifies whether the connection is established,
+             * optionally auto reconnecting.
+             * 
+             * @throw ZooKeeperConnection if this client is disconnected
+             *        and auto-reconnect failed or was not allowed
+             */
+            void verifyConnection() throw(ZooKeeperException);
+
+        private:
+
+            /**
+             * The current ZK configuration.
+             */
+            const ZooKeeperConfig m_zkConfig;
+
+            /**
+             * The current ZK session.
+             */
+            zhandle_t *mp_zkHandle;
+    };
+
+}   /* end of 'namespace zktreeutil' */
+
+#endif /* __ZK_ADAPTER_H__ */

Added: hadoop/zookeeper/trunk/src/contrib/zktreeutil/src/ZkTreeUtil.cc
URL: http://svn.apache.org/viewvc/hadoop/zookeeper/trunk/src/contrib/zktreeutil/src/ZkTreeUtil.cc?rev=898542&view=auto
==============================================================================
--- hadoop/zookeeper/trunk/src/contrib/zktreeutil/src/ZkTreeUtil.cc (added)
+++ hadoop/zookeeper/trunk/src/contrib/zktreeutil/src/ZkTreeUtil.cc Tue Jan 12 22:02:27 2010
@@ -0,0 +1,705 @@
+/**
+ * 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 "ZkTreeUtil.h"
+
+#include <map>
+#include <iostream>
+#include <log4cxx/logger.h>
+#include <boost/algorithm/string.hpp>
+#include <boost/algorithm/string/split.hpp>
+
+namespace zktreeutil
+{
+    using std::map;
+    using std::pair;
+
+    static ZkTreeNodeSptr loadZkTree_ (ZooKeeperAdapterSptr zkHandle,
+            const string& path)
+    {
+        // Extract the node value
+        string value = zkHandle->getNodeData(path);
+
+        // Extract nodename from the path
+        string nodename = "/";
+        if (path != "/")
+        {
+            vector< string > nodes;
+            boost::split(nodes, path, boost::is_any_of ("/") );
+            nodename = nodes[nodes.size()-1];
+        }
+
+        // Create tree-node with name and value
+        ZkTreeNodeSptr nodeSptr = ZkTreeNodeSptr (new ZkTreeNode (nodename, value));
+        std::cerr << "[zktreeutil] loaded nodename: "
+            << nodename
+            << " value: "
+            << value
+            << std::endl;
+
+        // Load all the children
+        vector< string > cnodes = zkHandle->getNodeChildren (path);
+        for (unsigned i = 0; i < cnodes.size(); i++)
+            nodeSptr->addChild (loadZkTree_ (zkHandle, cnodes[i]));
+
+        // Return the constructed node
+        return nodeSptr;
+    }
+
+    static ZkTreeNodeSptr loadZkTreeXml_ (xmlNode* xmlNodePtr)
+    {
+        // Null check
+        if (xmlNodePtr == NULL)
+        {
+            std::cerr << "[zktreeutil] empty XML node encountered" << std::endl;
+            exit (-1);
+        }
+
+        // Get the node name
+        xmlChar* name = xmlGetProp (xmlNodePtr, BAD_CAST "name");
+        string nameStr = (const char*)name;
+        std::cerr << "[zktreeutil] node name: " << nameStr;
+        xmlFree (name);
+        // Get the node value
+        string valueStr;
+        xmlChar* value = xmlGetProp (xmlNodePtr, BAD_CAST "value");
+        if (value)
+        {
+            valueStr = (const char*)value;
+            std::cerr << " value: " << valueStr;
+        }
+        xmlFree (value);
+        // Get the ignore flag
+        bool doIgnore = false;
+        xmlChar* ignore = xmlGetProp (xmlNodePtr, BAD_CAST "ignore");
+        if (ignore)
+        {
+            string ignoreStr = (const char*) ignore;
+            if (ignoreStr == "true" || ignoreStr == "yes" || ignoreStr == "1")
+            {
+                doIgnore = true;
+                std::cerr << " <ignore:>";
+            }
+        }
+        xmlFree (ignore);
+        std::cerr << std::endl;
+
+        // Create the zk node
+        ZkTreeNodeSptr nodeSptr =
+            ZkTreeNodeSptr (new ZkTreeNode (nameStr,
+                        ZkNodeData (valueStr, doIgnore)));
+
+        // Load the children
+        for (xmlNode* chldNode = xmlNodePtr->children;
+                chldNode;
+                chldNode = chldNode->next)
+            if (chldNode->type == XML_ELEMENT_NODE)
+                nodeSptr->addChild (loadZkTreeXml_ (chldNode));
+
+        // Return the loaded node
+        return nodeSptr;
+    }
+
+    static void writeZkTree_ (ZooKeeperAdapterSptr zkHandle,
+            const ZkTreeNodeSptr zkNodeSptr,
+            const string& path)
+    {
+        // Create the path in zk-tree
+        zkHandle->createNode(path.c_str(), "", 0, false);
+        std::cerr << "[zktreeutil] created key: " << path << std::endl;
+        // Set value for the path
+        string value = zkNodeSptr->getData().value;
+        if (value != "")
+        {
+            zkHandle->setNodeData (path.c_str(), value.c_str());
+            std::cerr << "[zktreeutil] set value: " << std::endl;
+        }
+
+        // Go deep to write the subtree rooted in the node, if not to be ignored
+        if (!(zkNodeSptr->getData().ignoreUpdate))
+        {
+            for (unsigned i=0; i < zkNodeSptr->numChildren(); i++)
+            {
+                ZkTreeNodeSptr childNodeSptr = zkNodeSptr->getChild (i);
+                // Add the node name into the path and write in zk-tree
+                string cpath = ((path != "/")? path : "")
+                    + string("/")
+                    + childNodeSptr->getKey();
+                writeZkTree_ (zkHandle, childNodeSptr, cpath);
+            }
+        }
+
+        return;
+    }
+
+    static void addTreeZkAction_ (const ZkTreeNodeSptr zkNodeSptr,
+            const string& path,
+            vector< ZkAction >& actions)
+    {
+        // Create the key
+        actions.push_back (ZkAction (ZkAction::CREATE, path));
+
+        // Set value for the new key
+        if (zkNodeSptr->getData().value != "")
+            actions.push_back (ZkAction (ZkAction::VALUE,
+                        path,
+                        zkNodeSptr->getData().value));
+
+        // Add all the children
+        for (unsigned i=0; i < zkNodeSptr->numChildren(); i++)
+        {
+            ZkTreeNodeSptr childSptr = zkNodeSptr->getChild (i);
+            string cpath = path + string("/") + childSptr->getKey();
+            addTreeZkAction_ (childSptr, cpath, actions);
+        }
+
+        return;
+    }
+
+    static xmlNodePtr dumpZkTreeXml_ (const ZkTreeNodeSptr zkNodeSptr)
+    {
+        // Create xml node with zknode name and value
+        string nodename = zkNodeSptr->getKey ();
+        string value = zkNodeSptr->getData().value;
+        xmlNodePtr node = xmlNewNode(NULL, BAD_CAST "zknode");
+        xmlNewProp (node, BAD_CAST "name", BAD_CAST nodename.c_str());
+        if (value.length())
+            xmlNewProp (node, BAD_CAST "value", BAD_CAST value.c_str());
+
+        // Add all the children rotted at this node
+        for (unsigned i=0; i < zkNodeSptr->numChildren(); i++)
+            xmlAddChild (node, dumpZkTreeXml_ (zkNodeSptr->getChild (i)));
+
+        // Return xml node
+        return node;
+    }
+
+    static void dumpZkTree_ (const ZkTreeNodeSptr zkNodeSptr,
+            int maxLevel,
+            int level,
+            vector< bool >& masks)
+    {
+        // Check the max. dlevel to be dumped
+        if (level > maxLevel)
+            return;
+
+        
+        // Create branch
+        for (int i=0; i < level; i++) 
+        {
+            if ( i== level-1) std::cout << "|   ";
+            else if (masks[i]) std::cout << "    ";
+            else std::cout << "|   ";
+        }
+        std::cout << std::endl;
+        for (int i=0; i < level-1; i++)
+        {
+            if (masks[i]) std::cout << "    ";
+            else std::cout << "|   ";
+        }
+
+        // Dump the node name and value
+        std::cout << "|--[" << zkNodeSptr->getKey();
+        if (zkNodeSptr->getData().value != "")
+            std::cout << " => " << zkNodeSptr->getData().value;
+        std::cout << "]" << std::endl;
+
+        // Dump all the children
+        for (unsigned i=0; i < zkNodeSptr->numChildren(); i++)
+        {
+            // Add mask for last child
+            if (i == zkNodeSptr->numChildren()-1)
+                masks.push_back(true);
+            else
+                masks.push_back(false);
+            dumpZkTree_ (zkNodeSptr->getChild (i), maxLevel, level+1, masks);
+        }
+
+        masks.pop_back();
+        return;
+    }
+
+    static ZkTreeNodeSptr traverseBranch_ (const ZkTreeNodeSptr& zkRootSptr,
+            const string& path)
+    {
+        // Check if the tree is loaded into memory
+        if (zkRootSptr == NULL)
+        {
+            string errMsg = "[zktreeutil] null root passed for traversing";
+            std::cout << errMsg << std::endl;
+            throw std::logic_error (errMsg);
+        }
+
+        // Split the path and add intermediate znodes
+        vector< string > nodes;
+        boost::split(nodes, path, boost::is_any_of ("/") );
+
+        // Start traversing the tree
+        ZkTreeNodeSptr currNodeSptr = zkRootSptr;
+        for (unsigned znode_idx = 1; znode_idx < nodes.size(); znode_idx++)
+        {
+            bool found = false;
+            for (unsigned i=0; i < currNodeSptr->numChildren(); i++)
+            {
+                ZkTreeNodeSptr  childNodeSptr = currNodeSptr->getChild(i);
+                if (childNodeSptr->getKey() == nodes[znode_idx])
+                {
+                    // Found! go to the znode
+                    currNodeSptr = childNodeSptr;
+                    found = true;
+                    break;
+                }
+            }
+            if (!found) // No such znode found; return NULL node-ptr
+            {
+                string errMsg = string("[zktreeutil] unknown znode during traversal: ")
+                    + nodes[znode_idx];
+                std::cout << errMsg << std::endl;
+                throw std::logic_error (errMsg);
+            }
+        }
+
+        return currNodeSptr;
+    }
+
+    static ZkTreeNodeSptr createAncestors_ (const string& path)
+    {
+        // Create the root znode
+        ZkTreeNodeSptr zkRootSptr = ZkTreeNodeSptr (new ZkTreeNode ("/"));
+        ZkTreeNodeSptr currNodeSptr = zkRootSptr;
+        // Split the path and add intermediate znodes
+        vector< string > nodes;
+        boost::split(nodes, path, boost::is_any_of ("/") );
+        for (unsigned i=1; i < nodes.size()-1; i++)
+        {
+            ZkTreeNodeSptr childNodeSptr = ZkTreeNodeSptr (new ZkTreeNode (nodes[i]));
+            currNodeSptr->addChild (childNodeSptr);
+            currNodeSptr = childNodeSptr;
+        }
+
+        //Return the root of the branch
+        return zkRootSptr;
+    }
+
+    ZooKeeperAdapterSptr ZkTreeUtil::get_zkHandle (const string& zkHosts)
+    {
+        try
+        {
+            // Create an instance of ZK adapter.
+            ZooKeeperConfig config (zkHosts, 10000);
+            ZooKeeperAdapterSptr zkHandleSptr =
+                ZooKeeperAdapterSptr (new ZooKeeperAdapter (config));
+            return zkHandleSptr;
+        }
+        catch (const ZooKeeperException &e)
+        {
+            std::cerr << "[zktreeutil] zooKeeper exception caught: "
+                << e.what()
+                << std::endl;
+            throw;
+        }
+        catch (std::exception &stde)
+        {
+            std::cerr << "[zktreeutil] standard exception caught: "
+                << stde.what()
+                << std::endl;
+            throw;
+        }
+        catch (...)
+        {
+            std::cerr
+                << "[zktreeutil] unknown exception while connecting to zookeeper"
+                << std::endl;
+            throw;
+        }
+    }
+
+
+    void ZkTreeUtil::loadZkTree (const string& zkHosts,
+            const string& path,
+            bool force)
+    {
+        // Check if already loaded
+        if (loaded_ && !force)
+        {
+            std::cerr << "[zktreeutil] zk-tree already loaded into memory"
+                << std::endl;
+            return;
+        }
+
+        // Connect to ZK server
+        ZooKeeperAdapterSptr zkHandle = get_zkHandle (zkHosts);
+        std::cerr << "[zktreeutil] connected to ZK serverfor reading"
+            << std::endl;
+
+        // Check the existance of the path to znode
+        if (!zkHandle->nodeExists (path))
+        {
+            string errMsg = string("[zktreeutil] path does not exists : ") + path;
+            std::cout << errMsg << std::endl;
+            throw std::logic_error (errMsg);
+        }
+
+        // Load the rooted (sub)tree
+        ZkTreeNodeSptr zkSubrootSptr = loadZkTree_ (zkHandle, path);
+
+        //  Create the ancestors before loading the rooted subtree
+        if (path != "/")
+        {
+            zkRootSptr_ = createAncestors_(path);
+            string ppath = path.substr (0, path.rfind('/'));
+            ZkTreeNodeSptr parentSptr = traverseBranch_( zkRootSptr_, ppath);
+            parentSptr->addChild (zkSubrootSptr);
+        }
+        else // Loaded entire zk-tree
+        {
+            zkRootSptr_ = zkSubrootSptr;
+        }
+
+        // Set load flag
+        loaded_ = true;
+        return;
+    }
+
+    void ZkTreeUtil::loadZkTreeXml (const string& zkXmlConfig,
+            bool force)
+    {
+        // Check if already loaded
+        if (loaded_ && !force)
+        {
+            std::cerr << "[zktreeutil] zk-tree already loaded into memory"
+                << std::endl;
+            return;
+        }
+
+        // Parse the file and get the DOM
+        xmlDocPtr docPtr = xmlReadFile(zkXmlConfig.c_str(), NULL, 0);
+        if (docPtr == NULL) {
+            std::cerr << "[zktreeutil] could not parse XML file "
+                << zkXmlConfig
+                << std::endl;
+            exit (-1);
+        }
+        std::cerr << "[zktreeutil] zk-tree XML parsing successful"
+            << std::endl;
+
+        // Get the root element node
+        xmlNodePtr rootPtr = xmlDocGetRootElement(docPtr);
+        // Create the root zk node
+        zkRootSptr_ = ZkTreeNodeSptr (new ZkTreeNode ("/"));
+        // Load the rooted XML tree
+        for (xmlNode* chldNode = rootPtr->children;
+                chldNode;
+                chldNode = chldNode->next)
+        {
+            if (chldNode->type == XML_ELEMENT_NODE)
+                zkRootSptr_->addChild (loadZkTreeXml_ (chldNode));
+        }
+
+        // set oad flag
+        loaded_ = true;
+        // Cleanup stuff
+        xmlFreeDoc(docPtr);
+        xmlCleanupParser();
+        return;
+    }
+
+    void ZkTreeUtil::writeZkTree (const string& zkHosts,
+            const string& path,
+            bool force) const
+    {
+        // Connect to ZK server
+        ZooKeeperAdapterSptr zkHandle = get_zkHandle (zkHosts);
+        std::cerr << "[zktreeutil] connected to ZK server for writing"
+            << std::endl;
+
+        // Go to the rooted subtree
+        ZkTreeNodeSptr zkRootSptr = traverseBranch_ (zkRootSptr_, path);
+
+        // Cleanup before write if forceful write enabled
+        if (force)
+        {
+            if (path != "/") // remove the subtree rooted at the znode
+            {
+                // Delete the subtree rooted at the znode before write
+                if (zkHandle->nodeExists (path))
+                {
+                    std::cerr << "[zktreeutil] deleting subtree rooted at "
+                        << path
+                        << "..."
+                        << std::endl;
+                    zkHandle->deleteNode (path, true);
+                }
+            }
+            else // remove the rooted znodes
+            {
+                std::cerr << "[zktreeutil] deleting rooted zk-tree"
+                    << "..."
+                    << std::endl;
+                // Get the root's children
+                vector< string > cnodes = zkHandle->getNodeChildren ("/");
+                for (unsigned i=0; i < cnodes.size(); i++)
+                {
+                    if ( cnodes[i] != "/zookeeper") // reserved for zookeeper use
+                        zkHandle->deleteNode(cnodes[i], true);
+                }
+            }
+        }
+
+        // Start tree construction
+        writeZkTree_ (zkHandle, zkRootSptr, path);
+        return;
+    }
+
+    void ZkTreeUtil::dumpZkTree (bool xml, int depth) const
+    {
+        if (xml)
+        {
+            // Creates a new document, a node and set it as a root node
+            xmlDocPtr docPtr = xmlNewDoc(BAD_CAST "1.0");
+            xmlNodePtr rootNode = xmlNewNode(NULL, BAD_CAST "root");
+            xmlDocSetRootElement(docPtr, rootNode);
+
+            // Add all the rooted children
+            for (unsigned i=0; i < zkRootSptr_->numChildren(); i++)
+                xmlAddChild (rootNode, dumpZkTreeXml_ (zkRootSptr_->getChild (i)));
+
+            // Dumping document to stdio or file
+            xmlSaveFormatFileEnc("-", docPtr, "UTF-8", 1);
+
+            // Cleanup stuff
+            xmlFreeDoc(docPtr);
+            xmlCleanupParser();
+            return;
+        }
+
+        // Dump text
+        std::cout << "/" << std::endl;
+        vector< bool > masks;
+        for (unsigned i=0; i < zkRootSptr_->numChildren(); i++)
+        {
+            if (i == zkRootSptr_->numChildren()-1)
+                masks.push_back(true);
+            else
+                masks.push_back(false);
+            dumpZkTree_ (zkRootSptr_->getChild (i), depth, 1, masks);
+        }
+
+        return;
+    }
+
+    vector< ZkAction > ZkTreeUtil::diffZkTree (const string& zkHosts,
+            const string& path) const
+    {
+        // Action container
+        vector< ZkAction > actions;
+
+        if (!loaded_)
+        {
+            std::cout << "[zktreeutil] zk-tree not loaded for diff"
+                << std::endl;
+            exit (-1);
+        }
+
+        // Load the rooted subtree from zookeeper
+        ZooKeeperAdapterSptr zkHandle = get_zkHandle (zkHosts);
+        std::cerr << "[zktreeutil] connected to ZK server for reading"
+            << std::endl;
+        ZkTreeNodeSptr zkLiveRootSptr = loadZkTree_ (zkHandle, path);
+
+        // Go to the saved rooted subtree
+        ZkTreeNodeSptr zkLoadedRootSptr =
+            traverseBranch_ (zkRootSptr_, path);
+
+        // Check the root value first
+        if (zkLoadedRootSptr->getData().value
+                != zkLiveRootSptr->getData().value)
+        {
+            actions.push_back (ZkAction (ZkAction::VALUE,
+                        path,
+                        zkLoadedRootSptr->getData().value,
+                        zkLiveRootSptr->getData().value));
+        }
+
+        // Start traversal from root
+        vector< string > ppaths;
+        vector< pair< ZkTreeNodeSptr, ZkTreeNodeSptr > > commonNodes;
+        ppaths.push_back ((path != "/")? path : "");
+        commonNodes.push_back (pair< ZkTreeNodeSptr, ZkTreeNodeSptr >
+                (zkLoadedRootSptr, zkLiveRootSptr));
+
+        for (unsigned j=0; j < commonNodes.size(); j++)
+        {
+            // Get children of loaded tree
+            map< string, ZkTreeNodeSptr > loadedChildren;
+            for (unsigned i=0; i < commonNodes[j].first->numChildren(); i++)
+            {
+                ZkTreeNodeSptr childSptr = commonNodes[j].first->getChild (i);
+                loadedChildren[childSptr->getKey()] = childSptr;
+            }
+            // Get children of live tree
+            map< string, ZkTreeNodeSptr > liveChildren;
+            for (unsigned i=0; i < commonNodes[j].second->numChildren(); i++)
+            {
+                ZkTreeNodeSptr childSptr = commonNodes[j].second->getChild (i);
+                liveChildren[childSptr->getKey()] = childSptr;
+            }
+
+            // Start comparing the children
+            for (map< string, ZkTreeNodeSptr >::const_iterator it =
+                    loadedChildren.begin();
+                    it != loadedChildren.end();
+                    it++)
+            {
+                bool ignoreKey = it->second->getData().ignoreUpdate;
+                string loadedVal = it->second->getData().value;
+                // Path to this node
+                string path = ppaths[j] + string("/") + it->first;
+
+                map< string, ZkTreeNodeSptr >::const_iterator jt =
+                    liveChildren.find (it->first);
+                if (jt != liveChildren.end())
+                {
+                    // Key is present in live zk-tree
+                    string liveVal = jt->second->getData().value;
+                    // Check value for the key, if not ignored
+                    if (!ignoreKey)
+                    {
+                        if (loadedVal != liveVal)
+                        {
+                            // Value differs, set the new value for the key
+                            actions.push_back (ZkAction (ZkAction::VALUE,
+                                        path,
+                                        loadedVal,
+                                        liveVal));
+                        }
+
+                        // Add node to common nodes
+                        ppaths.push_back (path);
+                        commonNodes.push_back (pair< ZkTreeNodeSptr, ZkTreeNodeSptr >
+                                (it->second, jt->second));
+                    }
+
+                    // Remove the live zk node
+                    liveChildren.erase (it->first);
+                }
+                else
+                {
+                    // Add the subtree rooted to this node, if not ignored
+                    if (!ignoreKey)
+                        addTreeZkAction_ (it->second, path, actions);
+                }
+            }
+
+            // Remaining live zk nodes to be deleted
+            for (map< string, ZkTreeNodeSptr >::const_iterator it = liveChildren.begin();
+                    it != liveChildren.end(); it++)
+            {
+                string path = ppaths[j] + string("/") + it->first;
+                actions.push_back (ZkAction (ZkAction::DELETE, path));
+            }
+        }
+        // return the diff actions
+        return actions;
+    }
+
+    void ZkTreeUtil::executeZkActions (const string& zkHosts,
+            const vector< ZkAction >& zkActions,
+            int execFlags) const
+    {
+        // Execute the diff zk actions
+        if (zkActions.size())
+        {
+            // Connect to Zookeeper for writing
+            ZooKeeperAdapterSptr zkHandleSptr;
+            if ((execFlags & EXECUTE)
+                    || (execFlags & INTERACTIVE))
+            {
+                zkHandleSptr = get_zkHandle (zkHosts);
+                std::cerr << "[zktreeutil] connected to ZK server for writing"
+                    << std::endl;
+            }
+
+            for (unsigned i=0; i < zkActions.size(); i++)
+            {
+                if (zkActions[i].action == ZkAction::CREATE)
+                {
+                    if (execFlags & PRINT)
+                        std::cout << "CREAT- key:" << zkActions[i].key << std::endl;
+                    if (execFlags & EXECUTE)
+                    {
+                        if (execFlags & INTERACTIVE)
+                        {
+                            string resp;
+                            std::cout << "Execute this action?[yes/no]: ";
+                            std::getline(std::cin, resp);
+                            if (resp != "yes")
+                                continue;
+                        }
+                        zkHandleSptr->createNode(zkActions[i].key.c_str(), "", 0, false);
+                    }
+                }
+                else if (zkActions[i].action == ZkAction::DELETE)
+                {
+                    if (execFlags & PRINT)
+                        std::cout << "DELET- key:" << zkActions[i].key << std::endl;
+                    if (execFlags & EXECUTE)
+                    {
+                        if (execFlags & INTERACTIVE)
+                        {
+                            string resp;
+                            std::cout << "Execute this action?[yes/no]: ";
+                            std::getline(std::cin, resp);
+                            if (resp != "yes")
+                                continue;
+                        }
+                        zkHandleSptr->deleteNode(zkActions[i].key.c_str(), true);
+                    }
+                }
+                else if (zkActions[i].action == ZkAction::VALUE)
+                {
+                    if (execFlags & PRINT)
+                    {
+                        std::cout << "VALUE- key:"
+                            << zkActions[i].key
+                            << " value:" << zkActions[i].newval;
+                        if (zkActions[i].oldval != "")
+                            std::cout << " old_value:" << zkActions[i].oldval;
+                        std::cout << std::endl;
+                    }
+                    if (execFlags & EXECUTE)
+                    {
+                        if (execFlags & INTERACTIVE)
+                        {
+                            string resp;
+                            std::cout << "Execute this action?[yes/no]: ";
+                            std::getline(std::cin, resp);
+                            if (resp != "yes")
+                                continue;
+                        }
+                        zkHandleSptr->setNodeData (zkActions[i].key, zkActions[i].newval);
+                    }
+                }
+            }
+        }
+
+        return;
+    }
+
+}
+

Added: hadoop/zookeeper/trunk/src/contrib/zktreeutil/src/ZkTreeUtil.h
URL: http://svn.apache.org/viewvc/hadoop/zookeeper/trunk/src/contrib/zktreeutil/src/ZkTreeUtil.h?rev=898542&view=auto
==============================================================================
--- hadoop/zookeeper/trunk/src/contrib/zktreeutil/src/ZkTreeUtil.h (added)
+++ hadoop/zookeeper/trunk/src/contrib/zktreeutil/src/ZkTreeUtil.h Tue Jan 12 22:02:27 2010
@@ -0,0 +1,262 @@
+/**
+ * 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_TREE_UTIL_H__
+#define __ZK_TREE_UTIL_H__
+
+#include <libxml/parser.h>
+#include <libxml/tree.h>
+#include "SimpleTree.h"
+#include "ZkAdaptor.h"
+
+namespace zktreeutil
+{
+
+#define ZKTREEUTIL_INF 1000000000
+    /**
+     * \brief A structure containing ZK node data.
+     */
+    struct ZkNodeData
+    {
+        /**
+         * \brief The value string of the ZK node.
+         */
+        string value;
+
+        /**
+         * \brief The flag indicating whether children of the
+         * \brief node shduld be ignored during create/diff/update
+         */
+        bool ignoreUpdate;
+
+        /**
+         * \brief Constructor.
+         *
+         * @param val the value string
+         * @param ignore the flag indicating ignore any update/diff
+         */
+        ZkNodeData (const string& val, bool ignore=false)
+            : value (val), ignoreUpdate (ignore) {}
+
+        /**
+         * \brief Constructor.
+         *
+         * @param ignore the flag indicating ignore any update/diff
+         */
+        ZkNodeData (bool ignore=false)
+            : ignoreUpdate (ignore) {}
+    };
+
+    /**
+     * \brief The type representing a ZK Treenode
+     */
+    typedef SimpleTreeNode< string, ZkNodeData > ZkTreeNode;
+
+    /**
+     * \brief The type representing a ZK Treenode smart-pointer
+     */
+    typedef boost::shared_ptr< ZkTreeNode > ZkTreeNodeSptr;
+
+    /**
+     * \brief The type representing a ZK Adapter smart-pointer
+     */
+    typedef boost::shared_ptr< ZooKeeperAdapter > ZooKeeperAdapterSptr;
+
+    /**
+     * \brief A structure defining a particular action on ZK node;
+     * \brief the action can be any of -
+     * \brief        CREAT- <zknode>                : creates <zknode> recussively
+     * \brief        DELET- <zknode>              : deletes <zknode> recursively
+     * \brief        VALUE- <zknode> <value>     : sets <value> to <zknode>
+     */
+    struct ZkAction
+    {
+        /**
+         * \brief The action type; any of create/delete/setvalue.
+         */
+        enum ZkActionType
+        {
+            NONE,
+            CREATE,
+            DELETE,
+            VALUE,
+        };
+
+        /**
+         * \brief action of this instance
+         */
+        ZkActionType action;
+
+        /**
+         * \brief ZK node key
+         */
+        string key;
+
+        /**
+         * \brief value to be set, if action is setvalue
+         */
+        string newval;
+
+        /**
+         * \brief existing value of the ZK node key
+         */
+        string oldval;
+
+        /**
+         * \brief Constructor.
+         */
+        ZkAction ()
+            : action (ZkAction::NONE) {}
+
+        /**
+         * \brief Constructor.
+         *
+         * @param act the action to be taken
+         * @param k the key on which action to be taken
+         */
+        ZkAction (ZkActionType act, const string& k)
+            : action(act),
+            key(k) {}
+
+        /**
+         * \brief Constructor.
+         *
+         * @param act the action to be taken
+         * @param k the key on which action to be taken
+         * @param v the value of the ZK node key
+         */
+        ZkAction (ZkActionType act, const string& k, const string& v)
+            : action(act),
+            key(k),
+            newval(v) {}
+
+        /**
+         * \brief Constructor.
+         *
+         * @param act the action to be taken
+         * @param k the key on which action to be taken
+         * @param nv the new value of the ZK node key
+         * @param ov the old value of the ZK node key
+         */
+        ZkAction (ZkActionType act, const string& k, const string& nv, const string& ov)
+            : action (act),
+            key(k),
+            newval(nv),
+            oldval(ov) {}
+    };
+
+    /**
+     * \brief The ZK tree utility class; supports loading ZK tree from ZK server OR
+     * \brief from saved XML file, saving ZK tree into XML file, dumping the ZK tree
+     * \brief on standard output, creting a diff between saved ZK tree and live ZK
+     * \brief tree and incremental update of the live ZK tree.
+     */
+    class ZkTreeUtil
+    {
+        public:
+            /**
+             * \brief Execution flag on ZkAction
+             */
+            enum ZkActionExecuteFlag
+            {
+                NONE = 0,
+                PRINT = 1,
+                EXECUTE = 2,
+                INTERACTIVE = 5,
+            };
+
+        public:
+            /**
+             * \brief Connects to zookeeper and returns a valid ZK handle
+             *
+             * @param zkHosts comma separated list of host:port forming ZK quorum
+             * @param a valid ZK handle
+             */
+            static ZooKeeperAdapterSptr get_zkHandle (const string& zkHosts);
+
+
+        public:
+            /**
+             * \brief Constructor.
+             */
+            ZkTreeUtil () : loaded_(false) {}
+
+            /**
+             * \brief loads the ZK tree from ZK server into memory
+             *
+             * @param zkHosts comma separated list of host:port forming ZK quorum
+             * @param path path to the subtree to be loaded into memory
+             * @param force forces reloading in case tree already loaded into memory
+             */
+            void loadZkTree (const string& zkHosts, const string& path="/", bool force=false);
+
+            /**
+             * \brief loads the ZK tree from XML file into memory
+             *
+             * @param zkXmlConfig ZK tree XML file
+             * @param force forces reloading in case tree already loaded into memory
+             */
+            void loadZkTreeXml (const string& zkXmlConfig, bool force=false);
+
+            /**
+             * \brief writes the in-memory ZK tree on to ZK server
+             *
+             * @param zkHosts comma separated list of host:port forming ZK quorum
+             * @param path path to the subtree to be written to ZK tree
+             * @param force forces cleanup of the ZK tree on the ZK server before writing
+             */
+            void writeZkTree (const string& zkHosts, const string& path="/", bool force=false) const;
+
+            /**
+             * \brief dupms the in-memory ZK tree on the standard output device;
+             *
+             * @param xml flag indicates whether tree should be dumped in XML format
+             * @param depth the depth of the tree to be dumped for non-xml dump
+             */
+            void dumpZkTree (bool xml=false, int depth=ZKTREEUTIL_INF) const;
+
+            /** 
+             * \brief returns a list of actions after taking a diff of in-memory
+             * \brief ZK tree and live ZK tree.
+             *
+             * @param zkHosts comma separated list of host:port forming ZK quorum
+             * @param path path to the subtree in consideration while taking diff with ZK tree
+             * @return a list of ZKAction instances to be performed on live ZK tree
+             */
+            vector< ZkAction > diffZkTree (const string& zkHosts, const string& path="/") const;
+
+            /**
+             * \brief performs create/delete/setvalue by executing a set of
+             * ZkActions on a live ZK tree.
+             *
+             * @param zkHosts comma separated list of host:port forming ZK quorum
+             * @param zkActions set of ZkActions
+             * @param execFlags flags indicating print/execute/interactive etc
+             */
+            void executeZkActions (const string& zkHosts,
+                    const vector< ZkAction >& zkActions,
+                    int execFlags) const;
+
+        private:
+
+            ZkTreeNodeSptr zkRootSptr_;     // ZK tree root node
+            bool loaded_;                        // Falg indicating whether ZK tree loaded into memory
+    };
+}
+
+#endif // __ZK_TREE_UTIL_H__