Document layered cursor internal contracts

XMLWordPrintableJSON

    • Type: Improvement
    • Resolution: Unresolved
    • Priority: Major - P3
    • None
    • Affects Version/s: None
    • None
    • Storage Engines - Foundations
    • 134.206
    • None
    • None

      Motivation

      Nearly every bug and fragility ticket in the Layered Cursors Rework epic (SPM-4736) traces back to an implicit contract: state that one function establishes, another relies on, and nothing documents or asserts. Reviews repeatedly stall on re-deriving these contracts from scratch (WT-17967 exists because the rationale behind WT-16955's search_near side-selection was lost; WT-17994 lists six spots in the iteration logic whose correctness rests on unstated invariants). WT-17781 additionally requires that every state covered (or intentionally excluded) by the grey-box unit tests be documented in some form.

      Goal

      Decide where this documentation should live and write it there. The deliverable is that a working engineer can answer "what state is this cursor guaranteed to be in here?" from documentation rather than archaeology. A single canonical home is preferred over spreading the same contract across several places that will drift apart.

      Candidate places to consider

      Ideas, not requirements - pick what fits, or propose another:

      • src/docs/arch-disagg-layered-cursor.dox - already exists (~47 lines: structure basics and the definition of "positioned") and is the natural canonical home; the architecture guide is where WiredTiger already keeps this kind of prose.
      • A contract comment at the top of src/cursor/cur_layered.c - lives next to the code that must honor it, visible in every review; risks drifting from a larger external page if both carry substance.
      • Function-header comments on the few contract-bearing functions (enter/leave, update_state, the iteration entry point) stating only their entry/exit guarantees - smallest form, enforced by review.
      • A state-transition table or diagram (in the arch page, or a separate artifact) - per API call: required entry state, guaranteed exit state on success, WT_NOTFOUND, WT_PREPARE_CONFLICT, WT_ROLLBACK, generic error.
      • Asserts as executable documentation - an invariant that can be asserted arguably should not be prose at all; whatever remains prose should be explicitly marked as unchecked.

      Content ideas

      • Cursor cast and "positioned". iface, ingest/stable constituents, current_cursor, the alternate. What "positioned" means at each level (WT_CURSTD_KEY_INT, current_cursor set, constituent parked on the same key), what a "parked" alternate is, when the alternate is expected positioned versus legitimately exhausted or unopened.
      • Durable vs. per-operation state. Which fields persist between API calls versus live only in WT_CLAYERED_OP; expected cursor state after each operation on success and on every failure class (positioned / key-only after remove / external key after largest_key / unpositioned).
      • Iteration state machine. Direction-flag lifecycle, alternate reuse versus repositioning, the prepare-conflict stall and resumption (the blocked constituent re-drives the blocked key), why repositioning the alternate mid-stall may have no viable anchor key (WT-17960 / BF-43990 as a worked example).
      • Context-change detection. How a checkpoint pickup, a snapshot change, and a read-timestamp change are each detected, which cursor state each invalidates, constituent reopen rules on both roles - including when reopening must not happen.
      • Tombstones and value encoding. Why deletes must land in ingest as tombstones (masking stable keys), the encode/decode scheme for user values colliding with the tombstone encoding, tombstone lifetime.
      • Prepared transactions. Why only ingest can raise a prepare conflict, what state is kept while stalled, exit contract when the prepare resolves as commit versus rollback (including resolution with a tombstone).
      • Write path. Why writes look up before the put and the cost implications; overwrite versus non-overwrite; conflict detection on keys not visible in ingest (__clayered_modify_check); the required reset of the non-target constituent before a write; remove on a cursor positioned in a previous transaction.
      • Roles. Leader/follower differences: which constituent receives writes, when constituents are skipped or absent (no stable before the first checkpoint on a follower, no ingest cursor on a leader), role-agnostic operation bodies, invariants across promotion/step-down.
      • Session interaction. enter/leave lifecycle, ncursors accounting, read-committed snapshot release, eviction back-pressure delivery.
      • search_near. Merged-result semantics, side selection in the straddle case, the recovered rationale for the current rule (input to WT-17967).
      • Deliberately disabled behaviors. Cursor reposition and other file-cursor features layered cursors opt out of, with reasons.
      • Testing map. Which suite owns which class of behavior (differential stress test, grey-box unit tests, Python integration) and what is intentionally out of scope of each.

      Possible extras: an error-exit contract table (what a caller may legally do after each error class), truncate semantics on layered tables, bounds / next_random / reserve / modify support status, observability (stats and verbose categories for diagnosing layered cursor issues), a short glossary (ingest, stable, constituent, alternate, parked, stall, pickup).

      Definition of Done

      • Chosen location(s) agreed with the team and documentation written there.
      • Contracts either asserted in code or explicitly documented as unchecked.
      • WT-17781's state-coverage documentation requirement satisfied or explicitly delegated.

            Assignee:
            [DO NOT USE] Backlog - Storage Engines Team
            Reporter:
            Ivan Kochin
            Votes:
            0 Vote for this issue
            Watchers:
            2 Start watching this issue

              Created:
              Updated: