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.classification.InterfaceAudience;
26  import org.apache.hadoop.conf.Configurable;
27  import org.apache.hadoop.conf.Configuration;
28  import org.apache.hadoop.hbase.util.Threads;
29  import org.apache.hadoop.hbase.ipc.HMasterInterface;
30  import org.apache.hadoop.hbase.ipc.HRegionInterface;
31  
32  /**
33   * This class defines methods that can help with managing HBase clusters
34   * from unit tests and system tests. There are 3 types of cluster deployments:
35   * <ul>
36   * <li><b>MiniHBaseCluster:</b> each server is run in the same JVM in separate threads,
37   * used by unit tests</li>
38   * <li><b>DistributedHBaseCluster:</b> the cluster is pre-deployed, system and integration tests can
39   * interact with the cluster. </li>
40   * <li><b>ProcessBasedLocalHBaseCluster:</b> each server is deployed locally but in separate
41   * JVMs. </li>
42   * </ul>
43   * <p>
44   * HBaseCluster unifies the way tests interact with the cluster, so that the same test can
45   * be run against a mini-cluster during unit test execution, or a distributed cluster having
46   * tens/hundreds of nodes during execution of integration tests.
47   *
48   * <p>
49   * HBaseCluster exposes client-side public interfaces to tests, so that tests does not assume
50   * running in a particular mode. Not all the tests are suitable to be run on an actual cluster,
51   * and some tests will still need to mock stuff and introspect internal state. For those use
52   * cases from unit tests, or if more control is needed, you can use the subclasses directly.
53   * In that sense, this class does not abstract away <strong>every</strong> interface that
54   * MiniHBaseCluster or DistributedHBaseCluster provide.
55   */
56  @InterfaceAudience.Private
57  public abstract class HBaseCluster implements Closeable, Configurable {
58    static final Log LOG = LogFactory.getLog(HBaseCluster.class.getName());
59    protected Configuration conf;
60  
61    /** the status of the cluster before we begin */
62    protected ClusterStatus initialClusterStatus;
63  
64    /**
65     * Construct an HBaseCluster
66     * @param conf Configuration to be used for cluster
67     */
68    public HBaseCluster(Configuration conf) {
69      setConf(conf);
70    }
71  
72    @Override
73    public void setConf(Configuration conf) {
74      this.conf = conf;
75    }
76  
77    @Override
78    public Configuration getConf() {
79      return conf;
80    }
81  
82    /**
83     * Returns a ClusterStatus for this HBase cluster.
84     * @see #getInitialClusterStatus()
85     */
86    public abstract ClusterStatus getClusterStatus() throws IOException;
87  
88    /**
89     * Returns a ClusterStatus for this HBase cluster as observed at the
90     * starting of the HBaseCluster
91     */
92    public ClusterStatus getInitialClusterStatus() throws IOException {
93      return initialClusterStatus;
94    }
95  
96    /**
97     * Returns an {@link HmasterInterface} to the active master
98     */
99    public abstract HMasterInterface getMasterAdmin()
100       throws IOException;
101 
102   /**
103    * Starts a new region server on the given hostname or if this is a mini/local cluster,
104    * starts a region server locally.
105    * @param hostname the hostname to start the regionserver on
106    * @throws IOException if something goes wrong
107    */
108   public abstract void startRegionServer(String hostname) throws IOException;
109 
110   /**
111    * Kills the region server process if this is a distributed cluster, otherwise
112    * this causes the region server to exit doing basic clean up only.
113    * @throws IOException if something goes wrong
114    */
115   public abstract void killRegionServer(ServerName serverName) throws IOException;
116 
117   /**
118    * Stops the given region server, by attempting a gradual stop.
119    * @return whether the operation finished with success
120    * @throws IOException if something goes wrong
121    */
122   public abstract void stopRegionServer(ServerName serverName) throws IOException;
123 
124   /**
125    * Wait for the specified region server to join the cluster
126    * @return whether the operation finished with success
127    * @throws IOException if something goes wrong or timeout occurs
128    */
129   public void waitForRegionServerToStart(String hostname, long timeout)
130       throws IOException {
131     long start = System.currentTimeMillis();
132     while ((System.currentTimeMillis() - start) < timeout) {
133       for (ServerName server : getClusterStatus().getServers()) {
134         if (server.getHostname().equals(hostname)) {
135           return;
136         }
137       }
138       Threads.sleep(100);
139     }
140     throw new IOException("did timeout waiting for region server to start:" + hostname);
141   }
142 
143   /**
144    * Wait for the specified region server to stop the thread / process.
145    * @return whether the operation finished with success
146    * @throws IOException if something goes wrong or timeout occurs
147    */
148   public abstract void waitForRegionServerToStop(ServerName serverName, long timeout)
149       throws IOException;
150 
151   /**
152    * Starts a new master on the given hostname or if this is a mini/local cluster,
153    * starts a master locally.
154    * @param hostname the hostname to start the master on
155    * @return whether the operation finished with success
156    * @throws IOException if something goes wrong
157    */
158   public abstract void startMaster(String hostname) throws IOException;
159 
160   /**
161    * Kills the master process if this is a distributed cluster, otherwise,
162    * this causes master to exit doing basic clean up only.
163    * @throws IOException if something goes wrong
164    */
165   public abstract void killMaster(ServerName serverName) throws IOException;
166 
167   /**
168    * Stops the given master, by attempting a gradual stop.
169    * @throws IOException if something goes wrong
170    */
171   public abstract void stopMaster(ServerName serverName) throws IOException;
172 
173   /**
174    * Wait for the specified master to stop the thread / process.
175    * @throws IOException if something goes wrong or timeout occurs
176    */
177   public abstract void waitForMasterToStop(ServerName serverName, long timeout)
178       throws IOException;
179 
180   /**
181    * Blocks until there is an active master and that master has completed
182    * initialization.
183    *
184    * @return true if an active master becomes available.  false if there are no
185    *         masters left.
186    * @throws IOException if something goes wrong or timeout occurs
187    */
188   public boolean waitForActiveAndReadyMaster()
189       throws IOException {
190     return waitForActiveAndReadyMaster(Long.MAX_VALUE);
191   }
192 
193   /**
194    * Blocks until there is an active master and that master has completed
195    * initialization.
196    * @param timeout the timeout limit in ms
197    * @return true if an active master becomes available.  false if there are no
198    *         masters left.
199    */
200   public abstract boolean waitForActiveAndReadyMaster(long timeout)
201       throws IOException;
202 
203   /**
204    * Wait for HBase Cluster to shut down.
205    */
206   public abstract void waitUntilShutDown() throws IOException;
207 
208   /**
209    * Shut down the HBase cluster
210    */
211   public abstract void shutdown() throws IOException;
212 
213   /**
214    * Restores the cluster to it's initial state if this is a real cluster,
215    * otherwise does nothing.
216    */
217   public void restoreInitialStatus() throws IOException {
218     restoreClusterStatus(getInitialClusterStatus());
219   }
220 
221   /**
222    * Restores the cluster to given state if this is a real cluster,
223    * otherwise does nothing.
224    */
225   public void restoreClusterStatus(ClusterStatus desiredStatus) throws IOException {
226   }
227 
228   /**
229    * Get the ServerName of region server serving ROOT region
230    */
231   public ServerName getServerHoldingRoot() throws IOException {
232     return getServerHoldingRegion(HRegionInfo.ROOT_REGIONINFO.getRegionName());
233   }
234 
235   /**
236    * Get the ServerName of region server serving the first META region
237    */
238   public ServerName getServerHoldingMeta() throws IOException {
239     return getServerHoldingRegion(HRegionInfo.FIRST_META_REGIONINFO.getRegionName());
240   }
241 
242   /**
243    * Get the ServerName of region server serving the specified region
244    * @param regionName Name of the region in bytes
245    * @return ServerName that hosts the region or null
246    */
247   public abstract ServerName getServerHoldingRegion(byte[] regionName) throws IOException;
248 
249   /**
250    * @return whether we are interacting with a distributed cluster as opposed to an
251    * in-process mini/local cluster.
252    */
253   public boolean isDistributedCluster() {
254     return false;
255   }
256 
257   /**
258    * Closes all the resources held open for this cluster. Note that this call does not shutdown
259    * the cluster.
260    * @see #shutdown()
261    */
262   @Override
263   public abstract void close() throws IOException;
264 }