Skip to content

fix: keep disk cache file state consistent on main - #24511

Merged
mergify[bot] merged 15 commits into
matrixorigin:mainfrom
LeftHandCold:fix/disk-cache-stale-index-main
May 21, 2026
Merged

fix: keep disk cache file state consistent on main#24511
mergify[bot] merged 15 commits into
matrixorigin:mainfrom
LeftHandCold:fix/disk-cache-stale-index-main

Conversation

@LeftHandCold

@LeftHandCold LeftHandCold commented May 20, 2026

Copy link
Copy Markdown
Contributor

What type of PR is this?

  • API-change
  • BUG
  • Improvement
  • Documentation
  • Feature
  • Test and CI
  • Code Refactoring

Which issue(s) this PR fixes:

issue #24493

What this PR does / why we need it:

This ports the disk-cache stale-index fix and its follow-up hardening to main.

The core bug is that, after FIFO postEvict callbacks were allowed to run outside queueLock, an old disk-cache eviction callback could delete the physical full-file cache file for a newer entry of the same key. That left the in-memory disk-cache index present while the file was gone, so later reads missed disk cache and repeatedly fetched the full object from S3 again.

This PR keeps the main-branch behavior aligned with the hardened 4.0-dev fix and also carries the conservative follow-up guards needed to avoid new cache lifecycle races:

  • keep disk-cache physical files and FIFO index state consistent during eviction and stale-index repair
  • preserve the deferred postEvict flow, including EvictWithWait
  • drain pending FIFO enqueue jobs before accounting-sensitive paths
  • retain mem-cache ownership before publishing a new FIFO entry
  • skip direct FIFO enqueue if the item was deleted before a slow postSet callback returns
  • keep the regression coverage for stale index repair, enqueue accounting, and mem-cache callback ordering

Validation

  • source /Users/shenjiangwei/Work/code/matrixone/setup_env.sh && go test -race -mod=mod ./pkg/fileservice ./pkg/fileservice/fifocache -run 'TestMemCacheRetainsBeforeSetVisible|TestMemCacheSkipsStalePostEvictAfterReinsert|TestMemCacheSerializesSameKeyCallbacks|TestDirectEnqueueSkipsDeletedItem|TestEvictSkipsDeletedPendingEnqueueJob|TestReplaceAccountsPendingEnqueueJob|TestEvictAccountsPendingEnqueueJob' -count=1 -timeout=120s
  • source /Users/shenjiangwei/Work/code/matrixone/setup_env.sh && go test -mod=mod ./pkg/objectio ./pkg/fileservice ./pkg/fileservice/fifocache -count=1 -timeout=180s

LeftHandCold and others added 4 commits May 20, 2026 19:12
Move FIFO post-evict callbacks outside internal locks safely and prevent stale disk cache eviction callbacks from deleting files that have been reinserted. Also repair stale disk cache index entries when SetFile sees an index hit but the physical file is gone.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Copilot AI review requested due to automatic review settings May 20, 2026 11:21
@qodo-code-review

Copy link
Copy Markdown

Qodo reviews are paused for this user.

Troubleshooting steps vary by plan Learn more →

On a Teams plan?
Reviews resume once this user has a paid seat and their Git account is linked in Qodo.
Link Git account →

Using GitHub Enterprise Server, GitLab Self-Managed, or Bitbucket Data Center?
These require an Enterprise plan - Contact us
Contact us →

Copilot AI 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.

Pull request overview

This PR cherry-picks a disk cache stale-index fix onto main by tightening coordination between the FIFO cache index and on-disk cache files during eviction and stale-file repair, and by adding regression tests to lock in the behavior.

Changes:

  • Update fifocache.Cache eviction flow to run postEvict callbacks outside queueLock, add Contains/Replace, and track item queue membership to improve eviction correctness.
  • Harden DiskCache eviction/write paths to avoid deleting files that are concurrently being updated, and to repair stale index entries when the physical file is missing.
  • Add/extend unit tests covering stale-index repair, eviction skipping updated paths, size replacement correctness, and post-evict concurrency behavior.

Reviewed changes

Copilot reviewed 5 out of 5 changed files in this pull request and generated 1 comment.

Show a summary per file
File Description
pkg/fileservice/fifocache/fifo.go Refactors eviction/post-evict flow, adds Contains/Replace, and introduces queue-state tracking for items.
pkg/fileservice/fifocache/fifo_test.go Adds regression tests for Replace accounting and for postEvict executing outside queueLock (including panic behavior).
pkg/fileservice/fifocache/data_cache.go Adjusts path deletion to defer post-evict callbacks until after shard unlock.
pkg/fileservice/disk_cache.go Prevents evict/remove races with in-flight writes, repairs stale index entries, and uses Replace to update FIFO accounting after rewrites.
pkg/fileservice/disk_cache_test.go Adds regression tests for stale index repair and eviction/write race scenarios.
Comments suppressed due to low confidence (1)

pkg/fileservice/fifocache/fifo.go:416

  • EvictWithWait defers all postEvict callbacks until after the whole eviction loop completes, which can keep many large values alive at once under heavy over-capacity conditions. If postEvict is responsible for releasing memory/resources, consider flushing callbacks in batches (or otherwise streaming them) to reduce peak retained memory during large evictions.
func (c *Cache[K, V]) EvictWithWait(ctx context.Context, capacityCut int64) {
	c.queueLock.Lock()
	var pendingPostEvicts []_PendingPostEvict[K, V]
	defer func() {
		c.queueLock.Unlock()
		if c.postEvict != nil {
			for i := range pendingPostEvicts {
				c.postEvictItem(ctx, pendingPostEvicts[i], true)
				pendingPostEvicts[i] = _PendingPostEvict[K, V]{}
			}

Comment thread pkg/fileservice/fifocache/fifo.go
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
LeftHandCold and others added 2 commits May 21, 2026 11:09
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
LeftHandCold and others added 4 commits May 21, 2026 11:42
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Retain memory cache values before publishing them in FIFO cache so delete/evict paths cannot release cache ownership before it is acquired. Keep slow post-set callbacks outside FIFO locks while preserving the existing public constructor.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Use the same shard-locked validation for immediate enqueue as pending enqueue so a slow post-set callback cannot enqueue an item deleted before enqueue. Add coverage for enqueue-after-delete accounting.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

@XuPeng-SH XuPeng-SH 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.

LGTM.

The stale-index fix looks correct end-to-end: delayed eviction callbacks no longer delete a reinserted disk-cache file, stale full-file index entries are repaired on rewrite, and the FIFO/mem-cache hardening around pending enqueue jobs, retain-before-publish, and same-key callback ordering closes the new lifecycle races introduced by moving post-evict work outside queueLock. The regression coverage also hits the key concurrency and accounting edges.

@mergify

mergify Bot commented May 21, 2026

Copy link
Copy Markdown
Contributor

Merge Queue Status

  • Entered queue2026-05-21 07:21 UTC · Rule: main
  • Checks passed · in-place
  • Merged2026-05-21 08:57 UTC · at 8717f86bc5f2c2446425878e5f849b62bb892da1 · squash

This pull request spent 1 hour 36 minutes 24 seconds in the queue, including 1 hour 6 minutes 27 seconds running CI.

Required conditions to merge
  • #approved-reviews-by >= 1 [🛡 GitHub branch protection]
  • #changes-requested-reviews-by = 0 [🛡 GitHub branch protection]
  • #review-threads-unresolved = 0 [🛡 GitHub branch protection]
  • github-review-decision = APPROVED [🛡 GitHub branch protection]
  • any of [🛡 GitHub branch protection]:
    • check-success = Matrixone Compose CI / multi cn e2e bvt test docker compose(PESSIMISTIC)
    • check-neutral = Matrixone Compose CI / multi cn e2e bvt test docker compose(PESSIMISTIC)
    • check-skipped = Matrixone Compose CI / multi cn e2e bvt test docker compose(PESSIMISTIC)
  • any of [🛡 GitHub branch protection]:
    • check-success = Matrixone Standlone CI / Multi-CN e2e BVT Test on Linux/x64(LAUNCH, PROXY)
    • check-neutral = Matrixone Standlone CI / Multi-CN e2e BVT Test on Linux/x64(LAUNCH, PROXY)
    • check-skipped = Matrixone Standlone CI / Multi-CN e2e BVT Test on Linux/x64(LAUNCH, PROXY)
  • any of [🛡 GitHub branch protection]:
    • check-success = Matrixone Standlone CI / e2e BVT Test on Linux/x64(LAUNCH, PESSIMISTIC)
    • check-neutral = Matrixone Standlone CI / e2e BVT Test on Linux/x64(LAUNCH, PESSIMISTIC)
    • check-skipped = Matrixone Standlone CI / e2e BVT Test on Linux/x64(LAUNCH, PESSIMISTIC)
  • any of [🛡 GitHub branch protection]:
    • check-success = Matrixone CI / SCA Test on Ubuntu/x86
    • check-neutral = Matrixone CI / SCA Test on Ubuntu/x86
    • check-skipped = Matrixone CI / SCA Test on Ubuntu/x86
  • any of [🛡 GitHub branch protection]:
    • check-success = Matrixone CI / UT Test on Ubuntu/x86
    • check-neutral = Matrixone CI / UT Test on Ubuntu/x86
    • check-skipped = Matrixone CI / UT Test on Ubuntu/x86
  • any of [🛡 GitHub branch protection]:
    • check-success = Matrixone Compose CI / multi cn e2e bvt test docker compose(Optimistic/PUSH)
    • check-neutral = Matrixone Compose CI / multi cn e2e bvt test docker compose(Optimistic/PUSH)
    • check-skipped = Matrixone Compose CI / multi cn e2e bvt test docker compose(Optimistic/PUSH)
  • any of [🛡 GitHub branch protection]:
    • check-success = Matrixone Standlone CI / e2e BVT Test on Linux/x64(LAUNCH,Optimistic)
    • check-neutral = Matrixone Standlone CI / e2e BVT Test on Linux/x64(LAUNCH,Optimistic)
    • check-skipped = Matrixone Standlone CI / e2e BVT Test on Linux/x64(LAUNCH,Optimistic)
  • any of [🛡 GitHub branch protection]:
    • check-success = Matrixone Upgrade CI / Compatibility Test With Target on Linux/x64(LAUNCH)
    • check-neutral = Matrixone Upgrade CI / Compatibility Test With Target on Linux/x64(LAUNCH)
    • check-skipped = Matrixone Upgrade CI / Compatibility Test With Target on Linux/x64(LAUNCH)
  • any of [🛡 GitHub branch protection]:
    • check-success = Matrixone Utils CI / Coverage
    • check-neutral = Matrixone Utils CI / Coverage
    • check-skipped = Matrixone Utils CI / Coverage

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

kind/bug Something isn't working kind/test-ci size/XL Denotes a PR that changes [1000, 1999] lines

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants