Puedes usar el --link-dest=
opción. Básicamente, crearía una nueva carpeta, todos los archivos están vinculados a la nueva. Cuando todo esté listo, puede cambiar los nombres de las carpetas y eliminar la anterior.
Es imposible hacer esto 100% atómico en Linux ya que no hay soporte de kernel/VFS para ello. Sin embargo, cambiar los nombres en realidad está a solo 2 llamadas del sistema, por lo que debería tomar menos de 1 segundo completarlo. Solo es posible en Darwin (MAC/OSX) con la llamada al sistema de intercambio de datos en sistemas de archivos HFS.
Hago algo similar con rsync
copias de seguridad [al disco] y encontré el mismo problema debido a que un demonio actualizaba los archivos mientras se ejecutaba la copia de seguridad.
A diferencia de muchos programas, rsync tiene muchos diferentes códigos de error [Ver la parte inferior de la página del manual]. De interés son dos:
23 -- transferencia parcial por error
24 -- transferencia parcial debido a la desaparición de los archivos de origen
Cuando rsync está realizando una transferencia y se encuentra con una de estas situaciones, no se detiene de inmediato. Se salta y continúa con los archivos que puede transferir. Al final, presenta el código de retorno.
Entonces, si obtiene el error 23/24, simplemente vuelva a ejecutar rsync. Las ejecuciones subsiguientes serán mucho más rápidas, generalmente solo transfiriendo los archivos faltantes de la ejecución anterior. Eventualmente, obtendrá [o debería obtener] una carrera limpia.
En cuanto a ser atómico, utilizo un directorio "tmp" durante la transferencia. Luego, cuando la ejecución de rsync está limpia, le cambio el nombre [atómicamente] a <date>
También uso el --link-dest
opción, pero la uso para mantener copias de seguridad delta (por ejemplo, --link-dest=yesterday
para diario)
Aunque no lo he usado yo mismo, el --partial-dir=DIR
puede evitar que los archivos ocultos abarroten el directorio de copia de seguridad. Asegúrese de que DIR esté en el mismo sistema de archivos que su directorio de copia de seguridad para que los cambios de nombre sean atómicos
Mientras hago esto en perl, escribí un script que resume lo que he estado diciendo con un poco más de detalle/precisión para su situación particular. Tiene una sintaxis similar a tcsh, [no probada y un poco tosca], pero trátelo como un pseudocódigo para escribir su propio bash
, perl
, python
guión como usted elija. Tenga en cuenta que no tiene límite de reintentos, pero puede agregarlo fácilmente, según sus deseos.
#!/bin/tcsh -f
# repo_backup -- backup repos even if they change
#
# use_tmp -- use temporary destination directory
# use_partial -- use partial directory
# use_delta -- make delta backup
# set remote server name ...
set remote_server="..."
# directory on server for backups
set backup_top="/path_to_backup_top"
set backup_backups="$backup_top/backups"
# set your rsync options ...
set rsync_opts=(...)
# keep partial files from cluttering backup
set server_partial=${remote_server}:$backup_top/partial
if ($use_partial) then
set rsync_opts=($rsync_opts --partial-dir=$server_partial)
endif
# do delta backups
if ($use_delta) then
set latest=(`ssh ${remote_server} ls $backup_backups | tail -1`)
# get latest
set delta_dir="$backup_backups/$latest"
if ($#latest > 0) then
set rsync_opts=($rsync_opts --link-dest=${remote_server}:$delta_dir)
endif
endif
while (1)
# get list of everything to backup
# set this to whatever you need
cd /local_top_directory
set transfer_list=(.)
# use whatever format you'd like
set date=`date +%Y%m%d_%H%M%S`
set server_tmp=${remote_server}:$backup_top/tmp
set server_final=${remote_server}:$backup_backups/$date
if ($use_tmp) then
set server_transfer=$server_tmp
else
set server_transfer=$server_final
endif
# do the transfer
rsync $rsync_opts $transfer_list $server_transfer
set code=$status
# run was clean
if ($code == 0) then
# atomically install backup
if ($use_tmp) then
ssh ${remote_server} mv $backup_top/tmp $backup_backups/$date
endif
break
endif
# partial -- some error
if ($code == 23) then
continue
endif
# partial -- some files disappeared
if ($code == 24) then
continue
endif
echo "fatal error ..."
exit(1)
end