mirror of
https://github.com/NixOS/nix.git
synced 2025-11-26 04:00:59 +01:00
* Conversion to a BDB-free store. Meta-information for each valid
path (content hash, references, deriver) is now stored in /nix/var/nix/db/meta/<base-path>.info. The referrers are stored separately in /nix/var/nix/db/meta/<base-path>.referrers. This is done because the referrers can change, which the info file is in principle immutable. The referrers must also be updated efficiently to prevent a regression of NIX-23 (quadratic complexity updating the referrers during garbage collection). This is just the conversion code, the rest of the code still uses BDB.
This commit is contained in:
parent
f5e6c9bcfd
commit
91313011f9
2 changed files with 90 additions and 14 deletions
|
|
@ -16,6 +16,7 @@
|
||||||
#include <sys/stat.h>
|
#include <sys/stat.h>
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
#include <utime.h>
|
#include <utime.h>
|
||||||
|
#include <fcntl.h> // !!! remove
|
||||||
|
|
||||||
|
|
||||||
namespace nix {
|
namespace nix {
|
||||||
|
|
@ -58,6 +59,7 @@ static TableId dbDerivers = 0;
|
||||||
|
|
||||||
static void upgradeStore09();
|
static void upgradeStore09();
|
||||||
static void upgradeStore11();
|
static void upgradeStore11();
|
||||||
|
static void upgradeStore12();
|
||||||
|
|
||||||
|
|
||||||
void checkStoreNotSymlink()
|
void checkStoreNotSymlink()
|
||||||
|
|
@ -133,6 +135,7 @@ LocalStore::LocalStore(bool reserveSpace)
|
||||||
throw Error("your Nix store is no longer supported");
|
throw Error("your Nix store is no longer supported");
|
||||||
if (curSchema <= 2) upgradeStore09();
|
if (curSchema <= 2) upgradeStore09();
|
||||||
if (curSchema <= 3) upgradeStore11();
|
if (curSchema <= 3) upgradeStore11();
|
||||||
|
if (curSchema <= 4) upgradeStore12();
|
||||||
writeFile(schemaFN, (format("%1%") % nixSchemaVersion).str());
|
writeFile(schemaFN, (format("%1%") % nixSchemaVersion).str());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -328,7 +331,7 @@ void setReferences(const Transaction & txn, const Path & storePath,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void queryReferences(const Transaction & txn,
|
void oldQueryReferences(const Transaction & txn,
|
||||||
const Path & storePath, PathSet & references)
|
const Path & storePath, PathSet & references)
|
||||||
{
|
{
|
||||||
Paths references2;
|
Paths references2;
|
||||||
|
|
@ -342,7 +345,7 @@ void queryReferences(const Transaction & txn,
|
||||||
void LocalStore::queryReferences(const Path & storePath,
|
void LocalStore::queryReferences(const Path & storePath,
|
||||||
PathSet & references)
|
PathSet & references)
|
||||||
{
|
{
|
||||||
nix::queryReferences(noTxn, storePath, references);
|
oldQueryReferences(noTxn, storePath, references);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -375,7 +378,7 @@ void setDeriver(const Transaction & txn, const Path & storePath,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
static Path queryDeriver(const Transaction & txn, const Path & storePath)
|
static Path oldQueryDeriver(const Transaction & txn, const Path & storePath)
|
||||||
{
|
{
|
||||||
if (!isValidPathTxn(txn, storePath))
|
if (!isValidPathTxn(txn, storePath))
|
||||||
throw Error(format("path `%1%' is not valid") % storePath);
|
throw Error(format("path `%1%' is not valid") % storePath);
|
||||||
|
|
@ -389,7 +392,7 @@ static Path queryDeriver(const Transaction & txn, const Path & storePath)
|
||||||
|
|
||||||
Path LocalStore::queryDeriver(const Path & path)
|
Path LocalStore::queryDeriver(const Path & path)
|
||||||
{
|
{
|
||||||
return nix::queryDeriver(noTxn, path);
|
return oldQueryDeriver(noTxn, path);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -423,7 +426,7 @@ bool LocalStore::hasSubstitutes(const Path & path)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
static void setHash(const Transaction & txn, const Path & storePath,
|
static void oldSetHash(const Transaction & txn, const Path & storePath,
|
||||||
const Hash & hash)
|
const Hash & hash)
|
||||||
{
|
{
|
||||||
assert(hash.type == htSHA256);
|
assert(hash.type == htSHA256);
|
||||||
|
|
@ -431,7 +434,7 @@ static void setHash(const Transaction & txn, const Path & storePath,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
static Hash queryHash(const Transaction & txn, const Path & storePath)
|
static Hash oldQueryHash(const Transaction & txn, const Path & storePath)
|
||||||
{
|
{
|
||||||
string s;
|
string s;
|
||||||
nixDB.queryString(txn, dbValidPaths, storePath, s);
|
nixDB.queryString(txn, dbValidPaths, storePath, s);
|
||||||
|
|
@ -451,7 +454,7 @@ Hash LocalStore::queryPathHash(const Path & path)
|
||||||
{
|
{
|
||||||
if (!isValidPath(path))
|
if (!isValidPath(path))
|
||||||
throw Error(format("path `%1%' is not valid") % path);
|
throw Error(format("path `%1%' is not valid") % path);
|
||||||
return queryHash(noTxn, path);
|
return oldQueryHash(noTxn, path);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -484,7 +487,7 @@ void registerValidPaths(const Transaction & txn,
|
||||||
assertStorePath(i->path);
|
assertStorePath(i->path);
|
||||||
|
|
||||||
debug(format("registering path `%1%'") % i->path);
|
debug(format("registering path `%1%'") % i->path);
|
||||||
setHash(txn, i->path, i->hash);
|
oldSetHash(txn, i->path, i->hash);
|
||||||
|
|
||||||
setReferences(txn, i->path, i->references);
|
setReferences(txn, i->path, i->references);
|
||||||
|
|
||||||
|
|
@ -834,7 +837,7 @@ void verifyStore(bool checkContents)
|
||||||
} else {
|
} else {
|
||||||
if (checkContents) {
|
if (checkContents) {
|
||||||
debug(format("checking contents of `%1%'") % *i);
|
debug(format("checking contents of `%1%'") % *i);
|
||||||
Hash expected = queryHash(txn, *i);
|
Hash expected = oldQueryHash(txn, *i);
|
||||||
Hash current = hashPath(expected.type, *i);
|
Hash current = hashPath(expected.type, *i);
|
||||||
if (current != expected) {
|
if (current != expected) {
|
||||||
printMsg(lvlError, format("path `%1%' was modified! "
|
printMsg(lvlError, format("path `%1%' was modified! "
|
||||||
|
|
@ -864,7 +867,7 @@ void verifyStore(bool checkContents)
|
||||||
nixDB.delPair(txn, dbDerivers, *i);
|
nixDB.delPair(txn, dbDerivers, *i);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
Path deriver = queryDeriver(txn, *i);
|
Path deriver = oldQueryDeriver(txn, *i);
|
||||||
if (!isStorePath(deriver)) {
|
if (!isStorePath(deriver)) {
|
||||||
printMsg(lvlError, format("removing corrupt deriver `%1%' for `%2%'")
|
printMsg(lvlError, format("removing corrupt deriver `%1%' for `%2%'")
|
||||||
% deriver % *i);
|
% deriver % *i);
|
||||||
|
|
@ -888,7 +891,7 @@ void verifyStore(bool checkContents)
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
PathSet references;
|
PathSet references;
|
||||||
queryReferences(txn, *i, references);
|
oldQueryReferences(txn, *i, references);
|
||||||
for (PathSet::iterator j = references.begin();
|
for (PathSet::iterator j = references.begin();
|
||||||
j != references.end(); ++j)
|
j != references.end(); ++j)
|
||||||
{
|
{
|
||||||
|
|
@ -936,7 +939,7 @@ void verifyStore(bool checkContents)
|
||||||
|
|
||||||
else {
|
else {
|
||||||
PathSet references;
|
PathSet references;
|
||||||
queryReferences(txn, from, references);
|
oldQueryReferences(txn, from, references);
|
||||||
if (find(references.begin(), references.end(), to) == references.end()) {
|
if (find(references.begin(), references.end(), to) == references.end()) {
|
||||||
printMsg(lvlError, format("adding missing referrer mapping from `%1%' to `%2%'")
|
printMsg(lvlError, format("adding missing referrer mapping from `%1%' to `%2%'")
|
||||||
% from % to);
|
% from % to);
|
||||||
|
|
@ -1144,4 +1147,77 @@ static void upgradeStore11()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
Path metaFileFor(const Path & path)
|
||||||
|
{
|
||||||
|
string baseName = baseNameOf(path);
|
||||||
|
return (format("%1%/meta/%2%") % nixDBPath % baseName).str();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* !!! move to util.cc */
|
||||||
|
void appendFile(const Path & path, const string & s)
|
||||||
|
{
|
||||||
|
AutoCloseFD fd = open(path.c_str(), O_WRONLY | O_APPEND | O_CREAT, 0666);
|
||||||
|
if (fd == -1)
|
||||||
|
throw SysError(format("opening file `%1%'") % path);
|
||||||
|
writeFull(fd, (unsigned char *) s.c_str(), s.size());
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void newRegisterValidPath(const Path & path,
|
||||||
|
const Hash & hash, const PathSet & references,
|
||||||
|
const Path & deriver)
|
||||||
|
{
|
||||||
|
Path infoFile = metaFileFor(path) + ".info";
|
||||||
|
|
||||||
|
string refs;
|
||||||
|
for (PathSet::const_iterator i = references.begin(); i != references.end(); ++i) {
|
||||||
|
if (!refs.empty()) refs += " ";
|
||||||
|
refs += *i;
|
||||||
|
|
||||||
|
/* Update the referrer mapping for *i. This must be done
|
||||||
|
before the info file is written to maintain the invariant
|
||||||
|
that if `path' is a valid path, then all its references
|
||||||
|
have referrer mappings back to `path'. A " " is prefixed
|
||||||
|
to separate it from the previous entry. It's not suffixed
|
||||||
|
to deal with interrupted partial writes to this file. */
|
||||||
|
Path referrersFile = metaFileFor(*i) + ".referrers";
|
||||||
|
/* !!! locking */
|
||||||
|
appendFile(referrersFile, " " + path);
|
||||||
|
}
|
||||||
|
|
||||||
|
string info = (format(
|
||||||
|
"Hash: sha256:%1%\n"
|
||||||
|
"References: %2%\n"
|
||||||
|
"Deriver: %3%\n"
|
||||||
|
"Registered-At: %4%\n")
|
||||||
|
% printHash(hash) % refs % deriver % time(0)).str();
|
||||||
|
|
||||||
|
// !!! atomicity
|
||||||
|
writeFile(infoFile, info);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* Upgrade from schema 4 (Nix 0.11) to schema 5 (Nix >= 0.12). The
|
||||||
|
old schema uses Berkeley DB, the new one stores store path
|
||||||
|
meta-information in files. */
|
||||||
|
static void upgradeStore12()
|
||||||
|
{
|
||||||
|
printMsg(lvlError, "upgrading Nix store to new schema (this may take a while)...");
|
||||||
|
|
||||||
|
Paths validPaths;
|
||||||
|
nixDB.enumTable(noTxn, dbValidPaths, validPaths);
|
||||||
|
|
||||||
|
for (Paths::iterator i = validPaths.begin(); i != validPaths.end(); ++i) {
|
||||||
|
Hash hash = oldQueryHash(noTxn, *i);
|
||||||
|
PathSet references; oldQueryReferences(noTxn, *i, references);
|
||||||
|
Path deriver = oldQueryDeriver(noTxn, *i);
|
||||||
|
newRegisterValidPath(*i, hash, references, deriver);
|
||||||
|
std::cerr << ".";
|
||||||
|
}
|
||||||
|
|
||||||
|
std::cerr << std::endl;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -14,8 +14,8 @@ class Transaction;
|
||||||
|
|
||||||
/* 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 4 is Nix 0.11. Version 5 is Nix 0.12*/
|
||||||
const int nixSchemaVersion = 4;
|
const int nixSchemaVersion = 5;
|
||||||
|
|
||||||
|
|
||||||
extern string drvsLogDir;
|
extern string drvsLogDir;
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue