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 }