views:

613

answers:

3

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.

+1  A: 

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.

Kevin
Thanks for clarifying. Do you know a way to check for fs-level lock?
alex
Not really. Cross platform (and cross process) file system locking really only be done through some coordination between the processes. Is all the file access happening in one process? If so, you should abstract the operations for that file into one class. If not, you might try a touch/lock file
Kevin
Nope, the access happens to be shared between different Java VMs.
alex
+1  A: 

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.

Nick Fortescue
But, say, if I launch 2 executable jars, each one would run in it's own copy of Java VM, right?
alex
A: 

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.

Nick Fortescue
Ok, the first thread gets the lock, all subsequent report 'true' for isOpen() and fail with OverlappingFileLockException on tryLock().
alex