aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorEelco Dolstra <e.dolstra@tudelft.nl>2010-02-18 15:11:08 +0000
committerEelco Dolstra <e.dolstra@tudelft.nl>2010-02-18 15:11:08 +0000
commit885e22b16e3a6ea2a94014d33de31d756fa32eda (patch)
tree40a48e97e861c5d4e7ec7577de1e75420fcb3f02
parentcfb09e0fadf7db240f4f8c35c35c13b192456b89 (diff)
* Implement isValidPath().
-rw-r--r--src/libstore/local-store.cc244
-rw-r--r--src/libstore/local-store.hh15
2 files changed, 100 insertions, 159 deletions
diff --git a/src/libstore/local-store.cc b/src/libstore/local-store.cc
index ac6d768a0..05133ba55 100644
--- a/src/libstore/local-store.cc
+++ b/src/libstore/local-store.cc
@@ -54,6 +54,14 @@ void SQLiteStmt::create(sqlite3 * db, const string & s)
}
+void SQLiteStmt::reset()
+{
+ assert(stmt);
+ if (sqlite3_reset(stmt) != SQLITE_OK)
+ throw SQLiteError(db, "resetting statement");
+}
+
+
SQLiteStmt::~SQLiteStmt()
{
try {
@@ -188,14 +196,11 @@ LocalStore::LocalStore()
LocalStore::~LocalStore()
{
try {
- flushDelayedUpdates();
-
foreach (RunningSubstituters::iterator, i, runningSubstituters) {
i->second.to.close();
i->second.from.close();
i->second.pid.wait(true);
}
-
} catch (...) {
ignoreException();
}
@@ -231,6 +236,7 @@ void LocalStore::prepareStatements()
"insert into ValidPaths (path, hash, registrationTime, deriver) values (?, ?, ?, ?);");
stmtAddReference.create(db,
"insert into Refs (referrer, reference) values (?, ?);");
+ stmtIsValidPath.create(db, "select 1 from ValidPaths where path = ?;");
}
@@ -308,98 +314,6 @@ void canonicalisePathMetaData(const Path & path)
}
-static Path infoFileFor(const Path & path)
-{
- string baseName = baseNameOf(path);
- return (format("%1%/info/%2%") % nixDBPath % baseName).str();
-}
-
-
-static Path referrersFileFor(const Path & path)
-{
- string baseName = baseNameOf(path);
- return (format("%1%/referrer/%2%") % nixDBPath % baseName).str();
-}
-
-
-static Path failedFileFor(const Path & path)
-{
- string baseName = baseNameOf(path);
- return (format("%1%/failed/%2%") % nixDBPath % baseName).str();
-}
-
-
-static Path tmpFileForAtomicUpdate(const Path & path)
-{
- return (format("%1%/.%2%.%3%") % dirOf(path) % getpid() % baseNameOf(path)).str();
-}
-
-
-void LocalStore::appendReferrer(const Path & from, const Path & to, bool lock)
-{
- Path referrersFile = referrersFileFor(from);
-
- PathLocks referrersLock;
- if (lock) {
- referrersLock.lockPaths(singleton<PathSet, Path>(referrersFile));
- referrersLock.setDeletion(true);
- }
-
- AutoCloseFD fd = open(referrersFile.c_str(), O_WRONLY | O_APPEND | O_CREAT, 0666);
- if (fd == -1) throw SysError(format("opening file `%1%'") % referrersFile);
-
- string s = " " + to;
- writeFull(fd, (const unsigned char *) s.c_str(), s.size());
-
- if (doFsync) fdatasync(fd);
-}
-
-
-/* Atomically update the referrers file. If `purge' is true, the set
- of referrers is set to `referrers'. Otherwise, the current set of
- referrers is purged of invalid paths. */
-void LocalStore::rewriteReferrers(const Path & path, bool purge, PathSet referrers)
-{
- Path referrersFile = referrersFileFor(path);
-
- PathLocks referrersLock(singleton<PathSet, Path>(referrersFile));
- referrersLock.setDeletion(true);
-
- if (purge)
- /* queryReferrers() purges invalid paths, so that's all we
- need. */
- queryReferrers(path, referrers);
-
- Path tmpFile = tmpFileForAtomicUpdate(referrersFile);
-
- AutoCloseFD fd = open(tmpFile.c_str(), O_WRONLY | O_TRUNC | O_CREAT, 0666);
- if (fd == -1) throw SysError(format("opening file `%1%'") % referrersFile);
-
- string s;
- foreach (PathSet::const_iterator, i, referrers) {
- s += " "; s += *i;
- }
-
- writeFull(fd, (const unsigned char *) s.c_str(), s.size());
-
- if (doFsync) fdatasync(fd);
-
- fd.close(); /* for Windows; can't rename open file */
-
- if (rename(tmpFile.c_str(), referrersFile.c_str()) == -1)
- throw SysError(format("cannot rename `%1%' to `%2%'") % tmpFile % referrersFile);
-}
-
-
-void LocalStore::flushDelayedUpdates()
-{
- foreach (PathSet::iterator, i, delayedUpdates) {
- rewriteReferrers(*i, true, PathSet());
- }
- delayedUpdates.clear();
-}
-
-
void LocalStore::registerValidPath(const Path & path,
const Hash & hash, const PathSet & references,
const Path & deriver)
@@ -415,6 +329,7 @@ void LocalStore::registerValidPath(const Path & path,
void LocalStore::registerValidPath(const ValidPathInfo & info, bool ignoreValidity)
{
+#if 0
Path infoFile = infoFileFor(info.path);
ValidPathInfo oldInfo;
@@ -467,22 +382,25 @@ void LocalStore::registerValidPath(const ValidPathInfo & info, bool ignoreValidi
writeFile(tmpFile, s, doFsync);
if (rename(tmpFile.c_str(), infoFile.c_str()) == -1)
throw SysError(format("cannot rename `%1%' to `%2%'") % tmpFile % infoFile);
-
- pathInfoCache[info.path] = info;
+#endif
}
void LocalStore::registerFailedPath(const Path & path)
{
+#if 0
/* Write an empty file in the .../failed directory to denote the
failure of the builder for `path'. */
writeFile(failedFileFor(path), "");
+#endif
}
bool LocalStore::hasPathFailed(const Path & path)
{
+#if 0
return pathExists(failedFileFor(path));
+#endif
}
@@ -502,6 +420,7 @@ Hash parseHashField(const Path & path, const string & s)
ValidPathInfo LocalStore::queryPathInfo(const Path & path, bool ignoreErrors)
{
+#if 0
ValidPathInfo res;
res.path = path;
@@ -510,9 +429,6 @@ ValidPathInfo LocalStore::queryPathInfo(const Path & path, bool ignoreErrors)
if (!isValidPath(path))
throw Error(format("path `%1%' is not valid") % path);
- std::map<Path, ValidPathInfo>::iterator lookup = pathInfoCache.find(path);
- if (lookup != pathInfoCache.end()) return lookup->second;
-
/* Read the info file. */
Path infoFile = infoFileFor(path);
if (!pathExists(infoFile))
@@ -550,31 +466,20 @@ ValidPathInfo LocalStore::queryPathInfo(const Path & path, bool ignoreErrors)
}
}
- return pathInfoCache[path] = res;
+ return res;
+#endif
}
bool LocalStore::isValidPath(const Path & path)
{
- /* Files in the info directory starting with a `.' are temporary
- files. */
- if (baseNameOf(path).at(0) == '.') return false;
-
- /* A path is valid if its info file exists and has a non-zero
- size. (The non-zero size restriction is to be robust to
- certain kinds of filesystem corruption, particularly with
- ext4.) */
- Path infoFile = infoFileFor(path);
-
- struct stat st;
- if (lstat(infoFile.c_str(), &st)) {
- if (errno == ENOENT) return false;
- throw SysError(format("getting status of `%1%'") % infoFile);
- }
-
- if (st.st_size == 0) return false;
-
- return true;
+ stmtIsValidPath.reset();
+ if (sqlite3_bind_text(stmtIsValidPath, 1, path.c_str(), -1, SQLITE_TRANSIENT) != SQLITE_OK)
+ throw SQLiteError(db, "binding argument");
+ int res = sqlite3_step(stmtIsValidPath);
+ if (res != SQLITE_DONE && res != SQLITE_ROW)
+ throw SQLiteError(db, "querying path in database");
+ return res == SQLITE_ROW;
}
@@ -598,6 +503,7 @@ void LocalStore::queryReferences(const Path & path,
bool LocalStore::queryReferrersInternal(const Path & path, PathSet & referrers)
{
+#if 0
bool allValid = true;
if (!isValidPath(path))
@@ -623,6 +529,7 @@ bool LocalStore::queryReferrersInternal(const Path & path, PathSet & referrers)
if (isStorePath(*i) && isValidPath(*i)) referrers.insert(*i); else allValid = false;
return allValid;
+#endif
}
@@ -788,6 +695,7 @@ void LocalStore::registerValidPaths(const ValidPathInfos & infos)
there are no referrers. */
void LocalStore::invalidatePath(const Path & path)
{
+#if 0
debug(format("invalidating path `%1%'") % path);
ValidPathInfo info;
@@ -805,28 +713,7 @@ void LocalStore::invalidatePath(const Path & path)
Path p = referrersFileFor(path);
if (pathExists(p) && unlink(p.c_str()) == -1)
throw SysError(format("unlinking `%1%'") % p);
-
- /* Clear `path' from the info cache. */
- pathInfoCache.erase(path);
- delayedUpdates.erase(path);
-
- /* Cause the referrer files for each path referenced by this one
- to be updated. This has to happen after removing the info file
- to preserve the invariant (see registerValidPath()).
-
- The referrer files are updated lazily in flushDelayedUpdates()
- to prevent quadratic performance in the garbage collector
- (i.e., when N referrers to some path X are deleted, we have to
- rewrite the referrers file for X N times, causing O(N^2) I/O).
-
- What happens if we die before the referrer file can be updated?
- That's not a problem, because stale (invalid) entries in the
- referrer file are ignored by queryReferrers(). Thus a referrer
- file is allowed to have stale entries; removing them is just an
- optimisation. verifyStore() gets rid of them eventually.
- */
- foreach (PathSet::iterator, i, info.references)
- if (*i != path) delayedUpdates.insert(*i);
+#endif
}
@@ -1130,6 +1017,7 @@ Path LocalStore::importPath(bool requireSignature, Source & source)
void LocalStore::deleteFromStore(const Path & path, unsigned long long & bytesFreed,
unsigned long long & blocksFreed)
{
+#if 0
bytesFreed = 0;
assertStorePath(path);
@@ -1149,11 +1037,13 @@ void LocalStore::deleteFromStore(const Path & path, unsigned long long & bytesFr
}
deletePathWrapped(path, bytesFreed, blocksFreed);
+#endif
}
void LocalStore::verifyStore(bool checkContents)
{
+#if 0
/* Check whether all valid paths actually exist. */
printMsg(lvlInfo, "checking path existence");
@@ -1279,6 +1169,64 @@ void LocalStore::verifyStore(bool checkContents)
if (update) rewriteReferrers(from, false, referrersNew);
}
+#endif
+}
+
+
+/* Functions for upgrading from the pre-SQLite database. */
+
+static Path infoFileFor(const Path & path)
+{
+ string baseName = baseNameOf(path);
+ return (format("%1%/info/%2%") % nixDBPath % baseName).str();
+}
+
+
+PathSet LocalStore::queryValidPathsOld()
+{
+ PathSet paths;
+ Strings entries = readDirectory(nixDBPath + "/info");
+ foreach (Strings::iterator, i, entries)
+ if (i->at(0) != '.') paths.insert(nixStore + "/" + *i);
+ return paths;
+}
+
+
+ValidPathInfo LocalStore::queryPathInfoOld(const Path & path)
+{
+ ValidPathInfo res;
+ res.path = path;
+
+ /* Read the info file. */
+ Path infoFile = infoFileFor(path);
+ if (!pathExists(infoFile))
+ throw Error(format("path `%1%' is not valid") % path);
+ string info = readFile(infoFile);
+
+ /* Parse it. */
+ Strings lines = tokenizeString(info, "\n");
+
+ foreach (Strings::iterator, i, lines) {
+ string::size_type p = i->find(':');
+ if (p == string::npos)
+ throw Error(format("corrupt line in `%1%': %2%") % infoFile % *i);
+ string name(*i, 0, p);
+ string value(*i, p + 2);
+ if (name == "References") {
+ Strings refs = tokenizeString(value, " ");
+ res.references = PathSet(refs.begin(), refs.end());
+ } else if (name == "Deriver") {
+ res.deriver = value;
+ } else if (name == "Hash") {
+ res.hash = parseHashField(path, value);
+ } else if (name == "Registered-At") {
+ int n = 0;
+ string2Int(value, n);
+ res.registrationTime = n;
+ }
+ }
+
+ return res;
}
@@ -1294,17 +1242,16 @@ void LocalStore::upgradeStore6()
initSchema();
- PathSet validPaths = queryValidPaths();
+ PathSet validPaths = queryValidPathsOld();
SQLiteTxn txn(db);
std::map<Path, sqlite3_int64> pathToId;
foreach (PathSet::iterator, i, validPaths) {
- ValidPathInfo info = queryPathInfo(*i, true);
+ ValidPathInfo info = queryPathInfoOld(*i);
- if (sqlite3_reset(stmtRegisterValidPath) != SQLITE_OK)
- throw SQLiteError(db, "resetting statement");
+ stmtRegisterValidPath.reset();
if (sqlite3_bind_text(stmtRegisterValidPath, 1, i->c_str(), -1, SQLITE_TRANSIENT) != SQLITE_OK)
throw SQLiteError(db, "binding argument 1");
string h = "sha256:" + printHash(info.hash);
@@ -1330,11 +1277,10 @@ void LocalStore::upgradeStore6()
std::cerr << "|";
foreach (PathSet::iterator, i, validPaths) {
- ValidPathInfo info = queryPathInfo(*i, true);
+ ValidPathInfo info = queryPathInfoOld(*i);
foreach (PathSet::iterator, j, info.references) {
- if (sqlite3_reset(stmtAddReference) != SQLITE_OK)
- throw SQLiteError(db, "resetting statement");
+ stmtAddReference.reset();
if (sqlite3_bind_int(stmtAddReference, 1, pathToId[*i]) != SQLITE_OK)
throw SQLiteError(db, "binding argument 1");
if (pathToId.find(*j) == pathToId.end())
diff --git a/src/libstore/local-store.hh b/src/libstore/local-store.hh
index 3637a5d07..fe4ed035d 100644
--- a/src/libstore/local-store.hh
+++ b/src/libstore/local-store.hh
@@ -63,6 +63,7 @@ struct SQLiteStmt
sqlite3_stmt * stmt;
SQLiteStmt() { stmt = 0; }
void create(sqlite3 * db, const string & s);
+ void reset();
~SQLiteStmt();
operator sqlite3_stmt * () { return stmt; }
};
@@ -178,13 +179,6 @@ private:
/* Lock file used for upgrading. */
AutoCloseFD globalLock;
- /* !!! The cache can grow very big. Maybe it should be pruned
- every once in a while. */
- std::map<Path, ValidPathInfo> pathInfoCache;
-
- /* Store paths for which the referrers file must be purged. */
- PathSet delayedUpdates;
-
/* Whether to do an fsync() after writing Nix metadata. */
bool doFsync;
@@ -194,6 +188,7 @@ private:
/* Some precompiled SQLite statements. */
SQLiteStmt stmtRegisterValidPath;
SQLiteStmt stmtAddReference;
+ SQLiteStmt stmtIsValidPath;
int getSchema();
@@ -209,13 +204,13 @@ private:
void rewriteReferrers(const Path & path, bool purge, PathSet referrers);
- void flushDelayedUpdates();
-
bool queryReferrersInternal(const Path & path, PathSet & referrers);
void invalidatePath(const Path & path);
-
+
void upgradeStore6();
+ PathSet queryValidPathsOld();
+ ValidPathInfo queryPathInfoOld(const Path & path);
struct GCState;