Aller au contenu
storagebits

Uberblok, un musée d'OpenZFS où chaque salle cite le code

Uberblok est un musée interactif à propos d'OpenZFS en 14 étapes : chaque affirmation technique y renvoie aux lignes exactes de zfs-2.4.4. Des agents l'ont construit, j'ai fixé la mission.

7 min de lecture#devlog#agents#zfs

Uberblok est en ligne : un musée à propos d’OpenZFS qu’on visite salle par salle. Quatorze étapes : un hall, une aile consacrée à l’histoire, onze salles techniques et une salle des machines. Chaque affirmation technique renvoie à un extrait annoté du code d’OpenZFS zfs-2.4.4, figé au commit 71a9f95. Chaque fait de l’aile Histoire a sa ligne dans SOURCES.md.

Ce sont des agents d’IA qui l’ont construit, entre le 18 et le 20 octobre. J’ai écrit la mission, donné mon avis sur chaque version et validé la mise en ligne. La salle des machines du site le dit en une phrase : le site « a été écrit par des agents d’IA, à partir d’une mission fixée par un humain qui en valide la publication ».

# Pourquoi ZFS

ZFS a beaucoup compté dans ma carrière. De 2010 à 2018, j’ai été responsable technique du stockage « file » chez OVHcloud. La robustesse de ZFS nous a impressionné dès que nous l’avons essayé, comme d’autres technologies avant-gardistes de Sun, de Solaris puis d’OpenSolaris : les Zones ou Crossbow. Sur ce socle, on a construit des produits vraiment puissants, jusqu’à des systèmes haute disponibilité qui basculent d’une tête à l’autre en cas de panne, et des send/receive très optimisés, avec du mbuffer et de la compression. Déployé à grande échelle, ZFS est un régal.

L’envie de lui rendre hommage est venue naturellement : plonger dans les entrailles de son code, qui est une magnifique pièce d’ingénierie logicielle.

# Ce que je voulais

La mission tenait en une phrase : « un musée que l’on visite salle par salle, où chaque salle rend visible […] une idée d’ingénierie du code source d’OpenZFS ». Deux règles l’accompagnaient. Pour les salles : « Une animation qui ne correspond à rien dans le code n’existe pas. » Pour l’histoire : « Aucun fait, aucune date, aucune citation sans source vérifiable. Dans le doute, on retire. »

Le code est donc passé avant les figures. Un premier fichier, ANALYSIS.md, cartographie l’architecture et, pour chaque salle, les fonctions et les structures qui portent l’idée. Il contient aujourd’hui 116 extraits. Les pages les lisent à la construction, et un script vérifie que chacun est identique, octet pour octet, au fichier du commit figé. La plupart des figures font tourner une transcription du code qu’elles montrent, testée sur des cas calculés à la main. L’aile Histoire s’appuie sur 43 sources, et la CI vérifie que chaque note du site correspond à une ligne de SOURCES.md.

La figure de la salle copie sur écriture : un arbre de blocs, de l'uberblock (UB, txg 41) jusqu'à quatre blocs de données, avec les boutons pour choisir un bloc, le réécrire pas à pas, couper le courant ou prendre un snapshot.
La salle copie sur écriture, dans sa version anglaise : chaque bloc porte le txg qui l'a écrit et son adresse sur le disque. On réécrit un bloc pas à pas, et on peut couper le courant à n'importe quelle étape.

# Là où ça a cassé

La première erreur venait de ma propre mission. J’y décrivais l’objet du hall comme « l’uberblock et son ring de 128 ». Le code dit autre chose : le ring occupe 128 Kio par label, et la taille d’un emplacement dépend de l’ashift du disque (vdev_impl.h, L482 à L496). Il y a 128 emplacements avec des secteurs de 512 octets, mais 32 seulement à ashift 12, le cas courant des disques à secteurs de 4 Kio.

Trois options ont été pesées. Écrire « 128 uberblocks » sans réserve était faux pour la plupart des pools en service. N’en montrer que 32 était exact, mais perdait l’image de départ. Le choix retenu : un ring de 128 Kio, dessiné avec 128 emplacements, et un sélecteur d’ashift qui les fusionne en 64, 32 ou 16. Le hall reste fidèle au code, et l’image de la mission est gardée.

Le ring du hall en vue 3D : un anneau de 128 emplacements, avec au centre « txg 4211, case 115 sur 128 ». L'emplacement 115 est en orange, le 114 en gris clair.
Le ring du hall en vue 3D, avec des secteurs de 512 octets ou de 1 Kio (ashift 9 ou 10) : 128 emplacements de 1 Kio. L'uberblock du txg 4211 occupe l'emplacement 115, car 4211 modulo 128 vaut 115 ; celui du txg 4210 reste intact juste avant.

La seconde a été trouvée par la revue de code d’une tranche. Une note de la salle send / receive affirmait que la déduplication et le clonage de blocs n’entraînent pas de renvoi de données inchangées. Le commentaire de spa.h qu’elle citait dit l’inverse : pour ces blocs, la naissance physique peut être antérieure à la naissance logique. Comme send s’appuie sur la naissance logique, un bloc dédupliqué ou cloné après le snapshot de départ est bien renvoyé. La note a été corrigée, sur la page comme dans ANALYSIS.md.

# La salle qui fait le plus travailler les méninges

Pour moi, c’est Metaslabs et space maps. Les metaslabs, c’est quelque chose ! Une révolution logicielle dont peu de gens ont conscience.

Le problème de départ, tel que la salle le pose : avec la copie sur écriture, chaque écriture alloue de l’espace neuf, et l’espace libre doit être noté sur le disque. Un bitmap d’un pool de 16 Tio, à un bit par secteur de 4 Kio, pèserait 512 Mio et devrait être modifié sur place, ce que la copie sur écriture interdit. ZFS découpe plutôt chaque vdev en metaslabs, environ 200 par défaut, garde l’espace libre de chacun dans un arbre en mémoire et n’écrit sur le disque que les changements, dans une space map à laquelle on ne fait qu’ajouter. Quand elle devient trop longue, il la réécrit en plus court à partir de l’arbre.

Dans la figure, la space map d’un metaslab de 512 Mio est une bande de mots de 64 bits, encodés comme le font les macros de space_map.h. En réécrivant une base de données de 64 Mio jusqu’à ce que le test de condensation dise oui, la map passe de 66 432 à 3 376 octets.

La figure de la salle Metaslabs : les 16 metaslabs d'un vdev de 8 Gio, la bande du metaslab 2 striée de segments libérés, l'état en mémoire (ms_allocatable : 380 Mio en 225 segments) et la space map sur le disque, longue de 37 392 octets, faite surtout d'entrées FREE de 128 et 256 Kio.
La salle Metaslabs après 40 txg de réécriture de la base de 64 Mio : l'espace libre du metaslab 2 est éclaté en 225 segments, et sa space map atteint 37 392 octets, surtout des entrées FREE. Elle n'est pas encore assez longue pour être condensée.

# Où j’en suis

Mon esprit n’a pas encore absorbé l’ensemble de ce qui a été généré ! C’est ce qui m’impressionne dans ce projet : il m’apprend des choses pendant que je le construis. Probablement qu’une vie ne suffira pas pour comprendre toutes les subtilités de ZFS.

Le critère de réussite de la mission était : « si Matt Ahrens ou Jeff Bonwick tombaient dessus, ils trouveraient l’exposé exact, élégant, et fidèle au code ». Je n’ai pas les compétences pour dire s’il est atteint. Si l’un d’eux tombe un jour sur le site, j’espère seulement qu’il n’y trouvera pas trop de coquilles. Et qu’il prendra autant de plaisir à le décortiquer que j’en prends moi-même.

Le musée est en ligne ; son code, ANALYSIS.md, DECISIONS.md et BUILDLOG.md sont dans le dépôt public.