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