View Javadoc

1   /**
2    * Copyright 2009 The Apache Software Foundation
3    *
4    * Licensed to the Apache Software Foundation (ASF) under one
5    * or more contributor license agreements.  See the NOTICE file
6    * distributed with this work for additional information
7    * regarding copyright ownership.  The ASF licenses this file
8    * to you under the Apache License, Version 2.0 (the
9    * "License"); you may not use this file except in compliance
10   * with the License.  You may obtain a copy of the License at
11   *
12   *     http://www.apache.org/licenses/LICENSE-2.0
13   *
14   * Unless required by applicable law or agreed to in writing, software
15   * distributed under the License is distributed on an "AS IS" BASIS,
16   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
17   * See the License for the specific language governing permissions and
18   * limitations under the License.
19   */
20  
21  package org.apache.hadoop.hbase;
22  
23  import java.io.DataInput;
24  import java.io.DataOutput;
25  import java.io.IOException;
26  import java.util.ArrayList;
27  import java.util.Arrays;
28  import java.util.Collection;
29  import java.util.Collections;
30  import java.util.HashMap;
31  import java.util.Map;
32  import java.util.TreeMap;
33  
34  import org.apache.hadoop.hbase.master.AssignmentManager.RegionState;
35  import org.apache.hadoop.hbase.util.Bytes;
36  import org.apache.hadoop.io.VersionMismatchException;
37  import org.apache.hadoop.io.VersionedWritable;
38  
39  /**
40   * Status information on the HBase cluster.
41   * <p>
42   * <tt>ClusterStatus</tt> provides clients with information such as:
43   * <ul>
44   * <li>The count and names of region servers in the cluster.</li>
45   * <li>The count and names of dead region servers in the cluster.</li>
46   * <li>The name of the active master for the cluster.</li>
47   * <li>The name(s) of the backup master(s) for the cluster, if they exist.</li>
48   * <li>The average cluster load.</li>
49   * <li>The number of regions deployed on the cluster.</li>
50   * <li>The number of requests since last report.</li>
51   * <li>Detailed region server loading and resource usage information,
52   *  per server and per region.</li>
53   * <li>Regions in transition at master</li>
54   * <li>The unique cluster ID</li>
55   * </ul>
56   */
57  public class ClusterStatus extends VersionedWritable {
58    /**
59     * Version for object serialization.  Incremented for changes in serialized
60     * representation.
61     * <dl>
62     *   <dt>0</dt> <dd>Initial version</dd>
63     *   <dt>1</dt> <dd>Added cluster ID</dd>
64     *   <dt>2</dt> <dd>Added Map of ServerName to ServerLoad</dd>
65     *   <dt>3</dt> <dd>Added master and backupMasters</dd>
66     * </dl>
67     */
68    private static final byte VERSION_MASTER_BACKUPMASTERS = 2;
69    private static final byte VERSION = 2;
70  
71    private String hbaseVersion;
72    private Map<ServerName, HServerLoad> liveServers;
73    private Collection<ServerName> deadServers;
74    private ServerName master;
75    private Collection<ServerName> backupMasters;
76    private Map<String, RegionState> intransition;
77    private String clusterId;
78    private String[] masterCoprocessors;
79  
80    /**
81     * Constructor, for Writable
82     */
83    public ClusterStatus() {
84      super();
85    }
86  
87    public ClusterStatus(final String hbaseVersion, final String clusterid,
88        final Map<ServerName, HServerLoad> servers,
89        final Collection<ServerName> deadServers,
90        final ServerName master,
91        final Collection<ServerName> backupMasters,
92        final Map<String, RegionState> rit,
93        final String[] masterCoprocessors) {
94      this.hbaseVersion = hbaseVersion;
95      this.liveServers = servers;
96      this.deadServers = deadServers;
97      this.master = master;
98      this.backupMasters = backupMasters;
99      this.intransition = rit;
100     this.clusterId = clusterid;
101     this.masterCoprocessors = masterCoprocessors;
102   }
103 
104   /**
105    * @return the names of region servers on the dead list
106    */
107   public Collection<ServerName> getDeadServerNames() {
108     return Collections.unmodifiableCollection(deadServers);
109   }
110 
111   /**
112    * @return the number of region servers in the cluster
113    */
114   public int getServersSize() {
115     return liveServers.size();
116   }
117 
118   /**
119    * @return the number of dead region servers in the cluster
120    */
121   public int getDeadServers() {
122     return deadServers.size();
123   }
124 
125   /**
126    * @return the average cluster load
127    */
128   public double getAverageLoad() {
129     int load = getRegionsCount();
130     return (double)load / (double)getServersSize();
131   }
132 
133   /**
134    * @return the number of regions deployed on the cluster
135    */
136   public int getRegionsCount() {
137     int count = 0;
138     for (Map.Entry<ServerName, HServerLoad> e: this.liveServers.entrySet()) {
139       count += e.getValue().getNumberOfRegions();
140     }
141     return count;
142   }
143 
144   /**
145    * @return the number of requests since last report
146    */
147   public int getRequestsCount() {
148     int count = 0;
149     for (Map.Entry<ServerName, HServerLoad> e: this.liveServers.entrySet()) {
150       count += e.getValue().getNumberOfRequests();
151     }
152     return count;
153   }
154 
155   /**
156    * @return the HBase version string as reported by the HMaster
157    */
158   public String getHBaseVersion() {
159     return hbaseVersion;
160   }
161 
162   /**
163    * @see java.lang.Object#equals(java.lang.Object)
164    */
165   public boolean equals(Object o) {
166     if (this == o) {
167       return true;
168     }
169     if (!(o instanceof ClusterStatus)) {
170       return false;
171     }
172     return (getVersion() == ((ClusterStatus)o).getVersion()) &&
173       getHBaseVersion().equals(((ClusterStatus)o).getHBaseVersion()) &&
174       this.liveServers.equals(((ClusterStatus)o).liveServers) &&
175       this.deadServers.containsAll(((ClusterStatus)o).deadServers) &&
176       Arrays.equals(this.masterCoprocessors,
177                     ((ClusterStatus)o).masterCoprocessors) &&
178       this.master.equals(((ClusterStatus)o).master) &&
179       this.backupMasters.containsAll(((ClusterStatus)o).backupMasters);
180   }
181 
182   /**
183    * @see java.lang.Object#hashCode()
184    */
185   public int hashCode() {
186     return VERSION + hbaseVersion.hashCode() + this.liveServers.hashCode() +
187       this.deadServers.hashCode() + this.master.hashCode() +
188       this.backupMasters.hashCode();
189   }
190 
191   /** @return the object version number */
192   public byte getVersion() {
193     return VERSION;
194   }
195 
196   //
197   // Getters
198   //
199 
200   /**
201    * Returns detailed region server information: A list of
202    * {@link ServerName}.
203    * @return region server information
204    * @deprecated Use {@link #getServers()}
205    */
206   public Collection<ServerName> getServerInfo() {
207     return getServers();
208   }
209 
210   public Collection<ServerName> getServers() {
211     return Collections.unmodifiableCollection(this.liveServers.keySet());
212   }
213 
214   /**
215    * Returns detailed information about the current master {@link ServerName}.
216    * @return current master information if it exists
217    */
218   public ServerName getMaster() {
219     return this.master;
220   }
221 
222   /**
223    * @return the number of backup masters in the cluster
224    */
225   public int getBackupMastersSize() {
226     return this.backupMasters.size();
227   }
228 
229   /**
230    * @return the names of backup masters
231    */
232   public Collection<ServerName> getBackupMasters() {
233     return Collections.unmodifiableCollection(this.backupMasters);
234   }
235 
236   /**
237    * @param sn
238    * @return Server's load or null if not found.
239    */
240   public HServerLoad getLoad(final ServerName sn) {
241     return this.liveServers.get(sn);
242   }
243 
244   public Map<String, RegionState> getRegionsInTransition() {
245     return this.intransition;
246   }
247 
248   public String getClusterId() {
249     return clusterId;
250   }
251 
252    public String[] getMasterCoprocessors() {
253      return masterCoprocessors;
254   }
255 
256   //
257   // Writable
258   //
259 
260   public void write(DataOutput out) throws IOException {
261     super.write(out);
262     out.writeUTF(hbaseVersion);
263     out.writeInt(getServersSize());
264     for (Map.Entry<ServerName, HServerLoad> e: this.liveServers.entrySet()) {
265       Bytes.writeByteArray(out, e.getKey().getVersionedBytes());
266       e.getValue().write(out);
267     }
268     out.writeInt(deadServers.size());
269     for (ServerName server: deadServers) {
270       Bytes.writeByteArray(out, server.getVersionedBytes());
271     }
272     out.writeInt(this.intransition.size());
273     for (Map.Entry<String, RegionState> e: this.intransition.entrySet()) {
274       out.writeUTF(e.getKey());
275       e.getValue().write(out);
276     }
277     out.writeUTF(clusterId);
278     out.writeInt(masterCoprocessors.length);
279     for(String masterCoprocessor: masterCoprocessors) {
280       out.writeUTF(masterCoprocessor);
281     }
282     Bytes.writeByteArray(out, this.master.getVersionedBytes());
283     out.writeInt(this.backupMasters.size());
284     for (ServerName backupMaster: this.backupMasters) {
285       Bytes.writeByteArray(out, backupMaster.getVersionedBytes());
286     }
287   }
288 
289   public void readFields(DataInput in) throws IOException {
290     int version = getVersion();
291     try {
292       super.readFields(in);
293     } catch (VersionMismatchException e) {
294       /*
295        * No API in VersionMismatchException to get the expected and found
296        * versions.  We use the only tool available to us: toString(), whose
297        * output has a dependency on hadoop-common.  Boo.
298        */
299       int startIndex = e.toString().lastIndexOf('v') + 1;
300       version = Integer.parseInt(e.toString().substring(startIndex));
301     }
302     hbaseVersion = in.readUTF();
303     int count = in.readInt();
304     this.liveServers = new HashMap<ServerName, HServerLoad>(count);
305     for (int i = 0; i < count; i++) {
306       byte [] versionedBytes = Bytes.readByteArray(in);
307       HServerLoad hsl = new HServerLoad();
308       hsl.readFields(in);
309       this.liveServers.put(ServerName.parseVersionedServerName(versionedBytes), hsl);
310     }
311     count = in.readInt();
312     deadServers = new ArrayList<ServerName>(count);
313     for (int i = 0; i < count; i++) {
314       deadServers.add(ServerName.parseVersionedServerName(Bytes.readByteArray(in)));
315     }
316     count = in.readInt();
317     this.intransition = new TreeMap<String, RegionState>();
318     for (int i = 0; i < count; i++) {
319       String key = in.readUTF();
320       RegionState regionState = new RegionState();
321       regionState.readFields(in);
322       this.intransition.put(key, regionState);
323     }
324     this.clusterId = in.readUTF();
325     int masterCoprocessorsLength = in.readInt();
326     masterCoprocessors = new String[masterCoprocessorsLength];
327     for(int i = 0; i < masterCoprocessorsLength; i++) {
328       masterCoprocessors[i] = in.readUTF();
329     }
330     // Only read extra fields for master and backup masters if
331     // version indicates that we should do so, else use defaults
332     if (version >= VERSION_MASTER_BACKUPMASTERS) {
333       this.master = ServerName.parseVersionedServerName(
334                       Bytes.readByteArray(in));
335       count = in.readInt();
336       this.backupMasters = new ArrayList<ServerName>(count);
337       for (int i = 0; i < count; i++) {
338         this.backupMasters.add(ServerName.parseVersionedServerName(
339                                  Bytes.readByteArray(in)));
340       }
341     } else {
342       this.master = new ServerName(ServerName.UNKNOWN_SERVERNAME, -1,
343                                    ServerName.NON_STARTCODE);
344       this.backupMasters = new ArrayList<ServerName>(0);
345     }
346   }
347 }