View Javadoc

1   /**
2    * Copyright 2010 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  package org.apache.hadoop.hbase;
21  
22  import java.io.DataInput;
23  import java.io.DataOutput;
24  import java.io.IOException;
25  import java.net.InetSocketAddress;
26  import java.util.Comparator;
27  import java.util.Set;
28  
29  import org.apache.hadoop.hbase.regionserver.HRegionServer;
30  import org.apache.hadoop.io.Writable;
31  import org.apache.hadoop.io.WritableComparable;
32  
33  
34  /**
35   * HServerInfo is meta info about an {@link HRegionServer}.  It is the token
36   * by which a master distingushes a particular regionserver from the rest.
37   * It holds hostname, ports, regionserver startcode, and load.  Each server has
38   * a <code>servername</code> where servername is made up of a concatenation of
39   * hostname, port, and regionserver startcode.  This servername is used in
40   * various places identifying this regionserver.  Its even used as part of
41   * a pathname in the filesystem.  As part of the initialization,
42   * master will pass the regionserver the address that it knows this regionserver
43   * by.  In subsequent communications, the regionserver will pass a HServerInfo
44   * with the master-supplied address.
45   */
46  public class HServerInfo implements WritableComparable<HServerInfo> {
47    /*
48     * This character is used as separator between server hostname and port and
49     * its startcode. Servername is formatted as
50     * <code>&lt;hostname> '{@ink #SERVERNAME_SEPARATOR"}' &lt;port> '{@ink #SERVERNAME_SEPARATOR"}' &lt;startcode></code>.
51     */
52    private static final String SERVERNAME_SEPARATOR = ",";
53  
54    private HServerAddress serverAddress;
55    private long startCode;
56    private HServerLoad load;
57    private int infoPort;
58    // Servername is made of hostname, port and startcode.
59    private String serverName = null;
60    // Hostname of the regionserver.
61    private String hostname;
62    private String cachedHostnamePort = null;
63  
64    public HServerInfo() {
65      this(new HServerAddress(), 0, HConstants.DEFAULT_REGIONSERVER_INFOPORT,
66        "default name");
67    }
68  
69    /**
70     * Constructor that creates a HServerInfo with a generated startcode and an
71     * empty load.
72     * @param serverAddress An {@link InetSocketAddress} encased in a {@link Writable}
73     * @param infoPort Port the webui runs on.
74     * @param hostname Server hostname.
75     */
76    public HServerInfo(HServerAddress serverAddress, final int infoPort,
77        final String hostname) {
78      this(serverAddress, System.currentTimeMillis(), infoPort, hostname);
79    }
80  
81    public HServerInfo(HServerAddress serverAddress, long startCode,
82        final int infoPort, String hostname) {
83      this.serverAddress = serverAddress;
84      this.startCode = startCode;
85      this.load = new HServerLoad();
86      this.infoPort = infoPort;
87      this.hostname = hostname;
88    }
89  
90    /**
91     * Copy-constructor
92     * @param other
93     */
94    public HServerInfo(HServerInfo other) {
95      this.serverAddress = new HServerAddress(other.getServerAddress());
96      this.startCode = other.getStartCode();
97      this.load = other.getLoad();
98      this.infoPort = other.getInfoPort();
99      this.hostname = other.hostname;
100   }
101 
102   public HServerLoad getLoad() {
103     return load;
104   }
105 
106   public void setLoad(HServerLoad load) {
107     this.load = load;
108   }
109 
110   public synchronized HServerAddress getServerAddress() {
111     return new HServerAddress(serverAddress);
112   }
113 
114   public synchronized void setServerAddress(HServerAddress serverAddress) {
115     this.serverAddress = serverAddress;
116     this.hostname = serverAddress.getHostname();
117     this.serverName = null;
118   }
119 
120   public synchronized long getStartCode() {
121     return startCode;
122   }
123 
124   public int getInfoPort() {
125     return this.infoPort;
126   }
127 
128   public String getHostname() {
129     return this.hostname;
130   }
131 
132   /**
133    * @return The hostname and port concatenated with a ':' as separator.
134    */
135   public synchronized String getHostnamePort() {
136     if (this.cachedHostnamePort == null) {
137       this.cachedHostnamePort = getHostnamePort(this.hostname, this.serverAddress.getPort());
138     }
139     return this.cachedHostnamePort;
140   }
141 
142   /**
143    * @param hostname
144    * @param port
145    * @return The hostname and port concatenated with a ':' as separator.
146    */
147   public static String getHostnamePort(final String hostname, final int port) {
148     return hostname + ":" + port;
149   }
150 
151   /**
152    * Gets the unique server instance name.  Includes the hostname, port, and
153    * start code.
154    * @return Server name made of the concatenation of hostname, port and
155    * startcode formatted as <code>&lt;hostname> ',' &lt;port> ',' &lt;startcode></code>
156    */
157   public synchronized String getServerName() {
158     if (this.serverName == null) {
159       this.serverName = getServerName(this.hostname,
160         this.serverAddress.getPort(), this.startCode);
161     }
162     return this.serverName;
163   }
164 
165   public static synchronized String getServerName(final String hostAndPort,
166       final long startcode) {
167     int index = hostAndPort.indexOf(":");
168     if (index <= 0) throw new IllegalArgumentException("Expected <hostname> ':' <port>");
169     return getServerName(hostAndPort.substring(0, index),
170       Integer.parseInt(hostAndPort.substring(index + 1)), startcode);
171   }
172 
173   /**
174    * @param address Server address
175    * @param startCode Server startcode
176    * @return Server name made of the concatenation of hostname, port and
177    * startcode formatted as <code>&lt;hostname> ',' &lt;port> ',' &lt;startcode></code>
178    */
179   public static String getServerName(HServerAddress address, long startCode) {
180     return getServerName(address.getHostname(), address.getPort(), startCode);
181   }
182 
183   /*
184    * @param hostName
185    * @param port
186    * @param startCode
187    * @return Server name made of the concatenation of hostname, port and
188    * startcode formatted as <code>&lt;hostname> ',' &lt;port> ',' &lt;startcode></code>
189    */
190   public static String getServerName(String hostName, int port, long startCode) {
191     StringBuilder name = new StringBuilder(hostName);
192     name.append(SERVERNAME_SEPARATOR);
193     name.append(port);
194     name.append(SERVERNAME_SEPARATOR);
195     name.append(startCode);
196     return name.toString();
197   }
198 
199   /**
200    * @return ServerName and load concatenated.
201    * @see #getServerName()
202    * @see #getLoad()
203    */
204   @Override
205   public String toString() {
206     return "serverName=" + getServerName() +
207       ", load=(" + this.load.toString() + ")";
208   }
209 
210   @Override
211   public boolean equals(Object obj) {
212     if (this == obj) {
213       return true;
214     }
215     if (obj == null) {
216       return false;
217     }
218     if (getClass() != obj.getClass()) {
219       return false;
220     }
221     return compareTo((HServerInfo)obj) == 0;
222   }
223 
224   @Override
225   public int hashCode() {
226     return this.getServerName().hashCode();
227   }
228 
229   public void readFields(DataInput in) throws IOException {
230     this.serverAddress.readFields(in);
231     this.startCode = in.readLong();
232     this.load.readFields(in);
233     this.infoPort = in.readInt();
234     this.hostname = in.readUTF();
235   }
236 
237   public void write(DataOutput out) throws IOException {
238     this.serverAddress.write(out);
239     out.writeLong(this.startCode);
240     this.load.write(out);
241     out.writeInt(this.infoPort);
242     out.writeUTF(hostname);
243   }
244 
245   public int compareTo(HServerInfo o) {
246     return this.getServerName().compareTo(o.getServerName());
247   }
248 
249   /**
250    * Orders HServerInfos by load then name.  Natural/ascending order.
251    */
252   public static class LoadComparator implements Comparator<HServerInfo> {
253     @Override
254     public int compare(HServerInfo left, HServerInfo right) {
255       int loadCompare = left.getLoad().compareTo(right.getLoad());
256       return loadCompare != 0 ? loadCompare : left.compareTo(right);
257     }
258   }
259 
260   /**
261    * Utility method that does a find of a servername or a hostandport combination
262    * in the passed Set.
263    * @param servers Set of server names
264    * @param serverName Name to look for
265    * @param hostAndPortOnly If <code>serverName</code> is a
266    * <code>hostname ':' port</code>
267    * or <code>hostname , port , startcode</code>.
268    * @return True if <code>serverName</code> found in <code>servers</code>
269    */
270   public static boolean isServer(final Set<String> servers,
271       final String serverName, final boolean hostAndPortOnly) {
272     if (!hostAndPortOnly) return servers.contains(serverName);
273     String serverNameColonReplaced =
274       serverName.replaceFirst(":", SERVERNAME_SEPARATOR);
275     for (String hostPortStartCode: servers) {
276       int index = hostPortStartCode.lastIndexOf(SERVERNAME_SEPARATOR);
277       String hostPortStrippedOfStartCode = hostPortStartCode.substring(0, index);
278       if (hostPortStrippedOfStartCode.equals(serverNameColonReplaced)) return true;
279     }
280     return false;
281   }
282 
283   /**
284    * Utility method to excise the start code from a server name
285    * @param inServerName full server name
286    * @return server name less its start code
287    */
288   public static String getServerNameLessStartCode(String inServerName) {
289     if (inServerName != null && inServerName.length() > 0) {
290       int index = inServerName.lastIndexOf(SERVERNAME_SEPARATOR);
291       if (index > 0) {
292         return inServerName.substring(0, index);
293       }
294     }
295     return inServerName;
296   }
297 
298 }