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 master on the given hostname or if this is a mini/local cluster, 187 * starts a master locally. 188 * @param hostname the hostname to start the master on 189 * @return whether the operation finished with success 190 * @throws IOException if something goes wrong 191 */ 192 public abstract void startMaster(String hostname, int port) throws IOException; 193 194 /** 195 * Kills the master process if this is a distributed cluster, otherwise, 196 * this causes master to exit doing basic clean up only. 197 * @throws IOException if something goes wrong 198 */ 199 public abstract void killMaster(ServerName serverName) throws IOException; 200 201 /** 202 * Stops the given master, by attempting a gradual stop. 203 * @throws IOException if something goes wrong 204 */ 205 public abstract void stopMaster(ServerName serverName) throws IOException; 206 207 /** 208 * Wait for the specified master to stop the thread / process. 209 * @throws IOException if something goes wrong or timeout occurs 210 */ 211 public abstract void waitForMasterToStop(ServerName serverName, long timeout) 212 throws IOException; 213 214 /** 215 * Blocks until there is an active master and that master has completed 216 * initialization. 217 * 218 * @return true if an active master becomes available. false if there are no 219 * masters left. 220 * @throws IOException if something goes wrong or timeout occurs 221 */ 222 public boolean waitForActiveAndReadyMaster() 223 throws IOException { 224 return waitForActiveAndReadyMaster(Long.MAX_VALUE); 225 } 226 227 /** 228 * Blocks until there is an active master and that master has completed 229 * initialization. 230 * @param timeout the timeout limit in ms 231 * @return true if an active master becomes available. false if there are no 232 * masters left. 233 */ 234 public abstract boolean waitForActiveAndReadyMaster(long timeout) 235 throws IOException; 236 237 /** 238 * Wait for HBase Cluster to shut down. 239 */ 240 public abstract void waitUntilShutDown() throws IOException; 241 242 /** 243 * Shut down the HBase cluster 244 */ 245 public abstract void shutdown() throws IOException; 246 247 /** 248 * Restores the cluster to it's initial state if this is a real cluster, 249 * otherwise does nothing. 250 * This is a best effort restore. If the servers are not reachable, or insufficient 251 * permissions, etc. restoration might be partial. 252 * @return whether restoration is complete 253 */ 254 public boolean restoreInitialStatus() throws IOException { 255 return restoreClusterStatus(getInitialClusterStatus()); 256 } 257 258 /** 259 * Restores the cluster to given state if this is a real cluster, 260 * otherwise does nothing. 261 * This is a best effort restore. If the servers are not reachable, or insufficient 262 * permissions, etc. restoration might be partial. 263 * @return whether restoration is complete 264 */ 265 public boolean restoreClusterStatus(ClusterStatus desiredStatus) throws IOException { 266 return true; 267 } 268 269 /** 270 * Get the ServerName of region server serving the first hbase:meta region 271 */ 272 public ServerName getServerHoldingMeta() throws IOException { 273 return getServerHoldingRegion(HRegionInfo.FIRST_META_REGIONINFO.getRegionName()); 274 } 275 276 /** 277 * Get the ServerName of region server serving the specified region 278 * @param regionName Name of the region in bytes 279 * @return ServerName that hosts the region or null 280 */ 281 public abstract ServerName getServerHoldingRegion(byte[] regionName) throws IOException; 282 283 /** 284 * @return whether we are interacting with a distributed cluster as opposed to an 285 * in-process mini/local cluster. 286 */ 287 public boolean isDistributedCluster() { 288 return false; 289 } 290 291 /** 292 * Closes all the resources held open for this cluster. Note that this call does not shutdown 293 * the cluster. 294 * @see #shutdown() 295 */ 296 @Override 297 public abstract void close() throws IOException; 298 299 /** 300 * Wait for the namenode. 301 * 302 * @throws InterruptedException 303 */ 304 public void waitForNamenodeAvailable() throws InterruptedException { 305 } 306 307 public void waitForDatanodesRegistered(int nbDN) throws Exception { 308 } 309 }