Reduce the time taken by NetUtil and DefaultChannelId class initialization
Motivation: As reported in #2331, some query operations in NetworkInterface takes much longer time than we expected. For example, specifying -Djava.net.preferIPv4Stack=true option in Window increases the execution time by more than 4 times. Some Windows systems have more than 20 network interfaces, and this problem gets bigger as the number of unused (virtual) NICs increases. Modification: Use NetworkInterface.getInetAddresses() wherever possible. Before iterating over all NICs reported by NetworkInterface, filter the NICs without proper InetAddresses. This reduces the number of candidates quite a lot. NetUtil does not query hardware address of NIC in the first place but uses InetAddress.isLoopbackAddress(). Do not call unnecessary query operations on NetworkInterface. Just get hardware address and compare. Result: Significantly reduced class initialization time, which should fix #2331.
This commit is contained in:
parent
241d24cbfa
commit
3621a0169c
@ -28,6 +28,7 @@ import java.net.NetworkInterface;
|
|||||||
import java.net.SocketException;
|
import java.net.SocketException;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Enumeration;
|
import java.util.Enumeration;
|
||||||
|
import java.util.List;
|
||||||
import java.util.StringTokenizer;
|
import java.util.StringTokenizer;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -56,7 +57,7 @@ public final class NetUtil {
|
|||||||
public static final InetAddress LOCALHOST;
|
public static final InetAddress LOCALHOST;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The loopback {@link NetworkInterface} on the current machine
|
* The loopback {@link NetworkInterface} of the current machine
|
||||||
*/
|
*/
|
||||||
public static final NetworkInterface LOOPBACK_IF;
|
public static final NetworkInterface LOOPBACK_IF;
|
||||||
|
|
||||||
@ -72,48 +73,13 @@ public final class NetUtil {
|
|||||||
private static final InternalLogger logger = InternalLoggerFactory.getInstance(NetUtil.class);
|
private static final InternalLogger logger = InternalLoggerFactory.getInstance(NetUtil.class);
|
||||||
|
|
||||||
static {
|
static {
|
||||||
// Find the first loopback interface available.
|
byte[] LOCALHOST4_BYTES = {127, 0, 0, 1};
|
||||||
NetworkInterface loopbackIface = null;
|
byte[] LOCALHOST6_BYTES = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1};
|
||||||
try {
|
|
||||||
for (Enumeration<NetworkInterface> ifaces = NetworkInterface.getNetworkInterfaces();
|
|
||||||
ifaces.hasMoreElements();) {
|
|
||||||
|
|
||||||
NetworkInterface iface = ifaces.nextElement();
|
|
||||||
if (iface.isLoopback()) {
|
|
||||||
// Found
|
|
||||||
loopbackIface = iface;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (loopbackIface == null) {
|
|
||||||
logger.warn("Failed to find the loopback interface");
|
|
||||||
}
|
|
||||||
} catch (SocketException e) {
|
|
||||||
logger.warn("Failed to find the loopback interface", e);
|
|
||||||
}
|
|
||||||
|
|
||||||
LOOPBACK_IF = loopbackIface;
|
|
||||||
|
|
||||||
// Find the localhost address
|
|
||||||
InetAddress localhost = null;
|
|
||||||
if (LOOPBACK_IF != null) {
|
|
||||||
logger.debug("Loopback interface: {}", LOOPBACK_IF.getDisplayName());
|
|
||||||
for (Enumeration<InetAddress> addrs = LOOPBACK_IF.getInetAddresses();
|
|
||||||
addrs.hasMoreElements();) {
|
|
||||||
InetAddress a = addrs.nextElement();
|
|
||||||
if (localhost == null) {
|
|
||||||
logger.debug("Loopback address: {} (primary)", a);
|
|
||||||
localhost = a;
|
|
||||||
} else {
|
|
||||||
logger.debug("Loopback address: {}", a);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Create IPv4 loopback address.
|
// Create IPv4 loopback address.
|
||||||
Inet4Address localhost4 = null;
|
Inet4Address localhost4 = null;
|
||||||
try {
|
try {
|
||||||
localhost4 = (Inet4Address) InetAddress.getByAddress(new byte[]{127, 0, 0, 1});
|
localhost4 = (Inet4Address) InetAddress.getByAddress(LOCALHOST4_BYTES);
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
// We should not get here as long as the length of the address is correct.
|
// We should not get here as long as the length of the address is correct.
|
||||||
PlatformDependent.throwException(e);
|
PlatformDependent.throwException(e);
|
||||||
@ -123,33 +89,96 @@ public final class NetUtil {
|
|||||||
// Create IPv6 loopback address.
|
// Create IPv6 loopback address.
|
||||||
Inet6Address localhost6 = null;
|
Inet6Address localhost6 = null;
|
||||||
try {
|
try {
|
||||||
localhost6 = (Inet6Address) InetAddress.getByAddress(
|
localhost6 = (Inet6Address) InetAddress.getByAddress(LOCALHOST6_BYTES);
|
||||||
new byte[]{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1});
|
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
// We should not get here as long as the length of the address is correct.
|
// We should not get here as long as the length of the address is correct.
|
||||||
PlatformDependent.throwException(e);
|
PlatformDependent.throwException(e);
|
||||||
}
|
}
|
||||||
LOCALHOST6 = localhost6;
|
LOCALHOST6 = localhost6;
|
||||||
|
|
||||||
// Try to determine the default loopback address if we couldn't yet.
|
// Retrieve the list of available network interfaces.
|
||||||
if (localhost == null) {
|
List<NetworkInterface> ifaces = new ArrayList<NetworkInterface>();
|
||||||
|
try {
|
||||||
|
for (Enumeration<NetworkInterface> i = NetworkInterface.getNetworkInterfaces(); i.hasMoreElements();) {
|
||||||
|
NetworkInterface iface = i.nextElement();
|
||||||
|
// Use the interface with proper INET addresses only.
|
||||||
|
if (iface.getInetAddresses().hasMoreElements()) {
|
||||||
|
ifaces.add(iface);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} catch (SocketException e) {
|
||||||
|
logger.warn("Failed to retrieve the list of available network interfaces", e);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Find the first loopback interface available from its INET address (127.0.0.1 or ::1)
|
||||||
|
// Note that we do not use NetworkInterface.isLoopback() in the first place because it takes long time
|
||||||
|
// on a certain environment. (e.g. Windows with -Djava.net.preferIPv4Stack=true)
|
||||||
|
NetworkInterface loopbackIface = null;
|
||||||
|
InetAddress loopbackAddr = null;
|
||||||
|
loop: for (NetworkInterface iface: ifaces) {
|
||||||
|
for (Enumeration<InetAddress> i = iface.getInetAddresses(); i.hasMoreElements();) {
|
||||||
|
InetAddress addr = i.nextElement();
|
||||||
|
if (addr.isLoopbackAddress()) {
|
||||||
|
// Found
|
||||||
|
loopbackIface = iface;
|
||||||
|
loopbackAddr = addr;
|
||||||
|
break loop;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// If failed to find the loopback interface from its INET address, fall back to isLoopback().
|
||||||
|
if (loopbackIface == null) {
|
||||||
|
try {
|
||||||
|
for (NetworkInterface iface: ifaces) {
|
||||||
|
if (iface.isLoopback()) {
|
||||||
|
Enumeration<InetAddress> i = iface.getInetAddresses();
|
||||||
|
if (i.hasMoreElements()) {
|
||||||
|
// Found the one with INET address.
|
||||||
|
loopbackIface = iface;
|
||||||
|
loopbackAddr = i.nextElement();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (loopbackIface == null) {
|
||||||
|
logger.warn("Failed to find the loopback interface");
|
||||||
|
}
|
||||||
|
} catch (SocketException e) {
|
||||||
|
logger.warn("Failed to find the loopback interface", e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (loopbackIface != null) {
|
||||||
|
// Found the loopback interface with an INET address.
|
||||||
|
logger.debug(
|
||||||
|
"Loopback interface: {} ({}, {})",
|
||||||
|
loopbackIface.getName(), loopbackIface.getDisplayName(), loopbackAddr.getHostAddress());
|
||||||
|
} else {
|
||||||
|
// Could not find the loopback interface, but we can't leave LOCALHOST as null.
|
||||||
|
// Use LOCALHOST6 or LOCALHOST4, preferably the IPv6 one.
|
||||||
|
if (loopbackAddr == null) {
|
||||||
try {
|
try {
|
||||||
if (NetworkInterface.getByInetAddress(LOCALHOST6) != null) {
|
if (NetworkInterface.getByInetAddress(LOCALHOST6) != null) {
|
||||||
logger.debug("Using hard-coded IPv6 localhost address: {}", localhost6);
|
logger.debug("Using hard-coded IPv6 localhost address: {}", localhost6);
|
||||||
localhost = localhost6;
|
loopbackAddr = localhost6;
|
||||||
}
|
}
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
// Ignore
|
// Ignore
|
||||||
} finally {
|
} finally {
|
||||||
if (localhost == null) {
|
if (loopbackAddr == null) {
|
||||||
logger.debug("Using hard-coded IPv4 localhost address: {}", localhost4);
|
logger.debug("Using hard-coded IPv4 localhost address: {}", localhost4);
|
||||||
localhost = localhost4;
|
loopbackAddr = localhost4;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
LOCALHOST = localhost;
|
LOOPBACK_IF = loopbackIface;
|
||||||
|
LOCALHOST = loopbackAddr;
|
||||||
|
|
||||||
|
// Determine the default somaxconn (server socket backlog) value of the platform.
|
||||||
int somaxconn = 3072;
|
int somaxconn = 3072;
|
||||||
BufferedReader in = null;
|
BufferedReader in = null;
|
||||||
try {
|
try {
|
||||||
@ -446,7 +475,9 @@ public final class NetUtil {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
try {
|
try {
|
||||||
Integer.parseInt(ipAddress.substring(i + 1));
|
if (Integer.parseInt(ipAddress.substring(i + 1)) < 0) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
} catch (NumberFormatException e) {
|
} catch (NumberFormatException e) {
|
||||||
// right now we just support an integer after the % so if
|
// right now we just support an integer after the % so if
|
||||||
// this is not
|
// this is not
|
||||||
@ -506,10 +537,7 @@ public final class NetUtil {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (Integer.parseInt(word) > 255) {
|
return Integer.parseInt(word) <= 255;
|
||||||
return false;
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static boolean isValidHexChar(char c) {
|
static boolean isValidHexChar(char c) {
|
||||||
@ -560,10 +588,8 @@ public final class NetUtil {
|
|||||||
if (word.length() == 0 || Integer.parseInt(word.toString()) > 255) {
|
if (word.length() == 0 || Integer.parseInt(word.toString()) > 255) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
if (periods != 3) {
|
|
||||||
return false;
|
return periods == 3;
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -23,10 +23,13 @@ import io.netty.util.internal.logging.InternalLogger;
|
|||||||
import io.netty.util.internal.logging.InternalLoggerFactory;
|
import io.netty.util.internal.logging.InternalLoggerFactory;
|
||||||
|
|
||||||
import java.lang.reflect.Method;
|
import java.lang.reflect.Method;
|
||||||
|
import java.net.InetAddress;
|
||||||
import java.net.NetworkInterface;
|
import java.net.NetworkInterface;
|
||||||
import java.net.SocketException;
|
import java.net.SocketException;
|
||||||
|
import java.util.ArrayList;
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
import java.util.Enumeration;
|
import java.util.Enumeration;
|
||||||
|
import java.util.List;
|
||||||
import java.util.concurrent.atomic.AtomicInteger;
|
import java.util.concurrent.atomic.AtomicInteger;
|
||||||
import java.util.regex.Pattern;
|
import java.util.regex.Pattern;
|
||||||
|
|
||||||
@ -123,22 +126,23 @@ final class DefaultChannelId implements ChannelId {
|
|||||||
final byte[] NOT_FOUND = { -1 };
|
final byte[] NOT_FOUND = { -1 };
|
||||||
byte[] bestMacAddr = NOT_FOUND;
|
byte[] bestMacAddr = NOT_FOUND;
|
||||||
|
|
||||||
Enumeration<NetworkInterface> ifaces = null;
|
// Retrieve the list of available network interfaces.
|
||||||
|
List<NetworkInterface> ifaces = new ArrayList<NetworkInterface>();
|
||||||
try {
|
try {
|
||||||
ifaces = NetworkInterface.getNetworkInterfaces();
|
for (Enumeration<NetworkInterface> i = NetworkInterface.getNetworkInterfaces(); i.hasMoreElements();) {
|
||||||
|
NetworkInterface iface = i.nextElement();
|
||||||
|
// Use the interface with proper INET addresses only.
|
||||||
|
Enumeration<InetAddress> addrs = iface.getInetAddresses();
|
||||||
|
if (addrs.hasMoreElements() && !addrs.nextElement().isLoopbackAddress()) {
|
||||||
|
ifaces.add(iface);
|
||||||
|
}
|
||||||
|
}
|
||||||
} catch (SocketException e) {
|
} catch (SocketException e) {
|
||||||
logger.warn("Failed to find the loopback interface", e);
|
logger.warn("Failed to retrieve the list of available network interfaces", e);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (ifaces != null) {
|
for (NetworkInterface iface: ifaces) {
|
||||||
while (ifaces.hasMoreElements()) {
|
if (iface.isVirtual()) {
|
||||||
NetworkInterface iface = ifaces.nextElement();
|
|
||||||
try {
|
|
||||||
if (iface.isLoopback() || iface.isPointToPoint() || iface.isVirtual()) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
} catch (SocketException e) {
|
|
||||||
logger.debug("Failed to determine the type of a network interface: {}", iface, e);
|
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -154,7 +158,6 @@ final class DefaultChannelId implements ChannelId {
|
|||||||
bestMacAddr = macAddr;
|
bestMacAddr = macAddr;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
if (bestMacAddr == NOT_FOUND) {
|
if (bestMacAddr == NOT_FOUND) {
|
||||||
bestMacAddr = new byte[MACHINE_ID_LEN];
|
bestMacAddr = new byte[MACHINE_ID_LEN];
|
||||||
@ -164,7 +167,16 @@ final class DefaultChannelId implements ChannelId {
|
|||||||
formatAddress(bestMacAddr));
|
formatAddress(bestMacAddr));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (bestMacAddr.length != MACHINE_ID_LEN) {
|
switch (bestMacAddr.length) {
|
||||||
|
case 6: // EUI-48 - convert to EUI-64
|
||||||
|
byte[] newAddr = new byte[MACHINE_ID_LEN];
|
||||||
|
System.arraycopy(bestMacAddr, 0, newAddr, 0, 3);
|
||||||
|
newAddr[3] = (byte) 0xFF;
|
||||||
|
newAddr[4] = (byte) 0xFE;
|
||||||
|
System.arraycopy(bestMacAddr, 3, newAddr, 5, 3);
|
||||||
|
bestMacAddr = newAddr;
|
||||||
|
break;
|
||||||
|
default: // Unknown
|
||||||
bestMacAddr = Arrays.copyOf(bestMacAddr, MACHINE_ID_LEN);
|
bestMacAddr = Arrays.copyOf(bestMacAddr, MACHINE_ID_LEN);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -181,20 +193,16 @@ final class DefaultChannelId implements ChannelId {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Must not be filled with only 0 or 1.
|
// Must not be filled with only 0 and 1.
|
||||||
boolean onlyZero = true;
|
boolean onlyZeroAndOne = true;
|
||||||
boolean onlyOne = true;
|
|
||||||
for (byte b: candidate) {
|
for (byte b: candidate) {
|
||||||
if (b != 0) {
|
if (b != 0 && b != 1) {
|
||||||
onlyZero = false;
|
onlyZeroAndOne = false;
|
||||||
}
|
break;
|
||||||
|
|
||||||
if (b != -1) {
|
|
||||||
onlyOne = false;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (onlyZero || onlyOne) {
|
if (onlyZeroAndOne) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user