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.testing; 019 020import java.util.List; 021import java.util.Optional; 022import java.util.UUID; 023import java.util.concurrent.CompletableFuture; 024import java.util.concurrent.ExecutorService; 025import java.util.concurrent.Executors; 026import java.util.stream.Collectors; 027import org.apache.hadoop.conf.Configuration; 028import org.apache.hadoop.fs.CommonConfigurationKeysPublic; 029import org.apache.hadoop.hbase.HBaseTestingUtility; 030import org.apache.hadoop.hbase.HConstants; 031import org.apache.hadoop.hbase.ServerName; 032import org.apache.hadoop.hbase.StartMiniClusterOption; 033import org.apache.hadoop.hbase.client.RegionInfo; 034import org.apache.hadoop.hbase.master.HMaster; 035import org.apache.hadoop.hbase.regionserver.HRegion; 036import org.apache.hadoop.hbase.regionserver.OnlineRegions; 037import org.apache.hadoop.hbase.regionserver.Region; 038import org.apache.hadoop.hbase.util.JVMClusterUtil.MasterThread; 039import org.apache.hadoop.hbase.util.JVMClusterUtil.RegionServerThread; 040import org.apache.yetus.audience.InterfaceAudience; 041 042import org.apache.hbase.thirdparty.com.google.common.base.Preconditions; 043import org.apache.hbase.thirdparty.com.google.common.util.concurrent.ThreadFactoryBuilder; 044 045@InterfaceAudience.Private 046class TestingHBaseClusterImpl implements TestingHBaseCluster { 047 048 private final HBaseTestingUtility util; 049 050 private final StartMiniClusterOption option; 051 052 private final String externalDfsUri; 053 054 private final String externalZkConnectString; 055 056 private final ExecutorService executor = Executors.newCachedThreadPool(new ThreadFactoryBuilder() 057 .setNameFormat(getClass().getSuperclass() + "-%d").setDaemon(true).build()); 058 059 private boolean miniClusterRunning = false; 060 061 private boolean miniHBaseClusterRunning = false; 062 063 TestingHBaseClusterImpl(TestingHBaseClusterOption option) { 064 this.util = new HBaseTestingUtility(option.conf()); 065 this.option = option.convert(); 066 this.externalDfsUri = option.getExternalDfsUri(); 067 this.externalZkConnectString = option.getExternalZkConnectString(); 068 } 069 070 @Override 071 public Configuration getConf() { 072 return util.getConfiguration(); 073 } 074 075 private int getRegionServerIndex(ServerName serverName) { 076 // we have a small number of region servers, this should be fine for now. 077 List<RegionServerThread> servers = util.getMiniHBaseCluster().getRegionServerThreads(); 078 for (int i = 0; i < servers.size(); i++) { 079 if (servers.get(i).getRegionServer().getServerName().equals(serverName)) { 080 return i; 081 } 082 } 083 return -1; 084 } 085 086 private int getMasterIndex(ServerName serverName) { 087 List<MasterThread> masters = util.getMiniHBaseCluster().getMasterThreads(); 088 for (int i = 0; i < masters.size(); i++) { 089 if (masters.get(i).getMaster().getServerName().equals(serverName)) { 090 return i; 091 } 092 } 093 return -1; 094 } 095 096 private void join(Thread thread, CompletableFuture<?> future) { 097 executor.execute(() -> { 098 try { 099 thread.join(); 100 future.complete(null); 101 } catch (InterruptedException e) { 102 future.completeExceptionally(e); 103 } 104 }); 105 } 106 107 @Override 108 public CompletableFuture<Void> stopMaster(ServerName serverName) throws Exception { 109 CompletableFuture<Void> future = new CompletableFuture<>(); 110 int index = getMasterIndex(serverName); 111 if (index == -1) { 112 future.completeExceptionally(new IllegalArgumentException("Unknown master " + serverName)); 113 } 114 join(util.getMiniHBaseCluster().stopMaster(index), future); 115 return future; 116 } 117 118 @Override 119 public CompletableFuture<Void> stopRegionServer(ServerName serverName) throws Exception { 120 CompletableFuture<Void> future = new CompletableFuture<>(); 121 int index = getRegionServerIndex(serverName); 122 if (index == -1) { 123 future 124 .completeExceptionally(new IllegalArgumentException("Unknown region server " + serverName)); 125 } 126 join(util.getMiniHBaseCluster().stopRegionServer(index), future); 127 return future; 128 } 129 130 @Override 131 public void stopHBaseCluster() throws Exception { 132 Preconditions.checkState(miniClusterRunning, "Cluster has already been stopped"); 133 Preconditions.checkState(miniHBaseClusterRunning, "HBase cluster has already been started"); 134 util.shutdownMiniHBaseCluster(); 135 miniHBaseClusterRunning = false; 136 } 137 138 @Override 139 public void startHBaseCluster() throws Exception { 140 Preconditions.checkState(miniClusterRunning, "Cluster has already been stopped"); 141 Preconditions.checkState(!miniHBaseClusterRunning, "HBase cluster has already been started"); 142 util.startMiniHBaseCluster(option); 143 miniHBaseClusterRunning = true; 144 } 145 146 @Override 147 public void start() throws Exception { 148 Preconditions.checkState(!miniClusterRunning, "Cluster has already been started"); 149 if (externalZkConnectString == null) { 150 util.startMiniZKCluster(); 151 } else { 152 Configuration conf = util.getConfiguration(); 153 conf.set(HConstants.ZOOKEEPER_QUORUM, externalZkConnectString); 154 conf.set(HConstants.ZOOKEEPER_ZNODE_PARENT, "/" + UUID.randomUUID().toString()); 155 } 156 if (externalDfsUri == null) { 157 util.startMiniDFSCluster(option.getNumDataNodes(), option.getDataNodeHosts()); 158 } else { 159 Configuration conf = util.getConfiguration(); 160 conf.set(CommonConfigurationKeysPublic.FS_DEFAULT_NAME_KEY, externalDfsUri); 161 } 162 util.startMiniHBaseCluster(option); 163 miniClusterRunning = true; 164 miniHBaseClusterRunning = true; 165 } 166 167 @Override 168 public void stop() throws Exception { 169 Preconditions.checkState(miniClusterRunning, "Cluster has already been stopped"); 170 util.shutdownMiniCluster(); 171 miniClusterRunning = false; 172 miniHBaseClusterRunning = false; 173 } 174 175 @Override 176 public boolean isHBaseClusterRunning() { 177 return miniHBaseClusterRunning; 178 } 179 180 @Override 181 public boolean isClusterRunning() { 182 return miniClusterRunning; 183 } 184 185 @Override 186 public void startMaster() throws Exception { 187 util.getMiniHBaseCluster().startMaster(); 188 } 189 190 @Override 191 public void startMaster(String hostname, int port) throws Exception { 192 util.getMiniHBaseCluster().startMaster(hostname, port); 193 } 194 195 @Override 196 public void startRegionServer() throws Exception { 197 util.getMiniHBaseCluster().startRegionServer(); 198 } 199 200 @Override 201 public void startRegionServer(String hostname, int port) throws Exception { 202 util.getMiniHBaseCluster().startRegionServer(hostname, port); 203 } 204 205 @Override 206 public Optional<ServerName> getActiveMasterAddress() { 207 return Optional.ofNullable(util.getMiniHBaseCluster().getMaster()).map(HMaster::getServerName); 208 } 209 210 @Override 211 public List<ServerName> getBackupMasterAddresses() { 212 return util.getMiniHBaseCluster().getMasterThreads().stream().map(MasterThread::getMaster) 213 .filter(m -> !m.isActiveMaster()).map(HMaster::getServerName).collect(Collectors.toList()); 214 } 215 216 @Override 217 public List<ServerName> getRegionServerAddresses() { 218 return util.getMiniHBaseCluster().getRegionServerThreads().stream() 219 .map(t -> t.getRegionServer().getServerName()).collect(Collectors.toList()); 220 } 221 222 @Override 223 public Optional<Region> getRegion(RegionInfo regionInfo) { 224 for (RegionServerThread t : util.getMiniHBaseCluster().getRegionServerThreads()) { 225 for (HRegion region : t.getRegionServer().getRegions()) { 226 if (region.getRegionInfo().equals(regionInfo)) { 227 return Optional.of(region); 228 } 229 } 230 } 231 return Optional.empty(); 232 } 233 234 @Override 235 public Optional<OnlineRegions> getOnlineRegionsInterface(ServerName serverName) { 236 return Optional.ofNullable(util.getMiniHBaseCluster().getRegionServer(serverName)); 237 } 238}