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