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     if (intransition == null) {
280       return Collections.EMPTY_MAP;
281     }
282     return Collections.unmodifiableMap(intransition);
283   }
284 
285   public String getClusterId() {
286     return clusterId;
287   }
288 
289   public String[] getMasterCoprocessors() {
290     return masterCoprocessors;
291   }
292 
293   public long getLastMajorCompactionTsForTable(TableName table) {
294     long result = Long.MAX_VALUE;
295     for (ServerName server : getServers()) {
296       ServerLoad load = getLoad(server);
297       for (RegionLoad rl : load.getRegionsLoad().values()) {
298         if (table.equals(HRegionInfo.getTable(rl.getName()))) {
299           result = Math.min(result, rl.getLastMajorCompactionTs());
300         }
301       }
302     }
303     return result == Long.MAX_VALUE ? 0 : result;
304   }
305 
306   public long getLastMajorCompactionTsForRegion(final byte[] region) {
307     for (ServerName server : getServers()) {
308       ServerLoad load = getLoad(server);
309       RegionLoad rl = load.getRegionsLoad().get(region);
310       if (rl != null) {
311         return rl.getLastMajorCompactionTs();
312       }
313     }
314     return 0;
315   }
316 
317   public boolean isBalancerOn() {
318     return balancerOn != null && balancerOn;
319   }
320 
321   public Boolean getBalancerOn() {
322     return balancerOn;
323   }
324 
325   public String toString() {
326     StringBuilder sb = new StringBuilder(1024);
327     sb.append("Master: " + master);
328 
329     int backupMastersSize = getBackupMastersSize();
330     sb.append("\nNumber of backup masters: " + backupMastersSize);
331     if (backupMastersSize > 0) {
332       for (ServerName serverName: backupMasters) {
333         sb.append("\n  " + serverName);
334       }
335     }
336 
337     int serversSize = getServersSize();
338     sb.append("\nNumber of live region servers: " + serversSize);
339     if (serversSize > 0) {
340       for (ServerName serverName: liveServers.keySet()) {
341         sb.append("\n  " + serverName.getServerName());
342       }
343     }
344 
345     int deadServerSize = getDeadServers();
346     sb.append("\nNumber of dead region servers: " + deadServerSize);
347     if (deadServerSize > 0) {
348       for (ServerName serverName: deadServers) {
349         sb.append("\n  " + serverName);
350       }
351     }
352 
353     sb.append("\nAverage load: " + getAverageLoad());
354     sb.append("\nNumber of requests: " + getRequestsCount());
355     sb.append("\nNumber of regions: " + getRegionsCount());
356 
357     int ritSize = (intransition != null) ? intransition.size() : 0;
358     sb.append("\nNumber of regions in transition: " + ritSize);
359     if (ritSize > 0) {
360       for (RegionState state: intransition.values()) {
361         sb.append("\n  " + state.toDescriptiveString());
362       }
363     }
364     return sb.toString();
365   }
366 
367   /**
368     * Convert a ClusterStatus to a protobuf ClusterStatus
369     *
370     * @return the protobuf ClusterStatus
371     */
372   public ClusterStatusProtos.ClusterStatus convert() {
373     ClusterStatusProtos.ClusterStatus.Builder builder =
374         ClusterStatusProtos.ClusterStatus.newBuilder();
375     builder.setHbaseVersion(HBaseVersionFileContent.newBuilder().setVersion(getHBaseVersion()));
376 
377     if (liveServers != null){
378       for (Map.Entry<ServerName, ServerLoad> entry : liveServers.entrySet()) {
379         LiveServerInfo.Builder lsi =
380           LiveServerInfo.newBuilder().setServer(ProtobufUtil.toServerName(entry.getKey()));
381         lsi.setServerLoad(entry.getValue().obtainServerLoadPB());
382         builder.addLiveServers(lsi.build());
383       }
384     }
385 
386     if (deadServers != null){
387       for (ServerName deadServer : deadServers) {
388         builder.addDeadServers(ProtobufUtil.toServerName(deadServer));
389       }
390     }
391 
392     if (intransition != null) {
393       for (Map.Entry<String, RegionState> rit : getRegionsInTransition().entrySet()) {
394         ClusterStatusProtos.RegionState rs = rit.getValue().convert();
395         RegionSpecifier.Builder spec =
396             RegionSpecifier.newBuilder().setType(RegionSpecifierType.REGION_NAME);
397         spec.setValue(ByteStringer.wrap(Bytes.toBytes(rit.getKey())));
398 
399         RegionInTransition pbRIT =
400             RegionInTransition.newBuilder().setSpec(spec.build()).setRegionState(rs).build();
401         builder.addRegionsInTransition(pbRIT);
402       }
403     }
404 
405     if (clusterId != null) {
406       builder.setClusterId(new ClusterId(clusterId).convert());
407     }
408 
409     if (masterCoprocessors != null) {
410       for (String coprocessor : masterCoprocessors) {
411         builder.addMasterCoprocessors(HBaseProtos.Coprocessor.newBuilder().setName(coprocessor));
412       }
413     }
414 
415     if (master != null){
416       builder.setMaster(ProtobufUtil.toServerName(getMaster()));
417     }
418 
419     if (backupMasters != null) {
420       for (ServerName backup : backupMasters) {
421         builder.addBackupMasters(ProtobufUtil.toServerName(backup));
422       }
423     }
424 
425     if (balancerOn != null){
426       builder.setBalancerOn(balancerOn);
427     }
428 
429     return builder.build();
430   }
431 
432   /**
433    * Convert a protobuf ClusterStatus to a ClusterStatus
434    *
435    * @param proto the protobuf ClusterStatus
436    * @return the converted ClusterStatus
437    */
438   public static ClusterStatus convert(ClusterStatusProtos.ClusterStatus proto) {
439 
440     Map<ServerName, ServerLoad> servers = null;
441     if (proto.getLiveServersList() != null) {
442       servers = new HashMap<ServerName, ServerLoad>(proto.getLiveServersList().size());
443       for (LiveServerInfo lsi : proto.getLiveServersList()) {
444         servers.put(ProtobufUtil.toServerName(
445             lsi.getServer()), new ServerLoad(lsi.getServerLoad()));
446       }
447     }
448 
449     Collection<ServerName> deadServers = null;
450     if (proto.getDeadServersList() != null) {
451       deadServers = new ArrayList<ServerName>(proto.getDeadServersList().size());
452       for (HBaseProtos.ServerName sn : proto.getDeadServersList()) {
453         deadServers.add(ProtobufUtil.toServerName(sn));
454       }
455     }
456 
457     Collection<ServerName> backupMasters = null;
458     if (proto.getBackupMastersList() != null) {
459       backupMasters = new ArrayList<ServerName>(proto.getBackupMastersList().size());
460       for (HBaseProtos.ServerName sn : proto.getBackupMastersList()) {
461         backupMasters.add(ProtobufUtil.toServerName(sn));
462       }
463     }
464 
465     Map<String, RegionState> rit = null;
466     if (proto.getRegionsInTransitionList() != null) {
467       rit = new HashMap<String, RegionState>(proto.getRegionsInTransitionList().size());
468       for (RegionInTransition region : proto.getRegionsInTransitionList()) {
469         String key = new String(region.getSpec().getValue().toByteArray());
470         RegionState value = RegionState.convert(region.getRegionState());
471         rit.put(key, value);
472       }
473     }
474 
475     String[] masterCoprocessors = null;
476     if (proto.getMasterCoprocessorsList() != null) {
477       final int numMasterCoprocessors = proto.getMasterCoprocessorsCount();
478       masterCoprocessors = new String[numMasterCoprocessors];
479       for (int i = 0; i < numMasterCoprocessors; i++) {
480         masterCoprocessors[i] = proto.getMasterCoprocessors(i).getName();
481       }
482     }
483 
484     return new ClusterStatus(proto.getHbaseVersion().getVersion(),
485       ClusterId.convert(proto.getClusterId()).toString(),servers,deadServers,
486       ProtobufUtil.toServerName(proto.getMaster()),backupMasters,rit,masterCoprocessors,
487       proto.getBalancerOn());
488   }
489 }