1 /** 2 * Licensed to the Apache Software Foundation (ASF) under one 3 * or more contributor license agreements. See the NOTICE file 4 * distributed with this work for additional information 5 * regarding copyright ownership. The ASF licenses this file 6 * to you under the Apache License, Version 2.0 (the 7 * "License"); you may not use this file except in compliance 8 * with the License. You may obtain a copy of the License at 9 * 10 * http://www.apache.org/licenses/LICENSE-2.0 11 * 12 * Unless required by applicable law or agreed to in writing, software 13 * distributed under the License is distributed on an "AS IS" BASIS, 14 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 * See the License for the specific language governing permissions and 16 * limitations under the License. 17 */ 18 package org.apache.hadoop.hbase.catalog; 19 20 import java.io.EOFException; 21 import java.io.IOException; 22 import java.net.ConnectException; 23 import java.net.NoRouteToHostException; 24 import java.net.SocketException; 25 import java.net.SocketTimeoutException; 26 import java.net.UnknownHostException; 27 import java.util.concurrent.atomic.AtomicBoolean; 28 29 import com.google.common.annotations.VisibleForTesting; 30 31 import org.apache.commons.logging.Log; 32 import org.apache.commons.logging.LogFactory; 33 import org.apache.hadoop.conf.Configuration; 34 import org.apache.hadoop.hbase.Abortable; 35 import org.apache.hadoop.hbase.HRegionInfo; 36 import org.apache.hadoop.hbase.NotAllMetaRegionsOnlineException; 37 import org.apache.hadoop.hbase.ServerName; 38 import org.apache.hadoop.hbase.client.HConnection; 39 import org.apache.hadoop.hbase.client.HConnectionManager; 40 import org.apache.hadoop.hbase.client.RetriesExhaustedException; 41 import org.apache.hadoop.hbase.ipc.HBaseClient.FailedServerException; 42 import org.apache.hadoop.hbase.ipc.HRegionInterface; 43 import org.apache.hadoop.hbase.ipc.ServerNotRunningYetException; 44 import org.apache.hadoop.hbase.util.Bytes; 45 import org.apache.hadoop.hbase.zookeeper.MetaNodeTracker; 46 import org.apache.hadoop.hbase.zookeeper.RootRegionTracker; 47 import org.apache.hadoop.hbase.zookeeper.ZooKeeperWatcher; 48 import org.apache.hadoop.ipc.RemoteException; 49 50 /** 51 * Tracks the availability of the catalog tables <code>-ROOT-</code> and 52 * <code>.META.</code>. 53 * 54 * This class is "read-only" in that the locations of the catalog tables cannot 55 * be explicitly set. Instead, ZooKeeper is used to learn of the availability 56 * and location of <code>-ROOT-</code>. <code>-ROOT-</code> is used to learn of 57 * the location of <code>.META.</code> If not available in <code>-ROOT-</code>, 58 * ZooKeeper is used to monitor for a new location of <code>.META.</code>. 59 * 60 * <p>Call {@link #start()} to start up operation. Call {@link #stop()}} to 61 * interrupt waits and close up shop. 62 */ 63 public class CatalogTracker { 64 // TODO: This class needs a rethink. The original intent was that it would be 65 // the one-stop-shop for root and meta locations and that it would get this 66 // info from reading and watching zk state. The class was to be used by 67 // servers when they needed to know of root and meta movement but also by 68 // client-side (inside in HTable) so rather than figure root and meta 69 // locations on fault, the client would instead get notifications out of zk. 70 // 71 // But this original intent is frustrated by the fact that this class has to 72 // read an hbase table, the -ROOT- table, to figure out the .META. region 73 // location which means we depend on an HConnection. HConnection will do 74 // retrying but also, it has its own mechanism for finding root and meta 75 // locations (and for 'verifying'; it tries the location and if it fails, does 76 // new lookup, etc.). So, at least for now, HConnection (or HTable) can't 77 // have a CT since CT needs a HConnection (Even then, do want HT to have a CT? 78 // For HT keep up a session with ZK? Rather, shouldn't we do like asynchbase 79 // where we'd open a connection to zk, read what we need then let the 80 // connection go?). The 'fix' is make it so both root and meta addresses 81 // are wholey up in zk -- not in zk (root) -- and in an hbase table (meta). 82 // 83 // But even then, this class does 'verification' of the location and it does 84 // this by making a call over an HConnection (which will do its own root 85 // and meta lookups). Isn't this verification 'useless' since when we 86 // return, whatever is dependent on the result of this call then needs to 87 // use HConnection; what we have verified may change in meantime (HConnection 88 // uses the CT primitives, the root and meta trackers finding root locations). 89 // 90 // When meta is moved to zk, this class may make more sense. In the 91 // meantime, it does not cohere. It should just watch meta and root and not 92 // NOT do verification -- let that be out in HConnection since its going to 93 // be done there ultimately anyways. 94 // 95 // This class has spread throughout the codebase. It needs to be reigned in. 96 // This class should be used server-side only, even if we move meta location 97 // up into zk. Currently its used over in the client package. Its used in 98 // MetaReader and MetaEditor classes usually just to get the Configuration 99 // its using (It does this indirectly by asking its HConnection for its 100 // Configuration and even then this is just used to get an HConnection out on 101 // the other end). I made https://issues.apache.org/jira/browse/HBASE-4495 for 102 // doing CT fixup. St.Ack 09/30/2011. 103 // 104 105 // TODO: Timeouts have never been as advertised in here and its worse now 106 // with retries; i.e. the HConnection retries and pause goes ahead whatever 107 // the passed timeout is. Fix. 108 private static final Log LOG = LogFactory.getLog(CatalogTracker.class); 109 private final HConnection connection; 110 private final ZooKeeperWatcher zookeeper; 111 private final RootRegionTracker rootRegionTracker; 112 private final MetaNodeTracker metaNodeTracker; 113 private final AtomicBoolean metaAvailable = new AtomicBoolean(false); 114 private boolean instantiatedzkw = false; 115 private Abortable abortable; 116 117 /* 118 * Do not clear this address once set. Its needed when we do 119 * server shutdown processing -- we need to know who had .META. last. If you 120 * want to know if the address is good, rely on {@link #metaAvailable} value. 121 */ 122 private ServerName metaLocation; 123 124 private volatile boolean stopped = false; 125 126 static final byte [] ROOT_REGION_NAME = 127 HRegionInfo.ROOT_REGIONINFO.getRegionName(); 128 static final byte [] META_REGION_NAME = 129 HRegionInfo.FIRST_META_REGIONINFO.getRegionName(); 130 131 /** 132 * Constructs a catalog tracker. Find current state of catalog tables. 133 * Begin active tracking by executing {@link #start()} post construction. Does 134 * not timeout. 135 * 136 * @param conf 137 * the {@link Configuration} from which a {@link HConnection} will be 138 * obtained; if problem, this connections 139 * {@link HConnection#abort(String, Throwable)} will be called. 140 * @throws IOException 141 */ 142 public CatalogTracker(final Configuration conf) throws IOException { 143 this(null, conf, null); 144 } 145 146 /** 147 * Constructs the catalog tracker. Find current state of catalog tables. 148 * Begin active tracking by executing {@link #start()} post construction. 149 * Does not timeout. 150 * @param zk If zk is null, we'll create an instance (and shut it down 151 * when {@link #stop()} is called) else we'll use what is passed. 152 * @param conf 153 * @param abortable If fatal exception we'll call abort on this. May be null. 154 * If it is we'll use the Connection associated with the passed 155 * {@link Configuration} as our Abortable. 156 * @throws IOException 157 */ 158 public CatalogTracker(final ZooKeeperWatcher zk, final Configuration conf, 159 Abortable abortable) 160 throws IOException { 161 this(zk, conf, HConnectionManager.getConnection(conf), abortable); 162 } 163 164 CatalogTracker(final ZooKeeperWatcher zk, final Configuration conf, 165 HConnection connection, Abortable abortable) 166 throws IOException { 167 this.connection = connection; 168 if (abortable == null) { 169 // A connection is abortable. 170 this.abortable = this.connection; 171 } 172 Abortable throwableAborter = new Abortable() { 173 174 @Override 175 public void abort(String why, Throwable e) { 176 throw new RuntimeException(why, e); 177 } 178 179 @Override 180 public boolean isAborted() { 181 return true; 182 } 183 184 }; 185 if (zk == null) { 186 // Create our own. Set flag so we tear it down on stop. 187 this.zookeeper = 188 new ZooKeeperWatcher(conf, "catalogtracker-on-" + connection.toString(), 189 abortable); 190 instantiatedzkw = true; 191 } else { 192 this.zookeeper = zk; 193 } 194 this.rootRegionTracker = new RootRegionTracker(zookeeper, throwableAborter); 195 final CatalogTracker ct = this; 196 // Override nodeDeleted so we get notified when meta node deleted 197 this.metaNodeTracker = new MetaNodeTracker(zookeeper, throwableAborter) { 198 public void nodeDeleted(String path) { 199 if (!path.equals(node)) return; 200 ct.resetMetaLocation(); 201 } 202 }; 203 } 204 205 /** 206 * Starts the catalog tracker. 207 * Determines current availability of catalog tables and ensures all further 208 * transitions of either region are tracked. 209 * @throws IOException 210 * @throws InterruptedException 211 */ 212 public void start() throws IOException, InterruptedException { 213 LOG.debug("Starting catalog tracker " + this); 214 try { 215 this.rootRegionTracker.start(); 216 this.metaNodeTracker.start(); 217 } catch (RuntimeException e) { 218 Throwable t = e.getCause(); 219 this.abortable.abort(e.getMessage(), t); 220 throw new IOException("Attempt to start root/meta tracker failed.", t); 221 } 222 } 223 224 /** 225 * @return True if we are stopped. Call only after start else indeterminate answer. 226 */ 227 @VisibleForTesting 228 public boolean isStopped() { 229 return this.stopped; 230 } 231 232 /** 233 * Stop working. 234 * Interrupts any ongoing waits. 235 */ 236 public void stop() { 237 if (!this.stopped) { 238 LOG.debug("Stopping catalog tracker " + this); 239 this.stopped = true; 240 this.rootRegionTracker.stop(); 241 this.metaNodeTracker.stop(); 242 try { 243 if (this.connection != null) { 244 this.connection.close(); 245 } 246 } catch (IOException e) { 247 // Although the {@link Closeable} interface throws an {@link 248 // IOException}, in reality, the implementation would never do that. 249 LOG.error("Attempt to close catalog tracker's connection failed.", e); 250 } 251 if (this.instantiatedzkw) { 252 this.zookeeper.close(); 253 } 254 // Call this and it will interrupt any ongoing waits on meta. 255 synchronized (this.metaAvailable) { 256 this.metaAvailable.notifyAll(); 257 } 258 } 259 } 260 261 /** 262 * Gets the current location for <code>-ROOT-</code> or null if location is 263 * not currently available. 264 * @return {@link ServerName} for server hosting <code>-ROOT-</code> or null 265 * if none available 266 * @throws InterruptedException 267 */ 268 public ServerName getRootLocation() throws InterruptedException { 269 return this.rootRegionTracker.getRootRegionLocation(); 270 } 271 272 /** 273 * @return {@link ServerName} for server hosting <code>.META.</code> or null 274 * if none available 275 */ 276 public ServerName getMetaLocation() { 277 return this.metaLocation; 278 } 279 280 /** 281 * Method used by master on startup trying to figure state of cluster. 282 * Returns the current meta location unless its null. In this latter case, 283 * it has not yet been set so go check whats up in <code>-ROOT-</code> and 284 * return that. 285 * @return {@link ServerName} for server hosting <code>.META.</code> or if null, 286 * we'll read the location that is up in <code>-ROOT-</code> table (which 287 * could be null or just plain stale). 288 * @throws IOException 289 */ 290 public ServerName getMetaLocationOrReadLocationFromRoot() throws IOException { 291 ServerName sn = getMetaLocation(); 292 return sn != null? sn: MetaReader.getMetaRegionLocation(this); 293 } 294 295 /** 296 * Waits indefinitely for availability of <code>-ROOT-</code>. Used during 297 * cluster startup. 298 * @throws InterruptedException if interrupted while waiting 299 */ 300 public void waitForRoot() 301 throws InterruptedException { 302 this.rootRegionTracker.blockUntilAvailable(); 303 } 304 305 /** 306 * Gets the current location for <code>-ROOT-</code> if available and waits 307 * for up to the specified timeout if not immediately available. Returns null 308 * if the timeout elapses before root is available. 309 * @param timeout maximum time to wait for root availability, in milliseconds 310 * @return {@link ServerName} for server hosting <code>-ROOT-</code> or null 311 * if none available 312 * @throws InterruptedException if interrupted while waiting 313 * @throws NotAllMetaRegionsOnlineException if root not available before 314 * timeout 315 */ 316 public ServerName waitForRoot(final long timeout) 317 throws InterruptedException, NotAllMetaRegionsOnlineException { 318 ServerName sn = rootRegionTracker.waitRootRegionLocation(timeout); 319 if (sn == null) { 320 throw new NotAllMetaRegionsOnlineException("Timed out; " + timeout + "ms"); 321 } 322 return sn; 323 } 324 325 /** 326 * Gets a connection to the server hosting root, as reported by ZooKeeper, 327 * waiting up to the specified timeout for availability. 328 * @param timeout How long to wait on root location 329 * @see #waitForRoot(long) for additional information 330 * @return connection to server hosting root 331 * @throws InterruptedException 332 * @throws NotAllMetaRegionsOnlineException if timed out waiting 333 * @throws IOException 334 * @deprecated Use #getRootServerConnection(long) 335 */ 336 public HRegionInterface waitForRootServerConnection(long timeout) 337 throws InterruptedException, NotAllMetaRegionsOnlineException, IOException { 338 return getRootServerConnection(timeout); 339 } 340 341 /** 342 * Gets a connection to the server hosting root, as reported by ZooKeeper, 343 * waiting up to the specified timeout for availability. 344 * <p>WARNING: Does not retry. Use an {@link HTable} instead. 345 * @param timeout How long to wait on root location 346 * @see #waitForRoot(long) for additional information 347 * @return connection to server hosting root 348 * @throws InterruptedException 349 * @throws NotAllMetaRegionsOnlineException if timed out waiting 350 * @throws IOException 351 */ 352 HRegionInterface getRootServerConnection(long timeout) 353 throws InterruptedException, NotAllMetaRegionsOnlineException, IOException { 354 return getCachedConnection(waitForRoot(timeout)); 355 } 356 357 /** 358 * Gets a connection to the server currently hosting <code>.META.</code> or 359 * null if location is not currently available. 360 * <p> 361 * If a location is known, a connection to the cached location is returned. 362 * If refresh is true, the cached connection is verified first before 363 * returning. If the connection is not valid, it is reset and rechecked. 364 * <p> 365 * If no location for meta is currently known, method checks ROOT for a new 366 * location, verifies META is currently there, and returns a cached connection 367 * to the server hosting META. 368 * 369 * @return connection to server hosting meta, null if location not available 370 * @throws IOException 371 * @throws InterruptedException 372 */ 373 private HRegionInterface getMetaServerConnection() 374 throws IOException, InterruptedException { 375 synchronized (metaAvailable) { 376 if (metaAvailable.get()) { 377 HRegionInterface current = getCachedConnection(this.metaLocation); 378 // If we are to refresh, verify we have a good connection by making 379 // an invocation on it. 380 if (verifyRegionLocation(current, this.metaLocation, META_REGION_NAME)) { 381 return current; 382 } 383 resetMetaLocation(); 384 } 385 // We got here because there is no meta available or because whats 386 // available is bad. 387 388 // Now read the current .META. content from -ROOT-. Note: This goes via 389 // an HConnection. It has its own way of figuring root and meta locations 390 // which we have to wait on. 391 ServerName newLocation = MetaReader.getMetaRegionLocation(this); 392 if (newLocation == null) return null; 393 394 HRegionInterface newConnection = getCachedConnection(newLocation); 395 if (verifyRegionLocation(newConnection, newLocation, META_REGION_NAME)) { 396 setMetaLocation(newLocation); 397 return newConnection; 398 } else { 399 if (LOG.isTraceEnabled()) { 400 LOG.trace("New .META. server: " + newLocation + " isn't valid." + 401 " Cached .META. server: " + this.metaLocation); 402 } 403 } 404 return null; 405 } 406 } 407 408 /** 409 * Waits indefinitely for availability of <code>.META.</code>. Used during 410 * cluster startup. Does not verify meta, just that something has been 411 * set up in zk. 412 * @see #waitForMeta(long) 413 * @throws InterruptedException if interrupted while waiting 414 */ 415 public void waitForMeta() throws InterruptedException { 416 while (!this.stopped) { 417 try { 418 if (waitForMeta(100) != null) break; 419 } catch (NotAllMetaRegionsOnlineException e) { 420 if (LOG.isTraceEnabled()) { 421 LOG.info(".META. still not available, sleeping and retrying." + 422 " Reason: " + e.getMessage()); 423 } 424 } catch (IOException e) { 425 LOG.info("Retrying", e); 426 } 427 } 428 } 429 430 /** 431 * Gets the current location for <code>.META.</code> if available and waits 432 * for up to the specified timeout if not immediately available. Throws an 433 * exception if timed out waiting. This method differs from {@link #waitForMeta()} 434 * in that it will go ahead and verify the location gotten from ZooKeeper and 435 * -ROOT- region by trying to use returned connection. 436 * @param timeout maximum time to wait for meta availability, in milliseconds 437 * @return {@link ServerName} for server hosting <code>.META.</code> or null 438 * if none available 439 * @throws InterruptedException if interrupted while waiting 440 * @throws IOException unexpected exception connecting to meta server 441 * @throws NotAllMetaRegionsOnlineException if meta not available before 442 * timeout 443 */ 444 public ServerName waitForMeta(long timeout) 445 throws InterruptedException, IOException, NotAllMetaRegionsOnlineException { 446 long stop = timeout == 0 ? Long.MAX_VALUE : System.currentTimeMillis() + timeout; 447 long waitTime = Math.min(50, timeout); 448 synchronized (metaAvailable) { 449 while(!stopped && System.currentTimeMillis() < stop) { 450 if (getMetaServerConnection() != null) { 451 return metaLocation; 452 } 453 // perhaps -ROOT- region isn't available, let us wait a bit and retry. 454 metaAvailable.wait(waitTime); 455 } 456 if (getMetaServerConnection() == null) { 457 throw new NotAllMetaRegionsOnlineException("Timed out (" + timeout + "ms)"); 458 } 459 return metaLocation; 460 } 461 } 462 463 /** 464 * Gets a connection to the server hosting meta, as reported by ZooKeeper, 465 * waiting up to the specified timeout for availability. 466 * @see #waitForMeta(long) for additional information 467 * @return connection to server hosting meta 468 * @throws InterruptedException 469 * @throws NotAllMetaRegionsOnlineException if timed out waiting 470 * @throws IOException 471 * @deprecated Does not retry; use an HTable instance instead. 472 */ 473 public HRegionInterface waitForMetaServerConnection(long timeout) 474 throws InterruptedException, NotAllMetaRegionsOnlineException, IOException { 475 return getCachedConnection(waitForMeta(timeout)); 476 } 477 478 /** 479 * Called when we figure current meta is off (called from zk callback). 480 */ 481 public void resetMetaLocation() { 482 LOG.debug("Current cached META location, " + metaLocation + 483 ", is not valid, resetting"); 484 synchronized(this.metaAvailable) { 485 this.metaAvailable.set(false); 486 this.metaAvailable.notifyAll(); 487 } 488 } 489 490 /** 491 * @param metaLocation 492 */ 493 void setMetaLocation(final ServerName metaLocation) { 494 LOG.debug("Set new cached META location: " + metaLocation); 495 synchronized (this.metaAvailable) { 496 this.metaLocation = metaLocation; 497 this.metaAvailable.set(true); 498 // no synchronization because these are private and already under lock 499 this.metaAvailable.notifyAll(); 500 } 501 } 502 503 /** 504 * @param sn ServerName to get a connection against. 505 * @return The HRegionInterface we got when we connected to <code>sn</code> 506 * May have come from cache, may not be good, may have been setup by this 507 * invocation, or may be null. 508 * @throws IOException 509 */ 510 private HRegionInterface getCachedConnection(ServerName sn) 511 throws IOException { 512 if (sn == null) { 513 return null; 514 } 515 HRegionInterface protocol = null; 516 try { 517 protocol = connection.getHRegionConnection(sn.getHostname(), sn.getPort()); 518 } catch (RetriesExhaustedException e) { 519 if (e.getCause() != null && e.getCause() instanceof ConnectException) { 520 // Catch this; presume it means the cached connection has gone bad. 521 } else { 522 throw e; 523 } 524 } catch (SocketTimeoutException e) { 525 LOG.debug("Timed out connecting to " + sn); 526 } catch (NoRouteToHostException e) { 527 LOG.debug("Connecting to " + sn, e); 528 } catch (SocketException e) { 529 LOG.debug("Exception connecting to " + sn); 530 } catch (UnknownHostException e) { 531 LOG.debug("Unknown host exception connecting to " + sn); 532 } catch (FailedServerException e) { 533 if (LOG.isDebugEnabled()) { 534 LOG.debug("Server " + sn + " is in failed server list."); 535 } 536 } catch (IOException ioe) { 537 Throwable cause = ioe.getCause(); 538 if (ioe instanceof ConnectException) { 539 // Catch. Connect refused. 540 } else if (cause != null && cause instanceof EOFException) { 541 // Catch. Other end disconnected us. 542 } else if (cause != null && cause.getMessage() != null && 543 cause.getMessage().toLowerCase().contains("connection reset")) { 544 // Catch. Connection reset. 545 } else { 546 throw ioe; 547 } 548 549 } 550 return protocol; 551 } 552 553 /** 554 * Verify we can connect to <code>hostingServer</code> and that its carrying 555 * <code>regionName</code>. 556 * @param hostingServer Interface to the server hosting <code>regionName</code> 557 * @param serverName The servername that goes with the <code>metaServer</code> 558 * Interface. Used logging. 559 * @param regionName The regionname we are interested in. 560 * @return True if we were able to verify the region located at other side of 561 * the Interface. 562 * @throws IOException 563 */ 564 // TODO: We should be able to get the ServerName from the HRegionInterface 565 // rather than have to pass it in. Its made awkward by the fact that the 566 // HRI is likely a proxy against remote server so the getServerName needs 567 // to be fixed to go to a local method or to a cache before we can do this. 568 private boolean verifyRegionLocation(HRegionInterface hostingServer, 569 final ServerName address, final byte [] regionName) 570 throws IOException { 571 if (hostingServer == null) { 572 LOG.info("Passed hostingServer is null"); 573 return false; 574 } 575 Throwable t = null; 576 try { 577 // Try and get regioninfo from the hosting server. 578 return hostingServer.getRegionInfo(regionName) != null; 579 } catch (ConnectException e) { 580 t = e; 581 } catch (RetriesExhaustedException e) { 582 t = e; 583 } catch (RemoteException e) { 584 IOException ioe = e.unwrapRemoteException(); 585 t = ioe; 586 } catch (IOException e) { 587 Throwable cause = e.getCause(); 588 if (cause != null && cause instanceof EOFException) { 589 t = cause; 590 } else if (cause != null && cause.getMessage() != null 591 && cause.getMessage().contains("Connection reset")) { 592 t = cause; 593 } else { 594 t = e; 595 } 596 } 597 LOG.info("Failed verification of " + Bytes.toStringBinary(regionName) + 598 " at address=" + address + "; " + t); 599 return false; 600 } 601 602 /** 603 * Verify <code>-ROOT-</code> is deployed and accessible. 604 * @param timeout How long to wait on zk for root address (passed through to 605 * the internal call to {@link #waitForRootServerConnection(long)}. 606 * @return True if the <code>-ROOT-</code> location is healthy. 607 * @throws IOException 608 * @throws InterruptedException 609 */ 610 public boolean verifyRootRegionLocation(final long timeout) 611 throws InterruptedException, IOException { 612 HRegionInterface connection = null; 613 try { 614 connection = waitForRootServerConnection(timeout); 615 } catch (NotAllMetaRegionsOnlineException e) { 616 // Pass 617 } catch (ServerNotRunningYetException e) { 618 // Pass -- remote server is not up so can't be carrying root 619 } catch (UnknownHostException e) { 620 // Pass -- server name doesn't resolve so it can't be assigned anything. 621 } 622 return (connection == null)? false: 623 verifyRegionLocation(connection, 624 this.rootRegionTracker.getRootRegionLocation(), ROOT_REGION_NAME); 625 } 626 627 /** 628 * Verify <code>.META.</code> is deployed and accessible. 629 * @param timeout How long to wait on zk for <code>.META.</code> address 630 * (passed through to the internal call to {@link #waitForMetaServerConnection(long)}. 631 * @return True if the <code>.META.</code> location is healthy. 632 * @throws IOException Some unexpected IOE. 633 * @throws InterruptedException 634 */ 635 public boolean verifyMetaRegionLocation(final long timeout) 636 throws InterruptedException, IOException { 637 HRegionInterface connection = null; 638 try { 639 connection = waitForMetaServerConnection(timeout); 640 } catch (NotAllMetaRegionsOnlineException e) { 641 // Pass 642 } catch (ServerNotRunningYetException e) { 643 // Pass -- remote server is not up so can't be carrying .META. 644 } catch (UnknownHostException e) { 645 // Pass -- server name doesn't resolve so it can't be assigned anything. 646 } catch (RetriesExhaustedException e) { 647 // Pass -- failed after bunch of retries. 648 LOG.debug("Failed verify meta region location after retries", e); 649 } 650 return connection != null; 651 } 652 653 // Used by tests. 654 MetaNodeTracker getMetaNodeTracker() { 655 return this.metaNodeTracker; 656 } 657 658 public HConnection getConnection() { 659 return this.connection; 660 } 661 }