לדלג לתוכן

פתרון מעקב שינויים ונעילה

ה־watcher צריך להחזיק שני סוגי מצב: מצב בקשת ה־I/O ומצב הידע על התיקייה. בקשה שהסתיימה בהצלחה יכולה עדיין להשאיר את הידע לא שלם כאשר אין פירוט. לכן דגל כגון needs_rescan הוא מצב לוגי נפרד משגיאת API.

לאחר completion מאפסים OVERLAPPED ומכינים אירוע שאינו מסומן לפני הגשה חדשה. אין לאפס בזמן שהבקשה הקודמת פעילה. אפשר לעבד עותק של ההודעות ולהגיש מיד buffer אחר, אבל אז כל buffer צריך בעלות נפרדת וגבול למספר batches שממתינים לעיבוד.

פענוח עמיד

הבדיקה של NextEntryOffset חייבת לוודא התקדמות, גבול ויישור. אחרת buffer פגום יכול ליצור לולאה שאינה מתקדמת או קריאה מחוץ לטווח. אורך השם נמדד בבתים, ולכן הוא חייב להתחלק בגודל wchar_t לפני בניית המחרוזת ביעד Windows.

הדוגמה משתמשת ב־memcpy לשדות כדי לא להניח שכבר קיים אובייקט C++ מטיפוס FILE_NOTIFY_INFORMATION בתוך מערך הבתים. אפשר להשתמש גם בגישה מתועדת אחרת עם הוכחת יישור וחיים, אבל אין צורך ב־reinterpret_cast כדי לפענח שלושה DWORDים.

סריקה מחדש

מסלול reconciliation מונה שמות ומאפיינים מתוך התיקייה ומייצר snapshot חדש. לאחר מכן משווים לזהויות ולשמות שבמצב הקודם. קובץ שנעלם תוך כדי enumeration אינו בהכרח שגיאה קטלנית; צריך להגדיר כיצד חוזרים או משלימים את התמונה באמצעות התראות נוספות.

ה־snapshot אינו אטומי מול שינויים במקביל. לכן בדיקה חזקה משתמשת ברצף שבו נרשמים להתראות לפני הסריקה, שומרים את מה שהגיע בזמן הסריקה ומוודאים שלא התקבל overflow נוסף. אם כן, מסמנים שוב צורך בסריקה. עבור מערכת בעלת דרישת עקביות חזקה יותר צריך פרוטוקול מתאים, ולא רק לולאה מהירה יותר.

כתיבה משותפת

שני writers יכולים לפתוח עם FILE_SHARE_WRITE ולקרוא את אותו ערך מונה. כל אחד מגדיל וכותב בחזרה, ואחד העדכונים הולך לאיבוד. מנגנון המעקב יראה שינוי כלשהו אחרי הפעולה, אך לא ימנע את המרוץ ולא יידע בהכרח כמה פעולות לוגיות היו.

התיקון יכול להיות writer יחיד שמקבל בקשות דרך IPC, נעילת טווח עם פרוטוקול ברור או מנגנון עסקה. הבחירה צריכה להתאים גם לקריסה של אחד המשתתפים, ולא רק למקרה שבו שניהם מסיימים כרגיל.