/*
* Copyright 2010 The Apache Software Foundation
*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.apache.hadoop.hbase.rest.model;
import java.io.IOException;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.List;
import javax.xml.bind.annotation.XmlAttribute;
import javax.xml.bind.annotation.XmlElement;
import javax.xml.bind.annotation.XmlElementWrapper;
import javax.xml.bind.annotation.XmlRootElement;
import org.apache.hadoop.hbase.rest.ProtobufMessageHandler;
import org.apache.hadoop.hbase.rest.protobuf.generated.StorageClusterStatusMessage.StorageClusterStatus;
import org.apache.hadoop.hbase.util.Bytes;
import com.google.protobuf.ByteString;
/**
* Representation of the status of a storage cluster:
* <p>
* <ul>
* <li>regions: the total number of regions served by the cluster</li>
* <li>requests: the total number of requests per second handled by the
* cluster in the last reporting interval</li>
* <li>averageLoad: the average load of the region servers in the cluster</li>
* <li>liveNodes: detailed status of the live region servers</li>
* <li>deadNodes: the names of region servers declared dead</li>
* </ul>
*
* <pre>
* <complexType name="StorageClusterStatus">
* <sequence>
* <element name="liveNode" type="tns:Node"
* maxOccurs="unbounded" minOccurs="0">
* </element>
* <element name="deadNode" type="string" maxOccurs="unbounded"
* minOccurs="0">
* </element>
* </sequence>
* <attribute name="regions" type="int"></attribute>
* <attribute name="requests" type="int"></attribute>
* <attribute name="averageLoad" type="float"></attribute>
* </complexType>
*
* <complexType name="Node">
* <sequence>
* <element name="region" type="tns:Region"
* maxOccurs="unbounded" minOccurs="0"></element>
* </sequence>
* <attribute name="name" type="string"></attribute>
* <attribute name="startCode" type="int"></attribute>
* <attribute name="requests" type="int"></attribute>
* <attribute name="heapSizeMB" type="int"></attribute>
* <attribute name="maxHeapSizeMB" type="int"></attribute>
* </complexType>
*
* <complexType name="Region">
* <attribute name="name" type="base64Binary"></attribute>
* <attribute name="stores" type="int"></attribute>
* <attribute name="storefiles" type="int"></attribute>
* <attribute name="storefileSizeMB" type="int"></attribute>
* <attribute name="memstoreSizeMB" type="int"></attribute>
* <attribute name="storefileIndexSizeMB" type="int"></attribute>
* <attribute name="readRequestsCount" type="int"></attribute>
* <attribute name="writeRequestsCount" type="int"></attribute>
* <attribute name="rootIndexSizeKB" type="int"></attribute>
* <attribute name="totalStaticIndexSizeKB" type="int"></attribute>
* <attribute name="totalStaticBloomSizeKB" type="int"></attribute>
* <attribute name="totalCompactingKVs" type="int"></attribute>
* <attribute name="currentCompactedKVs" type="int"></attribute>
* </complexType>
* </pre>
*/
@XmlRootElement(name="ClusterStatus")
public class StorageClusterStatusModel
implements Serializable, ProtobufMessageHandler {
private static final long serialVersionUID = 1L;
/**
* Represents a region server.
*/
public static class Node {
/**
* Represents a region hosted on a region server.
*/
public static class Region {
private byte[] name;
private int stores;
private int storefiles;
private int storefileSizeMB;
private int memstoreSizeMB;
private int storefileIndexSizeMB;
private long readRequestsCount;
private long writeRequestsCount;
private int rootIndexSizeKB;
private int totalStaticIndexSizeKB;
private int totalStaticBloomSizeKB;
private long totalCompactingKVs;
private long currentCompactedKVs;
/**
* Default constructor
*/
public Region() {}
/**
* Constructor
* @param name the region name
*/
public Region(byte[] name) {
this.name = name;
}
/**
* Constructor
* @param name the region name
* @param stores the number of stores
* @param storefiles the number of store files
* @param storefileSizeMB total size of store files, in MB
* @param memstoreSizeMB total size of memstore, in MB
* @param storefileIndexSizeMB total size of store file indexes, in MB
*/
public Region(byte[] name, int stores, int storefiles,
int storefileSizeMB, int memstoreSizeMB, int storefileIndexSizeMB,
long readRequestsCount, long writeRequestsCount, int rootIndexSizeKB,
int totalStaticIndexSizeKB, int totalStaticBloomSizeKB,
long totalCompactingKVs, long currentCompactedKVs) {
this.name = name;
this.stores = stores;
this.storefiles = storefiles;
this.storefileSizeMB = storefileSizeMB;
this.memstoreSizeMB = memstoreSizeMB;
this.storefileIndexSizeMB = storefileIndexSizeMB;
this.readRequestsCount = readRequestsCount;
this.writeRequestsCount = writeRequestsCount;
this.rootIndexSizeKB = rootIndexSizeKB;
this.totalStaticIndexSizeKB = totalStaticIndexSizeKB;
this.totalStaticBloomSizeKB = totalStaticBloomSizeKB;
this.totalCompactingKVs = totalCompactingKVs;
this.currentCompactedKVs = currentCompactedKVs;
}
/**
* @return the region name
*/
@XmlAttribute
public byte[] getName() {
return name;
}
/**
* @return the number of stores
*/
@XmlAttribute
public int getStores() {
return stores;
}
/**
* @return the number of store files
*/
@XmlAttribute
public int getStorefiles() {
return storefiles;
}
/**
* @return the total size of store files, in MB
*/
@XmlAttribute
public int getStorefileSizeMB() {
return storefileSizeMB;
}
/**
* @return memstore size, in MB
*/
@XmlAttribute
public int getMemstoreSizeMB() {
return memstoreSizeMB;
}
/**
* @return the total size of store file indexes, in MB
*/
@XmlAttribute
public int getStorefileIndexSizeMB() {
return storefileIndexSizeMB;
}
/**
* @return the current total read requests made to region
*/
@XmlAttribute
public long getReadRequestsCount() {
return readRequestsCount;
}
/**
* @return the current total write requests made to region
*/
@XmlAttribute
public long getWriteRequestsCount() {
return writeRequestsCount;
}
/**
* @return The current total size of root-level indexes for the region, in KB.
*/
@XmlAttribute
public int getRootIndexSizeKB() {
return rootIndexSizeKB;
}
/**
* @return The total size of static index, in KB
*/
@XmlAttribute
public int getTotalStaticIndexSizeKB() {
return totalStaticIndexSizeKB;
}
/**
* @return The total size of static bloom, in KB
*/
@XmlAttribute
public int getTotalStaticBloomSizeKB() {
return totalStaticBloomSizeKB;
}
/**
* @return The total number of compacting key-values
*/
@XmlAttribute
public long getTotalCompactingKVs() {
return totalCompactingKVs;
}
/**
* @return The number of current compacted key-values
*/
@XmlAttribute
public long getCurrentCompactedKVs() {
return currentCompactedKVs;
}
/**
* @param readRequestsCount The current total read requests made to region
*/
public void setReadRequestsCount(long readRequestsCount) {
this.readRequestsCount = readRequestsCount;
}
/**
* @param rootIndexSizeKB The current total size of root-level indexes
* for the region, in KB
*/
public void setRootIndexSizeKB(int rootIndexSizeKB) {
this.rootIndexSizeKB = rootIndexSizeKB;
}
/**
* @param writeRequestsCount The current total write requests made to region
*/
public void setWriteRequestsCount(long writeRequestsCount) {
this.writeRequestsCount = writeRequestsCount;
}
/**
* @param currentCompactedKVs The completed count of key values
* in currently running compaction
*/
public void setCurrentCompactedKVs(long currentCompactedKVs) {
this.currentCompactedKVs = currentCompactedKVs;
}
/**
* @param totalCompactingKVs The total compacting key values
* in currently running compaction
*/
public void setTotalCompactingKVs(long totalCompactingKVs) {
this.totalCompactingKVs = totalCompactingKVs;
}
/**
* @param totalStaticBloomSizeKB The total size of all Bloom filter blocks,
* not just loaded into the block cache, in KB.
*/
public void setTotalStaticBloomSizeKB(int totalStaticBloomSizeKB) {
this.totalStaticBloomSizeKB = totalStaticBloomSizeKB;
}
/**
* @param totalStaticIndexSizeKB The total size of all index blocks,
* not just the root level, in KB.
*/
public void setTotalStaticIndexSizeKB(int totalStaticIndexSizeKB) {
this.totalStaticIndexSizeKB = totalStaticIndexSizeKB;
}
/**
* @param name the region name
*/
public void setName(byte[] name) {
this.name = name;
}
/**
* @param stores the number of stores
*/
public void setStores(int stores) {
this.stores = stores;
}
/**
* @param storefiles the number of store files
*/
public void setStorefiles(int storefiles) {
this.storefiles = storefiles;
}
/**
* @param storefileSizeMB total size of store files, in MB
*/
public void setStorefileSizeMB(int storefileSizeMB) {
this.storefileSizeMB = storefileSizeMB;
}
/**
* @param memstoreSizeMB memstore size, in MB
*/
public void setMemstoreSizeMB(int memstoreSizeMB) {
this.memstoreSizeMB = memstoreSizeMB;
}
/**
* @param storefileIndexSizeMB total size of store file indexes, in MB
*/
public void setStorefileIndexSizeMB(int storefileIndexSizeMB) {
this.storefileIndexSizeMB = storefileIndexSizeMB;
}
}
private String name;
private long startCode;
private int requests;
private int heapSizeMB;
private int maxHeapSizeMB;
private List<Region> regions = new ArrayList<Region>();
/**
* Add a region name to the list
* @param name the region name
*/
public void addRegion(byte[] name, int stores, int storefiles,
int storefileSizeMB, int memstoreSizeMB, int storefileIndexSizeMB,
long readRequestsCount, long writeRequestsCount, int rootIndexSizeKB,
int totalStaticIndexSizeKB, int totalStaticBloomSizeKB,
long totalCompactingKVs, long currentCompactedKVs) {
regions.add(new Region(name, stores, storefiles, storefileSizeMB,
memstoreSizeMB, storefileIndexSizeMB, readRequestsCount,
writeRequestsCount, rootIndexSizeKB, totalStaticIndexSizeKB,
totalStaticBloomSizeKB, totalCompactingKVs, currentCompactedKVs));
}
/**
* @param index the index
* @return the region name
*/
public Region getRegion(int index) {
return regions.get(index);
}
/**
* Default constructor
*/
public Node() {}
/**
* Constructor
* @param name the region server name
* @param startCode the region server's start code
*/
public Node(String name, long startCode) {
this.name = name;
this.startCode = startCode;
}
/**
* @return the region server's name
*/
@XmlAttribute
public String getName() {
return name;
}
/**
* @return the region server's start code
*/
@XmlAttribute
public long getStartCode() {
return startCode;
}
/**
* @return the current heap size, in MB
*/
@XmlAttribute
public int getHeapSizeMB() {
return heapSizeMB;
}
/**
* @return the maximum heap size, in MB
*/
@XmlAttribute
public int getMaxHeapSizeMB() {
return maxHeapSizeMB;
}
/**
* @return the list of regions served by the region server
*/
@XmlElement(name="Region")
public List<Region> getRegions() {
return regions;
}
/**
* @return the number of requests per second processed by the region server
*/
@XmlAttribute
public int getRequests() {
return requests;
}
/**
* @param name the region server's hostname
*/
public void setName(String name) {
this.name = name;
}
/**
* @param startCode the region server's start code
*/
public void setStartCode(long startCode) {
this.startCode = startCode;
}
/**
* @param heapSizeMB the current heap size, in MB
*/
public void setHeapSizeMB(int heapSizeMB) {
this.heapSizeMB = heapSizeMB;
}
/**
* @param maxHeapSizeMB the maximum heap size, in MB
*/
public void setMaxHeapSizeMB(int maxHeapSizeMB) {
this.maxHeapSizeMB = maxHeapSizeMB;
}
/**
* @param regions a list of regions served by the region server
*/
public void setRegions(List<Region> regions) {
this.regions = regions;
}
/**
* @param requests the number of requests per second processed by the
* region server
*/
public void setRequests(int requests) {
this.requests = requests;
}
}
private List<Node> liveNodes = new ArrayList<Node>();
private List<String> deadNodes = new ArrayList<String>();
private int regions;
private int requests;
private double averageLoad;
/**
* Add a live node to the cluster representation.
* @param name the region server name
* @param startCode the region server's start code
* @param heapSizeMB the current heap size, in MB
* @param maxHeapSizeMB the maximum heap size, in MB
*/
public Node addLiveNode(String name, long startCode, int heapSizeMB,
int maxHeapSizeMB) {
Node node = new Node(name, startCode);
node.setHeapSizeMB(heapSizeMB);
node.setMaxHeapSizeMB(maxHeapSizeMB);
liveNodes.add(node);
return node;
}
/**
* @param index the index
* @return the region server model
*/
public Node getLiveNode(int index) {
return liveNodes.get(index);
}
/**
* Add a dead node to the cluster representation.
* @param node the dead region server's name
*/
public void addDeadNode(String node) {
deadNodes.add(node);
}
/**
* @param index the index
* @return the dead region server's name
*/
public String getDeadNode(int index) {
return deadNodes.get(index);
}
/**
* Default constructor
*/
public StorageClusterStatusModel() {}
/**
* @return the list of live nodes
*/
@XmlElement(name="Node")
@XmlElementWrapper(name="LiveNodes")
public List<Node> getLiveNodes() {
return liveNodes;
}
/**
* @return the list of dead nodes
*/
@XmlElement(name="Node")
@XmlElementWrapper(name="DeadNodes")
public List<String> getDeadNodes() {
return deadNodes;
}
/**
* @return the total number of regions served by the cluster
*/
@XmlAttribute
public int getRegions() {
return regions;
}
/**
* @return the total number of requests per second handled by the cluster in
* the last reporting interval
*/
@XmlAttribute
public int getRequests() {
return requests;
}
/**
* @return the average load of the region servers in the cluster
*/
@XmlAttribute
public double getAverageLoad() {
return averageLoad;
}
/**
* @param nodes the list of live node models
*/
public void setLiveNodes(List<Node> nodes) {
this.liveNodes = nodes;
}
/**
* @param nodes the list of dead node names
*/
public void setDeadNodes(List<String> nodes) {
this.deadNodes = nodes;
}
/**
* @param regions the total number of regions served by the cluster
*/
public void setRegions(int regions) {
this.regions = regions;
}
/**
* @param requests the total number of requests per second handled by the
* cluster
*/
public void setRequests(int requests) {
this.requests = requests;
}
/**
* @param averageLoad the average load of region servers in the cluster
*/
public void setAverageLoad(double averageLoad) {
this.averageLoad = averageLoad;
}
/* (non-Javadoc)
* @see java.lang.Object#toString()
*/
@Override
public String toString() {
StringBuilder sb = new StringBuilder();
sb.append(String.format("%d live servers, %d dead servers, " +
"%.4f average load\n\n", liveNodes.size(), deadNodes.size(),
averageLoad));
if (!liveNodes.isEmpty()) {
sb.append(liveNodes.size());
sb.append(" live servers\n");
for (Node node: liveNodes) {
sb.append(" ");
sb.append(node.name);
sb.append(' ');
sb.append(node.startCode);
sb.append("\n requests=");
sb.append(node.requests);
sb.append(", regions=");
sb.append(node.regions.size());
sb.append("\n heapSizeMB=");
sb.append(node.heapSizeMB);
sb.append("\n maxHeapSizeMB=");
sb.append(node.maxHeapSizeMB);
sb.append("\n\n");
for (Node.Region region: node.regions) {
sb.append(" ");
sb.append(Bytes.toString(region.name));
sb.append("\n stores=");
sb.append(region.stores);
sb.append("\n storefiless=");
sb.append(region.storefiles);
sb.append("\n storefileSizeMB=");
sb.append(region.storefileSizeMB);
sb.append("\n memstoreSizeMB=");
sb.append(region.memstoreSizeMB);
sb.append("\n storefileIndexSizeMB=");
sb.append(region.storefileIndexSizeMB);
sb.append("\n readRequestsCount=");
sb.append(region.readRequestsCount);
sb.append("\n writeRequestsCount=");
sb.append(region.writeRequestsCount);
sb.append("\n rootIndexSizeKB=");
sb.append(region.rootIndexSizeKB);
sb.append("\n totalStaticIndexSizeKB=");
sb.append(region.totalStaticIndexSizeKB);
sb.append("\n totalStaticBloomSizeKB=");
sb.append(region.totalStaticBloomSizeKB);
sb.append("\n totalCompactingKVs=");
sb.append(region.totalCompactingKVs);
sb.append("\n currentCompactedKVs=");
sb.append(region.currentCompactedKVs);
sb.append('\n');
}
sb.append('\n');
}
}
if (!deadNodes.isEmpty()) {
sb.append('\n');
sb.append(deadNodes.size());
sb.append(" dead servers\n");
for (String node: deadNodes) {
sb.append(" ");
sb.append(node);
sb.append('\n');
}
}
return sb.toString();
}
@Override
public byte[] createProtobufOutput() {
StorageClusterStatus.Builder builder = StorageClusterStatus.newBuilder();
builder.setRegions(regions);
builder.setRequests(requests);
builder.setAverageLoad(averageLoad);
for (Node node: liveNodes) {
StorageClusterStatus.Node.Builder nodeBuilder =
StorageClusterStatus.Node.newBuilder();
nodeBuilder.setName(node.name);
nodeBuilder.setStartCode(node.startCode);
nodeBuilder.setRequests(node.requests);
nodeBuilder.setHeapSizeMB(node.heapSizeMB);
nodeBuilder.setMaxHeapSizeMB(node.maxHeapSizeMB);
for (Node.Region region: node.regions) {
StorageClusterStatus.Region.Builder regionBuilder =
StorageClusterStatus.Region.newBuilder();
regionBuilder.setName(ByteString.copyFrom(region.name));
regionBuilder.setStores(region.stores);
regionBuilder.setStorefiles(region.storefiles);
regionBuilder.setStorefileSizeMB(region.storefileSizeMB);
regionBuilder.setMemstoreSizeMB(region.memstoreSizeMB);
regionBuilder.setStorefileIndexSizeMB(region.storefileIndexSizeMB);
regionBuilder.setReadRequestsCount(region.readRequestsCount);
regionBuilder.setWriteRequestsCount(region.writeRequestsCount);
regionBuilder.setRootIndexSizeKB(region.rootIndexSizeKB);
regionBuilder.setTotalStaticIndexSizeKB(region.totalStaticIndexSizeKB);
regionBuilder.setTotalStaticBloomSizeKB(region.totalStaticBloomSizeKB);
regionBuilder.setTotalCompactingKVs(region.totalCompactingKVs);
regionBuilder.setCurrentCompactedKVs(region.currentCompactedKVs);
nodeBuilder.addRegions(regionBuilder);
}
builder.addLiveNodes(nodeBuilder);
}
for (String node: deadNodes) {
builder.addDeadNodes(node);
}
return builder.build().toByteArray();
}
@Override
public ProtobufMessageHandler getObjectFromMessage(byte[] message)
throws IOException {
StorageClusterStatus.Builder builder = StorageClusterStatus.newBuilder();
builder.mergeFrom(message);
if (builder.hasRegions()) {
regions = builder.getRegions();
}
if (builder.hasRequests()) {
requests = builder.getRequests();
}
if (builder.hasAverageLoad()) {
averageLoad = builder.getAverageLoad();
}
for (StorageClusterStatus.Node node: builder.getLiveNodesList()) {
long startCode = node.hasStartCode() ? node.getStartCode() : -1;
StorageClusterStatusModel.Node nodeModel =
addLiveNode(node.getName(), startCode, node.getHeapSizeMB(),
node.getMaxHeapSizeMB());
int requests = node.hasRequests() ? node.getRequests() : 0;
nodeModel.setRequests(requests);
for (StorageClusterStatus.Region region: node.getRegionsList()) {
nodeModel.addRegion(
region.getName().toByteArray(),
region.getStores(),
region.getStorefiles(),
region.getStorefileSizeMB(),
region.getMemstoreSizeMB(),
region.getStorefileIndexSizeMB(),
region.getReadRequestsCount(),
region.getWriteRequestsCount(),
region.getRootIndexSizeKB(),
region.getTotalStaticIndexSizeKB(),
region.getTotalStaticBloomSizeKB(),
region.getTotalCompactingKVs(),
region.getCurrentCompactedKVs());
}
}
for (String node: builder.getDeadNodesList()) {
addDeadNode(node);
}
return this;
}
}