Skip to content

Commit 0539b58

Browse files
authored
Merge pull request #14246 from obsidiansystems/dummy-store-derivations-separately
Make Dummy store store derivations separately
2 parents beace42 + 18941a2 commit 0539b58

File tree

6 files changed

+147
-33
lines changed

6 files changed

+147
-33
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/derivations.cc

Lines changed: 23 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -105,7 +105,7 @@ bool BasicDerivation::isBuiltin() const
105105
return builder.substr(0, 8) == "builtin:";
106106
}
107107

108-
StorePath writeDerivation(Store & store, const Derivation & drv, RepairFlag repair, bool readOnly)
108+
static auto infoForDerivation(Store & store, const Derivation & drv)
109109
{
110110
auto references = drv.inputSrcs;
111111
for (auto & i : drv.inputDrvs.map)
@@ -117,13 +117,32 @@ StorePath writeDerivation(Store & store, const Derivation & drv, RepairFlag repa
117117
auto contents = drv.unparse(store, false);
118118
auto hash = hashString(HashAlgorithm::SHA256, contents);
119119
auto ca = TextInfo{.hash = hash, .references = references};
120-
auto path = store.makeFixedOutputPathFromCA(suffix, ca);
120+
return std::tuple{
121+
suffix,
122+
contents,
123+
references,
124+
store.makeFixedOutputPathFromCA(suffix, ca),
125+
};
126+
}
127+
128+
StorePath writeDerivation(Store & store, const Derivation & drv, RepairFlag repair, bool readOnly)
129+
{
130+
if (readOnly || settings.readOnlyMode) {
131+
auto [_x, _y, _z, path] = infoForDerivation(store, drv);
132+
return path;
133+
} else
134+
return store.writeDerivation(drv, repair);
135+
}
136+
137+
StorePath Store::writeDerivation(const Derivation & drv, RepairFlag repair)
138+
{
139+
auto [suffix, contents, references, path] = infoForDerivation(*this, drv);
121140

122-
if (readOnly || settings.readOnlyMode || (store.isValidPath(path) && !repair))
141+
if (isValidPath(path) && !repair)
123142
return path;
124143

125144
StringSource s{contents};
126-
auto path2 = store.addToStoreFromDump(
145+
auto path2 = addToStoreFromDump(
127146
s,
128147
suffix,
129148
FileSerialisationMethod::Flat,

src/libstore/dummy-store.cc

Lines changed: 106 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -137,12 +137,40 @@ 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);
165+
}
166+
167+
/**
168+
* Do this to avoid `queryPathInfoUncached` computing `PathInfo`
169+
* that we don't need just to return a `bool`.
170+
*/
171+
bool isValidPathUncached(const StorePath & path) override
172+
{
173+
return path.isDerivation() ? derivations.contains(path) : Store::isValidPathUncached(path);
146174
}
147175

148176
/**
@@ -169,18 +197,25 @@ struct DummyStoreImpl : DummyStore
169197
if (checkSigs)
170198
throw Error("checking signatures is not supported for '%s' store", config->getHumanReadableURI());
171199

172-
auto temp = make_ref<MemorySourceAccessor>();
173-
MemorySink tempSink{*temp};
200+
auto accessor = make_ref<MemorySourceAccessor>();
201+
MemorySink tempSink{*accessor};
174202
parseDump(tempSink, source);
175203
auto path = info.path;
176204

177-
auto accessor = make_ref<MemorySourceAccessor>(std::move(*temp));
178-
contents.insert(
179-
{path,
180-
PathInfoAndContents{
181-
std::move(info),
182-
accessor,
183-
}});
205+
if (info.path.isDerivation()) {
206+
warn("back compat supporting `addToStore` for inserting derivations in dummy store");
207+
writeDerivation(
208+
parseDerivation(*this, accessor->readFile(CanonPath::root), Derivation::nameFromPath(info.path)));
209+
return;
210+
}
211+
212+
contents.insert({
213+
path,
214+
PathInfoAndContents{
215+
std::move(info),
216+
accessor,
217+
},
218+
});
184219
wholeStoreView->addObject(path.to_string(), accessor);
185220
}
186221

@@ -193,6 +228,9 @@ struct DummyStoreImpl : DummyStore
193228
const StorePathSet & references = StorePathSet(),
194229
RepairFlag repair = NoRepair) override
195230
{
231+
if (isDerivation(name))
232+
throw Error("Do not insert derivation into dummy store with `addToStoreFromDump`");
233+
196234
if (config->readOnly)
197235
unsupported("addToStoreFromDump");
198236

@@ -239,17 +277,47 @@ struct DummyStoreImpl : DummyStore
239277

240278
auto path = info.path;
241279
auto accessor = make_ref<MemorySourceAccessor>(std::move(*temp));
242-
contents.insert(
243-
{path,
244-
PathInfoAndContents{
245-
std::move(info),
246-
accessor,
247-
}});
280+
contents.insert({
281+
path,
282+
PathInfoAndContents{
283+
std::move(info),
284+
accessor,
285+
},
286+
});
248287
wholeStoreView->addObject(path.to_string(), accessor);
249288

250289
return path;
251290
}
252291

292+
StorePath writeDerivation(const Derivation & drv, RepairFlag repair = NoRepair) override
293+
{
294+
auto drvPath = ::nix::writeDerivation(*this, drv, repair, /*readonly=*/true);
295+
296+
if (!derivations.contains(drvPath) || repair) {
297+
if (config->readOnly)
298+
unsupported("writeDerivation");
299+
derivations.insert({drvPath, drv});
300+
}
301+
302+
return drvPath;
303+
}
304+
305+
Derivation readDerivation(const StorePath & drvPath) override
306+
{
307+
if (std::optional res = getConcurrent(derivations, drvPath))
308+
return *res;
309+
else
310+
throw Error("derivation '%s' is not valid", printStorePath(drvPath));
311+
}
312+
313+
/**
314+
* No such thing as an "invalid derivation" with the dummy store
315+
*/
316+
Derivation readInvalidDerivation(const StorePath & drvPath) override
317+
{
318+
return readDerivation(drvPath);
319+
}
320+
253321
void registerDrvOutput(const Realisation & output) override
254322
{
255323
auto ref = make_ref<UnkeyedRealisation>(output);
@@ -273,13 +341,28 @@ struct DummyStoreImpl : DummyStore
273341
callback(nullptr);
274342
}
275343

276-
std::shared_ptr<SourceAccessor> getFSAccessor(const StorePath & path, bool requireValidPath) override
344+
std::shared_ptr<MemorySourceAccessor> getMemoryFSAccessor(const StorePath & path, bool requireValidPath = true)
277345
{
278-
std::shared_ptr<SourceAccessor> res;
279-
contents.cvisit(path, [&](const auto & kv) { res = kv.second.contents.get_ptr(); });
346+
std::shared_ptr<MemorySourceAccessor> res;
347+
if (path.isDerivation())
348+
derivations.cvisit(path, [&](const auto & kv) {
349+
/* compute path info on demand */
350+
auto res2 = make_ref<MemorySourceAccessor>();
351+
res2->root = MemorySourceAccessor::File::Regular{
352+
.contents = kv.second.unparse(*this, false),
353+
};
354+
res = std::move(res2).get_ptr();
355+
});
356+
else
357+
contents.cvisit(path, [&](const auto & kv) { res = kv.second.contents.get_ptr(); });
280358
return res;
281359
}
282360

361+
std::shared_ptr<SourceAccessor> getFSAccessor(const StorePath & path, bool requireValidPath = true) override
362+
{
363+
return getMemoryFSAccessor(path, requireValidPath);
364+
}
365+
283366
ref<SourceAccessor> getFSAccessor(bool requireValidPath) override
284367
{
285368
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

src/libstore/include/nix/store/store-api.hh

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -778,15 +778,20 @@ public:
778778
*/
779779
Derivation derivationFromPath(const StorePath & drvPath);
780780

781+
/**
782+
* Write a derivation to the Nix store, and return its path.
783+
*/
784+
virtual StorePath writeDerivation(const Derivation & drv, RepairFlag repair = NoRepair);
785+
781786
/**
782787
* Read a derivation (which must already be valid).
783788
*/
784-
Derivation readDerivation(const StorePath & drvPath);
789+
virtual Derivation readDerivation(const StorePath & drvPath);
785790

786791
/**
787792
* Read a derivation from a potentially invalid path.
788793
*/
789-
Derivation readInvalidDerivation(const StorePath & drvPath);
794+
virtual Derivation readInvalidDerivation(const StorePath & drvPath);
790795

791796
/**
792797
* @param [out] out Place in here the set of all store paths in the

src/libstore/store-api.cc

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1170,7 +1170,7 @@ std::optional<StorePath> Store::getBuildDerivationPath(const StorePath & path)
11701170
// resolved derivation, so we need to get it first
11711171
auto resolvedDrv = drv.tryResolve(*this);
11721172
if (resolvedDrv)
1173-
return writeDerivation(*this, *resolvedDrv, NoRepair, true);
1173+
return ::nix::writeDerivation(*this, *resolvedDrv, NoRepair, true);
11741174
}
11751175

11761176
return path;

0 commit comments

Comments
 (0)