Skip to content

Commit

Permalink
Merge pull request #1155 from spkenv/repo-ext-traits
Browse files Browse the repository at this point in the history
Make Repository dyn-compatible
  • Loading branch information
jrray authored Jan 13, 2025
2 parents 03e6172 + 9cf3488 commit 697958e
Show file tree
Hide file tree
Showing 20 changed files with 325 additions and 263 deletions.
20 changes: 13 additions & 7 deletions crates/spfs/src/graph/database.rs
Original file line number Diff line number Diff line change
Expand Up @@ -250,9 +250,6 @@ impl<T: DatabaseView> DatabaseView for &T {

#[async_trait::async_trait]
pub trait Database: DatabaseView {
/// Write an object to the database, for later retrieval.
async fn write_object<T: ObjectProto>(&self, obj: &FlatObject<T>) -> Result<()>;

/// Remove an object from the database.
async fn remove_object(&self, digest: encoding::Digest) -> Result<()>;

Expand All @@ -269,10 +266,6 @@ pub trait Database: DatabaseView {

#[async_trait::async_trait]
impl<T: Database> Database for &T {
async fn write_object<O: ObjectProto>(&self, obj: &FlatObject<O>) -> Result<()> {
Database::write_object(&**self, obj).await
}

async fn remove_object(&self, digest: encoding::Digest) -> Result<()> {
Database::remove_object(&**self, digest).await
}
Expand All @@ -285,3 +278,16 @@ impl<T: Database> Database for &T {
Database::remove_object_if_older_than(&**self, older_than, digest).await
}
}

#[async_trait::async_trait]
pub trait DatabaseExt: Send + Sync {
/// Write an object to the database, for later retrieval.
async fn write_object<T: ObjectProto>(&self, obj: &FlatObject<T>) -> Result<()>;
}

#[async_trait::async_trait]
impl<T: DatabaseExt + Send + Sync> DatabaseExt for &T {
async fn write_object<O: ObjectProto>(&self, obj: &FlatObject<O>) -> Result<()> {
DatabaseExt::write_object(&**self, obj).await
}
}
1 change: 1 addition & 0 deletions crates/spfs/src/graph/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ pub use annotation::{
pub use blob::Blob;
pub use database::{
Database,
DatabaseExt,
DatabaseIterator,
DatabaseView,
DatabaseWalker,
Expand Down
2 changes: 1 addition & 1 deletion crates/spfs/src/resolve.rs
Original file line number Diff line number Diff line change
Expand Up @@ -211,7 +211,7 @@ pub(crate) async fn resolve_overlay_dirs<R>(
skip_runtime_save: bool,
) -> Result<Vec<graph::Manifest>>
where
R: Repository + ManifestRenderPath,
R: Repository + graph::DatabaseExt + ManifestRenderPath,
{
enum ResolvedManifest {
Existing {
Expand Down
2 changes: 1 addition & 1 deletion crates/spfs/src/runtime/storage_test.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ use crate::fixtures::*;
use crate::graph::object::{DigestStrategy, EncodingFormat};
use crate::graph::{AnnotationValue, Layer, Platform};
use crate::runtime::{BindMount, KeyValuePair, LiveLayer, LiveLayerContents, SpecApiVersion};
use crate::storage::prelude::Database;
use crate::storage::prelude::DatabaseExt;
use crate::{encoding, Config};

#[rstest]
Expand Down
8 changes: 7 additions & 1 deletion crates/spfs/src/storage/blob.rs
Original file line number Diff line number Diff line change
Expand Up @@ -33,12 +33,18 @@ pub trait BlobStorage: graph::Database + Sync + Send {
}),
}
}
}

/// Blanket implementation.
impl<T> BlobStorage for T where T: graph::Database + Sync + Send {}

#[async_trait::async_trait]
pub trait BlobStorageExt: graph::DatabaseExt {
/// Store the given blob
async fn write_blob(&self, blob: graph::Blob) -> Result<()> {
self.write_object(&blob).await
}
}

/// Blanket implementation.
impl<T> BlobStorage for T where T: graph::Database + Sync + Send {}
impl<T> BlobStorageExt for T where T: graph::DatabaseExt + Sync + Send {}
13 changes: 8 additions & 5 deletions crates/spfs/src/storage/fallback/repository.rs
Original file line number Diff line number Diff line change
Expand Up @@ -157,11 +157,6 @@ impl graph::DatabaseView for FallbackProxy {

#[async_trait::async_trait]
impl graph::Database for FallbackProxy {
async fn write_object<T: ObjectProto>(&self, obj: &graph::FlatObject<T>) -> Result<()> {
self.primary.write_object(obj).await?;
Ok(())
}

async fn remove_object(&self, digest: encoding::Digest) -> Result<()> {
self.primary.remove_object(digest).await?;
Ok(())
Expand All @@ -179,6 +174,14 @@ impl graph::Database for FallbackProxy {
}
}

#[async_trait::async_trait]
impl graph::DatabaseExt for FallbackProxy {
async fn write_object<T: ObjectProto>(&self, obj: &graph::FlatObject<T>) -> Result<()> {
self.primary.write_object(obj).await?;
Ok(())
}
}

#[async_trait::async_trait]
impl PayloadStorage for FallbackProxy {
async fn has_payload(&self, digest: encoding::Digest) -> bool {
Expand Down
150 changes: 78 additions & 72 deletions crates/spfs/src/storage/fs/database.rs
Original file line number Diff line number Diff line change
Expand Up @@ -56,10 +56,6 @@ impl DatabaseView for super::FsRepository {

#[async_trait::async_trait]
impl graph::Database for super::FsRepository {
async fn write_object<T: ObjectProto>(&self, obj: &graph::FlatObject<T>) -> Result<()> {
self.opened().await?.write_object(obj).await
}

async fn remove_object(&self, digest: encoding::Digest) -> crate::Result<()> {
self.opened().await?.remove_object(digest).await
}
Expand All @@ -76,6 +72,13 @@ impl graph::Database for super::FsRepository {
}
}

#[async_trait::async_trait]
impl graph::DatabaseExt for super::FsRepository {
async fn write_object<T: ObjectProto>(&self, obj: &graph::FlatObject<T>) -> Result<()> {
self.opened().await?.write_object(obj).await
}
}

#[async_trait::async_trait]
impl DatabaseView for super::OpenFsRepository {
async fn has_object(&self, digest: encoding::Digest) -> bool {
Expand Down Expand Up @@ -127,6 +130,77 @@ impl DatabaseView for super::OpenFsRepository {

#[async_trait::async_trait]
impl graph::Database for super::OpenFsRepository {
async fn remove_object(&self, digest: encoding::Digest) -> crate::Result<()> {
let filepath = self.objects.build_digest_path(&digest);

// this might fail but we don't consider that fatal just yet
#[cfg(unix)]
let _ = tokio::fs::set_permissions(&filepath, std::fs::Permissions::from_mode(0o777)).await;

if let Err(err) = tokio::fs::remove_file(&filepath).await {
return match err.kind() {
std::io::ErrorKind::NotFound => Ok(()),
_ => Err(Error::StorageWriteError(
"remove_file on object file in remove_object",
filepath,
err,
)),
};
}
tracing::trace!(%digest, "removed object from db");
Ok(())
}

async fn remove_object_if_older_than(
&self,
older_than: DateTime<Utc>,
digest: encoding::Digest,
) -> crate::Result<bool> {
let filepath = self.objects.build_digest_path(&digest);

// this might fail but we don't consider that fatal just yet
#[cfg(unix)]
let _ = tokio::fs::set_permissions(&filepath, std::fs::Permissions::from_mode(0o777)).await;

let metadata = tokio::fs::symlink_metadata(&filepath)
.await
.map_err(|err| match err.kind() {
std::io::ErrorKind::NotFound => Error::UnknownObject(digest),
_ => Error::StorageReadError(
"symlink_metadata on digest path",
filepath.clone(),
err,
),
})?;

let mtime = metadata.modified().map_err(|err| {
Error::StorageReadError(
"modified on symlink metadata of digest path",
filepath.clone(),
err,
)
})?;

if DateTime::<Utc>::from(mtime) >= older_than {
return Ok(false);
}

if let Err(err) = tokio::fs::remove_file(&filepath).await {
return match err.kind() {
std::io::ErrorKind::NotFound => Ok(true),
_ => Err(Error::StorageWriteError(
"remove_file on object file in remove_object_if_older_than",
filepath,
err,
)),
};
}
Ok(true)
}
}

#[async_trait::async_trait]
impl graph::DatabaseExt for super::OpenFsRepository {
async fn write_object<T: ObjectProto>(&self, obj: &graph::FlatObject<T>) -> Result<()> {
let digest = obj.digest()?;
let filepath = self.objects.build_digest_path(&digest);
Expand Down Expand Up @@ -207,72 +281,4 @@ impl graph::Database for super::OpenFsRepository {
}
}
}

async fn remove_object(&self, digest: encoding::Digest) -> crate::Result<()> {
let filepath = self.objects.build_digest_path(&digest);

// this might fail but we don't consider that fatal just yet
#[cfg(unix)]
let _ = tokio::fs::set_permissions(&filepath, std::fs::Permissions::from_mode(0o777)).await;

if let Err(err) = tokio::fs::remove_file(&filepath).await {
return match err.kind() {
std::io::ErrorKind::NotFound => Ok(()),
_ => Err(Error::StorageWriteError(
"remove_file on object file in remove_object",
filepath,
err,
)),
};
}
tracing::trace!(%digest, "removed object from db");
Ok(())
}

async fn remove_object_if_older_than(
&self,
older_than: DateTime<Utc>,
digest: encoding::Digest,
) -> crate::Result<bool> {
let filepath = self.objects.build_digest_path(&digest);

// this might fail but we don't consider that fatal just yet
#[cfg(unix)]
let _ = tokio::fs::set_permissions(&filepath, std::fs::Permissions::from_mode(0o777)).await;

let metadata = tokio::fs::symlink_metadata(&filepath)
.await
.map_err(|err| match err.kind() {
std::io::ErrorKind::NotFound => Error::UnknownObject(digest),
_ => Error::StorageReadError(
"symlink_metadata on digest path",
filepath.clone(),
err,
),
})?;

let mtime = metadata.modified().map_err(|err| {
Error::StorageReadError(
"modified on symlink metadata of digest path",
filepath.clone(),
err,
)
})?;

if DateTime::<Utc>::from(mtime) >= older_than {
return Ok(false);
}

if let Err(err) = tokio::fs::remove_file(&filepath).await {
return match err.kind() {
std::io::ErrorKind::NotFound => Ok(true),
_ => Err(Error::StorageWriteError(
"remove_file on object file in remove_object_if_older_than",
filepath,
err,
)),
};
}
Ok(true)
}
}
2 changes: 1 addition & 1 deletion crates/spfs/src/storage/fs/renderer_test.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ use crate::encoding::prelude::*;
use crate::fixtures::*;
use crate::graph::object::{DigestStrategy, EncodingFormat};
use crate::storage::fs::{FsRepository, OpenFsRepository};
use crate::storage::{Repository, RepositoryHandle};
use crate::storage::{RepositoryExt, RepositoryHandle};
use crate::{tracking, Config};

#[rstest(
Expand Down
Loading

0 comments on commit 697958e

Please sign in to comment.