diff options
Diffstat (limited to 'pt-br/news/phase4-storage-deduplication/index.html')
| -rw-r--r-- | pt-br/news/phase4-storage-deduplication/index.html | 229 |
1 files changed, 229 insertions, 0 deletions
diff --git a/pt-br/news/phase4-storage-deduplication/index.html b/pt-br/news/phase4-storage-deduplication/index.html new file mode 100644 index 0000000..e927cfb --- /dev/null +++ b/pt-br/news/phase4-storage-deduplication/index.html @@ -0,0 +1,229 @@ +<!DOCTYPE html> +<html lang="pt-br"> +<head> + <meta charset="utf-8"> + <meta name="viewport" content="width=device-width, initial-scale=1"> + <title>Fase 4: Deduplicacao de Armazenamento — Tesseras</title> + <meta name="description" content="Uma nova camada de armazenamento enderecavel por conteudo elimina dados duplicados entre tesseras, reduzindo uso de disco e habilitando coleta de lixo automatica."> + <!-- Open Graph --> + <meta property="og:type" content="article"> + <meta property="og:title" content="Fase 4: Deduplicacao de Armazenamento"> + <meta property="og:description" content="Uma nova camada de armazenamento enderecavel por conteudo elimina dados duplicados entre tesseras, reduzindo uso de disco e habilitando coleta de lixo automatica."> + <meta property="og:image" content="https://tesseras.net/images/social.jpg"> + <meta property="og:image:width" content="1200"> + <meta property="og:image:height" content="630"> + <meta property="og:site_name" content="Tesseras"> + <!-- Twitter Card --> + <meta name="twitter:card" content="summary_large_image"> + <meta name="twitter:title" content="Fase 4: Deduplicacao de Armazenamento"> + <meta name="twitter:description" content="Uma nova camada de armazenamento enderecavel por conteudo elimina dados duplicados entre tesseras, reduzindo uso de disco e habilitando coleta de lixo automatica."> + <meta name="twitter:image" content="https://tesseras.net/images/social.jpg"> + <link rel="stylesheet" href="https://tesseras.net/style.css?h=21f0f32121928ee5c690"> + + + <link rel="alternate" type="application/atom+xml" title="Tesseras" href="https://tesseras.net/atom.xml"> + + + <link rel="icon" type="image/png" sizes="32x32" href="https://tesseras.net/images/favicon.png?h=be4e123a23393b1a027d"> + +</head> +<body> + <header> + <h1> + <a href="https://tesseras.net/pt-br/"> + <img src="https://tesseras.net/images/logo-64.png?h=c1b8d0c4c5f93b49d40b" alt="Tesseras" width="40" height="40" class="logo"> + Tesseras + </a> + </h1> + <nav> + + <a href="https://tesseras.net/pt-br/about/">Sobre</a> + <a href="https://tesseras.net/pt-br/news/">Notícias</a> + <a href="https://tesseras.net/pt-br/releases/">Lançamentos</a> + <a href="https://tesseras.net/pt-br/faq/">FAQ</a> + <a href="https://tesseras.net/pt-br/subscriptions/">Inscrições</a> + <a href="https://tesseras.net/pt-br/contact/">Contato</a> + + </nav> + <nav class="lang-switch"> + + <a href="https://tesseras.net/news/phase4-storage-deduplication/">English</a> | <strong>Português</strong> + + </nav> + </header> + + <main> + +<article> + <h2>Fase 4: Deduplicacao de Armazenamento</h2> + <p class="news-date">2026-02-15</p> + <p>Quando multiplas tesseras compartilham a mesma foto, o mesmo clipe de audio ou +os mesmos dados de fragmento, a camada de armazenamento antiga mantinha copias +separadas de cada. Em um no armazenando milhares de tesseras para a rede, essa +duplicacao se acumula rapidamente. A Fase 4 continua com deduplicacao de +armazenamento: um armazenamento enderecavel por conteudo (CAS) que garante que +cada dado unico seja armazenado exatamente uma vez em disco, independentemente +de quantas tesseras o referenciam.</p> +<p>O design e simples e comprovado: hash do conteudo com BLAKE3, usar o hash como +nome do arquivo e manter uma contagem de referencias no SQLite. Quando duas +tesseras incluem a mesma foto de 5 MB, um arquivo existe em disco com +refcount 2. Quando uma tessera e deletada, o refcount cai para 1 e o arquivo +permanece. Quando a ultima referencia e liberada, uma varredura periodica limpa +o orfao.</p> +<h2 id="o-que-foi-construido">O que foi construido</h2> +<p><strong>Migracao do esquema CAS</strong> (<code>tesseras-storage/migrations/004_dedup.sql</code>) — Tres +novas tabelas:</p> +<ul> +<li><code>cas_objects</code> — rastreia cada objeto no armazenamento: hash BLAKE3 (chave +primaria), tamanho em bytes, contagem de referencias e timestamp de criacao</li> +<li><code>blob_refs</code> — mapeia identificadores logicos de blobs (hash da tessera + hash +da memoria + nome do arquivo) para hashes CAS, substituindo a convencao antiga +de caminhos no sistema de arquivos</li> +<li><code>fragment_refs</code> — mapeia identificadores logicos de fragmentos (hash da +tessera + indice do fragmento) para hashes CAS, substituindo o antigo layout +do diretorio <code>fragments/</code></li> +</ul> +<p>Indices nas colunas de hash garantem lookups O(1) durante leituras e contagem de +referencias.</p> +<p><strong>CasStore</strong> (<code>tesseras-storage/src/cas.rs</code>) — O motor central de armazenamento +enderecavel por conteudo. Arquivos sao armazenados sob um diretorio de prefixo +de dois niveis: <code><raiz>/<prefixo-hex-2-chars>/<hash-completo>.blob</code>. O +armazenamento fornece cinco operacoes:</p> +<ul> +<li><code>put(hash, data)</code> — escreve dados em disco se ainda nao presente, incrementa o +refcount. Retorna se ocorreu um hit de deduplicacao.</li> +<li><code>get(hash)</code> — le dados do disco pelo hash</li> +<li><code>release(hash)</code> — decrementa o refcount. Se chegar a zero, o arquivo em disco +e deletado imediatamente.</li> +<li><code>contains(hash)</code> — verifica existencia sem ler</li> +<li><code>ref_count(hash)</code> — retorna a contagem de referencias atual</li> +</ul> +<p>Todas as operacoes sao atomicas dentro de uma unica transacao SQLite. O refcount +e a fonte de verdade — se o refcount diz que o objeto existe, o arquivo deve +estar em disco.</p> +<p><strong>FsBlobStore com CAS</strong> (<code>tesseras-storage/src/blob.rs</code>) — Reescrito para +delegar todo armazenamento ao CAS. Quando um blob e escrito, seu hash BLAKE3 e +computado e passado para <code>cas.put()</code>. Uma linha em <code>blob_refs</code> mapeia o caminho +logico (tessera + memoria + arquivo) para o hash CAS. Leituras buscam o hash CAS +via <code>blob_refs</code> e leem de <code>cas.get()</code>. Deletar uma tessera libera todas as suas +referencias de blob em uma unica transacao.</p> +<p><strong>FsFragmentStore com CAS</strong> (<code>tesseras-storage/src/fragment.rs</code>) — Mesmo padrao +para fragmentos codificados com erasure coding. O checksum BLAKE3 de cada +fragmento ja e computado durante a codificacao Reed-Solomon, entao e usado +diretamente como chave CAS. A verificacao de fragmentos agora checa o hash CAS +ao inves de recomputar do zero — se o CAS diz que os dados estao intactos, +estao.</p> +<p><strong>Coletor de lixo sweep</strong> (<code>cas.rs:sweep()</code>) — Uma passagem periodica de GC que +trata tres casos limite que o caminho normal de refcount nao consegue:</p> +<ol> +<li><strong>Arquivos orfaos</strong> — arquivos em disco sem linha correspondente em +<code>cas_objects</code>. Pode acontecer apos um crash durante escrita. Arquivos com +menos de 1 hora sao pulados (periodo de graca para escritas em andamento); +orfaos mais antigos sao deletados.</li> +<li><strong>Refcounts vazados</strong> — linhas em <code>cas_objects</code> com refcount zero que nao +foram limpas (ex: se o processo morreu entre decrementar e deletar). Essas +linhas sao removidas.</li> +<li><strong>Idempotente</strong> — executar sweep duas vezes produz o mesmo resultado.</li> +</ol> +<p>O sweep e conectado ao loop de reparo existente em <code>tesseras-replication</code>, entao +roda automaticamente a cada 24 horas junto com as verificacoes de saude dos +fragmentos.</p> +<p><strong>Migracao do layout antigo</strong> (<code>tesseras-storage/src/migration.rs</code>) — Uma +estrategia de migracao copy-first que move dados do layout antigo baseado em +diretorios (<code>blobs/<tessera>/<memoria>/<arquivo></code> e +<code>fragments/<tessera>/<indice>.shard</code>) para o CAS. A migracao:</p> +<ol> +<li>Verifica a versao de armazenamento em <code>storage_meta</code> (versao 1 = layout +antigo, versao 2 = CAS)</li> +<li>Percorre os diretorios antigos <code>blobs/</code> e <code>fragments/</code></li> +<li>Computa hashes BLAKE3 e insere no CAS via <code>put()</code> — duplicatas sao +automaticamente deduplicadas</li> +<li>Cria entradas correspondentes em <code>blob_refs</code> / <code>fragment_refs</code></li> +<li>Remove diretorios antigos somente apos todos os dados estarem seguros no CAS</li> +<li>Atualiza a versao de armazenamento para 2</li> +</ol> +<p>A migracao roda na inicializacao do daemon, e idempotente (segura para +re-executar) e reporta estatisticas: arquivos migrados, duplicatas encontradas, +bytes economizados.</p> +<p><strong>Metricas Prometheus</strong> (<code>tesseras-storage/src/metrics.rs</code>) — Dez novas metricas +para observabilidade:</p> +<table><thead><tr><th>Metrica</th><th>Descricao</th></tr></thead><tbody> +<tr><td><code>cas_objects_total</code></td><td>Total de objetos unicos no CAS</td></tr> +<tr><td><code>cas_bytes_total</code></td><td>Total de bytes armazenados</td></tr> +<tr><td><code>cas_dedup_hits_total</code></td><td>Numero de escritas que encontraram um objeto existente</td></tr> +<tr><td><code>cas_bytes_saved_total</code></td><td>Bytes economizados por deduplicacao</td></tr> +<tr><td><code>cas_gc_refcount_deletions_total</code></td><td>Objetos deletados quando refcount chegou a zero</td></tr> +<tr><td><code>cas_gc_sweep_orphans_cleaned_total</code></td><td>Arquivos orfaos removidos pelo sweep</td></tr> +<tr><td><code>cas_gc_sweep_leaked_refs_cleaned_total</code></td><td>Linhas de refcount vazadas limpas</td></tr> +<tr><td><code>cas_gc_sweep_skipped_young_total</code></td><td>Orfaos jovens pulados (periodo de graca)</td></tr> +<tr><td><code>cas_gc_sweep_duration_seconds</code></td><td>Tempo gasto no sweep GC</td></tr> +</tbody></table> +<p><strong>Testes baseados em propriedades</strong> — Dois testes proptest verificam invariantes +do CAS sob entradas aleatorias:</p> +<ul> +<li><code>refcount_matches_actual_refs</code> — apos N operacoes aleatorias de put/release, o +refcount sempre corresponde ao numero real de referencias pendentes</li> +<li><code>cas_path_is_deterministic</code> — o mesmo hash sempre produz o mesmo caminho no +sistema de arquivos</li> +</ul> +<p><strong>Atualizacao de testes de integracao</strong> — Todos os testes de integracao em +<code>tesseras-core</code>, <code>tesseras-replication</code>, <code>tesseras-embedded</code> e <code>tesseras-cli</code> +atualizados para os novos construtores com CAS. Testes de deteccao de +adulteracao atualizados para funcionar com o layout de diretorio CAS.</p> +<p>347 testes passam em todo o workspace. Clippy limpo com <code>-D warnings</code>.</p> +<h2 id="decisoes-de-arquitetura">Decisoes de arquitetura</h2> +<ul> +<li><strong>BLAKE3 como chave CAS</strong>: o hash de conteudo que ja computamos para +verificacao de integridade serve tambem como chave de deduplicacao. Nenhuma +etapa adicional de hashing — o hash computado durante <code>create</code> ou <code>replicate</code> +e reutilizado como endereco CAS.</li> +<li><strong>Refcount SQLite ao inves de reflinks do sistema de arquivos</strong>: consideramos +usar copy-on-write no nivel do sistema de arquivos (reflinks em btrfs/XFS), +mas isso amarraria o Tesseras a sistemas de arquivos especificos. Refcounting +em SQLite funciona em qualquer sistema de arquivos, incluindo FAT32 em +pendrives baratos e ext4 em Raspberry Pis.</li> +<li><strong>Diretorios de prefixo hexadecimal de dois niveis</strong>: armazenar todos os +objetos CAS em um diretorio plano desaceleraria sistemas de arquivos com +milhoes de entradas. A divisao <code><prefixo 2 chars>/</code> limita qualquer diretorio +individual a ~65k entradas antes de um segundo nivel ser necessario. Isso +segue a abordagem usada pelo object store do Git.</li> +<li><strong>Periodo de graca para arquivos orfaos</strong>: o sweep GC pula arquivos com menos +de 1 hora para evitar deletar objetos sendo escritos por uma operacao +concorrente. Esta e uma escolha pragmatica — troca uma pequena janela de +potenciais orfaos por seguranca contra crashes sem exigir fsync ou commit de +duas fases.</li> +<li><strong>Migracao copy-first</strong>: a migracao copia dados para o CAS antes de remover +diretorios antigos. Se o processo for interrompido, os dados antigos +permanecem intactos e a migracao pode ser re-executada. Isso e mais lento que +mover arquivos mas garante zero perda de dados.</li> +<li><strong>Sweep no loop de reparo</strong>: ao inves de adicionar um timer separado de GC, o +sweep CAS aproveita o loop de reparo existente de 24 horas. Isso mantem o +daemon simples — um unico ciclo de manutencao em segundo plano cuida tanto da +saude dos fragmentos quanto da limpeza de armazenamento.</li> +</ul> +<h2 id="o-que-vem-a-seguir">O que vem a seguir</h2> +<ul> +<li><strong>Fase 4 continuacao</strong> — auditorias de seguranca, empacotamento para OS +(Alpine, Arch, Debian, OpenBSD, FreeBSD)</li> +<li><strong>Fase 5: Exploracao e Cultura</strong> — navegador publico de tesseras por +era/localizacao/tema/idioma, curadoria institucional, integracao genealogica +(FamilySearch, Ancestry), exportacao para midia fisica (M-DISC, microfilme, +papel livre de acido com QR), contexto assistido por IA</li> +</ul> +<p>A deduplicacao de armazenamento completa a historia de eficiencia de +armazenamento do Tesseras. Um no que armazena fragmentos para milhares de +usuarios — comum para nos institucionais e nos completos sempre ligados — agora +paga o custo de disco apenas por dados unicos. Combinado com codificacao de +apagamento Reed-Solomon (que ja minimiza redundancia no nivel da rede), o +sistema alcanca armazenamento eficiente tanto nas camadas local quanto +distribuida.</p> + +</article> + + </main> + + <footer> + <p>© 2026 Tesseras Project. <a href="/atom.xml">News Feed</a> · <a href="https://git.sr.ht/~ijanc/tesseras">Source</a></p> + </footer> +</body> +</html> |