الخلاصة

  • كان NFSv2 يؤخر عودة عملية التعديل حتى تبلغ التخزين المستقر؛ سهّل ذلك تعافي الخادم عديم الحالة، لكنه وضع زمن الوسيط الدائم في كل كتابة.
  • أضاف NFSv3 درجات UNSTABLE وDATA_SYNC وFILE_SYNC، وجعل الرد يحمل عدد البايتات المكتوبة فعلاً ودرجة الالتزام ومتحقق كتابة معتماً.
  • يحتفظ العميل بالبيانات حتى COMMIT أو نتيجة أقوى. فإذا تغير المتحقق، يفترض أن بيانات النسخة السابقة غير المستقرة قد ضاعت ويعيد إرسالها.

نجاح لا يمنح حق النسيان

تصل إجابة NFS3_OK عن WRITE بعيد. مع ذلك قد تقول خانة committed إن النتيجة UNSTABLE. نجحت عملية البروتوكول، لكن البايتات قد تظل رهينة ذاكرة متطايرة.

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

سمّى RFC 1813 هذا الانتظار عنق زجاجة للأداء. لم تعنِ الكتابة غير المتزامنة الآمنة أن البيانات صارت دائمة مبكراً؛ بل إن النسخة والأدلة ظلت موجودة حتى يمكن إكمال العمل أو إعادته.

الطلب ليس هو النتيجة

يختار العميل UNSTABLE أو DATA_SYNC أو FILE_SYNC. تتطلب الأخيرة البيانات وكل بياناتها الوصفية على التخزين المستقر قبل الرد. تتطلب DATA_SYNC ما يكفي لاستعادة البيانات. أما UNSTABLE فتسمح للخادم بحفظ الكل أو البعض أو لا شيء قبل أن يجيب.

يصف committed في الرد المستوى الذي تحقق فعلاً. يستطيع الخادم أن يمنح مستوى أقوى مما طُلب. ويصف count طول الجزء المكتوب، لأن الكتابة القصيرة جائزة ويجب إرسال الباقي من جديد. وهكذا لا يثبت النجاح العام طول الطلب كله ولا دوام الجزء المقبول.

يرجع الرد أيضاً verf، وهو cookie معتم يبقى ثابتاً خلال نسخة الخادم المعنية ويتغير حين تنتقل الخدمة إلى نسخة ربما فقدت البيانات غير المثبتة. إعادة التشغيل هي الحالة الأشهر، لكن المعنى هو انقطاع الحراسة المتطايرة.

هذا المتحقق ليس بصمة للمحتوى ولا رقم نسخة للملف. تساوي القيم لا يثبت صحة البايتات أو غياب كاتب آخر. تغيرها لا يثبت أن كل شيء ضاع؛ بل يسقط مبرر الاعتماد على ذاكرة النسخة القديمة.

COMMIT يقفل الدين بشرط

بعد رد غير مستقر يحتفظ العميل بالـbuffer. يذكر RFC 1813 ثلاث حالات: dirty، ومنتهٍ لكنه يحتاج إلى commit، ومنتهٍ. الحالة الوسطى هي ثمن الاستجابة السريعة: النقل انتهى، أما مسؤولية البقاء فلم تنته.

يدفع COMMIT التعديلات السابقة إلى التخزين المستقر، ويمكنه معالجة مدى من الملف. تشبيهه بـfsync بعيد مفيد، لكنه لا يجعله دليلاً على صحة التطبيق أو النسخ الاحتياطي.

يعيد COMMIT الناجح متحققاً جديداً. إذا طابق متحقق الكتابات أمكن وصل المرحلتين بالنسخة نفسها. وإذا اختلف، فعلى العميل اعتبار المديات القديمة ذات UNSTABLE مفقودة على نحو محتمل وإعادة كتابتها.

القاعدة محافظة عمداً. ربما وصل بعض البيانات إلى القرص قبل العطل، لكن العميل لا يعرف أيها. إعادة الكتابة إلى offsets المعروفة فعل قابل للإصلاح، لا ادعاء بمعرفة غير موجودة.

حتى التخزين المستقر له حد

يصف RFC 1813 تخزيناً يصمد أمام انقطاعات طاقة متكررة وبعض أعطال العتاد ودورات الانهيار وإعادة التشغيل. لكنه يستثني عطل وحدة التخزين المستقر نفسها. لذلك لا يعني المصطلح نسخة احتياطية أو تكراراً أو خلوداً.

ولا يعد البروتوكول باتساق صارم بين caches. يمكن أن يكون مدى ما دائماً بينما يرى عميل آخر حالة قديمة. الدوام يجيب عن البقاء بعد العطل؛ أما أي نسخة ينبغي أن تسود فسؤال آخر.

استمر المبدأ في RFC 3530 وRFC 7530. وينص RFC 8881 بوضوح على أن تغير write verifier يلزم العميل بافتراض ضياع بيانات UNSTABLE4 القديمة واستعادتها.

السرعة نقلت المسؤولية

استطاع الخادم جمع عمليات التثبيت وتأخيرها، فصار المسار العادي أسرع. لكن العمل عاد في ذاكرة العميل وخرائط المديات وعمليات COMMIT وحركة الإعادة بعد تغير النسخة. لم تكن اللامزامنة مجانية؛ كانت ديناً مشروطاً له مالك واضح.

وقد يتعطل العميل نفسه قبل إرسال COMMIT، وهو احتمال يذكره RFC 1813. وجود مسار استعادة صحيح في البروتوكول لا يعني أن التطبيق أكمله. لذلك يجب أن تحدد الطبقة التي تعلن اكتمال العمل متى تنتظر التثبيت، وماذا تفعل عند الإغلاق، وأي دليل تحتاج قبل أن تحول نجاح WRITE إلى نتيجة أعمال نهائية.