summaryrefslogtreecommitdiffstats
path: root/pt-br/news/phase4-storage-deduplication/index.html
blob: e927cfb5732ddb3bc771e3ff517af4f6b26ec49a (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
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:&#x2F;&#x2F;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:&#x2F;&#x2F;tesseras.net&#x2F;news&#x2F;phase4-storage-deduplication&#x2F;">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>&lt;raiz&gt;/&lt;prefixo-hex-2-chars&gt;/&lt;hash-completo&gt;.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/&lt;tessera&gt;/&lt;memoria&gt;/&lt;arquivo&gt;</code> e
<code>fragments/&lt;tessera&gt;/&lt;indice&gt;.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>&lt;prefixo 2 chars&gt;/</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>&copy; 2026 Tesseras Project. <a href="/atom.xml">News Feed</a> · <a href="https://git.sr.ht/~ijanc/tesseras">Source</a></p>
    </footer>
</body>
</html>