refactor(tvix): make indicatif.pb_show=1 more explicit
This pushes generating spans with pb_show up to the caller. They usually have more context on how to present things, if at all. Change-Id: Icfcaa64a8a57dce50c0261f2d06e7c051e3946c2 Reviewed-on: https://cl.tvl.fyi/c/depot/+/12657 Autosubmit: flokli <flokli@flokli.de> Tested-by: BuildkiteCI Reviewed-by: raitobezarius <tvl@lahfa.xyz>
This commit is contained in:
parent
3fda90602d
commit
d52d889f2b
3 changed files with 125 additions and 46 deletions
|
@ -8,7 +8,9 @@ use std::os::unix::fs::MetadataExt;
|
||||||
use std::os::unix::fs::PermissionsExt;
|
use std::os::unix::fs::PermissionsExt;
|
||||||
use tokio::io::BufReader;
|
use tokio::io::BufReader;
|
||||||
use tokio_util::io::InspectReader;
|
use tokio_util::io::InspectReader;
|
||||||
|
use tracing::info_span;
|
||||||
use tracing::instrument;
|
use tracing::instrument;
|
||||||
|
use tracing::Instrument;
|
||||||
use tracing::Span;
|
use tracing::Span;
|
||||||
use tracing_indicatif::span_ext::IndicatifSpanExt;
|
use tracing_indicatif::span_ext::IndicatifSpanExt;
|
||||||
use walkdir::DirEntry;
|
use walkdir::DirEntry;
|
||||||
|
@ -30,7 +32,11 @@ use super::IngestionError;
|
||||||
///
|
///
|
||||||
/// This function will walk the filesystem using `walkdir` and will consume
|
/// This function will walk the filesystem using `walkdir` and will consume
|
||||||
/// `O(#number of entries)` space.
|
/// `O(#number of entries)` space.
|
||||||
#[instrument(skip(blob_service, directory_service, reference_scanner), fields(path, indicatif.pb_show=1), err)]
|
#[instrument(
|
||||||
|
skip(blob_service, directory_service, reference_scanner),
|
||||||
|
fields(path),
|
||||||
|
err
|
||||||
|
)]
|
||||||
pub async fn ingest_path<BS, DS, P, P2>(
|
pub async fn ingest_path<BS, DS, P, P2>(
|
||||||
blob_service: BS,
|
blob_service: BS,
|
||||||
directory_service: DS,
|
directory_service: DS,
|
||||||
|
@ -44,8 +50,6 @@ where
|
||||||
P2: AsRef<[u8]> + Send + Sync,
|
P2: AsRef<[u8]> + Send + Sync,
|
||||||
{
|
{
|
||||||
let span = Span::current();
|
let span = Span::current();
|
||||||
span.pb_set_message(&format!("Ingesting {:?}", path));
|
|
||||||
span.pb_start();
|
|
||||||
|
|
||||||
let iter = WalkDir::new(path.as_ref())
|
let iter = WalkDir::new(path.as_ref())
|
||||||
.follow_links(false)
|
.follow_links(false)
|
||||||
|
@ -158,8 +162,15 @@ where
|
||||||
.metadata()
|
.metadata()
|
||||||
.map_err(|e| Error::Stat(entry.path().to_path_buf(), e.into()))?;
|
.map_err(|e| Error::Stat(entry.path().to_path_buf(), e.into()))?;
|
||||||
|
|
||||||
let digest =
|
let digest = upload_blob(blob_service, entry.path().to_path_buf(), reference_scanner)
|
||||||
upload_blob(blob_service, entry.path().to_path_buf(), reference_scanner).await?;
|
.instrument({
|
||||||
|
let span = info_span!("upload_blob", "indicatif.pb_show" = tracing::field::Empty);
|
||||||
|
span.pb_set_message(&format!("Uploading blob for {:?}", fs_path));
|
||||||
|
span.pb_set_style(&tvix_tracing::PB_TRANSFER_STYLE);
|
||||||
|
|
||||||
|
span
|
||||||
|
})
|
||||||
|
.await?;
|
||||||
|
|
||||||
Ok(IngestionEntry::Regular {
|
Ok(IngestionEntry::Regular {
|
||||||
path,
|
path,
|
||||||
|
@ -175,7 +186,7 @@ where
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Uploads the file at the provided [Path] the the [BlobService].
|
/// Uploads the file at the provided [Path] the the [BlobService].
|
||||||
#[instrument(skip(blob_service, reference_scanner), fields(path, indicatif.pb_show=1), err)]
|
#[instrument(skip(blob_service, reference_scanner), fields(path), err)]
|
||||||
async fn upload_blob<BS, P>(
|
async fn upload_blob<BS, P>(
|
||||||
blob_service: BS,
|
blob_service: BS,
|
||||||
path: impl AsRef<std::path::Path>,
|
path: impl AsRef<std::path::Path>,
|
||||||
|
@ -186,8 +197,6 @@ where
|
||||||
P: AsRef<[u8]>,
|
P: AsRef<[u8]>,
|
||||||
{
|
{
|
||||||
let span = Span::current();
|
let span = Span::current();
|
||||||
span.pb_set_style(&tvix_tracing::PB_TRANSFER_STYLE);
|
|
||||||
span.pb_set_message(&format!("Uploading blob for {:?}", path.as_ref()));
|
|
||||||
span.pb_start();
|
span.pb_start();
|
||||||
|
|
||||||
let file = tokio::fs::File::open(path.as_ref())
|
let file = tokio::fs::File::open(path.as_ref())
|
||||||
|
|
|
@ -1,9 +1,11 @@
|
||||||
use clap::Parser;
|
use clap::Parser;
|
||||||
use clap::Subcommand;
|
use clap::Subcommand;
|
||||||
|
|
||||||
use futures::future::try_join_all;
|
|
||||||
use futures::StreamExt;
|
use futures::StreamExt;
|
||||||
use futures::TryStreamExt;
|
use futures::TryStreamExt;
|
||||||
|
use nix_compat::nix_daemon::de::Error;
|
||||||
|
use nix_compat::nixhash::CAHash;
|
||||||
|
use nix_compat::nixhash::NixHash;
|
||||||
use nix_compat::{path_info::ExportedPathInfo, store_path::StorePath};
|
use nix_compat::{path_info::ExportedPathInfo, store_path::StorePath};
|
||||||
use serde::Deserialize;
|
use serde::Deserialize;
|
||||||
use serde::Serialize;
|
use serde::Serialize;
|
||||||
|
@ -12,11 +14,13 @@ use std::sync::Arc;
|
||||||
use tonic::transport::Server;
|
use tonic::transport::Server;
|
||||||
use tower::ServiceBuilder;
|
use tower::ServiceBuilder;
|
||||||
use tower_http::trace::{DefaultMakeSpan, TraceLayer};
|
use tower_http::trace::{DefaultMakeSpan, TraceLayer};
|
||||||
use tracing::{info, info_span, instrument, Level, Span};
|
use tracing::{debug, info, info_span, instrument, warn, Instrument, Level, Span};
|
||||||
use tracing_indicatif::span_ext::IndicatifSpanExt as _;
|
use tracing_indicatif::span_ext::IndicatifSpanExt;
|
||||||
use tvix_castore::import::fs::ingest_path;
|
use tvix_castore::import::fs::ingest_path;
|
||||||
|
use tvix_store::import::path_to_name;
|
||||||
use tvix_store::nar::NarCalculationService;
|
use tvix_store::nar::NarCalculationService;
|
||||||
use tvix_store::utils::{ServiceUrls, ServiceUrlsGrpc};
|
use tvix_store::utils::{ServiceUrls, ServiceUrlsGrpc};
|
||||||
|
use tvix_tracing::TracingHandle;
|
||||||
|
|
||||||
use tvix_castore::proto::blob_service_server::BlobServiceServer;
|
use tvix_castore::proto::blob_service_server::BlobServiceServer;
|
||||||
use tvix_castore::proto::directory_service_server::DirectoryServiceServer;
|
use tvix_castore::proto::directory_service_server::DirectoryServiceServer;
|
||||||
|
@ -159,7 +163,10 @@ fn default_threads() -> usize {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[instrument(skip_all)]
|
#[instrument(skip_all)]
|
||||||
async fn run_cli(cli: Cli) -> Result<(), Box<dyn std::error::Error + Send + Sync>> {
|
async fn run_cli(
|
||||||
|
cli: Cli,
|
||||||
|
tracing_handle: TracingHandle,
|
||||||
|
) -> Result<(), Box<dyn std::error::Error + Send + Sync>> {
|
||||||
match cli.command {
|
match cli.command {
|
||||||
Commands::Daemon {
|
Commands::Daemon {
|
||||||
listen_args,
|
listen_args,
|
||||||
|
@ -242,37 +249,105 @@ async fn run_cli(cli: Cli) -> Result<(), Box<dyn std::error::Error + Send + Sync
|
||||||
let nar_calculation_service: Arc<dyn NarCalculationService> =
|
let nar_calculation_service: Arc<dyn NarCalculationService> =
|
||||||
nar_calculation_service.into();
|
nar_calculation_service.into();
|
||||||
|
|
||||||
let tasks = paths
|
// For each path passed, construct the name, or bail out if it's invalid.
|
||||||
|
let paths_and_names = paths
|
||||||
.into_iter()
|
.into_iter()
|
||||||
.map(|path| {
|
.map(|p| match path_to_name(&p) {
|
||||||
tokio::task::spawn({
|
Ok(name) => {
|
||||||
|
let name = name.to_owned();
|
||||||
|
Ok((p, name))
|
||||||
|
}
|
||||||
|
Err(e) => Err(e),
|
||||||
|
})
|
||||||
|
.collect::<Result<Vec<_>, _>>()?;
|
||||||
|
|
||||||
|
let imports_span =
|
||||||
|
info_span!("import paths", "indicatif.pb_show" = tracing::field::Empty);
|
||||||
|
imports_span.pb_set_message("Importing");
|
||||||
|
imports_span.pb_set_length(paths_and_names.len() as u64);
|
||||||
|
imports_span.pb_set_style(&tvix_tracing::PB_PROGRESS_STYLE);
|
||||||
|
imports_span.pb_start();
|
||||||
|
|
||||||
|
futures::stream::iter(paths_and_names)
|
||||||
|
.map(|(path, name)| {
|
||||||
let blob_service = blob_service.clone();
|
let blob_service = blob_service.clone();
|
||||||
let directory_service = directory_service.clone();
|
let directory_service = directory_service.clone();
|
||||||
let path_info_service = path_info_service.clone();
|
let path_info_service = path_info_service.clone();
|
||||||
let nar_calculation_service = nar_calculation_service.clone();
|
let nar_calculation_service = nar_calculation_service.clone();
|
||||||
|
let imports_span = imports_span.clone();
|
||||||
|
let tracing_handle = tracing_handle.clone();
|
||||||
|
|
||||||
async move {
|
async move {
|
||||||
if let Ok(name) = tvix_store::import::path_to_name(&path) {
|
let span = Span::current();
|
||||||
let resp = tvix_store::import::import_path_as_nar_ca(
|
span.pb_set_style(&tvix_tracing::PB_SPINNER_STYLE);
|
||||||
&path,
|
span.pb_set_message(&format!("Ingesting {:?}", path));
|
||||||
name,
|
span.pb_start();
|
||||||
|
|
||||||
|
// Ingest the contents at the given path into castore.
|
||||||
|
let root_node = ingest_path::<_, _, _, &[u8]>(
|
||||||
blob_service,
|
blob_service,
|
||||||
directory_service,
|
directory_service,
|
||||||
path_info_service,
|
&path,
|
||||||
nar_calculation_service,
|
None,
|
||||||
)
|
)
|
||||||
.await;
|
.await
|
||||||
if let Ok(path_info) = resp {
|
.map_err(std::io::Error::custom)?;
|
||||||
// If the import was successful, print the path to stdout.
|
|
||||||
println!("{}", path_info.store_path.to_absolute_path());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
})
|
|
||||||
})
|
|
||||||
.collect::<Vec<_>>();
|
|
||||||
|
|
||||||
try_join_all(tasks).await?;
|
span.pb_set_message(&format!("NAR Calculation for {:?}", path));
|
||||||
|
|
||||||
|
// Ask for the NAR size and sha256
|
||||||
|
let (nar_size, nar_sha256) =
|
||||||
|
nar_calculation_service.calculate_nar(&root_node).await?;
|
||||||
|
|
||||||
|
// Calculate the output path. This might still fail, as some names are illegal.
|
||||||
|
// FUTUREWORK: express the `name` at the type level to be valid and check for this earlier.
|
||||||
|
let ca = CAHash::Nar(NixHash::Sha256(nar_sha256));
|
||||||
|
let output_path: StorePath<String> =
|
||||||
|
nix_compat::store_path::build_ca_path::<&str, _, _>(
|
||||||
|
&name,
|
||||||
|
&ca,
|
||||||
|
[],
|
||||||
|
false,
|
||||||
|
)
|
||||||
|
.map_err(|e| {
|
||||||
|
warn!(err=%e, "unable to build CA path");
|
||||||
|
std::io::Error::custom(e)
|
||||||
|
})?;
|
||||||
|
|
||||||
|
// Construct and insert PathInfo
|
||||||
|
match path_info_service
|
||||||
|
.as_ref()
|
||||||
|
.put(PathInfo {
|
||||||
|
store_path: output_path.to_owned(),
|
||||||
|
node: root_node,
|
||||||
|
// There's no reference scanning on imported paths
|
||||||
|
references: vec![],
|
||||||
|
nar_size,
|
||||||
|
nar_sha256,
|
||||||
|
signatures: vec![],
|
||||||
|
deriver: None,
|
||||||
|
ca: Some(ca),
|
||||||
|
})
|
||||||
|
.await
|
||||||
|
{
|
||||||
|
// If the import was successful, print the path to stdout.
|
||||||
|
Ok(path_info) => {
|
||||||
|
use std::io::Write;
|
||||||
|
debug!(store_path=%path_info.store_path.to_absolute_path(), "imported path");
|
||||||
|
writeln!(&mut tracing_handle.get_stdout_writer(), "{}", path_info.store_path.to_absolute_path())?;
|
||||||
|
imports_span.pb_inc(1);
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
Err(e) => {
|
||||||
|
warn!(?path, err=%e, "failed to import");
|
||||||
|
Err(e)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}.instrument(info_span!("import path", "indicatif.pb_show" = tracing::field::Empty))
|
||||||
|
})
|
||||||
|
.buffer_unordered(50)
|
||||||
|
.try_collect()
|
||||||
|
.await?;
|
||||||
}
|
}
|
||||||
Commands::Copy {
|
Commands::Copy {
|
||||||
service_addrs,
|
service_addrs,
|
||||||
|
@ -465,7 +540,7 @@ async fn main() -> Result<(), Box<dyn std::error::Error + Send + Sync>> {
|
||||||
}
|
}
|
||||||
Ok(())
|
Ok(())
|
||||||
},
|
},
|
||||||
res = run_cli(cli) => {
|
res = run_cli(cli, tracing_handle.clone()) => {
|
||||||
if let Err(e) = tracing_handle.shutdown().await {
|
if let Err(e) = tracing_handle.shutdown().await {
|
||||||
eprintln!("failed to shutdown tracing: {e}");
|
eprintln!("failed to shutdown tracing: {e}");
|
||||||
}
|
}
|
||||||
|
|
|
@ -6,8 +6,7 @@ use nix_compat::nar::writer::r#async as nar_writer;
|
||||||
use sha2::{Digest, Sha256};
|
use sha2::{Digest, Sha256};
|
||||||
use tokio::io::{self, AsyncWrite, BufReader};
|
use tokio::io::{self, AsyncWrite, BufReader};
|
||||||
use tonic::async_trait;
|
use tonic::async_trait;
|
||||||
use tracing::{instrument, Span};
|
use tracing::instrument;
|
||||||
use tracing_indicatif::span_ext::IndicatifSpanExt;
|
|
||||||
use tvix_castore::{blobservice::BlobService, directoryservice::DirectoryService, Node};
|
use tvix_castore::{blobservice::BlobService, directoryservice::DirectoryService, Node};
|
||||||
|
|
||||||
pub struct SimpleRenderer<BS, DS> {
|
pub struct SimpleRenderer<BS, DS> {
|
||||||
|
@ -46,7 +45,7 @@ where
|
||||||
|
|
||||||
/// Invoke [write_nar], and return the size and sha256 digest of the produced
|
/// Invoke [write_nar], and return the size and sha256 digest of the produced
|
||||||
/// NAR output.
|
/// NAR output.
|
||||||
#[instrument(skip_all, fields(indicatif.pb_show=1))]
|
#[instrument(skip_all)]
|
||||||
pub async fn calculate_size_and_sha256<BS, DS>(
|
pub async fn calculate_size_and_sha256<BS, DS>(
|
||||||
root_node: &Node,
|
root_node: &Node,
|
||||||
blob_service: BS,
|
blob_service: BS,
|
||||||
|
@ -59,10 +58,6 @@ where
|
||||||
let mut h = Sha256::new();
|
let mut h = Sha256::new();
|
||||||
let mut cw = CountWrite::from(&mut h);
|
let mut cw = CountWrite::from(&mut h);
|
||||||
|
|
||||||
let span = Span::current();
|
|
||||||
span.pb_set_message("Calculating NAR");
|
|
||||||
span.pb_start();
|
|
||||||
|
|
||||||
write_nar(
|
write_nar(
|
||||||
// The hasher doesn't speak async. It doesn't
|
// The hasher doesn't speak async. It doesn't
|
||||||
// actually do any I/O, so it's fine to wrap.
|
// actually do any I/O, so it's fine to wrap.
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue