Rollback to stable leaves a stale durable mark on the stable update, so the rolled-back value survives on disk

XMLWordPrintableJSON

    • Type: Bug
    • Resolution: Fixed
    • Priority: Major - P3
    • WT12.0.0, 9.1.0-rc0
    • Affects Version/s: None
    • Component/s: RTS
    • None
    • Storage Engines - Transactions
    • 201.125
    • SE Transactions - 2026-08-28
    • 3

      On a disaggregated leader running fuzzy checkpoints, rollback to stable can leave the value it rolled back readable on disk.

      Sequence

      1. A key is written at timestamp 2, stable is 2, and a checkpoint writes it. Reconciliation marks that update WT_UPDATE_DURABLE.
      2. The key is overwritten at timestamp 3 with a durable timestamp beyond stable. A second checkpoint writes the new version and marks it durable too. The older version keeps its own mark, since it is not the on-page update this time.
      3. Rollback to stable aborts the newer version. The chain is left with the timestamp 2 update as current, still carrying WT_UPDATE_DURABLE from the first checkpoint.
      4. The next reconciliation selects that update, sees the durable mark, and concludes nothing changed. The skip-write path keeps the previous image, which still holds the rolled-back value, and a read after eviction returns it.

      Fix

      Rollback to stable should clear the durable marks on the stable update it lands on, in the same place and for the same reason that it already clears the history store flags there (__rts_btree_abort_update in src/rollback_to_stable/rts_btree.c: "Clear the history store flags for the stable update ... Otherwise, it will not be moved to history store again"). An aborted newer version means the stable one has to be written again, so no mark on it can be trusted.

      Relationship to WT-17426

      WT-17426 is the same failure through a different chain shape: a value underneath a tombstone that rollback to stable takes away. Its fix makes reconciliation stop marking a value while a tombstone covers it, which does not help here, because there is no tombstone and the stale mark is on a plain update. That fix and this one are independent.

      Reproducer

      test_checkpoint40 (attached) fails under --hook "disagg=(role=leader)" with the WT-17426 fix applied, in both the prepare and no-prepare scenarios:

      AssertionError: Lists differ: [638, 639, 640, 641, 642] != []
      keys reading back the rolled-back value: [638, 639, 640, 641, 642]
      

      It passes on a regular table, where the durable marks are not used. Clearing WT_UPDATE_DURABLE | WT_UPDATE_PREPARE_DURABLE on stable_upd makes it pass under the hook, with test_truncate32 from WT-17426 still passing.

            Assignee:
            Chenhao Qu
            Reporter:
            Chenhao Qu
            Votes:
            0 Vote for this issue
            Watchers:
            2 Start watching this issue

              Created:
              Updated:
              Resolved: