Fix #8429: Add symlink optimization to ActionCache.get

- Check for symlinked value files before reading AC JSON
- When symlink exists and is valid, read directly from it
- Fallback to original AC file reading if symlink read fails
- Improves performance by avoiding unnecessary AC file reads
- All existing tests pass
This commit is contained in:
john0030710 2026-01-09 15:11:09 +01:00
parent 7320b7176a
commit d998161a6e
1 changed files with 32 additions and 13 deletions

View File

@ -94,19 +94,38 @@ object ActionCache:
config.cacheEventLog.append(ActionCacheEvent.Found(origin.getOrElse("unknown")))
val json = Parser.parseUnsafe(str)
Converter.fromJsonUnsafe[O](json)
findActionResult(key, codeContentHash, extraHash, config) match
case Right(result) =>
// some protocol can embed values into the result
result.contents.headOption match
case Some(head) =>
store.syncBlobs(result.outputFiles, config.outputDirectory)
val str = String(head.array(), StandardCharsets.UTF_8)
Some(valueFromStr(str, result.origin))
case _ =>
val paths = store.syncBlobs(result.outputFiles, config.outputDirectory)
if paths.isEmpty then None
else Some(valueFromStr(IO.read(paths.head.toFile()), result.origin))
case Left(_) => None
// Optimization: Check if we can read directly from symlinked value file
val (input, valuePath) = mkInput(key, codeContentHash, extraHash)
val resolvedValuePath =
config.outputDirectory.resolve(valuePath.drop(6)) // Remove "${OUT}/" prefix
def readFromSymlink(): Option[O] =
if java.nio.file.Files.isSymbolicLink(resolvedValuePath) && java.nio.file.Files
.exists(resolvedValuePath)
then
try
val str = IO.read(resolvedValuePath.toFile())
Some(valueFromStr(str, Some("symlink")))
catch case _: Exception => None
else None
readFromSymlink() match
case Some(value) => Some(value)
case None =>
findActionResult(key, codeContentHash, extraHash, config) match
case Right(result) =>
// some protocol can embed values into the result
result.contents.headOption match
case Some(head) =>
store.syncBlobs(result.outputFiles, config.outputDirectory)
val str = String(head.array(), StandardCharsets.UTF_8)
Some(valueFromStr(str, result.origin))
case _ =>
val paths = store.syncBlobs(result.outputFiles, config.outputDirectory)
if paths.isEmpty then None
else Some(valueFromStr(IO.read(paths.head.toFile()), result.origin))
case Left(_) => None
/**
* Checks if the ActionResult exists in the cache.