* Refactor the upgrade / database initialisation logic a bit.

This commit is contained in:
Eelco Dolstra 2010-02-24 16:30:20 +00:00
parent cfe742cfc5
commit e33f67ff0b
2 changed files with 64 additions and 61 deletions

View file

@ -205,52 +205,43 @@ LocalStore::LocalStore()
lockFile(globalLock, ltRead, true); lockFile(globalLock, ltRead, true);
} }
/* Open the Nix database. */
if (sqlite3_open_v2((nixDBPath + "/db.sqlite").c_str(), &db.db,
SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE, 0) != SQLITE_OK)
throw Error("cannot open SQLite database");
if (sqlite3_busy_timeout(db, 60000) != SQLITE_OK)
throw SQLiteError(db, "setting timeout");
if (sqlite3_exec(db, "pragma foreign_keys = 1;", 0, 0, 0) != SQLITE_OK)
throw SQLiteError(db, "enabling foreign keys");
/* !!! check whether sqlite has been built with foreign key
support */
/* Whether SQLite should fsync(). "Normal" synchronous mode
should be safe enough. If the user asks for it, don't sync at
all. This can cause database corruption if the system
crashes. */
string syncMode = queryBoolSetting("fsync-metadata", true) ? "normal" : "off";
if (sqlite3_exec(db, ("pragma synchronous = " + syncMode + ";").c_str(), 0, 0, 0) != SQLITE_OK)
throw SQLiteError(db, "setting synchronous mode");
/* Use `truncate' journal mode, which should be a bit faster. */
if (sqlite3_exec(db, "pragma main.journal_mode = truncate;", 0, 0, 0) != SQLITE_OK)
throw SQLiteError(db, "setting journal mode");
/* Check the current database schema and if necessary do an /* Check the current database schema and if necessary do an
upgrade. !!! Race condition: several processes could start upgrade. */
the upgrade at the same time. */
int curSchema = getSchema(); int curSchema = getSchema();
if (curSchema > nixSchemaVersion) if (curSchema > nixSchemaVersion)
throw Error(format("current Nix store schema is version %1%, but I only support %2%") throw Error(format("current Nix store schema is version %1%, but I only support %2%")
% curSchema % nixSchemaVersion); % curSchema % nixSchemaVersion);
if (curSchema == 0) { /* new store */
else if (curSchema == 0) { /* new store */
curSchema = nixSchemaVersion; curSchema = nixSchemaVersion;
initSchema(); openDB(true);
writeFile(schemaPath, (format("%1%") % nixSchemaVersion).str()); writeFile(schemaPath, (format("%1%") % nixSchemaVersion).str());
} }
else if (curSchema == 1) throw Error("your Nix store is no longer supported");
else if (curSchema < 5) else if (curSchema < nixSchemaVersion) {
if (curSchema < 5)
throw Error( throw Error(
"Your Nix store has a database in Berkeley DB format,\n" "Your Nix store has a database in Berkeley DB format,\n"
"which is no longer supported. To convert to the new format,\n" "which is no longer supported. To convert to the new format,\n"
"please upgrade Nix to version 0.12 first."); "please upgrade Nix to version 0.12 first.");
else if (curSchema < 6) upgradeStore6();
else prepareStatements(); if (!lockFile(globalLock, ltWrite, false)) {
printMsg(lvlError, "waiting for exclusive access to the Nix store...");
lockFile(globalLock, ltWrite, true);
}
/* Get the schema version again, because another process may
have performed the upgrade already. */
curSchema = getSchema();
if (curSchema < 6) upgradeStore6();
writeFile(schemaPath, (format("%1%") % nixSchemaVersion).str());
lockFile(globalLock, ltRead, true);
}
else openDB(false);
} }
@ -280,19 +271,42 @@ int LocalStore::getSchema()
} }
void LocalStore::initSchema() void LocalStore::openDB(bool create)
{ {
#include "schema.sql.hh" /* Open the Nix database. */
if (sqlite3_open_v2((nixDBPath + "/db.sqlite").c_str(), &db.db,
SQLITE_OPEN_READWRITE | (create ? SQLITE_OPEN_CREATE : 0), 0) != SQLITE_OK)
throw Error("cannot open SQLite database");
if (sqlite3_busy_timeout(db, 60000) != SQLITE_OK)
throw SQLiteError(db, "setting timeout");
if (sqlite3_exec(db, "pragma foreign_keys = 1;", 0, 0, 0) != SQLITE_OK)
throw SQLiteError(db, "enabling foreign keys");
/* !!! check whether sqlite has been built with foreign key
support */
/* Whether SQLite should fsync(). "Normal" synchronous mode
should be safe enough. If the user asks for it, don't sync at
all. This can cause database corruption if the system
crashes. */
string syncMode = queryBoolSetting("fsync-metadata", true) ? "normal" : "off";
if (sqlite3_exec(db, ("pragma synchronous = " + syncMode + ";").c_str(), 0, 0, 0) != SQLITE_OK)
throw SQLiteError(db, "setting synchronous mode");
/* Use `truncate' journal mode, which should be a bit faster. */
if (sqlite3_exec(db, "pragma main.journal_mode = truncate;", 0, 0, 0) != SQLITE_OK)
throw SQLiteError(db, "setting journal mode");
/* Initialise the database schema, if necessary. */
if (create) {
#include "schema.sql.hh"
if (sqlite3_exec(db, (const char *) schema, 0, 0, 0) != SQLITE_OK) if (sqlite3_exec(db, (const char *) schema, 0, 0, 0) != SQLITE_OK)
throw SQLiteError(db, "initialising database schema"); throw SQLiteError(db, "initialising database schema");
prepareStatements();
} }
/* Prepare SQL statements. */
void LocalStore::prepareStatements()
{
stmtRegisterValidPath.create(db, stmtRegisterValidPath.create(db,
"insert or replace into ValidPaths (path, hash, registrationTime, deriver) values (?, ?, ?, ?);"); "insert or replace into ValidPaths (path, hash, registrationTime, deriver) values (?, ?, ?, ?);");
stmtAddReference.create(db, stmtAddReference.create(db,
@ -1225,14 +1239,9 @@ ValidPathInfo LocalStore::queryPathInfoOld(const Path & path)
/* Upgrade from schema 5 (Nix 0.12) to schema 6 (Nix >= 0.15). */ /* Upgrade from schema 5 (Nix 0.12) to schema 6 (Nix >= 0.15). */
void LocalStore::upgradeStore6() void LocalStore::upgradeStore6()
{ {
if (!lockFile(globalLock, ltWrite, false)) {
printMsg(lvlError, "waiting for exclusive access to the Nix store...");
lockFile(globalLock, ltWrite, true);
}
printMsg(lvlError, "upgrading Nix store to new schema (this may take a while)..."); printMsg(lvlError, "upgrading Nix store to new schema (this may take a while)...");
initSchema(); openDB(true);
PathSet validPaths = queryValidPathsOld(); PathSet validPaths = queryValidPathsOld();
@ -1256,10 +1265,6 @@ void LocalStore::upgradeStore6()
std::cerr << "\n"; std::cerr << "\n";
txn.commit(); txn.commit();
writeFile(schemaPath, (format("%1%") % nixSchemaVersion).str());
lockFile(globalLock, ltRead, true);
} }

View file

@ -209,9 +209,7 @@ private:
int getSchema(); int getSchema();
void initSchema(); void openDB(bool create);
void prepareStatements();
unsigned long long queryValidPathId(const Path & path); unsigned long long queryValidPathId(const Path & path);