قيد الاختبار حاليًا: سيتم فتح كود GitHub عند الاكتمال.

قيود الحقول ونطاقات القيم

حقول الطلب (C→S)

الحقلالنوعالنطاق الصالحالمعنىعند المخالفة
opASCII 1BA(0x41) · R(0x52)نوع الطلبE bad_op
waitu80255 (ثانية)0 محاولة فورية بلا queue؛ و1..255 حد انتظار acquire— (صالح دائمًا بحكم النوع)
leaseu81250 (ثانية)Lease؛ تُرفض/تُحجز 0 و251..255E bad_lease
owneru64 BE02^64-1 كاملًامعرّف محاولة الحصول (يولّده العميل)— (لا يتحقق منه الخادم)
tokenu64 BEقيمة يصدرها الخادميحدد ما سيُحرَّر (في R فقط)N عند عدم المطابقة
keyUTF-81 – 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 الأصلي يستخدم wire 0، ولهذه المحاولة الفورية 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)

الحقلالنوعالنطاقيظهر في
tokenu64 BE1 فأكثر، ويزداد مع كل إصدارA (إصدار جديد) · R/N (صدى الطلب)
owneru64 BEقيمة الطلب نفسهاA · T · B (صدى الطلب)
keyUTF-8قيمة الطلب نفسها (1–128 بايت)A · T · B · R · N
addrUTF-8host:portM · L
reasonASCIIالأسباب الثمانية المحددةE

لا يصدر الخادم token 0 أبدًا. يستخدم single counter خلال process lifetime الحالي؛ ويستخدم cluster counter منسوخًا بالإجماع ويفشل fail-closed قبل overflow. لا تضمن wall clock أو العشوائية الرتابة بعد restart.

أطوال الترويسات الثابتة

هو المقطع الثنائي ثابت الطول الذي يلي op مباشرة. قد تحتوي هذه البايتات على 0x0A، لذا يجب على المحلل استهلاك هذا الطول بالضبط قبل البحث عن السطر الجديد.

الاتجاهopالترويسة الثابتةالتركيب
C→SA10 Bwait(1) + lease(1) + owner(8)
C→SR8 بايتtoken(8)
S→CA16 بايتtoken(8) + owner(8)
S→CT · B8 بايتowner(8)
S→CR · N8 بايتtoken(8)
S→CM · L · E0 بايتلا شيء (نص مباشرة بعد op)

وإذا نقصت البايتات فالنتيجة E bad_request.

حجم الإطار

البندالقيمة
الحد الأقصى للإطار (دون \n)192 بايت — عند تجاوزه: E line_too_long
أقصى طلب A1 + 10 + 128 + 1 = 140 بايت
أقصى طلب R1 + 8 + 128 + 1 = 138 بايت
أقصى استجابة A1 + 16 + 128 + 1 = 146 بايت
إطار فارغ (\n فقط)keep-alive — يتجاهله الخادم

حد 192B أكبر من أكبر frame (146B)، لذلك لا يبلغه عميل ملتزم. بعد frame تالف بنيويًا أو oversized لا يعود framing موثوقًا ويُغلق الاتصال.

مصافحة المصادقة

البندالقيمة
التجزئةSHA-256 (مذكورة في سطر التحدي)
nonce8 محارف base64url
بصمة الاستجابة43 محرفًا base64url (بلا حشو)
الحد الأقصى للسطر256 بايت
المهلة10 ثوانٍ (شاملة تفاوض TLS) — وما زاد يُغلق الاتصال

للاطلاع على الإجراء بالتفصيل راجع مصافحة المصادقة.

حدود جانب الخادم

لا يضبط العميل هذه القيم مباشرة لكنها تؤثر في السلوك.

العنصرالافتراضيالإعدادعند التجاوز
Waiter لكل key2048 (حد 16384)MAX_WAITERSB (busy)
مجموع waiters16384 (حد 65536)MAX_TOTAL_WAITERSB لذلك acquire
اتصالات client المتزامنة1024 (حد 8192)MAX_CONNECTIONSإغلاق فوري
Replies المتراكمة لكل اتصال256compile-timeإغلاق اتصال العميل البطيء
Global in-flight acquire4096compile-timeB لذلك acquire
Global in-flight release512، lane منفصلةcompile-timeانتظار محدود حتى إغلاق الاتصال
Cluster active keys65536compile-timeB لـ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..255E bad_leaseمغلق
مفتاح فارغ / يتجاوز 128 بايت / يحتوي مسافة أو سطرًا جديدًا / ليس UTF-8E bad_keyمغلق
إطار يتجاوز 192 بايتE line_too_longمغلق
عدم تطابق بصمة المصادقةE auth_failedمغلق
امتلاء طابور الانتظارB + owner + keyيبقى
عدم تطابق رمز التحريرN + token + keyيبقى

لكل أسباب الأخطاء ومعالجة الاتصال المصاحبة راجع الاستجابة · خطأ E.