Skip to content

Commit 519a4fc

Browse files
committed
Avoid nondeterministically clearing the build description manager's build description cache in tests
If we've told the build description manager to never evict build descriptions from its cache, ensure that the cache isn't attached to the heavy cache global state, so that it isn't cleared by other tests running concurrently.
1 parent f13ab5a commit 519a4fc

File tree

3 files changed

+34
-27
lines changed

3 files changed

+34
-27
lines changed

Sources/SWBTaskExecution/BuildDescriptionManager.swift

Lines changed: 17 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -57,7 +57,7 @@ package struct BuildDescriptionRetrievalInfo {
5757
}
5858

5959
/// Controls the non-deterministic eviction policy of the cache. Note that this is distinct from deterministic _pruning_ (due to TTL or size limits).
60-
package enum BuildDescriptionMemoryCacheEvictionPolicy: Sendable {
60+
package enum BuildDescriptionMemoryCacheEvictionPolicy: Sendable, Hashable {
6161
/// Never evict due to memory pressure.
6262
case never
6363

@@ -104,20 +104,22 @@ package final class BuildDescriptionManager: Sendable {
104104

105105
package init(fs: any FSProxy, buildDescriptionMemoryCacheEvictionPolicy: BuildDescriptionMemoryCacheEvictionPolicy, maxCacheSize: (inMemory: Int, onDisk: Int) = (4, 4)) {
106106
self.fs = fs
107-
self.inMemoryCachedBuildDescriptions = HeavyCache(maximumSize: maxCacheSize.inMemory, evictionPolicy: {
108-
switch buildDescriptionMemoryCacheEvictionPolicy {
109-
case .never:
110-
.never
111-
case .default(let totalCostLimit):
112-
.default(totalCostLimit: totalCostLimit, willEvictCallback: { buildDescription in
113-
// Capture the path to a local variable so that the buildDescription instance isn't retained by OSLog's autoclosure message parameter.
114-
let packagePath = buildDescription.packagePath
115-
#if canImport(os)
116-
OSLog.log("Evicted cached build description at '\(packagePath.str)'")
117-
#endif
118-
})
119-
}
120-
}())
107+
self.inMemoryCachedBuildDescriptions = withHeavyCacheGlobalState(isolated: buildDescriptionMemoryCacheEvictionPolicy == .never) {
108+
HeavyCache(maximumSize: maxCacheSize.inMemory, evictionPolicy: {
109+
switch buildDescriptionMemoryCacheEvictionPolicy {
110+
case .never:
111+
.never
112+
case .default(let totalCostLimit):
113+
.default(totalCostLimit: totalCostLimit, willEvictCallback: { buildDescription in
114+
// Capture the path to a local variable so that the buildDescription instance isn't retained by OSLog's autoclosure message parameter.
115+
let packagePath = buildDescription.packagePath
116+
#if canImport(os)
117+
OSLog.log("Evicted cached build description at '\(packagePath.str)'")
118+
#endif
119+
})
120+
}
121+
}())
122+
}
121123
self.maxCacheSize = maxCacheSize
122124
}
123125

Sources/SWBUtil/HeavyCache.swift

Lines changed: 16 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -33,8 +33,22 @@ public func clearAllHeavyCaches() {
3333
}
3434
}
3535

36-
@_spi(Testing) public func withHeavyCacheGlobalState<T>(_ body: () async throws -> T) async rethrows -> T {
37-
try await $allHeavyCaches.withValue(.init([])) {
36+
public func withHeavyCacheGlobalState<T>(isolated: Bool = true, _ body: () throws -> T) rethrows -> T {
37+
if isolated {
38+
try $allHeavyCaches.withValue(.init([])) {
39+
try body()
40+
}
41+
} else {
42+
try body()
43+
}
44+
}
45+
46+
@_spi(Testing) public func withHeavyCacheGlobalState<T>(isolated: Bool = true, _ body: () async throws -> T) async rethrows -> T {
47+
if isolated {
48+
try await $allHeavyCaches.withValue(.init([])) {
49+
try await body()
50+
}
51+
} else {
3852
try await body()
3953
}
4054
}

Tests/SWBUtilTests/HeavyCacheTests.swift

Lines changed: 1 addition & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -188,16 +188,7 @@ fileprivate struct HeavyCacheTests {
188188

189189
/// Provides a HeavyCache suitable for use in tests (eviction policy disabled to prevent memory pressure interference).
190190
fileprivate func withHeavyCache<Key, Value>(isolatedGlobalState: Bool = true, maximumSize: Int? = nil, timeToLive: Duration? = nil, _ block: (HeavyCache<Key, Value>) async throws -> Void) async rethrows {
191-
func withIsolatedGlobalState(block: () async throws -> Void) async rethrows {
192-
if isolatedGlobalState {
193-
try await withHeavyCacheGlobalState {
194-
try await block()
195-
}
196-
} else {
197-
try await block()
198-
}
199-
}
200-
try await withIsolatedGlobalState {
191+
try await withHeavyCacheGlobalState(isolated: isolatedGlobalState) {
201192
try await block(HeavyCache<Key, Value>(maximumSize: maximumSize, timeToLive: timeToLive, evictionPolicy: .never))
202193
}
203194
}

0 commit comments

Comments
 (0)