summary refs log tree commit diff
path: root/src/libstore/local-store.cc
diff options
context:
space:
mode:
Diffstat (limited to 'src/libstore/local-store.cc')
-rw-r--r--src/libstore/local-store.cc119
1 files changed, 107 insertions, 12 deletions
diff --git a/src/libstore/local-store.cc b/src/libstore/local-store.cc
index 7c8db745cb..55637dd859 100644
--- a/src/libstore/local-store.cc
+++ b/src/libstore/local-store.cc
@@ -22,6 +22,16 @@
 namespace nix {
 
     
+class SQLiteError : public Error
+{
+public:
+    SQLiteError(sqlite3 * db, const format & f)
+        : Error(format("%1%: %2%") % f.str() % sqlite3_errmsg(db))
+    {
+    }
+};
+
+
 void checkStoreNotSymlink()
 {
     if (getEnv("NIX_IGNORE_SYMLINK_STORE") == "1") return;
@@ -42,6 +52,7 @@ void checkStoreNotSymlink()
 
 LocalStore::LocalStore()
 {
+    db = 0;
     substitutablePathsLoaded = false;
     
     schemaPath = nixDBPath + "/schema";
@@ -50,9 +61,6 @@ LocalStore::LocalStore()
 
     /* Create missing state directories if they don't already exist. */
     createDirs(nixStore);
-    createDirs(nixDBPath + "/info");
-    createDirs(nixDBPath + "/referrer");
-    createDirs(nixDBPath + "/failed");
     Path profilesDir = nixStateDir + "/profiles";
     createDirs(nixStateDir + "/profiles");
     createDirs(nixStateDir + "/temproots");
@@ -88,7 +96,12 @@ LocalStore::LocalStore()
         writeFile(schemaPath, (format("%1%") % nixSchemaVersion).str());
     }
     if (curSchema == 1) throw Error("your Nix store is no longer supported");
-    if (curSchema < nixSchemaVersion) upgradeStore12();
+    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 (curSchema < 6) upgradeStore6();
 
     doFsync = queryBoolSetting("fsync-metadata", false);
 }
@@ -99,6 +112,9 @@ LocalStore::~LocalStore()
     try {
         flushDelayedUpdates();
 
+        if (db && sqlite3_close(db) != SQLITE_OK)
+            throw SQLiteError(db, "closing database");
+
         foreach (RunningSubstituters::iterator, i, runningSubstituters) {
             i->second.to.close();
             i->second.from.close();
@@ -123,6 +139,22 @@ int LocalStore::getSchema()
 }
 
 
+#include "schema.sql.hh"
+
+void LocalStore::initSchema()
+{
+    if (sqlite3_open_v2((nixDBPath + "/db.sqlite").c_str(), &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, "sett");
+    
+    if (sqlite3_exec(db, (const char *) schema, 0, 0, 0) != SQLITE_OK)
+        throw SQLiteError(db, "initialising database schema");
+}
+
+
 void canonicalisePathMetaData(const Path & path, bool recurse)
 {
     checkInterrupt();
@@ -1171,15 +1203,78 @@ void LocalStore::verifyStore(bool checkContents)
 }
 
 
-/* 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. */
-void LocalStore::upgradeStore12()
+/* Upgrade from schema 5 (Nix 0.12) to schema 6 (Nix >= 0.15). */
+void LocalStore::upgradeStore6()
 {
-    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);
+    }
+
+    printMsg(lvlError, "upgrading Nix store to new schema (this may take a while)...");
+
+    initSchema();
+
+    PathSet validPaths = queryValidPaths();
+
+    sqlite3_stmt * registerStmt;
+    if (sqlite3_prepare_v2(db, "insert into ValidPaths (path, hash, registrationTime) values (?, ?, ?);",
+            -1, &registerStmt, 0) != SQLITE_OK)
+        throw SQLiteError(db, "creating statement");
+    
+    sqlite3_stmt * addRefStmt;
+    if (sqlite3_prepare_v2(db, "insert into Refs (referrer, reference) values (?, ?);",
+            -1, &addRefStmt, 0) != SQLITE_OK)
+        throw SQLiteError(db, "creating statement");
+    
+    if (sqlite3_exec(db, "begin;", 0, 0, 0) != SQLITE_OK)
+        throw SQLiteError(db, "running `begin' command");
+    
+    foreach (PathSet::iterator, i, validPaths) {
+        ValidPathInfo info = queryPathInfo(*i, true);
+        
+        if (sqlite3_reset(registerStmt) != SQLITE_OK)
+            throw SQLiteError(db, "resetting statement");
+        if (sqlite3_bind_text(registerStmt, 1, i->c_str(), -1, SQLITE_TRANSIENT) != SQLITE_OK)
+            throw SQLiteError(db, "binding argument 1");
+        string h = "sha256:" + printHash(info.hash);
+        if (sqlite3_bind_text(registerStmt, 2, h.c_str(), -1, SQLITE_TRANSIENT) != SQLITE_OK)
+            throw SQLiteError(db, "binding argument 2");
+        if (sqlite3_bind_int(registerStmt, 3, info.registrationTime) != SQLITE_OK)
+            throw SQLiteError(db, "binding argument 3");
+        if (sqlite3_step(registerStmt) != SQLITE_DONE)
+            throw SQLiteError(db, "registering valid path in database");
+
+        foreach (PathSet::iterator, j, info.references) {
+            if (sqlite3_reset(addRefStmt) != SQLITE_OK)
+                throw SQLiteError(db, "resetting statement");
+            if (sqlite3_bind_text(addRefStmt, 1, i->c_str(), -1, SQLITE_TRANSIENT) != SQLITE_OK)
+                throw SQLiteError(db, "binding argument 1");
+            if (sqlite3_bind_text(addRefStmt, 2, j->c_str(), -1, SQLITE_TRANSIENT) != SQLITE_OK)
+                throw SQLiteError(db, "binding argument 2");
+            if (sqlite3_step(addRefStmt) != SQLITE_DONE)
+                throw SQLiteError(db, "adding reference to database");
+        }
+
+        std::cerr << ".";
+    }
+
+    std::cerr << "\n";
+
+    if (sqlite3_exec(db, "commit;", 0, 0, 0) != SQLITE_OK)
+        throw SQLiteError(db, "running `commit' command");
+    
+    if (sqlite3_finalize(registerStmt) != SQLITE_OK)
+        throw SQLiteError(db, "finalizing statement");
+
+    if (sqlite3_finalize(addRefStmt) != SQLITE_OK)
+        throw SQLiteError(db, "finalizing statement");
+
+    throw Error("foo");
+
+    writeFile(schemaPath, (format("%1%") % nixSchemaVersion).str());
+
+    lockFile(globalLock, ltRead, true);
 }