البيانات المجمعة
تأخذ أساليب *Many مصفوفات وتعيد السجلات أو المعرّفات المنشأة؛ أما أساليب *Stream فتقبل أي عنصر قابل للتكرار، ولا تحتفظ بشيء في الذاكرة، وتعيد عدداً. استخدم التدفقات لمهام الإدخال التي يتجاوز حجم مدخلاتها ما تريده لمصفوفة PHP. تأخذ الأساليب المجمعة قفل المجموعة مرة واحدة، وتخزن مؤقتاً سجلات كثيرة لكل fsync في السجل وقائمة الانتظار، ما يجعل الكتابة المجمعة أسرع عدة مرات لكل سجل من الاستدعاءات المنفردة. أما عمليات الكتابة المجمعة في DocStore فتزامن كل ملف سجل؛ فهي توفر تكرار الأقفال، لا عمليات fsync.
واجهات DocStore المجمعة:
$records = $docs->putMany([
['slug' => 'home', 'kind' => 'page'],
['slug' => 'about', 'kind' => 'page'],
]);
$count = $docs->putStream($largeIterable);
$docs->exportJsonl(__DIR__ . '/pages.jsonl');
$docs->importJsonl(__DIR__ . '/pages.jsonl');
تكون صفوف JSONL كائناً واحداً في كل سطر، إما {"id": "...", "data": {...}} أو كائن بيانات مجرداً (ويُنشأ معرّف عند الاستيراد). يمكن أن تتضمن الصفوف معرّفات صريحة، لذا يعيد التصدير والاستيراد المجموعة كما هي تماماً.
واجهات SegmentedLog المجمعة:
$log->appendMany([
['type' => 'page.saved'],
['type' => 'page.rendered'],
]);
$log->appendStream($largeIterable);
واجهات Queue المجمعة:
$queue->enqueueMany([
['task' => 'render', 'pageId' => $home->id()],
['task' => 'notify', 'pageId' => $home->id()],
]);
$jobs = $queue->claimMany(100);
$queue->completeMany(array_map(fn ($job) => $job->id(), $jobs));
تضع الأقسام الاختيارية مقاطع السجل ضمن مجلد بحسب اليوم أو الشهر (events/partitions/2026-07-05/)، كي يمكن أرشفة الفترات القديمة أو حذفها كمجلدات كاملة:
$daily = new Storh\SegmentedLog($root, 'events', partition: 'daily');
$monthly = new Storh\SegmentedLog($root, 'events', partition: 'monthly');
يحذف الاحتفاظ سجلات السجل الأقدم من تاريخ القطع، ويضغط المساحة المستعادة؛ أما purgeDone فيحذف مهام قائمة الانتظار المكتملة من الذاكرة:
$deleted = $log->retain()->olderThanDays(90)->compact();
$queue->purgeDone(olderThanSeconds: 86400);