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