View Javadoc

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 volatile 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 }