1
1
Fork 0
mirror of https://github.com/NixOS/nix.git synced 2025-11-08 19:46:02 +01:00

Merge pull request #14246 from obsidiansystems/dummy-store-derivations-separately

Make Dummy store store derivations separately
This commit is contained in:
John Ericson 2025-11-03 17:29:28 +00:00 committed by GitHub
commit 0539b58253
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
6 changed files with 147 additions and 33 deletions

View file

@ -50,8 +50,8 @@ TEST_F(WriteDerivationTest, addToStoreFromDumpCalledOnce)
EXPECT_EQ(path1, path2); EXPECT_EQ(path1, path2);
EXPECT_THAT( EXPECT_THAT(
[&] { writeDerivation(*store, drv, Repair); }, [&] { writeDerivation(*store, drv, Repair); },
::testing::ThrowsMessage<Error>(testing::HasSubstrIgnoreANSIMatcher( ::testing::ThrowsMessage<Error>(
"operation 'addToStoreFromDump' is not supported by store 'dummy://'"))); testing::HasSubstrIgnoreANSIMatcher("operation 'writeDerivation' is not supported by store 'dummy://'")));
} }
} // namespace nix } // namespace nix

View file

@ -105,7 +105,7 @@ bool BasicDerivation::isBuiltin() const
return builder.substr(0, 8) == "builtin:"; return builder.substr(0, 8) == "builtin:";
} }
StorePath writeDerivation(Store & store, const Derivation & drv, RepairFlag repair, bool readOnly) static auto infoForDerivation(Store & store, const Derivation & drv)
{ {
auto references = drv.inputSrcs; auto references = drv.inputSrcs;
for (auto & i : drv.inputDrvs.map) for (auto & i : drv.inputDrvs.map)
@ -117,13 +117,32 @@ StorePath writeDerivation(Store & store, const Derivation & drv, RepairFlag repa
auto contents = drv.unparse(store, false); auto contents = drv.unparse(store, false);
auto hash = hashString(HashAlgorithm::SHA256, contents); auto hash = hashString(HashAlgorithm::SHA256, contents);
auto ca = TextInfo{.hash = hash, .references = references}; auto ca = TextInfo{.hash = hash, .references = references};
auto path = store.makeFixedOutputPathFromCA(suffix, ca); return std::tuple{
suffix,
contents,
references,
store.makeFixedOutputPathFromCA(suffix, ca),
};
}
if (readOnly || settings.readOnlyMode || (store.isValidPath(path) && !repair)) StorePath writeDerivation(Store & store, const Derivation & drv, RepairFlag repair, bool readOnly)
{
if (readOnly || settings.readOnlyMode) {
auto [_x, _y, _z, path] = infoForDerivation(store, drv);
return path;
} else
return store.writeDerivation(drv, repair);
}
StorePath Store::writeDerivation(const Derivation & drv, RepairFlag repair)
{
auto [suffix, contents, references, path] = infoForDerivation(*this, drv);
if (isValidPath(path) && !repair)
return path; return path;
StringSource s{contents}; StringSource s{contents};
auto path2 = store.addToStoreFromDump( auto path2 = addToStoreFromDump(
s, s,
suffix, suffix,
FileSerialisationMethod::Flat, FileSerialisationMethod::Flat,

View file

@ -137,14 +137,42 @@ struct DummyStoreImpl : DummyStore
void queryPathInfoUncached( void queryPathInfoUncached(
const StorePath & path, Callback<std::shared_ptr<const ValidPathInfo>> callback) noexcept override const StorePath & path, Callback<std::shared_ptr<const ValidPathInfo>> callback) noexcept override
{ {
bool visited = contents.cvisit(path, [&](const auto & kv) { if (path.isDerivation()) {
if (auto accessor_ = getMemoryFSAccessor(path)) {
ref<MemorySourceAccessor> accessor = ref{std::move(accessor_)};
/* compute path info on demand */
auto narHash =
hashPath({accessor, CanonPath::root}, FileSerialisationMethod::NixArchive, HashAlgorithm::SHA256);
auto info = std::make_shared<ValidPathInfo>(path, UnkeyedValidPathInfo{narHash.hash});
info->narSize = narHash.numBytesDigested;
info->ca = ContentAddress{
.method = ContentAddressMethod::Raw::Text,
.hash = hashString(
HashAlgorithm::SHA256,
std::get<MemorySourceAccessor::File::Regular>(accessor->root->raw).contents),
};
callback(std::move(info));
return;
}
} else {
if (contents.cvisit(path, [&](const auto & kv) {
callback(std::make_shared<ValidPathInfo>(StorePath{kv.first}, kv.second.info)); callback(std::make_shared<ValidPathInfo>(StorePath{kv.first}, kv.second.info));
}); }))
return;
}
if (!visited)
callback(nullptr); callback(nullptr);
} }
/**
* Do this to avoid `queryPathInfoUncached` computing `PathInfo`
* that we don't need just to return a `bool`.
*/
bool isValidPathUncached(const StorePath & path) override
{
return path.isDerivation() ? derivations.contains(path) : Store::isValidPathUncached(path);
}
/** /**
* The dummy store is incapable of *not* trusting! :) * The dummy store is incapable of *not* trusting! :)
*/ */
@ -169,18 +197,25 @@ struct DummyStoreImpl : DummyStore
if (checkSigs) if (checkSigs)
throw Error("checking signatures is not supported for '%s' store", config->getHumanReadableURI()); throw Error("checking signatures is not supported for '%s' store", config->getHumanReadableURI());
auto temp = make_ref<MemorySourceAccessor>(); auto accessor = make_ref<MemorySourceAccessor>();
MemorySink tempSink{*temp}; MemorySink tempSink{*accessor};
parseDump(tempSink, source); parseDump(tempSink, source);
auto path = info.path; auto path = info.path;
auto accessor = make_ref<MemorySourceAccessor>(std::move(*temp)); if (info.path.isDerivation()) {
contents.insert( warn("back compat supporting `addToStore` for inserting derivations in dummy store");
{path, writeDerivation(
parseDerivation(*this, accessor->readFile(CanonPath::root), Derivation::nameFromPath(info.path)));
return;
}
contents.insert({
path,
PathInfoAndContents{ PathInfoAndContents{
std::move(info), std::move(info),
accessor, accessor,
}}); },
});
wholeStoreView->addObject(path.to_string(), accessor); wholeStoreView->addObject(path.to_string(), accessor);
} }
@ -193,6 +228,9 @@ struct DummyStoreImpl : DummyStore
const StorePathSet & references = StorePathSet(), const StorePathSet & references = StorePathSet(),
RepairFlag repair = NoRepair) override RepairFlag repair = NoRepair) override
{ {
if (isDerivation(name))
throw Error("Do not insert derivation into dummy store with `addToStoreFromDump`");
if (config->readOnly) if (config->readOnly)
unsupported("addToStoreFromDump"); unsupported("addToStoreFromDump");
@ -239,17 +277,47 @@ struct DummyStoreImpl : DummyStore
auto path = info.path; auto path = info.path;
auto accessor = make_ref<MemorySourceAccessor>(std::move(*temp)); auto accessor = make_ref<MemorySourceAccessor>(std::move(*temp));
contents.insert( contents.insert({
{path, path,
PathInfoAndContents{ PathInfoAndContents{
std::move(info), std::move(info),
accessor, accessor,
}}); },
});
wholeStoreView->addObject(path.to_string(), accessor); wholeStoreView->addObject(path.to_string(), accessor);
return path; return path;
} }
StorePath writeDerivation(const Derivation & drv, RepairFlag repair = NoRepair) override
{
auto drvPath = ::nix::writeDerivation(*this, drv, repair, /*readonly=*/true);
if (!derivations.contains(drvPath) || repair) {
if (config->readOnly)
unsupported("writeDerivation");
derivations.insert({drvPath, drv});
}
return drvPath;
}
Derivation readDerivation(const StorePath & drvPath) override
{
if (std::optional res = getConcurrent(derivations, drvPath))
return *res;
else
throw Error("derivation '%s' is not valid", printStorePath(drvPath));
}
/**
* No such thing as an "invalid derivation" with the dummy store
*/
Derivation readInvalidDerivation(const StorePath & drvPath) override
{
return readDerivation(drvPath);
}
void registerDrvOutput(const Realisation & output) override void registerDrvOutput(const Realisation & output) override
{ {
auto ref = make_ref<UnkeyedRealisation>(output); auto ref = make_ref<UnkeyedRealisation>(output);
@ -273,13 +341,28 @@ struct DummyStoreImpl : DummyStore
callback(nullptr); callback(nullptr);
} }
std::shared_ptr<SourceAccessor> getFSAccessor(const StorePath & path, bool requireValidPath) override std::shared_ptr<MemorySourceAccessor> getMemoryFSAccessor(const StorePath & path, bool requireValidPath = true)
{ {
std::shared_ptr<SourceAccessor> res; std::shared_ptr<MemorySourceAccessor> res;
if (path.isDerivation())
derivations.cvisit(path, [&](const auto & kv) {
/* compute path info on demand */
auto res2 = make_ref<MemorySourceAccessor>();
res2->root = MemorySourceAccessor::File::Regular{
.contents = kv.second.unparse(*this, false),
};
res = std::move(res2).get_ptr();
});
else
contents.cvisit(path, [&](const auto & kv) { res = kv.second.contents.get_ptr(); }); contents.cvisit(path, [&](const auto & kv) { res = kv.second.contents.get_ptr(); });
return res; return res;
} }
std::shared_ptr<SourceAccessor> getFSAccessor(const StorePath & path, bool requireValidPath = true) override
{
return getMemoryFSAccessor(path, requireValidPath);
}
ref<SourceAccessor> getFSAccessor(bool requireValidPath) override ref<SourceAccessor> getFSAccessor(bool requireValidPath) override
{ {
return wholeStoreView; return wholeStoreView;

View file

@ -2,6 +2,7 @@
///@file ///@file
#include "nix/store/dummy-store.hh" #include "nix/store/dummy-store.hh"
#include "nix/store/derivations.hh"
#include <boost/unordered/concurrent_flat_map.hpp> #include <boost/unordered/concurrent_flat_map.hpp>
@ -25,11 +26,17 @@ struct DummyStore : virtual Store
}; };
/** /**
* This is map conceptually owns the file system objects for each * This map conceptually owns the file system objects for each
* store object. * store object.
*/ */
boost::concurrent_flat_map<StorePath, PathInfoAndContents> contents; boost::concurrent_flat_map<StorePath, PathInfoAndContents> contents;
/**
* This map conceptually owns every derivation, allowing us to
* avoid "on-disk drv format" serialization round-trips.
*/
boost::concurrent_flat_map<StorePath, Derivation> derivations;
/** /**
* The build trace maps the pair of a content-addressing (fixed or * The build trace maps the pair of a content-addressing (fixed or
* floating) derivations an one of its output to a * floating) derivations an one of its output to a

View file

@ -778,15 +778,20 @@ public:
*/ */
Derivation derivationFromPath(const StorePath & drvPath); Derivation derivationFromPath(const StorePath & drvPath);
/**
* Write a derivation to the Nix store, and return its path.
*/
virtual StorePath writeDerivation(const Derivation & drv, RepairFlag repair = NoRepair);
/** /**
* Read a derivation (which must already be valid). * Read a derivation (which must already be valid).
*/ */
Derivation readDerivation(const StorePath & drvPath); virtual Derivation readDerivation(const StorePath & drvPath);
/** /**
* Read a derivation from a potentially invalid path. * Read a derivation from a potentially invalid path.
*/ */
Derivation readInvalidDerivation(const StorePath & drvPath); virtual Derivation readInvalidDerivation(const StorePath & drvPath);
/** /**
* @param [out] out Place in here the set of all store paths in the * @param [out] out Place in here the set of all store paths in the

View file

@ -1170,7 +1170,7 @@ std::optional<StorePath> Store::getBuildDerivationPath(const StorePath & path)
// resolved derivation, so we need to get it first // resolved derivation, so we need to get it first
auto resolvedDrv = drv.tryResolve(*this); auto resolvedDrv = drv.tryResolve(*this);
if (resolvedDrv) if (resolvedDrv)
return writeDerivation(*this, *resolvedDrv, NoRepair, true); return ::nix::writeDerivation(*this, *resolvedDrv, NoRepair, true);
} }
return path; return path;