google-code-export / sqljet

Automatically exported from code.google.com/p/sqljet
0 stars 1 forks source link

pending locks after the thread reading from db interrupted #166

Closed GoogleCodeExporter closed 9 years ago

GoogleCodeExporter commented 9 years ago
I use SQLJet lib along with SVNKit 1.7 beta-3. SQLJet seems to keep a database 
locked is some circumstances and does not unlock it until you shut down your 
application.

What steps will reproduce the problem?
1. It is difficult to simulate, happens from time to time. However i was able 
to separate the problem
2. When accessing a database, the database gets locked twice, see the attached 
stacktraces with attempts to lock the db. These attempts pass without a problem
3. However when the thread accessing the db gets interrupted while in 
java.nio.channels.spi.AbstractInterruptibleChannel.blockedOn(AbstractInterruptib
leChannel.java:191), only one of the two locks are unlocked and released. The 
second one persists (stored in 
org.tmatesoft.sqljet.core.internal.fs.SqlJetFileLockManager.locks) as 
shared/invalid and the database cannot be locked for write any more until you 
shut the application down.

What is the expected output? What do you see instead?
As the attached stacktraces show (3rd and 4th), normally the locks are 
released, however when the thread is interrupted and an exception is thrown 
from java.nio.channels.spi.AbstractInterruptibleChannel, the thread never 
releases the second lock and the 
org.tmatesoft.sqljet.core.internal.fs.SqlJetFileLockManager.deleteLock from the 
4th stacktrace is never called. My assuption is that's because in 
SqlJetFile.unlock() the lock is released only if it's valid (but it's not for 
some reason after the thread is interrupted).
I would expect the database file gets unlocked no matter what happens.

What version of the product are you using? On what operating system?
On OS Linux, using sqljet-1.1.0 bundled as part of SVNKit beta-3 preview: 
http://www.svnkit.com/org.tmatesoft.svn_1.7.0-beta3.standalone.zip / 
http://www.svnkit.com/download

Please provide any additional information below.
See the attached file with stacktraces and output with SQLJET_LOG_FILES enabled

Original issue reported on code.google.com by ondra.vr...@gmail.com on 12 Mar 2012 at 1:22

Attachments:

GoogleCodeExporter commented 9 years ago

Original comment by sergey.s...@gmail.com on 12 Mar 2012 at 3:22

GoogleCodeExporter commented 9 years ago
Hi,

thanks for reporting. I would ask you few questions:

1. Are you using only one thread or concurrent access from many threads? Do all 
entries in your stacktrace describe different states of the same one thread or 
do all those entries describe different threads? I suppose you are using only 
one thread and stacktrace describe different states of this one thread, am I 
right?

2. Could you describe something about exception which is thrown from 
AbstractInterruptibleChannel? Why lock isn't valid after that?

3. Could you suggest something about what can be released invalid lock?

JDK reference states:

"void java.nio.channels.FileLock.release() throws IOException

Releases this lock. 

If this lock object is valid then invoking this method releases the lock and 
renders the object invalid. If this lock object is invalid then invoking this 
method has no effect."

So, if lock was become invalid after some exception in NIO SPI level then it 
can't be released, or there is some way to unlock it?

Thanks!

Original comment by sergey.s...@gmail.com on 12 Mar 2012 at 5:04

GoogleCodeExporter commented 9 years ago
In any case, what you find is a very serious and interesting. We only need to 
understand exactly what is happening and how is it possible to solve such 
situations. Thank you very much for your help.

Original comment by sergey.s...@gmail.com on 12 Mar 2012 at 5:22

GoogleCodeExporter commented 9 years ago
Hi,
> 1. Are you using only one thread or concurrent access from many threads?
The stacktraces come from a single thread, i suspended all other threads (in 
debugger) in our application before it called any code from SQLJet. So yes, all 
the stacktraces come from the single thread
> 2. an exception ClosedByInterruptException is then thrown. I guess it's an ex 
similar to InterruptedException.
> Why lock isn't valid after that?
I have no idea, i didn't investigate.
> 3. Could you suggest something about what can be released invalid lock?
I am sorry, i am not familiar too much with java.nio API. I'll take a look 
tomorrow at work and try to understand why the lock gets invalid.

Original comment by ondra.vr...@gmail.com on 12 Mar 2012 at 6:45

GoogleCodeExporter commented 9 years ago
Hi, i would like to correct my partially wrong assumptions. To 3)
> However when the thread accessing the db gets interrupted while in 
java.nio.channels.spi.AbstractInterruptibleChannel.blockedOn(AbstractInterruptib
leChannel.java:191), only one of the two locks are unlocked and released.
In the meaning of java.nio locking (java.​nio.​channels.FileLock), all 
locks are correctly released and the db file is unlocked.
> The second one persists (stored in 
org.tmatesoft.sqljet.core.internal.fs.SqlJetFileLockManager.locks) as 
shared/invalid and the database cannot be locked for write any more until you 
shut the application down.
Although invalid (and released) the lock is still kept by SqlJetFileLockManager 
and never gets deleted from its static field SqlJetFileLockManager.locks. And 
*this is the problem*. Because there is still this (shared though invalid) lock 
(SqlJetFileLock) in SqlJetFileLockManager it prevents SQLJet from acquiring an 
exclusive lock on the db file when needed sometimes later in another thread:
java.lang.Thread.State: RUNNABLE
        at org.tmatesoft.sqljet.core.internal.fs.SqlJetFileLockManager.createLock(SqlJetFileLockManager.java:70)
        - locked <0x00000000d1f4c990> (a java.util.concurrent.ConcurrentHashMap)
        at org.tmatesoft.sqljet.core.internal.fs.SqlJetFileLockManager.tryLock(SqlJetFileLockManager.java:87)
        at org.tmatesoft.sqljet.core.internal.fs.SqlJetFile.lock(SqlJetFile.java:542)
        - locked <0x00000000d1fcb470> (a java.util.HashMap)
        - locked <0x00000000f43f0c60> (a org.tmatesoft.sqljet.core.internal.fs.SqlJetFile)
        at org.tmatesoft.sqljet.core.internal.pager.SqlJetPager.waitOnLock(SqlJetPager.java:2522)

Because removal of the instance of SqlJetFileLock from the 
SqlJetFileLockManager is handled only in SqlJetFileLock.release() and this 
method is never called, because the java.nio.FileLock is invalid:
> if (l.isValid())
> l.release();
taken from the unlock() method of SqlJetFile, SqlJetFileLockManager will never 
release the pending invalid lock

I hope it makes sense now. Sorry i was not 100% clear before.

Original comment by ondra.vr...@gmail.com on 13 Mar 2012 at 9:11

GoogleCodeExporter commented 9 years ago
this small patch seems to resolve all my problems. However it is heavily 
dependent on the knowledge that all FileLock(s) handled in SqlJetFile are 
actually SqlJetFileLock(s). From the javadoc FileLock.release may throw an 
exception, the patch is not safe enough if for some reason an instance of 
java.nio.channels.FileLock instead of SqlJetFileLock would appear in 
SqlJetFile. But maybe it would be enough to just wrap the calls in try-catch 
blocks?

Original comment by ondra.vr...@gmail.com on 13 Mar 2012 at 9:28

Attachments:

GoogleCodeExporter commented 9 years ago
Thanks! I'll review your patch and I'm sure you have found and fixed very 
subtle flaw in SqlJet code. Thanks you a lot.

Soon there will be updated build with your patch included and it would be 
better if you will test it with your test cases.

Original comment by sergey.s...@gmail.com on 13 Mar 2012 at 1:05

GoogleCodeExporter commented 9 years ago
Thanks for the patch. New SVNKit build with the patch included is available 
here: 
http://teamcity.tmatesoft.com/viewLog.html?buildId=1924&tab=artifacts&buildTypeI
d=bt43

Original comment by kit...@gmail.com on 13 Mar 2012 at 5:38

GoogleCodeExporter commented 9 years ago
thanks, i tried the snapshot. Now i can perform any modification commands with 
SVNKit even after a previous command is canceled.

Original comment by ondra.vr...@gmail.com on 14 Mar 2012 at 9:48

GoogleCodeExporter commented 9 years ago

Original comment by sergey.s...@gmail.com on 30 Oct 2012 at 9:45