Wie ist es möglich, ein Live-Update durchzuführen, während ein Programm läuft?

Wie ist es möglich, ein Live-Update durchzuführen, während ein Programm läuft?

Ich frage mich, wie man Killer-Anwendungen wie Thunderbird oder Firefox über den Paketmanager des Systems aktualisieren kann, während sie noch laufen. Was passiert mit dem alten Code während der Aktualisierung? Was muss ich tun, wenn ich ein Programm a.out schreiben möchte, das sich während der Ausführung selbst aktualisiert?

Antwort1

Ersetzen von Dateien im Allgemeinen

Erstens gibt es mehrere Strategien zum Ersetzen einer Datei:

  1. Offendie vorhandene Datei zum Schreiben, kürzen Sie sie auf die Länge 0 und schreiben Sie den neuen Inhalt. (Eine weniger gebräuchliche Variante besteht darin, die vorhandene Datei zu öffnen, den alten Inhalt mit dem neuen Inhalt zu überschreiben und die Datei auf die neue Länge zu kürzen, wenn sie kürzer ist.) In Shell-Begriffen:

    echo 'new content' >somefile
    
  2. Entfernendie alte Datei und erstellen Sie eine neue Datei mit demselben Namen. In Shell-Begriffen:

    rm somefile
    echo 'new content' >somefile
    
  3. Schreiben Sie in eine neue Datei unter einem temporären Namen, dannbewegendie neue Datei auf den bestehenden Namen. Beim Verschieben wird die alte Datei gelöscht. In Shell-Begriffen:

    echo 'new content' >somefile.new
    mv somefile.new somefile
    

Ich werde nicht alle Unterschiede zwischen den Strategien auflisten, sondern nur einige erwähnen, die hier wichtig sind. Bei Strategie 1 sieht ein Prozess, der die Datei gerade verwendet, den neuen Inhalt, während er aktualisiert wird. Dies kann zu Verwirrung führen, wenn der Prozess erwartet, dass der Dateiinhalt gleich bleibt. Beachten Sie, dass dies nur Prozesse betrifft, die die Datei geöffnet haben (wie in lsofoder in sichtbar ); interaktive Anwendungen, die ein Dokument geöffnet haben (z. B. Öffnen einer Datei in einem Editor), lassen die Datei normalerweise nicht geöffnet, sondern laden den Dateiinhalt während des Vorgangs „Dokument öffnen“ und ersetzen die Datei (mit einer der oben genannten Strategien) während des Vorgangs „Dokument speichern“./proc/PID/fd/

Bei den Strategien 2 und 3 somefilebleibt die alte Datei während der Inhaltsaktualisierung geöffnet, wenn ein Prozess die Datei geöffnet hat. Bei Strategie 2 wird beim Entfernen der Datei tatsächlich nur der Eintrag der Datei im Verzeichnis entfernt. Die Datei selbst wird nur entfernt, wenn kein Verzeichniseintrag zu ihr führt (auf typischen Unix-Dateisystemen kann esmehrere Verzeichniseinträge für dieselbe Datei)Undkein Prozess hat sie geöffnet. So können Sie dies beobachten: Die Datei wird nur entfernt, wenn der sleepProzess beendet wird ( rmentfernt nur seinen Verzeichniseintrag).

echo 'old content' >somefile
sleep 9999999 <somefile &
df .
rm somefile
df .
cat /proc/$!/fd/0
kill $!
df .

Bei Strategie 3 wird beim Verschieben der neuen Datei auf den vorhandenen Namen der Verzeichniseintrag entfernt, der zum alten Inhalt führt, und ein Verzeichniseintrag erstellt, der zum neuen Inhalt führt. Dies geschieht in einer einzigen atomaren Operation, sodass diese Strategie einen großen Vorteil bietet: Wenn ein Prozess die Datei zu irgendeinem Zeitpunkt öffnet, sieht er entweder den alten oder den neuen Inhalt – es besteht keine Gefahr, dass gemischte Inhalte angezeigt werden oder die Datei nicht vorhanden ist.

Ersetzen ausführbarer Dateien

Wenn Sie Strategie 1 mit einer laufenden ausführbaren Datei unter Linux versuchen, wird eine Fehlermeldung angezeigt.

cp /bin/sleep .
./sleep 999999 &
echo oops >|sleep
bash: sleep: Text file busy

Eine „Textdatei“ ist eine Datei, die ausführbaren Code enthältaus unklaren historischen Gründen. Linux weigert sich wie viele andere Unix-Varianten, den Code eines laufenden Programms zu überschreiben. Einige Unix-Varianten lassen dies zu, was jedoch zu Abstürzen führen kann, sofern der neue Code keine sehr durchdachte Modifikation des alten Codes ist.

Unter Linux können Sie den Code einer dynamisch geladenen Bibliothek überschreiben. Dies führt wahrscheinlich zu einem Absturz des Programms, das die Bibliothek verwendet. (Bei können Sie dies möglicherweise nicht beobachten, sleepda beim Start der gesamte Bibliothekscode geladen wird, den es benötigt. Versuchen Sie es mit einem komplexeren Programm, das nach dem Ruhezustand etwas Nützliches tut, wie z . B. perl -e 'sleep 9; print lc $ARGV[0]'.)

Wenn ein Interpreter ein Skript ausführt, wird die Skriptdatei vom Interpreter auf normale Weise geöffnet, sodass es keinen Schutz vor dem Überschreiben des Skripts gibt. Einige Interpreter lesen und analysieren das gesamte Skript, bevor sie mit der Ausführung der ersten Zeile beginnen, andere lesen das Skript nach Bedarf. SieheWas passiert, wenn Sie ein Skript während der Ausführung bearbeiten?UndWie geht Linux mit Shell-Skripten um?für mehr Details.

Die Strategien 2 und 3 sind auch für ausführbare Dateien sicher: Obwohl laufende ausführbare Dateien (und dynamisch geladene Bibliotheken) keine offenen Dateien im Sinne eines Dateideskriptors sind, verhalten sie sich sehr ähnlich. Solange ein Programm den Code ausführt, bleibt die Datei auch ohne Verzeichniseintrag auf der Festplatte.

Aktualisieren einer Anwendung

Die meisten Paketmanager verwenden Strategie 3 zum Ersetzen von Dateien, da diese den oben genannten großen Vorteil bietet: Das Öffnen der Datei führt zu jedem Zeitpunkt zu einer gültigen Version davon.

Anwendungsupgrades können dadurch scheitern, dass das Upgrade einer Datei zwar atomar ist, das Upgrade der gesamten Anwendung jedoch nicht, wenn die Anwendung aus mehreren Dateien besteht (Programm, Bibliotheken, Daten usw.). Betrachten Sie die folgende Ereignissequenz:

  1. Eine Instanz der Anwendung wird gestartet.
  2. Die Anwendung wird aktualisiert.
  3. Die laufende Instanzanwendung öffnet eine ihrer Datendateien.

In Schritt 3 öffnet die laufende Instanz der alten Anwendungsversion eine Datendatei aus der neuen Version. Ob dies funktioniert, hängt von der Anwendung ab, von welcher Datei es sich handelt und wie stark die Datei geändert wurde.

Nach einem Upgrade werden Sie feststellen, dass das alte Programm noch läuft. Wenn Sie die neue Version ausführen möchten, müssen Sie das alte Programm beenden und die neue Version ausführen. Paketmanager beenden und starten Daemons bei einem Upgrade normalerweise neu, lassen Endbenutzeranwendungen jedoch in Ruhe.

Einige Daemons verfügen über spezielle Verfahren, um Upgrades durchzuführen, ohne den Daemon beenden und auf den Neustart der neuen Instanz warten zu müssen (was zu einer Dienstunterbrechung führen würde). Dies ist erforderlich im Fall vondrin, die nicht beendet werden kann; Init-Systeme bieten eine Möglichkeit, anzufordern, dass die laufende Instanzexecveum sich selbst durch die neue Version zu ersetzen.

Antwort2

Das Upgrade kann ausgeführt werden, während das Programm läuft, aber das laufende Programm, das Sie sehen, ist eigentlich die alte Version davon. Die alte Binärdatei bleibt auf der Festplatte, bis Sie das Programm schließen.

Erläuterung:Auf Linux-Systemen ist eine Datei nur ein Inode, der mehrere Links zu ihm haben kann. Das, was /bin/bashSie sehen, ist z. B. nur ein Link zu inode 3932163auf meinem System. Sie können herausfinden, zu welchem ​​Inode etwas verlinkt, indem Sie ls --inode /pathauf den Link klicken. Eine Datei (Inode) wird nur entfernt, wenn keine Links darauf zeigen und sie von keinem Programm verwendet wird. Wenn der Paketmanager z. B. ein Upgrade durchführt /usr/bin/firefox, hebt er zuerst die Verknüpfung auf (entfernt den Hardlink /usr/bin/firefox), erstellt dann eine neue Datei namens /usr/bin/firefox, die ein Hardlink zu einem anderen Inode ist (dem, der die neue firefoxVersion enthält). Der alte Inode ist nun als frei gekennzeichnet und kann zum Speichern neuer Daten wiederverwendet werden, verbleibt jedoch auf der Festplatte (Inodes werden nur beim Erstellen Ihres Dateisystems erstellt und nie gelöscht). Beim nächsten Start von firefoxwird der neue verwendet.

Wenn Sie ein Programm schreiben möchten, das sich während der Ausführung selbst „aktualisiert“, besteht die einzige Lösung, die mir einfällt, darin, regelmäßig den Zeitstempel der eigenen Binärdatei zu prüfen und sich selbst neu zu laden, wenn dieser neuer ist als die Startzeit des Programms.

Antwort3

Ich frage mich, wie Killeranwendungen wie Thunderbird oder Firefox über den Paketmanager des Systems aktualisiert werden können, während sie noch ausgeführt werden? Nun, ich kann Ihnen sagen, dass das nicht wirklich gut funktioniert ... Bei mir ist Firefox schon ziemlich furchtbar abgestürzt, wenn ich ihn geöffnet gelassen habe, während ein Paketupdate lief. Ich musste ihn manchmal gewaltsam beenden und neu starten, weil er so kaputt war, dass ich ihn nicht einmal richtig schließen konnte.

Was passiert mit dem alten Code während der Aktualisierung? Normalerweise wird ein Programm unter Linux in den Speicher geladen, sodass die ausführbare Datei auf der Festplatte während der Ausführung des Programms weder benötigt noch verwendet wird. Tatsächlich können Sie die ausführbare Datei sogar löschen, ohne dass es dem Programm etwas ausmacht ... Einige Programme benötigen die ausführbare Datei jedoch möglicherweise, und bestimmte Betriebssysteme (wie Windows) sperren die ausführbare Datei, sodass sie nicht gelöscht oder sogar umbenannt/verschiebt werden kann, während das Programm ausgeführt wird. Firefox bricht zusammen, weil es eigentlich ziemlich komplex ist und eine Reihe von Datendateien verwendet, die ihm sagen, wie seine GUI (Benutzeroberfläche) aufgebaut werden soll. Während einer Paketaktualisierung werden diese Dateien überschrieben (aktualisiert). Wenn also eine ältere ausführbare Firefox-Datei (im Speicher) versucht, die neuen GUI-Dateien zu verwenden, können seltsame Dinge passieren ...

Was muss ich tun, wenn ich ein Programm a.out schreiben möchte, das sich während der Ausführung selbst aktualisiert? Es gibt bereits viele Antworten auf Ihre Frage. Schauen Sie sich das hier an: https://stackoverflow.com/questions/232347/wie-sollte-ich-einen-auto-updater-implementieren Fragen zur Programmierung sind übrigens bei StackOverflow besser aufgehoben.

verwandte Informationen