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  import java.util.Set;
29
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.ByteStringer;
42  import org.apache.hadoop.hbase.util.Bytes;
43  import org.apache.hadoop.io.VersionedWritable;
44  
45
46  /**
47   * Status information on the HBase cluster.
48   * <p>
49   * <tt>ClusterStatus</tt> provides clients with information such as:
50   * <ul>
51   * <li>The count and names of region servers in the cluster.</li>
52   * <li>The count and names of dead region servers in the cluster.</li>
53   * <li>The name of the active master for the cluster.</li>
54   * <li>The name(s) of the backup master(s) for the cluster, if they exist.</li>
55   * <li>The average cluster load.</li>
56   * <li>The number of regions deployed on the cluster.</li>
57   * <li>The number of requests since last report.</li>
58   * <li>Detailed region server loading and resource usage information,
59   *  per server and per region.</li>
60   * <li>Regions in transition at master</li>
61   * <li>The unique cluster ID</li>
62   * </ul>
63   */
64  @InterfaceAudience.Public
65  @InterfaceStability.Evolving
66  public class ClusterStatus extends VersionedWritable {
67    /**
68     * Version for object serialization.  Incremented for changes in serialized
69     * representation.
70     * <dl>
71     *   <dt>0</dt> <dd>Initial version</dd>
72     *   <dt>1</dt> <dd>Added cluster ID</dd>
73     *   <dt>2</dt> <dd>Added Map of ServerName to ServerLoad</dd>
74     *   <dt>3</dt> <dd>Added master and backupMasters</dd>
75     * </dl>
76     */
77    private static final byte VERSION = 2;
78
79    private String hbaseVersion;
80    private Map<ServerName, ServerLoad> liveServers;
81    private Collection<ServerName> deadServers;
82    private ServerName master;
83    private Collection<ServerName> backupMasters;
84    private Set<RegionState> intransition;
85    private String clusterId;
86    private String[] masterCoprocessors;
87    private Boolean balancerOn;
88
89    public ClusterStatus(final String hbaseVersion, final String clusterid,
90        final Map<ServerName, ServerLoad> servers,
91        final Collection<ServerName> deadServers,
92        final ServerName master,
93        final Collection<ServerName> backupMasters,
94        final Set<RegionState> rit,
95        final String[] masterCoprocessors,
96        final Boolean balancerOn) {
97      this.hbaseVersion = hbaseVersion;
98
99      this.liveServers = servers;
100     this.deadServers = deadServers;
101     this.master = master;
102     this.backupMasters = backupMasters;
103     this.intransition = rit;
104     this.clusterId = clusterid;
105     this.masterCoprocessors = masterCoprocessors;
106     this.balancerOn = balancerOn;
107   }
108
109   /**
110    * @return the names of region servers on the dead list
111    */
112   public Collection<ServerName> getDeadServerNames() {
113     if (deadServers == null) {
114       return Collections.<ServerName>emptyList();
115     }
116     return Collections.unmodifiableCollection(deadServers);
117   }
118
119   /**
120    * @return the number of region servers in the cluster
121    */
122   public int getServersSize() {
123     return liveServers != null ? liveServers.size() : 0;
124   }
125
126   /**
127    * @return the number of dead region servers in the cluster
128    * @deprecated As of release 2.0.0, this will be removed in HBase 3.0.0
129    *             (<a href="https://issues.apache.org/jira/browse/HBASE-13656">HBASE-13656</a>).
130    *             Use {@link #getDeadServersSize()}.
131    */
132   @Deprecated
133   public int getDeadServers() {
134     return getDeadServersSize();
135   }
136
137   /**
138    * @return the number of dead region servers in the cluster
139    */
140   public int getDeadServersSize() {
141     return deadServers != null ? deadServers.size() : 0;
142   }
143 
144
145   /**
146    * @return the average cluster load
147    */
148   public double getAverageLoad() {
149     int load = getRegionsCount();
150     return (double)load / (double)getServersSize();
151   }
152
153   /**
154    * @return the number of regions deployed on the cluster
155    */
156   public int getRegionsCount() {
157     int count = 0;
158     if (liveServers != null && !liveServers.isEmpty()) {
159       for (Map.Entry<ServerName, ServerLoad> e: this.liveServers.entrySet()) {
160         count += e.getValue().getNumberOfRegions();
161       }
162     }
163     return count;
164   }
165
166   /**
167    * @return the number of requests since last report
168    */
169   public int getRequestsCount() {
170     int count = 0;
171     if (liveServers != null && !liveServers.isEmpty()) {
172       for (Map.Entry<ServerName, ServerLoad> e: this.liveServers.entrySet()) {
173         count += e.getValue().getNumberOfRequests();
174       }
175     }
176     return count;
177   }
178
179   /**
180    * @return the HBase version string as reported by the HMaster
181    */
182   public String getHBaseVersion() {
183     return hbaseVersion;
184   }
185
186   /**
187    * @see java.lang.Object#equals(java.lang.Object)
188    */
189   public boolean equals(Object o) {
190     if (this == o) {
191       return true;
192     }
193     if (!(o instanceof ClusterStatus)) {
194       return false;
195     }
196     return (getVersion() == ((ClusterStatus)o).getVersion()) &&
197       getHBaseVersion().equals(((ClusterStatus)o).getHBaseVersion()) &&
198       this.liveServers.equals(((ClusterStatus)o).liveServers) &&
199       this.deadServers.containsAll(((ClusterStatus)o).deadServers) &&
200       Arrays.equals(this.masterCoprocessors,
201                     ((ClusterStatus)o).masterCoprocessors) &&
202       this.master.equals(((ClusterStatus)o).master) &&
203       this.backupMasters.containsAll(((ClusterStatus)o).backupMasters);
204   }
205
206   /**
207    * @see java.lang.Object#hashCode()
208    */
209   public int hashCode() {
210     return VERSION + hbaseVersion.hashCode() + this.liveServers.hashCode() +
211       this.deadServers.hashCode() + this.master.hashCode() +
212       this.backupMasters.hashCode();
213   }
214
215   /** @return the object version number */
216   public byte getVersion() {
217     return VERSION;
218   }
219
220   //
221   // Getters
222   //
223
224   public Collection<ServerName> getServers() {
225     if (liveServers == null) {
226       return Collections.<ServerName>emptyList();
227     }
228     return Collections.unmodifiableCollection(this.liveServers.keySet());
229   }
230
231   /**
232    * Returns detailed information about the current master {@link ServerName}.
233    * @return current master information if it exists
234    */
235   public ServerName getMaster() {
236     return this.master;
237   }
238
239   /**
240    * @return the number of backup masters in the cluster
241    */
242   public int getBackupMastersSize() {
243     return backupMasters != null ? backupMasters.size() : 0;
244   }
245
246   /**
247    * @return the names of backup masters
248    */
249   public Collection<ServerName> getBackupMasters() {
250     if (backupMasters == null) {
251       return Collections.<ServerName>emptyList();
252     }
253     return Collections.unmodifiableCollection(this.backupMasters);
254   }
255
256   /**
257    * @param sn
258    * @return Server's load or null if not found.
259    */
260   public ServerLoad getLoad(final ServerName sn) {
261     return liveServers != null ? liveServers.get(sn) : null;
262   }
263
264   @InterfaceAudience.Private
265   public Set<RegionState> getRegionsInTransition() {
266     return this.intransition;
267   }
268
269   public String getClusterId() {
270     return clusterId;
271   }
272
273   public String[] getMasterCoprocessors() {
274     return masterCoprocessors;
275   }
276
277   public long getLastMajorCompactionTsForTable(TableName table) {
278     long result = Long.MAX_VALUE;
279     for (ServerName server : getServers()) {
280       ServerLoad load = getLoad(server);
281       for (RegionLoad rl : load.getRegionsLoad().values()) {
282         if (table.equals(HRegionInfo.getTable(rl.getName()))) {
283           result = Math.min(result, rl.getLastMajorCompactionTs());
284         }
285       }
286     }
287     return result == Long.MAX_VALUE ? 0 : result;
288   }
289
290   public long getLastMajorCompactionTsForRegion(final byte[] region) {
291     for (ServerName server : getServers()) {
292       ServerLoad load = getLoad(server);
293       RegionLoad rl = load.getRegionsLoad().get(region);
294       if (rl != null) {
295         return rl.getLastMajorCompactionTs();
296       }
297     }
298     return 0;
299   }
300
301   public boolean isBalancerOn() {
302     return balancerOn != null && balancerOn;
303   }
304
305   public Boolean getBalancerOn() {
306     return balancerOn;
307   }
308
309   public String toString() {
310     StringBuilder sb = new StringBuilder(1024);
311     sb.append("Master: " + master);
312
313     int backupMastersSize = getBackupMastersSize();
314     sb.append("\nNumber of backup masters: " + backupMastersSize);
315     if (backupMastersSize > 0) {
316       for (ServerName serverName: backupMasters) {
317         sb.append("\n  " + serverName);
318       }
319     }
320
321     int serversSize = getServersSize();
322     sb.append("\nNumber of live region servers: " + serversSize);
323     if (serversSize > 0) {
324       for (ServerName serverName: liveServers.keySet()) {
325         sb.append("\n  " + serverName.getServerName());
326       }
327     }
328
329     int deadServerSize = getDeadServersSize();
330     sb.append("\nNumber of dead region servers: " + deadServerSize);
331     if (deadServerSize > 0) {
332       for (ServerName serverName: deadServers) {
333         sb.append("\n  " + serverName);
334       }
335     }
336
337     sb.append("\nAverage load: " + getAverageLoad());
338     sb.append("\nNumber of requests: " + getRequestsCount());
339     sb.append("\nNumber of regions: " + getRegionsCount());
340
341     int ritSize = (intransition != null) ? intransition.size() : 0;
342     sb.append("\nNumber of regions in transition: " + ritSize);
343     if (ritSize > 0) {
344       for (RegionState state: intransition) {
345         sb.append("\n  " + state.toDescriptiveString());
346       }
347     }
348     return sb.toString();
349   }
350 }