001/* 002 * 003 * Licensed to the Apache Software Foundation (ASF) under one 004 * or more contributor license agreements. See the NOTICE file 005 * distributed with this work for additional information 006 * regarding copyright ownership. The ASF licenses this file 007 * to you under the Apache License, Version 2.0 (the 008 * "License"); you may not use this file except in compliance 009 * with the License. You may obtain a copy of the License at 010 * 011 * http://www.apache.org/licenses/LICENSE-2.0 012 * 013 * Unless required by applicable law or agreed to in writing, software 014 * distributed under the License is distributed on an "AS IS" BASIS, 015 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 016 * See the License for the specific language governing permissions and 017 * limitations under the License. 018 */ 019package org.apache.hadoop.hbase.zookeeper; 020 021import java.io.BufferedReader; 022import java.io.BufferedWriter; 023import java.io.IOException; 024import java.io.InputStreamReader; 025import java.io.OutputStreamWriter; 026import java.io.PrintWriter; 027import java.net.InetSocketAddress; 028import java.net.Socket; 029import java.nio.charset.StandardCharsets; 030import java.util.ArrayList; 031import java.util.Arrays; 032import java.util.Deque; 033import java.util.HashMap; 034import java.util.LinkedList; 035import java.util.List; 036import java.util.Map; 037 038import javax.security.auth.login.AppConfigurationEntry; 039import javax.security.auth.login.AppConfigurationEntry.LoginModuleControlFlag; 040 041import org.apache.commons.lang3.StringUtils; 042import org.apache.hadoop.conf.Configuration; 043import org.apache.hadoop.hbase.AuthUtil; 044import org.apache.hadoop.hbase.HBaseConfiguration; 045import org.apache.hadoop.hbase.HConstants; 046import org.apache.hadoop.hbase.exceptions.DeserializationException; 047import org.apache.hadoop.hbase.security.Superusers; 048import org.apache.hadoop.hbase.util.Bytes; 049import org.apache.hadoop.hbase.util.Threads; 050import org.apache.hadoop.hbase.zookeeper.ZKUtil.ZKUtilOp.CreateAndFailSilent; 051import org.apache.hadoop.hbase.zookeeper.ZKUtil.ZKUtilOp.DeleteNodeFailSilent; 052import org.apache.hadoop.hbase.zookeeper.ZKUtil.ZKUtilOp.SetData; 053import org.apache.hadoop.security.SecurityUtil; 054import org.apache.hadoop.security.UserGroupInformation; 055import org.apache.hadoop.security.authentication.util.KerberosUtil; 056import org.apache.yetus.audience.InterfaceAudience; 057import org.apache.zookeeper.AsyncCallback; 058import org.apache.zookeeper.CreateMode; 059import org.apache.zookeeper.KeeperException; 060import org.apache.zookeeper.KeeperException.NoNodeException; 061import org.apache.zookeeper.Op; 062import org.apache.zookeeper.Watcher; 063import org.apache.zookeeper.ZooDefs.Ids; 064import org.apache.zookeeper.ZooDefs.Perms; 065import org.apache.zookeeper.ZooKeeper; 066import org.apache.zookeeper.client.ZooKeeperSaslClient; 067import org.apache.zookeeper.data.ACL; 068import org.apache.zookeeper.data.Id; 069import org.apache.zookeeper.data.Stat; 070import org.apache.zookeeper.proto.CreateRequest; 071import org.apache.zookeeper.proto.DeleteRequest; 072import org.apache.zookeeper.proto.SetDataRequest; 073import org.apache.zookeeper.server.ZooKeeperSaslServer; 074import org.slf4j.Logger; 075import org.slf4j.LoggerFactory; 076 077import org.apache.hbase.thirdparty.com.google.protobuf.InvalidProtocolBufferException; 078import org.apache.hadoop.hbase.shaded.protobuf.ProtobufUtil; 079import org.apache.hadoop.hbase.shaded.protobuf.generated.ReplicationProtos; 080 081/** 082 * Internal HBase utility class for ZooKeeper. 083 * 084 * <p>Contains only static methods and constants. 085 * 086 * <p>Methods all throw {@link KeeperException} if there is an unexpected 087 * zookeeper exception, so callers of these methods must handle appropriately. 088 * If ZK is required for the operation, the server will need to be aborted. 089 */ 090@InterfaceAudience.Private 091public final class ZKUtil { 092 private static final Logger LOG = LoggerFactory.getLogger(ZKUtil.class); 093 094 private static int zkDumpConnectionTimeOut; 095 096 private ZKUtil() { 097 } 098 099 /** 100 * Creates a new connection to ZooKeeper, pulling settings and ensemble config 101 * from the specified configuration object using methods from {@link ZKConfig}. 102 * 103 * Sets the connection status monitoring watcher to the specified watcher. 104 * 105 * @param conf configuration to pull ensemble and other settings from 106 * @param watcher watcher to monitor connection changes 107 * @return connection to zookeeper 108 * @throws IOException if unable to connect to zk or config problem 109 */ 110 public static RecoverableZooKeeper connect(Configuration conf, Watcher watcher) 111 throws IOException { 112 String ensemble = ZKConfig.getZKQuorumServersString(conf); 113 return connect(conf, ensemble, watcher); 114 } 115 116 public static RecoverableZooKeeper connect(Configuration conf, String ensemble, 117 Watcher watcher) 118 throws IOException { 119 return connect(conf, ensemble, watcher, null); 120 } 121 122 public static RecoverableZooKeeper connect(Configuration conf, String ensemble, 123 Watcher watcher, final String identifier) 124 throws IOException { 125 if(ensemble == null) { 126 throw new IOException("Unable to determine ZooKeeper ensemble"); 127 } 128 int timeout = conf.getInt(HConstants.ZK_SESSION_TIMEOUT, 129 HConstants.DEFAULT_ZK_SESSION_TIMEOUT); 130 if (LOG.isTraceEnabled()) { 131 LOG.trace(identifier + " opening connection to ZooKeeper ensemble=" + ensemble); 132 } 133 int retry = conf.getInt("zookeeper.recovery.retry", 3); 134 int retryIntervalMillis = 135 conf.getInt("zookeeper.recovery.retry.intervalmill", 1000); 136 int maxSleepTime = conf.getInt("zookeeper.recovery.retry.maxsleeptime", 60000); 137 zkDumpConnectionTimeOut = conf.getInt("zookeeper.dump.connection.timeout", 138 1000); 139 return new RecoverableZooKeeper(ensemble, timeout, watcher, 140 retry, retryIntervalMillis, maxSleepTime, identifier); 141 } 142 143 /** 144 * Log in the current zookeeper server process using the given configuration 145 * keys for the credential file and login principal. 146 * 147 * <p><strong>This is only applicable when running on secure hbase</strong> 148 * On regular HBase (without security features), this will safely be ignored. 149 * </p> 150 * 151 * @param conf The configuration data to use 152 * @param keytabFileKey Property key used to configure the path to the credential file 153 * @param userNameKey Property key used to configure the login principal 154 * @param hostname Current hostname to use in any credentials 155 * @throws IOException underlying exception from SecurityUtil.login() call 156 */ 157 public static void loginServer(Configuration conf, String keytabFileKey, 158 String userNameKey, String hostname) throws IOException { 159 login(conf, keytabFileKey, userNameKey, hostname, 160 ZooKeeperSaslServer.LOGIN_CONTEXT_NAME_KEY, 161 JaasConfiguration.SERVER_KEYTAB_KERBEROS_CONFIG_NAME); 162 } 163 164 /** 165 * Log in the current zookeeper client using the given configuration 166 * keys for the credential file and login principal. 167 * 168 * <p><strong>This is only applicable when running on secure hbase</strong> 169 * On regular HBase (without security features), this will safely be ignored. 170 * </p> 171 * 172 * @param conf The configuration data to use 173 * @param keytabFileKey Property key used to configure the path to the credential file 174 * @param userNameKey Property key used to configure the login principal 175 * @param hostname Current hostname to use in any credentials 176 * @throws IOException underlying exception from SecurityUtil.login() call 177 */ 178 public static void loginClient(Configuration conf, String keytabFileKey, 179 String userNameKey, String hostname) throws IOException { 180 login(conf, keytabFileKey, userNameKey, hostname, 181 ZooKeeperSaslClient.LOGIN_CONTEXT_NAME_KEY, 182 JaasConfiguration.CLIENT_KEYTAB_KERBEROS_CONFIG_NAME); 183 } 184 185 /** 186 * Log in the current process using the given configuration keys for the 187 * credential file and login principal. 188 * 189 * <p><strong>This is only applicable when running on secure hbase</strong> 190 * On regular HBase (without security features), this will safely be ignored. 191 * </p> 192 * 193 * @param conf The configuration data to use 194 * @param keytabFileKey Property key used to configure the path to the credential file 195 * @param userNameKey Property key used to configure the login principal 196 * @param hostname Current hostname to use in any credentials 197 * @param loginContextProperty property name to expose the entry name 198 * @param loginContextName jaas entry name 199 * @throws IOException underlying exception from SecurityUtil.login() call 200 */ 201 private static void login(Configuration conf, String keytabFileKey, 202 String userNameKey, String hostname, 203 String loginContextProperty, String loginContextName) 204 throws IOException { 205 if (!isSecureZooKeeper(conf)) { 206 return; 207 } 208 209 // User has specified a jaas.conf, keep this one as the good one. 210 // HBASE_OPTS="-Djava.security.auth.login.config=jaas.conf" 211 if (System.getProperty("java.security.auth.login.config") != null) { 212 return; 213 } 214 215 // No keytab specified, no auth 216 String keytabFilename = conf.get(keytabFileKey); 217 if (keytabFilename == null) { 218 LOG.warn("no keytab specified for: " + keytabFileKey); 219 return; 220 } 221 222 String principalConfig = conf.get(userNameKey, System.getProperty("user.name")); 223 String principalName = SecurityUtil.getServerPrincipal(principalConfig, hostname); 224 225 // Initialize the "jaas.conf" for keyTab/principal, 226 // If keyTab is not specified use the Ticket Cache. 227 // and set the zookeeper login context name. 228 JaasConfiguration jaasConf = new JaasConfiguration(loginContextName, 229 principalName, keytabFilename); 230 javax.security.auth.login.Configuration.setConfiguration(jaasConf); 231 System.setProperty(loginContextProperty, loginContextName); 232 } 233 234 /** 235 * A JAAS configuration that defines the login modules that we want to use for login. 236 */ 237 private static class JaasConfiguration extends javax.security.auth.login.Configuration { 238 private static final String SERVER_KEYTAB_KERBEROS_CONFIG_NAME = 239 "zookeeper-server-keytab-kerberos"; 240 private static final String CLIENT_KEYTAB_KERBEROS_CONFIG_NAME = 241 "zookeeper-client-keytab-kerberos"; 242 243 private static final Map<String, String> BASIC_JAAS_OPTIONS = new HashMap<>(); 244 static { 245 String jaasEnvVar = System.getenv("HBASE_JAAS_DEBUG"); 246 if (jaasEnvVar != null && "true".equalsIgnoreCase(jaasEnvVar)) { 247 BASIC_JAAS_OPTIONS.put("debug", "true"); 248 } 249 } 250 251 private static final Map<String,String> KEYTAB_KERBEROS_OPTIONS = new HashMap<>(); 252 static { 253 KEYTAB_KERBEROS_OPTIONS.put("doNotPrompt", "true"); 254 KEYTAB_KERBEROS_OPTIONS.put("storeKey", "true"); 255 KEYTAB_KERBEROS_OPTIONS.put("refreshKrb5Config", "true"); 256 KEYTAB_KERBEROS_OPTIONS.putAll(BASIC_JAAS_OPTIONS); 257 } 258 259 private static final AppConfigurationEntry KEYTAB_KERBEROS_LOGIN = 260 new AppConfigurationEntry(KerberosUtil.getKrb5LoginModuleName(), 261 LoginModuleControlFlag.REQUIRED, 262 KEYTAB_KERBEROS_OPTIONS); 263 264 private static final AppConfigurationEntry[] KEYTAB_KERBEROS_CONF = 265 new AppConfigurationEntry[]{KEYTAB_KERBEROS_LOGIN}; 266 267 private javax.security.auth.login.Configuration baseConfig; 268 private final String loginContextName; 269 private final boolean useTicketCache; 270 private final String keytabFile; 271 private final String principal; 272 273 public JaasConfiguration(String loginContextName, String principal, String keytabFile) { 274 this(loginContextName, principal, keytabFile, keytabFile == null || keytabFile.length() == 0); 275 } 276 277 private JaasConfiguration(String loginContextName, String principal, 278 String keytabFile, boolean useTicketCache) { 279 try { 280 this.baseConfig = javax.security.auth.login.Configuration.getConfiguration(); 281 } catch (SecurityException e) { 282 this.baseConfig = null; 283 } 284 this.loginContextName = loginContextName; 285 this.useTicketCache = useTicketCache; 286 this.keytabFile = keytabFile; 287 this.principal = principal; 288 LOG.info("JaasConfiguration loginContextName=" + loginContextName + 289 " principal=" + principal + " useTicketCache=" + useTicketCache + 290 " keytabFile=" + keytabFile); 291 } 292 293 @Override 294 public AppConfigurationEntry[] getAppConfigurationEntry(String appName) { 295 if (loginContextName.equals(appName)) { 296 if (!useTicketCache) { 297 KEYTAB_KERBEROS_OPTIONS.put("keyTab", keytabFile); 298 KEYTAB_KERBEROS_OPTIONS.put("useKeyTab", "true"); 299 } 300 KEYTAB_KERBEROS_OPTIONS.put("principal", principal); 301 KEYTAB_KERBEROS_OPTIONS.put("useTicketCache", useTicketCache ? "true" : "false"); 302 return KEYTAB_KERBEROS_CONF; 303 } 304 305 if (baseConfig != null) { 306 return baseConfig.getAppConfigurationEntry(appName); 307 } 308 309 return(null); 310 } 311 } 312 313 // 314 // Helper methods 315 // 316 /** 317 * Returns the full path of the immediate parent of the specified node. 318 * @param node path to get parent of 319 * @return parent of path, null if passed the root node or an invalid node 320 */ 321 public static String getParent(String node) { 322 int idx = node.lastIndexOf(ZNodePaths.ZNODE_PATH_SEPARATOR); 323 return idx <= 0 ? null : node.substring(0, idx); 324 } 325 326 /** 327 * Get the name of the current node from the specified fully-qualified path. 328 * @param path fully-qualified path 329 * @return name of the current node 330 */ 331 public static String getNodeName(String path) { 332 return path.substring(path.lastIndexOf("/")+1); 333 } 334 335 // 336 // Existence checks and watches 337 // 338 339 /** 340 * Watch the specified znode for delete/create/change events. The watcher is 341 * set whether or not the node exists. If the node already exists, the method 342 * returns true. If the node does not exist, the method returns false. 343 * 344 * @param zkw zk reference 345 * @param znode path of node to watch 346 * @return true if znode exists, false if does not exist or error 347 * @throws KeeperException if unexpected zookeeper exception 348 */ 349 public static boolean watchAndCheckExists(ZKWatcher zkw, String znode) 350 throws KeeperException { 351 try { 352 Stat s = zkw.getRecoverableZooKeeper().exists(znode, zkw); 353 boolean exists = s != null ? true : false; 354 if (exists) { 355 LOG.debug(zkw.prefix("Set watcher on existing znode=" + znode)); 356 } else { 357 LOG.debug(zkw.prefix("Set watcher on znode that does not yet exist, " + znode)); 358 } 359 return exists; 360 } catch (KeeperException e) { 361 LOG.warn(zkw.prefix("Unable to set watcher on znode " + znode), e); 362 zkw.keeperException(e); 363 return false; 364 } catch (InterruptedException e) { 365 LOG.warn(zkw.prefix("Unable to set watcher on znode " + znode), e); 366 zkw.interruptedException(e); 367 return false; 368 } 369 } 370 371 /** 372 * Watch the specified znode, but only if exists. Useful when watching 373 * for deletions. Uses .getData() (and handles NoNodeException) instead 374 * of .exists() to accomplish this, as .getData() will only set a watch if 375 * the znode exists. 376 * @param zkw zk reference 377 * @param znode path of node to watch 378 * @return true if the watch is set, false if node does not exists 379 * @throws KeeperException if unexpected zookeeper exception 380 */ 381 public static boolean setWatchIfNodeExists(ZKWatcher zkw, String znode) 382 throws KeeperException { 383 try { 384 zkw.getRecoverableZooKeeper().getData(znode, true, null); 385 return true; 386 } catch (NoNodeException e) { 387 return false; 388 } catch (InterruptedException e) { 389 LOG.warn(zkw.prefix("Unable to set watcher on znode " + znode), e); 390 zkw.interruptedException(e); 391 return false; 392 } 393 } 394 395 /** 396 * Check if the specified node exists. Sets no watches. 397 * 398 * @param zkw zk reference 399 * @param znode path of node to watch 400 * @return version of the node if it exists, -1 if does not exist 401 * @throws KeeperException if unexpected zookeeper exception 402 */ 403 public static int checkExists(ZKWatcher zkw, String znode) 404 throws KeeperException { 405 try { 406 Stat s = zkw.getRecoverableZooKeeper().exists(znode, null); 407 return s != null ? s.getVersion() : -1; 408 } catch (KeeperException e) { 409 LOG.warn(zkw.prefix("Unable to set watcher on znode (" + znode + ")"), e); 410 zkw.keeperException(e); 411 return -1; 412 } catch (InterruptedException e) { 413 LOG.warn(zkw.prefix("Unable to set watcher on znode (" + znode + ")"), e); 414 zkw.interruptedException(e); 415 return -1; 416 } 417 } 418 419 // 420 // Znode listings 421 // 422 423 /** 424 * Lists the children znodes of the specified znode. Also sets a watch on 425 * the specified znode which will capture a NodeDeleted event on the specified 426 * znode as well as NodeChildrenChanged if any children of the specified znode 427 * are created or deleted. 428 * 429 * Returns null if the specified node does not exist. Otherwise returns a 430 * list of children of the specified node. If the node exists but it has no 431 * children, an empty list will be returned. 432 * 433 * @param zkw zk reference 434 * @param znode path of node to list and watch children of 435 * @return list of children of the specified node, an empty list if the node 436 * exists but has no children, and null if the node does not exist 437 * @throws KeeperException if unexpected zookeeper exception 438 */ 439 public static List<String> listChildrenAndWatchForNewChildren( 440 ZKWatcher zkw, String znode) 441 throws KeeperException { 442 try { 443 List<String> children = zkw.getRecoverableZooKeeper().getChildren(znode, zkw); 444 return children; 445 } catch(KeeperException.NoNodeException ke) { 446 LOG.debug(zkw.prefix("Unable to list children of znode " + znode + " " + 447 "because node does not exist (not an error)")); 448 return null; 449 } catch (KeeperException e) { 450 LOG.warn(zkw.prefix("Unable to list children of znode " + znode + " "), e); 451 zkw.keeperException(e); 452 return null; 453 } catch (InterruptedException e) { 454 LOG.warn(zkw.prefix("Unable to list children of znode " + znode + " "), e); 455 zkw.interruptedException(e); 456 return null; 457 } 458 } 459 460 /** 461 * List all the children of the specified znode, setting a watch for children 462 * changes and also setting a watch on every individual child in order to get 463 * the NodeCreated and NodeDeleted events. 464 * @param zkw zookeeper reference 465 * @param znode node to get children of and watch 466 * @return list of znode names, null if the node doesn't exist 467 * @throws KeeperException if a ZooKeeper operation fails 468 */ 469 public static List<String> listChildrenAndWatchThem(ZKWatcher zkw, 470 String znode) throws KeeperException { 471 List<String> children = listChildrenAndWatchForNewChildren(zkw, znode); 472 if (children == null) { 473 return null; 474 } 475 for (String child : children) { 476 watchAndCheckExists(zkw, ZNodePaths.joinZNode(znode, child)); 477 } 478 return children; 479 } 480 481 /** 482 * Lists the children of the specified znode without setting any watches. 483 * 484 * Sets no watches at all, this method is best effort. 485 * 486 * Returns an empty list if the node has no children. Returns null if the 487 * parent node itself does not exist. 488 * 489 * @param zkw zookeeper reference 490 * @param znode node to get children 491 * @return list of data of children of specified znode, empty if no children, 492 * null if parent does not exist 493 * @throws KeeperException if unexpected zookeeper exception 494 */ 495 public static List<String> listChildrenNoWatch(ZKWatcher zkw, String znode) 496 throws KeeperException { 497 List<String> children = null; 498 try { 499 // List the children without watching 500 children = zkw.getRecoverableZooKeeper().getChildren(znode, null); 501 } catch(KeeperException.NoNodeException nne) { 502 return null; 503 } catch(InterruptedException ie) { 504 zkw.interruptedException(ie); 505 } 506 return children; 507 } 508 509 /** 510 * Simple class to hold a node path and node data. 511 * @deprecated Unused 512 */ 513 @Deprecated 514 public static class NodeAndData { 515 private String node; 516 private byte [] data; 517 public NodeAndData(String node, byte [] data) { 518 this.node = node; 519 this.data = data; 520 } 521 public String getNode() { 522 return node; 523 } 524 public byte [] getData() { 525 return data; 526 } 527 @Override 528 public String toString() { 529 return node; 530 } 531 public boolean isEmpty() { 532 return (data == null || data.length == 0); 533 } 534 } 535 536 /** 537 * Checks if the specified znode has any children. Sets no watches. 538 * 539 * Returns true if the node exists and has children. Returns false if the 540 * node does not exist or if the node does not have any children. 541 * 542 * Used during master initialization to determine if the master is a 543 * failed-over-to master or the first master during initial cluster startup. 544 * If the directory for regionserver ephemeral nodes is empty then this is 545 * a cluster startup, if not then it is not cluster startup. 546 * 547 * @param zkw zk reference 548 * @param znode path of node to check for children of 549 * @return true if node has children, false if not or node does not exist 550 * @throws KeeperException if unexpected zookeeper exception 551 */ 552 public static boolean nodeHasChildren(ZKWatcher zkw, String znode) 553 throws KeeperException { 554 try { 555 return !zkw.getRecoverableZooKeeper().getChildren(znode, null).isEmpty(); 556 } catch(KeeperException.NoNodeException ke) { 557 LOG.debug(zkw.prefix("Unable to list children of znode " + znode + 558 " because node does not exist (not an error)")); 559 return false; 560 } catch (KeeperException e) { 561 LOG.warn(zkw.prefix("Unable to list children of znode " + znode), e); 562 zkw.keeperException(e); 563 return false; 564 } catch (InterruptedException e) { 565 LOG.warn(zkw.prefix("Unable to list children of znode " + znode), e); 566 zkw.interruptedException(e); 567 return false; 568 } 569 } 570 571 /** 572 * Get the number of children of the specified node. 573 * 574 * If the node does not exist or has no children, returns 0. 575 * 576 * Sets no watches at all. 577 * 578 * @param zkw zk reference 579 * @param znode path of node to count children of 580 * @return number of children of specified node, 0 if none or parent does not 581 * exist 582 * @throws KeeperException if unexpected zookeeper exception 583 */ 584 public static int getNumberOfChildren(ZKWatcher zkw, String znode) 585 throws KeeperException { 586 try { 587 Stat stat = zkw.getRecoverableZooKeeper().exists(znode, null); 588 return stat == null ? 0 : stat.getNumChildren(); 589 } catch(KeeperException e) { 590 LOG.warn(zkw.prefix("Unable to get children of node " + znode)); 591 zkw.keeperException(e); 592 } catch(InterruptedException e) { 593 zkw.interruptedException(e); 594 } 595 return 0; 596 } 597 598 // 599 // Data retrieval 600 // 601 602 /** 603 * Get znode data. Does not set a watcher. 604 * 605 * @return ZNode data, null if the node does not exist or if there is an error. 606 */ 607 public static byte [] getData(ZKWatcher zkw, String znode) 608 throws KeeperException, InterruptedException { 609 try { 610 byte [] data = zkw.getRecoverableZooKeeper().getData(znode, null, null); 611 logRetrievedMsg(zkw, znode, data, false); 612 return data; 613 } catch (KeeperException.NoNodeException e) { 614 LOG.debug(zkw.prefix("Unable to get data of znode " + znode + " " + 615 "because node does not exist (not an error)")); 616 return null; 617 } catch (KeeperException e) { 618 LOG.warn(zkw.prefix("Unable to get data of znode " + znode), e); 619 zkw.keeperException(e); 620 return null; 621 } 622 } 623 624 /** 625 * Get the data at the specified znode and set a watch. 626 * 627 * Returns the data and sets a watch if the node exists. Returns null and no 628 * watch is set if the node does not exist or there is an exception. 629 * 630 * @param zkw zk reference 631 * @param znode path of node 632 * @return data of the specified znode, or null 633 * @throws KeeperException if unexpected zookeeper exception 634 */ 635 public static byte [] getDataAndWatch(ZKWatcher zkw, String znode) 636 throws KeeperException { 637 return getDataInternal(zkw, znode, null, true); 638 } 639 640 /** 641 * Get the data at the specified znode and set a watch. 642 * 643 * Returns the data and sets a watch if the node exists. Returns null and no 644 * watch is set if the node does not exist or there is an exception. 645 * 646 * @param zkw zk reference 647 * @param znode path of node 648 * @param stat object to populate the version of the znode 649 * @return data of the specified znode, or null 650 * @throws KeeperException if unexpected zookeeper exception 651 */ 652 public static byte[] getDataAndWatch(ZKWatcher zkw, String znode, 653 Stat stat) throws KeeperException { 654 return getDataInternal(zkw, znode, stat, true); 655 } 656 657 private static byte[] getDataInternal(ZKWatcher zkw, String znode, Stat stat, 658 boolean watcherSet) 659 throws KeeperException { 660 try { 661 byte [] data = zkw.getRecoverableZooKeeper().getData(znode, zkw, stat); 662 logRetrievedMsg(zkw, znode, data, watcherSet); 663 return data; 664 } catch (KeeperException.NoNodeException e) { 665 // This log can get pretty annoying when we cycle on 100ms waits. 666 // Enable trace if you really want to see it. 667 LOG.trace(zkw.prefix("Unable to get data of znode " + znode + " " + 668 "because node does not exist (not an error)")); 669 return null; 670 } catch (KeeperException e) { 671 LOG.warn(zkw.prefix("Unable to get data of znode " + znode), e); 672 zkw.keeperException(e); 673 return null; 674 } catch (InterruptedException e) { 675 LOG.warn(zkw.prefix("Unable to get data of znode " + znode), e); 676 zkw.interruptedException(e); 677 return null; 678 } 679 } 680 681 /** 682 * Get the data at the specified znode without setting a watch. 683 * 684 * Returns the data if the node exists. Returns null if the node does not 685 * exist. 686 * 687 * Sets the stats of the node in the passed Stat object. Pass a null stat if 688 * not interested. 689 * 690 * @param zkw zk reference 691 * @param znode path of node 692 * @param stat node status to get if node exists 693 * @return data of the specified znode, or null if node does not exist 694 * @throws KeeperException if unexpected zookeeper exception 695 */ 696 public static byte [] getDataNoWatch(ZKWatcher zkw, String znode, 697 Stat stat) 698 throws KeeperException { 699 try { 700 byte [] data = zkw.getRecoverableZooKeeper().getData(znode, null, stat); 701 logRetrievedMsg(zkw, znode, data, false); 702 return data; 703 } catch (KeeperException.NoNodeException e) { 704 LOG.debug(zkw.prefix("Unable to get data of znode " + znode + " " + 705 "because node does not exist (not necessarily an error)")); 706 return null; 707 } catch (KeeperException e) { 708 LOG.warn(zkw.prefix("Unable to get data of znode " + znode), e); 709 zkw.keeperException(e); 710 return null; 711 } catch (InterruptedException e) { 712 LOG.warn(zkw.prefix("Unable to get data of znode " + znode), e); 713 zkw.interruptedException(e); 714 return null; 715 } 716 } 717 718 /** 719 * Returns the date of child znodes of the specified znode. Also sets a watch on 720 * the specified znode which will capture a NodeDeleted event on the specified 721 * znode as well as NodeChildrenChanged if any children of the specified znode 722 * are created or deleted. 723 * 724 * Returns null if the specified node does not exist. Otherwise returns a 725 * list of children of the specified node. If the node exists but it has no 726 * children, an empty list will be returned. 727 * 728 * @param zkw zk reference 729 * @param baseNode path of node to list and watch children of 730 * @return list of data of children of the specified node, an empty list if the node 731 * exists but has no children, and null if the node does not exist 732 * @throws KeeperException if unexpected zookeeper exception 733 * @deprecated Unused 734 */ 735 @Deprecated 736 public static List<NodeAndData> getChildDataAndWatchForNewChildren( 737 ZKWatcher zkw, String baseNode) throws KeeperException { 738 List<String> nodes = 739 ZKUtil.listChildrenAndWatchForNewChildren(zkw, baseNode); 740 if (nodes != null) { 741 List<NodeAndData> newNodes = new ArrayList<>(); 742 for (String node : nodes) { 743 String nodePath = ZNodePaths.joinZNode(baseNode, node); 744 byte[] data = ZKUtil.getDataAndWatch(zkw, nodePath); 745 newNodes.add(new NodeAndData(nodePath, data)); 746 } 747 return newNodes; 748 } 749 return null; 750 } 751 752 /** 753 * Update the data of an existing node with the expected version to have the 754 * specified data. 755 * 756 * Throws an exception if there is a version mismatch or some other problem. 757 * 758 * Sets no watches under any conditions. 759 * 760 * @param zkw zk reference 761 * @param znode the path to the ZNode 762 * @param data the data to store in ZooKeeper 763 * @param expectedVersion the expected version 764 * @throws KeeperException if unexpected zookeeper exception 765 * @throws KeeperException.BadVersionException if version mismatch 766 * @deprecated Unused 767 */ 768 @Deprecated 769 public static void updateExistingNodeData(ZKWatcher zkw, String znode, byte[] data, 770 int expectedVersion) throws KeeperException { 771 try { 772 zkw.getRecoverableZooKeeper().setData(znode, data, expectedVersion); 773 } catch(InterruptedException ie) { 774 zkw.interruptedException(ie); 775 } 776 } 777 778 // 779 // Data setting 780 // 781 782 /** 783 * Sets the data of the existing znode to be the specified data. Ensures that 784 * the current data has the specified expected version. 785 * 786 * <p>If the node does not exist, a {@link NoNodeException} will be thrown. 787 * 788 * <p>If their is a version mismatch, method returns null. 789 * 790 * <p>No watches are set but setting data will trigger other watchers of this 791 * node. 792 * 793 * <p>If there is another problem, a KeeperException will be thrown. 794 * 795 * @param zkw zk reference 796 * @param znode path of node 797 * @param data data to set for node 798 * @param expectedVersion version expected when setting data 799 * @return true if data set, false if version mismatch 800 * @throws KeeperException if unexpected zookeeper exception 801 */ 802 public static boolean setData(ZKWatcher zkw, String znode, 803 byte [] data, int expectedVersion) 804 throws KeeperException, KeeperException.NoNodeException { 805 try { 806 return zkw.getRecoverableZooKeeper().setData(znode, data, expectedVersion) != null; 807 } catch (InterruptedException e) { 808 zkw.interruptedException(e); 809 return false; 810 } 811 } 812 813 /** 814 * Set data into node creating node if it doesn't yet exist. 815 * Does not set watch. 816 * 817 * @param zkw zk reference 818 * @param znode path of node 819 * @param data data to set for node 820 * @throws KeeperException if a ZooKeeper operation fails 821 */ 822 public static void createSetData(final ZKWatcher zkw, final String znode, final byte [] data) 823 throws KeeperException { 824 if (checkExists(zkw, znode) == -1) { 825 ZKUtil.createWithParents(zkw, znode, data); 826 } else { 827 ZKUtil.setData(zkw, znode, data); 828 } 829 } 830 831 /** 832 * Sets the data of the existing znode to be the specified data. The node 833 * must exist but no checks are done on the existing data or version. 834 * 835 * <p>If the node does not exist, a {@link NoNodeException} will be thrown. 836 * 837 * <p>No watches are set but setting data will trigger other watchers of this 838 * node. 839 * 840 * <p>If there is another problem, a KeeperException will be thrown. 841 * 842 * @param zkw zk reference 843 * @param znode path of node 844 * @param data data to set for node 845 * @throws KeeperException if unexpected zookeeper exception 846 */ 847 public static void setData(ZKWatcher zkw, String znode, byte [] data) 848 throws KeeperException, KeeperException.NoNodeException { 849 setData(zkw, (SetData)ZKUtilOp.setData(znode, data)); 850 } 851 852 private static void setData(ZKWatcher zkw, SetData setData) 853 throws KeeperException, KeeperException.NoNodeException { 854 SetDataRequest sd = (SetDataRequest)toZooKeeperOp(zkw, setData).toRequestRecord(); 855 setData(zkw, sd.getPath(), sd.getData(), sd.getVersion()); 856 } 857 858 /** 859 * Returns whether or not secure authentication is enabled 860 * (whether <code>hbase.security.authentication</code> is set to 861 * <code>kerberos</code>. 862 */ 863 public static boolean isSecureZooKeeper(Configuration conf) { 864 // Detection for embedded HBase client with jaas configuration 865 // defined for third party programs. 866 try { 867 javax.security.auth.login.Configuration testConfig = 868 javax.security.auth.login.Configuration.getConfiguration(); 869 if (testConfig.getAppConfigurationEntry("Client") == null 870 && testConfig.getAppConfigurationEntry( 871 JaasConfiguration.CLIENT_KEYTAB_KERBEROS_CONFIG_NAME) == null 872 && testConfig.getAppConfigurationEntry( 873 JaasConfiguration.SERVER_KEYTAB_KERBEROS_CONFIG_NAME) == null 874 && conf.get(HConstants.ZK_CLIENT_KERBEROS_PRINCIPAL) == null 875 && conf.get(HConstants.ZK_SERVER_KERBEROS_PRINCIPAL) == null) { 876 877 return false; 878 } 879 } catch(Exception e) { 880 // No Jaas configuration defined. 881 return false; 882 } 883 884 // Master & RSs uses hbase.zookeeper.client.* 885 return "kerberos".equalsIgnoreCase(conf.get("hbase.security.authentication")); 886 } 887 888 private static ArrayList<ACL> createACL(ZKWatcher zkw, String node) { 889 return createACL(zkw, node, isSecureZooKeeper(zkw.getConfiguration())); 890 } 891 892 public static ArrayList<ACL> createACL(ZKWatcher zkw, String node, 893 boolean isSecureZooKeeper) { 894 if (!node.startsWith(zkw.getZNodePaths().baseZNode)) { 895 return Ids.OPEN_ACL_UNSAFE; 896 } 897 if (isSecureZooKeeper) { 898 ArrayList<ACL> acls = new ArrayList<>(); 899 // add permission to hbase supper user 900 String[] superUsers = zkw.getConfiguration().getStrings(Superusers.SUPERUSER_CONF_KEY); 901 String hbaseUser = null; 902 try { 903 hbaseUser = UserGroupInformation.getCurrentUser().getShortUserName(); 904 } catch (IOException e) { 905 LOG.debug("Could not acquire current User.", e); 906 } 907 if (superUsers != null) { 908 List<String> groups = new ArrayList<>(); 909 for (String user : superUsers) { 910 if (AuthUtil.isGroupPrincipal(user)) { 911 // TODO: Set node ACL for groups when ZK supports this feature 912 groups.add(user); 913 } else { 914 if(!user.equals(hbaseUser)) { 915 acls.add(new ACL(Perms.ALL, new Id("sasl", user))); 916 } 917 } 918 } 919 if (!groups.isEmpty()) { 920 LOG.warn("Znode ACL setting for group " + groups 921 + " is skipped, ZooKeeper doesn't support this feature presently."); 922 } 923 } 924 // Certain znodes are accessed directly by the client, 925 // so they must be readable by non-authenticated clients 926 if (zkw.getZNodePaths().isClientReadable(node)) { 927 acls.addAll(Ids.CREATOR_ALL_ACL); 928 acls.addAll(Ids.READ_ACL_UNSAFE); 929 } else { 930 acls.addAll(Ids.CREATOR_ALL_ACL); 931 } 932 return acls; 933 } else { 934 return Ids.OPEN_ACL_UNSAFE; 935 } 936 } 937 938 // 939 // Node creation 940 // 941 942 /** 943 * 944 * Set the specified znode to be an ephemeral node carrying the specified 945 * data. 946 * 947 * If the node is created successfully, a watcher is also set on the node. 948 * 949 * If the node is not created successfully because it already exists, this 950 * method will also set a watcher on the node. 951 * 952 * If there is another problem, a KeeperException will be thrown. 953 * 954 * @param zkw zk reference 955 * @param znode path of node 956 * @param data data of node 957 * @return true if node created, false if not, watch set in both cases 958 * @throws KeeperException if unexpected zookeeper exception 959 */ 960 public static boolean createEphemeralNodeAndWatch(ZKWatcher zkw, 961 String znode, byte [] data) 962 throws KeeperException { 963 boolean ret = true; 964 try { 965 zkw.getRecoverableZooKeeper().create(znode, data, createACL(zkw, znode), 966 CreateMode.EPHEMERAL); 967 } catch (KeeperException.NodeExistsException nee) { 968 ret = false; 969 } catch (InterruptedException e) { 970 LOG.info("Interrupted", e); 971 Thread.currentThread().interrupt(); 972 } 973 if(!watchAndCheckExists(zkw, znode)) { 974 // It did exist but now it doesn't, try again 975 return createEphemeralNodeAndWatch(zkw, znode, data); 976 } 977 return ret; 978 } 979 980 /** 981 * Creates the specified znode to be a persistent node carrying the specified 982 * data. 983 * 984 * Returns true if the node was successfully created, false if the node 985 * already existed. 986 * 987 * If the node is created successfully, a watcher is also set on the node. 988 * 989 * If the node is not created successfully because it already exists, this 990 * method will also set a watcher on the node but return false. 991 * 992 * If there is another problem, a KeeperException will be thrown. 993 * 994 * @param zkw zk reference 995 * @param znode path of node 996 * @param data data of node 997 * @return true if node created, false if not, watch set in both cases 998 * @throws KeeperException if unexpected zookeeper exception 999 */ 1000 public static boolean createNodeIfNotExistsAndWatch( 1001 ZKWatcher zkw, String znode, byte [] data) 1002 throws KeeperException { 1003 boolean ret = true; 1004 try { 1005 zkw.getRecoverableZooKeeper().create(znode, data, createACL(zkw, znode), 1006 CreateMode.PERSISTENT); 1007 } catch (KeeperException.NodeExistsException nee) { 1008 ret = false; 1009 } catch (InterruptedException e) { 1010 zkw.interruptedException(e); 1011 return false; 1012 } 1013 try { 1014 zkw.getRecoverableZooKeeper().exists(znode, zkw); 1015 } catch (InterruptedException e) { 1016 zkw.interruptedException(e); 1017 return false; 1018 } 1019 return ret; 1020 } 1021 1022 /** 1023 * Creates the specified znode with the specified data but does not watch it. 1024 * 1025 * Returns the znode of the newly created node 1026 * 1027 * If there is another problem, a KeeperException will be thrown. 1028 * 1029 * @param zkw zk reference 1030 * @param znode path of node 1031 * @param data data of node 1032 * @param createMode specifying whether the node to be created is ephemeral and/or sequential 1033 * @return true name of the newly created znode or null 1034 * @throws KeeperException if unexpected zookeeper exception 1035 */ 1036 public static String createNodeIfNotExistsNoWatch(ZKWatcher zkw, String znode, byte[] data, 1037 CreateMode createMode) throws KeeperException { 1038 String createdZNode = null; 1039 try { 1040 createdZNode = zkw.getRecoverableZooKeeper().create(znode, data, 1041 createACL(zkw, znode), createMode); 1042 } catch (KeeperException.NodeExistsException nee) { 1043 return znode; 1044 } catch (InterruptedException e) { 1045 zkw.interruptedException(e); 1046 return null; 1047 } 1048 return createdZNode; 1049 } 1050 1051 /** 1052 * Creates the specified node with the specified data and watches it. 1053 * 1054 * <p>Throws an exception if the node already exists. 1055 * 1056 * <p>The node created is persistent and open access. 1057 * 1058 * <p>Returns the version number of the created node if successful. 1059 * 1060 * @param zkw zk reference 1061 * @param znode path of node to create 1062 * @param data data of node to create 1063 * @return version of node created 1064 * @throws KeeperException if unexpected zookeeper exception 1065 * @throws KeeperException.NodeExistsException if node already exists 1066 */ 1067 public static int createAndWatch(ZKWatcher zkw, 1068 String znode, byte [] data) 1069 throws KeeperException, KeeperException.NodeExistsException { 1070 try { 1071 zkw.getRecoverableZooKeeper().create(znode, data, createACL(zkw, znode), 1072 CreateMode.PERSISTENT); 1073 Stat stat = zkw.getRecoverableZooKeeper().exists(znode, zkw); 1074 if (stat == null){ 1075 // Likely a race condition. Someone deleted the znode. 1076 throw KeeperException.create(KeeperException.Code.SYSTEMERROR, 1077 "ZK.exists returned null (i.e.: znode does not exist) for znode=" + znode); 1078 } 1079 1080 return stat.getVersion(); 1081 } catch (InterruptedException e) { 1082 zkw.interruptedException(e); 1083 return -1; 1084 } 1085 } 1086 1087 /** 1088 * Async creates the specified node with the specified data. 1089 * 1090 * <p>Throws an exception if the node already exists. 1091 * 1092 * <p>The node created is persistent and open access. 1093 * 1094 * @param zkw zk reference 1095 * @param znode path of node to create 1096 * @param data data of node to create 1097 * @param cb the callback to use for the creation 1098 * @param ctx the context to use for the creation 1099 */ 1100 public static void asyncCreate(ZKWatcher zkw, 1101 String znode, byte [] data, final AsyncCallback.StringCallback cb, 1102 final Object ctx) { 1103 zkw.getRecoverableZooKeeper().getZooKeeper().create(znode, data, 1104 createACL(zkw, znode), CreateMode.PERSISTENT, cb, ctx); 1105 } 1106 1107 /** 1108 * Creates the specified node, iff the node does not exist. Does not set a 1109 * watch and fails silently if the node already exists. 1110 * 1111 * The node created is persistent and open access. 1112 * 1113 * @param zkw zk reference 1114 * @param znode path of node 1115 * @throws KeeperException if unexpected zookeeper exception 1116 */ 1117 public static void createAndFailSilent(ZKWatcher zkw, 1118 String znode) throws KeeperException { 1119 createAndFailSilent(zkw, znode, new byte[0]); 1120 } 1121 1122 /** 1123 * Creates the specified node containing specified data, iff the node does not exist. Does 1124 * not set a watch and fails silently if the node already exists. 1125 * 1126 * The node created is persistent and open access. 1127 * 1128 * @param zkw zk reference 1129 * @param znode path of node 1130 * @param data a byte array data to store in the znode 1131 * @throws KeeperException if unexpected zookeeper exception 1132 */ 1133 public static void createAndFailSilent(ZKWatcher zkw, 1134 String znode, byte[] data) 1135 throws KeeperException { 1136 createAndFailSilent(zkw, 1137 (CreateAndFailSilent)ZKUtilOp.createAndFailSilent(znode, data)); 1138 } 1139 1140 private static void createAndFailSilent(ZKWatcher zkw, CreateAndFailSilent cafs) 1141 throws KeeperException { 1142 CreateRequest create = (CreateRequest)toZooKeeperOp(zkw, cafs).toRequestRecord(); 1143 String znode = create.getPath(); 1144 try { 1145 RecoverableZooKeeper zk = zkw.getRecoverableZooKeeper(); 1146 if (zk.exists(znode, false) == null) { 1147 zk.create(znode, create.getData(), create.getAcl(), CreateMode.fromFlag(create.getFlags())); 1148 } 1149 } catch(KeeperException.NodeExistsException nee) { 1150 } catch(KeeperException.NoAuthException nee){ 1151 try { 1152 if (null == zkw.getRecoverableZooKeeper().exists(znode, false)) { 1153 // If we failed to create the file and it does not already exist. 1154 throw(nee); 1155 } 1156 } catch (InterruptedException ie) { 1157 zkw.interruptedException(ie); 1158 } 1159 } catch(InterruptedException ie) { 1160 zkw.interruptedException(ie); 1161 } 1162 } 1163 1164 /** 1165 * Creates the specified node and all parent nodes required for it to exist. 1166 * 1167 * No watches are set and no errors are thrown if the node already exists. 1168 * 1169 * The nodes created are persistent and open access. 1170 * 1171 * @param zkw zk reference 1172 * @param znode path of node 1173 * @throws KeeperException if unexpected zookeeper exception 1174 */ 1175 public static void createWithParents(ZKWatcher zkw, String znode) 1176 throws KeeperException { 1177 createWithParents(zkw, znode, new byte[0]); 1178 } 1179 1180 /** 1181 * Creates the specified node and all parent nodes required for it to exist. The creation of 1182 * parent znodes is not atomic with the leafe znode creation but the data is written atomically 1183 * when the leaf node is created. 1184 * 1185 * No watches are set and no errors are thrown if the node already exists. 1186 * 1187 * The nodes created are persistent and open access. 1188 * 1189 * @param zkw zk reference 1190 * @param znode path of node 1191 * @throws KeeperException if unexpected zookeeper exception 1192 */ 1193 public static void createWithParents(ZKWatcher zkw, String znode, byte[] data) 1194 throws KeeperException { 1195 try { 1196 if(znode == null) { 1197 return; 1198 } 1199 zkw.getRecoverableZooKeeper().create(znode, data, createACL(zkw, znode), 1200 CreateMode.PERSISTENT); 1201 } catch(KeeperException.NodeExistsException nee) { 1202 return; 1203 } catch(KeeperException.NoNodeException nne) { 1204 createWithParents(zkw, getParent(znode)); 1205 createWithParents(zkw, znode, data); 1206 } catch(InterruptedException ie) { 1207 zkw.interruptedException(ie); 1208 } 1209 } 1210 1211 // 1212 // Deletes 1213 // 1214 1215 /** 1216 * Delete the specified node. Sets no watches. Throws all exceptions. 1217 */ 1218 public static void deleteNode(ZKWatcher zkw, String node) 1219 throws KeeperException { 1220 deleteNode(zkw, node, -1); 1221 } 1222 1223 /** 1224 * Delete the specified node with the specified version. Sets no watches. 1225 * Throws all exceptions. 1226 */ 1227 public static boolean deleteNode(ZKWatcher zkw, String node, 1228 int version) 1229 throws KeeperException { 1230 try { 1231 zkw.getRecoverableZooKeeper().delete(node, version); 1232 return true; 1233 } catch(KeeperException.BadVersionException bve) { 1234 return false; 1235 } catch(InterruptedException ie) { 1236 zkw.interruptedException(ie); 1237 return false; 1238 } 1239 } 1240 1241 /** 1242 * Deletes the specified node. Fails silent if the node does not exist. 1243 * 1244 * @param zkw reference to the {@link ZKWatcher} which also contains configuration and operation 1245 * @param node the node to delete 1246 * @throws KeeperException if a ZooKeeper operation fails 1247 */ 1248 public static void deleteNodeFailSilent(ZKWatcher zkw, String node) 1249 throws KeeperException { 1250 deleteNodeFailSilent(zkw, 1251 (DeleteNodeFailSilent)ZKUtilOp.deleteNodeFailSilent(node)); 1252 } 1253 1254 private static void deleteNodeFailSilent(ZKWatcher zkw, 1255 DeleteNodeFailSilent dnfs) throws KeeperException { 1256 DeleteRequest delete = (DeleteRequest)toZooKeeperOp(zkw, dnfs).toRequestRecord(); 1257 try { 1258 zkw.getRecoverableZooKeeper().delete(delete.getPath(), delete.getVersion()); 1259 } catch(KeeperException.NoNodeException nne) { 1260 } catch(InterruptedException ie) { 1261 zkw.interruptedException(ie); 1262 } 1263 } 1264 1265 1266 /** 1267 * Delete the specified node and all of it's children. 1268 * <p> 1269 * If the node does not exist, just returns. 1270 * <p> 1271 * Sets no watches. Throws all exceptions besides dealing with deletion of 1272 * children. 1273 */ 1274 public static void deleteNodeRecursively(ZKWatcher zkw, String node) 1275 throws KeeperException { 1276 deleteNodeRecursivelyMultiOrSequential(zkw, true, node); 1277 } 1278 1279 /** 1280 * Delete all the children of the specified node but not the node itself. 1281 * 1282 * Sets no watches. Throws all exceptions besides dealing with deletion of 1283 * children. 1284 * 1285 * @throws KeeperException if a ZooKeeper operation fails 1286 */ 1287 public static void deleteChildrenRecursively(ZKWatcher zkw, String node) 1288 throws KeeperException { 1289 deleteChildrenRecursivelyMultiOrSequential(zkw, true, node); 1290 } 1291 1292 /** 1293 * Delete all the children of the specified node but not the node itself. This 1294 * will first traverse the znode tree for listing the children and then delete 1295 * these znodes using multi-update api or sequential based on the specified 1296 * configurations. 1297 * <p> 1298 * Sets no watches. Throws all exceptions besides dealing with deletion of 1299 * children. 1300 * <p> 1301 * If the following is true: 1302 * <ul> 1303 * <li>runSequentialOnMultiFailure is true 1304 * </ul> 1305 * on calling multi, we get a ZooKeeper exception that can be handled by a 1306 * sequential call(*), we retry the operations one-by-one (sequentially). 1307 * 1308 * @param zkw 1309 * - zk reference 1310 * @param runSequentialOnMultiFailure 1311 * - if true when we get a ZooKeeper exception that could retry the 1312 * operations one-by-one (sequentially) 1313 * @param pathRoots 1314 * - path of the parent node(s) 1315 * @throws KeeperException.NotEmptyException 1316 * if node has children while deleting 1317 * @throws KeeperException 1318 * if unexpected ZooKeeper exception 1319 * @throws IllegalArgumentException 1320 * if an invalid path is specified 1321 */ 1322 public static void deleteChildrenRecursivelyMultiOrSequential( 1323 ZKWatcher zkw, boolean runSequentialOnMultiFailure, 1324 String... pathRoots) throws KeeperException { 1325 if (pathRoots == null || pathRoots.length <= 0) { 1326 LOG.warn("Given path is not valid!"); 1327 return; 1328 } 1329 List<ZKUtilOp> ops = new ArrayList<>(); 1330 for (String eachRoot : pathRoots) { 1331 List<String> children = listChildrenBFSNoWatch(zkw, eachRoot); 1332 // Delete the leaves first and eventually get rid of the root 1333 for (int i = children.size() - 1; i >= 0; --i) { 1334 ops.add(ZKUtilOp.deleteNodeFailSilent(children.get(i))); 1335 } 1336 } 1337 // atleast one element should exist 1338 if (ops.size() > 0) { 1339 multiOrSequential(zkw, ops, runSequentialOnMultiFailure); 1340 } 1341 } 1342 1343 /** 1344 * Delete the specified node and its children. This traverse the 1345 * znode tree for listing the children and then delete 1346 * these znodes including the parent using multi-update api or 1347 * sequential based on the specified configurations. 1348 * <p> 1349 * Sets no watches. Throws all exceptions besides dealing with deletion of 1350 * children. 1351 * <p> 1352 * If the following is true: 1353 * <ul> 1354 * <li>runSequentialOnMultiFailure is true 1355 * </ul> 1356 * on calling multi, we get a ZooKeeper exception that can be handled by a 1357 * sequential call(*), we retry the operations one-by-one (sequentially). 1358 * 1359 * @param zkw 1360 * - zk reference 1361 * @param runSequentialOnMultiFailure 1362 * - if true when we get a ZooKeeper exception that could retry the 1363 * operations one-by-one (sequentially) 1364 * @param pathRoots 1365 * - path of the parent node(s) 1366 * @throws KeeperException.NotEmptyException 1367 * if node has children while deleting 1368 * @throws KeeperException 1369 * if unexpected ZooKeeper exception 1370 * @throws IllegalArgumentException 1371 * if an invalid path is specified 1372 */ 1373 public static void deleteNodeRecursivelyMultiOrSequential(ZKWatcher zkw, 1374 boolean runSequentialOnMultiFailure, String... pathRoots) throws KeeperException { 1375 if (pathRoots == null || pathRoots.length <= 0) { 1376 LOG.warn("Given path is not valid!"); 1377 return; 1378 } 1379 List<ZKUtilOp> ops = new ArrayList<>(); 1380 for (String eachRoot : pathRoots) { 1381 // ZooKeeper Watches are one time triggers; When children of parent nodes are deleted 1382 // recursively, must set another watch, get notified of delete node 1383 List<String> children = listChildrenBFSAndWatchThem(zkw, eachRoot); 1384 // Delete the leaves first and eventually get rid of the root 1385 for (int i = children.size() - 1; i >= 0; --i) { 1386 ops.add(ZKUtilOp.deleteNodeFailSilent(children.get(i))); 1387 } 1388 try { 1389 if (zkw.getRecoverableZooKeeper().exists(eachRoot, zkw) != null) { 1390 ops.add(ZKUtilOp.deleteNodeFailSilent(eachRoot)); 1391 } 1392 } catch (InterruptedException e) { 1393 zkw.interruptedException(e); 1394 } 1395 } 1396 // atleast one element should exist 1397 if (ops.size() > 0) { 1398 multiOrSequential(zkw, ops, runSequentialOnMultiFailure); 1399 } 1400 } 1401 1402 /** 1403 * BFS Traversal of all the children under path, with the entries in the list, 1404 * in the same order as that of the traversal. Lists all the children without 1405 * setting any watches. 1406 * 1407 * @param zkw 1408 * - zk reference 1409 * @param znode 1410 * - path of node 1411 * @return list of children znodes under the path 1412 * @throws KeeperException 1413 * if unexpected ZooKeeper exception 1414 */ 1415 private static List<String> listChildrenBFSNoWatch(ZKWatcher zkw, 1416 final String znode) throws KeeperException { 1417 Deque<String> queue = new LinkedList<>(); 1418 List<String> tree = new ArrayList<>(); 1419 queue.add(znode); 1420 while (true) { 1421 String node = queue.pollFirst(); 1422 if (node == null) { 1423 break; 1424 } 1425 List<String> children = listChildrenNoWatch(zkw, node); 1426 if (children == null) { 1427 continue; 1428 } 1429 for (final String child : children) { 1430 final String childPath = node + "/" + child; 1431 queue.add(childPath); 1432 tree.add(childPath); 1433 } 1434 } 1435 return tree; 1436 } 1437 1438 /** 1439 * BFS Traversal of all the children under path, with the entries in the list, 1440 * in the same order as that of the traversal. 1441 * Lists all the children and set watches on to them. 1442 * 1443 * @param zkw 1444 * - zk reference 1445 * @param znode 1446 * - path of node 1447 * @return list of children znodes under the path 1448 * @throws KeeperException 1449 * if unexpected ZooKeeper exception 1450 */ 1451 private static List<String> listChildrenBFSAndWatchThem(ZKWatcher zkw, final String znode) 1452 throws KeeperException { 1453 Deque<String> queue = new LinkedList<>(); 1454 List<String> tree = new ArrayList<>(); 1455 queue.add(znode); 1456 while (true) { 1457 String node = queue.pollFirst(); 1458 if (node == null) { 1459 break; 1460 } 1461 List<String> children = listChildrenAndWatchThem(zkw, node); 1462 if (children == null) { 1463 continue; 1464 } 1465 for (final String child : children) { 1466 final String childPath = node + "/" + child; 1467 queue.add(childPath); 1468 tree.add(childPath); 1469 } 1470 } 1471 return tree; 1472 } 1473 1474 /** 1475 * Represents an action taken by ZKUtil, e.g. createAndFailSilent. 1476 * These actions are higher-level than ZKOp actions, which represent 1477 * individual actions in the ZooKeeper API, like create. 1478 */ 1479 public abstract static class ZKUtilOp { 1480 private String path; 1481 1482 private ZKUtilOp(String path) { 1483 this.path = path; 1484 } 1485 1486 /** 1487 * @return a createAndFailSilent ZKUtilOp 1488 */ 1489 public static ZKUtilOp createAndFailSilent(String path, byte[] data) { 1490 return new CreateAndFailSilent(path, data); 1491 } 1492 1493 /** 1494 * @return a deleteNodeFailSilent ZKUtilOP 1495 */ 1496 public static ZKUtilOp deleteNodeFailSilent(String path) { 1497 return new DeleteNodeFailSilent(path); 1498 } 1499 1500 /** 1501 * @return a setData ZKUtilOp 1502 */ 1503 public static ZKUtilOp setData(String path, byte[] data) { 1504 return new SetData(path, data); 1505 } 1506 1507 /** 1508 * @return a setData ZKUtilOp 1509 */ 1510 public static ZKUtilOp setData(String path, byte[] data, int version) { 1511 return new SetData(path, data, version); 1512 } 1513 1514 /** 1515 * @return path to znode where the ZKOp will occur 1516 */ 1517 public String getPath() { 1518 return path; 1519 } 1520 1521 /** 1522 * ZKUtilOp representing createAndFailSilent in ZooKeeper 1523 * (attempt to create node, ignore error if already exists) 1524 */ 1525 public static final class CreateAndFailSilent extends ZKUtilOp { 1526 private byte [] data; 1527 1528 private CreateAndFailSilent(String path, byte [] data) { 1529 super(path); 1530 this.data = data; 1531 } 1532 1533 public byte[] getData() { 1534 return data; 1535 } 1536 1537 @Override 1538 public boolean equals(Object o) { 1539 if (this == o) { 1540 return true; 1541 } 1542 if (!(o instanceof CreateAndFailSilent)) { 1543 return false; 1544 } 1545 1546 CreateAndFailSilent op = (CreateAndFailSilent) o; 1547 return getPath().equals(op.getPath()) && Arrays.equals(data, op.data); 1548 } 1549 1550 @Override 1551 public int hashCode() { 1552 int ret = 17 + getPath().hashCode() * 31; 1553 return ret * 31 + Bytes.hashCode(data); 1554 } 1555 } 1556 1557 /** 1558 * ZKUtilOp representing deleteNodeFailSilent in ZooKeeper 1559 * (attempt to delete node, ignore error if node doesn't exist) 1560 */ 1561 public static final class DeleteNodeFailSilent extends ZKUtilOp { 1562 private DeleteNodeFailSilent(String path) { 1563 super(path); 1564 } 1565 1566 @Override 1567 public boolean equals(Object o) { 1568 if (this == o) { 1569 return true; 1570 } 1571 if (!(o instanceof DeleteNodeFailSilent)) { 1572 return false; 1573 } 1574 1575 return super.equals(o); 1576 } 1577 1578 @Override 1579 public int hashCode() { 1580 return getPath().hashCode(); 1581 } 1582 } 1583 1584 /** 1585 * ZKUtilOp representing setData in ZooKeeper 1586 */ 1587 public static final class SetData extends ZKUtilOp { 1588 private byte[] data; 1589 private int version = -1; 1590 1591 private SetData(String path, byte[] data) { 1592 super(path); 1593 this.data = data; 1594 } 1595 1596 private SetData(String path, byte[] data, int version) { 1597 super(path); 1598 this.data = data; 1599 this.version = version; 1600 } 1601 1602 public byte[] getData() { 1603 return data; 1604 } 1605 1606 public int getVersion() { 1607 return version; 1608 } 1609 1610 @Override 1611 public boolean equals(Object o) { 1612 if (this == o) { 1613 return true; 1614 } 1615 if (!(o instanceof SetData)) { 1616 return false; 1617 } 1618 1619 SetData op = (SetData) o; 1620 return getPath().equals(op.getPath()) && Arrays.equals(data, op.data) 1621 && getVersion() == op.getVersion(); 1622 } 1623 1624 @Override 1625 public int hashCode() { 1626 int ret = getPath().hashCode(); 1627 ret = ret * 31 + Bytes.hashCode(data); 1628 return ret * 31 + Integer.hashCode(version); 1629 } 1630 } 1631 } 1632 1633 /** 1634 * Convert from ZKUtilOp to ZKOp 1635 */ 1636 private static Op toZooKeeperOp(ZKWatcher zkw, ZKUtilOp op) throws UnsupportedOperationException { 1637 if(op == null) { 1638 return null; 1639 } 1640 1641 if (op instanceof CreateAndFailSilent) { 1642 CreateAndFailSilent cafs = (CreateAndFailSilent)op; 1643 return Op.create(cafs.getPath(), cafs.getData(), createACL(zkw, cafs.getPath()), 1644 CreateMode.PERSISTENT); 1645 } else if (op instanceof DeleteNodeFailSilent) { 1646 DeleteNodeFailSilent dnfs = (DeleteNodeFailSilent)op; 1647 return Op.delete(dnfs.getPath(), -1); 1648 } else if (op instanceof SetData) { 1649 SetData sd = (SetData) op; 1650 return Op.setData(sd.getPath(), sd.getData(), sd.getVersion()); 1651 } else { 1652 throw new UnsupportedOperationException("Unexpected ZKUtilOp type: " 1653 + op.getClass().getName()); 1654 } 1655 } 1656 1657 /** 1658 * Use ZooKeeper's multi-update functionality. 1659 * 1660 * If all of the following are true: 1661 * - runSequentialOnMultiFailure is true 1662 * - on calling multi, we get a ZooKeeper exception that can be handled by a sequential call(*) 1663 * Then: 1664 * - we retry the operations one-by-one (sequentially) 1665 * 1666 * Note *: an example is receiving a NodeExistsException from a "create" call. Without multi, 1667 * a user could call "createAndFailSilent" to ensure that a node exists if they don't care who 1668 * actually created the node (i.e. the NodeExistsException from ZooKeeper is caught). 1669 * This will cause all operations in the multi to fail, however, because 1670 * the NodeExistsException that zk.create throws will fail the multi transaction. 1671 * In this case, if the previous conditions hold, the commands are run sequentially, which should 1672 * result in the correct final state, but means that the operations will not run atomically. 1673 * 1674 * @throws KeeperException if a ZooKeeper operation fails 1675 */ 1676 public static void multiOrSequential(ZKWatcher zkw, List<ZKUtilOp> ops, 1677 boolean runSequentialOnMultiFailure) throws KeeperException { 1678 if (zkw.getConfiguration().get("hbase.zookeeper.useMulti") != null) { 1679 LOG.warn("hbase.zookeeper.useMulti is deprecated. Default to true always."); 1680 } 1681 if (ops == null) { 1682 return; 1683 } 1684 1685 List<Op> zkOps = new LinkedList<>(); 1686 for (ZKUtilOp op : ops) { 1687 zkOps.add(toZooKeeperOp(zkw, op)); 1688 } 1689 try { 1690 zkw.getRecoverableZooKeeper().multi(zkOps); 1691 } catch (KeeperException ke) { 1692 switch (ke.code()) { 1693 case NODEEXISTS: 1694 case NONODE: 1695 case BADVERSION: 1696 case NOAUTH: 1697 // if we get an exception that could be solved by running sequentially 1698 // (and the client asked us to), then break out and run sequentially 1699 if (runSequentialOnMultiFailure) { 1700 LOG.info("On call to ZK.multi, received exception: " + ke.toString() + "." 1701 + " Attempting to run operations sequentially because" 1702 + " runSequentialOnMultiFailure is: " + runSequentialOnMultiFailure + "."); 1703 processSequentially(zkw, ops); 1704 break; 1705 } 1706 default: 1707 throw ke; 1708 } 1709 } catch (InterruptedException ie) { 1710 zkw.interruptedException(ie); 1711 } 1712 } 1713 1714 private static void processSequentially(ZKWatcher zkw, List<ZKUtilOp> ops) 1715 throws KeeperException, NoNodeException { 1716 for (ZKUtilOp op : ops) { 1717 if (op instanceof CreateAndFailSilent) { 1718 createAndFailSilent(zkw, (CreateAndFailSilent) op); 1719 } else if (op instanceof DeleteNodeFailSilent) { 1720 deleteNodeFailSilent(zkw, (DeleteNodeFailSilent) op); 1721 } else if (op instanceof SetData) { 1722 setData(zkw, (SetData) op); 1723 } else { 1724 throw new UnsupportedOperationException("Unexpected ZKUtilOp type: " 1725 + op.getClass().getName()); 1726 } 1727 } 1728 } 1729 1730 // 1731 // ZooKeeper cluster information 1732 // 1733 1734 /** @return String dump of everything in ZooKeeper. */ 1735 public static String dump(ZKWatcher zkw) { 1736 StringBuilder sb = new StringBuilder(); 1737 try { 1738 sb.append("HBase is rooted at ").append(zkw.getZNodePaths().baseZNode); 1739 sb.append("\nActive master address: "); 1740 try { 1741 sb.append(MasterAddressTracker.getMasterAddress(zkw)); 1742 } catch (IOException e) { 1743 sb.append("<<FAILED LOOKUP: " + e.getMessage() + ">>"); 1744 } 1745 sb.append("\nBackup master addresses:"); 1746 for (String child : listChildrenNoWatch(zkw, 1747 zkw.getZNodePaths().backupMasterAddressesZNode)) { 1748 sb.append("\n ").append(child); 1749 } 1750 sb.append("\nRegion server holding hbase:meta: " 1751 + new MetaTableLocator().getMetaRegionLocation(zkw)); 1752 Configuration conf = HBaseConfiguration.create(); 1753 int numMetaReplicas = conf.getInt(HConstants.META_REPLICAS_NUM, 1754 HConstants.DEFAULT_META_REPLICA_NUM); 1755 for (int i = 1; i < numMetaReplicas; i++) { 1756 sb.append("\nRegion server holding hbase:meta, replicaId " + i + " " 1757 + new MetaTableLocator().getMetaRegionLocation(zkw, i)); 1758 } 1759 sb.append("\nRegion servers:"); 1760 for (String child : listChildrenNoWatch(zkw, zkw.getZNodePaths().rsZNode)) { 1761 sb.append("\n ").append(child); 1762 } 1763 try { 1764 getReplicationZnodesDump(zkw, sb); 1765 } catch (KeeperException ke) { 1766 LOG.warn("Couldn't get the replication znode dump", ke); 1767 } 1768 sb.append("\nQuorum Server Statistics:"); 1769 String[] servers = zkw.getQuorum().split(","); 1770 for (String server : servers) { 1771 sb.append("\n ").append(server); 1772 try { 1773 String[] stat = getServerStats(server, ZKUtil.zkDumpConnectionTimeOut); 1774 1775 if (stat == null) { 1776 sb.append("[Error] invalid quorum server: " + server); 1777 break; 1778 } 1779 1780 for (String s : stat) { 1781 sb.append("\n ").append(s); 1782 } 1783 } catch (Exception e) { 1784 sb.append("\n ERROR: ").append(e.getMessage()); 1785 } 1786 } 1787 } catch (KeeperException ke) { 1788 sb.append("\nFATAL ZooKeeper Exception!\n"); 1789 sb.append("\n" + ke.getMessage()); 1790 } 1791 return sb.toString(); 1792 } 1793 1794 /** 1795 * Appends replication znodes to the passed StringBuilder. 1796 * 1797 * @param zkw reference to the {@link ZKWatcher} which also contains configuration and operation 1798 * @param sb the {@link StringBuilder} to append to 1799 * @throws KeeperException if a ZooKeeper operation fails 1800 */ 1801 private static void getReplicationZnodesDump(ZKWatcher zkw, StringBuilder sb) 1802 throws KeeperException { 1803 String replicationZnode = zkw.getZNodePaths().replicationZNode; 1804 1805 if (ZKUtil.checkExists(zkw, replicationZnode) == -1) { 1806 return; 1807 } 1808 1809 // do a ls -r on this znode 1810 sb.append("\n").append(replicationZnode).append(": "); 1811 List<String> children = ZKUtil.listChildrenNoWatch(zkw, replicationZnode); 1812 for (String child : children) { 1813 String znode = ZNodePaths.joinZNode(replicationZnode, child); 1814 if (znode.equals(zkw.getZNodePaths().peersZNode)) { 1815 appendPeersZnodes(zkw, znode, sb); 1816 } else if (znode.equals(zkw.getZNodePaths().queuesZNode)) { 1817 appendRSZnodes(zkw, znode, sb); 1818 } else if (znode.equals(zkw.getZNodePaths().hfileRefsZNode)) { 1819 appendHFileRefsZnodes(zkw, znode, sb); 1820 } 1821 } 1822 } 1823 1824 private static void appendHFileRefsZnodes(ZKWatcher zkw, String hfileRefsZnode, 1825 StringBuilder sb) throws KeeperException { 1826 sb.append("\n").append(hfileRefsZnode).append(": "); 1827 for (String peerIdZnode : ZKUtil.listChildrenNoWatch(zkw, hfileRefsZnode)) { 1828 String znodeToProcess = ZNodePaths.joinZNode(hfileRefsZnode, peerIdZnode); 1829 sb.append("\n").append(znodeToProcess).append(": "); 1830 List<String> peerHFileRefsZnodes = ZKUtil.listChildrenNoWatch(zkw, znodeToProcess); 1831 int size = peerHFileRefsZnodes.size(); 1832 for (int i = 0; i < size; i++) { 1833 sb.append(peerHFileRefsZnodes.get(i)); 1834 if (i != size - 1) { 1835 sb.append(", "); 1836 } 1837 } 1838 } 1839 } 1840 1841 /** 1842 * Returns a string with replication znodes and position of the replication log 1843 * @param zkw reference to the {@link ZKWatcher} which also contains configuration and operation 1844 * @return aq string of replication znodes and log positions 1845 */ 1846 public static String getReplicationZnodesDump(ZKWatcher zkw) throws KeeperException { 1847 StringBuilder sb = new StringBuilder(); 1848 getReplicationZnodesDump(zkw, sb); 1849 return sb.toString(); 1850 } 1851 1852 private static void appendRSZnodes(ZKWatcher zkw, String znode, StringBuilder sb) 1853 throws KeeperException { 1854 List<String> stack = new LinkedList<>(); 1855 stack.add(znode); 1856 do { 1857 String znodeToProcess = stack.remove(stack.size() - 1); 1858 sb.append("\n").append(znodeToProcess).append(": "); 1859 byte[] data; 1860 try { 1861 data = ZKUtil.getData(zkw, znodeToProcess); 1862 } catch (InterruptedException e) { 1863 zkw.interruptedException(e); 1864 return; 1865 } 1866 if (data != null && data.length > 0) { // log position 1867 long position = 0; 1868 try { 1869 position = ZKUtil.parseWALPositionFrom(ZKUtil.getData(zkw, znodeToProcess)); 1870 sb.append(position); 1871 } catch (DeserializationException ignored) { 1872 } catch (InterruptedException e) { 1873 zkw.interruptedException(e); 1874 return; 1875 } 1876 } 1877 for (String zNodeChild : ZKUtil.listChildrenNoWatch(zkw, znodeToProcess)) { 1878 stack.add(ZNodePaths.joinZNode(znodeToProcess, zNodeChild)); 1879 } 1880 } while (stack.size() > 0); 1881 } 1882 1883 private static void appendPeersZnodes(ZKWatcher zkw, String peersZnode, 1884 StringBuilder sb) throws KeeperException { 1885 int pblen = ProtobufUtil.lengthOfPBMagic(); 1886 sb.append("\n").append(peersZnode).append(": "); 1887 for (String peerIdZnode : ZKUtil.listChildrenNoWatch(zkw, peersZnode)) { 1888 String znodeToProcess = ZNodePaths.joinZNode(peersZnode, peerIdZnode); 1889 byte[] data; 1890 try { 1891 data = ZKUtil.getData(zkw, znodeToProcess); 1892 } catch (InterruptedException e) { 1893 zkw.interruptedException(e); 1894 return; 1895 } 1896 // parse the data of the above peer znode. 1897 try { 1898 ReplicationProtos.ReplicationPeer.Builder builder = 1899 ReplicationProtos.ReplicationPeer.newBuilder(); 1900 ProtobufUtil.mergeFrom(builder, data, pblen, data.length - pblen); 1901 String clusterKey = builder.getClusterkey(); 1902 sb.append("\n").append(znodeToProcess).append(": ").append(clusterKey); 1903 // add the peer-state. 1904 appendPeerState(zkw, znodeToProcess, sb); 1905 } catch (IOException ipbe) { 1906 LOG.warn("Got Exception while parsing peer: " + znodeToProcess, ipbe); 1907 } 1908 } 1909 } 1910 1911 private static void appendPeerState(ZKWatcher zkw, String znodeToProcess, StringBuilder sb) 1912 throws KeeperException, InvalidProtocolBufferException { 1913 String peerState = zkw.getConfiguration().get("zookeeper.znode.replication.peers.state", 1914 "peer-state"); 1915 int pblen = ProtobufUtil.lengthOfPBMagic(); 1916 for (String child : ZKUtil.listChildrenNoWatch(zkw, znodeToProcess)) { 1917 if (!child.equals(peerState)) { 1918 continue; 1919 } 1920 1921 String peerStateZnode = ZNodePaths.joinZNode(znodeToProcess, child); 1922 sb.append("\n").append(peerStateZnode).append(": "); 1923 byte[] peerStateData; 1924 try { 1925 peerStateData = ZKUtil.getData(zkw, peerStateZnode); 1926 ReplicationProtos.ReplicationState.Builder builder = 1927 ReplicationProtos.ReplicationState.newBuilder(); 1928 ProtobufUtil.mergeFrom(builder, peerStateData, pblen, peerStateData.length - pblen); 1929 sb.append(builder.getState().name()); 1930 } catch (IOException ipbe) { 1931 LOG.warn("Got Exception while parsing peer: " + znodeToProcess, ipbe); 1932 } catch (InterruptedException e) { 1933 zkw.interruptedException(e); 1934 return; 1935 } 1936 } 1937 } 1938 1939 /** 1940 * Gets the statistics from the given server. 1941 * 1942 * @param server The server to get the statistics from. 1943 * @param timeout The socket timeout to use. 1944 * @return The array of response strings. 1945 * @throws IOException When the socket communication fails. 1946 */ 1947 public static String[] getServerStats(String server, int timeout) 1948 throws IOException { 1949 String[] sp = server.split(":"); 1950 if (sp == null || sp.length == 0) { 1951 return null; 1952 } 1953 1954 String host = sp[0]; 1955 int port = sp.length > 1 ? Integer.parseInt(sp[1]) 1956 : HConstants.DEFAULT_ZOOKEEPER_CLIENT_PORT; 1957 1958 InetSocketAddress sockAddr = new InetSocketAddress(host, port); 1959 try (Socket socket = new Socket()) { 1960 socket.connect(sockAddr, timeout); 1961 1962 socket.setSoTimeout(timeout); 1963 try (PrintWriter out = new PrintWriter(new BufferedWriter( 1964 new OutputStreamWriter(socket.getOutputStream(), StandardCharsets.UTF_8)), true); 1965 BufferedReader in = new BufferedReader( 1966 new InputStreamReader(socket.getInputStream(), StandardCharsets.UTF_8))) { 1967 out.println("stat"); 1968 out.flush(); 1969 ArrayList<String> res = new ArrayList<>(); 1970 while (true) { 1971 String line = in.readLine(); 1972 if (line != null) { 1973 res.add(line); 1974 } else { 1975 break; 1976 } 1977 } 1978 return res.toArray(new String[res.size()]); 1979 } 1980 } 1981 } 1982 1983 private static void logRetrievedMsg(final ZKWatcher zkw, 1984 final String znode, final byte [] data, final boolean watcherSet) { 1985 if (!LOG.isTraceEnabled()) { 1986 return; 1987 } 1988 1989 LOG.trace(zkw.prefix("Retrieved " + ((data == null)? 0: data.length) + 1990 " byte(s) of data from znode " + znode + 1991 (watcherSet? " and set watcher; ": "; data=") + 1992 (data == null? "null": data.length == 0? "empty": ( 1993 znode.startsWith(zkw.getZNodePaths().metaZNodePrefix)? 1994 getServerNameOrEmptyString(data): 1995 znode.startsWith(zkw.getZNodePaths().backupMasterAddressesZNode)? 1996 getServerNameOrEmptyString(data): 1997 StringUtils.abbreviate(Bytes.toStringBinary(data), 32))))); 1998 } 1999 2000 private static String getServerNameOrEmptyString(final byte [] data) { 2001 try { 2002 return ProtobufUtil.parseServerNameFrom(data).toString(); 2003 } catch (DeserializationException e) { 2004 return ""; 2005 } 2006 } 2007 2008 /** 2009 * Waits for HBase installation's base (parent) znode to become available. 2010 * @throws IOException on ZK errors 2011 */ 2012 public static void waitForBaseZNode(Configuration conf) throws IOException { 2013 LOG.info("Waiting until the base znode is available"); 2014 String parentZNode = conf.get(HConstants.ZOOKEEPER_ZNODE_PARENT, 2015 HConstants.DEFAULT_ZOOKEEPER_ZNODE_PARENT); 2016 ZooKeeper zk = new ZooKeeper(ZKConfig.getZKQuorumServersString(conf), 2017 conf.getInt(HConstants.ZK_SESSION_TIMEOUT, 2018 HConstants.DEFAULT_ZK_SESSION_TIMEOUT), EmptyWatcher.instance); 2019 2020 final int maxTimeMs = 10000; 2021 final int maxNumAttempts = maxTimeMs / HConstants.SOCKET_RETRY_WAIT_MS; 2022 2023 KeeperException keeperEx = null; 2024 try { 2025 try { 2026 for (int attempt = 0; attempt < maxNumAttempts; ++attempt) { 2027 try { 2028 if (zk.exists(parentZNode, false) != null) { 2029 LOG.info("Parent znode exists: " + parentZNode); 2030 keeperEx = null; 2031 break; 2032 } 2033 } catch (KeeperException e) { 2034 keeperEx = e; 2035 } 2036 Threads.sleepWithoutInterrupt(HConstants.SOCKET_RETRY_WAIT_MS); 2037 } 2038 } finally { 2039 zk.close(); 2040 } 2041 } catch (InterruptedException ex) { 2042 Thread.currentThread().interrupt(); 2043 } 2044 2045 if (keeperEx != null) { 2046 throw new IOException(keeperEx); 2047 } 2048 } 2049 2050 /** 2051 * Convert a {@link DeserializationException} to a more palatable {@link KeeperException}. 2052 * Used when can't let a {@link DeserializationException} out w/o changing public API. 2053 * @param e Exception to convert 2054 * @return Converted exception 2055 */ 2056 public static KeeperException convert(final DeserializationException e) { 2057 KeeperException ke = new KeeperException.DataInconsistencyException(); 2058 ke.initCause(e); 2059 return ke; 2060 } 2061 2062 /** 2063 * Recursively print the current state of ZK (non-transactional) 2064 * @param root name of the root directory in zk to print 2065 */ 2066 public static void logZKTree(ZKWatcher zkw, String root) { 2067 if (!LOG.isDebugEnabled()) { 2068 return; 2069 } 2070 2071 LOG.debug("Current zk system:"); 2072 String prefix = "|-"; 2073 LOG.debug(prefix + root); 2074 try { 2075 logZKTree(zkw, root, prefix); 2076 } catch (KeeperException e) { 2077 throw new RuntimeException(e); 2078 } 2079 } 2080 2081 /** 2082 * Helper method to print the current state of the ZK tree. 2083 * @see #logZKTree(ZKWatcher, String) 2084 * @throws KeeperException if an unexpected exception occurs 2085 */ 2086 protected static void logZKTree(ZKWatcher zkw, String root, String prefix) 2087 throws KeeperException { 2088 List<String> children = ZKUtil.listChildrenNoWatch(zkw, root); 2089 2090 if (children == null) { 2091 return; 2092 } 2093 2094 for (String child : children) { 2095 LOG.debug(prefix + child); 2096 String node = ZNodePaths.joinZNode(root.equals("/") ? "" : root, child); 2097 logZKTree(zkw, node, prefix + "---"); 2098 } 2099 } 2100 2101 /** 2102 * @param position the position to serialize 2103 * @return Serialized protobuf of <code>position</code> with pb magic prefix prepended suitable 2104 * for use as content of an wal position in a replication queue. 2105 */ 2106 public static byte[] positionToByteArray(final long position) { 2107 byte[] bytes = ReplicationProtos.ReplicationHLogPosition.newBuilder().setPosition(position) 2108 .build().toByteArray(); 2109 return ProtobufUtil.prependPBMagic(bytes); 2110 } 2111 2112 /** 2113 * @param bytes - Content of a WAL position znode. 2114 * @return long - The current WAL position. 2115 * @throws DeserializationException if the WAL position cannot be parsed 2116 */ 2117 public static long parseWALPositionFrom(final byte[] bytes) throws DeserializationException { 2118 if (bytes == null) { 2119 throw new DeserializationException("Unable to parse null WAL position."); 2120 } 2121 if (ProtobufUtil.isPBMagicPrefix(bytes)) { 2122 int pblen = ProtobufUtil.lengthOfPBMagic(); 2123 ReplicationProtos.ReplicationHLogPosition.Builder builder = 2124 ReplicationProtos.ReplicationHLogPosition.newBuilder(); 2125 ReplicationProtos.ReplicationHLogPosition position; 2126 try { 2127 ProtobufUtil.mergeFrom(builder, bytes, pblen, bytes.length - pblen); 2128 position = builder.build(); 2129 } catch (IOException e) { 2130 throw new DeserializationException(e); 2131 } 2132 return position.getPosition(); 2133 } else { 2134 if (bytes.length > 0) { 2135 return Bytes.toLong(bytes); 2136 } 2137 return 0; 2138 } 2139 } 2140}