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  
20  package org.apache.hadoop.hbase;
21  
22  import java.util.ArrayList;
23  import java.util.Arrays;
24  import java.util.Collection;
25  import java.util.Collections;
26  import java.util.HashMap;
27  import java.util.Map;
28  
29  import org.apache.hadoop.hbase.util.ByteStringer;
30  import org.apache.hadoop.hbase.classification.InterfaceAudience;
31  import org.apache.hadoop.hbase.classification.InterfaceStability;
32  import org.apache.hadoop.hbase.master.RegionState;
33  import org.apache.hadoop.hbase.protobuf.ProtobufUtil;
34  import org.apache.hadoop.hbase.protobuf.generated.ClusterStatusProtos;
35  import org.apache.hadoop.hbase.protobuf.generated.ClusterStatusProtos.LiveServerInfo;
36  import org.apache.hadoop.hbase.protobuf.generated.ClusterStatusProtos.RegionInTransition;
37  import org.apache.hadoop.hbase.protobuf.generated.FSProtos.HBaseVersionFileContent;
38  import org.apache.hadoop.hbase.protobuf.generated.HBaseProtos;
39  import org.apache.hadoop.hbase.protobuf.generated.HBaseProtos.RegionSpecifier;
40  import org.apache.hadoop.hbase.protobuf.generated.HBaseProtos.RegionSpecifier.RegionSpecifierType;
41  import org.apache.hadoop.hbase.util.Bytes;
42  import org.apache.hadoop.io.VersionedWritable;
43  
44  
45  /**
46   * Status information on the HBase cluster.
47   * <p>
48   * <tt>ClusterStatus</tt> provides clients with information such as:
49   * <ul>
50   * <li>The count and names of region servers in the cluster.</li>
51   * <li>The count and names of dead region servers in the cluster.</li>
52   * <li>The name of the active master for the cluster.</li>
53   * <li>The name(s) of the backup master(s) for the cluster, if they exist.</li>
54   * <li>The average cluster load.</li>
55   * <li>The number of regions deployed on the cluster.</li>
56   * <li>The number of requests since last report.</li>
57   * <li>Detailed region server loading and resource usage information,
58   *  per server and per region.</li>
59   * <li>Regions in transition at master</li>
60   * <li>The unique cluster ID</li>
61   * </ul>
62   */
63  @InterfaceAudience.Public
64  @InterfaceStability.Evolving
65  public class ClusterStatus extends VersionedWritable {
66    /**
67     * Version for object serialization.  Incremented for changes in serialized
68     * representation.
69     * <dl>
70     *   <dt>0</dt> <dd>Initial version</dd>
71     *   <dt>1</dt> <dd>Added cluster ID</dd>
72     *   <dt>2</dt> <dd>Added Map of ServerName to ServerLoad</dd>
73     *   <dt>3</dt> <dd>Added master and backupMasters</dd>
74     * </dl>
75     */
76    private static final byte VERSION = 2;
77  
78    private String hbaseVersion;
79    private Map<ServerName, ServerLoad> liveServers;
80    private Collection<ServerName> deadServers;
81    private ServerName master;
82    private Collection<ServerName> backupMasters;
83    private Map<String, RegionState> intransition;
84    private String clusterId;
85    private String[] masterCoprocessors;
86    private Boolean balancerOn;
87  
88    /**
89     * Constructor, for Writable
90     * @deprecated Used by Writables and Writables are going away.
91     */
92    @Deprecated
93    public ClusterStatus() {
94      super();
95    }
96  
97    public ClusterStatus(final String hbaseVersion, final String clusterid,
98        final Map<ServerName, ServerLoad> servers,
99        final Collection<ServerName> deadServers,
100       final ServerName master,
101       final Collection<ServerName> backupMasters,
102       final Map<String, RegionState> rit,
103       final String[] masterCoprocessors,
104       final Boolean balancerOn) {
105     this.hbaseVersion = hbaseVersion;
106 
107     this.liveServers = servers;
108     this.deadServers = deadServers;
109     this.master = master;
110     this.backupMasters = backupMasters;
111     this.intransition = rit;
112     this.clusterId = clusterid;
113     this.masterCoprocessors = masterCoprocessors;
114     this.balancerOn = balancerOn;
115   }
116 
117   /**
118    * @return the names of region servers on the dead list
119    */
120   public Collection<ServerName> getDeadServerNames() {
121     if (deadServers == null) {
122       return Collections.<ServerName>emptyList();
123     }
124     return Collections.unmodifiableCollection(deadServers);
125   }
126 
127   /**
128    * @return the number of region servers in the cluster
129    */
130   public int getServersSize() {
131     return liveServers != null ? liveServers.size() : 0;
132   }
133 
134   /**
135    * @return the number of dead region servers in the cluster
136    */
137   public int getDeadServers() {
138     return deadServers != null ? deadServers.size() : 0;
139   }
140 
141   /**
142    * @return the average cluster load
143    */
144   public double getAverageLoad() {
145     int load = getRegionsCount();
146     return (double)load / (double)getServersSize();
147   }
148 
149   /**
150    * @return the number of regions deployed on the cluster
151    */
152   public int getRegionsCount() {
153     int count = 0;
154     if (liveServers != null && !liveServers.isEmpty()) {
155       for (Map.Entry<ServerName, ServerLoad> e: this.liveServers.entrySet()) {
156         count += e.getValue().getNumberOfRegions();
157       }
158     }
159     return count;
160   }
161 
162   /**
163    * @return the number of requests since last report
164    */
165   public int getRequestsCount() {
166     int count = 0;
167     if (liveServers != null && !liveServers.isEmpty()) {
168       for (Map.Entry<ServerName, ServerLoad> e: this.liveServers.entrySet()) {
169         count += e.getValue().getNumberOfRequests();
170       }
171     }
172     return count;
173   }
174 
175   /**
176    * @return the HBase version string as reported by the HMaster
177    */
178   public String getHBaseVersion() {
179     return hbaseVersion;
180   }
181 
182   /**
183    * @see java.lang.Object#equals(java.lang.Object)
184    */
185   public boolean equals(Object o) {
186     if (this == o) {
187       return true;
188     }
189     if (!(o instanceof ClusterStatus)) {
190       return false;
191     }
192     return (getVersion() == ((ClusterStatus)o).getVersion()) &&
193       getHBaseVersion().equals(((ClusterStatus)o).getHBaseVersion()) &&
194       this.liveServers.equals(((ClusterStatus)o).liveServers) &&
195       this.deadServers.containsAll(((ClusterStatus)o).deadServers) &&
196       Arrays.equals(this.masterCoprocessors,
197                     ((ClusterStatus)o).masterCoprocessors) &&
198       this.master.equals(((ClusterStatus)o).master) &&
199       this.backupMasters.containsAll(((ClusterStatus)o).backupMasters);
200   }
201 
202   /**
203    * @see java.lang.Object#hashCode()
204    */
205   public int hashCode() {
206     return VERSION + hbaseVersion.hashCode() + this.liveServers.hashCode() +
207       this.deadServers.hashCode() + this.master.hashCode() +
208       this.backupMasters.hashCode();
209   }
210 
211   /** @return the object version number */
212   public byte getVersion() {
213     return VERSION;
214   }
215 
216   //
217   // Getters
218   //
219 
220   /**
221    * Returns detailed region server information: A list of
222    * {@link ServerName}.
223    * @return region server information
224    * @deprecated Use {@link #getServers()}
225    */
226   public Collection<ServerName> getServerInfo() {
227     return getServers();
228   }
229 
230   public Collection<ServerName> getServers() {
231     if (liveServers == null) {
232       return Collections.<ServerName>emptyList();
233     }
234     return Collections.unmodifiableCollection(this.liveServers.keySet());
235   }
236 
237   /**
238    * Returns detailed information about the current master {@link ServerName}.
239    * @return current master information if it exists
240    */
241   public ServerName getMaster() {
242     return this.master;
243   }
244 
245   /**
246    * @return the number of backup masters in the cluster
247    */
248   public int getBackupMastersSize() {
249     return backupMasters != null ? backupMasters.size() : 0;
250   }
251 
252   /**
253    * @return the names of backup masters
254    */
255   public Collection<ServerName> getBackupMasters() {
256     if (backupMasters == null) {
257       return Collections.<ServerName>emptyList();
258     }
259     return Collections.unmodifiableCollection(this.backupMasters);
260   }
261 
262   /**
263    * @param sn
264    * @return Server's load or null if not found.
265    */
266   public ServerLoad getLoad(final ServerName sn) {
267     return liveServers != null ? liveServers.get(sn) : null;
268   }
269 
270   @InterfaceAudience.Private
271   public Map<String, RegionState> getRegionsInTransition() {
272     return this.intransition;
273   }
274 
275   public String getClusterId() {
276     return clusterId;
277   }
278 
279   public String[] getMasterCoprocessors() {
280     return masterCoprocessors;
281   }
282 
283 
284   public boolean isBalancerOn() {
285     return balancerOn != null && balancerOn;
286   }
287 
288   public Boolean getBalancerOn() {
289     return balancerOn;
290   }
291 
292   public String toString() {
293     StringBuilder sb = new StringBuilder(1024);
294     sb.append("Master: " + master);
295 
296     int backupMastersSize = getBackupMastersSize();
297     sb.append("\nNumber of backup masters: " + backupMastersSize);
298     if (backupMastersSize > 0) {
299       for (ServerName serverName: backupMasters) {
300         sb.append("\n  " + serverName);
301       }
302     }
303 
304     int serversSize = getServersSize();
305     sb.append("\nNumber of live region servers: " + serversSize);
306     if (serversSize > 0) {
307       for (ServerName serverName: liveServers.keySet()) {
308         sb.append("\n  " + serverName.getServerName());
309       }
310     }
311 
312     int deadServerSize = getDeadServers();
313     sb.append("\nNumber of dead region servers: " + deadServerSize);
314     if (deadServerSize > 0) {
315       for (ServerName serverName: deadServers) {
316         sb.append("\n  " + serverName);
317       }
318     }
319 
320     sb.append("\nAverage load: " + getAverageLoad());
321     sb.append("\nNumber of requests: " + getRequestsCount());
322     sb.append("\nNumber of regions: " + getRegionsCount());
323 
324     int ritSize = (intransition != null) ? intransition.size() : 0;
325     sb.append("\nNumber of regions in transition: " + ritSize);
326     if (ritSize > 0) {
327       for (RegionState state: intransition.values()) {
328         sb.append("\n  " + state.toDescriptiveString());
329       }
330     }
331     return sb.toString();
332   }
333 
334   /**
335     * Convert a ClusterStatus to a protobuf ClusterStatus
336     *
337     * @return the protobuf ClusterStatus
338     */
339   public ClusterStatusProtos.ClusterStatus convert() {
340     ClusterStatusProtos.ClusterStatus.Builder builder =
341         ClusterStatusProtos.ClusterStatus.newBuilder();
342     builder.setHbaseVersion(HBaseVersionFileContent.newBuilder().setVersion(getHBaseVersion()));
343 
344     if (liveServers != null){
345       for (Map.Entry<ServerName, ServerLoad> entry : liveServers.entrySet()) {
346         LiveServerInfo.Builder lsi =
347           LiveServerInfo.newBuilder().setServer(ProtobufUtil.toServerName(entry.getKey()));
348         lsi.setServerLoad(entry.getValue().obtainServerLoadPB());
349         builder.addLiveServers(lsi.build());
350       }
351     }
352 
353     if (deadServers != null){
354       for (ServerName deadServer : deadServers) {
355         builder.addDeadServers(ProtobufUtil.toServerName(deadServer));
356       }
357     }
358 
359     if (intransition != null) {
360       for (Map.Entry<String, RegionState> rit : getRegionsInTransition().entrySet()) {
361         ClusterStatusProtos.RegionState rs = rit.getValue().convert();
362         RegionSpecifier.Builder spec =
363             RegionSpecifier.newBuilder().setType(RegionSpecifierType.REGION_NAME);
364         spec.setValue(ByteStringer.wrap(Bytes.toBytes(rit.getKey())));
365 
366         RegionInTransition pbRIT =
367             RegionInTransition.newBuilder().setSpec(spec.build()).setRegionState(rs).build();
368         builder.addRegionsInTransition(pbRIT);
369       }
370     }
371 
372     if (clusterId != null) {
373       builder.setClusterId(new ClusterId(clusterId).convert());
374     }
375 
376     if (masterCoprocessors != null) {
377       for (String coprocessor : masterCoprocessors) {
378         builder.addMasterCoprocessors(HBaseProtos.Coprocessor.newBuilder().setName(coprocessor));
379       }
380     }
381 
382     if (master != null){
383       builder.setMaster(ProtobufUtil.toServerName(getMaster()));
384     }
385 
386     if (backupMasters != null) {
387       for (ServerName backup : backupMasters) {
388         builder.addBackupMasters(ProtobufUtil.toServerName(backup));
389       }
390     }
391 
392     if (balancerOn != null){
393       builder.setBalancerOn(balancerOn);
394     }
395 
396     return builder.build();
397   }
398 
399   /**
400    * Convert a protobuf ClusterStatus to a ClusterStatus
401    *
402    * @param proto the protobuf ClusterStatus
403    * @return the converted ClusterStatus
404    */
405   public static ClusterStatus convert(ClusterStatusProtos.ClusterStatus proto) {
406 
407     Map<ServerName, ServerLoad> servers = null;
408     if (proto.getLiveServersList() != null) {
409       servers = new HashMap<ServerName, ServerLoad>(proto.getLiveServersList().size());
410       for (LiveServerInfo lsi : proto.getLiveServersList()) {
411         servers.put(ProtobufUtil.toServerName(
412             lsi.getServer()), new ServerLoad(lsi.getServerLoad()));
413       }
414     }
415 
416     Collection<ServerName> deadServers = null;
417     if (proto.getDeadServersList() != null) {
418       deadServers = new ArrayList<ServerName>(proto.getDeadServersList().size());
419       for (HBaseProtos.ServerName sn : proto.getDeadServersList()) {
420         deadServers.add(ProtobufUtil.toServerName(sn));
421       }
422     }
423 
424     Collection<ServerName> backupMasters = null;
425     if (proto.getBackupMastersList() != null) {
426       backupMasters = new ArrayList<ServerName>(proto.getBackupMastersList().size());
427       for (HBaseProtos.ServerName sn : proto.getBackupMastersList()) {
428         backupMasters.add(ProtobufUtil.toServerName(sn));
429       }
430     }
431 
432     Map<String, RegionState> rit = null;
433     if (proto.getRegionsInTransitionList() != null) {
434       rit = new HashMap<String, RegionState>(proto.getRegionsInTransitionList().size());
435       for (RegionInTransition region : proto.getRegionsInTransitionList()) {
436         String key = new String(region.getSpec().getValue().toByteArray());
437         RegionState value = RegionState.convert(region.getRegionState());
438         rit.put(key, value);
439       }
440     }
441 
442     String[] masterCoprocessors = null;
443     if (proto.getMasterCoprocessorsList() != null) {
444       final int numMasterCoprocessors = proto.getMasterCoprocessorsCount();
445       masterCoprocessors = new String[numMasterCoprocessors];
446       for (int i = 0; i < numMasterCoprocessors; i++) {
447         masterCoprocessors[i] = proto.getMasterCoprocessors(i).getName();
448       }
449     }
450 
451     return new ClusterStatus(proto.getHbaseVersion().getVersion(),
452       ClusterId.convert(proto.getClusterId()).toString(),servers,deadServers,
453       ProtobufUtil.toServerName(proto.getMaster()),backupMasters,rit,masterCoprocessors,
454       proto.getBalancerOn());
455   }
456 }