Skip to content

fix: DiskCache served a cache miss for entries that were still fresh - #26009

Open
jkmassel wants to merge 1 commit into
trunkfrom
jkmassel/fix-diskcache-stale-read
Open

fix: DiskCache served a cache miss for entries that were still fresh#26009
jkmassel wants to merge 1 commit into
trunkfrom
jkmassel/fix-diskcache-stale-read

Conversation

@jkmassel

@jkmassel jkmassel commented Sep 8, 2026

Copy link
Copy Markdown
Contributor

Fixes a bug where DiskCache.read(_:forKey:notOlderThan:) returned a cache miss for every entry inside the requested window, and a hit only for entries that had already aged past it.

Found while sweeping for the URL.path() shape from #26005. Unrelated to that bug, so it's on its own.

Summary

  • The freshness comparison was inverted: it discarded entries that were still fresh and served entries that were stale.
  • The same block resolved the file through a percent-encoded path string while the existing-file check two lines above used the URL, so the two disagreed for any key needing encoding.
  • Both are latent. No caller passes notOlderThan: today, and every cache key in the app is an ASCII slug.

Root Cause

Modules/Sources/WordPressCore/DiskCache.swift

if creationDate.addingTimeInterval(interval) > Date.now {
    return nil
}

creationDate + interval is when the entry expires. The condition holds while that moment is still in the future — that is, while the entry is valid — and the branch returns nil. The comparison needs to be <.

The second issue is in the line above it:

guard FileManager.default.fileExists(at: path) else { ... }   // URL, decoded  ✅
let attributes = try FileManager.default.attributesOfItem(atPath: path.path())  // encoded  ❌

path(forKey:) is cacheRoot.appendingPathComponent("\(key).cache.json") with the key unhashed, so a key containing a space or a % would pass the first check and throw on the second.

Fix

1. Compare against the expiry correctly

< instead of >, with a comment naming what the branch means.

2. Read the creation date off the URL

path.resourceValues(forKeys: [.creationDateKey]) instead of attributesOfItem(atPath: path.path()). This matches the fileExists(at:) call above it and removes the encoding question rather than restating it.

3. Take the cache root as an init parameter

public init(cacheRoot: URL = .cachesDirectory). Defaulted, so DiskCache.shared, DiskCache() in AccountHelper, and CachedAndFetchedResult are unchanged. Without it the tests would read, write, and removeAll() in the developer's real caches directory.

Test plan

  • Added DiskCacheTests — 8 cases covering store/read round-trip, a fresh entry inside the window, an expired entry, no interval, a missing key, a key needing percent-encoding, remove(key:), and removeAll().
  • Verified the three bug-targeting cases fail without the fix and the five controls pass either way.
  • swift test --filter DiskCacheTests — 8/8 pass on macOS.

Each test writes to its own UUID-named directory under temporaryDirectory and removes it afterwards.

read(_:forKey:notOlderThan:) compared the entry's expiry against now and
returned nil when the expiry was still in the future, so it discarded every
entry inside the requested window and served only entries that had already
aged past it.

Also reads the creation date off the URL instead of a percent-encoded path
string, matching the fileExists(at:) check two lines above, and takes the cache
root as an init parameter so the tests don't touch the real caches directory.
@jkmassel jkmassel self-assigned this Sep 8, 2026
@jkmassel jkmassel added this to the 27.3 milestone Sep 8, 2026
@wpmobilebot

Copy link
Copy Markdown
Contributor
App Icon📲 You can test the changes from this Pull Request in WordPress by scanning the QR code below to install the corresponding build.
App NameWordPress
ConfigurationRelease-Alpha
Build Number34433
VersionPR #26009
Bundle IDorg.wordpress.alpha
Commit90870bd
Installation URL6jjlttnf25bng
Automatticians: You can use our internal self-serve MC tool to give yourself access to those builds if needed.

@wpmobilebot

Copy link
Copy Markdown
Contributor
App Icon📲 You can test the changes from this Pull Request in Jetpack by scanning the QR code below to install the corresponding build.
App NameJetpack
ConfigurationRelease-Alpha
Build Number34433
VersionPR #26009
Bundle IDcom.jetpack.alpha
Commit90870bd
Installation URL61vm5girviet0
Automatticians: You can use our internal self-serve MC tool to give yourself access to those builds if needed.

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

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants