001/**
002 *
003 * Licensed to the Apache Software Foundation (ASF) under one
004 * or more contributor license agreements.  See the NOTICE file
005 * distributed with this work for additional information
006 * regarding copyright ownership.  The ASF licenses this file
007 * to you under the Apache License, Version 2.0 (the
008 * "License"); you may not use this file except in compliance
009 * with the License.  You may obtain a copy of the License at
010 *
011 *     http://www.apache.org/licenses/LICENSE-2.0
012 *
013 * Unless required by applicable law or agreed to in writing, software
014 * distributed under the License is distributed on an "AS IS" BASIS,
015 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
016 * See the License for the specific language governing permissions and
017 * limitations under the License.
018 */
019package org.apache.hadoop.hbase;
020
021import java.util.Arrays;
022import java.util.List;
023
024import org.apache.commons.lang3.StringUtils;
025import org.apache.hadoop.hbase.master.HMaster;
026import org.apache.yetus.audience.InterfaceAudience;
027
028/**
029 * Options for starting up a mini cluster (including an hbase, dfs and zookeeper clusters) in test.
030 * The options include HDFS options to build mini dfs cluster, Zookeeper options to build mini zk
031 * cluster, and mostly HBase options to build mini hbase cluster.
032 *
033 * To create an object, use a {@link Builder}.
034 * Example usage:
035 * <pre>
036 *    StartMiniClusterOption option = StartMiniClusterOption.builder().
037 *        .numMasters(3).rsClass(MyRegionServer.class).createWALDir(true).build();
038 * </pre>
039 *
040 * Default values can be found in {@link Builder}.
041 */
042@InterfaceAudience.Public
043public final class StartMiniClusterOption {
044  /**
045   * Number of masters to start up.  We'll start this many hbase masters.  If numMasters > 1, you
046   * can find the active/primary master with {@link MiniHBaseCluster#getMaster()}.
047   */
048  private final int numMasters;
049  /**
050   * The class to use as HMaster, or null for default.
051   */
052  private final Class<? extends HMaster> masterClass;
053
054  /**
055   * Number of region servers to start up.
056   * If this value is > 1, then make sure config "hbase.regionserver.info.port" is -1
057   * (i.e. no ui per regionserver) otherwise bind errors.
058   */
059  private final int numRegionServers;
060  /**
061   * Ports that RegionServer should use. Pass ports if you want to test cluster restart where for
062   * sure the regionservers come up on same address+port (but just with different startcode); by
063   * default mini hbase clusters choose new arbitrary ports on each cluster start.
064   */
065  private final List<Integer> rsPorts;
066  /**
067   * The class to use as HRegionServer, or null for default.
068   */
069  private Class<? extends MiniHBaseCluster.MiniHBaseClusterRegionServer> rsClass;
070
071  /**
072   * Number of datanodes. Used to create mini DSF cluster. Surpassed by {@link #dataNodeHosts} size.
073   */
074  private final int numDataNodes;
075  /**
076   * The hostnames of DataNodes to run on. This is useful if you want to run datanode on distinct
077   * hosts for things like HDFS block location verification. If you start MiniDFSCluster without
078   * host names, all instances of the datanodes will have the same host name.
079   */
080  private final String[] dataNodeHosts;
081
082  /**
083   * Number of Zookeeper servers.
084   */
085  private final int numZkServers;
086
087  /**
088   * Whether to create a new root or data directory path.  If true, the newly created data directory
089   * will be configured as HBase rootdir.  This will overwrite existing root directory config.
090   */
091  private final boolean createRootDir;
092
093  /**
094   * Whether to create a new WAL directory.  If true, the newly created directory will be configured
095   * as HBase wal.dir which is separate from HBase rootdir.
096   */
097  private final boolean createWALDir;
098
099  /**
100   * Private constructor. Use {@link Builder#build()}.
101   */
102  private StartMiniClusterOption(int numMasters, Class<? extends HMaster> masterClass,
103      int numRegionServers, List<Integer> rsPorts,
104      Class<? extends MiniHBaseCluster.MiniHBaseClusterRegionServer> rsClass, int numDataNodes,
105      String[] dataNodeHosts, int numZkServers, boolean createRootDir, boolean createWALDir) {
106    this.numMasters = numMasters;
107    this.masterClass = masterClass;
108    this.numRegionServers = numRegionServers;
109    this.rsPorts = rsPorts;
110    this.rsClass = rsClass;
111    this.numDataNodes = numDataNodes;
112    this.dataNodeHosts = dataNodeHosts;
113    this.numZkServers = numZkServers;
114    this.createRootDir = createRootDir;
115    this.createWALDir = createWALDir;
116  }
117
118  public int getNumMasters() {
119    return numMasters;
120  }
121
122  public Class<? extends HMaster> getMasterClass() {
123    return masterClass;
124  }
125
126  public int getNumRegionServers() {
127    return numRegionServers;
128  }
129
130  public List<Integer> getRsPorts() {
131    return rsPorts;
132  }
133
134  public Class<? extends MiniHBaseCluster.MiniHBaseClusterRegionServer> getRsClass() {
135    return rsClass;
136  }
137
138  public int getNumDataNodes() {
139    return numDataNodes;
140  }
141
142  public String[] getDataNodeHosts() {
143    return dataNodeHosts;
144  }
145
146  public int getNumZkServers() {
147    return numZkServers;
148  }
149
150  public boolean isCreateRootDir() {
151    return createRootDir;
152  }
153
154  public boolean isCreateWALDir() {
155    return createWALDir;
156  }
157
158  @Override
159  public String toString() {
160    return "StartMiniClusterOption{" + "numMasters=" + numMasters + ", masterClass=" + masterClass
161        + ", numRegionServers=" + numRegionServers + ", rsPorts=" + StringUtils.join(rsPorts)
162        + ", rsClass=" + rsClass + ", numDataNodes=" + numDataNodes
163        + ", dataNodeHosts=" + Arrays.toString(dataNodeHosts) + ", numZkServers=" + numZkServers
164        + ", createRootDir=" + createRootDir + ", createWALDir=" + createWALDir + '}';
165  }
166
167  /**
168   * @return a new builder.
169   */
170  public static Builder builder() {
171    return new Builder();
172  }
173
174  /**
175   * Builder pattern for creating an {@link StartMiniClusterOption}.
176   *
177   * The default values of its fields should be considered public and constant. Changing the default
178   * values may cause other tests fail.
179   */
180  public static final class Builder {
181    private int numMasters = 1;
182    private Class<? extends HMaster> masterClass = null;
183    private int numRegionServers = 1;
184    private List<Integer> rsPorts = null;
185    private Class<? extends MiniHBaseCluster.MiniHBaseClusterRegionServer> rsClass = null;
186    private int numDataNodes = 1;
187    private String[] dataNodeHosts = null;
188    private int numZkServers = 1;
189    private boolean createRootDir = false;
190    private boolean createWALDir = false;
191
192    private Builder() {
193    }
194
195    public StartMiniClusterOption build() {
196      if (dataNodeHosts != null && dataNodeHosts.length != 0) {
197        numDataNodes = dataNodeHosts.length;
198      }
199      return new StartMiniClusterOption(numMasters, masterClass, numRegionServers, rsPorts, rsClass,
200          numDataNodes, dataNodeHosts, numZkServers, createRootDir, createWALDir);
201    }
202
203    public Builder numMasters(int numMasters) {
204      this.numMasters = numMasters;
205      return this;
206    }
207
208    public Builder masterClass(Class<? extends HMaster> masterClass) {
209      this.masterClass = masterClass;
210      return this;
211    }
212
213    public Builder numRegionServers(int numRegionServers) {
214      this.numRegionServers = numRegionServers;
215      return this;
216    }
217
218    public Builder rsPorts(List<Integer> rsPorts) {
219      this.rsPorts = rsPorts;
220      return this;
221    }
222
223    public Builder rsClass(Class<? extends MiniHBaseCluster.MiniHBaseClusterRegionServer> rsClass) {
224      this.rsClass = rsClass;
225      return this;
226    }
227
228    public Builder numDataNodes(int numDataNodes) {
229      this.numDataNodes = numDataNodes;
230      return this;
231    }
232
233    public Builder dataNodeHosts(String[] dataNodeHosts) {
234      this.dataNodeHosts = dataNodeHosts;
235      return this;
236    }
237
238    public Builder numZkServers(int numZkServers) {
239      this.numZkServers = numZkServers;
240      return this;
241    }
242
243    public Builder createRootDir(boolean createRootDir) {
244      this.createRootDir = createRootDir;
245      return this;
246    }
247
248    public Builder createWALDir(boolean createWALDir) {
249      this.createWALDir = createWALDir;
250      return this;
251    }
252  }
253
254}