Skip to content

chore(pebble): pin FormatMajorVersion to ratchet DBs for pebble v2#538

Merged
bootjp merged 2 commits into
mainfrom
prep/pebble-v2-format-ratchet
Apr 19, 2026
Merged

chore(pebble): pin FormatMajorVersion to ratchet DBs for pebble v2#538
bootjp merged 2 commits into
mainfrom
prep/pebble-v2-format-ratchet

Conversation

@bootjp

@bootjp bootjp commented Apr 19, 2026

Copy link
Copy Markdown
Owner

Summary

Prep step for #289 (pebble v1.1.5 → v2.1.4 bump).

Pebble v2 sets FormatMinSupported = FormatFlushableIngest and refuses to open DBs below that. Today both pebble instances in this repo open with defaults:

  • internal/raftstore/pebble.go — Raft log / stable store (raft.db)
  • store/lsm_store.go — MVCC FSM store

Pebble v1 treats an unset FormatMajorVersion as FormatMostCompatible, so any DB written by current binaries is unreadable by pebble v2. Merging #289 as-is would brick existing clusters on restart.

This PR pins FormatMajorVersion to pebble.FormatVirtualSSTables in both opens. That is the newest format pebble v1.1.5 supports and is well above v2's minimum, so:

  • Fresh DBs are created at a v2-compatible format.
  • Existing DBs are auto-ratcheted by pebble on open.

FormatVirtualSSTables was picked as an explicit, stable constant rather than FormatNewest so the intent is auditable and doesn't drift with future pebble patch releases.

Rollout order

  1. Ship this PR on pebble v1.1.5 to every node (rolling restart is fine).
  2. Verify that each node has successfully opened its DB at least once after running this build — the format ratchet happens during pebble.Open.
  3. Only then merge fix(deps): update module github.com/cockroachdb/pebble to v2 #289 to bump pebble to v2.

If step 2 is skipped on even one node, that node will fail to start after the v2 bump.

Test plan

  • go test ./internal/raftstore/... ./store/... — passes
  • go test ./... — passes
  • golangci-lint run ./internal/raftstore/... ./store/... — clean
  • New regression tests in internal/raftstore/pebble_test.go:
    • TestPebbleStore_FormatRatchetedForV2 — fresh DB opens ≥ FormatFlushableIngest
    • TestPebbleStore_RatchetsExistingDB — reopening a DB created at FormatMostCompatible ratchets it up
    • TestPebbleStore_PreservesLogsAcrossRatchet — committed Raft log entries survive the ratchet

Summary by CodeRabbit

  • Improvements

    • Enhanced database initialization with stricter format version configuration to ensure consistent and predictable behavior during database format transitions and version updates.
  • Tests

    • Added test coverage validating that data persists correctly across database format version changes, including verification that existing data remains intact and accessible following format version updates.

Prep step for bumping github.com/cockroachdb/pebble to v2 (PR #289).

Pebble v2 refuses to open DBs below FormatFlushableIngest. Both DBs in
this repo (internal/raftstore/pebble.go for the Raft log/stable store,
and store/lsm_store.go for the MVCC FSM store) currently open with the
default FormatMajorVersion, which pebble v1 treats as FormatMostCompatible
— so any on-disk state produced by a current binary is unreadable by
pebble v2.

Pin FormatMajorVersion to FormatVirtualSSTables (the newest format pebble
v1.1.5 supports, comfortably above v2 FormatMinSupported). Pebble auto
ratchets the on-disk format on open, so existing databases are upgraded
in place.

Rollout: deploy this change on pebble v1.1.5 first and wait for every
node to successfully open its DB at least once; only then merge the v2
bump in PR #289.

Regression tests in internal/raftstore/pebble_test.go cover:
  - fresh DB opens at a v2-compatible format
  - existing DBs created at FormatMostCompatible are ratcheted on reopen
  - committed Raft log entries survive the ratchet
@coderabbitai

coderabbitai Bot commented Apr 19, 2026

Copy link
Copy Markdown

Warning

Rate limit exceeded

@bootjp has exceeded the limit for the number of commits that can be reviewed per hour. Please wait 8 minutes and 20 seconds before requesting another review.

Your organization is not enrolled in usage-based pricing. Contact your admin to enable usage-based pricing to continue reviews beyond the rate limit, or try again in 8 minutes and 20 seconds.

⌛ How to resolve this issue?

After the wait time has elapsed, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

We recommend that you space out your commits to avoid hitting the rate limit.

🚦 How do rate limits work?

CodeRabbit enforces hourly rate limits for each developer per organization.

Our paid plans have higher rate limits than the trial, open-source and free plans. In all cases, we re-allow further reviews after a brief timeout.

Please see our FAQ for further information.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: bef5eed6-e622-4c1f-b027-7554f6a93f45

📥 Commits

Reviewing files that changed from the base of the PR and between 14558c2 and a357703.

📒 Files selected for processing (2)
  • internal/raftstore/pebble.go
  • internal/raftstore/pebble_test.go
📝 Walkthrough

Walkthrough

Pebble DB initialization is updated across two packages to pin FormatMajorVersion to pebble.FormatVirtualSSTables via helper functions. New tests verify format ratcheting behavior when opening existing databases and persistence of data across format upgrades.

Changes

Cohort / File(s) Summary
Pebble format pinning
internal/raftstore/pebble.go, store/lsm_store.go
Both files add or update functions to pin Pebble's FormatMajorVersion to FormatVirtualSSTables. The raftstore module introduces pebbleOptions() helper; lsm_store updates defaultPebbleOptions() with documentation of the ratchet v1 behavior.
Format ratcheting tests
internal/raftstore/pebble_test.go
New test file with three tests covering Pebble format ratcheting: verifying format version after new store creation, confirming ratchet behavior when reopening existing DBs, and validating log persistence across format upgrade operations.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

Poem

🐰 A rabbit hops through formats so grand,
Pinning versions across the land,
Virtual tables dance and sway,
Data ratchets the proper way,
Pebbles glow in harmony!

🚥 Pre-merge checks | ✅ 3
✅ Passed checks (3 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title accurately summarizes the main change: pinning FormatMajorVersion to support Pebble v2 migration, which is the core objective of this PR.
Docstring Coverage ✅ Passed Docstring coverage is 83.33% which is sufficient. The required threshold is 80.00%.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch prep/pebble-v2-format-ratchet

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@gemini-code-assist gemini-code-assist Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review

This pull request pins the Pebble FormatMajorVersion to FormatVirtualSSTables in both the raft store and the LSM store to ensure compatibility before upgrading to Pebble v2. It also adds comprehensive tests to verify the format ratcheting and data integrity. Feedback includes a suggestion to explicitly call EnsureDefaults() for consistency and to avoid ignoring errors from Close() calls in test cleanup.

Comment thread internal/raftstore/pebble.go
Comment thread internal/raftstore/pebble_test.go Outdated
Comment thread internal/raftstore/pebble_test.go Outdated
Comment thread internal/raftstore/pebble_test.go Outdated

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🧹 Nitpick comments (2)
internal/raftstore/pebble_test.go (1)

13-44: Nit: the two format-assertion tests could be table-driven.

TestPebbleStore_FormatRatchetedForV2 and TestPebbleStore_RatchetsExistingDB share the same post-condition (FormatMajorVersion() >= FormatFlushableIngest) and differ only in the pre-existing DB state. A table-driven test with cases {"fresh", nil} and {"existing-FormatMostCompatible", &pebble.Options{FormatMajorVersion: pebble.FormatMostCompatible}} would reduce duplication. TestPebbleStore_PreservesLogsAcrossRatchet exercises a distinct behavior and is fine standalone.

As per coding guidelines: "Unit tests must be co-located with packages in *_test.go files; prefer table-driven test cases".

internal/raftstore/pebble.go (1)

42-48: Consider centralizing the pinned-format helper.

pebbleOptions() here and defaultPebbleOptions() in store/lsm_store.go independently pin the same FormatMajorVersion. When the v2 bump lands (and likely future ratchets), keeping these in sync across two packages is a foot-gun. Consider extracting a single exported helper (e.g. an internal/pebbleopts package) that both sites consume, so the target format is defined once.

Not blocking for this PR — safe to defer until the v2 bump if you prefer to keep this change minimal.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@internal/raftstore/pebble.go` around lines 42 - 48, The two functions
pebbleOptions() and defaultPebbleOptions() both pin the same FormatMajorVersion
and should share a single exported helper to avoid drift; create a small
internal package (e.g. internal/pebbleopts) that exposes a function like
DefaultPinnedPebbleOptions() which returns a *pebble.Options with
FormatMajorVersion set (pebble.FormatVirtualSSTables), then replace the bodies
of pebbleOptions() and defaultPebbleOptions() to call that new helper so both
packages consume the same canonical value.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Nitpick comments:
In `@internal/raftstore/pebble.go`:
- Around line 42-48: The two functions pebbleOptions() and
defaultPebbleOptions() both pin the same FormatMajorVersion and should share a
single exported helper to avoid drift; create a small internal package (e.g.
internal/pebbleopts) that exposes a function like DefaultPinnedPebbleOptions()
which returns a *pebble.Options with FormatMajorVersion set
(pebble.FormatVirtualSSTables), then replace the bodies of pebbleOptions() and
defaultPebbleOptions() to call that new helper so both packages consume the same
canonical value.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 2809f5ef-2709-41d3-8d97-e2975193c0e8

📥 Commits

Reviewing files that changed from the base of the PR and between 1fa8069 and 14558c2.

📒 Files selected for processing (3)
  • internal/raftstore/pebble.go
  • internal/raftstore/pebble_test.go
  • store/lsm_store.go

- Call EnsureDefaults() in raftstore pebbleOptions() to match the
  lsm_store site (Gemini review).
- Surface errors from Close() in test cleanup instead of swallowing
  them (Gemini review).
@bootjp

bootjp commented Apr 19, 2026

Copy link
Copy Markdown
Owner Author

Thanks for the reviews. Pushed a357703 addressing the actionable items:

Applied (Gemini, medium priority):

  • internal/raftstore/pebble.go: call EnsureDefaults() in pebbleOptions() to match the store/lsm_store.go site.
  • internal/raftstore/pebble_test.go: t.Cleanup now surfaces Close() errors via require.NoError instead of swallowing them.

Not applying (CodeRabbit nitpicks):

  • Table-driving TestPebbleStore_FormatRatchetedForV2 + TestPebbleStore_RatchetsExistingDB: the two cases differ in setup (one pre-opens a FormatMostCompatible DB), so folding them into a table obscures the intent for only two rows. Preferring to keep them as named behaviors.
  • Extracting an internal/pebbleopts package: the reviewer explicitly marks this non-blocking, and with only two call sites on a one-time migration I would rather not introduce a package just for this. If more Pebble opens appear later, a helper can be added then.

@bootjp

bootjp commented Apr 19, 2026

Copy link
Copy Markdown
Owner Author

/gemini review

@gemini-code-assist gemini-code-assist Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review

This pull request updates the Pebble database configuration to pin the FormatMajorVersion to pebble.FormatVirtualSSTables. This change ensures that existing v1-era databases are ratcheted to a version supported by Pebble v2 before the upgrade occurs. The changes are applied to both the raft store and the LSM store, and new tests have been added to verify the ratcheting behavior and data integrity. I have no feedback to provide.

@bootjp bootjp merged commit ae34992 into main Apr 19, 2026
8 checks passed
@bootjp bootjp deleted the prep/pebble-v2-format-ratchet branch April 19, 2026 13:18
bootjp added a commit that referenced this pull request Apr 19, 2026
Supersedes the stale Renovate PR #289. That branch only bumped go.mod
and predates the format-ratchet prep (#538), so it could not be merged
as-is:

  - It kept imports under github.com/cockroachdb/pebble, but pebble v2
    moved the module to github.com/cockroachdb/pebble/v2 and go get
    refuses the old path.
  - It reverted the FormatMajorVersion pinning added in #538, which is
    the entire reason the migration was two-stepped.

Changes here:

  - go.mod / go.sum bumped to cockroachdb/pebble/v2 v2.1.4.
  - All source + test imports updated to the /v2 module path.
  - internal/raftstore/pebble_test.go: dropped the two tests that
    simulated a pre-migration DB by opening at FormatMostCompatible,
    since v2 unexports that constant and rejects opens below
    FormatFlushableIngest anyway; kept a single assertion that a fresh
    NewPebbleStore opens at the pinned FormatVirtualSSTables.

Rollout prerequisite satisfied: #538 has been merged and deployed to
every node, so on-disk DBs are already ratcheted above
FormatMinSupported (FormatFlushableIngest) and open cleanly under v2.
bootjp added a commit that referenced this pull request Apr 19, 2026
## Summary

Upgrades `github.com/cockroachdb/pebble` from v1.1.5 to v2.1.4.

Supersedes the stale Renovate PR #289, which:
- Only bumped `go.mod` / `go.sum` but kept imports under the v1 module
path (pebble v2 moved the module to `github.com/cockroachdb/pebble/v2`).
- Predates #538 and therefore reverts the `FormatMajorVersion` pinning
that was the entire point of the two-stage rollout.

## What changed

- `go.mod` / `go.sum`: pin `github.com/cockroachdb/pebble/v2` v2.1.4;
drop v1 indirect deps that v2 no longer pulls in; add v2-era indirects.
- All Go source + test imports updated to
`github.com/cockroachdb/pebble/v2` and
`github.com/cockroachdb/pebble/v2/vfs`.
- `internal/raftstore/pebble_test.go`:
- Dropped `TestPebbleStore_RatchetsExistingDB` and
`TestPebbleStore_PreservesLogsAcrossRatchet` — both opened a DB at
`FormatMostCompatible` to simulate pre-migration state, but v2 unexports
that constant and refuses to open below `FormatFlushableIngest`. The
behavior they guarded (the ratchet) was the job of #538 and has already
been validated and deployed.
- Renamed the remaining test to `TestPebbleStore_OpensAtPinnedFormat`
and tightened it to assert equality with `FormatVirtualSSTables`, so an
unintended downgrade of the pinned version is caught.

## Migration safety

Rollout prerequisite already satisfied: #538 is merged and deployed
cluster-wide. Every node has opened its `raft.db` at least once under
the prep binary, so on-disk format is ≥ `FormatVirtualSSTables` —
comfortably above v2 `FormatMinSupported` (`FormatFlushableIngest`). v2
will open existing DBs without needing any further ratchet.

## Test plan

- [x] `go build ./...`
- [x] `go vet ./...`
- [x] `go test ./...` (all packages pass locally, including `store/...`
MVCC + snapshot tests and `internal/raftstore/...`)
- [x] `golangci-lint run ./... --timeout=5m` — 0 issues
- [x] `go mod tidy` — no further changes

## Follow-up

PR #289 should be closed with a pointer to this PR.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant