diff options
Diffstat (limited to 'src/libstore')
-rw-r--r-- | src/libstore/build.cc | 7 | ||||
-rw-r--r-- | src/libstore/gc.cc | 30 | ||||
-rw-r--r-- | src/libstore/local-store.cc | 30 | ||||
-rw-r--r-- | src/libstore/local-store.hh | 2 | ||||
-rw-r--r-- | src/libstore/misc.cc | 36 | ||||
-rw-r--r-- | src/libstore/remote-store.cc | 10 | ||||
-rw-r--r-- | src/libstore/remote-store.hh | 2 | ||||
-rw-r--r-- | src/libstore/store-api.hh | 7 | ||||
-rw-r--r-- | src/libstore/worker-protocol.hh | 1 |
9 files changed, 90 insertions, 35 deletions
diff --git a/src/libstore/build.cc b/src/libstore/build.cc index 149cd8b09783..d8f8826e1990 100644 --- a/src/libstore/build.cc +++ b/src/libstore/build.cc @@ -278,10 +278,6 @@ public: }; -MakeError(SubstError, Error) -MakeError(BuildError, Error) /* denotes a permanent build failure */ - - ////////////////////////////////////////////////////////////////////// @@ -1982,7 +1978,8 @@ void DerivationGoal::computeClosure() } /* Register each output path as valid, and register the sets of - paths referenced by each of them. */ + paths referenced by each of them. If there are cycles in the + outputs, this will fail. */ ValidPathInfos infos; foreach (DerivationOutputs::iterator, i, drv.outputs) { ValidPathInfo info; diff --git a/src/libstore/gc.cc b/src/libstore/gc.cc index feaab573ef30..14c8ba0bfe90 100644 --- a/src/libstore/gc.cc +++ b/src/libstore/gc.cc @@ -371,36 +371,6 @@ static void addAdditionalRoots(StoreAPI & store, PathSet & roots) } -static void dfsVisit(StoreAPI & store, const PathSet & paths, - const Path & path, PathSet & visited, Paths & sorted) -{ - if (visited.find(path) != visited.end()) return; - visited.insert(path); - - PathSet references; - if (store.isValidPath(path)) - store.queryReferences(path, references); - - foreach (PathSet::iterator, 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.find(*i) != paths.end()) - dfsVisit(store, paths, *i, visited, sorted); - - sorted.push_front(path); -} - - -Paths topoSortPaths(StoreAPI & store, const PathSet & paths) -{ - Paths sorted; - PathSet visited; - foreach (PathSet::const_iterator, i, paths) - dfsVisit(store, paths, *i, visited, sorted); - return sorted; -} - - struct GCLimitReached { }; diff --git a/src/libstore/local-store.cc b/src/libstore/local-store.cc index cf0e2ad1b13b..771776f6a2c7 100644 --- a/src/libstore/local-store.cc +++ b/src/libstore/local-store.cc @@ -820,6 +820,28 @@ PathSet LocalStore::queryDerivationOutputs(const Path & path) } +StringSet LocalStore::queryDerivationOutputNames(const Path & path) +{ + SQLiteTxn txn(db); + + SQLiteStmtUse use(stmtQueryDerivationOutputs); + stmtQueryDerivationOutputs.bind(queryValidPathId(path)); + + StringSet outputNames; + int r; + while ((r = sqlite3_step(stmtQueryDerivationOutputs)) == SQLITE_ROW) { + const char * s = (const char *) sqlite3_column_text(stmtQueryDerivationOutputs, 0); + assert(s); + outputNames.insert(s); + } + + if (r != SQLITE_DONE) + throwSQLiteError(db, format("error getting output names of `%1%'") % path); + + return outputNames; +} + + void LocalStore::startSubstituter(const Path & substituter, RunningSubstituter & run) { if (run.pid != -1) return; @@ -944,12 +966,14 @@ void LocalStore::registerValidPaths(const ValidPathInfos & infos) while (1) { try { SQLiteTxn txn(db); + PathSet paths; foreach (ValidPathInfos::const_iterator, i, infos) { assert(i->hash.type == htSHA256); /* !!! Maybe the registration info should be updated if the path is already valid. */ if (!isValidPath(i->path)) addValidPath(*i); + paths.insert(i->path); } foreach (ValidPathInfos::const_iterator, i, infos) { @@ -958,6 +982,12 @@ void LocalStore::registerValidPaths(const ValidPathInfos & infos) addReference(referrer, queryValidPathId(*j)); } + /* Do a topological sort of the paths. This will throw an + error if a cycle is detected and roll back the + transaction. Cycles can only occur when a derivation + has multiple outputs. */ + topoSortPaths(*this, paths); + txn.commit(); break; } catch (SQLiteBusy & e) { diff --git a/src/libstore/local-store.hh b/src/libstore/local-store.hh index 4cb905f67231..2739c4eea69d 100644 --- a/src/libstore/local-store.hh +++ b/src/libstore/local-store.hh @@ -118,6 +118,8 @@ public: PathSet queryValidDerivers(const Path & path); PathSet queryDerivationOutputs(const Path & path); + + StringSet queryDerivationOutputNames(const Path & path); PathSet querySubstitutablePaths(); diff --git a/src/libstore/misc.cc b/src/libstore/misc.cc index d4bbccd111ba..4ac0afe844b6 100644 --- a/src/libstore/misc.cc +++ b/src/libstore/misc.cc @@ -97,4 +97,40 @@ void queryMissing(StoreAPI & store, const PathSet & targets, } +static void dfsVisit(StoreAPI & store, const PathSet & paths, + const Path & path, PathSet & visited, Paths & sorted, + PathSet & parents) +{ + if (parents.find(path) != parents.end()) + throw BuildError(format("cycle detected in the references of `%1%'") % path); + + if (visited.find(path) != visited.end()) return; + visited.insert(path); + parents.insert(path); + + PathSet references; + if (store.isValidPath(path)) + store.queryReferences(path, references); + + foreach (PathSet::iterator, 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.find(*i) != paths.end()) + dfsVisit(store, paths, *i, visited, sorted, parents); + + sorted.push_front(path); + parents.erase(path); +} + + +Paths topoSortPaths(StoreAPI & store, const PathSet & paths) +{ + Paths sorted; + PathSet visited, parents; + foreach (PathSet::const_iterator, i, paths) + dfsVisit(store, paths, *i, visited, sorted, parents); + return sorted; +} + + } diff --git a/src/libstore/remote-store.cc b/src/libstore/remote-store.cc index 942c5bcf1c7c..6e9921ede79f 100644 --- a/src/libstore/remote-store.cc +++ b/src/libstore/remote-store.cc @@ -326,6 +326,16 @@ PathSet RemoteStore::queryDerivationOutputs(const Path & path) } +PathSet RemoteStore::queryDerivationOutputNames(const Path & path) +{ + openConnection(); + writeInt(wopQueryDerivationOutputNames, to); + writeString(path, to); + processStderr(); + return readStrings<PathSet>(from); +} + + Path RemoteStore::addToStore(const Path & _srcPath, bool recursive, HashType hashAlgo, PathFilter & filter) { diff --git a/src/libstore/remote-store.hh b/src/libstore/remote-store.hh index 34a2d91dfcd1..c5853ef53646 100644 --- a/src/libstore/remote-store.hh +++ b/src/libstore/remote-store.hh @@ -41,6 +41,8 @@ public: PathSet queryDerivationOutputs(const Path & path); + StringSet queryDerivationOutputNames(const Path & path); + bool hasSubstitutes(const Path & path); bool querySubstitutablePathInfo(const Path & path, diff --git a/src/libstore/store-api.hh b/src/libstore/store-api.hh index d4997c886207..61bcaf50507f 100644 --- a/src/libstore/store-api.hh +++ b/src/libstore/store-api.hh @@ -140,6 +140,9 @@ public: /* Query the outputs of the derivation denoted by `path'. */ virtual PathSet queryDerivationOutputs(const Path & path) = 0; + + /* Query the output names of the derivation denoted by `path'. */ + virtual StringSet queryDerivationOutputNames(const Path & path) = 0; /* Query whether a path has substitutes. */ virtual bool hasSubstitutes(const Path & path) = 0; @@ -346,6 +349,10 @@ void exportPaths(StoreAPI & store, const Paths & paths, bool sign, Sink & sink); +MakeError(SubstError, Error) +MakeError(BuildError, Error) /* denotes a permanent build failure */ + + } diff --git a/src/libstore/worker-protocol.hh b/src/libstore/worker-protocol.hh index 760d08a747ae..ef1e0993df28 100644 --- a/src/libstore/worker-protocol.hh +++ b/src/libstore/worker-protocol.hh @@ -39,6 +39,7 @@ typedef enum { wopClearFailedPaths = 25, wopQueryPathInfo = 26, wopImportPaths = 27, + wopQueryDerivationOutputNames = 28, } WorkerOp; |