Garbage collection inter-clients gc Décidé
Mark-and-sweep par tenant, auto-réparant, sans jamais un verrou exclusif — le magasin reste ouvert pendant l'inventaire. Le bloom filter revient côté sortie, où ses erreurs tombent du côté sûr, et rien n'est détruit sans quarantaine.
Le problème en une phrase : on ne peut supprimer un chunk que si plus personne ne le référence — or tout le monde le partage, et des backups tournent pendant qu’on compte. Les voisins y ont tous laissé des plumes : restic a historiquement exigé un verrou exclusif pour le prune (le dépôt ferme, les backups attendent), borg maintient des caches de comptage qui se désynchronisent, kopia s’appuie sur des marges horloge sensibles au clock skew. Mais Cairn arrive au combat armé : les racines sont recensées, les sessions épinglent déjà tout backup en cours, l’index a son champ époque, les segments métadonnées sont séparés sur SSD, et la dédup est scopée au tenant.
Décision 1 — Mark-and-sweep, pas de comptage de références
Décision 2 — Par tenant : l’avantage structurel
Chaque chunk appartient à exactement un tenant (dédup scopée) → le GC tourne tenant par tenant : travail borné, parallélisable, ordonnancé en tournée (chaque tenant tous les N jours, ou déclenché par le volume pruné). Jamais de « stop the world » global. restic, borg et kopia sont des outils mono-dépôt — ils ne peuvent pas faire ça ; c’est l’architecture multi-tenant qui l’offre.
Décision 3 — Le protocole anti-course : l’horizon d’époque
Décision 4 — Le bloom filter, côté sortie
Le marquage parcourt le DAG depuis les racines — métadonnées SSD uniquement (la séparation des segments paie ici), sous-arbres partagés visités une fois — et remplit le bloom. Le sweep itère l’index du tenant et condamne ce qui n’y est pas (et dont l’époque < horizon).
Décision 5 — Quarantaine, puis compaction gloutonne
- La benne fermée à clé. Le sweep ne détruit rien : il marque « condamné à l'époque E ». La destruction physique n'arrive qu'à la compaction, après confirmation par un cycle suivant + délai de grâce (72 h) — fenêtre d'undelete, protection contre le bug du GC lui-même et l'erreur d'opérateur. Grâce en époques logiques, pas en horloge murale (la faiblesse de kopia).
- On ne réorganise que les caisses aux trois-quarts vides. Chaque segment a son taux de vivants ; la compaction prend les pires d'abord (le plus d'octets récupérés par octet réécrit — le glouton de la littérature log-structured), recopie les survivants dans un segment neuf, bascule l'index, supprime l'ancien. Seuil ~50 % ajustable ; les segments froids attendent d'être très morts. Ça referme le point laissé ouvert par la section D.
Décision 6 — Jamais de verrou exclusif, jamais
Le cycle complet
Le cycle du GC — par tenant, en tâche de fond, sans verrou
Quatre étapes par tenant, en tâche de fond. Le sweep condamne, ne détruit pas — la destruction n'arrive qu'à la compaction, un cycle et une grâce plus tard. Et tout recommence depuis les racines : le GC ne fait jamais confiance à sa mémoire.
Les chiffres qui rassurent : tenant de 100 To (50 M chunks) → marquage = lecture streaming de dizaines de Go de métadonnées SSD (~minutes), sweep = scan de ~2,5 Go d’index (~minutes), bloom 60 Mo en RAM. Le GC d’un gros tenant est une affaire de minutes par cycle, en tâche de fond.