לדלג לתוכן

פתרון תצורה ומדיניות

פתרון התרגיל הראשון

הערכים 1 ו64 מתקבלים. הערכים 0 ו65 הם REG_DWORD תקינים מבחינת הייצוג, אבל אינם חוקיים במוצר שלנו ולכן נשאר הערך הפעיל הקודם. ערך חסר או טיפוס מחרוזת יידחו כבר בקריאת הAPI שביקשה מספר מהטיפוס המדויק.

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

$labKey = 'HKCU:\Software\AmitTechCourse\ConfigurationLab'
New-ItemProperty -Path $labKey -Name Workers -PropertyType String -Value '7' -Force | Out-Null
New-ItemProperty -Path $labKey -Name Workers -PropertyType DWord -Value 4 -Force | Out-Null

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

פתרון התרגיל השני

נניח שהזוג הישן הוא מינימום 2 ומקסימום 4, והחדש הוא מינימום 8 ומקסימום 16. קורא שרואה מינימום חדש ומקסימום ישן יקבל 8 ו4, אף שאף כותב לא התכוון לפרסם זוג כזה.

נשתמש במפתחות Versions\v17 וVersions\v18, ובערך ActiveVersion. הכותב בונה את v18 בשלמותו, מאמת אותו ורק אז מחליף את המזהה הפעיל. הקורא מחזיק את שם הגרסה שבחר ולא מערבב ערכים מגרסאות שונות. בתכנון הזה יש כותב יחיד; כותבים מרובים ידרשו גם הכרעה ביניהם.

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

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

פתרון התרגיל השלישי

הקוד הבא הוא תוכנית בדיקה מלאה. המקור מציין אם התקרה שינתה בפועל את הבחירה; במוצר נוכל לשמור בנוסף גם את עצם קיום המדיניות לצורכי תצוגה.

#include <algorithm>
#include <cassert>
#include <optional>
#include <stdexcept>

enum class source { fallback, user, policy_limit };
struct effective { unsigned workers; source origin; };

effective choose(std::optional<unsigned> user,
                 std::optional<unsigned> policy) {
    auto valid = [](std::optional<unsigned> value) {
        return !value || (*value >= 1 && *value <= 64);
    };
    if (!valid(user) || !valid(policy))
        throw std::invalid_argument("workers outside allowed range");
    unsigned requested = user.value_or(2);
    if (policy && requested > *policy)
        return {*policy, source::policy_limit};
    return {requested, user ? source::user : source::fallback};
}

int main() {
    assert(choose({}, {}).workers == 2);
    assert(choose(8, {}).workers == 8);
    assert(choose({}, 1).workers == 1);
    assert(choose(8, 4).origin == source::policy_limit);
    assert(choose(3, 4).workers == 3);
    bool rejected = false;
    try { (void)choose(0, 4); }
    catch (const std::invalid_argument&) { rejected = true; }
    assert(rejected);
}

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