Skip to content

Commit 93fe335

Browse files
committed
refactor(libutil): add CompressedSource
Introduce a `CompressedSource` class in libutil's `serialise.hh` that compresses a `RestartableSource` and owns the compressed data. This is a general-purpose utility that can be used anywhere compressed data needs to be treated as a source.
1 parent bffbdcf commit 93fe335

File tree

3 files changed

+61
-9
lines changed

3 files changed

+61
-9
lines changed

src/libstore/http-binary-cache-store.cc

Lines changed: 3 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -141,18 +141,12 @@ void HttpBinaryCacheStore::upsertFile(
141141
req.method = HttpMethod::PUT;
142142
auto compressionMethod = getCompressionMethod(path);
143143

144-
std::string data;
145-
std::optional<StringSource> stringSource{};
144+
std::optional<CompressedSource> compressed;
146145

147146
if (compressionMethod) {
148-
StringSink sink{};
149-
auto compressionSink = makeCompressionSink(*compressionMethod, sink);
150-
source.drainInto(*compressionSink);
151-
compressionSink->finish();
152-
data = std::move(sink.s);
147+
compressed = CompressedSource(source, *compressionMethod);
153148
req.headers.emplace_back("Content-Encoding", *compressionMethod);
154-
stringSource = StringSource{data};
155-
req.data = {*stringSource};
149+
req.data = {compressed->size(), *compressed};
156150
} else {
157151
req.data = {sizeHint, source};
158152
}

src/libutil/include/nix/util/serialise.hh

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -272,6 +272,50 @@ struct StringSource : RestartableSource
272272
}
273273
};
274274

275+
/**
276+
* Compresses a RestartableSource using the specified compression method.
277+
*
278+
* @note currently this buffers the entire compressed data stream in memory. In the future it may instead compress data
279+
* on demand, lazily pulling from the original `RestartableSource`. In that case, the `size()` method would go away
280+
* because we would not in fact know the compressed size in advance.
281+
*/
282+
struct CompressedSource : RestartableSource
283+
{
284+
private:
285+
std::string compressedData;
286+
std::string compressionMethod;
287+
StringSource stringSource;
288+
289+
public:
290+
/**
291+
* Compress a RestartableSource using the specified compression method.
292+
*
293+
* @param source The source data to compress
294+
* @param compressionMethod The compression method to use (e.g., "xz", "br")
295+
*/
296+
CompressedSource(RestartableSource & source, const std::string & compressionMethod);
297+
298+
size_t read(char * data, size_t len) override
299+
{
300+
return stringSource.read(data, len);
301+
}
302+
303+
void restart() override
304+
{
305+
stringSource.restart();
306+
}
307+
308+
uint64_t size() const
309+
{
310+
return compressedData.size();
311+
}
312+
313+
std::string_view getCompressionMethod() const
314+
{
315+
return compressionMethod;
316+
}
317+
};
318+
275319
/**
276320
* Create a restartable Source from a factory function.
277321
*

src/libutil/serialise.cc

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
#include "nix/util/serialise.hh"
2+
#include "nix/util/compression.hh"
23
#include "nix/util/signals.hh"
34
#include "nix/util/util.hh"
45

@@ -252,6 +253,19 @@ void StringSource::skip(size_t len)
252253
pos += len;
253254
}
254255

256+
CompressedSource::CompressedSource(RestartableSource & source, const std::string & compressionMethod)
257+
: compressedData([&]() {
258+
StringSink sink;
259+
auto compressionSink = makeCompressionSink(compressionMethod, sink);
260+
source.drainInto(*compressionSink);
261+
compressionSink->finish();
262+
return std::move(sink.s);
263+
}())
264+
, compressionMethod(compressionMethod)
265+
, stringSource(compressedData)
266+
{
267+
}
268+
255269
std::unique_ptr<FinishSink> sourceToSink(std::function<void(Source &)> fun)
256270
{
257271
struct SourceToSink : FinishSink

0 commit comments

Comments
 (0)