mirror of
https://github.com/apple/sourcekit-lsp.git
synced 2026-03-02 18:23:24 +01:00
Cached transformed results in Cache
The transform to get the transformed result might be expensive, so we should cache its result.
This commit is contained in:
@@ -1009,19 +1009,21 @@ package actor BuildSystemManager: QueueBasedMessageHandler {
|
||||
return []
|
||||
}
|
||||
|
||||
let request = BuildTargetSourcesRequest(targets: targets.sorted { $0.uri.stringValue < $1.uri.stringValue })
|
||||
|
||||
// If we have a cached request for a superset of the targets, serve the result from that cache entry.
|
||||
let fromSuperset = await orLog("Getting source files from superset request") {
|
||||
try await cachedTargetSources.get(isolation: self) { request in
|
||||
targets.isSubset(of: request.targets)
|
||||
} transform: { response in
|
||||
return BuildTargetSourcesResponse(items: response.items.filter { targets.contains($0.target) })
|
||||
}
|
||||
try await cachedTargetSources.getDerived(
|
||||
isolation: self,
|
||||
request,
|
||||
canReuseKey: { targets.isSubset(of: $0.targets) },
|
||||
transform: { BuildTargetSourcesResponse(items: $0.items.filter { targets.contains($0.target) }) }
|
||||
)
|
||||
}
|
||||
if let fromSuperset {
|
||||
return fromSuperset.items
|
||||
}
|
||||
|
||||
let request = BuildTargetSourcesRequest(targets: targets.sorted { $0.uri.stringValue < $1.uri.stringValue })
|
||||
let response = try await cachedTargetSources.get(request, isolation: self) { request in
|
||||
try await buildSystemAdapter.send(request)
|
||||
}
|
||||
|
||||
@@ -33,15 +33,28 @@ package class Cache<Key: Sendable & Hashable, Result: Sendable> {
|
||||
return try await task.value
|
||||
}
|
||||
|
||||
package func get(
|
||||
/// Get the value cached for `key`. If no value exists for `key`, try deriving the result from an existing cache entry
|
||||
/// that satisfies `canReuseKey` by applying `transform` to that result.
|
||||
package func getDerived(
|
||||
isolation: isolated any Actor,
|
||||
whereKey keyPredicate: (Key) -> Bool,
|
||||
transform: @Sendable @escaping (Result) -> Result
|
||||
_ key: Key,
|
||||
canReuseKey: @Sendable @escaping (Key) -> Bool,
|
||||
transform: @Sendable @escaping (_ cachedResult: Result) -> Result
|
||||
) async throws -> Result? {
|
||||
for (key, value) in storage {
|
||||
if keyPredicate(key) {
|
||||
return try await transform(value.value)
|
||||
if let cached = storage[key] {
|
||||
// If we have a value for the requested key, prefer that
|
||||
return try await cached.value
|
||||
}
|
||||
|
||||
// See if don't have an entry for this key, see if we can derive the value from a cached entry.
|
||||
for (cachedKey, cachedValue) in storage {
|
||||
guard canReuseKey(cachedKey) else {
|
||||
continue
|
||||
}
|
||||
let transformed = Task { try await transform(cachedValue.value) }
|
||||
// Cache the transformed result.
|
||||
storage[key] = transformed
|
||||
return try await transformed.value
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user