Skip to content

fix: correct Pebble iterator bounds and use pre-allocated txn prefix bytes#432

Merged
bootjp merged 5 commits intofeature/refactorfrom
copilot/sub-pr-429
Mar 25, 2026
Merged

fix: correct Pebble iterator bounds and use pre-allocated txn prefix bytes#432
bootjp merged 5 commits intofeature/refactorfrom
copilot/sub-pr-429

Conversation

Copy link
Copy Markdown
Contributor

Copilot AI commented Mar 25, 2026

Two issues in the previous PR: iterator bounds in GetAt/LatestCommitTS leaked adjacent user keys into the scan range, and txnLockKey/txnIntentKey weren't using the pre-allocated prefix byte slices.

Iterator upper-bound bug (store/lsm_store.go)

With the [userKey][8-byte inverted TS] encoding, the old upper bound encodeKey(key, 0) + 0x00 = key + \xFF×8 + \x00 does not confine iteration to a single user key. Any key where key is a byte-prefix leaks in — e.g. for key="a", all versions of "ab" satisfy "ab\xFF…" < "a\xFF…\x00" and fall inside the range.

Adds a keyUpperBound helper (next lexicographic prefix, standard LSM idiom) and applies it to both GetAt and LatestCommitTS:

// before — too wide; "ab" versions bleed into "a"'s range
upper := encodeKey(key, 0)
upper = append(upper, 0)

// after — tightly confines to exactly userKey
UpperBound: keyUpperBound(key),  // e.g. "a" → "b", "a\xFF" → "b", all-\xFF → nil

In practice the userKey equality check after SeekGE/First would catch the mismatch, but incorrect bounds mean Pebble may scan unnecessary SST blocks, and conflict checks in LatestCommitTS could return a false negative if the seek lands on a prefix-adjacent key first.

txn prefix byte slices (kv/txn_keys.go)

txnLockKey and txnIntentKey were appending the string constants directly instead of the pre-allocated txnLockPrefixBytes/txnIntentPrefixBytes slices introduced in the same prior commit:

// before
k = append(k, txnLockPrefix...)   // string constant

// after
k = append(k, txnLockPrefixBytes...)  // pre-allocated []byte

💡 You can make Copilot smarter by setting up custom instructions, customizing its development environment and configuring Model Context Protocol (MCP) servers. Learn more Copilot coding agent tips in the docs.

…cated prefix bytes

Co-authored-by: bootjp <1306365+bootjp@users.noreply.github.com>
Agent-Logs-Url: https://github.com/bootjp/elastickv/sessions/8c736c29-0405-4197-93a2-8f290254f51d
Copilot AI changed the title [WIP] Fix address critical data safety, consistency, and performance issues fix: correct Pebble iterator bounds and use pre-allocated txn prefix bytes Mar 25, 2026
Copilot AI requested a review from bootjp March 25, 2026 09:21
@bootjp
Copy link
Copy Markdown
Owner

bootjp commented Mar 25, 2026

@copilot このPRの変更にかかわらず、 golangci-lint をパスさせてください

Copilot AI and others added 3 commits March 25, 2026 12:31
…rdinator_abort_test.go, and lsm_store.go

Co-authored-by: bootjp <1306365+bootjp@users.noreply.github.com>
Agent-Logs-Url: https://github.com/bootjp/elastickv/sessions/aed61b49-9084-425e-bd0e-899be4c0bf9d
…ction

- kv/fsm.go: extract decodeLegacyRaftRequest from decodeRaftRequests default case
- cmd/server/demo.go: extract setupFSMStore from run function
- store/lsm_store.go: extract compactEntryState/shouldDeleteEntry/compactFlushBatch
  for Compact; extract restoreMVCCEntries for restoreFromStreamingMVCC;
  extract restoreGobEntries for restoreFromLegacyGob; add hash import
- store/mvcc_store.go: lift compactEntry to package scope; extract
  computeScanCapHint/collectScanResults for ScanAt; extract
  compactPhase1/compactPhase2 for Compact
- store/mvcc_store_concurrency_test.go: extract goroutine bodies into
  concurrentGetAtWriter/concurrentGetAtReader, scanAtWriter/scanAtScanner,
  snapshotConsistencyWriter/snapshotConsistencyScanner helpers
- kv/lock_resolver.go: fix pre-existing undefined ok/userKey variables by
  using txnUserKeyFromLockKey; apply gofmt alignment

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
…etypeassert, wrapcheck, mnd, gosec, unused)

Co-authored-by: bootjp <1306365+bootjp@users.noreply.github.com>
Agent-Logs-Url: https://github.com/bootjp/elastickv/sessions/aed61b49-9084-425e-bd0e-899be4c0bf9d
Copy link
Copy Markdown
Contributor Author

Copilot AI commented Mar 25, 2026

@copilot このPRの変更にかかわらず、 golangci-lint をパスさせてください

Fixed all 23 golangci-lint issues in commit e27d5ab (plus e6ea2b8 for the gci auto-fixes):

  • gci (3): Auto-fixed import formatting in kv/lock_resolver.go, kv/sharded_coordinator_abort_test.go, store/lsm_store.go
  • unused (1): Removed unused withinBoundsKey from store/mvcc_store.go
  • forcetypeassert (1): Comma-ok assertion in store/lsm_store_test.go
  • wrapcheck (2): Wrapped ctx.Err() with errors.WithStack() in kv/lock_resolver.go and store/lsm_store.go
  • mnd (4): Extracted uint64FieldSize constant in kv/txn_codec.go and txnNamespaceSentinel in kv/lock_resolver.go
  • gosec G115 (2): Changed goroutine loop variables to uint64 in store/mvcc_store_concurrency_test.go
  • cyclop (9): Extracted helper functions across cmd/server/demo.go, kv/fsm.go, store/lsm_store.go, store/mvcc_store.go, and test files
  • gocognit (1): Extracted writer/scanner helpers in TestMVCCConcurrentScanAtAndPutAt

Local golangci-lint v2.11.4 now reports 0 issues.

Copilot AI requested a review from bootjp March 25, 2026 13:10
@bootjp bootjp marked this pull request as ready for review March 25, 2026 14:50
@bootjp bootjp merged commit 13366d2 into feature/refactor Mar 25, 2026
4 checks passed
@bootjp bootjp deleted the copilot/sub-pr-429 branch March 25, 2026 14:50
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.

2 participants