5

The AsynchronousFileChannel API in Java NIO.2 contains the void force(boolean) method.

Obviously this method is blocking, as it can only return once the changes have been successfully written to the device.

I'm looking for a way to achieve the same, without blocking the thread.

As mentioned in the comments, this would be the equivalent of the standard C library function aio_fsync: http://pubs.opengroup.org/onlinepubs/009695399/functions/aio_fsync.html

Chris Leishman
  • 1,777
  • 13
  • 19
  • Could you tell us a little more about your problem? For now, I cannot see any sense in "asynchronous force". Probably, opening your file with `SYNC` or `DSYNC` option is what you are looking for. – mkrakhin May 06 '15 at 09:45
  • Is there any point doing this asychronously? The file will be written eventually, but when your thread carries on, it doesn't have that guarantee if it's asynchronous. – artbristol May 06 '15 at 09:47
  • If you want to "force" a write, it cannot be asynchronous - the ideas are contradictory. You can either force a write, or just use the normal asynchronous write on the channel – kaykay May 06 '15 at 09:54
  • @kaykay: It's certainly not contradictory, or there wouldn't be a standard C library function for doing exactly that: http://pubs.opengroup.org/onlinepubs/009695399/functions/aio_fsync.html. It's only in Java that I can't currently find an equivalent. – Chris Leishman May 06 '15 at 20:01
  • @mkrakhin: I'm basically looking for a method like `void force(boolean, CompletionHandler)` . Using `SYNC` or `DSYNC` would cause every write to be forced immediately. What I want is to make a lot of writes, then choose an appropriate time to force them to storage - and rather than blocking the entire thread while the OS flushes it all down, I'd instead like a event/callback when it's completed. – Chris Leishman May 06 '15 at 20:05
  • @artbristol: The guarantee that the data has been forced to storage would be true only when the callback/event occurs. It's much the same as an asynchronous write: you ask for the write to occur, but there's no guarantee it has until the callback is issued. – Chris Leishman May 06 '15 at 20:07
  • @kaykay - actually there is more sense in asynchronous force() than in asynchronous write() because writing is fast and typically only copies data into the kernel buffers, while force() may block for a really long time, until the data get written to the physical storage. And in a full asynchronous application stack, e.g based on Netty you're not allowed to do long blocking operations in the event loop. In this case I'm forced to either use asio_fsync through JNA (haven't tried yet) or to use a separate pool of threads just to process force() calls. – Piotr Kołaczkowski Aug 03 '15 at 08:51

1 Answers1

0

I have some code where I send a ton of write operations to a file, mostly in fire-and-forget mode. Occasionally, I want to flush changes to disk just to give the user some confidence that if the power fails, they won't lose everything. To this end, I occasionally do this:

channel.write(ByteBuffer.wrap(new byte[0]), 0, null, new CompletionHandler<Integer, Object>() {
    @Override
    public void completed(Integer result, Object attachment) {
        try {
            channel.force(false);
        }
        catch (Throwable t) {
            t.printStackTrace();
        }
    }

    @Override
    public void failed(Throwable exc, Object attachment) {
        try {
            channel.force(false);
        }
        catch (Throwable t) {
            t.printStackTrace();
        }
    }
});

This does seem to cause the changes to be reflected on the disk, and it does not block the calling thread. Of course, it does block one of the threads in the channel's thread pool, thus preventing other writes from completing for a time.

It also has the disadvantage that CompletionHandler's methods cannot throw exceptions, hence the catch-call catch blocks. For my application, absolute certainty that the force has completed is not required, so this is not a problem.

Owen
  • 38,836
  • 14
  • 95
  • 125
  • As you've noted, this doesn't solve the question as it still blocks one of the threads in the channel's thread pool. It remains odd that Java has no way to call flush and provide a callback for completion. Would love to find out if there's a good reason or if it's an oversight. – Chris Leishman May 07 '18 at 23:20