Skip to content

tool/lsm: addFileToSublevels assertion fires when reconstructing L0 organizer from a production LSM #6075

Description

@dt

Summary

pebble/tool/lsm's runLSM reconstructs an L0 organizer from the engine's current state by calling manifest.NewVersionForTesting(*manifest.L0Organizer).ResetForTestingmanifest.newL0SublevelsaddFileToSublevels. On certain production LSM shapes the reconstruction trips an assertion ("addFileToSublevels found existing newer file") and panics. The production-path L0 organizer (which is maintained incrementally rather than rebuilt from scratch) does not trip the same condition on the same LSM.

Where it surfaces

CockroachDB's /debug/lsm-viz/<store> endpoint routes through tool/lsm via pkg/server/debug/server.go:analyzeLSM and inherits the panic. Observed reliably on a post-online-restore CockroachDB cluster whose LSM was holding linked external SSTs at intermediate levels — the CRDB-side report is at cockroachdb/cockroach#170896.

The shape was non-pathological from a correctness standpoint: production reads, writes, and compactions ran against the same LSM without issue. Only the from-scratch reconstruction in the test helpers asserted.

Stack

addFileToSublevels found existing newer file
  internal/manifest/l0_sublevels.go:679  (addFileToSublevels)
  internal/manifest/l0_sublevels.go:309  (newL0Sublevels)
  internal/manifest/l0_sublevels.go:2237 (L0Organizer.ResetForTesting)
  internal/manifest/version.go:124       (NewVersionForTesting)
  tool/lsm.go:326                        (lsmT.buildEdits)
  tool/lsm.go:160                        (lsmT.runLSM)

Conjecture

*ForTesting helpers exist for unit tests with hand-crafted LSMs and may carry stricter invariants than the live organizer maintenance path. Either:

  • The assertion in addFileToSublevels is genuinely over-broad and rejects a file ordering that the production code emits and handles correctly, or
  • The reconstruction's iteration order differs from how the live organizer would have produced the same final state, and that order trips an assertion that's only meaningful for hand-built test fixtures.

In either case, tool/lsm (and its callers) should not depend on *ForTesting reconstruction succeeding on arbitrary production LSMs.

Suggested directions

  • Identify which file ordering trips the assertion. A minimal MANIFEST reproduction would pin it down — restoring gs://cockroach-fixtures-us-east1/roachtest/master/tpcc-5k/20260522-090958.790 AS OF SYSTEM TIME '2026-05-22T10:56:00Z' with EXPERIMENTAL DEFERRED COPY and pausing the download job produces a triggering LSM.
  • If the assertion is legitimate, route tool/lsm around the test-helper path and have it build its view via production-path APIs only.
  • If the assertion is over-broad for production LSMs, narrow it (or remove it) and check whether the live organizer maintenance path was relying on a related invariant.

Related: cockroachdb/cockroach#170896.

Jira issue: PEBBLE-1446

Metadata

Metadata

Assignees

No one assigned

    Labels

    Type

    No type

    Fields

    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions