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 com.google.protobuf.HBaseZeroCopyByteString;
30  import org.apache.hadoop.classification.InterfaceAudience;
31  import org.apache.hadoop.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     return Collections.unmodifiableCollection(deadServers);
122   }
123 
124   /**
125    * @return the number of region servers in the cluster
126    */
127   public int getServersSize() {
128     return liveServers.size();
129   }
130 
131   /**
132    * @return the number of dead region servers in the cluster
133    */
134   public int getDeadServers() {
135     return deadServers.size();
136   }
137 
138   /**
139    * @return the average cluster load
140    */
141   public double getAverageLoad() {
142     int load = getRegionsCount();
143     return (double)load / (double)getServersSize();
144   }
145 
146   /**
147    * @return the number of regions deployed on the cluster
148    */
149   public int getRegionsCount() {
150     int count = 0;
151     for (Map.Entry<ServerName, ServerLoad> e: this.liveServers.entrySet()) {
152       count += e.getValue().getNumberOfRegions();
153     }
154     return count;
155   }
156 
157   /**
158    * @return the number of requests since last report
159    */
160   public int getRequestsCount() {
161     int count = 0;
162     for (Map.Entry<ServerName, ServerLoad> e: this.liveServers.entrySet()) {
163       count += e.getValue().getTotalNumberOfRequests();
164     }
165     return count;
166   }
167 
168   /**
169    * @return the HBase version string as reported by the HMaster
170    */
171   public String getHBaseVersion() {
172     return hbaseVersion;
173   }
174 
175   /**
176    * @see java.lang.Object#equals(java.lang.Object)
177    */
178   public boolean equals(Object o) {
179     if (this == o) {
180       return true;
181     }
182     if (!(o instanceof ClusterStatus)) {
183       return false;
184     }
185     return (getVersion() == ((ClusterStatus)o).getVersion()) &&
186       getHBaseVersion().equals(((ClusterStatus)o).getHBaseVersion()) &&
187       this.liveServers.equals(((ClusterStatus)o).liveServers) &&
188       this.deadServers.containsAll(((ClusterStatus)o).deadServers) &&
189       Arrays.equals(this.masterCoprocessors,
190                     ((ClusterStatus)o).masterCoprocessors) &&
191       this.master.equals(((ClusterStatus)o).master) &&
192       this.backupMasters.containsAll(((ClusterStatus)o).backupMasters);
193   }
194 
195   /**
196    * @see java.lang.Object#hashCode()
197    */
198   public int hashCode() {
199     return VERSION + hbaseVersion.hashCode() + this.liveServers.hashCode() +
200       this.deadServers.hashCode() + this.master.hashCode() +
201       this.backupMasters.hashCode();
202   }
203 
204   /** @return the object version number */
205   public byte getVersion() {
206     return VERSION;
207   }
208 
209   //
210   // Getters
211   //
212 
213   /**
214    * Returns detailed region server information: A list of
215    * {@link ServerName}.
216    * @return region server information
217    * @deprecated Use {@link #getServers()}
218    */
219   public Collection<ServerName> getServerInfo() {
220     return getServers();
221   }
222 
223   public Collection<ServerName> getServers() {
224     return Collections.unmodifiableCollection(this.liveServers.keySet());
225   }
226 
227   /**
228    * Returns detailed information about the current master {@link ServerName}.
229    * @return current master information if it exists
230    */
231   public ServerName getMaster() {
232     return this.master;
233   }
234 
235   /**
236    * @return the number of backup masters in the cluster
237    */
238   public int getBackupMastersSize() {
239     return this.backupMasters.size();
240   }
241 
242   /**
243    * @return the names of backup masters
244    */
245   public Collection<ServerName> getBackupMasters() {
246     return Collections.unmodifiableCollection(this.backupMasters);
247   }
248 
249   /**
250    * @param sn
251    * @return Server's load or null if not found.
252    */
253   public ServerLoad getLoad(final ServerName sn) {
254     return this.liveServers.get(sn);
255   }
256 
257   @InterfaceAudience.Private
258   public Map<String, RegionState> getRegionsInTransition() {
259     return this.intransition;
260   }
261 
262   public String getClusterId() {
263     return clusterId;
264   }
265 
266   public String[] getMasterCoprocessors() {
267     return masterCoprocessors;
268   }
269 
270 
271   public boolean isBalancerOn() {
272     return balancerOn != null && balancerOn;
273   }
274 
275   public Boolean getBalancerOn() {
276     return balancerOn;
277   }
278 
279   public String toString() {
280     StringBuilder sb = new StringBuilder(1024);
281     sb.append("Master: " + master);
282     sb.append("\nNumber of backup masters: " + backupMasters.size());
283     for (ServerName serverName: backupMasters) {
284       sb.append("\n  " + serverName);
285     }
286 
287     sb.append("\nNumber of live region servers: " + liveServers.size());
288     for (ServerName serverName: liveServers.keySet()) {
289       sb.append("\n  " + serverName.getServerName());
290     }
291 
292     sb.append("\nNumber of dead region servers: " + deadServers.size());
293     for (ServerName serverName: deadServers) {
294       sb.append("\n  " + serverName);
295     }
296 
297     sb.append("\nAverage load: " + getAverageLoad());
298     sb.append("\nNumber of requests: " + getRequestsCount());
299     sb.append("\nNumber of regions: " + getRegionsCount());
300     sb.append("\nNumber of regions in transition: " + intransition.size());
301     for (RegionState state: intransition.values()) {
302       sb.append("\n  " + state.toDescriptiveString());
303     }
304     return sb.toString();
305   }
306 
307   /**
308     * Convert a ClusterStatus to a protobuf ClusterStatus
309     *
310     * @return the protobuf ClusterStatus
311     */
312   public ClusterStatusProtos.ClusterStatus convert() {
313     ClusterStatusProtos.ClusterStatus.Builder builder =
314         ClusterStatusProtos.ClusterStatus.newBuilder();
315     builder.setHbaseVersion(HBaseVersionFileContent.newBuilder().setVersion(getHBaseVersion()));
316 
317     if (liveServers != null){
318       for (Map.Entry<ServerName, ServerLoad> entry : liveServers.entrySet()) {
319         LiveServerInfo.Builder lsi =
320           LiveServerInfo.newBuilder().setServer(ProtobufUtil.toServerName(entry.getKey()));
321         lsi.setServerLoad(entry.getValue().obtainServerLoadPB());
322         builder.addLiveServers(lsi.build());
323       }
324     }
325 
326     if (deadServers != null){
327       for (ServerName deadServer : deadServers) {
328         builder.addDeadServers(ProtobufUtil.toServerName(deadServer));
329       }
330     }
331 
332     if (intransition != null) {
333       for (Map.Entry<String, RegionState> rit : getRegionsInTransition().entrySet()) {
334         ClusterStatusProtos.RegionState rs = rit.getValue().convert();
335         RegionSpecifier.Builder spec =
336             RegionSpecifier.newBuilder().setType(RegionSpecifierType.REGION_NAME);
337         spec.setValue(HBaseZeroCopyByteString.wrap(Bytes.toBytes(rit.getKey())));
338 
339         RegionInTransition pbRIT =
340             RegionInTransition.newBuilder().setSpec(spec.build()).setRegionState(rs).build();
341         builder.addRegionsInTransition(pbRIT);
342       }
343     }
344 
345     if (clusterId != null) {
346       builder.setClusterId(new ClusterId(clusterId).convert());
347     }
348 
349     if (masterCoprocessors != null) {
350       for (String coprocessor : masterCoprocessors) {
351         builder.addMasterCoprocessors(HBaseProtos.Coprocessor.newBuilder().setName(coprocessor));
352       }
353     }
354 
355     if (master != null){
356       builder.setMaster(ProtobufUtil.toServerName(getMaster()));
357     }
358 
359     if (backupMasters != null) {
360       for (ServerName backup : backupMasters) {
361         builder.addBackupMasters(ProtobufUtil.toServerName(backup));
362       }
363     }
364 
365     if (balancerOn != null){
366       builder.setBalancerOn(balancerOn);
367     }
368 
369     return builder.build();
370   }
371 
372   /**
373    * Convert a protobuf ClusterStatus to a ClusterStatus
374    *
375    * @param proto the protobuf ClusterStatus
376    * @return the converted ClusterStatus
377    */
378   public static ClusterStatus convert(ClusterStatusProtos.ClusterStatus proto) {
379 
380     Map<ServerName, ServerLoad> servers = null;
381     if (proto.getLiveServersList() != null) {
382       servers = new HashMap<ServerName, ServerLoad>(proto.getLiveServersList().size());
383       for (LiveServerInfo lsi : proto.getLiveServersList()) {
384         servers.put(ProtobufUtil.toServerName(
385             lsi.getServer()), new ServerLoad(lsi.getServerLoad()));
386       }
387     }
388 
389     Collection<ServerName> deadServers = null;
390     if (proto.getDeadServersList() != null) {
391       deadServers = new ArrayList<ServerName>(proto.getDeadServersList().size());
392       for (HBaseProtos.ServerName sn : proto.getDeadServersList()) {
393         deadServers.add(ProtobufUtil.toServerName(sn));
394       }
395     }
396 
397     Collection<ServerName> backupMasters = null;
398     if (proto.getBackupMastersList() != null) {
399       backupMasters = new ArrayList<ServerName>(proto.getBackupMastersList().size());
400       for (HBaseProtos.ServerName sn : proto.getBackupMastersList()) {
401         backupMasters.add(ProtobufUtil.toServerName(sn));
402       }
403     }
404 
405     Map<String, RegionState> rit = null;
406     if (proto.getRegionsInTransitionList() != null) {
407       rit = new HashMap<String, RegionState>(proto.getRegionsInTransitionList().size());
408       for (RegionInTransition region : proto.getRegionsInTransitionList()) {
409         String key = new String(region.getSpec().getValue().toByteArray());
410         RegionState value = RegionState.convert(region.getRegionState());
411         rit.put(key, value);
412       }
413     }
414 
415     String[] masterCoprocessors = null;
416     if (proto.getMasterCoprocessorsList() != null) {
417       final int numMasterCoprocessors = proto.getMasterCoprocessorsCount();
418       masterCoprocessors = new String[numMasterCoprocessors];
419       for (int i = 0; i < numMasterCoprocessors; i++) {
420         masterCoprocessors[i] = proto.getMasterCoprocessors(i).getName();
421       }
422     }
423 
424     return new ClusterStatus(proto.getHbaseVersion().getVersion(),
425       ClusterId.convert(proto.getClusterId()).toString(),servers,deadServers,
426       ProtobufUtil.toServerName(proto.getMaster()),backupMasters,rit,masterCoprocessors,
427       proto.getBalancerOn());
428   }
429 }