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