Storh
Înregistrări bazate pe fișiere pentru PHP: documente JSONC, jurnale segmentate doar pentru adăugare și cozi susținute de jurnale, cu id-uri UUIDv7.
composer require storh/storhCea mai recentă versiune v0.5.2 MIT PHP 8.2+
$pages = $docs
->query()
->where('kind')->eq('page')
->orderBy('title')
->limit(20)
->get();În practică
Ghidul de pornire rapidă în două părți: un document într-un director rădăcină de stocare, apoi o intrare în jurnal și o sarcină în coadă alături.
O rădăcină, trei motoare
StorageRoot::resolve() normalizează un director de bază și un spațiu de nume într-o rădăcină, iar fiecare motor își creează propriul director în interiorul acesteia la prima utilizare.
Fiecare motor returnează obiecte StorageRecord cu id() și data(). Coada adaugă fiecare revendicare și finalizare în jurnalul său de evenimente.
use Storh\DocStore;
use Storh\Queue;
use Storh\RecordQuery;
use Storh\SegmentedLog;
use Storh\StorageRoot;
$root = StorageRoot::resolve(__DIR__ . '/var/storh', 'demo');
$docs = new DocStore($root, 'pages');
$home = $docs->put([
'kind' => 'page',
'title' => 'Home',
]);
$loaded = $docs->get($home->id());$log = new SegmentedLog($root, 'events');
$log->put([
'type' => 'page.saved',
'pageId' => $home->id(),
]);
foreach ($log->stream(RecordQuery::all()->after($home->id())->limit(50)) as $record) {
// Process records lazily.
}
$queue = new Queue($root, 'jobs');
$jobId = $queue->enqueue(['task' => 'render', 'pageId' => $home->id()]);
$job = $queue->claim();
if (null !== $job) {
$queue->complete($job->id());
}Stocare de documente JSONC
Un fișier JSONC pentru fiecare înregistrare, id-uri UUIDv7, partiționare după două caractere din grupul final al UUID, înlocuire atomică și filtre de câmpuri transmise în flux.
Jurnal segmentat
Segmente doar cu adăugare, alcătuite din linii JSON prefixate cu lungimea și suma de control, indexuri rarefiate, citiri cu cursor și pe interval de timp, recuperare după căderi și compactare.
Coadă de jurnale
Sarcinile trec prin stările în așteptare, în procesare și finalizate, folosind evenimente compacte de coadă, doar cu adăugare.
Înregistrări UUIDv7
ID-uri sortabile, adresabile în timp, pentru cursoare stabile, scanări limitate și căi de stocare potrivite pentru shard-uri.
Scrieri atomice
Scrierile într-un fișier temporar și redenumirile atomice păstrează integritatea înregistrărilor. După blocarea unui proces de scriere, următoarea deschidere elimină fișierele temporare orfane.
Recuperare după scrieri incomplete
Citirile segmentelor validează câmpurile de lungime și checksum; recuperarea trunchiază liniile incomplete de la final.
Fișiere înainte de toate
Fără server de baze de date, fără adaptor pentru framework, fără pachete runtime Composer; apelanții transmit un director.
Citește JSONC
Fișierele înregistrărilor pot conține comentarii și virgule finale. Scrierile storh folosesc JSON compacte, pe o singură linie, așa că comentariile rămân până la următoarea scriere.
Generator de interogări
Interogări fluente precum where('status')->in([...]) în DocStore și SegmentedLog; DocStore folosește indexuri secundare acolo unde există.
Indexuri secundare
Indexuri de egalitate, unice și de interval, stocate ca fișiere lângă colecție, derivate din înregistrări și reconstruibile oricând.
Scheme
Schemele opționale ale colecțiilor validează fiecare scriere și declară câmpurile indexate.
SQL Mirror
Împingeți colecțiile în SQLite sau MySQL pentru îmbinări, căutare și raportare, păstrând fișierele drept sursă canonică. Necesită ext-pdo sau ext-mysqli doar când sunt folosite.
De ce Storh
Un director, nu un server
Transmiteți un director de bază, iar storh scrie acolo. Necesită PHP 8.2 și ext-json, fără pachete runtime Composer și fără adaptor pentru framework.
O formă de înregistrare, trei structuri
Documentele, jurnalele și cozile stochează toate un ID UUIDv7 și un tablou de date. Alegeți structura pe disc în funcție de sarcină și păstrați-le pe toate trei sub aceeași rădăcină.
Verificări pe care le puteți rula
verify() verifică indexurile și starea jurnalelor printr-o scanare completă a fișierelor. repair() pune în carantină înregistrările corupte și trunchiază finalurile incomplete ale jurnalelor, iar CLI afișează JSON pentru sarcinile cron și verificările de stare.
Benchmark-uri cu configurația aferentă
README publică medianele pentru 50,000 de înregistrări per motor, pe un Apple M1 Pro cu PHP 8.5, de exemplu 5.6 µs pentru o citire punctuală. Fiecare scriere din aceste rulări este sincronizată cu fsync, așa că ratele de scriere depind de sistemul de fișiere.
Comparativ cu
storh este o stocare bazată pe fișiere, nu un motor de interogare relațional, așa că aceste instrumente îndeplinesc unele sarcini pe care acesta nu le acoperă.
| Instrument | Potrivit pentru | Diferența față de Storh |
|---|---|---|
| SQLite | Potrivit pentruUn motor SQL autonom, într-un singur fișier, cu tranzacții ACID serializabile care rezistă la blocarea programului sau la o pană de curent. Documentația îl prezintă ca înlocuitor pentru fișierele de date ad-hoc. | Diferența față de Storhstorh păstrează un fișier JSON per înregistrare, iar nucleul său nu necesită driver PDO. Nu oferă tranzacții pentru mai multe înregistrări, iar documentația recomandă o bază de date adevărată pentru acest tip de operațiuni. Poate împinge colecțiile în SQLite pentru îmbinări și raportare, păstrând fișierele drept sursă canonică. |
| MySQL | Potrivit pentruO bază de date relațională deservită de un server SQL multithread, cu programe și biblioteci client, instrumente administrative și o gamă largă de API-uri. | Diferența față de Storhstorh rulează în procesul PHP, lucrând cu un director, așa că nu există un server de administrat. Pentru îmbinări, căutare și raportare, reflectă colecțiile în MySQL, inclusiv printr-un handle mysqli existent, iar fișierele rămân sursa adevărului. |
| SleekDB | Potrivit pentruO bază de date documentară cu fișiere plate în PHP, fără dependențe de la terți, care stochează date fără schemă în fișiere JSON simple. API pentru interogări include îmbinări, căutare text, group by și having, precum și filtre pentru proprietăți imbricate. | Diferența față de Storhstorh asociază depozitului de documente un jurnal segmentat, doar cu adăugare, și o coadă bazată pe jurnal, toate sub aceeași rădăcină, și folosește fsync pentru fiecare scriere înainte de a confirma stocarea. Îmbinările nu fac parte din storh; pentru acestea, împinge colecțiile în SQLite sau MySQL. |
Întrebări și răspunsuri
Răspunsuri scurte din documentația Storh.
Da. DocStore serializează modificările cu o blocare la nivel de colecție, iar scrierile concurente pentru același ID folosesc regula „ultima redenumire câștigă”. Revendicările din coadă păstrează blocarea cozii, astfel încât doi lucrători să nu revendice aceeași sarcină în așteptare.
Da. Citirile acceptă comentarii și virgule finale, dar următoarea scriere put() pentru acel ID rescrie fișierul într-un format JSON compact și le elimină. În modul cache TRUST, modificările fișierelor făcute în afara storh nu sunt detectate.
Citirile punctuale după ID rămân rapide atât timp cât sistemul de fișiere poate gestiona numărul de fișiere. Scanările câmpurilor DocStore fără index încetinesc peste aproximativ 10k de înregistrări, așa că declarați indexuri pentru câmpurile după care filtrați. Scanările jurnalelor segmentate și citirile pe intervale rămân eficiente până la aproximativ 1M de înregistrări.
Scrierile sunt sincronizate cu fsync și publicate prin redenumire atomică, iar redeschiderea unui jurnal sau a unei cozi trunchiază finalurile incomplete până la ultimul eveniment confirmat. Durabilitatea în cazul unei pene de curent depinde în continuare de respectarea acestor sincronizări de către sistemul de fișiere și opțiunile de montare.
Nu. Împingeți colecțiile în SQLite sau MySQL cu SqlMirror pentru îmbinări, căutare și raportare. Scrierile atomice pentru mai multe înregistrări rămân o sarcină pentru o bază de date adevărată, folosită ca sistem de evidență.
Nu. Queue nu este un depozit general de înregistrări, iar conținutul unei sarcini este eliminat după finalizare.
Începeți cu ghidul de pornire rapidă, apoi folosiți Alegerea unui motor pentru a potrivi DocStore, SegmentedLog sau Queue cu sarcina dumneavoastră.