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;
019
020import static org.apache.hadoop.hbase.ChoreService.CHORE_SERVICE_INITIAL_POOL_SIZE;
021import static org.apache.hadoop.hbase.ChoreService.DEFAULT_CHORE_SERVICE_INITIAL_POOL_SIZE;
022import static org.apache.hadoop.hbase.HConstants.DEFAULT_HBASE_SPLIT_COORDINATED_BY_ZK;
023import static org.apache.hadoop.hbase.HConstants.HBASE_SPLIT_WAL_COORDINATED_BY_ZK;
024
025import com.google.errorprone.annotations.RestrictedApi;
026import io.opentelemetry.api.trace.Span;
027import io.opentelemetry.api.trace.StatusCode;
028import io.opentelemetry.context.Scope;
029import java.io.IOException;
030import java.lang.management.MemoryType;
031import java.net.BindException;
032import java.net.InetAddress;
033import java.net.InetSocketAddress;
034import java.util.concurrent.atomic.AtomicBoolean;
035import java.util.concurrent.atomic.AtomicReference;
036import javax.servlet.http.HttpServlet;
037import org.apache.commons.lang3.StringUtils;
038import org.apache.commons.lang3.SystemUtils;
039import org.apache.hadoop.conf.Configuration;
040import org.apache.hadoop.fs.FileSystem;
041import org.apache.hadoop.fs.Path;
042import org.apache.hadoop.hbase.client.AsyncClusterConnection;
043import org.apache.hadoop.hbase.client.ClusterConnectionFactory;
044import org.apache.hadoop.hbase.client.Connection;
045import org.apache.hadoop.hbase.client.ConnectionFactory;
046import org.apache.hadoop.hbase.client.ConnectionRegistryEndpoint;
047import org.apache.hadoop.hbase.conf.ConfigurationManager;
048import org.apache.hadoop.hbase.conf.ConfigurationObserver;
049import org.apache.hadoop.hbase.coordination.ZkCoordinatedStateManager;
050import org.apache.hadoop.hbase.coprocessor.CoprocessorHost;
051import org.apache.hadoop.hbase.executor.ExecutorService;
052import org.apache.hadoop.hbase.fs.HFileSystem;
053import org.apache.hadoop.hbase.http.InfoServer;
054import org.apache.hadoop.hbase.io.util.MemorySizeUtil;
055import org.apache.hadoop.hbase.ipc.RpcServerInterface;
056import org.apache.hadoop.hbase.keymeta.KeyManagementService;
057import org.apache.hadoop.hbase.keymeta.KeymetaAdmin;
058import org.apache.hadoop.hbase.keymeta.ManagedKeyDataCache;
059import org.apache.hadoop.hbase.keymeta.SystemKeyCache;
060import org.apache.hadoop.hbase.master.HMaster;
061import org.apache.hadoop.hbase.master.MasterCoprocessorHost;
062import org.apache.hadoop.hbase.namequeues.NamedQueueRecorder;
063import org.apache.hadoop.hbase.regionserver.ChunkCreator;
064import org.apache.hadoop.hbase.regionserver.HeapMemoryManager;
065import org.apache.hadoop.hbase.regionserver.MemStoreLAB;
066import org.apache.hadoop.hbase.regionserver.RegionServerCoprocessorHost;
067import org.apache.hadoop.hbase.regionserver.ShutdownHook;
068import org.apache.hadoop.hbase.security.Superusers;
069import org.apache.hadoop.hbase.security.User;
070import org.apache.hadoop.hbase.security.UserProvider;
071import org.apache.hadoop.hbase.security.access.AccessChecker;
072import org.apache.hadoop.hbase.security.access.ZKPermissionWatcher;
073import org.apache.hadoop.hbase.trace.TraceUtil;
074import org.apache.hadoop.hbase.unsafe.HBasePlatformDependent;
075import org.apache.hadoop.hbase.util.Addressing;
076import org.apache.hadoop.hbase.util.CommonFSUtils;
077import org.apache.hadoop.hbase.util.ConfigurationUtil;
078import org.apache.hadoop.hbase.util.DNS;
079import org.apache.hadoop.hbase.util.EnvironmentEdgeManager;
080import org.apache.hadoop.hbase.util.FSTableDescriptors;
081import org.apache.hadoop.hbase.util.NettyEventLoopGroupConfig;
082import org.apache.hadoop.hbase.util.Pair;
083import org.apache.hadoop.hbase.util.Sleeper;
084import org.apache.hadoop.hbase.zookeeper.ClusterStatusTracker;
085import org.apache.hadoop.hbase.zookeeper.ZKAuthentication;
086import org.apache.hadoop.hbase.zookeeper.ZKWatcher;
087import org.apache.yetus.audience.InterfaceAudience;
088import org.slf4j.Logger;
089import org.slf4j.LoggerFactory;
090
091/**
092 * Base class for hbase services, such as master or region server.
093 */
094@InterfaceAudience.Private
095public abstract class HBaseServerBase<R extends HBaseRpcServicesBase<?>> extends Thread
096  implements Server, ConfigurationObserver, ConnectionRegistryEndpoint, KeyManagementService {
097
098  private static final Logger LOG = LoggerFactory.getLogger(HBaseServerBase.class);
099
100  protected final Configuration conf;
101
102  // Go down hard. Used if file system becomes unavailable and also in
103  // debugging and unit tests.
104  protected final AtomicBoolean abortRequested = new AtomicBoolean(false);
105
106  // Set when a report to the master comes back with a message asking us to
107  // shut down. Also set by call to stop when debugging or running unit tests
108  // of HRegionServer in isolation.
109  protected volatile boolean stopped = false;
110
111  // Flag set when a read-only to read-write transition is blocked because another active cluster
112  // exists
113  protected final AtomicBoolean readOnlyTransitionBlocked;
114
115  // Tracks the active cluster in a read-replica setup when a ReadOnlyTransitionException occurs
116  private final AtomicReference<String> blockingActiveClusterId;
117
118  // Only for testing
119  private boolean isShutdownHookInstalled = false;
120
121  /**
122   * This server's startcode.
123   */
124  protected final long startcode;
125
126  protected final UserProvider userProvider;
127
128  // zookeeper connection and watcher
129  protected final ZKWatcher zooKeeper;
130
131  /**
132   * The server name the Master sees us as. Its made from the hostname the master passes us, port,
133   * and server startcode. Gets set after registration against Master.
134   */
135  protected ServerName serverName;
136
137  protected final R rpcServices;
138
139  /**
140   * hostname specified by hostname config
141   */
142  protected final String useThisHostnameInstead;
143
144  /**
145   * Provide online slow log responses from ringbuffer
146   */
147  protected final NamedQueueRecorder namedQueueRecorder;
148
149  /**
150   * Configuration manager is used to register/deregister and notify the configuration observers
151   * when the regionserver is notified that there was a change in the on disk configs.
152   */
153  protected final ConfigurationManager configurationManager;
154
155  /**
156   * ChoreService used to schedule tasks that we want to run periodically
157   */
158  protected final ChoreService choreService;
159
160  // Instance of the hbase executor executorService.
161  protected final ExecutorService executorService;
162
163  // Cluster Status Tracker
164  protected final ClusterStatusTracker clusterStatusTracker;
165
166  protected final CoordinatedStateManager csm;
167
168  // Info server. Default access so can be used by unit tests. REGIONSERVER
169  // is name of the webapp and the attribute name used stuffing this instance
170  // into web context.
171  protected InfoServer infoServer;
172
173  protected HFileSystem dataFs;
174
175  protected HFileSystem walFs;
176
177  protected Path dataRootDir;
178
179  protected Path walRootDir;
180
181  protected final int msgInterval;
182
183  // A sleeper that sleeps for msgInterval.
184  protected final Sleeper sleeper;
185
186  /**
187   * Go here to get table descriptors.
188   */
189  protected TableDescriptors tableDescriptors;
190
191  /**
192   * The asynchronous cluster connection to be shared by services.
193   */
194  protected AsyncClusterConnection asyncClusterConnection;
195
196  /**
197   * Cache for the meta region replica's locations. Also tracks their changes to avoid stale cache
198   * entries. Used for serving ClientMetaService.
199   */
200  protected final MetaRegionLocationCache metaRegionLocationCache;
201
202  protected final NettyEventLoopGroupConfig eventLoopGroupConfig;
203
204  private void setupSignalHandlers() {
205    if (!SystemUtils.IS_OS_WINDOWS) {
206      HBasePlatformDependent.handle("HUP", (number, name) -> {
207        try {
208          updateConfiguration();
209        } catch (IOException e) {
210          LOG.error("Problem while reloading configuration", e);
211        }
212      });
213    }
214  }
215
216  /**
217   * Setup our cluster connection if not already initialized.
218   */
219  protected final synchronized void setupClusterConnection() throws IOException {
220    if (asyncClusterConnection == null) {
221      InetSocketAddress localAddress =
222        new InetSocketAddress(rpcServices.getSocketAddress().getAddress(), 0);
223      User user = userProvider.getCurrent();
224      asyncClusterConnection =
225        ClusterConnectionFactory.createAsyncClusterConnection(this, conf, localAddress, user);
226    }
227  }
228
229  protected final void initializeFileSystem() throws IOException {
230    // Get fs instance used by this RS. Do we use checksum verification in the hbase? If hbase
231    // checksum verification enabled, then automatically switch off hdfs checksum verification.
232    boolean useHBaseChecksum = conf.getBoolean(HConstants.HBASE_CHECKSUM_VERIFICATION, true);
233    String walDirUri = CommonFSUtils.getDirUri(this.conf,
234      new Path(conf.get(CommonFSUtils.HBASE_WAL_DIR, conf.get(HConstants.HBASE_DIR))));
235    // set WAL's uri
236    if (walDirUri != null) {
237      CommonFSUtils.setFsDefault(this.conf, walDirUri);
238    }
239    // init the WALFs
240    this.walFs = new HFileSystem(this.conf, useHBaseChecksum);
241    this.walRootDir = CommonFSUtils.getWALRootDir(this.conf);
242    // Set 'fs.defaultFS' to match the filesystem on hbase.rootdir else
243    // underlying hadoop hdfs accessors will be going against wrong filesystem
244    // (unless all is set to defaults).
245    String rootDirUri =
246      CommonFSUtils.getDirUri(this.conf, new Path(conf.get(HConstants.HBASE_DIR)));
247    if (rootDirUri != null) {
248      CommonFSUtils.setFsDefault(this.conf, rootDirUri);
249    }
250    // init the filesystem
251    this.dataFs = new HFileSystem(this.conf, useHBaseChecksum);
252    this.dataRootDir = CommonFSUtils.getRootDir(this.conf);
253    int tableDescriptorParallelLoadThreads =
254      conf.getInt("hbase.tabledescriptor.parallel.load.threads", 0);
255    this.tableDescriptors = new FSTableDescriptors(this.dataFs, this.dataRootDir,
256      !canUpdateTableDescriptor(), cacheTableDescriptor(), tableDescriptorParallelLoadThreads);
257  }
258
259  public HBaseServerBase(Configuration conf, String name) throws IOException {
260    super(name); // thread name
261    this.readOnlyTransitionBlocked = new AtomicBoolean(false);
262    this.blockingActiveClusterId = new AtomicReference<>(null);
263    final Span span = TraceUtil.createSpan("HBaseServerBase.cxtor");
264    try (Scope ignored = span.makeCurrent()) {
265      this.conf = conf;
266      this.eventLoopGroupConfig =
267        NettyEventLoopGroupConfig.setup(conf, getClass().getSimpleName() + "-EventLoopGroup");
268      this.startcode = EnvironmentEdgeManager.currentTime();
269      this.userProvider = UserProvider.instantiate(conf);
270      this.msgInterval = conf.getInt("hbase.regionserver.msginterval", 3 * 1000);
271      this.sleeper = new Sleeper(this.msgInterval, this);
272      this.namedQueueRecorder = createNamedQueueRecord();
273      useThisHostnameInstead = getUseThisHostnameInstead(conf);
274      // Resolve the hostname up-front and log in before creating the RpcServer. The RpcServer
275      // constructor reads UserGroupInformation.getCurrentUser() (HBASE-28321); if the server
276      // has not logged in yet, UGI bootstraps from the ticket cache and spawns a TGT renewer
277      // for whichever principal happens to be there.
278      String hostName = resolveHostName(conf, useThisHostnameInstead);
279      // login the zookeeper client principal (if using security)
280      ZKAuthentication.loginClient(this.conf, HConstants.ZK_CLIENT_KEYTAB_FILE,
281        HConstants.ZK_CLIENT_KERBEROS_PRINCIPAL, hostName);
282      // login the server principal (if using secure Hadoop)
283      login(userProvider, hostName);
284      this.rpcServices = createRpcServices();
285      InetSocketAddress addr = rpcServices.getSocketAddress();
286      serverName = ServerName.valueOf(hostName, addr.getPort(), this.startcode);
287      // init superusers and add the server principal (if using security)
288      // or process owner as default super user.
289      Superusers.initialize(conf);
290      zooKeeper =
291        new ZKWatcher(conf, getProcessName() + ":" + addr.getPort(), this, canCreateBaseZNode());
292
293      this.configurationManager = new ConfigurationManager();
294      setupSignalHandlers();
295
296      initializeFileSystem();
297
298      int choreServiceInitialSize =
299        conf.getInt(CHORE_SERVICE_INITIAL_POOL_SIZE, DEFAULT_CHORE_SERVICE_INITIAL_POOL_SIZE);
300      this.choreService = new ChoreService(getName(), choreServiceInitialSize, true);
301      this.executorService = new ExecutorService(getName());
302
303      this.metaRegionLocationCache = new MetaRegionLocationCache(zooKeeper);
304
305      if (clusterMode()) {
306        if (
307          conf.getBoolean(HBASE_SPLIT_WAL_COORDINATED_BY_ZK, DEFAULT_HBASE_SPLIT_COORDINATED_BY_ZK)
308        ) {
309          csm = new ZkCoordinatedStateManager(this);
310        } else {
311          csm = null;
312        }
313        clusterStatusTracker = new ClusterStatusTracker(zooKeeper, this);
314        clusterStatusTracker.start();
315      } else {
316        csm = null;
317        clusterStatusTracker = null;
318      }
319      putUpWebUI();
320      span.setStatus(StatusCode.OK);
321    } catch (Throwable t) {
322      TraceUtil.setError(span, t);
323      throw t;
324    } finally {
325      span.end();
326    }
327  }
328
329  /**
330   * Puts up the webui.
331   */
332  private void putUpWebUI() throws IOException {
333    int port =
334      this.conf.getInt(HConstants.REGIONSERVER_INFO_PORT, HConstants.DEFAULT_REGIONSERVER_INFOPORT);
335    String addr = this.conf.get("hbase.regionserver.info.bindAddress", "0.0.0.0");
336
337    boolean isMaster = false;
338    if (this instanceof HMaster) {
339      port = conf.getInt(HConstants.MASTER_INFO_PORT, HConstants.DEFAULT_MASTER_INFOPORT);
340      addr = this.conf.get("hbase.master.info.bindAddress", "0.0.0.0");
341      isMaster = true;
342    }
343    // -1 is for disabling info server
344    if (port < 0) {
345      return;
346    }
347
348    if (!Addressing.isLocalAddress(InetAddress.getByName(addr))) {
349      String msg = "Failed to start http info server. Address " + addr
350        + " does not belong to this host. Correct configuration parameter: "
351        + (isMaster ? "hbase.master.info.bindAddress" : "hbase.regionserver.info.bindAddress");
352      LOG.error(msg);
353      throw new IOException(msg);
354    }
355    // check if auto port bind enabled
356    boolean auto = this.conf.getBoolean(HConstants.REGIONSERVER_INFO_PORT_AUTO, false);
357    while (true) {
358      try {
359        this.infoServer = new InfoServer(getProcessName(), addr, port, false, this.conf);
360        infoServer.addPrivilegedServlet("dump", "/dump", getDumpServlet());
361        configureInfoServer(infoServer);
362        this.infoServer.start();
363        break;
364      } catch (BindException e) {
365        if (!auto) {
366          // auto bind disabled throw BindException
367          LOG.error("Failed binding http info server to port: " + port);
368          throw e;
369        }
370        // auto bind enabled, try to use another port
371        LOG.info("Failed binding http info server to port: " + port);
372        port++;
373        LOG.info("Retry starting http info server with port: " + port);
374      }
375    }
376    port = this.infoServer.getPort();
377    conf.setInt(HConstants.REGIONSERVER_INFO_PORT, port);
378    int masterInfoPort =
379      conf.getInt(HConstants.MASTER_INFO_PORT, HConstants.DEFAULT_MASTER_INFOPORT);
380    conf.setInt("hbase.master.info.port.orig", masterInfoPort);
381    conf.setInt(HConstants.MASTER_INFO_PORT, port);
382  }
383
384  /**
385   * Sets the abort state if not already set.
386   * @return True if abortRequested set to True successfully, false if an abort is already in
387   *         progress.
388   */
389  protected final boolean setAbortRequested() {
390    return abortRequested.compareAndSet(false, true);
391  }
392
393  @Override
394  public boolean isStopped() {
395    return stopped;
396  }
397
398  @Override
399  public boolean isAborted() {
400    return abortRequested.get();
401  }
402
403  @Override
404  public Configuration getConfiguration() {
405    return conf;
406  }
407
408  @Override
409  public AsyncClusterConnection getAsyncClusterConnection() {
410    return asyncClusterConnection;
411  }
412
413  @Override
414  public ZKWatcher getZooKeeper() {
415    return zooKeeper;
416  }
417
418  @Override
419  public KeymetaAdmin getKeymetaAdmin() {
420    return null;
421  }
422
423  @Override
424  public ManagedKeyDataCache getManagedKeyDataCache() {
425    return null;
426  }
427
428  @Override
429  public SystemKeyCache getSystemKeyCache() {
430    return null;
431  }
432
433  protected final void shutdownChore(ScheduledChore chore) {
434    if (chore != null) {
435      chore.shutdown();
436    }
437  }
438
439  protected final void initializeMemStoreChunkCreator(HeapMemoryManager hMemManager) {
440    if (MemStoreLAB.isEnabled(conf)) {
441      // MSLAB is enabled. So initialize MemStoreChunkPool
442      // By this time, the MemstoreFlusher is already initialized. We can get the global limits from
443      // it.
444      Pair<Long, MemoryType> pair = MemorySizeUtil.getGlobalMemStoreSize(conf);
445      long globalMemStoreSize = pair.getFirst();
446      boolean offheap = pair.getSecond() == MemoryType.NON_HEAP;
447      // When off heap memstore in use, take full area for chunk pool.
448      float poolSizePercentage = offheap
449        ? 1.0F
450        : conf.getFloat(MemStoreLAB.CHUNK_POOL_MAXSIZE_KEY, MemStoreLAB.POOL_MAX_SIZE_DEFAULT);
451      float initialCountPercentage = conf.getFloat(MemStoreLAB.CHUNK_POOL_INITIALSIZE_KEY,
452        MemStoreLAB.POOL_INITIAL_SIZE_DEFAULT);
453      int chunkSize = conf.getInt(MemStoreLAB.CHUNK_SIZE_KEY, MemStoreLAB.CHUNK_SIZE_DEFAULT);
454      float indexChunkSizePercent = conf.getFloat(MemStoreLAB.INDEX_CHUNK_SIZE_PERCENTAGE_KEY,
455        MemStoreLAB.INDEX_CHUNK_SIZE_PERCENTAGE_DEFAULT);
456      // init the chunkCreator
457      ChunkCreator.initialize(chunkSize, offheap, globalMemStoreSize, poolSizePercentage,
458        initialCountPercentage, hMemManager, indexChunkSizePercent);
459    }
460  }
461
462  protected abstract void stopChores();
463
464  protected final void stopChoreService() {
465    // clean up the scheduled chores
466    if (choreService != null) {
467      LOG.info("Shutdown chores and chore service");
468      stopChores();
469      // cancel the remaining scheduled chores (in case we missed out any)
470      // TODO: cancel will not cleanup the chores, so we need make sure we do not miss any
471      choreService.shutdown();
472    }
473  }
474
475  protected final void stopExecutorService() {
476    if (executorService != null) {
477      LOG.info("Shutdown executor service");
478      executorService.shutdown();
479    }
480  }
481
482  protected final void closeClusterConnection() {
483    if (asyncClusterConnection != null) {
484      LOG.info("Close async cluster connection");
485      try {
486        this.asyncClusterConnection.close();
487      } catch (IOException e) {
488        // Although the {@link Closeable} interface throws an {@link
489        // IOException}, in reality, the implementation would never do that.
490        LOG.warn("Attempt to close server's AsyncClusterConnection failed.", e);
491      }
492    }
493  }
494
495  protected final void stopInfoServer() {
496    if (this.infoServer != null) {
497      LOG.info("Stop info server");
498      try {
499        this.infoServer.stop();
500      } catch (Exception e) {
501        LOG.error("Failed to stop infoServer", e);
502      }
503    }
504  }
505
506  protected final void closeZooKeeper() {
507    if (this.zooKeeper != null) {
508      LOG.info("Close zookeeper");
509      this.zooKeeper.close();
510    }
511  }
512
513  protected final void closeTableDescriptors() {
514    if (this.tableDescriptors != null) {
515      LOG.info("Close table descriptors");
516      try {
517        this.tableDescriptors.close();
518      } catch (IOException e) {
519        LOG.debug("Failed to close table descriptors gracefully", e);
520      }
521    }
522  }
523
524  /**
525   * In order to register ShutdownHook, this method is called when HMaster and HRegionServer are
526   * started. For details, please refer to HBASE-26951
527   */
528  protected final void installShutdownHook() {
529    ShutdownHook.install(conf, dataFs, this, Thread.currentThread());
530    isShutdownHookInstalled = true;
531  }
532
533  @RestrictedApi(explanation = "Should only be called in tests", link = "",
534      allowedOnPath = ".*/src/test/.*")
535  public boolean isShutdownHookInstalled() {
536    return isShutdownHookInstalled;
537  }
538
539  @Override
540  public ServerName getServerName() {
541    return serverName;
542  }
543
544  @Override
545  public ChoreService getChoreService() {
546    return choreService;
547  }
548
549  /** Returns Return table descriptors implementation. */
550  public TableDescriptors getTableDescriptors() {
551    return this.tableDescriptors;
552  }
553
554  public ExecutorService getExecutorService() {
555    return executorService;
556  }
557
558  public AccessChecker getAccessChecker() {
559    return rpcServices.getAccessChecker();
560  }
561
562  public ZKPermissionWatcher getZKPermissionWatcher() {
563    return rpcServices.getZkPermissionWatcher();
564  }
565
566  @Override
567  public CoordinatedStateManager getCoordinatedStateManager() {
568    return csm;
569  }
570
571  @Override
572  public Connection createConnection(Configuration conf) throws IOException {
573    User user = UserProvider.instantiate(conf).getCurrent();
574    return ConnectionFactory.createConnection(conf, null, user);
575  }
576
577  /** Returns Return the rootDir. */
578  public Path getDataRootDir() {
579    return dataRootDir;
580  }
581
582  @Override
583  public FileSystem getFileSystem() {
584    return dataFs;
585  }
586
587  /** Returns Return the walRootDir. */
588  public Path getWALRootDir() {
589    return walRootDir;
590  }
591
592  /** Returns Return the walFs. */
593  public FileSystem getWALFileSystem() {
594    return walFs;
595  }
596
597  /** Returns True if the cluster is up. */
598  public boolean isClusterUp() {
599    return !clusterMode() || this.clusterStatusTracker.isClusterUp();
600  }
601
602  /** Returns time stamp in millis of when this server was started */
603  public long getStartcode() {
604    return this.startcode;
605  }
606
607  public InfoServer getInfoServer() {
608    return infoServer;
609  }
610
611  public int getMsgInterval() {
612    return msgInterval;
613  }
614
615  /**
616   * get NamedQueue Provider to add different logs to ringbuffer
617   */
618  public NamedQueueRecorder getNamedQueueRecorder() {
619    return this.namedQueueRecorder;
620  }
621
622  public RpcServerInterface getRpcServer() {
623    return rpcServices.getRpcServer();
624  }
625
626  public NettyEventLoopGroupConfig getEventLoopGroupConfig() {
627    return eventLoopGroupConfig;
628  }
629
630  public R getRpcServices() {
631    return rpcServices;
632  }
633
634  @RestrictedApi(explanation = "Should only be called in tests", link = "",
635      allowedOnPath = ".*/src/test/.*")
636  public MetaRegionLocationCache getMetaRegionLocationCache() {
637    return this.metaRegionLocationCache;
638  }
639
640  @RestrictedApi(explanation = "Should only be called in tests", link = "",
641      allowedOnPath = ".*/src/test/.*")
642  public ConfigurationManager getConfigurationManager() {
643    return configurationManager;
644  }
645
646  /**
647   * Reload the configuration from disk.
648   */
649  public void updateConfiguration() throws IOException {
650    LOG.info("Reloading the configuration from disk.");
651    // Reload the configuration from disk.
652    preUpdateConfiguration();
653    this.readOnlyTransitionBlocked.set(false);
654    this.blockingActiveClusterId.set(null);
655    conf.reloadConfiguration();
656    configurationManager.notifyAllObservers(conf);
657    this.checkForBlockedReadOnlyTransition();
658    postUpdateConfiguration();
659  }
660
661  protected Configuration blockReadOnlyTransition(Configuration updatedConf,
662    String activeClusterId) {
663    this.blockingActiveClusterId.set(activeClusterId);
664    LOG.error(
665      "Cannot disable read-only mode. The {} file contains a different cluster ID ({}), which means "
666        + "that cluster is already the active cluster. Reverting {} to true",
667      HConstants.ACTIVE_CLUSTER_SUFFIX_FILE_NAME, this.blockingActiveClusterId.get(),
668      HConstants.HBASE_GLOBAL_READONLY_ENABLED_KEY);
669    this.readOnlyTransitionBlocked.set(true);
670    return ConfigurationUtil.copyWithReadOnlyModeEnabled(updatedConf);
671  }
672
673  protected void checkForBlockedReadOnlyTransition() throws ReadOnlyTransitionException {
674    if (this.readOnlyTransitionBlocked.get()) {
675      throw new ReadOnlyTransitionException(
676        "Cannot disable read-only mode because another active cluster already exists on this "
677          + "storage location. The read-only coprocessors have not been removed.",
678        this.blockingActiveClusterId.get());
679    }
680  }
681
682  @Override
683  public KeyManagementService getKeyManagementService() {
684    return this;
685  }
686
687  private void preUpdateConfiguration() throws IOException {
688    CoprocessorHost<?, ?> coprocessorHost = getCoprocessorHost();
689    if (coprocessorHost instanceof RegionServerCoprocessorHost) {
690      ((RegionServerCoprocessorHost) coprocessorHost).preUpdateConfiguration(conf);
691    } else if (coprocessorHost instanceof MasterCoprocessorHost) {
692      ((MasterCoprocessorHost) coprocessorHost).preUpdateConfiguration(conf);
693    }
694  }
695
696  private void postUpdateConfiguration() throws IOException {
697    CoprocessorHost<?, ?> coprocessorHost = getCoprocessorHost();
698    if (coprocessorHost instanceof RegionServerCoprocessorHost) {
699      ((RegionServerCoprocessorHost) coprocessorHost).postUpdateConfiguration(conf);
700    } else if (coprocessorHost instanceof MasterCoprocessorHost) {
701      ((MasterCoprocessorHost) coprocessorHost).postUpdateConfiguration(conf);
702    }
703  }
704
705  @Override
706  public String toString() {
707    return getServerName().toString();
708  }
709
710  protected abstract CoprocessorHost<?, ?> getCoprocessorHost();
711
712  protected abstract boolean canCreateBaseZNode();
713
714  protected abstract String getProcessName();
715
716  protected abstract R createRpcServices() throws IOException;
717
718  protected abstract String getUseThisHostnameInstead(Configuration conf) throws IOException;
719
720  protected abstract void login(UserProvider user, String host) throws IOException;
721
722  protected abstract DNS.ServerType getDNSServerType();
723
724  private String resolveHostName(Configuration conf, String useThisHostnameInstead)
725    throws IOException {
726    if (!StringUtils.isBlank(useThisHostnameInstead)) {
727      return useThisHostnameInstead;
728    }
729    // if use-ip is enabled, we will use ip to expose Master/RS service for client,
730    // see HBASE-27304 for details.
731    boolean useIp = conf.getBoolean(HConstants.HBASE_SERVER_USEIP_ENABLED_KEY,
732      HConstants.HBASE_SERVER_USEIP_ENABLED_DEFAULT);
733    InetAddress addr = InetAddress.getByName(DNS.getHostname(conf, getDNSServerType()));
734    return useIp ? addr.getHostAddress() : addr.getHostName();
735  }
736
737  protected abstract NamedQueueRecorder createNamedQueueRecord();
738
739  protected abstract void configureInfoServer(InfoServer infoServer);
740
741  protected abstract Class<? extends HttpServlet> getDumpServlet();
742
743  protected abstract boolean canUpdateTableDescriptor();
744
745  protected abstract boolean cacheTableDescriptor();
746
747  protected abstract boolean clusterMode();
748}