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.balancer;
019
020import com.google.errorprone.annotations.RestrictedApi;
021import java.io.IOException;
022import java.util.Collection;
023import java.util.Collections;
024import java.util.List;
025import java.util.Map;
026import java.util.function.Predicate;
027import java.util.function.Supplier;
028import org.apache.hadoop.conf.Configuration;
029import org.apache.hadoop.hbase.HDFSBlocksDistribution;
030import org.apache.hadoop.hbase.ServerMetrics;
031import org.apache.hadoop.hbase.ServerName;
032import org.apache.hadoop.hbase.TableDescriptors;
033import org.apache.hadoop.hbase.TableName;
034import org.apache.hadoop.hbase.client.BalancerDecision;
035import org.apache.hadoop.hbase.client.BalancerRejection;
036import org.apache.hadoop.hbase.client.Connection;
037import org.apache.hadoop.hbase.client.RegionInfo;
038import org.apache.hadoop.hbase.client.TableDescriptor;
039import org.apache.hadoop.hbase.master.MasterServices;
040import org.apache.hadoop.hbase.master.ServerManager;
041import org.apache.hadoop.hbase.master.assignment.AssignmentManager;
042import org.apache.hadoop.hbase.namequeues.BalancerDecisionDetails;
043import org.apache.hadoop.hbase.namequeues.BalancerRejectionDetails;
044import org.apache.hadoop.hbase.namequeues.NamedQueueRecorder;
045import org.apache.hadoop.hbase.regionserver.HRegion;
046import org.apache.hadoop.hbase.regionserver.compactions.OffPeakHours;
047import org.apache.yetus.audience.InterfaceAudience;
048
049/**
050 * Master based cluster info provider.
051 */
052@InterfaceAudience.Private
053public class MasterClusterInfoProvider implements ClusterInfoProvider {
054
055  private final MasterServices services;
056
057  private boolean isBalancerDecisionRecording;
058
059  private boolean isBalancerRejectionRecording;
060
061  /**
062   * Use to add balancer decision history to ring-buffer
063   */
064  private NamedQueueRecorder namedQueueRecorder;
065
066  private OffPeakHours offPeakHours;
067
068  private void loadConf(Configuration conf) {
069    this.offPeakHours = OffPeakHours.getInstance(conf);
070    isBalancerDecisionRecording = conf.getBoolean(BaseLoadBalancer.BALANCER_DECISION_BUFFER_ENABLED,
071      BaseLoadBalancer.DEFAULT_BALANCER_DECISION_BUFFER_ENABLED);
072    isBalancerRejectionRecording =
073      conf.getBoolean(BaseLoadBalancer.BALANCER_REJECTION_BUFFER_ENABLED,
074        BaseLoadBalancer.DEFAULT_BALANCER_REJECTION_BUFFER_ENABLED);
075    if (isBalancerDecisionRecording || isBalancerRejectionRecording) {
076      this.namedQueueRecorder = NamedQueueRecorder.getInstance(conf);
077    } else {
078      this.namedQueueRecorder = null;
079    }
080  }
081
082  public MasterClusterInfoProvider(MasterServices services) {
083    this.services = services;
084    loadConf(services.getConfiguration());
085  }
086
087  @Override
088  public Configuration getConfiguration() {
089    return services.getConfiguration();
090  }
091
092  @Override
093  public Connection getConnection() {
094    return services.getConnection();
095  }
096
097  @Override
098  public List<RegionInfo> getAssignedRegions() {
099    AssignmentManager am = services.getAssignmentManager();
100    return am != null ? am.getAssignedRegions() : Collections.emptyList();
101  }
102
103  @Override
104  public void unassign(RegionInfo regionInfo) throws IOException {
105    AssignmentManager am = services.getAssignmentManager();
106    if (am != null) {
107      am.unassign(regionInfo);
108    }
109  }
110
111  @Override
112  public TableDescriptor getTableDescriptor(TableName tableName) throws IOException {
113    TableDescriptors tds = services.getTableDescriptors();
114    return tds != null ? tds.get(tableName) : null;
115  }
116
117  @Override
118  public HDFSBlocksDistribution computeHDFSBlocksDistribution(Configuration conf,
119    TableDescriptor tableDescriptor, RegionInfo regionInfo) throws IOException {
120    return HRegion.computeHDFSBlocksDistribution(conf, tableDescriptor, regionInfo);
121  }
122
123  @Override
124  public boolean hasRegionReplica(Collection<RegionInfo> regions) throws IOException {
125    TableDescriptors tds = services.getTableDescriptors();
126    if (tds == null) {
127      return false;
128    }
129    for (RegionInfo region : regions) {
130      TableDescriptor td = tds.get(region.getTable());
131      if (td != null && td.getRegionReplication() > 1) {
132        return true;
133      }
134    }
135    return false;
136  }
137
138  @Override
139  public List<ServerName> getOnlineServersList() {
140    ServerManager sm = services.getServerManager();
141    return sm != null ? sm.getOnlineServersList() : Collections.emptyList();
142  }
143
144  @Override
145  public List<ServerName> getOnlineServersListWithPredicator(List<ServerName> servers,
146    Predicate<ServerMetrics> filter) {
147    ServerManager sm = services.getServerManager();
148    return sm != null
149      ? sm.getOnlineServersListWithPredicator(servers, filter)
150      : Collections.emptyList();
151  }
152
153  @Override
154  public Map<ServerName, List<RegionInfo>> getSnapShotOfAssignment(Collection<RegionInfo> regions) {
155    AssignmentManager am = services.getAssignmentManager();
156    return am != null ? am.getSnapShotOfAssignment(regions) : Collections.emptyMap();
157  }
158
159  @Override
160  public int getNumberOfTables() throws IOException {
161    return services.getTableDescriptors().getAll().size();
162  }
163
164  @Override
165  public boolean isOffPeakHour() {
166    return offPeakHours.isOffPeakHour();
167  }
168
169  @Override
170  public void onConfigurationChange(Configuration conf) {
171    loadConf(conf);
172  }
173
174  @Override
175  public void recordBalancerDecision(Supplier<BalancerDecision> decision) {
176    if (isBalancerDecisionRecording) {
177      namedQueueRecorder.addRecord(new BalancerDecisionDetails(decision.get()));
178    }
179  }
180
181  @Override
182  public void recordBalancerRejection(Supplier<BalancerRejection> rejection) {
183    if (isBalancerRejectionRecording) {
184      namedQueueRecorder.addRecord(new BalancerRejectionDetails(rejection.get()));
185    }
186  }
187
188  @Override
189  public ServerMetrics getLoad(ServerName serverName) {
190    ServerManager sm = services.getServerManager();
191    return sm != null ? sm.getLoad(serverName) : null;
192  }
193
194  @RestrictedApi(explanation = "Should only be called in tests", link = "",
195      allowedOnPath = ".*/src/test/.*")
196  NamedQueueRecorder getNamedQueueRecorder() {
197    return namedQueueRecorder;
198  }
199}