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;
19  
20  import java.io.Closeable;
21  import java.io.IOException;
22  
23  import org.apache.commons.logging.Log;
24  import org.apache.commons.logging.LogFactory;
25  import org.apache.hadoop.hbase.classification.InterfaceAudience;
26  import org.apache.hadoop.conf.Configurable;
27  import org.apache.hadoop.conf.Configuration;
28  import org.apache.hadoop.hbase.protobuf.generated.AdminProtos.AdminService;
29  import org.apache.hadoop.hbase.protobuf.generated.ClientProtos.ClientService;
30  import org.apache.hadoop.hbase.protobuf.generated.MasterProtos.MasterService;
31  import org.apache.hadoop.hbase.util.Threads;
32  
33  /**
34   * This class defines methods that can help with managing HBase clusters
35   * from unit tests and system tests. There are 3 types of cluster deployments:
36   * <ul>
37   * <li><b>MiniHBaseCluster:</b> each server is run in the same JVM in separate threads,
38   * used by unit tests</li>
39   * <li><b>DistributedHBaseCluster:</b> the cluster is pre-deployed, system and integration tests can
40   * interact with the cluster. </li>
41   * <li><b>ProcessBasedLocalHBaseCluster:</b> each server is deployed locally but in separate
42   * JVMs. </li>
43   * </ul>
44   * <p>
45   * HBaseCluster unifies the way tests interact with the cluster, so that the same test can
46   * be run against a mini-cluster during unit test execution, or a distributed cluster having
47   * tens/hundreds of nodes during execution of integration tests.
48   *
49   * <p>
50   * HBaseCluster exposes client-side public interfaces to tests, so that tests does not assume
51   * running in a particular mode. Not all the tests are suitable to be run on an actual cluster,
52   * and some tests will still need to mock stuff and introspect internal state. For those use
53   * cases from unit tests, or if more control is needed, you can use the subclasses directly.
54   * In that sense, this class does not abstract away <strong>every</strong> interface that
55   * MiniHBaseCluster or DistributedHBaseCluster provide.
56   */
57  @InterfaceAudience.Private
58  public abstract class HBaseCluster implements Closeable, Configurable {
59    static final Log LOG = LogFactory.getLog(HBaseCluster.class.getName());
60    protected Configuration conf;
61  
62    /** the status of the cluster before we begin */
63    protected ClusterStatus initialClusterStatus;
64  
65    /**
66     * Construct an HBaseCluster
67     * @param conf Configuration to be used for cluster
68     */
69    public HBaseCluster(Configuration conf) {
70      setConf(conf);
71    }
72  
73    @Override
74    public void setConf(Configuration conf) {
75      this.conf = conf;
76    }
77  
78    @Override
79    public Configuration getConf() {
80      return conf;
81    }
82  
83    /**
84     * Returns a ClusterStatus for this HBase cluster.
85     * @see #getInitialClusterStatus()
86     */
87    public abstract ClusterStatus getClusterStatus() throws IOException;
88  
89    /**
90     * Returns a ClusterStatus for this HBase cluster as observed at the
91     * starting of the HBaseCluster
92     */
93    public ClusterStatus getInitialClusterStatus() throws IOException {
94      return initialClusterStatus;
95    }
96  
97    /**
98     * Returns an {@link MasterService.BlockingInterface} to the active master
99     */
100   public abstract MasterService.BlockingInterface getMaster()
101   throws IOException;
102 
103   /**
104    * Returns an AdminProtocol interface to the regionserver
105    */
106   public abstract AdminService.BlockingInterface getAdminProtocol(ServerName serverName)
107   throws IOException;
108 
109   /**
110    * Returns a ClientProtocol interface to the regionserver
111    */
112   public abstract ClientService.BlockingInterface getClientProtocol(ServerName serverName)
113   throws IOException;
114 
115   /**
116    * Starts a new region server on the given hostname or if this is a mini/local cluster,
117    * starts a region server locally.
118    * @param hostname the hostname to start the regionserver on
119    * @throws IOException if something goes wrong
120    */
121   public abstract void startRegionServer(String hostname, int port) throws IOException;
122 
123   /**
124    * Kills the region server process if this is a distributed cluster, otherwise
125    * this causes the region server to exit doing basic clean up only.
126    * @throws IOException if something goes wrong
127    */
128   public abstract void killRegionServer(ServerName serverName) throws IOException;
129 
130   /**
131    * Stops the given region server, by attempting a gradual stop.
132    * @return whether the operation finished with success
133    * @throws IOException if something goes wrong
134    */
135   public abstract void stopRegionServer(ServerName serverName) throws IOException;
136 
137   /**
138    * Wait for the specified region server to join the cluster
139    * @return whether the operation finished with success
140    * @throws IOException if something goes wrong or timeout occurs
141    */
142   @Deprecated
143   public void waitForRegionServerToStart(String hostname, long timeout) throws IOException {
144     long start = System.currentTimeMillis();
145     while ((System.currentTimeMillis() - start) < timeout) {
146       for (ServerName server : getClusterStatus().getServers()) {
147         if (server.getHostname().equals(hostname)) {
148           return;
149         }
150       }
151       Threads.sleep(100);
152     }
153     throw new IOException("did timeout " + timeout + "ms waiting for region server to start: "
154         + hostname);
155   }
156 
157   /**
158    * Wait for the specified region server to join the cluster
159    * @return whether the operation finished with success
160    * @throws IOException if something goes wrong or timeout occurs
161    */
162   public void waitForRegionServerToStart(String hostname, int port, long timeout)
163       throws IOException {
164     long start = System.currentTimeMillis();
165     while ((System.currentTimeMillis() - start) < timeout) {
166       for (ServerName server : getClusterStatus().getServers()) {
167         if (server.getHostname().equals(hostname) && server.getPort() == port) {
168           return;
169         }
170       }
171       Threads.sleep(100);
172     }
173     throw new IOException("did timeout " + timeout + "ms waiting for region server to start: "
174         + hostname);
175   }
176 
177   /**
178    * Wait for the specified region server to stop the thread / process.
179    * @return whether the operation finished with success
180    * @throws IOException if something goes wrong or timeout occurs
181    */
182   public abstract void waitForRegionServerToStop(ServerName serverName, long timeout)
183       throws IOException;
184 
185   /**
186    * Starts a new zookeeper node on the given hostname or if this is a mini/local cluster,
187    * silently logs warning message.
188    * @param hostname the hostname to start the regionserver on
189    * @throws IOException if something goes wrong
190    */
191   public abstract void startZkNode(String hostname, int port) throws IOException;
192 
193   /**
194    * Kills the zookeeper node process if this is a distributed cluster, otherwise,
195    * this causes master to exit doing basic clean up only.
196    * @throws IOException if something goes wrong
197    */
198   public abstract void killZkNode(ServerName serverName) throws IOException;
199 
200   /**
201    * Stops the region zookeeper if this is a distributed cluster, otherwise
202    * silently logs warning message.
203    * @throws IOException if something goes wrong
204    */
205   public abstract void stopZkNode(ServerName serverName) throws IOException;
206 
207   /**
208    * Wait for the specified zookeeper node to join the cluster
209    * @return whether the operation finished with success
210    * @throws IOException if something goes wrong or timeout occurs
211    */
212   public abstract void waitForZkNodeToStart(ServerName serverName, long timeout)
213     throws IOException;
214 
215   /**
216    * Wait for the specified zookeeper node to stop the thread / process.
217    * @return whether the operation finished with success
218    * @throws IOException if something goes wrong or timeout occurs
219    */
220   public abstract void waitForZkNodeToStop(ServerName serverName, long timeout)
221     throws IOException;
222 
223   /**
224    * Starts a new datanode on the given hostname or if this is a mini/local cluster,
225    * silently logs warning message.
226    * @throws IOException if something goes wrong
227    */
228   public abstract void startDataNode(ServerName serverName) throws IOException;
229 
230   /**
231    * Kills the datanode process if this is a distributed cluster, otherwise,
232    * this causes master to exit doing basic clean up only.
233    * @throws IOException if something goes wrong
234    */
235   public abstract void killDataNode(ServerName serverName) throws IOException;
236 
237   /**
238    * Stops the datanode if this is a distributed cluster, otherwise
239    * silently logs warning message.
240    * @throws IOException if something goes wrong
241    */
242   public abstract void stopDataNode(ServerName serverName) throws IOException;
243 
244   /**
245    * Wait for the specified datanode to join the cluster
246    * @return whether the operation finished with success
247    * @throws IOException if something goes wrong or timeout occurs
248    */
249   public abstract void waitForDataNodeToStart(ServerName serverName, long timeout)
250     throws IOException;
251 
252   /**
253    * Wait for the specified datanode to stop the thread / process.
254    * @return whether the operation finished with success
255    * @throws IOException if something goes wrong or timeout occurs
256    */
257   public abstract void waitForDataNodeToStop(ServerName serverName, long timeout)
258     throws IOException;
259 
260   /**
261    * Starts a new master on the given hostname or if this is a mini/local cluster,
262    * starts a master locally.
263    * @param hostname the hostname to start the master on
264    * @return whether the operation finished with success
265    * @throws IOException if something goes wrong
266    */
267   public abstract void startMaster(String hostname, int port) throws IOException;
268 
269   /**
270    * Kills the master process if this is a distributed cluster, otherwise,
271    * this causes master to exit doing basic clean up only.
272    * @throws IOException if something goes wrong
273    */
274   public abstract void killMaster(ServerName serverName) throws IOException;
275 
276   /**
277    * Stops the given master, by attempting a gradual stop.
278    * @throws IOException if something goes wrong
279    */
280   public abstract void stopMaster(ServerName serverName) throws IOException;
281 
282   /**
283    * Wait for the specified master to stop the thread / process.
284    * @throws IOException if something goes wrong or timeout occurs
285    */
286   public abstract void waitForMasterToStop(ServerName serverName, long timeout)
287       throws IOException;
288 
289   /**
290    * Blocks until there is an active master and that master has completed
291    * initialization.
292    *
293    * @return true if an active master becomes available.  false if there are no
294    *         masters left.
295    * @throws IOException if something goes wrong or timeout occurs
296    */
297   public boolean waitForActiveAndReadyMaster()
298       throws IOException {
299     return waitForActiveAndReadyMaster(Long.MAX_VALUE);
300   }
301 
302   /**
303    * Blocks until there is an active master and that master has completed
304    * initialization.
305    * @param timeout the timeout limit in ms
306    * @return true if an active master becomes available.  false if there are no
307    *         masters left.
308    */
309   public abstract boolean waitForActiveAndReadyMaster(long timeout)
310       throws IOException;
311 
312   /**
313    * Wait for HBase Cluster to shut down.
314    */
315   public abstract void waitUntilShutDown() throws IOException;
316 
317   /**
318    * Shut down the HBase cluster
319    */
320   public abstract void shutdown() throws IOException;
321 
322   /**
323    * Restores the cluster to it's initial state if this is a real cluster,
324    * otherwise does nothing.
325    * This is a best effort restore. If the servers are not reachable, or insufficient
326    * permissions, etc. restoration might be partial.
327    * @return whether restoration is complete
328    */
329   public boolean restoreInitialStatus() throws IOException {
330     return restoreClusterStatus(getInitialClusterStatus());
331   }
332 
333   /**
334    * Restores the cluster to given state if this is a real cluster,
335    * otherwise does nothing.
336    * This is a best effort restore. If the servers are not reachable, or insufficient
337    * permissions, etc. restoration might be partial.
338    * @return whether restoration is complete
339    */
340   public boolean restoreClusterStatus(ClusterStatus desiredStatus) throws IOException {
341     return true;
342   }
343 
344   /**
345    * Get the ServerName of region server serving the first hbase:meta region
346    */
347   public ServerName getServerHoldingMeta() throws IOException {
348     return getServerHoldingRegion(HRegionInfo.FIRST_META_REGIONINFO.getRegionName());
349   }
350 
351   /**
352    * Get the ServerName of region server serving the specified region
353    * @param regionName Name of the region in bytes
354    * @return ServerName that hosts the region or null
355    */
356   public abstract ServerName getServerHoldingRegion(byte[] regionName) throws IOException;
357 
358   /**
359    * @return whether we are interacting with a distributed cluster as opposed to an
360    * in-process mini/local cluster.
361    */
362   public boolean isDistributedCluster() {
363     return false;
364   }
365 
366   /**
367    * Closes all the resources held open for this cluster. Note that this call does not shutdown
368    * the cluster.
369    * @see #shutdown()
370    */
371   @Override
372   public abstract void close() throws IOException;
373 
374   /**
375    * Wait for the namenode.
376    *
377    * @throws InterruptedException
378    */
379   public void waitForNamenodeAvailable() throws InterruptedException {
380   }
381 
382   public void waitForDatanodesRegistered(int nbDN) throws Exception {
383   }
384 }