I came up with this question because I want to recognize when a change occurred in the memory-mapped file. So I can handle appropriately on the second program.
Is this possible with the Watch Service?
EDIT:
To get events I used this demo code from the java docs.
I also used a Get-Content -Path "test.txt" -Wait
inside PowerShell to monitor the file for changes.
This is the code I wrote for the test. Running it several times with different values put in the TTT class doesn't trigger events but the changes are there when opening the file.
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.ObjectOutputStream;
import java.io.RandomAccessFile;
import java.io.Serializable;
import java.nio.MappedByteBuffer;
import java.nio.channels.FileChannel;
public class App1 {
// private static long count = 1_000_000L; // ~1MB
private static long size = 100_000L; // ~100KB
public static void main(String[] args) throws IOException, InterruptedException {
RandomAccessFile memoryMappedFile = new RandomAccessFile("test/test.txt", "rw");
MappedByteBuffer out = memoryMappedFile.getChannel().map(FileChannel.MapMode.READ_WRITE, 0, size);
// Changing data in here and running again wont trigger an event
// But the changes are actually there if you open the file
TTT t = new TTT("Somebody once told me", System.currentTimeMillis());
ByteArrayOutputStream bos = new ByteArrayOutputStream();
byte[] allBytes;
try {
ObjectOutputStream os = new ObjectOutputStream(bos);
os.writeObject(t);
os.flush();
allBytes = bos.toByteArray();
} finally { try { bos.close(); } catch (IOException ex) {} }
out.put(allBytes);
memoryMappedFile.close();
out.clear();
}
}
class TTT implements Serializable {
public String s;
public long a;
public TTT(String s, long a) {
this.s = s;
this.a = a;
}
}
CodePudding user response:
Are memory-mapped files recognized by the Watch Service API?
I think that the answer is No.
In Linux, the Java Watch Service API is implemented using inotify(7)
, and memory mapped files are implemented using mmap(2)
.
The manual entry for inotify says this in the limitations section:
"The inotify API does not report file accesses and modifications that may occur because of mmap(2), msync(2), and munmap(2)."
CodePudding user response:
It depends on the file mapping you create to open and modify the file.
Like conventional file handles, file mappings can be writable or read-only.
The first two mapping modes, MapMode.READ_ONLY
and MapMode.READ_WRITE
, are fairly obvious. They indicate whether you want the mapping to be read-only or to allow modification of the mapped file.
The third mode, MapMode.PRIVATE
, indicates that you want a copy-on-write mapping. This means that any modifications you make via put() will result in a private copy of the data that only the MappedByteBuffer
instance can see.
No changes will be made to the underlying file, and any changes made will be lost when the buffer is garbage collected. Even though a copy-on-write mapping prevents any changes to the underlying file, you must have opened the file for read/write to set up a MapMode.PRIVATE
mapping. This is necessary for the returned MappedByteBuffer
object to allow put()s
.
Also, then we look at the events to witch the WatchService
can react.
StandardWatchEventKinds.ENTRY_CREATE
– triggered when a new entry is made in the watched directory. It could be due to the creation of a new file or renaming of an existing file.StandardWatchEventKinds.ENTRY_MODIFY
– triggered when an existing entry in the watched directory is modified. All file edit's trigger this event. On some platforms, even changing file attributes will trigger it.StandardWatchEventKinds.ENTRY_DELETE
– triggered when an entry is deleted, moved or renamed in the watched directory.StandardWatchEventKinds.OVERFLOW
– triggered to indicate lost or discarded events. We won't focus much on it
Given this, the following can be said ...
- If the mapping mode is
READ_ONLY
, no event from the above will be fired, so no detection. - If the mapping mode is
PRIVATE
, no event from the above will be fired, because you're working with a private copy of the file. - Now the most interesting case is
READ_WRITE
. Since this one modifies the file on the disk drive at some point, at some point the OS is notified and in turn it will notify theWatchService
API.
The following caveat should also be noted however from the WatchService javadoc
The implementation that observes events from the file system is intended to map directly on to the native file event notification facility where available, or to use a primitive mechanism, such as polling, when a native facility is not available. Consequently, many of the details on how events are detected, their timeliness, and whether their ordering is preserved are highly implementation specific. For example, when a file in a watched directory is modified then it may result in a single ENTRY_MODIFY event in some implementations but several events in other implementations. Short-lived files (meaning files that are deleted very quickly after they are created) may not be detected by primitive implementations that periodically poll the file system to detect changes.
If a watched file is not located on a local storage device then it is implementation specific if changes to the file can be detected. In particular, it is not required that changes to files carried out on remote systems be detected.