|
@@ -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;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+}
|
|
|
|
+
|