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