Moving a Directory Atomically

Moving a directory atomically

You can do this if you use symlinks:

Let's say alpha is a symlink to directory alpha_1, and you want to switch the symlink to point to alpha_2. Here's what that looks like before the switch:

$ ls -l
lrwxrwxrwx alpha -> alpha_1
drwxr-xr-x alpha_1
drwxr-xr-x alpha_2

To make alpha refer to alpha_2, use ln -nsf:

$ ln -nsf alpha_2 alpha
$ ls -l
lrwxrwxrwx alpha -> alpha_2
drwxr-xr-x alpha_1
drwxr-xr-x alpha_2

Now you can remove the old directory:

$ rm -rf alpha_1

Note that this is NOT actually a fully atomic operation, but it does happen very quickly since the "ln" command both unlinks and then immediately recreates the symlink. You can verify this behaviour with strace:

$ strace ln -nsf alpha_2 alpha
...
symlink("alpha_2", "alpha") = -1 EEXIST (File exists)
unlink("alpha") = 0
symlink("alpha_2", "alpha") = 0
...

You can repeat this procedure as desired: e.g. when you have a new version, alpha_3:

$ ln -nsf alpha_3 alpha
$ rm -rf alpha_2

Guaranteed atomic move of folder

If your source and destination paths are on the same filesystem, then mv is an atomic operation. Since it does not actually involve copying or otherwise relocating files, your directories will never end up in a "half-moved" state.

If, on the other hand, your source and destination paths are on different filesystems, then mv is actually a copy followed by a delete over the entire tree, which can take a substantial amount of time and, if interrupted, will leave things in a half-completed state.

Atomically move and rename a Path instance

Regarding your first question, since Java 7 you can use Files#move:

Files.move(path, targetPath);

If you need it to be atomic, you can use the ATOMIC_MOVE option:

import static java.nio.file.StandardCopyOption.ATOMIC_MOVE;

Files.move(path, targetPath, ATOMIC_MOVE);

Note that:

  • this can fail with an AtomicMoveNotSupportedException if the option is not supported (for example if you are moving a file from a local hard drive to a network location).
  • The REPLACE_EXISTING option, if used, is ignored and if the target file exists then it is implementation specific if the existing file is replaced or this method fails by throwing an IOException.

How does one atomically replace a directory with another one in Java?

I am afraid you can't. Not at the SO level at least. So even if you manage "atomicity" in the context of your java application, you have no guarantee about some other "rogue" process interfering at the actual filesystem level.

If I were you, I'd read this article (quite old, but should give you some ideas) and then see if you can port the suggested approach to a more modern version .

Oh, wait, someone did this already!

And apparently your aren't the first one to ask here, either

Best of luck...

Atomicity of File.Move

Yes, in NTFS. From here:

As an aside if you are running under NTFS then file operations are atomic at the file system level. A rename will occur in a single operation as far as any higher code is concerned. The problem you are seeing almost appears to be an issue where the FileInfo object is being shared across applications. It is a MarshalByRef object and therefore can be used in remoting environments. Don't know if this applies to you.



Related Topics



Leave a reply



Submit