
# البيانات المجمعة

تأخذ أساليب `*Many` مصفوفات وتعيد السجلات أو المعرّفات المنشأة؛ أما أساليب `*Stream` فتقبل أي عنصر قابل للتكرار، ولا تحتفظ بشيء في الذاكرة، وتعيد عدداً. استخدم التدفقات لمهام الإدخال التي يتجاوز حجم مدخلاتها ما تريده لمصفوفة PHP. تأخذ الأساليب المجمعة قفل المجموعة مرة واحدة، وتخزن مؤقتاً سجلات كثيرة لكل fsync في السجل وقائمة الانتظار، ما يجعل الكتابة المجمعة أسرع عدة مرات لكل سجل من الاستدعاءات المنفردة. أما عمليات الكتابة المجمعة في `DocStore` فتزامن كل ملف سجل؛ فهي توفر تكرار الأقفال، لا عمليات fsync.

واجهات DocStore المجمعة:

```php
$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 المجمعة:

```php
$log->appendMany([
    ['type' => 'page.saved'],
    ['type' => 'page.rendered'],
]);

$log->appendStream($largeIterable);
```

واجهات Queue المجمعة:

```php
$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/`)، كي يمكن أرشفة الفترات القديمة أو حذفها كمجلدات كاملة:

```php
$daily = new Storh\SegmentedLog($root, 'events', partition: 'daily');
$monthly = new Storh\SegmentedLog($root, 'events', partition: 'monthly');
```

يحذف الاحتفاظ سجلات السجل الأقدم من تاريخ القطع، ويضغط المساحة المستعادة؛ أما `purgeDone` فيحذف مهام قائمة الانتظار المكتملة من الذاكرة:

```php
$deleted = $log->retain()->olderThanDays(90)->compact();
$queue->purgeDone(olderThanSeconds: 86400);
```
