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