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