Questão Sistema de arquivos da União com nomes de arquivos “versionados”?


Você sabe se existe um fs unificado para GNU / Linux que mostra também arquivos "sombreados" com nomes ligeiramente diferentes? I.E. se eu tiver dois fs como:

root1
+dir1
+dir2
 +file1
 +file2
 +file3

root2
+dir1
+dir2
 +file1
 +file2
 +file4

O resultante "unioned" fs deve resultar:

unioned
+dir1
+dir2
 +file1
 +file1.1
 +file2
 +file2.1
 +file3

Para que seja possível verificar rapidamente as diferenças entre os fs "unidos"

Parece que a UnionFS e a Aufs não oferecem essa opção

Obrigado


5


origem


Bem, eu diria que isso prejudicaria o conceito básico desses sistemas de arquivos. Se você quiser diferenciar as árvores de diretórios, por que não simplesmente usar diff? - Daniel B
porque eu preciso mesclar backups de propagação geográfica (criados com múltiplos rsync), verificando rapidamente as diferenças com diff / meld / etc. seria muito demorado para diferenciar todos os pares que eu tenho pelo menos 5 backups diferentes) - atrent
Se você pode montá-los, você pode usar diff. Eu não consigo ver o problema, desculpe. - Daniel B
demorado (300k arquivos por fs), enquanto com a união eu poderia sobrepor-los e usar ferramentas como rdfind (duplicate finder) em uma base por diretório - atrent
Além disso, lembre-se de que não estou interessado em escolher o arquivo mais novo ou prioritário de cada camada, também preciso verificar se eles são sãos. - atrent


Respostas:


Uma alternativa usando git-annex:

Primeiro, vamos configurar os arquivos de teste:

#!/bin/bash 
# faster than /dev/urandom
randfile='openssl enc -aes-256-ctr -pass pass:"$(dd if=/dev/urandom bs=128 count=1 2>/dev/null | base64)" -nosalt < /dev/zero'
dd='dd bs=1M count=5 iflag=fullblock'

for I in 1 2
do
  mkdir root$I
  cd root$I
  for J in 1 2
  do
    mkdir dir$J
    if [ -e dir2 ]
    then
      cd dir2
      eval $randfile | eval $dd of=file1
      eval $randfile | eval $dd of=file2
      if [ `pwd | grep root1` ]; then
        eval $randfile | eval $dd of=file3
      elif [ `pwd | grep root2` ]; then
        eval $randfile | eval $dd of=file4
      fi
      cd ..
    fi
  done
  cd ..
done

Isso cria os diretórios, com arquivos binários contendo dados aleatórios. Neste ponto, os arquivos são:

user@host$ find root? -path '*/.git*' -prune -o -print | sort -n 
root1
root1/dir1
root1/dir2
root1/dir2/file1
root1/dir2/file2
root1/dir2/file3
root2
root2/dir1
root2/dir2
root2/dir2/file1
root2/dir2/file2
root2/dir2/file4

Agora, inicializamos os repositórios e realizamos uma sincronização:

cd root1
  git init
  git annex init 'root1'
  git remote add root2 ../root2
  #git annex direct
  git annex add .
  git commit -a -m 'Files added.'
cd ..
cd root2
  git init
  git annex init 'root1'
  git remote add root1 ../root1
  #git annex direct
  git annex add .
  git commit -a -m 'Files added.'
cd ..
mkdir unioned
cd unioned
  git init
  git annex init 'unioned'
  git remote add root1 ../root1
  git remote add root2 ../root2
  git annex add . 
  git commit -a -m 'Files added.'
  git annex sync
cd ..

Neste ponto, o conteúdo de unioned/ estamos:

user@host$ find root? unioned -path '*/.git*' -prune -o -print | sort -n
root1
root1/dir1
root1/dir2
root1/dir2/file1
root1/dir2/file2
root1/dir2/file3
root2
root2/dir1
root2/dir2
root2/dir2/file1
root2/dir2/file2
root2/dir2/file4
unioned
unioned/dir2
unioned/dir2/file1
unioned/dir2/file1.variant-065a
unioned/dir2/file1.variant-a33e
unioned/dir2/file2
unioned/dir2/file2.variant-08f3
unioned/dir2/file2.variant-75c4
unioned/dir2/file3
unioned/dir2/file4

Onde *.variant-* link de volta para os diferentes arquivos nos diferentes repositórios. Além disso, unioned ainda não contém dados até que conduzamos uma git annex get. Para agora, git annex list mostra onde os arquivos estão localizados e / ou provenientes de:

user@host$ cd unioned; git annex list
here
|root1
||root2
|||web
||||
__X_ dir2/file1.variant-065a
_X__ dir2/file1.variant-a33e
__X_ dir2/file2.variant-08f3
_X__ dir2/file2.variant-75c4
_X__ dir2/file3
__X_ dir2/file4

Uma alternativa de forma mais longa é git annex whereis. Finalmente, para resolver os conflitos e propagar a mesclagem, de dentro unioned/dir2:

cd unioned/dir2
git annex get # retrieve the actual content
git annex unlock # unlock the files - replace the symlinks with the actual repofiles
rm file1
git mv file1.variant-065a file1
git rm -f file1.variant-a33e
rm file2
git mv file2.variant-75c4 file2
git rm -f file2.variant-08f3
git annex add . # "commits" the changes, converts files back into symlinks
git annex sync  # propagates the changes back to the other repos

Quais os rendimentos:

git annex sync
commit  ok
pull root2 
ok
pull root1 
ok
push root2 
Counting objects: 61, done.
Delta compression using up to 2 threads.
Compressing objects: 100% (26/26), done.
Writing objects: 100% (37/37), 2.67 KiB | 0 bytes/s, done.
Total 37 (delta 14), reused 0 (delta 0)
To ../root2
   e5df80f..720b34b  git-annex -> synced/git-annex
   b055385..ad8c5c2  master -> synced/master
ok
push root1 
Counting objects: 61, done.
Delta compression using up to 2 threads.
Compressing objects: 100% (26/26), done.
Writing objects: 100% (37/37), 2.67 KiB | 0 bytes/s, done.
Total 37 (delta 14), reused 0 (delta 0)
To ../root1
   e5df80f..720b34b  git-annex -> synced/git-annex
   b055385..ad8c5c2  master -> synced/master
ok

Finalmente, um git annex list mostra onde esses arquivos estão localizados após a sincronização: unioned/ O diretório tem cópias de todos os arquivos, escolhidos dos diferentes servidores como acima.


git-annex também tem um modo direto que opera diretamente no sistema de arquivos sem o uso de links simbólicos.

Configurar isso para uso em computadores remotos é uma questão de configurar controles remotos sobre o ssh usando o git padrão, no entanto, o comportamento é descrito aqui: http://git-annex.branchable.com/walkthrough/using_ssh_remotes/

O passo a passo geral de git anexo está localizado aqui: http://git-annex.branchable.com/walkthrough/


1





A resposta para a pergunta original parece ser "não no momento".

Soluções alternativas foram propostas, elas são baseadas:

  • em uma ferramenta notória (rsync, com a opção de backup ativada)
  • em sistemas de arquivos especiais (como ZFS ou btrfs) oferecendo "snapshot"

Ambas as propostas envolvem E / S pesadas porque criam um novo sistema de arquivos em vez de mapear os existentes em um sistema de arquivos virtual.


0





Em vez de olhar para o nível do sistema de arquivos, você precisa ver / manter as diferenças entre as versões. Se eles são arquivos de texto - então git  http://git-scm.com/ irá fornecer uma boa solução. git é um sistema de controle de versão usado para o código-fonte, e lida com ambos os vários diretórios de arquivos (aka repositórios), mas ramificação, diffs e mescla.

Se você não pode usar gitEm seguida, o rsync fornecerá uma solução, mas você precisará desenvolver manualmente uma solução para examinar os arquivos que deseja comparar ou mesclar. Com o git essas diferenças são rastreadas automaticamente.

Se eles são principalmente arquivos binários - você pode querer fazer algo com o rsync. Por exemplo, com o seguinte script: Para configurar o teste:

set -x
for DIR in a b c ; do mkdir $DIR ; done
for DIR in `ls -d ?`; do
  echo "TESTMSG1-$DIR" >> $DIR/A;
  echo "TESTMSG2-$DIR" >> $DIR/B;
  echo "TESTMSG3-$DIR" >> $DIR/C;
  done
ls
ls -R
grep -r $ ?

E para executar o teste, com -av para cópia de arquivo detalhado e -ccomparar os arquivos com uma soma de verificação e -b --suffix= para criar backups de arquivos com timestamp para comparação posterior:

rsync -avc -b --suffix=-$(date +%s.bk) a/ b
ls -R
grep -r $ ?
find . -name "*.bk"

Mostramos que os arquivos são copiados, com um registro de data e hora .bk sufixo é adicionado, então você pode encontrar os arquivos de backup para análise posterior: find . -name "*.bk"

$ sh test.sh
...output deleted for brevity...
+ ls
a  b  c  test.sh
+ ls -R
a  b  c  test.sh

./a:
A  B  C
./b:
A  B  C
./c:
A  B  C
+ grep -r $ a b c
a/A:TESTMSG1-a
a/B:TESTMSG2-a
a/C:TESTMSG3-a
b/A:TESTMSG1-b
b/B:TESTMSG2-b
b/C:TESTMSG3-b
c/A:TESTMSG1-c
c/B:TESTMSG2-c
c/C:TESTMSG3-c

+ date +%s.bk
+ rsync -avc -b --suffix=-1403746846.bk a/ b
sending incremental file list
A
B
C
sent 300 bytes  received 73 bytes  746.00 bytes/sec
total size is 33  speedup is 0.09
+ ls -R
a  b  c  test.sh

./a:
A  B  C
./b:
A  A-1403746846.bk  B  B-1403746846.bk  C  C-1403746846.bk
./c:
A  B  C
+ grep -r $ a b c
a/A:TESTMSG1-a
a/B:TESTMSG2-a
a/C:TESTMSG3-a
b/A:TESTMSG1-a
b/A-1403746846.bk:TESTMSG1-b
b/B:TESTMSG2-a
b/B-1403746846.bk:TESTMSG2-b
b/C:TESTMSG3-a
b/C-1403746846.bk:TESTMSG3-b
c/A:TESTMSG1-c
c/B:TESTMSG2-c
c/C:TESTMSG3-c

+find . -name "*.bk"
./b/B-1403746846.bk
./b/C-1403746846.bk
./b/A-1403746846.bk

Outra alternativa é usar instantâneos do ZFS para "espelhar" os diretórios no mesmo "namespace". Pseudo-código para essas etapas (já que não tenho zfs na minha frente) seria algo como:

for X in (a b c); do 
  zfs snapshot zfs-destination@baseline
  rsync -avc /src-$X/ zfs-destination
  zfs snapshot zfs-destination@$X
  diff -r zfs-destination/ zfs-destination/.zfs/snapshot/$X/
  # analyze diff files and validate changes to commit
  # restore files to not change from .zfs/snapshot/baseline
done

Não que você 'possa' fazer loop como um script, por causa do requisito manual de analisar as correções, mas repetir as etapas acima para cada diretório de origem forneceria a habilidade de mesclar e um histórico completo por meio de instantâneos. Substitua 'a b c' por algo como date -Is para timestamp os instantâneos.

Eu esqueci o zfs diff comando. A linha diff acima deve ser:

zfs diff -FH zfs-destination/ zfs-destination@baseline | \
  awk '/^[+MR]\tF/ {print $3}' > list

Onde awk seleciona (+) para arquivos adicionados (M) para modificados (R) para renomeados. Isso é muito mais rápido que o diff recursivo nos diretórios.


0



Obrigado! Primeira nota: Eu sei sobre git (eu uso todos os dias), mas minha necessidade não envolve (apenas) arquivos de texto, além disso, são muitos (meio milhão) e vêm de backups espalhados (geograficamente distribuídos) que eu periodicamente (continuamente) ) execute usando o rsync. Então, às vezes (não frequentemente, felizmente) eu tenho uma pane de disco e eu preciso mesclar os backups (já que eles estão em estados ligeiramente diferentes. No momento eu uso o rdfind (para limpar duplicatas) e meld / diff / etc para verificar o restante arquivos (não posso confiar em carimbos de data / hora porque meu último problema de disco estava no disco mestre e notei tarde demais) - atrent
Segunda nota: obrigado novamente! Eu não me lembro sobre a opção de backup do rsync, acho que resolve (embora com mais disco I / O) o meu problema por agora. - atrent
@atrent também existe 'uníssono' cis.upenn.edu/~bcpierce/unison Eu não usei muito, mas é mais afinado para mesclar em vez de mais novo substitui o antigo como rsync, e pode ser útil. - glallen
@atrent também, se isso resolveu sua pergunta, por favor marque a resposta apropriadamente. obrigado. - glallen
O uníssono é um dos piores programas que já vi ... inutilizável na melhor das hipóteses. A opção rsync não é uma solução completa, então deixo essa questão em aberto. - atrent