2

The findings in this question (fsyncing a directory by opening it as a regular file) seem to imply that FileChannel#force() applies to all changes done to a file, regardless of which file descriptor was used.

Prompted by this I tried to optimize my file writing procedure such that I would start a background thread which opens the same file and calls force(false) on it in a loop. When my main writing thread reaches the end and calls force(false) itself, it should suffer through less blocking because there would be less data left in the dirty cache pages. This is the code I wrote:

private static class Fsyncer implements Runnable {
    volatile File requested;
    File actual;
    FileChannel fc;

    @Override public void run() {
        try {
            while (!interrupted()) {
                if (requested != actual) {
                    if (fc != null) {
                        fc.close();
                        actual = requested;
                        fc = new FileInputStream(actual).getChannel();
                    }
                }
                if (fc != null) {
                    fc.force(false);
                }
            }
        } catch (InterruptedException e) {
            // thread done
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
    }
}

Usage:

Thread fsyncerThread = new Thread(fsyncer);
fsyncerThread.start();
writeFiles();
fsyncerThread.interrupt();

Finally, writeFiles() does

fsyncer.requested = file;

each time it opens another file.

However, I didn't measure any difference with and without the background forcing thread.

The documentation on force isn't fully clear: it says it will guarantee to force all changes done "via the methods defined in this class", but it doesn't precisely state whether it works only for the same FileChannel instance.

The two facts above seem to be in contradiction: if the hack with forcing a directory is reliable (and Lucene team has been testing it by actually shutting down the machines) then my background forcing technique should also work.

Is the directory-forcing technique reliable due to some special behavior applied to fsyncing a directory, which doesn't apply to my case? Or is it perhaps that changes from another FD are propagated only after the FD is closed? I'm looking for an explanation which would account for both the findings.

Community
  • 1
  • 1
Marko Topolnik
  • 195,646
  • 29
  • 319
  • 436
  • A `FileInputStream` gives you a read-only `FileChanne`l for which the `force()` operation is meaningless. Try a `FileChannel` acquired via a `RandomAccessFile.` But I don't see why you have two instances in the first place. You're deep into UB here. Try it with a single channel. – user207421 Feb 15 '16 at 11:43
  • But the only way the directory-fsync hack can work is by opening the file in read-only mode. And it's proven to have effect. Even the documentation on `force()` states that forcing a read-only channel can cause file write operations. However in my case i could as well use the same channel instance. – Marko Topolnik Feb 15 '16 at 12:35

0 Answers0