file-io - transaction - data consistency
Implementación de escrituras de archivos atómicos en un sistema de archivos no transaccional (2)
Solo hay una cosa que debes asumir, renombrar un archivo es operación atómica
Entonces, los siguientes pasos asegurarán la corrección (al menos en Unix como el sistema operativo)
- Escribir nuevo contenido en un archivo temporal Nuevo
- cambiar el nombre del archivo temporal a nombre original
De esta forma, si la aplicación falla al reiniciarse, obtén el contenido anterior o nuevo sin necesidad de código adicional.
Muchos sistemas de archivos comunes no ofrecen operaciones atómicas, pero escribir archivos de manera atómica es muy importante en ciertos escenarios. Traté de encontrar una solución para este problema.
Hice las siguientes suposiciones:
- El sistema de archivos en uso soporta operaciones atómicas a nivel de inodo (por ejemplo, NTFS). Esto significa que mover y eliminar son atómicos.
- Solo el programa en sí accede a los archivos.
- Solo hay 1 instancia del programa a la vez y actúa de una sola vez.
- Para simplificar, el contenido del archivo completo se escribe cada vez (es decir, escribir truncado).
Esto deja el siguiente problema: Al escribir un archivo, el programa podría interrumpirse y al archivo le quedaría solo una parte del contenido para escribir.
Propongo el siguiente proceso:
- Escribir nuevo contenido en un archivo temporal Nuevo
- Mueva el archivo original Original a una ubicación temporal Copia de seguridad
- Mover nuevo al original
- Eliminar copia de seguridad
Los archivos nuevos y de respaldo se distinguen de los archivos originales (por ejemplo, podrían tener el prefijo diferente, o podrían estar en un directorio separado en el mismo volumen). Al mismo tiempo, su nombre debe corresponder directamente con el original correspondiente (por ejemplo, simplemente usando el mismo nombre de archivo).
Esto, sin embargo, no hace que la operación sea atómica todavía. El proceso podría interrumpirse los pasos 1, 2, 3 o 4:
- Deja un Nuevo potencialmente incompleto.
- Move es atómico, pero el archivo de destino ahora está perdido. Tanto el nuevo como el respaldo existen y están completos.
- Move es atómico, pero hay una copia de seguridad no utilizada. El Original fue reemplazado por el Nuevo contenido
- La eliminación es atómica.
Usando las suposiciones 2 y 3 de antes, el programa debe reiniciarse después de un bloqueo. Durante el proceso de inicio, debe realizar estas comprobaciones de recuperación:
- Si existe New , pero Backup no funciona, fallamos en o después del paso 1. Eliminar New ya que podría estar incompleto.
- Si existe New y Backup también, colapsamos después del paso 2. Continúe con el paso 3.
- Si Backup existe pero New no lo hace, también fallamos después del paso 3. Continúe con el paso 4.
El proceso de recuperación en sí, solo usando operaciones atómicas, simplemente continuará donde lo dejó después de ser interrumpido.
Creo que esta idea asegura escrituras atómicas para un solo programa. Estos problemas existen aún:
- Cuando se utilizan varias instancias del mismo programa, existe una interferencia del proceso de recuperación con las grabaciones de archivos actualmente en curso en el otro programa.
- Los programas externos que solo leen pero nunca escriben normalmente obtendrán el resultado correcto, pero si hay una operación de escritura en la entrada solicitada al mismo tiempo, es posible que no encuentren entradas incorrectamente.
Esos problemas (que son excluidos por las suposiciones anteriores) podrían resolverse a través de la política de uso (por ejemplo, verificar otras instancias y denegar el acceso de directorio a otros usuarios).
Finalmente, mi pregunta: ¿Eso tiene sentido o hay un defecto en el proceso? ¿Hay algún problema que impida que este enfoque se use en la práctica?
Sus pasos se pueden simplificar aún más:
- Escribir nuevo contenido en un archivo temporal Nuevo
- Eliminar archivo original
- Mover nuevo al original
En el arranque:
- Si Original no existe pero New lo hace, el proceso se interrumpió antes del paso 3, mueva Nuevo a Original.
- Si Original y Nuevo ambos existen, el proceso se interrumpió antes del paso 2, elimine Nuevo.
Lo he usado en la administración de archivos de configuración y nunca he encontrado un problema en este proceso.