Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(async): add async_compatible methods to identify backend compatibility #355

Merged
merged 4 commits into from
Nov 18, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 7 additions & 0 deletions crates/backend/src/local.rs
Original file line number Diff line number Diff line change
Expand Up @@ -417,6 +417,13 @@ impl ReadBackend for LocalBackend {

Ok(vec.into())
}

/// [`LocalBackend`] doesn't use `async`, even under the hood.
///
/// So it can be called from `async` features.
fn is_async_compatible(&self) -> bool {
true
}
}

impl WriteBackend for LocalBackend {
Expand Down
9 changes: 9 additions & 0 deletions crates/backend/src/opendal.rs
Original file line number Diff line number Diff line change
Expand Up @@ -386,6 +386,15 @@ impl ReadBackend for OpenDALBackend {
)?
.to_bytes())
}

/// [`OpenDALBackend`] is `sync` and uses `block_on(async Fn)` under the hood.
///
/// When implementing `rustic_core` using this backend in some `async` features will not work.
///
/// see <https://github.com/rustic-rs/rustic/issues/1181>
fn is_async_compatible(&self) -> bool {
false
}
}

impl WriteBackend for OpenDALBackend {
Expand Down
5 changes: 5 additions & 0 deletions crates/backend/src/rclone.rs
Original file line number Diff line number Diff line change
Expand Up @@ -353,6 +353,11 @@ impl ReadBackend for RcloneBackend {
) -> RusticResult<Bytes> {
self.rest.read_partial(tpe, id, cacheable, offset, length)
}

/// [`RcloneBackend`] uses [`RestBackend`].
fn is_async_compatible(&self) -> bool {
self.rest.is_async_compatible()
}
}

impl WriteBackend for RcloneBackend {
Expand Down
10 changes: 10 additions & 0 deletions crates/backend/src/rest.rs
Original file line number Diff line number Diff line change
Expand Up @@ -350,6 +350,16 @@ impl ReadBackend for RestBackend {
})
.map_err(construct_backoff_error)
}

/// [`RestBackend`] uses `reqwest` which blocking implementation
/// uses an `async` runtime under the hood.
///
/// When implementing `rustic_core` using this backend in some `async` features will not work.
///
/// see <https://github.com/rustic-rs/rustic/issues/1181>
fn is_async_compatible(&self) -> bool {
false
}
}

fn construct_join_url_error(
Expand Down
21 changes: 20 additions & 1 deletion crates/core/src/backend.rs
Original file line number Diff line number Diff line change
Expand Up @@ -174,6 +174,21 @@ pub trait ReadBackend: Send + Sync + 'static {
fn warm_up(&self, _tpe: FileType, _id: &Id) -> RusticResult<()> {
Ok(())
}

/// Getter to determine if some backend is compatible
/// with async features in `rustic_core` implementations.
///
/// ## Default impl
///
/// A default impl allow these change to be non-breaking.
/// By default it is `false`, async compatibility is opt-in.
///
/// ## Temporary
///
/// see <https://github.com/rustic-rs/rustic/issues/1181>
fn is_async_compatible(&self) -> bool {
false
}
}

/// Trait for Searching in a backend.
Expand Down Expand Up @@ -343,7 +358,7 @@ pub trait WriteBackend: ReadBackend {
mock! {
Backend {}

impl ReadBackend for Backend{
impl ReadBackend for Backend {
fn location(&self) -> String;
fn list_with_size(&self, tpe: FileType) -> RusticResult<Vec<(Id, u32)>>;
fn read_full(&self, tpe: FileType, id: &Id) -> RusticResult<Bytes>;
Expand All @@ -355,6 +370,7 @@ mock! {
offset: u32,
length: u32,
) -> RusticResult<Bytes>;
fn is_async_compatible(&self) -> bool;
}

impl WriteBackend for Backend {
Expand Down Expand Up @@ -400,6 +416,9 @@ impl ReadBackend for Arc<dyn WriteBackend> {
self.deref()
.read_partial(tpe, id, cacheable, offset, length)
}
fn is_async_compatible(&self) -> bool {
self.deref().is_async_compatible()
}
}

impl std::fmt::Debug for dyn WriteBackend {
Expand Down
4 changes: 4 additions & 0 deletions crates/core/src/backend/cache.rs
Original file line number Diff line number Diff line change
Expand Up @@ -177,6 +177,10 @@ impl ReadBackend for CachedBackend {
fn warm_up(&self, tpe: FileType, id: &Id) -> RusticResult<()> {
self.be.warm_up(tpe, id)
}

fn is_async_compatible(&self) -> bool {
self.be.is_async_compatible()
}
}

impl WriteBackend for CachedBackend {
Expand Down
8 changes: 6 additions & 2 deletions crates/core/src/backend/decrypt.rs
Original file line number Diff line number Diff line change
Expand Up @@ -216,7 +216,7 @@ pub trait DecryptWriteBackend: WriteBackend + Clone + 'static {
///
/// # Returns
///
/// The processed data, the original data length and when compression is used, the uncomressed length
/// The processed data, the original data length and when compression is used, the uncompressed length
fn process_data(&self, data: &[u8]) -> RusticResult<(Vec<u8>, u32, Option<NonZeroU32>)>;

/// Writes the given data to the backend without compression and returns the id of the data.
Expand Down Expand Up @@ -559,7 +559,7 @@ impl<C: CryptoKey> DecryptWriteBackend for DecryptBackend<C> {
///
/// # Arguments
///
/// * `extra_echeck` - The compression level to use for zstd.
/// * `extra_verify` - The compression level to use for zstd.
fn set_extra_verify(&mut self, extra_verify: bool) {
self.extra_verify = extra_verify;
}
Expand Down Expand Up @@ -622,6 +622,10 @@ impl<C: CryptoKey> ReadBackend for DecryptBackend<C> {
) -> RusticResult<Bytes> {
self.be.read_partial(tpe, id, cacheable, offset, length)
}

fn is_async_compatible(&self) -> bool {
self.be.is_async_compatible()
}
}

impl<C: CryptoKey> WriteBackend for DecryptBackend<C> {
Expand Down
4 changes: 4 additions & 0 deletions crates/core/src/backend/dry_run.rs
Original file line number Diff line number Diff line change
Expand Up @@ -103,6 +103,10 @@ impl<BE: DecryptFullBackend> ReadBackend for DryRunBackend<BE> {
) -> RusticResult<Bytes> {
self.be.read_partial(tpe, id, cacheable, offset, length)
}

fn is_async_compatible(&self) -> bool {
self.be.is_async_compatible()
}
}

impl<BE: DecryptFullBackend> DecryptWriteBackend for DryRunBackend<BE> {
Expand Down
4 changes: 4 additions & 0 deletions crates/core/src/backend/hotcold.rs
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,10 @@ impl ReadBackend for HotColdBackend {
fn warm_up(&self, tpe: FileType, id: &Id) -> RusticResult<()> {
self.be.warm_up(tpe, id)
}

fn is_async_compatible(&self) -> bool {
self.be.is_async_compatible()
}
}

impl WriteBackend for HotColdBackend {
Expand Down
4 changes: 4 additions & 0 deletions crates/core/src/backend/warm_up.rs
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,10 @@ impl ReadBackend for WarmUpAccessBackend {
_ = self.be.read_partial(tpe, id, false, 0, 1);
Ok(())
}

fn is_async_compatible(&self) -> bool {
self.be.is_async_compatible()
}
}

impl WriteBackend for WarmUpAccessBackend {
Expand Down
15 changes: 14 additions & 1 deletion crates/core/src/repository.rs
Original file line number Diff line number Diff line change
Expand Up @@ -708,6 +708,19 @@ impl<P, S> Repository<P, S> {
pub fn list<T: RepoId>(&self) -> RusticResult<impl Iterator<Item = T>> {
Ok(self.be.list(T::TYPE)?.into_iter().map(Into::into))
}

/// Check if one of this repository backend is incompatible
/// with async features in `rustic_core` implementations.
///
/// see <https://github.com/rustic-rs/rustic/issues/1181>
pub fn is_async_compatible(&self) -> bool {
// check if be or be_hot is incompatible with async
self.be.is_async_compatible()
&& self
.be_hot
.as_ref()
.map_or(true, ReadBackend::is_async_compatible)
}
}

impl<P: ProgressBars, S> Repository<P, S> {
Expand Down Expand Up @@ -1896,7 +1909,7 @@ impl<P: ProgressBars, S: IndexedTree> Repository<P, S> {
impl<P: ProgressBars, S: IndexedIds> Repository<P, S> {
/// Run a backup of `source` using the given options.
///
/// You have to give a preflled [`SnapshotFile`] which is modified and saved.
/// You have to give a prefilled [`SnapshotFile`] which is modified and saved.
///
/// # Arguments
///
Expand Down
5 changes: 5 additions & 0 deletions crates/testing/src/backend.rs
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,11 @@ pub mod in_memory_backend {
) -> RusticResult<Bytes> {
Ok(self.0.read().unwrap()[tpe][id].slice(offset as usize..(offset + length) as usize))
}

/// [`InMemoryBackend`] doesn't use `async`, even under the hood.
fn is_async_compatible(&self) -> bool {
true
}
}

impl WriteBackend for InMemoryBackend {
Expand Down
Loading