Skip to content

Commit

Permalink
Fix | Refactored socket creation to simplify handling of socket creation
Browse files Browse the repository at this point in the history
Refactors socket creation in SocketFinder.findSocket(...) to simplify handling of socket creation.

When the host resolves to a single address the driver now defers to getConnectedSocket(...)
to create the socket without spawning any threads. This happens regardless of whether we're
running on an IBM JDK. Previously the single address case would still use NIO on an IBM JDK.

On non-IBM JDKs the driver now handles both IPv4 and IPv6 addresses concurrently with a single
shared timeout. Previously hosts that resolved to both types of addresses were allowed half the
timeout for socket creation per address type with the resolution performed sequentially.
  • Loading branch information
sehrope authored and cheenamalhotra committed Jun 21, 2018
1 parent 48139e7 commit 61b78d7
Showing 1 changed file with 11 additions and 47 deletions.
58 changes: 11 additions & 47 deletions src/main/java/com/microsoft/sqlserver/jdbc/IOBuffer.java
Original file line number Diff line number Diff line change
Expand Up @@ -2329,58 +2329,22 @@ else if (!useTnir) {
conn.terminate(SQLServerException.DRIVER_ERROR_UNSUPPORTED_CONFIG, errorStr);
}

if (inetAddrs.length == 1) {
// Single address so do not start any threads
return getConnectedSocket(inetAddrs[0], portNumber, timeoutInMilliSeconds);
}
timeoutInMilliSeconds = Math.max(timeoutInMilliSeconds, minTimeoutForParallelConnections);
if (Util.isIBM()) {
timeoutInMilliSeconds = Math.max(timeoutInMilliSeconds, minTimeoutForParallelConnections);
if (logger.isLoggable(Level.FINER)) {
logger.finer(this.toString() + "Using Java NIO with timeout:" + timeoutInMilliSeconds);
}
findSocketUsingJavaNIO(inetAddrs, portNumber, timeoutInMilliSeconds);
}
else {
LinkedList<InetAddress> inet4Addrs = new LinkedList<>();
LinkedList<InetAddress> inet6Addrs = new LinkedList<>();

for (InetAddress inetAddr : inetAddrs) {
if (inetAddr instanceof Inet4Address) {
inet4Addrs.add((Inet4Address) inetAddr);
}
else {
assert inetAddr instanceof Inet6Address : "Unexpected IP address " + inetAddr.toString();
inet6Addrs.add((Inet6Address) inetAddr);
}
}

// use half timeout only if both IPv4 and IPv6 addresses are present
int timeoutForEachIPAddressType;
if ((!inet4Addrs.isEmpty()) && (!inet6Addrs.isEmpty())) {
timeoutForEachIPAddressType = Math.max(timeoutInMilliSeconds / 2, minTimeoutForParallelConnections);
}
else
timeoutForEachIPAddressType = Math.max(timeoutInMilliSeconds, minTimeoutForParallelConnections);

if (!inet4Addrs.isEmpty()) {
if (logger.isLoggable(Level.FINER)) {
logger.finer(this.toString() + "Using Java Threading with timeout:" + timeoutForEachIPAddressType);
}

findSocketUsingThreading(inet4Addrs, portNumber, timeoutForEachIPAddressType);
}

if (!result.equals(Result.SUCCESS)) {
// try threading logic
if (!inet6Addrs.isEmpty()) {
// do not start any threads if there is only one ipv6 address
if (inet6Addrs.size() == 1) {
return getConnectedSocket(inet6Addrs.get(0), portNumber, timeoutForEachIPAddressType);
}

if (logger.isLoggable(Level.FINER)) {
logger.finer(this.toString() + "Using Threading with timeout:" + timeoutForEachIPAddressType);
}

findSocketUsingThreading(inet6Addrs, portNumber, timeoutForEachIPAddressType);
}
if (logger.isLoggable(Level.FINER)) {
logger.finer(this.toString() + "Using Threading with timeout:" + timeoutInMilliSeconds);
}
findSocketUsingThreading(inetAddrs, portNumber, timeoutInMilliSeconds);
}

// If the thread continued execution due to timeout, the result may not be known.
Expand Down Expand Up @@ -2633,20 +2597,20 @@ private Socket getConnectedSocket(InetSocketAddress addr,
return selectedSocket;
}

private void findSocketUsingThreading(LinkedList<InetAddress> inetAddrs,
private void findSocketUsingThreading(InetAddress[] inetAddrs,
int portNumber,
int timeoutInMilliSeconds) throws IOException, InterruptedException {
assert timeoutInMilliSeconds != 0 : "The timeout cannot be zero";

assert inetAddrs.isEmpty() == false : "Number of inetAddresses should not be zero in this function";
assert inetAddrs.length != 0 : "Number of inetAddresses should not be zero in this function";

LinkedList<Socket> sockets = new LinkedList<>();
LinkedList<SocketConnector> socketConnectors = new LinkedList<>();

try {

// create a socket, inetSocketAddress and a corresponding socketConnector per inetAddress
noOfSpawnedThreads = inetAddrs.size();
noOfSpawnedThreads = inetAddrs.length;
for (InetAddress inetAddress : inetAddrs) {
Socket s = new Socket();
sockets.add(s);
Expand Down

0 comments on commit 61b78d7

Please sign in to comment.