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: 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 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 aclaimMany()/completeMany()rozkladajú náklady na zámky a fsync. - Spájanie, vyhľadávanie alebo vykazovanie nad ľubovoľnou kolekciou: pridajte zrkadlo SQL. 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:
$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:
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). 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.
$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.
$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.