How to guarantee atomic moving or file exclusion in Java?

In one of my projects, I have simultaneous write access to one file within the same JRE and you want to handle this by first writing to a temporary file and then moving this temporary file to the target using atomic move. I do not care about the write access order or such, all I need to ensure that one file can be used at any given time. I already know about Files.move and so, my problem is that I considered at least one implementation for this method, and he had some doubts as to whether the implementations really guarantee atomic moves. Take a look at the following code:

Files.move on GrepCode for OpenJDK

1342 FileSystemProvider provider = provider(source); 1343 if (provider(target) == provider) { 1344 // same provider 1345 provider.move(source, target, options); 1346 } else { 1347 // different providers 1348 CopyMoveHelper.moveToForeignTarget(source, target, options); 1349 } 

The problem is that the ATOMIC_MOVE option is not considered in all cases, but the location of the source and destination paths is the only thing that matters first. This is not what I want, and as I understand the documentation:

If the move cannot be performed as an atomic file system operation, then an AtomicMoveNotSupportedException is thrown. This can occur, for example, when the target location is in another file storage and requires that the file be copied or the target location is associated with another provider of this object.

The above code clearly violates this documentation as it reverts to a copy-delete strategy without recognizing ATOMIC_MOVE at all. In my case, the exception would be perfectly normal, because the host of our service could change its settings to use only one file system that supports atomic moves, like what we expect in system requirements anyway. What I don't want to deal with are things that just fail just because the implementation uses a copy-delete strategy, which can lead to data corruption in the target file. So, from my understanding, it is simply unsafe to rely on Files.move for atomic operations, because it does not always fail if they are not supported, but implementations can return to the copy-delete strategy.

Is this behavior an implementation error and should be filed, or does the documentation allow this behavior, and I understand that this is wrong? Does it really matter if I already know that such possibly broken implementations are used there? In this case, I will need to synchronize write access ...

+6
source share
2 answers

You are looking at the wrong place. If the file system providers do not match, the operation will be delegated to moveToForeignTarget , as you saw in the published code snippet. However, the moveToForeignTarget method will use the convertMoveToCopyOptions method (note the name of the speaker ...) to obtain the necessary copy settings for the translated operation. And convertMoveToCopyOptions will throw an AtomicMoveNotSupportedException if it encounters the ATOMIC_MOVE parameter, since there is no way to convert this move parameter into a valid copy option.

So there is no reason to worry, and in general, it is recommended to avoid hasty completion by seeing only less than ten lines of code (especially when I have not tried a single test) ...

+3
source

The Java standard library does not provide a way to perform atomic displacement in all cases.

Files.move () does not guarantee atomic movement. You can pass ATOMIC_MOVE as an option, but if the move cannot be performed as an atomic operation, an AtomicMoveNotSupportedException is AtomicMoveNotSupportedException (this is the case when the target location is in another FileStore and requires the file to be copied).

You must implement it yourself if you really need it. One solution might be to catch an AtomicMoveNotSupportedException , and then do the following: try to transfer the file without the ATOMIC_MOVE option, but catch exceptions and delete the target if an error occurs during copying.

+2
source

Source: https://habr.com/ru/post/973637/


All Articles