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 for (Map.Entry<ServerName, Boolean> entry : requeuedDeadServers.entrySet()) {
700 processDeadServer(entry.getKey(), entry.getValue());
701 }
702 requeuedDeadServers.clear();
703 }
704
705
706
707
708 public boolean removeServerFromDrainList(final ServerName sn) {
709
710
711
712 if (!this.isServerOnline(sn)) {
713 LOG.warn("Server " + sn + " is not currently online. " +
714 "Removing from draining list anyway, as requested.");
715 }
716
717 return this.drainingServers.remove(sn);
718 }
719
720
721
722
723 public boolean addServerToDrainList(final ServerName sn) {
724
725
726
727 if (!this.isServerOnline(sn)) {
728 LOG.warn("Server " + sn + " is not currently online. " +
729 "Ignoring request to add it to draining list.");
730 return false;
731 }
732
733
734 if (this.drainingServers.contains(sn)) {
735 LOG.warn("Server " + sn + " is already in the draining server list." +
736 "Ignoring request to add it again.");
737 return false;
738 }
739 LOG.info("Server " + sn + " added to draining server list.");
740 return this.drainingServers.add(sn);
741 }
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756 public RegionOpeningState sendRegionOpen(final ServerName server,
757 HRegionInfo region, int versionOfOfflineNode, List<ServerName> favoredNodes)
758 throws IOException {
759 AdminService.BlockingInterface admin = getRsAdmin(server);
760 if (admin == null) {
761 LOG.warn("Attempting to send OPEN RPC to server " + server.toString() +
762 " failed because no RPC connection found to this server");
763 return RegionOpeningState.FAILED_OPENING;
764 }
765 OpenRegionRequest request = RequestConverter.buildOpenRegionRequest(server,
766 region, versionOfOfflineNode, favoredNodes,
767 (RecoveryMode.LOG_REPLAY == this.services.getMasterFileSystem().getLogRecoveryMode()));
768 try {
769 OpenRegionResponse response = admin.openRegion(null, request);
770 return ResponseConverter.getRegionOpeningState(response);
771 } catch (ServiceException se) {
772 throw ProtobufUtil.getRemoteException(se);
773 }
774 }
775
776
777
778
779
780
781
782
783
784
785 public List<RegionOpeningState> sendRegionOpen(ServerName server,
786 List<Triple<HRegionInfo, Integer, List<ServerName>>> regionOpenInfos)
787 throws IOException {
788 AdminService.BlockingInterface admin = getRsAdmin(server);
789 if (admin == null) {
790 LOG.warn("Attempting to send OPEN RPC to server " + server.toString() +
791 " failed because no RPC connection found to this server");
792 return null;
793 }
794
795 OpenRegionRequest request = RequestConverter.buildOpenRegionRequest(server, regionOpenInfos,
796 (RecoveryMode.LOG_REPLAY == this.services.getMasterFileSystem().getLogRecoveryMode()));
797 try {
798 OpenRegionResponse response = admin.openRegion(null, request);
799 return ResponseConverter.getRegionOpeningStateList(response);
800 } catch (ServiceException se) {
801 throw ProtobufUtil.getRemoteException(se);
802 }
803 }
804
805 private PayloadCarryingRpcController newRpcController() {
806 return rpcControllerFactory == null ? null : rpcControllerFactory.newController();
807 }
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823 public boolean sendRegionClose(ServerName server, HRegionInfo region,
824 int versionOfClosingNode, ServerName dest, boolean transitionInZK) throws IOException {
825 if (server == null) throw new NullPointerException("Passed server is null");
826 AdminService.BlockingInterface admin = getRsAdmin(server);
827 if (admin == null) {
828 throw new IOException("Attempting to send CLOSE RPC to server " +
829 server.toString() + " for region " +
830 region.getRegionNameAsString() +
831 " failed because no RPC connection found to this server");
832 }
833 PayloadCarryingRpcController controller = newRpcController();
834 return ProtobufUtil.closeRegion(controller, admin, server, region.getRegionName(),
835 versionOfClosingNode, dest, transitionInZK);
836 }
837
838 public boolean sendRegionClose(ServerName server,
839 HRegionInfo region, int versionOfClosingNode) throws IOException {
840 return sendRegionClose(server, region, versionOfClosingNode, null, true);
841 }
842
843
844
845
846
847
848
849
850
851 public void sendRegionWarmup(ServerName server,
852 HRegionInfo region) {
853 if (server == null) return;
854 try {
855 AdminService.BlockingInterface admin = getRsAdmin(server);
856 PayloadCarryingRpcController controller = newRpcController();
857 ProtobufUtil.warmupRegion(controller, admin, region);
858 } catch (IOException e) {
859 LOG.error("Received exception in RPC for warmup server:" +
860 server + "region: " + region +
861 "exception: " + e);
862 }
863 }
864
865
866
867
868
869 public static void closeRegionSilentlyAndWait(ClusterConnection connection,
870 ServerName server, HRegionInfo region, long timeout) throws IOException, InterruptedException {
871 AdminService.BlockingInterface rs = connection.getAdmin(server);
872 PayloadCarryingRpcController controller = connection.getRpcControllerFactory().newController();
873 try {
874 ProtobufUtil.closeRegion(controller, rs, server, region.getRegionName(), false);
875 } catch (IOException e) {
876 LOG.warn("Exception when closing region: " + region.getRegionNameAsString(), e);
877 }
878 long expiration = timeout + System.currentTimeMillis();
879 while (System.currentTimeMillis() < expiration) {
880 try {
881 HRegionInfo rsRegion =
882 ProtobufUtil.getRegionInfo(controller, rs, region.getRegionName());
883 if (rsRegion == null) return;
884 } catch (IOException ioe) {
885 if (ioe instanceof NotServingRegionException)
886 return;
887 LOG.warn("Exception when retrieving regioninfo from: "
888 + region.getRegionNameAsString(), ioe);
889 }
890 Thread.sleep(1000);
891 }
892 throw new IOException("Region " + region + " failed to close within"
893 + " timeout " + timeout);
894 }
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909 public void sendRegionsMerge(ServerName server, HRegionInfo region_a,
910 HRegionInfo region_b, boolean forcible, User user) throws IOException {
911 if (server == null)
912 throw new NullPointerException("Passed server is null");
913 if (region_a == null || region_b == null)
914 throw new NullPointerException("Passed region is null");
915 AdminService.BlockingInterface admin = getRsAdmin(server);
916 if (admin == null) {
917 throw new IOException("Attempting to send MERGE REGIONS RPC to server "
918 + server.toString() + " for region "
919 + region_a.getRegionNameAsString() + ","
920 + region_b.getRegionNameAsString()
921 + " failed because no RPC connection found to this server");
922 }
923 PayloadCarryingRpcController controller = newRpcController();
924 ProtobufUtil.mergeRegions(controller, admin, region_a, region_b, forcible, user);
925 }
926
927
928
929
930 public boolean isServerReachable(ServerName server) {
931 if (server == null) throw new NullPointerException("Passed server is null");
932
933
934 RetryCounter retryCounter = pingRetryCounterFactory.create();
935 while (retryCounter.shouldRetry()) {
936 synchronized (this.onlineServers) {
937 if (this.deadservers.isDeadServer(server)) {
938 return false;
939 }
940 }
941 try {
942 PayloadCarryingRpcController controller = newRpcController();
943 AdminService.BlockingInterface admin = getRsAdmin(server);
944 if (admin != null) {
945 ServerInfo info = ProtobufUtil.getServerInfo(controller, admin);
946 return info != null && info.hasServerName()
947 && server.getStartcode() == info.getServerName().getStartCode();
948 }
949 } catch (IOException ioe) {
950 if (LOG.isDebugEnabled()) {
951 LOG.debug("Couldn't reach " + server + ", try=" + retryCounter.getAttemptTimes() + " of "
952 + retryCounter.getMaxAttempts(), ioe);
953 }
954 try {
955 retryCounter.sleepUntilNextRetry();
956 } catch(InterruptedException ie) {
957 Thread.currentThread().interrupt();
958 break;
959 }
960 }
961 }
962 return false;
963 }
964
965
966
967
968
969
970
971 private AdminService.BlockingInterface getRsAdmin(final ServerName sn)
972 throws IOException {
973 AdminService.BlockingInterface admin = this.rsAdmins.get(sn);
974 if (admin == null) {
975 LOG.debug("New admin connection to " + sn.toString());
976 if (sn.equals(master.getServerName()) && master instanceof HRegionServer) {
977
978 admin = ((HRegionServer)master).getRSRpcServices();
979 } else {
980 admin = this.connection.getAdmin(sn);
981 }
982 this.rsAdmins.put(sn, admin);
983 }
984 return admin;
985 }
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000 public void waitForRegionServers(MonitoredTask status)
1001 throws InterruptedException {
1002 final long interval = this.master.getConfiguration().
1003 getLong(WAIT_ON_REGIONSERVERS_INTERVAL, 1500);
1004 final long timeout = this.master.getConfiguration().
1005 getLong(WAIT_ON_REGIONSERVERS_TIMEOUT, 4500);
1006 int defaultMinToStart = 1;
1007 if (BaseLoadBalancer.tablesOnMaster(master.getConfiguration())) {
1008
1009
1010
1011
1012 defaultMinToStart = 2;
1013 }
1014 int minToStart = this.master.getConfiguration().
1015 getInt(WAIT_ON_REGIONSERVERS_MINTOSTART, defaultMinToStart);
1016 if (minToStart < 1) {
1017 LOG.warn(String.format(
1018 "The value of '%s' (%d) can not be less than 1, ignoring.",
1019 WAIT_ON_REGIONSERVERS_MINTOSTART, minToStart));
1020 minToStart = 1;
1021 }
1022 int maxToStart = this.master.getConfiguration().
1023 getInt(WAIT_ON_REGIONSERVERS_MAXTOSTART, Integer.MAX_VALUE);
1024 if (maxToStart < minToStart) {
1025 LOG.warn(String.format(
1026 "The value of '%s' (%d) is set less than '%s' (%d), ignoring.",
1027 WAIT_ON_REGIONSERVERS_MAXTOSTART, maxToStart,
1028 WAIT_ON_REGIONSERVERS_MINTOSTART, minToStart));
1029 maxToStart = Integer.MAX_VALUE;
1030 }
1031
1032 long now = System.currentTimeMillis();
1033 final long startTime = now;
1034 long slept = 0;
1035 long lastLogTime = 0;
1036 long lastCountChange = startTime;
1037 int count = countOfRegionServers();
1038 int oldCount = 0;
1039 while (!this.master.isStopped() && count < maxToStart
1040 && (lastCountChange+interval > now || timeout > slept || count < minToStart)) {
1041
1042 if (oldCount != count || lastLogTime+interval < now){
1043 lastLogTime = now;
1044 String msg =
1045 "Waiting for region servers count to settle; currently"+
1046 " checked in " + count + ", slept for " + slept + " ms," +
1047 " expecting minimum of " + minToStart + ", maximum of "+ maxToStart+
1048 ", timeout of "+timeout+" ms, interval of "+interval+" ms.";
1049 LOG.info(msg);
1050 status.setStatus(msg);
1051 }
1052
1053
1054 final long sleepTime = 50;
1055 Thread.sleep(sleepTime);
1056 now = System.currentTimeMillis();
1057 slept = now - startTime;
1058
1059 oldCount = count;
1060 count = countOfRegionServers();
1061 if (count != oldCount) {
1062 lastCountChange = now;
1063 }
1064 }
1065
1066 LOG.info("Finished waiting for region servers count to settle;" +
1067 " checked in " + count + ", slept for " + slept + " ms," +
1068 " expecting minimum of " + minToStart + ", maximum of "+ maxToStart+","+
1069 " master is "+ (this.master.isStopped() ? "stopped.": "running")
1070 );
1071 }
1072
1073
1074
1075
1076 public List<ServerName> getOnlineServersList() {
1077
1078
1079 return new ArrayList<ServerName>(this.onlineServers.keySet());
1080 }
1081
1082
1083
1084
1085 public List<ServerName> getDrainingServersList() {
1086 return new ArrayList<ServerName>(this.drainingServers);
1087 }
1088
1089
1090
1091
1092 Set<ServerName> getDeadNotExpiredServers() {
1093 return new HashSet<ServerName>(this.queuedDeadServers);
1094 }
1095
1096
1097
1098
1099
1100
1101 void removeRequeuedDeadServers() {
1102 requeuedDeadServers.clear();
1103 }
1104
1105
1106
1107
1108
1109 Map<ServerName, Boolean> getRequeuedDeadServers() {
1110 return Collections.unmodifiableMap(this.requeuedDeadServers);
1111 }
1112
1113 public boolean isServerOnline(ServerName serverName) {
1114 return serverName != null && onlineServers.containsKey(serverName);
1115 }
1116
1117
1118
1119
1120
1121 public boolean isServerWithSameHostnamePortOnline(final ServerName serverName) {
1122 return findServerWithSameHostnamePortWithLock(serverName) != null;
1123 }
1124
1125
1126
1127
1128
1129
1130
1131 public synchronized boolean isServerDead(ServerName serverName) {
1132 return serverName == null || deadservers.isDeadServer(serverName)
1133 || queuedDeadServers.contains(serverName)
1134 || requeuedDeadServers.containsKey(serverName);
1135 }
1136
1137 public void shutdownCluster() {
1138 this.clusterShutdown = true;
1139 this.master.stop("Cluster shutdown requested");
1140 }
1141
1142 public boolean isClusterShutdown() {
1143 return this.clusterShutdown;
1144 }
1145
1146
1147
1148
1149 public void stop() {
1150 if (connection != null) {
1151 try {
1152 connection.close();
1153 } catch (IOException e) {
1154 LOG.error("Attempt to close connection to master failed", e);
1155 }
1156 }
1157 }
1158
1159
1160
1161
1162
1163
1164 public List<ServerName> createDestinationServersList(final ServerName serverToExclude){
1165 final List<ServerName> destServers = getOnlineServersList();
1166
1167 if (serverToExclude != null){
1168 destServers.remove(serverToExclude);
1169 }
1170
1171
1172 final List<ServerName> drainingServersCopy = getDrainingServersList();
1173 if (!drainingServersCopy.isEmpty()) {
1174 for (final ServerName server: drainingServersCopy) {
1175 destServers.remove(server);
1176 }
1177 }
1178
1179
1180 removeDeadNotExpiredServers(destServers);
1181 return destServers;
1182 }
1183
1184
1185
1186
1187 public List<ServerName> createDestinationServersList(){
1188 return createDestinationServersList(null);
1189 }
1190
1191
1192
1193
1194
1195
1196
1197 void removeDeadNotExpiredServers(List<ServerName> servers) {
1198 Set<ServerName> deadNotExpiredServersCopy = this.getDeadNotExpiredServers();
1199 if (!deadNotExpiredServersCopy.isEmpty()) {
1200 for (ServerName server : deadNotExpiredServersCopy) {
1201 LOG.debug("Removing dead but not expired server: " + server
1202 + " from eligible server pool.");
1203 servers.remove(server);
1204 }
1205 }
1206 }
1207
1208
1209
1210
1211 void clearDeadServersWithSameHostNameAndPortOfOnlineServer() {
1212 for (ServerName serverName : getOnlineServersList()) {
1213 deadservers.cleanAllPreviousInstances(serverName);
1214 }
1215 }
1216
1217
1218
1219
1220 public void removeRegion(final HRegionInfo regionInfo) {
1221 final byte[] encodedName = regionInfo.getEncodedNameAsBytes();
1222 storeFlushedSequenceIdsByRegion.remove(encodedName);
1223 flushedSequenceIdByRegion.remove(encodedName);
1224 }
1225
1226 @VisibleForTesting
1227 public boolean isRegionInServerManagerStates(final HRegionInfo hri) {
1228 final byte[] encodedName = hri.getEncodedNameAsBytes();
1229 return (storeFlushedSequenceIdsByRegion.containsKey(encodedName)
1230 || flushedSequenceIdByRegion.containsKey(encodedName));
1231 }
1232
1233
1234
1235
1236 public void removeRegions(final List<HRegionInfo> regions) {
1237 for (HRegionInfo hri: regions) {
1238 removeRegion(hri);
1239 }
1240 }
1241 }