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