Skip to content

Commit

Permalink
Merge pull request #23 from obsidiansystems/ipfs-develop+substituteSt…
Browse files Browse the repository at this point in the history
…oredir

IPFS develop+substitute storedir
  • Loading branch information
Ericson2314 authored Jun 20, 2020
2 parents 8e6f79b + 4bf4725 commit d38faf7
Show file tree
Hide file tree
Showing 16 changed files with 195 additions and 121 deletions.
28 changes: 0 additions & 28 deletions doc/manual/command-ref/conf-file.xml
Original file line number Diff line number Diff line change
Expand Up @@ -370,34 +370,6 @@ false</literal>.</para>

</varlistentry>

<varlistentry xml:id="conf-hashed-mirrors"><term><literal>hashed-mirrors</literal></term>

<listitem><para>A list of web servers used by
<function>builtins.fetchurl</function> to obtain files by
hash. The default is
<literal>http://tarballs.nixos.org/</literal>. Given a hash type
<replaceable>ht</replaceable> and a base-16 hash
<replaceable>h</replaceable>, Nix will try to download the file
from
<literal>hashed-mirror/<replaceable>ht</replaceable>/<replaceable>h</replaceable></literal>.
This allows files to be downloaded even if they have disappeared
from their original URI. For example, given the default mirror
<literal>http://tarballs.nixos.org/</literal>, when building the derivation

<programlisting>
builtins.fetchurl {
url = "https://example.org/foo-1.2.3.tar.xz";
sha256 = "2c26b46b68ffc68ff99b453c1d30413413422d706483bfa0f98a5e886266e7ae";
}
</programlisting>

Nix will attempt to download this file from
<literal>http://tarballs.nixos.org/sha256/2c26b46b68ffc68ff99b453c1d30413413422d706483bfa0f98a5e886266e7ae</literal>
first. If it is not available there, if will try the original URI.</para></listitem>

</varlistentry>


<varlistentry xml:id="conf-http-connections"><term><literal>http-connections</literal></term>

<listitem><para>The maximum number of parallel TCP connections
Expand Down
48 changes: 37 additions & 11 deletions src/libstore/build.cc
Original file line number Diff line number Diff line change
Expand Up @@ -297,7 +297,7 @@ class Worker
GoalPtr makeDerivationGoal(const StorePath & drvPath, const StringSet & wantedOutputs, BuildMode buildMode = bmNormal);
std::shared_ptr<DerivationGoal> makeBasicDerivationGoal(const StorePath & drvPath,
const BasicDerivation & drv, BuildMode buildMode = bmNormal);
GoalPtr makeSubstitutionGoal(const StorePath & storePath, RepairFlag repair = NoRepair);
GoalPtr makeSubstitutionGoal(const StorePath & storePath, RepairFlag repair = NoRepair, std::optional<ContentAddress> ca = std::nullopt);

/* Remove a dead goal. */
void removeGoal(GoalPtr goal);
Expand Down Expand Up @@ -1206,7 +1206,7 @@ void DerivationGoal::haveDerivation()
them. */
if (settings.useSubstitutes && parsedDrv->substitutesAllowed())
for (auto & i : invalidOutputs)
addWaitee(worker.makeSubstitutionGoal(i, buildMode == bmRepair ? Repair : NoRepair));
addWaitee(worker.makeSubstitutionGoal(i, buildMode == bmRepair ? Repair : NoRepair, getDerivationCA(*drv)));

if (waitees.empty()) /* to prevent hang (no wake-up event) */
outputsSubstituted();
Expand Down Expand Up @@ -4300,8 +4300,11 @@ class SubstitutionGoal : public Goal
typedef void (SubstitutionGoal::*GoalState)();
GoalState state;

/* Content address for recomputing store path */
std::optional<ContentAddress> ca;

public:
SubstitutionGoal(const StorePath & storePath, Worker & worker, RepairFlag repair = NoRepair);
SubstitutionGoal(const StorePath & storePath, Worker & worker, RepairFlag repair = NoRepair, std::optional<ContentAddress> ca = std::nullopt);
~SubstitutionGoal();

void timedOut(Error && ex) override { abort(); };
Expand Down Expand Up @@ -4331,10 +4334,11 @@ class SubstitutionGoal : public Goal
};


SubstitutionGoal::SubstitutionGoal(const StorePath & storePath, Worker & worker, RepairFlag repair)
SubstitutionGoal::SubstitutionGoal(const StorePath & storePath, Worker & worker, RepairFlag repair, std::optional<ContentAddress> ca)
: Goal(worker)
, storePath(storePath)
, repair(repair)
, ca(ca)
{
state = &SubstitutionGoal::init;
name = fmt("substitution of '%s'", worker.store.printStorePath(this->storePath));
Expand Down Expand Up @@ -4409,14 +4413,16 @@ void SubstitutionGoal::tryNext()
sub = subs.front();
subs.pop_front();

if (sub->storeDir != worker.store.storeDir) {
tryNext();
return;
auto subPath = storePath;
if (ca) {
subPath = sub->makeFixedOutputPathFromCA(storePath.name(), *ca);
if (sub->storeDir == worker.store.storeDir)
assert(subPath == storePath);
}

try {
// FIXME: make async
info = sub->queryPathInfo(storePath);
info = sub->queryPathInfo(subPath);
} catch (InvalidPath &) {
tryNext();
return;
Expand All @@ -4435,6 +4441,19 @@ void SubstitutionGoal::tryNext()
throw;
}

if (info->path != storePath) {
if (info->isContentAddressed(*sub) && info->references.empty()) {
auto info2 = std::make_shared<ValidPathInfo>(*info);
info2->path = storePath;
info = info2;
} else {
printError("asked '%s' for '%s' but got '%s'",
sub->getUri(), worker.store.printStorePath(storePath), sub->printStorePath(info->path));
tryNext();
return;
}
}

/* Update the total expected download size. */
auto narInfo = std::dynamic_pointer_cast<const NarInfo>(info);

Expand Down Expand Up @@ -4523,8 +4542,15 @@ void SubstitutionGoal::tryToRun()
Activity act(*logger, actSubstitute, Logger::Fields{worker.store.printStorePath(storePath), sub->getUri()});
PushActivity pact(act.id);

auto subPath = storePath;
if (ca) {
subPath = sub->makeFixedOutputPathFromCA(storePath.name(), *ca);
if (sub->storeDir == worker.store.storeDir)
assert(subPath == storePath);
}

copyStorePath(ref<Store>(sub), ref<Store>(worker.store.shared_from_this()),
storePath, repair, sub->isTrusted ? NoCheckSigs : CheckSigs);
subPath, repair, sub->isTrusted ? NoCheckSigs : CheckSigs);

promise.set_value();
} catch (...) {
Expand Down Expand Up @@ -4657,11 +4683,11 @@ std::shared_ptr<DerivationGoal> Worker::makeBasicDerivationGoal(const StorePath
}


GoalPtr Worker::makeSubstitutionGoal(const StorePath & path, RepairFlag repair)
GoalPtr Worker::makeSubstitutionGoal(const StorePath & path, RepairFlag repair, std::optional<ContentAddress> ca)
{
GoalPtr goal = substitutionGoals[path].lock(); // FIXME
if (!goal) {
goal = std::make_shared<SubstitutionGoal>(path, *this, repair);
goal = std::make_shared<SubstitutionGoal>(path, *this, repair, ca);
substitutionGoals.insert_or_assign(path, goal);
wakeUp(goal);
}
Expand Down
13 changes: 0 additions & 13 deletions src/libstore/builtins/fetchurl.cc
Original file line number Diff line number Diff line change
Expand Up @@ -58,19 +58,6 @@ void builtinFetchurl(const BasicDerivation & drv, const std::string & netrcData)
}
};

/* Try the hashed mirrors first. */
if (getAttr("outputHashMode") == "flat")
for (auto hashedMirror : settings.hashedMirrors.get())
try {
if (!hasSuffix(hashedMirror, "/")) hashedMirror += '/';
auto ht = parseHashTypeOpt(getAttr("outputHashAlgo"));
auto h = Hash(getAttr("outputHash"), ht);
fetch(hashedMirror + printHashType(*h.type) + "/" + h.to_string(Base16, false));
return;
} catch (Error & e) {
debug(e.what());
}

/* Otherwise try the specified URL. */
fetch(mainUrl);
}
Expand Down
7 changes: 5 additions & 2 deletions src/libstore/daemon.cc
Original file line number Diff line number Diff line change
Expand Up @@ -606,7 +606,7 @@ static void performOp(TunnelLogger * logger, ref<Store> store,
auto path = store->parseStorePath(readString(from));
logger->startWork();
SubstitutablePathInfos infos;
store->querySubstitutablePathInfos({path}, infos);
store->querySubstitutablePathInfos({{path, std::nullopt}}, infos);
logger->stopWork();
auto i = infos.find(path);
if (i == infos.end())
Expand All @@ -625,7 +625,10 @@ static void performOp(TunnelLogger * logger, ref<Store> store,
auto paths = readStorePaths<StorePathSet>(*store, from);
logger->startWork();
SubstitutablePathInfos infos;
store->querySubstitutablePathInfos(paths, infos);
StorePathCAMap pathsMap = {};
for (auto & path : paths)
pathsMap.emplace(path, std::nullopt);
store->querySubstitutablePathInfos(pathsMap, infos);
logger->stopWork();
to << infos.size();
for (auto & i : infos) {
Expand Down
3 changes: 0 additions & 3 deletions src/libstore/globals.hh
Original file line number Diff line number Diff line change
Expand Up @@ -339,9 +339,6 @@ public:
"setuid/setgid bits or with file capabilities."};
#endif

Setting<Strings> hashedMirrors{this, {"http://tarballs.nixos.org/"}, "hashed-mirrors",
"A list of servers used by builtins.fetchurl to fetch files by hash."};

Setting<uint64_t> minFree{this, 0, "min-free",
"Automatically run the garbage collector when free disk space drops below the specified amount."};

Expand Down
32 changes: 20 additions & 12 deletions src/libstore/local-store.cc
Original file line number Diff line number Diff line change
Expand Up @@ -844,20 +844,32 @@ StorePathSet LocalStore::querySubstitutablePaths(const StorePathSet & paths)
}


void LocalStore::querySubstitutablePathInfos(const StorePathSet & paths,
SubstitutablePathInfos & infos)
void LocalStore::querySubstitutablePathInfos(const StorePathCAMap & paths, SubstitutablePathInfos & infos)
{
if (!settings.useSubstitutes) return;
for (auto & sub : getDefaultSubstituters()) {
if (sub->storeDir != storeDir) continue;
for (auto & path : paths) {
if (infos.count(path)) continue;
debug("checking substituter '%s' for path '%s'", sub->getUri(), printStorePath(path));
auto subPath(path.first);

// recompute store path so that we can use a different store root
if (path.second) {
subPath = makeFixedOutputPathFromCA(path.first.name(), *path.second);
if (sub->storeDir == storeDir)
assert(subPath == path.first);
if (subPath != path.first)
debug("replaced path '%s' with '%s' for substituter '%s'", printStorePath(path.first), sub->printStorePath(subPath), sub->getUri());
} else if (sub->storeDir != storeDir) continue;

debug("checking substituter '%s' for path '%s'", sub->getUri(), sub->printStorePath(subPath));
try {
auto info = sub->queryPathInfo(path);
auto info = sub->queryPathInfo(subPath);

if (sub->storeDir != storeDir && !(info->isContentAddressed(*sub) && info->references.empty()))
continue;

auto narInfo = std::dynamic_pointer_cast<const NarInfo>(
std::shared_ptr<const ValidPathInfo>(info));
infos.insert_or_assign(path, SubstitutablePathInfo{
infos.insert_or_assign(path.first, SubstitutablePathInfo{
info->deriver,
info->references,
narInfo ? narInfo->fileSize : 0,
Expand Down Expand Up @@ -1005,11 +1017,7 @@ void LocalStore::addToStore(const ValidPathInfo & info, Source & source,
return n;
});

auto p = info.ca ? std::get_if<FixedOutputHash>(&*info.ca) : NULL;
if (p && p->method == FileIngestionMethod::Git)
restoreGit(realPath, wrapperSource, realStoreDir, storeDir);
else
restorePath(realPath, wrapperSource);
restorePath(realPath, wrapperSource);

auto hashResult = hashSink->finish();

Expand Down
2 changes: 1 addition & 1 deletion src/libstore/local-store.hh
Original file line number Diff line number Diff line change
Expand Up @@ -139,7 +139,7 @@ public:

StorePathSet querySubstitutablePaths(const StorePathSet & paths) override;

void querySubstitutablePathInfos(const StorePathSet & paths,
void querySubstitutablePathInfos(const StorePathCAMap & paths,
SubstitutablePathInfos & infos) override;

void addToStore(const ValidPathInfo & info, Source & source,
Expand Down
14 changes: 12 additions & 2 deletions src/libstore/misc.cc
Original file line number Diff line number Diff line change
Expand Up @@ -108,6 +108,16 @@ void Store::computeFSClosure(const StorePath & startPath,
}


std::optional<FixedOutputHash> getDerivationCA(const BasicDerivation & drv)
{
if (drv.outputs.count("out") > 0) {
auto res = drv.outputs.find("out");
return res->second.hash;
}

return std::nullopt;
}

void Store::queryMissing(const std::vector<StorePathWithOutputs> & targets,
StorePathSet & willBuild_, StorePathSet & willSubstitute_, StorePathSet & unknown_,
unsigned long long & downloadSize_, unsigned long long & narSize_)
Expand Down Expand Up @@ -157,7 +167,7 @@ void Store::queryMissing(const std::vector<StorePathWithOutputs> & targets,
auto outPath = parseStorePath(outPathS);

SubstitutablePathInfos infos;
querySubstitutablePathInfos({outPath}, infos);
querySubstitutablePathInfos({{outPath, getDerivationCA(*drv)}}, infos);

if (infos.empty()) {
drvState_->lock()->done = true;
Expand Down Expand Up @@ -214,7 +224,7 @@ void Store::queryMissing(const std::vector<StorePathWithOutputs> & targets,
if (isValidPath(path.path)) return;

SubstitutablePathInfos infos;
querySubstitutablePathInfos({path.path}, infos);
querySubstitutablePathInfos({{path.path, std::nullopt}}, infos);

if (infos.empty()) {
auto state(state_.lock());
Expand Down
2 changes: 2 additions & 0 deletions src/libstore/path.hh
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,8 @@ public:
typedef std::set<StorePath> StorePathSet;
typedef std::vector<StorePath> StorePaths;

typedef std::map<StorePath, std::optional<ContentAddress>> StorePathCAMap;

/* Extension of derivations in the Nix store. */
const std::string drvExtension = ".drv";

Expand Down
14 changes: 8 additions & 6 deletions src/libstore/remote-store.cc
Original file line number Diff line number Diff line change
Expand Up @@ -309,18 +309,17 @@ StorePathSet RemoteStore::querySubstitutablePaths(const StorePathSet & paths)
}


void RemoteStore::querySubstitutablePathInfos(const StorePathSet & paths,
SubstitutablePathInfos & infos)
void RemoteStore::querySubstitutablePathInfos(const StorePathCAMap & pathsMap, SubstitutablePathInfos & infos)
{
if (paths.empty()) return;
if (pathsMap.empty()) return;

auto conn(getConnection());

if (GET_PROTOCOL_MINOR(conn->daemonVersion) < 12) {

for (auto & i : paths) {
for (auto & i : pathsMap) {
SubstitutablePathInfo info;
conn->to << wopQuerySubstitutablePathInfo << printStorePath(i);
conn->to << wopQuerySubstitutablePathInfo << printStorePath(i.first);
conn.processStderr();
unsigned int reply = readInt(conn->from);
if (reply == 0) continue;
Expand All @@ -330,12 +329,15 @@ void RemoteStore::querySubstitutablePathInfos(const StorePathSet & paths,
info.references = readStorePaths<StorePathSet>(*this, conn->from);
info.downloadSize = readLongLong(conn->from);
info.narSize = readLongLong(conn->from);
infos.insert_or_assign(i, std::move(info));
infos.insert_or_assign(i.first, std::move(info));
}

} else {

conn->to << wopQuerySubstitutablePathInfos;
StorePathSet paths;
for (auto & path : pathsMap)
paths.insert(path.first);
writeStorePaths(*this, conn->to, paths);
conn.processStderr();
size_t count = readNum<size_t>(conn->from);
Expand Down
2 changes: 1 addition & 1 deletion src/libstore/remote-store.hh
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,7 @@ public:

StorePathSet querySubstitutablePaths(const StorePathSet & paths) override;

void querySubstitutablePathInfos(const StorePathSet & paths,
void querySubstitutablePathInfos(const StorePathCAMap & paths,
SubstitutablePathInfos & infos) override;

void addToStore(const ValidPathInfo & info, Source & nar,
Expand Down
Loading

0 comments on commit d38faf7

Please sign in to comment.