reescribe el archivo existente para que sea reemplazado por una nueva versión atómicamente, solo una vez que esté completamente escrito

18

Recuerdo vagamente haber leído en algún lugar que solía haber, en algunos Unices, una forma de abrir un archivo existente para escribir, con una bandera que le pedía al kernel que usara la versión anterior (para que otros procesos accedan a ella para leer), hasta que aparezca "nuevo "la versión estaba completamente escrita (fd cerrado), desde ese momento el archivo apareció como la nueva versión.

En otras palabras, otros procesos vieron la versión anterior, o la nueva, nunca una incompleta.

¿Alguien conocedor puede señalarme una referencia?

eudoxos
fuente
Suena como lo que podría hacer el Plan 9 , pero no.
Gilles 'SO- deja de ser malvado'
2
Suena como Archivos-11 en OpenVMS: "Cada vez que se guarda un archivo, en lugar de sobrescribir la versión existente, se crea un nuevo archivo con el mismo nombre pero con un número de versión incrementado".
Mat
¿Por qué preguntaste? ¿Necesita esa funcionalidad, o fue solo curiosidad?
Nils
1
Estaría feliz de tener esa funcionalidad, y recordé haber leído en alguna parte que existía. Entonces, una mezcla de necesidad y curiosidad.
eudoxos
Todos los sistemas Unix permiten esto de otra manera: cree un nuevo archivo en el mismo directorio, complete con contenido modificado y cambie el nombre atómico. Esto es mucho más costoso para pequeños cambios pero funciona.
Netch

Respuestas:

14

Lo que estás describiendo suena exactamente como un cambio de nombre básico para sobrescribir un archivo.

Cuando cambia el nombre / mueve un archivo encima de otro, el archivo antiguo se desvincula. Lo que significa que el archivo todavía existe, pero ya no está en el árbol del sistema de archivos. Por lo tanto, las aplicaciones antiguas continuarán pudiendo acceder al archivo siempre que lo mantengan abierto. Una vez que todas las aplicaciones han cerrado el archivo anterior, entonces no está asignado en el disco.

La renamellamada al sistema es una operación atómica. Para hacer esto, debe crear un nuevo archivo con un nombre diferente y luego llamar renamepara cambiar el nombre del archivo temporal como el que desea reemplazar. Como la operación es atómica, no hay absolutamente ningún período en el que falte el archivo. Al instante pasa del archivo antiguo al archivo nuevo.
Sin embargo, tenga en cuenta que el archivo temporal y el archivo que se va a reemplazar deben residir en el mismo punto de montaje.

Patricio
fuente
Solo puede usar eso si su programa está escrito específicamente con la funcionalidad en mente. En este caso, sin embargo, era una característica del sistema operativo, de donde incluso los programas regulares recibieron automáticamente esta semántica atómica.
eudoxos
1
@eudoxos tu comentario no tiene sentido. Estás diciendo que los programas tendrían que escribirse específicamente para hacer el renameintercambio. Incluso si existiera una 'característica del sistema operativo' de la que está hablando, el programa también tendría que escribirse para aprovechar eso también. ¿Cual es la diferencia?
Patrick
Hay una diferencia si pasa una bandera (posiblemente no compatible) a la openllamada al sistema o si tiene que hacer lo que describe a mano.
eudoxos
Tenga en cuenta que para mantener la versión antigua o la nueva totalmente escrita en caso de un bloqueo, debe sincronizar adicionalmente el nuevo archivo al disco con fsync o similar
texthell
@textshell sin la sincronización, aún obtienes atomicidad ... pero no durabilidad ... ¿correcto? No entiendo el argumento en goo.gl/qfQQfy en este caso. En mi caso, tengo un sistema bajo carga extrema y quiero evitar los enjuagues del sistema de archivos y no me importa si el archivo sobrevive a un bloqueo.
wcochran
6

Como Patrick escribe , la forma habitual de hacer esto es escribir la nueva versión en un archivo separado y, cuando termine, cambie el nombre de la nueva versión al antiguo nombre de archivo, sobrescribiéndola atómicamente. Esta segunda operación se llama sobrescribir por cambio de nombre .

Ahora, algunas referencias:

Caracol mecánico
fuente
man 3p renameme dice que renamees atómico, y supongo que está destinado a todos los sistemas de archivos Linux. Y cuando leí el primer artículo que vinculaste, sigo pensando que las operaciones de cambio de nombre de Btrfs son atómicas.
hagello
1

Esto me recuerda a Allocate On Flush . Cuando un sistema de archivos usa esta función, en lugar de escribir datos directamente en el disco, resta el tamaño de los datos que se escribirán en el contador de espacio libre del disco y retiene los datos en la memoria hasta que se realiza una llamada al sistema de sincronización o el núcleo decide para limpiar los tampones sucios.

En este caso, si un archivo está modificando el archivo y otro proceso lo abre, este último proceso "verá" la versión del archivo sin modificar ( o "antigua" si lo prefiere ).

Por supuesto, lo anterior es teórico y depende de varios factores, y diría que es un poco impredecible, ya que no sabe exactamente cuándo el núcleo va a enjuagar las páginas sucias. Por ejemplo, en Linux ( como también puede leer en la sección 15.3 de Comprensión del kernel de Linux ), las páginas sucias se escriben en el disco bajo las siguientes condiciones:

  • El caché de la página se llena demasiado y se necesitan más páginas, o la cantidad de páginas sucias se vuelve demasiado grande.

  • Ha transcurrido demasiado tiempo desde que una página se mantuvo sucia.

  • Un proceso solicita que se vacíen todos los cambios pendientes de un dispositivo de bloque o de un archivo en particular; lo hace invocando una llamada al sistema sync (), fsync () o fdatasync ().

Se sabe que esta característica se implementa en los sistemas de archivos HFS +, XFS, Reiser4, ZFS, Btrfs y ext4.

dkaragasidis
fuente
2
Lo que describe es una técnica de sistema de archivos que debería ser invisible desde el espacio del usuario (y por lo tanto no hace lo que usted indica) en los sistemas POSIX (archivo) (vea escribir : "Si se puede probar una lectura () de los datos del archivo (por cualquier medio) para que ocurra después de una escritura () de los datos, debe reflejar esa escritura (), incluso si las llamadas son realizadas por diferentes procesos "). Otros procesos no verán los datos antiguos (en POSIX).
Mat
Gracias por la corrección. Creo que mi comprensión de esta técnica del sistema de archivos fue incorrecta.
dkaragasidis
Bien, esto se ve como algo más. Recuerdo vagamente ahora que fue en una entrevista con RMS que mencionó esta característica, tal vez fue un viejo sistema arcano que nunca vivió fuera de la academia ... Gracias de todos modos.
eudoxos