diff --git a/src/db.cc b/src/db.cc index f9d618b3b3..75f97a1e45 100644 --- a/src/db.cc +++ b/src/db.cc @@ -70,6 +70,14 @@ void Transaction::abort() } +void Transaction::moveTo(Transaction & t) +{ + if (t.txn) throw Error("target txn already exists"); + t.txn = txn; + txn = 0; +} + + void Database::requireEnv() { if (!env) throw Error("database environment not open"); diff --git a/src/db.hh b/src/db.hh index e3dc7ce7af..1c681b9b54 100644 --- a/src/db.hh +++ b/src/db.hh @@ -29,6 +29,8 @@ public: void abort(); void commit(); + + void moveTo(Transaction & t); }; diff --git a/src/expr.cc b/src/expr.cc index 521dffc9c6..cfc4af1f39 100644 --- a/src/expr.cc +++ b/src/expr.cc @@ -39,14 +39,11 @@ Path writeTerm(ATerm t, const string & suffix) (string) h + suffix + ".nix"); if (!isValidPath(path)) { - if (!ATwriteToNamedTextFile(t, path.c_str())) - throw Error(format("cannot write aterm %1%") % path); - - Transaction txn(nixDB); - registerValidPath(txn, path); - txn.commit(); + char * s = ATwriteToString(t); + if (!s) throw Error(format("cannot write aterm to `%1%'") % path); + addTextToStore(path, string(s)); } - + return path; } diff --git a/src/globals.cc b/src/globals.cc index 22d2758b61..a292b49aea 100644 --- a/src/globals.cc +++ b/src/globals.cc @@ -1,37 +1,8 @@ #include "globals.hh" -#include "db.hh" - - -Database nixDB; - - -TableId dbValidPaths; -TableId dbSuccessors; -TableId dbSuccessorsRev; -TableId dbSubstitutes; -TableId dbSubstitutesRev; - string nixStore = "/UNINIT"; string nixDataDir = "/UNINIT"; string nixLogDir = "/UNINIT"; string nixDBPath = "/UNINIT"; - bool keepFailed = false; - - -void openDB() -{ - nixDB.open(nixDBPath); - dbValidPaths = nixDB.openTable("validpaths"); - dbSuccessors = nixDB.openTable("successors"); - dbSuccessorsRev = nixDB.openTable("successors-rev"); - dbSubstitutes = nixDB.openTable("substitutes"); - dbSubstitutesRev = nixDB.openTable("substitutes-rev"); -} - - -void initDB() -{ -} diff --git a/src/globals.hh b/src/globals.hh index 816cb4766e..1b4d0bde3f 100644 --- a/src/globals.hh +++ b/src/globals.hh @@ -3,65 +3,8 @@ #include -#include "db.hh" - using namespace std; - -extern Database nixDB; - - -/* Database tables. */ - - -/* dbValidPaths :: Path -> () - - The existence of a key $p$ indicates that path $p$ is valid (that - is, produced by a succesful build). */ -extern TableId dbValidPaths; - - -/* dbSuccessors :: Path -> Path - - Each pair $(p_1, p_2)$ in this mapping records the fact that the - Nix expression stored at path $p_1$ has a successor expression - stored at path $p_2$. - - Note that a term $y$ is a successor of $x$ iff there exists a - sequence of rewrite steps that rewrites $x$ into $y$. -*/ -extern TableId dbSuccessors; - - -/* dbSuccessorsRev :: Path -> [Path] - - The reverse mapping of dbSuccessors (i.e., it stores the - predecessors of a Nix expression). -*/ -extern TableId dbSuccessorsRev; - - -/* dbSubstitutes :: Path -> [Path] - - Each pair $(p, [ps])$ tells Nix that it can realise any of the - Nix expressions stored at paths $ps$ to produce a path $p$. - - The main purpose of this is for distributed caching of derivates. - One system can compute a derivate and put it on a website (as a Nix - archive), for instance, and then another system can register a - substitute for that derivate. The substitute in this case might be - a Nix expression that fetches the Nix archive. -*/ -extern TableId dbSubstitutes; - - -/* dbSubstitutesRev :: Path -> [Path] - - The reverse mapping of dbSubstitutes. -*/ -extern TableId dbSubstitutesRev; - - /* Path names. */ /* nixStore is the directory where we generally store atomic and @@ -83,11 +26,4 @@ extern string nixDBPath; extern bool keepFailed; -/* Open the database environment. */ -void openDB(); - -/* Create the required database tables. */ -void initDB(); - - #endif /* !__GLOBALS_H */ diff --git a/src/nix-help.txt b/src/nix-help.txt index ceff114ae5..bf2afd0612 100644 --- a/src/nix-help.txt +++ b/src/nix-help.txt @@ -23,7 +23,6 @@ Query flags: --list / -l: query the output paths (roots) of a Nix expression (default) --requisites / -r: print all paths necessary to realise expression - --generators / -g: find expressions producing a subset of given ids --predecessors: print predecessors of a Nix expression --graph: print a dot graph rooted at given ids diff --git a/src/nix.cc b/src/nix.cc index 1012780af8..a4d2898f15 100644 --- a/src/nix.cc +++ b/src/nix.cc @@ -73,7 +73,7 @@ Path maybeNormalise(const Path & ne, bool normalise) /* Perform various sorts of queries. */ static void opQuery(Strings opFlags, Strings opArgs) { - enum { qList, qRequisites, qGenerators, qPredecessors, qGraph + enum { qList, qRequisites, qPredecessors, qGraph } query = qList; bool normalise = false; bool includeExprs = true; @@ -83,7 +83,6 @@ static void opQuery(Strings opFlags, Strings opArgs) i != opFlags.end(); i++) if (*i == "--list" || *i == "-l") query = qList; else if (*i == "--requisites" || *i == "-r") query = qRequisites; - else if (*i == "--generators" || *i == "-g") query = qGenerators; else if (*i == "--predecessors") query = qPredecessors; else if (*i == "--graph") query = qGraph; else if (*i == "--normalise" || *i == "-n") normalise = true; @@ -124,22 +123,6 @@ static void opQuery(Strings opFlags, Strings opArgs) break; } -#if 0 - case qGenerators: { - FSIds outIds; - for (Strings::iterator i = opArgs.begin(); - i != opArgs.end(); i++) - outIds.push_back(checkPath(*i)); - - FSIds genIds = findGenerators(outIds); - - for (FSIds::iterator i = genIds.begin(); - i != genIds.end(); i++) - cout << format("%s\n") % expandId(*i); - break; - } -#endif - case qPredecessors: { for (Strings::iterator i = opArgs.begin(); i != opArgs.end(); i++) @@ -172,7 +155,8 @@ static void opSuccessor(Strings opFlags, Strings opArgs) if (!opFlags.empty()) throw UsageError("unknown flag"); if (opArgs.size() % 2) throw UsageError("expecting even number of arguments"); - Transaction txn(nixDB); /* !!! this could be a big transaction */ + Transaction txn; + createStoreTransaction(txn); for (Strings::iterator i = opArgs.begin(); i != opArgs.end(); ) { diff --git a/src/normalise.cc b/src/normalise.cc index 0dfc9f8e4d..160130d966 100644 --- a/src/normalise.cc +++ b/src/normalise.cc @@ -2,7 +2,6 @@ #include "normalise.hh" #include "references.hh" -#include "db.hh" #include "exec.hh" #include "pathlocks.hh" #include "globals.hh" @@ -11,7 +10,7 @@ static Path useSuccessor(const Path & path) { string pathSucc; - if (nixDB.queryString(noTxn, dbSuccessors, path, pathSucc)) { + if (querySuccessor(path, pathSucc)) { debug(format("successor %1% -> %2%") % (string) path % pathSucc); return pathSucc; } else @@ -349,7 +348,8 @@ Path normaliseNixExpr(const Path & _nePath, PathSet pending) for recoverability: unregistered paths in the store can be deleted arbitrarily, while registered paths can only be deleted by running the garbage collector. */ - Transaction txn(nixDB); + Transaction txn; + createStoreTransaction(txn); for (PathSet::iterator i = ne.derivation.outputs.begin(); i != ne.derivation.outputs.end(); i++) registerValidPath(txn, *i); @@ -434,50 +434,3 @@ PathSet nixExprRequisites(const Path & nePath, paths, doneSet); return paths; } - - -#if 0 -PathSet findGenerators(const PathSet & outputs) -{ - FSIdSet ids(_ids.begin(), _ids.end()); - FSIds generators; - - /* !!! hack; for performance, we just look at the rhs of successor - mappings, since we know that those are Nix expressions. */ - - Strings sucs; - nixDB.enumTable(noTxn, dbSuccessors, sucs); - - for (Strings::iterator i = sucs.begin(); - i != sucs.end(); i++) - { - string s; - if (!nixDB.queryString(noTxn, dbSuccessors, *i, s)) continue; - FSId id = parseHash(s); - - NixExpr ne; - try { - /* !!! should substitutes be used? */ - ne = parseNixExpr(termFromId(id)); - } catch (...) { /* !!! only catch parse errors */ - continue; - } - - if (ne.type != NixExpr::neClosure) continue; - - bool okay = true; - for (ClosureElems::const_iterator i = ne.closure.elems.begin(); - i != ne.closure.elems.end(); i++) - if (ids.find(i->second.id) == ids.end()) { - okay = false; - break; - } - - if (!okay) continue; - - generators.push_back(id); - } - - return generators; -} -#endif diff --git a/src/store.cc b/src/store.cc index 3e755a0d1a..7f10c6377d 100644 --- a/src/store.cc +++ b/src/store.cc @@ -1,7 +1,10 @@ #include #include +#include #include +#include +#include #include "store.hh" #include "globals.hh" @@ -10,6 +13,81 @@ #include "pathlocks.hh" +/* Nix database. */ +static Database nixDB; + + +/* Database tables. */ + +/* dbValidPaths :: Path -> () + + The existence of a key $p$ indicates that path $p$ is valid (that + is, produced by a succesful build). */ +static TableId dbValidPaths; + +/* dbSuccessors :: Path -> Path + + Each pair $(p_1, p_2)$ in this mapping records the fact that the + Nix expression stored at path $p_1$ has a successor expression + stored at path $p_2$. + + Note that a term $y$ is a successor of $x$ iff there exists a + sequence of rewrite steps that rewrites $x$ into $y$. +*/ +static TableId dbSuccessors; + +/* dbSuccessorsRev :: Path -> [Path] + + The reverse mapping of dbSuccessors (i.e., it stores the + predecessors of a Nix expression). +*/ +static TableId dbSuccessorsRev; + +/* dbSubstitutes :: Path -> [Path] + + Each pair $(p, [ps])$ tells Nix that it can realise any of the + Nix expressions stored at paths $ps$ to produce a path $p$. + + The main purpose of this is for distributed caching of derivates. + One system can compute a derivate and put it on a website (as a Nix + archive), for instance, and then another system can register a + substitute for that derivate. The substitute in this case might be + a Nix expression that fetches the Nix archive. +*/ +static TableId dbSubstitutes; + +/* dbSubstitutesRev :: Path -> [Path] + + The reverse mapping of dbSubstitutes. +*/ +static TableId dbSubstitutesRev; + + +void openDB() +{ + nixDB.open(nixDBPath); + dbValidPaths = nixDB.openTable("validpaths"); + dbSuccessors = nixDB.openTable("successors"); + dbSuccessorsRev = nixDB.openTable("successors-rev"); + dbSubstitutes = nixDB.openTable("substitutes"); + dbSubstitutesRev = nixDB.openTable("substitutes-rev"); +} + + +void initDB() +{ +} + + +void createStoreTransaction(Transaction & txn) +{ + Transaction txn2(nixDB); + txn2.moveTo(txn); +} + + +/* Path copying. */ + struct CopySink : DumpSink { int fd; @@ -104,6 +182,12 @@ void registerSuccessor(const Transaction & txn, } +bool querySuccessor(const Path & srcPath, Path & sucPath) +{ + return nixDB.queryString(noTxn, dbSuccessors, srcPath, sucPath); +} + + Paths queryPredecessors(const Path & sucPath) { Paths revs; @@ -204,6 +288,27 @@ Path addToStore(const Path & _srcPath) } +void addTextToStore(const Path & dstPath, const string & s) +{ + if (!isValidPath(dstPath)) { + + /* !!! locking? -> parallel writes are probably idempotent */ + + int fd = open(dstPath.c_str(), O_CREAT | O_EXCL | O_WRONLY, 0666); + if (fd == -1) throw SysError(format("creating store file `%1%'") % dstPath); + + if (write(fd, s.c_str(), s.size()) != (ssize_t) s.size()) + throw SysError(format("writing store file `%1%'") % dstPath); + + close(fd); /* !!! close on exception */ + + Transaction txn(nixDB); + registerValidPath(txn, dstPath); + txn.commit(); + } +} + + void deleteFromStore(const Path & _path) { Path path(canonPath(_path)); diff --git a/src/store.hh b/src/store.hh index 7851b1e3d8..3d7575c3e8 100644 --- a/src/store.hh +++ b/src/store.hh @@ -9,6 +9,15 @@ using namespace std; +/* Open the database environment. */ +void openDB(); + +/* Create the required database tables. */ +void initDB(); + +/* Get a transaction object. */ +void createStoreTransaction(Transaction & txn); + /* Copy a path recursively. */ void copyPath(const Path & src, const Path & dst); @@ -22,6 +31,10 @@ void copyPath(const Path & src, const Path & dst); void registerSuccessor(const Transaction & txn, const Path & srcPath, const Path & sucPath); +/* Return the predecessors of the Nix expression stored at the given + path. */ +bool querySuccessor(const Path & srcPath, Path & sucPath); + /* Return the predecessors of the Nix expression stored at the given path. */ Paths queryPredecessors(const Path & sucPath); @@ -42,6 +55,11 @@ bool isValidPath(const Path & path); the resulting path. The resulting path is returned. */ Path addToStore(const Path & srcPath); +/* Like addToStore, but the path of the output is given, and the + contents written to the output path is a regular file containing + the given string. */ +void addTextToStore(const Path & dstPath, const string & s); + /* Delete a value from the nixStore directory. */ void deleteFromStore(const Path & path);