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.master;
019
020import com.google.errorprone.annotations.RestrictedApi;
021import org.apache.hadoop.conf.Configuration;
022import org.apache.hadoop.hbase.ChoreService;
023import org.apache.hadoop.hbase.HConstants;
024import org.apache.hadoop.hbase.conf.ConfigurationObserver;
025import org.apache.yetus.audience.InterfaceAudience;
026import org.slf4j.Logger;
027import org.slf4j.LoggerFactory;
028
029/**
030 * Config manager for RegionsRecovery Chore - Dynamically reload config and update chore accordingly
031 */
032@InterfaceAudience.Private
033public class RegionsRecoveryConfigManager implements ConfigurationObserver {
034
035  private static final Logger LOG = LoggerFactory.getLogger(RegionsRecoveryConfigManager.class);
036
037  private final HMaster hMaster;
038  private RegionsRecoveryChore chore;
039  private int prevMaxStoreFileRefCount;
040  private int prevRegionsRecoveryInterval;
041
042  RegionsRecoveryConfigManager(final HMaster hMaster) {
043    this.hMaster = hMaster;
044    Configuration conf = hMaster.getConfiguration();
045    this.prevMaxStoreFileRefCount = getMaxStoreFileRefCount(conf);
046    this.prevRegionsRecoveryInterval = getRegionsRecoveryChoreInterval(conf);
047  }
048
049  @Override
050  public void onConfigurationChange(Configuration conf) {
051    final int newMaxStoreFileRefCount = getMaxStoreFileRefCount(conf);
052    final int newRegionsRecoveryInterval = getRegionsRecoveryChoreInterval(conf);
053
054    if (
055      prevMaxStoreFileRefCount == newMaxStoreFileRefCount
056        && prevRegionsRecoveryInterval == newRegionsRecoveryInterval
057    ) {
058      // no need to re-schedule the chore with updated config
059      // as there is no change in desired configs
060      return;
061    }
062
063    LOG.info(
064      "Config Reload for RegionsRecovery Chore. prevMaxStoreFileRefCount: {},"
065        + " newMaxStoreFileRefCount: {}, prevRegionsRecoveryInterval: {}, "
066        + "newRegionsRecoveryInterval: {}",
067      prevMaxStoreFileRefCount, newMaxStoreFileRefCount, prevRegionsRecoveryInterval,
068      newRegionsRecoveryInterval);
069
070    RegionsRecoveryChore regionsRecoveryChore =
071      new RegionsRecoveryChore(this.hMaster, conf, this.hMaster);
072    ChoreService choreService = this.hMaster.getChoreService();
073
074    // Regions Reopen based on very high storeFileRefCount is considered enabled
075    // only if hbase.regions.recovery.store.file.ref.count has value > 0
076    synchronized (this) {
077      if (chore != null) {
078        chore.shutdown();
079        chore = null;
080      }
081      if (newMaxStoreFileRefCount > 0) {
082        // schedule the new chore
083        choreService.scheduleChore(regionsRecoveryChore);
084        chore = regionsRecoveryChore;
085      }
086      this.prevMaxStoreFileRefCount = newMaxStoreFileRefCount;
087      this.prevRegionsRecoveryInterval = newRegionsRecoveryInterval;
088    }
089  }
090
091  private int getMaxStoreFileRefCount(Configuration configuration) {
092    return configuration.getInt(HConstants.STORE_FILE_REF_COUNT_THRESHOLD,
093      HConstants.DEFAULT_STORE_FILE_REF_COUNT_THRESHOLD);
094  }
095
096  private int getRegionsRecoveryChoreInterval(Configuration configuration) {
097    return configuration.getInt(HConstants.REGIONS_RECOVERY_INTERVAL,
098      HConstants.DEFAULT_REGIONS_RECOVERY_INTERVAL);
099  }
100
101  @RestrictedApi(explanation = "Only visible for testing", link = "",
102      allowedOnPath = ".*/src/test/.*")
103  RegionsRecoveryChore getChore() {
104    return chore;
105  }
106}