Подтвердить что ты не робот

Перемещение каталога атомарно

У меня есть два каталога в одной родительской директории. Вызовите родительский каталог base и каталоги для детей alpha и bravo. Я хочу заменить альфа на bravo. Самый простой способ:

rm -rf alpha
mv bravo alpha

Команда mv является атомарной, но rm -rf не является. Есть ли простой способ в bash для атомной замены alpha с помощью bravo? Если нет, существует ли сложный путь?

ДОПОЛНЕНИЕ:

Постепенно это не является непреодолимой проблемой, если каталог не существует в течение короткого периода времени. Там только одно место, которое пытается получить доступ к альфе, и проверяет, существует ли альфа, прежде чем делать что-либо критическое. В противном случае появляется сообщение об ошибке. Но было бы неплохо, если бы был способ сделать это.:) Может быть, есть способ изменить inodes напрямую или что-то...

4b9b3361

Ответ 1

Вы можете сделать это, если используете символические ссылки:

Скажем, альфа является символической ссылкой на каталог alpha_1, и вы хотите переключить символическую ссылку на point_ alpha. Вот как это выглядит перед коммутатором:

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

Чтобы альфа ссылалась на альфа_2, используйте ln -nsf:

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

Теперь вы можете удалить старый каталог:

$ rm -rf alpha_1

Обратите внимание: это НЕ является полностью атомной операцией, но это происходит очень быстро, так как команда "ln" и отключается, а затем немедленно воссоздает символическую ссылку. Вы можете проверить это поведение с помощью strace:

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

Вы можете повторить эту процедуру по желанию: например. когда у вас есть новая версия, alpha_3:

$ ln -nsf alpha_3 alpha
$ rm -rf alpha_2

Ответ 2

Окончательное решение объединяет подход symlink и rename:

mkdir alpha_real
ln -s alpha_real alpha

# now use "alpha"

mkdir beta_real
ln -s beta_real tmp 

# atomically rename "tmp" to "alpha"
# use -T to actually replace "alpha" instead of moving *into* "alpha"
mv -T tmp alpha

Конечно, приложение, обращаясь к альфе, должно иметь дело с заменой символических ссылок на пути.

Ответ 3

Если вы имеете в виду атомарность для обеих операций, я не верю в это. Ближайшим будет:

mv alpha delta
mv bravo alpha
rm -rf delta

но это все равно будет иметь небольшое окно, в котором альфа не существует.

Чтобы свести к минимуму вероятность того, что вы пытаетесь использовать альфу, пока она не существует (если у вас есть полномочия):

nice --20 ( mv alpha delta ; mv bravo alpha )
rm -rf delta

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

Если, как вы говорите в своем добавлении, есть только одно место, которое проверяет альфу и ошибки, если оно не существует, вы можете сразу изменить этот код, чтобы не ошибка, но повторите попытку за короткое время (легко подсечку для две операции mv) - эти повторы должны устранять любую проблему, если вы не часто меняете alpha очень.

Ответ 4

Используйте отдельную гарантированную атомную операцию, чтобы действовать как семафор.

Итак, если создание и удаление операций с файлом являются атомарными:

1) создайте файл с именем "семафор".

2) Если и только если это успешно (не конфликтует с существующим файлом), выполните операцию (либо обработать альфа, либо переместить каталог в зависимости от процесса)

3) rm семафор.

Ответ 5

Поднимая решение David здесь, которое является полностью атомным... единственная проблема, с которой вы столкнулись, заключается в том, что параметр -T для mv не является POSIX, поэтому некоторые ОС POSIX могут не поддерживать его (FreeBSD, Solaris и т.д.... http://pubs.opengroup.org/onlinepubs/9699919799/utilities/mv.html). С небольшими изменениями этот подход может быть изменен, чтобы быть полностью атомарным и переносимым во всех ОС POSIX:

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 ./

exaple via: http://axialcorps.wordpress.com/2013/07/03/atomically-replacing-files-and-directories/

Ответ 6

SQLite раздел документации Блокировка файлов и Concurrency в SQLite версии 3 имеет хорошо написанное описание своего эскалационного протокола блокировки для управления одновременным чтением, исключительной записью и откатом после сбоя. Некоторые из этих идей применимы здесь.

Ответ 7

Это должно сделать трюк:

mkdir bravo_dir alpha_dir
ln -s bravo_dir bravo
ln -s alpha_dir alpha
mv -fT bravo alpha

strace mv -fT bravo alpha показывает:

rename("bravo", "alpha")

который выглядит довольно атомным для меня.

Ответ 8

Я не верю, что есть атомный способ сделать это. Лучше всего сделать следующее:

mv alpha delme
mv bravo alpha
rm -rf delme

Ответ 9

Даже если вы напрямую обращались к inodes, все равно не было бы возможности автоматически менять значения inode в пользовательском пространстве.

Ответ 10

Беспокойство об атомной природе операции бессмысленно. Дело в том, что доступ к альфе другой задачей не будет атомарным.

Непонятный семафорный подход - единственный способ пойти.

Если вы не можете изменить другую задачу, вам нужно будет убедиться, что она не работает до выполнения замены.

Ответ 11

Что-то, о чем следует помнить, заключается в том, что если ваш процесс имеет какой-либо из файлов в alpha open, когда этот переход/удаление происходит, процесс не заметит, и любые записанные данные будут потеряны, когда файл будет закрыт и, наконец, удален.

Ответ 12

mv и ln могут использоваться для атомных операций. Я использовал ln (1) для автоматического развертывания веб-приложений.

Правильный способ замены символической ссылки - ln -nsf

ln -nsf <target> <link_name>

например.

$ mkdir dir1
$ mkdir dir2
$ ln -s dir1 mylink
$ ls -l mylink
lrwxrwxrwx  1 phil phil 4 Nov 16 14:45 mylink -> dir1
$ ln -nsf dir2 mylink
$ ls -l mylink
lrwxrwxrwx  1 phil phil 4 Nov 16 14:46 mylink -> dir2

Ответ 13

Почему бы вам просто не сделать что-то вроде:

rm -rf alpha/*
mv bravo/* alpha/
rm -rf bravo/

Это означало бы, что все в альфе уничтожается, альфа никогда не удаляется, и все содержимое перемещается.