Skip to content

pager4-1.4: a same-second stranger at a vacated path passes the tip proof (seed commits are byte-identical) #1884

Description

@timsehn

The one residual from #1853, split out so that issue can close on the landed fix
(#1878 / #1879 / #1881).

What still fails

pager4-1.4: a never-committed database is renamed away while open, and a
different database is created at the vacated path within the same second. The
moved-file ownership check probes the file at the path for one of the handle's
branch tips; the stranger passes the probe and is adopted, so the write is not
refused:

expected: [1 {attempt to write a readonly database}]
got:      [1 {no such table: t1}]

Any database with one real dolt_commit is protected — its tip is unique
content over its own data. The exposure is exactly: seed-only history, plus a
same-second stranger at the vacated path. No data is lost when it happens; the real
store is intact at its renamed path.

Mechanism

Two databases created in the same second are byte-identical: the seed commit
hashes an empty parent, an empty catalog, the fixed message, NULL author/email, and
a second-resolution timestamp — same content, same hash (#1864, closed as correct
content addressing; Dolt is also second-resolution with no nonce). So the stranger
genuinely contains the handle's tip, and no content probe can separate them. This
is not a flaw in the tip probe; it is the limit of content addressing as an identity.

Why this is parked

Every real fix changes something customers may now treat as stable, and there has
been no format change in over a month (decision deliberately deferred):

  1. Unique seed commit — per-database entropy in the seed. The only
    non-user-visible slot is a new commit format field (DOLTLITE_COMMIT_V3), the
    Concurrent commits still drop uncommitted-recent chunks after #1545 (second layer) → dangling chunk → gc mark-fail → unreclaimable bloat #1547 area. Parking entropy in author/email/message is visible in dolt_log
    forever and diverges from Dolt. Note this bends the commit format to serve a
    pager-level question — the concern that closed Seed every database, and prove a replaced file is ours by its head commit (#1853, #1873) #1872's first approach.
  2. Manifest store ID — 16 random bytes minted at creation, carried forward by
    GC's rewrite; 24 free bytes exist after SELF_HASH (offsets 144..167 of 168) and
    SELF_HASH already covers new fields. Conceptually the right layer (file
    identity answered by a store property, not VC content) and the probe collapses to
    a header read, deleting the GC dependency entirely. Cost: every manifest writer
    must preserve it, plus a legacy-zero-ID rule and a clone inherit-or-mint decision.
  3. Graph-lock sidecar record — GC records the installed inode under the lock it
    already holds. No database-format change, but the .name-lock file has been
    zero-byte since it existed, so giving it a payload is an on-disk contract change
    too, and it needs answers for a deleted sidecar (tester.tcl forcedeletes) and
    torn writes.

If/when a format window opens, (2) is the recommendation on record: it fixes this
case and replaces the content probe wholesale rather than patching it.

Guardrails already in place

  • The gate carries the true reason:
    pager4-1.4 # two databases created in the same second are byte-identical, ...
  • gc_tip_survival_test pins the GC contract the current probe depends on, so this
    issue is only about the same-second seed collision, not probe soundness.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions