פתרון עמידות ופורמט נתונים¶
הפענוח צריך להחזיר תוצאה שמבחינה בין סיבות הכשל. האורך נבדק לפני קריאת השדות, ואז magic, גרסה, סוג, שדות שמורים ו־checksum. רק אחר כך בונים ערך לוגי של רשומה. כך אין שימוש בשדה length לא אמין כדי לגשת מחוץ ל־buffer.
בגרסת המעבדה כל עסקה מכילה שתי רשומות קבועות. אפשר לקרוא data, לשמור אותה כמועמד ואז לקרוא commit. מספר הרצף ושדות העסקה צריכים להתאים. רק לאחר ההתאמה מעדכנים את המפה. מספר רצף שכבר הוחל אינו מוחל שוב.
תוצאות חיתוך¶
חתך לפני תחילת הזוג האחרון משאיר רק עסקאות קודמות. חתך באמצע data או commit משאיר סיומת לא שלמה, ולכן העסקה האחרונה אינה מוחלת. זוג שלם ותקין יכול להיות מוחל בזמן recovery גם אם הלקוח לא קיבל תשובה לפני הקריסה. זו אינה כפילות, אלא אי־ודאות של הלקוח לגבי תוצאה שכבר התקבלה.
פגם ב־checksum באמצע רשומה שלמה הוא ממצא שצריך לדווח. אין להניח שכל פגם הוא סוף כתיבה שנקטעה. אם היומן מכיל אחריו רשומות נוספות, השלכה שקטה של הסיומת עלולה למחוק לוגית עסקאות מאושרות.
לולאת כתיבה מלאה¶
הקטע הבא הוא פונקציית עזר לשילוב בקוד Windows, עם handle סינכרוני ו־span שהגודל שלו קטן מן הגבול של DWORD בכל איטרציה:
void write_all(HANDLE file, std::span<const std::byte> bytes) {
while (!bytes.empty()) {
const DWORD request = static_cast<DWORD>(
std::min<std::size_t>(bytes.size(), 1024 * 1024));
DWORD written = 0;
if (!WriteFile(file, bytes.data(), request, &written, nullptr))
throw std::system_error(static_cast<int>(GetLastError()),
std::system_category(), "WriteFile");
if (written == 0 || written > request)
throw std::runtime_error("no valid write progress");
bytes = bytes.subspan(written);
}
}
הפונקציה דורשת את כותרות Windows, span, algorithm, cstddef, system_error ו־stdexcept. היא אינה מבצעת flush, משום שגבול העסקה נמצא מעליה. לאחר כתיבת שני חלקי העסקה, הקורא מפעיל FlushFileBuffers ובודק את התוצאה לפני אישור.
ידע אחרי כשל¶
אם נכשלה כתיבת data, אין אישור וה־recovery בודק סיומת חלקית. אם commit נכתב אבל flush נכשל, התוצאה עדיין אינה מאושרת ללקוח; ייתכן שב־recovery תופיע עסקה שלמה. אם flush הצליח אבל התשובה אבדה, השרת יכול לשחזר עסקה שהלקוח רואה כלא ודאית.
הפתרון לכך אינו למחוק עסקאות שהלקוח לא זוכר, אלא לשמור מזהה בקשה ולענות על ניסיון חוזר באופן מוגדר. קריסת תהליך בודקת את פרוטוקול היישום ואת קריאת הקובץ מחדש; היא אינה מוכיחה שהחומרה תעמוד בהבטחה מול אובדן חשמל.