Exercise 3: Three Writes to the Same Page, One Undo Record — Possible Solution ==================================================================== THE TEST ------------------------------ real_heap = HeapFile(heap_path) pn = real_heap.allocate_page() original = bytes(real_heap.read_page(pn).data) txn = Transaction() thf = TransactionalHeapFile(real_heap, txn, 'x') for content in [b'V1', b'V2-X', b'V3-LONGEST-OF-THE-THREE']: p = Page(); p.add_record(content) thf.write_page(pn, p) print(len(txn.undo_log)) txn.rollback({'x': real_heap}) after = bytes(real_heap.read_page(pn).data) print(after == original) RESULT ------------------------------ undo log entries after THREE writes to the same page: 1 page restored to true original after 3 writes + rollback: True Even with three separate writes -- V1, then V2-X, then V3-LONGEST-OF-THE-THREE -- the undo log still ends up with exactly one entry, and rollback restores the page to its genuine pre-transaction state, not to V1 or V2-X (either of which would be an intermediate state, not the true original). WHY THE COUNT DOESN'T GROW WITH THE NUMBER OF WRITES ------------------------------ record_write()'s own guard clause runs on every single write, not just the first: key = (file_name, page_num) if key in self.touched: return The second write to page pn finds key already present in self.touched (added during the first write) and returns immediately -- no new undo entry, no re-reading the page's current content. The third write hits the exact same guard and does the exact same thing. No matter how many times a single transaction rewrites the same page -- three, thirty, three hundred -- exactly one undo record ever gets created for it, captured at the moment of the very first touch, which is the only moment that actually corresponds to the true pre-transaction state. WHY THIS GENERALIZES BEYOND JUST THREE WRITES ------------------------------ This is the same mechanism Finding 2 already demonstrated with two writes -- this exercise simply confirms the property holds for an arbitrary number of repeated writes, not just exactly two. The guard clause doesn't count writes or special-case "the second one" versus "the third one" -- it only ever asks "have I already captured this page's before-image," which is a question whose answer stays "yes" for every write after the first, regardless of how many more follow. WHY THIS WORKS AS AN ANSWER ------------------------------ Extending Finding 2's own two-write scenario to three writes with three genuinely different contents, and confirming the undo log still holds exactly one entry, rules out the possibility that the dedup behavior was specific to the "exactly two writes" case tested in the chapter -- it's a structural property of the guard clause itself, correct for any number of repeated writes to the same page.