tar 目录仅发送修改后的文件块

tar 目录仅发送修改后的文件块

可以修改深层且复杂的目录结构:可以移动文件(更改前缀),同时可以部分更改文件内容。

我想减少通过网络传输的数据量。

rsync适用于 4k 大小的数据块(如果我没记错的话)。

我是否可以使用某种串联(tar类似)来保留有关文件系统结构和属性的元信息,将文件内容从每个下一个文件的多个 4k 字节的偏移量开始,以实现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 上发现的,当您重命名文件或在源树的目录之间移动文件时,它似乎非常擅长维护文件的内存。

  • 它可以跟踪源树中文件的移动和编辑
  • 它是一个 shell 脚本,不需要管理权限即可在源系统上安装,尽管将其放入/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

相关内容