View Javadoc

1   /*
2    *
3    * Licensed to the Apache Software Foundation (ASF) under one
4    * or more contributor license agreements.  See the NOTICE file
5    * distributed with this work for additional information
6    * regarding copyright ownership.  The ASF licenses this file
7    * to you under the Apache License, Version 2.0 (the
8    * "License"); you may not use this file except in compliance
9    * with the License.  You may obtain a copy of the License at
10   *
11   *     http://www.apache.org/licenses/LICENSE-2.0
12   *
13   * Unless required by applicable law or agreed to in writing, software
14   * distributed under the License is distributed on an "AS IS" BASIS,
15   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16   * See the License for the specific language governing permissions and
17   * limitations under the License.
18   */
19  package org.apache.hadoop.hbase.rest.model;
20  
21  import com.fasterxml.jackson.annotation.JsonProperty;
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.classification.InterfaceAudience;
34  import org.apache.hadoop.hbase.protobuf.ProtobufUtil;
35  import org.apache.hadoop.hbase.rest.ProtobufMessageHandler;
36  import org.apache.hadoop.hbase.rest.protobuf.generated.StorageClusterStatusMessage.StorageClusterStatus;
37  import org.apache.hadoop.hbase.util.ByteStringer;
38  import org.apache.hadoop.hbase.util.Bytes;
39  
40  /**
41   * Representation of the status of a storage cluster:
42   * <p>
43   * <ul>
44   * <li>regions: the total number of regions served by the cluster</li>
45   * <li>requests: the total number of requests per second handled by the
46   * cluster in the last reporting interval</li>
47   * <li>averageLoad: the average load of the region servers in the cluster</li>
48   * <li>liveNodes: detailed status of the live region servers</li>
49   * <li>deadNodes: the names of region servers declared dead</li>
50   * </ul>
51   *
52   * <pre>
53   * &lt;complexType name="StorageClusterStatus"&gt;
54   *   &lt;sequence&gt;
55   *     &lt;element name="liveNode" type="tns:Node"
56   *       maxOccurs="unbounded" minOccurs="0"&gt;
57   *     &lt;/element&gt;
58   *     &lt;element name="deadNode" type="string" maxOccurs="unbounded"
59   *       minOccurs="0"&gt;
60   *     &lt;/element&gt;
61   *   &lt;/sequence&gt;
62   *   &lt;attribute name="regions" type="int"&gt;&lt;/attribute&gt;
63   *   &lt;attribute name="requests" type="int"&gt;&lt;/attribute&gt;
64   *   &lt;attribute name="averageLoad" type="float"&gt;&lt;/attribute&gt;
65   * &lt;/complexType&gt;
66   *
67   * &lt;complexType name="Node"&gt;
68   *   &lt;sequence&gt;
69   *     &lt;element name="region" type="tns:Region"
70   *       maxOccurs="unbounded" minOccurs="0"&gt;&lt;/element&gt;
71   *   &lt;/sequence&gt;
72   *   &lt;attribute name="name" type="string"&gt;&lt;/attribute&gt;
73   *   &lt;attribute name="startCode" type="int"&gt;&lt;/attribute&gt;
74   *   &lt;attribute name="requests" type="int"&gt;&lt;/attribute&gt;
75   *   &lt;attribute name="heapSizeMB" type="int"&gt;&lt;/attribute&gt;
76   *   &lt;attribute name="maxHeapSizeMB" type="int"&gt;&lt;/attribute&gt;
77   * &lt;/complexType&gt;
78   *
79   * &lt;complexType name="Region"&gt;
80   *   &lt;attribute name="name" type="base64Binary"&gt;&lt;/attribute&gt;
81   *   &lt;attribute name="stores" type="int"&gt;&lt;/attribute&gt;
82   *   &lt;attribute name="storefiles" type="int"&gt;&lt;/attribute&gt;
83   *   &lt;attribute name="storefileSizeMB" type="int"&gt;&lt;/attribute&gt;
84   *   &lt;attribute name="memstoreSizeMB" type="int"&gt;&lt;/attribute&gt;
85   *   &lt;attribute name="storefileIndexSizeMB" type="int"&gt;&lt;/attribute&gt;
86   *   &lt;attribute name="readRequestsCount" type="int"&gt;&lt;/attribute&gt;
87   *   &lt;attribute name="writeRequestsCount" type="int"&gt;&lt;/attribute&gt;
88   *   &lt;attribute name="rootIndexSizeKB" type="int"&gt;&lt;/attribute&gt;
89   *   &lt;attribute name="totalStaticIndexSizeKB" type="int"&gt;&lt;/attribute&gt;
90   *   &lt;attribute name="totalStaticBloomSizeKB" type="int"&gt;&lt;/attribute&gt;
91   *   &lt;attribute name="totalCompactingKVs" type="int"&gt;&lt;/attribute&gt;
92   *   &lt;attribute name="currentCompactedKVs" type="int"&gt;&lt;/attribute&gt;
93   * &lt;/complexType&gt;
94   * </pre>
95   */
96  @XmlRootElement(name="ClusterStatus")
97  @InterfaceAudience.Private
98  public class StorageClusterStatusModel implements Serializable, ProtobufMessageHandler {
99    private static final long serialVersionUID = 1L;
100 
101   /**
102    * Represents a region server.
103    */
104   public static class Node implements Serializable {
105     private static final long serialVersionUID = 1L;
106 
107     /**
108      * Represents a region hosted on a region server.
109      */
110     public static class Region implements Serializable {
111       private static final long serialVersionUID = -1326683840086398193L;
112 
113       private byte[] name;
114       private int stores;
115       private int storefiles;
116       private int storefileSizeMB;
117       private int memstoreSizeMB;
118       private int storefileIndexSizeMB;
119       private long readRequestsCount;
120       private long writeRequestsCount;
121       private int rootIndexSizeKB;
122       private int totalStaticIndexSizeKB;
123       private int totalStaticBloomSizeKB;
124       private long totalCompactingKVs;
125       private long currentCompactedKVs;
126 
127       /**
128        * Default constructor
129        */
130       public Region() {
131       }
132 
133       /**
134        * Constructor
135        * @param name the region name
136        */
137       public Region(byte[] name) {
138         this.name = name;
139       }
140 
141       /**
142        * Constructor
143        * @param name the region name
144        * @param stores the number of stores
145        * @param storefiles the number of store files
146        * @param storefileSizeMB total size of store files, in MB
147        * @param memstoreSizeMB total size of memstore, in MB
148        * @param storefileIndexSizeMB total size of store file indexes, in MB
149        */
150       public Region(byte[] name, int stores, int storefiles,
151           int storefileSizeMB, int memstoreSizeMB, int storefileIndexSizeMB,
152           long readRequestsCount, long writeRequestsCount, int rootIndexSizeKB,
153           int totalStaticIndexSizeKB, int totalStaticBloomSizeKB,
154           long totalCompactingKVs, long currentCompactedKVs) {
155         this.name = name;
156         this.stores = stores;
157         this.storefiles = storefiles;
158         this.storefileSizeMB = storefileSizeMB;
159         this.memstoreSizeMB = memstoreSizeMB;
160         this.storefileIndexSizeMB = storefileIndexSizeMB;
161         this.readRequestsCount = readRequestsCount;
162         this.writeRequestsCount = writeRequestsCount;
163         this.rootIndexSizeKB = rootIndexSizeKB;
164         this.totalStaticIndexSizeKB = totalStaticIndexSizeKB;
165         this.totalStaticBloomSizeKB = totalStaticBloomSizeKB;
166         this.totalCompactingKVs = totalCompactingKVs;
167         this.currentCompactedKVs = currentCompactedKVs;
168       }
169 
170       /**
171        * @return the region name
172        */
173       @XmlAttribute
174       public byte[] getName() {
175         return name;
176       }
177 
178       /**
179        * @return the number of stores
180        */
181       @XmlAttribute
182       public int getStores() {
183         return stores;
184       }
185 
186       /**
187        * @return the number of store files
188        */
189       @XmlAttribute
190       public int getStorefiles() {
191         return storefiles;
192       }
193 
194       /**
195        * @return the total size of store files, in MB
196        */
197       @XmlAttribute
198       public int getStorefileSizeMB() {
199         return storefileSizeMB;
200       }
201 
202       /**
203        * @return memstore size, in MB
204        */
205       @XmlAttribute
206       public int getMemstoreSizeMB() {
207         return memstoreSizeMB;
208       }
209 
210       /**
211        * @return the total size of store file indexes, in MB
212        */
213       @XmlAttribute
214       public int getStorefileIndexSizeMB() {
215         return storefileIndexSizeMB;
216       }
217 
218       /**
219        * @return the current total read requests made to region
220        */
221       @XmlAttribute
222       public long getReadRequestsCount() {
223         return readRequestsCount;
224       }
225 
226       /**
227        * @return the current total write requests made to region
228        */
229       @XmlAttribute
230       public long getWriteRequestsCount() {
231         return writeRequestsCount;
232       }
233 
234       /**
235        * @return The current total size of root-level indexes for the region, in KB.
236        */
237       @XmlAttribute
238       public int getRootIndexSizeKB() {
239         return rootIndexSizeKB;
240       }
241 
242       /**
243        * @return The total size of static index, in KB
244        */
245       @XmlAttribute
246       public int getTotalStaticIndexSizeKB() {
247         return totalStaticIndexSizeKB;
248       }
249 
250       /**
251        * @return The total size of static bloom, in KB
252        */
253       @XmlAttribute
254       public int getTotalStaticBloomSizeKB() {
255         return totalStaticBloomSizeKB;
256       }
257 
258       /**
259        * @return The total number of compacting key-values
260        */
261       @XmlAttribute
262       public long getTotalCompactingKVs() {
263         return totalCompactingKVs;
264       }
265 
266       /**
267        * @return The number of current compacted key-values
268        */
269       @XmlAttribute
270       public long getCurrentCompactedKVs() {
271         return currentCompactedKVs;
272       }
273 
274       /**
275        * @param readRequestsCount The current total read requests made to region
276        */
277       public void setReadRequestsCount(long readRequestsCount) {
278         this.readRequestsCount = readRequestsCount;
279       }
280 
281       /**
282        * @param rootIndexSizeKB The current total size of root-level indexes
283        *                        for the region, in KB
284        */
285       public void setRootIndexSizeKB(int rootIndexSizeKB) {
286         this.rootIndexSizeKB = rootIndexSizeKB;
287       }
288 
289       /**
290        * @param writeRequestsCount The current total write requests made to region
291        */
292       public void setWriteRequestsCount(long writeRequestsCount) {
293         this.writeRequestsCount = writeRequestsCount;
294       }
295 
296       /**
297        * @param currentCompactedKVs The completed count of key values
298        *                            in currently running compaction
299        */
300       public void setCurrentCompactedKVs(long currentCompactedKVs) {
301         this.currentCompactedKVs = currentCompactedKVs;
302       }
303 
304       /**
305        * @param totalCompactingKVs The total compacting key values
306        *                           in currently running compaction
307        */
308       public void setTotalCompactingKVs(long totalCompactingKVs) {
309         this.totalCompactingKVs = totalCompactingKVs;
310       }
311 
312       /**
313        * @param totalStaticBloomSizeKB The total size of all Bloom filter blocks,
314        *                               not just loaded into the block cache, in KB.
315        */
316       public void setTotalStaticBloomSizeKB(int totalStaticBloomSizeKB) {
317         this.totalStaticBloomSizeKB = totalStaticBloomSizeKB;
318       }
319 
320       /**
321        * @param totalStaticIndexSizeKB The total size of all index blocks,
322        *                               not just the root level, in KB.
323        */
324       public void setTotalStaticIndexSizeKB(int totalStaticIndexSizeKB) {
325         this.totalStaticIndexSizeKB = totalStaticIndexSizeKB;
326       }
327 
328       /**
329        * @param name the region name
330        */
331       public void setName(byte[] name) {
332         this.name = name;
333       }
334 
335       /**
336        * @param stores the number of stores
337        */
338       public void setStores(int stores) {
339         this.stores = stores;
340       }
341 
342       /**
343        * @param storefiles the number of store files
344        */
345       public void setStorefiles(int storefiles) {
346         this.storefiles = storefiles;
347       }
348 
349       /**
350        * @param storefileSizeMB total size of store files, in MB
351        */
352       public void setStorefileSizeMB(int storefileSizeMB) {
353         this.storefileSizeMB = storefileSizeMB;
354       }
355 
356       /**
357        * @param memstoreSizeMB memstore size, in MB
358        */
359       public void setMemstoreSizeMB(int memstoreSizeMB) {
360         this.memstoreSizeMB = memstoreSizeMB;
361       }
362 
363       /**
364        * @param storefileIndexSizeMB total size of store file indexes, in MB
365        */
366       public void setStorefileIndexSizeMB(int storefileIndexSizeMB) {
367         this.storefileIndexSizeMB = storefileIndexSizeMB;
368       }
369     }
370 
371     private String name;
372     private long startCode;
373     private long requests;
374     private int heapSizeMB;
375     private int maxHeapSizeMB;
376     private List<Region> regions = new ArrayList<>();
377 
378     /**
379      * Add a region name to the list
380      * @param name the region name
381      */
382     public void addRegion(byte[] name, int stores, int storefiles,
383         int storefileSizeMB, int memstoreSizeMB, int storefileIndexSizeMB,
384         long readRequestsCount, long writeRequestsCount, int rootIndexSizeKB,
385         int totalStaticIndexSizeKB, int totalStaticBloomSizeKB,
386         long totalCompactingKVs, long currentCompactedKVs) {
387       regions.add(new Region(name, stores, storefiles, storefileSizeMB,
388         memstoreSizeMB, storefileIndexSizeMB, readRequestsCount,
389         writeRequestsCount, rootIndexSizeKB, totalStaticIndexSizeKB,
390         totalStaticBloomSizeKB, totalCompactingKVs, currentCompactedKVs));
391     }
392 
393     /**
394      * @param index the index
395      * @return the region name
396      */
397     public Region getRegion(int index) {
398       return regions.get(index);
399     }
400 
401     /**
402      * Default constructor
403      */
404     public Node() {}
405 
406     /**
407      * Constructor
408      * @param name the region server name
409      * @param startCode the region server's start code
410      */
411     public Node(String name, long startCode) {
412       this.name = name;
413       this.startCode = startCode;
414     }
415 
416     /**
417      * @return the region server's name
418      */
419     @XmlAttribute
420     public String getName() {
421       return name;
422     }
423 
424     /**
425      * @return the region server's start code
426      */
427     @XmlAttribute
428     public long getStartCode() {
429       return startCode;
430     }
431 
432     /**
433      * @return the current heap size, in MB
434      */
435     @XmlAttribute
436     public int getHeapSizeMB() {
437       return heapSizeMB;
438     }
439 
440     /**
441      * @return the maximum heap size, in MB
442      */
443     @XmlAttribute
444     public int getMaxHeapSizeMB() {
445       return maxHeapSizeMB;
446     }
447 
448     /**
449      * @return the list of regions served by the region server
450      */
451     @XmlElement(name="Region")
452     public List<Region> getRegions() {
453       return regions;
454     }
455 
456     /**
457      * @return the number of requests per second processed by the region server
458      */
459     @XmlAttribute
460     public long getRequests() {
461       return requests;
462     }
463 
464     /**
465      * @param name the region server's hostname
466      */
467     public void setName(String name) {
468       this.name = name;
469     }
470 
471     /**
472      * @param startCode the region server's start code
473      */
474     public void setStartCode(long startCode) {
475       this.startCode = startCode;
476     }
477 
478     /**
479      * @param heapSizeMB the current heap size, in MB
480      */
481     public void setHeapSizeMB(int heapSizeMB) {
482       this.heapSizeMB = heapSizeMB;
483     }
484 
485     /**
486      * @param maxHeapSizeMB the maximum heap size, in MB
487      */
488     public void setMaxHeapSizeMB(int maxHeapSizeMB) {
489       this.maxHeapSizeMB = maxHeapSizeMB;
490     }
491 
492     /**
493      * @param regions a list of regions served by the region server
494      */
495     public void setRegions(List<Region> regions) {
496       this.regions = regions;
497     }
498 
499     /**
500      * @param requests the number of requests per second processed by the region server
501      */
502     public void setRequests(long requests) {
503       this.requests = requests;
504     }
505   }
506 
507   private List<Node> liveNodes = new ArrayList<>();
508   private List<String> deadNodes = new ArrayList<>();
509   private int regions;
510   private long requests;
511   private double averageLoad;
512 
513   /**
514    * Add a live node to the cluster representation.
515    * @param name the region server name
516    * @param startCode the region server's start code
517    * @param heapSizeMB the current heap size, in MB
518    * @param maxHeapSizeMB the maximum heap size, in MB
519    */
520   public Node addLiveNode(String name, long startCode, int heapSizeMB, int maxHeapSizeMB) {
521     Node node = new Node(name, startCode);
522     node.setHeapSizeMB(heapSizeMB);
523     node.setMaxHeapSizeMB(maxHeapSizeMB);
524     liveNodes.add(node);
525     return node;
526   }
527 
528   /**
529    * @param index the index
530    * @return the region server model
531    */
532   public Node getLiveNode(int index) {
533     return liveNodes.get(index);
534   }
535 
536   /**
537    * Add a dead node to the cluster representation.
538    * @param node the dead region server's name
539    */
540   public void addDeadNode(String node) {
541     deadNodes.add(node);
542   }
543 
544   /**
545    * @param index the index
546    * @return the dead region server's name
547    */
548   public String getDeadNode(int index) {
549     return deadNodes.get(index);
550   }
551 
552   /**
553    * Default constructor
554    */
555   public StorageClusterStatusModel() {
556   }
557 
558   /**
559    * @return the list of live nodes
560    */
561   @XmlElement(name = "Node")
562   @XmlElementWrapper(name = "LiveNodes")
563   // workaround https://github.com/FasterXML/jackson-dataformat-xml/issues/192
564   @JsonProperty("LiveNodes")
565   public List<Node> getLiveNodes() {
566     return liveNodes;
567   }
568 
569   /**
570    * @return the list of dead nodes
571    */
572   @XmlElement(name = "Node")
573   @XmlElementWrapper(name = "DeadNodes")
574   // workaround https://github.com/FasterXML/jackson-dataformat-xml/issues/192
575   @JsonProperty("DeadNodes")
576   public List<String> getDeadNodes() {
577     return deadNodes;
578   }
579 
580   /**
581    * @return the total number of regions served by the cluster
582    */
583   @XmlAttribute
584   public int getRegions() {
585     return regions;
586   }
587 
588   /**
589    * @return the total number of requests per second handled by the cluster in the last reporting
590    *    interval
591    */
592   @XmlAttribute
593   public long getRequests() {
594     return requests;
595   }
596 
597   /**
598    * @return the average load of the region servers in the cluster
599    */
600   @XmlAttribute
601   public double getAverageLoad() {
602     return averageLoad;
603   }
604 
605   /**
606    * @param nodes the list of live node models
607    */
608   public void setLiveNodes(List<Node> nodes) {
609     this.liveNodes = nodes;
610   }
611 
612   /**
613    * @param nodes the list of dead node names
614    */
615   public void setDeadNodes(List<String> nodes) {
616     this.deadNodes = nodes;
617   }
618 
619   /**
620    * @param regions the total number of regions served by the cluster
621    */
622   public void setRegions(int regions) {
623     this.regions = regions;
624   }
625 
626   /**
627    * @param requests the total number of requests per second handled by the cluster
628    */
629   public void setRequests(int requests) {
630     this.requests = requests;
631   }
632 
633   /**
634    * @param averageLoad the average load of region servers in the cluster
635    */
636   public void setAverageLoad(double averageLoad) {
637     this.averageLoad = averageLoad;
638   }
639 
640   @Override
641   public String toString() {
642     StringBuilder sb = new StringBuilder();
643     sb.append(String.format("%d live servers, %d dead servers, " +
644       "%.4f average load%n%n", liveNodes.size(), deadNodes.size(),
645       averageLoad));
646     if (!liveNodes.isEmpty()) {
647       sb.append(liveNodes.size());
648       sb.append(" live servers\n");
649       for (Node node : liveNodes) {
650         sb.append("    ");
651         sb.append(node.name);
652         sb.append(' ');
653         sb.append(node.startCode);
654         sb.append("\n        requests=");
655         sb.append(node.requests);
656         sb.append(", regions=");
657         sb.append(node.regions.size());
658         sb.append("\n        heapSizeMB=");
659         sb.append(node.heapSizeMB);
660         sb.append("\n        maxHeapSizeMB=");
661         sb.append(node.maxHeapSizeMB);
662         sb.append("\n\n");
663         for (Node.Region region : node.regions) {
664           sb.append("        ");
665           sb.append(Bytes.toString(region.name));
666           sb.append("\n            stores=");
667           sb.append(region.stores);
668           sb.append("\n            storefiless=");
669           sb.append(region.storefiles);
670           sb.append("\n            storefileSizeMB=");
671           sb.append(region.storefileSizeMB);
672           sb.append("\n            memstoreSizeMB=");
673           sb.append(region.memstoreSizeMB);
674           sb.append("\n            storefileIndexSizeMB=");
675           sb.append(region.storefileIndexSizeMB);
676           sb.append("\n            readRequestsCount=");
677           sb.append(region.readRequestsCount);
678           sb.append("\n            writeRequestsCount=");
679           sb.append(region.writeRequestsCount);
680           sb.append("\n            rootIndexSizeKB=");
681           sb.append(region.rootIndexSizeKB);
682           sb.append("\n            totalStaticIndexSizeKB=");
683           sb.append(region.totalStaticIndexSizeKB);
684           sb.append("\n            totalStaticBloomSizeKB=");
685           sb.append(region.totalStaticBloomSizeKB);
686           sb.append("\n            totalCompactingKVs=");
687           sb.append(region.totalCompactingKVs);
688           sb.append("\n            currentCompactedKVs=");
689           sb.append(region.currentCompactedKVs);
690           sb.append('\n');
691         }
692         sb.append('\n');
693       }
694     }
695     if (!deadNodes.isEmpty()) {
696       sb.append('\n');
697       sb.append(deadNodes.size());
698       sb.append(" dead servers\n");
699       for (String node : deadNodes) {
700         sb.append("    ");
701         sb.append(node);
702         sb.append('\n');
703       }
704     }
705     return sb.toString();
706   }
707 
708   @Override
709   public byte[] createProtobufOutput() {
710     StorageClusterStatus.Builder builder = StorageClusterStatus.newBuilder();
711     builder.setRegions(regions);
712     builder.setRequests(requests);
713     builder.setAverageLoad(averageLoad);
714     for (Node node : liveNodes) {
715       StorageClusterStatus.Node.Builder nodeBuilder =
716         StorageClusterStatus.Node.newBuilder();
717       nodeBuilder.setName(node.name);
718       nodeBuilder.setStartCode(node.startCode);
719       nodeBuilder.setRequests(node.requests);
720       nodeBuilder.setHeapSizeMB(node.heapSizeMB);
721       nodeBuilder.setMaxHeapSizeMB(node.maxHeapSizeMB);
722       for (Node.Region region : node.regions) {
723         StorageClusterStatus.Region.Builder regionBuilder =
724           StorageClusterStatus.Region.newBuilder();
725         regionBuilder.setName(ByteStringer.wrap(region.name));
726         regionBuilder.setStores(region.stores);
727         regionBuilder.setStorefiles(region.storefiles);
728         regionBuilder.setStorefileSizeMB(region.storefileSizeMB);
729         regionBuilder.setMemstoreSizeMB(region.memstoreSizeMB);
730         regionBuilder.setStorefileIndexSizeMB(region.storefileIndexSizeMB);
731         regionBuilder.setReadRequestsCount(region.readRequestsCount);
732         regionBuilder.setWriteRequestsCount(region.writeRequestsCount);
733         regionBuilder.setRootIndexSizeKB(region.rootIndexSizeKB);
734         regionBuilder.setTotalStaticIndexSizeKB(region.totalStaticIndexSizeKB);
735         regionBuilder.setTotalStaticBloomSizeKB(region.totalStaticBloomSizeKB);
736         regionBuilder.setTotalCompactingKVs(region.totalCompactingKVs);
737         regionBuilder.setCurrentCompactedKVs(region.currentCompactedKVs);
738         nodeBuilder.addRegions(regionBuilder);
739       }
740       builder.addLiveNodes(nodeBuilder);
741     }
742     for (String node : deadNodes) {
743       builder.addDeadNodes(node);
744     }
745     return builder.build().toByteArray();
746   }
747 
748   @Override
749   public ProtobufMessageHandler getObjectFromMessage(byte[] message) throws IOException {
750     StorageClusterStatus.Builder builder = StorageClusterStatus.newBuilder();
751     ProtobufUtil.mergeFrom(builder, message);
752     if (builder.hasRegions()) {
753       regions = builder.getRegions();
754     }
755     if (builder.hasRequests()) {
756       requests = builder.getRequests();
757     }
758     if (builder.hasAverageLoad()) {
759       averageLoad = builder.getAverageLoad();
760     }
761     for (StorageClusterStatus.Node node : builder.getLiveNodesList()) {
762       long startCode = node.hasStartCode() ? node.getStartCode() : -1;
763       StorageClusterStatusModel.Node nodeModel =
764         addLiveNode(node.getName(), startCode, node.getHeapSizeMB(),
765           node.getMaxHeapSizeMB());
766       long requests = node.hasRequests() ? node.getRequests() : 0;
767       nodeModel.setRequests(requests);
768       for (StorageClusterStatus.Region region : node.getRegionsList()) {
769         nodeModel.addRegion(
770           region.getName().toByteArray(),
771           region.getStores(),
772           region.getStorefiles(),
773           region.getStorefileSizeMB(),
774           region.getMemstoreSizeMB(),
775           region.getStorefileIndexSizeMB(),
776           region.getReadRequestsCount(),
777           region.getWriteRequestsCount(),
778           region.getRootIndexSizeKB(),
779           region.getTotalStaticIndexSizeKB(),
780           region.getTotalStaticBloomSizeKB(),
781           region.getTotalCompactingKVs(),
782           region.getCurrentCompactedKVs());
783       }
784     }
785     for (String node : builder.getDeadNodesList()) {
786       addDeadNode(node);
787     }
788     return this;
789   }
790 }