* Maintain the references/referers relation also for derivations.

This simplifies garbage collection and `nix-store --query
  --requisites' since we no longer need to treat derivations
  specially.

* Better maintaining of the invariants, e.g., setReferences() can only
  be called on a valid/substitutable path.
This commit is contained in:
Eelco Dolstra 2005-01-25 21:28:25 +00:00
parent 2a2756b856
commit a24b78e9f1
8 changed files with 84 additions and 82 deletions

View file

@ -1135,8 +1135,7 @@ void DerivationGoal::computeClosure()
i != drv.outputs.end(); ++i) i != drv.outputs.end(); ++i)
{ {
registerValidPath(txn, i->second.path, registerValidPath(txn, i->second.path,
contentHashes[i->second.path]); contentHashes[i->second.path],
setReferences(txn, i->second.path,
allReferences[i->second.path]); allReferences[i->second.path]);
} }
txn.commit(); txn.commit();
@ -1494,7 +1493,7 @@ void SubstitutionGoal::finished()
Transaction txn; Transaction txn;
createStoreTransaction(txn); createStoreTransaction(txn);
registerValidPath(txn, storePath, contentHash); registerValidPath(txn, storePath, contentHash, references);
txn.commit(); txn.commit();
outputLock->setDeletion(true); outputLock->setDeletion(true);

View file

@ -28,23 +28,4 @@ Derivation derivationFromPath(const Path & drvPath);
void computeFSClosure(const Path & storePath, void computeFSClosure(const Path & storePath,
PathSet & paths, bool flipDirection = false); PathSet & paths, bool flipDirection = false);
/* Place in `paths' the set of paths that are required to `realise'
the given store path, i.e., all paths necessary for valid
deployment of the path. For a derivation, this is the union of
requisites of the inputs, plus the derivation; for other store
paths, it is the set of paths in the FS closure of the path. If
`includeOutputs' is true, include the requisites of the output
paths of derivations as well.
Note that this function can be used to implement three different
deployment policies:
- Source deployment (when called on a derivation).
- Binary deployment (when called on an output path).
- Source/binary deployment (when called on a derivation with
`includeOutputs' set to true).
*/
void storePathRequisites(const Path & storePath,
bool includeOutputs, PathSet & paths);
#endif /* !__BUILD_H */ #endif /* !__BUILD_H */

View file

@ -14,8 +14,16 @@ Hash hashTerm(ATerm t)
Path writeDerivation(const Derivation & drv, const string & name) Path writeDerivation(const Derivation & drv, const string & name)
{ {
PathSet references;
references.insert(drv.inputSrcs.begin(), drv.inputSrcs.end());
for (DerivationInputs::const_iterator i = drv.inputDrvs.begin();
i != drv.inputDrvs.end(); ++i)
references.insert(i->first);
/* Note that the outputs of a derivation are *not* references
(that can be missing (of course) and should not necessarily be
held during a garbage collection). */
return addTextToStore(name + drvExtension, return addTextToStore(name + drvExtension,
atPrint(unparseDerivation(drv))); atPrint(unparseDerivation(drv)), references);
} }

View file

@ -27,44 +27,3 @@ void computeFSClosure(const Path & storePath,
i != references.end(); ++i) i != references.end(); ++i)
computeFSClosure(*i, paths, flipDirection); computeFSClosure(*i, paths, flipDirection);
} }
void storePathRequisites(const Path & storePath,
bool includeOutputs, PathSet & paths)
{
checkInterrupt();
if (paths.find(storePath) != paths.end()) return;
if (isDerivation(storePath)) {
paths.insert(storePath);
Derivation drv = derivationFromPath(storePath);
for (DerivationInputs::iterator i = drv.inputDrvs.begin();
i != drv.inputDrvs.end(); ++i)
/* !!! Maybe this is too strict, since it will include
*all* output paths of the input derivation, not just
the ones needed by this derivation. */
storePathRequisites(i->first, includeOutputs, paths);
for (PathSet::iterator i = drv.inputSrcs.begin();
i != drv.inputSrcs.end(); ++i)
storePathRequisites(*i, includeOutputs, paths);
if (includeOutputs) {
for (DerivationOutputs::iterator i = drv.outputs.begin();
i != drv.outputs.end(); ++i)
if (isValidPath(i->second.path))
storePathRequisites(i->second.path, includeOutputs, paths);
}
}
else {
computeFSClosure(storePath, paths);
}
}

View file

@ -229,7 +229,7 @@ void canonicalisePathMetaData(const Path & path)
} }
static bool isValidPathTxn(const Path & path, const Transaction & txn) static bool isValidPathTxn(const Transaction & txn, const Path & path)
{ {
string s; string s;
return nixDB.queryString(txn, dbValidPaths, path, s); return nixDB.queryString(txn, dbValidPaths, path, s);
@ -238,13 +238,29 @@ static bool isValidPathTxn(const Path & path, const Transaction & txn)
bool isValidPath(const Path & path) bool isValidPath(const Path & path)
{ {
return isValidPathTxn(path, noTxn); return isValidPathTxn(noTxn, path);
}
static Substitutes readSubstitutes(const Transaction & txn,
const Path & srcPath);
static bool isRealisablePath(const Transaction & txn, const Path & path)
{
return isValidPathTxn(txn, path)
|| readSubstitutes(txn, path).size() > 0;
} }
void setReferences(const Transaction & txn, const Path & storePath, void setReferences(const Transaction & txn, const Path & storePath,
const PathSet & references) const PathSet & references)
{ {
if (!isRealisablePath(txn, storePath))
throw Error(
format("cannot set references for path `%1%' which is invalid and has no substitutes")
% storePath);
nixDB.setStrings(txn, dbReferences, storePath, nixDB.setStrings(txn, dbReferences, storePath,
Paths(references.begin(), references.end())); Paths(references.begin(), references.end()));
@ -265,8 +281,8 @@ void setReferences(const Transaction & txn, const Path & storePath,
void queryReferences(const Path & storePath, PathSet & references) void queryReferences(const Path & storePath, PathSet & references)
{ {
Paths references2; Paths references2;
// if (!isValidPath(storePath)) if (!isRealisablePath(noTxn, storePath))
// throw Error(format("path `%1%' is not valid") % storePath); throw Error(format("path `%1%' is not valid") % storePath);
nixDB.queryStrings(noTxn, dbReferences, storePath, references2); nixDB.queryStrings(noTxn, dbReferences, storePath, references2);
references.insert(references2.begin(), references2.end()); references.insert(references2.begin(), references2.end());
} }
@ -275,8 +291,8 @@ void queryReferences(const Path & storePath, PathSet & references)
void queryReferers(const Path & storePath, PathSet & referers) void queryReferers(const Path & storePath, PathSet & referers)
{ {
Paths referers2; Paths referers2;
// if (!isValidPath(storePath)) if (!isRealisablePath(noTxn, storePath))
// throw Error(format("path `%1%' is not valid") % storePath); throw Error(format("path `%1%' is not valid") % storePath);
nixDB.queryStrings(noTxn, dbReferers, storePath, referers2); nixDB.queryStrings(noTxn, dbReferers, storePath, referers2);
referers.insert(referers2.begin(), referers2.end()); referers.insert(referers2.begin(), referers2.end());
} }
@ -370,7 +386,7 @@ void clearSubstitutes()
void registerValidPath(const Transaction & txn, void registerValidPath(const Transaction & txn,
const Path & _path, const Hash & hash) const Path & _path, const Hash & hash, const PathSet & references)
{ {
Path path(canonPath(_path)); Path path(canonPath(_path));
assertStorePath(path); assertStorePath(path);
@ -380,11 +396,11 @@ void registerValidPath(const Transaction & txn,
debug(format("registering path `%1%'") % path); debug(format("registering path `%1%'") % path);
nixDB.setString(txn, dbValidPaths, path, "sha256:" + printHash(hash)); nixDB.setString(txn, dbValidPaths, path, "sha256:" + printHash(hash));
setReferences(txn, path, references);
/* Check that all referenced paths are also valid. */ /* Check that all referenced paths are also valid. */
Paths references; for (PathSet::iterator i = references.begin(); i != references.end(); ++i)
nixDB.queryStrings(txn, dbReferences, path, references); if (!isValidPathTxn(txn, *i))
for (Paths::iterator i = references.begin(); i != references.end(); ++i)
if (!isValidPathTxn(*i, txn))
throw Error(format("cannot register path `%1%' as valid, since its reference `%2%' is invalid") throw Error(format("cannot register path `%1%' as valid, since its reference `%2%' is invalid")
% path % *i); % path % *i);
} }
@ -451,7 +467,7 @@ Path addToStore(const Path & _srcPath)
canonicalisePathMetaData(dstPath); canonicalisePathMetaData(dstPath);
Transaction txn(nixDB); Transaction txn(nixDB);
registerValidPath(txn, dstPath, h); registerValidPath(txn, dstPath, h, PathSet());
txn.commit(); txn.commit();
} }
@ -462,7 +478,8 @@ Path addToStore(const Path & _srcPath)
} }
Path addTextToStore(const string & suffix, const string & s) Path addTextToStore(const string & suffix, const string & s,
const PathSet & references)
{ {
Hash hash = hashString(htSHA256, s); Hash hash = hashString(htSHA256, s);
@ -483,7 +500,8 @@ Path addTextToStore(const string & suffix, const string & s)
canonicalisePathMetaData(dstPath); canonicalisePathMetaData(dstPath);
Transaction txn(nixDB); Transaction txn(nixDB);
registerValidPath(txn, dstPath, hashPath(htSHA256, dstPath)); registerValidPath(txn, dstPath,
hashPath(htSHA256, dstPath), references);
txn.commit(); txn.commit();
} }

View file

@ -57,7 +57,7 @@ void clearSubstitutes();
of the file system contents of the path. The hash must be a of the file system contents of the path. The hash must be a
SHA-256 hash. */ SHA-256 hash. */
void registerValidPath(const Transaction & txn, void registerValidPath(const Transaction & txn,
const Path & path, const Hash & hash); const Path & path, const Hash & hash, const PathSet & references);
/* Throw an exception if `path' is not directly in the Nix store. */ /* Throw an exception if `path' is not directly in the Nix store. */
void assertStorePath(const Path & path); void assertStorePath(const Path & path);
@ -97,7 +97,8 @@ Path addToStore(const Path & srcPath);
/* Like addToStore, but the contents written to the output path is a /* Like addToStore, but the contents written to the output path is a
regular file containing the given string. */ regular file containing the given string. */
Path addTextToStore(const string & suffix, const string & s); Path addTextToStore(const string & suffix, const string & s,
const PathSet & references);
/* Delete a value from the nixStore directory. */ /* Delete a value from the nixStore directory. */
void deleteFromStore(const Path & path); void deleteFromStore(const Path & path);

View file

@ -205,7 +205,8 @@ void createUserEnv(EvalState & state, const DrvInfos & drvs,
/* Also write a copy of the list of inputs to the store; we need /* Also write a copy of the list of inputs to the store; we need
it for future modifications of the environment. */ it for future modifications of the environment. */
Path inputsFile = addTextToStore("env-inputs", atPrint(inputs2)); Path inputsFile = addTextToStore("env-inputs", atPrint(inputs2),
PathSet() /* !!! incorrect */);
Expr topLevel = makeCall(envBuilder, makeAttrs(ATmakeList3( Expr topLevel = makeCall(envBuilder, makeAttrs(ATmakeList3(
makeBind(toATerm("system"), makeBind(toATerm("system"),

View file

@ -74,6 +74,41 @@ static void opAdd(Strings opFlags, Strings opArgs)
} }
/* Place in `paths' the set of paths that are required to `realise'
the given store path, i.e., all paths necessary for valid
deployment of the path. For a derivation, this is the union of
requisites of the inputs, plus the derivation; for other store
paths, it is the set of paths in the FS closure of the path. If
`includeOutputs' is true, include the requisites of the output
paths of derivations as well.
Note that this function can be used to implement three different
deployment policies:
- Source deployment (when called on a derivation).
- Binary deployment (when called on an output path).
- Source/binary deployment (when called on a derivation with
`includeOutputs' set to true).
*/
static void storePathRequisites(const Path & storePath,
bool includeOutputs, PathSet & paths)
{
computeFSClosure(storePath, paths);
if (includeOutputs) {
for (PathSet::iterator i = paths.begin();
i != paths.end(); ++i)
if (isDerivation(*i)) {
Derivation drv = derivationFromPath(*i);
for (DerivationOutputs::iterator j = drv.outputs.begin();
j != drv.outputs.end(); ++j)
if (isValidPath(j->second.path))
computeFSClosure(j->second.path, paths);
}
}
}
static Path maybeUseOutput(const Path & storePath, bool useOutput, bool forceRealise) static Path maybeUseOutput(const Path & storePath, bool useOutput, bool forceRealise)
{ {
if (forceRealise) realisePath(storePath); if (forceRealise) realisePath(storePath);
@ -221,7 +256,7 @@ static void opValidPath(Strings opFlags, Strings opArgs)
createStoreTransaction(txn); createStoreTransaction(txn);
for (Strings::iterator i = opArgs.begin(); for (Strings::iterator i = opArgs.begin();
i != opArgs.end(); ++i) i != opArgs.end(); ++i)
registerValidPath(txn, *i, hashPath(htSHA256, *i)); registerValidPath(txn, *i, hashPath(htSHA256, *i), PathSet());
txn.commit(); txn.commit();
} }