3 * Licensed to the Apache Software Foundation (ASF) under one
4 * or more contributor license agreements. See the NOTICE file
5 * distributed with this work for additional information
6 * regarding copyright ownership. The ASF licenses this file
7 * to you under the Apache License, Version 2.0 (the
8 * "License"); you may not use this file except in compliance
9 * with the License. You may obtain a copy of the License at
11 * http://www.apache.org/licenses/LICENSE-2.0
13 * Unless required by applicable law or agreed to in writing, software
14 * distributed under the License is distributed on an "AS IS" BASIS,
15 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16 * See the License for the specific language governing permissions and
17 * limitations under the License.
19 package org
.apache
.hadoop
.hbase
.master
;
21 import java
.util
.ArrayList
;
22 import java
.util
.Collections
;
23 import java
.util
.Comparator
;
24 import java
.util
.Date
;
25 import java
.util
.HashMap
;
26 import java
.util
.HashSet
;
27 import java
.util
.Iterator
;
28 import java
.util
.List
;
31 import org
.apache
.hadoop
.hbase
.ServerName
;
32 import org
.apache
.hadoop
.hbase
.util
.EnvironmentEdgeManager
;
33 import org
.apache
.hadoop
.hbase
.util
.Pair
;
34 import org
.apache
.yetus
.audience
.InterfaceAudience
;
35 import org
.slf4j
.Logger
;
36 import org
.slf4j
.LoggerFactory
;
38 import org
.apache
.hbase
.thirdparty
.com
.google
.common
.base
.Preconditions
;
42 * Class to hold dead servers list and utility querying dead server list.
43 * On znode expiration, servers are added here.
45 @InterfaceAudience.Private
46 public class DeadServer
{
47 private static final Logger LOG
= LoggerFactory
.getLogger(DeadServer
.class);
50 * Set of known dead servers. On znode expiration, servers are added here.
51 * This is needed in case of a network partitioning where the server's lease
52 * expires, but the server is still running. After the network is healed,
53 * and it's server logs are recovered, it will be told to call server startup
54 * because by then, its regions have probably been reassigned.
56 private final Map
<ServerName
, Long
> deadServers
= new HashMap
<>();
59 * Set of dead servers currently being processed
61 private final Set
<ServerName
> processingServers
= new HashSet
<ServerName
>();
64 * A dead server that comes back alive has a different start code. The new start code should be
65 * greater than the old one, but we don't take this into account in this method.
67 * @param newServerName Servername as either <code>host:port</code> or
68 * <code>host,port,startcode</code>.
69 * @return true if this server was dead before and coming back alive again
71 public synchronized boolean cleanPreviousInstance(final ServerName newServerName
) {
72 Iterator
<ServerName
> it
= deadServers
.keySet().iterator();
73 while (it
.hasNext()) {
74 ServerName sn
= it
.next();
75 if (ServerName
.isSameAddress(sn
, newServerName
)) {
76 // remove from deadServers
78 // remove from processingServers
79 boolean removed
= processingServers
.remove(sn
);
81 LOG
.debug("Removed " + sn
+ " ; numProcessing=" + processingServers
.size());
91 * @param serverName server name.
92 * @return true if this server is on the dead servers list false otherwise
94 public synchronized boolean isDeadServer(final ServerName serverName
) {
95 return deadServers
.containsKey(serverName
);
99 * @param serverName server name.
100 * @return true if this server is on the processing servers list false otherwise
102 public synchronized boolean isProcessingServer(final ServerName serverName
) {
103 return processingServers
.contains(serverName
);
107 * Checks if there are currently any dead servers being processed by the
108 * master. Returns true if at least one region server is currently being
111 * @return true if any RS are being processed as dead
113 public synchronized boolean areDeadServersInProgress() {
114 return !processingServers
.isEmpty();
117 public synchronized Set
<ServerName
> copyServerNames() {
118 Set
<ServerName
> clone
= new HashSet
<>(deadServers
.size());
119 clone
.addAll(deadServers
.keySet());
124 * Adds the server to the dead server list if it's not there already.
125 * @param sn the server name
127 public synchronized void add(ServerName sn
) {
128 if (!deadServers
.containsKey(sn
)){
129 deadServers
.put(sn
, EnvironmentEdgeManager
.currentTime());
131 boolean added
= processingServers
.add(sn
);
132 if (LOG
.isDebugEnabled() && added
) {
133 LOG
.debug("Added " + sn
+ "; numProcessing=" + processingServers
.size());
138 * Notify that we started processing this dead server.
139 * @param sn ServerName for the dead server.
141 public synchronized void notifyServer(ServerName sn
) {
142 boolean added
= processingServers
.add(sn
);
143 if (LOG
.isDebugEnabled()) {
145 LOG
.debug("Added " + sn
+ "; numProcessing=" + processingServers
.size());
147 LOG
.debug("Started processing " + sn
+ "; numProcessing=" + processingServers
.size());
152 * Complete processing for this dead server.
153 * @param sn ServerName for the dead server.
155 public synchronized void finish(ServerName sn
) {
156 boolean removed
= processingServers
.remove(sn
);
157 if (LOG
.isDebugEnabled()) {
158 LOG
.debug("Finished processing " + sn
+ "; numProcessing=" + processingServers
.size());
160 LOG
.debug("Removed " + sn
+ " ; numProcessing=" + processingServers
.size());
165 public synchronized int size() {
166 return deadServers
.size();
169 public synchronized boolean isEmpty() {
170 return deadServers
.isEmpty();
173 public synchronized void cleanAllPreviousInstances(final ServerName newServerName
) {
174 Iterator
<ServerName
> it
= deadServers
.keySet().iterator();
175 while (it
.hasNext()) {
176 ServerName sn
= it
.next();
177 if (ServerName
.isSameAddress(sn
, newServerName
)) {
178 // remove from deadServers
180 // remove from processingServers
181 boolean removed
= processingServers
.remove(sn
);
183 LOG
.debug("Removed " + sn
+ " ; numProcessing=" + processingServers
.size());
190 public synchronized String
toString() {
191 // Display unified set of servers from both maps
192 Set
<ServerName
> servers
= new HashSet
<ServerName
>();
193 servers
.addAll(deadServers
.keySet());
194 servers
.addAll(processingServers
);
195 StringBuilder sb
= new StringBuilder();
196 for (ServerName sn
: servers
) {
197 if (sb
.length() > 0) {
200 sb
.append(sn
.toString());
201 // Star entries that are being processed
202 if (processingServers
.contains(sn
)) {
206 return sb
.toString();
210 * Extract all the servers dead since a given time, and sort them.
211 * @param ts the time, 0 for all
212 * @return a sorted array list, by death time, lowest values first.
214 public synchronized List
<Pair
<ServerName
, Long
>> copyDeadServersSince(long ts
){
215 List
<Pair
<ServerName
, Long
>> res
= new ArrayList
<>(size());
217 for (Map
.Entry
<ServerName
, Long
> entry
:deadServers
.entrySet()){
218 if (entry
.getValue() >= ts
){
219 res
.add(new Pair
<>(entry
.getKey(), entry
.getValue()));
223 Collections
.sort(res
, ServerNameDeathDateComparator
);
228 * Get the time when a server died
229 * @param deadServerName the dead server name
230 * @return the date when the server died
232 public synchronized Date
getTimeOfDeath(final ServerName deadServerName
){
233 Long time
= deadServers
.get(deadServerName
);
234 return time
== null ?
null : new Date(time
);
237 private static Comparator
<Pair
<ServerName
, Long
>> ServerNameDeathDateComparator
=
238 new Comparator
<Pair
<ServerName
, Long
>>(){
241 public int compare(Pair
<ServerName
, Long
> o1
, Pair
<ServerName
, Long
> o2
) {
242 return o1
.getSecond().compareTo(o2
.getSecond());
247 * remove the specified dead server
248 * @param deadServerName the dead server name
249 * @return true if this server was removed
252 public synchronized boolean removeDeadServer(final ServerName deadServerName
) {
253 Preconditions
.checkState(!processingServers
.contains(deadServerName
),
254 "Asked to remove server still in processingServers set " + deadServerName
+
255 " (numProcessing=" + processingServers
.size() + ")");
256 if (deadServers
.remove(deadServerName
) == null) {