buildRemote(): Copy paths to the destination store in O(1) memory

This commit is contained in:
Eelco Dolstra 2020-07-27 18:11:04 +02:00
parent cbcf6359b4
commit 7622cbfe37
No known key found for this signature in database
GPG key ID: 8170B4726D7198DE

View file

@ -124,6 +124,38 @@ static void copyClosureTo(std::timed_mutex & sendMutex, ref<Store> destStore,
} }
// FIXME: use Store::topoSortPaths().
StorePaths topoSortPaths(const std::map<StorePath, ValidPathInfo> & paths)
{
StorePaths sorted;
StorePathSet visited;
std::function<void(const StorePath & path)> dfsVisit;
dfsVisit = [&](const StorePath & path) {
if (!visited.insert(path).second) return;
auto info = paths.find(path);
auto references = info == paths.end() ? StorePathSet() : info->second.references;
for (auto & i : references)
/* Don't traverse into paths that don't exist. That can
happen due to substitutes for non-existent paths. */
if (i != path && paths.count(i))
dfsVisit(i);
sorted.push_back(path);
};
for (auto & i : paths)
dfsVisit(i.first);
std::reverse(sorted.begin(), sorted.end());
return sorted;
}
void State::buildRemote(ref<Store> destStore, void State::buildRemote(ref<Store> destStore,
Machine::ptr machine, Step::ptr step, Machine::ptr machine, Step::ptr step,
unsigned int maxSilentTime, unsigned int buildTimeout, unsigned int repeats, unsigned int maxSilentTime, unsigned int buildTimeout, unsigned int repeats,
@ -148,6 +180,7 @@ void State::buildRemote(ref<Store> destStore,
updateStep(ssConnecting); updateStep(ssConnecting);
// FIXME: rewrite to use Store.
Child child; Child child;
openConnection(machine, tmpDir, logFD.get(), child); openConnection(machine, tmpDir, logFD.get(), child);
@ -182,7 +215,7 @@ void State::buildRemote(ref<Store> destStore,
unsigned int remoteVersion; unsigned int remoteVersion;
try { try {
to << SERVE_MAGIC_1 << 0x203; to << SERVE_MAGIC_1 << 0x204;
to.flush(); to.flush();
unsigned int magic = readInt(from); unsigned int magic = readInt(from);
@ -405,17 +438,26 @@ void State::buildRemote(ref<Store> destStore,
auto outputs = step->drv->outputPaths(); auto outputs = step->drv->outputPaths();
/* Query the size of the output paths. */ /* Get info about each output path. */
std::map<StorePath, ValidPathInfo> infos;
size_t totalNarSize = 0; size_t totalNarSize = 0;
to << cmdQueryPathInfos; to << cmdQueryPathInfos;
writeStorePaths(*localStore, to, outputs); writeStorePaths(*localStore, to, outputs);
to.flush(); to.flush();
while (true) { while (true) {
if (readString(from) == "") break; auto storePathS = readString(from);
if (storePathS == "") break;
ValidPathInfo info(localStore->parseStorePath(storePathS));
assert(outputs.count(info.path));
readString(from); // deriver readString(from); // deriver
readStrings<PathSet>(from); // references info.references = readStorePaths<StorePathSet>(*localStore, from);
readLongLong(from); // download size readLongLong(from); // download size
totalNarSize += readLongLong(from); info.narSize = readLongLong(from);
totalNarSize += info.narSize;
info.narHash = Hash(readString(from), htSHA256);
info.ca = parseContentAddressOpt(readString(from));
readStrings<StringSet>(from); // sigs
infos.insert_or_assign(info.path, info);
} }
if (totalNarSize > maxOutputSize) { if (totalNarSize > maxOutputSize) {
@ -423,13 +465,18 @@ void State::buildRemote(ref<Store> destStore,
return; return;
} }
/* Copy each path. */
printMsg(lvlDebug, "copying outputs of %s from %s (%d bytes)", printMsg(lvlDebug, "copying outputs of %s from %s (%d bytes)",
localStore->printStorePath(step->drvPath), machine->sshName, totalNarSize); localStore->printStorePath(step->drvPath), machine->sshName, totalNarSize);
to << cmdExportPaths << 0; auto pathsSorted = topoSortPaths(infos);
writeStorePaths(*localStore, to, outputs);
to.flush(); for (auto & path : pathsSorted) {
destStore->importPaths(from, /* result.accessor, */ NoCheckSigs); auto & info = infos.find(path)->second;
to << cmdDumpStorePath << localStore->printStorePath(path);
to.flush();
destStore->addToStore(info, from);
}
auto now2 = std::chrono::steady_clock::now(); auto now2 = std::chrono::steady_clock::now();