about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--src/libstore/local-store.cc117
-rw-r--r--src/libstore/local-store.hh4
2 files changed, 62 insertions, 59 deletions
diff --git a/src/libstore/local-store.cc b/src/libstore/local-store.cc
index bfb253bc10..7e205a9bf2 100644
--- a/src/libstore/local-store.cc
+++ b/src/libstore/local-store.cc
@@ -205,52 +205,43 @@ LocalStore::LocalStore()
         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
-       upgrade.  !!! Race condition: several processes could start
-       the upgrade at the same time. */
+       upgrade.  */
     int curSchema = getSchema();
     if (curSchema > nixSchemaVersion)
         throw Error(format("current Nix store schema is version %1%, but I only support %2%")
             % curSchema % nixSchemaVersion);
-    if (curSchema == 0) { /* new store */
+    
+    else if (curSchema == 0) { /* new store */
         curSchema = nixSchemaVersion;
-        initSchema();
+        openDB(true);
+        writeFile(schemaPath, (format("%1%") % nixSchemaVersion).str());
+    }
+    
+    else if (curSchema < nixSchemaVersion) {
+        if (curSchema < 5)
+            throw Error(
+                "Your Nix store has a database in Berkeley DB format,\n"
+                "which is no longer supported. To convert to the new format,\n"
+                "please upgrade Nix to version 0.12 first.");
+        
+        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 if (curSchema == 1) throw Error("your Nix store is no longer supported");
-    else if (curSchema < 5)
-        throw Error(
-            "Your Nix store has a database in Berkeley DB format,\n"
-            "which is no longer supported. To convert to the new format,\n"
-            "please upgrade Nix to version 0.12 first.");
-    else if (curSchema < 6) upgradeStore6();
-    else prepareStatements();
+    
+    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_exec(db, (const char *) schema, 0, 0, 0) != SQLITE_OK)
-        throw SQLiteError(db, "initialising database schema");
+    if (sqlite3_busy_timeout(db, 60000) != SQLITE_OK)
+        throw SQLiteError(db, "setting timeout");
 
-    prepareStatements();
-}
+    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");
 
-void LocalStore::prepareStatements()
-{
+    /* Initialise the database schema, if necessary. */
+    if (create) {
+#include "schema.sql.hh"
+        if (sqlite3_exec(db, (const char *) schema, 0, 0, 0) != SQLITE_OK)
+            throw SQLiteError(db, "initialising database schema");
+    }
+
+    /* Prepare SQL statements. */
     stmtRegisterValidPath.create(db,
         "insert or replace into ValidPaths (path, hash, registrationTime, deriver) values (?, ?, ?, ?);");
     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). */
 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)...");
 
-    initSchema();
+    openDB(true);
 
     PathSet validPaths = queryValidPathsOld();
 
@@ -1256,10 +1265,6 @@ void LocalStore::upgradeStore6()
     std::cerr << "\n";
 
     txn.commit();
-
-    writeFile(schemaPath, (format("%1%") % nixSchemaVersion).str());
-
-    lockFile(globalLock, ltRead, true);
 }
 
 
diff --git a/src/libstore/local-store.hh b/src/libstore/local-store.hh
index 1e4080becd..0c5f04158e 100644
--- a/src/libstore/local-store.hh
+++ b/src/libstore/local-store.hh
@@ -209,9 +209,7 @@ private:
 
     int getSchema();
 
-    void initSchema();
-
-    void prepareStatements();
+    void openDB(bool create);
 
     unsigned long long queryValidPathId(const Path & path);