diff --git a/src/libstore/store.cc b/src/libstore/store.cc index fdd22c3b88..110ec2b485 100644 --- a/src/libstore/store.cc +++ b/src/libstore/store.cc @@ -322,29 +322,44 @@ static void writeSubstitutes(const Transaction & txn, } -void registerSubstitute(const Transaction & txn, - const Path & srcPath, const Substitute & sub) +typedef map SubstitutesRev; + + +void registerSubstitutes(const Transaction & txn, + const SubstitutePairs & subPairs) { - assertStorePath(srcPath); - assertStorePath(sub.storeExpr); + SubstitutesRev revMap; - Substitutes subs = readSubstitutes(txn, srcPath); + for (SubstitutePairs::const_iterator i = subPairs.begin(); + i != subPairs.end(); ++i) + { + const Path & srcPath(i->first); + const Substitute & sub(i->second); - if (find(subs.begin(), subs.end(), sub) != subs.end()) { - /* Nothing to do if the substitute is already known. */ - return; + assertStorePath(srcPath); + assertStorePath(sub.storeExpr); + + Substitutes subs = readSubstitutes(txn, srcPath); + + /* New substitutes take precedence over old ones. If the + substitute is already present, it's moved to the front. */ + remove(subs.begin(), subs.end(), sub); + subs.push_front(sub); + + writeSubstitutes(txn, srcPath, subs); + + Paths & revs = revMap[sub.storeExpr]; + if (revs.empty()) + nixDB.queryStrings(txn, dbSubstitutesRev, sub.storeExpr, revs); + if (find(revs.begin(), revs.end(), srcPath) == revs.end()) + revs.push_back(srcPath); } - subs.push_front(sub); /* new substitutes take precedence */ - writeSubstitutes(txn, srcPath, subs); - - Paths revs; - nixDB.queryStrings(txn, dbSubstitutesRev, sub.storeExpr, revs); - if (find(revs.begin(), revs.end(), srcPath) == revs.end()) - revs.push_back(srcPath); - - // !!! O(n^2) complexity in building this - // nixDB.setStrings(txn, dbSubstitutesRev, sub.storeExpr, revs); + /* Re-write the reverse mapping in one go to prevent Theta(n^2) + performance. (This would occur because the data fields of the + `substitutes-rev' table are lists). */ + for (SubstitutesRev::iterator i = revMap.begin(); i != revMap.end(); ++i) + nixDB.setStrings(txn, dbSubstitutesRev, i->first, i->second); } diff --git a/src/libstore/store.hh b/src/libstore/store.hh index 68f7d61905..10d2890b8f 100644 --- a/src/libstore/store.hh +++ b/src/libstore/store.hh @@ -66,8 +66,9 @@ bool querySuccessor(const Path & srcPath, Path & sucPath); Paths queryPredecessors(const Path & sucPath); /* Register a substitute. */ -void registerSubstitute(const Transaction & txn, - const Path & srcPath, const Substitute & sub); +typedef list > SubstitutePairs; +void registerSubstitutes(const Transaction & txn, + const SubstitutePairs & subPairs); /* Return the substitutes expression for the given path. */ Substitutes querySubstitutes(const Path & srcPath); diff --git a/src/nix-store/main.cc b/src/nix-store/main.cc index e9948c7cf8..a8acd30c77 100644 --- a/src/nix-store/main.cc +++ b/src/nix-store/main.cc @@ -158,6 +158,7 @@ static void opSubstitute(Strings opFlags, Strings opArgs) if (!opArgs.empty()) throw UsageError("no arguments expected"); + SubstitutePairs subPairs; Transaction txn; createStoreTransaction(txn); @@ -179,9 +180,11 @@ static void opSubstitute(Strings opFlags, Strings opArgs) sub.args.push_back(s); } if (!cin || cin.eof()) throw Error("missing input"); - registerSubstitute(txn, srcPath, sub); + subPairs.push_back(pair(srcPath, sub)); } + registerSubstitutes(txn, subPairs); + txn.commit(); }