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}