Allow setting the state directory as a store parameter

E.g. "local?store=/tmp/store&state=/tmp/var".
This commit is contained in:
Eelco Dolstra 2016-06-02 13:33:49 +02:00
parent f2682e6e18
commit 812c0dfbe2
13 changed files with 112 additions and 77 deletions

View file

@ -29,7 +29,7 @@ static string gcRootsDir = "gcroots";
int LocalStore::openGCLock(LockType lockType) int LocalStore::openGCLock(LockType lockType)
{ {
Path fnGCLock = (format("%1%/%2%") Path fnGCLock = (format("%1%/%2%")
% settings.nixStateDir % gcLockName).str(); % stateDir % gcLockName).str();
debug(format("acquiring global GC lock %1%") % fnGCLock); debug(format("acquiring global GC lock %1%") % fnGCLock);
@ -78,12 +78,12 @@ void LocalStore::addIndirectRoot(const Path & path)
{ {
string hash = printHash32(hashString(htSHA1, path)); string hash = printHash32(hashString(htSHA1, path));
Path realRoot = canonPath((format("%1%/%2%/auto/%3%") Path realRoot = canonPath((format("%1%/%2%/auto/%3%")
% settings.nixStateDir % gcRootsDir % hash).str()); % stateDir % gcRootsDir % hash).str());
makeSymlink(realRoot, path); makeSymlink(realRoot, path);
} }
Path Store::addPermRoot(const Path & _storePath, Path LocalFSStore::addPermRoot(const Path & _storePath,
const Path & _gcRoot, bool indirect, bool allowOutsideRootsDir) const Path & _gcRoot, bool indirect, bool allowOutsideRootsDir)
{ {
Path storePath(canonPath(_storePath)); Path storePath(canonPath(_storePath));
@ -106,7 +106,7 @@ Path Store::addPermRoot(const Path & _storePath,
else { else {
if (!allowOutsideRootsDir) { 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 + "/") if (string(gcRoot, 0, rootsDir.size() + 1) != rootsDir + "/")
throw Error(format( throw Error(format(
@ -153,7 +153,7 @@ void LocalStore::addTempRoot(const Path & path)
if (state->fdTempRoots == -1) { if (state->fdTempRoots == -1) {
while (1) { while (1) {
Path dir = (format("%1%/%2%") % settings.nixStateDir % tempRootsDir).str(); Path dir = (format("%1%/%2%") % stateDir % tempRootsDir).str();
createDirs(dir); createDirs(dir);
state->fnTempRoots = (format("%1%/%2%") % dir % getpid()).str(); state->fnTempRoots = (format("%1%/%2%") % dir % getpid()).str();
@ -200,19 +200,15 @@ void LocalStore::addTempRoot(const Path & path)
} }
typedef std::shared_ptr<AutoCloseFD> FDPtr; void LocalStore::readTempRoots(PathSet & tempRoots, FDs & fds)
typedef list<FDPtr> FDs;
static void readTempRoots(Store & store, PathSet & tempRoots, FDs & fds)
{ {
/* Read the `temproots' directory for per-process temporary root /* Read the `temproots' directory for per-process temporary root
files. */ files. */
DirEntries tempRootFiles = readDirectory( DirEntries tempRootFiles = readDirectory(
(format("%1%/%2%") % settings.nixStateDir % tempRootsDir).str()); (format("%1%/%2%") % stateDir % tempRootsDir).str());
for (auto & i : tempRootFiles) { 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); debug(format("reading temporary root file %1%") % path);
FDPtr fd(new AutoCloseFD(open(path.c_str(), O_RDWR, 0666))); 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) { while ((end = contents.find((char) 0, pos)) != string::npos) {
Path root(contents, pos, end - pos); Path root(contents, pos, end - pos);
debug(format("got temporary root %1%") % root); debug(format("got temporary root %1%") % root);
store.assertStorePath(root); assertStorePath(root);
tempRoots.insert(root); tempRoots.insert(root);
pos = end + 1; pos = end + 1;
} }
@ -290,7 +286,7 @@ void LocalStore::findRoots(const Path & path, unsigned char type, Roots & roots)
else { else {
target = absPath(target, dirOf(path)); target = absPath(target, dirOf(path));
if (!pathExists(target)) { 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); printMsg(lvlInfo, format("removing stale link from %1% to %2%") % path % target);
unlink(path.c_str()); unlink(path.c_str());
} }
@ -326,10 +322,10 @@ Roots LocalStore::findRoots()
Roots roots; Roots roots;
/* Process direct roots in {gcroots,manifests,profiles}. */ /* Process direct roots in {gcroots,manifests,profiles}. */
findRoots(settings.nixStateDir + "/" + gcRootsDir, DT_UNKNOWN, roots); findRoots(stateDir + "/" + gcRootsDir, DT_UNKNOWN, roots);
if (pathExists(settings.nixStateDir + "/manifests")) if (pathExists(stateDir + "/manifests"))
findRoots(settings.nixStateDir + "/manifests", DT_UNKNOWN, roots); findRoots(stateDir + "/manifests", DT_UNKNOWN, roots);
findRoots(settings.nixStateDir + "/profiles", DT_UNKNOWN, roots); findRoots(stateDir + "/profiles", DT_UNKNOWN, roots);
return 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 per-process temporary root files. So after this point no paths
can be added to the set of temporary roots. */ can be added to the set of temporary roots. */
FDs fds; FDs fds;
readTempRoots(*this, state.tempRoots, fds); readTempRoots(state.tempRoots, fds);
state.roots.insert(state.tempRoots.begin(), state.tempRoots.end()); state.roots.insert(state.tempRoots.begin(), state.tempRoots.end());
/* After this point the set of roots or temporary roots cannot /* After this point the set of roots or temporary roots cannot

View file

@ -1,9 +1,16 @@
#include "archive.hh" #include "archive.hh"
#include "fs-accessor.hh" #include "fs-accessor.hh"
#include "store-api.hh" #include "store-api.hh"
#include "globals.hh"
namespace nix { namespace nix {
LocalFSStore::LocalFSStore(const Params & params)
: Store(params)
, stateDir(get(params, "state", settings.nixStateDir))
{
}
struct LocalStoreAccessor : public FSAccessor struct LocalStoreAccessor : public FSAccessor
{ {
ref<Store> store; ref<Store> store;

View file

@ -38,9 +38,10 @@ namespace nix {
LocalStore::LocalStore(const Params & params) LocalStore::LocalStore(const Params & params)
: LocalFSStore(params) : LocalFSStore(params)
, dbDir(get(params, "state", "") != "" ? get(params, "state", "") + "/db" : settings.nixDBPath)
, linksDir(storeDir + "/.links") , linksDir(storeDir + "/.links")
, reservedPath(settings.nixDBPath + "/reserved") , reservedPath(dbDir + "/reserved")
, schemaPath(settings.nixDBPath + "/schema") , schemaPath(dbDir + "/schema")
, requireSigs(settings.get("signed-binary-caches", std::string("")) != "") // FIXME: rename option , requireSigs(settings.get("signed-binary-caches", std::string("")) != "") // FIXME: rename option
, publicKeys(getDefaultPublicKeys()) , publicKeys(getDefaultPublicKeys())
{ {
@ -55,11 +56,11 @@ LocalStore::LocalStore(const Params & params)
createDirs(storeDir); createDirs(storeDir);
makeStoreWritable(); makeStoreWritable();
createDirs(linksDir); createDirs(linksDir);
Path profilesDir = settings.nixStateDir + "/profiles"; Path profilesDir = stateDir + "/profiles";
createDirs(profilesDir); createDirs(profilesDir);
createDirs(settings.nixStateDir + "/temproots"); createDirs(stateDir + "/temproots");
createDirs(settings.nixDBPath); createDirs(dbDir);
Path gcRootsDir = settings.nixStateDir + "/gcroots"; Path gcRootsDir = stateDir + "/gcroots";
if (!pathExists(gcRootsDir)) { if (!pathExists(gcRootsDir)) {
createDirs(gcRootsDir); createDirs(gcRootsDir);
createSymlink(profilesDir, gcRootsDir + "/profiles"); 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 /* Acquire the big fat lock in shared mode to make sure that no
schema upgrade is in progress. */ schema upgrade is in progress. */
try { try {
Path globalLockPath = settings.nixDBPath + "/big-lock"; Path globalLockPath = dbDir + "/big-lock";
globalLock = openLockFile(globalLockPath.c_str(), true); globalLock = openLockFile(globalLockPath.c_str(), true);
} catch (SysError & e) { } catch (SysError & e) {
if (e.errNo != EACCES) throw; 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) void LocalStore::openDB(State & state, bool create)
{ {
if (!haveWriteAccess()) if (access(dbDir.c_str(), R_OK | W_OK))
throw SysError(format("Nix database directory %1% is not writable") % settings.nixDBPath); throw SysError(format("Nix database directory %1% is not writable") % dbDir);
/* Open the Nix database. */ /* Open the Nix database. */
string dbPath = settings.nixDBPath + "/db.sqlite"; string dbPath = dbDir + "/db.sqlite";
auto & db(state.db); auto & db(state.db);
if (sqlite3_open_v2(dbPath.c_str(), &db.db, if (sqlite3_open_v2(dbPath.c_str(), &db.db,
SQLITE_OPEN_READWRITE | (create ? SQLITE_OPEN_CREATE : 0), 0) != SQLITE_OK) SQLITE_OPEN_READWRITE | (create ? SQLITE_OPEN_CREATE : 0), 0) != SQLITE_OK)

View file

@ -73,6 +73,7 @@ private:
Sync<State, std::recursive_mutex> _state; Sync<State, std::recursive_mutex> _state;
const Path dbDir;
const Path linksDir; const Path linksDir;
const Path reservedPath; const Path reservedPath;
const Path schemaPath; const Path schemaPath;
@ -146,6 +147,15 @@ public:
void syncWithGC() override; void syncWithGC() override;
private:
typedef std::shared_ptr<AutoCloseFD> FDPtr;
typedef list<FDPtr> FDs;
void readTempRoots(PathSet & tempRoots, FDs & fds);
public:
Roots findRoots() override; Roots findRoots() override;
void collectGarbage(const GCOptions & options, GCResults & results) override; void collectGarbage(const GCOptions & options, GCResults & results) override;
@ -179,8 +189,6 @@ public:
void addSignatures(const Path & storePath, const StringSet & sigs) override; void addSignatures(const Path & storePath, const StringSet & sigs) override;
static bool haveWriteAccess();
private: private:
int getSchema(); int getSchema();

View file

@ -74,7 +74,7 @@ static void makeName(const Path & profile, unsigned int num,
} }
Path createGeneration(ref<Store> store, Path profile, Path outPath) Path createGeneration(ref<LocalFSStore> store, Path profile, Path outPath)
{ {
/* The new generation number should be higher than old the /* The new generation number should be higher than old the
previous ones. */ previous ones. */

View file

@ -31,9 +31,9 @@ typedef list<Generation> Generations;
profile, sorted by generation number. */ profile, sorted by generation number. */
Generations findGenerations(Path profile, int & curGen); Generations findGenerations(Path profile, int & curGen);
class Store; class LocalFSStore;
Path createGeneration(ref<Store> store, Path profile, Path outPath); Path createGeneration(ref<LocalFSStore> store, Path profile, Path outPath);
void deleteGeneration(const Path & profile, unsigned int gen); void deleteGeneration(const Path & profile, unsigned int gen);

View file

@ -230,7 +230,7 @@ Path Store::computeStorePathForText(const string & name, const string & s,
Store::Store(const Params & params) Store::Store(const Params & params)
: storeDir(settings.nixStore) : storeDir(get(params, "store", settings.nixStore))
{ {
} }
@ -508,7 +508,8 @@ static RegisterStoreImplementation regStore([](
else return 0; else return 0;
if (mode == mAuto) { 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; mode = mLocal;
else if (pathExists(settings.nixDaemonSocketFile)) else if (pathExists(settings.nixDaemonSocketFile))
mode = mDaemon; mode = mDaemon;

View file

@ -372,10 +372,6 @@ public:
`path' has disappeared. */ `path' has disappeared. */
virtual void addIndirectRoot(const Path & path) = 0; 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 /* Acquire the global GC lock, then immediately release it. This
function must be called after registering a new permanent root, function must be called after registering a new permanent root,
but before exiting. Otherwise, it is possible that a running but before exiting. Otherwise, it is possible that a running
@ -494,11 +490,17 @@ protected:
class LocalFSStore : public Store class LocalFSStore : public Store
{ {
protected:
using Store::Store;
public: public:
const Path stateDir;
LocalFSStore(const Params & params);
void narFromPath(const Path & path, Sink & sink) override; void narFromPath(const Path & path, Sink & sink) override;
ref<FSAccessor> getFSAccessor() override; ref<FSAccessor> getFSAccessor() override;
/* Register a permanent GC root. */
Path addPermRoot(const Path & storePath,
const Path & gcRoot, bool indirect, bool allowOutsideRootsDir = false);
}; };

View file

@ -45,19 +45,30 @@ public:
return *p; return *p;
} }
operator std::shared_ptr<T> () operator std::shared_ptr<T> () const
{
return p;
}
std::shared_ptr<T> get_ptr() const
{ {
return p; return p;
} }
template<typename T2> template<typename T2>
ref<T2> cast() ref<T2> cast() const
{ {
return ref<T2>(std::dynamic_pointer_cast<T2>(p)); return ref<T2>(std::dynamic_pointer_cast<T2>(p));
} }
template<typename T2> template<typename T2>
operator ref<T2> () std::shared_ptr<T2> dynamic_pointer_cast() const
{
return std::dynamic_pointer_cast<T2>(p);
}
template<typename T2>
operator ref<T2> () const
{ {
return ref<T2>((std::shared_ptr<T2>) p); return ref<T2>((std::shared_ptr<T2>) p);
} }

View file

@ -692,6 +692,9 @@ static void opSetFlag(Globals & globals, Strings opFlags, Strings opArgs)
static void opSet(Globals & globals, Strings opFlags, Strings opArgs) static void opSet(Globals & globals, Strings opFlags, Strings opArgs)
{ {
auto store2 = globals.state->store.dynamic_pointer_cast<LocalFSStore>();
if (!store2) throw Error("--set is not supported for this Nix store");
for (Strings::iterator i = opFlags.begin(); i != opFlags.end(); ) { for (Strings::iterator i = opFlags.begin(); i != opFlags.end(); ) {
string arg = *i++; string arg = *i++;
if (parseInstallSourceOptions(globals, i, opFlags, arg)) ; 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")); debug(format("switching to new user environment"));
Path generation = createGeneration(globals.state->store, globals.profile, drv.queryOutPath()); Path generation = createGeneration(ref<LocalFSStore>(store2), globals.profile, drv.queryOutPath());
switchLink(globals.profile, generation); switchLink(globals.profile, generation);
} }

View file

@ -131,6 +131,9 @@ bool createUserEnv(EvalState & state, DrvInfos & elems,
state.store->buildPaths({topLevelDrv}, state.repair ? bmRepair : bmNormal); state.store->buildPaths({topLevelDrv}, state.repair ? bmRepair : bmNormal);
/* Switch the current user environment to the output path. */ /* Switch the current user environment to the output path. */
auto store2 = state.store.dynamic_pointer_cast<LocalFSStore>();
if (store2) {
PathLocks lock; PathLocks lock;
lockProfile(lock, profile); lockProfile(lock, profile);
@ -141,8 +144,9 @@ bool createUserEnv(EvalState & state, DrvInfos & elems,
} }
debug(format("switching to new user environment")); debug(format("switching to new user environment"));
Path generation = createGeneration(state.store, profile, topLevelOut); Path generation = createGeneration(ref<LocalFSStore>(store2), profile, topLevelOut);
switchLink(profile, generation); switchLink(profile, generation);
}
return true; return true;
} }

View file

@ -79,7 +79,9 @@ void processExpr(EvalState & state, const Strings & attrPaths,
else { else {
Path rootName = gcRoot; Path rootName = gcRoot;
if (++rootNr > 1) rootName += "-" + std::to_string(rootNr); if (++rootNr > 1) rootName += "-" + std::to_string(rootNr);
drvPath = state.store->addPermRoot(drvPath, rootName, indirectRoot); auto store2 = state.store.dynamic_pointer_cast<LocalFSStore>();
if (store2)
drvPath = store2->addPermRoot(drvPath, rootName, indirectRoot);
} }
std::cout << format("%1%%2%\n") % drvPath % (outputName != "out" ? "!" + outputName : ""); std::cout << format("%1%%2%\n") % drvPath % (outputName != "out" ? "!" + outputName : "");
} }

View file

@ -63,6 +63,8 @@ static PathSet realisePath(Path path, bool build = true)
{ {
DrvPathWithOutputs p = parseDrvPathWithOutputs(path); DrvPathWithOutputs p = parseDrvPathWithOutputs(path);
auto store2 = std::dynamic_pointer_cast<LocalFSStore>(store);
if (isDerivation(p.first)) { if (isDerivation(p.first)) {
if (build) store->buildPaths({path}); if (build) store->buildPaths({path});
Derivation drv = store->derivationFromPath(p.first); Derivation drv = store->derivationFromPath(p.first);
@ -77,13 +79,15 @@ static PathSet realisePath(Path path, bool build = true)
if (i == drv.outputs.end()) if (i == drv.outputs.end())
throw Error(format("derivation %1% does not have an output named %2%") % p.first % j); throw Error(format("derivation %1% does not have an output named %2%") % p.first % j);
Path outPath = i->second.path; Path outPath = i->second.path;
if (store2) {
if (gcRoot == "") if (gcRoot == "")
printGCWarning(); printGCWarning();
else { else {
Path rootName = gcRoot; Path rootName = gcRoot;
if (rootNr > 1) rootName += "-" + std::to_string(rootNr); if (rootNr > 1) rootName += "-" + std::to_string(rootNr);
if (i->first != "out") rootName += "-" + i->first; if (i->first != "out") rootName += "-" + i->first;
outPath = store->addPermRoot(outPath, rootName, indirectRoot); outPath = store2->addPermRoot(outPath, rootName, indirectRoot);
}
} }
outputs.insert(outPath); outputs.insert(outPath);
} }
@ -93,13 +97,15 @@ static PathSet realisePath(Path path, bool build = true)
else { else {
if (build) store->ensurePath(path); if (build) store->ensurePath(path);
else if (!store->isValidPath(path)) throw Error(format("path %1% does not exist and cannot be created") % path); else if (!store->isValidPath(path)) throw Error(format("path %1% does not exist and cannot be created") % path);
if (store2) {
if (gcRoot == "") if (gcRoot == "")
printGCWarning(); printGCWarning();
else { else {
Path rootName = gcRoot; Path rootName = gcRoot;
rootNr++; rootNr++;
if (rootNr > 1) rootName += "-" + std::to_string(rootNr); if (rootNr > 1) rootName += "-" + std::to_string(rootNr);
path = store->addPermRoot(path, rootName, indirectRoot); path = store2->addPermRoot(path, rootName, indirectRoot);
}
} }
return {path}; return {path};
} }