2016-02-24 15:48:16 +02:00
|
|
|
|
#include "archive.hh"
|
2016-02-25 18:43:19 +02:00
|
|
|
|
#include "binary-cache-store.hh"
|
2016-02-24 15:48:16 +02:00
|
|
|
|
#include "compression.hh"
|
|
|
|
|
#include "derivations.hh"
|
2023-11-01 18:09:28 +02:00
|
|
|
|
#include "source-accessor.hh"
|
2016-02-24 15:48:16 +02:00
|
|
|
|
#include "globals.hh"
|
|
|
|
|
#include "nar-info.hh"
|
2016-02-25 18:43:19 +02:00
|
|
|
|
#include "sync.hh"
|
2016-09-02 21:24:34 +03:00
|
|
|
|
#include "remote-fs-accessor.hh"
|
2016-04-20 16:27:48 +03:00
|
|
|
|
#include "nar-info-disk-cache.hh"
|
2016-11-09 19:57:22 +02:00
|
|
|
|
#include "nar-accessor.hh"
|
2019-09-04 20:24:35 +03:00
|
|
|
|
#include "thread-pool.hh"
|
2020-09-21 19:40:11 +03:00
|
|
|
|
#include "callback.hh"
|
2023-10-25 07:43:36 +03:00
|
|
|
|
#include "signals.hh"
|
2023-11-09 04:11:48 +02:00
|
|
|
|
#include "archive.hh"
|
2016-02-24 15:48:16 +02:00
|
|
|
|
|
|
|
|
|
#include <chrono>
|
2016-09-16 19:54:14 +03:00
|
|
|
|
#include <future>
|
2019-09-04 20:24:35 +03:00
|
|
|
|
#include <regex>
|
2020-07-13 21:07:19 +03:00
|
|
|
|
#include <fstream>
|
Remove 100s of CPU time (10%) from build times (1465s -> 1302s)
Result's from Mic92's framework 13th Gen Intel Core i7-1360P:
Before: 3595.92s user 183.01s system 1360% cpu 4:37.74 total
After: 3486.07s user 168.93s system 1354% cpu 4:29.79 total
I saw that boost/lexical_cast was costing about 100s in CPU time on our
compiles. We can fix this trivially by doing explicit template
instantiation in exactly one place and eliminating all other includes of
it, which is a code improvement anyway by hiding the boost.
Before:
```
lix/lix2 » ClangBuildAnalyzer --analyze buildtimeold.bin
Analyzing build trace from 'buildtimeold.bin'...
**** Time summary:
Compilation (551 times):
Parsing (frontend): 1465.3 s
Codegen & opts (backend): 1110.9 s
<snip>
**** Expensive headers:
178153 ms: ../src/libcmd/installable-value.hh (included 52 times, avg 3426 ms), included via:
40x: command.hh
5x: command-installable-value.hh
3x: installable-flake.hh
2x: <direct include>
2x: installable-attr-path.hh
176217 ms: ../src/libutil/error.hh (included 246 times, avg 716 ms), included via:
36x: command.hh installable-value.hh installables.hh derived-path.hh config.hh experimental-features.hh
12x: globals.hh config.hh experimental-features.hh
11x: file-system.hh file-descriptor.hh
6x: serialise.hh strings.hh
6x: <direct include>
6x: archive.hh serialise.hh strings.hh
...
173243 ms: ../src/libstore/store-api.hh (included 152 times, avg 1139 ms), included via:
55x: <direct include>
39x: command.hh installable-value.hh installables.hh
7x: libexpr.hh
4x: local-store.hh
4x: command-installable-value.hh installable-value.hh installables.hh
3x: binary-cache-store.hh
...
170482 ms: ../src/libutil/serialise.hh (included 201 times, avg 848 ms), included via:
37x: command.hh installable-value.hh installables.hh built-path.hh realisation.hh hash.hh
14x: store-api.hh nar-info.hh hash.hh
11x: <direct include>
7x: primops.hh eval.hh attr-set.hh nixexpr.hh value.hh source-path.hh archive.hh
7x: libexpr.hh value.hh source-path.hh archive.hh
6x: fetchers.hh hash.hh
...
169397 ms: ../src/libcmd/installables.hh (included 53 times, avg 3196 ms), included via:
40x: command.hh installable-value.hh
5x: command-installable-value.hh installable-value.hh
3x: installable-flake.hh installable-value.hh
2x: <direct include>
1x: installable-derived-path.hh
1x: installable-value.hh
...
159740 ms: ../src/libutil/strings.hh (included 221 times, avg 722 ms), included via:
37x: command.hh installable-value.hh installables.hh built-path.hh realisation.hh hash.hh serialise.hh
19x: <direct include>
14x: store-api.hh nar-info.hh hash.hh serialise.hh
11x: serialise.hh
7x: primops.hh eval.hh attr-set.hh nixexpr.hh value.hh source-path.hh archive.hh serialise.hh
7x: libexpr.hh value.hh source-path.hh archive.hh serialise.hh
...
156796 ms: ../src/libcmd/command.hh (included 51 times, avg 3074 ms), included via:
42x: <direct include>
7x: command-installable-value.hh
2x: installable-attr-path.hh
150392 ms: ../src/libutil/types.hh (included 251 times, avg 599 ms), included via:
36x: command.hh installable-value.hh installables.hh path.hh
11x: file-system.hh
10x: globals.hh
6x: fetchers.hh
6x: serialise.hh strings.hh error.hh
5x: archive.hh
...
133101 ms: /nix/store/644b90j1vms44nr18yw3520pzkrg4dd1-boost-1.81.0-dev/include/boost/lexical_cast.hpp (included 226 times, avg 588 ms), included via
:
37x: command.hh installable-value.hh installables.hh built-path.hh realisation.hh hash.hh serialise.hh strings.hh
19x: file-system.hh
11x: store-api.hh nar-info.hh hash.hh serialise.hh strings.hh
7x: primops.hh eval.hh attr-set.hh nixexpr.hh value.hh source-path.hh archive.hh serialise.hh strings.hh
7x: libexpr.hh value.hh source-path.hh archive.hh serialise.hh strings.hh
6x: eval.hh attr-set.hh nixexpr.hh value.hh source-path.hh archive.hh serialise.hh strings.hh
...
132887 ms: /nix/store/h2abv2l8irqj942i5rq9wbrj42kbsh5y-gcc-12.3.0/include/c++/12.3.0/memory (included 262 times, avg 507 ms), included via:
36x: command.hh installable-value.hh installables.hh path.hh types.hh ref.hh
16x: gtest.h
11x: file-system.hh types.hh ref.hh
10x: globals.hh types.hh ref.hh
10x: json.hpp
6x: serialise.hh
...
done in 0.6s.
```
After:
```
lix/lix2 » maintainers/buildtime_report.sh build
Processing all files and saving to '/home/jade/lix/lix2/maintainers/../buildtime.bin'...
done in 0.6s. Run 'ClangBuildAnalyzer --analyze /home/jade/lix/lix2/maintainers/../buildtime.bin' to analyze it.
Analyzing build trace from '/home/jade/lix/lix2/maintainers/../buildtime.bin'...
**** Time summary:
Compilation (551 times):
Parsing (frontend): 1302.1 s
Codegen & opts (backend): 956.3 s
<snip>
**** Expensive headers:
178145 ms: ../src/libutil/error.hh (included 246 times, avg 724 ms), included via:
36x: command.hh installable-value.hh installables.hh derived-path.hh config.hh experimental-features.hh
12x: globals.hh config.hh experimental-features.hh
11x: file-system.hh file-descriptor.hh
6x: <direct include>
6x: serialise.hh strings.hh
6x: fetchers.hh hash.hh serialise.hh strings.hh
...
154043 ms: ../src/libcmd/installable-value.hh (included 52 times, avg 2962 ms), included via:
40x: command.hh
5x: command-installable-value.hh
3x: installable-flake.hh
2x: <direct include>
2x: installable-attr-path.hh
153593 ms: ../src/libstore/store-api.hh (included 152 times, avg 1010 ms), included via:
55x: <direct include>
39x: command.hh installable-value.hh installables.hh
7x: libexpr.hh
4x: local-store.hh
4x: command-installable-value.hh installable-value.hh installables.hh
3x: binary-cache-store.hh
...
149948 ms: ../src/libutil/types.hh (included 251 times, avg 597 ms), included via:
36x: command.hh installable-value.hh installables.hh path.hh
11x: file-system.hh
10x: globals.hh
6x: fetchers.hh
6x: serialise.hh strings.hh error.hh
5x: archive.hh
...
144560 ms: ../src/libcmd/installables.hh (included 53 times, avg 2727 ms), included via:
40x: command.hh installable-value.hh
5x: command-installable-value.hh installable-value.hh
3x: installable-flake.hh installable-value.hh
2x: <direct include>
1x: installable-value.hh
1x: installable-derived-path.hh
...
136585 ms: ../src/libcmd/command.hh (included 51 times, avg 2678 ms), included via:
42x: <direct include>
7x: command-installable-value.hh
2x: installable-attr-path.hh
133394 ms: /nix/store/h2abv2l8irqj942i5rq9wbrj42kbsh5y-gcc-12.3.0/include/c++/12.3.0/memory (included 262 times, avg 509 ms), included via:
36x: command.hh installable-value.hh installables.hh path.hh types.hh ref.hh
16x: gtest.h
11x: file-system.hh types.hh ref.hh
10x: globals.hh types.hh ref.hh
10x: json.hpp
6x: serialise.hh
...
89315 ms: ../src/libstore/derived-path.hh (included 178 times, avg 501 ms), included via:
37x: command.hh installable-value.hh installables.hh
25x: store-api.hh realisation.hh
7x: primops.hh eval.hh attr-set.hh nixexpr.hh value.hh context.hh
6x: eval.hh attr-set.hh nixexpr.hh value.hh context.hh
6x: libexpr.hh value.hh context.hh
6x: shared.hh
...
87347 ms: /nix/store/h2abv2l8irqj942i5rq9wbrj42kbsh5y-gcc-12.3.0/include/c++/12.3.0/ostream (included 273 times, avg 319 ms), included via:
35x: command.hh installable-value.hh installables.hh path.hh types.hh ref.hh memory unique_ptr.h
12x: regex sstream istream
10x: file-system.hh types.hh ref.hh memory unique_ptr.h
10x: gtest.h memory unique_ptr.h
10x: globals.hh types.hh ref.hh memory unique_ptr.h
6x: fetchers.hh types.hh ref.hh memory unique_ptr.h
...
85249 ms: ../src/libutil/config.hh (included 213 times, avg 400 ms), included via:
37x: command.hh installable-value.hh installables.hh derived-path.hh
20x: globals.hh
20x: logging.hh
16x: store-api.hh logging.hh
6x: <direct include>
6x: eval.hh attr-set.hh nixexpr.hh value.hh context.hh derived-path.hh
...
done in 0.5s.
```
Adapated from https://git.lix.systems/lix-project/lix/commit/18aa3e1d570b4ecbb9962376e5fba5757dad8da9
2024-05-30 07:12:34 +03:00
|
|
|
|
#include <sstream>
|
2019-09-04 20:24:35 +03:00
|
|
|
|
|
|
|
|
|
#include <nlohmann/json.hpp>
|
2016-09-16 19:54:14 +03:00
|
|
|
|
|
2016-02-24 15:48:16 +02:00
|
|
|
|
namespace nix {
|
|
|
|
|
|
2016-06-01 15:49:12 +03:00
|
|
|
|
BinaryCacheStore::BinaryCacheStore(const Params & params)
|
2020-09-10 11:55:51 +03:00
|
|
|
|
: BinaryCacheStoreConfig(params)
|
|
|
|
|
, Store(params)
|
2016-02-24 15:48:16 +02:00
|
|
|
|
{
|
2016-04-29 17:28:57 +03:00
|
|
|
|
if (secretKeyFile != "")
|
2024-01-03 22:02:20 +02:00
|
|
|
|
signer = std::make_unique<LocalSigner>(
|
|
|
|
|
SecretKey { readFile(secretKeyFile) });
|
2016-02-24 17:52:28 +02:00
|
|
|
|
|
|
|
|
|
StringSink sink;
|
|
|
|
|
sink << narVersionMagic1;
|
2022-01-17 23:20:05 +02:00
|
|
|
|
narMagic = sink.s;
|
2016-02-24 15:48:16 +02:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void BinaryCacheStore::init()
|
|
|
|
|
{
|
|
|
|
|
std::string cacheInfoFile = "nix-cache-info";
|
2016-05-30 14:33:05 +03:00
|
|
|
|
|
|
|
|
|
auto cacheInfo = getFile(cacheInfoFile);
|
|
|
|
|
if (!cacheInfo) {
|
2017-03-14 16:26:01 +02:00
|
|
|
|
upsertFile(cacheInfoFile, "StoreDir: " + storeDir + "\n", "text/x-nix-cache-info");
|
2016-05-30 14:33:05 +03:00
|
|
|
|
} else {
|
|
|
|
|
for (auto & line : tokenizeString<Strings>(*cacheInfo, "\n")) {
|
2020-04-22 02:07:07 +03:00
|
|
|
|
size_t colon= line.find(':');
|
|
|
|
|
if (colon ==std::string::npos) continue;
|
2016-05-30 14:33:05 +03:00
|
|
|
|
auto name = line.substr(0, colon);
|
|
|
|
|
auto value = trim(line.substr(colon + 1, std::string::npos));
|
|
|
|
|
if (name == "StoreDir") {
|
2016-06-01 15:49:12 +03:00
|
|
|
|
if (value != storeDir)
|
2020-04-22 02:07:07 +03:00
|
|
|
|
throw Error("binary cache '%s' is for Nix stores with prefix '%s', not '%s'",
|
|
|
|
|
getUri(), value, storeDir);
|
2016-05-30 14:33:05 +03:00
|
|
|
|
} else if (name == "WantMassQuery") {
|
2021-09-22 15:15:35 +03:00
|
|
|
|
wantMassQuery.setDefault(value == "1");
|
2016-05-30 14:33:05 +03:00
|
|
|
|
} else if (name == "Priority") {
|
2021-09-22 15:15:35 +03:00
|
|
|
|
priority.setDefault(std::stoi(value));
|
2016-05-30 14:33:05 +03:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
2016-02-24 15:48:16 +02:00
|
|
|
|
}
|
|
|
|
|
|
2020-07-10 21:58:02 +03:00
|
|
|
|
void BinaryCacheStore::upsertFile(const std::string & path,
|
2020-07-13 21:07:19 +03:00
|
|
|
|
std::string && data,
|
2020-07-10 21:58:02 +03:00
|
|
|
|
const std::string & mimeType)
|
|
|
|
|
{
|
2020-07-13 21:07:19 +03:00
|
|
|
|
upsertFile(path, std::make_shared<std::stringstream>(std::move(data)), mimeType);
|
2020-07-10 21:58:02 +03:00
|
|
|
|
}
|
|
|
|
|
|
2018-03-28 00:12:31 +03:00
|
|
|
|
void BinaryCacheStore::getFile(const std::string & path,
|
2022-01-17 23:20:05 +02:00
|
|
|
|
Callback<std::optional<std::string>> callback) noexcept
|
2018-03-28 00:12:31 +03:00
|
|
|
|
{
|
|
|
|
|
try {
|
|
|
|
|
callback(getFile(path));
|
|
|
|
|
} catch (...) { callback.rethrow(); }
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void BinaryCacheStore::getFile(const std::string & path, Sink & sink)
|
2016-09-16 19:54:14 +03:00
|
|
|
|
{
|
2022-01-17 23:20:05 +02:00
|
|
|
|
std::promise<std::optional<std::string>> promise;
|
2016-09-16 19:54:14 +03:00
|
|
|
|
getFile(path,
|
2022-01-17 23:20:05 +02:00
|
|
|
|
{[&](std::future<std::optional<std::string>> result) {
|
2018-03-27 23:16:01 +03:00
|
|
|
|
try {
|
|
|
|
|
promise.set_value(result.get());
|
|
|
|
|
} catch (...) {
|
|
|
|
|
promise.set_exception(std::current_exception());
|
|
|
|
|
}
|
|
|
|
|
}});
|
2020-12-02 15:00:43 +02:00
|
|
|
|
sink(*promise.get_future().get());
|
2018-03-28 00:12:31 +03:00
|
|
|
|
}
|
|
|
|
|
|
2022-01-17 23:20:05 +02:00
|
|
|
|
std::optional<std::string> BinaryCacheStore::getFile(const std::string & path)
|
2018-03-28 00:12:31 +03:00
|
|
|
|
{
|
2019-07-10 20:46:15 +03:00
|
|
|
|
StringSink sink;
|
|
|
|
|
try {
|
|
|
|
|
getFile(path, sink);
|
|
|
|
|
} catch (NoSuchBinaryCacheFile &) {
|
2022-01-17 23:20:05 +02:00
|
|
|
|
return std::nullopt;
|
2019-07-10 20:46:15 +03:00
|
|
|
|
}
|
2022-01-17 23:20:05 +02:00
|
|
|
|
return std::move(sink.s);
|
2016-09-16 19:54:14 +03:00
|
|
|
|
}
|
|
|
|
|
|
2019-12-05 20:11:09 +02:00
|
|
|
|
std::string BinaryCacheStore::narInfoFileFor(const StorePath & storePath)
|
2016-02-24 15:48:16 +02:00
|
|
|
|
{
|
2020-06-16 15:16:39 +03:00
|
|
|
|
return std::string(storePath.hashPart()) + ".narinfo";
|
2016-02-24 15:48:16 +02:00
|
|
|
|
}
|
|
|
|
|
|
2017-11-14 19:44:05 +02:00
|
|
|
|
void BinaryCacheStore::writeNarInfo(ref<NarInfo> narInfo)
|
|
|
|
|
{
|
|
|
|
|
auto narInfoFile = narInfoFileFor(narInfo->path);
|
|
|
|
|
|
2019-12-05 20:11:09 +02:00
|
|
|
|
upsertFile(narInfoFile, narInfo->to_string(*this), "text/x-nix-narinfo");
|
2017-11-14 19:44:05 +02:00
|
|
|
|
|
|
|
|
|
{
|
|
|
|
|
auto state_(state.lock());
|
2021-10-14 14:28:22 +03:00
|
|
|
|
state_->pathInfoCache.upsert(
|
|
|
|
|
std::string(narInfo->path.to_string()),
|
|
|
|
|
PathInfoCacheValue { .value = std::shared_ptr<NarInfo>(narInfo) });
|
2017-11-14 19:44:05 +02:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (diskCache)
|
2021-10-14 14:28:22 +03:00
|
|
|
|
diskCache->upsertNarInfo(getUri(), std::string(narInfo->path.hashPart()), std::shared_ptr<NarInfo>(narInfo));
|
2017-11-14 19:44:05 +02:00
|
|
|
|
}
|
|
|
|
|
|
2020-09-23 17:40:41 +03:00
|
|
|
|
ref<const ValidPathInfo> BinaryCacheStore::addToStoreCommon(
|
2020-08-15 19:41:28 +03:00
|
|
|
|
Source & narSource, RepairFlag repair, CheckSigsFlag checkSigs,
|
|
|
|
|
std::function<ValidPathInfo(HashResult)> mkInfo)
|
2016-02-24 15:48:16 +02:00
|
|
|
|
{
|
2020-07-10 21:58:02 +03:00
|
|
|
|
auto [fdTemp, fnTemp] = createTempFile();
|
|
|
|
|
|
2020-08-03 19:33:39 +03:00
|
|
|
|
AutoDelete autoDelete(fnTemp);
|
|
|
|
|
|
2020-07-10 21:58:02 +03:00
|
|
|
|
auto now1 = std::chrono::steady_clock::now();
|
|
|
|
|
|
2020-07-13 18:30:42 +03:00
|
|
|
|
/* Read the NAR simultaneously into a CompressionSink+FileSink (to
|
|
|
|
|
write the compressed NAR to disk), into a HashSink (to get the
|
|
|
|
|
NAR hash), and into a NarAccessor (to get the NAR listing). */
|
2023-11-28 15:20:27 +02:00
|
|
|
|
HashSink fileHashSink { HashAlgorithm::SHA256 };
|
2023-11-01 18:09:28 +02:00
|
|
|
|
std::shared_ptr<SourceAccessor> narAccessor;
|
2023-11-28 15:20:27 +02:00
|
|
|
|
HashSink narHashSink { HashAlgorithm::SHA256 };
|
2020-07-10 21:58:02 +03:00
|
|
|
|
{
|
|
|
|
|
FdSink fileSink(fdTemp.get());
|
2020-08-15 19:41:28 +03:00
|
|
|
|
TeeSink teeSinkCompressed { fileSink, fileHashSink };
|
2021-10-12 09:14:36 +03:00
|
|
|
|
auto compressionSink = makeCompressionSink(compression, teeSinkCompressed, parallelCompression, compressionLevel);
|
2020-08-15 19:41:28 +03:00
|
|
|
|
TeeSink teeSinkUncompressed { *compressionSink, narHashSink };
|
|
|
|
|
TeeSource teeSource { narSource, teeSinkUncompressed };
|
2020-07-13 18:30:42 +03:00
|
|
|
|
narAccessor = makeNarAccessor(teeSource);
|
2020-07-10 21:58:02 +03:00
|
|
|
|
compressionSink->finish();
|
2020-08-04 15:50:43 +03:00
|
|
|
|
fileSink.flush();
|
2020-07-10 21:58:02 +03:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
auto now2 = std::chrono::steady_clock::now();
|
|
|
|
|
|
2020-08-15 19:41:28 +03:00
|
|
|
|
auto info = mkInfo(narHashSink.finish());
|
2020-07-10 21:58:02 +03:00
|
|
|
|
auto narInfo = make_ref<NarInfo>(info);
|
|
|
|
|
narInfo->compression = compression;
|
|
|
|
|
auto [fileHash, fileSize] = fileHashSink.finish();
|
|
|
|
|
narInfo->fileHash = fileHash;
|
|
|
|
|
narInfo->fileSize = fileSize;
|
2023-11-28 16:38:15 +02:00
|
|
|
|
narInfo->url = "nar/" + narInfo->fileHash->to_string(HashFormat::Nix32, false) + ".nar"
|
|
|
|
|
+ (compression == "xz" ? ".xz" :
|
2020-07-10 21:58:02 +03:00
|
|
|
|
compression == "bzip2" ? ".bz2" :
|
2021-04-10 00:13:08 +03:00
|
|
|
|
compression == "zstd" ? ".zst" :
|
|
|
|
|
compression == "lzip" ? ".lzip" :
|
|
|
|
|
compression == "lz4" ? ".lz4" :
|
2020-07-10 21:58:02 +03:00
|
|
|
|
compression == "br" ? ".br" :
|
|
|
|
|
"");
|
2020-05-29 23:19:48 +03:00
|
|
|
|
|
2020-07-10 21:58:02 +03:00
|
|
|
|
auto duration = std::chrono::duration_cast<std::chrono::milliseconds>(now2 - now1).count();
|
|
|
|
|
printMsg(lvlTalkative, "copying path '%1%' (%2% bytes, compressed %3$.1f%% in %4% ms) to binary cache",
|
|
|
|
|
printStorePath(narInfo->path), info.narSize,
|
|
|
|
|
((1.0 - (double) fileSize / info.narSize) * 100.0),
|
|
|
|
|
duration);
|
2016-05-04 14:36:54 +03:00
|
|
|
|
|
2016-04-22 13:15:06 +03:00
|
|
|
|
/* Verify that all references are valid. This may do some .narinfo
|
2023-01-14 23:38:43 +02:00
|
|
|
|
reads, but typically they'll already be cached. */
|
|
|
|
|
for (auto & ref : info.references)
|
2016-04-22 13:15:06 +03:00
|
|
|
|
try {
|
2023-01-14 23:38:43 +02:00
|
|
|
|
if (ref != info.path)
|
|
|
|
|
queryPathInfo(ref);
|
2016-04-22 13:15:06 +03:00
|
|
|
|
} catch (InvalidPath &) {
|
2019-12-05 20:11:09 +02:00
|
|
|
|
throw Error("cannot add '%s' to the binary cache because the reference '%s' is not valid",
|
|
|
|
|
printStorePath(info.path), printStorePath(ref));
|
2016-04-22 13:15:06 +03:00
|
|
|
|
}
|
|
|
|
|
|
2016-10-21 17:50:28 +03:00
|
|
|
|
/* Optionally write a JSON file containing a listing of the
|
|
|
|
|
contents of the NAR. */
|
|
|
|
|
if (writeNARListing) {
|
2022-11-16 17:49:49 +02:00
|
|
|
|
nlohmann::json j = {
|
|
|
|
|
{"version", 1},
|
2023-11-01 18:09:28 +02:00
|
|
|
|
{"root", listNar(ref<SourceAccessor>(narAccessor), CanonPath::root, true)},
|
2022-11-16 17:49:49 +02:00
|
|
|
|
};
|
2016-10-21 17:50:28 +03:00
|
|
|
|
|
2022-11-16 17:49:49 +02:00
|
|
|
|
upsertFile(std::string(info.path.hashPart()) + ".ls", j.dump(), "application/json");
|
2016-10-21 17:50:28 +03:00
|
|
|
|
}
|
|
|
|
|
|
2019-09-04 20:24:35 +03:00
|
|
|
|
/* Optionally maintain an index of DWARF debug info files
|
|
|
|
|
consisting of JSON files named 'debuginfo/<build-id>' that
|
|
|
|
|
specify the NAR file and member containing the debug info. */
|
|
|
|
|
if (writeDebugInfo) {
|
|
|
|
|
|
2023-11-01 18:09:28 +02:00
|
|
|
|
CanonPath buildIdDir("lib/debug/.build-id");
|
2019-09-04 20:24:35 +03:00
|
|
|
|
|
2023-11-01 18:09:28 +02:00
|
|
|
|
if (auto st = narAccessor->maybeLstat(buildIdDir); st && st->type == SourceAccessor::tDirectory) {
|
2019-09-04 20:24:35 +03:00
|
|
|
|
|
|
|
|
|
ThreadPool threadPool(25);
|
|
|
|
|
|
|
|
|
|
auto doFile = [&](std::string member, std::string key, std::string target) {
|
|
|
|
|
checkInterrupt();
|
|
|
|
|
|
|
|
|
|
nlohmann::json json;
|
|
|
|
|
json["archive"] = target;
|
|
|
|
|
json["member"] = member;
|
|
|
|
|
|
|
|
|
|
// FIXME: or should we overwrite? The previous link may point
|
|
|
|
|
// to a GC'ed file, so overwriting might be useful...
|
|
|
|
|
if (fileExists(key)) return;
|
|
|
|
|
|
|
|
|
|
printMsg(lvlTalkative, "creating debuginfo link from '%s' to '%s'", key, target);
|
|
|
|
|
|
|
|
|
|
upsertFile(key, json.dump(), "application/json");
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
std::regex regex1("^[0-9a-f]{2}$");
|
|
|
|
|
std::regex regex2("^[0-9a-f]{38}\\.debug$");
|
|
|
|
|
|
2023-11-01 16:33:19 +02:00
|
|
|
|
for (auto & [s1, _type] : narAccessor->readDirectory(buildIdDir)) {
|
2024-02-05 16:13:11 +02:00
|
|
|
|
auto dir = buildIdDir / s1;
|
2019-09-04 20:24:35 +03:00
|
|
|
|
|
2023-11-01 18:09:28 +02:00
|
|
|
|
if (narAccessor->lstat(dir).type != SourceAccessor::tDirectory
|
2019-09-04 20:24:35 +03:00
|
|
|
|
|| !std::regex_match(s1, regex1))
|
|
|
|
|
continue;
|
|
|
|
|
|
2023-11-01 16:33:19 +02:00
|
|
|
|
for (auto & [s2, _type] : narAccessor->readDirectory(dir)) {
|
2024-02-05 16:13:11 +02:00
|
|
|
|
auto debugPath = dir / s2;
|
2019-09-04 20:24:35 +03:00
|
|
|
|
|
2023-11-01 21:19:08 +02:00
|
|
|
|
if (narAccessor->lstat(debugPath).type != SourceAccessor::tRegular
|
2019-09-04 20:24:35 +03:00
|
|
|
|
|| !std::regex_match(s2, regex2))
|
|
|
|
|
continue;
|
|
|
|
|
|
|
|
|
|
auto buildId = s1 + s2;
|
|
|
|
|
|
|
|
|
|
std::string key = "debuginfo/" + buildId;
|
|
|
|
|
std::string target = "../" + narInfo->url;
|
|
|
|
|
|
2023-11-01 18:09:28 +02:00
|
|
|
|
threadPool.enqueue(std::bind(doFile, std::string(debugPath.rel()), key, target));
|
2019-09-04 20:24:35 +03:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
threadPool.process();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Atomically write the NAR file. */
|
2016-05-04 14:36:54 +03:00
|
|
|
|
if (repair || !fileExists(narInfo->url)) {
|
2016-02-24 15:48:16 +02:00
|
|
|
|
stats.narWrite++;
|
2020-07-13 21:07:19 +03:00
|
|
|
|
upsertFile(narInfo->url,
|
2020-08-04 17:00:59 +03:00
|
|
|
|
std::make_shared<std::fstream>(fnTemp, std::ios_base::in | std::ios_base::binary),
|
2020-07-13 21:07:19 +03:00
|
|
|
|
"application/x-nix-nar");
|
2016-02-24 15:48:16 +02:00
|
|
|
|
} else
|
|
|
|
|
stats.narWriteAverted++;
|
|
|
|
|
|
2020-07-10 21:58:02 +03:00
|
|
|
|
stats.narWriteBytes += info.narSize;
|
|
|
|
|
stats.narWriteCompressedBytes += fileSize;
|
2016-02-24 15:48:16 +02:00
|
|
|
|
stats.narWriteCompressionTimeMs += duration;
|
|
|
|
|
|
|
|
|
|
/* Atomically write the NAR info file.*/
|
2024-01-03 22:02:20 +02:00
|
|
|
|
if (signer) narInfo->sign(*this, *signer);
|
2016-02-24 15:48:16 +02:00
|
|
|
|
|
2017-11-14 19:44:05 +02:00
|
|
|
|
writeNarInfo(narInfo);
|
2016-04-20 16:27:48 +03:00
|
|
|
|
|
2016-02-24 15:48:16 +02:00
|
|
|
|
stats.narInfoWrite++;
|
2020-08-15 19:41:28 +03:00
|
|
|
|
|
2020-09-23 17:40:41 +03:00
|
|
|
|
return narInfo;
|
2020-08-15 19:41:28 +03:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void BinaryCacheStore::addToStore(const ValidPathInfo & info, Source & narSource,
|
|
|
|
|
RepairFlag repair, CheckSigsFlag checkSigs)
|
|
|
|
|
{
|
|
|
|
|
if (!repair && isValidPath(info.path)) {
|
|
|
|
|
// FIXME: copyNAR -> null sink
|
|
|
|
|
narSource.drain();
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
2020-09-28 18:32:58 +03:00
|
|
|
|
addToStoreCommon(narSource, repair, checkSigs, {[&](HashResult nar) {
|
2020-08-15 19:41:28 +03:00
|
|
|
|
/* FIXME reinstate these, once we can correctly do hash modulo sink as
|
2020-09-23 17:36:55 +03:00
|
|
|
|
needed. We need to throw here in case we uploaded a corrupted store path. */
|
2020-08-15 19:41:28 +03:00
|
|
|
|
// assert(info.narHash == nar.first);
|
|
|
|
|
// assert(info.narSize == nar.second);
|
|
|
|
|
return info;
|
|
|
|
|
}});
|
|
|
|
|
}
|
|
|
|
|
|
2023-11-04 22:25:41 +02:00
|
|
|
|
StorePath BinaryCacheStore::addToStoreFromDump(
|
|
|
|
|
Source & dump,
|
|
|
|
|
std::string_view name,
|
2024-01-19 06:57:26 +02:00
|
|
|
|
FileSerialisationMethod dumpMethod,
|
|
|
|
|
ContentAddressMethod hashMethod,
|
2023-11-04 22:25:41 +02:00
|
|
|
|
HashAlgorithm hashAlgo,
|
|
|
|
|
const StorePathSet & references,
|
|
|
|
|
RepairFlag repair)
|
2020-08-15 19:41:28 +03:00
|
|
|
|
{
|
2023-11-09 04:11:48 +02:00
|
|
|
|
std::optional<Hash> caHash;
|
|
|
|
|
std::string nar;
|
|
|
|
|
|
2024-01-19 06:57:26 +02:00
|
|
|
|
// Calculating Git hash from NAR stream not yet implemented. May not
|
|
|
|
|
// be possible to implement in single-pass if the NAR is in an
|
|
|
|
|
// inconvenient order. Could fetch after uploading, however.
|
|
|
|
|
if (hashMethod.getFileIngestionMethod() == FileIngestionMethod::Git)
|
|
|
|
|
unsupported("addToStoreFromDump");
|
|
|
|
|
|
2023-11-09 04:11:48 +02:00
|
|
|
|
if (auto * dump2p = dynamic_cast<StringSource *>(&dump)) {
|
|
|
|
|
auto & dump2 = *dump2p;
|
|
|
|
|
// Hack, this gives us a "replayable" source so we can compute
|
|
|
|
|
// multiple hashes more easily.
|
2024-01-19 06:57:26 +02:00
|
|
|
|
//
|
|
|
|
|
// Only calculate if the dump is in the right format, however.
|
|
|
|
|
if (static_cast<FileIngestionMethod>(dumpMethod) == hashMethod.getFileIngestionMethod())
|
|
|
|
|
caHash = hashString(HashAlgorithm::SHA256, dump2.s);
|
|
|
|
|
switch (dumpMethod) {
|
2024-05-17 00:46:43 +03:00
|
|
|
|
case FileSerialisationMethod::NixArchive:
|
2023-11-09 04:11:48 +02:00
|
|
|
|
// The dump is already NAR in this case, just use it.
|
|
|
|
|
nar = dump2.s;
|
|
|
|
|
break;
|
2024-01-19 06:57:26 +02:00
|
|
|
|
case FileSerialisationMethod::Flat:
|
2023-09-04 16:51:23 +03:00
|
|
|
|
{
|
2023-11-09 04:11:48 +02:00
|
|
|
|
// The dump is Flat, so we need to convert it to NAR with a
|
|
|
|
|
// single file.
|
|
|
|
|
StringSink s;
|
|
|
|
|
dumpString(dump2.s, s);
|
|
|
|
|
nar = std::move(s.s);
|
|
|
|
|
break;
|
|
|
|
|
}
|
2023-09-04 16:51:23 +03:00
|
|
|
|
}
|
2023-11-09 04:11:48 +02:00
|
|
|
|
} else {
|
|
|
|
|
// Otherwise, we have to do th same hashing as NAR so our single
|
|
|
|
|
// hash will suffice for both purposes.
|
2024-05-17 00:46:43 +03:00
|
|
|
|
if (dumpMethod != FileSerialisationMethod::NixArchive || hashAlgo != HashAlgorithm::SHA256)
|
2023-11-09 04:11:48 +02:00
|
|
|
|
unsupported("addToStoreFromDump");
|
|
|
|
|
}
|
|
|
|
|
StringSource narDump { nar };
|
|
|
|
|
|
|
|
|
|
// Use `narDump` if we wrote to `nar`.
|
|
|
|
|
Source & narDump2 = nar.size() > 0
|
|
|
|
|
? static_cast<Source &>(narDump)
|
|
|
|
|
: dump;
|
|
|
|
|
|
|
|
|
|
return addToStoreCommon(narDump2, repair, CheckSigs, [&](HashResult nar) {
|
2020-08-15 19:41:28 +03:00
|
|
|
|
ValidPathInfo info {
|
2020-10-07 16:52:20 +03:00
|
|
|
|
*this,
|
2023-01-23 19:58:11 +02:00
|
|
|
|
name,
|
2023-11-04 22:25:41 +02:00
|
|
|
|
ContentAddressWithReferences::fromParts(
|
2024-01-19 06:57:26 +02:00
|
|
|
|
hashMethod,
|
2023-11-09 04:11:48 +02:00
|
|
|
|
caHash ? *caHash : nar.first,
|
2023-11-04 22:25:41 +02:00
|
|
|
|
{
|
2023-01-23 19:58:11 +02:00
|
|
|
|
.others = references,
|
2023-04-17 16:15:11 +03:00
|
|
|
|
// caller is not capable of creating a self-reference, because this is content-addressed without modulus
|
2023-01-23 19:58:11 +02:00
|
|
|
|
.self = false,
|
2023-11-04 22:25:41 +02:00
|
|
|
|
}),
|
2020-08-15 19:41:28 +03:00
|
|
|
|
nar.first,
|
|
|
|
|
};
|
|
|
|
|
info.narSize = nar.second;
|
|
|
|
|
return info;
|
2020-09-23 17:40:41 +03:00
|
|
|
|
})->path;
|
2016-02-24 15:48:16 +02:00
|
|
|
|
}
|
|
|
|
|
|
2019-12-05 20:11:09 +02:00
|
|
|
|
bool BinaryCacheStore::isValidPathUncached(const StorePath & storePath)
|
2016-02-24 15:48:16 +02:00
|
|
|
|
{
|
2016-02-25 18:43:19 +02:00
|
|
|
|
// FIXME: this only checks whether a .narinfo with a matching hash
|
2016-11-26 01:37:43 +02:00
|
|
|
|
// part exists. So ‘f4kb...-foo’ matches ‘f4kb...-bar’, even
|
2016-02-25 18:43:19 +02:00
|
|
|
|
// though they shouldn't. Not easily fixed.
|
2016-02-24 15:48:16 +02:00
|
|
|
|
return fileExists(narInfoFileFor(storePath));
|
|
|
|
|
}
|
|
|
|
|
|
2022-10-18 18:48:09 +03:00
|
|
|
|
std::optional<StorePath> BinaryCacheStore::queryPathFromHashPart(const std::string & hashPart)
|
|
|
|
|
{
|
|
|
|
|
auto pseudoPath = StorePath(hashPart + "-" + MissingName);
|
|
|
|
|
try {
|
|
|
|
|
auto info = queryPathInfo(pseudoPath);
|
|
|
|
|
return info->path;
|
|
|
|
|
} catch (InvalidPath &) {
|
|
|
|
|
return std::nullopt;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2019-12-05 20:11:09 +02:00
|
|
|
|
void BinaryCacheStore::narFromPath(const StorePath & storePath, Sink & sink)
|
2016-02-24 15:48:16 +02:00
|
|
|
|
{
|
2016-04-19 19:50:15 +03:00
|
|
|
|
auto info = queryPathInfo(storePath).cast<const NarInfo>();
|
2016-02-24 15:48:16 +02:00
|
|
|
|
|
2020-08-13 17:47:53 +03:00
|
|
|
|
LengthSink narSize;
|
|
|
|
|
TeeSink tee { sink, narSize };
|
2016-02-24 15:48:16 +02:00
|
|
|
|
|
2020-08-13 17:47:53 +03:00
|
|
|
|
auto decompressor = makeDecompressionSink(info->compression, tee);
|
2016-02-24 15:48:16 +02:00
|
|
|
|
|
2018-08-06 16:40:29 +03:00
|
|
|
|
try {
|
|
|
|
|
getFile(info->url, *decompressor);
|
|
|
|
|
} catch (NoSuchBinaryCacheFile & e) {
|
2022-12-07 13:58:58 +02:00
|
|
|
|
throw SubstituteGone(std::move(e.info()));
|
2018-08-06 16:40:29 +03:00
|
|
|
|
}
|
|
|
|
|
|
2018-08-21 16:19:20 +03:00
|
|
|
|
decompressor->finish();
|
2018-08-06 16:40:29 +03:00
|
|
|
|
|
|
|
|
|
stats.narRead++;
|
|
|
|
|
//stats.narReadCompressedBytes += nar->size(); // FIXME
|
2020-08-13 17:47:53 +03:00
|
|
|
|
stats.narReadBytes += narSize.length;
|
2016-03-21 18:55:57 +02:00
|
|
|
|
}
|
|
|
|
|
|
2019-12-05 20:11:09 +02:00
|
|
|
|
void BinaryCacheStore::queryPathInfoUncached(const StorePath & storePath,
|
2018-09-25 19:54:16 +03:00
|
|
|
|
Callback<std::shared_ptr<const ValidPathInfo>> callback) noexcept
|
2016-02-24 15:48:16 +02:00
|
|
|
|
{
|
2017-08-31 16:25:58 +03:00
|
|
|
|
auto uri = getUri();
|
2019-12-05 20:11:09 +02:00
|
|
|
|
auto storePathS = printStorePath(storePath);
|
2017-08-31 16:25:58 +03:00
|
|
|
|
auto act = std::make_shared<Activity>(*logger, lvlTalkative, actQueryPathInfo,
|
2019-12-05 20:11:09 +02:00
|
|
|
|
fmt("querying info about '%s' on '%s'", storePathS, uri), Logger::Fields{storePathS, uri});
|
2017-08-31 16:25:58 +03:00
|
|
|
|
PushActivity pact(act->id);
|
|
|
|
|
|
2016-04-19 19:50:15 +03:00
|
|
|
|
auto narInfoFile = narInfoFileFor(storePath);
|
|
|
|
|
|
2019-09-03 13:51:35 +03:00
|
|
|
|
auto callbackPtr = std::make_shared<decltype(callback)>(std::move(callback));
|
|
|
|
|
|
2016-09-16 19:54:14 +03:00
|
|
|
|
getFile(narInfoFile,
|
2022-10-22 16:25:35 +03:00
|
|
|
|
{[=,this](std::future<std::optional<std::string>> fut) {
|
2018-03-27 23:16:01 +03:00
|
|
|
|
try {
|
|
|
|
|
auto data = fut.get();
|
|
|
|
|
|
2022-01-18 15:06:51 +02:00
|
|
|
|
if (!data) return (*callbackPtr)({});
|
2016-04-19 19:50:15 +03:00
|
|
|
|
|
2018-03-27 23:16:01 +03:00
|
|
|
|
stats.narInfoRead++;
|
2016-04-19 19:50:15 +03:00
|
|
|
|
|
2019-09-03 13:51:35 +03:00
|
|
|
|
(*callbackPtr)((std::shared_ptr<ValidPathInfo>)
|
2018-03-27 23:16:01 +03:00
|
|
|
|
std::make_shared<NarInfo>(*this, *data, narInfoFile));
|
2017-08-31 16:25:58 +03:00
|
|
|
|
|
2018-03-27 23:16:01 +03:00
|
|
|
|
(void) act; // force Activity into this lambda to ensure it stays alive
|
|
|
|
|
} catch (...) {
|
2019-09-03 13:51:35 +03:00
|
|
|
|
callbackPtr->rethrow();
|
2018-03-27 23:16:01 +03:00
|
|
|
|
}
|
|
|
|
|
}});
|
2016-02-24 15:48:16 +02:00
|
|
|
|
}
|
|
|
|
|
|
2022-02-25 17:00:00 +02:00
|
|
|
|
StorePath BinaryCacheStore::addToStore(
|
2023-11-04 22:25:41 +02:00
|
|
|
|
std::string_view name,
|
2024-05-06 20:05:42 +03:00
|
|
|
|
const SourcePath & path,
|
2023-11-04 22:25:41 +02:00
|
|
|
|
ContentAddressMethod method,
|
|
|
|
|
HashAlgorithm hashAlgo,
|
|
|
|
|
const StorePathSet & references,
|
|
|
|
|
PathFilter & filter,
|
|
|
|
|
RepairFlag repair)
|
2016-02-24 17:52:28 +02:00
|
|
|
|
{
|
2020-08-15 19:41:28 +03:00
|
|
|
|
/* FIXME: Make BinaryCacheStore::addToStoreCommon support
|
|
|
|
|
non-recursive+sha256 so we can just use the default
|
|
|
|
|
implementation of this method in terms of addToStoreFromDump. */
|
2016-02-24 17:52:28 +02:00
|
|
|
|
|
2024-05-07 20:25:44 +03:00
|
|
|
|
auto h = hashPath(path, method.getFileIngestionMethod(), hashAlgo, filter).first;
|
2016-02-24 17:52:28 +02:00
|
|
|
|
|
2020-09-26 07:56:29 +03:00
|
|
|
|
auto source = sinkToSource([&](Sink & sink) {
|
2024-05-06 20:05:42 +03:00
|
|
|
|
path.dumpPath(sink, filter);
|
2020-09-26 07:56:29 +03:00
|
|
|
|
});
|
|
|
|
|
return addToStoreCommon(*source, repair, CheckSigs, [&](HashResult nar) {
|
|
|
|
|
ValidPathInfo info {
|
2020-10-07 16:52:20 +03:00
|
|
|
|
*this,
|
2023-01-23 19:58:11 +02:00
|
|
|
|
name,
|
2023-11-04 22:25:41 +02:00
|
|
|
|
ContentAddressWithReferences::fromParts(
|
|
|
|
|
method,
|
|
|
|
|
h,
|
|
|
|
|
{
|
2023-01-23 19:58:11 +02:00
|
|
|
|
.others = references,
|
2023-04-17 16:15:11 +03:00
|
|
|
|
// caller is not capable of creating a self-reference, because this is content-addressed without modulus
|
2023-01-23 19:58:11 +02:00
|
|
|
|
.self = false,
|
2023-11-04 22:25:41 +02:00
|
|
|
|
}),
|
2020-09-26 07:56:29 +03:00
|
|
|
|
nar.first,
|
|
|
|
|
};
|
|
|
|
|
info.narSize = nar.second;
|
|
|
|
|
return info;
|
|
|
|
|
})->path;
|
2016-02-24 17:52:28 +02:00
|
|
|
|
}
|
|
|
|
|
|
2021-10-27 12:36:51 +03:00
|
|
|
|
void BinaryCacheStore::queryRealisationUncached(const DrvOutput & id,
|
|
|
|
|
Callback<std::shared_ptr<const Realisation>> callback) noexcept
|
2020-10-08 18:36:51 +03:00
|
|
|
|
{
|
|
|
|
|
auto outputInfoFilePath = realisationsPrefix + "/" + id.to_string() + ".doi";
|
|
|
|
|
|
2021-10-27 12:50:57 +03:00
|
|
|
|
auto callbackPtr = std::make_shared<decltype(callback)>(std::move(callback));
|
|
|
|
|
|
2022-01-17 23:20:05 +02:00
|
|
|
|
Callback<std::optional<std::string>> newCallback = {
|
|
|
|
|
[=](std::future<std::optional<std::string>> fut) {
|
2021-10-27 12:50:57 +03:00
|
|
|
|
try {
|
|
|
|
|
auto data = fut.get();
|
2022-01-18 15:06:51 +02:00
|
|
|
|
if (!data) return (*callbackPtr)({});
|
2021-05-06 17:45:09 +03:00
|
|
|
|
|
2021-10-27 12:50:57 +03:00
|
|
|
|
auto realisation = Realisation::fromJSON(
|
|
|
|
|
nlohmann::json::parse(*data), outputInfoFilePath);
|
|
|
|
|
return (*callbackPtr)(std::make_shared<const Realisation>(realisation));
|
|
|
|
|
} catch (...) {
|
|
|
|
|
callbackPtr->rethrow();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
};
|
2021-05-06 17:45:09 +03:00
|
|
|
|
|
2021-10-27 12:50:57 +03:00
|
|
|
|
getFile(outputInfoFilePath, std::move(newCallback));
|
2020-10-08 18:36:51 +03:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void BinaryCacheStore::registerDrvOutput(const Realisation& info) {
|
2021-05-06 17:45:09 +03:00
|
|
|
|
if (diskCache)
|
|
|
|
|
diskCache->upsertRealisation(getUri(), info);
|
2020-10-08 18:36:51 +03:00
|
|
|
|
auto filePath = realisationsPrefix + "/" + info.id.to_string() + ".doi";
|
2020-12-15 10:34:45 +02:00
|
|
|
|
upsertFile(filePath, info.toJSON().dump(), "application/json");
|
2020-10-08 18:36:51 +03:00
|
|
|
|
}
|
|
|
|
|
|
2023-11-01 18:09:28 +02:00
|
|
|
|
ref<SourceAccessor> BinaryCacheStore::getFSAccessor(bool requireValidPath)
|
2016-02-25 18:43:19 +02:00
|
|
|
|
{
|
2023-11-01 18:09:28 +02:00
|
|
|
|
return make_ref<RemoteFSAccessor>(ref<Store>(shared_from_this()), requireValidPath, localNarCache);
|
2016-02-25 18:43:19 +02:00
|
|
|
|
}
|
|
|
|
|
|
2019-12-05 20:11:09 +02:00
|
|
|
|
void BinaryCacheStore::addSignatures(const StorePath & storePath, const StringSet & sigs)
|
2017-11-14 19:44:05 +02:00
|
|
|
|
{
|
|
|
|
|
/* Note: this is inherently racy since there is no locking on
|
|
|
|
|
binary caches. In particular, with S3 this unreliable, even
|
|
|
|
|
when addSignatures() is called sequentially on a path, because
|
|
|
|
|
S3 might return an outdated cached version. */
|
|
|
|
|
|
|
|
|
|
auto narInfo = make_ref<NarInfo>((NarInfo &) *queryPathInfo(storePath));
|
|
|
|
|
|
|
|
|
|
narInfo->sigs.insert(sigs.begin(), sigs.end());
|
|
|
|
|
|
|
|
|
|
writeNarInfo(narInfo);
|
|
|
|
|
}
|
|
|
|
|
|
2022-12-15 22:58:54 +02:00
|
|
|
|
std::optional<std::string> BinaryCacheStore::getBuildLogExact(const StorePath & path)
|
2017-03-13 15:07:58 +02:00
|
|
|
|
{
|
2022-12-15 22:58:54 +02:00
|
|
|
|
auto logPath = "log/" + std::string(baseNameOf(printStorePath(path)));
|
2017-03-13 15:07:58 +02:00
|
|
|
|
|
2017-07-30 14:27:57 +03:00
|
|
|
|
debug("fetching build log from binary cache '%s/%s'", getUri(), logPath);
|
2017-03-13 15:07:58 +02:00
|
|
|
|
|
|
|
|
|
return getFile(logPath);
|
|
|
|
|
}
|
|
|
|
|
|
2022-01-18 17:14:01 +02:00
|
|
|
|
void BinaryCacheStore::addBuildLog(const StorePath & drvPath, std::string_view log)
|
|
|
|
|
{
|
|
|
|
|
assert(drvPath.isDerivation());
|
|
|
|
|
|
|
|
|
|
upsertFile(
|
|
|
|
|
"log/" + std::string(drvPath.to_string()),
|
|
|
|
|
(std::string) log, // FIXME: don't copy
|
|
|
|
|
"text/plain; charset=utf-8");
|
|
|
|
|
}
|
|
|
|
|
|
2016-02-24 15:48:16 +02:00
|
|
|
|
}
|