Skip to content

Commit 136825b

Browse files
committed
Make Dummy store store derivations separately
This makes for more efficiency. Once we have JSON for the dummy store, it will also make for better JSON, too.
1 parent 28b73ca commit 136825b

File tree

3 files changed

+107
-26
lines changed

3 files changed

+107
-26
lines changed

src/libstore-tests/write-derivation.cc

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -50,8 +50,8 @@ TEST_F(WriteDerivationTest, addToStoreFromDumpCalledOnce)
5050
EXPECT_EQ(path1, path2);
5151
EXPECT_THAT(
5252
[&] { writeDerivation(*store, drv, Repair); },
53-
::testing::ThrowsMessage<Error>(testing::HasSubstrIgnoreANSIMatcher(
54-
"operation 'addToStoreFromDump' is not supported by store 'dummy://'")));
53+
::testing::ThrowsMessage<Error>(
54+
testing::HasSubstrIgnoreANSIMatcher("operation 'writeDerivation' is not supported by store 'dummy://'")));
5555
}
5656

5757
} // namespace nix

src/libstore/dummy-store.cc

Lines changed: 97 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -137,12 +137,31 @@ struct DummyStoreImpl : DummyStore
137137
void queryPathInfoUncached(
138138
const StorePath & path, Callback<std::shared_ptr<const ValidPathInfo>> callback) noexcept override
139139
{
140-
bool visited = contents.cvisit(path, [&](const auto & kv) {
141-
callback(std::make_shared<ValidPathInfo>(StorePath{kv.first}, kv.second.info));
142-
});
140+
if (path.isDerivation()) {
141+
if (auto accessor_ = getMemoryFSAccessor(path)) {
142+
ref<MemorySourceAccessor> accessor = ref{std::move(accessor_)};
143+
/* compute path info on demand */
144+
auto narHash =
145+
hashPath({accessor, CanonPath::root}, FileSerialisationMethod::NixArchive, HashAlgorithm::SHA256);
146+
auto info = std::make_shared<ValidPathInfo>(path, UnkeyedValidPathInfo{narHash.hash});
147+
info->narSize = narHash.numBytesDigested;
148+
info->ca = ContentAddress{
149+
.method = ContentAddressMethod::Raw::Text,
150+
.hash = hashString(
151+
HashAlgorithm::SHA256,
152+
std::get<MemorySourceAccessor::File::Regular>(accessor->root->raw).contents),
153+
};
154+
callback(std::move(info));
155+
return;
156+
}
157+
} else {
158+
if (contents.cvisit(path, [&](const auto & kv) {
159+
callback(std::make_shared<ValidPathInfo>(StorePath{kv.first}, kv.second.info));
160+
}))
161+
return;
162+
}
143163

144-
if (!visited)
145-
callback(nullptr);
164+
callback(nullptr);
146165
}
147166

148167
/**
@@ -169,18 +188,25 @@ struct DummyStoreImpl : DummyStore
169188
if (checkSigs)
170189
throw Error("checking signatures is not supported for '%s' store", config->getHumanReadableURI());
171190

172-
auto temp = make_ref<MemorySourceAccessor>();
173-
MemorySink tempSink{*temp};
191+
auto accessor = make_ref<MemorySourceAccessor>();
192+
MemorySink tempSink{*accessor};
174193
parseDump(tempSink, source);
175194
auto path = info.path;
176195

177-
auto accessor = make_ref<MemorySourceAccessor>(std::move(*temp));
178-
contents.insert(
179-
{path,
180-
PathInfoAndContents{
181-
std::move(info),
182-
accessor,
183-
}});
196+
if (info.path.isDerivation()) {
197+
warn("back compat supporting `addToStore` for inserting derivations in dummy store");
198+
writeDerivation(
199+
parseDerivation(*this, accessor->readFile(CanonPath::root), Derivation::nameFromPath(info.path)));
200+
return;
201+
}
202+
203+
contents.insert({
204+
path,
205+
PathInfoAndContents{
206+
std::move(info),
207+
accessor,
208+
},
209+
});
184210
wholeStoreView->addObject(path.to_string(), accessor);
185211
}
186212

@@ -193,6 +219,9 @@ struct DummyStoreImpl : DummyStore
193219
const StorePathSet & references = StorePathSet(),
194220
RepairFlag repair = NoRepair) override
195221
{
222+
if (isDerivation(name))
223+
throw Error("Do not insert derivation into dummy store with `addToStoreFromDump`");
224+
196225
if (config->readOnly)
197226
unsupported("addToStoreFromDump");
198227

@@ -239,17 +268,47 @@ struct DummyStoreImpl : DummyStore
239268

240269
auto path = info.path;
241270
auto accessor = make_ref<MemorySourceAccessor>(std::move(*temp));
242-
contents.insert(
243-
{path,
244-
PathInfoAndContents{
245-
std::move(info),
246-
accessor,
247-
}});
271+
contents.insert({
272+
path,
273+
PathInfoAndContents{
274+
std::move(info),
275+
accessor,
276+
},
277+
});
248278
wholeStoreView->addObject(path.to_string(), accessor);
249279

250280
return path;
251281
}
252282

283+
StorePath writeDerivation(const Derivation & drv, RepairFlag repair = NoRepair) override
284+
{
285+
auto drvPath = ::nix::writeDerivation(*this, drv, repair, /*readonly=*/true);
286+
287+
if (!derivations.contains(drvPath) || repair) {
288+
if (config->readOnly)
289+
unsupported("writeDerivation");
290+
derivations.insert({drvPath, drv});
291+
}
292+
293+
return drvPath;
294+
}
295+
296+
Derivation readDerivation(const StorePath & drvPath) override
297+
{
298+
if (std::optional res = getConcurrent(derivations, drvPath))
299+
return *res;
300+
else
301+
throw Error("derivation '%s' is not valid", printStorePath(drvPath));
302+
}
303+
304+
/**
305+
* No such thing as an "invalid derivation" with the dummy store
306+
*/
307+
Derivation readInvalidDerivation(const StorePath & drvPath) override
308+
{
309+
return readDerivation(drvPath);
310+
}
311+
253312
void registerDrvOutput(const Realisation & output) override
254313
{
255314
auto ref = make_ref<UnkeyedRealisation>(output);
@@ -273,13 +332,28 @@ struct DummyStoreImpl : DummyStore
273332
callback(nullptr);
274333
}
275334

276-
std::shared_ptr<SourceAccessor> getFSAccessor(const StorePath & path, bool requireValidPath) override
335+
std::shared_ptr<MemorySourceAccessor> getMemoryFSAccessor(const StorePath & path, bool requireValidPath = true)
277336
{
278-
std::shared_ptr<SourceAccessor> res;
279-
contents.cvisit(path, [&](const auto & kv) { res = kv.second.contents.get_ptr(); });
337+
std::shared_ptr<MemorySourceAccessor> res;
338+
if (path.isDerivation())
339+
derivations.cvisit(path, [&](const auto & kv) {
340+
/* compute path info on demand */
341+
auto res2 = make_ref<MemorySourceAccessor>();
342+
res2->root = MemorySourceAccessor::File::Regular{
343+
.contents = kv.second.unparse(*this, false),
344+
};
345+
res = std::move(res2).get_ptr();
346+
});
347+
else
348+
contents.cvisit(path, [&](const auto & kv) { res = kv.second.contents.get_ptr(); });
280349
return res;
281350
}
282351

352+
std::shared_ptr<SourceAccessor> getFSAccessor(const StorePath & path, bool requireValidPath = true) override
353+
{
354+
return getMemoryFSAccessor(path, requireValidPath);
355+
}
356+
283357
ref<SourceAccessor> getFSAccessor(bool requireValidPath) override
284358
{
285359
return wholeStoreView;

src/libstore/include/nix/store/dummy-store-impl.hh

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
///@file
33

44
#include "nix/store/dummy-store.hh"
5+
#include "nix/store/derivations.hh"
56

67
#include <boost/unordered/concurrent_flat_map.hpp>
78

@@ -25,11 +26,17 @@ struct DummyStore : virtual Store
2526
};
2627

2728
/**
28-
* This is map conceptually owns the file system objects for each
29+
* This map conceptually owns the file system objects for each
2930
* store object.
3031
*/
3132
boost::concurrent_flat_map<StorePath, PathInfoAndContents> contents;
3233

34+
/**
35+
* This map conceptually owns every derivation, allowing us to
36+
* avoid "on-disk drv format" serialization round-trips.
37+
*/
38+
boost::concurrent_flat_map<StorePath, Derivation> derivations;
39+
3340
/**
3441
* The build trace maps the pair of a content-addressing (fixed or
3542
* floating) derivations an one of its output to a

0 commit comments

Comments
 (0)