diretório tar para enviar apenas blocos modificados de arquivos

2

Estrutura de diretórios profunda e complexa pode ser modificada: arquivos podem ser movidos (prefixo alterado) e simultaneamente o conteúdo dos arquivos pode ser alterado parcialmente.

Eu quero diminuir uma quantidade de dados para transmitir pela rede.

rsync trabalha com pedaços de dados de tamanho 4k (se bem me lembro).

Posso usar algum tipo de concatenação ( tar -like) preservando meta informações sobre estrutura do sistema de arquivos e atributos, o que coloca o conteúdo do arquivo iniciando a partir de deslocamentos de múltiplos bytes de 4k para cada próximo arquivo para habilitar rsync algoritmo vantagens ?

O problema que quero resolver é a omissão de rsync : não é possível detectar se o conteúdo do arquivo foi alterado e o arquivo foi movido ao mesmo tempo entre as sincronizações para usar blocos correspondentes de arquivos de destino para reduzir a transferência de dados.

    
por Orient 13.12.2017 / 15:10

3 respostas

2

Com base na sua sugestão em um comentário (que deve estar na sua pergunta), isso parece ser o que você quer

cd /path/to/directory
tar cf /var/tmp/directory.tar .
rsync -azv /var/tmp/directory.tar remote:/var/tmp/directory.tar
ssh remote 'cd /path/to/destination && tar xf /var/tmp/directory.tar'

Você precisa de espaço suficiente para armazenar directory.tar em ambos os lados.

Já me perguntaram se essa solução aparentemente trivial pode funcionar na situação em que uma pequena quantidade, como um único byte, é adicionada (ou removida) do início do arquivo tar.

Espero que esta amostra mostre como rsync é bom em lidar com tais situações. Ele funciona melhor se você tiver um login de equivalência (chave de certificado) para o servidor remoto, de modo que nenhum tempo seja gasto inserindo uma senha.

# Generate some data
dd iflag=fullblock bs=1M count=200 </dev/urandom >200M.dat

# See how long it takes to transfer
time rsync -av 200M.dat remote:

# See how long it takes to transfer "nothing"
time rsync -av 200M.dat remote:

# Generate one byte of data and prepend it to another data file
dd bs=1 count=1 </dev/urandom >1b.dat
cat 1b.dat 200M.dat >200M1b.dat

# Copy the new file across to the original target
time rsync -av 200M1b.dat remote:200M.dat

# Clean up
rm 1b.dat 200M.dat 200M1b.dat
ssh remote rm 200M.dat

Se o algoritmo puder manipular o byte único inserido no início do fluxo de dados, a transferência deverá demorar alguns instantes. Se não puder, você esperaria que o tempo de transferência fosse amplamente semelhante ao primeiro.

    
por 13.12.2017 / 22:38
1

Aqui está outra sugestão para você. A hrsync tool , que encontrei no GitHub, parece ser muito boa em manter uma memória de arquivos quando você renomeia ou movê-los entre diretórios de uma árvore de fontes.

  • Ele pode rastrear movimentos e edições em arquivos dentro da árvore de origem
  • É um script de shell e não requer privilégios administrativos para instalar no sistema de origem, embora colocá-lo em /usr/local/bin tenha vantagens
  • Requer que sistemas locais e remotos tenham um sistema de arquivos capaz de lidar com hard links
  • Não é possível rastrear alterações em um arquivo em que esse arquivo é renomeado e substituído (ou seja, excluído e depois recriado, em vez de editado no local)

Exemplo

hrsync /path/to/directory/ remote:/path/to/destination/
    
por 15.12.2017 / 11:02
0

Eu encontrei a solução usando apenas bash e utilitários de linha de comando. É possível otimizar a solução: classifique os arquivos por tamanho em ordem crescente e coloque tantos arquivos pequenos quanto possível em cada pedaço (problema da mochila aqui =), mas seria overengineering):

pack.bash :

#! /usr/bin/env bash

set -e

[[ -d "$1" ]]
[[ -d "$( dirname '$2' )" ]]

BLOB="$2.blob"
FSIZES="$2.sizes"
OFFSET=0

shopt -s globstar
for f in "$1"/* "$1"/**/*
do
    if [[ -f "$f" ]]
    then
        SIZE=$( stat -c %s "$f" )
        echo "$SIZE" >> "$FSIZES"
        COUNT=$(( ($SIZE + 4096 - 1) / 4096 ))
        dd if="$f" of="$BLOB" bs=4096 seek=$OFFSET count=$COUNT conv=notrunc
        OFFSET=$(( $COUNT + $OFFSET ))
    fi
done

cp --recursive --archive --attributes-only "$1" "$2.dir"
XZ_OPT="-9e --threads=$(( $( nproc ) + 1 ))" tar cpJf "$2.tar.xz" -C "$2.dir" .
rm --recursive "$2.dir"

unpack.bash :

#! /usr/bin/env bash

set -e

BLOB="$2.blob"
FSIZES="$2.sizes"

[[ -f "$BLOB" ]]
[[ -f "$FSIZES" ]]

mkdir --parents "$1"
[[ ! "$( ls -A '$1' )" ]]

tar xpJf "$2.tar.xz" -C "$1"

SIZES=($( < "$FSIZES" ))

i=0
OFFSET=0
shopt -s globstar
for f in "$1"/* "$1"/**/*
do
    if [[ -f "$f" ]]
    then
        SIZE=${SIZES[i]}
        dd if="$BLOB" of="$f" bs=4096 skip=$OFFSET count=$SIZE iflag=count_bytes
        OFFSET=$(( $OFFSET + ($SIZE + 4096 - 1) / 4096 ))
        i=$(( $i + 1 ))
    fi
done
    
por 14.12.2017 / 10:20