From d7b6afecdb8b8ed4f714c15c55833e82b96b443d Mon Sep 17 00:00:00 2001 From: Eelco Dolstra Date: Tue, 25 Nov 2025 13:29:29 +0100 Subject: [PATCH 1/2] LambdaSink: Allow passing a destructor callback --- src/libutil/include/nix/util/serialise.hh | 19 ++++++++++++++----- 1 file changed, 14 insertions(+), 5 deletions(-) diff --git a/src/libutil/include/nix/util/serialise.hh b/src/libutil/include/nix/util/serialise.hh index 09b33bf95..5db55c60d 100644 --- a/src/libutil/include/nix/util/serialise.hh +++ b/src/libutil/include/nix/util/serialise.hh @@ -447,18 +447,27 @@ struct LengthSource : Source */ struct LambdaSink : Sink { - typedef std::function lambda_t; + typedef std::function data_t; + typedef std::function cleanup_t; - lambda_t lambda; + data_t dataFun; + cleanup_t cleanupFun; - LambdaSink(const lambda_t & lambda) - : lambda(lambda) + LambdaSink( + const data_t & dataFun, const cleanup_t & cleanupFun = []() {}) + : dataFun(dataFun) + , cleanupFun(cleanupFun) { } + ~LambdaSink() + { + cleanupFun(); + } + void operator()(std::string_view data) override { - lambda(data); + dataFun(data); } }; From 7ba84437be28ef6bd7ada581e0edd0c4199f9d0c Mon Sep 17 00:00:00 2001 From: Eelco Dolstra Date: Tue, 25 Nov 2025 14:19:32 +0100 Subject: [PATCH 2/2] BinaryCacheStore::narFromPath(): Fix unreachable code When this function is called as a coroutine (e.g. when it's called by `copyStorePath()`), the code after `decompressor->finish()` is never reached because the coroutine is destroyed when the caller reaches the end of the NAR. So put that code in a `LambdaSink` destructor. --- src/libstore/binary-cache-store.cc | 20 ++++++++++++++------ 1 file changed, 14 insertions(+), 6 deletions(-) diff --git a/src/libstore/binary-cache-store.cc b/src/libstore/binary-cache-store.cc index caae72479..e1f1d24c6 100644 --- a/src/libstore/binary-cache-store.cc +++ b/src/libstore/binary-cache-store.cc @@ -418,10 +418,20 @@ void BinaryCacheStore::narFromPath(const StorePath & storePath, Sink & sink) { auto info = queryPathInfo(storePath).cast(); - LengthSink narSize; - TeeSink tee{sink, narSize}; + uint64_t narSize = 0; - auto decompressor = makeDecompressionSink(info->compression, tee); + LambdaSink uncompressedSink{ + [&](std::string_view data) { + narSize += data.size(); + sink(data); + }, + [&]() { + stats.narRead++; + // stats.narReadCompressedBytes += nar->size(); // FIXME + stats.narReadBytes += narSize; + }}; + + auto decompressor = makeDecompressionSink(info->compression, uncompressedSink); try { getFile(info->url, *decompressor); @@ -431,9 +441,7 @@ void BinaryCacheStore::narFromPath(const StorePath & storePath, Sink & sink) decompressor->finish(); - stats.narRead++; - // stats.narReadCompressedBytes += nar->size(); // FIXME - stats.narReadBytes += narSize.length; + // Note: don't do anything here because it's never reached if we're called as a coroutine. } void BinaryCacheStore::queryPathInfoUncached(