forked from lix-project/lix
* 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:
parent
2a2756b856
commit
a24b78e9f1
|
@ -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);
|
||||||
|
|
|
@ -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 */
|
||||||
|
|
|
@ -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);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -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);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
|
@ -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();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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);
|
||||||
|
|
|
@ -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"),
|
||||||
|
|
|
@ -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();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue