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