0

I'm developing disk cache (multithread). Cache can have many users at once. That is why I can write some rules:

1) Cache can't edit (or delete) file when client reads it.

2) When cache is editing file, clients should wait for the end of editing (and after read the file).

I need to organize this lock strategy with the help of java.

I read about synchronizatioan (synchronized block and java.util.concurrent.Locks) and as I understood it can't help here.

I tried to understand the FileLock. But when client reads file, cache lock can abort reading. And if clients will lock files before reading, there will be long sequence of client to read. I need for advice how to organize it (maybe another ways).

UPDATE

public void write(InputStream is) throws FileNotFoundException, IOException {

    File file = new File("path");

    try (FileOutputStream fos = new FileOutputStream(file);
            FileChannel filechannel = fos.getChannel();
            FileLock lock = filechannel.lock(0, Long.MAX_VALUE, false)) {

        // writing....

    }
}

public void read(OutputStream osToClient) throws IOException {

    File file = new File("path");

    try (FileInputStream fis = new FileInputStream(file);
            FileChannel filechannel = fis.getChannel();
            FileLock lock = filechannel.lock(0, Long.MAX_VALUE, true)) {

        IOUtils.copy(fis, osToClient);

    }

}
Adey
  • 1,846
  • 1
  • 10
  • 18
  • Your question seems to be related to engineering in general rather than java. In the spirit of microservices you could implement a service that deals with reading / writing to file based on events published in a queue (ex RabbitMQ) and publish events in the queue for read operations. Your users can be other processes that publish and read messages from the queue. – Catalin Mar 16 '18 at 14:49

1 Answers1

1

You should probably not build this yourself unless you do it for fun or for a school assignment. However, except that there are warnings about portability (so it may not work the way you expect on all platforms) FileLock should do the job. When you are reading, first get a shared lock on the file, read the file and release the lock when done, ideally in a try-with-resources block. When you are writing, get an exclusive lock (shared=false) instead. There can be multiple readers but only one writer, and when there is a writer there can be no readers.

ewramner
  • 5,810
  • 2
  • 17
  • 33
  • Is your idea the same as code in my updated question? Why I should not build this myself? Is there any instruments to do this work? – Adey Mar 16 '18 at 15:32
  • Your code seems correct. Please note the reservations about platform dependencies in https://docs.oracle.com/javase/8/docs/api/java/nio/channels/FileLock.html. In particular the locks may be advisory only on some platforms, i.e. not working. If all accesses use the same Java process you can use https://docs.oracle.com/javase/8/docs/api/java/util/concurrent/locks/ReadWriteLock.html instead. There are tons of tested high-performing caches out there, see for example http://www.ehcache.org, so you should be able to find one that works for you. – ewramner Mar 17 '18 at 19:08
  • as I understand ReadWriteLock can't help me because I need to lock one particular file in different threads. Ty for advice, I know about ehcache, but it saves files only in memory but I need to save to the disk. That is why I must to make access control by myself. – Adey Mar 19 '18 at 12:22
  • 1
    It is possible to configure ehcache to overflow to disk. JCA (http://commons.apache.org/proper/commons-jcs) is another alternative, it also supports disk overflow. If you search you will find several other alternatives. But I don't know your application, perhaps you need a custom solution. Good luck! – ewramner Mar 19 '18 at 18:45