Zastanawiam się, jak aplikacje typu Killer, takie jak Thunderbird lub Firefox, można aktualizować za pomocą menedżera pakietów systemu, gdy są one nadal uruchomione. Co dzieje się ze starym kodem podczas ich aktualizacji? Co muszę zrobić, gdy chcę napisać program, który aktualizuje się podczas działania?
files
upgrade
executable
ubuplex
źródło
źródło
Odpowiedzi:
Ogólne zastępowanie plików
Po pierwsze, istnieje kilka strategii zastępowania pliku:
Otwórz istniejący plik do zapisu, skróć go do 0 długości i napisz nową zawartość. (Mniej powszechnym wariantem jest otwarcie istniejącego pliku, zastąpienie starej treści nową treścią, obcięcie pliku do nowej długości, jeśli jest krótszy.)
Usuń stary plik i utwórz nowy plik o tej samej nazwie. W skrócie:
Napisz do nowego pliku pod tymczasową nazwą, a następnie przenieś nowy plik do istniejącej nazwy. Przeniesienie usuwa stary plik. W skrócie:
Nie wymienię wszystkich różnic między strategiami, wymienię tylko niektóre z nich, które są tutaj ważne. W przypadku strategii 1, jeśli jakikolwiek proces aktualnie korzysta z pliku, proces widzi nową zawartość w trakcie aktualizacji. Może to powodować pewne zamieszanie, jeśli proces oczekuje, że zawartość pliku pozostanie taka sama. Należy pamiętać, że dotyczy to tylko procesów, w których plik jest otwarty (jak widać w
lsof
lub w ; aplikacje interaktywne, które mają otwarty dokument (np. Otwieranie pliku w edytorze) zwykle nie utrzymują pliku otwartego, ładują zawartość pliku podczas Operacja „otwórz dokument” i zastępują plik (przy użyciu jednej z powyższych strategii) podczas operacji „zapisuj dokument”./proc/PID/fd/
W przypadku strategii 2 i 3, jeśli jakiś proces ma
somefile
otwarty plik , stary plik pozostaje otwarty podczas aktualizacji zawartości. W przypadku strategii 2 krok usuwania pliku w rzeczywistości usuwa tylko pozycję pliku w katalogu. Sam plik jest usuwany tylko wtedy, gdy nie prowadzi do niego pozycja katalogu (w typowych systemach plików Unix może istnieć więcej niż jedna pozycja katalogu dla tego samego pliku ) i żaden proces nie ma otwartego. Oto sposób, aby to zaobserwować - plik jest usuwany tylko posleep
zabiciu procesu (rm
usuwa tylko pozycję katalogu).W strategii 3 krok przeniesienia nowego pliku do istniejącej nazwy usuwa pozycję katalogu prowadzącą do starej treści i tworzy pozycję katalogu prowadzącą do nowej treści. Odbywa się to w jednej operacji atomowej, więc ta strategia ma główną zaletę: jeśli proces otworzy plik w dowolnym momencie, zobaczy albo starą lub nową zawartość - nie ma ryzyka, że zawartość zostanie zmieszana lub plik nie będzie istniejący.
Zastępowanie plików wykonywalnych
Jeśli wypróbujesz strategię 1 z działającym plikiem wykonywalnym w systemie Linux, pojawi się błąd.
„Plik tekstowy” oznacza plik zawierający kod wykonywalny z niejasnych powodów historycznych . Linux, podobnie jak wiele innych wariantów uniksowych, odmawia zastąpienia kodu działającego programu; na to pozwala kilka wariantów uniksowych, co prowadzi do awarii, chyba że nowy kod był bardzo przemyślaną modyfikacją starego kodu.
W systemie Linux można zastąpić kod biblioteki dynamicznie ładowanej. Prawdopodobnie doprowadzi to do awarii używającego go programu. (Możesz nie być w stanie tego zaobserwować,
sleep
ponieważ ładuje cały kod biblioteki, którego potrzebuje, gdy się uruchamia. Wypróbuj bardziej złożony program, który robi coś pożytecznego po spaniu, jakperl -e 'sleep 9; print lc $ARGV[0]'
.)Jeśli interpreter uruchamia skrypt, plik skryptu jest otwierany przez interpretera w zwykły sposób, więc nie ma ochrony przed zastąpieniem skryptu. Niektórzy tłumacze czytają i analizują cały skrypt przed rozpoczęciem wykonywania pierwszego wiersza, inni czytają skrypt w razie potrzeby. Zobacz Co się stanie, jeśli edytujesz skrypt podczas wykonywania? i jak Linux radzi sobie ze skryptami powłoki? po więcej szczegółów.
Strategie 2 i 3 są również bezpieczne dla plików wykonywalnych: chociaż uruchamianie plików wykonywalnych (i bibliotek ładowanych dynamicznie) nie jest plikami otwartymi w sensie posiadania deskryptora plików, zachowują się w bardzo podobny sposób. Tak długo, jak jakiś program uruchamia kod, plik pozostaje na dysku, nawet bez wpisu katalogu.
Aktualizowanie aplikacji
Większość menedżerów pakietów używa strategii 3 do zastępowania plików, ze względu na główną zaletę wspomnianą powyżej - w dowolnym momencie otwarcie pliku prowadzi do jego prawidłowej wersji.
Uaktualnienia aplikacji mogą się zepsuć, ponieważ podczas aktualizacji jednego pliku jest atomowy, aktualizacja aplikacji jako całości nie jest taka, że aplikacja składa się z wielu plików (program, biblioteki, dane,…). Rozważ następującą sekwencję zdarzeń:
W kroku 3 działająca instancja starej wersji aplikacji otwiera plik danych z nowej wersji. To, czy to działa, zależy od aplikacji, jakiego pliku to jest i jak bardzo plik został zmodyfikowany.
Po aktualizacji zauważysz, że stary program nadal działa. Jeśli chcesz uruchomić nową wersję, musisz wyjść ze starego programu i uruchomić nową wersję. Menedżerowie pakietów zwykle zabijają i ponownie uruchamiają demony podczas aktualizacji, ale pozostawiają aplikacje użytkowników w spokoju.
Kilka demonów ma specjalne procedury do obsługi aktualizacji bez konieczności zabijania demona i czekania na ponowne uruchomienie nowej instancji (co powoduje zakłócenie usługi). Jest to konieczne w przypadku init , którego nie można zabić; Systemy init zapewniają sposób żądania wywołania działającej instancji w
execve
celu zastąpienia się nową wersją.źródło
unlink
, jak omówisz później. Może „zastępuje istniejącą nazwę”, ale nadal jest to nieco mylące.Uaktualnienie można uruchomić podczas działania programu, ale uruchomiony program, który widzisz, jest w rzeczywistości jego starą wersją. Stary plik binarny pozostaje na dysku, dopóki nie zamkniesz programu.
Objaśnienie: w systemach Linux plik jest tylko i-węzłem, do którego może mieć kilka łączy. Na przykład.
/bin/bash
widzisz jest tylko linkinode 3932163
w moim systemie. Możesz sprawdzić, z którym i-węzłem łączy się coś, wydającls --inode /path
link. Plik (i-węzeł) jest usuwany tylko wtedy, gdy wskazuje na niego zero łączy i nie jest używany przez żaden program. Gdy menedżer pakietów aktualizuje np./usr/bin/firefox
, najpierw odłącza (usuwa twardy link/usr/bin/firefox
), a następnie tworzy nowy plik o nazwie/usr/bin/firefox
hardlink do innego i-węzła (tego, który zawiera nowąfirefox
wersję). Stary i-węzeł jest teraz oznaczony jako wolny i może być ponownie użyty do przechowywania nowych danych, ale pozostaje na dysku (i-węzły są tworzone tylko podczas budowania systemu plików i nigdy nie są usuwane). Na następnym początkufirefox
, zostanie użyty nowy.Jeśli chcesz napisać program, który sam się „aktualizuje” podczas działania, jedynym możliwym rozwiązaniem, jakie mogę wymyślić, jest okresowe sprawdzanie znacznika czasu własnego pliku binarnego, a jeśli jest on nowszy niż czas uruchomienia programu, przeładuj się.
źródło
apt
Prace aktualizacyjne Debiana ? Mogę zaktualizować dowolny działający program bez problemów, w tymIceweasel
(Firefox
).dpkg
) nie zastępuje plików. Zamiast tego rozłącza je i umieszcza nowy pod tą samą nazwą. Wyjaśnienia znajdują się w pytaniu i odpowiedzi, z którą się połączyłem.ln
(twardych linków). Możesz usunąć nazwy za pomocąrm
(rozłącz). Nie można bezpośrednio usunąć pliku, wystarczy usunąć jego nazwy. Gdy plik nie ma nazw i dodatkowo nie jest otwarty, jądro go usunie. Działający program ma otwarty plik, więc nawet po usunięciu wszystkich nazw plik jest nadal dostępny.Zastanawiam się, jak aplikacje typu Killer, takie jak Thunderbird lub Firefox, można aktualizować za pomocą menedżera pakietów systemowych, gdy są one nadal uruchomione? Cóż, mogę ci powiedzieć, że to naprawdę nie działa dobrze ... Miałem Firefoksa dość okropnie, gdybym zostawił otwarty, gdy działała aktualizacja pakietu. Czasami musiałem go zabijać z dużą siłą i uruchamiać ponownie, ponieważ był tak zepsuty, że nawet nie mogłem go poprawnie zamknąć.
Co dzieje się ze starym kodem podczas ich aktualizacji? Zwykle w systemie Linux program jest ładowany do pamięci, więc plik wykonywalny na dysku nie jest potrzebny ani używany podczas działania programu. W rzeczywistości możesz nawet usunąć plik wykonywalny, a program nie powinien się tym przejmować ... Jednak niektóre programy mogą wymagać pliku wykonywalnego, a niektóre systemy operacyjne (np. Windows) zablokują plik wykonywalny, zapobiegając usunięciu lub nawet zmianie nazw / przeniesień, podczas gdy program działa. Firefox się psuje, ponieważ jest dość skomplikowany i korzysta z wielu plików danych, które mówią mu, jak zbudować GUI (interfejs użytkownika). Podczas aktualizacji pakietu pliki te są nadpisywane (aktualizowane), więc kiedy starszy plik wykonywalny Firefoksa (w pamięci) próbuje użyć nowych plików GUI, mogą się zdarzyć dziwne rzeczy ...
Co muszę zrobić, gdy chcę napisać program, który aktualizuje się podczas działania? Istnieje już wiele odpowiedzi na twoje pytanie. Sprawdź to: /programming/232347/how-should-i-implement-an-auto-updater Przy okazji, pytania o programowanie są lepsze na StackOverflow.
źródło