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