Exercise 1: Rebuilding the Index After a Crashed Insert — Possible Solution ==================================================================== THE TEST ------------------------------ db = Database(tmp) db.create_table('accounts', [('id','INTEGER'),('name','TEXT'),('balance','INTEGER')]) db.create_index('accounts', 'id') db.insert('accounts', [1, 'Alice', 500]) schema, table = db.tables['accounts'] table.insert([2, 'Bob', 300]) # simulated crash -- index never updated # BEFORE rebuilding: before = db.select('accounts', where=('id', '=', 2)) # rebuild the index from scratch, by re-scanning the real table db.create_index('accounts', 'id') # AFTER rebuilding: after = db.select('accounts', where=('id', '=', 2)) RESULT ------------------------------ before rebuilding: [] after rebuilding: [[2, 'Bob', 300]] WHY REBUILDING FIXES IT HERE ------------------------------ create_index() doesn't trust whatever is currently sitting in self.indexes -- it throws the old (stale) tree away entirely and builds a brand new one by scanning every row genuinely present in the heap table right now (table.scan_with_locations()), feeding each one through btree_insert() from a clean root. Since the heap table itself was never corrupted -- only the index fell out of sync -- a full rebuild from the real, physical data is guaranteed to produce a tree that agrees with the table again, because it is built directly FROM the table, not incrementally patched. WHY THIS IS A WORKAROUND, NOT A GUARANTEE ------------------------------ Three real problems with relying on "just rebuild the index": 1. It requires someone (or something) to NOTICE the index is stale in the first place. Nothing in Course 1's engine detects this on its own -- the bug is completely silent until a query happens to return a suspiciously short result and a human investigates. 2. A full rebuild means a full table scan -- exactly the O(n) cost Course 1's own Chapter 1 built the index to avoid in the first place. For a large table, "just rebuild it" is not a cheap fix. 3. It only works AFTER the fact. It does nothing to stop the next crash from creating the exact same problem again five minutes later, for a different row. A real fix has to prevent the two steps (write the row, update the index) from ever being allowed to complete only one at a time -- which is exactly what atomicity, built in Chapter 4, actually guarantees. WHY THIS WORKS AS AN ANSWER ------------------------------ The result confirms the underlying row was never lost or corrupted -- only the index's own knowledge of it was missing -- and that a full, honest rebuild from real data is a genuine, working fix for THIS instance of the bug. But framing it as a workaround rather than a solution is the important part of the exercise: it correctly distinguishes "a fix exists" from "the problem is prevented," which is the entire reason Course 2 exists.