¿Cómo es posible realizar una actualización en vivo mientras se ejecuta un programa?

¿Cómo es posible realizar una actualización en vivo mientras se ejecuta un programa?

Me pregunto cómo se pueden actualizar aplicaciones geniales como Thunderbird o Firefox a través del administrador de paquetes del sistema mientras aún se están ejecutando. ¿Qué pasa con el código antiguo mientras se actualizan? ¿Qué tengo que hacer cuando quiero escribir un programa a.out que se actualice solo mientras se está ejecutando?

Respuesta1

Reemplazo de archivos en general

Primero, existen varias estrategias para reemplazar un archivo:

  1. Abiertoel archivo existente para escribir, truncarlo a 0 de longitud y escribir el nuevo contenido. (Una variante menos común es abrir el archivo existente, sobrescribir el contenido antiguo con el contenido nuevo, truncar el archivo a la nueva longitud si es más corto). En términos de Shell:

    echo 'new content' >somefile
    
  2. Eliminarel archivo antiguo y cree un archivo nuevo con el mismo nombre. En términos de cáscara:

    rm somefile
    echo 'new content' >somefile
    
  3. Escriba en un nuevo archivo con un nombre temporal, luegomoverel nuevo archivo al nombre existente. La medida elimina el archivo antiguo. En términos de cáscara:

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

No enumeraré todas las diferencias entre las estrategias, solo mencionaré algunas que son importantes aquí. Con la estrategia 1, si algún proceso está utilizando actualmente el archivo, el proceso ve el nuevo contenido a medida que se actualiza. Esto puede causar cierta confusión si el proceso espera que el contenido del archivo siga siendo el mismo. Tenga en cuenta que esto se trata solo de procesos que tienen el archivo abierto (como se ve en lsofo en ; las aplicaciones interactivas que tienen un documento abierto (por ejemplo, abrir un archivo en un editor) generalmente no mantienen el archivo abierto, cargan el contenido del archivo durante el proceso. operación de “abrir documento” y reemplazan el archivo (usando una de las estrategias anteriores) durante la operación de “guardar documento”./proc/PID/fd/

Con las estrategias 2 y 3, si algún proceso tiene el archivo somefileabierto, el archivo antiguo permanece abierto durante la actualización del contenido. Con la estrategia 2, el paso de eliminar el archivo en realidad solo elimina la entrada del archivo en el directorio. El archivo en sí sólo se elimina cuando no tiene ninguna entrada de directorio que conduzca a él (en los sistemas de archivos Unix típicos, puede habermás de una entrada de directorio para el mismo archivo)yningún proceso lo tiene abierto. Aquí hay una manera de observar esto: el archivo solo se elimina cuando sleepse finaliza el proceso ( rmsolo se elimina su entrada de directorio).

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

Con la estrategia 3, el paso de mover el nuevo archivo al nombre existente elimina la entrada del directorio que conduce al contenido antiguo y crea una entrada de directorio que conduce al contenido nuevo. Esto se hace en una operación atómica, por lo que esta estrategia tiene una gran ventaja: si un proceso abre el archivo en cualquier momento, verá el contenido antiguo o el contenido nuevo; no hay riesgo de que se mezcle contenido o de que el archivo no funcione. existente.

Reemplazo de ejecutables

Si prueba la estrategia 1 con un ejecutable en ejecución en Linux, obtendrá un error.

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

Un "archivo de texto" significa un archivo que contiene código ejecutable.por oscuras razones históricas. Linux, como muchas otras variantes de Unix, se niega a sobrescribir el código de un programa en ejecución; algunas variantes de Unix lo permiten, lo que provoca fallos a menos que el nuevo código sea una modificación muy bien pensada del código antiguo.

En Linux, puede sobrescribir el código de una biblioteca cargada dinámicamente. Es probable que provoque un bloqueo del programa que lo está utilizando. (Es posible que no pueda observar esto sleepporque carga todo el código de biblioteca que necesita cuando se inicia. Pruebe con un programa más complejo que haga algo útil después de dormir, como perl -e 'sleep 9; print lc $ARGV[0]'.)

Si un intérprete está ejecutando un script, el intérprete abre el archivo del script de forma normal, por lo que no hay protección contra la sobrescritura del script. Algunos intérpretes leen y analizan todo el guión antes de comenzar a ejecutar la primera línea, otros leen el guión según sea necesario. Ver¿Qué sucede si edita un script durante la ejecución?y¿Cómo trata Linux los scripts de shell?para más detalles.

Las estrategias 2 y 3 también son seguras para los ejecutables: aunque los ejecutables en ejecución (y las bibliotecas cargadas dinámicamente) no son archivos abiertos en el sentido de que tienen un descriptor de archivo, se comportan de una manera muy similar. Mientras algún programa esté ejecutando el código, el archivo permanecerá en el disco incluso sin una entrada de directorio.

Actualizar una aplicación

La mayoría de los administradores de paquetes utilizan la estrategia 3 para reemplazar archivos, debido a la principal ventaja mencionada anteriormente: en cualquier momento, abrir el archivo conduce a una versión válida del mismo.

Donde las actualizaciones de aplicaciones pueden fallar es que, si bien la actualización de un archivo es atómica, la actualización de la aplicación en su conjunto no lo es si la aplicación consta de varios archivos (programa, bibliotecas, datos,…). Considere la siguiente secuencia de eventos:

  1. Se inicia una instancia de la aplicación.
  2. La aplicación está actualizada.
  3. La aplicación de instancia en ejecución abre uno de sus archivos de datos.

En el paso 3, la instancia en ejecución de la versión anterior de la aplicación abre un archivo de datos de la nueva versión. Si esto funciona o no depende de la aplicación, de qué archivo se trata y cuánto se ha modificado el archivo.

Después de una actualización, observará que el programa anterior todavía se está ejecutando. Si desea ejecutar la nueva versión, deberá salir del programa anterior y ejecutar la nueva versión. Los administradores de paquetes generalmente eliminan y reinician demonios en una actualización, pero dejan en paz las aplicaciones del usuario final.

Algunos demonios tienen procedimientos especiales para manejar las actualizaciones sin tener que cerrar el demonio y esperar a que se reinicie la nueva instancia (lo que provoca una interrupción del servicio). Esto es necesario en el caso deen eso, que no se puede matar; Los sistemas de inicio proporcionan una forma de solicitar que la instancia en ejecución llameexecvepara reemplazarse con la nueva versión.

Respuesta2

La actualización se puede ejecutar mientras se ejecuta el programa, pero el programa en ejecución que ve es en realidad la versión anterior. El binario antiguo permanece en el disco hasta que cierre el programa.

Explicación:En los sistemas Linux, un archivo es sólo un inodo, que puede tener varios enlaces. P.ej. Lo /bin/bashque ves es solo un enlace inode 3932163en mi sistema. Puede encontrar a qué inodo se vincula algo emitiendo ls --inode /pathen el enlace. Un archivo (inodo) solo se elimina si no hay enlaces que apunten a él y ningún programa lo utiliza. Cuando el administrador de paquetes actualiza, por ejemplo. /usr/bin/firefox, primero se desvincula (elimina el enlace físico /usr/bin/firefox), luego crea un nuevo archivo llamado /usr/bin/firefoxque es un enlace físico a un inodo diferente (el que contiene la nueva firefoxversión). El inodo antiguo ahora está marcado como libre y se puede reutilizar para almacenar nuevos datos, pero permanece en el disco (los inodos sólo se crean cuando construye su sistema de archivos y nunca se eliminan). En el próximo inicio de firefox, se utilizará el nuevo.

Si desea escribir un programa que se "actualice" mientras se ejecuta, la única solución posible que se me ocurre es verificar periódicamente la marca de tiempo de su propio archivo binario y, si es más reciente que la hora de inicio del programa, recargarlo.

Respuesta3

Me pregunto cómo se pueden actualizar aplicaciones excelentes como Thunderbird o Firefox a través del administrador de paquetes del sistema mientras aún se están ejecutando. Bueno, puedo decirles que esto realmente no funciona bien... Firefox se me rompió terriblemente si lo dejé abierto mientras se ejecutaba una actualización de paquete. A veces tuve que apagarlo a la fuerza y ​​reiniciarlo, porque estaba tan roto que ni siquiera podía cerrarlo correctamente.

¿Qué pasa con el código antiguo mientras se actualizan? Normalmente en Linux un programa se carga en la memoria, por lo que el ejecutable en el disco no es necesario ni utilizado mientras el programa se está ejecutando. De hecho, incluso puedes eliminar el ejecutable y al programa no debería importarle... Sin embargo, algunos programas pueden necesitar el ejecutable, y ciertos sistemas operativos (como Windows) bloquearán el archivo ejecutable, evitando su eliminación o incluso renombrando/moviendo, mientras que el El programa se está ejecutando. Firefox falla porque en realidad es bastante complejo y utiliza un montón de archivos de datos que le indican cómo construir su GUI (interfaz de usuario). Durante la actualización de un paquete, estos archivos se sobrescriben (actualizan), por lo que cuando un ejecutable antiguo de Firefox (en la memoria) intenta utilizar los nuevos archivos GUI, pueden suceder cosas raras...

¿Qué tengo que hacer cuando quiero escribir un programa a.out que se actualice solo mientras se está ejecutando? Ya hay muchas respuestas a tu pregunta. Mira esto: https://stackoverflow.com/questions/232347/how-should-i-implement-an-auto-updater Por cierto, las preguntas sobre programación se resuelven mejor en StackOverflow.

información relacionada