001/* 002 * 003 * Licensed to the Apache Software Foundation (ASF) under one 004 * or more contributor license agreements. See the NOTICE file 005 * distributed with this work for additional information 006 * regarding copyright ownership. The ASF licenses this file 007 * to you under the Apache License, Version 2.0 (the 008 * "License"); you may not use this file except in compliance 009 * with the License. You may obtain a copy of the License at 010 * 011 * http://www.apache.org/licenses/LICENSE-2.0 012 * 013 * Unless required by applicable law or agreed to in writing, software 014 * distributed under the License is distributed on an "AS IS" BASIS, 015 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 016 * See the License for the specific language governing permissions and 017 * limitations under the License. 018 */ 019package org.apache.hadoop.hbase.zookeeper; 020 021import java.io.BufferedReader; 022import java.io.BufferedWriter; 023import java.io.IOException; 024import java.io.InputStreamReader; 025import java.io.OutputStreamWriter; 026import java.io.PrintWriter; 027import java.net.InetSocketAddress; 028import java.net.Socket; 029import java.nio.charset.StandardCharsets; 030import java.util.ArrayList; 031import java.util.Arrays; 032import java.util.Deque; 033import java.util.HashMap; 034import java.util.LinkedList; 035import java.util.List; 036import java.util.Map; 037 038import javax.security.auth.login.AppConfigurationEntry; 039import javax.security.auth.login.AppConfigurationEntry.LoginModuleControlFlag; 040 041import org.apache.commons.lang3.StringUtils; 042import org.apache.hadoop.conf.Configuration; 043import org.apache.hadoop.hbase.AuthUtil; 044import org.apache.hadoop.hbase.HBaseConfiguration; 045import org.apache.hadoop.hbase.HConstants; 046import org.apache.hadoop.hbase.exceptions.DeserializationException; 047import org.apache.hadoop.hbase.security.Superusers; 048import org.apache.hadoop.hbase.util.Bytes; 049import org.apache.hadoop.hbase.util.Threads; 050import org.apache.hadoop.hbase.zookeeper.ZKUtil.ZKUtilOp.CreateAndFailSilent; 051import org.apache.hadoop.hbase.zookeeper.ZKUtil.ZKUtilOp.DeleteNodeFailSilent; 052import org.apache.hadoop.hbase.zookeeper.ZKUtil.ZKUtilOp.SetData; 053import org.apache.hadoop.security.SecurityUtil; 054import org.apache.hadoop.security.UserGroupInformation; 055import org.apache.hadoop.security.authentication.util.KerberosUtil; 056import org.apache.yetus.audience.InterfaceAudience; 057import org.apache.zookeeper.AsyncCallback; 058import org.apache.zookeeper.CreateMode; 059import org.apache.zookeeper.KeeperException; 060import org.apache.zookeeper.KeeperException.NoNodeException; 061import org.apache.zookeeper.Op; 062import org.apache.zookeeper.Watcher; 063import org.apache.zookeeper.ZooDefs.Ids; 064import org.apache.zookeeper.ZooDefs.Perms; 065import org.apache.zookeeper.ZooKeeper; 066import org.apache.zookeeper.client.ZooKeeperSaslClient; 067import org.apache.zookeeper.data.ACL; 068import org.apache.zookeeper.data.Id; 069import org.apache.zookeeper.data.Stat; 070import org.apache.zookeeper.proto.CreateRequest; 071import org.apache.zookeeper.proto.DeleteRequest; 072import org.apache.zookeeper.proto.SetDataRequest; 073import org.apache.zookeeper.server.ZooKeeperSaslServer; 074import org.slf4j.Logger; 075import org.slf4j.LoggerFactory; 076 077import org.apache.hbase.thirdparty.com.google.protobuf.InvalidProtocolBufferException; 078import org.apache.hadoop.hbase.shaded.protobuf.ProtobufUtil; 079import org.apache.hadoop.hbase.shaded.protobuf.generated.ReplicationProtos; 080 081/** 082 * Internal HBase utility class for ZooKeeper. 083 * 084 * <p>Contains only static methods and constants. 085 * 086 * <p>Methods all throw {@link KeeperException} if there is an unexpected 087 * zookeeper exception, so callers of these methods must handle appropriately. 088 * If ZK is required for the operation, the server will need to be aborted. 089 */ 090@InterfaceAudience.Private 091public final class ZKUtil { 092 private static final Logger LOG = LoggerFactory.getLogger(ZKUtil.class); 093 094 private static int zkDumpConnectionTimeOut; 095 096 private ZKUtil() { 097 } 098 099 /** 100 * Creates a new connection to ZooKeeper, pulling settings and ensemble config 101 * from the specified configuration object using methods from {@link ZKConfig}. 102 * 103 * Sets the connection status monitoring watcher to the specified watcher. 104 * 105 * @param conf configuration to pull ensemble and other settings from 106 * @param watcher watcher to monitor connection changes 107 * @return connection to zookeeper 108 * @throws IOException if unable to connect to zk or config problem 109 */ 110 public static RecoverableZooKeeper connect(Configuration conf, Watcher watcher) 111 throws IOException { 112 String ensemble = ZKConfig.getZKQuorumServersString(conf); 113 return connect(conf, ensemble, watcher); 114 } 115 116 public static RecoverableZooKeeper connect(Configuration conf, String ensemble, 117 Watcher watcher) 118 throws IOException { 119 return connect(conf, ensemble, watcher, null); 120 } 121 122 public static RecoverableZooKeeper connect(Configuration conf, String ensemble, 123 Watcher watcher, final String identifier) 124 throws IOException { 125 if(ensemble == null) { 126 throw new IOException("Unable to determine ZooKeeper ensemble"); 127 } 128 int timeout = conf.getInt(HConstants.ZK_SESSION_TIMEOUT, 129 HConstants.DEFAULT_ZK_SESSION_TIMEOUT); 130 if (LOG.isTraceEnabled()) { 131 LOG.trace(identifier + " opening connection to ZooKeeper ensemble=" + ensemble); 132 } 133 int retry = conf.getInt("zookeeper.recovery.retry", 3); 134 int retryIntervalMillis = 135 conf.getInt("zookeeper.recovery.retry.intervalmill", 1000); 136 int maxSleepTime = conf.getInt("zookeeper.recovery.retry.maxsleeptime", 60000); 137 zkDumpConnectionTimeOut = conf.getInt("zookeeper.dump.connection.timeout", 138 1000); 139 return new RecoverableZooKeeper(ensemble, timeout, watcher, 140 retry, retryIntervalMillis, maxSleepTime, identifier); 141 } 142 143 /** 144 * Log in the current zookeeper server process using the given configuration 145 * keys for the credential file and login principal. 146 * 147 * <p><strong>This is only applicable when running on secure hbase</strong> 148 * On regular HBase (without security features), this will safely be ignored. 149 * </p> 150 * 151 * @param conf The configuration data to use 152 * @param keytabFileKey Property key used to configure the path to the credential file 153 * @param userNameKey Property key used to configure the login principal 154 * @param hostname Current hostname to use in any credentials 155 * @throws IOException underlying exception from SecurityUtil.login() call 156 */ 157 public static void loginServer(Configuration conf, String keytabFileKey, 158 String userNameKey, String hostname) throws IOException { 159 login(conf, keytabFileKey, userNameKey, hostname, 160 ZooKeeperSaslServer.LOGIN_CONTEXT_NAME_KEY, 161 JaasConfiguration.SERVER_KEYTAB_KERBEROS_CONFIG_NAME); 162 } 163 164 /** 165 * Log in the current zookeeper client using the given configuration 166 * keys for the credential file and login principal. 167 * 168 * <p><strong>This is only applicable when running on secure hbase</strong> 169 * On regular HBase (without security features), this will safely be ignored. 170 * </p> 171 * 172 * @param conf The configuration data to use 173 * @param keytabFileKey Property key used to configure the path to the credential file 174 * @param userNameKey Property key used to configure the login principal 175 * @param hostname Current hostname to use in any credentials 176 * @throws IOException underlying exception from SecurityUtil.login() call 177 */ 178 public static void loginClient(Configuration conf, String keytabFileKey, 179 String userNameKey, String hostname) throws IOException { 180 login(conf, keytabFileKey, userNameKey, hostname, 181 ZooKeeperSaslClient.LOGIN_CONTEXT_NAME_KEY, 182 JaasConfiguration.CLIENT_KEYTAB_KERBEROS_CONFIG_NAME); 183 } 184 185 /** 186 * Log in the current process using the given configuration keys for the 187 * credential file and login principal. 188 * 189 * <p><strong>This is only applicable when running on secure hbase</strong> 190 * On regular HBase (without security features), this will safely be ignored. 191 * </p> 192 * 193 * @param conf The configuration data to use 194 * @param keytabFileKey Property key used to configure the path to the credential file 195 * @param userNameKey Property key used to configure the login principal 196 * @param hostname Current hostname to use in any credentials 197 * @param loginContextProperty property name to expose the entry name 198 * @param loginContextName jaas entry name 199 * @throws IOException underlying exception from SecurityUtil.login() call 200 */ 201 private static void login(Configuration conf, String keytabFileKey, 202 String userNameKey, String hostname, 203 String loginContextProperty, String loginContextName) 204 throws IOException { 205 if (!isSecureZooKeeper(conf)) { 206 return; 207 } 208 209 // User has specified a jaas.conf, keep this one as the good one. 210 // HBASE_OPTS="-Djava.security.auth.login.config=jaas.conf" 211 if (System.getProperty("java.security.auth.login.config") != null) { 212 return; 213 } 214 215 // No keytab specified, no auth 216 String keytabFilename = conf.get(keytabFileKey); 217 if (keytabFilename == null) { 218 LOG.warn("no keytab specified for: " + keytabFileKey); 219 return; 220 } 221 222 String principalConfig = conf.get(userNameKey, System.getProperty("user.name")); 223 String principalName = SecurityUtil.getServerPrincipal(principalConfig, hostname); 224 225 // Initialize the "jaas.conf" for keyTab/principal, 226 // If keyTab is not specified use the Ticket Cache. 227 // and set the zookeeper login context name. 228 JaasConfiguration jaasConf = new JaasConfiguration(loginContextName, 229 principalName, keytabFilename); 230 javax.security.auth.login.Configuration.setConfiguration(jaasConf); 231 System.setProperty(loginContextProperty, loginContextName); 232 } 233 234 /** 235 * A JAAS configuration that defines the login modules that we want to use for login. 236 */ 237 private static class JaasConfiguration extends javax.security.auth.login.Configuration { 238 private static final String SERVER_KEYTAB_KERBEROS_CONFIG_NAME = 239 "zookeeper-server-keytab-kerberos"; 240 private static final String CLIENT_KEYTAB_KERBEROS_CONFIG_NAME = 241 "zookeeper-client-keytab-kerberos"; 242 243 private static final Map<String, String> BASIC_JAAS_OPTIONS = new HashMap<>(); 244 static { 245 String jaasEnvVar = System.getenv("HBASE_JAAS_DEBUG"); 246 if (jaasEnvVar != null && "true".equalsIgnoreCase(jaasEnvVar)) { 247 BASIC_JAAS_OPTIONS.put("debug", "true"); 248 } 249 } 250 251 private static final Map<String,String> KEYTAB_KERBEROS_OPTIONS = new HashMap<>(); 252 static { 253 KEYTAB_KERBEROS_OPTIONS.put("doNotPrompt", "true"); 254 KEYTAB_KERBEROS_OPTIONS.put("storeKey", "true"); 255 KEYTAB_KERBEROS_OPTIONS.put("refreshKrb5Config", "true"); 256 KEYTAB_KERBEROS_OPTIONS.putAll(BASIC_JAAS_OPTIONS); 257 } 258 259 private static final AppConfigurationEntry KEYTAB_KERBEROS_LOGIN = 260 new AppConfigurationEntry(KerberosUtil.getKrb5LoginModuleName(), 261 LoginModuleControlFlag.REQUIRED, 262 KEYTAB_KERBEROS_OPTIONS); 263 264 private static final AppConfigurationEntry[] KEYTAB_KERBEROS_CONF = 265 new AppConfigurationEntry[]{KEYTAB_KERBEROS_LOGIN}; 266 267 private javax.security.auth.login.Configuration baseConfig; 268 private final String loginContextName; 269 private final boolean useTicketCache; 270 private final String keytabFile; 271 private final String principal; 272 273 public JaasConfiguration(String loginContextName, String principal, String keytabFile) { 274 this(loginContextName, principal, keytabFile, keytabFile == null || keytabFile.length() == 0); 275 } 276 277 private JaasConfiguration(String loginContextName, String principal, 278 String keytabFile, boolean useTicketCache) { 279 try { 280 this.baseConfig = javax.security.auth.login.Configuration.getConfiguration(); 281 } catch (SecurityException e) { 282 this.baseConfig = null; 283 } 284 this.loginContextName = loginContextName; 285 this.useTicketCache = useTicketCache; 286 this.keytabFile = keytabFile; 287 this.principal = principal; 288 LOG.info("JaasConfiguration loginContextName=" + loginContextName + 289 " principal=" + principal + " useTicketCache=" + useTicketCache + 290 " keytabFile=" + keytabFile); 291 } 292 293 @Override 294 public AppConfigurationEntry[] getAppConfigurationEntry(String appName) { 295 if (loginContextName.equals(appName)) { 296 if (!useTicketCache) { 297 KEYTAB_KERBEROS_OPTIONS.put("keyTab", keytabFile); 298 KEYTAB_KERBEROS_OPTIONS.put("useKeyTab", "true"); 299 } 300 KEYTAB_KERBEROS_OPTIONS.put("principal", principal); 301 KEYTAB_KERBEROS_OPTIONS.put("useTicketCache", useTicketCache ? "true" : "false"); 302 return KEYTAB_KERBEROS_CONF; 303 } 304 305 if (baseConfig != null) { 306 return baseConfig.getAppConfigurationEntry(appName); 307 } 308 309 return(null); 310 } 311 } 312 313 // 314 // Helper methods 315 // 316 /** 317 * Returns the full path of the immediate parent of the specified node. 318 * @param node path to get parent of 319 * @return parent of path, null if passed the root node or an invalid node 320 */ 321 public static String getParent(String node) { 322 int idx = node.lastIndexOf(ZNodePaths.ZNODE_PATH_SEPARATOR); 323 return idx <= 0 ? null : node.substring(0, idx); 324 } 325 326 /** 327 * Get the name of the current node from the specified fully-qualified path. 328 * @param path fully-qualified path 329 * @return name of the current node 330 */ 331 public static String getNodeName(String path) { 332 return path.substring(path.lastIndexOf("/")+1); 333 } 334 335 // 336 // Existence checks and watches 337 // 338 339 /** 340 * Watch the specified znode for delete/create/change events. The watcher is 341 * set whether or not the node exists. If the node already exists, the method 342 * returns true. If the node does not exist, the method returns false. 343 * 344 * @param zkw zk reference 345 * @param znode path of node to watch 346 * @return true if znode exists, false if does not exist or error 347 * @throws KeeperException if unexpected zookeeper exception 348 */ 349 public static boolean watchAndCheckExists(ZKWatcher zkw, String znode) 350 throws KeeperException { 351 try { 352 Stat s = zkw.getRecoverableZooKeeper().exists(znode, zkw); 353 boolean exists = s != null ? true : false; 354 if (exists) { 355 LOG.debug(zkw.prefix("Set watcher on existing znode=" + znode)); 356 } else { 357 LOG.debug(zkw.prefix("Set watcher on znode that does not yet exist, " + znode)); 358 } 359 return exists; 360 } catch (KeeperException e) { 361 LOG.warn(zkw.prefix("Unable to set watcher on znode " + znode), e); 362 zkw.keeperException(e); 363 return false; 364 } catch (InterruptedException e) { 365 LOG.warn(zkw.prefix("Unable to set watcher on znode " + znode), e); 366 zkw.interruptedException(e); 367 return false; 368 } 369 } 370 371 /** 372 * Watch the specified znode, but only if exists. Useful when watching 373 * for deletions. Uses .getData() (and handles NoNodeException) instead 374 * of .exists() to accomplish this, as .getData() will only set a watch if 375 * the znode exists. 376 * @param zkw zk reference 377 * @param znode path of node to watch 378 * @return true if the watch is set, false if node does not exists 379 * @throws KeeperException if unexpected zookeeper exception 380 */ 381 public static boolean setWatchIfNodeExists(ZKWatcher zkw, String znode) 382 throws KeeperException { 383 try { 384 zkw.getRecoverableZooKeeper().getData(znode, true, null); 385 return true; 386 } catch (NoNodeException e) { 387 return false; 388 } catch (InterruptedException e) { 389 LOG.warn(zkw.prefix("Unable to set watcher on znode " + znode), e); 390 zkw.interruptedException(e); 391 return false; 392 } 393 } 394 395 /** 396 * Check if the specified node exists. Sets no watches. 397 * 398 * @param zkw zk reference 399 * @param znode path of node to watch 400 * @return version of the node if it exists, -1 if does not exist 401 * @throws KeeperException if unexpected zookeeper exception 402 */ 403 public static int checkExists(ZKWatcher zkw, String znode) 404 throws KeeperException { 405 try { 406 Stat s = zkw.getRecoverableZooKeeper().exists(znode, null); 407 return s != null ? s.getVersion() : -1; 408 } catch (KeeperException e) { 409 LOG.warn(zkw.prefix("Unable to set watcher on znode (" + znode + ")"), e); 410 zkw.keeperException(e); 411 return -1; 412 } catch (InterruptedException e) { 413 LOG.warn(zkw.prefix("Unable to set watcher on znode (" + znode + ")"), e); 414 zkw.interruptedException(e); 415 return -1; 416 } 417 } 418 419 // 420 // Znode listings 421 // 422 423 /** 424 * Lists the children znodes of the specified znode. Also sets a watch on 425 * the specified znode which will capture a NodeDeleted event on the specified 426 * znode as well as NodeChildrenChanged if any children of the specified znode 427 * are created or deleted. 428 * 429 * Returns null if the specified node does not exist. Otherwise returns a 430 * list of children of the specified node. If the node exists but it has no 431 * children, an empty list will be returned. 432 * 433 * @param zkw zk reference 434 * @param znode path of node to list and watch children of 435 * @return list of children of the specified node, an empty list if the node 436 * exists but has no children, and null if the node does not exist 437 * @throws KeeperException if unexpected zookeeper exception 438 */ 439 public static List<String> listChildrenAndWatchForNewChildren( 440 ZKWatcher zkw, String znode) 441 throws KeeperException { 442 try { 443 List<String> children = zkw.getRecoverableZooKeeper().getChildren(znode, zkw); 444 return children; 445 } catch(KeeperException.NoNodeException ke) { 446 LOG.debug(zkw.prefix("Unable to list children of znode " + znode + " " + 447 "because node does not exist (not an error)")); 448 return null; 449 } catch (KeeperException e) { 450 LOG.warn(zkw.prefix("Unable to list children of znode " + znode + " "), e); 451 zkw.keeperException(e); 452 return null; 453 } catch (InterruptedException e) { 454 LOG.warn(zkw.prefix("Unable to list children of znode " + znode + " "), e); 455 zkw.interruptedException(e); 456 return null; 457 } 458 } 459 460 /** 461 * List all the children of the specified znode, setting a watch for children 462 * changes and also setting a watch on every individual child in order to get 463 * the NodeCreated and NodeDeleted events. 464 * @param zkw zookeeper reference 465 * @param znode node to get children of and watch 466 * @return list of znode names, null if the node doesn't exist 467 * @throws KeeperException if a ZooKeeper operation fails 468 */ 469 public static List<String> listChildrenAndWatchThem(ZKWatcher zkw, 470 String znode) throws KeeperException { 471 List<String> children = listChildrenAndWatchForNewChildren(zkw, znode); 472 if (children == null) { 473 return null; 474 } 475 for (String child : children) { 476 watchAndCheckExists(zkw, ZNodePaths.joinZNode(znode, child)); 477 } 478 return children; 479 } 480 481 /** 482 * Lists the children of the specified znode without setting any watches. 483 * 484 * Sets no watches at all, this method is best effort. 485 * 486 * Returns an empty list if the node has no children. Returns null if the 487 * parent node itself does not exist. 488 * 489 * @param zkw zookeeper reference 490 * @param znode node to get children 491 * @return list of data of children of specified znode, empty if no children, 492 * null if parent does not exist 493 * @throws KeeperException if unexpected zookeeper exception 494 */ 495 public static List<String> listChildrenNoWatch(ZKWatcher zkw, String znode) 496 throws KeeperException { 497 List<String> children = null; 498 try { 499 // List the children without watching 500 children = zkw.getRecoverableZooKeeper().getChildren(znode, null); 501 } catch(KeeperException.NoNodeException nne) { 502 return null; 503 } catch(InterruptedException ie) { 504 zkw.interruptedException(ie); 505 } 506 return children; 507 } 508 509 /** 510 * Simple class to hold a node path and node data. 511 * @deprecated Unused 512 */ 513 @Deprecated 514 public static class NodeAndData { 515 private String node; 516 private byte [] data; 517 public NodeAndData(String node, byte [] data) { 518 this.node = node; 519 this.data = data; 520 } 521 public String getNode() { 522 return node; 523 } 524 public byte [] getData() { 525 return data; 526 } 527 @Override 528 public String toString() { 529 return node; 530 } 531 public boolean isEmpty() { 532 return (data == null || data.length == 0); 533 } 534 } 535 536 /** 537 * Checks if the specified znode has any children. Sets no watches. 538 * 539 * Returns true if the node exists and has children. Returns false if the 540 * node does not exist or if the node does not have any children. 541 * 542 * Used during master initialization to determine if the master is a 543 * failed-over-to master or the first master during initial cluster startup. 544 * If the directory for regionserver ephemeral nodes is empty then this is 545 * a cluster startup, if not then it is not cluster startup. 546 * 547 * @param zkw zk reference 548 * @param znode path of node to check for children of 549 * @return true if node has children, false if not or node does not exist 550 * @throws KeeperException if unexpected zookeeper exception 551 */ 552 public static boolean nodeHasChildren(ZKWatcher zkw, String znode) 553 throws KeeperException { 554 try { 555 return !zkw.getRecoverableZooKeeper().getChildren(znode, null).isEmpty(); 556 } catch(KeeperException.NoNodeException ke) { 557 LOG.debug(zkw.prefix("Unable to list children of znode " + znode + 558 " because node does not exist (not an error)")); 559 return false; 560 } catch (KeeperException e) { 561 LOG.warn(zkw.prefix("Unable to list children of znode " + znode), e); 562 zkw.keeperException(e); 563 return false; 564 } catch (InterruptedException e) { 565 LOG.warn(zkw.prefix("Unable to list children of znode " + znode), e); 566 zkw.interruptedException(e); 567 return false; 568 } 569 } 570 571 /** 572 * Get the number of children of the specified node. 573 * 574 * If the node does not exist or has no children, returns 0. 575 * 576 * Sets no watches at all. 577 * 578 * @param zkw zk reference 579 * @param znode path of node to count children of 580 * @return number of children of specified node, 0 if none or parent does not 581 * exist 582 * @throws KeeperException if unexpected zookeeper exception 583 */ 584 public static int getNumberOfChildren(ZKWatcher zkw, String znode) 585 throws KeeperException { 586 try { 587 Stat stat = zkw.getRecoverableZooKeeper().exists(znode, null); 588 return stat == null ? 0 : stat.getNumChildren(); 589 } catch(KeeperException e) { 590 LOG.warn(zkw.prefix("Unable to get children of node " + znode)); 591 zkw.keeperException(e); 592 } catch(InterruptedException e) { 593 zkw.interruptedException(e); 594 } 595 return 0; 596 } 597 598 // 599 // Data retrieval 600 // 601 602 /** 603 * Get znode data. Does not set a watcher. 604 * 605 * @return ZNode data, null if the node does not exist or if there is an error. 606 */ 607 public static byte [] getData(ZKWatcher zkw, String znode) 608 throws KeeperException, InterruptedException { 609 try { 610 byte [] data = zkw.getRecoverableZooKeeper().getData(znode, null, null); 611 logRetrievedMsg(zkw, znode, data, false); 612 return data; 613 } catch (KeeperException.NoNodeException e) { 614 LOG.debug(zkw.prefix("Unable to get data of znode " + znode + " " + 615 "because node does not exist (not an error)")); 616 return null; 617 } catch (KeeperException e) { 618 LOG.warn(zkw.prefix("Unable to get data of znode " + znode), e); 619 zkw.keeperException(e); 620 return null; 621 } 622 } 623 624 /** 625 * Get the data at the specified znode and set a watch. 626 * 627 * Returns the data and sets a watch if the node exists. Returns null and no 628 * watch is set if the node does not exist or there is an exception. 629 * 630 * @param zkw zk reference 631 * @param znode path of node 632 * @return data of the specified znode, or null 633 * @throws KeeperException if unexpected zookeeper exception 634 */ 635 public static byte [] getDataAndWatch(ZKWatcher zkw, String znode) 636 throws KeeperException { 637 return getDataInternal(zkw, znode, null, true); 638 } 639 640 /** 641 * Get the data at the specified znode and set a watch. 642 * 643 * Returns the data and sets a watch if the node exists. Returns null and no 644 * watch is set if the node does not exist or there is an exception. 645 * 646 * @param zkw zk reference 647 * @param znode path of node 648 * @param stat object to populate the version of the znode 649 * @return data of the specified znode, or null 650 * @throws KeeperException if unexpected zookeeper exception 651 */ 652 public static byte[] getDataAndWatch(ZKWatcher zkw, String znode, 653 Stat stat) throws KeeperException { 654 return getDataInternal(zkw, znode, stat, true); 655 } 656 657 private static byte[] getDataInternal(ZKWatcher zkw, String znode, Stat stat, 658 boolean watcherSet) 659 throws KeeperException { 660 try { 661 byte [] data = zkw.getRecoverableZooKeeper().getData(znode, zkw, stat); 662 logRetrievedMsg(zkw, znode, data, watcherSet); 663 return data; 664 } catch (KeeperException.NoNodeException e) { 665 // This log can get pretty annoying when we cycle on 100ms waits. 666 // Enable trace if you really want to see it. 667 LOG.trace(zkw.prefix("Unable to get data of znode " + znode + " " + 668 "because node does not exist (not an error)")); 669 return null; 670 } catch (KeeperException e) { 671 LOG.warn(zkw.prefix("Unable to get data of znode " + znode), e); 672 zkw.keeperException(e); 673 return null; 674 } catch (InterruptedException e) { 675 LOG.warn(zkw.prefix("Unable to get data of znode " + znode), e); 676 zkw.interruptedException(e); 677 return null; 678 } 679 } 680 681 /** 682 * Get the data at the specified znode without setting a watch. 683 * 684 * Returns the data if the node exists. Returns null if the node does not 685 * exist. 686 * 687 * Sets the stats of the node in the passed Stat object. Pass a null stat if 688 * not interested. 689 * 690 * @param zkw zk reference 691 * @param znode path of node 692 * @param stat node status to get if node exists 693 * @return data of the specified znode, or null if node does not exist 694 * @throws KeeperException if unexpected zookeeper exception 695 */ 696 public static byte [] getDataNoWatch(ZKWatcher zkw, String znode, 697 Stat stat) 698 throws KeeperException { 699 try { 700 byte [] data = zkw.getRecoverableZooKeeper().getData(znode, null, stat); 701 logRetrievedMsg(zkw, znode, data, false); 702 return data; 703 } catch (KeeperException.NoNodeException e) { 704 LOG.debug(zkw.prefix("Unable to get data of znode " + znode + " " + 705 "because node does not exist (not necessarily an error)")); 706 return null; 707 } catch (KeeperException e) { 708 LOG.warn(zkw.prefix("Unable to get data of znode " + znode), e); 709 zkw.keeperException(e); 710 return null; 711 } catch (InterruptedException e) { 712 LOG.warn(zkw.prefix("Unable to get data of znode " + znode), e); 713 zkw.interruptedException(e); 714 return null; 715 } 716 } 717 718 /** 719 * Returns the date of child znodes of the specified znode. Also sets a watch on 720 * the specified znode which will capture a NodeDeleted event on the specified 721 * znode as well as NodeChildrenChanged if any children of the specified znode 722 * are created or deleted. 723 * 724 * Returns null if the specified node does not exist. Otherwise returns a 725 * list of children of the specified node. If the node exists but it has no 726 * children, an empty list will be returned. 727 * 728 * @param zkw zk reference 729 * @param baseNode path of node to list and watch children of 730 * @return list of data of children of the specified node, an empty list if the node 731 * exists but has no children, and null if the node does not exist 732 * @throws KeeperException if unexpected zookeeper exception 733 * @deprecated Unused 734 */ 735 @Deprecated 736 public static List<NodeAndData> getChildDataAndWatchForNewChildren( 737 ZKWatcher zkw, String baseNode) throws KeeperException { 738 List<String> nodes = 739 ZKUtil.listChildrenAndWatchForNewChildren(zkw, baseNode); 740 if (nodes != null) { 741 List<NodeAndData> newNodes = new ArrayList<>(); 742 for (String node : nodes) { 743 String nodePath = ZNodePaths.joinZNode(baseNode, node); 744 byte[] data = ZKUtil.getDataAndWatch(zkw, nodePath); 745 newNodes.add(new NodeAndData(nodePath, data)); 746 } 747 return newNodes; 748 } 749 return null; 750 } 751 752 /** 753 * Update the data of an existing node with the expected version to have the 754 * specified data. 755 * 756 * Throws an exception if there is a version mismatch or some other problem. 757 * 758 * Sets no watches under any conditions. 759 * 760 * @param zkw zk reference 761 * @param znode the path to the ZNode 762 * @param data the data to store in ZooKeeper 763 * @param expectedVersion the expected version 764 * @throws KeeperException if unexpected zookeeper exception 765 * @throws KeeperException.BadVersionException if version mismatch 766 * @deprecated Unused 767 */ 768 @Deprecated 769 public static void updateExistingNodeData(ZKWatcher zkw, String znode, byte[] data, 770 int expectedVersion) throws KeeperException { 771 try { 772 zkw.getRecoverableZooKeeper().setData(znode, data, expectedVersion); 773 } catch(InterruptedException ie) { 774 zkw.interruptedException(ie); 775 } 776 } 777 778 // 779 // Data setting 780 // 781 782 /** 783 * Sets the data of the existing znode to be the specified data. Ensures that 784 * the current data has the specified expected version. 785 * 786 * <p>If the node does not exist, a {@link NoNodeException} will be thrown. 787 * 788 * <p>If their is a version mismatch, method returns null. 789 * 790 * <p>No watches are set but setting data will trigger other watchers of this 791 * node. 792 * 793 * <p>If there is another problem, a KeeperException will be thrown. 794 * 795 * @param zkw zk reference 796 * @param znode path of node 797 * @param data data to set for node 798 * @param expectedVersion version expected when setting data 799 * @return true if data set, false if version mismatch 800 * @throws KeeperException if unexpected zookeeper exception 801 */ 802 public static boolean setData(ZKWatcher zkw, String znode, 803 byte [] data, int expectedVersion) 804 throws KeeperException, KeeperException.NoNodeException { 805 try { 806 return zkw.getRecoverableZooKeeper().setData(znode, data, expectedVersion) != null; 807 } catch (InterruptedException e) { 808 zkw.interruptedException(e); 809 return false; 810 } 811 } 812 813 /** 814 * Set data into node creating node if it doesn't yet exist. 815 * Does not set watch. 816 * 817 * @param zkw zk reference 818 * @param znode path of node 819 * @param data data to set for node 820 * @throws KeeperException if a ZooKeeper operation fails 821 */ 822 public static void createSetData(final ZKWatcher zkw, final String znode, final byte [] data) 823 throws KeeperException { 824 if (checkExists(zkw, znode) == -1) { 825 ZKUtil.createWithParents(zkw, znode, data); 826 } else { 827 ZKUtil.setData(zkw, znode, data); 828 } 829 } 830 831 /** 832 * Sets the data of the existing znode to be the specified data. The node 833 * must exist but no checks are done on the existing data or version. 834 * 835 * <p>If the node does not exist, a {@link NoNodeException} will be thrown. 836 * 837 * <p>No watches are set but setting data will trigger other watchers of this 838 * node. 839 * 840 * <p>If there is another problem, a KeeperException will be thrown. 841 * 842 * @param zkw zk reference 843 * @param znode path of node 844 * @param data data to set for node 845 * @throws KeeperException if unexpected zookeeper exception 846 */ 847 public static void setData(ZKWatcher zkw, String znode, byte [] data) 848 throws KeeperException, KeeperException.NoNodeException { 849 setData(zkw, (SetData)ZKUtilOp.setData(znode, data)); 850 } 851 852 private static void setData(ZKWatcher zkw, SetData setData) 853 throws KeeperException, KeeperException.NoNodeException { 854 SetDataRequest sd = (SetDataRequest)toZooKeeperOp(zkw, setData).toRequestRecord(); 855 setData(zkw, sd.getPath(), sd.getData(), sd.getVersion()); 856 } 857 858 /** 859 * Returns whether or not secure authentication is enabled 860 * (whether <code>hbase.security.authentication</code> is set to 861 * <code>kerberos</code>. 862 */ 863 public static boolean isSecureZooKeeper(Configuration conf) { 864 // Detection for embedded HBase client with jaas configuration 865 // defined for third party programs. 866 try { 867 javax.security.auth.login.Configuration testConfig = 868 javax.security.auth.login.Configuration.getConfiguration(); 869 if (testConfig.getAppConfigurationEntry("Client") == null 870 && testConfig.getAppConfigurationEntry( 871 JaasConfiguration.CLIENT_KEYTAB_KERBEROS_CONFIG_NAME) == null 872 && testConfig.getAppConfigurationEntry( 873 JaasConfiguration.SERVER_KEYTAB_KERBEROS_CONFIG_NAME) == null 874 && conf.get(HConstants.ZK_CLIENT_KERBEROS_PRINCIPAL) == null 875 && conf.get(HConstants.ZK_SERVER_KERBEROS_PRINCIPAL) == null) { 876 877 return false; 878 } 879 } catch(Exception e) { 880 // No Jaas configuration defined. 881 return false; 882 } 883 884 // Master & RSs uses hbase.zookeeper.client.* 885 return "kerberos".equalsIgnoreCase(conf.get("hbase.security.authentication")); 886 } 887 888 private static ArrayList<ACL> createACL(ZKWatcher zkw, String node) { 889 return createACL(zkw, node, isSecureZooKeeper(zkw.getConfiguration())); 890 } 891 892 public static ArrayList<ACL> createACL(ZKWatcher zkw, String node, 893 boolean isSecureZooKeeper) { 894 if (!node.startsWith(zkw.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 // atleast one element should exist 1397 if (ops.size() > 0) { 1398 multiOrSequential(zkw, ops, runSequentialOnMultiFailure); 1399 } 1400 } 1401 1402 /** 1403 * BFS Traversal of all the children under path, with the entries in the list, 1404 * in the same order as that of the traversal. Lists all the children without 1405 * setting any watches. 1406 * 1407 * @param zkw 1408 * - zk reference 1409 * @param znode 1410 * - path of node 1411 * @return list of children znodes under the path 1412 * @throws KeeperException 1413 * if unexpected ZooKeeper exception 1414 */ 1415 private static List<String> listChildrenBFSNoWatch(ZKWatcher zkw, 1416 final String znode) throws KeeperException { 1417 Deque<String> queue = new LinkedList<>(); 1418 List<String> tree = new ArrayList<>(); 1419 queue.add(znode); 1420 while (true) { 1421 String node = queue.pollFirst(); 1422 if (node == null) { 1423 break; 1424 } 1425 List<String> children = listChildrenNoWatch(zkw, node); 1426 if (children == null) { 1427 continue; 1428 } 1429 for (final String child : children) { 1430 final String childPath = node + "/" + child; 1431 queue.add(childPath); 1432 tree.add(childPath); 1433 } 1434 } 1435 return tree; 1436 } 1437 1438 /** 1439 * BFS Traversal of all the children under path, with the entries in the list, 1440 * in the same order as that of the traversal. 1441 * Lists all the children and set watches on to them. 1442 * 1443 * @param zkw 1444 * - zk reference 1445 * @param znode 1446 * - path of node 1447 * @return list of children znodes under the path 1448 * @throws KeeperException 1449 * if unexpected ZooKeeper exception 1450 */ 1451 private static List<String> listChildrenBFSAndWatchThem(ZKWatcher zkw, final String znode) 1452 throws KeeperException { 1453 Deque<String> queue = new LinkedList<>(); 1454 List<String> tree = new ArrayList<>(); 1455 queue.add(znode); 1456 while (true) { 1457 String node = queue.pollFirst(); 1458 if (node == null) { 1459 break; 1460 } 1461 List<String> children = listChildrenAndWatchThem(zkw, node); 1462 if (children == null) { 1463 continue; 1464 } 1465 for (final String child : children) { 1466 final String childPath = node + "/" + child; 1467 queue.add(childPath); 1468 tree.add(childPath); 1469 } 1470 } 1471 return tree; 1472 } 1473 1474 /** 1475 * Represents an action taken by ZKUtil, e.g. createAndFailSilent. 1476 * These actions are higher-level than ZKOp actions, which represent 1477 * individual actions in the ZooKeeper API, like create. 1478 */ 1479 public abstract static class ZKUtilOp { 1480 private String path; 1481 1482 private ZKUtilOp(String path) { 1483 this.path = path; 1484 } 1485 1486 /** 1487 * @return a createAndFailSilent ZKUtilOp 1488 */ 1489 public static ZKUtilOp createAndFailSilent(String path, byte[] data) { 1490 return new CreateAndFailSilent(path, data); 1491 } 1492 1493 /** 1494 * @return a deleteNodeFailSilent ZKUtilOP 1495 */ 1496 public static ZKUtilOp deleteNodeFailSilent(String path) { 1497 return new DeleteNodeFailSilent(path); 1498 } 1499 1500 /** 1501 * @return a setData ZKUtilOp 1502 */ 1503 public static ZKUtilOp setData(String path, byte [] data) { 1504 return new SetData(path, data); 1505 } 1506 1507 /** 1508 * @return 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 for (String child : listChildrenNoWatch(zkw, zkw.znodePaths.backupMasterAddressesZNode)) { 1727 sb.append("\n ").append(child); 1728 } 1729 sb.append("\nRegion server holding hbase:meta: " 1730 + new MetaTableLocator().getMetaRegionLocation(zkw)); 1731 Configuration conf = HBaseConfiguration.create(); 1732 int numMetaReplicas = conf.getInt(HConstants.META_REPLICAS_NUM, 1733 HConstants.DEFAULT_META_REPLICA_NUM); 1734 for (int i = 1; i < numMetaReplicas; i++) { 1735 sb.append("\nRegion server holding hbase:meta, replicaId " + i + " " 1736 + new MetaTableLocator().getMetaRegionLocation(zkw, i)); 1737 } 1738 sb.append("\nRegion servers:"); 1739 for (String child : listChildrenNoWatch(zkw, zkw.znodePaths.rsZNode)) { 1740 sb.append("\n ").append(child); 1741 } 1742 try { 1743 getReplicationZnodesDump(zkw, sb); 1744 } catch (KeeperException ke) { 1745 LOG.warn("Couldn't get the replication znode dump", ke); 1746 } 1747 sb.append("\nQuorum Server Statistics:"); 1748 String[] servers = zkw.getQuorum().split(","); 1749 for (String server : servers) { 1750 sb.append("\n ").append(server); 1751 try { 1752 String[] stat = getServerStats(server, ZKUtil.zkDumpConnectionTimeOut); 1753 1754 if (stat == null) { 1755 sb.append("[Error] invalid quorum server: " + server); 1756 break; 1757 } 1758 1759 for (String s : stat) { 1760 sb.append("\n ").append(s); 1761 } 1762 } catch (Exception e) { 1763 sb.append("\n ERROR: ").append(e.getMessage()); 1764 } 1765 } 1766 } catch (KeeperException ke) { 1767 sb.append("\nFATAL ZooKeeper Exception!\n"); 1768 sb.append("\n" + ke.getMessage()); 1769 } 1770 return sb.toString(); 1771 } 1772 1773 /** 1774 * Appends replication znodes to the passed StringBuilder. 1775 * 1776 * @param zkw reference to the {@link ZKWatcher} which also contains configuration and operation 1777 * @param sb the {@link StringBuilder} to append to 1778 * @throws KeeperException if a ZooKeeper operation fails 1779 */ 1780 private static void getReplicationZnodesDump(ZKWatcher zkw, StringBuilder sb) 1781 throws KeeperException { 1782 String replicationZnode = zkw.znodePaths.replicationZNode; 1783 1784 if (ZKUtil.checkExists(zkw, replicationZnode) == -1) { 1785 return; 1786 } 1787 1788 // do a ls -r on this znode 1789 sb.append("\n").append(replicationZnode).append(": "); 1790 List<String> children = ZKUtil.listChildrenNoWatch(zkw, replicationZnode); 1791 for (String child : children) { 1792 String znode = ZNodePaths.joinZNode(replicationZnode, child); 1793 if (znode.equals(zkw.znodePaths.peersZNode)) { 1794 appendPeersZnodes(zkw, znode, sb); 1795 } else if (znode.equals(zkw.znodePaths.queuesZNode)) { 1796 appendRSZnodes(zkw, znode, sb); 1797 } else if (znode.equals(zkw.znodePaths.hfileRefsZNode)) { 1798 appendHFileRefsZnodes(zkw, znode, sb); 1799 } 1800 } 1801 } 1802 1803 private static void appendHFileRefsZnodes(ZKWatcher zkw, String hfileRefsZnode, 1804 StringBuilder sb) throws KeeperException { 1805 sb.append("\n").append(hfileRefsZnode).append(": "); 1806 for (String peerIdZnode : ZKUtil.listChildrenNoWatch(zkw, hfileRefsZnode)) { 1807 String znodeToProcess = ZNodePaths.joinZNode(hfileRefsZnode, peerIdZnode); 1808 sb.append("\n").append(znodeToProcess).append(": "); 1809 List<String> peerHFileRefsZnodes = ZKUtil.listChildrenNoWatch(zkw, znodeToProcess); 1810 int size = peerHFileRefsZnodes.size(); 1811 for (int i = 0; i < size; i++) { 1812 sb.append(peerHFileRefsZnodes.get(i)); 1813 if (i != size - 1) { 1814 sb.append(", "); 1815 } 1816 } 1817 } 1818 } 1819 1820 /** 1821 * Returns a string with replication znodes and position of the replication log 1822 * @param zkw reference to the {@link ZKWatcher} which also contains configuration and operation 1823 * @return aq string of replication znodes and log positions 1824 */ 1825 public static String getReplicationZnodesDump(ZKWatcher zkw) throws KeeperException { 1826 StringBuilder sb = new StringBuilder(); 1827 getReplicationZnodesDump(zkw, sb); 1828 return sb.toString(); 1829 } 1830 1831 private static void appendRSZnodes(ZKWatcher zkw, String znode, StringBuilder sb) 1832 throws KeeperException { 1833 List<String> stack = new LinkedList<>(); 1834 stack.add(znode); 1835 do { 1836 String znodeToProcess = stack.remove(stack.size() - 1); 1837 sb.append("\n").append(znodeToProcess).append(": "); 1838 byte[] data; 1839 try { 1840 data = ZKUtil.getData(zkw, znodeToProcess); 1841 } catch (InterruptedException e) { 1842 zkw.interruptedException(e); 1843 return; 1844 } 1845 if (data != null && data.length > 0) { // log position 1846 long position = 0; 1847 try { 1848 position = ZKUtil.parseWALPositionFrom(ZKUtil.getData(zkw, znodeToProcess)); 1849 sb.append(position); 1850 } catch (DeserializationException ignored) { 1851 } catch (InterruptedException e) { 1852 zkw.interruptedException(e); 1853 return; 1854 } 1855 } 1856 for (String zNodeChild : ZKUtil.listChildrenNoWatch(zkw, znodeToProcess)) { 1857 stack.add(ZNodePaths.joinZNode(znodeToProcess, zNodeChild)); 1858 } 1859 } while (stack.size() > 0); 1860 } 1861 1862 private static void appendPeersZnodes(ZKWatcher zkw, String peersZnode, 1863 StringBuilder sb) throws KeeperException { 1864 int pblen = ProtobufUtil.lengthOfPBMagic(); 1865 sb.append("\n").append(peersZnode).append(": "); 1866 for (String peerIdZnode : ZKUtil.listChildrenNoWatch(zkw, peersZnode)) { 1867 String znodeToProcess = ZNodePaths.joinZNode(peersZnode, peerIdZnode); 1868 byte[] data; 1869 try { 1870 data = ZKUtil.getData(zkw, znodeToProcess); 1871 } catch (InterruptedException e) { 1872 zkw.interruptedException(e); 1873 return; 1874 } 1875 // parse the data of the above peer znode. 1876 try { 1877 ReplicationProtos.ReplicationPeer.Builder builder = 1878 ReplicationProtos.ReplicationPeer.newBuilder(); 1879 ProtobufUtil.mergeFrom(builder, data, pblen, data.length - pblen); 1880 String clusterKey = builder.getClusterkey(); 1881 sb.append("\n").append(znodeToProcess).append(": ").append(clusterKey); 1882 // add the peer-state. 1883 appendPeerState(zkw, znodeToProcess, sb); 1884 } catch (IOException ipbe) { 1885 LOG.warn("Got Exception while parsing peer: " + znodeToProcess, ipbe); 1886 } 1887 } 1888 } 1889 1890 private static void appendPeerState(ZKWatcher zkw, String znodeToProcess, StringBuilder sb) 1891 throws KeeperException, InvalidProtocolBufferException { 1892 String peerState = zkw.getConfiguration().get("zookeeper.znode.replication.peers.state", 1893 "peer-state"); 1894 int pblen = ProtobufUtil.lengthOfPBMagic(); 1895 for (String child : ZKUtil.listChildrenNoWatch(zkw, znodeToProcess)) { 1896 if (!child.equals(peerState)) { 1897 continue; 1898 } 1899 1900 String peerStateZnode = ZNodePaths.joinZNode(znodeToProcess, child); 1901 sb.append("\n").append(peerStateZnode).append(": "); 1902 byte[] peerStateData; 1903 try { 1904 peerStateData = ZKUtil.getData(zkw, peerStateZnode); 1905 ReplicationProtos.ReplicationState.Builder builder = 1906 ReplicationProtos.ReplicationState.newBuilder(); 1907 ProtobufUtil.mergeFrom(builder, peerStateData, pblen, peerStateData.length - pblen); 1908 sb.append(builder.getState().name()); 1909 } catch (IOException ipbe) { 1910 LOG.warn("Got Exception while parsing peer: " + znodeToProcess, ipbe); 1911 } catch (InterruptedException e) { 1912 zkw.interruptedException(e); 1913 return; 1914 } 1915 } 1916 } 1917 1918 /** 1919 * Gets the statistics from the given server. 1920 * 1921 * @param server The server to get the statistics from. 1922 * @param timeout The socket timeout to use. 1923 * @return The array of response strings. 1924 * @throws IOException When the socket communication fails. 1925 */ 1926 public static String[] getServerStats(String server, int timeout) 1927 throws IOException { 1928 String[] sp = server.split(":"); 1929 if (sp == null || sp.length == 0) { 1930 return null; 1931 } 1932 1933 String host = sp[0]; 1934 int port = sp.length > 1 ? Integer.parseInt(sp[1]) 1935 : HConstants.DEFAULT_ZOOKEPER_CLIENT_PORT; 1936 1937 InetSocketAddress sockAddr = new InetSocketAddress(host, port); 1938 try (Socket socket = new Socket()) { 1939 socket.connect(sockAddr, timeout); 1940 1941 socket.setSoTimeout(timeout); 1942 try (PrintWriter out = new PrintWriter(new BufferedWriter( 1943 new OutputStreamWriter(socket.getOutputStream(), StandardCharsets.UTF_8)), true); 1944 BufferedReader in = new BufferedReader( 1945 new InputStreamReader(socket.getInputStream(), StandardCharsets.UTF_8))) { 1946 out.println("stat"); 1947 out.flush(); 1948 ArrayList<String> res = new ArrayList<>(); 1949 while (true) { 1950 String line = in.readLine(); 1951 if (line != null) { 1952 res.add(line); 1953 } else { 1954 break; 1955 } 1956 } 1957 return res.toArray(new String[res.size()]); 1958 } 1959 } 1960 } 1961 1962 private static void logRetrievedMsg(final ZKWatcher zkw, 1963 final String znode, final byte [] data, final boolean watcherSet) { 1964 if (!LOG.isTraceEnabled()) { 1965 return; 1966 } 1967 1968 LOG.trace(zkw.prefix("Retrieved " + ((data == null)? 0: data.length) + 1969 " byte(s) of data from znode " + znode + 1970 (watcherSet? " and set watcher; ": "; data=") + 1971 (data == null? "null": data.length == 0? "empty": ( 1972 znode.startsWith(zkw.znodePaths.metaZNodePrefix)? 1973 getServerNameOrEmptyString(data): 1974 znode.startsWith(zkw.znodePaths.backupMasterAddressesZNode)? 1975 getServerNameOrEmptyString(data): 1976 StringUtils.abbreviate(Bytes.toStringBinary(data), 32))))); 1977 } 1978 1979 private static String getServerNameOrEmptyString(final byte [] data) { 1980 try { 1981 return ProtobufUtil.parseServerNameFrom(data).toString(); 1982 } catch (DeserializationException e) { 1983 return ""; 1984 } 1985 } 1986 1987 /** 1988 * Waits for HBase installation's base (parent) znode to become available. 1989 * @throws IOException on ZK errors 1990 */ 1991 public static void waitForBaseZNode(Configuration conf) throws IOException { 1992 LOG.info("Waiting until the base znode is available"); 1993 String parentZNode = conf.get(HConstants.ZOOKEEPER_ZNODE_PARENT, 1994 HConstants.DEFAULT_ZOOKEEPER_ZNODE_PARENT); 1995 ZooKeeper zk = new ZooKeeper(ZKConfig.getZKQuorumServersString(conf), 1996 conf.getInt(HConstants.ZK_SESSION_TIMEOUT, 1997 HConstants.DEFAULT_ZK_SESSION_TIMEOUT), EmptyWatcher.instance); 1998 1999 final int maxTimeMs = 10000; 2000 final int maxNumAttempts = maxTimeMs / HConstants.SOCKET_RETRY_WAIT_MS; 2001 2002 KeeperException keeperEx = null; 2003 try { 2004 try { 2005 for (int attempt = 0; attempt < maxNumAttempts; ++attempt) { 2006 try { 2007 if (zk.exists(parentZNode, false) != null) { 2008 LOG.info("Parent znode exists: " + parentZNode); 2009 keeperEx = null; 2010 break; 2011 } 2012 } catch (KeeperException e) { 2013 keeperEx = e; 2014 } 2015 Threads.sleepWithoutInterrupt(HConstants.SOCKET_RETRY_WAIT_MS); 2016 } 2017 } finally { 2018 zk.close(); 2019 } 2020 } catch (InterruptedException ex) { 2021 Thread.currentThread().interrupt(); 2022 } 2023 2024 if (keeperEx != null) { 2025 throw new IOException(keeperEx); 2026 } 2027 } 2028 2029 /** 2030 * Convert a {@link DeserializationException} to a more palatable {@link KeeperException}. 2031 * Used when can't let a {@link DeserializationException} out w/o changing public API. 2032 * @param e Exception to convert 2033 * @return Converted exception 2034 */ 2035 public static KeeperException convert(final DeserializationException e) { 2036 KeeperException ke = new KeeperException.DataInconsistencyException(); 2037 ke.initCause(e); 2038 return ke; 2039 } 2040 2041 /** 2042 * Recursively print the current state of ZK (non-transactional) 2043 * @param root name of the root directory in zk to print 2044 */ 2045 public static void logZKTree(ZKWatcher zkw, String root) { 2046 if (!LOG.isDebugEnabled()) { 2047 return; 2048 } 2049 2050 LOG.debug("Current zk system:"); 2051 String prefix = "|-"; 2052 LOG.debug(prefix + root); 2053 try { 2054 logZKTree(zkw, root, prefix); 2055 } catch (KeeperException e) { 2056 throw new RuntimeException(e); 2057 } 2058 } 2059 2060 /** 2061 * Helper method to print the current state of the ZK tree. 2062 * @see #logZKTree(ZKWatcher, String) 2063 * @throws KeeperException if an unexpected exception occurs 2064 */ 2065 protected static void logZKTree(ZKWatcher zkw, String root, String prefix) 2066 throws KeeperException { 2067 List<String> children = ZKUtil.listChildrenNoWatch(zkw, root); 2068 2069 if (children == null) { 2070 return; 2071 } 2072 2073 for (String child : children) { 2074 LOG.debug(prefix + child); 2075 String node = ZNodePaths.joinZNode(root.equals("/") ? "" : root, child); 2076 logZKTree(zkw, node, prefix + "---"); 2077 } 2078 } 2079 2080 /** 2081 * @param position the position to serialize 2082 * @return Serialized protobuf of <code>position</code> with pb magic prefix prepended suitable 2083 * for use as content of an wal position in a replication queue. 2084 */ 2085 public static byte[] positionToByteArray(final long position) { 2086 byte[] bytes = ReplicationProtos.ReplicationHLogPosition.newBuilder().setPosition(position) 2087 .build().toByteArray(); 2088 return ProtobufUtil.prependPBMagic(bytes); 2089 } 2090 2091 /** 2092 * @param bytes - Content of a WAL position znode. 2093 * @return long - The current WAL position. 2094 * @throws DeserializationException if the WAL position cannot be parsed 2095 */ 2096 public static long parseWALPositionFrom(final byte[] bytes) throws DeserializationException { 2097 if (bytes == null) { 2098 throw new DeserializationException("Unable to parse null WAL position."); 2099 } 2100 if (ProtobufUtil.isPBMagicPrefix(bytes)) { 2101 int pblen = ProtobufUtil.lengthOfPBMagic(); 2102 ReplicationProtos.ReplicationHLogPosition.Builder builder = 2103 ReplicationProtos.ReplicationHLogPosition.newBuilder(); 2104 ReplicationProtos.ReplicationHLogPosition position; 2105 try { 2106 ProtobufUtil.mergeFrom(builder, bytes, pblen, bytes.length - pblen); 2107 position = builder.build(); 2108 } catch (IOException e) { 2109 throw new DeserializationException(e); 2110 } 2111 return position.getPosition(); 2112 } else { 2113 if (bytes.length > 0) { 2114 return Bytes.toLong(bytes); 2115 } 2116 return 0; 2117 } 2118 } 2119}