refactor(tvix/store): drop calculate_nar from PathInfoService
This shouldn't be part of the PathInfoService trait. Pretty much none of the PathInfoServices do implement it, and requiring them to implement it means they also cannot make use of this calculation already being done by other PathInfoServices. Move it out into its own NarCalculationService trait, defined somewhere at tvix_store::nar, and have everyone who wants to trigger nar calculation use nar_calculation_service directly, which now is an additional field in TvixStoreIO for example. It being moved outside the PathInfoService trait doesn't prohibit specific implementations to implement it (like the GRPC client for the `PathInfoService` does. This is currently wired together in a bit of a hacky fashion - as of now, everything uses the naive implementation that traverses blob and directoryservice, rather than composing it properly. I want to leave that up to a later CL, dealing with other parts of store composition too. Change-Id: I18d07ea4301d4a07651b8218bc5fe95e4e307208 Reviewed-on: https://cl.tvl.fyi/c/depot/+/11619 Reviewed-by: Connor Brewster <cbrewster@hey.com> Autosubmit: flokli <flokli@flokli.de> Tested-by: BuildkiteCI
This commit is contained in:
parent
944a781354
commit
14766cfe1d
20 changed files with 241 additions and 187 deletions
|
|
@ -178,7 +178,7 @@ mod import_builtins {
|
|||
CAHash::Nar(NixHash::Sha256(state.tokio_handle.block_on(async {
|
||||
Ok::<_, tvix_eval::ErrorKind>(
|
||||
state
|
||||
.path_info_service
|
||||
.nar_calculation_service
|
||||
.as_ref()
|
||||
.calculate_nar(&root_node)
|
||||
.await
|
||||
|
|
@ -255,7 +255,7 @@ mod import_builtins {
|
|||
.tokio_handle
|
||||
.block_on(async {
|
||||
let (_, nar_sha256) = state
|
||||
.path_info_service
|
||||
.nar_calculation_service
|
||||
.as_ref()
|
||||
.calculate_nar(&root_node)
|
||||
.await?;
|
||||
|
|
|
|||
|
|
@ -68,7 +68,7 @@ mod tests {
|
|||
fn eval(str: &str) -> EvaluationResult {
|
||||
// We assemble a complete store in memory.
|
||||
let runtime = tokio::runtime::Runtime::new().expect("Failed to build a Tokio runtime");
|
||||
let (blob_service, directory_service, path_info_service) = runtime
|
||||
let (blob_service, directory_service, path_info_service, nar_calculation_service) = runtime
|
||||
.block_on(async { construct_services("memory://", "memory://", "memory://").await })
|
||||
.expect("Failed to construct store services in memory");
|
||||
|
||||
|
|
@ -76,6 +76,7 @@ mod tests {
|
|||
blob_service,
|
||||
directory_service,
|
||||
path_info_service.into(),
|
||||
nar_calculation_service.into(),
|
||||
Arc::<DummyBuildService>::default(),
|
||||
runtime.handle().clone(),
|
||||
));
|
||||
|
|
|
|||
|
|
@ -14,7 +14,7 @@ use tvix_castore::{
|
|||
directoryservice::DirectoryService,
|
||||
proto::{node::Node, FileNode},
|
||||
};
|
||||
use tvix_store::{pathinfoservice::PathInfoService, proto::PathInfo};
|
||||
use tvix_store::{nar::NarCalculationService, pathinfoservice::PathInfoService, proto::PathInfo};
|
||||
use url::Url;
|
||||
|
||||
use crate::builtins::FetcherError;
|
||||
|
|
@ -106,20 +106,27 @@ impl Fetch {
|
|||
}
|
||||
|
||||
/// Knows how to fetch a given [Fetch].
|
||||
pub struct Fetcher<BS, DS, PS> {
|
||||
pub struct Fetcher<BS, DS, PS, NS> {
|
||||
http_client: reqwest::Client,
|
||||
blob_service: BS,
|
||||
directory_service: DS,
|
||||
path_info_service: PS,
|
||||
nar_calculation_service: NS,
|
||||
}
|
||||
|
||||
impl<BS, DS, PS> Fetcher<BS, DS, PS> {
|
||||
pub fn new(blob_service: BS, directory_service: DS, path_info_service: PS) -> Self {
|
||||
impl<BS, DS, PS, NS> Fetcher<BS, DS, PS, NS> {
|
||||
pub fn new(
|
||||
blob_service: BS,
|
||||
directory_service: DS,
|
||||
path_info_service: PS,
|
||||
nar_calculation_service: NS,
|
||||
) -> Self {
|
||||
Self {
|
||||
http_client: reqwest::Client::new(),
|
||||
blob_service,
|
||||
directory_service,
|
||||
path_info_service,
|
||||
nar_calculation_service,
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -170,11 +177,12 @@ async fn hash<D: Digest + std::io::Write>(
|
|||
Ok((hasher.finalize(), bytes_copied))
|
||||
}
|
||||
|
||||
impl<BS, DS, PS> Fetcher<BS, DS, PS>
|
||||
impl<BS, DS, PS, NS> Fetcher<BS, DS, PS, NS>
|
||||
where
|
||||
BS: BlobService + Clone + 'static,
|
||||
DS: DirectoryService + Clone,
|
||||
PS: PathInfoService,
|
||||
NS: NarCalculationService,
|
||||
{
|
||||
/// Ingest the data from a specified [Fetch].
|
||||
/// On success, return the root node, a content digest and length.
|
||||
|
|
@ -257,7 +265,7 @@ where
|
|||
// Even if no expected NAR sha256 has been provided, we need
|
||||
// the actual one later.
|
||||
let (nar_size, actual_nar_sha256) = self
|
||||
.path_info_service
|
||||
.nar_calculation_service
|
||||
.calculate_nar(&node)
|
||||
.await
|
||||
.map_err(|e| {
|
||||
|
|
@ -309,7 +317,7 @@ where
|
|||
// the [PathInfo].
|
||||
let (nar_size, nar_sha256) = match &ca_hash {
|
||||
CAHash::Flat(_nix_hash) => self
|
||||
.path_info_service
|
||||
.nar_calculation_service
|
||||
.calculate_nar(&node)
|
||||
.await
|
||||
.map_err(|e| FetcherError::Io(e.into()))?,
|
||||
|
|
|
|||
|
|
@ -3,12 +3,8 @@ use std::{rc::Rc, sync::Arc};
|
|||
use pretty_assertions::assert_eq;
|
||||
use std::path::PathBuf;
|
||||
use tvix_build::buildservice::DummyBuildService;
|
||||
use tvix_castore::{
|
||||
blobservice::{BlobService, MemoryBlobService},
|
||||
directoryservice::{DirectoryService, MemoryDirectoryService},
|
||||
};
|
||||
use tvix_eval::{EvalIO, Value};
|
||||
use tvix_store::pathinfoservice::{MemoryPathInfoService, PathInfoService};
|
||||
use tvix_store::utils::construct_services;
|
||||
|
||||
use rstest::rstest;
|
||||
|
||||
|
|
@ -36,19 +32,17 @@ fn eval_test(code_path: PathBuf, expect_success: bool) {
|
|||
return;
|
||||
}
|
||||
|
||||
let blob_service = Arc::new(MemoryBlobService::default()) as Arc<dyn BlobService>;
|
||||
let directory_service =
|
||||
Arc::new(MemoryDirectoryService::default()) as Arc<dyn DirectoryService>;
|
||||
let path_info_service = Box::new(MemoryPathInfoService::new(
|
||||
blob_service.clone(),
|
||||
directory_service.clone(),
|
||||
)) as Box<dyn PathInfoService>;
|
||||
let tokio_runtime = tokio::runtime::Runtime::new().unwrap();
|
||||
let (blob_service, directory_service, path_info_service, nar_calculation_service) =
|
||||
tokio_runtime
|
||||
.block_on(async { construct_services("memory://", "memory://", "memory://").await })
|
||||
.unwrap();
|
||||
|
||||
let tvix_store_io = Rc::new(TvixStoreIO::new(
|
||||
blob_service,
|
||||
directory_service,
|
||||
path_info_service.into(),
|
||||
nar_calculation_service.into(),
|
||||
Arc::new(DummyBuildService::default()),
|
||||
tokio_runtime.handle().clone(),
|
||||
));
|
||||
|
|
|
|||
|
|
@ -18,6 +18,7 @@ use tracing::{error, info, instrument, warn, Level};
|
|||
use tvix_build::buildservice::BuildService;
|
||||
use tvix_castore::proto::node::Node;
|
||||
use tvix_eval::{EvalIO, FileType, StdIO};
|
||||
use tvix_store::nar::NarCalculationService;
|
||||
use tvix_store::utils::AsyncIoBridge;
|
||||
|
||||
use tvix_castore::{
|
||||
|
|
@ -52,13 +53,20 @@ pub struct TvixStoreIO {
|
|||
pub(crate) blob_service: Arc<dyn BlobService>,
|
||||
pub(crate) directory_service: Arc<dyn DirectoryService>,
|
||||
pub(crate) path_info_service: Arc<dyn PathInfoService>,
|
||||
pub(crate) nar_calculation_service: Arc<dyn NarCalculationService>,
|
||||
|
||||
std_io: StdIO,
|
||||
#[allow(dead_code)]
|
||||
build_service: Arc<dyn BuildService>,
|
||||
pub(crate) tokio_handle: tokio::runtime::Handle,
|
||||
|
||||
pub(crate) fetcher:
|
||||
Fetcher<Arc<dyn BlobService>, Arc<dyn DirectoryService>, Arc<dyn PathInfoService>>,
|
||||
#[allow(clippy::type_complexity)]
|
||||
pub(crate) fetcher: Fetcher<
|
||||
Arc<dyn BlobService>,
|
||||
Arc<dyn DirectoryService>,
|
||||
Arc<dyn PathInfoService>,
|
||||
Arc<dyn NarCalculationService>,
|
||||
>,
|
||||
|
||||
// Paths known how to produce, by building or fetching.
|
||||
pub(crate) known_paths: RefCell<KnownPaths>,
|
||||
|
|
@ -69,6 +77,7 @@ impl TvixStoreIO {
|
|||
blob_service: Arc<dyn BlobService>,
|
||||
directory_service: Arc<dyn DirectoryService>,
|
||||
path_info_service: Arc<dyn PathInfoService>,
|
||||
nar_calculation_service: Arc<dyn NarCalculationService>,
|
||||
build_service: Arc<dyn BuildService>,
|
||||
tokio_handle: tokio::runtime::Handle,
|
||||
) -> Self {
|
||||
|
|
@ -76,10 +85,16 @@ impl TvixStoreIO {
|
|||
blob_service: blob_service.clone(),
|
||||
directory_service: directory_service.clone(),
|
||||
path_info_service: path_info_service.clone(),
|
||||
nar_calculation_service: nar_calculation_service.clone(),
|
||||
std_io: StdIO {},
|
||||
build_service,
|
||||
tokio_handle,
|
||||
fetcher: Fetcher::new(blob_service, directory_service, path_info_service),
|
||||
fetcher: Fetcher::new(
|
||||
blob_service,
|
||||
directory_service,
|
||||
path_info_service,
|
||||
nar_calculation_service,
|
||||
),
|
||||
known_paths: Default::default(),
|
||||
}
|
||||
}
|
||||
|
|
@ -247,8 +262,10 @@ impl TvixStoreIO {
|
|||
let root_node = output.node.as_ref().expect("invalid root node");
|
||||
|
||||
// calculate the nar representation
|
||||
let (nar_size, nar_sha256) =
|
||||
self.path_info_service.calculate_nar(root_node).await?;
|
||||
let (nar_size, nar_sha256) = self
|
||||
.nar_calculation_service
|
||||
.calculate_nar(root_node)
|
||||
.await?;
|
||||
|
||||
// assemble the PathInfo to persist
|
||||
let path_info = PathInfo {
|
||||
|
|
@ -323,7 +340,7 @@ impl TvixStoreIO {
|
|||
// because the path info construct a narinfo which *always*
|
||||
// require a SHA256 of the NAR representation and the NAR size.
|
||||
let (nar_size, nar_sha256) = self
|
||||
.path_info_service
|
||||
.nar_calculation_service
|
||||
.as_ref()
|
||||
.calculate_nar(&root_node)
|
||||
.await?;
|
||||
|
|
@ -564,6 +581,7 @@ impl EvalIO for TvixStoreIO {
|
|||
&self.blob_service,
|
||||
&self.directory_service,
|
||||
&self.path_info_service,
|
||||
&self.nar_calculation_service,
|
||||
)
|
||||
.await
|
||||
})?;
|
||||
|
|
@ -584,12 +602,8 @@ mod tests {
|
|||
use bstr::ByteSlice;
|
||||
use tempfile::TempDir;
|
||||
use tvix_build::buildservice::DummyBuildService;
|
||||
use tvix_castore::{
|
||||
blobservice::{BlobService, MemoryBlobService},
|
||||
directoryservice::{DirectoryService, MemoryDirectoryService},
|
||||
};
|
||||
use tvix_eval::{EvalIO, EvaluationResult};
|
||||
use tvix_store::pathinfoservice::MemoryPathInfoService;
|
||||
use tvix_store::utils::construct_services;
|
||||
|
||||
use super::TvixStoreIO;
|
||||
use crate::builtins::{add_derivation_builtins, add_fetcher_builtins, add_import_builtins};
|
||||
|
|
@ -598,22 +612,19 @@ mod tests {
|
|||
/// Takes care of setting up the evaluator so it knows about the
|
||||
// `derivation` builtin.
|
||||
fn eval(str: &str) -> EvaluationResult {
|
||||
let blob_service = Arc::new(MemoryBlobService::default()) as Arc<dyn BlobService>;
|
||||
let directory_service =
|
||||
Arc::new(MemoryDirectoryService::default()) as Arc<dyn DirectoryService>;
|
||||
let path_info_service = Arc::new(MemoryPathInfoService::new(
|
||||
blob_service.clone(),
|
||||
directory_service.clone(),
|
||||
));
|
||||
|
||||
let runtime = tokio::runtime::Runtime::new().unwrap();
|
||||
let tokio_runtime = tokio::runtime::Runtime::new().unwrap();
|
||||
let (blob_service, directory_service, path_info_service, nar_calculation_service) =
|
||||
tokio_runtime
|
||||
.block_on(async { construct_services("memory://", "memory://", "memory://").await })
|
||||
.unwrap();
|
||||
|
||||
let io = Rc::new(TvixStoreIO::new(
|
||||
blob_service.clone(),
|
||||
directory_service.clone(),
|
||||
path_info_service,
|
||||
blob_service,
|
||||
directory_service,
|
||||
path_info_service.into(),
|
||||
nar_calculation_service.into(),
|
||||
Arc::<DummyBuildService>::default(),
|
||||
runtime.handle().clone(),
|
||||
tokio_runtime.handle().clone(),
|
||||
));
|
||||
let mut eval = tvix_eval::Evaluation::new(io.clone() as Rc<dyn EvalIO>, true);
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue