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