
# Motorer

## Välj en motor

Alla tre motorer lagrar samma sak: ett id av typen UUIDv7 plus en dataarray,
men organiserar det olika på disk. Den organisationen avgör vad varje motor
passar bäst för:

|            | DocStore | SegmentedLog | Queue |
| ---------- | -------- | ------------ | ----- |
| På disk    | en JSONC-fil per post, uppdelad i kataloger efter UUID-suffix | endast tillägg i segment med längd- och kontrollsummeförsedda JSON-rader samt ett manifest | en händelselogg med endast tillägg |
| Skrivning  | atomiskt filbyte per post | kontrollsummeverifierade tillägg; överskrivningar och raderingar lägger till nya poster som återtas genom `compact()` | kontrollsummeverifierat tillägg per köhändelse |
| Läsning    | `get()` efter id, indexerade frågor | markör- och tidsintervallssökningar, `get()` via tillståndsindexet | `claim()` i inskickningsordning |
| Passar bäst | punktläsningar och indexerade sökningar vid alla samlingsstorlekar | strömmar med många tillägg och upp till cirka 1M poster | beständig arbetsdistribution mellan processer |
| Svaghet | fältsökningar utan index vid fler än cirka 10k poster | frekventa omskrivningar av enskilda poster (äldre versioner tar plats tills de kompakteras) | ingen generell postlagring; nyttolaster tas bort när ett jobb slutförs |

`DocStore` och `SegmentedLog` har samma flytande
[fråge-API](https://storh.inline0.dev/sv/docs/query-builder): samma kedja av `where()`-anrop körs på båda
motorerna, och endast exekveringen skiljer sig. `DocStore` kan svara från sina
sekundära index, medan `SegmentedLog` filtrerar vid genomsökning av segmenten.
`Queue` bygger på anspråk och kan inte frågas mot: arbetare `claim()` nästa jobb i stället
för att filtrera jobb.

Tumregler:

- Poster som du hämtar, uppdaterar eller raderar enskilt och söker på fält:
  `DocStore`. Lägg till [index](https://storh.inline0.dev/sv/docs/indexes) för fälten du filtrerar på.
- Händelser eller versioner som du främst lägger till och läser i ordning eller inom ett
  tidsintervall: `SegmentedLog`.
- Jobb som skickas från producenter till arbetarprocesser: `Queue`. Anspråk och
  slutföranden är säkra mellan flera processer, och `claimMany()`/`completeMany()`
  fördelar kostnaden för lås och fsync över flera jobb.
- Kopplingar, sökning eller rapportering över en samling: lägg till en
  [SQL-spegel](https://storh.inline0.dev/sv/docs/sql-mirror). Filerna är fortsatt kanoniska; spegeln är en
  återskapningsbar projektion i SQLite eller MySQL.

Motorer kan kombineras: de delar bara rotkatalog, så en applikation kan
lagra innehåll i en `DocStore`, en granskningslogg i en `SegmentedLog` och
bakgrundsjobb i en `Queue` under samma lagringsrot.

## DocStore

`DocStore` är avsedd för punktläsningar och enkla genomsökningar av beständiga poster. Den skriver
en JSONC-fil per post:

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

Postfiler delas upp efter UUID avslutande tecken så att UUIDv7 skrivtoppar sprids
över katalogerna:

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

## SegmentedLog

`SegmentedLog` är avsedd för poster med många tillägg, markörläsningar och tidsintervallsläsningar.
Poster skrivs till det aktiva segmentet, en rad per post i formatet
`<byte-length>\t<xxh32>\t<json>` (se [Atomicitet](https://storh.inline0.dev/sv/docs/atomicity)). Segmentfilerna har tillägget `.ndjson`,
men prefixet med längd och kontrollsumma innebär att vanliga NDJSON-verktyg inte kan läsa dem; läs tillbaka poster med `stream()` eller
frågebyggaren. Fulla segment rullas över till förseglade segment med glesa index.

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

## Queue

`Queue` är avsedd för beständiga arbetsköer med högt genomflöde. Enqueue, claim, complete,
requeue och purge skriver händelser med endast tillägg till `queue.log`; köstatus
spelas upp i minnet när kön öppnas. Batchmetoder fördelar kostnaden för lås och
flush över många jobb. Loggen växer med varje händelse; `stats()`
rapporterar dess aktuella storlek i byte.

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

## Beständighet och samtidighet

storh publicerar filskrivningar med atomärt namnbyte i målkatalogen.
Vid återöppning och `repair()` tas övergivna temporära filer bort när ägarprocessen har avslutats,
medan temporära filer från aktiva skrivare lämnas ifred. Skrivarmarkörer gör kontrollen
konstant i tid, så en samling genomsöks när ett lager öppnas endast efter en krasch.

`SegmentedLog` och `Queue` skriver loggrader som skyddas av längd och kontrollsumma. Vid återöppning
eller reparation kapas trasiga slutrader till den senaste bekräftade händelsen, och tillståndet i minnet
byggs om från loggens beständiga innehåll. Logg- och köskrivningar serialiseras med
filsystemslås.

`DocStore`-ändringar serialiseras med ett skrivlås på samlingsnivå, så
postfiler och sekundära index uppdateras som en enda konsekvent enhet mellan
processer. Samtidiga skrivningar till olika post-id:n är säkra med samma
antaganden om atomärt namnbyte i filsystemet. Vid samtidiga skrivningar till samma id vinner
sista namnbytet.

storh tömmer buffertar och synkroniserar filhandtag före avslutat namnbyte eller tillägg och
försöker synkronisera överordnade kataloger efter atomära namnbyten. Beständighet
vid strömavbrott beror fortfarande på att det underliggande filsystemet och monteringsalternativen respekterar dessa
synkroniseringar.
