001/* 002 * Licensed to the Apache Software Foundation (ASF) under one 003 * or more contributor license agreements. See the NOTICE file 004 * distributed with this work for additional information 005 * regarding copyright ownership. The ASF licenses this file 006 * to you under the Apache License, Version 2.0 (the 007 * "License"); you may not use this file except in compliance 008 * with the License. You may obtain a copy of the License at 009 * 010 * http://www.apache.org/licenses/LICENSE-2.0 011 * 012 * Unless required by applicable law or agreed to in writing, software 013 * distributed under the License is distributed on an "AS IS" BASIS, 014 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 015 * See the License for the specific language governing permissions and 016 * limitations under the License. 017 */ 018package org.apache.hadoop.hbase; 019 020import java.io.Serializable; 021import java.util.ArrayList; 022import java.util.List; 023import java.util.Locale; 024import java.util.regex.Pattern; 025import org.apache.hadoop.hbase.net.Address; 026import org.apache.hadoop.hbase.util.Addressing; 027import org.apache.hadoop.hbase.util.Bytes; 028import org.apache.yetus.audience.InterfaceAudience; 029 030import org.apache.hbase.thirdparty.com.google.common.collect.Interner; 031import org.apache.hbase.thirdparty.com.google.common.collect.Interners; 032import org.apache.hbase.thirdparty.com.google.common.net.InetAddresses; 033 034/** 035 * Name of a particular incarnation of an HBase Server. A {@link ServerName} is used uniquely 036 * identifying a server instance in a cluster and is made of the combination of hostname, port, and 037 * startcode. The startcode distinguishes restarted servers on same hostname and port (startcode is 038 * usually timestamp of server startup). The {@link #toString()} format of ServerName is safe to use 039 * in the filesystem and as znode name up in ZooKeeper. Its format is: 040 * <code><hostname> '{@link #SERVERNAME_SEPARATOR}' <port> 041 * '{@link #SERVERNAME_SEPARATOR}' <startcode></code>. For example, if hostname is 042 * <code>www.example.org</code>, port is <code>1234</code>, and the startcode for the regionserver 043 * is <code>1212121212</code>, then the {@link #toString()} would be 044 * <code>www.example.org,1234,1212121212</code>. 045 * <p> 046 * You can obtain a versioned serialized form of this class by calling {@link #getVersionedBytes()}. 047 * To deserialize, call {@link #parseVersionedServerName(byte[])}. 048 * <p> 049 * Use {@link #getAddress()} to obtain the Server hostname + port (Endpoint/Socket Address). 050 * <p> 051 * Immutable. 052 */ 053@InterfaceAudience.Public 054public class ServerName implements Comparable<ServerName>, Serializable { 055 private static final long serialVersionUID = 1367463982557264981L; 056 057 /** 058 * Version for this class. Its a short rather than a byte so I can for sure distinguish between 059 * this version of this class and the version previous to this which did not have a version. 060 */ 061 private static final short VERSION = 0; 062 static final byte[] VERSION_BYTES = Bytes.toBytes(VERSION); 063 064 /** 065 * What to use if no startcode supplied. 066 */ 067 public static final int NON_STARTCODE = -1; 068 069 /** 070 * This character is used as separator between server hostname, port and startcode. 071 */ 072 public static final String SERVERNAME_SEPARATOR = ","; 073 074 public static final Pattern SERVERNAME_PATTERN = 075 Pattern.compile("[^" + SERVERNAME_SEPARATOR + "]+" + SERVERNAME_SEPARATOR 076 + Addressing.VALID_PORT_REGEX + SERVERNAME_SEPARATOR + Addressing.VALID_PORT_REGEX + "$"); 077 078 /** 079 * What to use if server name is unknown. 080 */ 081 public static final String UNKNOWN_SERVERNAME = "#unknown#"; 082 083 private final String servername; 084 private final long startcode; 085 private transient Address address; 086 087 /** 088 * Cached versioned bytes of this ServerName instance. 089 * @see #getVersionedBytes() 090 */ 091 private byte[] bytes; 092 public static final List<ServerName> EMPTY_SERVER_LIST = new ArrayList<>(0); 093 094 /** 095 * Intern ServerNames. The Set of ServerNames is mostly-fixed changing slowly as Servers restart. 096 * Rather than create a new instance everytime, try and return existing instance if there is one. 097 */ 098 private static final Interner<ServerName> INTERN_POOL = Interners.newWeakInterner(); 099 100 protected ServerName(final String hostname, final int port, final long startcode) { 101 this(Address.fromParts(hostname, port), startcode); 102 } 103 104 private ServerName(final Address address, final long startcode) { 105 // Use HostAndPort to host port and hostname. Does validation and can do ipv6 106 this.address = address; 107 this.startcode = startcode; 108 this.servername = getServerName(this.address.getHostname(), this.address.getPort(), startcode); 109 } 110 111 private ServerName(final String hostAndPort, final long startCode) { 112 this(Address.fromString(hostAndPort), startCode); 113 } 114 115 /** 116 * @param hostname the hostname string to get the actual hostname from 117 * @return hostname minus the domain, if there is one (will do pass-through on ip addresses) 118 * @deprecated Since 2.0. This is for internal use only. 119 */ 120 @Deprecated 121 // Make this private in hbase-3.0. 122 static String getHostNameMinusDomain(final String hostname) { 123 if (InetAddresses.isInetAddress(hostname)) { 124 return hostname; 125 } 126 String[] parts = hostname.split("\\."); 127 if (parts.length == 0) { 128 return hostname; 129 } 130 return parts[0]; 131 } 132 133 /** 134 * @deprecated Since 2.0. Use {@link #valueOf(String)} 135 */ 136 @Deprecated 137 // This is unused. Get rid of it. 138 public static String parseHostname(final String serverName) { 139 if (serverName == null || serverName.length() <= 0) { 140 throw new IllegalArgumentException("Passed hostname is null or empty"); 141 } 142 if (!Character.isLetterOrDigit(serverName.charAt(0))) { 143 throw new IllegalArgumentException("Bad passed hostname, serverName=" + serverName); 144 } 145 int index = serverName.indexOf(SERVERNAME_SEPARATOR); 146 return serverName.substring(0, index); 147 } 148 149 /** 150 * @deprecated Since 2.0. Use {@link #valueOf(String)} 151 */ 152 @Deprecated 153 // This is unused. Get rid of it. 154 public static int parsePort(final String serverName) { 155 String[] split = serverName.split(SERVERNAME_SEPARATOR); 156 return Integer.parseInt(split[1]); 157 } 158 159 /** 160 * @deprecated Since 2.0. Use {@link #valueOf(String)} 161 */ 162 @Deprecated 163 // This is unused. Get rid of it. 164 public static long parseStartcode(final String serverName) { 165 int index = serverName.lastIndexOf(SERVERNAME_SEPARATOR); 166 return Long.parseLong(serverName.substring(index + 1)); 167 } 168 169 /** 170 * Retrieve an instance of ServerName. Callers should use the equals method to compare returned 171 * instances, though we may return a shared immutable object as an internal optimization. 172 */ 173 public static ServerName valueOf(final String hostname, final int port, final long startcode) { 174 return INTERN_POOL.intern(new ServerName(hostname, port, startcode)); 175 } 176 177 /** 178 * Retrieve an instance of ServerName. Callers should use the equals method to compare returned 179 * instances, though we may return a shared immutable object as an internal optimization. 180 */ 181 public static ServerName valueOf(final String serverName) { 182 final String hostname = serverName.substring(0, serverName.indexOf(SERVERNAME_SEPARATOR)); 183 final int port = Integer.parseInt(serverName.split(SERVERNAME_SEPARATOR)[1]); 184 final long statuscode = 185 Long.parseLong(serverName.substring(serverName.lastIndexOf(SERVERNAME_SEPARATOR) + 1)); 186 return INTERN_POOL.intern(new ServerName(hostname, port, statuscode)); 187 } 188 189 /** 190 * Retrieve an instance of ServerName. Callers should use the equals method to compare returned 191 * instances, though we may return a shared immutable object as an internal optimization. 192 */ 193 public static ServerName valueOf(final String hostAndPort, final long startCode) { 194 return INTERN_POOL.intern(new ServerName(hostAndPort, startCode)); 195 } 196 197 /** 198 * Retrieve an instance of {@link ServerName}. Callers should use the {@link #equals(Object)} 199 * method to compare returned instances, though we may return a shared immutable object as an 200 * internal optimization. 201 * @param address the {@link Address} to use for getting the {@link ServerName} 202 * @param startcode the startcode to use for getting the {@link ServerName} 203 * @return the constructed {@link ServerName} 204 * @see #valueOf(String, int, long) 205 */ 206 public static ServerName valueOf(final Address address, final long startcode) { 207 return valueOf(address.getHostname(), address.getPort(), startcode); 208 } 209 210 @Override 211 public String toString() { 212 return getServerName(); 213 } 214 215 /** 216 * @return Return a SHORT version of {@link #toString()}, one that has the host only, minus the 217 * domain, and the port only -- no start code; the String is for us internally mostly 218 * tying threads to their server. Not for external use. It is lossy and will not work in 219 * in compares, etc. 220 */ 221 public String toShortString() { 222 return Addressing.createHostAndPortStr(getHostNameMinusDomain(this.address.getHostname()), 223 this.address.getPort()); 224 } 225 226 /** 227 * @return {@link #getServerName()} as bytes with a short-sized prefix with the {@link #VERSION} 228 * of this class. 229 */ 230 public synchronized byte[] getVersionedBytes() { 231 if (this.bytes == null) { 232 this.bytes = Bytes.add(VERSION_BYTES, Bytes.toBytes(getServerName())); 233 } 234 return this.bytes; 235 } 236 237 public String getServerName() { 238 return servername; 239 } 240 241 public String getHostname() { 242 return this.address.getHostname(); 243 } 244 245 public String getHostnameLowerCase() { 246 return this.address.getHostname().toLowerCase(Locale.ROOT); 247 } 248 249 public int getPort() { 250 return this.address.getPort(); 251 } 252 253 public long getStartcode() { 254 return startcode; 255 } 256 257 /** 258 * For internal use only. 259 * @param hostName the name of the host to use 260 * @param port the port on the host to use 261 * @param startcode the startcode to use for formatting 262 * @return Server name made of the concatenation of hostname, port and startcode formatted as 263 * <code><hostname> ',' <port> ',' <startcode></code> 264 * @deprecated Since 2.0. Use {@link ServerName#valueOf(String, int, long)} instead. 265 */ 266 @Deprecated 267 // TODO: Make this private in hbase-3.0. 268 static String getServerName(String hostName, int port, long startcode) { 269 return hostName.toLowerCase(Locale.ROOT) + SERVERNAME_SEPARATOR + port + SERVERNAME_SEPARATOR 270 + startcode; 271 } 272 273 /** 274 * @param hostAndPort String in form of <hostname> ':' <port> 275 * @param startcode the startcode to use 276 * @return Server name made of the concatenation of hostname, port and startcode formatted as 277 * <code><hostname> ',' <port> ',' <startcode></code> 278 * @deprecated Since 2.0. Use {@link ServerName#valueOf(String, long)} instead. 279 */ 280 @Deprecated 281 public static String getServerName(final String hostAndPort, final long startcode) { 282 int index = hostAndPort.indexOf(':'); 283 if (index <= 0) { 284 throw new IllegalArgumentException("Expected <hostname> ':' <port>"); 285 } 286 return getServerName(hostAndPort.substring(0, index), 287 Integer.parseInt(hostAndPort.substring(index + 1)), startcode); 288 } 289 290 /** 291 * @return Hostname and port formatted as described at 292 * {@link Addressing#createHostAndPortStr(String, int)} 293 * @deprecated Since 2.0. Use {@link #getAddress()} instead. 294 */ 295 @Deprecated 296 public String getHostAndPort() { 297 return this.address.toString(); 298 } 299 300 public Address getAddress() { 301 return this.address; 302 } 303 304 /** 305 * @param serverName ServerName in form specified by {@link #getServerName()} 306 * @return The server start code parsed from <code>servername</code> 307 * @deprecated Since 2.0. Use instance of ServerName to pull out start code. 308 */ 309 @Deprecated 310 public static long getServerStartcodeFromServerName(final String serverName) { 311 int index = serverName.lastIndexOf(SERVERNAME_SEPARATOR); 312 return Long.parseLong(serverName.substring(index + 1)); 313 } 314 315 /** 316 * Utility method to excise the start code from a server name 317 * @param inServerName full server name 318 * @return server name less its start code 319 * @deprecated Since 2.0. Use {@link #getAddress()} 320 */ 321 @Deprecated 322 public static String getServerNameLessStartCode(String inServerName) { 323 if (inServerName != null && inServerName.length() > 0) { 324 int index = inServerName.lastIndexOf(SERVERNAME_SEPARATOR); 325 if (index > 0) { 326 return inServerName.substring(0, index); 327 } 328 } 329 return inServerName; 330 } 331 332 @Override 333 public int compareTo(ServerName other) { 334 int compare; 335 if (other == null) { 336 return -1; 337 } 338 if (this.getHostname() == null) { 339 if (other.getHostname() != null) { 340 return 1; 341 } 342 } else { 343 if (other.getHostname() == null) { 344 return -1; 345 } 346 compare = this.getHostname().compareToIgnoreCase(other.getHostname()); 347 if (compare != 0) { 348 return compare; 349 } 350 } 351 compare = this.getPort() - other.getPort(); 352 if (compare != 0) { 353 return compare; 354 } 355 return Long.compare(this.getStartcode(), other.getStartcode()); 356 } 357 358 @Override 359 public int hashCode() { 360 return getServerName().hashCode(); 361 } 362 363 @Override 364 public boolean equals(Object o) { 365 if (this == o) { 366 return true; 367 } 368 if (o == null) { 369 return false; 370 } 371 if (!(o instanceof ServerName)) { 372 return false; 373 } 374 return this.compareTo((ServerName) o) == 0; 375 } 376 377 /** 378 * @param left the first server address to compare 379 * @param right the second server address to compare 380 * @return {@code true} if {@code left} and {@code right} have the same hostname and port. 381 */ 382 public static boolean isSameAddress(final ServerName left, final ServerName right) { 383 return left.getAddress().equals(right.getAddress()); 384 } 385 386 /** 387 * Use this method instantiating a {@link ServerName} from bytes gotten from a call to 388 * {@link #getVersionedBytes()}. Will take care of the case where bytes were written by an earlier 389 * version of hbase. 390 * @param versionedBytes Pass bytes gotten from a call to {@link #getVersionedBytes()} 391 * @return A ServerName instance. 392 * @see #getVersionedBytes() 393 */ 394 public static ServerName parseVersionedServerName(final byte[] versionedBytes) { 395 // Version is a short. 396 short version = Bytes.toShort(versionedBytes); 397 if (version == VERSION) { 398 int length = versionedBytes.length - Bytes.SIZEOF_SHORT; 399 return valueOf(Bytes.toString(versionedBytes, Bytes.SIZEOF_SHORT, length)); 400 } 401 // Presume the bytes were written with an old version of hbase and that the 402 // bytes are actually a String of the form "'<hostname>' ':' '<port>'". 403 return valueOf(Bytes.toString(versionedBytes), NON_STARTCODE); 404 } 405 406 /** 407 * @param str Either an instance of {@link #toString()} or a "'<hostname>' ':' 408 * '<port>'". 409 * @return A ServerName instance. 410 */ 411 public static ServerName parseServerName(final String str) { 412 return SERVERNAME_PATTERN.matcher(str).matches() ? valueOf(str) : valueOf(str, NON_STARTCODE); 413 } 414 415 /** Returns true if the String follows the pattern of {@link #toString()}, false otherwise. */ 416 public static boolean isFullServerName(final String str) { 417 if (str == null || str.isEmpty()) { 418 return false; 419 } 420 return SERVERNAME_PATTERN.matcher(str).matches(); 421 } 422}