001/**
002 *
003 * Licensed to the Apache Software Foundation (ASF) under one
004 * or more contributor license agreements.  See the NOTICE file
005 * distributed with this work for additional information
006 * regarding copyright ownership.  The ASF licenses this file
007 * to you under the Apache License, Version 2.0 (the
008 * "License"); you may not use this file except in compliance
009 * with the License.  You may obtain a copy of the License at
010 *
011 *     http://www.apache.org/licenses/LICENSE-2.0
012 *
013 * Unless required by applicable law or agreed to in writing, software
014 * distributed under the License is distributed on an "AS IS" BASIS,
015 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
016 * See the License for the specific language governing permissions and
017 * limitations under the License.
018 */
019
020package org.apache.hadoop.hbase;
021
022import edu.umd.cs.findbugs.annotations.Nullable;
023import java.util.Collections;
024import java.util.EnumSet;
025import java.util.List;
026import java.util.Map;
027import java.util.TreeMap;
028import java.util.stream.Collectors;
029import org.apache.hadoop.hbase.master.RegionState;
030import org.apache.yetus.audience.InterfaceAudience;
031
032import org.apache.hbase.thirdparty.com.google.common.base.Preconditions;
033import org.apache.hbase.thirdparty.com.google.protobuf.UnsafeByteOperations;
034import org.apache.hadoop.hbase.shaded.protobuf.ProtobufUtil;
035import org.apache.hadoop.hbase.shaded.protobuf.generated.ClusterStatusProtos;
036import org.apache.hadoop.hbase.shaded.protobuf.generated.FSProtos;
037import org.apache.hadoop.hbase.shaded.protobuf.generated.HBaseProtos;
038
039@InterfaceAudience.Private
040public final class ClusterMetricsBuilder {
041
042  public static ClusterStatusProtos.ClusterStatus toClusterStatus(ClusterMetrics metrics) {
043    ClusterStatusProtos.ClusterStatus.Builder builder
044        = ClusterStatusProtos.ClusterStatus.newBuilder()
045        .addAllBackupMasters(metrics.getBackupMasterNames().stream()
046            .map(ProtobufUtil::toServerName).collect(Collectors.toList()))
047        .addAllDeadServers(metrics.getDeadServerNames().stream()
048            .map(ProtobufUtil::toServerName).collect(Collectors.toList()))
049        .addAllLiveServers(metrics.getLiveServerMetrics().entrySet().stream()
050            .map(s -> ClusterStatusProtos.LiveServerInfo
051                .newBuilder()
052                .setServer(ProtobufUtil.toServerName(s.getKey()))
053                .setServerLoad(ServerMetricsBuilder.toServerLoad(s.getValue()))
054                .build())
055            .collect(Collectors.toList()))
056        .addAllMasterCoprocessors(metrics.getMasterCoprocessorNames().stream()
057            .map(n -> HBaseProtos.Coprocessor.newBuilder().setName(n).build())
058            .collect(Collectors.toList()))
059        .addAllRegionsInTransition(metrics.getRegionStatesInTransition().stream()
060            .map(r -> ClusterStatusProtos.RegionInTransition
061                .newBuilder()
062                .setSpec(HBaseProtos.RegionSpecifier
063                    .newBuilder()
064                    .setType(HBaseProtos.RegionSpecifier.RegionSpecifierType.REGION_NAME)
065                    .setValue(UnsafeByteOperations.unsafeWrap(r.getRegion().getRegionName()))
066                    .build())
067                .setRegionState(r.convert())
068                .build())
069            .collect(Collectors.toList()))
070        .setMasterInfoPort(metrics.getMasterInfoPort());
071    if (metrics.getMasterName() != null) {
072      builder.setMaster(ProtobufUtil.toServerName((metrics.getMasterName())));
073    }
074    if (metrics.getBalancerOn() != null) {
075      builder.setBalancerOn(metrics.getBalancerOn());
076    }
077    if (metrics.getClusterId() != null) {
078      builder.setClusterId(new ClusterId(metrics.getClusterId()).convert());
079    }
080    if (metrics.getHBaseVersion() != null) {
081      builder.setHbaseVersion(
082          FSProtos.HBaseVersionFileContent.newBuilder()
083              .setVersion(metrics.getHBaseVersion()));
084    }
085    return builder.build();
086  }
087
088  public static ClusterMetrics toClusterMetrics(
089      ClusterStatusProtos.ClusterStatus proto) {
090    ClusterMetricsBuilder builder = ClusterMetricsBuilder.newBuilder();
091    builder.setLiveServerMetrics(proto.getLiveServersList().stream()
092        .collect(Collectors.toMap(e -> ProtobufUtil.toServerName(e.getServer()),
093            ServerMetricsBuilder::toServerMetrics)))
094        .setDeadServerNames(proto.getDeadServersList().stream()
095            .map(ProtobufUtil::toServerName)
096            .collect(Collectors.toList()))
097        .setBackerMasterNames(proto.getBackupMastersList().stream()
098            .map(ProtobufUtil::toServerName)
099            .collect(Collectors.toList()))
100        .setRegionsInTransition(proto.getRegionsInTransitionList().stream()
101            .map(ClusterStatusProtos.RegionInTransition::getRegionState)
102            .map(RegionState::convert)
103            .collect(Collectors.toList()))
104        .setMasterCoprocessorNames(proto.getMasterCoprocessorsList().stream()
105            .map(HBaseProtos.Coprocessor::getName)
106            .collect(Collectors.toList()));
107    if (proto.hasClusterId()) {
108      builder.setClusterId(ClusterId.convert(proto.getClusterId()).toString());
109    }
110
111    if (proto.hasHbaseVersion()) {
112      builder.setHBaseVersion(proto.getHbaseVersion().getVersion());
113    }
114
115    if (proto.hasMaster()) {
116      builder.setMasterName(ProtobufUtil.toServerName(proto.getMaster()));
117    }
118
119    if (proto.hasBalancerOn()) {
120      builder.setBalancerOn(proto.getBalancerOn());
121    }
122
123    if (proto.hasMasterInfoPort()) {
124      builder.setMasterInfoPort(proto.getMasterInfoPort());
125    }
126    return builder.build();
127  }
128
129  /**
130   * Convert ClusterStatusProtos.Option to ClusterMetrics.Option
131   * @param option a ClusterStatusProtos.Option
132   * @return converted ClusterMetrics.Option
133   */
134  public static ClusterMetrics.Option toOption(ClusterStatusProtos.Option option) {
135    switch (option) {
136      case HBASE_VERSION: return ClusterMetrics.Option.HBASE_VERSION;
137      case LIVE_SERVERS: return ClusterMetrics.Option.LIVE_SERVERS;
138      case DEAD_SERVERS: return ClusterMetrics.Option.DEAD_SERVERS;
139      case REGIONS_IN_TRANSITION: return ClusterMetrics.Option.REGIONS_IN_TRANSITION;
140      case CLUSTER_ID: return ClusterMetrics.Option.CLUSTER_ID;
141      case MASTER_COPROCESSORS: return ClusterMetrics.Option.MASTER_COPROCESSORS;
142      case MASTER: return ClusterMetrics.Option.MASTER;
143      case BACKUP_MASTERS: return ClusterMetrics.Option.BACKUP_MASTERS;
144      case BALANCER_ON: return ClusterMetrics.Option.BALANCER_ON;
145      case MASTER_INFO_PORT: return ClusterMetrics.Option.MASTER_INFO_PORT;
146      // should not reach here
147      default: throw new IllegalArgumentException("Invalid option: " + option);
148    }
149  }
150
151  /**
152   * Convert ClusterMetrics.Option to ClusterStatusProtos.Option
153   * @param option a ClusterMetrics.Option
154   * @return converted ClusterStatusProtos.Option
155   */
156  public static ClusterStatusProtos.Option toOption(ClusterMetrics.Option option) {
157    switch (option) {
158      case HBASE_VERSION: return ClusterStatusProtos.Option.HBASE_VERSION;
159      case LIVE_SERVERS: return ClusterStatusProtos.Option.LIVE_SERVERS;
160      case DEAD_SERVERS: return ClusterStatusProtos.Option.DEAD_SERVERS;
161      case REGIONS_IN_TRANSITION: return ClusterStatusProtos.Option.REGIONS_IN_TRANSITION;
162      case CLUSTER_ID: return ClusterStatusProtos.Option.CLUSTER_ID;
163      case MASTER_COPROCESSORS: return ClusterStatusProtos.Option.MASTER_COPROCESSORS;
164      case MASTER: return ClusterStatusProtos.Option.MASTER;
165      case BACKUP_MASTERS: return ClusterStatusProtos.Option.BACKUP_MASTERS;
166      case BALANCER_ON: return ClusterStatusProtos.Option.BALANCER_ON;
167      case MASTER_INFO_PORT: return ClusterStatusProtos.Option.MASTER_INFO_PORT;
168      // should not reach here
169      default: throw new IllegalArgumentException("Invalid option: " + option);
170    }
171  }
172
173  /**
174   * Convert a list of ClusterStatusProtos.Option to an enum set of ClusterMetrics.Option
175   * @param options the pb options
176   * @return an enum set of ClusterMetrics.Option
177   */
178  public static EnumSet<ClusterMetrics.Option> toOptions(List<ClusterStatusProtos.Option> options) {
179    return options.stream().map(ClusterMetricsBuilder::toOption)
180        .collect(Collectors.toCollection(() -> EnumSet.noneOf(ClusterMetrics.Option.class)));
181  }
182
183  /**
184   * Convert an enum set of ClusterMetrics.Option to a list of ClusterStatusProtos.Option
185   * @param options the ClusterMetrics options
186   * @return a list of ClusterStatusProtos.Option
187   */
188  public static List<ClusterStatusProtos.Option> toOptions(EnumSet<ClusterMetrics.Option> options) {
189    return options.stream().map(ClusterMetricsBuilder::toOption).collect(Collectors.toList());
190  }
191
192  public static ClusterMetricsBuilder newBuilder() {
193    return new ClusterMetricsBuilder();
194  }
195  @Nullable
196  private String hbaseVersion;
197  private List<ServerName> deadServerNames = Collections.emptyList();
198  private Map<ServerName, ServerMetrics> liveServerMetrics = new TreeMap<>();
199  @Nullable
200  private ServerName masterName;
201  private List<ServerName> backupMasterNames = Collections.emptyList();
202  private List<RegionState> regionsInTransition = Collections.emptyList();
203  @Nullable
204  private String clusterId;
205  private List<String> masterCoprocessorNames = Collections.emptyList();
206  @Nullable
207  private Boolean balancerOn;
208  private int masterInfoPort;
209
210  private ClusterMetricsBuilder() {
211  }
212  public ClusterMetricsBuilder setHBaseVersion(String value) {
213    this.hbaseVersion = value;
214    return this;
215  }
216  public ClusterMetricsBuilder setDeadServerNames(List<ServerName> value) {
217    this.deadServerNames = value;
218    return this;
219  }
220
221  public ClusterMetricsBuilder setLiveServerMetrics(Map<ServerName, ServerMetrics> value) {
222    liveServerMetrics.putAll(value);
223    return this;
224  }
225
226  public ClusterMetricsBuilder setMasterName(ServerName value) {
227    this.masterName = value;
228    return this;
229  }
230  public ClusterMetricsBuilder setBackerMasterNames(List<ServerName> value) {
231    this.backupMasterNames = value;
232    return this;
233  }
234  public ClusterMetricsBuilder setRegionsInTransition(List<RegionState> value) {
235    this.regionsInTransition = value;
236    return this;
237  }
238  public ClusterMetricsBuilder setClusterId(String value) {
239    this.clusterId = value;
240    return this;
241  }
242  public ClusterMetricsBuilder setMasterCoprocessorNames(List<String> value) {
243    this.masterCoprocessorNames = value;
244    return this;
245  }
246  public ClusterMetricsBuilder setBalancerOn(@Nullable Boolean value) {
247    this.balancerOn = value;
248    return this;
249  }
250  public ClusterMetricsBuilder setMasterInfoPort(int value) {
251    this.masterInfoPort = value;
252    return this;
253  }
254  public ClusterMetrics build() {
255    return new ClusterMetricsImpl(
256        hbaseVersion,
257        deadServerNames,
258        liveServerMetrics,
259        masterName,
260        backupMasterNames,
261        regionsInTransition,
262        clusterId,
263        masterCoprocessorNames,
264        balancerOn,
265        masterInfoPort);
266  }
267  private static class ClusterMetricsImpl implements ClusterMetrics {
268    @Nullable
269    private final String hbaseVersion;
270    private final List<ServerName> deadServerNames;
271    private final Map<ServerName, ServerMetrics> liveServerMetrics;
272    @Nullable
273    private final ServerName masterName;
274    private final List<ServerName> backupMasterNames;
275    private final List<RegionState> regionsInTransition;
276    @Nullable
277    private final String clusterId;
278    private final List<String> masterCoprocessorNames;
279    @Nullable
280    private final Boolean balancerOn;
281    private final int masterInfoPort;
282
283    ClusterMetricsImpl(String hbaseVersion, List<ServerName> deadServerNames,
284        Map<ServerName, ServerMetrics> liveServerMetrics,
285        ServerName masterName,
286        List<ServerName> backupMasterNames,
287        List<RegionState> regionsInTransition,
288        String clusterId,
289        List<String> masterCoprocessorNames,
290        Boolean balancerOn,
291        int masterInfoPort) {
292      this.hbaseVersion = hbaseVersion;
293      this.deadServerNames = Preconditions.checkNotNull(deadServerNames);
294      this.liveServerMetrics = Preconditions.checkNotNull(liveServerMetrics);
295      this.masterName = masterName;
296      this.backupMasterNames = Preconditions.checkNotNull(backupMasterNames);
297      this.regionsInTransition = Preconditions.checkNotNull(regionsInTransition);
298      this.clusterId = clusterId;
299      this.masterCoprocessorNames = Preconditions.checkNotNull(masterCoprocessorNames);
300      this.balancerOn = balancerOn;
301      this.masterInfoPort = masterInfoPort;
302    }
303
304    @Override
305    public String getHBaseVersion() {
306      return hbaseVersion;
307    }
308
309    @Override
310    public List<ServerName> getDeadServerNames() {
311      return Collections.unmodifiableList(deadServerNames);
312    }
313
314    @Override
315    public Map<ServerName, ServerMetrics> getLiveServerMetrics() {
316      return Collections.unmodifiableMap(liveServerMetrics);
317    }
318
319    @Override
320    public ServerName getMasterName() {
321      return masterName;
322    }
323
324    @Override
325    public List<ServerName> getBackupMasterNames() {
326      return Collections.unmodifiableList(backupMasterNames);
327    }
328
329    @Override
330    public List<RegionState> getRegionStatesInTransition() {
331      return Collections.unmodifiableList(regionsInTransition);
332    }
333
334    @Override
335    public String getClusterId() {
336      return clusterId;
337    }
338
339    @Override
340    public List<String> getMasterCoprocessorNames() {
341      return Collections.unmodifiableList(masterCoprocessorNames);
342    }
343
344    @Override
345    public Boolean getBalancerOn() {
346      return balancerOn;
347    }
348
349    @Override
350    public int getMasterInfoPort() {
351      return masterInfoPort;
352    }
353
354    @Override
355    public String toString() {
356      StringBuilder sb = new StringBuilder(1024);
357      sb.append("Master: " + getMasterName());
358
359      int backupMastersSize = getBackupMasterNames().size();
360      sb.append("\nNumber of backup masters: " + backupMastersSize);
361      if (backupMastersSize > 0) {
362        for (ServerName serverName: getBackupMasterNames()) {
363          sb.append("\n  " + serverName);
364        }
365      }
366
367      int serversSize = getLiveServerMetrics().size();
368      sb.append("\nNumber of live region servers: " + serversSize);
369      if (serversSize > 0) {
370        for (ServerName serverName : getLiveServerMetrics().keySet()) {
371          sb.append("\n  " + serverName.getServerName());
372        }
373      }
374
375      int deadServerSize = getDeadServerNames().size();
376      sb.append("\nNumber of dead region servers: " + deadServerSize);
377      if (deadServerSize > 0) {
378        for (ServerName serverName : getDeadServerNames()) {
379          sb.append("\n  " + serverName);
380        }
381      }
382
383      sb.append("\nAverage load: " + getAverageLoad());
384      sb.append("\nNumber of requests: " + getRequestCount());
385      sb.append("\nNumber of regions: " + getRegionCount());
386
387      int ritSize = getRegionStatesInTransition().size();
388      sb.append("\nNumber of regions in transition: " + ritSize);
389      if (ritSize > 0) {
390        for (RegionState state : getRegionStatesInTransition()) {
391          sb.append("\n  " + state.toDescriptiveString());
392        }
393      }
394      return sb.toString();
395    }
396  }
397}