
# Nástroje

## Výber nástroja

Všetky tri nástroje ukladajú to isté: ID UUIDv7 a pole údajov, ale na disku ich usporadúvajú odlišne. Toto usporiadanie určuje, na čo sa každý nástroj hodí:

|            | DocStore | SegmentedLog | Queue |
| ---------- | -------- | ------------ | ----- |
| Na disku   | jeden súbor JSONC na záznam, rozdelený podľa koncových znakov UUID | segmenty iba na pridávanie, pričom každý riadok JSON má predponu s dĺžkou a kontrolným súčtom, plus manifest | jeden protokol udalostí, do ktorého sa iba pridáva |
| Zápis      | atomická náhrada súboru pri každom zázname | pridania s kontrolným súčtom; prepísania a odstránenia pridávajú nové položky, uvoľnené miesto získava `compact()` | pridanie s kontrolným súčtom pri každej udalosti frontu |
| Čítanie    | `get()` podľa ID, indexované dopyty | prechádzanie kurzorom a podľa časového rozsahu, `get()` cez stavový index | `claim()` v poradí zaradenia do frontu |
| Vhodné najmä na | priame čítanie a indexované vyhľadávanie v kolekcii ľubovoľnej veľkosti | prúdy s častým pridávaním, približne do 1M záznamov | spoľahlivé odovzdávanie práce medzi procesmi |
| Slabá stránka | prechádzanie polí bez indexu pri viac než približne 10k záznamoch | časté prepisovanie jednotlivých záznamov (staré verzie zaberajú miesto až do kompakcie) | nejde o všeobecné úložisko záznamov; po dokončení úlohy sa jej dátový obsah zahodí |

`DocStore` a `SegmentedLog` používajú rovnaký plynulý [dopyt API](https://storh.inline0.dev/sk/docs/query-builder): rovnaký reťazec `where()` funguje v oboch nástrojoch a líši sa iba vykonanie. `DocStore` dokáže odpovedať pomocou sekundárnych indexov, zatiaľ čo `SegmentedLog` filtruje pri prechádzaní segmentov. `Queue` používa nárokovanie, nie dopytovanie: pracovníci `claim()` ďalšiu úlohu namiesto filtrovania úloh.

Praktické pravidlá:

- Záznamy, ktoré načítavate, aktualizujete alebo odstraňujete jednotlivo a vyhľadávate podľa poľa:
  `DocStore`. Pridajte [indexy](https://storh.inline0.dev/sk/docs/indexes) pre polia, podľa ktorých filtrujete.
- Udalosti alebo verzie, ktoré väčšinou pridávate a čítate späť v poradí alebo podľa časového okna: `SegmentedLog`.
- Úlohy odovzdávané producentmi pracovným procesom: `Queue`. Nárokovanie a dokončovanie sú bezpečné pri viacerých procesoch a `claimMany()`/`completeMany()` rozkladajú náklady na zámky a fsync.
- Spájanie, vyhľadávanie alebo vykazovanie nad ľubovoľnou kolekciou: pridajte zrkadlo [SQL](https://storh.inline0.dev/sk/docs/sql-mirror). Súbory zostávajú autoritatívne; zrkadlo je projekcia, ktorú možno znova zostaviť v SQLite alebo MySQL.

Nástroje možno kombinovať: zdieľajú iba koreňový adresár, takže jedna aplikácia môže uchovávať obsah v `DocStore`, auditnú stopu v `SegmentedLog` a prácu na pozadí v `Queue` pod rovnakým koreňom úložiska.

## DocStore

`DocStore` je určený na priame čítanie a jednoduché prechádzanie trvalých záznamov. Pre každý záznam zapisuje jeden súbor JSONC:

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

Súbory záznamov sa rozdeľujú podľa posledných znakov UUID, aby sa nápor zápisov UUIDv7 rozložil medzi adresáre:

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

## SegmentedLog

`SegmentedLog` je určený na záznamy s častým pridávaním, čítanie kurzorom a čítanie podľa časového rozsahu. Záznamy sa zapisujú do aktívneho segmentu, jeden na riadok vo formáte `<byte-length>\t<xxh32>\t<json>` (pozri [Atomicity](https://storh.inline0.dev/sk/docs/atomicity)). Súbory segmentov používajú príponu `.ndjson`, ale predpona s dĺžkou a kontrolným súčtom znamená, že bežné nástroje NDJSON ich nedokážu čítať; záznamy načítajte pomocou `stream()` alebo nástroja na tvorbu dopytov. Úplné segmenty sa uzatvoria a zmenia na segmenty s riedkymi indexmi.

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

## Queue

`Queue` je určený pre trvalé pracovné fronty s vysokou priepustnosťou. Operácie zaradenia do frontu, nárokovania, dokončenia, opätovného zaradenia a vyčistenia zapisujú udalosti iba na koniec súboru `queue.log`; stav frontu sa pri otvorení frontu znovu prehrá do pamäte. Hromadné metódy rozkladajú náklady na zámky a vyprázdnenie vyrovnávacej pamäte medzi mnohé úlohy. Log rastie s každou udalosťou; `stats()` uvádza jeho aktuálnu veľkosť v bajtoch.

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

## Trvácnosť a súbežnosť

storh zverejňuje zápisy súborov pomocou atomického premenovania v cieľovom adresári. Opätovné otvorenie a `repair()` odstránia opustené dočasné súbory, ktorých vlastniaci proces už nebeží, a živé dočasné súbory zapisovateľov ponechajú. Značky zapisovateľov umožňujú túto kontrolu vykonať v konštantnom čase, takže ku skenovaniu kolekcie pri otvorení úložiska dôjde iba po páde.

`SegmentedLog` a `Queue` zapisujú riadky logu chránené dĺžkou a kontrolným súčtom. Opätovné otvorenie alebo oprava skrátia poškodený koniec po poslednú potvrdenú udalosť a obnovia stav v pamäti z trvalého obsahu logu. Zápisy do logu a frontu sa serializujú pomocou zámkov súborového systému.

Zmeny v `DocStore` sa serializujú pomocou zámku zápisu na úrovni kolekcie, takže súbory záznamov a sekundárne indexy sa medzi procesmi aktualizujú ako jeden konzistentný celok. Súbežné zápisy do rôznych ID záznamov sú bezpečné pri rovnakých predpokladoch o atomickom premenovaní súborov. Pri súbežných zápisoch s rovnakým ID vyhráva posledné premenovanie.

storh pred dokončením premenovania alebo pridania vyprázdni obslužné objekty súborov a zavolá fsync; po atomickom premenovaní sa pokúsi zavolať fsync aj na nadradených adresároch. Odolnosť voči výpadku napájania stále závisí od toho, či podkladový súborový systém a možnosti pripojenia rešpektujú tieto synchronizácie.
