`nix-store --verify' improvements:
* If a path has disappeared, check its referrers first, and don't try to invalidate paths that have valid referrers. Otherwise we get a foreign key constraint violation. * Read the whole Nix store directory instead of statting each valid path, which is slower. * Acquire the global GC lock.
This commit is contained in:
parent
80e722278c
commit
e2e168f7c2
3 changed files with 62 additions and 20 deletions
|
@ -1,6 +1,5 @@
|
||||||
#include "globals.hh"
|
#include "globals.hh"
|
||||||
#include "misc.hh"
|
#include "misc.hh"
|
||||||
#include "pathlocks.hh"
|
|
||||||
#include "local-store.hh"
|
#include "local-store.hh"
|
||||||
|
|
||||||
#include <boost/shared_ptr.hpp>
|
#include <boost/shared_ptr.hpp>
|
||||||
|
@ -31,7 +30,7 @@ static const int defaultGcLevel = 1000;
|
||||||
read. To be precise: when they try to create a new temporary root
|
read. To be precise: when they try to create a new temporary root
|
||||||
file, they will block until the garbage collector has finished /
|
file, they will block until the garbage collector has finished /
|
||||||
yielded the GC lock. */
|
yielded the GC lock. */
|
||||||
static int openGCLock(LockType lockType)
|
int LocalStore::openGCLock(LockType lockType)
|
||||||
{
|
{
|
||||||
Path fnGCLock = (format("%1%/%2%")
|
Path fnGCLock = (format("%1%/%2%")
|
||||||
% nixStateDir % gcLockName).str();
|
% nixStateDir % gcLockName).str();
|
||||||
|
|
|
@ -1226,27 +1226,25 @@ void LocalStore::deleteFromStore(const Path & path, unsigned long long & bytesFr
|
||||||
|
|
||||||
void LocalStore::verifyStore(bool checkContents)
|
void LocalStore::verifyStore(bool checkContents)
|
||||||
{
|
{
|
||||||
|
printMsg(lvlError, format("reading the Nix store..."));
|
||||||
|
|
||||||
|
/* Acquire the global GC lock to prevent a garbage collection. */
|
||||||
|
AutoCloseFD fdGCLock = openGCLock(ltWrite);
|
||||||
|
|
||||||
|
Paths entries = readDirectory(nixStore);
|
||||||
|
PathSet store(entries.begin(), entries.end());
|
||||||
|
|
||||||
/* Check whether all valid paths actually exist. */
|
/* Check whether all valid paths actually exist. */
|
||||||
printMsg(lvlInfo, "checking path existence");
|
printMsg(lvlInfo, "checking path existence...");
|
||||||
|
|
||||||
PathSet validPaths2 = queryValidPaths(), validPaths;
|
PathSet validPaths2 = queryValidPaths(), validPaths, done;
|
||||||
|
|
||||||
foreach (PathSet::iterator, i, validPaths2) {
|
foreach (PathSet::iterator, i, validPaths2)
|
||||||
checkInterrupt();
|
verifyPath(*i, store, done, validPaths);
|
||||||
/* !!! invalidatePath() will probably fail due to the foreign
|
|
||||||
key constraints on the Ref table. */
|
|
||||||
if (!isStorePath(*i)) {
|
|
||||||
printMsg(lvlError, format("path `%1%' is not in the Nix store") % *i);
|
|
||||||
invalidatePath(*i);
|
|
||||||
} else if (!pathExists(*i)) {
|
|
||||||
printMsg(lvlError, format("path `%1%' disappeared") % *i);
|
|
||||||
invalidatePath(*i);
|
|
||||||
} else validPaths.insert(*i);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Optionally, check the content hashes (slow). */
|
/* Optionally, check the content hashes (slow). */
|
||||||
if (checkContents) {
|
if (checkContents) {
|
||||||
printMsg(lvlInfo, "checking hashes");
|
printMsg(lvlInfo, "checking hashes...");
|
||||||
|
|
||||||
foreach (PathSet::iterator, i, validPaths) {
|
foreach (PathSet::iterator, i, validPaths) {
|
||||||
ValidPathInfo info = queryPathInfo(*i);
|
ValidPathInfo info = queryPathInfo(*i);
|
||||||
|
@ -1264,6 +1262,45 @@ void LocalStore::verifyStore(bool checkContents)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void LocalStore::verifyPath(const Path & path, const PathSet & store,
|
||||||
|
PathSet & done, PathSet & validPaths)
|
||||||
|
{
|
||||||
|
checkInterrupt();
|
||||||
|
|
||||||
|
if (done.find(path) != done.end()) return;
|
||||||
|
done.insert(path);
|
||||||
|
|
||||||
|
if (!isStorePath(path)) {
|
||||||
|
printMsg(lvlError, format("path `%1%' is not in the Nix store") % path);
|
||||||
|
invalidatePath(path);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (store.find(baseNameOf(path)) == store.end()) {
|
||||||
|
/* Check any referrers first. If we can invalidate them
|
||||||
|
first, then we can invalidate this path as well. */
|
||||||
|
bool canInvalidate = true;
|
||||||
|
PathSet referrers; queryReferrers(path, referrers);
|
||||||
|
foreach (PathSet::iterator, i, referrers)
|
||||||
|
if (*i != path) {
|
||||||
|
verifyPath(*i, store, done, validPaths);
|
||||||
|
if (validPaths.find(*i) != validPaths.end())
|
||||||
|
canInvalidate = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (canInvalidate) {
|
||||||
|
printMsg(lvlError, format("path `%1%' disappeared, removing from database...") % path);
|
||||||
|
invalidatePath(path);
|
||||||
|
} else
|
||||||
|
printMsg(lvlError, format("path `%1%' disappeared, but it still has valid referrers!") % path);
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
validPaths.insert(path);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/* Functions for upgrading from the pre-SQLite database. */
|
/* Functions for upgrading from the pre-SQLite database. */
|
||||||
|
|
||||||
PathSet LocalStore::queryValidPathsOld()
|
PathSet LocalStore::queryValidPathsOld()
|
||||||
|
|
|
@ -5,6 +5,7 @@
|
||||||
|
|
||||||
#include "store-api.hh"
|
#include "store-api.hh"
|
||||||
#include "util.hh"
|
#include "util.hh"
|
||||||
|
#include "pathlocks.hh"
|
||||||
|
|
||||||
|
|
||||||
class sqlite3;
|
class sqlite3;
|
||||||
|
@ -16,8 +17,8 @@ namespace nix {
|
||||||
|
|
||||||
/* Nix store and database schema version. Version 1 (or 0) was Nix <=
|
/* Nix store and database schema version. Version 1 (or 0) was Nix <=
|
||||||
0.7. Version 2 was Nix 0.8 and 0.9. Version 3 is Nix 0.10.
|
0.7. Version 2 was Nix 0.8 and 0.9. Version 3 is Nix 0.10.
|
||||||
Version 4 is Nix 0.11. Version 5 is Nix 0.12-0.14. Version 6 is
|
Version 4 is Nix 0.11. Version 5 is Nix 0.12-0.16. Version 6 is
|
||||||
Nix 0.15. */
|
Nix 1.0. */
|
||||||
const int nixSchemaVersion = 6;
|
const int nixSchemaVersion = 6;
|
||||||
|
|
||||||
|
|
||||||
|
@ -233,6 +234,9 @@ private:
|
||||||
|
|
||||||
void invalidatePath(const Path & path);
|
void invalidatePath(const Path & path);
|
||||||
|
|
||||||
|
void verifyPath(const Path & path, const PathSet & store,
|
||||||
|
PathSet & done, PathSet & validPaths);
|
||||||
|
|
||||||
void upgradeStore6();
|
void upgradeStore6();
|
||||||
PathSet queryValidPathsOld();
|
PathSet queryValidPathsOld();
|
||||||
ValidPathInfo queryPathInfoOld(const Path & path);
|
ValidPathInfo queryPathInfoOld(const Path & path);
|
||||||
|
@ -244,6 +248,8 @@ private:
|
||||||
bool isActiveTempFile(const GCState & state,
|
bool isActiveTempFile(const GCState & state,
|
||||||
const Path & path, const string & suffix);
|
const Path & path, const string & suffix);
|
||||||
|
|
||||||
|
int openGCLock(LockType lockType);
|
||||||
|
|
||||||
void startSubstituter(const Path & substituter,
|
void startSubstituter(const Path & substituter,
|
||||||
RunningSubstituter & runningSubstituter);
|
RunningSubstituter & runningSubstituter);
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue