Skip to content
KitploitKITPLOIT
أدواتالمدونة
إرسال
أدواتالمدونة
إرسال

أدوات الاختراق واختبار الاختراق والأمن السيبراني لترسانتك الأمنية!

Kitploit هو دليل لأدوات الاختراق والأمن السيبراني واختبار الاختراق. اكتشف آخر تحديثات المشاريع للعثور على الثغرات وتحليل الأنظمة وأتمتة الاختبارات وتعزيز أمنك.

··الخلاصات·اتصال·الخصوصية·© 2026 Kitploit

دليل الأدوات

الفئات

عرض جميع الفئات
Loading categories
turbolite — SQLite VFS مع استعلامات JOIN باردة من S3 بأقل من 100 مللي ثانية + ضغط وتشفير على مستوى الصفحات | Kitploit
أدوات/GitHubGitHub/russellromney/turbolite
أدوات التشفير/فك التشفيرالتشفيرأمن السحابةالأدوات والمكوناتأمن قواعد البيانات
GitHubrussellromney/turbolite

turbolite

SQLite VFS مع استعلامات JOIN باردة من S3 بأقل من 100 مللي ثانية + ضغط وتشفير على مستوى الصفحات

عرض المستودع
48012منذ 2 أشهرتمت المراجعة من قبل Kitploit

الأكثر شعبية

عرض الكل →

اكتشف الأدوات الأكثر استخدامًا من قبل مجتمعنا.

استكشف جميع الأدوات

تصفح مجموعتنا من الأدوات

عرض جميع الأدوات →
مشاركة

turbolite

turbolite هي VFS (نظام ملفات افتراضي) لـ SQLite مكتوبة بلغة Rust تقدم عمليات بحث نقطية و JOIN مباشرة من S3 بزمن استجابة بارد أقل من 250 مللي ثانية.

هذا المستودع هو مساحة عمل Cargo تحتوي على حزمتين:

  • turbolite — مكتبة Rust خالصة. VFS لـ SQLite مع ضغط على مستوى الصفحات، تشفير، وتصنيف إلى S3.
  • turbolite-ffi — واجهة C FFI / إضافة قابلة للتحميل + روابط لغوية (Python، Node.js، Go).

كما تقدم ضغطًا على مستوى الصفحات (zstd) وتشفيرًا (AES-256) للكفاءة والأمان أثناء التخزين، ويمكن استخدامها بشكل منفصل عن S3.

تجريبي. turbolite قيد التطوير النشط ويحتوي على أخطاء. كن حذرًا.

تخزين الكائنات أصبح سريعًا. S3 Express One Zone يوفر عمليات GET بزمن استجابة أحادي الرقم بالميلي ثانية و Tigris سريع للغاية أيضًا. الفجوة بين القرص المحلي والتخزين السحابي تتقلص، و turbolite تستغل ذلك.

التصميم والاسم مستوحى من نهج turbopuffer في البناء بصرامة حول قيود التخزين السحابي. الهدف الأولي للمشروع كان التغلب على بدء التشغيل البارد الذي يتجاوز 500 مللي ثانية لـ Neon. الهدف تحقق.

إذا كان لديك قاعدة بيانات واحدة لكل خادم، استخدم وحدة تخزين. turbolite تستكشف كيفية امتلاك مئات أو آلاف قواعد البيانات (واحدة لكل مستأجر، واحدة لكل مساحة عمل، واحدة لكل جهاز)، ولا ترغب في وحدة تخزين لكل منها، وتقبل وجود مصدر كتابة واحد.

يتم شحن turbolite كمكتبة Rust، و إضافة قابلة للتحميل لـ SQLite (.so/.dylib)، وحزم لغات لـ Python و Node.js، بالإضافة إلى تبعيات Github لـ Go. أي تخزين متوافق مع S3 يعمل (AWS S3، Tigris، R2، MinIO، إلخ). إنها VFS قياسية لـ SQLite تعمل على مستوى الصفحات، لذا يجب أن تعمل معظم ميزات SQLite: FTS، R-tree، JSON، وضع WAL، إلخ.

turbolite جزء من النظام البيئي الأوسع hadb. turbolite المستقلة هي VFS تخزين مع كاتب آمن واحد؛ إذا كنت تريد انتخاب القائد عالي التوفر بالإضافة إلى نسخ WAL المستمر، استخدمها من خلال haqlite-turbolite، التي تضيف HaQLite و walrust فوقها. هذا المسار عالي التوفر لا يزال تجريبيًا جدًا.

إذا كنت ترغب في المساهمة في turbolite أو العثور على أخطاء، يرجى إنشاء طلب سحب أو فتح مشكلة.

الأداء

1M منشور / 100K مستخدم (~1.5GB مخزن) مع عدم تخزين أي شيء مؤقتًا، كل بايت من S3. EC2 c5.2xlarge + S3 Express One Zone (نفس منطقة التوفر، ~4ms زمن استجابة GET). Fly performance-8x + Tigris (~25ms زمن استجابة GET). كلاهما: 8 vCPU مخصصة، 16GB RAM، 7 خيوط عمل جلب مسبق. انظر قياس الأداء و مهمة الواجهة الخلفية للتخزين.

يتم تنظيم المقاييس حسب مستوى التخزين المؤقت (ما هو موجود بالفعل على القرص المحلي عند تشغيل الاستعلام):

الداخلي هو المعيار الأكثر واقعية للبرودة: يتم تحميل الصفحات الداخلية بفارغ الصبر عند فتح الاتصال، لذا بحلول وقت تشغيل أول استعلام، تكون مخبأة. يتم جلب صفحات الفهرس بقوة في الخلفية عند أول وصول وقد لا تكون جاهزة بعد.

ذاكرة تخزين مؤقت دافئة (النفقات العامة لـ VFS مقابل SQLite العادي)

100K صف، Fly.io performance-2x (vCPU مخصصة، NVMe، IAD):

عمليات البحث النقطي لديها أعلى نفقات عامة لكل صفحة (~2x). كل شيء آخر يحقق التعادل أو يتجاوزه. بنية التخزين المؤقت الخالية من الأقفال تعني أن القراءات المتزامنة لا تمنع الكتابة أبدًا.

تكلفة نقطة التفتيش

بعدمحليS3 (RustFS في نفس المنطقة)
1K إدخالات19ms38ms
10K دفعة17ms114ms
1K تحديثات9ms36ms

الكتابة دائمًا بسرعة محلية. تكلفة S3 تكون فقط عند نقطة التفتيش. الأرقام مع RustFS في نفس منطقة Fly (~2ms RTT). S3 Express One Zone سيكون مشابهًا.

بداية سريعة

Python```bash

pip install turbolite

root@kitploit:~

curl -X POST http://127.0.0.1:5000/update
-H "Content-Type: application/x-www-form-urlencoded"
-d 'username=test&password=test&new_password=newpassword'

root@kitploit:~

سيقوم هذا الأمر بتعيين كلمة مرور جديدة للمستخدم `test`.

## الميزات

- **مصادقة المستخدم**: تسجيل دخول آمن باستخدام اسم المستخدم وكلمة المرور.
- **تحديث كلمة المرور**: تغيير كلمة المرور للمستخدمين الموثَّقين.
- **استرجاع العَلَمة**: الحصول على العَلَمة (flag) للمستخدم المسؤول.
- **ميزات الأمان**:
  - تحديد معدل المحاولات لتسجيل الدخول.
  - التحقق من صحة الإدخال لجميع الحقول.
  - إدارة الجلسات باستخدام رموز JWT.
  - تجزئة كلمة المرور باستخدام bcrypt.

## التثبيت

1. استنساخ المستودع:
   ```bash
   git clone https://github.com/example/repo.git
   cd repo
  1. تثبيت التبعيات:
    root@kitploit:~
    pip install -r requirements.txt
    
  2. تشغيل التطبيق:
    root@kitploit:~
    python app.py
    ``````python
    

import turbolite

conn = turbolite.connect("my.db", mode="s3", bucket="my-bucket", endpoint="https://t3.storage.dev")

conn.execute("CREATE TABLE users (id INTEGER PRIMARY KEY, name TEXT, email TEXT)") conn.execute("INSERT INTO users VALUES (1, 'alice', '[email protected]')") conn.commit()

alice = conn.cursor().execute("SELECT * FROM users").fetchone() print(alice[1])

"alice"

root@kitploit:~
انظر [التثبيت](#installation) لـ Node، Go، Rust، الوضع المحلي فقط، واستخدام الامتداد القابل للتحميل `.so` مباشرة

## التصميم

صُممت turbolite لقيود S3 بدلاً من قيود نظام الملفات. كل قرار ينبع من هذا النموذج:

| قيد S3 | التأثير |
|--------|---------|
| **رحلة الذهاب والإياب بطيئة** | قلل عدد الطلبات. اكتب بشكل مجمع، اقرأ مسبقاً بشكل هجومي. |
| **عرض النطاق هو عنق الزجاجة** | عزز استخدام عرض النطاق الترددي إلى أقصى حد. |
| **عمليات PUT و GET تُفرض رسوم لكل عملية** | تكلفة GET بحجم 64KB نفس تكلفة GET بحجم 16MB. حسّن عدد الطلبات، وليس كفاءة البايت. |
| **الكائنات غير قابلة للتعديل** | لا تقم بالتحديث في المكان. اكتب إصدارات جديدة، بدّل المؤشر. لا تلف ناتج عن الكتابة الجزئية. |
| **التخزين رخيص** | لا تحسّن للمساحة. وفّر في التجهيز، احتفظ بالإصدارات القديمة، واترك لمجمع القمامة التنظيف لاحقاً. |

### الهندسة المعمارية

تضيف turbolite طبقات من الفحص الداخلي والإعادة التوجيه بين SQLite و S3 تقوم بتجميع الصفحات وضغطها وتتبعها وجلبها بكفاءة.

يستخدم SQLite فهرس B-tree ويطلب صفحة واحدة في كل مرة. يعلم أن الصفحة N تقع عند الإزاحة البايتية `N * page_size`. وهذه الصفحات موزعة عشوائياً على خريطة الصفحات للوصول العشوائي الفعال. لكن على S3، جلب صفحة واحدة لكل طلب يعني آلاف عمليات GET العشوائية المحتملة لكل استعلام.

لكن الصفحات ليست متساوية. يحتوي SQLite على أنواع مختلفة من الصفحات. تفصل turbolite **مجموعات الصفحات حسب النوع**: الصفحات الداخلية لـ B-tree، وصفحات أوراق الفهرس، وصفحات أوراق البيانات.

يتم الوصول إلى الصفحات الداخلية في كل استعلام لتوجيه عمليات البحث إلى صفحات الأوراق. تكتشفها turbolite، وتخزنها في حزم مضغوطة في S3، وتحمّلها بشغف عند فتح VFS. بعد ذلك، كل مسار B-tree يصبح ضربة مخبأ.

تحصل صفحات أوراق الفهرس على نفس المعاملة: حزم منفصلة، جلب مسبق كسول في الخلفية، مثبتة ضد الإخراج. الاستعلامات الباردة تحتاج فقط إلى جلب صفحات البيانات.

تستفيد turbolite من **الفحص الداخلي لـ B-tree** لفهم *أي شجرة (جدول أو فهرس) تنتمي إليها الصفحة*، وتخزين تلك الصفحات معاً بذكاء في S3 كـ **مجموعات صفحات**: العديد من الصفحات مجزأة في كائن S3 واحد. كبيرة بما يكفي لتشبع عرض النطاق عند الجلب المسبق، وصغيرة بما يكفي للاستعلامات النقطية. الافتراضي: 256 صفحة لكل مجموعة، حوالي 16MB بصفحات 64KB.

تخزين نفس الجدول/الفهرس معاً يعني أننا نقوم بأقل عدد ممكن من عمليات GET للاستعلامات الباردة.

تقوم turbolite **بتوجيه عمليات بحث الصفحات عبر ملف بيان** هو مصدر الحقيقة حول مكان كل صفحة. يستبدل علاقة SQLite الضمنية `offset = page * size` بمؤشرات صريحة. لا يتم أبداً استبدال إصدارات مجموعة الصفحات القديمة؛ وضع البيان هو نقطة الالتزام الذرية. تصبح الإصدارات القديمة قمامة، ويتم تنظيفها بواسطة `gc()`.

يستخدم SQLite افتراضياً صفحات بحجم 4KB لمطابقة حجم صفحة قرص نظام الملفات. على S3، حجم صفحة القرص غير ذي صلة. المهم هو تقليل عدد الطلبات وتعظيم انتشار B-tree. الإجابة هي **صفحات كبيرة**: تستخدم turbolite افتراضياً صفحات بحجم 64KB. صفحات أقل = رحلات ذهاب وإياب أقل في S3 للوصول إلى ورقة.

لتسريع الاستعلامات النقطية، تستخدم turbolite **ضغطاً قابلاً للبحث**: كل مجموعة صفحات مشفرة كـ **إطارات zstd** متعددة (حوالي 4 صفحات لكل إطار). يخزن ملف البيان إزاحات البايت لكل إطار، لذا تجلب ضربة مخبأ مفقودة فقط الجزء الفرعي ~256KB الذي يحتوي على الصفحة المطلوبة عبر GET نطاق S3، وليس المجموعة بأكملها.

للجلب المسبق طبقتان: **استباقي** (التنبؤ بخطة الاستعلام) و **تفاعلي** (تكيفي يعتمد على الأخطاء).

**التنبؤ بخطة الاستعلام** يعمل أولاً. قبل تنفيذ الاستعلام، تعترض turbolite خطة استعلام SQLite عبر `EXPLAIN QUERY PLAN`، وتستخرج بالضبط الجداول والفهارس التي سيلمسها الاستعلام، وتُرسل جميع مجموعات صفحاتها إلى تجمع الجلب المسبق قبل حتى قراءة الصفحة الأولى. عملية JOIN من خمسة جداول كانت ستؤدي إلى خمس سلاسل متتالية من خطأ ثم جلب، لكنها بدلاً من ذلك تشعل جميع عمليات الجلب الخمسة بشكل متوازٍ في بداية الاستعلام. بالنسبة لاستعلامات `SCAN`، يعني هذا أن الجدول بأكمله يُجلب مسبقاً من البداية.

> تنبيه: يدعم SQLite استدعاء تتبع واحد لكل اتصال. إذا طالب إضافة أخرى بالفتحة أولاً، يتراجع التنبؤ بصمت إلى الجلب المسبق التفاعلي.

**الجلب المسبق التفاعلي** يعالج ما يفوته التنبؤ ويعمل كبديل احتياطي. عند خطأ في المخبأ، يحدث أمران في وقت واحد:
1. **GET نطاق مضمن**: جلب الجزء الفرعي المحدد الذي يحتوي على الصفحة المطلوبة، وإعادتها فوراً إلى SQLite.
2. **جلب مسبق في الخلفية**: إرسال مجموعات شقيقة *لذلك الشجرة* إلى تجمع الجلب المسبق وفقاً لجدول.

تُتتبع عدادات الأخطاء **لكل B-tree، وليس عالمياً**. استعلام ملف تعريف يضرب `users` (خطأ 1) ثم `posts` (خطأ 1) يتتبع كل شجرة بشكل صحيح عند 1، وليس 2. هذا يمنع استعلام JOIN متعدد الجداول من تصعيد الجلب المسبق عن طريق الخطأ على كل شجرة فقط لأنه يلمس عدة أشجار.

كل خطأ متتالي يتقدم عبر **جدول جلب مسبق** يتحكم في أي جزء من مجموعات نفس الشجرة سيتم جلبه مسبقاً. تختار turbolite جدولاً تلقائياً بناءً على خطة الاستعلام:
- **جدول البحث** `[0.3, 0.3, 0.4]`: لاستعلامات `SEARCH ... USING INDEX` التي تمسح أجزاء غير معروفة من الفهارس. عدواني من أول خطأ لأننا لا نعرف كم من الفهرس سيتم مسحه.
- **جدول الاستعلام النقطي** `[0.0, 0.0, 0.0]`: للاستعلامات النقطية وعمليات بحث الفهرس التي تصيب 1-2 صفحات لكل شجرة. ثلاث فرص مجانية قبل أي جلب مسبق. الجداول ذات الأصفار الثقيلة تتفوق على الصعود المبكر في كل من S3 Express و Tigris.

يمكنك ضبط جدول الجلب المسبق عند الفتح عن طريق تعيين `prefetch.search` / `prefetch.lookup` على `TurboliteConfig` - أنت تعرف شكل الحمل المتوقع، لذا لا يحتاج VFS إلى التخمين. انظر [تكوين الجلب المسبق](#configuring-prefetch).

كلا الجدولين يستفيدان من الفحص الداخلي لـ B-tree: كل مجموعة تم جلبها مسبقاً مضمونة أن تحتوي على صفحات من الشجرة الصحيحة. مثال: إذا طلب SQLite صفحة من جدول `users`، ثم طلب أخرى من نفس الجدول، تفترض turbolite أن مسحاً قادماً وتجلب مسبقاً بقية جدول `users` في الخلفية، ولا شيء آخر. بدون الفحص الداخلي لـ B-tree، كانت ستجلب عن طريق الخطأ نصف جدول users ونصف جدول posts فقط لأن البيانات تعيش بجانب بعضها على القرص.

**النظر إلى الأمام في أوراق الفهرس** يفعل الشيء نفسه لـ `SEARCH` المفهرس. ورقة الفهرس تدرج بالفعل rowids الجدول التي سيطلبها SQLite بعد ذلك — لذا تقوم turbolite بحلها من خلال الصفحات الداخلية المخزنة وتجلب تلك الإطارات من الجدول دفعة واحدة بدلاً من واحدة تلو الأخرى، مما يقلل عدد الطلبات.

### مخبأ الصفحات في الذاكرة

لدى turbolite مخبأ صفحات خاص بها في الذاكرة يحل محل مخبأ الصفحات المدمج في SQLite. يخبئ مُجدول صفحات SQLite الصفحات داخلياً ولا يقرأ أبداً من VFS للصفحات المخبأة. هذا جيد لقواعد بيانات ذات كاتب واحد، لكن لنسخ القراءة المتماثلة (متابعي HA، قراء استقصاء البيان)، يصبح مخبأ SQLite قديماً عندما تتغير البيانات الأساسية عبر النسخ المتماثل.

مخبأ turbolite **مدرك للبيان**: عندما يتم تشغيل `set_manifest()` (بيانات جديدة من النسخ المتماثل)، فإنه يبطل الصفحات المتأثرة في كل من مخبأ القرص ومخبأ الذاكرة. الكتابات أيضاً تبطل صفحاتها في مخبأ الذاكرة. هذا يضمن قراءات جديدة بعد النسخ المتماثل أو الكتابات.

**الهندسة المعمارية:**```
SQLite (PRAGMA cache_size=0)
  -> turbolite VFS xRead
    -> in-memory page cache (64MB default, AtomicPtr, zero-lock reads)
      -> disk cache (NVMe pread)
        -> S3 (on miss)

الإعدادات:

  • cache.mem_budget في TurboliteConfig (بايت). الافتراضي: 64 ميجابايت.
  • متغير البيئة TURBOLITE_MEM_CACHE_BUDGET (مثال: 128MB، 1GB).
  • اضبط على 0 لتعطيل ذاكرة التخزين المؤقت في الذاكرة تمامًا.

يقوم turbolite.connect() (Python/Go/TypeScript) تلقائيًا بتعطيل ذاكرة التخزين المؤقت للصفحات في SQLite ويستخدم بدلاً منها ذاكرة turbolite. يجب على مستخدمي Rust الذين يستخدمون Connection::open_with_flags_and_vfs مباشرةً تعيين PRAGMA cache_size=0 للحصول على نفس السلوك.

التشفير والضغط

الضغط

يتم ضغط جميع البيانات باستخدام zstd قبل التخزين. تستخدم مجموعات الصفحات ترميزًا متعدد الإطارات قابلاً للبحث يقوم بضغط كل إطار بشكل مستقل (~4 صفحات، ~256 كيلوبايت)، لذا فإن البحث النقطي يفك ضغط الإطار ذي الصلة فقط بدلاً من مجموعة الصفحات بأكملها. يمكن لقواميس zstd المخصصة تحسين نسب الضغط بشكل أكبر.

يقوم الوضع المحلي (غير S3) أيضًا بالضغط على مستوى الصفحة باستخدام zstd. راجع CLI للحصول على أدوات تدريب القاموس.

التشفير

إذا تم تمكين التشفير، يقوم turbolite بتشفير كل شيء: كائنات S3، ذاكرة التخزين المؤقت المحلية، WAL، البيانات الوصفية. تستخدم بيانات S3 تشفير AES-256-GCM مع nonces عشوائية لكل إطار (مصادقة، كشف التلاعب). تستخدم البيانات المحلية تشفير AES-256-CTR بدون زيادة في حجم البيانات. يحدث التشفير بعد الضغط: plaintext → zstd → encrypt → S3.

تدوير المفاتيح: يقوم rotate_encryption_key(config, new_key) بإعادة التشفير، أو الإضافة، أو إزالة التشفير على جميع بيانات S3 دون فك الضغط. Some إلى Some يدور المفاتيح، Some إلى None يزيل التشفير، None إلى Some يضيفه. آمن ضد الأعطال: لا يتم استبدال الكائنات القديمة أبدًا، تحميل البيان هو نقطة الالتزام الذرية، وتؤكد خطوة التحقق أن البيانات الجديدة قابلة للقراءة قبل الالتزام. يتم تنظيف الكائنات اليتيمة من عمليات التشغيل الجزئية بواسطة gc().

نقاط القوة والقيود

أين يكون turbolite سريعًا

عمليات البحث النقطية هي نقطة القوة. عند مستوى ذاكرة التخزين المؤقت index، تجلب عملية البحث النقطية 1-2 مجموعة فرعية عبر طلب نطاق S3 (~100 كيلوبايت لكل منها). يتم تخزين الصفحات الداخلية وصفحات الفهرس بالفعل. عند مستوى ذاكرة التخزين المؤقت none، أضف ~120 مللي ثانية لإعادة جلب الصفحات الداخلية بالإضافة إلى أول جلب لصفحة البيانات. هذا يعمل على أي حجم جهاز.

المسح الضوئي بعدد كافٍ من النوى. يملأ تجمع الجلب المسبق عرض النطاق الترددي لـ S3 مع جدولة تكيفية لكل شجرة. تشغل استعلامات البحث الجلب المسبق بشكل عدواني من أول خطأ؛ تستعلم استعلامات SCAN المدركة للخطة عن الجلب المسبق للجدول بأكمله مقدمًا. يمكن للخيوط الكافية مزامنة قواعد بيانات متعددة الجيجابايت في ثوانٍ مع 2-3 دفعات جلب مسبق.

أين يكون turbolite بطيئًا

المسح الضوئي على الأجهزة الصغيرة. مع خيط جلب مسبق واحد، يستغرق المسح الضوئي عبر 1.46 جيجابايت ثوانٍ، وليس ميلي ثانية. عنق الزجاجة هو رحلات S3 ذهابًا وإيابًا: كل قفزة تجلب المجموعات بشكل تسلسلي. إذا كان استعلامك الأول هو مسح كامل على جهاز 1 وحدة معالجة مركزية، فتوقع أن يكون بدء التشغيل مؤلمًا.

ضبط الخيوط السيئ. عدد قليل جدًا من خيوط الجلب المسبق يؤدي إلى توقف المسح الضوئي في انتظار S3. عدد كبير جدًا يؤدي إلى بدء عمل SQLite في المقدمة يتنافس مع التنزيلات. الافتراضي (max(num_cpus - 1, 1)) يترك نواة واحدة للعمل الأمامي، لكن أحمال العمل الثقيلة في المسح الضوئي على قواعد البيانات الكبيرة لا تزال بحاجة إلى وحدات معالجة مركزية كافية.

عقوبة الاستعلام الأول. يدفع الاستعلام الأول عند مستوى ذاكرة التخزين المؤقت none حوالي 50-200 مللي ثانية لتحميل الصفحات الداخلية بالإضافة إلى جلب بيانات واحد على الأقل. إذا كان الاستعلام بحاجة إلى صفحة فهرس قبل انتهاء الجلب المسبق في الخلفية، فإنه يعود إلى طلب نطاق S3 مضمن.

القيود الحالية

  • turbolite المستقل هو كاتب واحد. جهازان يكتبان مباشرةً إلى نفس البادئة سوف يتلفان البيان.
  • وضع التوافر العالي / تجاوز الفشل تجريبي ومتوفر في haqlite-turbolite. تجمع هذه المجموعة بين تراخيص HaQLite، وتقسيم صفحات turbolite، ونسخ WAL المستمر لـ walrust. هذا هو المسار المقصود لنشر العقد المتعددة، وليس الوصول المباشر متعدد الكتاب إلى بادئة turbolite واحدة.
  • شحن WAL تجريبي. يتطلب علامة الميزة wal + walrust. راجع المتانة.

ميزات SQLite التي تعمل: FTS، R-tree، JSON، وضع WAL، وضع دفتر اليومية DELETE، VACUUM، autovacuum.

الضبط

المعلمات العامة

جداول الجلب المسبق

التشغيل المسبق لخطة الاستعلام (انظر العمارة) هو آلية الجلب المسبق الأساسية. تعمل الجداول التفاعلية أدناه كبديل عندما لا يكون التشغيل المسبق متاحًا أو عندما تصل الاستعلامات إلى صفحات لم تكن في الخطة.

كل عنصر هو كسر المجموعات الشقيقة المراد جلبها مسبقًا عند الخطأ المتتالي n لكل شجرة في ذاكرة التخزين المؤقت. عندما تتجاوز الأخطاء طول المصفوفة، الكسر = 1.0 (كل الباقي).

لماذا جدولين تفاعليين؟ تقوم استعلامات SEARCH بمسح أجزاء غير معروفة من الفهارس/الجداول وتحتاج إلى إحماء عدواني. تضرب عمليات البحث النقطية 1-2 صفحة لكل شجرة ولا تحتاج تقريبًا إلى جلب مسبق. تضمن عدادات الأخطاء لكل شجرة تتبعًا مستقلاً: استعلام ملف تعريف يصيب المستخدمين (خطأ 1) ثم المشاركات (خطأ 1) يتتبع كل شجرة على حدة.

تكوين الجلب المسبق

اضبط prefetch.search و prefetch.lookup في TurboliteConfig عند بناء VFS:```rust use turbolite::tiered::{TurboliteConfig, PrefetchConfig};

let config = TurboliteConfig { prefetch: PrefetchConfig { search: vec![0.4, 0.3, 0.3], lookup: vec![0.0, 0.0, 0.2], query_plan: true, ..Default::default() }, ..Default::default() };

root@kitploit:~
لإعادة الضبط لكل استعلام دون إعادة فتح الاتصال، استخدم دالة SQL `turbolite_config_set` (المرحلة Cirrus c). كل دفعة تكون محصورة في مقبض الاتصال المُستدعى وتبقى سارية المفعول حتى تغيرها مرة أخرى:```sql
SELECT turbolite_config_set('prefetch_search', '0.5,0.5,0.0');
SELECT turbolite_config_set('prefetch_lookup', '0.0,0.0,0.0');
SELECT * FROM posts WHERE created_at > ?;   -- runs with the new schedule

مؤشر الأوراق الاستباقي

عندما يستخدم استعلام مؤشرًا للعثور على صفوف الجدول (SEARCH ... USING INDEX)، فإن مؤشر الأوراق الذي يقرأه SQLite يسمي بالفعل معرفات الصفوف (rowids) للجدول التي سيجلبها. يقوم الاستباق بتحليل هذه المعرفات، وحلها إلى إطارات أوراق الجدول من خلال الصفحات الداخلية المخزنة مؤقتًا، ويجلب الإطارات دفعة واحدة — بحيث تصل صفوف الجدول معًا بدلاً من رحلة ذهاب وعودة واحدة إلى S3 في كل مرة.

هذه الميزة مفعلة افتراضيًا ولا تعمل إلا مع عمليات SEARCH المفهرسة التي تتبع الجدول. المسح الضوئي والقراءات نقطة بنقطة ومعرف الصفوف والاستعلامات الدافئة بالكامل تتبع المسار الطبيعي دون تغيير، لذلك نادرًا ما يكون هناك سبب لتعطيلها. تحتاج إلى جلب مسبق لخطة الاستعلام (plan_aware، صحيح افتراضيًا).

الحالة الوحيدة لتعطيلها هي حمل العمل الحساس لوحدة المعالجة المركزية الدافئ بالكامل، حيث يكلف تحليل كل ورقة مؤشر القليل ولا يجلب شيئًا لأن الصفحات مخزنة بالفعل في الذاكرة المؤقتة:```sql SELECT turbolite_config_set('lookahead', 'false');

root@kitploit:~
أو قم بتعيين `lookahead` على `TurboliteConfig` / متغير البيئة `TURBOLITE_LOOKAHEAD` عند وقت الفتح.

يمكن للمتصلين بلغة Rust استدعاء نفس المسار عبر `turbolite::tiered::settings::set`.

### الإعدادات الموصى بها

| عبء العمل | الإعداد | السبب |
|----------|--------|-----|
| OLTP المختلط | الافتراضية | معالج يعتمد على خطة التعامل مع المسح الضوئي، جدول البحث يسخن الفهارس، جدول الاستعلام يبقى محافظًا. |
| ثقيل النقاط (قواعد بيانات الوكيل) | `prefetch.lookup: vec![0.0, 0.0, 0.0]` | الاستعلامات لا تحتاج تقريبًا إلى الجلب المسبق. |
| تحليلات ثقيلة المسح | `prefetch.search: vec![0.5, 0.5]`, `prefetch.query_plan: true` | تسخين بحث عدواني بالإضافة إلى جلب مسبق جماعي يعتمد على خطة. |
| محافظ (خادم متقطع) | `prefetch.search: vec![0.1, 0.2, 0.3]`, `prefetch.lookup: vec![0.0, 0.0, 0.1]` | أقل ضوضاء جلب مسبق. |

**ملاحظة**: الجلب المسبق يكون لكل اتصال. كل اتصال جديد يبدأ بعدادات فقدان لكل شجرة باردة. ذاكرة التخزين المؤقت مشتركة، لذا يستفيد الاتصال الثاني من الصفحات المخبأة من الأول.

### أهمية خلفية التخزين

تعتمد جداول الجلب المسبق المثلى على التنازل بين زمن الاستجابة وعرض النطاق الترددي لخلفية S3 الخاصة بك. اختبرنا 10 أزواج جداول عبر 6 استعلامات على كل من S3 Express (~4ms GET) و Tigris (~25ms GET):

| الخلفية | زمن استجابة GET | أفضل استعلام نقطي | أفضل ملف تعريف | كسب الضبط |
|---------|-------------|-------------------|-------------|-------------|
| **S3 Express** | ~4ms | 74ms (off/off: 96ms) | 188ms (off/off: 212ms) | 5-23% مقارنة بعدم الجلب المسبق |
| **Tigris** | ~25ms | 192ms (off/off: 231ms) | 524ms (off/off: 616ms) | 8-34% مقارنة بعدم الجلب المسبق |

على S3 Express، يكون `off/off` (بدون جلب مسبق على الإطلاق) تنافسيًا بشكل مفاجئ للاستعلامات النقطية لأن كل GET لنطاق فرعي صغير يستغرق حوالي 4 مللي ثانية فقط. الفجوة بين "بدون جلب مسبق" و"الجلب المسبق الأمثل" صغيرة (23% للاستعلامات النقطية) لأن عمليات GET الفردية رخيصة. على Tigris، يستفيد نفس الاستعلام بشكل أكبر من الجلب المسبق (حتى 39% على idx-filter) لأن كل دورة مهدورة تكلف 25 مللي ثانية.

التأثير العملي: على الخلفيات ذات زمن الاستجابة العالي، ادفع جداول البحث بقوة أكبر واحتفظ بجداول الاستعلام مع المزيد من الأصفار البادئة. على S3 Express، تعمل الإعدادات الافتراضية بشكل جيد ويوفر الضبط مكاسب أصغر. أداء المسح الكامل غير حساس للجدول على كلا الخلفيتين لأن التنفيذ المسبق لخطة الاستعلام يقوم بجلب مسبق جماعي للجدول بالكامل مقدمًا.

استخدم `tiered-tune` (انظر أدناه) للعثور على الجداول المثلى لخلفيتك واستعلاماتك المحددة.

### أداة الضبط

يتصل `tiered-tune` بقاعدة بيانات turbolite موجودة ويبحث في جداول الجلب المسبق مقابل استعلاماتك الفعلية. بدلاً من تخمين الجداول، قم بتشغيل حملك الفعلي ودع الأداة تجد أفضل زوج:```bash
# Connect to existing database, test your queries
cargo run --release --features cloud,zstd --bin tiered-tune -- \
  --prefix "databases/tenant-123" \
  --query "SELECT * FROM users WHERE id = ?1" \
  --query "SELECT p.*, u.name FROM posts p JOIN users u ON p.user_id = u.id WHERE p.id = ?1" \
  --iterations 10

# Custom schedule grid
cargo run --release --features cloud,zstd --bin tiered-tune -- \
  --prefix "databases/tenant-123" \
  --query "SELECT * FROM orders WHERE user_id = ?1 ORDER BY created_at DESC LIMIT 20" \
  --search-schedules "0.3,0.3,0.4;0.5,0.5;1.0" \
  --lookup-schedules "0;0,0,0.1;0,0,0,0.1,0.2" \
  --iterations 10

الناتج هو جدول مقارنة لكل استعلام (مثل tiered-bench --matrix) يوضح p50 و p90 وعدد GET والبايت لكل زوج جدولة. توصي الأداة بجدولة وتطبع تعيين TurboliteConfig لتطبيقه.

المتانة

turbolite هي طبقة تخزين، وليس نظام نسخ متماثل. تعتمد المتانة على وقت وصول البيانات إلى S3.

بعد نقطة التحقق (checkpoint): مجموعات الصفحات + manifest موجودة في S3. توفر S3 11 تسعات من المتانة. تنجو هذه البيانات من فقدان الجهاز.

بين نقاط التحقق: تعيش عمليات الكتابة فقط في WAL المحلي على القرص المحلي. إذا تعطل الجهاز قبل نقطة التحقق التالية، تفقد تلك الكتابات.

يتحكم تواتر نقاط التحقق في المفاضلة: نقاط تحقق أكثر تكرارًا = نافذة بيانات معرضة للخطر أصغر ولكن المزيد من PUTs في S3. الإعداد الافتراضي هو نقطة التحقق التلقائية لـ SQLite (كل 1000 إطار WAL).

أوضاع نقطة التحقق

تدعم turbolite وضعين لنقطة التحقق عبر sync_mode في TurboliteConfig:

SyncMode::Durable (افتراضي). تقوم نقطة التحقق برفع مجموعات الصفحات إلى S3 أثناء الاحتفاظ بقفل EXCLUSIVE لـ SQLite. بسيط، متين بالكامل في كل نقطة تحقق. لا يمكن متابعة أي كتابة أو قراءة حتى اكتمال الرفع. جيد لمعظم أعباء العمل.

SyncMode::LocalThenFlush. تقوم نقطة التحقق بالكتابة فقط إلى ذاكرة التخزين المؤقت على القرص المحلي (~1ms تعليق القفل)، ثم تحرر القفل. يقوم المتصل بالرفع إلى S3 بشكل منفصل عبر flush_to_s3()، وخلال ذلك تستمر القراءات والكتابات بشكل طبيعي. هذا مفيد لأعباء العمل ذات الكتابة الثقيلة حيث يكون حظر القراء لمدة رفع S3 غير مقبول.

بين نقطة التحقق والرفع، توجد البيانات فقط في ذاكرة التخزين المؤقت على القرص المحلي. تعطل العملية (crash) لا بأس به (البيانات على القرص المحلي، وstaging logs تلتقط محتويات الصفحات الدقيقة للرفع). فقدان الجهاز قبل الرفع يعني فقدان تلك الكتابات. إخلاء ذاكرة التخزين المؤقت (cache eviction) آمن: تحمي turbolite الصفحات المعلقة من الإخلاء تلقائيًا.

استعادة التعطل (Crash recovery): إذا تعطلت العملية بين نقطة التحقق والرفع، تبقى staging logs على قيد الحياة على القرص. في المرة التالية من TurboliteVfs::new()، يتم استعادتها تلقائيًا ووضعها في قائمة انتظار لاستدعاء flush_to_s3() التالي. يتم تقديم القراءات فورًا من ذاكرة التخزين المؤقت المحلية دون انتظار الرفع.

شحن WAL (تجريبي)

مع تمكين علامة الميزة wal، تقوم turbolite بشحن إطارات WAL إلى S3 عبر walrust، مما يسد فجوة المتانة بين عمليات الكتابة الفردية ونقاط التحقق.```toml

Cargo.toml

turbolite = { version = "0.5", features = ["cloud", "zstd", "wal"] }

root@kitploit:~
[No content provided for translation.]```rust
let config = TurboliteConfig {
    wal_replication: true,  // enable WAL shipping
    ..Default::default()
};

turbolite و walrust يظلان متزامنين عبر مؤشر الإعادة (replay cursor) المخزن كـ manifest.change_counter. مسارات الاستيراد/التدقيق (import/checkpoint) تغذي هذا المؤشر من عداد تغيير ملف SQLite؛ إعادة الصفحة المباشرة يمكن أن تتقدم به إلى أحدث تسلسل تغييرات ملتزم. عند بدء التشغيل البارد، يقوم turbolite بتحقيق قاعدة البيانات من مجموعات الصفحات، ثم يقوم walrust بإعادة تشغيل مقاطع WAL ذات txid > change_counter لاستعادة عمليات الكتابة التي حدثت بعد آخر تدقيق.

نموذج المتانة مع شحن WAL: كل معاملة ملتزمة تُشحن إلى S3 كمقطع WAL ضمن فترة المزامنة (الافتراضي 100ms). إذا تعطل الجهاز، يتم فقدان كتابات فترة مزامنة واحدة على الأكثر. بعد التدقيق، يتم جمع مقاطع WAL ذات txid <= change_counter تلقائيًا كقمامة.

شحن WAL مكمل لـ SyncMode: يتحكم SyncMode في كيفية وصول التدقيقات إلى S3، بينما يجعل شحن WAL عمليات الكتابة الفردية مستقرة قبل التدقيق.

نموذج الاتساق

كاتب واحد، قرّاء لقطات (snapshot readers). عملية واحدة تكتب؛ يرى القرّاء آخر بيان (manifest) ملتزم عندما فتحوا. turbolite ليس قاعدة بيانات موزعة ولا ينسق بين عدة كتّاب.

الوضع المحلي (بدون S3)

يعمل turbolite أيضًا كنظام VFS محلي مضغوط/مشفر:

الضغط: zstd (افتراضي)، lz4، snappy، gzip. مع zstd، يمكنك تدريب ودمج قواميس ضغط مخصصة وتدويرها تلقائيًا لضغط أكثر كفاءة. أحجام الصفحات الأكبر تضغط بشكل أفضل. راجع CLI لأدوات التدريب.

التشفير: AES-256-GCM لكل صفحة.

العمل على مستوى الصفحة يعني أن معظم ميزات SQLite لا تزال تعمل: FTS، R-tree، JSON، وضع WAL. معظم إضافات ضغط/تشفير SQLite الأخرى تعمل على مستوى الملف أو تتطلب بنيات مخصصة.

التثبيت

هذا المستودع هو مساحة عمل Cargo. حزمة turbolite هي مكتبة Rust الخالصة في جذر مساحة العمل. روابط اللغات والإضافة القابلة للتحميل موجودة في turbolite-ffi/.

Python: pip install turbolite — راجع turbolite-ffi/packages/python/```python import turbolite

Local compressed (no S3 needed)

conn = turbolite.connect("my.db")

S3 cloud

conn = turbolite.connect("my.db", mode="s3", bucket="my-bucket", endpoint="https://t3.storage.dev")

Manual extension loading for full control

import sqlite3 conn = sqlite3.connect(":memory:") turbolite.load(conn) conn.close() conn = sqlite3.connect("file:my.db?vfs=turbolite", uri=True) # local

For S3, prefer turbolite.connect(..., mode="s3", bucket=..., prefix=...).

It registers a per-database VFS so multiple S3 volumes can share one process.

root@kitploit:~
**Node.js**: `npm install turbolite` — see [turbolite-ffi/packages/node/](https://github.com/russellromney/turbolite/blob/HEAD/turbolite-ffi/packages/node/)

**Rust**:```toml
[dependencies]
turbolite = "0.5"                                              # local VFS
turbolite = { version = "0.5", features = ["cloud"] }          # + S3 storage
turbolite = { version = "0.5", features = ["encryption"] }     # + encryption

Go (cgo, يربط المكتبة المشتركة):```bash make lib-bundled # build libturbolite.{so,dylib}

root@kitploit:~
```go
// #cgo LDFLAGS: -L/path/to/target/release -lturbolite
// #include <stdlib.h>
// extern int turbolite_register_local_file_first(const char* name, const char* db_path, int level);
// extern void* turbolite_open(const char* path, const char* vfs_name);
// extern int turbolite_exec(void* db, const char* sql);
// extern char* turbolite_query_json(void* db, const char* sql);
// extern void turbolite_close(void* db);
import "C"

الموصى به turbolite_register_local_file_first(name, db_path, level) يتم مفتاحه على مسار قاعدة البيانات المواجه للمستخدم. الدالة ذات المستوى الأدنى turbolite_register_local(name, cache_dir, level) لا تزال مصدرة للمُضمِّنين الذين يرغبون في إدارة دليل التخزين المؤقت بأنفسهم. راجع examples/go/ للحصول على مثال كامل لخادم HTTP.

الإضافة القابلة للتحميل (أي لغة)

قم ببناء الإضافة القابلة للتحميل لأي لغة باستخدام load_extension الخاصة بـ SQLite:```bash

after cloning the turbolite repo

make ext # produces target/release/turbolite.{so,dylib}

root@kitploit:~
Please provide the Markdown content to translate.```c
sqlite3_enable_load_extension(db, 1);
sqlite3_load_extension(db, "path/to/turbolite", NULL, NULL);
// "turbolite" VFS (local) is always registered
// "turbolite-s3" is a single-volume convenience VFS when TURBOLITE_BUCKET is set

بالنسبة لقصة المستخدم الملف أولاً، قم بتسجيل VFS لكل قاعدة بيانات يمتلك app.db الخاص بالمستدعي:```sql SELECT turbolite_register_file_first_vfs('app', '/data/app.db'); -- now open /data/app.db via vfs=app; turbolite stores its sidecar -- metadata at /data/app.db-turbolite/.

root@kitploit:~
لتكوين نظام الملفات الافتراضي `"turbolite"` لوضع الملف أولاً عند وقت تحميل الإضافة، قم بتعيين `TURBOLITE_DATABASE_PATH=/data/app.db` في البيئة قبل تحميل الإضافة. يكون الملف الجانبي عندها `/data/app.db-turbolite/` ويتم تجاهل المتحكم الأدنى `TURBOLITE_CACHE_DIR`.
### Node.js```bash
npm install turbolite

INPUT:

root@kitploit:~
INPUT:
``````js
const { connect } = require("turbolite");

// File-first: /data/app.db is the local page image.
// /data/app.db-turbolite/ holds hidden implementation state.
const db = connect("/data/app.db");
db.exec("CREATE TABLE users (id INTEGER PRIMARY KEY, name TEXT)");
db.prepare("INSERT INTO users VALUES (?, ?)").run(1, 'alice');

const rows = db.prepare("SELECT id, name FROM users").all();
// [{ id: 1, name: 'alice' }]
db.close();

db هي قاعدة بيانات better-sqlite3 قياسية. connect() تسجل VFS أولوية الملف لكل قاعدة بيانات لك. لتصدير ملف SQLite قياسي (على سبيل المثال لفحصه باستخدام واجهة سطر الأوامر sqlite3)، استخدم واجهة برمجة تطبيقات النسخ الاحتياطي better-sqlite3: await db.backup('export.sqlite'). انظر turbolite-ffi/packages/node/ للوثائق الكاملة.

Rust (محلي، أولوية الملف)```rust

use turbolite::tiered::{TurboliteVfs, TurboliteConfig};

// app.db is the user-visible local page image. // app.db-turbolite/ holds hidden implementation state. let config = TurboliteConfig::for_database_path("/data/app.db"); let vfs = TurboliteVfs::new_local(config)?; turbolite::tiered::register("turbolite", vfs)?;

let conn = rusqlite::Connection::open_with_flags_and_vfs( "/data/app.db", rusqlite::OpenFlags::SQLITE_OPEN_READ_WRITE | rusqlite::OpenFlags::SQLITE_OPEN_CREATE, "turbolite", )?;

root@kitploit:~
النموذج ذو المستوى المنخفض يتيح لك اختيار دليل التخزين المؤقت مباشرة:```rust
let config = TurboliteConfig {
    cache_dir: "/path/to/data".into(),  // turbolite owns this dir
    ..Default::default()
};

في هذه الحالة، الصورة المحلية هي /path/to/data/data.cache بدلاً من app.db المسمى من قبل المتصل. يجب على المدمجين الجدد تفضيل النموذج القائم على الملف أولاً.

Rust (S3 cloud)```rust

use turbolite::tiered::{TurboliteVfs, TurboliteConfig}; use hadb_storage::StorageBackend;

let config = TurboliteConfig::for_database_path("/data/app.db"); let storage: Arc = /* your S3 backend */; let vfs = TurboliteVfs::with_backend(config, storage, tokio::runtime::Handle::current())?; turbolite::tiered::register("turbolite", vfs)?;

let conn = rusqlite::Connection::open_with_flags_and_vfs( "/data/app.db", rusqlite::OpenFlags::SQLITE_OPEN_READ_WRITE | rusqlite::OpenFlags::SQLITE_OPEN_CREATE, "turbolite", )?;

root@kitploit:~
`app.db` هي صورة الصفحة المضغوطة لـ turbolite. ليس من المضمون أن يتم فتحها مباشرة بواسطة `sqlite3` القياسي. بالنسبة لملف SQLite عادي (مثل واجهة سطر الأوامر `sqlite3`)، استخدم واجهة برمجة تطبيقات النسخ الاحتياطي عبر الإنترنت لـ SQLite أو أداة التصدير الخاصة بالربط (`conn.iterdump()` في بايثون، `db.backup()` في نود).

## CLI```bash
cargo install turbolite --features cloud,zstd

الأوامر```bash

Inspect a database manifest

turbolite info --db my.db turbolite info --db my.db --bucket my-bucket --endpoint https://t3.storage.dev

Interactive SQLite shell (with turbolite VFS)

turbolite shell --db my.db turbolite shell --db my.db --bucket my-bucket --read-only

Download entire database from S3 into local cache

turbolite download --db my.db --bucket my-bucket --threads 8

Export to plain SQLite (for migration or backup)

turbolite export --db my.db --output plain.db

Import a plain SQLite file into turbolite S3 format

turbolite import --input plain.db --bucket my-bucket --prefix databases/my-db

root@kitploit:~
تقبل جميع أوامر S3 العلامات `--bucket` و`--prefix` و`--endpoint` و`--region`، أو تقرأ من متغيرات البيئة `TURBOLITE_BUCKET` و`TURBOLITE_PREFIX` و`AWS_ENDPOINT_URL` و`AWS_REGION`.

## المشاريع ذات الصلة والمقارنة

هناك العديد من المشاريع في مجال SQLite عبر الشبكة. يستعير turbolite أفكارًا من جميعها.

### طلبات النطاق على ملفات .db الخام (للقراءة فقط)

النهج الأكثر شيوعًا: وضع ملف `.db` غير معدل على S3 أو CDN وإصدار طلبات HTTP Range GET عندما يقرأ SQLite صفحة.

- [**sql.js-httpvfs**](https://github.com/phiresky/sql.js-httpvfs): الأصلية. WASM SQLite مع طلبات HTTP Range. يحتوي على رؤوس قراءة افتراضية مع جلب مسبق أسي للمسح الضوئي. كانت رائدة فكرة أنك لست بحاجة إلى تنزيل قاعدة البيانات بأكملها للاستعلام عنها.
- [**sqlite_web_vfs**](https://github.com/mlin/sqlite_web_vfs): إضافة VFS أصلية بلغة C++ مع دمج الطلبات التكيفي وملف فهرس `.dbi` اختياري يجمع عُقد B-tree الداخلية مسبقًا للجلب المسبق - نفس فكرة حزم الصفحات الداخلية في turbolite. مصمم للتوافق مع sqlite_zstd_vfs.
- [**sqlite3vfshttp**](https://github.com/psanford/sqlite3vfshttp): VFS نظيف وبسيط بلغة Go. مبني للاستعلام عن SQLite في S3 من Lambda دون تنزيل الملف.
- [**sqlite-s3-query**](https://github.com/michalc/sqlite-s3-query): مكتبة Python تستخدم ctypes لاعتراض إدخال/إخراج الملف وترجمة القراءات إلى طلبات S3 Range GET. تتطلب مجلدات ذات إصدار للاتساق أثناء استبدال قاعدة البيانات.
- [**sqlite-wasm-http**](https://github.com/mmomtchev/sqlite-wasm-http): الخلف الروحي لـ sql.js-httpvfs باستخدام بناء SQLite WASM الرسمي. ذاكرة تخزين مؤقت للصفحات مشتركة عبر SharedArrayBuffer. نشط الصيانة.
- [**s3sqlite](https://github.com/litements/s3sqlite): Python، يستخدم s3fs (FUSE) + APSW. يترك FUSE يتعامل مع طلبات النطاق.

هذه جميعها للقراءة فقط وتجلب الصفحات غير المضغوطة من الملف الخام. بحث نقطة واحد ينقل صفحة خام بحجم 4KB (أو 64KB) لكل طلب.

### تكرار/مزامنة على مستوى الصفحة

تعامل هذه المشاريع التخزين الكائني كمصدر للحقيقة وتكرر الصفحات الفردية أو مجموعات التغييرات، مما يتيح النسخ المتماثلة الجزئية والنشر في وضع عدم الاتصال/الحافة.

- [**Graft**](https://graft.rs/) ([`orbitinghail/graft`](https://github.com/orbitinghail/graft)): محرك تخزين معاملات للنسخ المتماثل الكسول والجزئي والمتسق بقوة عبر S3. إضافة SQLite `libgraft` تنفذ VFS يقرأ ويكتب صفحات بحجم 4KB عبر وحدات تخزين Graft. يستخدم ضغط zstd المؤطر ومجموعات تغييرات قائمة على splinter. أقرب قريب معماري لـ turbolite في مجال "تكرار الصفحات، وليس إطارات WAL"، مع التركيز على مزامنة الحافة متعددة الكُتّاب بدلاً من زمن وصول القراءة الباردة.
- [**mvsqlite**](https://github.com/losfair/mvsqlite): الصفحات مخزنة في FoundationDB كأزواج قيمة-مفتاح موجهة بالمحتوى. MVCC كامل مع السفر في الزمن إلى أي لقطة، ترميز delta XOR+zstd بين إصدارات الصفحة. أكثر محركات التخزين تطورًا في هذا المجال، ولكنه يتطلب FoundationDB، وليس S3.

### التكرار والنسخ الاحتياطي إلى S3

تكرر هذه المشاريع الكتابات المحلية إلى S3 للنسخ الاحتياطي أو الاستعادة.

- [**Litestream**](https://github.com/benbjohnson/litestream): يشحن إطارات WAL باستمرار إلى S3. المعيار الذهبي لنسخ SQLite الاحتياطي. يمكن لـ VFS الأحدث في Litestream تقديم القراءات من S3 باستخدام طلبات النطاق على ملفات LTX مع ذاكرة تخزين مؤقت LRU وفهرس صفحات — أقرب شيء معماريًا لمسار القراءة في turbolite، لكنه للقراءة فقط ومرتبط بتنسيق تكرار Litestream.
- [**LiteFS**](https://github.com/superfly/litefs): نظام أساسي/تابع قائم على FUSE من Fly.io. يلتقط مجموعات تغييرات الصفحات ويدفقها إلى النسخ المتماثلة. يحل مشكلة التوفر، وليس التخزين.
- [**Verneuil**](https://github.com/backtrace-labs/verneuil): يقسم قاعدة البيانات إلى أجزاء بحجم 64KB مع ضغط zstd وملف بيان، ويكرر بشكل غير متزامن إلى S3. نموذج الجزء+البيان يشبه مجموعات الصفحات + البيان في turbolite، ولكن Verneuil أداة تكرار - تستعلم من القرص المحلي، وليس S3.
- [**libSQL/sqld**](https://github.com/tursodatabase/libsql) (بواسطة Turso): Fork من SQLite مع واجهة WAL افتراضية. وضع "Bottomless" يشحن إطارات WAL إلى S3. الاستعلامات محلية؛ S3 للاستعادة.

### محركات تخزين مخصصة

- [**sqlite-s3vfs**](https://github.com/simonw/sqlite-s3vfs): كل صفحة SQLite مخزنة ككائن S3 منفصل. يتيح الكتابات ولكن بتكلفة PUT واحدة لكل صفحة، تكلفة 0.02 دولار لكل 4096 صفحة مقابل 0.000005 دولار من turbolite لنفس الدفعة (بحجم صفحة افتراضي 64KB). انظر جدول المقارنة أعلاه لزمن وصول الاستعلام البارد؛ turbolite أسرع بمقدار 7.5–263× على نفس مجموعة البيانات.
- [**wa-sqlite-s3vfs**](https://github.com/LoneRifle/wa-sqlite-s3vfs): منفذ TypeScript / متصفح لـ sqlite-s3vfs لـ `wa-sqlite`. نفس نموذج كائن واحد لكل صفحة، مكيف للاستخدام مع WASM / جانب العميل.

### الضغط

- [**sqlite_zstd_vfs**](https://github.com/mlin/sqlite_zstd_vfs): يخزن الصفحات المضغوطة كصفوف في قاعدة بيانات "غلاف" خارجية. ضغط zstd مع تدريب القاموس. يتوافق مع sqlite_web_vfs لقراءات مضغوطة عبر طلبات النطاق عبر HTTP. الجمع بين sqlite_web_vfs + sqlite_zstd_vfs هو على الأرجح أقرب شيء موجود لمسار القراءة في turbolite، لكنه للقراءة فقط ولا يجمع الصفحات في مجموعات.
- [**SQLCipher**](https://github.com/sqlcipher/sqlcipher): تشفير AES-256 على مستوى الصفحة لـ SQLite المحلي. لا تخزين عن بعد.

### أين يختلف turbolite

| | turbolite | Raw-file range GETs | Litestream VFS | sqlite_web_vfs + zstd_vfs | mvsqlite | Graft | sqlite-s3vfs |
|---|---|---|---|---|---|---|---|
| القراءة من S3 | طلبات range GET قابلة للبحث على مجموعات الصفحات المضغوطة | طلبات range GET على الصفحات الخام | طلبات range GET على ملفات LTX | طلبات range GET على قاعدة البيانات الخارجية المضغوطة | عمليات بحث KV على FoundationDB | جلب كسول للصفحات 4KB / مجموعات التغييرات | GetObject واحد لكل صفحة |
| الكتابة إلى S3 | نقطة تفتيش (PUT واحد لكل مجموعة) | لا | لا | لا | نعم (MVCC) | نعم (تكرار مجموعات التغييرات غير المتزامن) | PUT واحد لكل صفحة |
| الضغط | zstd متعدد الإطارات قابل للبحث | لا | لا | zstd (قاعدة بيانات متداخلة) | ترميز delta zstd | zstd مؤطر | لا |
| التشفير | AES-256-GCM لكل صفحة | لا | لا | لا | لا | غير مذكور | لا |
| الجلب المسبق | نظرة للأمام + جدول قفز | لا أو قراءة مسبقة أساسية | ذاكرة تخزين مؤقت LRU | دمج تكيفي | مخازن العميل | كسول / حسب الطلب | لا |
| تحسين الصفحات الداخلية | مكتشفة، مثبتة، مجمعة بشكل منفصل | لا | فهرس الصفحات من ذيل LTX | ملف `.dbi` اختياري | لا | غير مذكور | لا |
| بايت لكل بحث نقطة (ذاكرة تخزين مؤقت: فهرس) | ~100KB (إطار مضغوط واحد) | 4-64KB (صفحة خام واحدة) | يختلف | يختلف | يختلف | 4KB (صفحة واحدة) | 4KB (صفحة واحدة) |
| تكلفة الكتابة لكل 4096 صفحة | ~0.000005 دولار (PUT واحد) | غير متاح | غير متاح | غير متاح | عمليات FoundationDB | مجموعات تغييرات مجمعة | ~0.02 دولار (4096 PUT) |

## الاختبارات المعيارية

جميع الاختبارات المعيارية موجودة في [`benchmark/`](https://github.com/russellromney/turbolite/blob/HEAD/benchmark/). انظر [`benchmark/README.md`](https://github.com/russellromney/turbolite/blob/HEAD/benchmark/README.md) لسيناريوهات النشر (محلي، Fly.io، EC2).

يقوم الثنائي `tiered-bench` بتوليد مجموعة بيانات وسائل التواصل الاجتماعي (المستخدمون، المنشورات، الإعجابات، الصداقات) واختبار الاستعلامات على كل مستوى من مستويات التخزين المؤقت مقابل S3.

يقوم إطار منفصل [`benchmark/bench_s3vfs.py`](https://github.com/russellromney/turbolite/blob/HEAD/benchmark/bench_s3vfs.py) بتشغيل نفس الاستعلامات مقابل [sqlite-s3vfs](https://github.com/simonw/sqlite-s3vfs) للمقارنة المباشرة. يتم نشره عبر [`benchmark/fly-s3vfs.toml`](https://github.com/russellromney/turbolite/blob/HEAD/benchmark/fly-s3vfs.toml) ويستخدم نفس مولد مجموعة البيانات الحتمية مثل `tiered-bench`.```bash
# Basic benchmark: 100K posts, default settings
TIERED_TEST_BUCKET=my-bucket AWS_ENDPOINT_URL=https://t3.storage.dev \
  cargo run --features zstd,cloud --bin tiered-bench --release -- \
    --sizes 100000

# 1M posts, 8 prefetch threads, only interior-level point queries
cargo run --features zstd,cloud --bin tiered-bench --release -- \
    --sizes 1000000 --prefetch-threads 8 --queries post --modes interior

# Quick local VFS comparison (no S3 needed)
cargo run --example quick-bench --features encryption --release

الأعلام الرئيسية: --sizes (عدد الصفوف)، --ppg (الصفحات لكل مجموعة)، --prefetch-threads، --prefetch-search (جدول SEARCH)، --prefetch-lookup (جدول lookup)، --grouping (موضعي أو btree)، --queries (post/profile/who-liked/mutual)، --modes (لا شيء/داخلي/فهرس/بيانات)، --skip-verify (تخطي COUNT(*) على الأجهزة الصغيرة)، --iterations، --plan-aware (تفعيل التحميل المسبق مع الرؤية المستقبلية)، --matrix (مسح أزواج الجداول). جداول لكل استعلام: --post-prefetch/--post-lookup، /، إلخ. (البحث وال lookup مستقلان لكل استعلام).```bash

Matrix mode: test 10 schedule pairs x 6 queries at cold level

cargo run --features zstd,cloud --bin tiered-bench --release --
--sizes 1000000 --import auto --plan-aware --matrix --iterations 10

Tune schedules for your own database and queries

cargo run --features zstd,cloud --bin tiered-tune --release --
--prefix "databases/my-db"
--query "SELECT * FROM users WHERE id = ?1" --param 42
--plan-aware --iterations 10

root@kitploit:~
## اختبار```bash
cargo test --features zstd                    # local VFS tests
cargo test --features zstd,cloud             # + S3 integration tests
cargo test --features zstd,encryption         # + encryption tests

ملاحظات

كانت turbolite تُسمى سابقًا sqlite-compress-encrypt-vfs، والمعروفة أيضًا باسم sqlces.

تفاصيل نموذج الأمان

بيانات S3 تستخدم AES-256-GCM مع أرقام عشوائية فريدة لكل إطار (موثقة، كاشفة للتلاعب). الملفات المحلية تستخدم AES-256-CTR مع أرقام غير عشوائية حتمية (رقم الصفحة / إزاحة البايت)، مما يوفر السرية ضد المهاجمين الذين يستهدفون القرص في حالة السكون. الأرقام غير العشوائية الحتمية في CTR تعني أن المهاجمين الذين يحصلون على لقطات متعددة يمكنهم استعادة XOR للنصوص الواضحة في الإزاحات المعاد استخدامها، وهو ما يتطابق مع مفاضلة امتداد SEE الخاص بـ SQLite. ذاكرة التخزين المؤقت المحلية مؤقتة ويمكن إعادة إنشائها من S3.

الترخيص

Apache-2.0

تنزيل الأداة
الاستعلامالنوعبارد (S3 Express)بارد (Tigris)
منشور + مستخدمبحث نقطي + JOIN86ms172ms
الملف الشخصيJOIN متعدد الجداول (5 JOIN)251ms479ms
من أعجببحث فهرس + JOIN206ms302ms
الأصدقاء المشتركونبحث متعدد + JOIN19ms49ms
تصفية مفهرسةمسح فهرس مغطى79ms88ms
مسح كامل + تصفيةمسح جدول كامل476ms532ms
مستوى التخزين المؤقتما هو مخبأما يتم جلبه من S3متى يحدث هذا
لا شيءلا شيءكل شيءبداية جديدة، ذاكرة تخزين مؤقت فارغة
داخليصفحات B-tree الداخليةصفحات الفهرس + البياناتأول استعلام بعد فتح الاتصال
فهرسالصفحات الداخلية + صفحات الفهرسصفحات البيانات فقطعملية turbolite العادية
بياناتكل شيءلا شيءمكافئ لـ SQLite المحلي
العمليةSQLiteturboliteالنفقات العامة
بحث نقطي145K/s73K/s2.0x
مسح نطاقي8.8K/s8.3K/sتعادل
مسح جدول كامل56/s60/sتعادل
INSERT19K/s23K/sتعادل
UPDATE حسب المفتاح الأساسي40K/s27K/s1.5x
INSERT دفعي (في معاملة)685K/s740K/sتعادل
المعاملما يتحكم فيهالافتراضي
prefetch.threadsخيوط العامل لجلب S3 المتوازيmax(num_cpus - 1, 1)
cache.pages_per_groupالصفحات لكل كائن S3، أكبر = عدد أقل من PUTs، بايتات أكثر لكل جلب256
cache.gc_enabledحذف إصدارات مجموعات الصفحات القديمة بعد نقطة التفتيشtrue
sync_modeمتانة نقطة التفتيش: Durable (تحميل S3 في نقطة التفتيش) أو LocalThenFlush (تأجيل التحميل)Durable
الإستراتيجيةمتىالجدول الافتراضيما يحدث
SCAN (مسبق)يقول EQP SCAN tableجميع المجموعات مقدمًاالجلب المسبق للجدول بأكمله قبل القراءة الأولى. لا حاجة لجدول القفزات.
SEARCH (تفاعلي)يقول EQP SEARCH ... USING INDEX[0.3, 0.3, 0.4]جلب مسبق عدواني من أول خطأ؛ يقوم بمسح أجزاء الفهرس غير المعروفة.
Lookup (تفاعلي)الاستعلامات النقطية، لا معلومات EQP[0.0, 0.0, 0.0]ثلاث قفزات مجانية، صفر جلب مسبق. نادرًا ما تستفيد الاستعلامات النقطية من الجلب المسبق.
--profile-prefetch
--profile-lookup