From 812c0dfbe24c8fe93992f77abbf1e5a975ea42f4 Mon Sep 17 00:00:00 2001 From: Eelco Dolstra Date: Thu, 2 Jun 2016 13:33:49 +0200 Subject: [PATCH] Allow setting the state directory as a store parameter E.g. "local?store=/tmp/store&state=/tmp/var". --- src/libstore/gc.cc | 34 ++++++++++++-------------- src/libstore/local-fs-store.cc | 7 ++++++ src/libstore/local-store.cc | 27 +++++++++----------- src/libstore/local-store.hh | 12 +++++++-- src/libstore/profiles.cc | 2 +- src/libstore/profiles.hh | 4 +-- src/libstore/store-api.cc | 5 ++-- src/libstore/store-api.hh | 14 ++++++----- src/libutil/ref.hh | 17 ++++++++++--- src/nix-env/nix-env.cc | 5 +++- src/nix-env/user-env.cc | 24 ++++++++++-------- src/nix-instantiate/nix-instantiate.cc | 4 ++- src/nix-store/nix-store.cc | 34 +++++++++++++++----------- 13 files changed, 112 insertions(+), 77 deletions(-) diff --git a/src/libstore/gc.cc b/src/libstore/gc.cc index df48e8b66..e5be048d8 100644 --- a/src/libstore/gc.cc +++ b/src/libstore/gc.cc @@ -29,7 +29,7 @@ static string gcRootsDir = "gcroots"; int LocalStore::openGCLock(LockType lockType) { Path fnGCLock = (format("%1%/%2%") - % settings.nixStateDir % gcLockName).str(); + % stateDir % gcLockName).str(); debug(format("acquiring global GC lock ‘%1%’") % fnGCLock); @@ -78,12 +78,12 @@ void LocalStore::addIndirectRoot(const Path & path) { string hash = printHash32(hashString(htSHA1, path)); Path realRoot = canonPath((format("%1%/%2%/auto/%3%") - % settings.nixStateDir % gcRootsDir % hash).str()); + % stateDir % gcRootsDir % hash).str()); makeSymlink(realRoot, path); } -Path Store::addPermRoot(const Path & _storePath, +Path LocalFSStore::addPermRoot(const Path & _storePath, const Path & _gcRoot, bool indirect, bool allowOutsideRootsDir) { Path storePath(canonPath(_storePath)); @@ -106,7 +106,7 @@ Path Store::addPermRoot(const Path & _storePath, else { if (!allowOutsideRootsDir) { - Path rootsDir = canonPath((format("%1%/%2%") % settings.nixStateDir % gcRootsDir).str()); + Path rootsDir = canonPath((format("%1%/%2%") % stateDir % gcRootsDir).str()); if (string(gcRoot, 0, rootsDir.size() + 1) != rootsDir + "/") throw Error(format( @@ -153,7 +153,7 @@ void LocalStore::addTempRoot(const Path & path) if (state->fdTempRoots == -1) { while (1) { - Path dir = (format("%1%/%2%") % settings.nixStateDir % tempRootsDir).str(); + Path dir = (format("%1%/%2%") % stateDir % tempRootsDir).str(); createDirs(dir); state->fnTempRoots = (format("%1%/%2%") % dir % getpid()).str(); @@ -200,19 +200,15 @@ void LocalStore::addTempRoot(const Path & path) } -typedef std::shared_ptr FDPtr; -typedef list FDs; - - -static void readTempRoots(Store & store, PathSet & tempRoots, FDs & fds) +void LocalStore::readTempRoots(PathSet & tempRoots, FDs & fds) { /* Read the `temproots' directory for per-process temporary root files. */ DirEntries tempRootFiles = readDirectory( - (format("%1%/%2%") % settings.nixStateDir % tempRootsDir).str()); + (format("%1%/%2%") % stateDir % tempRootsDir).str()); for (auto & i : tempRootFiles) { - Path path = (format("%1%/%2%/%3%") % settings.nixStateDir % tempRootsDir % i.name).str(); + Path path = (format("%1%/%2%/%3%") % stateDir % tempRootsDir % i.name).str(); debug(format("reading temporary root file ‘%1%’") % path); FDPtr fd(new AutoCloseFD(open(path.c_str(), O_RDWR, 0666))); @@ -251,7 +247,7 @@ static void readTempRoots(Store & store, PathSet & tempRoots, FDs & fds) while ((end = contents.find((char) 0, pos)) != string::npos) { Path root(contents, pos, end - pos); debug(format("got temporary root ‘%1%’") % root); - store.assertStorePath(root); + assertStorePath(root); tempRoots.insert(root); pos = end + 1; } @@ -290,7 +286,7 @@ void LocalStore::findRoots(const Path & path, unsigned char type, Roots & roots) else { target = absPath(target, dirOf(path)); if (!pathExists(target)) { - if (isInDir(path, settings.nixStateDir + "/" + gcRootsDir + "/auto")) { + if (isInDir(path, stateDir + "/" + gcRootsDir + "/auto")) { printMsg(lvlInfo, format("removing stale link from ‘%1%’ to ‘%2%’") % path % target); unlink(path.c_str()); } @@ -326,10 +322,10 @@ Roots LocalStore::findRoots() Roots roots; /* Process direct roots in {gcroots,manifests,profiles}. */ - findRoots(settings.nixStateDir + "/" + gcRootsDir, DT_UNKNOWN, roots); - if (pathExists(settings.nixStateDir + "/manifests")) - findRoots(settings.nixStateDir + "/manifests", DT_UNKNOWN, roots); - findRoots(settings.nixStateDir + "/profiles", DT_UNKNOWN, roots); + findRoots(stateDir + "/" + gcRootsDir, DT_UNKNOWN, roots); + if (pathExists(stateDir + "/manifests")) + findRoots(stateDir + "/manifests", DT_UNKNOWN, roots); + findRoots(stateDir + "/profiles", DT_UNKNOWN, roots); return roots; } @@ -635,7 +631,7 @@ void LocalStore::collectGarbage(const GCOptions & options, GCResults & results) per-process temporary root files. So after this point no paths can be added to the set of temporary roots. */ FDs fds; - readTempRoots(*this, state.tempRoots, fds); + readTempRoots(state.tempRoots, fds); state.roots.insert(state.tempRoots.begin(), state.tempRoots.end()); /* After this point the set of roots or temporary roots cannot diff --git a/src/libstore/local-fs-store.cc b/src/libstore/local-fs-store.cc index ea9c6b541..a19e4ce5d 100644 --- a/src/libstore/local-fs-store.cc +++ b/src/libstore/local-fs-store.cc @@ -1,9 +1,16 @@ #include "archive.hh" #include "fs-accessor.hh" #include "store-api.hh" +#include "globals.hh" namespace nix { +LocalFSStore::LocalFSStore(const Params & params) + : Store(params) + , stateDir(get(params, "state", settings.nixStateDir)) +{ +} + struct LocalStoreAccessor : public FSAccessor { ref store; diff --git a/src/libstore/local-store.cc b/src/libstore/local-store.cc index 7588d4b07..e1ff94d2c 100644 --- a/src/libstore/local-store.cc +++ b/src/libstore/local-store.cc @@ -38,9 +38,10 @@ namespace nix { LocalStore::LocalStore(const Params & params) : LocalFSStore(params) + , dbDir(get(params, "state", "") != "" ? get(params, "state", "") + "/db" : settings.nixDBPath) , linksDir(storeDir + "/.links") - , reservedPath(settings.nixDBPath + "/reserved") - , schemaPath(settings.nixDBPath + "/schema") + , reservedPath(dbDir + "/reserved") + , schemaPath(dbDir + "/schema") , requireSigs(settings.get("signed-binary-caches", std::string("")) != "") // FIXME: rename option , publicKeys(getDefaultPublicKeys()) { @@ -55,11 +56,11 @@ LocalStore::LocalStore(const Params & params) createDirs(storeDir); makeStoreWritable(); createDirs(linksDir); - Path profilesDir = settings.nixStateDir + "/profiles"; + Path profilesDir = stateDir + "/profiles"; createDirs(profilesDir); - createDirs(settings.nixStateDir + "/temproots"); - createDirs(settings.nixDBPath); - Path gcRootsDir = settings.nixStateDir + "/gcroots"; + createDirs(stateDir + "/temproots"); + createDirs(dbDir); + Path gcRootsDir = stateDir + "/gcroots"; if (!pathExists(gcRootsDir)) { createDirs(gcRootsDir); createSymlink(profilesDir, gcRootsDir + "/profiles"); @@ -135,7 +136,7 @@ LocalStore::LocalStore(const Params & params) /* Acquire the big fat lock in shared mode to make sure that no schema upgrade is in progress. */ try { - Path globalLockPath = settings.nixDBPath + "/big-lock"; + Path globalLockPath = dbDir + "/big-lock"; globalLock = openLockFile(globalLockPath.c_str(), true); } catch (SysError & e) { if (e.errNo != EACCES) throw; @@ -246,19 +247,13 @@ int LocalStore::getSchema() } -bool LocalStore::haveWriteAccess() -{ - return access(settings.nixDBPath.c_str(), R_OK | W_OK) == 0; -} - - void LocalStore::openDB(State & state, bool create) { - if (!haveWriteAccess()) - throw SysError(format("Nix database directory ‘%1%’ is not writable") % settings.nixDBPath); + if (access(dbDir.c_str(), R_OK | W_OK)) + throw SysError(format("Nix database directory ‘%1%’ is not writable") % dbDir); /* Open the Nix database. */ - string dbPath = settings.nixDBPath + "/db.sqlite"; + string dbPath = dbDir + "/db.sqlite"; auto & db(state.db); if (sqlite3_open_v2(dbPath.c_str(), &db.db, SQLITE_OPEN_READWRITE | (create ? SQLITE_OPEN_CREATE : 0), 0) != SQLITE_OK) diff --git a/src/libstore/local-store.hh b/src/libstore/local-store.hh index eb5fcf833..5166c04e5 100644 --- a/src/libstore/local-store.hh +++ b/src/libstore/local-store.hh @@ -73,6 +73,7 @@ private: Sync _state; + const Path dbDir; const Path linksDir; const Path reservedPath; const Path schemaPath; @@ -146,6 +147,15 @@ public: void syncWithGC() override; +private: + + typedef std::shared_ptr FDPtr; + typedef list FDs; + + void readTempRoots(PathSet & tempRoots, FDs & fds); + +public: + Roots findRoots() override; void collectGarbage(const GCOptions & options, GCResults & results) override; @@ -179,8 +189,6 @@ public: void addSignatures(const Path & storePath, const StringSet & sigs) override; - static bool haveWriteAccess(); - private: int getSchema(); diff --git a/src/libstore/profiles.cc b/src/libstore/profiles.cc index 18e3bcbec..449c88b57 100644 --- a/src/libstore/profiles.cc +++ b/src/libstore/profiles.cc @@ -74,7 +74,7 @@ static void makeName(const Path & profile, unsigned int num, } -Path createGeneration(ref store, Path profile, Path outPath) +Path createGeneration(ref store, Path profile, Path outPath) { /* The new generation number should be higher than old the previous ones. */ diff --git a/src/libstore/profiles.hh b/src/libstore/profiles.hh index d758d94b6..1d4e6d303 100644 --- a/src/libstore/profiles.hh +++ b/src/libstore/profiles.hh @@ -31,9 +31,9 @@ typedef list Generations; profile, sorted by generation number. */ Generations findGenerations(Path profile, int & curGen); -class Store; +class LocalFSStore; -Path createGeneration(ref store, Path profile, Path outPath); +Path createGeneration(ref store, Path profile, Path outPath); void deleteGeneration(const Path & profile, unsigned int gen); diff --git a/src/libstore/store-api.cc b/src/libstore/store-api.cc index cea4b4b6e..c6616a43d 100644 --- a/src/libstore/store-api.cc +++ b/src/libstore/store-api.cc @@ -230,7 +230,7 @@ Path Store::computeStorePathForText(const string & name, const string & s, Store::Store(const Params & params) - : storeDir(settings.nixStore) + : storeDir(get(params, "store", settings.nixStore)) { } @@ -508,7 +508,8 @@ static RegisterStoreImplementation regStore([]( else return 0; if (mode == mAuto) { - if (LocalStore::haveWriteAccess()) + auto stateDir = get(params, "state", settings.nixStateDir); + if (access(stateDir.c_str(), R_OK | W_OK) == 0) mode = mLocal; else if (pathExists(settings.nixDaemonSocketFile)) mode = mDaemon; diff --git a/src/libstore/store-api.hh b/src/libstore/store-api.hh index 45cf7e781..b665babc0 100644 --- a/src/libstore/store-api.hh +++ b/src/libstore/store-api.hh @@ -372,10 +372,6 @@ public: `path' has disappeared. */ virtual void addIndirectRoot(const Path & path) = 0; - /* Register a permanent GC root. */ - Path addPermRoot(const Path & storePath, - const Path & gcRoot, bool indirect, bool allowOutsideRootsDir = false); - /* Acquire the global GC lock, then immediately release it. This function must be called after registering a new permanent root, but before exiting. Otherwise, it is possible that a running @@ -494,11 +490,17 @@ protected: class LocalFSStore : public Store { -protected: - using Store::Store; public: + const Path stateDir; + + LocalFSStore(const Params & params); + void narFromPath(const Path & path, Sink & sink) override; ref getFSAccessor() override; + + /* Register a permanent GC root. */ + Path addPermRoot(const Path & storePath, + const Path & gcRoot, bool indirect, bool allowOutsideRootsDir = false); }; diff --git a/src/libutil/ref.hh b/src/libutil/ref.hh index 85afa2811..0be2a7e74 100644 --- a/src/libutil/ref.hh +++ b/src/libutil/ref.hh @@ -45,19 +45,30 @@ public: return *p; } - operator std::shared_ptr () + operator std::shared_ptr () const + { + return p; + } + + std::shared_ptr get_ptr() const { return p; } template - ref cast() + ref cast() const { return ref(std::dynamic_pointer_cast(p)); } template - operator ref () + std::shared_ptr dynamic_pointer_cast() const + { + return std::dynamic_pointer_cast(p); + } + + template + operator ref () const { return ref((std::shared_ptr) p); } diff --git a/src/nix-env/nix-env.cc b/src/nix-env/nix-env.cc index fbb0f61a1..3f0486bb6 100644 --- a/src/nix-env/nix-env.cc +++ b/src/nix-env/nix-env.cc @@ -692,6 +692,9 @@ static void opSetFlag(Globals & globals, Strings opFlags, Strings opArgs) static void opSet(Globals & globals, Strings opFlags, Strings opArgs) { + auto store2 = globals.state->store.dynamic_pointer_cast(); + if (!store2) throw Error("--set is not supported for this Nix store"); + for (Strings::iterator i = opFlags.begin(); i != opFlags.end(); ) { string arg = *i++; if (parseInstallSourceOptions(globals, i, opFlags, arg)) ; @@ -722,7 +725,7 @@ static void opSet(Globals & globals, Strings opFlags, Strings opArgs) } debug(format("switching to new user environment")); - Path generation = createGeneration(globals.state->store, globals.profile, drv.queryOutPath()); + Path generation = createGeneration(ref(store2), globals.profile, drv.queryOutPath()); switchLink(globals.profile, generation); } diff --git a/src/nix-env/user-env.cc b/src/nix-env/user-env.cc index ca27a7248..f239f6377 100644 --- a/src/nix-env/user-env.cc +++ b/src/nix-env/user-env.cc @@ -131,19 +131,23 @@ bool createUserEnv(EvalState & state, DrvInfos & elems, state.store->buildPaths({topLevelDrv}, state.repair ? bmRepair : bmNormal); /* Switch the current user environment to the output path. */ - PathLocks lock; - lockProfile(lock, profile); + auto store2 = state.store.dynamic_pointer_cast(); - Path lockTokenCur = optimisticLockProfile(profile); - if (lockToken != lockTokenCur) { - printMsg(lvlError, format("profile ‘%1%’ changed while we were busy; restarting") % profile); - return false; + if (store2) { + PathLocks lock; + lockProfile(lock, profile); + + Path lockTokenCur = optimisticLockProfile(profile); + if (lockToken != lockTokenCur) { + printMsg(lvlError, format("profile ‘%1%’ changed while we were busy; restarting") % profile); + return false; + } + + debug(format("switching to new user environment")); + Path generation = createGeneration(ref(store2), profile, topLevelOut); + switchLink(profile, generation); } - debug(format("switching to new user environment")); - Path generation = createGeneration(state.store, profile, topLevelOut); - switchLink(profile, generation); - return true; } diff --git a/src/nix-instantiate/nix-instantiate.cc b/src/nix-instantiate/nix-instantiate.cc index 7dce08400..c1b0b0ea0 100644 --- a/src/nix-instantiate/nix-instantiate.cc +++ b/src/nix-instantiate/nix-instantiate.cc @@ -79,7 +79,9 @@ void processExpr(EvalState & state, const Strings & attrPaths, else { Path rootName = gcRoot; if (++rootNr > 1) rootName += "-" + std::to_string(rootNr); - drvPath = state.store->addPermRoot(drvPath, rootName, indirectRoot); + auto store2 = state.store.dynamic_pointer_cast(); + if (store2) + drvPath = store2->addPermRoot(drvPath, rootName, indirectRoot); } std::cout << format("%1%%2%\n") % drvPath % (outputName != "out" ? "!" + outputName : ""); } diff --git a/src/nix-store/nix-store.cc b/src/nix-store/nix-store.cc index cd00412a8..78b2aa102 100644 --- a/src/nix-store/nix-store.cc +++ b/src/nix-store/nix-store.cc @@ -63,6 +63,8 @@ static PathSet realisePath(Path path, bool build = true) { DrvPathWithOutputs p = parseDrvPathWithOutputs(path); + auto store2 = std::dynamic_pointer_cast(store); + if (isDerivation(p.first)) { if (build) store->buildPaths({path}); Derivation drv = store->derivationFromPath(p.first); @@ -77,13 +79,15 @@ static PathSet realisePath(Path path, bool build = true) if (i == drv.outputs.end()) throw Error(format("derivation ‘%1%’ does not have an output named ‘%2%’") % p.first % j); Path outPath = i->second.path; - if (gcRoot == "") - printGCWarning(); - else { - Path rootName = gcRoot; - if (rootNr > 1) rootName += "-" + std::to_string(rootNr); - if (i->first != "out") rootName += "-" + i->first; - outPath = store->addPermRoot(outPath, rootName, indirectRoot); + if (store2) { + if (gcRoot == "") + printGCWarning(); + else { + Path rootName = gcRoot; + if (rootNr > 1) rootName += "-" + std::to_string(rootNr); + if (i->first != "out") rootName += "-" + i->first; + outPath = store2->addPermRoot(outPath, rootName, indirectRoot); + } } outputs.insert(outPath); } @@ -93,13 +97,15 @@ static PathSet realisePath(Path path, bool build = true) else { if (build) store->ensurePath(path); else if (!store->isValidPath(path)) throw Error(format("path ‘%1%’ does not exist and cannot be created") % path); - if (gcRoot == "") - printGCWarning(); - else { - Path rootName = gcRoot; - rootNr++; - if (rootNr > 1) rootName += "-" + std::to_string(rootNr); - path = store->addPermRoot(path, rootName, indirectRoot); + if (store2) { + if (gcRoot == "") + printGCWarning(); + else { + Path rootName = gcRoot; + rootNr++; + if (rootNr > 1) rootName += "-" + std::to_string(rootNr); + path = store2->addPermRoot(path, rootName, indirectRoot); + } } return {path}; }