* Convert the Nix database to SQLite.
This commit is contained in:
		
							parent
							
								
									eaaa13ce47
								
							
						
					
					
						commit
						c1a07f9445
					
				
					 6 changed files with 151 additions and 15 deletions
				
			
		|  | @ -249,6 +249,9 @@ AC_SUBST(bzip2_bin_test) | ||||||
| AC_CHECK_LIB(pthread, pthread_mutex_init) | AC_CHECK_LIB(pthread, pthread_mutex_init) | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
|  | LDFLAGS="-lsqlite3" | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
| AC_ARG_ENABLE(init-state, AC_HELP_STRING([--disable-init-state], | AC_ARG_ENABLE(init-state, AC_HELP_STRING([--disable-init-state], | ||||||
|   [do not initialise DB etc. in `make install']), |   [do not initialise DB etc. in `make install']), | ||||||
|   init_state=$enableval, init_state=yes) |   init_state=$enableval, init_state=yes) | ||||||
|  |  | ||||||
|  | @ -18,6 +18,6 @@ int main(int argc, char * * argv) | ||||||
|     while ((c = getchar()) != EOF) { |     while ((c = getchar()) != EOF) { | ||||||
|         print("0x%02x, ", (unsigned char) c); |         print("0x%02x, ", (unsigned char) c); | ||||||
|     } |     } | ||||||
|     print("};\n"); |     print("0 };\n"); | ||||||
|     return 0; |     return 0; | ||||||
| } | } | ||||||
|  |  | ||||||
|  | @ -19,5 +19,10 @@ EXTRA_DIST = derivations-ast.def derivations-ast.cc | ||||||
| AM_CXXFLAGS = -Wall \ | AM_CXXFLAGS = -Wall \ | ||||||
|  -I$(srcdir)/.. ${aterm_include} -I$(srcdir)/../libutil |  -I$(srcdir)/.. ${aterm_include} -I$(srcdir)/../libutil | ||||||
| 
 | 
 | ||||||
|  | local-store.lo: schema.sql.hh | ||||||
|  | 
 | ||||||
|  | %.sql.hh: %.sql | ||||||
|  | 	../bin2c/bin2c schema < $< > $@ || (rm $@ && exit 1) | ||||||
|  | 
 | ||||||
| derivations-ast.cc derivations-ast.hh: ../aterm-helper.pl derivations-ast.def | derivations-ast.cc derivations-ast.hh: ../aterm-helper.pl derivations-ast.def | ||||||
| 	$(perl) $(srcdir)/../aterm-helper.pl derivations-ast.hh derivations-ast.cc < $(srcdir)/derivations-ast.def | 	$(perl) $(srcdir)/../aterm-helper.pl derivations-ast.hh derivations-ast.cc < $(srcdir)/derivations-ast.def | ||||||
|  |  | ||||||
|  | @ -22,6 +22,16 @@ | ||||||
| namespace nix { | namespace nix { | ||||||
| 
 | 
 | ||||||
|      |      | ||||||
|  | class SQLiteError : public Error | ||||||
|  | { | ||||||
|  | public: | ||||||
|  |     SQLiteError(sqlite3 * db, const format & f) | ||||||
|  |         : Error(format("%1%: %2%") % f.str() % sqlite3_errmsg(db)) | ||||||
|  |     { | ||||||
|  |     } | ||||||
|  | }; | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
| void checkStoreNotSymlink() | void checkStoreNotSymlink() | ||||||
| { | { | ||||||
|     if (getEnv("NIX_IGNORE_SYMLINK_STORE") == "1") return; |     if (getEnv("NIX_IGNORE_SYMLINK_STORE") == "1") return; | ||||||
|  | @ -42,6 +52,7 @@ void checkStoreNotSymlink() | ||||||
| 
 | 
 | ||||||
| LocalStore::LocalStore() | LocalStore::LocalStore() | ||||||
| { | { | ||||||
|  |     db = 0; | ||||||
|     substitutablePathsLoaded = false; |     substitutablePathsLoaded = false; | ||||||
|      |      | ||||||
|     schemaPath = nixDBPath + "/schema"; |     schemaPath = nixDBPath + "/schema"; | ||||||
|  | @ -50,9 +61,6 @@ LocalStore::LocalStore() | ||||||
| 
 | 
 | ||||||
|     /* Create missing state directories if they don't already exist. */ |     /* Create missing state directories if they don't already exist. */ | ||||||
|     createDirs(nixStore); |     createDirs(nixStore); | ||||||
|     createDirs(nixDBPath + "/info"); |  | ||||||
|     createDirs(nixDBPath + "/referrer"); |  | ||||||
|     createDirs(nixDBPath + "/failed"); |  | ||||||
|     Path profilesDir = nixStateDir + "/profiles"; |     Path profilesDir = nixStateDir + "/profiles"; | ||||||
|     createDirs(nixStateDir + "/profiles"); |     createDirs(nixStateDir + "/profiles"); | ||||||
|     createDirs(nixStateDir + "/temproots"); |     createDirs(nixStateDir + "/temproots"); | ||||||
|  | @ -88,7 +96,12 @@ LocalStore::LocalStore() | ||||||
|         writeFile(schemaPath, (format("%1%") % nixSchemaVersion).str()); |         writeFile(schemaPath, (format("%1%") % nixSchemaVersion).str()); | ||||||
|     } |     } | ||||||
|     if (curSchema == 1) throw Error("your Nix store is no longer supported"); |     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); |     doFsync = queryBoolSetting("fsync-metadata", false); | ||||||
| } | } | ||||||
|  | @ -99,6 +112,9 @@ LocalStore::~LocalStore() | ||||||
|     try { |     try { | ||||||
|         flushDelayedUpdates(); |         flushDelayedUpdates(); | ||||||
| 
 | 
 | ||||||
|  |         if (db && sqlite3_close(db) != SQLITE_OK) | ||||||
|  |             throw SQLiteError(db, "closing database"); | ||||||
|  | 
 | ||||||
|         foreach (RunningSubstituters::iterator, i, runningSubstituters) { |         foreach (RunningSubstituters::iterator, i, runningSubstituters) { | ||||||
|             i->second.to.close(); |             i->second.to.close(); | ||||||
|             i->second.from.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) | void canonicalisePathMetaData(const Path & path, bool recurse) | ||||||
| { | { | ||||||
|     checkInterrupt(); |     checkInterrupt(); | ||||||
|  | @ -1171,15 +1203,78 @@ void LocalStore::verifyStore(bool checkContents) | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
| /* Upgrade from schema 4 (Nix 0.11) to schema 5 (Nix >= 0.12).  The
 | /* Upgrade from schema 5 (Nix 0.12) to schema 6 (Nix >= 0.15). */ | ||||||
|    old schema uses Berkeley DB, the new one stores store path | void LocalStore::upgradeStore6() | ||||||
|    meta-information in files. */ |  | ||||||
| void LocalStore::upgradeStore12() |  | ||||||
| { | { | ||||||
|     throw Error( |     if (!lockFile(globalLock, ltWrite, false)) { | ||||||
|         "Your Nix store has a database in Berkeley DB format,\n" |         printMsg(lvlError, "waiting for exclusive access to the Nix store..."); | ||||||
|         "which is no longer supported. To convert to the new format,\n" |         lockFile(globalLock, ltWrite, true); | ||||||
|         "please upgrade Nix to version 0.12 first."); |     } | ||||||
|  | 
 | ||||||
|  |     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, ®isterStmt, 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); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
|  | @ -6,6 +6,8 @@ | ||||||
| #include "store-api.hh" | #include "store-api.hh" | ||||||
| #include "util.hh" | #include "util.hh" | ||||||
| 
 | 
 | ||||||
|  | #include <sqlite3.h> | ||||||
|  | 
 | ||||||
| 
 | 
 | ||||||
| namespace nix { | namespace nix { | ||||||
| 
 | 
 | ||||||
|  | @ -161,8 +163,12 @@ private: | ||||||
|     /* Whether to do an fsync() after writing Nix metadata. */ |     /* Whether to do an fsync() after writing Nix metadata. */ | ||||||
|     bool doFsync; |     bool doFsync; | ||||||
| 
 | 
 | ||||||
|  |     sqlite3 * db; | ||||||
|  | 
 | ||||||
|     int getSchema(); |     int getSchema(); | ||||||
| 
 | 
 | ||||||
|  |     void initSchema(); | ||||||
|  | 
 | ||||||
|     void registerValidPath(const ValidPathInfo & info, bool ignoreValidity = false); |     void registerValidPath(const ValidPathInfo & info, bool ignoreValidity = false); | ||||||
| 
 | 
 | ||||||
|     ValidPathInfo queryPathInfo(const Path & path, bool ignoreErrors = false); |     ValidPathInfo queryPathInfo(const Path & path, bool ignoreErrors = false); | ||||||
|  | @ -177,7 +183,7 @@ private: | ||||||
|      |      | ||||||
|     void invalidatePath(const Path & path); |     void invalidatePath(const Path & path); | ||||||
|      |      | ||||||
|     void upgradeStore12(); |     void upgradeStore6(); | ||||||
| 
 | 
 | ||||||
|     struct GCState; |     struct GCState; | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
							
								
								
									
										27
									
								
								src/libstore/schema.sql
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										27
									
								
								src/libstore/schema.sql
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,27 @@ | ||||||
|  | pragma foreign_keys = on; | ||||||
|  | 
 | ||||||
|  | create table if not exists ValidPaths ( | ||||||
|  |     path             text primary key not null, | ||||||
|  |     hash             text not null, | ||||||
|  |     registrationTime integer not null | ||||||
|  | ); | ||||||
|  | 
 | ||||||
|  | create table if not exists Refs ( | ||||||
|  |     referrer  text not null, | ||||||
|  |     reference text not null, | ||||||
|  |     primary key (referrer, reference), | ||||||
|  |     foreign key (referrer) references ValidPaths(path) | ||||||
|  |       on delete cascade | ||||||
|  |       deferrable initially deferred, | ||||||
|  |     foreign key (reference) references ValidPaths(path) | ||||||
|  |       on delete restrict | ||||||
|  |       deferrable initially deferred | ||||||
|  | ); | ||||||
|  | 
 | ||||||
|  | create table if not exists FailedDerivations ( | ||||||
|  |     path text primary key not null, | ||||||
|  |     time integer not null | ||||||
|  | ); | ||||||
|  | 
 | ||||||
|  | create index IndexReferrer on Refs(referrer); | ||||||
|  | create index IndexReference on Refs(reference); | ||||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue