/** * Copyright 2007 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; import java.io.DataInput; import java.io.DataOutput; import java.io.IOException; import java.util.ArrayList; import java.util.Collection; import java.util.Collections; import org.apache.hadoop.hbase.util.Bytes; import org.apache.hadoop.hbase.util.Strings; import org.apache.hadoop.io.Writable; import org.apache.hadoop.io.WritableComparable; /** * This class encapsulates metrics for determining the load on a HRegionServer */ public class HServerLoad implements WritableComparable<HServerLoad> { /** number of regions */ // could just use regionLoad.size() but master.RegionManager likes to play // around with this value while passing HServerLoad objects around during // balancer calculations private int numberOfRegions; /** number of requests since last report */ private int numberOfRequests; /** the amount of used heap, in MB */ private int usedHeapMB; /** the maximum allowable size of the heap, in MB */ private int maxHeapMB; /** per-region load metrics */ private ArrayList<RegionLoad> regionLoad = new ArrayList<RegionLoad>(); /** * Encapsulates per-region loading metrics. */ public static class RegionLoad implements Writable { /** the region name */ private byte[] name; /** the number of stores for the region */ private int stores; /** the number of storefiles for the region */ private int storefiles; /** the current total size of the store files for the region, in MB */ private int storefileSizeMB; /** the current size of the memstore for the region, in MB */ private int memstoreSizeMB; /** the current total size of storefile indexes for the region, in MB */ private int storefileIndexSizeMB; /** * Constructor, for Writable */ public RegionLoad() { super(); } /** * @param name * @param stores * @param storefiles * @param storefileSizeMB * @param memstoreSizeMB * @param storefileIndexSizeMB */ public RegionLoad(final byte[] name, final int stores, final int storefiles, final int storefileSizeMB, final int memstoreSizeMB, final int storefileIndexSizeMB) { this.name = name; this.stores = stores; this.storefiles = storefiles; this.storefileSizeMB = storefileSizeMB; this.memstoreSizeMB = memstoreSizeMB; this.storefileIndexSizeMB = storefileIndexSizeMB; } // Getters /** * @return the region name */ public byte[] getName() { return name; } /** * @return the region name as a string */ public String getNameAsString() { return Bytes.toString(name); } /** * @return the number of stores */ public int getStores() { return stores; } /** * @return the number of storefiles */ public int getStorefiles() { return storefiles; } /** * @return the total size of the storefiles, in MB */ public int getStorefileSizeMB() { return storefileSizeMB; } /** * @return the memstore size, in MB */ public int getMemStoreSizeMB() { return memstoreSizeMB; } /** * @return the approximate size of storefile indexes on the heap, in MB */ public int getStorefileIndexSizeMB() { return storefileIndexSizeMB; } // Setters /** * @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 storefiles */ public void setStorefiles(int storefiles) { this.storefiles = storefiles; } /** * @param memstoreSizeMB the memstore size, in MB */ public void setMemStoreSizeMB(int memstoreSizeMB) { this.memstoreSizeMB = memstoreSizeMB; } /** * @param storefileIndexSizeMB the approximate size of storefile indexes * on the heap, in MB */ public void setStorefileIndexSizeMB(int storefileIndexSizeMB) { this.storefileIndexSizeMB = storefileIndexSizeMB; } // Writable public void readFields(DataInput in) throws IOException { int namelen = in.readInt(); this.name = new byte[namelen]; in.readFully(this.name); this.stores = in.readInt(); this.storefiles = in.readInt(); this.storefileSizeMB = in.readInt(); this.memstoreSizeMB = in.readInt(); this.storefileIndexSizeMB = in.readInt(); } public void write(DataOutput out) throws IOException { out.writeInt(name.length); out.write(name); out.writeInt(stores); out.writeInt(storefiles); out.writeInt(storefileSizeMB); out.writeInt(memstoreSizeMB); out.writeInt(storefileIndexSizeMB); } /** * @see java.lang.Object#toString() */ @Override public String toString() { StringBuilder sb = Strings.appendKeyValue(new StringBuilder(), "stores", Integer.valueOf(this.stores)); sb = Strings.appendKeyValue(sb, "storefiles", Integer.valueOf(this.storefiles)); sb = Strings.appendKeyValue(sb, "storefileSizeMB", Integer.valueOf(this.storefileSizeMB)); sb = Strings.appendKeyValue(sb, "memstoreSizeMB", Integer.valueOf(this.memstoreSizeMB)); sb = Strings.appendKeyValue(sb, "storefileIndexSizeMB", Integer.valueOf(this.storefileIndexSizeMB)); return sb.toString(); } } /* * TODO: Other metrics that might be considered when the master is actually * doing load balancing instead of merely trying to decide where to assign * a region: * <ul> * <li># of CPUs, heap size (to determine the "class" of machine). For * now, we consider them to be homogeneous.</li> * <li>#requests per region (Map<{String|HRegionInfo}, Integer>)</li> * <li>#compactions and/or #splits (churn)</li> * <li>server death rate (maybe there is something wrong with this server)</li> * </ul> */ /** default constructor (used by Writable) */ public HServerLoad() { super(); } /** * Constructor * @param numberOfRequests * @param usedHeapMB * @param maxHeapMB */ public HServerLoad(final int numberOfRequests, final int usedHeapMB, final int maxHeapMB) { this.numberOfRequests = numberOfRequests; this.usedHeapMB = usedHeapMB; this.maxHeapMB = maxHeapMB; } /** * Constructor * @param hsl the template HServerLoad */ public HServerLoad(final HServerLoad hsl) { this(hsl.numberOfRequests, hsl.usedHeapMB, hsl.maxHeapMB); this.regionLoad.addAll(hsl.regionLoad); } /** * Originally, this method factored in the effect of requests going to the * server as well. However, this does not interact very well with the current * region rebalancing code, which only factors number of regions. For the * interim, until we can figure out how to make rebalancing use all the info * available, we're just going to make load purely the number of regions. * * @return load factor for this server */ public int getLoad() { // int load = numberOfRequests == 0 ? 1 : numberOfRequests; // load *= numberOfRegions == 0 ? 1 : numberOfRegions; // return load; return numberOfRegions; } /** * @see java.lang.Object#toString() */ @Override public String toString() { return toString(1); } /** * Returns toString() with the number of requests divided by the message * interval in seconds * @param msgInterval * @return The load as a String */ public String toString(int msgInterval) { StringBuilder sb = new StringBuilder(); sb = Strings.appendKeyValue(sb, "requests", Integer.valueOf(numberOfRequests/msgInterval)); sb = Strings.appendKeyValue(sb, "regions", Integer.valueOf(numberOfRegions)); sb = Strings.appendKeyValue(sb, "usedHeap", Integer.valueOf(this.usedHeapMB)); sb = Strings.appendKeyValue(sb, "maxHeap", Integer.valueOf(maxHeapMB)); return sb.toString(); } /** * @see java.lang.Object#equals(java.lang.Object) */ @Override public boolean equals(Object o) { if (this == o) { return true; } if (o == null) { return false; } if (getClass() != o.getClass()) { return false; } return compareTo((HServerLoad)o) == 0; } /** * @see java.lang.Object#hashCode() */ @Override public int hashCode() { int result = Integer.valueOf(numberOfRequests).hashCode(); result ^= Integer.valueOf(numberOfRegions).hashCode(); return result; } // Getters /** * @return the numberOfRegions */ public int getNumberOfRegions() { return numberOfRegions; } /** * @return the numberOfRequests */ public int getNumberOfRequests() { return numberOfRequests; } /** * @return the amount of heap in use, in MB */ public int getUsedHeapMB() { return usedHeapMB; } /** * @return the maximum allowable heap size, in MB */ public int getMaxHeapMB() { return maxHeapMB; } /** * @return region load metrics */ public Collection<RegionLoad> getRegionsLoad() { return Collections.unmodifiableCollection(regionLoad); } /** * @return Count of storefiles on this regionserver */ public int getStorefiles() { int count = 0; for (RegionLoad info: regionLoad) count += info.getStorefiles(); return count; } /** * @return Total size of store files in MB */ public int getStorefileSizeInMB() { int count = 0; for (RegionLoad info: regionLoad) count += info.getStorefileSizeMB(); return count; } /** * @return Size of memstores in MB */ public int getMemStoreSizeInMB() { int count = 0; for (RegionLoad info: regionLoad) count += info.getMemStoreSizeMB(); return count; } /** * @return Size of store file indexes in MB */ public int getStorefileIndexSizeInMB() { int count = 0; for (RegionLoad info: regionLoad) count += info.getStorefileIndexSizeMB(); return count; } // Setters /** * @param numberOfRegions the number of regions */ public void setNumberOfRegions(int numberOfRegions) { this.numberOfRegions = numberOfRegions; } /** * @param numberOfRequests the number of requests to set */ public void setNumberOfRequests(int numberOfRequests) { this.numberOfRequests = numberOfRequests; } /** * @param usedHeapMB the amount of heap in use, in MB */ public void setUsedHeapMB(int usedHeapMB) { this.usedHeapMB = usedHeapMB; } /** * @param maxHeapMB the maximum allowable heap size, in MB */ public void setMaxHeapMB(int maxHeapMB) { this.maxHeapMB = maxHeapMB; } /** * @param load Instance of HServerLoad */ public void addRegionInfo(final HServerLoad.RegionLoad load) { this.numberOfRegions++; this.regionLoad.add(load); } /** * @param name * @param stores * @param storefiles * @param memstoreSizeMB * @param storefileIndexSizeMB * @deprecated Use {@link #addRegionInfo(RegionLoad)} */ @Deprecated public void addRegionInfo(final byte[] name, final int stores, final int storefiles, final int storefileSizeMB, final int memstoreSizeMB, final int storefileIndexSizeMB) { this.regionLoad.add(new HServerLoad.RegionLoad(name, stores, storefiles, storefileSizeMB, memstoreSizeMB, storefileIndexSizeMB)); } // Writable public void readFields(DataInput in) throws IOException { numberOfRequests = in.readInt(); usedHeapMB = in.readInt(); maxHeapMB = in.readInt(); numberOfRegions = in.readInt(); for (int i = 0; i < numberOfRegions; i++) { RegionLoad rl = new RegionLoad(); rl.readFields(in); regionLoad.add(rl); } } public void write(DataOutput out) throws IOException { out.writeInt(numberOfRequests); out.writeInt(usedHeapMB); out.writeInt(maxHeapMB); out.writeInt(numberOfRegions); for (int i = 0; i < numberOfRegions; i++) regionLoad.get(i).write(out); } // Comparable public int compareTo(HServerLoad o) { return this.getLoad() - o.getLoad(); } }