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