1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19 package org.apache.hadoop.hbase.client;
20
21 import static org.apache.hadoop.hbase.util.DNS.getMasterHostname;
22 import com.google.common.base.Preconditions;
23 import com.google.common.base.Strings;
24 import com.google.common.collect.ImmutableMap;
25 import com.google.common.collect.ImmutableSet;
26 import com.google.common.net.HostAndPort;
27 import com.google.protobuf.Message;
28 import com.google.protobuf.RpcController;
29 import java.io.IOException;
30 import java.net.UnknownHostException;
31 import java.util.ArrayList;
32 import java.util.Collections;
33 import java.util.HashSet;
34 import java.util.List;
35 import java.util.Set;
36 import java.util.concurrent.ThreadLocalRandom;
37 import org.apache.hadoop.conf.Configuration;
38 import org.apache.hadoop.hbase.HBaseIOException;
39 import org.apache.hadoop.hbase.HConstants;
40 import org.apache.hadoop.hbase.HRegionLocation;
41 import org.apache.hadoop.hbase.RegionLocations;
42 import org.apache.hadoop.hbase.ServerName;
43 import org.apache.hadoop.hbase.TableName;
44 import org.apache.hadoop.hbase.classification.InterfaceAudience;
45 import org.apache.hadoop.hbase.exceptions.ClientExceptionsUtil;
46 import org.apache.hadoop.hbase.exceptions.MasterRegistryFetchException;
47 import org.apache.hadoop.hbase.ipc.BlockingRpcCallback;
48 import org.apache.hadoop.hbase.ipc.HBaseRpcController;
49 import org.apache.hadoop.hbase.ipc.RpcClient;
50 import org.apache.hadoop.hbase.ipc.RpcClientFactory;
51 import org.apache.hadoop.hbase.ipc.RpcControllerFactory;
52 import org.apache.hadoop.hbase.protobuf.ProtobufUtil;
53 import org.apache.hadoop.hbase.protobuf.generated.HBaseProtos;
54 import org.apache.hadoop.hbase.security.User;
55
56 import org.apache.hadoop.hbase.protobuf.generated.MasterProtos.ClientMetaService;
57 import org.apache.hadoop.hbase.protobuf.generated.MasterProtos.GetClusterIdRequest;
58 import org.apache.hadoop.hbase.protobuf.generated.MasterProtos.GetClusterIdResponse;
59 import org.apache.hadoop.hbase.protobuf.generated.MasterProtos.GetMastersRequest;
60 import org.apache.hadoop.hbase.protobuf.generated.MasterProtos.GetMastersResponse;
61 import org.apache.hadoop.hbase.protobuf.generated.MasterProtos.GetMastersResponseEntry;
62 import org.apache.hadoop.hbase.protobuf.generated.MasterProtos.GetMetaRegionLocationsRequest;
63 import org.apache.hadoop.hbase.protobuf.generated.MasterProtos.GetMetaRegionLocationsResponse;
64 import org.apache.hadoop.hbase.protobuf.generated.MasterProtos.GetNumLiveRSRequest;
65 import org.apache.hadoop.hbase.protobuf.generated.MasterProtos.GetNumLiveRSResponse;
66 import org.apache.hadoop.hbase.protobuf.generated.MasterProtos.GetTableStateRequest;
67 import org.apache.hadoop.hbase.protobuf.generated.MasterProtos.GetTableStateResponse;
68
69
70
71
72
73
74 @InterfaceAudience.Private
75 public class MasterRegistry implements ConnectionRegistry {
76 private static final String MASTER_ADDRS_CONF_SEPARATOR = ",";
77
78 private volatile ImmutableMap<String, ClientMetaService.Interface> masterAddr2Stub;
79
80
81 private RpcClient rpcClient;
82 private RpcControllerFactory rpcControllerFactory;
83 private int rpcTimeoutMs;
84
85 protected MasterAddressRefresher masterAddressRefresher;
86
87 @Override
88 public void init(Connection connection) throws IOException {
89 Configuration conf = connection.getConfiguration();
90 rpcTimeoutMs = (int) Math.min(Integer.MAX_VALUE,
91 conf.getLong(HConstants.HBASE_RPC_TIMEOUT_KEY, HConstants.DEFAULT_HBASE_RPC_TIMEOUT));
92
93
94
95 rpcClient = RpcClientFactory.createClient(conf, null);
96 rpcControllerFactory = RpcControllerFactory.instantiate(conf);
97 populateMasterStubs(parseMasterAddrs(conf));
98 masterAddressRefresher = new MasterAddressRefresher(conf, this);
99 }
100
101 protected interface Callable <T extends Message> {
102 T call(ClientMetaService.Interface stub, RpcController controller) throws IOException;
103 }
104
105 protected <T extends Message> T doCall(Callable<T> callable)
106 throws MasterRegistryFetchException {
107 Exception lastException = null;
108 Set<String> masters = masterAddr2Stub.keySet();
109 List<ClientMetaService.Interface> stubs = new ArrayList<>(masterAddr2Stub.values());
110 Collections.shuffle(stubs, ThreadLocalRandom.current());
111 for (ClientMetaService.Interface stub: stubs) {
112 HBaseRpcController controller = rpcControllerFactory.newController();
113 try {
114 T resp = callable.call(stub, controller);
115 if (!controller.failed()) {
116 return resp;
117 }
118 lastException = controller.getFailed();
119 } catch (Exception e) {
120 lastException = e;
121 }
122 if (ClientExceptionsUtil.isConnectionException(lastException)) {
123 masterAddressRefresher.refreshNow();
124 }
125 }
126
127 throw new MasterRegistryFetchException(masters, lastException);
128 }
129
130 @Override
131 public ServerName getActiveMaster() throws IOException {
132 GetMastersResponseEntry activeMaster = null;
133 for (GetMastersResponseEntry entry: getMastersInternal().getMasterServersList()) {
134 if (entry.getIsActive()) {
135 activeMaster = entry;
136 break;
137 }
138 }
139 if (activeMaster == null) {
140 throw new HBaseIOException("No active master found");
141 }
142 return ProtobufUtil.toServerName(activeMaster.getServerName());
143 }
144
145 List<ServerName> getMasters() throws IOException {
146 List<ServerName> result = new ArrayList<>();
147 for (GetMastersResponseEntry entry: getMastersInternal().getMasterServersList()) {
148 result.add(ProtobufUtil.toServerName(entry.getServerName()));
149 }
150 return result;
151 }
152
153 private GetMastersResponse getMastersInternal() throws IOException {
154 return doCall(new Callable<GetMastersResponse>() {
155 @Override
156 public GetMastersResponse call(
157 ClientMetaService.Interface stub, RpcController controller) throws IOException {
158 BlockingRpcCallback<GetMastersResponse> cb = new BlockingRpcCallback<>();
159 stub.getMasters(controller, GetMastersRequest.getDefaultInstance(), cb);
160 return cb.get();
161 }
162 });
163 }
164
165 @Override
166 public RegionLocations getMetaRegionLocations() throws IOException {
167 GetMetaRegionLocationsResponse resp = doCall(new Callable<GetMetaRegionLocationsResponse>() {
168 @Override
169 public GetMetaRegionLocationsResponse call(
170 ClientMetaService.Interface stub, RpcController controller) throws IOException {
171 BlockingRpcCallback<GetMetaRegionLocationsResponse> cb = new BlockingRpcCallback<>();
172 stub.getMetaRegionLocations(controller, GetMetaRegionLocationsRequest.getDefaultInstance(),
173 cb);
174 return cb.get();
175 }
176 });
177 List<HRegionLocation> result = new ArrayList<>();
178 for (HBaseProtos.RegionLocation loc: resp.getMetaLocationsList()) {
179 result.add(ProtobufUtil.toRegionLocation(loc));
180 }
181 return new RegionLocations(result);
182 }
183
184 @Override
185 public String getClusterId() throws IOException {
186 GetClusterIdResponse resp = doCall(new Callable<GetClusterIdResponse>() {
187 @Override
188 public GetClusterIdResponse call(ClientMetaService.Interface stub, RpcController controller)
189 throws IOException {
190 BlockingRpcCallback<GetClusterIdResponse> cb = new BlockingRpcCallback<>();
191 stub.getClusterId(controller, GetClusterIdRequest.getDefaultInstance(), cb);
192 return cb.get();
193 }
194 });
195 return resp.getClusterId();
196 }
197
198 @Override
199 public int getCurrentNrHRS() throws IOException {
200 GetNumLiveRSResponse resp = doCall(new Callable<GetNumLiveRSResponse>() {
201 @Override
202 public GetNumLiveRSResponse call(ClientMetaService.Interface stub, RpcController controller)
203 throws IOException {
204 BlockingRpcCallback<GetNumLiveRSResponse> cb = new BlockingRpcCallback<>();
205 stub.getNumLiveRS(controller, GetNumLiveRSRequest.getDefaultInstance(), cb);
206 return cb.get();
207 }
208 });
209 return resp.getNumRegionServers();
210 }
211
212 @Override
213 public boolean isTableOnlineState(TableName tableName, boolean enabled) throws IOException {
214 final GetTableStateRequest request = GetTableStateRequest.newBuilder().setTableName(
215 tableName.getNameAsString()).setIsEnabled(enabled).build();
216 GetTableStateResponse resp = doCall(new Callable<GetTableStateResponse>() {
217 @Override
218 public GetTableStateResponse call(ClientMetaService.Interface stub, RpcController controller)
219 throws IOException {
220 BlockingRpcCallback<GetTableStateResponse> cb = new BlockingRpcCallback<>();
221 stub.getTableState(controller, request, cb);
222 return cb.get();
223 }
224 });
225 return resp.getEnabledOrDisabled();
226 }
227
228 @Override
229 public void close() {
230 if (rpcClient != null) {
231 rpcClient.close();
232 }
233 }
234
235
236
237
238
239
240 @InterfaceAudience.Private
241 public static Set<ServerName> parseMasterAddrs(Configuration conf) throws UnknownHostException {
242 Set<ServerName> masterAddrs = new HashSet<>();
243 String configuredMasters = getMasterAddr(conf);
244 for (String masterAddr : configuredMasters.split(MASTER_ADDRS_CONF_SEPARATOR)) {
245 HostAndPort masterHostPort =
246 HostAndPort.fromString(masterAddr.trim()).withDefaultPort(HConstants.DEFAULT_MASTER_PORT);
247 masterAddrs.add(ServerName.valueOf(masterHostPort.toString(), ServerName.NON_STARTCODE));
248 }
249 Preconditions.checkArgument(!masterAddrs.isEmpty(), "At least one master address is needed");
250 return masterAddrs;
251 }
252
253
254
255
256
257
258 @InterfaceAudience.Private
259 public static String getMasterAddr(Configuration conf) throws UnknownHostException {
260 String masterAddrFromConf = conf.get(HConstants.MASTER_ADDRS_KEY);
261 if (!Strings.isNullOrEmpty(masterAddrFromConf)) {
262 return masterAddrFromConf;
263 }
264 String hostname = getMasterHostname(conf);
265 int port = conf.getInt(HConstants.MASTER_PORT, HConstants.DEFAULT_MASTER_PORT);
266 return String.format("%s:%d", hostname, port);
267 }
268
269 void populateMasterStubs(Set<ServerName> masters) throws IOException {
270 Preconditions.checkNotNull(masters);
271 ImmutableMap.Builder<String, ClientMetaService.Interface> builder = ImmutableMap.builder();
272 User user = User.getCurrent();
273 for (ServerName masterAddr : masters) {
274 builder.put(masterAddr.toString(), ClientMetaService.newStub(
275 rpcClient.createRpcChannel(masterAddr, user, rpcTimeoutMs)));
276 }
277 masterAddr2Stub = builder.build();
278 }
279
280 @InterfaceAudience.Private
281 ImmutableSet<String> getParsedMasterServers() {
282 return masterAddr2Stub.keySet();
283 }
284 }