From 9e294db8206ee8f8ed99887367222c2197c5c83c Mon Sep 17 00:00:00 2001 From: Vova Kryachko Date: Tue, 29 Oct 2024 14:00:23 -0400 Subject: 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 Tested-by: BuildkiteCI --- tvix/Cargo.lock | 17 +++++++ tvix/Cargo.nix | 76 +++++++++++++++++++++++++++++ tvix/Cargo.toml | 1 + tvix/nix-daemon/Cargo.toml | 24 ++++++++++ tvix/nix-daemon/default.nix | 5 ++ tvix/nix-daemon/src/bin/nix-daemon.rs | 90 +++++++++++++++++++++++++++++++++++ 6 files changed, 213 insertions(+) create mode 100644 tvix/nix-daemon/Cargo.toml create mode 100644 tvix/nix-daemon/default.nix create mode 100644 tvix/nix-daemon/src/bin/nix-daemon.rs (limited to 'tvix') diff --git a/tvix/Cargo.lock b/tvix/Cargo.lock index f9c5907e20ef..2984479c18ef 100644 --- a/tvix/Cargo.lock +++ b/tvix/Cargo.lock @@ -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" diff --git a/tvix/Cargo.nix b/tvix/Cargo.nix index d0b94380ee00..749f39fb93cc 100644 --- a/tvix/Cargo.nix +++ b/tvix/Cargo.nix @@ -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"; diff --git a/tvix/Cargo.toml b/tvix/Cargo.toml index 6b30e1196c39..19f3a2b9c521 100644 --- a/tvix/Cargo.toml +++ b/tvix/Cargo.toml @@ -29,6 +29,7 @@ members = [ "nix-compat", "nix-compat-derive", "nix-compat-derive-tests", + "nix-daemon", "serde", "store", "tracing", diff --git a/tvix/nix-daemon/Cargo.toml b/tvix/nix-daemon/Cargo.toml new file mode 100644 index 000000000000..39b34019b424 --- /dev/null +++ b/tvix/nix-daemon/Cargo.toml @@ -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"] \ No newline at end of file diff --git a/tvix/nix-daemon/default.nix b/tvix/nix-daemon/default.nix new file mode 100644 index 000000000000..740bc851ea19 --- /dev/null +++ b/tvix/nix-daemon/default.nix @@ -0,0 +1,5 @@ +{ depot, ... }: + +depot.tvix.crates.workspaceMembers.nix-daemon.build.override { + runTests = true; +} diff --git a/tvix/nix-daemon/src/bin/nix-daemon.rs b/tvix/nix-daemon/src/bin/nix-daemon.rs new file mode 100644 index 000000000000..769e968309f8 --- /dev/null +++ b/tvix/nix-daemon/src/bin/nix-daemon.rs @@ -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> { + 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> { + 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(()) +} -- cgit 1.4.1