001/*
002 * Licensed to the Apache Software Foundation (ASF) under one
003 * or more contributor license agreements.  See the NOTICE file
004 * distributed with this work for additional information
005 * regarding copyright ownership.  The ASF licenses this file
006 * to you under the Apache License, Version 2.0 (the
007 * "License"); you may not use this file except in compliance
008 * with the License.  You may obtain a copy of the License at
009 *
010 *     http://www.apache.org/licenses/LICENSE-2.0
011 *
012 * Unless required by applicable law or agreed to in writing, software
013 * distributed under the License is distributed on an "AS IS" BASIS,
014 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
015 * See the License for the specific language governing permissions and
016 * limitations under the License.
017 */
018package org.apache.hadoop.hbase.regionserver;
019
020import static org.apache.hadoop.hbase.HConstants.DEFAULT_HBASE_SPLIT_COORDINATED_BY_ZK;
021import static org.apache.hadoop.hbase.HConstants.DEFAULT_HBASE_SPLIT_WAL_MAX_SPLITTER;
022import static org.apache.hadoop.hbase.HConstants.DEFAULT_SLOW_LOG_SYS_TABLE_CHORE_DURATION;
023import static org.apache.hadoop.hbase.HConstants.HBASE_SPLIT_WAL_COORDINATED_BY_ZK;
024import static org.apache.hadoop.hbase.HConstants.HBASE_SPLIT_WAL_MAX_SPLITTER;
025import static org.apache.hadoop.hbase.master.waleventtracker.WALEventTrackerTableCreator.WAL_EVENT_TRACKER_ENABLED_DEFAULT;
026import static org.apache.hadoop.hbase.master.waleventtracker.WALEventTrackerTableCreator.WAL_EVENT_TRACKER_ENABLED_KEY;
027import static org.apache.hadoop.hbase.namequeues.NamedQueueServiceChore.NAMED_QUEUE_CHORE_DURATION_DEFAULT;
028import static org.apache.hadoop.hbase.namequeues.NamedQueueServiceChore.NAMED_QUEUE_CHORE_DURATION_KEY;
029import static org.apache.hadoop.hbase.replication.regionserver.ReplicationMarkerChore.REPLICATION_MARKER_CHORE_DURATION_DEFAULT;
030import static org.apache.hadoop.hbase.replication.regionserver.ReplicationMarkerChore.REPLICATION_MARKER_CHORE_DURATION_KEY;
031import static org.apache.hadoop.hbase.replication.regionserver.ReplicationMarkerChore.REPLICATION_MARKER_ENABLED_DEFAULT;
032import static org.apache.hadoop.hbase.replication.regionserver.ReplicationMarkerChore.REPLICATION_MARKER_ENABLED_KEY;
033import static org.apache.hadoop.hbase.util.DNS.UNSAFE_RS_HOSTNAME_KEY;
034
035import io.opentelemetry.api.trace.Span;
036import io.opentelemetry.api.trace.StatusCode;
037import io.opentelemetry.context.Scope;
038import java.io.IOException;
039import java.io.PrintWriter;
040import java.lang.management.MemoryUsage;
041import java.lang.reflect.Constructor;
042import java.net.InetSocketAddress;
043import java.time.Duration;
044import java.util.ArrayList;
045import java.util.Collection;
046import java.util.Collections;
047import java.util.Comparator;
048import java.util.HashSet;
049import java.util.Iterator;
050import java.util.List;
051import java.util.Map;
052import java.util.Map.Entry;
053import java.util.Objects;
054import java.util.Optional;
055import java.util.Set;
056import java.util.SortedMap;
057import java.util.Timer;
058import java.util.TimerTask;
059import java.util.TreeMap;
060import java.util.TreeSet;
061import java.util.concurrent.ConcurrentHashMap;
062import java.util.concurrent.ConcurrentMap;
063import java.util.concurrent.ConcurrentSkipListMap;
064import java.util.concurrent.ThreadLocalRandom;
065import java.util.concurrent.TimeUnit;
066import java.util.concurrent.atomic.AtomicBoolean;
067import java.util.concurrent.locks.ReentrantReadWriteLock;
068import java.util.stream.Collectors;
069import javax.management.MalformedObjectNameException;
070import javax.servlet.http.HttpServlet;
071import org.apache.commons.lang3.StringUtils;
072import org.apache.commons.lang3.mutable.MutableFloat;
073import org.apache.hadoop.conf.Configuration;
074import org.apache.hadoop.fs.FileSystem;
075import org.apache.hadoop.fs.Path;
076import org.apache.hadoop.hbase.Abortable;
077import org.apache.hadoop.hbase.ActiveClusterSuffix;
078import org.apache.hadoop.hbase.CacheEvictionStats;
079import org.apache.hadoop.hbase.CallQueueTooBigException;
080import org.apache.hadoop.hbase.ClockOutOfSyncException;
081import org.apache.hadoop.hbase.ClusterId;
082import org.apache.hadoop.hbase.DoNotRetryIOException;
083import org.apache.hadoop.hbase.ExecutorStatusChore;
084import org.apache.hadoop.hbase.HBaseConfiguration;
085import org.apache.hadoop.hbase.HBaseInterfaceAudience;
086import org.apache.hadoop.hbase.HBaseServerBase;
087import org.apache.hadoop.hbase.HConstants;
088import org.apache.hadoop.hbase.HDFSBlocksDistribution;
089import org.apache.hadoop.hbase.HRegionLocation;
090import org.apache.hadoop.hbase.HealthCheckChore;
091import org.apache.hadoop.hbase.MetaTableAccessor;
092import org.apache.hadoop.hbase.NotServingRegionException;
093import org.apache.hadoop.hbase.PleaseHoldException;
094import org.apache.hadoop.hbase.ScheduledChore;
095import org.apache.hadoop.hbase.ServerName;
096import org.apache.hadoop.hbase.Stoppable;
097import org.apache.hadoop.hbase.TableName;
098import org.apache.hadoop.hbase.YouAreDeadException;
099import org.apache.hadoop.hbase.ZNodeClearer;
100import org.apache.hadoop.hbase.client.ConnectionUtils;
101import org.apache.hadoop.hbase.client.RegionInfo;
102import org.apache.hadoop.hbase.client.RegionInfoBuilder;
103import org.apache.hadoop.hbase.client.locking.EntityLock;
104import org.apache.hadoop.hbase.client.locking.LockServiceClient;
105import org.apache.hadoop.hbase.conf.ConfigurationObserver;
106import org.apache.hadoop.hbase.coprocessor.CoprocessorHost;
107import org.apache.hadoop.hbase.exceptions.RegionMovedException;
108import org.apache.hadoop.hbase.exceptions.RegionOpeningException;
109import org.apache.hadoop.hbase.exceptions.UnknownProtocolException;
110import org.apache.hadoop.hbase.executor.ExecutorType;
111import org.apache.hadoop.hbase.http.InfoServer;
112import org.apache.hadoop.hbase.io.hfile.BlockCache;
113import org.apache.hadoop.hbase.io.hfile.BlockCacheFactory;
114import org.apache.hadoop.hbase.io.hfile.HFile;
115import org.apache.hadoop.hbase.io.util.MemorySizeUtil;
116import org.apache.hadoop.hbase.ipc.CoprocessorRpcUtils;
117import org.apache.hadoop.hbase.ipc.DecommissionedHostRejectedException;
118import org.apache.hadoop.hbase.ipc.RpcClient;
119import org.apache.hadoop.hbase.ipc.RpcServer;
120import org.apache.hadoop.hbase.ipc.ServerNotRunningYetException;
121import org.apache.hadoop.hbase.ipc.ServerRpcController;
122import org.apache.hadoop.hbase.log.HBaseMarkers;
123import org.apache.hadoop.hbase.mob.MobFileCache;
124import org.apache.hadoop.hbase.mob.RSMobFileCleanerChore;
125import org.apache.hadoop.hbase.monitoring.TaskMonitor;
126import org.apache.hadoop.hbase.namequeues.NamedQueueRecorder;
127import org.apache.hadoop.hbase.namequeues.NamedQueueServiceChore;
128import org.apache.hadoop.hbase.net.Address;
129import org.apache.hadoop.hbase.procedure.RegionServerProcedureManagerHost;
130import org.apache.hadoop.hbase.procedure2.RSProcedureCallable;
131import org.apache.hadoop.hbase.quotas.FileSystemUtilizationChore;
132import org.apache.hadoop.hbase.quotas.QuotaUtil;
133import org.apache.hadoop.hbase.quotas.RegionServerRpcQuotaManager;
134import org.apache.hadoop.hbase.quotas.RegionServerSpaceQuotaManager;
135import org.apache.hadoop.hbase.quotas.RegionSize;
136import org.apache.hadoop.hbase.quotas.RegionSizeStore;
137import org.apache.hadoop.hbase.regionserver.compactions.CompactionConfiguration;
138import org.apache.hadoop.hbase.regionserver.compactions.CompactionLifeCycleTracker;
139import org.apache.hadoop.hbase.regionserver.compactions.CompactionProgress;
140import org.apache.hadoop.hbase.regionserver.compactions.CompactionRequester;
141import org.apache.hadoop.hbase.regionserver.handler.CloseMetaHandler;
142import org.apache.hadoop.hbase.regionserver.handler.CloseRegionHandler;
143import org.apache.hadoop.hbase.regionserver.handler.RSProcedureHandler;
144import org.apache.hadoop.hbase.regionserver.handler.RegionReplicaFlushHandler;
145import org.apache.hadoop.hbase.regionserver.http.RSDumpServlet;
146import org.apache.hadoop.hbase.regionserver.http.RSStatusServlet;
147import org.apache.hadoop.hbase.regionserver.regionreplication.RegionReplicationBufferManager;
148import org.apache.hadoop.hbase.regionserver.throttle.FlushThroughputControllerFactory;
149import org.apache.hadoop.hbase.regionserver.throttle.ThroughputController;
150import org.apache.hadoop.hbase.regionserver.wal.WALActionsListener;
151import org.apache.hadoop.hbase.regionserver.wal.WALEventTrackerListener;
152import org.apache.hadoop.hbase.replication.regionserver.ReplicationLoad;
153import org.apache.hadoop.hbase.replication.regionserver.ReplicationMarkerChore;
154import org.apache.hadoop.hbase.replication.regionserver.ReplicationSourceInterface;
155import org.apache.hadoop.hbase.replication.regionserver.ReplicationStatus;
156import org.apache.hadoop.hbase.security.SecurityConstants;
157import org.apache.hadoop.hbase.security.Superusers;
158import org.apache.hadoop.hbase.security.User;
159import org.apache.hadoop.hbase.security.UserProvider;
160import org.apache.hadoop.hbase.security.access.AbstractReadOnlyController;
161import org.apache.hadoop.hbase.trace.TraceUtil;
162import org.apache.hadoop.hbase.util.Bytes;
163import org.apache.hadoop.hbase.util.CompressionTest;
164import org.apache.hadoop.hbase.util.ConfigurationUtil;
165import org.apache.hadoop.hbase.util.CoprocessorConfigurationUtil;
166import org.apache.hadoop.hbase.util.DNS;
167import org.apache.hadoop.hbase.util.EnvironmentEdgeManager;
168import org.apache.hadoop.hbase.util.FSUtils;
169import org.apache.hadoop.hbase.util.FutureUtils;
170import org.apache.hadoop.hbase.util.JvmPauseMonitor;
171import org.apache.hadoop.hbase.util.Pair;
172import org.apache.hadoop.hbase.util.RetryCounter;
173import org.apache.hadoop.hbase.util.RetryCounterFactory;
174import org.apache.hadoop.hbase.util.ServerRegionReplicaUtil;
175import org.apache.hadoop.hbase.util.Strings;
176import org.apache.hadoop.hbase.util.Threads;
177import org.apache.hadoop.hbase.util.VersionInfo;
178import org.apache.hadoop.hbase.wal.AbstractFSWALProvider;
179import org.apache.hadoop.hbase.wal.WAL;
180import org.apache.hadoop.hbase.wal.WALFactory;
181import org.apache.hadoop.hbase.zookeeper.MasterAddressTracker;
182import org.apache.hadoop.hbase.zookeeper.ZKClusterId;
183import org.apache.hadoop.hbase.zookeeper.ZKNodeTracker;
184import org.apache.hadoop.hbase.zookeeper.ZKUtil;
185import org.apache.hadoop.ipc.RemoteException;
186import org.apache.hadoop.util.ReflectionUtils;
187import org.apache.yetus.audience.InterfaceAudience;
188import org.apache.zookeeper.KeeperException;
189import org.slf4j.Logger;
190import org.slf4j.LoggerFactory;
191
192import org.apache.hbase.thirdparty.com.google.common.base.Preconditions;
193import org.apache.hbase.thirdparty.com.google.common.base.Throwables;
194import org.apache.hbase.thirdparty.com.google.common.cache.Cache;
195import org.apache.hbase.thirdparty.com.google.common.cache.CacheBuilder;
196import org.apache.hbase.thirdparty.com.google.common.collect.Maps;
197import org.apache.hbase.thirdparty.com.google.common.net.InetAddresses;
198import org.apache.hbase.thirdparty.com.google.protobuf.BlockingRpcChannel;
199import org.apache.hbase.thirdparty.com.google.protobuf.Descriptors.MethodDescriptor;
200import org.apache.hbase.thirdparty.com.google.protobuf.Descriptors.ServiceDescriptor;
201import org.apache.hbase.thirdparty.com.google.protobuf.Message;
202import org.apache.hbase.thirdparty.com.google.protobuf.RpcController;
203import org.apache.hbase.thirdparty.com.google.protobuf.Service;
204import org.apache.hbase.thirdparty.com.google.protobuf.ServiceException;
205import org.apache.hbase.thirdparty.com.google.protobuf.TextFormat;
206import org.apache.hbase.thirdparty.com.google.protobuf.UnsafeByteOperations;
207
208import org.apache.hadoop.hbase.shaded.protobuf.ProtobufUtil;
209import org.apache.hadoop.hbase.shaded.protobuf.RequestConverter;
210import org.apache.hadoop.hbase.shaded.protobuf.generated.ClientProtos.CoprocessorServiceCall;
211import org.apache.hadoop.hbase.shaded.protobuf.generated.ClientProtos.CoprocessorServiceRequest;
212import org.apache.hadoop.hbase.shaded.protobuf.generated.ClientProtos.CoprocessorServiceResponse;
213import org.apache.hadoop.hbase.shaded.protobuf.generated.ClusterStatusProtos;
214import org.apache.hadoop.hbase.shaded.protobuf.generated.ClusterStatusProtos.RegionLoad;
215import org.apache.hadoop.hbase.shaded.protobuf.generated.ClusterStatusProtos.RegionStoreSequenceIds;
216import org.apache.hadoop.hbase.shaded.protobuf.generated.ClusterStatusProtos.UserLoad;
217import org.apache.hadoop.hbase.shaded.protobuf.generated.HBaseProtos.Coprocessor;
218import org.apache.hadoop.hbase.shaded.protobuf.generated.HBaseProtos.NameStringPair;
219import org.apache.hadoop.hbase.shaded.protobuf.generated.HBaseProtos.RegionServerInfo;
220import org.apache.hadoop.hbase.shaded.protobuf.generated.HBaseProtos.RegionSpecifier;
221import org.apache.hadoop.hbase.shaded.protobuf.generated.HBaseProtos.RegionSpecifier.RegionSpecifierType;
222import org.apache.hadoop.hbase.shaded.protobuf.generated.LockServiceProtos.LockService;
223import org.apache.hadoop.hbase.shaded.protobuf.generated.RegionServerStatusProtos;
224import org.apache.hadoop.hbase.shaded.protobuf.generated.RegionServerStatusProtos.GetLastFlushedSequenceIdRequest;
225import org.apache.hadoop.hbase.shaded.protobuf.generated.RegionServerStatusProtos.GetLastFlushedSequenceIdResponse;
226import org.apache.hadoop.hbase.shaded.protobuf.generated.RegionServerStatusProtos.RegionServerReportRequest;
227import org.apache.hadoop.hbase.shaded.protobuf.generated.RegionServerStatusProtos.RegionServerStartupRequest;
228import org.apache.hadoop.hbase.shaded.protobuf.generated.RegionServerStatusProtos.RegionServerStartupResponse;
229import org.apache.hadoop.hbase.shaded.protobuf.generated.RegionServerStatusProtos.RegionServerStatusService;
230import org.apache.hadoop.hbase.shaded.protobuf.generated.RegionServerStatusProtos.RegionSpaceUse;
231import org.apache.hadoop.hbase.shaded.protobuf.generated.RegionServerStatusProtos.RegionSpaceUseReportRequest;
232import org.apache.hadoop.hbase.shaded.protobuf.generated.RegionServerStatusProtos.RegionStateTransition;
233import org.apache.hadoop.hbase.shaded.protobuf.generated.RegionServerStatusProtos.RegionStateTransition.TransitionCode;
234import org.apache.hadoop.hbase.shaded.protobuf.generated.RegionServerStatusProtos.ReportProcedureDoneRequest;
235import org.apache.hadoop.hbase.shaded.protobuf.generated.RegionServerStatusProtos.ReportRSFatalErrorRequest;
236import org.apache.hadoop.hbase.shaded.protobuf.generated.RegionServerStatusProtos.ReportRegionStateTransitionRequest;
237import org.apache.hadoop.hbase.shaded.protobuf.generated.RegionServerStatusProtos.ReportRegionStateTransitionResponse;
238
239/**
240 * HRegionServer makes a set of HRegions available to clients. It checks in with the HMaster. There
241 * are many HRegionServers in a single HBase deployment.
242 */
243@InterfaceAudience.LimitedPrivate(HBaseInterfaceAudience.TOOLS)
244@SuppressWarnings({ "deprecation" })
245public class HRegionServer extends HBaseServerBase<RSRpcServices>
246  implements RegionServerServices, LastSequenceId {
247
248  private static final Logger LOG = LoggerFactory.getLogger(HRegionServer.class);
249
250  int unitMB = 1024 * 1024;
251  int unitKB = 1024;
252
253  /**
254   * For testing only! Set to true to skip notifying region assignment to master .
255   */
256  @InterfaceAudience.Private
257  @edu.umd.cs.findbugs.annotations.SuppressWarnings(value = "MS_SHOULD_BE_FINAL")
258  public static boolean TEST_SKIP_REPORTING_TRANSITION = false;
259
260  /**
261   * A map from RegionName to current action in progress. Boolean value indicates: true - if open
262   * region action in progress false - if close region action in progress
263   */
264  private final ConcurrentMap<byte[], Boolean> regionsInTransitionInRS =
265    new ConcurrentSkipListMap<>(Bytes.BYTES_COMPARATOR);
266
267  /**
268   * Used to cache the open/close region procedures which already submitted. See
269   * {@link #submitRegionProcedure(long)}.
270   */
271  private final ConcurrentMap<Long, Long> submittedRegionProcedures = new ConcurrentHashMap<>();
272  /**
273   * Used to cache the open/close region procedures which already executed. See
274   * {@link #submitRegionProcedure(long)}.
275   */
276  private final Cache<Long, Long> executedRegionProcedures =
277    CacheBuilder.newBuilder().expireAfterAccess(600, TimeUnit.SECONDS).build();
278
279  /**
280   * Used to cache the moved-out regions
281   */
282  private final Cache<String, MovedRegionInfo> movedRegionInfoCache = CacheBuilder.newBuilder()
283    .expireAfterWrite(movedRegionCacheExpiredTime(), TimeUnit.MILLISECONDS).build();
284
285  private MemStoreFlusher cacheFlusher;
286
287  private HeapMemoryManager hMemManager;
288
289  // Replication services. If no replication, this handler will be null.
290  private ReplicationSourceService replicationSourceHandler;
291  private ReplicationSinkService replicationSinkHandler;
292  private boolean sameReplicationSourceAndSink;
293
294  // Compactions
295  private CompactSplit compactSplitThread;
296
297  /**
298   * Map of regions currently being served by this region server. Key is the encoded region name.
299   * All access should be synchronized.
300   */
301  private final Map<String, HRegion> onlineRegions = new ConcurrentHashMap<>();
302  /**
303   * Lock for gating access to {@link #onlineRegions}. TODO: If this map is gated by a lock, does it
304   * need to be a ConcurrentHashMap?
305   */
306  private final ReentrantReadWriteLock onlineRegionsLock = new ReentrantReadWriteLock();
307
308  /**
309   * Map of encoded region names to the DataNode locations they should be hosted on We store the
310   * value as Address since InetSocketAddress is required by the HDFS API (create() that takes
311   * favored nodes as hints for placing file blocks). We could have used ServerName here as the
312   * value class, but we'd need to convert it to InetSocketAddress at some point before the HDFS API
313   * call, and it seems a bit weird to store ServerName since ServerName refers to RegionServers and
314   * here we really mean DataNode locations. We don't store it as InetSocketAddress here because the
315   * conversion on demand from Address to InetSocketAddress will guarantee the resolution results
316   * will be fresh when we need it.
317   */
318  private final Map<String, Address[]> regionFavoredNodesMap = new ConcurrentHashMap<>();
319
320  private LeaseManager leaseManager;
321
322  private volatile boolean dataFsOk;
323
324  static final String ABORT_TIMEOUT = "hbase.regionserver.abort.timeout";
325  // Default abort timeout is 1200 seconds for safe
326  private static final long DEFAULT_ABORT_TIMEOUT = 1200000;
327  // Will run this task when abort timeout
328  static final String ABORT_TIMEOUT_TASK = "hbase.regionserver.abort.timeout.task";
329
330  // A state before we go into stopped state. At this stage we're closing user
331  // space regions.
332  private boolean stopping = false;
333  private volatile boolean killed = false;
334
335  private final int threadWakeFrequency;
336
337  private static final String PERIOD_COMPACTION = "hbase.regionserver.compaction.check.period";
338  private final int compactionCheckFrequency;
339  private static final String PERIOD_FLUSH = "hbase.regionserver.flush.check.period";
340  private final int flushCheckFrequency;
341
342  // Stub to do region server status calls against the master.
343  private volatile RegionServerStatusService.BlockingInterface rssStub;
344  private volatile LockService.BlockingInterface lockStub;
345  // RPC client. Used to make the stub above that does region server status checking.
346  private RpcClient rpcClient;
347
348  private UncaughtExceptionHandler uncaughtExceptionHandler;
349
350  private JvmPauseMonitor pauseMonitor;
351
352  private RSSnapshotVerifier rsSnapshotVerifier;
353
354  /** region server process name */
355  public static final String REGIONSERVER = "regionserver";
356
357  private MetricsRegionServer metricsRegionServer;
358  MetricsRegionServerWrapperImpl metricsRegionServerImpl;
359
360  /**
361   * Check for compactions requests.
362   */
363  private ScheduledChore compactionChecker;
364
365  /**
366   * Check for flushes
367   */
368  private ScheduledChore periodicFlusher;
369
370  private volatile WALFactory walFactory;
371
372  private LogRoller walRoller;
373
374  // A thread which calls reportProcedureDone
375  private RemoteProcedureResultReporter procedureResultReporter;
376
377  // flag set after we're done setting up server threads
378  final AtomicBoolean online = new AtomicBoolean(false);
379
380  // master address tracker
381  private final MasterAddressTracker masterAddressTracker;
382
383  // Log Splitting Worker
384  private SplitLogWorker splitLogWorker;
385
386  private final int shortOperationTimeout;
387
388  // Time to pause if master says 'please hold'
389  private final long retryPauseTime;
390
391  private final RegionServerAccounting regionServerAccounting;
392
393  private NamedQueueServiceChore namedQueueServiceChore = null;
394
395  // Block cache
396  private BlockCache blockCache;
397  // The cache for mob files
398  private MobFileCache mobFileCache;
399
400  /** The health check chore. */
401  private HealthCheckChore healthCheckChore;
402
403  /** The Executor status collect chore. */
404  private ExecutorStatusChore executorStatusChore;
405
406  /** The nonce manager chore. */
407  private ScheduledChore nonceManagerChore;
408
409  private Map<String, Service> coprocessorServiceHandlers = Maps.newHashMap();
410
411  /**
412   * @deprecated since 2.4.0 and will be removed in 4.0.0. Use
413   *             {@link HRegionServer#UNSAFE_RS_HOSTNAME_DISABLE_MASTER_REVERSEDNS_KEY} instead.
414   * @see <a href="https://issues.apache.org/jira/browse/HBASE-24667">HBASE-24667</a>
415   */
416  @Deprecated
417  @InterfaceAudience.LimitedPrivate(HBaseInterfaceAudience.CONFIG)
418  final static String RS_HOSTNAME_DISABLE_MASTER_REVERSEDNS_KEY =
419    "hbase.regionserver.hostname.disable.master.reversedns";
420
421  /**
422   * HBASE-18226: This config and hbase.unsafe.regionserver.hostname are mutually exclusive.
423   * Exception will be thrown if both are used.
424   */
425  @InterfaceAudience.LimitedPrivate(HBaseInterfaceAudience.CONFIG)
426  final static String UNSAFE_RS_HOSTNAME_DISABLE_MASTER_REVERSEDNS_KEY =
427    "hbase.unsafe.regionserver.hostname.disable.master.reversedns";
428
429  /**
430   * Unique identifier for the cluster we are a part of.
431   */
432  private String clusterId;
433
434  // chore for refreshing store files for secondary regions
435  private StorefileRefresherChore storefileRefresher;
436
437  private volatile RegionServerCoprocessorHost rsHost;
438
439  private RegionServerProcedureManagerHost rspmHost;
440
441  private RegionServerRpcQuotaManager rsQuotaManager;
442  private RegionServerSpaceQuotaManager rsSpaceQuotaManager;
443
444  /**
445   * Nonce manager. Nonces are used to make operations like increment and append idempotent in the
446   * case where client doesn't receive the response from a successful operation and retries. We
447   * track the successful ops for some time via a nonce sent by client and handle duplicate
448   * operations (currently, by failing them; in future we might use MVCC to return result). Nonces
449   * are also recovered from WAL during, recovery; however, the caveats (from HBASE-3787) are: - WAL
450   * recovery is optimized, and under high load we won't read nearly nonce-timeout worth of past
451   * records. If we don't read the records, we don't read and recover the nonces. Some WALs within
452   * nonce-timeout at recovery may not even be present due to rolling/cleanup. - There's no WAL
453   * recovery during normal region move, so nonces will not be transfered. We can have separate
454   * additional "Nonce WAL". It will just contain bunch of numbers and won't be flushed on main path
455   * - because WAL itself also contains nonces, if we only flush it before memstore flush, for a
456   * given nonce we will either see it in the WAL (if it was never flushed to disk, it will be part
457   * of recovery), or we'll see it as part of the nonce log (or both occasionally, which doesn't
458   * matter). Nonce log file can be deleted after the latest nonce in it expired. It can also be
459   * recovered during move.
460   */
461  final ServerNonceManager nonceManager;
462
463  private BrokenStoreFileCleaner brokenStoreFileCleaner;
464
465  private RSMobFileCleanerChore rsMobFileCleanerChore;
466
467  @InterfaceAudience.Private
468  CompactedHFilesDischarger compactedFileDischarger;
469
470  private volatile ThroughputController flushThroughputController;
471
472  private SecureBulkLoadManager secureBulkLoadManager;
473
474  private FileSystemUtilizationChore fsUtilizationChore;
475
476  private BootstrapNodeManager bootstrapNodeManager;
477
478  /**
479   * True if this RegionServer is coming up in a cluster where there is no Master; means it needs to
480   * just come up and make do without a Master to talk to: e.g. in test or HRegionServer is doing
481   * other than its usual duties: e.g. as an hollowed-out host whose only purpose is as a
482   * Replication-stream sink; see HBASE-18846 for more. TODO: can this replace
483   * {@link #TEST_SKIP_REPORTING_TRANSITION} ?
484   */
485  private final boolean masterless;
486  private static final String MASTERLESS_CONFIG_NAME = "hbase.masterless";
487
488  /** regionserver codec list **/
489  private static final String REGIONSERVER_CODEC = "hbase.regionserver.codecs";
490
491  // A timer to shutdown the process if abort takes too long
492  private Timer abortMonitor;
493
494  private RegionReplicationBufferManager regionReplicationBufferManager;
495
496  /*
497   * Chore that creates replication marker rows.
498   */
499  private ReplicationMarkerChore replicationMarkerChore;
500
501  // A timer submit requests to the PrefetchExecutor
502  private PrefetchExecutorNotifier prefetchExecutorNotifier;
503
504  /**
505   * Starts a HRegionServer at the default location.
506   * <p/>
507   * Don't start any services or managers in here in the Constructor. Defer till after we register
508   * with the Master as much as possible. See {@link #startServices}.
509   */
510  public HRegionServer(final Configuration conf) throws IOException {
511    super(conf, "RegionServer"); // thread name
512    final Span span = TraceUtil.createSpan("HRegionServer.cxtor");
513    try (Scope ignored = span.makeCurrent()) {
514      this.dataFsOk = true;
515      this.masterless = !clusterMode();
516      MemorySizeUtil.validateRegionServerHeapMemoryAllocation(conf);
517      HFile.checkHFileVersion(this.conf);
518      checkCodecs(this.conf);
519      FSUtils.setupShortCircuitRead(this.conf);
520
521      // Disable usage of meta replicas in the regionserver
522      this.conf.setBoolean(HConstants.USE_META_REPLICAS, false);
523      // Config'ed params
524      this.threadWakeFrequency = conf.getInt(HConstants.THREAD_WAKE_FREQUENCY, 10 * 1000);
525      this.compactionCheckFrequency = conf.getInt(PERIOD_COMPACTION, this.threadWakeFrequency);
526      this.flushCheckFrequency = conf.getInt(PERIOD_FLUSH, this.threadWakeFrequency);
527
528      boolean isNoncesEnabled = conf.getBoolean(HConstants.HBASE_RS_NONCES_ENABLED, true);
529      this.nonceManager = isNoncesEnabled ? new ServerNonceManager(this.conf) : null;
530
531      this.shortOperationTimeout = conf.getInt(HConstants.HBASE_RPC_SHORTOPERATION_TIMEOUT_KEY,
532        HConstants.DEFAULT_HBASE_RPC_SHORTOPERATION_TIMEOUT);
533
534      this.retryPauseTime = conf.getLong(HConstants.HBASE_RPC_SHORTOPERATION_RETRY_PAUSE_TIME,
535        HConstants.DEFAULT_HBASE_RPC_SHORTOPERATION_RETRY_PAUSE_TIME);
536
537      regionServerAccounting = new RegionServerAccounting(conf);
538
539      blockCache = BlockCacheFactory.createBlockCache(conf);
540      // The call below, instantiates the DataTieringManager only when
541      // the configuration "hbase.regionserver.datatiering.enable" is set to true.
542      DataTieringManager.instantiate(conf, onlineRegions);
543
544      mobFileCache = new MobFileCache(conf);
545
546      rsSnapshotVerifier = new RSSnapshotVerifier(conf);
547
548      uncaughtExceptionHandler =
549        (t, e) -> abort("Uncaught exception in executorService thread " + t.getName(), e);
550
551      // If no master in cluster, skip trying to track one or look for a cluster status.
552      if (!this.masterless) {
553        masterAddressTracker = new MasterAddressTracker(getZooKeeper(), this);
554        masterAddressTracker.start();
555      } else {
556        masterAddressTracker = null;
557      }
558      this.rpcServices.start(zooKeeper);
559      span.setStatus(StatusCode.OK);
560    } catch (Throwable t) {
561      // Make sure we log the exception. HRegionServer is often started via reflection and the
562      // cause of failed startup is lost.
563      TraceUtil.setError(span, t);
564      LOG.error("Failed construction RegionServer", t);
565      throw t;
566    } finally {
567      span.end();
568    }
569  }
570
571  // HMaster should override this method to load the specific config for master
572  @Override
573  protected String getUseThisHostnameInstead(Configuration conf) throws IOException {
574    String hostname = conf.get(UNSAFE_RS_HOSTNAME_KEY);
575    if (conf.getBoolean(UNSAFE_RS_HOSTNAME_DISABLE_MASTER_REVERSEDNS_KEY, false)) {
576      if (!StringUtils.isBlank(hostname)) {
577        String msg = UNSAFE_RS_HOSTNAME_DISABLE_MASTER_REVERSEDNS_KEY + " and "
578          + UNSAFE_RS_HOSTNAME_KEY + " are mutually exclusive. Do not set "
579          + UNSAFE_RS_HOSTNAME_DISABLE_MASTER_REVERSEDNS_KEY + " to true while "
580          + UNSAFE_RS_HOSTNAME_KEY + " is used";
581        throw new IOException(msg);
582      } else {
583        return DNS.getHostname(conf, DNS.ServerType.REGIONSERVER);
584      }
585    } else {
586      return hostname;
587    }
588  }
589
590  @Override
591  protected DNS.ServerType getDNSServerType() {
592    return DNS.ServerType.REGIONSERVER;
593  }
594
595  @Override
596  protected void login(UserProvider user, String host) throws IOException {
597    user.login(SecurityConstants.REGIONSERVER_KRB_KEYTAB_FILE,
598      SecurityConstants.REGIONSERVER_KRB_PRINCIPAL, host);
599  }
600
601  @Override
602  protected String getProcessName() {
603    return REGIONSERVER;
604  }
605
606  @Override
607  protected RegionServerCoprocessorHost getCoprocessorHost() {
608    return getRegionServerCoprocessorHost();
609  }
610
611  @Override
612  protected boolean canCreateBaseZNode() {
613    return !clusterMode();
614  }
615
616  @Override
617  protected boolean canUpdateTableDescriptor() {
618    return false;
619  }
620
621  @Override
622  protected boolean cacheTableDescriptor() {
623    return false;
624  }
625
626  protected RSRpcServices createRpcServices() throws IOException {
627    return new RSRpcServices(this);
628  }
629
630  @Override
631  protected void configureInfoServer(InfoServer infoServer) {
632    infoServer.addUnprivilegedServlet("rs-status", "/rs-status", RSStatusServlet.class);
633    infoServer.setAttribute(REGIONSERVER, this);
634  }
635
636  @Override
637  protected Class<? extends HttpServlet> getDumpServlet() {
638    return RSDumpServlet.class;
639  }
640
641  /**
642   * Used by {@link RSDumpServlet} to generate debugging information.
643   */
644  public void dumpRowLocks(final PrintWriter out) {
645    StringBuilder sb = new StringBuilder();
646    for (HRegion region : getRegions()) {
647      if (region.getLockedRows().size() > 0) {
648        for (HRegion.RowLockContext rowLockContext : region.getLockedRows().values()) {
649          sb.setLength(0);
650          sb.append(region.getTableDescriptor().getTableName()).append(",")
651            .append(region.getRegionInfo().getEncodedName()).append(",");
652          sb.append(rowLockContext.toString());
653          out.println(sb);
654        }
655      }
656    }
657  }
658
659  @Override
660  public boolean registerService(Service instance) {
661    // No stacking of instances is allowed for a single executorService name
662    ServiceDescriptor serviceDesc = instance.getDescriptorForType();
663    String serviceName = CoprocessorRpcUtils.getServiceName(serviceDesc);
664    if (coprocessorServiceHandlers.containsKey(serviceName)) {
665      LOG.error("Coprocessor executorService " + serviceName
666        + " already registered, rejecting request from " + instance);
667      return false;
668    }
669
670    coprocessorServiceHandlers.put(serviceName, instance);
671    if (LOG.isDebugEnabled()) {
672      LOG.debug(
673        "Registered regionserver coprocessor executorService: executorService=" + serviceName);
674    }
675    return true;
676  }
677
678  /**
679   * Run test on configured codecs to make sure supporting libs are in place.
680   */
681  private static void checkCodecs(final Configuration c) throws IOException {
682    // check to see if the codec list is available:
683    String[] codecs = c.getStrings(REGIONSERVER_CODEC, (String[]) null);
684    if (codecs == null) {
685      return;
686    }
687    for (String codec : codecs) {
688      if (!CompressionTest.testCompression(codec)) {
689        throw new IOException(
690          "Compression codec " + codec + " not supported, aborting RS construction");
691      }
692    }
693  }
694
695  public String getClusterId() {
696    return this.clusterId;
697  }
698
699  /**
700   * All initialization needed before we go register with Master.<br>
701   * Do bare minimum. Do bulk of initializations AFTER we've connected to the Master.<br>
702   * In here we just put up the RpcServer, setup Connection, and ZooKeeper.
703   */
704  private void preRegistrationInitialization() {
705    final Span span = TraceUtil.createSpan("HRegionServer.preRegistrationInitialization");
706    try (Scope ignored = span.makeCurrent()) {
707      initializeZooKeeper();
708      setupClusterConnection();
709      bootstrapNodeManager = new BootstrapNodeManager(asyncClusterConnection, masterAddressTracker);
710      regionReplicationBufferManager = new RegionReplicationBufferManager(this);
711      // Setup RPC client for master communication
712      this.rpcClient = asyncClusterConnection.getRpcClient();
713      span.setStatus(StatusCode.OK);
714    } catch (Throwable t) {
715      // Call stop if error or process will stick around for ever since server
716      // puts up non-daemon threads.
717      TraceUtil.setError(span, t);
718      this.rpcServices.stop();
719      abort("Initialization of RS failed.  Hence aborting RS.", t);
720    } finally {
721      span.end();
722    }
723  }
724
725  /**
726   * Bring up connection to zk ensemble and then wait until a master for this cluster and then after
727   * that, wait until cluster 'up' flag has been set. This is the order in which master does things.
728   * <p>
729   * Finally open long-living server short-circuit connection.
730   */
731  @edu.umd.cs.findbugs.annotations.SuppressWarnings(value = "RV_RETURN_VALUE_IGNORED_BAD_PRACTICE",
732      justification = "cluster Id znode read would give us correct response")
733  private void initializeZooKeeper() throws IOException, InterruptedException {
734    // Nothing to do in here if no Master in the mix.
735    if (this.masterless) {
736      return;
737    }
738
739    // Create the master address tracker, register with zk, and start it. Then
740    // block until a master is available. No point in starting up if no master
741    // running.
742    blockAndCheckIfStopped(this.masterAddressTracker);
743
744    // Wait on cluster being up. Master will set this flag up in zookeeper
745    // when ready.
746    blockAndCheckIfStopped(this.clusterStatusTracker);
747
748    // If we are HMaster then the cluster id should have already been set.
749    if (clusterId == null) {
750      // Retrieve clusterId
751      // Since cluster status is now up
752      // ID should have already been set by HMaster
753      try {
754        clusterId = ZKClusterId.readClusterIdZNode(this.zooKeeper);
755        if (clusterId == null) {
756          this.abort("Cluster ID has not been set");
757        }
758        LOG.info("ClusterId : " + clusterId);
759      } catch (KeeperException e) {
760        this.abort("Failed to retrieve Cluster ID", e);
761      }
762    }
763
764    if (isStopped() || isAborted()) {
765      return; // No need for further initialization
766    }
767
768    // watch for snapshots and other procedures
769    try {
770      rspmHost = new RegionServerProcedureManagerHost();
771      rspmHost.loadProcedures(conf);
772      rspmHost.initialize(this);
773    } catch (KeeperException e) {
774      this.abort("Failed to reach coordination cluster when creating procedure handler.", e);
775    }
776  }
777
778  /**
779   * Utilty method to wait indefinitely on a znode availability while checking if the region server
780   * is shut down
781   * @param tracker znode tracker to use
782   * @throws IOException          any IO exception, plus if the RS is stopped
783   * @throws InterruptedException if the waiting thread is interrupted
784   */
785  private void blockAndCheckIfStopped(ZKNodeTracker tracker)
786    throws IOException, InterruptedException {
787    while (tracker.blockUntilAvailable(this.msgInterval, false) == null) {
788      if (this.stopped) {
789        throw new IOException("Received the shutdown message while waiting.");
790      }
791    }
792  }
793
794  /** Returns True if the cluster is up. */
795  @Override
796  public boolean isClusterUp() {
797    return this.masterless
798      || (this.clusterStatusTracker != null && this.clusterStatusTracker.isClusterUp());
799  }
800
801  private void initializeReplicationMarkerChore() {
802    boolean replicationMarkerEnabled =
803      conf.getBoolean(REPLICATION_MARKER_ENABLED_KEY, REPLICATION_MARKER_ENABLED_DEFAULT);
804    // If replication or replication marker is not enabled then return immediately.
805    if (replicationMarkerEnabled) {
806      int period = conf.getInt(REPLICATION_MARKER_CHORE_DURATION_KEY,
807        REPLICATION_MARKER_CHORE_DURATION_DEFAULT);
808      replicationMarkerChore = new ReplicationMarkerChore(this, this, period, conf);
809    }
810  }
811
812  @Override
813  public boolean isStopping() {
814    return stopping;
815  }
816
817  /**
818   * The HRegionServer sticks in this loop until closed.
819   */
820  @Override
821  public void run() {
822    if (isStopped()) {
823      LOG.info("Skipping run; stopped");
824      return;
825    }
826    try {
827      // Do pre-registration initializations; zookeeper, lease threads, etc.
828      preRegistrationInitialization();
829    } catch (Throwable e) {
830      abort("Fatal exception during initialization", e);
831    }
832
833    try {
834      if (!isStopped() && !isAborted()) {
835        installShutdownHook();
836
837        CoprocessorConfigurationUtil.syncReadOnlyConfigurations(conf,
838          CoprocessorHost.REGIONSERVER_COPROCESSOR_CONF_KEY);
839
840        // Initialize the RegionServerCoprocessorHost now that our ephemeral
841        // node was created, in case any coprocessors want to use ZooKeeper
842        this.rsHost = new RegionServerCoprocessorHost(this, this.conf);
843
844        // Try and register with the Master; tell it we are here. Break if server is stopped or
845        // the clusterup flag is down or hdfs went wacky. Once registered successfully, go ahead and
846        // start up all Services. Use RetryCounter to get backoff in case Master is struggling to
847        // come up.
848        LOG.debug("About to register with Master.");
849        TraceUtil.trace(() -> {
850          RetryCounterFactory rcf =
851            new RetryCounterFactory(Integer.MAX_VALUE, this.sleeper.getPeriod(), 1000 * 60 * 5);
852          RetryCounter rc = rcf.create();
853          while (keepLooping()) {
854            RegionServerStartupResponse w = reportForDuty();
855            if (w == null) {
856              long sleepTime = rc.getBackoffTimeAndIncrementAttempts();
857              LOG.warn("reportForDuty failed; sleeping {} ms and then retrying.", sleepTime);
858              this.sleeper.sleep(sleepTime);
859            } else {
860              handleReportForDutyResponse(w);
861              break;
862            }
863          }
864        }, "HRegionServer.registerWithMaster");
865      }
866
867      if (!isStopped() && isHealthy()) {
868        TraceUtil.trace(() -> {
869          // start the snapshot handler and other procedure handlers,
870          // since the server is ready to run
871          if (this.rspmHost != null) {
872            this.rspmHost.start();
873          }
874          // Start the Quota Manager
875          if (this.rsQuotaManager != null) {
876            rsQuotaManager.start(getRpcServer().getScheduler());
877          }
878          if (this.rsSpaceQuotaManager != null) {
879            this.rsSpaceQuotaManager.start();
880          }
881        }, "HRegionServer.startup");
882      }
883
884      // We registered with the Master. Go into run mode.
885      long lastMsg = EnvironmentEdgeManager.currentTime();
886      long oldRequestCount = -1;
887      // The main run loop.
888      while (!isStopped() && isHealthy()) {
889        if (!isClusterUp()) {
890          if (onlineRegions.isEmpty()) {
891            stop("Exiting; cluster shutdown set and not carrying any regions");
892          } else if (!this.stopping) {
893            this.stopping = true;
894            LOG.info("Closing user regions");
895            closeUserRegions(isAborted());
896          } else {
897            boolean allUserRegionsOffline = areAllUserRegionsOffline();
898            if (allUserRegionsOffline) {
899              // Set stopped if no more write requests tp meta tables
900              // since last time we went around the loop. Any open
901              // meta regions will be closed on our way out.
902              if (oldRequestCount == getWriteRequestCount()) {
903                stop("Stopped; only catalog regions remaining online");
904                break;
905              }
906              oldRequestCount = getWriteRequestCount();
907            } else {
908              // Make sure all regions have been closed -- some regions may
909              // have not got it because we were splitting at the time of
910              // the call to closeUserRegions.
911              closeUserRegions(this.abortRequested.get());
912            }
913            LOG.debug("Waiting on " + getOnlineRegionsAsPrintableString());
914          }
915        }
916        long now = EnvironmentEdgeManager.currentTime();
917        if ((now - lastMsg) >= msgInterval) {
918          tryRegionServerReport(lastMsg, now);
919          lastMsg = EnvironmentEdgeManager.currentTime();
920        }
921        if (!isStopped() && !isAborted()) {
922          this.sleeper.sleep();
923        }
924      } // for
925    } catch (Throwable t) {
926      if (!rpcServices.checkOOME(t)) {
927        String prefix = t instanceof YouAreDeadException ? "" : "Unhandled: ";
928        abort(prefix + t.getMessage(), t);
929      }
930    }
931
932    final Span span = TraceUtil.createSpan("HRegionServer exiting main loop");
933    try (Scope ignored = span.makeCurrent()) {
934      if (this.leaseManager != null) {
935        this.leaseManager.closeAfterLeasesExpire();
936      }
937      if (this.splitLogWorker != null) {
938        splitLogWorker.stop();
939      }
940      stopInfoServer();
941      // Send cache a shutdown.
942      if (blockCache != null) {
943        blockCache.shutdown();
944      }
945      if (mobFileCache != null) {
946        mobFileCache.shutdown();
947      }
948
949      // Send interrupts to wake up threads if sleeping so they notice shutdown.
950      // TODO: Should we check they are alive? If OOME could have exited already
951      if (this.hMemManager != null) {
952        this.hMemManager.stop();
953      }
954      if (this.cacheFlusher != null) {
955        this.cacheFlusher.interruptIfNecessary();
956      }
957      if (this.compactSplitThread != null) {
958        this.compactSplitThread.interruptIfNecessary();
959      }
960
961      // Stop the snapshot and other procedure handlers, forcefully killing all running tasks
962      if (rspmHost != null) {
963        rspmHost.stop(this.abortRequested.get() || this.killed);
964      }
965
966      if (this.killed) {
967        // Just skip out w/o closing regions. Used when testing.
968      } else if (abortRequested.get()) {
969        if (this.dataFsOk) {
970          closeUserRegions(abortRequested.get()); // Don't leave any open file handles
971        }
972        LOG.info("aborting server " + this.serverName);
973      } else {
974        closeUserRegions(abortRequested.get());
975        LOG.info("stopping server " + this.serverName);
976      }
977      regionReplicationBufferManager.stop();
978      closeClusterConnection();
979      // Closing the compactSplit thread before closing meta regions
980      if (!this.killed && containsMetaTableRegions()) {
981        if (!abortRequested.get() || this.dataFsOk) {
982          if (this.compactSplitThread != null) {
983            this.compactSplitThread.join();
984            this.compactSplitThread = null;
985          }
986          closeMetaTableRegions(abortRequested.get());
987        }
988      }
989
990      if (!this.killed && this.dataFsOk) {
991        waitOnAllRegionsToClose(abortRequested.get());
992        LOG.info("stopping server " + this.serverName + "; all regions closed.");
993      }
994
995      // Stop the quota manager
996      if (rsQuotaManager != null) {
997        rsQuotaManager.stop();
998      }
999      if (rsSpaceQuotaManager != null) {
1000        rsSpaceQuotaManager.stop();
1001        rsSpaceQuotaManager = null;
1002      }
1003
1004      // flag may be changed when closing regions throws exception.
1005      if (this.dataFsOk) {
1006        shutdownWAL(!abortRequested.get());
1007      }
1008
1009      // Make sure the proxy is down.
1010      if (this.rssStub != null) {
1011        this.rssStub = null;
1012      }
1013      if (this.lockStub != null) {
1014        this.lockStub = null;
1015      }
1016      if (this.rpcClient != null) {
1017        this.rpcClient.close();
1018      }
1019      if (this.leaseManager != null) {
1020        this.leaseManager.close();
1021      }
1022      if (this.pauseMonitor != null) {
1023        this.pauseMonitor.stop();
1024      }
1025
1026      if (!killed) {
1027        stopServiceThreads();
1028      }
1029
1030      if (this.rpcServices != null) {
1031        this.rpcServices.stop();
1032      }
1033
1034      try {
1035        deleteMyEphemeralNode();
1036      } catch (KeeperException.NoNodeException nn) {
1037        // pass
1038      } catch (KeeperException e) {
1039        LOG.warn("Failed deleting my ephemeral node", e);
1040      }
1041      // We may have failed to delete the znode at the previous step, but
1042      // we delete the file anyway: a second attempt to delete the znode is likely to fail again.
1043      ZNodeClearer.deleteMyEphemeralNodeOnDisk();
1044
1045      closeZooKeeper();
1046      closeTableDescriptors();
1047      LOG.info("Exiting; stopping=" + this.serverName + "; zookeeper connection closed.");
1048      span.setStatus(StatusCode.OK);
1049    } finally {
1050      span.end();
1051    }
1052  }
1053
1054  private boolean containsMetaTableRegions() {
1055    return onlineRegions.containsKey(RegionInfoBuilder.FIRST_META_REGIONINFO.getEncodedName());
1056  }
1057
1058  private boolean areAllUserRegionsOffline() {
1059    if (getNumberOfOnlineRegions() > 2) {
1060      return false;
1061    }
1062    boolean allUserRegionsOffline = true;
1063    for (Map.Entry<String, HRegion> e : this.onlineRegions.entrySet()) {
1064      if (!e.getValue().getRegionInfo().isMetaRegion()) {
1065        allUserRegionsOffline = false;
1066        break;
1067      }
1068    }
1069    return allUserRegionsOffline;
1070  }
1071
1072  /** Returns Current write count for all online regions. */
1073  private long getWriteRequestCount() {
1074    long writeCount = 0;
1075    for (Map.Entry<String, HRegion> e : this.onlineRegions.entrySet()) {
1076      writeCount += e.getValue().getWriteRequestsCount();
1077    }
1078    return writeCount;
1079  }
1080
1081  @InterfaceAudience.Private
1082  protected void tryRegionServerReport(long reportStartTime, long reportEndTime)
1083    throws IOException {
1084    RegionServerStatusService.BlockingInterface rss = rssStub;
1085    if (rss == null) {
1086      // the current server could be stopping.
1087      return;
1088    }
1089    ClusterStatusProtos.ServerLoad sl = buildServerLoad(reportStartTime, reportEndTime);
1090    final Span span = TraceUtil.createSpan("HRegionServer.tryRegionServerReport");
1091    try (Scope ignored = span.makeCurrent()) {
1092      RegionServerReportRequest.Builder request = RegionServerReportRequest.newBuilder();
1093      request.setServer(ProtobufUtil.toServerName(this.serverName));
1094      request.setLoad(sl);
1095      rss.regionServerReport(null, request.build());
1096      span.setStatus(StatusCode.OK);
1097    } catch (ServiceException se) {
1098      IOException ioe = ProtobufUtil.getRemoteException(se);
1099      if (ioe instanceof YouAreDeadException) {
1100        // This will be caught and handled as a fatal error in run()
1101        TraceUtil.setError(span, ioe);
1102        throw ioe;
1103      }
1104      if (rssStub == rss) {
1105        rssStub = null;
1106      }
1107      TraceUtil.setError(span, se);
1108      // Couldn't connect to the master, get location from zk and reconnect
1109      // Method blocks until new master is found or we are stopped
1110      createRegionServerStatusStub(true);
1111    } finally {
1112      span.end();
1113    }
1114  }
1115
1116  /**
1117   * Reports the given map of Regions and their size on the filesystem to the active Master.
1118   * @param regionSizeStore The store containing region sizes
1119   * @return false if FileSystemUtilizationChore should pause reporting to master. true otherwise
1120   */
1121  public boolean reportRegionSizesForQuotas(RegionSizeStore regionSizeStore) {
1122    RegionServerStatusService.BlockingInterface rss = rssStub;
1123    if (rss == null) {
1124      // the current server could be stopping.
1125      LOG.trace("Skipping Region size report to HMaster as stub is null");
1126      return true;
1127    }
1128    try {
1129      buildReportAndSend(rss, regionSizeStore);
1130    } catch (ServiceException se) {
1131      IOException ioe = ProtobufUtil.getRemoteException(se);
1132      if (ioe instanceof PleaseHoldException) {
1133        LOG.trace("Failed to report region sizes to Master because it is initializing."
1134          + " This will be retried.", ioe);
1135        // The Master is coming up. Will retry the report later. Avoid re-creating the stub.
1136        return true;
1137      }
1138      if (rssStub == rss) {
1139        rssStub = null;
1140      }
1141      createRegionServerStatusStub(true);
1142      if (ioe instanceof DoNotRetryIOException) {
1143        DoNotRetryIOException doNotRetryEx = (DoNotRetryIOException) ioe;
1144        if (doNotRetryEx.getCause() != null) {
1145          Throwable t = doNotRetryEx.getCause();
1146          if (t instanceof UnsupportedOperationException) {
1147            LOG.debug("master doesn't support ReportRegionSpaceUse, pause before retrying");
1148            return false;
1149          }
1150        }
1151      }
1152      LOG.debug("Failed to report region sizes to Master. This will be retried.", ioe);
1153    }
1154    return true;
1155  }
1156
1157  /**
1158   * Builds the region size report and sends it to the master. Upon successful sending of the
1159   * report, the region sizes that were sent are marked as sent.
1160   * @param rss             The stub to send to the Master
1161   * @param regionSizeStore The store containing region sizes
1162   */
1163  private void buildReportAndSend(RegionServerStatusService.BlockingInterface rss,
1164    RegionSizeStore regionSizeStore) throws ServiceException {
1165    RegionSpaceUseReportRequest request =
1166      buildRegionSpaceUseReportRequest(Objects.requireNonNull(regionSizeStore));
1167    rss.reportRegionSpaceUse(null, request);
1168    // Record the number of size reports sent
1169    if (metricsRegionServer != null) {
1170      metricsRegionServer.incrementNumRegionSizeReportsSent(regionSizeStore.size());
1171    }
1172  }
1173
1174  /**
1175   * Builds a {@link RegionSpaceUseReportRequest} protobuf message from the region size map.
1176   * @param regionSizes The size in bytes of regions
1177   * @return The corresponding protocol buffer message.
1178   */
1179  RegionSpaceUseReportRequest buildRegionSpaceUseReportRequest(RegionSizeStore regionSizes) {
1180    RegionSpaceUseReportRequest.Builder request = RegionSpaceUseReportRequest.newBuilder();
1181    for (Entry<RegionInfo, RegionSize> entry : regionSizes) {
1182      request.addSpaceUse(convertRegionSize(entry.getKey(), entry.getValue().getSize()));
1183    }
1184    return request.build();
1185  }
1186
1187  /**
1188   * Converts a pair of {@link RegionInfo} and {@code long} into a {@link RegionSpaceUse} protobuf
1189   * message.
1190   * @param regionInfo  The RegionInfo
1191   * @param sizeInBytes The size in bytes of the Region
1192   * @return The protocol buffer
1193   */
1194  RegionSpaceUse convertRegionSize(RegionInfo regionInfo, Long sizeInBytes) {
1195    return RegionSpaceUse.newBuilder()
1196      .setRegionInfo(ProtobufUtil.toRegionInfo(Objects.requireNonNull(regionInfo)))
1197      .setRegionSize(Objects.requireNonNull(sizeInBytes)).build();
1198  }
1199
1200  private ClusterStatusProtos.ServerLoad buildServerLoad(long reportStartTime, long reportEndTime)
1201    throws IOException {
1202    // We're getting the MetricsRegionServerWrapper here because the wrapper computes requests
1203    // per second, and other metrics As long as metrics are part of ServerLoad it's best to use
1204    // the wrapper to compute those numbers in one place.
1205    // In the long term most of these should be moved off of ServerLoad and the heart beat.
1206    // Instead they should be stored in an HBase table so that external visibility into HBase is
1207    // improved; Additionally the load balancer will be able to take advantage of a more complete
1208    // history.
1209    MetricsRegionServerWrapper regionServerWrapper = metricsRegionServer.getRegionServerWrapper();
1210    Collection<HRegion> regions = getOnlineRegionsLocalContext();
1211    long usedMemory = -1L;
1212    long maxMemory = -1L;
1213    final MemoryUsage usage = MemorySizeUtil.safeGetHeapMemoryUsage();
1214    if (usage != null) {
1215      usedMemory = usage.getUsed();
1216      maxMemory = usage.getMax();
1217    }
1218
1219    ClusterStatusProtos.ServerLoad.Builder serverLoad = ClusterStatusProtos.ServerLoad.newBuilder();
1220    serverLoad.setNumberOfRequests((int) regionServerWrapper.getRequestsPerSecond());
1221    serverLoad.setTotalNumberOfRequests(regionServerWrapper.getTotalRequestCount());
1222    serverLoad.setUsedHeapMB((int) (usedMemory / 1024 / 1024));
1223    serverLoad.setMaxHeapMB((int) (maxMemory / 1024 / 1024));
1224    serverLoad.setReadRequestsCount(this.metricsRegionServerImpl.getReadRequestsCount());
1225    serverLoad.setWriteRequestsCount(this.metricsRegionServerImpl.getWriteRequestsCount());
1226    Set<String> coprocessors = getWAL(null).getCoprocessorHost().getCoprocessors();
1227    Coprocessor.Builder coprocessorBuilder = Coprocessor.newBuilder();
1228    for (String coprocessor : coprocessors) {
1229      serverLoad.addCoprocessors(coprocessorBuilder.setName(coprocessor).build());
1230    }
1231    RegionLoad.Builder regionLoadBldr = RegionLoad.newBuilder();
1232    RegionSpecifier.Builder regionSpecifier = RegionSpecifier.newBuilder();
1233    for (HRegion region : regions) {
1234      if (region.getCoprocessorHost() != null) {
1235        Set<String> regionCoprocessors = region.getCoprocessorHost().getCoprocessors();
1236        for (String regionCoprocessor : regionCoprocessors) {
1237          serverLoad.addCoprocessors(coprocessorBuilder.setName(regionCoprocessor).build());
1238        }
1239      }
1240      serverLoad.addRegionLoads(createRegionLoad(region, regionLoadBldr, regionSpecifier));
1241      for (String coprocessor : getWAL(region.getRegionInfo()).getCoprocessorHost()
1242        .getCoprocessors()) {
1243        serverLoad.addCoprocessors(coprocessorBuilder.setName(coprocessor).build());
1244      }
1245    }
1246
1247    getBlockCache().ifPresent(cache -> {
1248      cache.getRegionCachedInfo().ifPresent(regionCachedInfo -> {
1249        regionCachedInfo.forEach((regionName, prefetchSize) -> {
1250          serverLoad.putRegionCachedInfo(regionName, roundSize(prefetchSize, unitMB));
1251        });
1252      });
1253    });
1254    serverLoad.setCacheFreeSize(regionServerWrapper.getBlockCacheFreeSize());
1255    if (DataTieringManager.getInstance() != null) {
1256      DataTieringManager.getInstance().getRegionColdDataSize()
1257        .forEach((regionName, coldDataSize) -> serverLoad.putRegionColdData(regionName,
1258          roundSize(coldDataSize.getSecond(), unitMB)));
1259    }
1260    serverLoad.setReportStartTime(reportStartTime);
1261    serverLoad.setReportEndTime(reportEndTime);
1262    if (this.infoServer != null) {
1263      serverLoad.setInfoServerPort(this.infoServer.getPort());
1264    } else {
1265      serverLoad.setInfoServerPort(-1);
1266    }
1267    MetricsUserAggregateSource userSource =
1268      metricsRegionServer.getMetricsUserAggregate().getSource();
1269    if (userSource != null) {
1270      Map<String, MetricsUserSource> userMetricMap = userSource.getUserSources();
1271      for (Entry<String, MetricsUserSource> entry : userMetricMap.entrySet()) {
1272        serverLoad.addUserLoads(createUserLoad(entry.getKey(), entry.getValue()));
1273      }
1274    }
1275
1276    if (sameReplicationSourceAndSink && replicationSourceHandler != null) {
1277      // always refresh first to get the latest value
1278      ReplicationLoad rLoad = replicationSourceHandler.refreshAndGetReplicationLoad();
1279      if (rLoad != null) {
1280        serverLoad.setReplLoadSink(rLoad.getReplicationLoadSink());
1281        for (ClusterStatusProtos.ReplicationLoadSource rLS : rLoad
1282          .getReplicationLoadSourceEntries()) {
1283          serverLoad.addReplLoadSource(rLS);
1284        }
1285      }
1286    } else {
1287      if (replicationSourceHandler != null) {
1288        ReplicationLoad rLoad = replicationSourceHandler.refreshAndGetReplicationLoad();
1289        if (rLoad != null) {
1290          for (ClusterStatusProtos.ReplicationLoadSource rLS : rLoad
1291            .getReplicationLoadSourceEntries()) {
1292            serverLoad.addReplLoadSource(rLS);
1293          }
1294        }
1295      }
1296      if (replicationSinkHandler != null) {
1297        ReplicationLoad rLoad = replicationSinkHandler.refreshAndGetReplicationLoad();
1298        if (rLoad != null) {
1299          serverLoad.setReplLoadSink(rLoad.getReplicationLoadSink());
1300        }
1301      }
1302    }
1303
1304    TaskMonitor.get().getTasks().forEach(task -> serverLoad.addTasks(ClusterStatusProtos.ServerTask
1305      .newBuilder().setDescription(task.getDescription())
1306      .setStatus(task.getStatus() != null ? task.getStatus() : "")
1307      .setState(ClusterStatusProtos.ServerTask.State.valueOf(task.getState().name()))
1308      .setStartTime(task.getStartTime()).setCompletionTime(task.getCompletionTimestamp()).build()));
1309
1310    return serverLoad.build();
1311  }
1312
1313  private String getOnlineRegionsAsPrintableString() {
1314    StringBuilder sb = new StringBuilder();
1315    for (Region r : this.onlineRegions.values()) {
1316      if (sb.length() > 0) {
1317        sb.append(", ");
1318      }
1319      sb.append(r.getRegionInfo().getEncodedName());
1320    }
1321    return sb.toString();
1322  }
1323
1324  /**
1325   * Wait on regions close.
1326   */
1327  private void waitOnAllRegionsToClose(final boolean abort) {
1328    // Wait till all regions are closed before going out.
1329    int lastCount = -1;
1330    long previousLogTime = 0;
1331    Set<String> closedRegions = new HashSet<>();
1332    boolean interrupted = false;
1333    try {
1334      while (!onlineRegions.isEmpty()) {
1335        int count = getNumberOfOnlineRegions();
1336        // Only print a message if the count of regions has changed.
1337        if (count != lastCount) {
1338          // Log every second at most
1339          if (EnvironmentEdgeManager.currentTime() > (previousLogTime + 1000)) {
1340            previousLogTime = EnvironmentEdgeManager.currentTime();
1341            lastCount = count;
1342            LOG.info("Waiting on " + count + " regions to close");
1343            // Only print out regions still closing if a small number else will
1344            // swamp the log.
1345            if (count < 10 && LOG.isDebugEnabled()) {
1346              LOG.debug("Online Regions=" + this.onlineRegions);
1347            }
1348          }
1349        }
1350        // Ensure all user regions have been sent a close. Use this to
1351        // protect against the case where an open comes in after we start the
1352        // iterator of onlineRegions to close all user regions.
1353        for (Map.Entry<String, HRegion> e : this.onlineRegions.entrySet()) {
1354          RegionInfo hri = e.getValue().getRegionInfo();
1355          if (
1356            !this.regionsInTransitionInRS.containsKey(hri.getEncodedNameAsBytes())
1357              && !closedRegions.contains(hri.getEncodedName())
1358          ) {
1359            closedRegions.add(hri.getEncodedName());
1360            // Don't update zk with this close transition; pass false.
1361            closeRegionIgnoreErrors(hri, abort);
1362          }
1363        }
1364        // No regions in RIT, we could stop waiting now.
1365        if (this.regionsInTransitionInRS.isEmpty()) {
1366          if (!onlineRegions.isEmpty()) {
1367            LOG.info("We were exiting though online regions are not empty,"
1368              + " because some regions failed closing");
1369          }
1370          break;
1371        } else {
1372          LOG.debug("Waiting on {}", this.regionsInTransitionInRS.keySet().stream()
1373            .map(e -> Bytes.toString(e)).collect(Collectors.joining(", ")));
1374        }
1375        if (sleepInterrupted(200)) {
1376          interrupted = true;
1377        }
1378      }
1379    } finally {
1380      if (interrupted) {
1381        Thread.currentThread().interrupt();
1382      }
1383    }
1384  }
1385
1386  private static boolean sleepInterrupted(long millis) {
1387    boolean interrupted = false;
1388    try {
1389      Thread.sleep(millis);
1390    } catch (InterruptedException e) {
1391      LOG.warn("Interrupted while sleeping");
1392      interrupted = true;
1393    }
1394    return interrupted;
1395  }
1396
1397  private void shutdownWAL(final boolean close) {
1398    if (this.walFactory != null) {
1399      try {
1400        if (close) {
1401          walFactory.close();
1402        } else {
1403          walFactory.shutdown();
1404        }
1405      } catch (Throwable e) {
1406        e = e instanceof RemoteException ? ((RemoteException) e).unwrapRemoteException() : e;
1407        LOG.error("Shutdown / close of WAL failed: " + e);
1408        LOG.debug("Shutdown / close exception details:", e);
1409      }
1410    }
1411  }
1412
1413  /**
1414   * Run init. Sets up wal and starts up all server threads.
1415   * @param c Extra configuration.
1416   */
1417  protected void handleReportForDutyResponse(final RegionServerStartupResponse c)
1418    throws IOException {
1419    try {
1420      boolean updateRootDir = false;
1421      for (NameStringPair e : c.getMapEntriesList()) {
1422        String key = e.getName();
1423        // The hostname the master sees us as.
1424        if (key.equals(HConstants.KEY_FOR_HOSTNAME_SEEN_BY_MASTER)) {
1425          String hostnameFromMasterPOV = e.getValue();
1426          this.serverName = ServerName.valueOf(hostnameFromMasterPOV,
1427            rpcServices.getSocketAddress().getPort(), this.startcode);
1428          String expectedHostName = rpcServices.getSocketAddress().getHostName();
1429          // if Master use-ip is enabled, RegionServer use-ip will be enabled by default even if it
1430          // is set to disable. so we will use the ip of the RegionServer to compare with the
1431          // hostname passed by the Master, see HBASE-27304 for details.
1432          if (
1433            StringUtils.isBlank(useThisHostnameInstead) && getActiveMaster().isPresent()
1434              && InetAddresses.isInetAddress(getActiveMaster().get().getHostname())
1435          ) {
1436            expectedHostName = rpcServices.getSocketAddress().getAddress().getHostAddress();
1437          }
1438          boolean isHostnameConsist = StringUtils.isBlank(useThisHostnameInstead)
1439            ? Strings.hostnamesEqual(hostnameFromMasterPOV, expectedHostName)
1440            : Strings.hostnamesEqual(hostnameFromMasterPOV, useThisHostnameInstead);
1441
1442          if (!isHostnameConsist) {
1443            String msg = "Master passed us a different hostname to use; was="
1444              + (StringUtils.isBlank(useThisHostnameInstead)
1445                ? expectedHostName
1446                : this.useThisHostnameInstead)
1447              + ", but now=" + hostnameFromMasterPOV;
1448            LOG.error(msg);
1449            throw new IOException(msg);
1450          }
1451          continue;
1452        }
1453
1454        String value = e.getValue();
1455        if (key.equals(HConstants.HBASE_DIR)) {
1456          if (value != null && !value.equals(conf.get(HConstants.HBASE_DIR))) {
1457            updateRootDir = true;
1458          }
1459        }
1460
1461        if (LOG.isDebugEnabled()) {
1462          LOG.debug("Config from master: " + key + "=" + value);
1463        }
1464        this.conf.set(key, value);
1465      }
1466      // Set our ephemeral znode up in zookeeper now we have a name.
1467      createMyEphemeralNode();
1468
1469      if (updateRootDir) {
1470        // initialize file system by the config fs.defaultFS and hbase.rootdir from master
1471        initializeFileSystem();
1472      }
1473
1474      // hack! Maps DFSClient => RegionServer for logs. HDFS made this
1475      // config param for task trackers, but we can piggyback off of it.
1476      if (this.conf.get("mapreduce.task.attempt.id") == null) {
1477        this.conf.set("mapreduce.task.attempt.id", "hb_rs_" + this.serverName.toString());
1478      }
1479
1480      // Save it in a file, this will allow to see if we crash
1481      ZNodeClearer.writeMyEphemeralNodeOnDisk(getMyEphemeralNodePath());
1482
1483      // This call sets up an initialized replication and WAL. Later we start it up.
1484      setupWALAndReplication();
1485      // Init in here rather than in constructor after thread name has been set
1486      final MetricsTable metricsTable =
1487        new MetricsTable(new MetricsTableWrapperAggregateImpl(this));
1488      this.metricsRegionServerImpl = new MetricsRegionServerWrapperImpl(this);
1489      this.metricsRegionServer =
1490        new MetricsRegionServer(metricsRegionServerImpl, conf, metricsTable);
1491      // Now that we have a metrics source, start the pause monitor
1492      this.pauseMonitor = new JvmPauseMonitor(conf, getMetrics().getMetricsSource());
1493      pauseMonitor.start();
1494
1495      // There is a rare case where we do NOT want services to start. Check config.
1496      if (getConfiguration().getBoolean("hbase.regionserver.workers", true)) {
1497        startServices();
1498      }
1499      // In here we start up the replication Service. Above we initialized it. TODO. Reconcile.
1500      // or make sense of it.
1501      startReplicationService();
1502
1503      // Set up ZK
1504      LOG.info("Serving as " + this.serverName + ", RpcServer on " + rpcServices.getSocketAddress()
1505        + ", sessionid=0x"
1506        + Long.toHexString(this.zooKeeper.getRecoverableZooKeeper().getSessionId()));
1507
1508      // Wake up anyone waiting for this server to online
1509      synchronized (online) {
1510        online.set(true);
1511        online.notifyAll();
1512      }
1513    } catch (Throwable e) {
1514      stop("Failed initialization");
1515      throw convertThrowableToIOE(cleanup(e, "Failed init"), "Region server startup failed");
1516    } finally {
1517      sleeper.skipSleepCycle();
1518    }
1519  }
1520
1521  private void startHeapMemoryManager() {
1522    if (this.blockCache != null) {
1523      this.hMemManager =
1524        new HeapMemoryManager(this.blockCache, this.cacheFlusher, this, regionServerAccounting);
1525      this.hMemManager.start(getChoreService());
1526    }
1527  }
1528
1529  private void createMyEphemeralNode() throws KeeperException {
1530    RegionServerInfo.Builder rsInfo = RegionServerInfo.newBuilder();
1531    rsInfo.setInfoPort(infoServer != null ? infoServer.getPort() : -1);
1532    rsInfo.setVersionInfo(ProtobufUtil.getVersionInfo());
1533    byte[] data = ProtobufUtil.prependPBMagic(rsInfo.build().toByteArray());
1534    ZKUtil.createEphemeralNodeAndWatch(this.zooKeeper, getMyEphemeralNodePath(), data);
1535  }
1536
1537  private void deleteMyEphemeralNode() throws KeeperException {
1538    ZKUtil.deleteNode(this.zooKeeper, getMyEphemeralNodePath());
1539  }
1540
1541  @Override
1542  public RegionServerAccounting getRegionServerAccounting() {
1543    return regionServerAccounting;
1544  }
1545
1546  // Round the size with KB or MB.
1547  // A trick here is that if the sizeInBytes is less than sizeUnit, we will round the size to 1
1548  // instead of 0 if it is not 0, to avoid some schedulers think the region has no data. See
1549  // HBASE-26340 for more details on why this is important.
1550  private static int roundSize(long sizeInByte, int sizeUnit) {
1551    if (sizeInByte == 0) {
1552      return 0;
1553    } else if (sizeInByte < sizeUnit) {
1554      return 1;
1555    } else {
1556      return (int) Math.min(sizeInByte / sizeUnit, Integer.MAX_VALUE);
1557    }
1558  }
1559
1560  /**
1561   * @param r               Region to get RegionLoad for.
1562   * @param regionLoadBldr  the RegionLoad.Builder, can be null
1563   * @param regionSpecifier the RegionSpecifier.Builder, can be null
1564   * @return RegionLoad instance.
1565   */
1566  RegionLoad createRegionLoad(final HRegion r, RegionLoad.Builder regionLoadBldr,
1567    RegionSpecifier.Builder regionSpecifier) throws IOException {
1568    byte[] name = r.getRegionInfo().getRegionName();
1569    String regionEncodedName = r.getRegionInfo().getEncodedName();
1570    int stores = 0;
1571    int storefiles = 0;
1572    int storeRefCount = 0;
1573    int maxCompactedStoreFileRefCount = 0;
1574    long storeUncompressedSize = 0L;
1575    long storefileSize = 0L;
1576    long storefileIndexSize = 0L;
1577    long rootLevelIndexSize = 0L;
1578    long totalStaticIndexSize = 0L;
1579    long totalStaticBloomSize = 0L;
1580    long totalCompactingKVs = 0L;
1581    long currentCompactedKVs = 0L;
1582    long totalRegionSize = 0L;
1583    List<HStore> storeList = r.getStores();
1584    stores += storeList.size();
1585    for (HStore store : storeList) {
1586      storefiles += store.getStorefilesCount();
1587      int currentStoreRefCount = store.getStoreRefCount();
1588      storeRefCount += currentStoreRefCount;
1589      int currentMaxCompactedStoreFileRefCount = store.getMaxCompactedStoreFileRefCount();
1590      maxCompactedStoreFileRefCount =
1591        Math.max(maxCompactedStoreFileRefCount, currentMaxCompactedStoreFileRefCount);
1592      storeUncompressedSize += store.getStoreSizeUncompressed();
1593      storefileSize += store.getStorefilesSize();
1594      totalRegionSize += store.getHFilesSize();
1595      // TODO: storefileIndexSizeKB is same with rootLevelIndexSizeKB?
1596      storefileIndexSize += store.getStorefilesRootLevelIndexSize();
1597      CompactionProgress progress = store.getCompactionProgress();
1598      if (progress != null) {
1599        totalCompactingKVs += progress.getTotalCompactingKVs();
1600        currentCompactedKVs += progress.currentCompactedKVs;
1601      }
1602      rootLevelIndexSize += store.getStorefilesRootLevelIndexSize();
1603      totalStaticIndexSize += store.getTotalStaticIndexSize();
1604      totalStaticBloomSize += store.getTotalStaticBloomSize();
1605    }
1606
1607    int memstoreSizeMB = roundSize(r.getMemStoreDataSize(), unitMB);
1608    int storeUncompressedSizeMB = roundSize(storeUncompressedSize, unitMB);
1609    int storefileSizeMB = roundSize(storefileSize, unitMB);
1610    int storefileIndexSizeKB = roundSize(storefileIndexSize, unitKB);
1611    int rootLevelIndexSizeKB = roundSize(rootLevelIndexSize, unitKB);
1612    int totalStaticIndexSizeKB = roundSize(totalStaticIndexSize, unitKB);
1613    int totalStaticBloomSizeKB = roundSize(totalStaticBloomSize, unitKB);
1614    int regionSizeMB = roundSize(totalRegionSize, unitMB);
1615    final MutableFloat currentRegionCachedRatio = new MutableFloat(0.0f);
1616    getBlockCache().ifPresent(bc -> {
1617      bc.getRegionCachedInfo().ifPresent(regionCachedInfo -> {
1618        if (regionCachedInfo.containsKey(regionEncodedName)) {
1619          currentRegionCachedRatio.setValue(regionSizeMB == 0
1620            ? 0.0f
1621            : (float) roundSize(regionCachedInfo.get(regionEncodedName), unitMB) / regionSizeMB);
1622        }
1623      });
1624    });
1625    final MutableFloat currentRegionColdDataRatio = new MutableFloat(0.0f);
1626    if (DataTieringManager.getInstance() != null) {
1627      DataTieringManager.getInstance().getRegionColdDataSize().computeIfPresent(regionEncodedName,
1628        (k, v) -> {
1629          int coldSizeMB = roundSize(v.getSecond(), unitMB);
1630          currentRegionColdDataRatio
1631            .setValue(regionSizeMB == 0 ? 0.0f : (float) coldSizeMB / regionSizeMB);
1632          return v;
1633        });
1634    }
1635
1636    HDFSBlocksDistribution hdfsBd = r.getHDFSBlocksDistribution();
1637    float dataLocality = hdfsBd.getBlockLocalityIndex(serverName.getHostname());
1638    float dataLocalityForSsd = hdfsBd.getBlockLocalityIndexForSsd(serverName.getHostname());
1639    long blocksTotalWeight = hdfsBd.getUniqueBlocksTotalWeight();
1640    long blocksLocalWeight = hdfsBd.getBlocksLocalWeight(serverName.getHostname());
1641    long blocksLocalWithSsdWeight = hdfsBd.getBlocksLocalWithSsdWeight(serverName.getHostname());
1642    if (regionLoadBldr == null) {
1643      regionLoadBldr = RegionLoad.newBuilder();
1644    }
1645    if (regionSpecifier == null) {
1646      regionSpecifier = RegionSpecifier.newBuilder();
1647    }
1648
1649    regionSpecifier.setType(RegionSpecifierType.REGION_NAME);
1650    regionSpecifier.setValue(UnsafeByteOperations.unsafeWrap(name));
1651    regionLoadBldr.setRegionSpecifier(regionSpecifier.build()).setStores(stores)
1652      .setStorefiles(storefiles).setStoreRefCount(storeRefCount)
1653      .setMaxCompactedStoreFileRefCount(maxCompactedStoreFileRefCount)
1654      .setStoreUncompressedSizeMB(storeUncompressedSizeMB).setStorefileSizeMB(storefileSizeMB)
1655      .setMemStoreSizeMB(memstoreSizeMB).setStorefileIndexSizeKB(storefileIndexSizeKB)
1656      .setRootIndexSizeKB(rootLevelIndexSizeKB).setTotalStaticIndexSizeKB(totalStaticIndexSizeKB)
1657      .setTotalStaticBloomSizeKB(totalStaticBloomSizeKB)
1658      .setReadRequestsCount(r.getReadRequestsCount()).setCpRequestsCount(r.getCpRequestsCount())
1659      .setFilteredReadRequestsCount(r.getFilteredReadRequestsCount())
1660      .setWriteRequestsCount(r.getWriteRequestsCount()).setTotalCompactingKVs(totalCompactingKVs)
1661      .setCurrentCompactedKVs(currentCompactedKVs).setDataLocality(dataLocality)
1662      .setDataLocalityForSsd(dataLocalityForSsd).setBlocksLocalWeight(blocksLocalWeight)
1663      .setBlocksLocalWithSsdWeight(blocksLocalWithSsdWeight).setBlocksTotalWeight(blocksTotalWeight)
1664      .setCompactionState(ProtobufUtil.createCompactionStateForRegionLoad(r.getCompactionState()))
1665      .setLastMajorCompactionTs(r.getOldestHfileTs(true)).setRegionSizeMB(regionSizeMB)
1666      .setCurrentRegionCachedRatio(currentRegionCachedRatio.floatValue())
1667      .setCurrentRegionColdDataRatio(currentRegionColdDataRatio.floatValue());
1668    r.setCompleteSequenceId(regionLoadBldr);
1669    return regionLoadBldr.build();
1670  }
1671
1672  private UserLoad createUserLoad(String user, MetricsUserSource userSource) {
1673    UserLoad.Builder userLoadBldr = UserLoad.newBuilder();
1674    userLoadBldr.setUserName(user);
1675    userSource.getClientMetrics().values().stream()
1676      .map(clientMetrics -> ClusterStatusProtos.ClientMetrics.newBuilder()
1677        .setHostName(clientMetrics.getHostName())
1678        .setWriteRequestsCount(clientMetrics.getWriteRequestsCount())
1679        .setFilteredRequestsCount(clientMetrics.getFilteredReadRequests())
1680        .setReadRequestsCount(clientMetrics.getReadRequestsCount())
1681        .setHostAddress(clientMetrics.getHostAddress()).setUserName(clientMetrics.getUserName())
1682        .setClientVersion(clientMetrics.getClientVersion())
1683        .setServiceName(clientMetrics.getServiceName())
1684        .setClientVersion(clientMetrics.getClientVersion()).build())
1685      .forEach(userLoadBldr::addClientMetrics);
1686    return userLoadBldr.build();
1687  }
1688
1689  public RegionLoad createRegionLoad(final String encodedRegionName) throws IOException {
1690    HRegion r = onlineRegions.get(encodedRegionName);
1691    return r != null ? createRegionLoad(r, null, null) : null;
1692  }
1693
1694  /**
1695   * Inner class that runs on a long period checking if regions need compaction.
1696   */
1697  private static class CompactionChecker extends ScheduledChore {
1698    private final HRegionServer instance;
1699    private final int majorCompactPriority;
1700    private final static int DEFAULT_PRIORITY = Integer.MAX_VALUE;
1701    // Iteration is 1-based rather than 0-based so we don't check for compaction
1702    // immediately upon region server startup
1703    private long iteration = 1;
1704
1705    CompactionChecker(final HRegionServer h, final int sleepTime, final Stoppable stopper) {
1706      super("CompactionChecker", stopper, sleepTime);
1707      this.instance = h;
1708      LOG.info(this.getName() + " runs every " + Duration.ofMillis(sleepTime));
1709
1710      /*
1711       * MajorCompactPriority is configurable. If not set, the compaction will use default priority.
1712       */
1713      this.majorCompactPriority = this.instance.conf
1714        .getInt("hbase.regionserver.compactionChecker.majorCompactPriority", DEFAULT_PRIORITY);
1715    }
1716
1717    @Override
1718    protected void chore() {
1719      for (HRegion hr : this.instance.onlineRegions.values()) {
1720        // If region is read only or compaction is disabled at table level, there's no need to
1721        // iterate through region's stores
1722        if (hr == null || hr.isReadOnly() || !hr.getTableDescriptor().isCompactionEnabled()) {
1723          continue;
1724        }
1725
1726        for (HStore s : hr.stores.values()) {
1727          try {
1728            long multiplier = s.getCompactionCheckMultiplier();
1729            assert multiplier > 0;
1730            if (iteration % multiplier != 0) {
1731              continue;
1732            }
1733            if (s.needsCompaction()) {
1734              // Queue a compaction. Will recognize if major is needed.
1735              this.instance.compactSplitThread.requestSystemCompaction(hr, s,
1736                getName() + " requests compaction");
1737            } else if (s.shouldPerformMajorCompaction()) {
1738              s.triggerMajorCompaction();
1739              if (
1740                majorCompactPriority == DEFAULT_PRIORITY
1741                  || majorCompactPriority > hr.getCompactPriority()
1742              ) {
1743                this.instance.compactSplitThread.requestCompaction(hr, s,
1744                  getName() + " requests major compaction; use default priority", Store.NO_PRIORITY,
1745                  CompactionLifeCycleTracker.DUMMY, null);
1746              } else {
1747                this.instance.compactSplitThread.requestCompaction(hr, s,
1748                  getName() + " requests major compaction; use configured priority",
1749                  this.majorCompactPriority, CompactionLifeCycleTracker.DUMMY, null);
1750              }
1751            }
1752          } catch (IOException e) {
1753            LOG.warn("Failed major compaction check on " + hr, e);
1754          }
1755        }
1756      }
1757      iteration = (iteration == Long.MAX_VALUE) ? 0 : (iteration + 1);
1758    }
1759  }
1760
1761  private static class PeriodicMemStoreFlusher extends ScheduledChore {
1762    private final HRegionServer server;
1763    private final static int RANGE_OF_DELAY = 5 * 60; // 5 min in seconds
1764    private final static int MIN_DELAY_TIME = 0; // millisec
1765    private final long rangeOfDelayMs;
1766
1767    PeriodicMemStoreFlusher(int cacheFlushInterval, final HRegionServer server) {
1768      super("MemstoreFlusherChore", server, cacheFlushInterval);
1769      this.server = server;
1770
1771      final long configuredRangeOfDelay = server.getConfiguration()
1772        .getInt("hbase.regionserver.periodicmemstoreflusher.rangeofdelayseconds", RANGE_OF_DELAY);
1773      this.rangeOfDelayMs = TimeUnit.SECONDS.toMillis(configuredRangeOfDelay);
1774    }
1775
1776    @Override
1777    protected void chore() {
1778      final StringBuilder whyFlush = new StringBuilder();
1779      for (HRegion r : this.server.onlineRegions.values()) {
1780        if (r == null) {
1781          continue;
1782        }
1783        if (r.shouldFlush(whyFlush)) {
1784          FlushRequester requester = server.getFlushRequester();
1785          if (requester != null) {
1786            long delay = ThreadLocalRandom.current().nextLong(rangeOfDelayMs) + MIN_DELAY_TIME;
1787            // Throttle the flushes by putting a delay. If we don't throttle, and there
1788            // is a balanced write-load on the regions in a table, we might end up
1789            // overwhelming the filesystem with too many flushes at once.
1790            if (requester.requestDelayedFlush(r, delay)) {
1791              LOG.info("{} requesting flush of {} because {} after random delay {} ms", getName(),
1792                r.getRegionInfo().getRegionNameAsString(), whyFlush.toString(), delay);
1793            }
1794          }
1795        }
1796      }
1797    }
1798  }
1799
1800  /**
1801   * Report the status of the server. A server is online once all the startup is completed (setting
1802   * up filesystem, starting executorService threads, etc.). This method is designed mostly to be
1803   * useful in tests.
1804   * @return true if online, false if not.
1805   */
1806  public boolean isOnline() {
1807    return online.get();
1808  }
1809
1810  /**
1811   * Setup WAL log and replication if enabled. Replication setup is done in here because it wants to
1812   * be hooked up to WAL.
1813   */
1814  private void setupWALAndReplication() throws IOException {
1815    WALFactory factory = new WALFactory(conf, serverName, this);
1816    // TODO Replication make assumptions here based on the default filesystem impl
1817    Path oldLogDir = new Path(walRootDir, HConstants.HREGION_OLDLOGDIR_NAME);
1818    String logName = AbstractFSWALProvider.getWALDirectoryName(this.serverName.toString());
1819
1820    Path logDir = new Path(walRootDir, logName);
1821    LOG.debug("logDir={}", logDir);
1822    if (this.walFs.exists(logDir)) {
1823      throw new RegionServerRunningException(
1824        "Region server has already created directory at " + this.serverName.toString());
1825    }
1826    // Create wal directory here and we will never create it again in other places. This is
1827    // important to make sure that our fencing way takes effect. See HBASE-29797 for more details.
1828    if (!this.walFs.mkdirs(logDir)) {
1829      throw new IOException("Can not create wal directory " + logDir);
1830    }
1831    // Instantiate replication if replication enabled. Pass it the log directories.
1832    createNewReplicationInstance(conf, this, this.walFs, logDir, oldLogDir, factory);
1833
1834    WALActionsListener walEventListener = getWALEventTrackerListener(conf);
1835    if (walEventListener != null && factory.getWALProvider() != null) {
1836      factory.getWALProvider().addWALActionsListener(walEventListener);
1837    }
1838    this.walFactory = factory;
1839  }
1840
1841  private WALActionsListener getWALEventTrackerListener(Configuration conf) {
1842    if (conf.getBoolean(WAL_EVENT_TRACKER_ENABLED_KEY, WAL_EVENT_TRACKER_ENABLED_DEFAULT)) {
1843      WALEventTrackerListener listener =
1844        new WALEventTrackerListener(conf, getNamedQueueRecorder(), getServerName());
1845      return listener;
1846    }
1847    return null;
1848  }
1849
1850  /**
1851   * Start up replication source and sink handlers.
1852   */
1853  private void startReplicationService() throws IOException {
1854    if (sameReplicationSourceAndSink && this.replicationSourceHandler != null) {
1855      this.replicationSourceHandler.startReplicationService();
1856    } else {
1857      if (this.replicationSourceHandler != null) {
1858        this.replicationSourceHandler.startReplicationService();
1859      }
1860      if (this.replicationSinkHandler != null) {
1861        this.replicationSinkHandler.startReplicationService();
1862      }
1863    }
1864  }
1865
1866  /** Returns Master address tracker instance. */
1867  public MasterAddressTracker getMasterAddressTracker() {
1868    return this.masterAddressTracker;
1869  }
1870
1871  /**
1872   * Start maintenance Threads, Server, Worker and lease checker threads. Start all threads we need
1873   * to run. This is called after we've successfully registered with the Master. Install an
1874   * UncaughtExceptionHandler that calls abort of RegionServer if we get an unhandled exception. We
1875   * cannot set the handler on all threads. Server's internal Listener thread is off limits. For
1876   * Server, if an OOME, it waits a while then retries. Meantime, a flush or a compaction that tries
1877   * to run should trigger same critical condition and the shutdown will run. On its way out, this
1878   * server will shut down Server. Leases are sort of inbetween. It has an internal thread that
1879   * while it inherits from Chore, it keeps its own internal stop mechanism so needs to be stopped
1880   * by this hosting server. Worker logs the exception and exits.
1881   */
1882  private void startServices() throws IOException {
1883    if (!isStopped() && !isAborted()) {
1884      initializeThreads();
1885    }
1886    this.secureBulkLoadManager = new SecureBulkLoadManager(this.conf, asyncClusterConnection);
1887    this.secureBulkLoadManager.start();
1888
1889    // Health checker thread.
1890    if (isHealthCheckerConfigured()) {
1891      int sleepTime = this.conf.getInt(HConstants.HEALTH_CHORE_WAKE_FREQ,
1892        HConstants.DEFAULT_THREAD_WAKE_FREQUENCY);
1893      healthCheckChore = new HealthCheckChore(sleepTime, this, getConfiguration());
1894    }
1895    // Executor status collect thread.
1896    if (
1897      this.conf.getBoolean(HConstants.EXECUTOR_STATUS_COLLECT_ENABLED,
1898        HConstants.DEFAULT_EXECUTOR_STATUS_COLLECT_ENABLED)
1899    ) {
1900      int sleepTime =
1901        this.conf.getInt(ExecutorStatusChore.WAKE_FREQ, ExecutorStatusChore.DEFAULT_WAKE_FREQ);
1902      executorStatusChore = new ExecutorStatusChore(sleepTime, this, this.getExecutorService(),
1903        this.metricsRegionServer.getMetricsSource());
1904    }
1905
1906    this.walRoller = new LogRoller(this);
1907    this.flushThroughputController = FlushThroughputControllerFactory.create(this, conf);
1908    this.procedureResultReporter = new RemoteProcedureResultReporter(this);
1909
1910    // Create the CompactedFileDischarger chore executorService. This chore helps to
1911    // remove the compacted files that will no longer be used in reads.
1912    // Default is 2 mins. The default value for TTLCleaner is 5 mins so we set this to
1913    // 2 mins so that compacted files can be archived before the TTLCleaner runs
1914    int cleanerInterval = conf.getInt("hbase.hfile.compaction.discharger.interval", 2 * 60 * 1000);
1915    this.compactedFileDischarger = new CompactedHFilesDischarger(cleanerInterval, this, this);
1916    choreService.scheduleChore(compactedFileDischarger);
1917
1918    // Start executor services
1919    final int openRegionThreads = conf.getInt("hbase.regionserver.executor.openregion.threads", 3);
1920    executorService.startExecutorService(executorService.new ExecutorConfig()
1921      .setExecutorType(ExecutorType.RS_OPEN_REGION).setCorePoolSize(openRegionThreads));
1922    final int openMetaThreads = conf.getInt("hbase.regionserver.executor.openmeta.threads", 1);
1923    executorService.startExecutorService(executorService.new ExecutorConfig()
1924      .setExecutorType(ExecutorType.RS_OPEN_META).setCorePoolSize(openMetaThreads));
1925    final int openPriorityRegionThreads =
1926      conf.getInt("hbase.regionserver.executor.openpriorityregion.threads", 3);
1927    executorService.startExecutorService(
1928      executorService.new ExecutorConfig().setExecutorType(ExecutorType.RS_OPEN_PRIORITY_REGION)
1929        .setCorePoolSize(openPriorityRegionThreads));
1930    final int closeRegionThreads =
1931      conf.getInt("hbase.regionserver.executor.closeregion.threads", 3);
1932    executorService.startExecutorService(executorService.new ExecutorConfig()
1933      .setExecutorType(ExecutorType.RS_CLOSE_REGION).setCorePoolSize(closeRegionThreads));
1934    final int closeMetaThreads = conf.getInt("hbase.regionserver.executor.closemeta.threads", 1);
1935    executorService.startExecutorService(executorService.new ExecutorConfig()
1936      .setExecutorType(ExecutorType.RS_CLOSE_META).setCorePoolSize(closeMetaThreads));
1937    if (conf.getBoolean(StoreScanner.STORESCANNER_PARALLEL_SEEK_ENABLE, false)) {
1938      final int storeScannerParallelSeekThreads =
1939        conf.getInt("hbase.storescanner.parallel.seek.threads", 10);
1940      executorService.startExecutorService(
1941        executorService.new ExecutorConfig().setExecutorType(ExecutorType.RS_PARALLEL_SEEK)
1942          .setCorePoolSize(storeScannerParallelSeekThreads).setAllowCoreThreadTimeout(true));
1943    }
1944    final int logReplayOpsThreads =
1945      conf.getInt(HBASE_SPLIT_WAL_MAX_SPLITTER, DEFAULT_HBASE_SPLIT_WAL_MAX_SPLITTER);
1946    executorService.startExecutorService(
1947      executorService.new ExecutorConfig().setExecutorType(ExecutorType.RS_LOG_REPLAY_OPS)
1948        .setCorePoolSize(logReplayOpsThreads).setAllowCoreThreadTimeout(true));
1949    // Start the threads for compacted files discharger
1950    final int compactionDischargerThreads =
1951      conf.getInt(CompactionConfiguration.HBASE_HFILE_COMPACTION_DISCHARGER_THREAD_COUNT, 10);
1952    executorService.startExecutorService(executorService.new ExecutorConfig()
1953      .setExecutorType(ExecutorType.RS_COMPACTED_FILES_DISCHARGER)
1954      .setCorePoolSize(compactionDischargerThreads));
1955    if (ServerRegionReplicaUtil.isRegionReplicaWaitForPrimaryFlushEnabled(conf)) {
1956      final int regionReplicaFlushThreads =
1957        conf.getInt("hbase.regionserver.region.replica.flusher.threads",
1958          conf.getInt("hbase.regionserver.executor.openregion.threads", 3));
1959      executorService.startExecutorService(executorService.new ExecutorConfig()
1960        .setExecutorType(ExecutorType.RS_REGION_REPLICA_FLUSH_OPS)
1961        .setCorePoolSize(regionReplicaFlushThreads));
1962    }
1963    final int refreshPeerThreads =
1964      conf.getInt("hbase.regionserver.executor.refresh.peer.threads", 2);
1965    executorService.startExecutorService(executorService.new ExecutorConfig()
1966      .setExecutorType(ExecutorType.RS_REFRESH_PEER).setCorePoolSize(refreshPeerThreads));
1967    final int replaySyncReplicationWALThreads =
1968      conf.getInt("hbase.regionserver.executor.replay.sync.replication.wal.threads", 1);
1969    executorService.startExecutorService(executorService.new ExecutorConfig()
1970      .setExecutorType(ExecutorType.RS_REPLAY_SYNC_REPLICATION_WAL)
1971      .setCorePoolSize(replaySyncReplicationWALThreads));
1972    final int switchRpcThrottleThreads =
1973      conf.getInt("hbase.regionserver.executor.switch.rpc.throttle.threads", 1);
1974    executorService.startExecutorService(
1975      executorService.new ExecutorConfig().setExecutorType(ExecutorType.RS_SWITCH_RPC_THROTTLE)
1976        .setCorePoolSize(switchRpcThrottleThreads));
1977    final int claimReplicationQueueThreads =
1978      conf.getInt("hbase.regionserver.executor.claim.replication.queue.threads", 1);
1979    executorService.startExecutorService(
1980      executorService.new ExecutorConfig().setExecutorType(ExecutorType.RS_CLAIM_REPLICATION_QUEUE)
1981        .setCorePoolSize(claimReplicationQueueThreads));
1982    final int rsSnapshotOperationThreads =
1983      conf.getInt("hbase.regionserver.executor.snapshot.operations.threads", 3);
1984    executorService.startExecutorService(
1985      executorService.new ExecutorConfig().setExecutorType(ExecutorType.RS_SNAPSHOT_OPERATIONS)
1986        .setCorePoolSize(rsSnapshotOperationThreads));
1987    final int rsFlushOperationThreads =
1988      conf.getInt("hbase.regionserver.executor.flush.operations.threads", 3);
1989    executorService.startExecutorService(executorService.new ExecutorConfig()
1990      .setExecutorType(ExecutorType.RS_FLUSH_OPERATIONS).setCorePoolSize(rsFlushOperationThreads));
1991    final int rsRefreshQuotasThreads =
1992      conf.getInt("hbase.regionserver.executor.refresh.quotas.threads", 1);
1993    executorService.startExecutorService(
1994      executorService.new ExecutorConfig().setExecutorType(ExecutorType.RS_RELOAD_QUOTAS_OPERATIONS)
1995        .setCorePoolSize(rsRefreshQuotasThreads));
1996    final int logRollThreads = conf.getInt("hbase.regionserver.executor.log.roll.threads", 1);
1997    executorService.startExecutorService(executorService.new ExecutorConfig()
1998      .setExecutorType(ExecutorType.RS_LOG_ROLL).setCorePoolSize(logRollThreads));
1999    final int rsRefreshHFilesThreads =
2000      conf.getInt("hbase.regionserver.executor.refresh.hfiles.threads", 3);
2001    executorService.startExecutorService(executorService.new ExecutorConfig()
2002      .setExecutorType(ExecutorType.RS_REFRESH_HFILES).setCorePoolSize(rsRefreshHFilesThreads));
2003
2004    Threads.setDaemonThreadRunning(this.walRoller, getName() + ".logRoller",
2005      uncaughtExceptionHandler);
2006    if (this.cacheFlusher != null) {
2007      this.cacheFlusher.start(uncaughtExceptionHandler);
2008    }
2009    Threads.setDaemonThreadRunning(this.procedureResultReporter,
2010      getName() + ".procedureResultReporter", uncaughtExceptionHandler);
2011
2012    if (this.compactionChecker != null) {
2013      choreService.scheduleChore(compactionChecker);
2014    }
2015    if (this.periodicFlusher != null) {
2016      choreService.scheduleChore(periodicFlusher);
2017    }
2018    if (this.healthCheckChore != null) {
2019      choreService.scheduleChore(healthCheckChore);
2020    }
2021    if (this.executorStatusChore != null) {
2022      choreService.scheduleChore(executorStatusChore);
2023    }
2024    if (this.nonceManagerChore != null) {
2025      choreService.scheduleChore(nonceManagerChore);
2026    }
2027    if (this.storefileRefresher != null) {
2028      choreService.scheduleChore(storefileRefresher);
2029    }
2030    if (this.fsUtilizationChore != null) {
2031      choreService.scheduleChore(fsUtilizationChore);
2032    }
2033    if (this.namedQueueServiceChore != null) {
2034      choreService.scheduleChore(namedQueueServiceChore);
2035    }
2036    if (this.brokenStoreFileCleaner != null) {
2037      choreService.scheduleChore(brokenStoreFileCleaner);
2038    }
2039    if (this.rsMobFileCleanerChore != null) {
2040      choreService.scheduleChore(rsMobFileCleanerChore);
2041    }
2042    if (replicationMarkerChore != null) {
2043      LOG.info("Starting replication marker chore");
2044      choreService.scheduleChore(replicationMarkerChore);
2045    }
2046
2047    // Leases is not a Thread. Internally it runs a daemon thread. If it gets
2048    // an unhandled exception, it will just exit.
2049    Threads.setDaemonThreadRunning(this.leaseManager, getName() + ".leaseChecker",
2050      uncaughtExceptionHandler);
2051
2052    // Create the log splitting worker and start it
2053    // set a smaller retries to fast fail otherwise splitlogworker could be blocked for
2054    // quite a while inside Connection layer. The worker won't be available for other
2055    // tasks even after current task is preempted after a split task times out.
2056    Configuration sinkConf = HBaseConfiguration.create(conf);
2057    sinkConf.setInt(HConstants.HBASE_CLIENT_RETRIES_NUMBER,
2058      conf.getInt("hbase.log.replay.retries.number", 8)); // 8 retries take about 23 seconds
2059    sinkConf.setInt(HConstants.HBASE_RPC_TIMEOUT_KEY,
2060      conf.getInt("hbase.log.replay.rpc.timeout", 30000)); // default 30 seconds
2061    sinkConf.setInt(HConstants.HBASE_CLIENT_SERVERSIDE_RETRIES_MULTIPLIER, 1);
2062    if (
2063      this.csm != null
2064        && conf.getBoolean(HBASE_SPLIT_WAL_COORDINATED_BY_ZK, DEFAULT_HBASE_SPLIT_COORDINATED_BY_ZK)
2065    ) {
2066      // SplitLogWorker needs csm. If none, don't start this.
2067      this.splitLogWorker = new SplitLogWorker(sinkConf, this, this, walFactory);
2068      splitLogWorker.start();
2069      LOG.debug("SplitLogWorker started");
2070    }
2071
2072    // Memstore services.
2073    startHeapMemoryManager();
2074    // Call it after starting HeapMemoryManager.
2075    initializeMemStoreChunkCreator(hMemManager);
2076  }
2077
2078  private void initializeThreads() {
2079    // Cache flushing thread.
2080    this.cacheFlusher = new MemStoreFlusher(conf, this);
2081
2082    // Compaction thread
2083    this.compactSplitThread = new CompactSplit(this);
2084
2085    // Prefetch Notifier
2086    this.prefetchExecutorNotifier = new PrefetchExecutorNotifier(conf);
2087
2088    // Background thread to check for compactions; needed if region has not gotten updates
2089    // in a while. It will take care of not checking too frequently on store-by-store basis.
2090    this.compactionChecker = new CompactionChecker(this, this.compactionCheckFrequency, this);
2091    this.periodicFlusher = new PeriodicMemStoreFlusher(this.flushCheckFrequency, this);
2092    this.leaseManager = new LeaseManager(this.threadWakeFrequency);
2093
2094    final boolean isSlowLogTableEnabled = conf.getBoolean(HConstants.SLOW_LOG_SYS_TABLE_ENABLED_KEY,
2095      HConstants.DEFAULT_SLOW_LOG_SYS_TABLE_ENABLED_KEY);
2096    final boolean walEventTrackerEnabled =
2097      conf.getBoolean(WAL_EVENT_TRACKER_ENABLED_KEY, WAL_EVENT_TRACKER_ENABLED_DEFAULT);
2098
2099    if (isSlowLogTableEnabled || walEventTrackerEnabled) {
2100      // default chore duration: 10 min
2101      // After <version number>, we will remove hbase.slowlog.systable.chore.duration conf property
2102      final int slowLogChoreDuration = conf.getInt(HConstants.SLOW_LOG_SYS_TABLE_CHORE_DURATION_KEY,
2103        DEFAULT_SLOW_LOG_SYS_TABLE_CHORE_DURATION);
2104
2105      final int namedQueueChoreDuration =
2106        conf.getInt(NAMED_QUEUE_CHORE_DURATION_KEY, NAMED_QUEUE_CHORE_DURATION_DEFAULT);
2107      // Considering min of slowLogChoreDuration and namedQueueChoreDuration
2108      int choreDuration = Math.min(slowLogChoreDuration, namedQueueChoreDuration);
2109
2110      namedQueueServiceChore = new NamedQueueServiceChore(this, choreDuration,
2111        this.namedQueueRecorder, this.getConnection());
2112    }
2113
2114    if (this.nonceManager != null) {
2115      // Create the scheduled chore that cleans up nonces.
2116      nonceManagerChore = this.nonceManager.createCleanupScheduledChore(this);
2117    }
2118
2119    // Setup the Quota Manager
2120    rsQuotaManager = new RegionServerRpcQuotaManager(this);
2121    configurationManager.registerObserver(rsQuotaManager);
2122    rsSpaceQuotaManager = new RegionServerSpaceQuotaManager(this);
2123
2124    if (QuotaUtil.isQuotaEnabled(conf)) {
2125      this.fsUtilizationChore = new FileSystemUtilizationChore(this);
2126    }
2127
2128    boolean onlyMetaRefresh = false;
2129    int storefileRefreshPeriod =
2130      conf.getInt(StorefileRefresherChore.REGIONSERVER_STOREFILE_REFRESH_PERIOD,
2131        StorefileRefresherChore.DEFAULT_REGIONSERVER_STOREFILE_REFRESH_PERIOD);
2132    if (storefileRefreshPeriod == 0) {
2133      storefileRefreshPeriod =
2134        conf.getInt(StorefileRefresherChore.REGIONSERVER_META_STOREFILE_REFRESH_PERIOD,
2135          StorefileRefresherChore.DEFAULT_REGIONSERVER_STOREFILE_REFRESH_PERIOD);
2136      onlyMetaRefresh = true;
2137    }
2138    if (storefileRefreshPeriod > 0) {
2139      this.storefileRefresher =
2140        new StorefileRefresherChore(storefileRefreshPeriod, onlyMetaRefresh, this, this);
2141    }
2142
2143    int brokenStoreFileCleanerPeriod =
2144      conf.getInt(BrokenStoreFileCleaner.BROKEN_STOREFILE_CLEANER_PERIOD,
2145        BrokenStoreFileCleaner.DEFAULT_BROKEN_STOREFILE_CLEANER_PERIOD);
2146    int brokenStoreFileCleanerDelay =
2147      conf.getInt(BrokenStoreFileCleaner.BROKEN_STOREFILE_CLEANER_DELAY,
2148        BrokenStoreFileCleaner.DEFAULT_BROKEN_STOREFILE_CLEANER_DELAY);
2149    double brokenStoreFileCleanerDelayJitter =
2150      conf.getDouble(BrokenStoreFileCleaner.BROKEN_STOREFILE_CLEANER_DELAY_JITTER,
2151        BrokenStoreFileCleaner.DEFAULT_BROKEN_STOREFILE_CLEANER_DELAY_JITTER);
2152    double jitterRate =
2153      (ThreadLocalRandom.current().nextDouble() - 0.5D) * brokenStoreFileCleanerDelayJitter;
2154    long jitterValue = Math.round(brokenStoreFileCleanerDelay * jitterRate);
2155    this.brokenStoreFileCleaner =
2156      new BrokenStoreFileCleaner((int) (brokenStoreFileCleanerDelay + jitterValue),
2157        brokenStoreFileCleanerPeriod, this, conf, this);
2158
2159    this.rsMobFileCleanerChore = new RSMobFileCleanerChore(this);
2160
2161    registerConfigurationObservers();
2162    initializeReplicationMarkerChore();
2163  }
2164
2165  private void registerConfigurationObservers() {
2166    // Register Replication if possible, as now we support recreating replication peer storage, for
2167    // migrating across different replication peer storages online
2168    if (replicationSourceHandler instanceof ConfigurationObserver) {
2169      configurationManager.registerObserver((ConfigurationObserver) replicationSourceHandler);
2170    }
2171    if (!sameReplicationSourceAndSink && replicationSinkHandler instanceof ConfigurationObserver) {
2172      configurationManager.registerObserver((ConfigurationObserver) replicationSinkHandler);
2173    }
2174    // Registering the compactSplitThread object with the ConfigurationManager.
2175    configurationManager.registerObserver(this.compactSplitThread);
2176    configurationManager.registerObserver(this.cacheFlusher);
2177    configurationManager.registerObserver(this.rpcServices);
2178    configurationManager.registerObserver(this.prefetchExecutorNotifier);
2179    configurationManager.registerObserver(this);
2180  }
2181
2182  /*
2183   * Verify that server is healthy
2184   */
2185  private boolean isHealthy() {
2186    if (!dataFsOk) {
2187      // File system problem
2188      return false;
2189    }
2190    // Verify that all threads are alive
2191    boolean healthy = (this.leaseManager == null || this.leaseManager.isAlive())
2192      && (this.cacheFlusher == null || this.cacheFlusher.isAlive())
2193      && (this.walRoller == null || this.walRoller.isAlive())
2194      && (this.compactionChecker == null || this.compactionChecker.isScheduled())
2195      && (this.periodicFlusher == null || this.periodicFlusher.isScheduled());
2196    if (!healthy) {
2197      stop("One or more threads are no longer alive -- stop");
2198    }
2199    return healthy;
2200  }
2201
2202  @Override
2203  public List<WAL> getWALs() {
2204    return walFactory.getWALs();
2205  }
2206
2207  @Override
2208  public WAL getWAL(RegionInfo regionInfo) throws IOException {
2209    WAL wal = walFactory.getWAL(regionInfo);
2210    if (this.walRoller != null) {
2211      this.walRoller.addWAL(wal);
2212    }
2213    return wal;
2214  }
2215
2216  public LogRoller getWalRoller() {
2217    return walRoller;
2218  }
2219
2220  public WALFactory getWalFactory() {
2221    return walFactory;
2222  }
2223
2224  @Override
2225  public void stop(final String msg) {
2226    stop(msg, false, RpcServer.getRequestUser().orElse(null));
2227  }
2228
2229  /**
2230   * Stops the regionserver.
2231   * @param msg   Status message
2232   * @param force True if this is a regionserver abort
2233   * @param user  The user executing the stop request, or null if no user is associated
2234   */
2235  public void stop(final String msg, final boolean force, final User user) {
2236    if (!this.stopped) {
2237      LOG.info("***** STOPPING region server '{}' *****", this);
2238      if (this.rsHost != null) {
2239        // when forced via abort don't allow CPs to override
2240        try {
2241          this.rsHost.preStop(msg, user);
2242        } catch (IOException ioe) {
2243          if (!force) {
2244            LOG.warn("The region server did not stop", ioe);
2245            return;
2246          }
2247          LOG.warn("Skipping coprocessor exception on preStop() due to forced shutdown", ioe);
2248        }
2249      }
2250      this.stopped = true;
2251      LOG.info("STOPPED: " + msg);
2252      // Wakes run() if it is sleeping
2253      sleeper.skipSleepCycle();
2254    }
2255  }
2256
2257  public void waitForServerOnline() {
2258    while (!isStopped() && !isOnline()) {
2259      synchronized (online) {
2260        try {
2261          online.wait(msgInterval);
2262        } catch (InterruptedException ie) {
2263          Thread.currentThread().interrupt();
2264          break;
2265        }
2266      }
2267    }
2268  }
2269
2270  @Override
2271  public void postOpenDeployTasks(final PostOpenDeployContext context) throws IOException {
2272    HRegion r = context.getRegion();
2273    long openProcId = context.getOpenProcId();
2274    long masterSystemTime = context.getMasterSystemTime();
2275    long initiatingMasterActiveTime = context.getInitiatingMasterActiveTime();
2276    rpcServices.checkOpen();
2277    LOG.info("Post open deploy tasks for {}, pid={}, masterSystemTime={}",
2278      r.getRegionInfo().getRegionNameAsString(), openProcId, masterSystemTime);
2279    // Do checks to see if we need to compact (references or too many files)
2280    // Skip compaction check if region is read only
2281    if (!r.isReadOnly()) {
2282      for (HStore s : r.stores.values()) {
2283        if (s.hasReferences() || s.needsCompaction()) {
2284          this.compactSplitThread.requestSystemCompaction(r, s, "Opening Region");
2285        }
2286      }
2287    }
2288    long openSeqNum = r.getOpenSeqNum();
2289    if (openSeqNum == HConstants.NO_SEQNUM) {
2290      // If we opened a region, we should have read some sequence number from it.
2291      LOG.error(
2292        "No sequence number found when opening " + r.getRegionInfo().getRegionNameAsString());
2293      openSeqNum = 0;
2294    }
2295
2296    // Notify master
2297    if (
2298      !reportRegionStateTransition(new RegionStateTransitionContext(TransitionCode.OPENED,
2299        openSeqNum, openProcId, masterSystemTime, r.getRegionInfo(), initiatingMasterActiveTime))
2300    ) {
2301      throw new IOException(
2302        "Failed to report opened region to master: " + r.getRegionInfo().getRegionNameAsString());
2303    }
2304
2305    triggerFlushInPrimaryRegion(r);
2306
2307    LOG.debug("Finished post open deploy task for " + r.getRegionInfo().getRegionNameAsString());
2308  }
2309
2310  /**
2311   * Helper method for use in tests. Skip the region transition report when there's no master around
2312   * to receive it.
2313   */
2314  private boolean skipReportingTransition(final RegionStateTransitionContext context) {
2315    final TransitionCode code = context.getCode();
2316    final long openSeqNum = context.getOpenSeqNum();
2317    long masterSystemTime = context.getMasterSystemTime();
2318    final RegionInfo[] hris = context.getHris();
2319
2320    if (code == TransitionCode.OPENED) {
2321      Preconditions.checkArgument(hris != null && hris.length == 1);
2322      if (hris[0].isMetaRegion()) {
2323        LOG.warn(
2324          "meta table location is stored in master local store, so we can not skip reporting");
2325        return false;
2326      } else {
2327        try {
2328          MetaTableAccessor.updateRegionLocation(asyncClusterConnection.toConnection(), hris[0],
2329            serverName, openSeqNum, masterSystemTime);
2330        } catch (IOException e) {
2331          LOG.info("Failed to update meta", e);
2332          return false;
2333        }
2334      }
2335    }
2336    return true;
2337  }
2338
2339  private ReportRegionStateTransitionRequest
2340    createReportRegionStateTransitionRequest(final RegionStateTransitionContext context) {
2341    final TransitionCode code = context.getCode();
2342    final long openSeqNum = context.getOpenSeqNum();
2343    final RegionInfo[] hris = context.getHris();
2344    final long[] procIds = context.getProcIds();
2345
2346    ReportRegionStateTransitionRequest.Builder builder =
2347      ReportRegionStateTransitionRequest.newBuilder();
2348    builder.setServer(ProtobufUtil.toServerName(serverName));
2349    RegionStateTransition.Builder transition = builder.addTransitionBuilder();
2350    transition.setTransitionCode(code);
2351    if (code == TransitionCode.OPENED && openSeqNum >= 0) {
2352      transition.setOpenSeqNum(openSeqNum);
2353    }
2354    for (RegionInfo hri : hris) {
2355      transition.addRegionInfo(ProtobufUtil.toRegionInfo(hri));
2356    }
2357    for (long procId : procIds) {
2358      transition.addProcId(procId);
2359    }
2360    transition.setInitiatingMasterActiveTime(context.getInitiatingMasterActiveTime());
2361
2362    return builder.build();
2363  }
2364
2365  @Override
2366  public boolean reportRegionStateTransition(final RegionStateTransitionContext context) {
2367    if (TEST_SKIP_REPORTING_TRANSITION) {
2368      return skipReportingTransition(context);
2369    }
2370    final ReportRegionStateTransitionRequest request =
2371      createReportRegionStateTransitionRequest(context);
2372
2373    int tries = 0;
2374    long pauseTime = this.retryPauseTime;
2375    // Keep looping till we get an error. We want to send reports even though server is going down.
2376    // Only go down if clusterConnection is null. It is set to null almost as last thing as the
2377    // HRegionServer does down.
2378    while (this.asyncClusterConnection != null && !this.asyncClusterConnection.isClosed()) {
2379      RegionServerStatusService.BlockingInterface rss = rssStub;
2380      try {
2381        if (rss == null) {
2382          createRegionServerStatusStub();
2383          continue;
2384        }
2385        ReportRegionStateTransitionResponse response =
2386          rss.reportRegionStateTransition(null, request);
2387        if (response.hasErrorMessage()) {
2388          LOG.info("TRANSITION FAILED " + request + ": " + response.getErrorMessage());
2389          break;
2390        }
2391        // Log if we had to retry else don't log unless TRACE. We want to
2392        // know if were successful after an attempt showed in logs as failed.
2393        if (tries > 0 || LOG.isTraceEnabled()) {
2394          LOG.info("TRANSITION REPORTED " + request);
2395        }
2396        // NOTE: Return mid-method!!!
2397        return true;
2398      } catch (ServiceException se) {
2399        IOException ioe = ProtobufUtil.getRemoteException(se);
2400        boolean pause = ioe instanceof ServerNotRunningYetException
2401          || ioe instanceof PleaseHoldException || ioe instanceof CallQueueTooBigException;
2402        if (pause) {
2403          // Do backoff else we flood the Master with requests.
2404          pauseTime = ConnectionUtils.getPauseTime(this.retryPauseTime, tries);
2405        } else {
2406          pauseTime = this.retryPauseTime; // Reset.
2407        }
2408        LOG.info("Failed report transition " + TextFormat.shortDebugString(request) + "; retry (#"
2409          + tries + ")"
2410          + (pause
2411            ? " after " + pauseTime + "ms delay (Master is coming online...)."
2412            : " immediately."),
2413          ioe);
2414        if (pause) {
2415          Threads.sleep(pauseTime);
2416        }
2417        tries++;
2418        if (rssStub == rss) {
2419          rssStub = null;
2420        }
2421      }
2422    }
2423    return false;
2424  }
2425
2426  /**
2427   * Trigger a flush in the primary region replica if this region is a secondary replica. Does not
2428   * block this thread. See RegionReplicaFlushHandler for details.
2429   */
2430  private void triggerFlushInPrimaryRegion(final HRegion region) {
2431    if (ServerRegionReplicaUtil.isDefaultReplica(region.getRegionInfo())) {
2432      return;
2433    }
2434    TableName tn = region.getTableDescriptor().getTableName();
2435    if (
2436      !ServerRegionReplicaUtil.isRegionReplicaReplicationEnabled(region.conf, tn)
2437        || !ServerRegionReplicaUtil.isRegionReplicaWaitForPrimaryFlushEnabled(region.conf) ||
2438        // If the memstore replication not setup, we do not have to wait for observing a flush event
2439        // from primary before starting to serve reads, because gaps from replication is not
2440        // applicable,this logic is from
2441        // TableDescriptorBuilder.ModifyableTableDescriptor.setRegionMemStoreReplication by
2442        // HBASE-13063
2443        !region.getTableDescriptor().hasRegionMemStoreReplication()
2444    ) {
2445      region.setReadsEnabled(true);
2446      return;
2447    }
2448
2449    region.setReadsEnabled(false); // disable reads before marking the region as opened.
2450    // RegionReplicaFlushHandler might reset this.
2451
2452    // Submit it to be handled by one of the handlers so that we do not block OpenRegionHandler
2453    if (this.executorService != null) {
2454      this.executorService.submit(new RegionReplicaFlushHandler(this, region));
2455    } else {
2456      LOG.info("Executor is null; not running flush of primary region replica for {}",
2457        region.getRegionInfo());
2458    }
2459  }
2460
2461  @InterfaceAudience.Private
2462  public RSRpcServices getRSRpcServices() {
2463    return rpcServices;
2464  }
2465
2466  /**
2467   * Cause the server to exit without closing the regions it is serving, the log it is using and
2468   * without notifying the master. Used unit testing and on catastrophic events such as HDFS is
2469   * yanked out from under hbase or we OOME. the reason we are aborting the exception that caused
2470   * the abort, or null
2471   */
2472  @Override
2473  public void abort(String reason, Throwable cause) {
2474    if (!setAbortRequested()) {
2475      // Abort already in progress, ignore the new request.
2476      LOG.debug("Abort already in progress. Ignoring the current request with reason: {}", reason);
2477      return;
2478    }
2479    String msg = "***** ABORTING region server " + this + ": " + reason + " *****";
2480    if (cause != null) {
2481      LOG.error(HBaseMarkers.FATAL, msg, cause);
2482    } else {
2483      LOG.error(HBaseMarkers.FATAL, msg);
2484    }
2485    // HBASE-4014: show list of coprocessors that were loaded to help debug
2486    // regionserver crashes.Note that we're implicitly using
2487    // java.util.HashSet's toString() method to print the coprocessor names.
2488    LOG.error(HBaseMarkers.FATAL,
2489      "RegionServer abort: loaded coprocessors are: " + CoprocessorHost.getLoadedCoprocessors());
2490    // Try and dump metrics if abort -- might give clue as to how fatal came about....
2491    try {
2492      LOG.info("Dump of metrics as JSON on abort: " + DumpRegionServerMetrics.dumpMetrics());
2493    } catch (MalformedObjectNameException | IOException e) {
2494      LOG.warn("Failed dumping metrics", e);
2495    }
2496
2497    // Do our best to report our abort to the master, but this may not work
2498    try {
2499      if (cause != null) {
2500        msg += "\nCause:\n" + Throwables.getStackTraceAsString(cause);
2501      }
2502      // Report to the master but only if we have already registered with the master.
2503      RegionServerStatusService.BlockingInterface rss = rssStub;
2504      if (rss != null && this.serverName != null) {
2505        ReportRSFatalErrorRequest.Builder builder = ReportRSFatalErrorRequest.newBuilder();
2506        builder.setServer(ProtobufUtil.toServerName(this.serverName));
2507        builder.setErrorMessage(msg);
2508        rss.reportRSFatalError(null, builder.build());
2509      }
2510    } catch (Throwable t) {
2511      LOG.warn("Unable to report fatal error to master", t);
2512    }
2513
2514    scheduleAbortTimer();
2515    // shutdown should be run as the internal user
2516    stop(reason, true, null);
2517  }
2518
2519  /*
2520   * Simulate a kill -9 of this server. Exits w/o closing regions or cleaninup logs but it does
2521   * close socket in case want to bring up server on old hostname+port immediately.
2522   */
2523  @InterfaceAudience.Private
2524  protected void kill() {
2525    this.killed = true;
2526    abort("Simulated kill");
2527  }
2528
2529  // Limits the time spent in the shutdown process.
2530  private void scheduleAbortTimer() {
2531    if (this.abortMonitor == null) {
2532      this.abortMonitor = new Timer("Abort regionserver monitor", true);
2533      TimerTask abortTimeoutTask = null;
2534      try {
2535        Constructor<? extends TimerTask> timerTaskCtor =
2536          Class.forName(conf.get(ABORT_TIMEOUT_TASK, SystemExitWhenAbortTimeout.class.getName()))
2537            .asSubclass(TimerTask.class).getDeclaredConstructor();
2538        timerTaskCtor.setAccessible(true);
2539        abortTimeoutTask = timerTaskCtor.newInstance();
2540      } catch (Exception e) {
2541        LOG.warn("Initialize abort timeout task failed", e);
2542      }
2543      if (abortTimeoutTask != null) {
2544        abortMonitor.schedule(abortTimeoutTask, conf.getLong(ABORT_TIMEOUT, DEFAULT_ABORT_TIMEOUT));
2545      }
2546    }
2547  }
2548
2549  /**
2550   * Wait on all threads to finish. Presumption is that all closes and stops have already been
2551   * called.
2552   */
2553  protected void stopServiceThreads() {
2554    // clean up the scheduled chores
2555    stopChoreService();
2556    if (bootstrapNodeManager != null) {
2557      bootstrapNodeManager.stop();
2558    }
2559    if (this.cacheFlusher != null) {
2560      this.cacheFlusher.shutdown();
2561    }
2562    if (this.walRoller != null) {
2563      this.walRoller.close();
2564    }
2565    if (this.compactSplitThread != null) {
2566      this.compactSplitThread.join();
2567    }
2568    stopExecutorService();
2569    if (sameReplicationSourceAndSink && this.replicationSourceHandler != null) {
2570      this.replicationSourceHandler.stopReplicationService();
2571    } else {
2572      if (this.replicationSourceHandler != null) {
2573        this.replicationSourceHandler.stopReplicationService();
2574      }
2575      if (this.replicationSinkHandler != null) {
2576        this.replicationSinkHandler.stopReplicationService();
2577      }
2578    }
2579  }
2580
2581  /** Returns Return the object that implements the replication source executorService. */
2582  @Override
2583  public ReplicationSourceService getReplicationSourceService() {
2584    return replicationSourceHandler;
2585  }
2586
2587  /** Returns Return the object that implements the replication sink executorService. */
2588  public ReplicationSinkService getReplicationSinkService() {
2589    return replicationSinkHandler;
2590  }
2591
2592  /**
2593   * Get the current master from ZooKeeper and open the RPC connection to it. To get a fresh
2594   * connection, the current rssStub must be null. Method will block until a master is available.
2595   * You can break from this block by requesting the server stop.
2596   * @return master + port, or null if server has been stopped
2597   */
2598  private synchronized ServerName createRegionServerStatusStub() {
2599    // Create RS stub without refreshing the master node from ZK, use cached data
2600    return createRegionServerStatusStub(false);
2601  }
2602
2603  /**
2604   * Get the current master from ZooKeeper and open the RPC connection to it. To get a fresh
2605   * connection, the current rssStub must be null. Method will block until a master is available.
2606   * You can break from this block by requesting the server stop.
2607   * @param refresh If true then master address will be read from ZK, otherwise use cached data
2608   * @return master + port, or null if server has been stopped
2609   */
2610  @InterfaceAudience.Private
2611  protected synchronized ServerName createRegionServerStatusStub(boolean refresh) {
2612    if (rssStub != null) {
2613      return masterAddressTracker.getMasterAddress();
2614    }
2615    ServerName sn = null;
2616    long previousLogTime = 0;
2617    RegionServerStatusService.BlockingInterface intRssStub = null;
2618    LockService.BlockingInterface intLockStub = null;
2619    boolean interrupted = false;
2620    try {
2621      while (keepLooping()) {
2622        sn = this.masterAddressTracker.getMasterAddress(refresh);
2623        if (sn == null) {
2624          if (!keepLooping()) {
2625            // give up with no connection.
2626            LOG.debug("No master found and cluster is stopped; bailing out");
2627            return null;
2628          }
2629          if (EnvironmentEdgeManager.currentTime() > (previousLogTime + 1000)) {
2630            LOG.debug("No master found; retry");
2631            previousLogTime = EnvironmentEdgeManager.currentTime();
2632          }
2633          refresh = true; // let's try pull it from ZK directly
2634          if (sleepInterrupted(200)) {
2635            interrupted = true;
2636          }
2637          continue;
2638        }
2639        try {
2640          BlockingRpcChannel channel = this.rpcClient.createBlockingRpcChannel(sn,
2641            userProvider.getCurrent(), shortOperationTimeout);
2642          intRssStub = RegionServerStatusService.newBlockingStub(channel);
2643          intLockStub = LockService.newBlockingStub(channel);
2644          break;
2645        } catch (IOException e) {
2646          if (EnvironmentEdgeManager.currentTime() > (previousLogTime + 1000)) {
2647            e = e instanceof RemoteException ? ((RemoteException) e).unwrapRemoteException() : e;
2648            if (e instanceof ServerNotRunningYetException) {
2649              LOG.info("Master isn't available yet, retrying");
2650            } else {
2651              LOG.warn("Unable to connect to master. Retrying. Error was:", e);
2652            }
2653            previousLogTime = EnvironmentEdgeManager.currentTime();
2654          }
2655          if (sleepInterrupted(200)) {
2656            interrupted = true;
2657          }
2658        }
2659      }
2660    } finally {
2661      if (interrupted) {
2662        Thread.currentThread().interrupt();
2663      }
2664    }
2665    this.rssStub = intRssStub;
2666    this.lockStub = intLockStub;
2667    return sn;
2668  }
2669
2670  /**
2671   * @return True if we should break loop because cluster is going down or this server has been
2672   *         stopped or hdfs has gone bad.
2673   */
2674  private boolean keepLooping() {
2675    return !this.stopped && isClusterUp();
2676  }
2677
2678  /*
2679   * Let the master know we're here Run initialization using parameters passed us by the master.
2680   * @return A Map of key/value configurations we got from the Master else null if we failed to
2681   * register.
2682   */
2683  private RegionServerStartupResponse reportForDuty() throws IOException {
2684    if (this.masterless) {
2685      return RegionServerStartupResponse.getDefaultInstance();
2686    }
2687    ServerName masterServerName = createRegionServerStatusStub(true);
2688    RegionServerStatusService.BlockingInterface rss = rssStub;
2689    if (masterServerName == null || rss == null) {
2690      return null;
2691    }
2692    RegionServerStartupResponse result = null;
2693    try {
2694      rpcServices.requestCount.reset();
2695      rpcServices.rpcGetRequestCount.reset();
2696      rpcServices.rpcScanRequestCount.reset();
2697      rpcServices.rpcFullScanRequestCount.reset();
2698      rpcServices.rpcMultiRequestCount.reset();
2699      rpcServices.rpcMutateRequestCount.reset();
2700      LOG.info("reportForDuty to master=" + masterServerName + " with port="
2701        + rpcServices.getSocketAddress().getPort() + ", startcode=" + this.startcode);
2702      long now = EnvironmentEdgeManager.currentTime();
2703      int port = rpcServices.getSocketAddress().getPort();
2704      RegionServerStartupRequest.Builder request = RegionServerStartupRequest.newBuilder();
2705      if (!StringUtils.isBlank(useThisHostnameInstead)) {
2706        request.setUseThisHostnameInstead(useThisHostnameInstead);
2707      }
2708      request.setPort(port);
2709      request.setServerStartCode(this.startcode);
2710      request.setServerCurrentTime(now);
2711      result = rss.regionServerStartup(null, request.build());
2712    } catch (ServiceException se) {
2713      IOException ioe = ProtobufUtil.getRemoteException(se);
2714      if (ioe instanceof ClockOutOfSyncException) {
2715        LOG.error(HBaseMarkers.FATAL, "Master rejected startup because clock is out of sync", ioe);
2716        // Re-throw IOE will cause RS to abort
2717        throw ioe;
2718      } else if (ioe instanceof DecommissionedHostRejectedException) {
2719        LOG.error(HBaseMarkers.FATAL,
2720          "Master rejected startup because the host is considered decommissioned", ioe);
2721        // Re-throw IOE will cause RS to abort
2722        throw ioe;
2723      } else if (ioe instanceof ServerNotRunningYetException) {
2724        LOG.debug("Master is not running yet");
2725      } else {
2726        LOG.warn("error telling master we are up", se);
2727      }
2728      rssStub = null;
2729    }
2730    return result;
2731  }
2732
2733  @Override
2734  public RegionStoreSequenceIds getLastSequenceId(byte[] encodedRegionName) {
2735    try {
2736      GetLastFlushedSequenceIdRequest req =
2737        RequestConverter.buildGetLastFlushedSequenceIdRequest(encodedRegionName);
2738      RegionServerStatusService.BlockingInterface rss = rssStub;
2739      if (rss == null) { // Try to connect one more time
2740        createRegionServerStatusStub();
2741        rss = rssStub;
2742        if (rss == null) {
2743          // Still no luck, we tried
2744          LOG.warn("Unable to connect to the master to check " + "the last flushed sequence id");
2745          return RegionStoreSequenceIds.newBuilder().setLastFlushedSequenceId(HConstants.NO_SEQNUM)
2746            .build();
2747        }
2748      }
2749      GetLastFlushedSequenceIdResponse resp = rss.getLastFlushedSequenceId(null, req);
2750      return RegionStoreSequenceIds.newBuilder()
2751        .setLastFlushedSequenceId(resp.getLastFlushedSequenceId())
2752        .addAllStoreSequenceId(resp.getStoreLastFlushedSequenceIdList()).build();
2753    } catch (ServiceException e) {
2754      LOG.warn("Unable to connect to the master to check the last flushed sequence id", e);
2755      return RegionStoreSequenceIds.newBuilder().setLastFlushedSequenceId(HConstants.NO_SEQNUM)
2756        .build();
2757    }
2758  }
2759
2760  /**
2761   * Close meta region if we carry it
2762   * @param abort Whether we're running an abort.
2763   */
2764  private void closeMetaTableRegions(final boolean abort) {
2765    HRegion meta = null;
2766    this.onlineRegionsLock.writeLock().lock();
2767    try {
2768      for (Map.Entry<String, HRegion> e : onlineRegions.entrySet()) {
2769        RegionInfo hri = e.getValue().getRegionInfo();
2770        if (hri.isMetaRegion()) {
2771          meta = e.getValue();
2772        }
2773        if (meta != null) {
2774          break;
2775        }
2776      }
2777    } finally {
2778      this.onlineRegionsLock.writeLock().unlock();
2779    }
2780    if (meta != null) {
2781      closeRegionIgnoreErrors(meta.getRegionInfo(), abort);
2782    }
2783  }
2784
2785  /**
2786   * Schedule closes on all user regions. Should be safe calling multiple times because it wont'
2787   * close regions that are already closed or that are closing.
2788   * @param abort Whether we're running an abort.
2789   */
2790  private void closeUserRegions(final boolean abort) {
2791    this.onlineRegionsLock.writeLock().lock();
2792    try {
2793      for (Map.Entry<String, HRegion> e : this.onlineRegions.entrySet()) {
2794        HRegion r = e.getValue();
2795        if (!r.getRegionInfo().isMetaRegion() && r.isAvailable()) {
2796          // Don't update zk with this close transition; pass false.
2797          closeRegionIgnoreErrors(r.getRegionInfo(), abort);
2798        }
2799      }
2800    } finally {
2801      this.onlineRegionsLock.writeLock().unlock();
2802    }
2803  }
2804
2805  protected Map<String, HRegion> getOnlineRegions() {
2806    return this.onlineRegions;
2807  }
2808
2809  public int getNumberOfOnlineRegions() {
2810    return this.onlineRegions.size();
2811  }
2812
2813  /**
2814   * For tests, web ui and metrics. This method will only work if HRegionServer is in the same JVM
2815   * as client; HRegion cannot be serialized to cross an rpc.
2816   */
2817  public Collection<HRegion> getOnlineRegionsLocalContext() {
2818    Collection<HRegion> regions = this.onlineRegions.values();
2819    return Collections.unmodifiableCollection(regions);
2820  }
2821
2822  @Override
2823  public void addRegion(HRegion region) {
2824    this.onlineRegions.put(region.getRegionInfo().getEncodedName(), region);
2825    configurationManager.registerObserver(region);
2826  }
2827
2828  private void addRegion(SortedMap<Long, Collection<HRegion>> sortedRegions, HRegion region,
2829    long size) {
2830    if (!sortedRegions.containsKey(size)) {
2831      sortedRegions.put(size, new ArrayList<>());
2832    }
2833    sortedRegions.get(size).add(region);
2834  }
2835
2836  /**
2837   * @return A new Map of online regions sorted by region off-heap size with the first entry being
2838   *         the biggest.
2839   */
2840  SortedMap<Long, Collection<HRegion>> getCopyOfOnlineRegionsSortedByOffHeapSize() {
2841    // we'll sort the regions in reverse
2842    SortedMap<Long, Collection<HRegion>> sortedRegions = new TreeMap<>(Comparator.reverseOrder());
2843    // Copy over all regions. Regions are sorted by size with biggest first.
2844    for (HRegion region : this.onlineRegions.values()) {
2845      addRegion(sortedRegions, region, region.getMemStoreOffHeapSize());
2846    }
2847    return sortedRegions;
2848  }
2849
2850  /**
2851   * @return A new Map of online regions sorted by region heap size with the first entry being the
2852   *         biggest.
2853   */
2854  SortedMap<Long, Collection<HRegion>> getCopyOfOnlineRegionsSortedByOnHeapSize() {
2855    // we'll sort the regions in reverse
2856    SortedMap<Long, Collection<HRegion>> sortedRegions = new TreeMap<>(Comparator.reverseOrder());
2857    // Copy over all regions. Regions are sorted by size with biggest first.
2858    for (HRegion region : this.onlineRegions.values()) {
2859      addRegion(sortedRegions, region, region.getMemStoreHeapSize());
2860    }
2861    return sortedRegions;
2862  }
2863
2864  /** Returns reference to FlushRequester */
2865  @Override
2866  public FlushRequester getFlushRequester() {
2867    return this.cacheFlusher;
2868  }
2869
2870  @Override
2871  public CompactionRequester getCompactionRequestor() {
2872    return this.compactSplitThread;
2873  }
2874
2875  @Override
2876  public LeaseManager getLeaseManager() {
2877    return leaseManager;
2878  }
2879
2880  /** Returns {@code true} when the data file system is available, {@code false} otherwise. */
2881  boolean isDataFileSystemOk() {
2882    return this.dataFsOk;
2883  }
2884
2885  public RegionServerCoprocessorHost getRegionServerCoprocessorHost() {
2886    return this.rsHost;
2887  }
2888
2889  @Override
2890  public ConcurrentMap<byte[], Boolean> getRegionsInTransitionInRS() {
2891    return this.regionsInTransitionInRS;
2892  }
2893
2894  @Override
2895  public RegionServerRpcQuotaManager getRegionServerRpcQuotaManager() {
2896    return rsQuotaManager;
2897  }
2898
2899  //
2900  // Main program and support routines
2901  //
2902  /**
2903   * Load the replication executorService objects, if any
2904   */
2905  private static void createNewReplicationInstance(Configuration conf, HRegionServer server,
2906    FileSystem walFs, Path walDir, Path oldWALDir, WALFactory walFactory) throws IOException {
2907    // read in the name of the source replication class from the config file.
2908    String sourceClassname = conf.get(HConstants.REPLICATION_SOURCE_SERVICE_CLASSNAME,
2909      HConstants.REPLICATION_SERVICE_CLASSNAME_DEFAULT);
2910
2911    // read in the name of the sink replication class from the config file.
2912    String sinkClassname = conf.get(HConstants.REPLICATION_SINK_SERVICE_CLASSNAME,
2913      HConstants.REPLICATION_SINK_SERVICE_CLASSNAME_DEFAULT);
2914
2915    // If both the sink and the source class names are the same, then instantiate
2916    // only one object.
2917    if (sourceClassname.equals(sinkClassname)) {
2918      server.replicationSourceHandler = newReplicationInstance(sourceClassname,
2919        ReplicationSourceService.class, conf, server, walFs, walDir, oldWALDir, walFactory);
2920      server.replicationSinkHandler = (ReplicationSinkService) server.replicationSourceHandler;
2921      server.sameReplicationSourceAndSink = true;
2922    } else {
2923      server.replicationSourceHandler = newReplicationInstance(sourceClassname,
2924        ReplicationSourceService.class, conf, server, walFs, walDir, oldWALDir, walFactory);
2925      server.replicationSinkHandler = newReplicationInstance(sinkClassname,
2926        ReplicationSinkService.class, conf, server, walFs, walDir, oldWALDir, walFactory);
2927      server.sameReplicationSourceAndSink = false;
2928    }
2929  }
2930
2931  private static <T extends ReplicationService> T newReplicationInstance(String classname,
2932    Class<T> xface, Configuration conf, HRegionServer server, FileSystem walFs, Path logDir,
2933    Path oldLogDir, WALFactory walFactory) throws IOException {
2934    final Class<? extends T> clazz;
2935    try {
2936      ClassLoader classLoader = Thread.currentThread().getContextClassLoader();
2937      clazz = Class.forName(classname, true, classLoader).asSubclass(xface);
2938    } catch (java.lang.ClassNotFoundException nfe) {
2939      throw new IOException("Could not find class for " + classname);
2940    }
2941    T service = ReflectionUtils.newInstance(clazz, conf);
2942    service.initialize(server, walFs, logDir, oldLogDir, walFactory);
2943    return service;
2944  }
2945
2946  public Map<String, ReplicationStatus> getWalGroupsReplicationStatus() {
2947    Map<String, ReplicationStatus> walGroupsReplicationStatus = new TreeMap<>();
2948    if (!this.isOnline()) {
2949      return walGroupsReplicationStatus;
2950    }
2951    List<ReplicationSourceInterface> allSources = new ArrayList<>();
2952    allSources.addAll(replicationSourceHandler.getReplicationManager().getSources());
2953    allSources.addAll(replicationSourceHandler.getReplicationManager().getOldSources());
2954    for (ReplicationSourceInterface source : allSources) {
2955      walGroupsReplicationStatus.putAll(source.getWalGroupStatus());
2956    }
2957    return walGroupsReplicationStatus;
2958  }
2959
2960  /**
2961   * Utility for constructing an instance of the passed HRegionServer class.
2962   */
2963  static HRegionServer constructRegionServer(final Class<? extends HRegionServer> regionServerClass,
2964    final Configuration conf) {
2965    try {
2966      Constructor<? extends HRegionServer> c =
2967        regionServerClass.getConstructor(Configuration.class);
2968      return c.newInstance(conf);
2969    } catch (Exception e) {
2970      throw new RuntimeException(
2971        "Failed construction of " + "Regionserver: " + regionServerClass.toString(), e);
2972    }
2973  }
2974
2975  /**
2976   * @see org.apache.hadoop.hbase.regionserver.HRegionServerCommandLine
2977   */
2978  public static void main(String[] args) {
2979    LOG.info("STARTING executorService " + HRegionServer.class.getSimpleName());
2980    VersionInfo.logVersion();
2981    Configuration conf = HBaseConfiguration.create();
2982    @SuppressWarnings("unchecked")
2983    Class<? extends HRegionServer> regionServerClass = (Class<? extends HRegionServer>) conf
2984      .getClass(HConstants.REGION_SERVER_IMPL, HRegionServer.class);
2985
2986    new HRegionServerCommandLine(regionServerClass).doMain(args);
2987  }
2988
2989  /**
2990   * Gets the online regions of the specified table. This method looks at the in-memory
2991   * onlineRegions. It does not go to <code>hbase:meta</code>. Only returns <em>online</em> regions.
2992   * If a region on this table has been closed during a disable, etc., it will not be included in
2993   * the returned list. So, the returned list may not necessarily be ALL regions in this table, its
2994   * all the ONLINE regions in the table.
2995   * @param tableName table to limit the scope of the query
2996   * @return Online regions from <code>tableName</code>
2997   */
2998  @Override
2999  public List<HRegion> getRegions(TableName tableName) {
3000    List<HRegion> tableRegions = new ArrayList<>();
3001    synchronized (this.onlineRegions) {
3002      for (HRegion region : this.onlineRegions.values()) {
3003        RegionInfo regionInfo = region.getRegionInfo();
3004        if (regionInfo.getTable().equals(tableName)) {
3005          tableRegions.add(region);
3006        }
3007      }
3008    }
3009    return tableRegions;
3010  }
3011
3012  @Override
3013  public List<HRegion> getRegions() {
3014    List<HRegion> allRegions;
3015    synchronized (this.onlineRegions) {
3016      // Return a clone copy of the onlineRegions
3017      allRegions = new ArrayList<>(onlineRegions.values());
3018    }
3019    return allRegions;
3020  }
3021
3022  /**
3023   * Gets the online tables in this RS. This method looks at the in-memory onlineRegions.
3024   * @return all the online tables in this RS
3025   */
3026  public Set<TableName> getOnlineTables() {
3027    Set<TableName> tables = new HashSet<>();
3028    synchronized (this.onlineRegions) {
3029      for (Region region : this.onlineRegions.values()) {
3030        tables.add(region.getTableDescriptor().getTableName());
3031      }
3032    }
3033    return tables;
3034  }
3035
3036  public String[] getRegionServerCoprocessors() {
3037    TreeSet<String> coprocessors = new TreeSet<>();
3038    try {
3039      coprocessors.addAll(getWAL(null).getCoprocessorHost().getCoprocessors());
3040    } catch (IOException exception) {
3041      LOG.warn("Exception attempting to fetch wal coprocessor information for the common wal; "
3042        + "skipping.");
3043      LOG.debug("Exception details for failure to fetch wal coprocessor information.", exception);
3044    }
3045    Collection<HRegion> regions = getOnlineRegionsLocalContext();
3046    for (HRegion region : regions) {
3047      coprocessors.addAll(region.getCoprocessorHost().getCoprocessors());
3048      try {
3049        coprocessors.addAll(getWAL(region.getRegionInfo()).getCoprocessorHost().getCoprocessors());
3050      } catch (IOException exception) {
3051        LOG.warn("Exception attempting to fetch wal coprocessor information for region " + region
3052          + "; skipping.");
3053        LOG.debug("Exception details for failure to fetch wal coprocessor information.", exception);
3054      }
3055    }
3056    coprocessors.addAll(rsHost.getCoprocessors());
3057    return coprocessors.toArray(new String[0]);
3058  }
3059
3060  /**
3061   * Try to close the region, logs a warning on failure but continues.
3062   * @param region Region to close
3063   */
3064  private void closeRegionIgnoreErrors(RegionInfo region, final boolean abort) {
3065    try {
3066      if (!closeRegion(region.getEncodedName(), abort, null)) {
3067        LOG
3068          .warn("Failed to close " + region.getRegionNameAsString() + " - ignoring and continuing");
3069      }
3070    } catch (IOException e) {
3071      LOG.warn("Failed to close " + region.getRegionNameAsString() + " - ignoring and continuing",
3072        e);
3073    }
3074  }
3075
3076  /**
3077   * Close asynchronously a region, can be called from the master or internally by the regionserver
3078   * when stopping. If called from the master, the region will update the status.
3079   * <p>
3080   * If an opening was in progress, this method will cancel it, but will not start a new close. The
3081   * coprocessors are not called in this case. A NotServingRegionException exception is thrown.
3082   * </p>
3083   * <p>
3084   * If a close was in progress, this new request will be ignored, and an exception thrown.
3085   * </p>
3086   * <p>
3087   * Provides additional flag to indicate if this region blocks should be evicted from the cache.
3088   * </p>
3089   * @param encodedName Region to close
3090   * @param abort       True if we are aborting
3091   * @param destination Where the Region is being moved too... maybe null if unknown.
3092   * @return True if closed a region.
3093   * @throws NotServingRegionException if the region is not online
3094   */
3095  protected boolean closeRegion(String encodedName, final boolean abort,
3096    final ServerName destination) throws NotServingRegionException {
3097    // Check for permissions to close.
3098    HRegion actualRegion = this.getRegion(encodedName);
3099    // Can be null if we're calling close on a region that's not online
3100    if ((actualRegion != null) && (actualRegion.getCoprocessorHost() != null)) {
3101      try {
3102        actualRegion.getCoprocessorHost().preClose(false);
3103      } catch (IOException exp) {
3104        LOG.warn("Unable to close region: the coprocessor launched an error ", exp);
3105        return false;
3106      }
3107    }
3108
3109    // previous can come back 'null' if not in map.
3110    final Boolean previous =
3111      this.regionsInTransitionInRS.putIfAbsent(Bytes.toBytes(encodedName), Boolean.FALSE);
3112
3113    if (Boolean.TRUE.equals(previous)) {
3114      LOG.info("Received CLOSE for the region:" + encodedName + " , which we are already "
3115        + "trying to OPEN. Cancelling OPENING.");
3116      if (!regionsInTransitionInRS.replace(Bytes.toBytes(encodedName), previous, Boolean.FALSE)) {
3117        // The replace failed. That should be an exceptional case, but theoretically it can happen.
3118        // We're going to try to do a standard close then.
3119        LOG.warn("The opening for region " + encodedName + " was done before we could cancel it."
3120          + " Doing a standard close now");
3121        return closeRegion(encodedName, abort, destination);
3122      }
3123      // Let's get the region from the online region list again
3124      actualRegion = this.getRegion(encodedName);
3125      if (actualRegion == null) { // If already online, we still need to close it.
3126        LOG.info("The opening previously in progress has been cancelled by a CLOSE request.");
3127        // The master deletes the znode when it receives this exception.
3128        throw new NotServingRegionException(
3129          "The region " + encodedName + " was opening but not yet served. Opening is cancelled.");
3130      }
3131    } else if (previous == null) {
3132      LOG.info("Received CLOSE for {}", encodedName);
3133    } else if (Boolean.FALSE.equals(previous)) {
3134      LOG.info("Received CLOSE for the region: " + encodedName
3135        + ", which we are already trying to CLOSE, but not completed yet");
3136      return true;
3137    }
3138
3139    if (actualRegion == null) {
3140      LOG.debug("Received CLOSE for a region which is not online, and we're not opening.");
3141      this.regionsInTransitionInRS.remove(Bytes.toBytes(encodedName));
3142      // The master deletes the znode when it receives this exception.
3143      throw new NotServingRegionException(
3144        "The region " + encodedName + " is not online, and is not opening.");
3145    }
3146
3147    CloseRegionHandler crh;
3148    final RegionInfo hri = actualRegion.getRegionInfo();
3149    if (hri.isMetaRegion()) {
3150      crh = new CloseMetaHandler(this, this, hri, abort);
3151    } else {
3152      crh = new CloseRegionHandler(this, this, hri, abort, destination);
3153    }
3154    this.executorService.submit(crh);
3155    return true;
3156  }
3157
3158  /**
3159   * @return HRegion for the passed binary <code>regionName</code> or null if named region is not
3160   *         member of the online regions.
3161   */
3162  public HRegion getOnlineRegion(final byte[] regionName) {
3163    String encodedRegionName = RegionInfo.encodeRegionName(regionName);
3164    return this.onlineRegions.get(encodedRegionName);
3165  }
3166
3167  @Override
3168  public HRegion getRegion(final String encodedRegionName) {
3169    return this.onlineRegions.get(encodedRegionName);
3170  }
3171
3172  @Override
3173  public boolean removeRegion(final HRegion r, ServerName destination) {
3174    HRegion toReturn = this.onlineRegions.remove(r.getRegionInfo().getEncodedName());
3175    if (DataTieringManager.getInstance() != null) {
3176      DataTieringManager.getInstance().getRegionColdDataSize()
3177        .remove(r.getRegionInfo().getEncodedName());
3178    }
3179    metricsRegionServerImpl.requestsCountCache.remove(r.getRegionInfo().getEncodedName());
3180    if (destination != null) {
3181      long closeSeqNum = r.getMaxFlushedSeqId();
3182      if (closeSeqNum == HConstants.NO_SEQNUM) {
3183        // No edits in WAL for this region; get the sequence number when the region was opened.
3184        closeSeqNum = r.getOpenSeqNum();
3185        if (closeSeqNum == HConstants.NO_SEQNUM) {
3186          closeSeqNum = 0;
3187        }
3188      }
3189      boolean selfMove = ServerName.isSameAddress(destination, this.getServerName());
3190      addToMovedRegions(r.getRegionInfo().getEncodedName(), destination, closeSeqNum, selfMove);
3191      if (selfMove) {
3192        this.regionServerAccounting.getRetainedRegionRWRequestsCnt().put(
3193          r.getRegionInfo().getEncodedName(),
3194          new Pair<>(r.getReadRequestsCount(), r.getWriteRequestsCount()));
3195      }
3196    }
3197    this.regionFavoredNodesMap.remove(r.getRegionInfo().getEncodedName());
3198    configurationManager.deregisterObserver(r);
3199    return toReturn != null;
3200  }
3201
3202  /**
3203   * Protected Utility method for safely obtaining an HRegion handle.
3204   * @param regionName Name of online {@link HRegion} to return
3205   * @return {@link HRegion} for <code>regionName</code>
3206   */
3207  protected HRegion getRegion(final byte[] regionName) throws NotServingRegionException {
3208    String encodedRegionName = RegionInfo.encodeRegionName(regionName);
3209    return getRegionByEncodedName(regionName, encodedRegionName);
3210  }
3211
3212  public HRegion getRegionByEncodedName(String encodedRegionName) throws NotServingRegionException {
3213    return getRegionByEncodedName(null, encodedRegionName);
3214  }
3215
3216  private HRegion getRegionByEncodedName(byte[] regionName, String encodedRegionName)
3217    throws NotServingRegionException {
3218    HRegion region = this.onlineRegions.get(encodedRegionName);
3219    if (region == null) {
3220      MovedRegionInfo moveInfo = getMovedRegion(encodedRegionName);
3221      if (moveInfo != null) {
3222        throw new RegionMovedException(moveInfo.getServerName(), moveInfo.getSeqNum());
3223      }
3224      Boolean isOpening = this.regionsInTransitionInRS.get(Bytes.toBytes(encodedRegionName));
3225      String regionNameStr =
3226        regionName == null ? encodedRegionName : Bytes.toStringBinary(regionName);
3227      if (isOpening != null && isOpening) {
3228        throw new RegionOpeningException(
3229          "Region " + regionNameStr + " is opening on " + this.serverName);
3230      }
3231      throw new NotServingRegionException(
3232        "" + regionNameStr + " is not online on " + this.serverName);
3233    }
3234    return region;
3235  }
3236
3237  /**
3238   * Cleanup after Throwable caught invoking method. Converts <code>t</code> to IOE if it isn't
3239   * already.
3240   * @param t   Throwable
3241   * @param msg Message to log in error. Can be null.
3242   * @return Throwable converted to an IOE; methods can only let out IOEs.
3243   */
3244  private Throwable cleanup(final Throwable t, final String msg) {
3245    // Don't log as error if NSRE; NSRE is 'normal' operation.
3246    if (t instanceof NotServingRegionException) {
3247      LOG.debug("NotServingRegionException; " + t.getMessage());
3248      return t;
3249    }
3250    Throwable e = t instanceof RemoteException ? ((RemoteException) t).unwrapRemoteException() : t;
3251    if (msg == null) {
3252      LOG.error("", e);
3253    } else {
3254      LOG.error(msg, e);
3255    }
3256    if (!rpcServices.checkOOME(t)) {
3257      checkFileSystem();
3258    }
3259    return t;
3260  }
3261
3262  /**
3263   * @param msg Message to put in new IOE if passed <code>t</code> is not an IOE
3264   * @return Make <code>t</code> an IOE if it isn't already.
3265   */
3266  private IOException convertThrowableToIOE(final Throwable t, final String msg) {
3267    return (t instanceof IOException ? (IOException) t
3268      : msg == null || msg.length() == 0 ? new IOException(t)
3269      : new IOException(msg, t));
3270  }
3271
3272  /**
3273   * Checks to see if the file system is still accessible. If not, sets abortRequested and
3274   * stopRequested
3275   * @return false if file system is not available
3276   */
3277  boolean checkFileSystem() {
3278    if (this.dataFsOk && this.dataFs != null) {
3279      try {
3280        FSUtils.checkFileSystemAvailable(this.dataFs);
3281      } catch (IOException e) {
3282        abort("File System not available", e);
3283        this.dataFsOk = false;
3284      }
3285    }
3286    return this.dataFsOk;
3287  }
3288
3289  @Override
3290  public void updateRegionFavoredNodesMapping(String encodedRegionName,
3291    List<org.apache.hadoop.hbase.shaded.protobuf.generated.HBaseProtos.ServerName> favoredNodes) {
3292    Address[] addr = new Address[favoredNodes.size()];
3293    // Refer to the comment on the declaration of regionFavoredNodesMap on why
3294    // it is a map of region name to Address[]
3295    for (int i = 0; i < favoredNodes.size(); i++) {
3296      addr[i] = Address.fromParts(favoredNodes.get(i).getHostName(), favoredNodes.get(i).getPort());
3297    }
3298    regionFavoredNodesMap.put(encodedRegionName, addr);
3299  }
3300
3301  /**
3302   * Return the favored nodes for a region given its encoded name. Look at the comment around
3303   * {@link #regionFavoredNodesMap} on why we convert to InetSocketAddress[] here.
3304   * @param encodedRegionName the encoded region name.
3305   * @return array of favored locations
3306   */
3307  @Override
3308  public InetSocketAddress[] getFavoredNodesForRegion(String encodedRegionName) {
3309    return Address.toSocketAddress(regionFavoredNodesMap.get(encodedRegionName));
3310  }
3311
3312  @Override
3313  public ServerNonceManager getNonceManager() {
3314    return this.nonceManager;
3315  }
3316
3317  private static class MovedRegionInfo {
3318    private final ServerName serverName;
3319    private final long seqNum;
3320
3321    MovedRegionInfo(ServerName serverName, long closeSeqNum) {
3322      this.serverName = serverName;
3323      this.seqNum = closeSeqNum;
3324    }
3325
3326    public ServerName getServerName() {
3327      return serverName;
3328    }
3329
3330    public long getSeqNum() {
3331      return seqNum;
3332    }
3333  }
3334
3335  /**
3336   * We need a timeout. If not there is a risk of giving a wrong information: this would double the
3337   * number of network calls instead of reducing them.
3338   */
3339  private static final int TIMEOUT_REGION_MOVED = (2 * 60 * 1000);
3340
3341  private void addToMovedRegions(String encodedName, ServerName destination, long closeSeqNum,
3342    boolean selfMove) {
3343    if (selfMove) {
3344      LOG.warn("Not adding moved region record: " + encodedName + " to self.");
3345      return;
3346    }
3347    LOG.info("Adding " + encodedName + " move to " + destination + " record at close sequenceid="
3348      + closeSeqNum);
3349    movedRegionInfoCache.put(encodedName, new MovedRegionInfo(destination, closeSeqNum));
3350  }
3351
3352  // public for being called in tests
3353  @InterfaceAudience.Private
3354  public void removeFromMovedRegions(String encodedName) {
3355    movedRegionInfoCache.invalidate(encodedName);
3356  }
3357
3358  @InterfaceAudience.Private
3359  public MovedRegionInfo getMovedRegion(String encodedRegionName) {
3360    return movedRegionInfoCache.getIfPresent(encodedRegionName);
3361  }
3362
3363  @InterfaceAudience.Private
3364  public int movedRegionCacheExpiredTime() {
3365    return TIMEOUT_REGION_MOVED;
3366  }
3367
3368  private String getMyEphemeralNodePath() {
3369    return zooKeeper.getZNodePaths().getRsPath(serverName);
3370  }
3371
3372  private boolean isHealthCheckerConfigured() {
3373    String healthScriptLocation = this.conf.get(HConstants.HEALTH_SCRIPT_LOC);
3374    return org.apache.commons.lang3.StringUtils.isNotBlank(healthScriptLocation);
3375  }
3376
3377  /** Returns the underlying {@link CompactSplit} for the servers */
3378  public CompactSplit getCompactSplitThread() {
3379    return this.compactSplitThread;
3380  }
3381
3382  CoprocessorServiceResponse execRegionServerService(
3383    @SuppressWarnings("UnusedParameters") final RpcController controller,
3384    final CoprocessorServiceRequest serviceRequest) throws ServiceException {
3385    try {
3386      ServerRpcController serviceController = new ServerRpcController();
3387      CoprocessorServiceCall call = serviceRequest.getCall();
3388      String serviceName = call.getServiceName();
3389      Service service = coprocessorServiceHandlers.get(serviceName);
3390      if (service == null) {
3391        throw new UnknownProtocolException(null,
3392          "No registered coprocessor executorService found for " + serviceName);
3393      }
3394      ServiceDescriptor serviceDesc = service.getDescriptorForType();
3395
3396      String methodName = call.getMethodName();
3397      MethodDescriptor methodDesc = serviceDesc.findMethodByName(methodName);
3398      if (methodDesc == null) {
3399        throw new UnknownProtocolException(service.getClass(),
3400          "Unknown method " + methodName + " called on executorService " + serviceName);
3401      }
3402
3403      Message request = CoprocessorRpcUtils.getRequest(service, methodDesc, call.getRequest());
3404      final Message.Builder responseBuilder =
3405        service.getResponsePrototype(methodDesc).newBuilderForType();
3406      service.callMethod(methodDesc, serviceController, request, message -> {
3407        if (message != null) {
3408          responseBuilder.mergeFrom(message);
3409        }
3410      });
3411      IOException exception = CoprocessorRpcUtils.getControllerException(serviceController);
3412      if (exception != null) {
3413        throw exception;
3414      }
3415      return CoprocessorRpcUtils.getResponse(responseBuilder.build(), HConstants.EMPTY_BYTE_ARRAY);
3416    } catch (IOException ie) {
3417      throw new ServiceException(ie);
3418    }
3419  }
3420
3421  /**
3422   * May be null if this is a master which not carry table.
3423   * @return The block cache instance used by the regionserver.
3424   */
3425  @Override
3426  public Optional<BlockCache> getBlockCache() {
3427    return Optional.ofNullable(this.blockCache);
3428  }
3429
3430  /**
3431   * May be null if this is a master which not carry table.
3432   * @return The cache for mob files used by the regionserver.
3433   */
3434  @Override
3435  public Optional<MobFileCache> getMobFileCache() {
3436    return Optional.ofNullable(this.mobFileCache);
3437  }
3438
3439  CacheEvictionStats clearRegionBlockCache(Region region) {
3440    long evictedBlocks = 0;
3441
3442    for (Store store : region.getStores()) {
3443      for (StoreFile hFile : store.getStorefiles()) {
3444        evictedBlocks += blockCache.evictBlocksByHfileName(hFile.getPath().getName());
3445      }
3446    }
3447
3448    return CacheEvictionStats.builder().withEvictedBlocks(evictedBlocks).build();
3449  }
3450
3451  @Override
3452  public double getCompactionPressure() {
3453    double max = 0;
3454    for (Region region : onlineRegions.values()) {
3455      for (Store store : region.getStores()) {
3456        double normCount = store.getCompactionPressure();
3457        if (normCount > max) {
3458          max = normCount;
3459        }
3460      }
3461    }
3462    return max;
3463  }
3464
3465  @Override
3466  public HeapMemoryManager getHeapMemoryManager() {
3467    return hMemManager;
3468  }
3469
3470  public MemStoreFlusher getMemStoreFlusher() {
3471    return cacheFlusher;
3472  }
3473
3474  /**
3475   * For testing
3476   * @return whether all wal roll request finished for this regionserver
3477   */
3478  @InterfaceAudience.Private
3479  public boolean walRollRequestFinished() {
3480    return this.walRoller.walRollFinished();
3481  }
3482
3483  @Override
3484  public ThroughputController getFlushThroughputController() {
3485    return flushThroughputController;
3486  }
3487
3488  @Override
3489  public double getFlushPressure() {
3490    if (getRegionServerAccounting() == null || cacheFlusher == null) {
3491      // return 0 during RS initialization
3492      return 0.0;
3493    }
3494    return getRegionServerAccounting().getFlushPressure();
3495  }
3496
3497  /**
3498   * Dynamically updates HRegionServer's configuration. Since HRegionServer inherits from
3499   * {@link HBaseServerBase}, the {@code updatedConf} parameter references the same
3500   * {@link Configuration} object as HRegionServer's {@code this.conf} instance variable in a real
3501   * HBase deployment. This isn't necessarily the case in unit tests.
3502   * @param updatedConf the dynamically updated configuration
3503   */
3504  @Override
3505  public void onConfigurationChange(Configuration updatedConf) {
3506    ThroughputController old = this.flushThroughputController;
3507    if (old != null) {
3508      old.stop("configuration change");
3509    }
3510    this.flushThroughputController = FlushThroughputControllerFactory.create(this, updatedConf);
3511    try {
3512      Superusers.initialize(updatedConf);
3513    } catch (IOException e) {
3514      LOG.warn("Failed to initialize SuperUsers on reloading of the configuration");
3515    }
3516
3517    boolean originalIsReadOnlyEnabled = CoprocessorConfigurationUtil
3518      .areReadOnlyCoprocessorsLoaded(this.conf, CoprocessorHost.REGIONSERVER_COPROCESSOR_CONF_KEY);
3519    boolean newReadOnlyEnabled = ConfigurationUtil.isReadOnlyModeEnabledInConf(updatedConf);
3520
3521    // The updatedConf is potentially a shared Configuration object, so we do not want to directly
3522    // revert its read-only value if another active cluster already exists. For now, we reference
3523    // updatedConf and create a copy for modification below if necessary.
3524    Configuration confForCoprocessors = updatedConf;
3525
3526    if (originalIsReadOnlyEnabled && !newReadOnlyEnabled) {
3527      // Changing this cluster from a replica to an active cluster. There should not be another
3528      // active cluster already.
3529      ActiveClusterSuffix localSuffix =
3530        ActiveClusterSuffix.fromConfig(this.conf, new ClusterId(getClusterId()));
3531      if (
3532        AbstractReadOnlyController.isAnotherClusterActive(getFileSystem(), getDataRootDir(),
3533          localSuffix)
3534      ) {
3535        String activeClusterId =
3536          FSUtils.getClusterIdFromActiveClusterFile(getFileSystem(), getDataRootDir());
3537        // Revert read-only mode here
3538        confForCoprocessors = this.blockReadOnlyTransition(updatedConf, activeClusterId);
3539      }
3540    }
3541
3542    // In a real HBase deployment, confForCoprocessors may reference the same object as this.conf.
3543    // This is assuming confForCoprocessors still references updatedConf, as mentioned in a previous
3544    // comment. For unit tests, this Configuration object is not shared, so we need to make sure to
3545    // update the coprocessors specifically for this.conf.
3546    CoprocessorConfigurationUtil.maybeUpdateCoprocessors(confForCoprocessors, this.conf,
3547      originalIsReadOnlyEnabled, this.rsHost, CoprocessorHost.REGIONSERVER_COPROCESSOR_CONF_KEY,
3548      false, this.toString(), conf -> this.rsHost = new RegionServerCoprocessorHost(this, conf));
3549  }
3550
3551  @Override
3552  public MetricsRegionServer getMetrics() {
3553    return metricsRegionServer;
3554  }
3555
3556  @Override
3557  public SecureBulkLoadManager getSecureBulkLoadManager() {
3558    return this.secureBulkLoadManager;
3559  }
3560
3561  @Override
3562  public EntityLock regionLock(final List<RegionInfo> regionInfo, final String description,
3563    final Abortable abort) {
3564    final LockServiceClient client =
3565      new LockServiceClient(conf, lockStub, asyncClusterConnection.getNonceGenerator());
3566    return client.regionLock(regionInfo, description, abort);
3567  }
3568
3569  @Override
3570  public void unassign(byte[] regionName) throws IOException {
3571    FutureUtils.get(asyncClusterConnection.getAdmin().unassign(regionName, false));
3572  }
3573
3574  @Override
3575  public RegionServerSpaceQuotaManager getRegionServerSpaceQuotaManager() {
3576    return this.rsSpaceQuotaManager;
3577  }
3578
3579  @Override
3580  public boolean reportFileArchivalForQuotas(TableName tableName,
3581    Collection<Entry<String, Long>> archivedFiles) {
3582    if (TEST_SKIP_REPORTING_TRANSITION) {
3583      return false;
3584    }
3585    RegionServerStatusService.BlockingInterface rss = rssStub;
3586    if (rss == null || rsSpaceQuotaManager == null) {
3587      // the current server could be stopping.
3588      LOG.trace("Skipping file archival reporting to HMaster as stub is null");
3589      return false;
3590    }
3591    try {
3592      RegionServerStatusProtos.FileArchiveNotificationRequest request =
3593        rsSpaceQuotaManager.buildFileArchiveRequest(tableName, archivedFiles);
3594      rss.reportFileArchival(null, request);
3595    } catch (ServiceException se) {
3596      IOException ioe = ProtobufUtil.getRemoteException(se);
3597      if (ioe instanceof PleaseHoldException) {
3598        if (LOG.isTraceEnabled()) {
3599          LOG.trace("Failed to report file archival(s) to Master because it is initializing."
3600            + " This will be retried.", ioe);
3601        }
3602        // The Master is coming up. Will retry the report later. Avoid re-creating the stub.
3603        return false;
3604      }
3605      if (rssStub == rss) {
3606        rssStub = null;
3607      }
3608      // re-create the stub if we failed to report the archival
3609      createRegionServerStatusStub(true);
3610      LOG.debug("Failed to report file archival(s) to Master. This will be retried.", ioe);
3611      return false;
3612    }
3613    return true;
3614  }
3615
3616  void executeProcedure(long procId, long initiatingMasterActiveTime,
3617    RSProcedureCallable callable) {
3618    executorService
3619      .submit(new RSProcedureHandler(this, procId, initiatingMasterActiveTime, callable));
3620  }
3621
3622  public void remoteProcedureComplete(long procId, long initiatingMasterActiveTime, Throwable error,
3623    byte[] procResultData) {
3624    procedureResultReporter.complete(procId, initiatingMasterActiveTime, error, procResultData);
3625  }
3626
3627  void reportProcedureDone(ReportProcedureDoneRequest request) throws IOException {
3628    RegionServerStatusService.BlockingInterface rss;
3629    // TODO: juggling class state with an instance variable, outside of a synchronized block :'(
3630    for (;;) {
3631      rss = rssStub;
3632      if (rss != null) {
3633        break;
3634      }
3635      createRegionServerStatusStub();
3636    }
3637    try {
3638      rss.reportProcedureDone(null, request);
3639    } catch (ServiceException se) {
3640      if (rssStub == rss) {
3641        rssStub = null;
3642      }
3643      throw ProtobufUtil.getRemoteException(se);
3644    }
3645  }
3646
3647  /**
3648   * Will ignore the open/close region procedures which already submitted or executed. When master
3649   * had unfinished open/close region procedure and restarted, new active master may send duplicate
3650   * open/close region request to regionserver. The open/close request is submitted to a thread pool
3651   * and execute. So first need a cache for submitted open/close region procedures. After the
3652   * open/close region request executed and report region transition succeed, cache it in executed
3653   * region procedures cache. See {@link #finishRegionProcedure(long)}. After report region
3654   * transition succeed, master will not send the open/close region request to regionserver again.
3655   * And we thought that the ongoing duplicate open/close region request should not be delayed more
3656   * than 600 seconds. So the executed region procedures cache will expire after 600 seconds. See
3657   * HBASE-22404 for more details.
3658   * @param procId the id of the open/close region procedure
3659   * @return true if the procedure can be submitted.
3660   */
3661  boolean submitRegionProcedure(long procId) {
3662    if (procId == -1) {
3663      return true;
3664    }
3665    // Ignore the region procedures which already submitted.
3666    Long previous = submittedRegionProcedures.putIfAbsent(procId, procId);
3667    if (previous != null) {
3668      LOG.warn("Received procedure pid={}, which already submitted, just ignore it", procId);
3669      return false;
3670    }
3671    // Ignore the region procedures which already executed.
3672    if (executedRegionProcedures.getIfPresent(procId) != null) {
3673      LOG.warn("Received procedure pid={}, which already executed, just ignore it", procId);
3674      return false;
3675    }
3676    return true;
3677  }
3678
3679  /**
3680   * See {@link #submitRegionProcedure(long)}.
3681   * @param procId the id of the open/close region procedure
3682   */
3683  public void finishRegionProcedure(long procId) {
3684    executedRegionProcedures.put(procId, procId);
3685    submittedRegionProcedures.remove(procId);
3686  }
3687
3688  /**
3689   * Force to terminate region server when abort timeout.
3690   */
3691  private static class SystemExitWhenAbortTimeout extends TimerTask {
3692
3693    public SystemExitWhenAbortTimeout() {
3694    }
3695
3696    @Override
3697    public void run() {
3698      LOG.warn("Aborting region server timed out, terminating forcibly"
3699        + " and does not wait for any running shutdown hooks or finalizers to finish their work."
3700        + " Thread dump to stdout.");
3701      Threads.printThreadInfo(System.out, "Zombie HRegionServer");
3702      Runtime.getRuntime().halt(1);
3703    }
3704  }
3705
3706  @InterfaceAudience.Private
3707  public CompactedHFilesDischarger getCompactedHFilesDischarger() {
3708    return compactedFileDischarger;
3709  }
3710
3711  /**
3712   * Return pause time configured in {@link HConstants#HBASE_RPC_SHORTOPERATION_RETRY_PAUSE_TIME}}
3713   * @return pause time
3714   */
3715  @InterfaceAudience.Private
3716  public long getRetryPauseTime() {
3717    return this.retryPauseTime;
3718  }
3719
3720  @Override
3721  public Optional<ServerName> getActiveMaster() {
3722    return Optional.ofNullable(masterAddressTracker.getMasterAddress());
3723  }
3724
3725  @Override
3726  public List<ServerName> getBackupMasters() {
3727    return masterAddressTracker.getBackupMasters();
3728  }
3729
3730  @Override
3731  public Iterator<ServerName> getBootstrapNodes() {
3732    return bootstrapNodeManager.getBootstrapNodes().iterator();
3733  }
3734
3735  @Override
3736  public List<HRegionLocation> getMetaLocations() {
3737    return metaRegionLocationCache.getMetaRegionLocations();
3738  }
3739
3740  @Override
3741  protected NamedQueueRecorder createNamedQueueRecord() {
3742    return NamedQueueRecorder.getInstance(conf);
3743  }
3744
3745  @Override
3746  protected boolean clusterMode() {
3747    // this method will be called in the constructor of super class, so we can not return masterless
3748    // directly here, as it will always be false.
3749    return !conf.getBoolean(MASTERLESS_CONFIG_NAME, false);
3750  }
3751
3752  @InterfaceAudience.Private
3753  public BrokenStoreFileCleaner getBrokenStoreFileCleaner() {
3754    return brokenStoreFileCleaner;
3755  }
3756
3757  @InterfaceAudience.Private
3758  public RSMobFileCleanerChore getRSMobFileCleanerChore() {
3759    return rsMobFileCleanerChore;
3760  }
3761
3762  RSSnapshotVerifier getRsSnapshotVerifier() {
3763    return rsSnapshotVerifier;
3764  }
3765
3766  @Override
3767  protected void stopChores() {
3768    shutdownChore(nonceManagerChore);
3769    shutdownChore(compactionChecker);
3770    shutdownChore(compactedFileDischarger);
3771    shutdownChore(periodicFlusher);
3772    shutdownChore(healthCheckChore);
3773    shutdownChore(executorStatusChore);
3774    shutdownChore(storefileRefresher);
3775    shutdownChore(fsUtilizationChore);
3776    shutdownChore(namedQueueServiceChore);
3777    shutdownChore(brokenStoreFileCleaner);
3778    shutdownChore(rsMobFileCleanerChore);
3779    shutdownChore(replicationMarkerChore);
3780  }
3781
3782  @Override
3783  public RegionReplicationBufferManager getRegionReplicationBufferManager() {
3784    return regionReplicationBufferManager;
3785  }
3786}