1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19 package org.apache.hadoop.hbase.master;
20
21 import java.io.IOException;
22 import java.net.InetAddress;
23 import java.util.ArrayList;
24 import java.util.Collections;
25 import java.util.HashMap;
26 import java.util.HashSet;
27 import java.util.Iterator;
28 import java.util.List;
29 import java.util.Map;
30 import java.util.Map.Entry;
31 import java.util.Set;
32 import java.util.concurrent.ConcurrentHashMap;
33 import java.util.concurrent.ConcurrentNavigableMap;
34 import java.util.concurrent.ConcurrentSkipListMap;
35 import java.util.concurrent.CopyOnWriteArrayList;
36
37 import org.apache.commons.logging.Log;
38 import org.apache.commons.logging.LogFactory;
39 import org.apache.hadoop.conf.Configuration;
40 import org.apache.hadoop.hbase.ClockOutOfSyncException;
41 import org.apache.hadoop.hbase.HConstants;
42 import org.apache.hadoop.hbase.HRegionInfo;
43 import org.apache.hadoop.hbase.NotServingRegionException;
44 import org.apache.hadoop.hbase.RegionLoad;
45 import org.apache.hadoop.hbase.Server;
46 import org.apache.hadoop.hbase.ServerLoad;
47 import org.apache.hadoop.hbase.ServerName;
48 import org.apache.hadoop.hbase.YouAreDeadException;
49 import org.apache.hadoop.hbase.ZooKeeperConnectionException;
50 import org.apache.hadoop.hbase.classification.InterfaceAudience;
51 import org.apache.hadoop.hbase.client.ClusterConnection;
52 import org.apache.hadoop.hbase.client.ConnectionFactory;
53 import org.apache.hadoop.hbase.client.RetriesExhaustedException;
54 import org.apache.hadoop.hbase.ipc.PayloadCarryingRpcController;
55 import org.apache.hadoop.hbase.ipc.RpcControllerFactory;
56 import org.apache.hadoop.hbase.master.balancer.BaseLoadBalancer;
57 import org.apache.hadoop.hbase.master.procedure.MasterProcedureEnv;
58 import org.apache.hadoop.hbase.master.procedure.ServerCrashProcedure;
59 import org.apache.hadoop.hbase.monitoring.MonitoredTask;
60 import org.apache.hadoop.hbase.procedure2.ProcedureExecutor;
61 import org.apache.hadoop.hbase.protobuf.ProtobufUtil;
62 import org.apache.hadoop.hbase.protobuf.RequestConverter;
63 import org.apache.hadoop.hbase.protobuf.ResponseConverter;
64 import org.apache.hadoop.hbase.protobuf.generated.AdminProtos.AdminService;
65 import org.apache.hadoop.hbase.protobuf.generated.AdminProtos.OpenRegionRequest;
66 import org.apache.hadoop.hbase.protobuf.generated.AdminProtos.OpenRegionResponse;
67 import org.apache.hadoop.hbase.protobuf.generated.AdminProtos.ServerInfo;
68 import org.apache.hadoop.hbase.protobuf.generated.RegionServerStatusProtos.RegionServerStartupRequest;
69 import org.apache.hadoop.hbase.protobuf.generated.ClusterStatusProtos.RegionStoreSequenceIds;
70 import org.apache.hadoop.hbase.protobuf.generated.ClusterStatusProtos.StoreSequenceId;
71 import org.apache.hadoop.hbase.protobuf.generated.ZooKeeperProtos.SplitLogTask.RecoveryMode;
72 import org.apache.hadoop.hbase.regionserver.HRegionServer;
73 import org.apache.hadoop.hbase.regionserver.RegionOpeningState;
74 import org.apache.hadoop.hbase.security.User;
75 import org.apache.hadoop.hbase.util.Bytes;
76 import org.apache.hadoop.hbase.util.Triple;
77 import org.apache.hadoop.hbase.util.RetryCounter;
78 import org.apache.hadoop.hbase.util.RetryCounterFactory;
79 import org.apache.hadoop.hbase.zookeeper.ZKUtil;
80 import org.apache.hadoop.hbase.zookeeper.ZooKeeperWatcher;
81 import org.apache.zookeeper.KeeperException;
82
83 import com.google.common.annotations.VisibleForTesting;
84 import com.google.protobuf.ByteString;
85 import com.google.protobuf.ServiceException;
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109 @InterfaceAudience.Private
110 public class ServerManager {
111 public static final String WAIT_ON_REGIONSERVERS_MAXTOSTART =
112 "hbase.master.wait.on.regionservers.maxtostart";
113
114 public static final String WAIT_ON_REGIONSERVERS_MINTOSTART =
115 "hbase.master.wait.on.regionservers.mintostart";
116
117 public static final String WAIT_ON_REGIONSERVERS_TIMEOUT =
118 "hbase.master.wait.on.regionservers.timeout";
119
120 public static final String WAIT_ON_REGIONSERVERS_INTERVAL =
121 "hbase.master.wait.on.regionservers.interval";
122
123 private static final Log LOG = LogFactory.getLog(ServerManager.class);
124
125
126 private volatile boolean clusterShutdown = false;
127
128
129
130
131 private final ConcurrentNavigableMap<byte[], Long> flushedSequenceIdByRegion =
132 new ConcurrentSkipListMap<byte[], Long>(Bytes.BYTES_COMPARATOR);
133
134
135
136
137 private final ConcurrentNavigableMap<byte[], ConcurrentNavigableMap<byte[], Long>>
138 storeFlushedSequenceIdsByRegion =
139 new ConcurrentSkipListMap<byte[], ConcurrentNavigableMap<byte[], Long>>(Bytes.BYTES_COMPARATOR);
140
141
142 private final ConcurrentHashMap<ServerName, ServerLoad> onlineServers =
143 new ConcurrentHashMap<ServerName, ServerLoad>();
144
145
146
147
148
149 private final Map<ServerName, AdminService.BlockingInterface> rsAdmins =
150 new HashMap<ServerName, AdminService.BlockingInterface>();
151
152
153
154
155
156 private final ArrayList<ServerName> drainingServers =
157 new ArrayList<ServerName>();
158
159 private final Server master;
160 private final MasterServices services;
161 private final ClusterConnection connection;
162
163 private final DeadServer deadservers = new DeadServer();
164
165 private final long maxSkew;
166 private final long warningSkew;
167
168 private final RetryCounterFactory pingRetryCounterFactory;
169 private final RpcControllerFactory rpcControllerFactory;
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187 private Set<ServerName> queuedDeadServers = new HashSet<ServerName>();
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204 private Map<ServerName, Boolean> requeuedDeadServers
205 = new ConcurrentHashMap<ServerName, Boolean>();
206
207
208 private List<ServerListener> listeners = new CopyOnWriteArrayList<ServerListener>();
209
210
211
212
213
214
215
216 public ServerManager(final Server master, final MasterServices services)
217 throws IOException {
218 this(master, services, true);
219 }
220
221 ServerManager(final Server master, final MasterServices services,
222 final boolean connect) throws IOException {
223 this.master = master;
224 this.services = services;
225 Configuration c = master.getConfiguration();
226 maxSkew = c.getLong("hbase.master.maxclockskew", 30000);
227 warningSkew = c.getLong("hbase.master.warningclockskew", 10000);
228 this.connection = connect ? (ClusterConnection)ConnectionFactory.createConnection(c) : null;
229 int pingMaxAttempts = Math.max(1, master.getConfiguration().getInt(
230 "hbase.master.maximum.ping.server.attempts", 10));
231 int pingSleepInterval = Math.max(1, master.getConfiguration().getInt(
232 "hbase.master.ping.server.retry.sleep.interval", 100));
233 this.pingRetryCounterFactory = new RetryCounterFactory(pingMaxAttempts, pingSleepInterval);
234 this.rpcControllerFactory = this.connection == null
235 ? null
236 : connection.getRpcControllerFactory();
237 }
238
239
240
241
242
243 public void registerListener(final ServerListener listener) {
244 this.listeners.add(listener);
245 }
246
247
248
249
250
251 public boolean unregisterListener(final ServerListener listener) {
252 return this.listeners.remove(listener);
253 }
254
255
256
257
258
259
260
261
262 ServerName regionServerStartup(RegionServerStartupRequest request, InetAddress ia)
263 throws IOException {
264
265
266
267
268
269
270
271
272 final String hostname = request.hasUseThisHostnameInstead() ?
273 request.getUseThisHostnameInstead() :ia.getHostName();
274 ServerName sn = ServerName.valueOf(hostname, request.getPort(),
275 request.getServerStartCode());
276 checkClockSkew(sn, request.getServerCurrentTime());
277 checkIsDead(sn, "STARTUP");
278 if (!checkAndRecordNewServer(sn, ServerLoad.EMPTY_SERVERLOAD)) {
279 LOG.warn("THIS SHOULD NOT HAPPEN, RegionServerStartup"
280 + " could not record the server: " + sn);
281 }
282 return sn;
283 }
284
285 private ConcurrentNavigableMap<byte[], Long> getOrCreateStoreFlushedSequenceId(
286 byte[] regionName) {
287 ConcurrentNavigableMap<byte[], Long> storeFlushedSequenceId =
288 storeFlushedSequenceIdsByRegion.get(regionName);
289 if (storeFlushedSequenceId != null) {
290 return storeFlushedSequenceId;
291 }
292 storeFlushedSequenceId = new ConcurrentSkipListMap<byte[], Long>(Bytes.BYTES_COMPARATOR);
293 ConcurrentNavigableMap<byte[], Long> alreadyPut =
294 storeFlushedSequenceIdsByRegion.putIfAbsent(regionName, storeFlushedSequenceId);
295 return alreadyPut == null ? storeFlushedSequenceId : alreadyPut;
296 }
297
298
299
300
301
302 private void updateLastFlushedSequenceIds(ServerName sn, ServerLoad hsl) {
303 Map<byte[], RegionLoad> regionsLoad = hsl.getRegionsLoad();
304 for (Entry<byte[], RegionLoad> entry : regionsLoad.entrySet()) {
305 byte[] encodedRegionName = Bytes.toBytes(HRegionInfo.encodeRegionName(entry.getKey()));
306 Long existingValue = flushedSequenceIdByRegion.get(encodedRegionName);
307 long l = entry.getValue().getCompleteSequenceId();
308
309 if (LOG.isTraceEnabled()) {
310 LOG.trace(Bytes.toString(encodedRegionName) + ", existingValue=" + existingValue +
311 ", completeSequenceId=" + l);
312 }
313 if (existingValue == null || (l != HConstants.NO_SEQNUM && l > existingValue)) {
314 flushedSequenceIdByRegion.put(encodedRegionName, l);
315 } else if (l != HConstants.NO_SEQNUM && l < existingValue) {
316 LOG.warn("RegionServer " + sn + " indicates a last flushed sequence id ("
317 + l + ") that is less than the previous last flushed sequence id ("
318 + existingValue + ") for region " + Bytes.toString(entry.getKey()) + " Ignoring.");
319 }
320 ConcurrentNavigableMap<byte[], Long> storeFlushedSequenceId =
321 getOrCreateStoreFlushedSequenceId(encodedRegionName);
322 for (StoreSequenceId storeSeqId : entry.getValue().getStoreCompleteSequenceId()) {
323 byte[] family = storeSeqId.getFamilyName().toByteArray();
324 existingValue = storeFlushedSequenceId.get(family);
325 l = storeSeqId.getSequenceId();
326 if (LOG.isTraceEnabled()) {
327 LOG.trace(Bytes.toString(encodedRegionName) + ", family=" + Bytes.toString(family) +
328 ", existingValue=" + existingValue + ", completeSequenceId=" + l);
329 }
330
331 if (existingValue == null || (l != HConstants.NO_SEQNUM && l > existingValue.longValue())) {
332 storeFlushedSequenceId.put(family, l);
333 }
334 }
335 }
336 }
337
338 void regionServerReport(ServerName sn,
339 ServerLoad sl) throws YouAreDeadException {
340 checkIsDead(sn, "REPORT");
341 if (null == this.onlineServers.replace(sn, sl)) {
342
343
344
345
346
347
348 if (!checkAndRecordNewServer(sn, sl)) {
349 LOG.info("RegionServerReport ignored, could not record the server: " + sn);
350 return;
351 }
352 }
353 updateLastFlushedSequenceIds(sn, sl);
354 }
355
356
357
358
359
360
361
362
363
364 boolean checkAndRecordNewServer(
365 final ServerName serverName, final ServerLoad sl) {
366 ServerName existingServer = null;
367 synchronized (this.onlineServers) {
368 existingServer = findServerWithSameHostnamePortWithLock(serverName);
369 if (existingServer != null && (existingServer.getStartcode() > serverName.getStartcode())) {
370 LOG.info("Server serverName=" + serverName + " rejected; we already have "
371 + existingServer.toString() + " registered with same hostname and port");
372 return false;
373 }
374 recordNewServerWithLock(serverName, sl);
375 }
376
377
378 if (!this.listeners.isEmpty()) {
379 for (ServerListener listener : this.listeners) {
380 listener.serverAdded(serverName);
381 }
382 }
383
384
385
386 if (existingServer != null && (existingServer.getStartcode() < serverName.getStartcode())) {
387 LOG.info("Triggering server recovery; existingServer " +
388 existingServer + " looks stale, new server:" + serverName);
389 expireServer(existingServer);
390 }
391 return true;
392 }
393
394
395
396
397
398
399
400
401
402 private void checkClockSkew(final ServerName serverName, final long serverCurrentTime)
403 throws ClockOutOfSyncException {
404 long skew = Math.abs(System.currentTimeMillis() - serverCurrentTime);
405 if (skew > maxSkew) {
406 String message = "Server " + serverName + " has been " +
407 "rejected; Reported time is too far out of sync with master. " +
408 "Time difference of " + skew + "ms > max allowed of " + maxSkew + "ms";
409 LOG.warn(message);
410 throw new ClockOutOfSyncException(message);
411 } else if (skew > warningSkew){
412 String message = "Reported time for server " + serverName + " is out of sync with master " +
413 "by " + skew + "ms. (Warning threshold is " + warningSkew + "ms; " +
414 "error threshold is " + maxSkew + "ms)";
415 LOG.warn(message);
416 }
417 }
418
419
420
421
422
423
424
425
426
427 private void checkIsDead(final ServerName serverName, final String what)
428 throws YouAreDeadException {
429 if (this.deadservers.isDeadServer(serverName)) {
430
431
432 String message = "Server " + what + " rejected; currently processing " +
433 serverName + " as dead server";
434 LOG.debug(message);
435 throw new YouAreDeadException(message);
436 }
437
438
439 if ((this.services == null || ((HMaster) this.services).isInitialized())
440 && this.deadservers.cleanPreviousInstance(serverName)) {
441
442
443 LOG.debug(what + ":" + " Server " + serverName + " came back up," +
444 " removed it from the dead servers list");
445 }
446 }
447
448
449
450
451
452 private ServerName findServerWithSameHostnamePortWithLock(
453 final ServerName serverName) {
454 for (ServerName sn: this.onlineServers.keySet()) {
455 if (ServerName.isSameHostnameAndPort(serverName, sn)) return sn;
456 }
457 return null;
458 }
459
460
461
462
463
464
465
466 @VisibleForTesting
467 void recordNewServerWithLock(final ServerName serverName, final ServerLoad sl) {
468 LOG.info("Registering server=" + serverName);
469 this.onlineServers.put(serverName, sl);
470 this.rsAdmins.remove(serverName);
471 }
472
473 public RegionStoreSequenceIds getLastFlushedSequenceId(byte[] encodedRegionName) {
474 RegionStoreSequenceIds.Builder builder = RegionStoreSequenceIds.newBuilder();
475 Long seqId = flushedSequenceIdByRegion.get(encodedRegionName);
476 builder.setLastFlushedSequenceId(seqId != null ? seqId.longValue() : HConstants.NO_SEQNUM);
477 Map<byte[], Long> storeFlushedSequenceId =
478 storeFlushedSequenceIdsByRegion.get(encodedRegionName);
479 if (storeFlushedSequenceId != null) {
480 for (Map.Entry<byte[], Long> entry : storeFlushedSequenceId.entrySet()) {
481 builder.addStoreSequenceId(StoreSequenceId.newBuilder()
482 .setFamilyName(ByteString.copyFrom(entry.getKey()))
483 .setSequenceId(entry.getValue().longValue()).build());
484 }
485 }
486 return builder.build();
487 }
488
489
490
491
492
493 public ServerLoad getLoad(final ServerName serverName) {
494 return this.onlineServers.get(serverName);
495 }
496
497
498
499
500
501
502
503 public double getAverageLoad() {
504 int totalLoad = 0;
505 int numServers = 0;
506 for (ServerLoad sl: this.onlineServers.values()) {
507 numServers++;
508 totalLoad += sl.getNumberOfRegions();
509 }
510 return numServers == 0 ? 0 :
511 (double)totalLoad / (double)numServers;
512 }
513
514
515 public int countOfRegionServers() {
516
517 return this.onlineServers.size();
518 }
519
520
521
522
523 public Map<ServerName, ServerLoad> getOnlineServers() {
524
525 synchronized (this.onlineServers) {
526 return Collections.unmodifiableMap(this.onlineServers);
527 }
528 }
529
530 public DeadServer getDeadServers() {
531 return this.deadservers;
532 }
533
534
535
536
537
538 public boolean areDeadServersInProgress() {
539 return this.deadservers.areDeadServersInProgress();
540 }
541
542 void letRegionServersShutdown() {
543 long previousLogTime = 0;
544 ServerName sn = master.getServerName();
545 ZooKeeperWatcher zkw = master.getZooKeeper();
546 int onlineServersCt;
547 while ((onlineServersCt = onlineServers.size()) > 0){
548
549 if (System.currentTimeMillis() > (previousLogTime + 1000)) {
550 Set<ServerName> remainingServers = onlineServers.keySet();
551 synchronized (onlineServers) {
552 if (remainingServers.size() == 1 && remainingServers.contains(sn)) {
553
554 return;
555 }
556 }
557 StringBuilder sb = new StringBuilder();
558
559 for (ServerName key : remainingServers) {
560 if (sb.length() > 0) {
561 sb.append(", ");
562 }
563 sb.append(key);
564 }
565 LOG.info("Waiting on regionserver(s) to go down " + sb.toString());
566 previousLogTime = System.currentTimeMillis();
567 }
568
569 try {
570 List<String> servers = ZKUtil.listChildrenNoWatch(zkw, zkw.rsZNode);
571 if (servers == null || servers.size() == 0 || (servers.size() == 1
572 && servers.contains(sn.toString()))) {
573 LOG.info("ZK shows there is only the master self online, exiting now");
574
575 break;
576 }
577 } catch (KeeperException ke) {
578 LOG.warn("Failed to list regionservers", ke);
579
580 break;
581 }
582 synchronized (onlineServers) {
583 try {
584 if (onlineServersCt == onlineServers.size()) onlineServers.wait(100);
585 } catch (InterruptedException ignored) {
586
587 }
588 }
589 }
590 }
591
592
593
594
595
596 public synchronized void expireServer(final ServerName serverName) {
597 if (serverName.equals(master.getServerName())) {
598 if (!(master.isAborted() || master.isStopped())) {
599 master.stop("We lost our znode?");
600 }
601 return;
602 }
603 if (!services.isServerCrashProcessingEnabled()) {
604 LOG.info("Master doesn't enable ServerShutdownHandler during initialization, "
605 + "delay expiring server " + serverName);
606 this.queuedDeadServers.add(serverName);
607 return;
608 }
609 if (this.deadservers.isDeadServer(serverName)) {
610
611 LOG.warn("Expiration of " + serverName +
612 " but server shutdown already in progress");
613 return;
614 }
615 moveFromOnelineToDeadServers(serverName);
616
617
618
619 if (this.clusterShutdown) {
620 LOG.info("Cluster shutdown set; " + serverName +
621 " expired; onlineServers=" + this.onlineServers.size());
622 if (this.onlineServers.isEmpty()) {
623 master.stop("Cluster shutdown set; onlineServer=0");
624 }
625 return;
626 }
627
628 boolean carryingMeta = services.getAssignmentManager().isCarryingMeta(serverName) ==
629 AssignmentManager.ServerHostRegion.HOSTING_REGION;
630 ProcedureExecutor<MasterProcedureEnv> procExec = this.services.getMasterProcedureExecutor();
631 procExec.submitProcedure(new ServerCrashProcedure(
632 procExec.getEnvironment(), serverName, true, carryingMeta));
633 LOG.debug("Added=" + serverName +
634 " to dead servers, submitted shutdown handler to be executed meta=" + carryingMeta);
635
636
637 if (!this.listeners.isEmpty()) {
638 for (ServerListener listener : this.listeners) {
639 listener.serverRemoved(serverName);
640 }
641 }
642 }
643
644 @VisibleForTesting
645 public void moveFromOnelineToDeadServers(final ServerName sn) {
646 synchronized (onlineServers) {
647 if (!this.onlineServers.containsKey(sn)) {
648 LOG.warn("Expiration of " + sn + " but server not online");
649 }
650
651
652
653 this.deadservers.add(sn);
654 this.onlineServers.remove(sn);
655 onlineServers.notifyAll();
656 }
657 this.rsAdmins.remove(sn);
658 }
659
660 public synchronized void processDeadServer(final ServerName serverName, boolean shouldSplitWal) {
661
662
663
664
665
666
667
668
669 if (!services.getAssignmentManager().isFailoverCleanupDone()) {
670 requeuedDeadServers.put(serverName, shouldSplitWal);
671 return;
672 }
673
674 this.deadservers.add(serverName);
675 ProcedureExecutor<MasterProcedureEnv> procExec = this.services.getMasterProcedureExecutor();
676 procExec.submitProcedure(new ServerCrashProcedure(
677 procExec.getEnvironment(), serverName, shouldSplitWal, false));
678 }
679
680
681
682
683
684 synchronized void processQueuedDeadServers() {
685 if (!services.isServerCrashProcessingEnabled()) {
686 LOG.info("Master hasn't enabled ServerShutdownHandler");
687 }
688 Iterator<ServerName> serverIterator = queuedDeadServers.iterator();
689 while (serverIterator.hasNext()) {
690 ServerName tmpServerName = serverIterator.next();
691 expireServer(tmpServerName);
692 serverIterator.remove();
693 requeuedDeadServers.remove(tmpServerName);
694 }
695
696 if (!services.getAssignmentManager().isFailoverCleanupDone()) {
697 LOG.info("AssignmentManager hasn't finished failover cleanup; waiting");
698 }
699
700 for(ServerName tmpServerName : requeuedDeadServers.keySet()){
701 processDeadServer(tmpServerName, requeuedDeadServers.get(tmpServerName));
702 }
703 requeuedDeadServers.clear();
704 }
705
706
707
708
709 public boolean removeServerFromDrainList(final ServerName sn) {
710
711
712
713 if (!this.isServerOnline(sn)) {
714 LOG.warn("Server " + sn + " is not currently online. " +
715 "Removing from draining list anyway, as requested.");
716 }
717
718 return this.drainingServers.remove(sn);
719 }
720
721
722
723
724 public boolean addServerToDrainList(final ServerName sn) {
725
726
727
728 if (!this.isServerOnline(sn)) {
729 LOG.warn("Server " + sn + " is not currently online. " +
730 "Ignoring request to add it to draining list.");
731 return false;
732 }
733
734
735 if (this.drainingServers.contains(sn)) {
736 LOG.warn("Server " + sn + " is already in the draining server list." +
737 "Ignoring request to add it again.");
738 return false;
739 }
740 LOG.info("Server " + sn + " added to draining server list.");
741 return this.drainingServers.add(sn);
742 }
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757 public RegionOpeningState sendRegionOpen(final ServerName server,
758 HRegionInfo region, int versionOfOfflineNode, List<ServerName> favoredNodes)
759 throws IOException {
760 AdminService.BlockingInterface admin = getRsAdmin(server);
761 if (admin == null) {
762 LOG.warn("Attempting to send OPEN RPC to server " + server.toString() +
763 " failed because no RPC connection found to this server");
764 return RegionOpeningState.FAILED_OPENING;
765 }
766 OpenRegionRequest request = RequestConverter.buildOpenRegionRequest(server,
767 region, versionOfOfflineNode, favoredNodes,
768 (RecoveryMode.LOG_REPLAY == this.services.getMasterFileSystem().getLogRecoveryMode()));
769 try {
770 OpenRegionResponse response = admin.openRegion(null, request);
771 return ResponseConverter.getRegionOpeningState(response);
772 } catch (ServiceException se) {
773 throw ProtobufUtil.getRemoteException(se);
774 }
775 }
776
777
778
779
780
781
782
783
784
785
786 public List<RegionOpeningState> sendRegionOpen(ServerName server,
787 List<Triple<HRegionInfo, Integer, List<ServerName>>> regionOpenInfos)
788 throws IOException {
789 AdminService.BlockingInterface admin = getRsAdmin(server);
790 if (admin == null) {
791 LOG.warn("Attempting to send OPEN RPC to server " + server.toString() +
792 " failed because no RPC connection found to this server");
793 return null;
794 }
795
796 OpenRegionRequest request = RequestConverter.buildOpenRegionRequest(server, regionOpenInfos,
797 (RecoveryMode.LOG_REPLAY == this.services.getMasterFileSystem().getLogRecoveryMode()));
798 try {
799 OpenRegionResponse response = admin.openRegion(null, request);
800 return ResponseConverter.getRegionOpeningStateList(response);
801 } catch (ServiceException se) {
802 throw ProtobufUtil.getRemoteException(se);
803 }
804 }
805
806 private PayloadCarryingRpcController newRpcController() {
807 return rpcControllerFactory == null ? null : rpcControllerFactory.newController();
808 }
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824 public boolean sendRegionClose(ServerName server, HRegionInfo region,
825 int versionOfClosingNode, ServerName dest, boolean transitionInZK) throws IOException {
826 if (server == null) throw new NullPointerException("Passed server is null");
827 AdminService.BlockingInterface admin = getRsAdmin(server);
828 if (admin == null) {
829 throw new IOException("Attempting to send CLOSE RPC to server " +
830 server.toString() + " for region " +
831 region.getRegionNameAsString() +
832 " failed because no RPC connection found to this server");
833 }
834 PayloadCarryingRpcController controller = newRpcController();
835 return ProtobufUtil.closeRegion(controller, admin, server, region.getRegionName(),
836 versionOfClosingNode, dest, transitionInZK);
837 }
838
839 public boolean sendRegionClose(ServerName server,
840 HRegionInfo region, int versionOfClosingNode) throws IOException {
841 return sendRegionClose(server, region, versionOfClosingNode, null, true);
842 }
843
844
845
846
847
848
849
850
851
852 public void sendRegionWarmup(ServerName server,
853 HRegionInfo region) {
854 if (server == null) return;
855 try {
856 AdminService.BlockingInterface admin = getRsAdmin(server);
857 PayloadCarryingRpcController controller = newRpcController();
858 ProtobufUtil.warmupRegion(controller, admin, region);
859 } catch (IOException e) {
860 LOG.error("Received exception in RPC for warmup server:" +
861 server + "region: " + region +
862 "exception: " + e);
863 }
864 }
865
866
867
868
869
870 public static void closeRegionSilentlyAndWait(ClusterConnection connection,
871 ServerName server, HRegionInfo region, long timeout) throws IOException, InterruptedException {
872 AdminService.BlockingInterface rs = connection.getAdmin(server);
873 PayloadCarryingRpcController controller = connection.getRpcControllerFactory().newController();
874 try {
875 ProtobufUtil.closeRegion(controller, rs, server, region.getRegionName(), false);
876 } catch (IOException e) {
877 LOG.warn("Exception when closing region: " + region.getRegionNameAsString(), e);
878 }
879 long expiration = timeout + System.currentTimeMillis();
880 while (System.currentTimeMillis() < expiration) {
881 try {
882 HRegionInfo rsRegion =
883 ProtobufUtil.getRegionInfo(controller, rs, region.getRegionName());
884 if (rsRegion == null) return;
885 } catch (IOException ioe) {
886 if (ioe instanceof NotServingRegionException)
887 return;
888 LOG.warn("Exception when retrieving regioninfo from: "
889 + region.getRegionNameAsString(), ioe);
890 }
891 Thread.sleep(1000);
892 }
893 throw new IOException("Region " + region + " failed to close within"
894 + " timeout " + timeout);
895 }
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910 public void sendRegionsMerge(ServerName server, HRegionInfo region_a,
911 HRegionInfo region_b, boolean forcible, User user) throws IOException {
912 if (server == null)
913 throw new NullPointerException("Passed server is null");
914 if (region_a == null || region_b == null)
915 throw new NullPointerException("Passed region is null");
916 AdminService.BlockingInterface admin = getRsAdmin(server);
917 if (admin == null) {
918 throw new IOException("Attempting to send MERGE REGIONS RPC to server "
919 + server.toString() + " for region "
920 + region_a.getRegionNameAsString() + ","
921 + region_b.getRegionNameAsString()
922 + " failed because no RPC connection found to this server");
923 }
924 PayloadCarryingRpcController controller = newRpcController();
925 ProtobufUtil.mergeRegions(controller, admin, region_a, region_b, forcible, user);
926 }
927
928
929
930
931 public boolean isServerReachable(ServerName server) {
932 if (server == null) throw new NullPointerException("Passed server is null");
933
934
935 RetryCounter retryCounter = pingRetryCounterFactory.create();
936 while (retryCounter.shouldRetry()) {
937 synchronized (this.onlineServers) {
938 if (this.deadservers.isDeadServer(server)) {
939 return false;
940 }
941 }
942 try {
943 PayloadCarryingRpcController controller = newRpcController();
944 AdminService.BlockingInterface admin = getRsAdmin(server);
945 if (admin != null) {
946 ServerInfo info = ProtobufUtil.getServerInfo(controller, admin);
947 return info != null && info.hasServerName()
948 && server.getStartcode() == info.getServerName().getStartCode();
949 }
950 } catch (IOException ioe) {
951 if (LOG.isDebugEnabled()) {
952 LOG.debug("Couldn't reach " + server + ", try=" + retryCounter.getAttemptTimes() + " of "
953 + retryCounter.getMaxAttempts(), ioe);
954 }
955 try {
956 retryCounter.sleepUntilNextRetry();
957 } catch(InterruptedException ie) {
958 Thread.currentThread().interrupt();
959 break;
960 }
961 }
962 }
963 return false;
964 }
965
966
967
968
969
970
971
972 private AdminService.BlockingInterface getRsAdmin(final ServerName sn)
973 throws IOException {
974 AdminService.BlockingInterface admin = this.rsAdmins.get(sn);
975 if (admin == null) {
976 LOG.debug("New admin connection to " + sn.toString());
977 if (sn.equals(master.getServerName()) && master instanceof HRegionServer) {
978
979 admin = ((HRegionServer)master).getRSRpcServices();
980 } else {
981 admin = this.connection.getAdmin(sn);
982 }
983 this.rsAdmins.put(sn, admin);
984 }
985 return admin;
986 }
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
1001 public void waitForRegionServers(MonitoredTask status)
1002 throws InterruptedException {
1003 final long interval = this.master.getConfiguration().
1004 getLong(WAIT_ON_REGIONSERVERS_INTERVAL, 1500);
1005 final long timeout = this.master.getConfiguration().
1006 getLong(WAIT_ON_REGIONSERVERS_TIMEOUT, 4500);
1007 int defaultMinToStart = 1;
1008 if (BaseLoadBalancer.tablesOnMaster(master.getConfiguration())) {
1009
1010
1011
1012
1013 defaultMinToStart = 2;
1014 }
1015 int minToStart = this.master.getConfiguration().
1016 getInt(WAIT_ON_REGIONSERVERS_MINTOSTART, defaultMinToStart);
1017 if (minToStart < 1) {
1018 LOG.warn(String.format(
1019 "The value of '%s' (%d) can not be less than 1, ignoring.",
1020 WAIT_ON_REGIONSERVERS_MINTOSTART, minToStart));
1021 minToStart = 1;
1022 }
1023 int maxToStart = this.master.getConfiguration().
1024 getInt(WAIT_ON_REGIONSERVERS_MAXTOSTART, Integer.MAX_VALUE);
1025 if (maxToStart < minToStart) {
1026 LOG.warn(String.format(
1027 "The value of '%s' (%d) is set less than '%s' (%d), ignoring.",
1028 WAIT_ON_REGIONSERVERS_MAXTOSTART, maxToStart,
1029 WAIT_ON_REGIONSERVERS_MINTOSTART, minToStart));
1030 maxToStart = Integer.MAX_VALUE;
1031 }
1032
1033 long now = System.currentTimeMillis();
1034 final long startTime = now;
1035 long slept = 0;
1036 long lastLogTime = 0;
1037 long lastCountChange = startTime;
1038 int count = countOfRegionServers();
1039 int oldCount = 0;
1040 while (!this.master.isStopped() && count < maxToStart
1041 && (lastCountChange+interval > now || timeout > slept || count < minToStart)) {
1042
1043 if (oldCount != count || lastLogTime+interval < now){
1044 lastLogTime = now;
1045 String msg =
1046 "Waiting for region servers count to settle; currently"+
1047 " checked in " + count + ", slept for " + slept + " ms," +
1048 " expecting minimum of " + minToStart + ", maximum of "+ maxToStart+
1049 ", timeout of "+timeout+" ms, interval of "+interval+" ms.";
1050 LOG.info(msg);
1051 status.setStatus(msg);
1052 }
1053
1054
1055 final long sleepTime = 50;
1056 Thread.sleep(sleepTime);
1057 now = System.currentTimeMillis();
1058 slept = now - startTime;
1059
1060 oldCount = count;
1061 count = countOfRegionServers();
1062 if (count != oldCount) {
1063 lastCountChange = now;
1064 }
1065 }
1066
1067 LOG.info("Finished waiting for region servers count to settle;" +
1068 " checked in " + count + ", slept for " + slept + " ms," +
1069 " expecting minimum of " + minToStart + ", maximum of "+ maxToStart+","+
1070 " master is "+ (this.master.isStopped() ? "stopped.": "running")
1071 );
1072 }
1073
1074
1075
1076
1077 public List<ServerName> getOnlineServersList() {
1078
1079
1080 return new ArrayList<ServerName>(this.onlineServers.keySet());
1081 }
1082
1083
1084
1085
1086 public List<ServerName> getDrainingServersList() {
1087 return new ArrayList<ServerName>(this.drainingServers);
1088 }
1089
1090
1091
1092
1093 Set<ServerName> getDeadNotExpiredServers() {
1094 return new HashSet<ServerName>(this.queuedDeadServers);
1095 }
1096
1097
1098
1099
1100
1101
1102 void removeRequeuedDeadServers() {
1103 requeuedDeadServers.clear();
1104 }
1105
1106
1107
1108
1109
1110 Map<ServerName, Boolean> getRequeuedDeadServers() {
1111 return Collections.unmodifiableMap(this.requeuedDeadServers);
1112 }
1113
1114 public boolean isServerOnline(ServerName serverName) {
1115 return serverName != null && onlineServers.containsKey(serverName);
1116 }
1117
1118
1119
1120
1121
1122
1123
1124 public synchronized boolean isServerDead(ServerName serverName) {
1125 return serverName == null || deadservers.isDeadServer(serverName)
1126 || queuedDeadServers.contains(serverName)
1127 || requeuedDeadServers.containsKey(serverName);
1128 }
1129
1130 public void shutdownCluster() {
1131 this.clusterShutdown = true;
1132 this.master.stop("Cluster shutdown requested");
1133 }
1134
1135 public boolean isClusterShutdown() {
1136 return this.clusterShutdown;
1137 }
1138
1139
1140
1141
1142 public void stop() {
1143 if (connection != null) {
1144 try {
1145 connection.close();
1146 } catch (IOException e) {
1147 LOG.error("Attempt to close connection to master failed", e);
1148 }
1149 }
1150 }
1151
1152
1153
1154
1155
1156
1157 public List<ServerName> createDestinationServersList(final ServerName serverToExclude){
1158 final List<ServerName> destServers = getOnlineServersList();
1159
1160 if (serverToExclude != null){
1161 destServers.remove(serverToExclude);
1162 }
1163
1164
1165 final List<ServerName> drainingServersCopy = getDrainingServersList();
1166 if (!drainingServersCopy.isEmpty()) {
1167 for (final ServerName server: drainingServersCopy) {
1168 destServers.remove(server);
1169 }
1170 }
1171
1172
1173 removeDeadNotExpiredServers(destServers);
1174 return destServers;
1175 }
1176
1177
1178
1179
1180 public List<ServerName> createDestinationServersList(){
1181 return createDestinationServersList(null);
1182 }
1183
1184
1185
1186
1187
1188
1189
1190 void removeDeadNotExpiredServers(List<ServerName> servers) {
1191 Set<ServerName> deadNotExpiredServersCopy = this.getDeadNotExpiredServers();
1192 if (!deadNotExpiredServersCopy.isEmpty()) {
1193 for (ServerName server : deadNotExpiredServersCopy) {
1194 LOG.debug("Removing dead but not expired server: " + server
1195 + " from eligible server pool.");
1196 servers.remove(server);
1197 }
1198 }
1199 }
1200
1201
1202
1203
1204 void clearDeadServersWithSameHostNameAndPortOfOnlineServer() {
1205 for (ServerName serverName : getOnlineServersList()) {
1206 deadservers.cleanAllPreviousInstances(serverName);
1207 }
1208 }
1209
1210
1211
1212
1213 public void removeRegion(final HRegionInfo regionInfo) {
1214 final byte[] encodedName = regionInfo.getEncodedNameAsBytes();
1215 storeFlushedSequenceIdsByRegion.remove(encodedName);
1216 flushedSequenceIdByRegion.remove(encodedName);
1217 }
1218
1219
1220
1221
1222 public void removeRegions(final List<HRegionInfo> regions) {
1223 for (HRegionInfo hri: regions) {
1224 removeRegion(hri);
1225 }
1226 }
1227 }