Question

To put it simple: a swing app that uses sqlitejdbc as backend. Currently, there's no problem launching multiple instances that work with the same database file. And there should be. The file is locked (can't delete it while the app is running) so the check should be trivial. Turns out not.

    File f = new File("/path/to/file/db.sqlite");
    FileChannel channel = new RandomAccessFile(f, "rw").getChannel();
    System.out.println(channel.isOpen());
    System.out.println(channel.tryLock());

results in

    true
    sun.nio.ch.FileLockImpl[0:9223372036854775807 exclusive valid]

No matter whether the app is running or not. Am I missing the point? TIA.

Was it helpful?

Solution

FileLocks are exclusive to the JVM, not an individual thread. So if you ran that code inside the same process as your Swing app, you would get the lock because it is shared by the JVM.

If your Swing app is not running, no other process is contending for the lock so you will obtain it there is well.

OTHER TIPS

A File System level lock interacts with other applications. You get one of these from FileChannel. So what you do in your example code will make the file seem locked to another process, for example vi.

However, other Java threads or processes within the JVM will NOT see the lock. The key sentence is "File locks are held on behalf of the entire Java virtual machine. They are not suitable for controlling access to a file by multiple threads within the same virtual machine." You are not seeing the lock, so you are running sqlitejdbc from within the same JVM as your application.

So the question is how do you see whether your JVM has already acquired a lock on a file (assuming you don't control the code acquiring the lock)? One suggestion I would have is try and acquire an exclusive lock on a different subset of the file, for example with this code:

fc.tryLock(0L, 1L, false)

If there is already a lock you should get an OverlappingFileLockException. This is a bit hacky but might work.

Can you do a little experiment? Run two copies of this program (just your code with a sleep):

public class Main {
    public static void main(String [] args) throws Exception {
        File f = new File("/path/to/file/db.sqlite");
        FileChannel channel = new RandomAccessFile(f, "rw").getChannel();
        System.out.println(channel.isOpen());
        System.out.println(channel.tryLock());
        Thread.sleep(60000);
    }
}

If this doesn't lock you know that tryLock() isn't working on your OS/drive/JVM. If this does lock then something else is wrong with your logic. Let us know the result in a comment.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top