feat(tvix/nix-daemon): Initial skeleton for nix-daemon

The goal is to create a drop-in replacement nix-daemon that nix-cpp can
use as a `daemon` store.

Change-Id: Ie092047dcc6a24a3b8d8d1b808f3e6fd2c493bf2
Reviewed-on: https://cl.tvl.fyi/c/depot/+/12711
Reviewed-by: flokli <flokli@flokli.de>
Tested-by: BuildkiteCI
This commit is contained in:
Vova Kryachko 2024-10-29 14:00:23 -04:00 committed by Vladimir Kryachko
parent eb2ca5f079
commit 9e294db820
6 changed files with 213 additions and 0 deletions

17
tvix/Cargo.lock generated
View file

@ -2343,6 +2343,23 @@ dependencies = [
"trybuild",
]
[[package]]
name = "nix-daemon"
version = "0.1.0"
dependencies = [
"async-trait",
"clap",
"futures",
"mimalloc",
"nix-compat",
"tokio",
"tokio-listener",
"tracing",
"tvix-castore",
"tvix-store",
"tvix-tracing",
]
[[package]]
name = "nohash-hasher"
version = "0.2.0"

View file

@ -75,6 +75,16 @@ rec {
# File a bug if you depend on any for non-debug work!
debug = internal.debugCrate { inherit packageId; };
};
"nix-daemon" = rec {
packageId = "nix-daemon";
build = internal.buildRustCrateWithFeatures {
packageId = "nix-daemon";
};
# Debug support which might change between releases.
# File a bug if you depend on any for non-debug work!
debug = internal.debugCrate { inherit packageId; };
};
"tvix-build" = rec {
packageId = "tvix-build";
build = internal.buildRustCrateWithFeatures {
@ -7419,6 +7429,72 @@ rec {
features = { };
resolvedDefaultFeatures = [ "compile-tests" ];
};
"nix-daemon" = rec {
crateName = "nix-daemon";
version = "0.1.0";
edition = "2021";
crateBin = [
{
name = "nix-daemon";
path = "src/bin/nix-daemon.rs";
requiredFeatures = [ ];
}
];
src = lib.cleanSourceWith { filter = sourceFilter; src = ./nix-daemon; };
dependencies = [
{
name = "async-trait";
packageId = "async-trait";
}
{
name = "clap";
packageId = "clap";
features = [ "derive" "env" ];
}
{
name = "futures";
packageId = "futures";
}
{
name = "mimalloc";
packageId = "mimalloc";
}
{
name = "nix-compat";
packageId = "nix-compat";
}
{
name = "tokio";
packageId = "tokio";
features = [ "fs" "macros" "net" "rt" "rt-multi-thread" "signal" ];
}
{
name = "tokio-listener";
packageId = "tokio-listener";
}
{
name = "tracing";
packageId = "tracing";
}
{
name = "tvix-castore";
packageId = "tvix-castore";
}
{
name = "tvix-store";
packageId = "tvix-store";
}
{
name = "tvix-tracing";
packageId = "tvix-tracing";
}
];
features = {
"default" = [ "otlp" ];
"otlp" = [ "tvix-tracing/otlp" ];
};
resolvedDefaultFeatures = [ "default" "otlp" ];
};
"nohash-hasher" = rec {
crateName = "nohash-hasher";
version = "0.2.0";

View file

@ -29,6 +29,7 @@ members = [
"nix-compat",
"nix-compat-derive",
"nix-compat-derive-tests",
"nix-daemon",
"serde",
"store",
"tracing",

View file

@ -0,0 +1,24 @@
[package]
name = "nix-daemon"
version = "0.1.0"
edition = "2021"
[dependencies]
async-trait = "0.1.83"
clap = { workspace = true, features = ["derive", "env"] }
futures = { workspace = true }
mimalloc = { workspace = true }
nix-compat = { path = "../nix-compat" }
tvix-castore = { path = "../castore" }
tvix-store = { path = "../store" }
tvix-tracing = { path = "../tracing" }
tokio = { workspace = true, features = ["fs", "macros", "net", "rt", "rt-multi-thread", "signal"] }
tokio-listener = { workspace = true }
tracing = { workspace = true }
[lints]
workspace = true
[features]
default = ["otlp"]
otlp = ["tvix-tracing/otlp"]

View file

@ -0,0 +1,5 @@
{ depot, ... }:
depot.tvix.crates.workspaceMembers.nix-daemon.build.override {
runTests = true;
}

View file

@ -0,0 +1,90 @@
use clap::Parser;
use mimalloc::MiMalloc;
use std::error::Error;
use tokio::io::AsyncWriteExt;
use tokio_listener::SystemOptions;
use tvix_store::utils::{construct_services, ServiceUrlsGrpc};
#[global_allocator]
static GLOBAL: MiMalloc = MiMalloc;
/// Run Nix-compatible store daemon backed by tvix.
#[derive(Parser)]
struct Cli {
#[clap(flatten)]
service_addrs: ServiceUrlsGrpc,
/// The address to listen on. Must be a unix domain socket.
#[clap(flatten)]
listen_args: tokio_listener::ListenerAddressLFlag,
#[cfg(feature = "otlp")]
/// Whether to configure OTLP. Set --otlp=false to disable.
#[arg(long, default_missing_value = "true", default_value = "true", num_args(0..=1), require_equals(true), action(clap::ArgAction::Set))]
otlp: bool,
}
#[tokio::main]
async fn main() -> Result<(), Box<dyn Error + Send + Sync>> {
let cli = Cli::parse();
let tracing_handle = {
let mut builder = tvix_tracing::TracingBuilder::default();
builder = builder.enable_progressbar();
#[cfg(feature = "otlp")]
{
if cli.otlp {
builder = builder.enable_otlp("tvix.daemon");
}
}
builder.build()?
};
tokio::select! {
res = tokio::signal::ctrl_c() => {
res?;
if let Err(e) = tracing_handle.force_shutdown().await {
eprintln!("failed to shutdown tracing: {e}");
}
Ok(())
},
res = run(cli) => {
if let Err(e) = tracing_handle.shutdown().await {
eprintln!("failed to shutdown tracing: {e}");
}
res
}
}
}
async fn run(cli: Cli) -> Result<(), Box<dyn std::error::Error + Send + Sync>> {
let (_blob_service, _directory_service, _path_info_service, _nar_calculation_service) =
construct_services(cli.service_addrs).await?;
let listen_address = cli.listen_args.listen_address.unwrap_or_else(|| {
"/tmp/tvix-daemon.sock"
.parse()
.expect("invalid fallback listen address")
});
let mut listener = tokio_listener::Listener::bind(
&listen_address,
&SystemOptions::default(),
&cli.listen_args.listener_options,
)
.await?;
while let Ok((mut connection, _)) = listener.accept().await {
tokio::spawn(async move {
let ucred = connection
.try_borrow_unix()
.and_then(|u| u.peer_cred().ok());
// For now we just write the connected process credentials into the connection.
let _ = connection
.write_all(format!("Hello {:?}", ucred).as_bytes())
.await;
});
}
Ok(())
}