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.util.Arrays; 021import java.util.List; 022import org.apache.commons.lang3.StringUtils; 023import org.apache.hadoop.hbase.master.HMaster; 024import org.apache.yetus.audience.InterfaceAudience; 025import org.apache.yetus.audience.InterfaceStability; 026 027/** 028 * Options for starting up a testing cluster (including an hbase, dfs and zookeeper clusters) in 029 * test. The options include HDFS options to build mini dfs cluster, Zookeeper options to build mini 030 * zk cluster, and mostly HBase options to build mini hbase cluster. 031 * <p/> 032 * To create an object, use a {@link Builder}. 033 * <p/> 034 * Example usage: 035 * 036 * <pre> 037 * StartTestingClusterOption option = StartTestingClusterOption.builder(). 038 * .numMasters(3).rsClass(MyRegionServer.class).createWALDir(true).build(); 039 * </pre> 040 * 041 * Default values can be found in {@link Builder}. 042 */ 043@InterfaceAudience.LimitedPrivate(HBaseInterfaceAudience.PHOENIX) 044@InterfaceStability.Evolving 045public final class StartTestingClusterOption { 046 /** 047 * Number of masters to start up. We'll start this many hbase masters. If numMasters > 1, you can 048 * find the active/primary master with {@link SingleProcessHBaseCluster#getMaster()}. 049 */ 050 private final int numMasters; 051 052 /** 053 * Number of masters that always remain standby. These set of masters never transition to active 054 * even if an active master does not exist. These are needed for testing scenarios where there are 055 * no active masters in the cluster but the cluster connection (backed by master registry) should 056 * still work. 057 */ 058 private final int numAlwaysStandByMasters; 059 /** 060 * The class to use as HMaster, or null for default. 061 */ 062 private final Class<? extends HMaster> masterClass; 063 064 /** 065 * Number of region servers to start up. If this value is > 1, then make sure config 066 * "hbase.regionserver.info.port" is -1 (i.e. no ui per regionserver) otherwise bind errors. 067 */ 068 private final int numRegionServers; 069 /** 070 * Ports that RegionServer should use. Pass ports if you want to test cluster restart where for 071 * sure the regionservers come up on same address+port (but just with different startcode); by 072 * default mini hbase clusters choose new arbitrary ports on each cluster start. 073 */ 074 private final List<Integer> rsPorts; 075 /** 076 * The class to use as HRegionServer, or null for default. 077 */ 078 private Class<? extends SingleProcessHBaseCluster.MiniHBaseClusterRegionServer> rsClass; 079 080 /** 081 * Number of datanodes. Used to create mini DSF cluster. Surpassed by {@link #dataNodeHosts} size. 082 */ 083 private final int numDataNodes; 084 /** 085 * The hostnames of DataNodes to run on. This is useful if you want to run datanode on distinct 086 * hosts for things like HDFS block location verification. If you start MiniDFSCluster without 087 * host names, all instances of the datanodes will have the same host name. 088 */ 089 private final String[] dataNodeHosts; 090 091 /** 092 * Number of Zookeeper servers. 093 */ 094 private final int numZkServers; 095 096 /** 097 * Whether to create a new root or data directory path. If true, the newly created data directory 098 * will be configured as HBase rootdir. This will overwrite existing root directory config. 099 */ 100 private final boolean createRootDir; 101 102 /** 103 * Whether to create a new WAL directory. If true, the newly created directory will be configured 104 * as HBase wal.dir which is separate from HBase rootdir. 105 */ 106 private final boolean createWALDir; 107 108 /** 109 * Private constructor. Use {@link Builder#build()}. 110 */ 111 private StartTestingClusterOption(int numMasters, int numAlwaysStandByMasters, 112 Class<? extends HMaster> masterClass, int numRegionServers, List<Integer> rsPorts, 113 Class<? extends SingleProcessHBaseCluster.MiniHBaseClusterRegionServer> rsClass, 114 int numDataNodes, String[] dataNodeHosts, int numZkServers, boolean createRootDir, 115 boolean createWALDir) { 116 this.numMasters = numMasters; 117 this.numAlwaysStandByMasters = numAlwaysStandByMasters; 118 this.masterClass = masterClass; 119 this.numRegionServers = numRegionServers; 120 this.rsPorts = rsPorts; 121 this.rsClass = rsClass; 122 this.numDataNodes = numDataNodes; 123 this.dataNodeHosts = dataNodeHosts; 124 this.numZkServers = numZkServers; 125 this.createRootDir = createRootDir; 126 this.createWALDir = createWALDir; 127 } 128 129 public int getNumMasters() { 130 return numMasters; 131 } 132 133 public int getNumAlwaysStandByMasters() { 134 return numAlwaysStandByMasters; 135 } 136 137 public Class<? extends HMaster> getMasterClass() { 138 return masterClass; 139 } 140 141 public int getNumRegionServers() { 142 return numRegionServers; 143 } 144 145 public List<Integer> getRsPorts() { 146 return rsPorts; 147 } 148 149 public Class<? extends SingleProcessHBaseCluster.MiniHBaseClusterRegionServer> getRsClass() { 150 return rsClass; 151 } 152 153 public int getNumDataNodes() { 154 return numDataNodes; 155 } 156 157 public String[] getDataNodeHosts() { 158 return dataNodeHosts; 159 } 160 161 public int getNumZkServers() { 162 return numZkServers; 163 } 164 165 public boolean isCreateRootDir() { 166 return createRootDir; 167 } 168 169 public boolean isCreateWALDir() { 170 return createWALDir; 171 } 172 173 @Override 174 public String toString() { 175 return "StartMiniClusterOption{" + "numMasters=" + numMasters + ", masterClass=" + masterClass 176 + ", numRegionServers=" + numRegionServers + ", rsPorts=" + StringUtils.join(rsPorts) 177 + ", rsClass=" + rsClass + ", numDataNodes=" + numDataNodes + ", dataNodeHosts=" 178 + Arrays.toString(dataNodeHosts) + ", numZkServers=" + numZkServers + ", createRootDir=" 179 + createRootDir + ", createWALDir=" + createWALDir + '}'; 180 } 181 182 /** 183 * Returns a new builder. 184 */ 185 public static Builder builder() { 186 return new Builder(); 187 } 188 189 /** 190 * Builder pattern for creating an {@link StartTestingClusterOption}. 191 * <p/> 192 * The default values of its fields should be considered public and constant. Changing the default 193 * values may cause other tests fail. 194 */ 195 public static final class Builder { 196 private int numMasters = 1; 197 private int numAlwaysStandByMasters = 0; 198 private Class<? extends HMaster> masterClass = null; 199 private int numRegionServers = 1; 200 private List<Integer> rsPorts = null; 201 private Class<? extends SingleProcessHBaseCluster.MiniHBaseClusterRegionServer> rsClass = null; 202 private int numDataNodes = 1; 203 private String[] dataNodeHosts = null; 204 private int numZkServers = 1; 205 private boolean createRootDir = false; 206 private boolean createWALDir = false; 207 208 private Builder() { 209 } 210 211 public StartTestingClusterOption build() { 212 if (dataNodeHosts != null && dataNodeHosts.length != 0) { 213 numDataNodes = dataNodeHosts.length; 214 } 215 return new StartTestingClusterOption(numMasters, numAlwaysStandByMasters, masterClass, 216 numRegionServers, rsPorts, rsClass, numDataNodes, dataNodeHosts, numZkServers, 217 createRootDir, createWALDir); 218 } 219 220 public Builder numMasters(int numMasters) { 221 this.numMasters = numMasters; 222 return this; 223 } 224 225 public Builder numAlwaysStandByMasters(int numAlwaysStandByMasters) { 226 this.numAlwaysStandByMasters = numAlwaysStandByMasters; 227 return this; 228 } 229 230 public Builder masterClass(Class<? extends HMaster> masterClass) { 231 this.masterClass = masterClass; 232 return this; 233 } 234 235 public Builder numRegionServers(int numRegionServers) { 236 this.numRegionServers = numRegionServers; 237 return this; 238 } 239 240 public Builder rsPorts(List<Integer> rsPorts) { 241 this.rsPorts = rsPorts; 242 return this; 243 } 244 245 public Builder 246 rsClass(Class<? extends SingleProcessHBaseCluster.MiniHBaseClusterRegionServer> rsClass) { 247 this.rsClass = rsClass; 248 return this; 249 } 250 251 public Builder numDataNodes(int numDataNodes) { 252 this.numDataNodes = numDataNodes; 253 return this; 254 } 255 256 public Builder dataNodeHosts(String[] dataNodeHosts) { 257 this.dataNodeHosts = dataNodeHosts; 258 return this; 259 } 260 261 public Builder numZkServers(int numZkServers) { 262 this.numZkServers = numZkServers; 263 return this; 264 } 265 266 public Builder numWorkers(int numWorkers) { 267 return numDataNodes(numWorkers).numRegionServers(numWorkers); 268 } 269 270 public Builder createRootDir(boolean createRootDir) { 271 this.createRootDir = createRootDir; 272 return this; 273 } 274 275 public Builder createWALDir(boolean createWALDir) { 276 this.createWALDir = createWALDir; 277 return this; 278 } 279 } 280 281}