Как один атомарно заменить каталог другим в Java? - PullRequest
5 голосов
/ 08 декабря 2010

У меня есть каталог, который содержит файлы данных, обслуживаемые клиентами, скажем, /srv/data. Делая серию обновлений, я работаю над /srv/data_tmp, и в конце операции я бы хотел атомарно заменить data на data_tmp. File.renameTo() всегда возвращает ложь для меня, когда местом назначения является существующий каталог. Как я могу это сделать?

Ответы [ 4 ]

1 голос
/ 08 декабря 2010

Системный вызов Linux rename не позволяет этого (системный вызов rename может перезаписать только пустой каталог), поэтому я сомневаюсь, что это возможно в Java на Linux.

1 голос
/ 08 декабря 2010

Боюсь, ты не сможешь. По крайней мере, на уровне SO. Таким образом, даже если вы управляете «атомарностью» в контексте вашего Java-приложения, вы не можете гарантировать, что какой-то другой «мошеннический» процесс будет вмешиваться на уровне фактической файловой системы.

На вашем месте я прочитал бы эту статью (довольно старая, но должна дать вам несколько идей), а затем посмотрел, сможете ли вы перенести предложенный подход на более современную версию .

Ой, подождите, кто-то сделал это уже!

И, очевидно, вы не первый, кто спрашивает здесь , либо

Удачи ...

1 голос
/ 08 декабря 2010

Вы можете заменить каталог /srv/data символической ссылкой (или соединением в Windows XP ) и изменить целевое назначение ссылки, когда это необходимо.Вы не сможете сделать это с API Java 6 - вам придется полагаться на библиотеку или писать команды командной строки самостоятельно.

Примечание: я ничего не гарантирую в атомарности этой операции.

0 голосов
/ 05 июля 2013

Достижение этой цели вполне возможно при использовании комбинации «symlink» и «rename» вместе с промежуточным каталогом tmp.Следующий пример в оболочке, но вы могли бы легко перевести эту функциональность здесь, чтобы использовать базовые вызовы:

mkdir -p tmp/real_dir1 tmp/real_dir2
touch tmp/real_dir1/a tmp/real_dir2/a
# start with ./target_dir pointing to tmp/real_dir1
ln -s tmp/real_dir1 target_dir
# create a symlink named target_dir in tmp, pointing to real_dir2
ln -sf tmp/real_dir2 tmp/target_dir
# atomically mv it into ./ replacing ./target_dir
mv tmp/target_dir ./

Пример здесь взят из: http://axialcorps.wordpress.com/2013/07/03/atomically-replacing-files-and-directories/

Это сводится к (впсевдокод):

mkdir('./tmp');
mkdir('./tmp/real_dir1');
mkdir('./tmp/real_dir2');
symlink('./tmp/real_dir1', './target_dir')
symlink('./tmp/real_dir2', './tmp/target_dir')
rename('./tmp/target_dir', './target_dir')

Окончательное переименование здесь атомарное, поэтому действие будет либо успешным, либо неудачным, с точки зрения любого процесса, использующего каталог, действие является атомарным.

...