-
Notifications
You must be signed in to change notification settings - Fork 5
Concurrency
Currently, file objects in Yarep are written incrementally with no locking. This means that if a process is writing to a file, another process may be able to read an incomplete version. We would like to avoid the issue of being able to read incomplete data.
Instead of writing to the same file on a write operation, write the new data to a temporary file instead. Then we can use the native java.nio.file.Path.move function (with the ATOMIC_MOVE argument) to move the temporary file to the back to the correct position.
Semantics
- While a file is being written/updated, all processes reading the file in the meantime will be reading the old contents.
- If a move happens while other processes are reading the file, they will none the less be reading the old contents correctly. The semantics of ATOMIC_MOVE ensure that moving the file happens atomically.
- All processes which start reading the file after the move happened will be reading the new contents.
- If two processes are trying to write to the file at the same time, the process to finish last will win.
Advantages: This also works if multiple processes (virtual machines) try to access the same file, so we don't need to worry about communicating locking between processes. Threads reading a file will not be blocked, and can always and instantly read a resource (but they may still see the old version while the write is in progress).
Drawbacks: Some older platforms, such as Windows XP, do not support moving files atomically (therefore ATOMIC_MOVE will fail). A fallback to a regular move could be implemented. Thankfully, all newer Windows Server versions (as well as all versions of Linux/UNIHoweverHoweverX/Solaris) support moving files atomically, so this should not be much of an issue.
Use native Java interfaces (such as java.nio.channels.FileLock) to perform locking on files. Files can be locked in regions, can be locked with a shared (reader) lock, or with an exclusive (writer) lock. The semantics are essentially those of the flock(2) system call on Linux.
Semantics
- If a thread is writing to a file, no other thread will be allowed to read and/or write to that file. Instead, the threads will block, waiting for the operation to finish.
- If a thread wants to write to a file, it will have to wait for all other reading operations to finish before the write can be initiated.
Advantages: Will never allow two threads to write at the same time. Does not create temporary files. Does not depend on ATOMIC_MOVE support by the operating system.
Drawbacks: If not coded carefully, can lead to possible deadlocks. Can lead to deadlocks if a thread terminates without releasing a lock. Does not work across multiple processes or virtual machines. Threads will block if locks are held, and will have to wait to finish operations.