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.rsgroup;
019
020import java.io.IOException;
021import java.util.ArrayList;
022import java.util.Collection;
023import java.util.List;
024import java.util.Optional;
025import java.util.function.Predicate;
026import org.apache.hadoop.conf.Configuration;
027import org.apache.hadoop.hbase.NamespaceDescriptor;
028import org.apache.hadoop.hbase.TableName;
029import org.apache.hadoop.hbase.client.TableDescriptor;
030import org.apache.hadoop.hbase.master.ClusterSchema;
031import org.apache.hadoop.hbase.master.MasterServices;
032import org.apache.yetus.audience.InterfaceAudience;
033import org.slf4j.Logger;
034import org.slf4j.LoggerFactory;
035
036/**
037 * Helper class for RSGroup implementation
038 */
039@InterfaceAudience.Private
040public final class RSGroupUtil {
041
042  private static final Logger LOG = LoggerFactory.getLogger(RSGroupUtil.class);
043
044  public static final String RS_GROUP_ENABLED = "hbase.balancer.rsgroup.enabled";
045
046  private RSGroupUtil() {
047  }
048
049  public static boolean isRSGroupEnabled(Configuration conf) {
050    return conf.getBoolean(RS_GROUP_ENABLED, false);
051  }
052
053  public static void enableRSGroup(Configuration conf) {
054    conf.setBoolean(RS_GROUP_ENABLED, true);
055  }
056
057  public static List<TableName> listTablesInRSGroup(MasterServices master, String groupName)
058    throws IOException {
059    List<TableName> tables = new ArrayList<>();
060    boolean isDefaultGroup = RSGroupInfo.DEFAULT_GROUP.equals(groupName);
061    for (TableDescriptor td : master.getTableDescriptors().getAll().values()) {
062      // no config means in default group
063      if (
064        RSGroupUtil.getRSGroupInfo(master, master.getRSGroupInfoManager(), td.getTableName())
065          .map(g -> g.getName().equals(groupName)).orElse(isDefaultGroup)
066      ) {
067        tables.add(td.getTableName());
068      }
069    }
070    return tables;
071  }
072
073  /**
074   * Will try to get the rsgroup from {@link TableDescriptor} first, and then try to get the rsgroup
075   * from the {@link NamespaceDescriptor}. If still not present, return empty.
076   */
077  public static Optional<RSGroupInfo> getRSGroupInfo(MasterServices master,
078    RSGroupInfoManager manager, TableName tableName) throws IOException {
079    TableDescriptor td = master.getTableDescriptors().get(tableName);
080    if (td == null) {
081      return Optional.empty();
082    }
083    // RSGroup information determined by client.
084    Optional<String> optGroupNameOfTable = td.getRegionServerGroup();
085    if (optGroupNameOfTable.isPresent()) {
086      RSGroupInfo group = manager.getRSGroup(optGroupNameOfTable.get());
087      if (group != null) {
088        return Optional.of(group);
089      }
090    }
091    // for backward compatible, where we may still have table configs in the RSGroupInfo after
092    // upgrading when migrating is still on-going.
093    RSGroupInfo groupFromOldRSGroupInfo = manager.getRSGroupForTable(tableName);
094    if (groupFromOldRSGroupInfo != null) {
095      return Optional.of(groupFromOldRSGroupInfo);
096    }
097    // RSGroup information determined by administrator.
098    String groupDeterminedByAdmin = manager.determineRSGroupInfoForTable(tableName);
099    RSGroupInfo groupInfo = null;
100    if (groupDeterminedByAdmin != null) {
101      groupInfo = manager.getRSGroup(groupDeterminedByAdmin);
102    }
103    if (groupInfo != null) {
104      return Optional.of(groupInfo);
105    }
106    // Finally, we will try to fall back to namespace as rsgroup if exists
107    ClusterSchema clusterSchema = master.getClusterSchema();
108    if (clusterSchema == null) {
109      if (TableName.isMetaTableName(tableName)) {
110        LOG.info("Can not get the namespace rs group config for meta table, since the"
111          + " meta table is not online yet, will use default group to assign meta first");
112      } else {
113        LOG.warn("ClusterSchema is null, can only use default rsgroup, should not happen?");
114      }
115      return Optional.empty();
116    }
117    NamespaceDescriptor nd = clusterSchema.getNamespace(tableName.getNamespaceAsString());
118    String groupNameOfNs = nd.getConfigurationValue(RSGroupInfo.NAMESPACE_DESC_PROP_GROUP);
119    if (groupNameOfNs == null) {
120      return Optional.empty();
121    }
122    return Optional.ofNullable(manager.getRSGroup(groupNameOfNs));
123  }
124
125  /**
126   * Fill the tables field for {@link RSGroupInfo}, for backward compatibility.
127   */
128  @SuppressWarnings("deprecation")
129  public static RSGroupInfo fillTables(RSGroupInfo rsGroupInfo, Collection<TableDescriptor> tds) {
130    RSGroupInfo newRsGroupInfo = new RSGroupInfo(rsGroupInfo);
131    Predicate<TableDescriptor> filter;
132    if (rsGroupInfo.getName().equals(RSGroupInfo.DEFAULT_GROUP)) {
133      filter = td -> {
134        Optional<String> optGroupName = td.getRegionServerGroup();
135        return !optGroupName.isPresent() || optGroupName.get().equals(RSGroupInfo.DEFAULT_GROUP);
136      };
137    } else {
138      filter = td -> {
139        Optional<String> optGroupName = td.getRegionServerGroup();
140        return optGroupName.isPresent() && optGroupName.get().equals(newRsGroupInfo.getName());
141      };
142    }
143    tds.stream().filter(filter).map(TableDescriptor::getTableName)
144      .forEach(newRsGroupInfo::addTable);
145    return newRsGroupInfo;
146  }
147}