
# Moteurs

## Choisir un moteur

Les trois moteurs stockent les mêmes éléments, un identifiant UUIDv7 et un tableau de données, mais les organisent différemment sur le disque. Cette organisation détermine les usages adaptés à chaque moteur :

|            | DocStore | SegmentedLog | Queue |
| ---------- | -------- | ------------ | ----- |
| Sur le disque | un fichier JSONC par enregistrement, partitionné par suffixe UUID | segments en ajout uniquement, avec des lignes JSON précédées de leur longueur et somme de contrôle, plus un manifeste | un journal d'événements en ajout uniquement |
| Écriture | remplacement atomique du fichier pour chaque enregistrement | ajouts avec somme de contrôle ; les modifications et suppressions ajoutent de nouvelles entrées, l'espace étant récupéré par `compact()` | ajout avec somme de contrôle pour chaque événement de file |
| Lecture | `get()` par identifiant, requêtes indexées | balayages par curseur et par plage temporelle, `get()` avec l'index d'état | `claim()` dans l'ordre de mise en file |
| Idéal pour | lectures ponctuelles et recherches indexées, quelle que soit la taille de la collection | flux à nombreux ajouts, jusqu'à environ 1M d'enregistrements | distribution durable de tâches entre processus |
| Limite | balayages de champs non indexés au-delà d'environ 10k enregistrements | réécritures fréquentes d'un seul enregistrement (les anciennes versions occupent de l'espace jusqu'au compactage) | ce n'est pas un magasin général d'enregistrements ; les données utiles sont supprimées une fois la tâche terminée |

`DocStore` et `SegmentedLog` partagent la même interface fluide de
[requêtes API](https://storh.inline0.dev/fr/docs/query-builder) : la même chaîne `where()` s'exécute sur les deux moteurs ; seule l'exécution diffère. `DocStore` peut répondre à partir de ses index secondaires, tandis que `SegmentedLog` filtre pendant le balayage des segments. `Queue` repose sur des revendications, sans possibilité d'effectuer des requêtes : les processus de travail `claim()` le travail suivant au lieu de filtrer les tâches.

Conseils pratiques :

- Enregistrements récupérés, modifiés ou supprimés individuellement et recherchés par champ : `DocStore`. Ajoutez des [index](https://storh.inline0.dev/fr/docs/indexes) pour les champs utilisés dans vos filtres.
- Événements ou versions ajoutés principalement à la suite, puis relus dans l'ordre ou par plage temporelle : `SegmentedLog`.
- Tâches transmises des producteurs aux processus de travail : `Queue`. Les revendications et les finalisations sont sûres pour plusieurs processus, et `claimMany()`/`completeMany()` répartissent le coût des verrouillages et des fsync.
- Jointures, recherches ou rapports sur une collection : ajoutez un [SQL miroir](https://storh.inline0.dev/fr/docs/sql-mirror). Les fichiers restent canoniques ; le miroir est une projection reconstructible dans SQLite ou MySQL.

Les moteurs peuvent être combinés : ils ne partagent que le répertoire racine. Une application peut donc conserver le contenu dans un `DocStore`, une piste d'audit dans un `SegmentedLog` et les tâches d'arrière-plan dans un `Queue` sous la même racine de stockage.

## DocStore

`DocStore` convient aux lectures ponctuelles et aux balayages simples d'enregistrements durables. Il écrit un fichier JSONC par enregistrement :

```php
$store = new Storh\DocStore($root, 'articles');
$record = $store->put(['slug' => 'hello', 'published' => true]);
$same = $store->get($record->id());
```

Les fichiers d'enregistrement sont répartis dans des sous-répertoires selon les derniers caractères UUID, afin que les pics d'écriture UUIDv7 se répartissent entre plusieurs répertoires :

```text
articles/data/2d/018bcfe5-6800-7000-8000-2d5dba6274da.jsonc
```

## SegmentedLog

`SegmentedLog` convient aux enregistrements avec de nombreux ajouts, aux lectures par curseur et aux lectures par plage temporelle. Les enregistrements sont écrits dans le segment actif, à raison d'une ligne par enregistrement au format `<byte-length>\t<xxh32>\t<json>` (voir [Atomicité](https://storh.inline0.dev/fr/docs/atomicity)). Les fichiers de segment ont l'extension `.ndjson`, mais le préfixe de longueur et de somme de contrôle empêche les outils NDJSON classiques de les lire ; utilisez `stream()` ou le générateur de requêtes pour relire les enregistrements. Les segments complets deviennent des segments scellés dotés d'index clairsemés.

```php
$events = new Storh\SegmentedLog($root, 'events');
$events->put(['type' => 'user.created']);
$events->compact();
```

## Queue

`Queue` est conçu pour les files de travaux durables à haut débit. Les opérations d’ajout, de prise en charge, de validation, de remise en file et de purge écrivent des événements en ajout seul dans `queue.log` ; l’état de la file est rejoué en mémoire à son ouverture. Les méthodes par lots répartissent le coût des verrous et des vidages sur de nombreux travaux. Le journal grossit à chaque événement ; `stats()` indique sa taille actuelle en octets.

```php
$queue = new Storh\Queue($root, 'mail');
$queue->enqueue(['to' => 'person@example.test']);
$job = $queue->claim();
```

## Durabilité et concurrence

storh publie les écritures de fichiers par renommage atomique dans le répertoire cible. À la réouverture, `repair()` supprime les fichiers temporaires abandonnés dont le processus propriétaire n’est plus actif, tout en laissant intacts les fichiers temporaires des processus d’écriture actifs. Les marqueurs d’écriture rendent cette vérification instantanée ; ainsi, le nettoyage de toute la collection à l’ouverture du magasin n’a lieu qu’après un plantage.

`SegmentedLog` et `Queue` écrivent des lignes de journal protégées par une longueur et une somme de contrôle. La réouverture ou la réparation tronque les fins incomplètes jusqu’au dernier événement validé et reconstruit l’état en mémoire à partir du contenu durable du journal. Les écritures dans le journal et la file sont sérialisées à l’aide de verrous du système de fichiers.

Les mutations de `DocStore` sont sérialisées par un verrou en écriture au niveau de la collection ; les fichiers des enregistrements et les index secondaires sont donc mis à jour dans une même limite de cohérence entre les processus. Les écritures simultanées sur des identifiants d’enregistrement distincts sont sûres si le système de fichiers respecte les mêmes hypothèses de renommage atomique. Pour les écritures simultanées sur un même identifiant, le dernier renommage l’emporte.

storh vide les tampons et synchronise les descripteurs de fichiers avant la fin d’un renommage ou d’un ajout, et tente de synchroniser les répertoires parents après les renommages atomiques. La durabilité en cas de coupure de courant dépend toujours du respect de ces synchronisations par le système de fichiers et les options de montage sous-jacents.
