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;
029
030import org.apache.hadoop.hbase.client.RegionStatesCount;
031import org.apache.hadoop.hbase.master.RegionState;
032import org.apache.yetus.audience.InterfaceAudience;
033
034import org.apache.hbase.thirdparty.com.google.common.base.Preconditions;
035import org.apache.hbase.thirdparty.com.google.protobuf.UnsafeByteOperations;
036import org.apache.hadoop.hbase.shaded.protobuf.ProtobufUtil;
037import org.apache.hadoop.hbase.shaded.protobuf.generated.ClusterStatusProtos;
038import org.apache.hadoop.hbase.shaded.protobuf.generated.FSProtos;
039import org.apache.hadoop.hbase.shaded.protobuf.generated.HBaseProtos;
040
041@InterfaceAudience.Private
042public final class ClusterMetricsBuilder {
043
044  public static ClusterStatusProtos.ClusterStatus toClusterStatus(ClusterMetrics metrics) {
045    ClusterStatusProtos.ClusterStatus.Builder builder
046        = ClusterStatusProtos.ClusterStatus.newBuilder()
047        .addAllBackupMasters(metrics.getBackupMasterNames().stream()
048            .map(ProtobufUtil::toServerName).collect(Collectors.toList()))
049        .addAllDeadServers(metrics.getDeadServerNames().stream()
050            .map(ProtobufUtil::toServerName).collect(Collectors.toList()))
051        .addAllLiveServers(metrics.getLiveServerMetrics().entrySet().stream()
052            .map(s -> ClusterStatusProtos.LiveServerInfo
053                .newBuilder()
054                .setServer(ProtobufUtil.toServerName(s.getKey()))
055                .setServerLoad(ServerMetricsBuilder.toServerLoad(s.getValue()))
056                .build())
057            .collect(Collectors.toList()))
058        .addAllMasterCoprocessors(metrics.getMasterCoprocessorNames().stream()
059            .map(n -> HBaseProtos.Coprocessor.newBuilder().setName(n).build())
060            .collect(Collectors.toList()))
061        .addAllRegionsInTransition(metrics.getRegionStatesInTransition().stream()
062            .map(r -> ClusterStatusProtos.RegionInTransition
063                .newBuilder()
064                .setSpec(HBaseProtos.RegionSpecifier
065                    .newBuilder()
066                    .setType(HBaseProtos.RegionSpecifier.RegionSpecifierType.REGION_NAME)
067                    .setValue(UnsafeByteOperations.unsafeWrap(r.getRegion().getRegionName()))
068                    .build())
069                .setRegionState(r.convert())
070                .build())
071            .collect(Collectors.toList()))
072        .setMasterInfoPort(metrics.getMasterInfoPort())
073        .addAllTableRegionStatesCount(metrics.getTableRegionStatesCount().entrySet().stream()
074          .map(status ->
075            ClusterStatusProtos.TableRegionStatesCount.newBuilder()
076              .setTableName(ProtobufUtil.toProtoTableName((status.getKey())))
077              .setRegionStatesCount(ProtobufUtil.toTableRegionStatesCount(status.getValue()))
078              .build())
079          .collect(Collectors.toList()));
080    if (metrics.getMasterName() != null) {
081      builder.setMaster(ProtobufUtil.toServerName((metrics.getMasterName())));
082    }
083    if (metrics.getBalancerOn() != null) {
084      builder.setBalancerOn(metrics.getBalancerOn());
085    }
086    if (metrics.getClusterId() != null) {
087      builder.setClusterId(new ClusterId(metrics.getClusterId()).convert());
088    }
089    if (metrics.getHBaseVersion() != null) {
090      builder.setHbaseVersion(
091          FSProtos.HBaseVersionFileContent.newBuilder()
092              .setVersion(metrics.getHBaseVersion()));
093    }
094    return builder.build();
095  }
096
097  public static ClusterMetrics toClusterMetrics(
098      ClusterStatusProtos.ClusterStatus proto) {
099    ClusterMetricsBuilder builder = ClusterMetricsBuilder.newBuilder();
100    builder.setLiveServerMetrics(proto.getLiveServersList().stream()
101        .collect(Collectors.toMap(e -> ProtobufUtil.toServerName(e.getServer()),
102            ServerMetricsBuilder::toServerMetrics)))
103        .setDeadServerNames(proto.getDeadServersList().stream()
104            .map(ProtobufUtil::toServerName)
105            .collect(Collectors.toList()))
106        .setBackerMasterNames(proto.getBackupMastersList().stream()
107            .map(ProtobufUtil::toServerName)
108            .collect(Collectors.toList()))
109        .setRegionsInTransition(proto.getRegionsInTransitionList().stream()
110            .map(ClusterStatusProtos.RegionInTransition::getRegionState)
111            .map(RegionState::convert)
112            .collect(Collectors.toList()))
113        .setMasterCoprocessorNames(proto.getMasterCoprocessorsList().stream()
114            .map(HBaseProtos.Coprocessor::getName)
115            .collect(Collectors.toList()))
116        .setTableRegionStatesCount(
117          proto.getTableRegionStatesCountList().stream()
118          .collect(Collectors.toMap(
119            e -> ProtobufUtil.toTableName(e.getTableName()),
120            e -> ProtobufUtil.toTableRegionStatesCount(e.getRegionStatesCount()))));
121    if (proto.hasClusterId()) {
122      builder.setClusterId(ClusterId.convert(proto.getClusterId()).toString());
123    }
124
125    if (proto.hasHbaseVersion()) {
126      builder.setHBaseVersion(proto.getHbaseVersion().getVersion());
127    }
128
129    if (proto.hasMaster()) {
130      builder.setMasterName(ProtobufUtil.toServerName(proto.getMaster()));
131    }
132
133    if (proto.hasBalancerOn()) {
134      builder.setBalancerOn(proto.getBalancerOn());
135    }
136
137    if (proto.hasMasterInfoPort()) {
138      builder.setMasterInfoPort(proto.getMasterInfoPort());
139    }
140    return builder.build();
141  }
142
143  /**
144   * Convert ClusterStatusProtos.Option to ClusterMetrics.Option
145   * @param option a ClusterStatusProtos.Option
146   * @return converted ClusterMetrics.Option
147   */
148  public static ClusterMetrics.Option toOption(ClusterStatusProtos.Option option) {
149    switch (option) {
150      case HBASE_VERSION: return ClusterMetrics.Option.HBASE_VERSION;
151      case LIVE_SERVERS: return ClusterMetrics.Option.LIVE_SERVERS;
152      case DEAD_SERVERS: return ClusterMetrics.Option.DEAD_SERVERS;
153      case REGIONS_IN_TRANSITION: return ClusterMetrics.Option.REGIONS_IN_TRANSITION;
154      case CLUSTER_ID: return ClusterMetrics.Option.CLUSTER_ID;
155      case MASTER_COPROCESSORS: return ClusterMetrics.Option.MASTER_COPROCESSORS;
156      case MASTER: return ClusterMetrics.Option.MASTER;
157      case BACKUP_MASTERS: return ClusterMetrics.Option.BACKUP_MASTERS;
158      case BALANCER_ON: return ClusterMetrics.Option.BALANCER_ON;
159      case MASTER_INFO_PORT: return ClusterMetrics.Option.MASTER_INFO_PORT;
160      case TABLE_TO_REGIONS_COUNT: return ClusterMetrics.Option.TABLE_TO_REGIONS_COUNT;
161      // should not reach here
162      default: throw new IllegalArgumentException("Invalid option: " + option);
163    }
164  }
165
166  /**
167   * Convert ClusterMetrics.Option to ClusterStatusProtos.Option
168   * @param option a ClusterMetrics.Option
169   * @return converted ClusterStatusProtos.Option
170   */
171  public static ClusterStatusProtos.Option toOption(ClusterMetrics.Option option) {
172    switch (option) {
173      case HBASE_VERSION: return ClusterStatusProtos.Option.HBASE_VERSION;
174      case LIVE_SERVERS: return ClusterStatusProtos.Option.LIVE_SERVERS;
175      case DEAD_SERVERS: return ClusterStatusProtos.Option.DEAD_SERVERS;
176      case REGIONS_IN_TRANSITION: return ClusterStatusProtos.Option.REGIONS_IN_TRANSITION;
177      case CLUSTER_ID: return ClusterStatusProtos.Option.CLUSTER_ID;
178      case MASTER_COPROCESSORS: return ClusterStatusProtos.Option.MASTER_COPROCESSORS;
179      case MASTER: return ClusterStatusProtos.Option.MASTER;
180      case BACKUP_MASTERS: return ClusterStatusProtos.Option.BACKUP_MASTERS;
181      case BALANCER_ON: return ClusterStatusProtos.Option.BALANCER_ON;
182      case MASTER_INFO_PORT: return ClusterStatusProtos.Option.MASTER_INFO_PORT;
183      case TABLE_TO_REGIONS_COUNT: return ClusterStatusProtos.Option.TABLE_TO_REGIONS_COUNT;
184      // should not reach here
185      default: throw new IllegalArgumentException("Invalid option: " + option);
186    }
187  }
188
189  /**
190   * Convert a list of ClusterStatusProtos.Option to an enum set of ClusterMetrics.Option
191   * @param options the pb options
192   * @return an enum set of ClusterMetrics.Option
193   */
194  public static EnumSet<ClusterMetrics.Option> toOptions(List<ClusterStatusProtos.Option> options) {
195    return options.stream().map(ClusterMetricsBuilder::toOption)
196        .collect(Collectors.toCollection(() -> EnumSet.noneOf(ClusterMetrics.Option.class)));
197  }
198
199  /**
200   * Convert an enum set of ClusterMetrics.Option to a list of ClusterStatusProtos.Option
201   * @param options the ClusterMetrics options
202   * @return a list of ClusterStatusProtos.Option
203   */
204  public static List<ClusterStatusProtos.Option> toOptions(EnumSet<ClusterMetrics.Option> options) {
205    return options.stream().map(ClusterMetricsBuilder::toOption).collect(Collectors.toList());
206  }
207
208  public static ClusterMetricsBuilder newBuilder() {
209    return new ClusterMetricsBuilder();
210  }
211  @Nullable
212  private String hbaseVersion;
213  private List<ServerName> deadServerNames = Collections.emptyList();
214  private Map<ServerName, ServerMetrics> liveServerMetrics = new TreeMap<>();
215  @Nullable
216  private ServerName masterName;
217  private List<ServerName> backupMasterNames = Collections.emptyList();
218  private List<RegionState> regionsInTransition = Collections.emptyList();
219  @Nullable
220  private String clusterId;
221  private List<String> masterCoprocessorNames = Collections.emptyList();
222  @Nullable
223  private Boolean balancerOn;
224  private int masterInfoPort;
225  private Map<TableName, RegionStatesCount> tableRegionStatesCount = Collections.emptyMap();
226
227  private ClusterMetricsBuilder() {
228  }
229  public ClusterMetricsBuilder setHBaseVersion(String value) {
230    this.hbaseVersion = value;
231    return this;
232  }
233  public ClusterMetricsBuilder setDeadServerNames(List<ServerName> value) {
234    this.deadServerNames = value;
235    return this;
236  }
237
238  public ClusterMetricsBuilder setLiveServerMetrics(Map<ServerName, ServerMetrics> value) {
239    liveServerMetrics.putAll(value);
240    return this;
241  }
242
243  public ClusterMetricsBuilder setMasterName(ServerName value) {
244    this.masterName = value;
245    return this;
246  }
247  public ClusterMetricsBuilder setBackerMasterNames(List<ServerName> value) {
248    this.backupMasterNames = value;
249    return this;
250  }
251  public ClusterMetricsBuilder setRegionsInTransition(List<RegionState> value) {
252    this.regionsInTransition = value;
253    return this;
254  }
255  public ClusterMetricsBuilder setClusterId(String value) {
256    this.clusterId = value;
257    return this;
258  }
259  public ClusterMetricsBuilder setMasterCoprocessorNames(List<String> value) {
260    this.masterCoprocessorNames = value;
261    return this;
262  }
263  public ClusterMetricsBuilder setBalancerOn(@Nullable Boolean value) {
264    this.balancerOn = value;
265    return this;
266  }
267  public ClusterMetricsBuilder setMasterInfoPort(int value) {
268    this.masterInfoPort = value;
269    return this;
270  }
271
272  public ClusterMetricsBuilder setTableRegionStatesCount(
273      Map<TableName, RegionStatesCount> tableRegionStatesCount) {
274    this.tableRegionStatesCount = tableRegionStatesCount;
275    return this;
276  }
277
278  public ClusterMetrics build() {
279    return new ClusterMetricsImpl(
280        hbaseVersion,
281        deadServerNames,
282        liveServerMetrics,
283        masterName,
284        backupMasterNames,
285        regionsInTransition,
286        clusterId,
287        masterCoprocessorNames,
288        balancerOn,
289        masterInfoPort,
290        tableRegionStatesCount
291    );
292  }
293  private static class ClusterMetricsImpl implements ClusterMetrics {
294    @Nullable
295    private final String hbaseVersion;
296    private final List<ServerName> deadServerNames;
297    private final Map<ServerName, ServerMetrics> liveServerMetrics;
298    @Nullable
299    private final ServerName masterName;
300    private final List<ServerName> backupMasterNames;
301    private final List<RegionState> regionsInTransition;
302    @Nullable
303    private final String clusterId;
304    private final List<String> masterCoprocessorNames;
305    @Nullable
306    private final Boolean balancerOn;
307    private final int masterInfoPort;
308    private final Map<TableName, RegionStatesCount> tableRegionStatesCount;
309
310    ClusterMetricsImpl(String hbaseVersion, List<ServerName> deadServerNames,
311        Map<ServerName, ServerMetrics> liveServerMetrics,
312        ServerName masterName,
313        List<ServerName> backupMasterNames,
314        List<RegionState> regionsInTransition,
315        String clusterId,
316        List<String> masterCoprocessorNames,
317        Boolean balancerOn,
318        int masterInfoPort,
319        Map<TableName, RegionStatesCount> tableRegionStatesCount) {
320      this.hbaseVersion = hbaseVersion;
321      this.deadServerNames = Preconditions.checkNotNull(deadServerNames);
322      this.liveServerMetrics = Preconditions.checkNotNull(liveServerMetrics);
323      this.masterName = masterName;
324      this.backupMasterNames = Preconditions.checkNotNull(backupMasterNames);
325      this.regionsInTransition = Preconditions.checkNotNull(regionsInTransition);
326      this.clusterId = clusterId;
327      this.masterCoprocessorNames = Preconditions.checkNotNull(masterCoprocessorNames);
328      this.balancerOn = balancerOn;
329      this.masterInfoPort = masterInfoPort;
330      this.tableRegionStatesCount = Preconditions.checkNotNull(tableRegionStatesCount);
331    }
332
333    @Override
334    public String getHBaseVersion() {
335      return hbaseVersion;
336    }
337
338    @Override
339    public List<ServerName> getDeadServerNames() {
340      return Collections.unmodifiableList(deadServerNames);
341    }
342
343    @Override
344    public Map<ServerName, ServerMetrics> getLiveServerMetrics() {
345      return Collections.unmodifiableMap(liveServerMetrics);
346    }
347
348    @Override
349    public ServerName getMasterName() {
350      return masterName;
351    }
352
353    @Override
354    public List<ServerName> getBackupMasterNames() {
355      return Collections.unmodifiableList(backupMasterNames);
356    }
357
358    @Override
359    public List<RegionState> getRegionStatesInTransition() {
360      return Collections.unmodifiableList(regionsInTransition);
361    }
362
363    @Override
364    public String getClusterId() {
365      return clusterId;
366    }
367
368    @Override
369    public List<String> getMasterCoprocessorNames() {
370      return Collections.unmodifiableList(masterCoprocessorNames);
371    }
372
373    @Override
374    public Boolean getBalancerOn() {
375      return balancerOn;
376    }
377
378    @Override
379    public int getMasterInfoPort() {
380      return masterInfoPort;
381    }
382
383    @Override
384    public Map<TableName, RegionStatesCount> getTableRegionStatesCount() {
385      return Collections.unmodifiableMap(tableRegionStatesCount);
386    }
387
388    @Override
389    public String toString() {
390      StringBuilder sb = new StringBuilder(1024);
391      sb.append("Master: " + getMasterName());
392
393      int backupMastersSize = getBackupMasterNames().size();
394      sb.append("\nNumber of backup masters: " + backupMastersSize);
395      if (backupMastersSize > 0) {
396        for (ServerName serverName: getBackupMasterNames()) {
397          sb.append("\n  " + serverName);
398        }
399      }
400
401      int serversSize = getLiveServerMetrics().size();
402      sb.append("\nNumber of live region servers: " + serversSize);
403      if (serversSize > 0) {
404        for (ServerName serverName : getLiveServerMetrics().keySet()) {
405          sb.append("\n  " + serverName.getServerName());
406        }
407      }
408
409      int deadServerSize = getDeadServerNames().size();
410      sb.append("\nNumber of dead region servers: " + deadServerSize);
411      if (deadServerSize > 0) {
412        for (ServerName serverName : getDeadServerNames()) {
413          sb.append("\n  " + serverName);
414        }
415      }
416
417      sb.append("\nAverage load: " + getAverageLoad());
418      sb.append("\nNumber of requests: " + getRequestCount());
419      sb.append("\nNumber of regions: " + getRegionCount());
420
421      int ritSize = getRegionStatesInTransition().size();
422      sb.append("\nNumber of regions in transition: " + ritSize);
423      if (ritSize > 0) {
424        for (RegionState state : getRegionStatesInTransition()) {
425          sb.append("\n  " + state.toDescriptiveString());
426        }
427      }
428      return sb.toString();
429    }
430  }
431}