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