انتقل إلى المحتوى

التجزئة

يكتب DocStore ملفًا واحدًا لكل سجل. من دون التجزئة، ستتكدس ملفات المجموعة الكبيرة في دليل واحد، ويتباطأ التعامل مع الدليل مع زيادة عدد مدخلاته. لذلك يوزع storh ملفات السجلات على مجموعات وفق حرفين من معرّف السجل:

Text
pages/data/2d/018bcfe5-6800-7000-8000-2d5dba6274da.jsonc

يُؤخذ تصنيف المجموعة من بداية المجموعة الأخيرة في UUID (الحرفان 24 و25)، وهي بيانات عشوائية. يوفر حرفان سداسيان عشريان 256 مجموعة، لذا يبلغ متوسط الملفات في كل دليل أقل من 400 عند وجود 100k سجل.

لماذا الذيل وليس الرأس

تبدأ معرّفات UUIDv7 بطابع زمني بدقة المللي ثانية من 48 بت، لذا تشترك المعرّفات المنشأة في أوقات متقاربة في أحرفها الأولى. كانت التجزئة بحسب البادئة ستوجه كل دفعة كتابة إلى الدليل المزدحم نفسه، ولا تتبدل المجموعات إلا مع مرور الوقت. أما بايتات الذيل فعشوائية لكل سجل، لذا تتوزع الكتابات بالتساوي منذ أول سجل.

لا تؤثر التجزئة في القراءة والاستعلامات: يحسب get() المجموعة انطلاقًا من المعرّف، ويعيد stream() السجلات مرتبة حسب المعرّف عبر جميع المجموعات، فتعمل تقسيمات الصفحات بالمؤشر كما لو كانت المجموعة قائمة مرتبة واحدة.

عند التوسع

لا يزداد عدد المجموعات أبدًا: فالحرفان السداسيان العشريان يعنيان 256 دليلًا مهما بلغ حجم المجموعة. ما يزداد هو عدد الملفات في كل مجموعة:

السجلات الملفات لكل مجموعة
10k ~40
100k ~390
1M ~3,900
10M ~39,000

تفهرس أنظمة الملفات الحديثة إدخالات المجلدات، لذا فإن الاحتفاظ ببضعة آلاف من الملفات لكل حاوية يُبقي عمليات البحث المباشر سريعة؛ ويُعد مليون سجل حجمًا مريحًا لـ get() والاستعلامات المفهرسة. يستغرق فتح مخزن وقتًا ثابتًا مهما كان حجم المجموعة: ولا يجري مسح الملفات المؤقتة المتروكة إلا عندما يشير ملف علامة كاتب متوقف إلى أن عملية سابقة تعطلت أثناء الكتابة. أما العمليات التي يزداد وقتها خطيًا مع الحجم فهي العمليات على المجموعة بأكملها: عمليات المسح غير المفهرسة، وreindex()، وverify()؛ إذ تمر كل منها على ملفات السجلات كافة، لذا تعامل معها كمهام دفعية. عندما يتجاوز عدد السجلات في المجموعة نحو 10 ملايين، تبدأ أعداد الملفات لكل حاوية وإجمالي استخدام العُقد في الأهمية: قسّم المجموعات، أو استخدم السجل المجزأ للبيانات الملائمة للمسح، فهو يُبقي أعداد الملفات منخفضة بطبيعته.

المحركات الأخرى

لا يقوم SegmentedLog وQueue بتقسيم البيانات، لأنهما لا ينشئان ملفًا لكل سجل. يضيف السجل البيانات إلى ملفات المقاطع ضمن segments/، بحد أقصى تحدده max_segment_bytes (1 MiB افتراضيًا)، بينما يضيف طابور المهام الأحداث إلى queue.log واحد. وتظل أعداد الملفات منخفضة بطبيعتها.