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}