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(identifier + " opening connection to ZooKeeper ensemble=" + 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=" + loginContextName + 290 " principal=" + principal + " useTicketCache=" + useTicketCache + 291 " keytabFile=" + keytabFile); 292 } 293 294 @Override 295 public AppConfigurationEntry[] getAppConfigurationEntry(String appName) { 296 if (loginContextName.equals(appName)) { 297 if (!useTicketCache) { 298 KEYTAB_KERBEROS_OPTIONS.put("keyTab", keytabFile); 299 KEYTAB_KERBEROS_OPTIONS.put("useKeyTab", "true"); 300 } 301 KEYTAB_KERBEROS_OPTIONS.put("principal", principal); 302 KEYTAB_KERBEROS_OPTIONS.put("useTicketCache", useTicketCache ? "true" : "false"); 303 return KEYTAB_KERBEROS_CONF; 304 } 305 306 if (baseConfig != null) { 307 return baseConfig.getAppConfigurationEntry(appName); 308 } 309 310 return(null); 311 } 312 } 313 314 // 315 // Helper methods 316 // 317 /** 318 * Returns the full path of the immediate parent of the specified node. 319 * @param node path to get parent of 320 * @return parent of path, null if passed the root node or an invalid node 321 */ 322 public static String getParent(String node) { 323 int idx = node.lastIndexOf(ZNodePaths.ZNODE_PATH_SEPARATOR); 324 return idx <= 0 ? null : node.substring(0, idx); 325 } 326 327 /** 328 * Get the name of the current node from the specified fully-qualified path. 329 * @param path fully-qualified path 330 * @return name of the current node 331 */ 332 public static String getNodeName(String path) { 333 return path.substring(path.lastIndexOf("/")+1); 334 } 335 336 // 337 // Existence checks and watches 338 // 339 340 /** 341 * Watch the specified znode for delete/create/change events. The watcher is 342 * set whether or not the node exists. If the node already exists, the method 343 * returns true. If the node does not exist, the method returns false. 344 * 345 * @param zkw zk reference 346 * @param znode path of node to watch 347 * @return true if znode exists, false if does not exist or error 348 * @throws KeeperException if unexpected zookeeper exception 349 */ 350 public static boolean watchAndCheckExists(ZKWatcher zkw, String znode) 351 throws KeeperException { 352 try { 353 Stat s = zkw.getRecoverableZooKeeper().exists(znode, zkw); 354 boolean exists = s != null; 355 if (exists) { 356 LOG.debug(zkw.prefix("Set watcher on existing znode=" + znode)); 357 } else { 358 LOG.debug(zkw.prefix("Set watcher on znode that does not yet exist, " + znode)); 359 } 360 return exists; 361 } catch (KeeperException e) { 362 LOG.warn(zkw.prefix("Unable to set watcher on znode " + znode), e); 363 zkw.keeperException(e); 364 return false; 365 } catch (InterruptedException e) { 366 LOG.warn(zkw.prefix("Unable to set watcher on znode " + znode), e); 367 zkw.interruptedException(e); 368 return false; 369 } 370 } 371 372 /** 373 * Watch the specified znode, but only if exists. Useful when watching 374 * for deletions. Uses .getData() (and handles NoNodeException) instead 375 * of .exists() to accomplish this, as .getData() will only set a watch if 376 * the znode exists. 377 * @param zkw zk reference 378 * @param znode path of node to watch 379 * @return true if the watch is set, false if node does not exists 380 * @throws KeeperException if unexpected zookeeper exception 381 */ 382 public static boolean setWatchIfNodeExists(ZKWatcher zkw, String znode) 383 throws KeeperException { 384 try { 385 zkw.getRecoverableZooKeeper().getData(znode, true, null); 386 return true; 387 } catch (NoNodeException e) { 388 return false; 389 } catch (InterruptedException e) { 390 LOG.warn(zkw.prefix("Unable to set watcher on znode " + znode), e); 391 zkw.interruptedException(e); 392 return false; 393 } 394 } 395 396 /** 397 * Check if the specified node exists. Sets no watches. 398 * 399 * @param zkw zk reference 400 * @param znode path of node to watch 401 * @return version of the node if it exists, -1 if does not exist 402 * @throws KeeperException if unexpected zookeeper exception 403 */ 404 public static int checkExists(ZKWatcher zkw, String znode) 405 throws KeeperException { 406 try { 407 Stat s = zkw.getRecoverableZooKeeper().exists(znode, null); 408 return s != null ? s.getVersion() : -1; 409 } catch (KeeperException e) { 410 LOG.warn(zkw.prefix("Unable to set watcher on znode (" + znode + ")"), e); 411 zkw.keeperException(e); 412 return -1; 413 } catch (InterruptedException e) { 414 LOG.warn(zkw.prefix("Unable to set watcher on znode (" + znode + ")"), e); 415 zkw.interruptedException(e); 416 return -1; 417 } 418 } 419 420 // 421 // Znode listings 422 // 423 424 /** 425 * Lists the children znodes of the specified znode. Also sets a watch on 426 * the specified znode which will capture a NodeDeleted event on the specified 427 * znode as well as NodeChildrenChanged if any children of the specified znode 428 * are created or deleted. 429 * 430 * Returns null if the specified node does not exist. Otherwise returns a 431 * list of children of the specified node. If the node exists but it has no 432 * children, an empty list will be returned. 433 * 434 * @param zkw zk reference 435 * @param znode path of node to list and watch children of 436 * @return list of children of the specified node, an empty list if the node 437 * exists but has no children, and null if the node does not exist 438 * @throws KeeperException if unexpected zookeeper exception 439 */ 440 public static List<String> listChildrenAndWatchForNewChildren( 441 ZKWatcher zkw, String znode) 442 throws KeeperException { 443 try { 444 return zkw.getRecoverableZooKeeper().getChildren(znode, zkw); 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.znodePaths.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.znodePaths.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 // at least 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 path to znode where the ZKOp will occur 1509 */ 1510 public String getPath() { 1511 return path; 1512 } 1513 1514 /** 1515 * ZKUtilOp representing createAndFailSilent in ZooKeeper 1516 * (attempt to create node, ignore error if already exists) 1517 */ 1518 public static final class CreateAndFailSilent extends ZKUtilOp { 1519 private byte [] data; 1520 1521 private CreateAndFailSilent(String path, byte [] data) { 1522 super(path); 1523 this.data = data; 1524 } 1525 1526 public byte[] getData() { 1527 return data; 1528 } 1529 1530 @Override 1531 public boolean equals(Object o) { 1532 if (this == o) { 1533 return true; 1534 } 1535 if (!(o instanceof CreateAndFailSilent)) { 1536 return false; 1537 } 1538 1539 CreateAndFailSilent op = (CreateAndFailSilent) o; 1540 return getPath().equals(op.getPath()) && Arrays.equals(data, op.data); 1541 } 1542 1543 @Override 1544 public int hashCode() { 1545 int ret = 17 + getPath().hashCode() * 31; 1546 return ret * 31 + Bytes.hashCode(data); 1547 } 1548 } 1549 1550 /** 1551 * ZKUtilOp representing deleteNodeFailSilent in ZooKeeper 1552 * (attempt to delete node, ignore error if node doesn't exist) 1553 */ 1554 public static final class DeleteNodeFailSilent extends ZKUtilOp { 1555 private DeleteNodeFailSilent(String path) { 1556 super(path); 1557 } 1558 1559 @Override 1560 public boolean equals(Object o) { 1561 if (this == o) { 1562 return true; 1563 } 1564 if (!(o instanceof DeleteNodeFailSilent)) { 1565 return false; 1566 } 1567 1568 return super.equals(o); 1569 } 1570 1571 @Override 1572 public int hashCode() { 1573 return getPath().hashCode(); 1574 } 1575 } 1576 1577 /** 1578 * ZKUtilOp representing setData in ZooKeeper 1579 */ 1580 public static final class SetData extends ZKUtilOp { 1581 private byte [] data; 1582 1583 private SetData(String path, byte [] data) { 1584 super(path); 1585 this.data = data; 1586 } 1587 1588 public byte[] getData() { 1589 return data; 1590 } 1591 1592 @Override 1593 public boolean equals(Object o) { 1594 if (this == o) { 1595 return true; 1596 } 1597 if (!(o instanceof SetData)) { 1598 return false; 1599 } 1600 1601 SetData op = (SetData) o; 1602 return getPath().equals(op.getPath()) && Arrays.equals(data, op.data); 1603 } 1604 1605 @Override 1606 public int hashCode() { 1607 int ret = getPath().hashCode(); 1608 return ret * 31 + Bytes.hashCode(data); 1609 } 1610 } 1611 } 1612 1613 /** 1614 * Convert from ZKUtilOp to ZKOp 1615 */ 1616 private static Op toZooKeeperOp(ZKWatcher zkw, ZKUtilOp op) throws UnsupportedOperationException { 1617 if(op == null) { 1618 return null; 1619 } 1620 1621 if (op instanceof CreateAndFailSilent) { 1622 CreateAndFailSilent cafs = (CreateAndFailSilent)op; 1623 return Op.create(cafs.getPath(), cafs.getData(), createACL(zkw, cafs.getPath()), 1624 CreateMode.PERSISTENT); 1625 } else if (op instanceof DeleteNodeFailSilent) { 1626 DeleteNodeFailSilent dnfs = (DeleteNodeFailSilent)op; 1627 return Op.delete(dnfs.getPath(), -1); 1628 } else if (op instanceof SetData) { 1629 SetData sd = (SetData)op; 1630 return Op.setData(sd.getPath(), sd.getData(), -1); 1631 } else { 1632 throw new UnsupportedOperationException("Unexpected ZKUtilOp type: " 1633 + op.getClass().getName()); 1634 } 1635 } 1636 1637 /** 1638 * Use ZooKeeper's multi-update functionality. 1639 * 1640 * If all of the following are true: 1641 * - runSequentialOnMultiFailure is true 1642 * - on calling multi, we get a ZooKeeper exception that can be handled by a sequential call(*) 1643 * Then: 1644 * - we retry the operations one-by-one (sequentially) 1645 * 1646 * Note *: an example is receiving a NodeExistsException from a "create" call. Without multi, 1647 * a user could call "createAndFailSilent" to ensure that a node exists if they don't care who 1648 * actually created the node (i.e. the NodeExistsException from ZooKeeper is caught). 1649 * This will cause all operations in the multi to fail, however, because 1650 * the NodeExistsException that zk.create throws will fail the multi transaction. 1651 * In this case, if the previous conditions hold, the commands are run sequentially, which should 1652 * result in the correct final state, but means that the operations will not run atomically. 1653 * 1654 * @throws KeeperException if a ZooKeeper operation fails 1655 */ 1656 public static void multiOrSequential(ZKWatcher zkw, List<ZKUtilOp> ops, 1657 boolean runSequentialOnMultiFailure) throws KeeperException { 1658 if (zkw.getConfiguration().get("hbase.zookeeper.useMulti") != null) { 1659 LOG.warn("hbase.zookeeper.useMulti is deprecated. Default to true always."); 1660 } 1661 if (ops == null) { 1662 return; 1663 } 1664 1665 List<Op> zkOps = new LinkedList<>(); 1666 for (ZKUtilOp op : ops) { 1667 zkOps.add(toZooKeeperOp(zkw, op)); 1668 } 1669 try { 1670 zkw.getRecoverableZooKeeper().multi(zkOps); 1671 } catch (KeeperException ke) { 1672 switch (ke.code()) { 1673 case NODEEXISTS: 1674 case NONODE: 1675 case BADVERSION: 1676 case NOAUTH: 1677 // if we get an exception that could be solved by running sequentially 1678 // (and the client asked us to), then break out and run sequentially 1679 if (runSequentialOnMultiFailure) { 1680 LOG.info("On call to ZK.multi, received exception: " + ke.toString() + "." 1681 + " Attempting to run operations sequentially because" 1682 + " runSequentialOnMultiFailure is: " + runSequentialOnMultiFailure + "."); 1683 processSequentially(zkw, ops); 1684 break; 1685 } 1686 default: 1687 throw ke; 1688 } 1689 } catch (InterruptedException ie) { 1690 zkw.interruptedException(ie); 1691 } 1692 } 1693 1694 private static void processSequentially(ZKWatcher zkw, List<ZKUtilOp> ops) 1695 throws KeeperException, NoNodeException { 1696 for (ZKUtilOp op : ops) { 1697 if (op instanceof CreateAndFailSilent) { 1698 createAndFailSilent(zkw, (CreateAndFailSilent) op); 1699 } else if (op instanceof DeleteNodeFailSilent) { 1700 deleteNodeFailSilent(zkw, (DeleteNodeFailSilent) op); 1701 } else if (op instanceof SetData) { 1702 setData(zkw, (SetData) op); 1703 } else { 1704 throw new UnsupportedOperationException("Unexpected ZKUtilOp type: " 1705 + op.getClass().getName()); 1706 } 1707 } 1708 } 1709 1710 // 1711 // ZooKeeper cluster information 1712 // 1713 1714 /** @return String dump of everything in ZooKeeper. */ 1715 public static String dump(ZKWatcher zkw) { 1716 StringBuilder sb = new StringBuilder(); 1717 try { 1718 sb.append("HBase is rooted at ").append(zkw.znodePaths.baseZNode); 1719 sb.append("\nActive master address: "); 1720 try { 1721 sb.append(MasterAddressTracker.getMasterAddress(zkw)); 1722 } catch (IOException e) { 1723 sb.append("<<FAILED LOOKUP: " + e.getMessage() + ">>"); 1724 } 1725 sb.append("\nBackup master addresses:"); 1726 final List<String> backupMasterChildrenNoWatchList = listChildrenNoWatch(zkw, 1727 zkw.znodePaths.backupMasterAddressesZNode); 1728 if (backupMasterChildrenNoWatchList != null) { 1729 for (String child : backupMasterChildrenNoWatchList) { 1730 sb.append("\n ").append(child); 1731 } 1732 } 1733 sb.append("\nRegion server holding hbase:meta: " 1734 + new MetaTableLocator().getMetaRegionLocation(zkw)); 1735 Configuration conf = HBaseConfiguration.create(); 1736 int numMetaReplicas = conf.getInt(HConstants.META_REPLICAS_NUM, 1737 HConstants.DEFAULT_META_REPLICA_NUM); 1738 for (int i = 1; i < numMetaReplicas; i++) { 1739 sb.append("\nRegion server holding hbase:meta, replicaId " + i + " " 1740 + new MetaTableLocator().getMetaRegionLocation(zkw, i)); 1741 } 1742 sb.append("\nRegion servers:"); 1743 final List<String> rsChildrenNoWatchList = 1744 listChildrenNoWatch(zkw, zkw.znodePaths.rsZNode); 1745 if (rsChildrenNoWatchList != null) { 1746 for (String child : rsChildrenNoWatchList) { 1747 sb.append("\n ").append(child); 1748 } 1749 } 1750 try { 1751 getReplicationZnodesDump(zkw, sb); 1752 } catch (KeeperException ke) { 1753 LOG.warn("Couldn't get the replication znode dump", ke); 1754 } 1755 sb.append("\nQuorum Server Statistics:"); 1756 String[] servers = zkw.getQuorum().split(","); 1757 for (String server : servers) { 1758 sb.append("\n ").append(server); 1759 try { 1760 String[] stat = getServerStats(server, ZKUtil.zkDumpConnectionTimeOut); 1761 1762 if (stat == null) { 1763 sb.append("[Error] invalid quorum server: " + server); 1764 break; 1765 } 1766 1767 for (String s : stat) { 1768 sb.append("\n ").append(s); 1769 } 1770 } catch (Exception e) { 1771 sb.append("\n ERROR: ").append(e.getMessage()); 1772 } 1773 } 1774 } catch (KeeperException ke) { 1775 sb.append("\nFATAL ZooKeeper Exception!\n"); 1776 sb.append("\n" + ke.getMessage()); 1777 } 1778 return sb.toString(); 1779 } 1780 1781 /** 1782 * Appends replication znodes to the passed StringBuilder. 1783 * 1784 * @param zkw reference to the {@link ZKWatcher} which also contains configuration and operation 1785 * @param sb the {@link StringBuilder} to append to 1786 * @throws KeeperException if a ZooKeeper operation fails 1787 */ 1788 private static void getReplicationZnodesDump(ZKWatcher zkw, StringBuilder sb) 1789 throws KeeperException { 1790 String replicationZnode = zkw.znodePaths.replicationZNode; 1791 1792 if (ZKUtil.checkExists(zkw, replicationZnode) == -1) { 1793 return; 1794 } 1795 1796 // do a ls -r on this znode 1797 sb.append("\n").append(replicationZnode).append(": "); 1798 List<String> children = ZKUtil.listChildrenNoWatch(zkw, replicationZnode); 1799 if (children != null) { 1800 Collections.sort(children); 1801 for (String child : children) { 1802 String zNode = ZNodePaths.joinZNode(replicationZnode, child); 1803 if (zNode.equals(zkw.znodePaths.peersZNode)) { 1804 appendPeersZnodes(zkw, zNode, sb); 1805 } else if (zNode.equals(zkw.znodePaths.queuesZNode)) { 1806 appendRSZnodes(zkw, zNode, sb); 1807 } else if (zNode.equals(zkw.znodePaths.hfileRefsZNode)) { 1808 appendHFileRefsZNodes(zkw, zNode, sb); 1809 } 1810 } 1811 } 1812 } 1813 1814 private static void appendHFileRefsZNodes(ZKWatcher zkw, String hFileRefsZNode, 1815 StringBuilder sb) throws KeeperException { 1816 sb.append("\n").append(hFileRefsZNode).append(": "); 1817 final List<String> hFileRefChildrenNoWatchList = 1818 ZKUtil.listChildrenNoWatch(zkw, hFileRefsZNode); 1819 if (hFileRefChildrenNoWatchList != null) { 1820 for (String peerIdZNode : hFileRefChildrenNoWatchList) { 1821 String zNodeToProcess = ZNodePaths.joinZNode(hFileRefsZNode, peerIdZNode); 1822 sb.append("\n").append(zNodeToProcess).append(": "); 1823 List<String> peerHFileRefsZNodes = ZKUtil.listChildrenNoWatch(zkw, zNodeToProcess); 1824 if (peerHFileRefsZNodes != null) { 1825 sb.append(String.join(", ", peerHFileRefsZNodes)); 1826 } 1827 } 1828 } 1829 } 1830 1831 /** 1832 * Returns a string with replication znodes and position of the replication log 1833 * @param zkw reference to the {@link ZKWatcher} which also contains configuration and operation 1834 * @return aq string of replication znodes and log positions 1835 */ 1836 public static String getReplicationZnodesDump(ZKWatcher zkw) throws KeeperException { 1837 StringBuilder sb = new StringBuilder(); 1838 getReplicationZnodesDump(zkw, sb); 1839 return sb.toString(); 1840 } 1841 1842 private static void appendRSZnodes(ZKWatcher zkw, String znode, StringBuilder sb) 1843 throws KeeperException { 1844 List<String> stack = new LinkedList<>(); 1845 stack.add(znode); 1846 do { 1847 String znodeToProcess = stack.remove(stack.size() - 1); 1848 sb.append("\n").append(znodeToProcess).append(": "); 1849 byte[] data; 1850 try { 1851 data = ZKUtil.getData(zkw, znodeToProcess); 1852 } catch (InterruptedException e) { 1853 zkw.interruptedException(e); 1854 return; 1855 } 1856 if (data != null && data.length > 0) { // log position 1857 long position = 0; 1858 try { 1859 position = ZKUtil.parseWALPositionFrom(ZKUtil.getData(zkw, znodeToProcess)); 1860 sb.append(position); 1861 } catch (DeserializationException ignored) { 1862 } catch (InterruptedException e) { 1863 zkw.interruptedException(e); 1864 return; 1865 } 1866 } 1867 for (String zNodeChild : ZKUtil.listChildrenNoWatch(zkw, znodeToProcess)) { 1868 stack.add(ZNodePaths.joinZNode(znodeToProcess, zNodeChild)); 1869 } 1870 } while (stack.size() > 0); 1871 } 1872 1873 private static void appendPeersZnodes(ZKWatcher zkw, String peersZnode, 1874 StringBuilder sb) throws KeeperException { 1875 int pblen = ProtobufUtil.lengthOfPBMagic(); 1876 sb.append("\n").append(peersZnode).append(": "); 1877 for (String peerIdZnode : ZKUtil.listChildrenNoWatch(zkw, peersZnode)) { 1878 String znodeToProcess = ZNodePaths.joinZNode(peersZnode, peerIdZnode); 1879 byte[] data; 1880 try { 1881 data = ZKUtil.getData(zkw, znodeToProcess); 1882 } catch (InterruptedException e) { 1883 zkw.interruptedException(e); 1884 return; 1885 } 1886 // parse the data of the above peer znode. 1887 try { 1888 ReplicationProtos.ReplicationPeer.Builder builder = 1889 ReplicationProtos.ReplicationPeer.newBuilder(); 1890 ProtobufUtil.mergeFrom(builder, data, pblen, data.length - pblen); 1891 String clusterKey = builder.getClusterkey(); 1892 sb.append("\n").append(znodeToProcess).append(": ").append(clusterKey); 1893 // add the peer-state. 1894 appendPeerState(zkw, znodeToProcess, sb); 1895 } catch (IOException ipbe) { 1896 LOG.warn("Got Exception while parsing peer: " + znodeToProcess, ipbe); 1897 } 1898 } 1899 } 1900 1901 private static void appendPeerState(ZKWatcher zkw, String znodeToProcess, StringBuilder sb) 1902 throws KeeperException, InvalidProtocolBufferException { 1903 String peerState = zkw.getConfiguration().get("zookeeper.znode.replication.peers.state", 1904 "peer-state"); 1905 int pblen = ProtobufUtil.lengthOfPBMagic(); 1906 for (String child : ZKUtil.listChildrenNoWatch(zkw, znodeToProcess)) { 1907 if (!child.equals(peerState)) { 1908 continue; 1909 } 1910 1911 String peerStateZnode = ZNodePaths.joinZNode(znodeToProcess, child); 1912 sb.append("\n").append(peerStateZnode).append(": "); 1913 byte[] peerStateData; 1914 try { 1915 peerStateData = ZKUtil.getData(zkw, peerStateZnode); 1916 ReplicationProtos.ReplicationState.Builder builder = 1917 ReplicationProtos.ReplicationState.newBuilder(); 1918 ProtobufUtil.mergeFrom(builder, peerStateData, pblen, peerStateData.length - pblen); 1919 sb.append(builder.getState().name()); 1920 } catch (IOException ipbe) { 1921 LOG.warn("Got Exception while parsing peer: " + znodeToProcess, ipbe); 1922 } catch (InterruptedException e) { 1923 zkw.interruptedException(e); 1924 return; 1925 } 1926 } 1927 } 1928 1929 /** 1930 * Gets the statistics from the given server. 1931 * 1932 * @param server The server to get the statistics from. 1933 * @param timeout The socket timeout to use. 1934 * @return The array of response strings. 1935 * @throws IOException When the socket communication fails. 1936 */ 1937 private static String[] getServerStats(String server, int timeout) 1938 throws IOException { 1939 String[] sp = server.split(":"); 1940 if (sp.length == 0) { 1941 return null; 1942 } 1943 1944 String host = sp[0]; 1945 int port = sp.length > 1 ? Integer.parseInt(sp[1]) 1946 : HConstants.DEFAULT_ZOOKEPER_CLIENT_PORT; 1947 1948 InetSocketAddress sockAddr = new InetSocketAddress(host, port); 1949 try (Socket socket = new Socket()) { 1950 socket.connect(sockAddr, timeout); 1951 1952 socket.setSoTimeout(timeout); 1953 try (PrintWriter out = new PrintWriter(new BufferedWriter( 1954 new OutputStreamWriter(socket.getOutputStream(), StandardCharsets.UTF_8)), true); 1955 BufferedReader in = new BufferedReader( 1956 new InputStreamReader(socket.getInputStream(), StandardCharsets.UTF_8))) { 1957 out.println("stat"); 1958 out.flush(); 1959 ArrayList<String> res = new ArrayList<>(); 1960 while (true) { 1961 String line = in.readLine(); 1962 if (line != null) { 1963 res.add(line); 1964 } else { 1965 break; 1966 } 1967 } 1968 return res.toArray(new String[res.size()]); 1969 } 1970 } 1971 } 1972 1973 private static void logRetrievedMsg(final ZKWatcher zkw, 1974 final String znode, final byte [] data, final boolean watcherSet) { 1975 if (!LOG.isTraceEnabled()) { 1976 return; 1977 } 1978 1979 LOG.trace(zkw.prefix("Retrieved " + ((data == null)? 0: data.length) + 1980 " byte(s) of data from znode " + znode + 1981 (watcherSet? " and set watcher; ": "; data=") + 1982 (data == null? "null": data.length == 0? "empty": ( 1983 znode.startsWith(zkw.znodePaths.metaZNodePrefix)? 1984 getServerNameOrEmptyString(data): 1985 znode.startsWith(zkw.znodePaths.backupMasterAddressesZNode)? 1986 getServerNameOrEmptyString(data): 1987 StringUtils.abbreviate(Bytes.toStringBinary(data), 32))))); 1988 } 1989 1990 private static String getServerNameOrEmptyString(final byte [] data) { 1991 try { 1992 return ProtobufUtil.parseServerNameFrom(data).toString(); 1993 } catch (DeserializationException e) { 1994 return ""; 1995 } 1996 } 1997 1998 /** 1999 * Waits for HBase installation's base (parent) znode to become available. 2000 * @throws IOException on ZK errors 2001 */ 2002 public static void waitForBaseZNode(Configuration conf) throws IOException { 2003 LOG.info("Waiting until the base znode is available"); 2004 String parentZNode = conf.get(HConstants.ZOOKEEPER_ZNODE_PARENT, 2005 HConstants.DEFAULT_ZOOKEEPER_ZNODE_PARENT); 2006 ZooKeeper zk = new ZooKeeper(ZKConfig.getZKQuorumServersString(conf), 2007 conf.getInt(HConstants.ZK_SESSION_TIMEOUT, 2008 HConstants.DEFAULT_ZK_SESSION_TIMEOUT), EmptyWatcher.instance); 2009 2010 final int maxTimeMs = 10000; 2011 final int maxNumAttempts = maxTimeMs / HConstants.SOCKET_RETRY_WAIT_MS; 2012 2013 KeeperException keeperEx = null; 2014 try { 2015 try { 2016 for (int attempt = 0; attempt < maxNumAttempts; ++attempt) { 2017 try { 2018 if (zk.exists(parentZNode, false) != null) { 2019 LOG.info("Parent znode exists: " + parentZNode); 2020 keeperEx = null; 2021 break; 2022 } 2023 } catch (KeeperException e) { 2024 keeperEx = e; 2025 } 2026 Threads.sleepWithoutInterrupt(HConstants.SOCKET_RETRY_WAIT_MS); 2027 } 2028 } finally { 2029 zk.close(); 2030 } 2031 } catch (InterruptedException ex) { 2032 Thread.currentThread().interrupt(); 2033 } 2034 2035 if (keeperEx != null) { 2036 throw new IOException(keeperEx); 2037 } 2038 } 2039 2040 /** 2041 * Convert a {@link DeserializationException} to a more palatable {@link KeeperException}. 2042 * Used when can't let a {@link DeserializationException} out w/o changing public API. 2043 * @param e Exception to convert 2044 * @return Converted exception 2045 */ 2046 public static KeeperException convert(final DeserializationException e) { 2047 KeeperException ke = new KeeperException.DataInconsistencyException(); 2048 ke.initCause(e); 2049 return ke; 2050 } 2051 2052 /** 2053 * Recursively print the current state of ZK (non-transactional) 2054 * @param root name of the root directory in zk to print 2055 */ 2056 public static void logZKTree(ZKWatcher zkw, String root) { 2057 if (!LOG.isDebugEnabled()) { 2058 return; 2059 } 2060 2061 LOG.debug("Current zk system:"); 2062 String prefix = "|-"; 2063 LOG.debug(prefix + root); 2064 try { 2065 logZKTree(zkw, root, prefix); 2066 } catch (KeeperException e) { 2067 throw new RuntimeException(e); 2068 } 2069 } 2070 2071 /** 2072 * Helper method to print the current state of the ZK tree. 2073 * @see #logZKTree(ZKWatcher, String) 2074 * @throws KeeperException if an unexpected exception occurs 2075 */ 2076 private static void logZKTree(ZKWatcher zkw, String root, String prefix) 2077 throws KeeperException { 2078 List<String> children = ZKUtil.listChildrenNoWatch(zkw, root); 2079 2080 if (children == null) { 2081 return; 2082 } 2083 2084 for (String child : children) { 2085 LOG.debug(prefix + child); 2086 String node = ZNodePaths.joinZNode(root.equals("/") ? "" : root, child); 2087 logZKTree(zkw, node, prefix + "---"); 2088 } 2089 } 2090 2091 /** 2092 * @param position the position to serialize 2093 * @return Serialized protobuf of <code>position</code> with pb magic prefix prepended suitable 2094 * for use as content of an wal position in a replication queue. 2095 */ 2096 public static byte[] positionToByteArray(final long position) { 2097 byte[] bytes = ReplicationProtos.ReplicationHLogPosition.newBuilder().setPosition(position) 2098 .build().toByteArray(); 2099 return ProtobufUtil.prependPBMagic(bytes); 2100 } 2101 2102 /** 2103 * @param bytes - Content of a WAL position znode. 2104 * @return long - The current WAL position. 2105 * @throws DeserializationException if the WAL position cannot be parsed 2106 */ 2107 public static long parseWALPositionFrom(final byte[] bytes) throws DeserializationException { 2108 if (bytes == null) { 2109 throw new DeserializationException("Unable to parse null WAL position."); 2110 } 2111 if (ProtobufUtil.isPBMagicPrefix(bytes)) { 2112 int pblen = ProtobufUtil.lengthOfPBMagic(); 2113 ReplicationProtos.ReplicationHLogPosition.Builder builder = 2114 ReplicationProtos.ReplicationHLogPosition.newBuilder(); 2115 ReplicationProtos.ReplicationHLogPosition position; 2116 try { 2117 ProtobufUtil.mergeFrom(builder, bytes, pblen, bytes.length - pblen); 2118 position = builder.build(); 2119 } catch (IOException e) { 2120 throw new DeserializationException(e); 2121 } 2122 return position.getPosition(); 2123 } else { 2124 if (bytes.length > 0) { 2125 return Bytes.toLong(bytes); 2126 } 2127 return 0; 2128 } 2129 } 2130}