Skip to content

Commit

Permalink
Clean up store hierarchy with IndirectRootStore
Browse files Browse the repository at this point in the history
See the API doc comments for details.
  • Loading branch information
Ericson2314 committed Jul 24, 2023
1 parent 13269ba commit 60d8dd7
Show file tree
Hide file tree
Showing 12 changed files with 136 additions and 37 deletions.
4 changes: 2 additions & 2 deletions src/libstore/build/local-derivation-goal.cc
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
#include "local-derivation-goal.hh"
#include "gc-store.hh"
#include "indirect-root-store.hh"
#include "hook-instance.hh"
#include "worker.hh"
#include "builtins.hh"
Expand Down Expand Up @@ -1200,7 +1200,7 @@ struct RestrictedStoreConfig : virtual LocalFSStoreConfig
/* A wrapper around LocalStore that only allows building/querying of
paths that are in the input closures of the build or were added via
recursive Nix calls. */
struct RestrictedStore : public virtual RestrictedStoreConfig, public virtual LocalFSStore, public virtual GcStore
struct RestrictedStore : public virtual RestrictedStoreConfig, public virtual IndirectRootStore, public virtual GcStore
{
ref<LocalStore> next;

Expand Down
5 changes: 3 additions & 2 deletions src/libstore/daemon.cc
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
#include "store-cast.hh"
#include "gc-store.hh"
#include "log-store.hh"
#include "indirect-root-store.hh"
#include "path-with-outputs.hh"
#include "finally.hh"
#include "archive.hh"
Expand Down Expand Up @@ -675,8 +676,8 @@ static void performOp(TunnelLogger * logger, ref<Store> store,
Path path = absPath(readString(from));

logger->startWork();
auto & gcStore = require<GcStore>(*store);
gcStore.addIndirectRoot(path);
auto & indirectRootStore = require<IndirectRootStore>(*store);
indirectRootStore.addIndirectRoot(path);
logger->stopWork();

to << 1;
Expand Down
35 changes: 26 additions & 9 deletions src/libstore/gc-store.hh
Original file line number Diff line number Diff line change
Expand Up @@ -71,19 +71,36 @@ struct GCResults
};


/**
* Mix-in class for \ref Store "stores" which expose a notion of garbage
* collection.
*
* Garbage collection will allow deleting paths which are not
* transitively "rooted".
*
* The notion of GC roots actually not part of this class.
*
* - The base `Store` class has `Store::addTempRoot()` because for a store
* that doesn't support garbage collection at all, a temporary GC root is
* safely implementable as no-op.
*
* @todo actually this is not so good because stores are *views*.
* Some views have only a no-op temp roots even though others to the
* same store allow triggering GC. For instance one can't add a root
* over ssh, but that doesn't prevent someone from gc-ing that store
* accesed via SSH locally).
*
* - The derived `LocalFSStore` class has `LocalFSStore::addPermRoot`,
* which is not part of this class because it relies on the notion of
* an ambient file system. There are stores (`ssh-ng://`, for one),
* that *do* support garbage collection but *don't* expose any file
* system, and `LocalFSStore::addPermRoot` thus does not make sense
* for them.
*/
struct GcStore : public virtual Store
{
inline static std::string operationName = "Garbage collection";

/**
* Add an indirect root, which is merely a symlink to `path` from
* `/nix/var/nix/gcroots/auto/<hash of path>`. `path` is supposed
* to be a symlink to a store path. The garbage collector will
* automatically remove the indirect root when it finds that
* `path` has disappeared.
*/
virtual void addIndirectRoot(const Path & path) = 0;

/**
* Find the roots of the garbage collector. Each root is a pair
* `(link, storepath)` where `link` is the path of the symlink
Expand Down
3 changes: 1 addition & 2 deletions src/libstore/gc.cc
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
#include "derivations.hh"
#include "globals.hh"
#include "local-store.hh"
#include "local-fs-store.hh"
#include "finally.hh"

#include <functional>
Expand Down Expand Up @@ -50,7 +49,7 @@ void LocalStore::addIndirectRoot(const Path & path)
}


Path LocalFSStore::addPermRoot(const StorePath & storePath, const Path & _gcRoot)
Path IndirectRootStore::addPermRoot(const StorePath & storePath, const Path & _gcRoot)
{
Path gcRoot(canonPath(_gcRoot));

Expand Down
48 changes: 48 additions & 0 deletions src/libstore/indirect-root-store.hh
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
#pragma once
///@file

#include "local-fs-store.hh"

namespace nix {

/**
* Mix-in class for implementing permanent roots as a pair of a direct
* (strong) reference and indirect weak reference to the first
* reference.
*
* See methods for details on the operations it represents.
*/
struct IndirectRootStore : public virtual LocalFSStore
{
inline static std::string operationName = "Indirect GC roots registration";

/**
* Implementation of `LocalFSStore::addPermRoot` where the permanent
* root is a pair of
*
* - The user-facing symlink which all implementations must create
*
* - An additional weak reference known as the "indirect root" that
* points to that symlink.
*
* The garbage collector will automatically remove the indirect root
* when it finds that the symlink has disappeared.
*
* The implementation of this method is concrete, but it delegates
* to `addIndirectRoot()` which is abstract.
*/
Path addPermRoot(const StorePath & storePath, const Path & gcRoot) override final;

/**
* Add an indirect root, which is a weak reference to the
* user-facing symlink created by `addPermRoot()`.
*
* @param path user-facing and user-controlled symlink to a store
* path.
*
* The form this weak-reference takes is implementation-specific.
*/
virtual void addIndirectRoot(const Path & path) = 0;
};

}
16 changes: 14 additions & 2 deletions src/libstore/local-fs-store.hh
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@ class LocalFSStore : public virtual LocalFSStoreConfig,
public virtual LogStore
{
public:
inline static std::string operationName = "Local Filesystem Store";

const static std::string drvsLogDir;

Expand All @@ -49,9 +50,20 @@ public:
ref<FSAccessor> getFSAccessor() override;

/**
* Register a permanent GC root.
* Creates symlink from the `gcRoot` to the `storePath` and
* registers the `gcRoot` as a permanent GC root. The `gcRoot`
* symlink lives outside the store and is created and owned by the
* user.
*
* @param gcRoot The location of the symlink.
*
* @param storePath The store object being rooted. The symlink will
* point to `toRealPath(store.printStorePath(storePath))`.
*
* How the permanent GC root corresponding to this symlink is
* managed is implementation-specific.
*/
Path addPermRoot(const StorePath & storePath, const Path & gcRoot);
virtual Path addPermRoot(const StorePath & storePath, const Path & gcRoot) = 0;

virtual Path getRealStoreDir() { return realStoreDir; }

Expand Down
13 changes: 10 additions & 3 deletions src/libstore/local-store.hh
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,7 @@

#include "pathlocks.hh"
#include "store-api.hh"
#include "local-fs-store.hh"
#include "gc-store.hh"
#include "indirect-root-store.hh"
#include "sync.hh"
#include "util.hh"

Expand Down Expand Up @@ -68,7 +67,9 @@ struct LocalStoreConfig : virtual LocalFSStoreConfig
std::string doc() override;
};

class LocalStore : public virtual LocalStoreConfig, public virtual LocalFSStore, public virtual GcStore
class LocalStore : public virtual LocalStoreConfig
, public virtual IndirectRootStore
, public virtual GcStore
{
private:

Expand Down Expand Up @@ -209,6 +210,12 @@ private:

public:

/**
* Implementation of IndirectRootStore::addIndirectRoot().
*
* The weak reference merely is a symlink to `path' from
* /nix/var/nix/gcroots/auto/<hash of `path'>.
*/
void addIndirectRoot(const Path & path) override;

private:
Expand Down
9 changes: 0 additions & 9 deletions src/libstore/remote-store.cc
Original file line number Diff line number Diff line change
Expand Up @@ -822,15 +822,6 @@ void RemoteStore::addTempRoot(const StorePath & path)
}


void RemoteStore::addIndirectRoot(const Path & path)
{
auto conn(getConnection());
conn->to << WorkerProto::Op::AddIndirectRoot << path;
conn.processStderr();
readInt(conn->from);
}


Roots RemoteStore::findRoots(bool censor)
{
auto conn(getConnection());
Expand Down
2 changes: 0 additions & 2 deletions src/libstore/remote-store.hh
Original file line number Diff line number Diff line change
Expand Up @@ -126,8 +126,6 @@ public:

void addTempRoot(const StorePath & path) override;

void addIndirectRoot(const Path & path) override;

Roots findRoots(bool censor) override;

void collectGarbage(const GCOptions & options, GCResults & results) override;
Expand Down
12 changes: 8 additions & 4 deletions src/libstore/ssh-store.cc
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
#include "ssh-store-config.hh"
#include "store-api.hh"
#include "local-fs-store.hh"
#include "remote-store.hh"
#include "remote-store-connection.hh"
#include "remote-fs-accessor.hh"
Expand Down Expand Up @@ -61,7 +62,7 @@ class SSHStore : public virtual SSHStoreConfig, public virtual RemoteStore
std::optional<std::string> getBuildLogExact(const StorePath & path) override
{ unsupported("getBuildLogExact"); }

private:
protected:

struct Connection : RemoteStore::Connection
{
Expand Down Expand Up @@ -93,9 +94,12 @@ class SSHStore : public virtual SSHStoreConfig, public virtual RemoteStore
ref<RemoteStore::Connection> SSHStore::openConnection()
{
auto conn = make_ref<Connection>();
conn->sshConn = master.startCommand(
fmt("%s --stdio", remoteProgram)
+ (remoteStore.get() == "" ? "" : " --store " + shellEscape(remoteStore.get())));

std::string command = remoteProgram + " --stdio";
if (remoteStore.get() != "")
command += " --store " + shellEscape(remoteStore.get());

conn->sshConn = master.startCommand(command);
conn->to = FdSink(conn->sshConn->in.get());
conn->from = FdSource(conn->sshConn->out.get());
return conn;
Expand Down
10 changes: 10 additions & 0 deletions src/libstore/uds-remote-store.cc
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
#include "uds-remote-store.hh"
#include "worker-protocol.hh"

#include <sys/types.h>
#include <sys/stat.h>
Expand Down Expand Up @@ -77,6 +78,15 @@ ref<RemoteStore::Connection> UDSRemoteStore::openConnection()
}


void UDSRemoteStore::addIndirectRoot(const Path & path)
{
auto conn(getConnection());
conn->to << WorkerProto::Op::AddIndirectRoot << path;
conn.processStderr();
readInt(conn->from);
}


static RegisterStoreImplementation<UDSRemoteStore, UDSRemoteStoreConfig> regUDSRemoteStore;

}
16 changes: 14 additions & 2 deletions src/libstore/uds-remote-store.hh
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@

#include "remote-store.hh"
#include "remote-store-connection.hh"
#include "local-fs-store.hh"
#include "indirect-root-store.hh"

namespace nix {

Expand All @@ -21,7 +21,9 @@ struct UDSRemoteStoreConfig : virtual LocalFSStoreConfig, virtual RemoteStoreCon
std::string doc() override;
};

class UDSRemoteStore : public virtual UDSRemoteStoreConfig, public virtual LocalFSStore, public virtual RemoteStore
class UDSRemoteStore : public virtual UDSRemoteStoreConfig
, public virtual IndirectRootStore
, public virtual RemoteStore
{
public:

Expand All @@ -39,6 +41,16 @@ public:
void narFromPath(const StorePath & path, Sink & sink) override
{ LocalFSStore::narFromPath(path, sink); }

/**
* Implementation of `IndirectRootStore::addIndirectRoot()` which
* delegates to the remote store.
*
* The idea is that the client makes the direct symlink, so it is
* owned managed by the client's user account, and the server makes
* the indirect symlink.
*/
void addIndirectRoot(const Path & path) override;

private:

struct Connection : RemoteStore::Connection
Expand Down

0 comments on commit 60d8dd7

Please sign in to comment.