View Javadoc

1   /**
2    * Copyright 2010 The Apache Software Foundation
3    *
4    * Licensed to the Apache Software Foundation (ASF) under one
5    * or more contributor license agreements.  See the NOTICE file
6    * distributed with this work for additional information
7    * regarding copyright ownership.  The ASF licenses this file
8    * to you under the Apache License, Version 2.0 (the
9    * "License"); you may not use this file except in compliance
10   * with the License.  You may obtain a copy of the License at
11   *
12   *     http://www.apache.org/licenses/LICENSE-2.0
13   *
14   * Unless required by applicable law or agreed to in writing, software
15   * distributed under the License is distributed on an "AS IS" BASIS,
16   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
17   * See the License for the specific language governing permissions and
18   * limitations under the License.
19   */
20  package org.apache.hadoop.hbase.zookeeper;
21  
22  import java.io.BufferedReader;
23  import java.io.IOException;
24  import java.io.InputStreamReader;
25  import java.io.PrintWriter;
26  import java.net.Socket;
27  import java.util.ArrayList;
28  import java.util.List;
29  import java.util.Properties;
30  
31  import org.apache.commons.lang.StringUtils;
32  import org.apache.commons.logging.Log;
33  import org.apache.commons.logging.LogFactory;
34  import org.apache.hadoop.conf.Configuration;
35  import org.apache.hadoop.hbase.HConstants;
36  import org.apache.hadoop.hbase.HServerAddress;
37  import org.apache.hadoop.hbase.HServerInfo;
38  import org.apache.hadoop.hbase.executor.RegionTransitionData;
39  import org.apache.hadoop.hbase.util.Bytes;
40  import org.apache.zookeeper.AsyncCallback;
41  import org.apache.zookeeper.CreateMode;
42  import org.apache.zookeeper.KeeperException;
43  import org.apache.zookeeper.Watcher;
44  import org.apache.zookeeper.ZooKeeper;
45  import org.apache.zookeeper.KeeperException.NoNodeException;
46  import org.apache.zookeeper.ZooDefs.Ids;
47  import org.apache.zookeeper.data.Stat;
48  
49  /**
50   * Internal HBase utility class for ZooKeeper.
51   *
52   * <p>Contains only static methods and constants.
53   *
54   * <p>Methods all throw {@link KeeperException} if there is an unexpected
55   * zookeeper exception, so callers of these methods must handle appropriately.
56   * If ZK is required for the operation, the server will need to be aborted.
57   */
58  public class ZKUtil {
59    private static final Log LOG = LogFactory.getLog(ZKUtil.class);
60  
61    // TODO: Replace this with ZooKeeper constant when ZOOKEEPER-277 is resolved.
62    private static final char ZNODE_PATH_SEPARATOR = '/';
63  
64    /**
65     * Creates a new connection to ZooKeeper, pulling settings and ensemble config
66     * from the specified configuration object using methods from {@link ZKConfig}.
67     *
68     * Sets the connection status monitoring watcher to the specified watcher.
69     *
70     * @param conf configuration to pull ensemble and other settings from
71     * @param watcher watcher to monitor connection changes
72     * @return connection to zookeeper
73     * @throws IOException if unable to connect to zk or config problem
74     */
75    public static ZooKeeper connect(Configuration conf, Watcher watcher)
76    throws IOException {
77      Properties properties = ZKConfig.makeZKProps(conf);
78      String ensemble = ZKConfig.getZKQuorumServersString(properties);
79      return connect(conf, ensemble, watcher);
80    }
81  
82    public static ZooKeeper connect(Configuration conf, String ensemble,
83        Watcher watcher)
84    throws IOException {
85      return connect(conf, ensemble, watcher, "");
86    }
87  
88    public static ZooKeeper connect(Configuration conf, String ensemble,
89        Watcher watcher, final String descriptor)
90    throws IOException {
91      if(ensemble == null) {
92        throw new IOException("Unable to determine ZooKeeper ensemble");
93      }
94      int timeout = conf.getInt("zookeeper.session.timeout", 180 * 1000);
95      LOG.debug(descriptor + " opening connection to ZooKeeper with ensemble (" +
96          ensemble + ")");
97      return new ZooKeeper(ensemble, timeout, watcher);
98    }
99  
100   //
101   // Helper methods
102   //
103 
104   /**
105    * Join the prefix znode name with the suffix znode name to generate a proper
106    * full znode name.
107    *
108    * Assumes prefix does not end with slash and suffix does not begin with it.
109    *
110    * @param prefix beginning of znode name
111    * @param suffix ending of znode name
112    * @return result of properly joining prefix with suffix
113    */
114   public static String joinZNode(String prefix, String suffix) {
115     return prefix + ZNODE_PATH_SEPARATOR + suffix;
116   }
117 
118   /**
119    * Returns the full path of the immediate parent of the specified node.
120    * @param node path to get parent of
121    * @return parent of path, null if passed the root node or an invalid node
122    */
123   public static String getParent(String node) {
124     int idx = node.lastIndexOf(ZNODE_PATH_SEPARATOR);
125     return idx <= 0 ? null : node.substring(0, idx);
126   }
127 
128   /**
129    * Get the unique node-name for the specified regionserver.
130    *
131    * Used when a server puts up an ephemeral node for itself and needs to use
132    * a unique name.
133    *
134    * @param serverInfo server information
135    * @return unique, zookeeper-safe znode path for the server instance
136    */
137   public static String getNodeName(HServerInfo serverInfo) {
138     return serverInfo.getServerName();
139   }
140 
141   /**
142    * Get the name of the current node from the specified fully-qualified path.
143    * @param path fully-qualified path
144    * @return name of the current node
145    */
146   public static String getNodeName(String path) {
147     return path.substring(path.lastIndexOf("/")+1);
148   }
149 
150   /**
151    * Get the key to the ZK ensemble for this configuration without
152    * adding a name at the end
153    * @param conf Configuration to use to build the key
154    * @return ensemble key without a name
155    */
156   public static String getZooKeeperClusterKey(Configuration conf) {
157     return getZooKeeperClusterKey(conf, null);
158   }
159 
160   /**
161    * Get the key to the ZK ensemble for this configuration and append
162    * a name at the end
163    * @param conf Configuration to use to build the key
164    * @param name Name that should be appended at the end if not empty or null
165    * @return ensemble key with a name (if any)
166    */
167   public static String getZooKeeperClusterKey(Configuration conf, String name) {
168     String ensemble = conf.get(HConstants.ZOOKEEPER_QUORUM.replaceAll(
169         "[\\t\\n\\x0B\\f\\r]", ""));
170     StringBuilder builder = new StringBuilder(ensemble);
171     builder.append(":");
172     builder.append(conf.get("hbase.zookeeper.property.clientPort"));
173     builder.append(":");
174     builder.append(conf.get(HConstants.ZOOKEEPER_ZNODE_PARENT));
175     if (name != null && !name.isEmpty()) {
176       builder.append(",");
177       builder.append(name);
178     }
179     return builder.toString();
180   }
181 
182   /**
183    * Apply the settings in the given key to the given configuration, this is
184    * used to communicate with distant clusters
185    * @param conf configuration object to configure
186    * @param key string that contains the 3 required configuratins
187    * @throws IOException
188    */
189   public static void applyClusterKeyToConf(Configuration conf, String key)
190       throws IOException{
191     String[] parts = transformClusterKey(key);
192     conf.set(HConstants.ZOOKEEPER_QUORUM, parts[0]);
193     conf.set("hbase.zookeeper.property.clientPort", parts[1]);
194     conf.set(HConstants.ZOOKEEPER_ZNODE_PARENT, parts[2]);
195   }
196 
197   /**
198    * Separate the given key into the three configurations it should contain:
199    * hbase.zookeeper.quorum, hbase.zookeeper.client.port
200    * and zookeeper.znode.parent
201    * @param key
202    * @return the three configuration in the described order
203    * @throws IOException
204    */
205   public static String[] transformClusterKey(String key) throws IOException {
206     String[] parts = key.split(":");
207     if (parts.length != 3) {
208       throw new IOException("Cluster key invalid, the format should be:" +
209           HConstants.ZOOKEEPER_QUORUM + ":hbase.zookeeper.client.port:"
210           + HConstants.ZOOKEEPER_ZNODE_PARENT);
211     }
212     return parts;
213   }
214 
215   //
216   // Existence checks and watches
217   //
218 
219   /**
220    * Watch the specified znode for delete/create/change events.  The watcher is
221    * set whether or not the node exists.  If the node already exists, the method
222    * returns true.  If the node does not exist, the method returns false.
223    *
224    * @param zkw zk reference
225    * @param znode path of node to watch
226    * @return true if znode exists, false if does not exist or error
227    * @throws KeeperException if unexpected zookeeper exception
228    */
229   public static boolean watchAndCheckExists(ZooKeeperWatcher zkw, String znode)
230   throws KeeperException {
231     try {
232       Stat s = zkw.getZooKeeper().exists(znode, zkw);
233       LOG.debug(zkw.prefix("Set watcher on existing znode " + znode));
234       return s != null ? true : false;
235     } catch (KeeperException e) {
236       LOG.warn(zkw.prefix("Unable to set watcher on znode " + znode), e);
237       zkw.keeperException(e);
238       return false;
239     } catch (InterruptedException e) {
240       LOG.warn(zkw.prefix("Unable to set watcher on znode " + znode), e);
241       zkw.interruptedException(e);
242       return false;
243     }
244   }
245 
246   /**
247    * Check if the specified node exists.  Sets no watches.
248    *
249    * Returns true if node exists, false if not.  Returns an exception if there
250    * is an unexpected zookeeper exception.
251    *
252    * @param zkw zk reference
253    * @param znode path of node to watch
254    * @return version of the node if it exists, -1 if does not exist
255    * @throws KeeperException if unexpected zookeeper exception
256    */
257   public static int checkExists(ZooKeeperWatcher zkw, String znode)
258   throws KeeperException {
259     try {
260       Stat s = zkw.getZooKeeper().exists(znode, null);
261       return s != null ? s.getVersion() : -1;
262     } catch (KeeperException e) {
263       LOG.warn(zkw.prefix("Unable to set watcher on znode (" + znode + ")"), e);
264       zkw.keeperException(e);
265       return -1;
266     } catch (InterruptedException e) {
267       LOG.warn(zkw.prefix("Unable to set watcher on znode (" + znode + ")"), e);
268       zkw.interruptedException(e);
269       return -1;
270     }
271   }
272 
273   //
274   // Znode listings
275   //
276 
277   /**
278    * Lists the children znodes of the specified znode.  Also sets a watch on
279    * the specified znode which will capture a NodeDeleted event on the specified
280    * znode as well as NodeChildrenChanged if any children of the specified znode
281    * are created or deleted.
282    *
283    * Returns null if the specified node does not exist.  Otherwise returns a
284    * list of children of the specified node.  If the node exists but it has no
285    * children, an empty list will be returned.
286    *
287    * @param zkw zk reference
288    * @param znode path of node to list and watch children of
289    * @return list of children of the specified node, an empty list if the node
290    *          exists but has no children, and null if the node does not exist
291    * @throws KeeperException if unexpected zookeeper exception
292    */
293   public static List<String> listChildrenAndWatchForNewChildren(
294       ZooKeeperWatcher zkw, String znode)
295   throws KeeperException {
296     try {
297       List<String> children = zkw.getZooKeeper().getChildren(znode, zkw);
298       return children;
299     } catch(KeeperException.NoNodeException ke) {
300       LOG.debug(zkw.prefix("Unable to list children of znode " + znode + " " +
301           "because node does not exist (not an error)"));
302       return null;
303     } catch (KeeperException e) {
304       LOG.warn(zkw.prefix("Unable to list children of znode " + znode + " "), e);
305       zkw.keeperException(e);
306       return null;
307     } catch (InterruptedException e) {
308       LOG.warn(zkw.prefix("Unable to list children of znode " + znode + " "), e);
309       zkw.interruptedException(e);
310       return null;
311     }
312   }
313 
314   /**
315    * List all the children of the specified znode, setting a watch for children
316    * changes and also setting a watch on every individual child in order to get
317    * the NodeCreated and NodeDeleted events.
318    * @param zkw zookeeper reference
319    * @param znode node to get children of and watch
320    * @return list of znode names, null if the node doesn't exist
321    * @throws KeeperException
322    */
323   public static List<String> listChildrenAndWatchThem(ZooKeeperWatcher zkw,
324       String znode) throws KeeperException {
325     List<String> children = listChildrenAndWatchForNewChildren(zkw, znode);
326     if (children == null) {
327       return null;
328     }
329     for (String child : children) {
330       watchAndCheckExists(zkw, joinZNode(znode, child));
331     }
332     return children;
333   }
334 
335   /**
336    * Lists the children of the specified znode, retrieving the data of each
337    * child as a server address.
338    *
339    * Used to list the currently online regionservers and their addresses.
340    *
341    * Sets no watches at all, this method is best effort.
342    *
343    * Returns an empty list if the node has no children.  Returns null if the
344    * parent node itself does not exist.
345    *
346    * @param zkw zookeeper reference
347    * @param znode node to get children of as addresses
348    * @return list of data of children of specified znode, empty if no children,
349    *         null if parent does not exist
350    * @throws KeeperException if unexpected zookeeper exception
351    */
352   public static List<HServerAddress> listChildrenAndGetAsAddresses(
353       ZooKeeperWatcher zkw, String znode)
354   throws KeeperException {
355     List<String> children = listChildrenNoWatch(zkw, znode);
356     if(children == null) {
357       return null;
358     }
359     List<HServerAddress> addresses =
360       new ArrayList<HServerAddress>(children.size());
361     for(String child : children) {
362       addresses.add(getDataAsAddress(zkw, joinZNode(znode, child)));
363     }
364     return addresses;
365   }
366 
367   /**
368    * Lists the children of the specified znode without setting any watches.
369    *
370    * Used to list the currently online regionservers and their addresses.
371    *
372    * Sets no watches at all, this method is best effort.
373    *
374    * Returns an empty list if the node has no children.  Returns null if the
375    * parent node itself does not exist.
376    *
377    * @param zkw zookeeper reference
378    * @param znode node to get children of as addresses
379    * @return list of data of children of specified znode, empty if no children,
380    *         null if parent does not exist
381    * @throws KeeperException if unexpected zookeeper exception
382    */
383   public static List<String> listChildrenNoWatch(
384       ZooKeeperWatcher zkw, String znode)
385   throws KeeperException {
386     List<String> children = null;
387     try {
388       // List the children without watching
389       children = zkw.getZooKeeper().getChildren(znode, null);
390     } catch(KeeperException.NoNodeException nne) {
391       return null;
392     } catch(InterruptedException ie) {
393       zkw.interruptedException(ie);
394     }
395     return children;
396   }
397 
398   /**
399    * Atomically add watches and read data from all unwatched unassigned nodes.
400    *
401    * <p>This works because master is the only person deleting nodes.
402    */
403   public static List<NodeAndData> watchAndGetNewChildren(ZooKeeperWatcher zkw,
404       String baseNode)
405   throws KeeperException {
406     List<NodeAndData> newNodes = new ArrayList<NodeAndData>();
407     synchronized(zkw.getNodes()) {
408       List<String> nodes =
409         ZKUtil.listChildrenAndWatchForNewChildren(zkw, baseNode);
410       for(String node : nodes) {
411         String nodePath = ZKUtil.joinZNode(baseNode, node);
412         if(!zkw.getNodes().contains(nodePath)) {
413           byte [] data = ZKUtil.getDataAndWatch(zkw, nodePath);
414           newNodes.add(new NodeAndData(nodePath, data));
415           zkw.getNodes().add(nodePath);
416         }
417       }
418     }
419     return newNodes;
420   }
421 
422   /**
423    * Simple class to hold a node path and node data.
424    */
425   public static class NodeAndData {
426     private String node;
427     private byte [] data;
428     public NodeAndData(String node, byte [] data) {
429       this.node = node;
430       this.data = data;
431     }
432     public String getNode() {
433       return node;
434     }
435     public byte [] getData() {
436       return data;
437     }
438     @Override
439     public String toString() {
440       return node + " (" + RegionTransitionData.fromBytes(data) + ")";
441     }
442   }
443 
444   /**
445    * Checks if the specified znode has any children.  Sets no watches.
446    *
447    * Returns true if the node exists and has children.  Returns false if the
448    * node does not exist or if the node does not have any children.
449    *
450    * Used during master initialization to determine if the master is a
451    * failed-over-to master or the first master during initial cluster startup.
452    * If the directory for regionserver ephemeral nodes is empty then this is
453    * a cluster startup, if not then it is not cluster startup.
454    *
455    * @param zkw zk reference
456    * @param znode path of node to check for children of
457    * @return true if node has children, false if not or node does not exist
458    * @throws KeeperException if unexpected zookeeper exception
459    */
460   public static boolean nodeHasChildren(ZooKeeperWatcher zkw, String znode)
461   throws KeeperException {
462     try {
463       return !zkw.getZooKeeper().getChildren(znode, null).isEmpty();
464     } catch(KeeperException.NoNodeException ke) {
465       LOG.debug(zkw.prefix("Unable to list children of znode " + znode + " " +
466       "because node does not exist (not an error)"));
467       return false;
468     } catch (KeeperException e) {
469       LOG.warn(zkw.prefix("Unable to list children of znode " + znode), e);
470       zkw.keeperException(e);
471       return false;
472     } catch (InterruptedException e) {
473       LOG.warn(zkw.prefix("Unable to list children of znode " + znode), e);
474       zkw.interruptedException(e);
475       return false;
476     }
477   }
478 
479   /**
480    * Get the number of children of the specified node.
481    *
482    * If the node does not exist or has no children, returns 0.
483    *
484    * Sets no watches at all.
485    *
486    * @param zkw zk reference
487    * @param znode path of node to count children of
488    * @return number of children of specified node, 0 if none or parent does not
489    *         exist
490    * @throws KeeperException if unexpected zookeeper exception
491    */
492   public static int getNumberOfChildren(ZooKeeperWatcher zkw, String znode)
493   throws KeeperException {
494     try {
495       Stat stat = zkw.getZooKeeper().exists(znode, null);
496       return stat == null ? 0 : stat.getNumChildren();
497     } catch(KeeperException e) {
498       LOG.warn(zkw.prefix("Unable to get children of node " + znode));
499       zkw.keeperException(e);
500     } catch(InterruptedException e) {
501       zkw.interruptedException(e);
502     }
503     return 0;
504   }
505 
506   //
507   // Data retrieval
508   //
509 
510   /**
511    * Get znode data. Does not set a watcher.
512    * @return ZNode data
513    */
514   public static byte [] getData(ZooKeeperWatcher zkw, String znode)
515   throws KeeperException {
516     try {
517       byte [] data = zkw.getZooKeeper().getData(znode, null, null);
518       logRetrievedMsg(zkw, znode, data, false);
519       return data;
520     } catch (KeeperException.NoNodeException e) {
521       LOG.debug(zkw.prefix("Unable to get data of znode " + znode + " " +
522         "because node does not exist (not an error)"));
523       return null;
524     } catch (KeeperException e) {
525       LOG.warn(zkw.prefix("Unable to get data of znode " + znode), e);
526       zkw.keeperException(e);
527       return null;
528     } catch (InterruptedException e) {
529       LOG.warn(zkw.prefix("Unable to get data of znode " + znode), e);
530       zkw.interruptedException(e);
531       return null;
532     }
533   }
534 
535   /**
536    * Get the data at the specified znode and set a watch.
537    *
538    * Returns the data and sets a watch if the node exists.  Returns null and no
539    * watch is set if the node does not exist or there is an exception.
540    *
541    * @param zkw zk reference
542    * @param znode path of node
543    * @return data of the specified znode, or null
544    * @throws KeeperException if unexpected zookeeper exception
545    */
546   public static byte [] getDataAndWatch(ZooKeeperWatcher zkw, String znode)
547   throws KeeperException {
548     try {
549       byte [] data = zkw.getZooKeeper().getData(znode, zkw, null);
550       logRetrievedMsg(zkw, znode, data, true);
551       return data;
552     } catch (KeeperException.NoNodeException e) {
553       LOG.debug(zkw.prefix("Unable to get data of znode " + znode + " " +
554         "because node does not exist (not an error)"));
555       return null;
556     } catch (KeeperException e) {
557       LOG.warn(zkw.prefix("Unable to get data of znode " + znode), e);
558       zkw.keeperException(e);
559       return null;
560     } catch (InterruptedException e) {
561       LOG.warn(zkw.prefix("Unable to get data of znode " + znode), e);
562       zkw.interruptedException(e);
563       return null;
564     }
565   }
566 
567   /**
568    * Get the data at the specified znode without setting a watch.
569    *
570    * Returns the data if the node exists.  Returns null if the node does not
571    * exist.
572    *
573    * Sets the stats of the node in the passed Stat object.  Pass a null stat if
574    * not interested.
575    *
576    * @param zkw zk reference
577    * @param znode path of node
578    * @param stat node status to set if node exists
579    * @return data of the specified znode, or null if node does not exist
580    * @throws KeeperException if unexpected zookeeper exception
581    */
582   public static byte [] getDataNoWatch(ZooKeeperWatcher zkw, String znode,
583       Stat stat)
584   throws KeeperException {
585     try {
586       byte [] data = zkw.getZooKeeper().getData(znode, zkw, stat);
587       logRetrievedMsg(zkw, znode, data, false);
588       return data;
589     } catch (KeeperException.NoNodeException e) {
590       LOG.debug(zkw.prefix("Unable to get data of znode " + znode + " " +
591           "because node does not exist (not necessarily an error)"));
592       return null;
593     } catch (KeeperException e) {
594       LOG.warn(zkw.prefix("Unable to get data of znode " + znode), e);
595       zkw.keeperException(e);
596       return null;
597     } catch (InterruptedException e) {
598       LOG.warn(zkw.prefix("Unable to get data of znode " + znode), e);
599       zkw.interruptedException(e);
600       return null;
601     }
602   }
603 
604   /**
605    * Get the data at the specified znode, deserialize it as an HServerAddress,
606    * and set a watch.
607    *
608    * Returns the data as a server address and sets a watch if the node exists.
609    * Returns null and no watch is set if the node does not exist or there is an
610    * exception.
611    *
612    * @param zkw zk reference
613    * @param znode path of node
614    * @return data of the specified node as a server address, or null
615    * @throws KeeperException if unexpected zookeeper exception
616    */
617   public static HServerAddress getDataAsAddress(ZooKeeperWatcher zkw,
618       String znode)
619   throws KeeperException {
620     byte [] data = getDataAndWatch(zkw, znode);
621     if(data == null) {
622       return null;
623     }
624     String addrString = Bytes.toString(data);
625     LOG.debug(zkw.prefix("Read server address from znode " + znode + ": " +
626       addrString));
627     return new HServerAddress(addrString);
628   }
629 
630   /**
631    * Update the data of an existing node with the expected version to have the
632    * specified data.
633    *
634    * Throws an exception if there is a version mismatch or some other problem.
635    *
636    * Sets no watches under any conditions.
637    *
638    * @param zkw zk reference
639    * @param znode
640    * @param data
641    * @param expectedVersion
642    * @throws KeeperException if unexpected zookeeper exception
643    * @throws KeeperException.BadVersionException if version mismatch
644    */
645   public static void updateExistingNodeData(ZooKeeperWatcher zkw, String znode,
646       byte [] data, int expectedVersion)
647   throws KeeperException {
648     try {
649       zkw.getZooKeeper().setData(znode, data, expectedVersion);
650     } catch(InterruptedException ie) {
651       zkw.interruptedException(ie);
652     }
653   }
654 
655   //
656   // Data setting
657   //
658 
659   /**
660    * Set the specified znode to be an ephemeral node carrying the specified
661    * server address.  Used by masters for their ephemeral node and regionservers
662    * for their ephemeral node.
663    *
664    * If the node is created successfully, a watcher is also set on the node.
665    *
666    * If the node is not created successfully because it already exists, this
667    * method will also set a watcher on the node.
668    *
669    * If there is another problem, a KeeperException will be thrown.
670    *
671    * @param zkw zk reference
672    * @param znode path of node
673    * @param address server address
674    * @return true if address set, false if not, watch set in both cases
675    * @throws KeeperException if unexpected zookeeper exception
676    */
677   public static boolean setAddressAndWatch(ZooKeeperWatcher zkw,
678       String znode, HServerAddress address)
679   throws KeeperException {
680     return createEphemeralNodeAndWatch(zkw, znode,
681         Bytes.toBytes(address.toString()));
682   }
683 
684   /**
685    * Sets the data of the existing znode to be the specified data.  Ensures that
686    * the current data has the specified expected version.
687    *
688    * <p>If the node does not exist, a {@link NoNodeException} will be thrown.
689    *
690    * <p>If their is a version mismatch, method returns null.
691    *
692    * <p>No watches are set but setting data will trigger other watchers of this
693    * node.
694    *
695    * <p>If there is another problem, a KeeperException will be thrown.
696    *
697    * @param zkw zk reference
698    * @param znode path of node
699    * @param data data to set for node
700    * @param expectedVersion version expected when setting data
701    * @return true if data set, false if version mismatch
702    * @throws KeeperException if unexpected zookeeper exception
703    */
704   public static boolean setData(ZooKeeperWatcher zkw, String znode,
705       byte [] data, int expectedVersion)
706   throws KeeperException, KeeperException.NoNodeException {
707     try {
708       return zkw.getZooKeeper().setData(znode, data, expectedVersion) != null;
709     } catch (InterruptedException e) {
710       zkw.interruptedException(e);
711       return false;
712     }
713   }
714 
715   /**
716    * Set data into node creating node if it doesn't yet exist.
717    * Does not set watch.
718    * @param zkw zk reference
719    * @param znode path of node
720    * @param data data to set for node
721    * @throws KeeperException
722    */
723   public static void createSetData(final ZooKeeperWatcher zkw, final String znode,
724       final byte [] data)
725   throws KeeperException {
726     if (checkExists(zkw, znode) == -1) {
727       ZKUtil.createWithParents(zkw, znode);
728     }
729     ZKUtil.setData(zkw, znode, data);
730   }
731 
732   /**
733    * Sets the data of the existing znode to be the specified data.  The node
734    * must exist but no checks are done on the existing data or version.
735    *
736    * <p>If the node does not exist, a {@link NoNodeException} will be thrown.
737    *
738    * <p>No watches are set but setting data will trigger other watchers of this
739    * node.
740    *
741    * <p>If there is another problem, a KeeperException will be thrown.
742    *
743    * @param zkw zk reference
744    * @param znode path of node
745    * @param data data to set for node
746    * @throws KeeperException if unexpected zookeeper exception
747    */
748   public static void setData(ZooKeeperWatcher zkw, String znode,
749       byte [] data)
750   throws KeeperException, KeeperException.NoNodeException {
751     setData(zkw, znode, data, -1);
752   }
753 
754   //
755   // Node creation
756   //
757 
758   /**
759    *
760    * Set the specified znode to be an ephemeral node carrying the specified
761    * data.
762    *
763    * If the node is created successfully, a watcher is also set on the node.
764    *
765    * If the node is not created successfully because it already exists, this
766    * method will also set a watcher on the node.
767    *
768    * If there is another problem, a KeeperException will be thrown.
769    *
770    * @param zkw zk reference
771    * @param znode path of node
772    * @param data data of node
773    * @return true if node created, false if not, watch set in both cases
774    * @throws KeeperException if unexpected zookeeper exception
775    */
776   public static boolean createEphemeralNodeAndWatch(ZooKeeperWatcher zkw,
777       String znode, byte [] data)
778   throws KeeperException {
779     try {
780       zkw.getZooKeeper().create(znode, data, Ids.OPEN_ACL_UNSAFE,
781           CreateMode.EPHEMERAL);
782     } catch (KeeperException.NodeExistsException nee) {
783       if(!watchAndCheckExists(zkw, znode)) {
784         // It did exist but now it doesn't, try again
785         return createEphemeralNodeAndWatch(zkw, znode, data);
786       }
787       return false;
788     } catch (InterruptedException e) {
789       LOG.info("Interrupted", e);
790       Thread.currentThread().interrupt();
791     }
792     return true;
793   }
794 
795   /**
796    * Creates the specified znode to be a persistent node carrying the specified
797    * data.
798    *
799    * Returns true if the node was successfully created, false if the node
800    * already existed.
801    *
802    * If the node is created successfully, a watcher is also set on the node.
803    *
804    * If the node is not created successfully because it already exists, this
805    * method will also set a watcher on the node but return false.
806    *
807    * If there is another problem, a KeeperException will be thrown.
808    *
809    * @param zkw zk reference
810    * @param znode path of node
811    * @param data data of node
812    * @return true if node created, false if not, watch set in both cases
813    * @throws KeeperException if unexpected zookeeper exception
814    */
815   public static boolean createNodeIfNotExistsAndWatch(
816       ZooKeeperWatcher zkw, String znode, byte [] data)
817   throws KeeperException {
818     try {
819       zkw.getZooKeeper().create(znode, data, Ids.OPEN_ACL_UNSAFE,
820           CreateMode.PERSISTENT);
821     } catch (KeeperException.NodeExistsException nee) {
822       try {
823         zkw.getZooKeeper().exists(znode, zkw);
824       } catch (InterruptedException e) {
825         zkw.interruptedException(e);
826         return false;
827       }
828       return false;
829     } catch (InterruptedException e) {
830       zkw.interruptedException(e);
831       return false;
832     }
833     return true;
834   }
835 
836   /**
837    * Creates the specified node with the specified data and watches it.
838    *
839    * <p>Throws an exception if the node already exists.
840    *
841    * <p>The node created is persistent and open access.
842    *
843    * <p>Returns the version number of the created node if successful.
844    *
845    * @param zkw zk reference
846    * @param znode path of node to create
847    * @param data data of node to create
848    * @return version of node created
849    * @throws KeeperException if unexpected zookeeper exception
850    * @throws KeeperException.NodeExistsException if node already exists
851    */
852   public static int createAndWatch(ZooKeeperWatcher zkw,
853       String znode, byte [] data)
854   throws KeeperException, KeeperException.NodeExistsException {
855     try {
856       zkw.getZooKeeper().create(znode, data, Ids.OPEN_ACL_UNSAFE,
857           CreateMode.PERSISTENT);
858       return zkw.getZooKeeper().exists(znode, zkw).getVersion();
859     } catch (InterruptedException e) {
860       zkw.interruptedException(e);
861       return -1;
862     }
863   }
864 
865   /**
866    * Async creates the specified node with the specified data.
867    *
868    * <p>Throws an exception if the node already exists.
869    *
870    * <p>The node created is persistent and open access.
871    *
872    * @param zkw zk reference
873    * @param znode path of node to create
874    * @param data data of node to create
875    * @param cb
876    * @param ctx
877    * @throws KeeperException if unexpected zookeeper exception
878    * @throws KeeperException.NodeExistsException if node already exists
879    */
880   public static void asyncCreate(ZooKeeperWatcher zkw,
881       String znode, byte [] data, final AsyncCallback.StringCallback cb,
882       final Object ctx)
883   throws KeeperException, KeeperException.NodeExistsException {
884     zkw.getZooKeeper().create(znode, data, Ids.OPEN_ACL_UNSAFE,
885        CreateMode.PERSISTENT, cb, ctx);
886   }
887 
888   /**
889    * Creates the specified node, if the node does not exist.  Does not set a
890    * watch and fails silently if the node already exists.
891    *
892    * The node created is persistent and open access.
893    *
894    * @param zkw zk reference
895    * @param znode path of node
896    * @throws KeeperException if unexpected zookeeper exception
897    */
898   public static void createAndFailSilent(ZooKeeperWatcher zkw,
899       String znode)
900   throws KeeperException {
901     try {
902       ZooKeeper zk = zkw.getZooKeeper();
903       if (zk.exists(znode, false) == null) {
904         zk.create(znode, new byte[0], Ids.OPEN_ACL_UNSAFE,
905             CreateMode.PERSISTENT);
906       }
907     } catch(KeeperException.NodeExistsException nee) {
908     } catch(InterruptedException ie) {
909       zkw.interruptedException(ie);
910     }
911   }
912 
913   /**
914    * Creates the specified node and all parent nodes required for it to exist.
915    *
916    * No watches are set and no errors are thrown if the node already exists.
917    *
918    * The nodes created are persistent and open access.
919    *
920    * @param zkw zk reference
921    * @param znode path of node
922    * @throws KeeperException if unexpected zookeeper exception
923    */
924   public static void createWithParents(ZooKeeperWatcher zkw, String znode)
925   throws KeeperException {
926     try {
927       if(znode == null) {
928         return;
929       }
930       zkw.getZooKeeper().create(znode, new byte[0], Ids.OPEN_ACL_UNSAFE,
931           CreateMode.PERSISTENT);
932     } catch(KeeperException.NodeExistsException nee) {
933       return;
934     } catch(KeeperException.NoNodeException nne) {
935       createWithParents(zkw, getParent(znode));
936       createWithParents(zkw, znode);
937     } catch(InterruptedException ie) {
938       zkw.interruptedException(ie);
939     }
940   }
941 
942   //
943   // Deletes
944   //
945 
946   /**
947    * Delete the specified node.  Sets no watches.  Throws all exceptions.
948    */
949   public static void deleteNode(ZooKeeperWatcher zkw, String node)
950   throws KeeperException {
951     deleteNode(zkw, node, -1);
952   }
953 
954   /**
955    * Delete the specified node with the specified version.  Sets no watches.
956    * Throws all exceptions.
957    */
958   public static boolean deleteNode(ZooKeeperWatcher zkw, String node,
959       int version)
960   throws KeeperException {
961     try {
962       zkw.getZooKeeper().delete(node, version);
963       return true;
964     } catch(KeeperException.BadVersionException bve) {
965       return false;
966     } catch(InterruptedException ie) {
967       zkw.interruptedException(ie);
968       return false;
969     }
970   }
971 
972   /**
973    * Deletes the specified node.  Fails silent if the node does not exist.
974    * @param zkw
975    * @param node
976    * @throws KeeperException
977    */
978   public static void deleteNodeFailSilent(ZooKeeperWatcher zkw, String node)
979   throws KeeperException {
980     try {
981       zkw.getZooKeeper().delete(node, -1);
982     } catch(KeeperException.NoNodeException nne) {
983     } catch(InterruptedException ie) {
984       zkw.interruptedException(ie);
985     }
986   }
987 
988   /**
989    * Delete the specified node and all of it's children.
990    *
991    * Sets no watches.  Throws all exceptions besides dealing with deletion of
992    * children.
993    */
994   public static void deleteNodeRecursively(ZooKeeperWatcher zkw, String node)
995   throws KeeperException {
996     try {
997       List<String> children = ZKUtil.listChildrenNoWatch(zkw, node);
998       if(!children.isEmpty()) {
999         for(String child : children) {
1000           deleteNodeRecursively(zkw, joinZNode(node, child));
1001         }
1002       }
1003       zkw.getZooKeeper().delete(node, -1);
1004     } catch(InterruptedException ie) {
1005       zkw.interruptedException(ie);
1006     }
1007   }
1008 
1009   /**
1010    * Delete all the children of the specified node but not the node itself.
1011    *
1012    * Sets no watches.  Throws all exceptions besides dealing with deletion of
1013    * children.
1014    */
1015   public static void deleteChildrenRecursively(ZooKeeperWatcher zkw, String node)
1016   throws KeeperException {
1017     List<String> children = ZKUtil.listChildrenNoWatch(zkw, node);
1018     if (children == null || children.isEmpty()) return;
1019     for(String child : children) {
1020       deleteNodeRecursively(zkw, joinZNode(node, child));
1021     }
1022   }
1023 
1024   //
1025   // ZooKeeper cluster information
1026   //
1027 
1028   /** @return String dump of everything in ZooKeeper. */
1029   public static String dump(ZooKeeperWatcher zkw) {
1030     StringBuilder sb = new StringBuilder();
1031     try {
1032       sb.append("HBase is rooted at ").append(zkw.baseZNode);
1033       sb.append("\nMaster address: ").append(
1034           getDataAsAddress(zkw, zkw.masterAddressZNode));
1035       sb.append("\nRegion server holding ROOT: ").append(
1036           getDataAsAddress(zkw, zkw.rootServerZNode));
1037       sb.append("\nRegion servers:");
1038       for (HServerAddress address : listChildrenAndGetAsAddresses(zkw,
1039           zkw.rsZNode)) {
1040         sb.append("\n ").append(address);
1041       }
1042       sb.append("\nQuorum Server Statistics:");
1043       String[] servers = zkw.getQuorum().split(",");
1044       for (String server : servers) {
1045         sb.append("\n ").append(server);
1046         try {
1047           String[] stat = getServerStats(server);
1048           for (String s : stat) {
1049             sb.append("\n  ").append(s);
1050           }
1051         } catch (Exception e) {
1052           sb.append("\n  ERROR: ").append(e.getMessage());
1053         }
1054       }
1055     } catch(KeeperException ke) {
1056       sb.append("\nFATAL ZooKeeper Exception!\n");
1057       sb.append("\n" + ke.getMessage());
1058     }
1059     return sb.toString();
1060   }
1061 
1062   /**
1063    * Gets the statistics from the given server. Uses a 1 minute timeout.
1064    *
1065    * @param server  The server to get the statistics from.
1066    * @return The array of response strings.
1067    * @throws IOException When the socket communication fails.
1068    */
1069   public static String[] getServerStats(String server)
1070   throws IOException {
1071     return getServerStats(server, 60 * 1000);
1072   }
1073 
1074   /**
1075    * Gets the statistics from the given server.
1076    *
1077    * @param server  The server to get the statistics from.
1078    * @param timeout  The socket timeout to use.
1079    * @return The array of response strings.
1080    * @throws IOException When the socket communication fails.
1081    */
1082   public static String[] getServerStats(String server, int timeout)
1083   throws IOException {
1084     String[] sp = server.split(":");
1085     Socket socket = new Socket(sp[0],
1086       sp.length > 1 ? Integer.parseInt(sp[1]) : 2181);
1087     socket.setSoTimeout(timeout);
1088     PrintWriter out = new PrintWriter(socket.getOutputStream(), true);
1089     BufferedReader in = new BufferedReader(new InputStreamReader(
1090       socket.getInputStream()));
1091     out.println("stat");
1092     out.flush();
1093     ArrayList<String> res = new ArrayList<String>();
1094     while (true) {
1095       String line = in.readLine();
1096       if (line != null) {
1097         res.add(line);
1098       } else {
1099         break;
1100       }
1101     }
1102     socket.close();
1103     return res.toArray(new String[res.size()]);
1104   }
1105 
1106   private static void logRetrievedMsg(final ZooKeeperWatcher zkw,
1107       final String znode, final byte [] data, final boolean watcherSet) {
1108     if (!LOG.isDebugEnabled()) return;
1109     LOG.debug(zkw.prefix("Retrieved " + ((data == null)? 0: data.length) +
1110       " byte(s) of data from znode " + znode +
1111       (watcherSet? " and set watcher; ": "; data=") +
1112       (data == null? "null": (
1113           znode.startsWith(zkw.assignmentZNode) ?
1114               RegionTransitionData.fromBytes(data).toString()
1115               : StringUtils.abbreviate(Bytes.toStringBinary(data), 32)))));
1116   }
1117 }