Przenoszenie katalogu atomicznie
Mam dwa katalogi w tym samym katalogu nadrzędnym. Wywołanie katalogu nadrzędnego base oraz katalogów podrzędnych alpha i bravo . Chcę zastąpić alpha bravo. Najprostsza metoda to:
rm -rf alpha
mv bravo alpha
Komenda mv jest atomowa, ale rm-rf nie. Czy istnieje prosty sposób w bash aby atomicznie zastąpić alpha bravo ? Jeśli nie, czy jest jakiś skomplikowany sposób?
Dodatek:
By The by, it ' s nie jest to problem nie do pokonania, jeśli katalog nie istnieje przez krótki okres. Jest tylko jedno miejsce, które próbuje uzyskać dostęp do alfy i sprawdza, czy Alfa istnieje, zanim zrobi coś krytycznego. Jeśli nie, zostanie wyświetlony komunikat o błędzie. Ale byłoby miło, gdyby był na to sposób. :) Może jest jakiś sposób na bezpośrednią modyfikację i-węzłów, czy coś...
15 answers
Możesz to zrobić, jeśli używasz dowiązań symbolicznych:
Załóżmy, że alpha jest dowiązaniem symbolicznym do katalogu alpha_1 i chcemy przełączyć dowiązanie symboliczne na wskazujące na alpha_2. Oto jak to wygląda przed przełącznikiem:
$ ls -l
lrwxrwxrwx alpha -> alpha_1
drwxr-xr-x alpha_1
drwxr-xr-x alpha_2
Aby Alfa odnosiła się do alpha_2, użyj ln-nsf:
$ ln -nsf alpha_2 alpha
$ ls -l
lrwxrwxrwx alpha -> alpha_2
drwxr-xr-x alpha_1
drwxr-xr-x alpha_2
Teraz możesz usunąć stary katalog:
$ rm -rf alpha_1
Zauważ, że nie jest to operacja w pełni atomowa, ale dzieje się to bardzo szybko, ponieważ polecenie " ln " zarówno unlinks, jak i natychmiast odtwarza dowiązanie symboliczne. Możesz zweryfikować to zachowanie za pomocą strace:
$ strace ln -nsf alpha_2 alpha
...
symlink("alpha_2", "alpha") = -1 EEXIST (File exists)
unlink("alpha") = 0
symlink("alpha_2", "alpha") = 0
...
Możesz powtórzyć tę procedurę zgodnie z życzeniem: np. gdy masz nową wersję, alpha_3:
$ ln -nsf alpha_3 alpha
$ rm -rf alpha_2
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2011-03-24 15:47:59
Ostatecznym rozwiązaniem jest połączenie symlink-i rename-podejście:
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
Oczywiście, aplikacja uzyskująca dostęp do alfy musi być w stanie poradzić sobie ze zmianami dowiązań symbolicznych w ścieżce.
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2012-06-05 00:36:40
Przyjrzałem się rozwiązaniu Davida, które jest w pełni atomowe ... jedynym problemem jest to, że opcja -T
dla {[2] } nie jest zgodna z POSIX, więc niektóre systemy POSIX mogą jej nie obsługiwać (FreeBSD, Solaris, itp. ... http://pubs.opengroup.org/onlinepubs/9699919799/utilities/mv.html). z niewielką modyfikacją, to podejście może być zmienione tak, aby było w pełni atomowe i przenośne we wszystkich systemach operacyjnych 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/
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2013-07-05 15:55:16
Jeśli masz na myśli atomowe w obu operacjach, to nie sądzę. Najbliżej byłoby:
mv alpha delta
mv bravo alpha
rm -rf delta
Ale to wciąż miałoby małe okienko, w którym alfa nie istniała.
Aby zminimalizować prawdopodobieństwo, że cokolwiek spróbuje użyć Alfy, gdy jej nie ma, możesz (jeśli masz uprawnienia):
nice --20 ( mv alpha delta ; mv bravo alpha )
rm -rf delta
, co znacznie zwiększy priorytet Twojego procesu podczas operacji mv
.
Jeśli, jak mówisz w swoim dodatku, jest tylko jedno miejsce, które sprawdza alpha i błędy it jeśli go nie ma, możesz zmienić ten kod na not error natychmiast, ale spróbuj ponownie w krótkim czasie ( łatwo sub-sekunda dla dwóch operacji mv
) - te powtórzenia powinny złagodzić każdy problem, chyba że często zastępujesz alpha bardzo.
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2008-11-21 01:06:56
Użyj oddzielnej, gwarantowanej operacji atomowej, aby działać jako SEMAFOR.
Tak więc, jeśli operacje tworzenia i usuwania plików są atomowe:
1) Utwórz plik o nazwie "SEMAFOR".
2) wtedy i tylko wtedy, gdy to się powiedzie (brak konfliktu z istniejącym plikiem), wykonaj operację (albo proces alpha albo przenieś katalog, w zależności od procesu)
3) SEMAFOR rm.
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2008-11-21 01:33:45
Sekcja SQLite Dokumentacja blokowanie plików i współbieżność w wersji SQLite 3 posiada dobrze napisany opis swojego eskalującego protokołu blokującego, który kontroluje jednoczesne czytanie, ekskluzywne pisanie i wycofywanie po awarii. Niektóre z tych pomysłów mają tu zastosowanie.
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2009-11-07 23:00:18
To powinno załatwić sprawę:
mkdir bravo_dir alpha_dir
ln -s bravo_dir bravo
ln -s alpha_dir alpha
mv -fT bravo alpha
Strace mv-ft bravo alpha pokazuje:
rename("bravo", "alpha")
Co dla mnie wygląda dość atomowo.Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2014-01-06 21:50:52
Nawet jeśli uzyskujesz bezpośredni dostęp do i-węzłów, nadal nie będzie możliwości atomicznej wymiany wartości i-węzłów w przestrzeni użytkownika.
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2008-11-21 01:19:56
Martwienie się o atomowy charakter operacji jest bez znaczenia. Chodzi o to, że dostęp do alfy przez inne zadanie i tak nie będzie atomowy.
Podejście do semafora Oddthinking to jedyna droga.
Jeśli nie możesz zmodyfikować innego zadania, musisz upewnić się, że nie działa przed wykonaniem wymiany.
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2008-11-21 04:17:12
Od Linuksa 3.15, nowe wywołanie systemowe renameat2
może atomicznie wymieniać dwie ścieżki w tym samym systemie plików. Jednakże, nie ma nawet glibc
owijarki do niego jeszcze, nie mówiąc już o coreutils
sposób, aby uzyskać do niego dostęp. Więc wyglądałoby to mniej więcej tak:
int dirfd = open(".../base", O_PATH | O_DIRECTORY | O_CLOEXEC);
syscall(SYS_renameat2, dirfd, "alpha", dirfd, "bravo", RENAME_EXCHANGE);
close(dirfd);
system("rm -rf alpha");
(oczywiście, należy zrobić właściwą obsługę błędów itp. - zobacz Ten gist {[10] } dla bardziej wyrafinowanego renameat2
opakowania.)
To powiedziawszy - rozwiązanie dowiązania symbolicznego wymienione przez innych jest zarówno łatwiejsze, jak i przenośne, więc chyba że bravo
już istnieje, a ty musisz atomicznie go zaktualizować, zamiast tego użyj dowiązania symbolicznego.
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2018-05-15 15:05:25
Nie wierzę, że jest na to jakiś atomowy sposób. Najlepiej zrobić coś takiego:
mv alpha delme
mv bravo alpha
rm -rf delme
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2008-11-21 00:51:34
Należy pamiętać, że jeśli twój proces ma otwarty któryś z plików w alfie, gdy wystąpi ten ruch/usuwanie, proces nie zauważy, a wszelkie zapisane dane zostaną utracone, gdy plik zostanie zamknięty i ostatecznie usunięty.
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2008-11-21 03:38:51
Mv i ln mogą być używane do operacji atomowych. Użyłem ln (1) do atomicznego wdrażania aplikacji internetowych.
Poprawnym sposobem zastąpienia dowiązania symbolicznego jest LN-nsf
ln -nsf <target> <link_name>
Np.
$ 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
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2009-11-16 14:48:00
Możliwe jest również zastąpienie całej części zawartości jednocześnie w jakimś prefiksie (Z
tutaj) za pomocą unionfs-fuse
:
# mkdir a b c Z
# touch a/1 b/2 c/3
# ln -s a X
# ln -s b Y
# unionfs X=RW:Y=RW Z
# shopt -s globstar
# file **
a: directory
a/1: empty
b: directory
b/2: empty
c: directory
c/3: empty
X: symbolic link to a
Y: symbolic link to b
Z: directory
Z/1: empty
Z/2: empty
# ln -sfn c Y
# file **/*
a: directory
a/1: empty
b: directory
b/2: empty
c: directory
c/3: empty
X: symbolic link to a
X/1: empty
Y: symbolic link to c
Y/3: empty
Z: directory
Z/1: empty
Z/3: empty
# fusermount -u Z
# rm -r a b c X Y Z
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2018-01-12 20:09:16
Dlaczego po prostu nie zrobisz czegoś takiego:
rm -rf alpha/*
mv bravo/* alpha/
rm -rf bravo/
Oznaczałoby to, że wszystko w alfa zostanie zniszczone, alfa nigdy nie zostanie usunięta, a cała zawartość zostanie przeniesiona.
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2008-11-21 04:44:07