View Javadoc

1   /*
2    * Copyright 2010 The Apache Software Foundation
3    *
4    * Licensed to the Apache Software Foundation (ASF) under one
5    * or more contributor license agreements.  See the NOTICE file
6    * distributed with this work for additional information
7    * regarding copyright ownership.  The ASF licenses this file
8    * to you under the Apache License, Version 2.0 (the
9    * "License"); you may not use this file except in compliance
10   * with the License.  You may obtain a copy of the License at
11   *
12   *     http://www.apache.org/licenses/LICENSE-2.0
13   *
14   * Unless required by applicable law or agreed to in writing, software
15   * distributed under the License is distributed on an "AS IS" BASIS,
16   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
17   * See the License for the specific language governing permissions and
18   * limitations under the License.
19   */
20  
21  package org.apache.hadoop.hbase.rest.model;
22  
23  import java.io.IOException;
24  import java.io.Serializable;
25  import java.util.ArrayList;
26  import java.util.List;
27  
28  import javax.xml.bind.annotation.XmlAttribute;
29  import javax.xml.bind.annotation.XmlElement;
30  import javax.xml.bind.annotation.XmlElementWrapper;
31  import javax.xml.bind.annotation.XmlRootElement;
32  
33  import org.apache.hadoop.hbase.rest.ProtobufMessageHandler;
34  import org.apache.hadoop.hbase.rest.protobuf.generated.StorageClusterStatusMessage.StorageClusterStatus;
35  import org.apache.hadoop.hbase.util.Bytes;
36  
37  import com.google.protobuf.ByteString;
38  
39  /**
40   * Representation of the status of a storage cluster:
41   * <p>
42   * <ul>
43   * <li>regions: the total number of regions served by the cluster</li>
44   * <li>requests: the total number of requests per second handled by the
45   * cluster in the last reporting interval</li>
46   * <li>averageLoad: the average load of the region servers in the cluster</li>
47   * <li>liveNodes: detailed status of the live region servers</li>
48   * <li>deadNodes: the names of region servers declared dead</li>
49   * </ul>
50   * 
51   * <pre>
52   * &lt;complexType name="StorageClusterStatus"&gt;
53   *   &lt;sequence&gt;
54   *     &lt;element name="liveNode" type="tns:Node"
55   *       maxOccurs="unbounded" minOccurs="0"&gt;
56   *     &lt;/element&gt;
57   *     &lt;element name="deadNode" type="string" maxOccurs="unbounded"
58   *       minOccurs="0"&gt;
59   *     &lt;/element&gt;
60   *   &lt;/sequence&gt;
61   *   &lt;attribute name="regions" type="int"&gt;&lt;/attribute&gt;
62   *   &lt;attribute name="requests" type="int"&gt;&lt;/attribute&gt;
63   *   &lt;attribute name="averageLoad" type="float"&gt;&lt;/attribute&gt;
64   * &lt;/complexType&gt;
65   *
66   * &lt;complexType name="Node"&gt;
67   *   &lt;sequence&gt;
68   *     &lt;element name="region" type="tns:Region" 
69   *       maxOccurs="unbounded" minOccurs="0"&gt;&lt;/element&gt;
70   *   &lt;/sequence&gt;
71   *   &lt;attribute name="name" type="string"&gt;&lt;/attribute&gt;
72   *   &lt;attribute name="startCode" type="int"&gt;&lt;/attribute&gt;
73   *   &lt;attribute name="requests" type="int"&gt;&lt;/attribute&gt;
74   *   &lt;attribute name="heapSizeMB" type="int"&gt;&lt;/attribute&gt;
75   *   &lt;attribute name="maxHeapSizeMB" type="int"&gt;&lt;/attribute&gt;
76   * &lt;/complexType&gt;
77   *
78   * &lt;complexType name="Region"&gt;
79   *   &lt;attribute name="name" type="base64Binary"&gt;&lt;/attribute&gt;
80   *   &lt;attribute name="stores" type="int"&gt;&lt;/attribute&gt;
81   *   &lt;attribute name="storefiles" type="int"&gt;&lt;/attribute&gt;
82   *   &lt;attribute name="storefileSizeMB" type="int"&gt;&lt;/attribute&gt;
83   *   &lt;attribute name="memstoreSizeMB" type="int"&gt;&lt;/attribute&gt;
84   *   &lt;attribute name="storefileIndexSizeMB" type="int"&gt;&lt;/attribute&gt;
85   * &lt;/complexType&gt;
86   * </pre>
87   */
88  @XmlRootElement(name="ClusterStatus")
89  public class StorageClusterStatusModel 
90      implements Serializable, ProtobufMessageHandler {
91  	private static final long serialVersionUID = 1L;
92  
93  	/**
94  	 * Represents a region server.
95  	 */
96  	public static class Node {
97  	  
98  	  /**
99  	   * Represents a region hosted on a region server.
100 	   */
101 	  public static class Region {
102 	    private byte[] name;
103 	    private int stores;
104 	    private int storefiles;
105 	    private int storefileSizeMB;
106 	    private int memstoreSizeMB;
107 	    private int storefileIndexSizeMB;
108 
109 	    /**
110 	     * Default constructor
111 	     */
112 	    public Region() {}
113 
114 	    /**
115 	     * Constructor
116 	     * @param name the region name
117 	     */
118 	    public Region(byte[] name) {
119 	      this.name = name;
120 	    }
121 
122 	    /**
123 	     * Constructor
124 	     * @param name the region name
125 	     * @param stores the number of stores
126 	     * @param storefiles the number of store files
127 	     * @param storefileSizeMB total size of store files, in MB
128 	     * @param memstoreSizeMB total size of memstore, in MB
129 	     * @param storefileIndexSizeMB total size of store file indexes, in MB
130 	     */
131 	    public Region(byte[] name, int stores, int storefiles,
132           int storefileSizeMB, int memstoreSizeMB, int storefileIndexSizeMB) {
133         this.name = name;
134         this.stores = stores;
135         this.storefiles = storefiles;
136         this.storefileSizeMB = storefileSizeMB;
137         this.memstoreSizeMB = memstoreSizeMB;
138         this.storefileIndexSizeMB = storefileIndexSizeMB;
139       }
140 
141       /**
142 	     * @return the region name
143 	     */
144 	    @XmlAttribute
145 	    public byte[] getName() {
146 	      return name;
147 	    }
148 
149 	    /**
150 	     * @return the number of stores 
151 	     */
152 	    @XmlAttribute
153 	    public int getStores() {
154         return stores;
155       }
156 
157       /**
158        * @return the number of store files 
159        */
160       @XmlAttribute
161       public int getStorefiles() {
162         return storefiles;
163       }
164 
165       /**
166        * @return the total size of store files, in MB
167        */
168       @XmlAttribute
169       public int getStorefileSizeMB() {
170         return storefileSizeMB;
171       }
172 
173       /**
174        * @return memstore size, in MB
175        */
176       @XmlAttribute
177       public int getMemstoreSizeMB() {
178         return memstoreSizeMB;
179       }
180 
181       /**
182        * @return the total size of store file indexes, in MB
183        */
184       @XmlAttribute
185       public int getStorefileIndexSizeMB() {
186         return storefileIndexSizeMB;
187       }
188 
189       /**
190 	     * @param name the region name
191 	     */
192 	    public void setName(byte[] name) {
193 	      this.name = name;
194 	    }
195 
196 	    /**
197 	     * @param stores the number of stores
198 	     */
199       public void setStores(int stores) {
200         this.stores = stores;
201       }
202 
203       /**
204        * @param storefiles the number of store files
205        */
206       public void setStorefiles(int storefiles) {
207         this.storefiles = storefiles;
208       }
209 
210       /**
211        * @param storefileSizeMB total size of store files, in MB
212        */
213       public void setStorefileSizeMB(int storefileSizeMB) {
214         this.storefileSizeMB = storefileSizeMB;
215       }
216 
217       /**
218        * @param memstoreSizeMB memstore size, in MB
219        */
220       public void setMemstoreSizeMB(int memstoreSizeMB) {
221         this.memstoreSizeMB = memstoreSizeMB;
222       }
223 
224       /**
225        * @param storefileIndexSizeMB total size of store file indexes, in MB
226        */
227       public void setStorefileIndexSizeMB(int storefileIndexSizeMB) {
228         this.storefileIndexSizeMB = storefileIndexSizeMB;
229       }
230 	  }
231 
232 	  private String name;
233     private long startCode;
234     private int requests;
235     private int heapSizeMB;
236     private int maxHeapSizeMB;
237     private List<Region> regions = new ArrayList<Region>();
238 
239     /**
240      * Add a region name to the list
241      * @param name the region name
242      */
243     public void addRegion(byte[] name, int stores, int storefiles,
244         int storefileSizeMB, int memstoreSizeMB, int storefileIndexSizeMB) {
245       regions.add(new Region(name, stores, storefiles, storefileSizeMB,
246         memstoreSizeMB, storefileIndexSizeMB));
247     }
248 
249     /**
250      * @param index the index
251      * @return the region name
252      */
253     public Region getRegion(int index) {
254       return regions.get(index);
255     }
256 
257     /**
258      * Default constructor
259      */
260     public Node() {}
261 
262     /**
263      * Constructor
264      * @param name the region server name
265      * @param startCode the region server's start code
266      */
267     public Node(String name, long startCode) {
268       this.name = name;
269       this.startCode = startCode;
270     }
271 
272     /**
273      * @return the region server's name
274      */
275     @XmlAttribute
276     public String getName() {
277       return name;
278     }
279 
280     /**
281      * @return the region server's start code
282      */
283     @XmlAttribute
284     public long getStartCode() {
285       return startCode;
286     }
287 
288     /**
289      * @return the current heap size, in MB
290      */
291     @XmlAttribute
292     public int getHeapSizeMB() {
293       return heapSizeMB;
294     }
295 
296     /**
297      * @return the maximum heap size, in MB
298      */
299     @XmlAttribute
300     public int getMaxHeapSizeMB() {
301       return maxHeapSizeMB;
302     }
303 
304     /**
305      * @return the list of regions served by the region server
306      */
307     @XmlElement(name="Region")
308     public List<Region> getRegions() {
309       return regions;
310     }
311 
312     /**
313      * @return the number of requests per second processed by the region server
314      */
315     @XmlAttribute
316     public int getRequests() {
317       return requests;
318     }
319 
320     /**
321      * @param name the region server's hostname
322      */
323     public void setName(String name) {
324       this.name = name;
325     }
326 
327     /**
328      * @param startCode the region server's start code
329      */
330     public void setStartCode(long startCode) {
331       this.startCode = startCode;
332     }
333 
334     /**
335      * @param heapSizeMB the current heap size, in MB
336      */
337     public void setHeapSizeMB(int heapSizeMB) {
338       this.heapSizeMB = heapSizeMB;
339     }
340 
341     /**
342      * @param maxHeapSizeMB the maximum heap size, in MB
343      */
344     public void setMaxHeapSizeMB(int maxHeapSizeMB) {
345       this.maxHeapSizeMB = maxHeapSizeMB;
346     }
347 
348     /**
349      * @param regions a list of regions served by the region server
350      */
351     public void setRegions(List<Region> regions) {
352       this.regions = regions;
353     }
354 
355     /**
356      * @param requests the number of requests per second processed by the
357      * region server
358      */
359     public void setRequests(int requests) {
360       this.requests = requests;
361     }
362 	}
363 
364 	private List<Node> liveNodes = new ArrayList<Node>();
365 	private List<String> deadNodes = new ArrayList<String>();
366 	private int regions;
367 	private int requests;
368 	private double averageLoad;
369 
370 	/**
371 	 * Add a live node to the cluster representation.
372 	 * @param name the region server name
373 	 * @param startCode the region server's start code
374 	 * @param heapSizeMB the current heap size, in MB
375 	 * @param maxHeapSizeMB the maximum heap size, in MB
376 	 */
377 	public Node addLiveNode(String name, long startCode, int heapSizeMB,
378 	    int maxHeapSizeMB) {
379 	  Node node = new Node(name, startCode);
380 	  node.setHeapSizeMB(heapSizeMB);
381 	  node.setMaxHeapSizeMB(maxHeapSizeMB);
382 	  liveNodes.add(node);
383 	  return node;
384 	}
385 
386 	/**
387 	 * @param index the index
388 	 * @return the region server model
389 	 */
390 	public Node getLiveNode(int index) {
391 	  return liveNodes.get(index);
392 	}
393 
394 	/**
395 	 * Add a dead node to the cluster representation.
396 	 * @param node the dead region server's name
397 	 */
398 	public void addDeadNode(String node) {
399 	  deadNodes.add(node);
400 	}
401 	
402 	/**
403 	 * @param index the index
404 	 * @return the dead region server's name
405 	 */
406 	public String getDeadNode(int index) {
407 	  return deadNodes.get(index);
408 	}
409 
410 	/**
411 	 * Default constructor
412 	 */
413 	public StorageClusterStatusModel() {}
414 
415 	/**
416 	 * @return the list of live nodes
417 	 */
418 	@XmlElement(name="Node")
419 	@XmlElementWrapper(name="LiveNodes")
420 	public List<Node> getLiveNodes() {
421 	  return liveNodes;
422 	}
423 
424 	/**
425 	 * @return the list of dead nodes
426 	 */
427   @XmlElement(name="Node")
428   @XmlElementWrapper(name="DeadNodes")
429   public List<String> getDeadNodes() {
430     return deadNodes;
431   }
432 
433   /**
434    * @return the total number of regions served by the cluster
435    */
436   @XmlAttribute
437   public int getRegions() {
438     return regions;
439   }
440 
441   /**
442    * @return the total number of requests per second handled by the cluster in
443    * the last reporting interval
444    */
445   @XmlAttribute
446   public int getRequests() {
447     return requests;
448   }
449 
450   /**
451    * @return the average load of the region servers in the cluster
452    */
453   @XmlAttribute
454   public double getAverageLoad() {
455     return averageLoad;
456   }
457 
458   /**
459    * @param nodes the list of live node models
460    */
461   public void setLiveNodes(List<Node> nodes) {
462     this.liveNodes = nodes;
463   }
464 
465   /**
466    * @param nodes the list of dead node names
467    */
468   public void setDeadNodes(List<String> nodes) {
469     this.deadNodes = nodes;
470   }
471 
472   /**
473    * @param regions the total number of regions served by the cluster
474    */
475   public void setRegions(int regions) {
476     this.regions = regions;
477   }
478 
479   /**
480    * @param requests the total number of requests per second handled by the
481    * cluster
482    */
483   public void setRequests(int requests) {
484     this.requests = requests;
485   }
486 
487   /**
488    * @param averageLoad the average load of region servers in the cluster
489    */
490   public void setAverageLoad(double averageLoad) {
491     this.averageLoad = averageLoad;
492   }
493 
494 	/* (non-Javadoc)
495 	 * @see java.lang.Object#toString()
496 	 */
497 	@Override
498 	public String toString() {
499 	  StringBuilder sb = new StringBuilder();
500 	  sb.append(String.format("%d live servers, %d dead servers, " + 
501       "%.4f average load\n\n", liveNodes.size(), deadNodes.size(),
502       averageLoad));
503     if (!liveNodes.isEmpty()) {
504       sb.append(liveNodes.size());
505       sb.append(" live servers\n");
506       for (Node node: liveNodes) {
507         sb.append("    ");
508         sb.append(node.name);
509         sb.append(' ');
510         sb.append(node.startCode);
511         sb.append("\n        requests=");
512         sb.append(node.requests);
513         sb.append(", regions=");
514         sb.append(node.regions.size());
515         sb.append("\n        heapSizeMB=");
516         sb.append(node.heapSizeMB);
517         sb.append("\n        maxHeapSizeMB=");
518         sb.append(node.maxHeapSizeMB);
519         sb.append("\n\n");
520         for (Node.Region region: node.regions) {
521           sb.append("        ");
522           sb.append(Bytes.toString(region.name));
523           sb.append("\n            stores=");
524           sb.append(region.stores);
525           sb.append("\n            storefiless=");
526           sb.append(region.storefiles);
527           sb.append("\n            storefileSizeMB=");
528           sb.append(region.storefileSizeMB);
529           sb.append("\n            memstoreSizeMB=");
530           sb.append(region.memstoreSizeMB);
531           sb.append("\n            storefileIndexSizeMB=");
532           sb.append(region.storefileIndexSizeMB);
533           sb.append('\n');
534         }
535         sb.append('\n');
536       }
537     }
538     if (!deadNodes.isEmpty()) {
539       sb.append('\n');
540       sb.append(deadNodes.size());
541       sb.append(" dead servers\n");
542       for (String node: deadNodes) {
543         sb.append("    ");
544         sb.append(node);
545         sb.append('\n');
546       }
547     }
548 	  return sb.toString();
549 	}
550 
551   @Override
552   public byte[] createProtobufOutput() {
553     StorageClusterStatus.Builder builder = StorageClusterStatus.newBuilder();
554     builder.setRegions(regions);
555     builder.setRequests(requests);
556     builder.setAverageLoad(averageLoad);
557     for (Node node: liveNodes) {
558       StorageClusterStatus.Node.Builder nodeBuilder = 
559         StorageClusterStatus.Node.newBuilder();
560       nodeBuilder.setName(node.name);
561       nodeBuilder.setStartCode(node.startCode);
562       nodeBuilder.setRequests(node.requests);
563       nodeBuilder.setHeapSizeMB(node.heapSizeMB);
564       nodeBuilder.setMaxHeapSizeMB(node.maxHeapSizeMB);
565       for (Node.Region region: node.regions) {
566         StorageClusterStatus.Region.Builder regionBuilder =
567           StorageClusterStatus.Region.newBuilder();
568         regionBuilder.setName(ByteString.copyFrom(region.name));
569         regionBuilder.setStores(region.stores);
570         regionBuilder.setStorefiles(region.storefiles);
571         regionBuilder.setStorefileSizeMB(region.storefileSizeMB);
572         regionBuilder.setMemstoreSizeMB(region.memstoreSizeMB);
573         regionBuilder.setStorefileIndexSizeMB(region.storefileIndexSizeMB);
574         nodeBuilder.addRegions(regionBuilder);
575       }
576       builder.addLiveNodes(nodeBuilder);
577     }
578     for (String node: deadNodes) {
579       builder.addDeadNodes(node);
580     }
581     return builder.build().toByteArray();
582   }
583 
584   @Override
585   public ProtobufMessageHandler getObjectFromMessage(byte[] message)
586       throws IOException {
587     StorageClusterStatus.Builder builder = StorageClusterStatus.newBuilder();
588     builder.mergeFrom(message);
589     if (builder.hasRegions()) {
590       regions = builder.getRegions();
591     }
592     if (builder.hasRequests()) {
593       requests = builder.getRequests();
594     }
595     if (builder.hasAverageLoad()) {
596       averageLoad = builder.getAverageLoad();
597     }
598     for (StorageClusterStatus.Node node: builder.getLiveNodesList()) {
599       long startCode = node.hasStartCode() ? node.getStartCode() : -1;
600       StorageClusterStatusModel.Node nodeModel = 
601         addLiveNode(node.getName(), startCode, node.getHeapSizeMB(),
602           node.getMaxHeapSizeMB());
603       int requests = node.hasRequests() ? node.getRequests() : 0;
604       nodeModel.setRequests(requests);
605       for (StorageClusterStatus.Region region: node.getRegionsList()) {
606         nodeModel.addRegion(
607           region.getName().toByteArray(),
608           region.getStores(),
609           region.getStorefiles(),
610           region.getStorefileSizeMB(),
611           region.getMemstoreSizeMB(),
612           region.getStorefileIndexSizeMB());
613       }
614     }
615     for (String node: builder.getDeadNodesList()) {
616       addDeadNode(node);
617     }
618     return this;
619   }
620 }