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