Clarification of Connection.setNetworkTimeout() behavior

Douglas Surber douglas.surber at oracle.com
Mon Nov 13 16:57:09 UTC 2017


> 1) Are the effects of setNetworkTimeout() intended to be immediate?

The network timeout should apply to all subsequent database interactions. It does not apply to pending interactions. It is vendor dependent whether the timeout applies to the entire JDBC API method call or to each network round trip (if there are more than one) to implement the method call.

> 2) What is the role/purpose of the Executor parameter passed to
> setNetworkTimeout()?

When the timeout expires the thread that is hung will be kicked loose with an exception. This thread may not clean up the connection so it is closed properly. The Executor provides a thread that the implementation can use to do this clean up. If the hung thread does the full clean up as it throws then the Executor is not needed. 

Douglas


> On Nov 12, 2017, at 5:20 PM, Brett Wooldridge <brett.wooldridge at gmail.com> wrote:
> 
> 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