Summary: | 7.0.21 and newer break the JDK 6 Service provider mechanism for loading JDBC Drivers | ||
---|---|---|---|
Product: | Tomcat 7 | Reporter: | Rick Bullotta <rick.bullotta> |
Component: | Catalina | Assignee: | Tomcat Developers Mailing List <dev> |
Status: | RESOLVED INVALID | ||
Severity: | regression | ||
Priority: | P2 | ||
Version: | 7.0.21 | ||
Target Milestone: | --- | ||
Hardware: | PC | ||
OS: | All |
Description
Rick Bullotta
2011-10-13 21:19:49 UTC
Try setting driverManagerProtection="false" for the JreMemoryLeakPreventionListener in server.xml. If I recall correctly, the service provider mechanism didn't work across multiple web applications with different drivers anyway. (In reply to comment #0) > would automatically be loaded using the JDK's service provider > mechanisms. Can you be more specific? Preferably with a step-by-step instruction on how to reproduce this. Mark, thanks for the quick feedback. That does indeed seem to return it to the pre-7.0.21 behavior. That said, I still think we'd have to call it a regression issue, since it changes previous behavior and would break existing apps. It is an issue with the implementation of the JreMemoryLeakPreventionListener or just a changed behavior? Mark, thanks for the quick feedback. That does indeed seem to return it to the pre-7.0.21 behavior. That said, I still think we'd have to call it a regression issue, since it changes previous behavior and would break existing apps. It is an issue with the implementation of the JreMemoryLeakPreventionListener or just a changed behavior? (In reply to comment #1) > Try setting driverManagerProtection="false" for the > JreMemoryLeakPreventionListener in server.xml. > If I recall correctly, the service provider mechanism didn't work across > multiple web applications with different drivers anyway. I'll need to do some testing to see how well this actually worked before the change. I have my suspicions about possible failure modes I need to check. Depending on what the testing shows, this will / will not be treated as a regression but either way the docs will probably end up being updated. (In reply to comment #5) > I'll need to do some testing to see how well this actually worked before the > change. I have my suspicions about possible failure modes I need to check. > Depending on what the testing shows, this will / will not be treated as a > regression but either way the docs will probably end up being updated. I can reproduce fairly easily with the following scenario: Drop a couple JDBC drivers (any will do, MySQL connector and jTDS are two that we use) in the lib directly of a webapp. When an attempt is made to get a JDBC connection, in the loadInitialDrivers of the DriverManager class, it will (one time) try to get a list of JDBC drivers using the Service Provider mechanism. 7.0.20 and earlier would load and find three drivers (the two in the webapp and one built into the JVM). 7.0.21 and later do not see the drivers in the webapp. It uses the getCallerClassLoader() method to pass a classloader into the ServiceProvider stuff that is in sun.misc.Service. I'm guessing that the classloader here is obviously behaving differently - just not sure the mechanics, and it sound like you're very familiar with what's going on. LMK if you want us to test/try anything else. I am closing this as INVALID as the Service Provider mechanism for DriverManager is - as I suspected - broken for servlet container environments. Given that it was a lottery if this ever worked before, that it now consistently doesn't work isn't really a regression. What I have done is updated the documentation to try and explain what is going on and how to work-around it. Basically, just assume the service provider mechanism isn't there and manually register (and deregister) the Driver. The change for the updated docs is here: http://svn.apache.org/viewvc/tomcat/trunk/webapps/docs/jndi-datasource-examples-howto.xml?r1=1184919&r2=1184918&pathrev=1184919 You may find this presentation on memory leaks useful / interesting: http://people.apache.org/~markt/presentations/2010-11-04-Memory-Leaks-60mins.pdf Thanks, Mark. Probably the reason they left the Service provider stuff in sun.misc!!! We'll just go back to the ever-popular Class.forName, which (almost) always works... (In reply to comment #7) > I am closing this as INVALID as the Service Provider mechanism for > DriverManager is - as I suspected - broken for servlet container environments. > Given that it was a lottery if this ever worked before, that it now > consistently doesn't work isn't really a regression. > > What I have done is updated the documentation to try and explain what is going > on and how to work-around it. Basically, just assume the service provider > mechanism isn't there and manually register (and deregister) the Driver. > > The change for the updated docs is here: > http://svn.apache.org/viewvc/tomcat/trunk/webapps/docs/jndi-datasource-examples-howto.xml?r1=1184919&r2=1184918&pathrev=1184919 > > You may find this presentation on memory leaks useful / interesting: > http://people.apache.org/~markt/presentations/2010-11-04-Memory-Leaks-60mins.pdf (In reply to comment #7) > I am closing this as INVALID as the Service Provider mechanism for > DriverManager is - as I suspected - broken for servlet container environments. The scan for service providers happens only once when DriverManager initializes. See DriverManager.getDrivers() / DriverManager.loadInitialDrivers(). (JDK 6u26) 1. My understanding regarding DriverManager.getDrivers() call in JreMemoryLeakPreventionListener is that Service Provider mechanism should work if the class is visible to the JreMemoryLeakPreventionListener. That is, it should work if the driver jar is in $CATALINA_BASE\lib It might be nice to mention it in the docs, because it might be useful for users, but I have not tested whether it actually works. 2. I agree with Mark that for webapps it is broken at JRE level and cannot be fixed, thus INVALID. Even if you disable the listener, at most one webapp per JVM would be able to make use of it. (In reply to comment #9) > 1. My understanding regarding DriverManager.getDrivers() call in > JreMemoryLeakPreventionListener is that Service Provider mechanism should work > if the class is visible to the JreMemoryLeakPreventionListener. > > That is, it should work if the driver jar is in $CATALINA_BASE\lib > > It might be nice to mention it in the docs, because it might be useful for > users, but I have not tested whether it actually works. Yes, it does work. I'll add that to the docs. |