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 As of release 0.96
91     *             (<a href="https://issues.apache.org/jira/browse/HBASE-6038">HBASE-6038</a>).
92     *             This will be removed in HBase 2.0.0.
93     *             Used by Writables and Writables are going away.
94     */
95    @Deprecated
96    public ClusterStatus() {
97      super();
98    }
99  
100   public ClusterStatus(final String hbaseVersion, final String clusterid,
101       final Map<ServerName, ServerLoad> servers,
102       final Collection<ServerName> deadServers,
103       final ServerName master,
104       final Collection<ServerName> backupMasters,
105       final Map<String, RegionState> rit,
106       final String[] masterCoprocessors,
107       final Boolean balancerOn) {
108     this.hbaseVersion = hbaseVersion;
109 
110     this.liveServers = servers;
111     this.deadServers = deadServers;
112     this.master = master;
113     this.backupMasters = backupMasters;
114     this.intransition = rit;
115     this.clusterId = clusterid;
116     this.masterCoprocessors = masterCoprocessors;
117     this.balancerOn = balancerOn;
118   }
119 
120   /**
121    * @return the names of region servers on the dead list
122    */
123   public Collection<ServerName> getDeadServerNames() {
124     if (deadServers == null) {
125       return Collections.<ServerName>emptyList();
126     }
127     return Collections.unmodifiableCollection(deadServers);
128   }
129 
130   /**
131    * @return the number of region servers in the cluster
132    */
133   public int getServersSize() {
134     return liveServers != null ? liveServers.size() : 0;
135   }
136 
137   /**
138    * @return the number of dead region servers in the cluster
139    */
140   public int getDeadServers() {
141     return deadServers != null ? deadServers.size() : 0;
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   /**
224    * Returns detailed region server information: A list of
225    * {@link ServerName}.
226    * @return region server information
227    * @deprecated As of release 0.92
228    *             (<a href="https://issues.apache.org/jira/browse/HBASE-1502">HBASE-1502</a>).
229    *             This will be removed in HBase 2.0.0.
230    *             Use {@link #getServers()}.
231    */
232   @Deprecated
233   public Collection<ServerName> getServerInfo() {
234     return getServers();
235   }
236 
237   public Collection<ServerName> getServers() {
238     if (liveServers == null) {
239       return Collections.<ServerName>emptyList();
240     }
241     return Collections.unmodifiableCollection(this.liveServers.keySet());
242   }
243 
244   /**
245    * Returns detailed information about the current master {@link ServerName}.
246    * @return current master information if it exists
247    */
248   public ServerName getMaster() {
249     return this.master;
250   }
251 
252   /**
253    * @return the number of backup masters in the cluster
254    */
255   public int getBackupMastersSize() {
256     return backupMasters != null ? backupMasters.size() : 0;
257   }
258 
259   /**
260    * @return the names of backup masters
261    */
262   public Collection<ServerName> getBackupMasters() {
263     if (backupMasters == null) {
264       return Collections.<ServerName>emptyList();
265     }
266     return Collections.unmodifiableCollection(this.backupMasters);
267   }
268 
269   /**
270    * @param sn
271    * @return Server's load or null if not found.
272    */
273   public ServerLoad getLoad(final ServerName sn) {
274     return liveServers != null ? liveServers.get(sn) : null;
275   }
276 
277   @InterfaceAudience.Private
278   public Map<String, RegionState> getRegionsInTransition() {
279     return this.intransition;
280   }
281 
282   public String getClusterId() {
283     return clusterId;
284   }
285 
286   public String[] getMasterCoprocessors() {
287     return masterCoprocessors;
288   }
289 
290   public long getLastMajorCompactionTsForTable(TableName table) {
291     long result = Long.MAX_VALUE;
292     for (ServerName server : getServers()) {
293       ServerLoad load = getLoad(server);
294       for (RegionLoad rl : load.getRegionsLoad().values()) {
295         if (table.equals(HRegionInfo.getTable(rl.getName()))) {
296           result = Math.min(result, rl.getLastMajorCompactionTs());
297         }
298       }
299     }
300     return result == Long.MAX_VALUE ? 0 : result;
301   }
302 
303   public long getLastMajorCompactionTsForRegion(final byte[] region) {
304     for (ServerName server : getServers()) {
305       ServerLoad load = getLoad(server);
306       RegionLoad rl = load.getRegionsLoad().get(region);
307       if (rl != null) {
308         return rl.getLastMajorCompactionTs();
309       }
310     }
311     return 0;
312   }
313 
314   public boolean isBalancerOn() {
315     return balancerOn != null && balancerOn;
316   }
317 
318   public Boolean getBalancerOn() {
319     return balancerOn;
320   }
321 
322   public String toString() {
323     StringBuilder sb = new StringBuilder(1024);
324     sb.append("Master: " + master);
325 
326     int backupMastersSize = getBackupMastersSize();
327     sb.append("\nNumber of backup masters: " + backupMastersSize);
328     if (backupMastersSize > 0) {
329       for (ServerName serverName: backupMasters) {
330         sb.append("\n  " + serverName);
331       }
332     }
333 
334     int serversSize = getServersSize();
335     sb.append("\nNumber of live region servers: " + serversSize);
336     if (serversSize > 0) {
337       for (ServerName serverName: liveServers.keySet()) {
338         sb.append("\n  " + serverName.getServerName());
339       }
340     }
341 
342     int deadServerSize = getDeadServers();
343     sb.append("\nNumber of dead region servers: " + deadServerSize);
344     if (deadServerSize > 0) {
345       for (ServerName serverName: deadServers) {
346         sb.append("\n  " + serverName);
347       }
348     }
349 
350     sb.append("\nAverage load: " + getAverageLoad());
351     sb.append("\nNumber of requests: " + getRequestsCount());
352     sb.append("\nNumber of regions: " + getRegionsCount());
353 
354     int ritSize = (intransition != null) ? intransition.size() : 0;
355     sb.append("\nNumber of regions in transition: " + ritSize);
356     if (ritSize > 0) {
357       for (RegionState state: intransition.values()) {
358         sb.append("\n  " + state.toDescriptiveString());
359       }
360     }
361     return sb.toString();
362   }
363 
364   /**
365     * Convert a ClusterStatus to a protobuf ClusterStatus
366     *
367     * @return the protobuf ClusterStatus
368     */
369   public ClusterStatusProtos.ClusterStatus convert() {
370     ClusterStatusProtos.ClusterStatus.Builder builder =
371         ClusterStatusProtos.ClusterStatus.newBuilder();
372     builder.setHbaseVersion(HBaseVersionFileContent.newBuilder().setVersion(getHBaseVersion()));
373 
374     if (liveServers != null){
375       for (Map.Entry<ServerName, ServerLoad> entry : liveServers.entrySet()) {
376         LiveServerInfo.Builder lsi =
377           LiveServerInfo.newBuilder().setServer(ProtobufUtil.toServerName(entry.getKey()));
378         lsi.setServerLoad(entry.getValue().obtainServerLoadPB());
379         builder.addLiveServers(lsi.build());
380       }
381     }
382 
383     if (deadServers != null){
384       for (ServerName deadServer : deadServers) {
385         builder.addDeadServers(ProtobufUtil.toServerName(deadServer));
386       }
387     }
388 
389     if (intransition != null) {
390       for (Map.Entry<String, RegionState> rit : getRegionsInTransition().entrySet()) {
391         ClusterStatusProtos.RegionState rs = rit.getValue().convert();
392         RegionSpecifier.Builder spec =
393             RegionSpecifier.newBuilder().setType(RegionSpecifierType.REGION_NAME);
394         spec.setValue(ByteStringer.wrap(Bytes.toBytes(rit.getKey())));
395 
396         RegionInTransition pbRIT =
397             RegionInTransition.newBuilder().setSpec(spec.build()).setRegionState(rs).build();
398         builder.addRegionsInTransition(pbRIT);
399       }
400     }
401 
402     if (clusterId != null) {
403       builder.setClusterId(new ClusterId(clusterId).convert());
404     }
405 
406     if (masterCoprocessors != null) {
407       for (String coprocessor : masterCoprocessors) {
408         builder.addMasterCoprocessors(HBaseProtos.Coprocessor.newBuilder().setName(coprocessor));
409       }
410     }
411 
412     if (master != null){
413       builder.setMaster(ProtobufUtil.toServerName(getMaster()));
414     }
415 
416     if (backupMasters != null) {
417       for (ServerName backup : backupMasters) {
418         builder.addBackupMasters(ProtobufUtil.toServerName(backup));
419       }
420     }
421 
422     if (balancerOn != null){
423       builder.setBalancerOn(balancerOn);
424     }
425 
426     return builder.build();
427   }
428 
429   /**
430    * Convert a protobuf ClusterStatus to a ClusterStatus
431    *
432    * @param proto the protobuf ClusterStatus
433    * @return the converted ClusterStatus
434    */
435   public static ClusterStatus convert(ClusterStatusProtos.ClusterStatus proto) {
436 
437     Map<ServerName, ServerLoad> servers = null;
438     if (proto.getLiveServersList() != null) {
439       servers = new HashMap<ServerName, ServerLoad>(proto.getLiveServersList().size());
440       for (LiveServerInfo lsi : proto.getLiveServersList()) {
441         servers.put(ProtobufUtil.toServerName(
442             lsi.getServer()), new ServerLoad(lsi.getServerLoad()));
443       }
444     }
445 
446     Collection<ServerName> deadServers = null;
447     if (proto.getDeadServersList() != null) {
448       deadServers = new ArrayList<ServerName>(proto.getDeadServersList().size());
449       for (HBaseProtos.ServerName sn : proto.getDeadServersList()) {
450         deadServers.add(ProtobufUtil.toServerName(sn));
451       }
452     }
453 
454     Collection<ServerName> backupMasters = null;
455     if (proto.getBackupMastersList() != null) {
456       backupMasters = new ArrayList<ServerName>(proto.getBackupMastersList().size());
457       for (HBaseProtos.ServerName sn : proto.getBackupMastersList()) {
458         backupMasters.add(ProtobufUtil.toServerName(sn));
459       }
460     }
461 
462     Map<String, RegionState> rit = null;
463     if (proto.getRegionsInTransitionList() != null) {
464       rit = new HashMap<String, RegionState>(proto.getRegionsInTransitionList().size());
465       for (RegionInTransition region : proto.getRegionsInTransitionList()) {
466         String key = new String(region.getSpec().getValue().toByteArray());
467         RegionState value = RegionState.convert(region.getRegionState());
468         rit.put(key, value);
469       }
470     }
471 
472     String[] masterCoprocessors = null;
473     if (proto.getMasterCoprocessorsList() != null) {
474       final int numMasterCoprocessors = proto.getMasterCoprocessorsCount();
475       masterCoprocessors = new String[numMasterCoprocessors];
476       for (int i = 0; i < numMasterCoprocessors; i++) {
477         masterCoprocessors[i] = proto.getMasterCoprocessors(i).getName();
478       }
479     }
480 
481     return new ClusterStatus(proto.getHbaseVersion().getVersion(),
482       ClusterId.convert(proto.getClusterId()).toString(),servers,deadServers,
483       ProtobufUtil.toServerName(proto.getMaster()),backupMasters,rit,masterCoprocessors,
484       proto.getBalancerOn());
485   }
486 }