diff --git a/hbase-common/src/main/java/org/apache/hadoop/hbase/ServerName.java b/hbase-common/src/main/java/org/apache/hadoop/hbase/ServerName.java index 5223bac3e5b1..ee1735b578e6 100644 --- a/hbase-common/src/main/java/org/apache/hadoop/hbase/ServerName.java +++ b/hbase-common/src/main/java/org/apache/hadoop/hbase/ServerName.java @@ -18,6 +18,9 @@ package org.apache.hadoop.hbase; import java.io.Serializable; +import java.io.UnsupportedEncodingException; +import java.net.URLDecoder; +import java.net.URLEncoder; import java.util.ArrayList; import java.util.Iterator; import java.util.List; @@ -62,6 +65,12 @@ public class ServerName implements Comparable, Serializable { */ private static final short VERSION = 0; static final byte[] VERSION_BYTES = Bytes.toBytes(VERSION); + private static final String COLON_ENCODED_VALUE = "%3a"; + + public static final String COLON = ":"; + + // IPV6 address length separated by COLON(:), eg: "0:0:0:0:0:0:0:1".split(colon).length + private static final int IPV6_SPLIT_COLON_LENGTH = 8; /** * What to use if no startcode supplied. @@ -424,7 +433,49 @@ public static ServerName parseVersionedServerName(final byte[] versionedBytes) { * @return A ServerName instance. */ public static ServerName parseServerName(final String str) { - return SERVERNAME_PATTERN.matcher(str).matches() ? valueOf(str) : valueOf(str, NON_STARTCODE); + ServerName sn = + SERVERNAME_PATTERN.matcher(str).matches() ? valueOf(str) : valueOf(str, NON_STARTCODE); + String hostname = sn.getHostname(); + // if IPV6 address is in encoded format, need to check and validate its address length + // eg: if address is like "0%3a0%3a0%3a0%3a0%3a0%3a0%3a0%3a1,16020,1720673488765" decode to + // "0:0:0:0:0:0:0:1,16020,1720673488765" + if (isIpv6ServerName(hostname, COLON_ENCODED_VALUE)) { + try { + hostname = URLDecoder.decode(sn.getHostname(), "UTF8"); + return ServerName.valueOf(hostname, sn.getPort(), sn.getStartCode()); + } catch (UnsupportedEncodingException e) { + throw new IllegalArgumentException("Exception occurred while decoding server name", e); + } + } + return sn; + } + + /** + * Verify the ServerAddress is in IPV6 format or not + * @param serverAddress IP address + * @param addressSeparator IPV6 address separator + * @return true if server address is in IPV6 format + */ + public static boolean isIpv6ServerName(String serverAddress, String addressSeparator) { + return serverAddress.contains(addressSeparator) + && serverAddress.split(addressSeparator).length == IPV6_SPLIT_COLON_LENGTH; + } + + /** + * Encode the Server Address + * @param str Either an instance of {@link #toString()} or a "'<hostname>' ':' + * '<port>'". + * @return ServerName instance + */ + public static ServerName getEncodedServerName(final String str) { + ServerName sn = + SERVERNAME_PATTERN.matcher(str).matches() ? valueOf(str) : valueOf(str, NON_STARTCODE); + try { + return ServerName.valueOf(URLEncoder.encode(sn.getHostname(), "UTF8"), sn.getPort(), + sn.getStartCode()); + } catch (UnsupportedEncodingException e) { + throw new IllegalArgumentException("Exception occurred while encoding server name", e); + } } /** Returns true if the String follows the pattern of {@link #toString()}, false otherwise. */ diff --git a/hbase-server/src/main/java/org/apache/hadoop/hbase/wal/AbstractFSWALProvider.java b/hbase-server/src/main/java/org/apache/hadoop/hbase/wal/AbstractFSWALProvider.java index 44365ea9c1ff..69b5f9286c69 100644 --- a/hbase-server/src/main/java/org/apache/hadoop/hbase/wal/AbstractFSWALProvider.java +++ b/hbase-server/src/main/java/org/apache/hadoop/hbase/wal/AbstractFSWALProvider.java @@ -291,9 +291,13 @@ public static boolean validateWALFilename(String filename) { * @return the relative WAL directory name, e.g. .logs/1.example.org,60030,12345 if * serverName passed is 1.example.org,60030,12345 */ - public static String getWALDirectoryName(final String serverName) { + public static String getWALDirectoryName(String serverName) { + // If ServerName is IPV6 address, then need to encode server address + if (ServerName.isIpv6ServerName(serverName, ServerName.COLON)) { + serverName = ServerName.getEncodedServerName(serverName).getServerName(); + } StringBuilder dirName = new StringBuilder(HConstants.HREGION_LOGDIR_NAME); - dirName.append("/"); + dirName.append(Path.SEPARATOR); dirName.append(serverName); return dirName.toString(); } @@ -305,9 +309,13 @@ public static String getWALDirectoryName(final String serverName) { * @param serverName Server name formatted as described in {@link ServerName} * @return the relative WAL directory name */ - public static String getWALArchiveDirectoryName(Configuration conf, final String serverName) { + public static String getWALArchiveDirectoryName(Configuration conf, String serverName) { StringBuilder dirName = new StringBuilder(HConstants.HREGION_OLDLOGDIR_NAME); if (conf.getBoolean(SEPARATE_OLDLOGDIR, DEFAULT_SEPARATE_OLDLOGDIR)) { + // If ServerName is IPV6 address, then need to encode server address + if (ServerName.isIpv6ServerName(serverName, ServerName.COLON)) { + serverName = ServerName.getEncodedServerName(serverName).getServerName(); + } dirName.append(Path.SEPARATOR); dirName.append(serverName); }