java.jdbc

Deadlock when using JDBC from two separate threads with two separate drivers

Details

  • Type: Defect Defect
  • Status: Closed Closed
  • Priority: Minor Minor
  • Resolution: Completed
  • Affects Version/s: None
  • Fix Version/s: None
  • Component/s: None
  • Labels:
    None
  • Environment:
    Ubuntu 16.04, Leiningen

Description

In `clojure.java.jdbc`, it is possible for the function `get-connection` to call `clojure.lang.RT/loadClassForName` on the driver's classname. JDBC drivers have a static initializer to register themselves with `java.sql.DriverManager` upon load. However, `DriverManager`, as part of its static initializer, loads every implementation of `Driver` on the classpath. This causes an insidious bug when trying to use JDBC from two separate threads where each thread is using a different driver.

For example, if thread A tries to call `get-connection` with a db-spec using driver X, and thread B tries to call `get-connection` with a db-spec using driver Y, then thread A will load driver X which in turn loads `DriverManager`, which again in turn tries to load all drivers on the classpath, including driver Y. If driver Y is simultaneously being loaded by thread B, then driver Y will be trying to load `DriverManager` which is trying to load driver Y, thus creating deadlock. This behaviour can be reliably reproduced using the Clojure files attached.

I am not sure if this is even the responsibility of JDBC to fix. If you want to patch it on the JDBC side, it is easily possible to do so by making sure `DriverManager` is loaded before trying to load the driver.

Activity

Hide
Sean Corfield added a comment -

Definitely an interesting edge case and, like you, I am not sure if this is the responsibility of java.jdbc to fix. I would note that java.jdbc imports DriverManager so I would expect its static initializer to be run as part of loading the clojure.java.jdbc namespace and thus DriverManager should be loaded before get-connection is called...?

Show
Sean Corfield added a comment - Definitely an interesting edge case and, like you, I am not sure if this is the responsibility of java.jdbc to fix. I would note that java.jdbc imports DriverManager so I would expect its static initializer to be run as part of loading the clojure.java.jdbc namespace and thus DriverManager should be loaded before get-connection is called...?
Hide
Rogan Morrow added a comment - - edited

It would appear that import does not actually load the class and that classes are only loaded by Clojure at the point that they are first referenced, at least that is my observation based on the output of lein run on the attached project in staticinitializer.zip.

Show
Rogan Morrow added a comment - - edited It would appear that import does not actually load the class and that classes are only loaded by Clojure at the point that they are first referenced, at least that is my observation based on the output of lein run on the attached project in staticinitializer.zip.
Hide
Sean Corfield added a comment -

Cool, will take a look at that. Not what I expected the behavior to be, if you're right.

Show
Sean Corfield added a comment - Cool, will take a look at that. Not what I expected the behavior to be, if you're right.
Hide
Sean Corfield added a comment -

Can you try the latest master version (which force-loads DriverManager prior to calling classForName on the driver) to see if it solves this issue?

Show
Sean Corfield added a comment - Can you try the latest master version (which force-loads DriverManager prior to calling classForName on the driver) to see if it solves this issue?
Hide
Sean Corfield added a comment -

Should be fixed in 0.7.0-alpha2

Show
Sean Corfield added a comment - Should be fixed in 0.7.0-alpha2
Hide
Rogan Morrow added a comment -

I tested master and it no longer deadlocks. Thanks for the fix.

Show
Rogan Morrow added a comment - I tested master and it no longer deadlocks. Thanks for the fix.
Hide
Sean Corfield added a comment -

Thank you for verifying that Roger!

Show
Sean Corfield added a comment - Thank you for verifying that Roger!
Hide
Sean Corfield added a comment -

0.7.0-alpha2 includes this fix.

Show
Sean Corfield added a comment - 0.7.0-alpha2 includes this fix.

People

Vote (0)
Watch (1)

Dates

  • Created:
    Updated:
    Resolved: