2010-09-21 10 views
14

¿Cuál es la forma correcta de renombrar de forma duradera un archivo en un sistema de archivos POSIX? Específicamente preguntándose sobre fsyncs en los directorios . (Si esto depende de OS/FS, estoy preguntando por Linux y ext3/ext4).¿Cómo renombrar de forma duradera un archivo en POSIX?

Nota: hay otras preguntas sobre stackoverflow sobre cambios de nombre duraderos, pero AFAICT no abordan fsync-ción de los directorios (que es lo que me importa - los datos de archivos Ni siquiera estoy modificando).

Actualmente tengo (en Python):

dstdirfd = open(dstdirpath, O_DIRECTORY|O_RDONLY) 
rename(srcdirpath + '/' + filename, dstdirpath + '/' + filename) 
fsync(dstdirfd) 

preguntas específicas:

  • ¿Esto también implícitamente FSYNC el directorio de origen? ¿O podría terminar con el archivo que aparece en ambos directorios después de un ciclo de encendido (lo que significa que tendría que verificar el recuento del enlace duro y realizar la recuperación de forma manual), es decir, es imposible garantizar una operación de movimiento atómico duradero?
  • Si fsync el directorio de origen en lugar de el directorio de destino, ¿eso también fsync implícitamente el directorio de destino?
  • ¿Hay herramientas de prueba/depuración/aprendizaje relacionadas útiles (inyectores de falla, herramientas de introspección, sistemas de archivos simulacros, etc.)?

Gracias de antemano.

Respuesta

14

POSIX define que la función de cambio de nombre debe ser atómica:

http://pubs.opengroup.org/onlinepubs/009695399/functions/rename.html

Así que si cambia el nombre (A, B), bajo ninguna circunstancia debe ver un estado con el archivo en ambos directorios o en ninguno de los directorios. Siempre habrá exactamente uno, sin importar lo que haga con fsync() o si el sistema falla.

Pero eso no resuelve el problema de asegurarse de que la operación de cambio de nombre() es duradera. POSIX responde a esta pregunta:

Si se define _POSIX_SYNCHRONIZED_IO, la función fsync() obligarán a todos los que están programados operaciones I/O asociados con el archivo indicado por Fildes descriptores de fichero para el estado de finalización de E/S sincronizada. Todas las operaciones de E/S se completarán según lo definido para la integridad de archivo de E/S sincronizada.

(de http://pubs.opengroup.org/onlinepubs/009695399/functions/fsync.html)

Así que si fsync() un directorio, en espera de cambiar el nombre de las operaciones deben ser transferidos al disco por el momento esto devuelve. fsync() de cualquiera de los directorios debería ser suficiente porque la atomicidad de la operación rename() requeriría que los cambios de ambos directorios se sincronicen atómicamente.

Por último, en contraste con la reclamación en el blog mencionado en otra respuesta, la razón de esto explica lo siguiente: Función

El fsync() tiene la intención de forzar una escritura física de los datos de la memoria caché de búfer, y para garantizar que, después de un bloqueo del sistema u otra falla, todos los datos almacenados hasta el momento de la llamada fsync() se graben en el disco. Dado que los conceptos de "memoria caché de búfer", "bloqueo del sistema", "escritura física" y "almacenamiento no volátil" no se definen aquí, la redacción debe ser más abstracta.

Un sistema que pretendían ser compatible con POSIX y que lo consideraban un comportamiento correcto (es decir, no es un error o un fallo de hardware) que efectúe un fsync() y no persistir esos cambios a través de un fallo del sistema tendría que ser tergiversar deliberadamente sí mismo con respecto a la especificación.

(actualizado con información adicional Re: Linux-específicos contra el comportamiento portátil)

+1

El razonamiento aquí es muy incorrecto. - La "atomicidad" de rename(), por ejemplo, se refiere a "newpath", debajo de la cual debe estar el archivo anterior (si hubo uno) o el archivo renombrado, sin estado intermedio (como lo ven otros procesos) . –

+0

Robert lo señaló, el cambio de nombre es "atómico" con respecto a la asignación de un nuevo inodo a su nombre, ya sea que POSIX defina si los nuevos puntos de inode son o no borrados. – ArekBulski

-1

La respuesta a su pregunta dependerá en gran medida del sistema operativo específico que se utilice, el tipo de sistema de archivos utilizado y si la fuente y el destino están en el mismo dispositivo o no.

Comenzaré leyendo la página de manual de cambio de nombre (2) en la plataforma que está utilizando.

+0

Ya he consultado esa página de hombre - nada relevante. ¿Estás diciendo que no hay una forma portátil de cambiar el nombre de los directorios? Estoy dispuesto a creer eso, pero me interesa una declaración más clara y una evidencia ideal que respalde. Además, ¿conoce la respuesta para los recientes Linux 2.6 con ext3/4 (ya que esta pregunta fue etiquetada, también se actualizó el texto principal)? – Yang

+0

Ah ok, más simple si solo es linux y ext3/4 lo que te importa. Una advertencia que menciona la página de manual de cambio de nombre de Linux (2) es: 'Sin embargo, al sobrescribir probablemente haya una ventana en la que tanto oldpath como newpath se refieren al archivo que se cambia de nombre. –

-3

Me suena como que está tratando de hacer el trabajo del sistema de archivos. Si mueve un archivo, el kernel y el sistema de archivos son responsables de la operación atómica y la recuperación de fallas, no su código.

De todos modos, este artículo parece responder a sus preguntas con respecto a fsync: http://blogs.gnome.org/alexl/2009/03/16/ext4-vs-fsync-my-take/

+0

Lea esa publicación antes, y es una de muchas eso me trajo aquí. Específicamente dice: "En caso de un bloqueo del sistema poco después de la escritura, es más probable que obtengamos el nuevo archivo que el anterior (para una mayor posibilidad de esto, también necesita fsync el directorio en el que se encuentra el archivo)". Mi pregunta es acerca de lo que ocurre cuando cambias el nombre de un directorio a otro. – Yang

11

Desafortunadamente la respuesta de Dave es incorrecta.

Es posible que no todos los sistemas POSIX tengan un almacenamiento duradero. Y si lo hacen, todavía se "permite" que se humedezcan las mangueras después de un bloqueo del sistema. Para esos sistemas, una fsync no operativa() tiene sentido, y dicha fsync() está explícitamente permitida en POSIX. También es legal que el archivo sea recuperable en el directorio anterior, en el nuevo directorio, en ambos o en cualquier otra ubicación. POSIX no garantiza las fallas del sistema o las recuperaciones del sistema de archivos.

La verdadera pregunta debería ser:

cómo hacer un cambio de nombre duradera en los sistemas que apoyan que a través de la API POSIX?

que tiene que hacer un fsync() en ambos, la fuente y directorio de destino, debido a que el mínimo los fsync se supone (s) que hacer es persistir cómo directorio de origen o de destino debe ser similar.

¿Una fsync (destdirfd) también fsync implícitamente el directorio de origen?

  • POSIX en general: no, nada implica que
  • ext3/4: No estoy seguro de si ambos cambios a la fuente y el destino dir terminan en la misma transacción en la revista. Si lo hacen, ambos se comprometen juntos.

O puede que terminar con el archivo aparecer en ambos directorios después de un ciclo de potencia (“crash”), es decir que es imposible garantizar una operación de movimiento de forma duradera atómica?

  • POSIX en general: no hay garantías, pero se supone que fsync() ambos directorios, que podrían no ser atómica duradera
  • ext3/4: la cantidad de fsync() que mínimamente necesita depende de las opciones de montaje. P.ej. si está montado con "dirsync", no necesita ninguno de esos dos fsync() s. A lo sumo necesitas ambos fsync() s, pero estoy casi seguro de que uno es suficiente (atómico-durable entonces).

Si fsync el directorio de origen en lugar del directorio de destino, ¿eso también fsync implícitamente el directorio de destino?

  • POSIX: no
  • ext3/4: Realmente creo que ambos terminan en la misma transacción, por lo que no importa cuál de ellos fsync()
  • mayores núcleos ext3: (si no están en la misma transacción) alguna implementación no tan óptima hizo demasiada sincronización en fsync(), apuesto a que cometió cada transacción anterior. Y sí, una implementación normal primero lo vincularía al destino y luego lo eliminaría de la fuente. Por lo tanto, fsync (srcdirfd) también activaría el fsync() del destino.
  • ext4/ext3 última: si no están en la misma transacción, que podría ser capaz de sincronizarlos de manera totalmente independiente (por lo que hacer ambas cosas)

¿Hay algunas herramientas de prueba/depuración/aprendizaje pertinente sobre la (inyectores de fallas, herramientas de introspección, sistemas de archivos simulados, etc.)?

Para un accidente real, no. Por cierto, una caída real va más allá del punto de vista del kernel. El hardware podría reordenar las escrituras (y no escribir todo), corrompiendo el sistema de archivos. Ext4 está mejor preparado contra esto, porque habilita las barries de escritura (opciones de montaje) de manera predeterminada (ext3 no) y puede detectar daños con sumas de verificación de diario (también una opción de montaje).

Y para aprender: descubra si ambos cambios están vinculados de algún modo en el diario. :-P

+1

Este es un punto sutil, pero no estaba argumentando que fsync() de un directorio * implique * fsync() del otro. Fue que fsync() de uno, combinado con la atomicidad de rename(), requiere que * ese cambio específico * del otro directorio también se sincronice con el disco.Podría creer que ese no es el caso, pero esa es mi lectura de la especificación. ¿Tiene alguna referencia para respaldar su interpretación de que la atomicidad no está garantizada durante un choque, incluso si parte del cambio "atómico" fue fsync'd? –

+0

Sí, lo hago: su enlace a [fsync() en opengroup.org] (http://pubs.opengroup.org/onlinepubs/009695399/functions/fsync.html). "Se pretende explícitamente que se permita una implementación nula". Es decir: sin garantías. - Y esa unión deseosa de rename() y fsync() es tu invención. Y no, no es un punto sutil. –

+1

Acordó que los sistemas POSIX no están obligados a hacer que tales cambios sean duraderos, y que la verdadera pregunta es cómo usar la API para hacer que el cambio sea duradero en los sistemas que lo soportan. (Esto parece pedante, ya que la pregunta obviamente presupone que el sistema subyacente lo admite.) Al pedir una referencia, me refería a su afirmación de que incluso en sistemas que * do * admiten cambios de sincronización en el disco, un éxito fsync() de cualquiera de los directorios aún puede dar como resultado que el archivo aparezca en ambos lugares (o en ninguno de ellos) después de un bloqueo. –

Cuestiones relacionadas