قيود الحقول ونطاقات القيم
حقول الطلب (C→S)
| الحقل | النوع | النطاق الصالح | المعنى | عند المخالفة |
|---|---|---|---|---|
op | ASCII 1B | A(0x41) · R(0x52) | نوع الطلب | E bad_op |
wait | u8 | 0–255 (ثانية) | 0 محاولة فورية بلا queue؛ و1..255 حد انتظار acquire | — (صالح دائمًا بحكم النوع) |
lease | u8 | 1–250 (ثانية) | Lease؛ تُرفض/تُحجز 0 و251..255 | E bad_lease |
owner | u64 BE | 0 – 2^64-1 كاملًا | معرّف محاولة الحصول (يولّده العميل) | — (لا يتحقق منه الخادم) |
token | u64 BE | قيمة يصدرها الخادم | يحدد ما سيُحرَّر (في R فقط) | N عند عدم المطابقة |
key | UTF-8 | 1 – 128 بايت | اسم القفل. لا مسافة (0x20) ولا سطر جديد (0x0A) | E bad_key |
- لا يوجد wait أو lease بلا نهاية. تقرّب العملاء الرسمية كسور الثانية إلى الأعلى وتتحقق من المجال، وتعيد خطأ إدخال صريحًا قبل الإرسال بدل clamp. الـlease الافتراضية 30 ثانية.
- في client API الرسمية، تمثل
waitالحد الكلي لعملية acquire منذ بدء الاستدعاء، مرورًا بـlocal queue ومحاولات الاتصال المؤكد عدم إرسالها وwrite، وحتى الاستجابة. تُنشأ monotonic operation deadline واحدة فقط؛ وقبل الإرسال الفعلي مباشرة يضع writer فيwaitداخل frame عدد الثواني المتبقية بعد تقريبه إلى أعلى كـu8. لذلك لا يستطيع اتصال متأخر أو failover مؤكد عدم إرساله إعادة بدء server wait من البداية. إذا ظل الطلب في queue عند deadline ينتهي timeout مع تأكد عدم إرساله؛ وإذا أمكن أن يكون قد أُرسل ولو بايت واحد، تُغلق الـsession الدقيقة نفسها وتكون النتيجةIndeterminate. وحدهwait=0الأصلي يستخدم wire0، ولهذه المحاولة الفورية I/O deadline محدودة مستقلة كي لا تنتظر transport متوقفًا بلا نهاية. إذا لم يُكتشفAالمترابط قبل deadline إلا متأخرًا عند gate تسليم Ticket، يكون server waiter قد انتهى بالفعل: تبقى session مفتوحة، ويُنفذ release تعويضي للـexact token المعروف، وتظل النتيجةIndeterminate. أماT/Bالمترابطان فهما عدم حصول نهائي. - بالنسبة إلى
wait=0الأصلي، يظل سلوك wire وserver محاولة فورية واحدة بلا queue. ضمن transport deadline المنفصلة ومدتها 5 ثوان، يجوز للفشل المؤكد عدم إرساله اختيار اتصال آخر وإعادة المحاولة بالـowner نفسه. بعد احتمال إرسال ولو بايت واحد، لا يُعاد إرسال acquire أبدًا. - تتطلب API الرسمية
min_work_budgetغير الموجود على wire. يجب أن يغطيcritical work + pause متوقعة + إتمام DB commit/rollback، وأن يكون0..250ثانية ولا يتجاوز lease بعد التطبيع. المخالفة تفشل قبل الإرسال بخطأ من فئةUnsupportedDuration/InsufficientLease. - طول المفتاح يُحسب بالبايت لا بالمحارف — فمحارف الكورية تشغل 3 بايت لكل محرف في UTF-8، أي 42 محرفًا كحد أقصى.
ownerمجرد ID لربط الاستجابة وليس صلاحية. تكراره لا يعيد active token ولا يجدد lease. الطلبات concurrent in-flight للعميل نفسه تحتاج قيمًا مختلفة غير صفرية؛ إذا صار counter صفرًا أو حدث wrap تفشل العملاء الرسمية fail-closed.- للـrelease الصريح والتعويضي لـtoken معروف 5 ثوان مطلقة من call/enqueue تشمل reconnect وretry. تؤكد
Rالنجاح؛ وتعنيNأنه اختفى أو ليس الـtoken الحالي. غياب الاستجابة لا يُفترض نجاحًا؛ وعند امتلاء compensation queue المحدودة يُعتمد على lease expiry. - يشمل
bad_keyالمفتاح الفارغ، وما يتجاوز 128 بايت، وما يحتوي مسافة أو سطرًا جديدًا، وUTF-8 غير الصالح، كلها على حد سواء. لا ترسل العملاء الرسميون أيضًا\rأبدًا — إذ إن مفتاحًا ينتهي بـ\rيصبح مفتاحًا مختلفًا دون أن يظهر ذلك للعين.
حقول الاستجابة (S→C)
| الحقل | النوع | النطاق | يظهر في |
|---|---|---|---|
token | u64 BE | 1 فأكثر، ويزداد مع كل إصدار | A (إصدار جديد) · R/N (صدى الطلب) |
owner | u64 BE | قيمة الطلب نفسها | A · T · B (صدى الطلب) |
key | UTF-8 | قيمة الطلب نفسها (1–128 بايت) | A · T · B · R · N |
addr | UTF-8 | host:port | M · L |
reason | ASCII | الأسباب الثمانية المحددة | E |
لا يصدر الخادم token 0 أبدًا. يستخدم single counter خلال process lifetime الحالي؛ ويستخدم cluster counter منسوخًا بالإجماع ويفشل fail-closed قبل overflow. لا تضمن wall clock أو العشوائية الرتابة بعد restart.
أطوال الترويسات الثابتة
هو المقطع الثنائي ثابت الطول الذي يلي op مباشرة. قد تحتوي هذه البايتات على 0x0A، لذا يجب على المحلل استهلاك هذا الطول بالضبط قبل البحث عن السطر الجديد.
| الاتجاه | op | الترويسة الثابتة | التركيب |
|---|---|---|---|
| C→S | A | 10 B | wait(1) + lease(1) + owner(8) |
| C→S | R | 8 بايت | token(8) |
| S→C | A | 16 بايت | token(8) + owner(8) |
| S→C | T · B | 8 بايت | owner(8) |
| S→C | R · N | 8 بايت | token(8) |
| S→C | M · L · E | 0 بايت | لا شيء (نص مباشرة بعد op) |
وإذا نقصت البايتات فالنتيجة E bad_request.
حجم الإطار
| البند | القيمة |
|---|---|
الحد الأقصى للإطار (دون \n) | 192 بايت — عند تجاوزه: E line_too_long |
أقصى طلب A | 1 + 10 + 128 + 1 = 140 بايت |
أقصى طلب R | 1 + 8 + 128 + 1 = 138 بايت |
أقصى استجابة A | 1 + 16 + 128 + 1 = 146 بايت |
إطار فارغ (\n فقط) | keep-alive — يتجاهله الخادم |
حد 192B أكبر من أكبر frame (146B)، لذلك لا يبلغه عميل ملتزم. بعد frame تالف بنيويًا أو oversized لا يعود framing موثوقًا ويُغلق الاتصال.
مصافحة المصادقة
| البند | القيمة |
|---|---|
| التجزئة | SHA-256 (مذكورة في سطر التحدي) |
| nonce | 8 محارف base64url |
| بصمة الاستجابة | 43 محرفًا base64url (بلا حشو) |
| الحد الأقصى للسطر | 256 بايت |
| المهلة | 10 ثوانٍ (شاملة تفاوض TLS) — وما زاد يُغلق الاتصال |
للاطلاع على الإجراء بالتفصيل راجع مصافحة المصادقة.
حدود جانب الخادم
لا يضبط العميل هذه القيم مباشرة لكنها تؤثر في السلوك.
| العنصر | الافتراضي | الإعداد | عند التجاوز |
|---|---|---|---|
| Waiter لكل key | 2048 (حد 16384) | MAX_WAITERS | B (busy) |
| مجموع waiters | 16384 (حد 65536) | MAX_TOTAL_WAITERS | B لذلك acquire |
| اتصالات client المتزامنة | 1024 (حد 8192) | MAX_CONNECTIONS | إغلاق فوري |
| Replies المتراكمة لكل اتصال | 256 | compile-time | إغلاق اتصال العميل البطيء |
| Global in-flight acquire | 4096 | compile-time | B لذلك acquire |
| Global in-flight release | 512، lane منفصلة | compile-time | انتظار محدود حتى إغلاق الاتصال |
| Cluster active keys | 65536 | compile-time | B لـkey جديدة |
Read buffer (4096B) وresponse batch (64) وprogress timeout لإطار client بدأ (5 ثوان) وsingle expiry sweep (5 ثوان) ثوابت compile-time. يستخدم cluster expiry deadline min-heap يتحقق من token بدل full scan. راجع الإعداد.
يُغلق admission لكل acquire وkey جديدة وكل waiter عند 90% من hard limit، ولا يُفتح حتى ينخفض الاستخدام دون 75%. لذلك قد يتلقى acquire جديد B قبل الحد؛ وتبقى capacity المحجوزة لـrelease وتعافي Raft منفصلة عن هذه hysteresis.
موجز المخالفة ← الاستجابة
| الحالة | الاستجابة | الاتصال |
|---|---|---|
| op غير معروف | E bad_op | مغلق |
| نقص في الترويسة الثابتة | E bad_request | مغلق |
lease = 0 أو 251..255 | E bad_lease | مغلق |
| مفتاح فارغ / يتجاوز 128 بايت / يحتوي مسافة أو سطرًا جديدًا / ليس UTF-8 | E bad_key | مغلق |
| إطار يتجاوز 192 بايت | E line_too_long | مغلق |
| عدم تطابق بصمة المصادقة | E auth_failed | مغلق |
| امتلاء طابور الانتظار | B + owner + key | يبقى |
| عدم تطابق رمز التحرير | N + token + key | يبقى |
لكل أسباب الأخطاء ومعالجة الاتصال المصاحبة راجع الاستجابة · خطأ E.