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