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