tarディレクトリは変更されたファイルブロックのみを送信します。

tarディレクトリは変更されたファイルブロックのみを送信します。

深く複雑なディレクトリ構造を変更できます。ファイルを移動(プレフィックス変更)したり、ファイルの内容を部分的に変更したりできます。

ネットワーク経由で送信されるデータ量を減らしたいです。

rsync4kサイズのブロックで動作します(私の記憶が正しい場合)。

tarファイルシステムの構造と属性に関するメタ情報を保存し、次の各ファイルの複数の4 KBオフセットからファイルの内容を開始してrsyncアルゴリズムの利点を得るために、ある種の接続(類似)を使用できますか?

私が解決したい問題はありませんrsync。ファイルの内容が変更されたか、ファイルが同期間で同時に移動されたかを検出して、データ転送を減らすためにターゲットファイルの一致ブロックを使用するかどうかを検出できません。

答え1

あなたの意見にあなたの提案(実際にあなたの質問になければならない)によると、これはあなたが望むようです。

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'

directory.tar収納には両側に十分なスペースが必要です。


tarファイルの先頭に少量のコンテンツ(シングルバイトなど)を追加(または削除)すると、マイナーに見えるこのソリューションが機能するかどうかを尋ねられました。

この例では、rsyncこのような状況をどれだけうまく処理できるかを示すことを願っています。これは、リモートサーバーへの同等の(証明書キー)ログインがある場合に最適です。パスワードを入力するのに時間を費やす必要はありません。

# 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

アルゴリズムがデータストリームの先頭に挿入された単一バイトを処理できる場合、転送には数分しかかかりません。そうでない場合、送信時間は最初とほぼ同じであると予想できます。

答え2

ここに別のヒントがあります。これhrsyncツールGitHubで見つけたものは、ファイル名を変更したりソースツリーのディレクトリ間でファイルを移動したりするときにファイルのメモリを保持するのに非常に良いようです。

  • ソースツリーでファイルの移動と編集を追跡できます。
  • これはシェルスクリプトであり、ソースシステムにインストールするための管理権限は必要ありませんが/usr/local/bin
  • ローカルシステムとリモートシステムの両方にハードリンクを処理できるファイルシステムが必要です。
  • 名前が変更されたファイルの変更を追跡できません。交換済み(つまり、その場で編集するのではなく削除して再生成)

はい

hrsync /path/to/directory/ remote:/path/to/destination/

答え3

bashコマンドラインユーティリティのみを使用してソリューションを見つけました。ソリューションを最適化できます。ファイルをサイズの昇順に並べ替え、各ブロックにできるだけ多くの小さなファイルを配置します(ここではバックパックの問題=)。しかし、これは過度のエンジニアリングになります。

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

関連情報