001/** 002 * Licensed to the Apache Software Foundation (ASF) under one 003 * or more contributor license agreements. See the NOTICE file 004 * distributed with this work for additional information 005 * regarding copyright ownership. The ASF licenses this file 006 * to you under the Apache License, Version 2.0 (the 007 * "License"); you may not use this file except in compliance 008 * with the License. You may obtain a copy of the License at 009 * 010 * http://www.apache.org/licenses/LICENSE-2.0 011 * 012 * Unless required by applicable law or agreed to in writing, software 013 * distributed under the License is distributed on an "AS IS" BASIS, 014 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 015 * See the License for the specific language governing permissions and 016 * limitations under the License. 017 */ 018package org.apache.hadoop.hbase; 019 020import java.io.Closeable; 021import java.io.IOException; 022import org.apache.hadoop.conf.Configurable; 023import org.apache.hadoop.conf.Configuration; 024import org.apache.hadoop.hbase.util.Threads; 025import org.apache.yetus.audience.InterfaceAudience; 026import org.slf4j.Logger; 027import org.slf4j.LoggerFactory; 028 029import org.apache.hadoop.hbase.shaded.protobuf.generated.AdminProtos.AdminService; 030import org.apache.hadoop.hbase.shaded.protobuf.generated.ClientProtos.ClientService; 031import org.apache.hadoop.hbase.shaded.protobuf.generated.MasterProtos.MasterService; 032 033/** 034 * This class defines methods that can help with managing HBase clusters 035 * from unit tests and system tests. There are 3 types of cluster deployments: 036 * <ul> 037 * <li><b>MiniHBaseCluster:</b> each server is run in the same JVM in separate threads, 038 * used by unit tests</li> 039 * <li><b>DistributedHBaseCluster:</b> the cluster is pre-deployed, system and integration tests can 040 * interact with the cluster. </li> 041 * <li><b>ProcessBasedLocalHBaseCluster:</b> each server is deployed locally but in separate 042 * JVMs. </li> 043 * </ul> 044 * <p> 045 * HBaseCluster unifies the way tests interact with the cluster, so that the same test can 046 * be run against a mini-cluster during unit test execution, or a distributed cluster having 047 * tens/hundreds of nodes during execution of integration tests. 048 * 049 * <p> 050 * HBaseCluster exposes client-side public interfaces to tests, so that tests does not assume 051 * running in a particular mode. Not all the tests are suitable to be run on an actual cluster, 052 * and some tests will still need to mock stuff and introspect internal state. For those use 053 * cases from unit tests, or if more control is needed, you can use the subclasses directly. 054 * In that sense, this class does not abstract away <strong>every</strong> interface that 055 * MiniHBaseCluster or DistributedHBaseCluster provide. 056 */ 057@InterfaceAudience.Private 058public abstract class HBaseCluster implements Closeable, Configurable { 059 // Log is being used in DistributedHBaseCluster class, hence keeping it as package scope 060 static final Logger LOG = LoggerFactory.getLogger(HBaseCluster.class.getName()); 061 protected Configuration conf; 062 063 /** the status of the cluster before we begin */ 064 protected ClusterMetrics initialClusterStatus; 065 066 /** 067 * Construct an HBaseCluster 068 * @param conf Configuration to be used for cluster 069 */ 070 public HBaseCluster(Configuration conf) { 071 setConf(conf); 072 } 073 074 @Override 075 public void setConf(Configuration conf) { 076 this.conf = conf; 077 } 078 079 @Override 080 public Configuration getConf() { 081 return conf; 082 } 083 084 /** 085 * Returns a ClusterMetrics for this HBase cluster. 086 * @see #getInitialClusterMetrics() 087 */ 088 public abstract ClusterMetrics getClusterMetrics() throws IOException; 089 090 /** 091 * Returns a ClusterStatus for this HBase cluster as observed at the 092 * starting of the HBaseCluster 093 */ 094 public ClusterMetrics getInitialClusterMetrics() throws IOException { 095 return initialClusterStatus; 096 } 097 098 /** 099 * Returns an {@link MasterService.BlockingInterface} to the active master 100 */ 101 public abstract MasterService.BlockingInterface getMasterAdminService() 102 throws IOException; 103 104 /** 105 * Returns an AdminProtocol interface to the regionserver 106 */ 107 public abstract AdminService.BlockingInterface getAdminProtocol(ServerName serverName) 108 throws IOException; 109 110 /** 111 * Returns a ClientProtocol interface to the regionserver 112 */ 113 public abstract ClientService.BlockingInterface getClientProtocol(ServerName serverName) 114 throws IOException; 115 116 /** 117 * Starts a new region server on the given hostname or if this is a mini/local cluster, 118 * starts a region server locally. 119 * @param hostname the hostname to start the regionserver on 120 * @throws IOException if something goes wrong 121 */ 122 public abstract void startRegionServer(String hostname, int port) throws IOException; 123 124 /** 125 * Kills the region server process if this is a distributed cluster, otherwise 126 * this causes the region server to exit doing basic clean up only. 127 * @throws IOException if something goes wrong 128 */ 129 public abstract void killRegionServer(ServerName serverName) throws IOException; 130 131 /** 132 * Keeping track of killed servers and being able to check if a particular server was killed makes 133 * it possible to do fault tolerance testing for dead servers in a deterministic way. A concrete 134 * example of such case is - killing servers and waiting for all regions of a particular table 135 * to be assigned. We can check for server column in META table and that its value is not one 136 * of the killed servers. 137 */ 138 public abstract boolean isKilledRS(ServerName serverName); 139 140 /** 141 * Stops the given region server, by attempting a gradual stop. 142 * @return whether the operation finished with success 143 * @throws IOException if something goes wrong 144 */ 145 public abstract void stopRegionServer(ServerName serverName) throws IOException; 146 147 /** 148 * Wait for the specified region server to join the cluster 149 * @return whether the operation finished with success 150 * @throws IOException if something goes wrong or timeout occurs 151 */ 152 public void waitForRegionServerToStart(String hostname, int port, long timeout) 153 throws IOException { 154 long start = System.currentTimeMillis(); 155 while ((System.currentTimeMillis() - start) < timeout) { 156 for (ServerName server : getClusterMetrics().getLiveServerMetrics().keySet()) { 157 if (server.getHostname().equals(hostname) && server.getPort() == port) { 158 return; 159 } 160 } 161 Threads.sleep(100); 162 } 163 throw new IOException("did timeout " + timeout + "ms waiting for region server to start: " 164 + hostname); 165 } 166 167 /** 168 * Wait for the specified region server to stop the thread / process. 169 * @return whether the operation finished with success 170 * @throws IOException if something goes wrong or timeout occurs 171 */ 172 public abstract void waitForRegionServerToStop(ServerName serverName, long timeout) 173 throws IOException; 174 175 /** 176 * Starts a new zookeeper node on the given hostname or if this is a mini/local cluster, 177 * silently logs warning message. 178 * @param hostname the hostname to start the regionserver on 179 * @throws IOException if something goes wrong 180 */ 181 public abstract void startZkNode(String hostname, int port) throws IOException; 182 183 /** 184 * Kills the zookeeper node process if this is a distributed cluster, otherwise, 185 * this causes master to exit doing basic clean up only. 186 * @throws IOException if something goes wrong 187 */ 188 public abstract void killZkNode(ServerName serverName) throws IOException; 189 190 /** 191 * Stops the region zookeeper if this is a distributed cluster, otherwise 192 * silently logs warning message. 193 * @throws IOException if something goes wrong 194 */ 195 public abstract void stopZkNode(ServerName serverName) throws IOException; 196 197 /** 198 * Wait for the specified zookeeper node to join the cluster 199 * @return whether the operation finished with success 200 * @throws IOException if something goes wrong or timeout occurs 201 */ 202 public abstract void waitForZkNodeToStart(ServerName serverName, long timeout) 203 throws IOException; 204 205 /** 206 * Wait for the specified zookeeper node to stop the thread / process. 207 * @return whether the operation finished with success 208 * @throws IOException if something goes wrong or timeout occurs 209 */ 210 public abstract void waitForZkNodeToStop(ServerName serverName, long timeout) 211 throws IOException; 212 213 /** 214 * Starts a new datanode on the given hostname or if this is a mini/local cluster, 215 * silently logs warning message. 216 * @throws IOException if something goes wrong 217 */ 218 public abstract void startDataNode(ServerName serverName) throws IOException; 219 220 /** 221 * Kills the datanode process if this is a distributed cluster, otherwise, 222 * this causes master to exit doing basic clean up only. 223 * @throws IOException if something goes wrong 224 */ 225 public abstract void killDataNode(ServerName serverName) throws IOException; 226 227 /** 228 * Stops the datanode if this is a distributed cluster, otherwise 229 * silently logs warning message. 230 * @throws IOException if something goes wrong 231 */ 232 public abstract void stopDataNode(ServerName serverName) throws IOException; 233 234 /** 235 * Wait for the specified datanode to join the cluster 236 * @return whether the operation finished with success 237 * @throws IOException if something goes wrong or timeout occurs 238 */ 239 public abstract void waitForDataNodeToStart(ServerName serverName, long timeout) 240 throws IOException; 241 242 /** 243 * Wait for the specified datanode to stop the thread / process. 244 * @return whether the operation finished with success 245 * @throws IOException if something goes wrong or timeout occurs 246 */ 247 public abstract void waitForDataNodeToStop(ServerName serverName, long timeout) 248 throws IOException; 249 250 /** 251 * Starts a new master on the given hostname or if this is a mini/local cluster, 252 * starts a master locally. 253 * @param hostname the hostname to start the master on 254 * @return whether the operation finished with success 255 * @throws IOException if something goes wrong 256 */ 257 public abstract void startMaster(String hostname, int port) throws IOException; 258 259 /** 260 * Kills the master process if this is a distributed cluster, otherwise, 261 * this causes master to exit doing basic clean up only. 262 * @throws IOException if something goes wrong 263 */ 264 public abstract void killMaster(ServerName serverName) throws IOException; 265 266 /** 267 * Stops the given master, by attempting a gradual stop. 268 * @throws IOException if something goes wrong 269 */ 270 public abstract void stopMaster(ServerName serverName) throws IOException; 271 272 /** 273 * Wait for the specified master to stop the thread / process. 274 * @throws IOException if something goes wrong or timeout occurs 275 */ 276 public abstract void waitForMasterToStop(ServerName serverName, long timeout) 277 throws IOException; 278 279 /** 280 * Blocks until there is an active master and that master has completed 281 * initialization. 282 * 283 * @return true if an active master becomes available. false if there are no 284 * masters left. 285 * @throws IOException if something goes wrong or timeout occurs 286 */ 287 public boolean waitForActiveAndReadyMaster() 288 throws IOException { 289 return waitForActiveAndReadyMaster(Long.MAX_VALUE); 290 } 291 292 /** 293 * Blocks until there is an active master and that master has completed 294 * initialization. 295 * @param timeout the timeout limit in ms 296 * @return true if an active master becomes available. false if there are no 297 * masters left. 298 */ 299 public abstract boolean waitForActiveAndReadyMaster(long timeout) 300 throws IOException; 301 302 /** 303 * Wait for HBase Cluster to shut down. 304 */ 305 public abstract void waitUntilShutDown() throws IOException; 306 307 /** 308 * Shut down the HBase cluster 309 */ 310 public abstract void shutdown() throws IOException; 311 312 /** 313 * Restores the cluster to it's initial state if this is a real cluster, 314 * otherwise does nothing. 315 * This is a best effort restore. If the servers are not reachable, or insufficient 316 * permissions, etc. restoration might be partial. 317 * @return whether restoration is complete 318 */ 319 public boolean restoreInitialStatus() throws IOException { 320 return restoreClusterMetrics(getInitialClusterMetrics()); 321 } 322 323 /** 324 * Restores the cluster to given state if this is a real cluster, 325 * otherwise does nothing. 326 * This is a best effort restore. If the servers are not reachable, or insufficient 327 * permissions, etc. restoration might be partial. 328 * @return whether restoration is complete 329 */ 330 public boolean restoreClusterMetrics(ClusterMetrics desiredStatus) throws IOException { 331 return true; 332 } 333 334 /** 335 * Get the ServerName of region server serving the first hbase:meta region 336 */ 337 public ServerName getServerHoldingMeta() throws IOException { 338 return getServerHoldingRegion(TableName.META_TABLE_NAME, 339 HRegionInfo.FIRST_META_REGIONINFO.getRegionName()); 340 } 341 342 /** 343 * Get the ServerName of region server serving the specified region 344 * @param regionName Name of the region in bytes 345 * @param tn Table name that has the region. 346 * @return ServerName that hosts the region or null 347 */ 348 public abstract ServerName getServerHoldingRegion(final TableName tn, byte[] regionName) 349 throws IOException; 350 351 /** 352 * @return whether we are interacting with a distributed cluster as opposed to an 353 * in-process mini/local cluster. 354 */ 355 public boolean isDistributedCluster() { 356 return false; 357 } 358 359 /** 360 * Closes all the resources held open for this cluster. Note that this call does not shutdown 361 * the cluster. 362 * @see #shutdown() 363 */ 364 @Override 365 public abstract void close() throws IOException; 366 367 /** 368 * Wait for the namenode. 369 * 370 * @throws InterruptedException 371 */ 372 public void waitForNamenodeAvailable() throws InterruptedException { 373 } 374 375 public void waitForDatanodesRegistered(int nbDN) throws Exception { 376 } 377}