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__