* 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) {
throw Error( if (curSchema < 5)
"Your Nix store has a database in Berkeley DB format,\n" throw Error(
"which is no longer supported. To convert to the new format,\n" "Your Nix store has a database in Berkeley DB format,\n"
"please upgrade Nix to version 0.12 first."); "which is no longer supported. To convert to the new format,\n"
else if (curSchema < 6) upgradeStore6(); "please upgrade Nix to version 0.12 first.");
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)
{ {
/* 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" #include "schema.sql.hh"
if (sqlite3_exec(db, (const char *) schema, 0, 0, 0) != SQLITE_OK)
throw SQLiteError(db, "initialising database schema");
}
if (sqlite3_exec(db, (const char *) schema, 0, 0, 0) != SQLITE_OK) /* Prepare SQL statements. */
throw SQLiteError(db, "initialising database schema");
prepareStatements();
}
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);