Clarification of Connection.setNetworkTimeout() behavior

Brett Wooldridge brett.wooldridge at gmail.com
Mon Nov 13 01:20:03 UTC 2017


I am looking for clarification on the expected behavior of
the Connection.setNetworkTimeout() method.

I am the author of the popular connection pool, HikariCP.  One of the goals
of HikariCP is to protect against network partition events, at least with
respect to the pool's own interactions with the database.  To this end,
HikariCP makes use of *setNetworkTimeout()* quite extensively.

The fundamental pattern employed is basically this:

  int originalTimeout = conn.getNetworkTimeout();
  try {
     conn.setNetworkTimeout(executor, timeout);
     // some further interaction with Connection
  }
  finally {
     conn.setNetworkTimeout(executor, originalTimeout);
  }

We have encountered a bug with a particular JDBC driver, and in discussions
regarding a fix it has become clear that there is disagreement and/or
different understanding on two points:

1) Are the effects of setNetworkTimeout() intended to be immediate?
2) What is the role/purpose of the Executor parameter passed to
setNetworkTimeout()?


The bug in question boils down to this case:

  conn.setNetworkTimeout(executor, timeout);
  conn.close()

Here, the pool is attempting to ensure that, in the case of unacknowledged
TCP, the Connection.close() call does not hang indefinitely.

The "bug", as it were, in this particular driver, is encountered when
passing a ThreadPoolExecutor as the Executor, and this particular driver
doing something like this:

executor.execute(new Runnable() {
  public void run() {
    try {
      sock.setSocketTimeout(milliseconds); // for re-connects
    } catch (SQLException e) {
       throw new RuntimeException(e);
    }
  });
}

In our case, calling *setNetworkTimeout()* is followed by an immediately
call to *close()*.  The *close()* implementation of this driver sets sock
to null, so when the Executor gets around to executing the above Runnable
an NPE is thrown in the executor thread.

Further, because the actual setting of the socket timeout is queued into
the executor as a Runnable, the driver cannot guarantee that the timeout is
actually set upon return, and therefore a subsequent call to *close()* (or
any *other* method) is not guaranteed protection against a network
partition event.  Which rather seems to defeat the started purpose of the
*setNetworkTimeout()*:

This method is intended to address a rare but serious condition where
> network partitions can cause threads issuing JDBC calls to hang
> uninterruptedly in socket reads, until the OS TCP-TIMEOUT (typically 10
> minutes).


My interpretation is that the effects of *setNetworkTimeout()* *must* apply
to subsequent calls against the driver upon its completion, and not at
some *indeterminate
time* in the future (at the whim of the OS scheduler, Executor queue depth,
etc).

A solution proposed by one of the JDBC driver developers was to accept
*null* as a parameter, in which case they could make the action immediate,
and if an *Executor* is supplied the code would continue to behave as above.

My issues with this solution are, 1) that the JavaDoc plainly states that a
SQLException should be thrown:

if a database access error occurs, this method is called on a closed
> connection, *the **executor is null*, or the value specified for seconds is
> less than 0.


and, 2) for most users passing in a Executor, the behavior of the method
would be quite non-deterministic.

Having said that, every other driver source I have been able to find simply
*ignores* the supplied Executor completely.  Therefore, that was my
suggestion for the driver in question -- "just ignore the Executor, as
other drivers do, as you have direct access to the socket and the effect
can be immediate."

Again pointing to lack of clarity, the driver developer's objection is
based on the use of the word "will" in the JavaDoc for the executor
parameter:
executor - The Executor implementation which *will* be used by
setNetworkTimeout.
I have searched high and low for some archive of the discussions around the
original proposal for this method, and its parameters, in order to find
some clarity, but have come up short-handed.


Please, keepers of the specification, provide guidance as to these two
questions:

1) Are the effects of *setNetworkTimeout()* intended to be immediate?
2) What is the role/purpose of the *Executor* parameter passed to
*setNetworkTimeout()*?


Brett Wooldridge


More information about the jdbc-spec-discuss mailing list