Storh
Bestandsgerichte records voor PHP: JSONC-documenten, append-only gesegmenteerde logs en loggestuurde wachtrijen met UUIDv7-ID's.
composer require storh/storhNieuwste release v0.5.2 MIT PHP 8.2+
$pages = $docs
->query()
->where('kind')->eq('page')
->orderBy('title')
->limit(20)
->get();In de praktijk
De snelstart in twee delen: eerst een document in een opslagroot, daarna een logitem en een wachtrijtaak ernaast.
Eén root, drie engines
StorageRoot::resolve() normaliseert een basismap en namespace tot één root; elke engine maakt bij het eerste gebruik een eigen map daarin aan.
Elke engine retourneert StorageRecord-objecten met id() en data(). De wachtrij voegt elke claim en voltooiing toe aan het eventlog.
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());
}JSONC-documentstore
Eén JSONC-bestand per record, ID's van UUIDv7, sharding op basis van twee tekens uit de laatste groep van UUID, atomair vervangen en streamingfilters op velden.
Gesegmenteerd log
Append-only segmenten met JSON-regels voorafgegaan door lengte en controlesom, ijle indexen, cursor- en tijdsbereiklezingen, herstel na crashes en verdichting.
Logwachtrij
Taken doorlopen de statussen in behandeling, in verwerking en voltooid met compacte, append-only wachtrijevents.
UUIDv7-records
Sorteerbare, op tijd opvraagbare ID's voor stabiele cursors, begrensde scans en opslagpaden die geschikt zijn voor sharding.
Atomaire schrijfbewerkingen
Schrijfbewerkingen via tijdelijke bestanden en atomaire hernoemingen houden records intact. Na een crash van een schrijvend proces ruimt de volgende keer openen de verweesde tijdelijke bestanden op.
Herstel van onvolledige schrijfbewerkingen
Bij het lezen van segmenten worden velden voor lengte en controlesom gevalideerd; herstel verwijdert onvolledige regels aan het einde.
Bestandsgericht
Geen databaseserver, geen frameworkadapter en geen Composer-runtimepakketten; u geeft een map door.
Lezen accepteert JSONC
Recordbestanden mogen commentaar en afsluitende komma's bevatten. storh schrijft compacte JSON op één regel, dus commentaar blijft behouden tot de volgende schrijfopdracht.
Querybuilder
Vloeiende queries zoals where('status')->in([...]) voor DocStore en SegmentedLog; DocStore gebruikt secundaire indexen als die beschikbaar zijn.
Secundaire indexen
Gelijkheids-, unieke en bereikindexen worden als bestanden naast de collectie opgeslagen, van records afgeleid en zijn altijd opnieuw op te bouwen.
Schema's
Optionele collectieschema's valideren elke schrijfopdracht en geven aan welke velden indexen krijgen.
SQL Mirror
Push collecties naar SQLite of MySQL voor joins, zoeken en rapportages, terwijl de bestanden canoniek blijven. ext-pdo of ext-mysqli is alleen nodig wanneer u deze functie gebruikt.
Waarom Storh
Een map, geen server
U geeft een basismap door en storh schrijft daarin. Het vereist PHP 8.2 en ext-json, zonder Composer-runtimepakketten of frameworkadapter.
Eén recordstructuur, drie indelingen
Documenten, logs en wachtrijen slaan allemaal een UUIDv7-ID plus een array met gegevens op. Kies de schijfindeling per workload en bewaar ze alle drie onder één root.
Controles die u zelf kunt uitvoeren
verify() controleert indexen en de status van het log aan de hand van een volledige scan van de bestanden. repair() plaatst corrupte records in quarantaine en kapt beschadigde logeindes af; de CLI toont JSON voor cron-taken en gezondheidscontroles.
Benchmarks met hun configuratie
De README publiceert medianen voor 50,000 records per engine op een Apple M1 Pro met PHP 8.5, bijvoorbeeld 5.6 µs per opzoeking op basis van ID. Elke schrijfopdracht in die runs wordt met fsync vastgelegd, dus de schrijfsnelheid hangt af van het bestandssysteem.
Vergeleken met
storh is bestandsgerichte opslag, geen relationele query-engine, en deze tools doen daarom een aantal dingen die het niet biedt.
| Tool | Goed in | Verschil met Storh |
|---|---|---|
| SQLite | Goed inEen zelfstandige SQL-engine in één bestand, met serialiseerbare ACID-transacties die ook bij een programma-crash of stroomuitval intact blijven. De documentatie presenteert het als vervanging voor ad-hocdatabestanden. | Verschil met Storhstorh bewaart één JSON-bestand per record en heeft voor de kern geen PDO-driver nodig. Er zijn geen transacties voor meerdere records; de documentatie raadt aan daarvoor een echte database te gebruiken. Collecties kunnen naar SQLite worden gepusht voor joins en rapportages, terwijl de bestanden canoniek blijven. |
| MySQL | Goed inEen relationele database die wordt aangeboden door een multithreaded SQL-server, met clientprogramma's en bibliotheken, beheerprogramma's en een breed scala aan API's. | Verschil met Storhstorh draait binnen het PHP-proces en werkt met een map, dus er is geen server die u moet beheren. Voor joins, zoeken en rapportages spiegelt het collecties naar MySQL, ook via een bestaande mysqli-handle; de bestanden blijven de bron van waarheid. |
| SleekDB | Goed inEen documentdatabase met platte bestanden in PHP, zonder afhankelijkheden van derden, die schemaloze gegevens opslaat als gewone JSON-bestanden. De query-API omvat joins, zoeken in tekst, group by en having, en filters op geneste eigenschappen. | Verschil met Storhstorh combineert een documentstore met een append-only gesegmenteerd log en een loggestuurde wachtrij onder één hoofdmap, en voert bij elke schrijfactie eerst fsync uit voordat het meldt dat de gegevens zijn opgeslagen. Joins maken geen deel uit van storh; daarvoor stuurt het collecties door naar SQLite of MySQL. |
Vragen en antwoorden
Korte antwoorden uit de documentatie van Storh.
Ja. DocStore serialiseert wijzigingen met een schrijversvergrendeling op collectieniveau; bij gelijktijdige schrijfbewerkingen naar dezelfde ID wint de laatste hernoeming. Claims in de wachtrij houden de wachtrijvergrendeling vast, zodat twee workers niet dezelfde openstaande taak claimen.
Ja. Bij het lezen worden commentaar en afsluitende komma's geaccepteerd, maar de volgende put() naar die ID herschrijft het bestand als compacte JSON en verwijdert ze. In de TRUST-cachemodus worden wijzigingen aan bestanden buiten storh niet gedetecteerd.
Opzoeken op ID blijft snel zolang het bestandssysteem het aantal bestanden aankan. Niet-geïndexeerde veldscans van DocStore worden trager bij meer dan ongeveer 10k records; declareer daarom indexen voor de velden waarop u filtert. Scans en bereiklezingen van gesegmenteerde logs werken goed tot ongeveer 1M records.
Schrijfbewerkingen worden met fsync vastgelegd en gepubliceerd via een atomaire hernoeming; bij het opnieuw openen van een log of wachtrij worden beschadigde eindes afgekapt tot de laatste bevestigde event. De duurzaamheid bij stroomuitval hangt nog steeds af van de mate waarin het bestandssysteem en de mountopties deze synchronisaties uitvoeren.
Nee. Push collecties met SqlMirror naar SQLite of MySQL voor joins, zoeken en rapportages. Atomair schrijven van meerdere records blijft een taak voor een echte database die als bronsysteem dient.
Nee. Queue is geen algemene recordstore en de payload van een taak wordt verwijderd zodra de taak is voltooid.
Begin met de snelstartgids en gebruik daarna Engine kiezen om DocStore, SegmentedLog of Queue op uw workload af te stemmen.