Skip to content

Commit 3d23f17

Browse files
committed
Refactor FsRepository's renders
The goal is to make it so it is possible to open repo without creating the renders directory for the current user, in situations where that renders directory will not be used. Examples include when using fuse or when running `spfs clean`. This introduces different flavors of a "render store" besides `RenderStore` that either represent a render store that hasn't been created yet (but can be) or the lack of a render store. Operations that don't require a render store can access the local repository without the renders directory being created. Signed-off-by: J Robert Ray <[email protected]>
1 parent 51a8e45 commit 3d23f17

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

49 files changed

+1162
-429
lines changed

crates/spfs-cli/cmd-render/src/cmd_render.rs

+9-4
Original file line numberDiff line numberDiff line change
@@ -4,9 +4,10 @@
44

55
use clap::builder::TypedValueParser;
66
use clap::Parser;
7-
use miette::{Context, Result};
7+
use miette::{Context, IntoDiagnostic, Result};
88
use spfs::prelude::*;
99
use spfs::storage::fallback::FallbackProxy;
10+
use spfs::storage::fs::{MaybeRenderStore, RenderStore};
1011
use spfs::{graph, Error, RenderResult};
1112
use spfs_cli_common as cli;
1213
use spfs_cli_common::CommandName;
@@ -74,7 +75,11 @@ impl CmdRender {
7475

7576
let rendered = match &self.target {
7677
Some(target) => self.render_to_dir(fallback, env_spec, target).await?,
77-
None => self.render_to_repo(fallback, env_spec).await?,
78+
None => {
79+
// This path requires a repository that supports renders.
80+
let fallback: FallbackProxy<RenderStore> = fallback.try_into().into_diagnostic()?;
81+
self.render_to_repo(fallback, env_spec).await?
82+
}
7883
};
7984

8085
tracing::debug!("render(s) completed successfully");
@@ -85,7 +90,7 @@ impl CmdRender {
8590

8691
async fn render_to_dir(
8792
&self,
88-
repo: FallbackProxy,
93+
repo: FallbackProxy<MaybeRenderStore>,
8994
env_spec: spfs::tracking::EnvSpec,
9095
target: &std::path::Path,
9196
) -> Result<RenderResult> {
@@ -134,7 +139,7 @@ impl CmdRender {
134139

135140
async fn render_to_repo(
136141
&self,
137-
repo: FallbackProxy,
142+
repo: FallbackProxy<RenderStore>,
138143
env_spec: spfs::tracking::EnvSpec,
139144
) -> Result<RenderResult> {
140145
let mut stack = graph::Stack::default();

crates/spfs-cli/common/src/args.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ use miette::{Error, IntoDiagnostic, Result, WrapErr};
1111
#[cfg(feature = "sentry")]
1212
use once_cell::sync::OnceCell;
1313
use spfs::io::Pluralize;
14-
use spfs::storage::LocalRepository;
14+
use spfs::storage::LocalPayloads;
1515
use tracing_subscriber::prelude::*;
1616

1717
const SPFS_LOG: &str = "SPFS_LOG";
@@ -138,7 +138,7 @@ impl Render {
138138
reporter: Reporter,
139139
) -> spfs::storage::fs::Renderer<'repo, Repo, Reporter>
140140
where
141-
Repo: spfs::storage::Repository + LocalRepository,
141+
Repo: spfs::storage::Repository + LocalPayloads,
142142
Reporter: spfs::storage::fs::RenderReporter,
143143
{
144144
spfs::storage::fs::Renderer::new(repo)

crates/spfs-cli/main/src/cmd_init.rs

+2-1
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ use std::path::PathBuf;
66

77
use clap::{Args, Subcommand};
88
use miette::Result;
9+
use spfs::storage::fs::NoRenderStore;
910

1011
/// Create an empty filesystem repository
1112
#[derive(Debug, Args)]
@@ -36,7 +37,7 @@ impl InitSubcommand {
3637
pub async fn run(&self, _config: &spfs::Config) -> Result<i32> {
3738
match self {
3839
Self::Repo { path } => {
39-
spfs::storage::fs::MaybeOpenFsRepository::create(&path).await?;
40+
spfs::storage::fs::MaybeOpenFsRepository::<NoRenderStore>::create(&path).await?;
4041
Ok(0)
4142
}
4243
}

crates/spfs-cli/main/src/cmd_search.rs

+5-1
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
use clap::Args;
66
use miette::Result;
77
use spfs::prelude::*;
8+
use spfs::storage::fs::NoRenderStore;
89
use tokio_stream::StreamExt;
910

1011
/// Search for available tags by substring
@@ -29,7 +30,10 @@ impl CmdSearch {
2930
};
3031
repos.push(remote);
3132
}
32-
repos.insert(0, config.get_local_repository().await?.into());
33+
repos.insert(
34+
0,
35+
config.get_local_repository::<NoRenderStore>().await?.into(),
36+
);
3337
for repo in repos.into_iter() {
3438
let mut tag_streams = repo.iter_tags();
3539
while let Some(tag) = tag_streams.next().await {

crates/spfs-vfs/src/fuse.rs

+21-4
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,7 @@ use fuser::{
2929
Request,
3030
};
3131
use spfs::prelude::*;
32-
use spfs::storage::LocalRepository;
32+
use spfs::storage::LocalPayloads;
3333
#[cfg(feature = "fuse-backend-abi-7-31")]
3434
use spfs::tracking::BlobRead;
3535
use spfs::tracking::{Entry, EntryKind, EnvSpec, Manifest};
@@ -376,9 +376,13 @@ impl Filesystem {
376376
#[allow(unused_mut)]
377377
let mut flags = FOPEN_KEEP_CACHE;
378378
for repo in self.repos.iter() {
379-
match &**repo {
380-
spfs::storage::RepositoryHandle::FS(fs_repo) => {
381-
let Ok(fs_repo) = fs_repo.opened().await else {
379+
// XXX: Using a macro here for an easy fix but it would be nicer
380+
// if there was a way to borrow the RepositoryHandle as a
381+
// `&MaybeOpenFsRepository<NoRenderStore>` since this code
382+
// doesn't need to access renders.
383+
macro_rules! read_fs {
384+
($fs_repo:ident) => {
385+
let Ok(fs_repo) = $fs_repo.opened().await else {
382386
reply.error(libc::ENOENT);
383387
return;
384388
};
@@ -393,6 +397,19 @@ impl Filesystem {
393397
}
394398
Err(err) => err!(reply, err),
395399
}
400+
};
401+
}
402+
match &**repo {
403+
spfs::storage::RepositoryHandle::FSWithMaybeRenders(fs_repo) => {
404+
// XXX: Will this cause the renders directory to get
405+
// created?
406+
read_fs!(fs_repo);
407+
}
408+
spfs::storage::RepositoryHandle::FSWithRenders(fs_repo) => {
409+
read_fs!(fs_repo);
410+
}
411+
spfs::storage::RepositoryHandle::FSWithoutRenders(fs_repo) => {
412+
read_fs!(fs_repo);
396413
}
397414
#[cfg(feature = "fuse-backend-abi-7-31")]
398415
repo => match repo.open_payload(*digest).await {

crates/spfs-vfs/src/winfsp/mount.rs

+19-4
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ use std::sync::Arc;
99
use dashmap::DashMap;
1010
use libc::c_void;
1111
use spfs::prelude::*;
12-
use spfs::storage::LocalRepository;
12+
use spfs::storage::LocalPayloads;
1313
use spfs::tracking::{Entry, EntryKind};
1414
use spfs::OsError;
1515
use tokio::io::AsyncReadExt;
@@ -281,9 +281,13 @@ impl winfsp::filesystem::FileSystemContext for Mount {
281281
let digest = entry.object;
282282
self.rt.spawn(async move {
283283
for repo in repos.into_iter() {
284-
match &*repo {
285-
spfs::storage::RepositoryHandle::FS(fs_repo) => {
286-
let Ok(fs_repo) = fs_repo.opened().await else {
284+
// XXX: Using a macro here for an easy fix but it would be nicer
285+
// if there was a way to borrow the RepositoryHandle as a
286+
// `&MaybeOpenFsRepository<NoRenderStore>` since this code
287+
// doesn't need to access renders.
288+
macro_rules! read_fs {
289+
($fs_repo:ident) => {
290+
let Ok(fs_repo) = $fs_repo.opened().await else {
287291
let _ =
288292
send.send(Err(winfsp::FspError::IO(std::io::ErrorKind::NotFound)));
289293
return;
@@ -299,6 +303,17 @@ impl winfsp::filesystem::FileSystemContext for Mount {
299303
}
300304
Err(err) => err!(send, err),
301305
}
306+
};
307+
}
308+
match &*repo {
309+
spfs::storage::RepositoryHandle::FSWithMaybeRenders(fs_repo) => {
310+
read_fs!(fs_repo);
311+
}
312+
spfs::storage::RepositoryHandle::FSWithRenders(fs_repo) => {
313+
read_fs!(fs_repo);
314+
}
315+
spfs::storage::RepositoryHandle::FSWithoutRenders(fs_repo) => {
316+
read_fs!(fs_repo);
302317
}
303318
repo => match repo.open_payload(digest).await {
304319
Ok((stream, _)) => {

crates/spfs/benches/spfs_bench.rs

+6-3
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ use std::time::Duration;
99

1010
use criterion::{criterion_group, criterion_main, Criterion, Throughput};
1111
use spfs::prelude::*;
12+
use spfs::storage::fs::NoRenderStore;
1213

1314
pub fn commit_benchmark(c: &mut Criterion) {
1415
const NUM_FILES: usize = 1024;
@@ -44,9 +45,11 @@ pub fn commit_benchmark(c: &mut Criterion) {
4445
.expect("create a temp directory for spfs repo");
4546
let repo: Arc<RepositoryHandle> = Arc::new(
4647
tokio_runtime
47-
.block_on(spfs::storage::fs::MaybeOpenFsRepository::create(
48-
repo_path.path().join("repo"),
49-
))
48+
.block_on(
49+
spfs::storage::fs::MaybeOpenFsRepository::<NoRenderStore>::create(
50+
repo_path.path().join("repo"),
51+
),
52+
)
5053
.expect("create spfs repo")
5154
.into(),
5255
);

crates/spfs/src/bootstrap_test.rs

+3-2
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ use super::build_shell_initialized_command;
1111
use crate::fixtures::*;
1212
use crate::resolve::which;
1313
use crate::runtime;
14+
use crate::storage::fs::RenderStore;
1415

1516
#[rstest(
1617
shell,
@@ -37,7 +38,7 @@ async fn test_shell_initialization_startup_scripts(
3738
};
3839
let root = tmpdir.path().to_string_lossy().to_string();
3940
let repo = crate::storage::RepositoryHandle::from(
40-
crate::storage::fs::MaybeOpenFsRepository::create(&root)
41+
crate::storage::fs::MaybeOpenFsRepository::<RenderStore>::create(&root)
4142
.await
4243
.unwrap(),
4344
);
@@ -113,7 +114,7 @@ async fn test_shell_initialization_no_startup_scripts(shell: &str, tmpdir: tempf
113114
};
114115
let root = tmpdir.path().to_string_lossy().to_string();
115116
let repo = crate::storage::RepositoryHandle::from(
116-
crate::storage::fs::MaybeOpenFsRepository::create(&root)
117+
crate::storage::fs::MaybeOpenFsRepository::<RenderStore>::create(&root)
117118
.await
118119
.unwrap(),
119120
);

crates/spfs/src/clean.rs

+5-3
Original file line numberDiff line numberDiff line change
@@ -570,7 +570,7 @@ where
570570
/// remove data that is still being used
571571
async unsafe fn remove_unvisited_renders_and_proxies(&self) -> Result<CleanResult> {
572572
let mut result = CleanResult::default();
573-
let storage::RepositoryHandle::FS(repo) = self.repo else {
573+
let storage::RepositoryHandle::FSWithRenders(repo) = self.repo else {
574574
return Ok(result);
575575
};
576576
let repo = repo.opened().await?;
@@ -715,8 +715,10 @@ where
715715
let future = async move {
716716
if !self.dry_run {
717717
tracing::trace!(?path, "removing proxy render");
718-
storage::fs::OpenFsRepository::remove_dir_atomically(&path, &workdir)
719-
.await?;
718+
storage::fs::OpenFsRepository::<storage::fs::RenderStore>::remove_dir_atomically(
719+
&path, &workdir,
720+
)
721+
.await?;
720722
}
721723
Ok(digest)
722724
};

crates/spfs/src/clean_test.rs

+4-3
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ use tokio::time::sleep;
1313
use super::{Cleaner, TracingCleanReporter};
1414
use crate::encoding::prelude::*;
1515
use crate::fixtures::*;
16+
use crate::storage::fs::RenderStore;
1617
use crate::{storage, tracking, Error};
1718

1819
#[rstest]
@@ -225,7 +226,7 @@ async fn test_clean_untagged_objects_layers_platforms(#[future] tmprepo: TempRep
225226
async fn test_clean_manifest_renders(tmpdir: tempfile::TempDir) {
226227
init_logging();
227228
let tmprepo = Arc::new(
228-
storage::fs::MaybeOpenFsRepository::create(tmpdir.path())
229+
storage::fs::MaybeOpenFsRepository::<RenderStore>::create(tmpdir.path())
229230
.await
230231
.unwrap()
231232
.into(),
@@ -249,7 +250,7 @@ async fn test_clean_manifest_renders(tmpdir: tempfile::TempDir) {
249250
.unwrap();
250251

251252
let fs_repo = match &*tmprepo {
252-
RepositoryHandle::FS(fs) => fs,
253+
RepositoryHandle::FSWithRenders(fs) => fs,
253254
_ => panic!("Unexpected tmprepo type!"),
254255
};
255256
let fs_repo = fs_repo.opened().await.unwrap();
@@ -269,7 +270,7 @@ async fn test_clean_manifest_renders(tmpdir: tempfile::TempDir) {
269270
.expect("failed to clean repo");
270271
println!("{result:#?}");
271272

272-
let files = list_files(fs_repo.fs_impl.renders.as_ref().unwrap().renders.root());
273+
let files = list_files(fs_repo.fs_impl.rs_impl.renders.root());
273274
assert_eq!(
274275
files,
275276
Vec::<String>::new(),

crates/spfs/src/commit_test.rs

+3-2
Original file line numberDiff line numberDiff line change
@@ -6,20 +6,21 @@ use rstest::rstest;
66

77
use super::Committer;
88
use crate::fixtures::*;
9+
use crate::storage::fs::RenderStore;
910
use crate::Error;
1011

1112
#[rstest]
1213
#[tokio::test]
1314
async fn test_commit_empty(tmpdir: tempfile::TempDir) {
1415
let root = tmpdir.path().to_string_lossy().to_string();
1516
let repo = crate::storage::RepositoryHandle::from(
16-
crate::storage::fs::MaybeOpenFsRepository::create(&root)
17+
crate::storage::fs::MaybeOpenFsRepository::<RenderStore>::create(&root)
1718
.await
1819
.unwrap(),
1920
);
2021
let storage = crate::runtime::Storage::new(repo).unwrap();
2122
let repo = crate::storage::RepositoryHandle::from(
22-
crate::storage::fs::MaybeOpenFsRepository::create(root)
23+
crate::storage::fs::MaybeOpenFsRepository::<RenderStore>::create(root)
2324
.await
2425
.unwrap(),
2526
);

0 commit comments

Comments
 (0)