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