215 lines
9.2 KiB
Markdown
215 lines
9.2 KiB
Markdown
# Persistance et base de données Lardon3D
|
|
|
|
## Vision
|
|
|
|
Lardon3D doit stocker les métadonnées de reconstruction dans une base de données persistante légère, probablement SQLite, tandis que les données numériques massives restent dans des fichiers/binaires adaptés.
|
|
|
|
## Principes fondamentaux
|
|
|
|
### Séparation logique/binaire
|
|
- État logique, relations, index → base persistante légère
|
|
- Données numériques massives → fichiers/artefacts binaires adaptés
|
|
|
|
### Cycle de publication
|
|
```
|
|
lot calculé
|
|
→ artefact temporaire
|
|
→ validation
|
|
→ publication atomique
|
|
→ transaction de métadonnées
|
|
→ état READY
|
|
```
|
|
|
|
### Règle de reprise
|
|
Une reprise ne considère jamais un artefact partiellement publié comme valide.
|
|
|
|
## Concepts de domaine
|
|
|
|
Les éléments suivants sont des concepts de domaine, PAS des tables SQL imposées :
|
|
|
|
- project
|
|
- scan_set
|
|
- image
|
|
- feature_set
|
|
- visual_signature
|
|
- candidate_pair
|
|
- verified_pair
|
|
- track
|
|
- observation
|
|
- camera
|
|
- pose
|
|
- point3d
|
|
- reconstruction_layer
|
|
- measurement
|
|
- document_source
|
|
- geometric_constraint
|
|
- artifact
|
|
- checkpoint
|
|
|
|
## Invariants
|
|
|
|
- Chaque publication est atomique
|
|
- Les artefacts partiels ne sont jamais considérés comme valides
|
|
- La reprise commence à la dernière frontière connue
|
|
|
|
## Checkpoint durable de tâche v1
|
|
|
|
### État durable
|
|
|
|
Le modèle durable versionné contient uniquement l'identifiant stable, le nom,
|
|
l'estimation immuable, l'état observé, l'état de reprise, la progression, le
|
|
message, les horodatages et le compteur de séquences. Il ne contient aucun gros
|
|
artefact numérique. Une future version pourra référencer des identifiants
|
|
d'artefacts publiés et validés sans incorporer leur contenu.
|
|
|
|
Les mutex, conditions, callbacks, userdata, workers, gouverneur, réservations et
|
|
contrats d'exécution sont transitoires et ne sont jamais sérialisés.
|
|
|
|
### Normalisation après arrêt de processus
|
|
|
|
| État observé | État restauré |
|
|
|---|---|
|
|
| `TASK_PENDING` | `TASK_PENDING` |
|
|
| `TASK_RUNNING` | `TASK_PENDING` |
|
|
| `TASK_PAUSED` | `TASK_PENDING` |
|
|
| `TASK_COMPLETED` | `TASK_COMPLETED` |
|
|
| `TASK_FAILED` | `TASK_FAILED` |
|
|
| `TASK_CANCELLED` | `TASK_CANCELLED` |
|
|
|
|
Une rupture de séquence n'est pas un état : elle est observée comme
|
|
`TASK_RUNNING`. Son `sequence_count` est durable, mais la reprise revient à
|
|
`TASK_PENDING` et exige une nouvelle admission.
|
|
|
|
### Stockage minimal
|
|
|
|
Le codec v1 est indépendant de la future Project Database. Le fichier est de
|
|
taille fixe et bornée, encodé champ par champ, avec magie, version, taille et
|
|
checksum de payload.
|
|
La publication écrit un fichier temporaire unique dans le même répertoire,
|
|
effectue `fsync`, renomme atomiquement puis synchronise le répertoire parent.
|
|
La lecture distingue absence, corruption, version inconnue et erreur d'I/O.
|
|
|
|
La sauvegarde distingue trois frontières :
|
|
|
|
- avant `rename`, toute erreur retourne `IO_ERROR`, supprime le temporaire et
|
|
laisse l'ancien checkpoint publié inchangé ;
|
|
- après un `rename` réussi, le nouveau checkpoint est publié et visible et
|
|
n'est jamais présenté comme rollbackable ;
|
|
- si le `fsync` du répertoire échoue après ce `rename`, le résultat est
|
|
`PUBLISHED_NOT_DURABLE` : le fichier visible est valide, mais sa présence sous
|
|
ce nom après un crash ou une coupure n'est pas garantie. `OK` garantit que le
|
|
contenu et l'entrée de répertoire ont tous deux été synchronisés avec succès,
|
|
sous réserve des garanties fournies par le système de fichiers et le stockage.
|
|
|
|
Les tailles persistantes sont refusées avant conversion lorsqu'elles dépassent
|
|
`SIZE_MAX`. Les secondes sont des entiers non signés v1 : les timestamps
|
|
négatifs ne sont pas sérialisables et une valeur lue doit être représentable
|
|
par le `time_t` local avant conversion. Le format reste donc lisible entre
|
|
plateformes uniquement pour les valeurs communes à leurs domaines `size_t` et
|
|
`time_t`.
|
|
|
|
## Project Database v6
|
|
|
|
SQLite contient l'état logique interrogable et les références aux fichiers ;
|
|
les checkpoints et artefacts volumineux restent externes. L'enregistrement du
|
|
résumé de tâche et de sa référence checkpoint est une transaction unique. Un
|
|
artefact est d'abord publié et vérifié comme fichier régulier, puis seulement
|
|
marqué `READY` en DB. Le chemin inverse est interdit.
|
|
|
|
### Protocole checkpoint projet
|
|
|
|
Le protocole réel n'est pas une transaction distribuée :
|
|
|
|
1. capture locale du snapshot sous le mutex de tâche puis déverrouillage ;
|
|
2. publication atomique du fichier sous
|
|
`.lardon3d/checkpoints/<task_id>.chk` ;
|
|
3. transaction SQLite sur `tasks` et `checkpoints` avec chemin relatif.
|
|
|
|
Une erreur avant publication ne modifie pas la DB. `PUBLISHED_NOT_DURABLE` est
|
|
conservé comme tel en DB. Si la publication réussit puis que SQLite retourne
|
|
`BUSY` ou une erreur, le fichier valide reste sur disque, la DB conserve son
|
|
ancienne vérité et le nouveau fichier est un orphelin à réconcilier plus tard.
|
|
Il n'est pas supprimé et aucune atomicité FS+SQLite n'est revendiquée.
|
|
|
|
L'inventaire distingue checkpoint récupérable durable, récupérable mais publié
|
|
non durable, absent, invalide, version inconnue et erreur d'I/O. Aucune réparation
|
|
ou suppression silencieuse n'est effectuée.
|
|
|
|
Le format checkpoint reste en version 1 et ne contient pas de `task_kind`. Le
|
|
schéma SQLite v4 conserve `task_kind` et `task_kind_version` dans le résumé
|
|
logique interrogable. La migration v1→v2 laisse ces deux colonnes à `NULL` : une
|
|
tâche legacy reste inspectable mais ne peut pas être reconstruite ou resoumise.
|
|
Un kind inconnu ou une version non supportée est diagnostiqué sans exécuter de
|
|
code.
|
|
|
|
## Statut
|
|
|
|
**IMPLEMENTED** — modèle durable, codec v1, lecture validée, publication
|
|
atomique et restauration sûre d'une tâche isolée.
|
|
|
|
**IMPLEMENTED** — Project Database v6 pour identité, tâches typées, ScanSets,
|
|
images logiques, Feature Sets/assets SHA-256, Visual Index segmenté,
|
|
checkpoints et artefacts génériques.
|
|
|
|
**IMPLEMENTED** — registry statique bornée et reconstruction explicite avec
|
|
ownership du userdata.
|
|
|
|
**IMPLEMENTED** — API projet de sauvegarde fichier+DB et inventaire validé au
|
|
redémarrage.
|
|
|
|
**IMPLEMENTED** — `import.images` persiste son chemin source absolu et son
|
|
`scanset_id`, puis publie un checkpoint après chaque lot validé. Le catalogue
|
|
SQLite rend le rejeu idempotent à la granularité du contenu dans un ScanSet.
|
|
|
|
Le chemin source absolu est l'intention durable v1 : il doit rester accessible
|
|
après redémarrage et un projet déplacé ne rend pas une source externe portable.
|
|
Une source absente ou devenue non-répertoire fait échouer proprement la
|
|
reconstruction. Après import terminé, l'image dépend de l'asset géré, plus de la
|
|
source. Le SHA-256 est calculé pendant la copie avec un tampon fixe de 64 Kio.
|
|
L'asset est publié sans écrasement sous
|
|
`assets/images/<prefix>/<sha256>`, puis seulement enregistré `READY` dans une
|
|
transaction SQLite. Un asset concurrent déjà présent n'est adopté qu'après
|
|
rehash complet et vérification de taille. Si SQLite échoue après publication,
|
|
le fichier reste orphelin pour une future réconciliation ; aucune transaction
|
|
FS+SQLite n'est revendiquée.
|
|
|
|
Les identités publiées `scanset_id`, `image_id` et `asset_id` utilisent les
|
|
séquences SQLite `AUTOINCREMENT` : une valeur issue d'une transaction validée
|
|
n'est jamais réattribuée à un autre objet, même après suppression de la ligne.
|
|
Une valeur réservée par une transaction annulée n'est pas une identité publiée.
|
|
|
|
`manifest.tsv` reste supporté par l'ancien chemin d'import/catalogue. Le chemin
|
|
persistant entretient une projection best-effort par hardlinks pour la TUI,
|
|
mais SQLite est le commit logique canonique : la correction de la reprise ne
|
|
dépend plus de l'ordre de `readdir()` ni du nom de fichier.
|
|
|
|
La migration v3 vers v4 ne transforme pas les lignes du manifeste historique
|
|
en images cataloguées : elles ne contiennent pas toutes les preuves exigées par
|
|
le modèle v4. Le marqueur durable `legacy_image_catalog_pending` rend cette
|
|
situation visible. Une tâche récupérable peut repeupler le catalogue par rejeu
|
|
si sa source existe encore ; sinon les fichiers et le manifeste restent une
|
|
projection legacy, explicitement non cataloguée. Une tâche v3 déjà terminée
|
|
n'est pas rejouée automatiquement.
|
|
|
|
**IMPLEMENTED** — reprise automatique sélective à l'ouverture : pagination
|
|
bornée, validation checkpoint/kind, reconstruction production et enqueue sans
|
|
claim persistant supplémentaire.
|
|
|
|
Les records sont parcourus par task ID croissant. Un checkpoint
|
|
`PUBLISHED_NOT_DURABLE` présent, valide et cohérent peut être repris ; le résumé
|
|
conserve cet avertissement jusqu'au prochain checkpoint durable. Une tâche
|
|
terminale n'appartient pas à la requête de reprise.
|
|
|
|
**NOT_YET_WIRED** — autosave complet, réconciliation des fichiers orphelins et
|
|
retry piloté par l'utilisateur pour les sources indisponibles.
|
|
|
|
**NOT_YET_WIRED** — migration de la vue TUI en mémoire vers la pagination
|
|
SQLite, scrub des assets et réconciliation globale des orphelins.
|
|
|
|
**IMPLEMENTED** — Feature Store externe versionné, immutable, borné et relié
|
|
transactionnellement à ses métadonnées SQLite après publication.
|
|
|
|
**IMPLEMENTED** — Visual Index externe segmenté, memberships transactionnels
|
|
et tâche `visual_index.update` récupérable.
|
|
|
|
**PLANNED** — migrations v7+ et reprise avec dépendances.
|