-
Notifications
You must be signed in to change notification settings - Fork 17
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
11 changed files
with
286 additions
and
6 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,113 @@ | ||
use std::{process::Command, sync::Arc}; | ||
|
||
use anyhow::Result; | ||
use bytes::Bytes; | ||
use chrono::{DateTime, Local}; | ||
use log::{debug, warn}; | ||
|
||
use crate::{ | ||
backend::{FileType, ReadBackend, WriteBackend}, | ||
id::Id, | ||
CommandInput, | ||
}; | ||
|
||
/// A backend which warms up files by simply accessing them. | ||
#[derive(Clone, Debug)] | ||
pub struct LockBackend { | ||
/// The backend to use. | ||
be: Arc<dyn WriteBackend>, | ||
/// The command to be called to lock files in the backend | ||
command: CommandInput, | ||
} | ||
|
||
impl LockBackend { | ||
/// Creates a new `WarmUpAccessBackend`. | ||
/// | ||
/// # Arguments | ||
/// | ||
/// * `be` - The backend to use. | ||
pub fn new_lock(be: Arc<dyn WriteBackend>, command: CommandInput) -> Arc<dyn WriteBackend> { | ||
Arc::new(Self { be, command }) | ||
} | ||
} | ||
|
||
impl ReadBackend for LockBackend { | ||
fn location(&self) -> String { | ||
self.be.location() | ||
} | ||
|
||
fn list_with_size(&self, tpe: FileType) -> Result<Vec<(Id, u32)>> { | ||
self.be.list_with_size(tpe) | ||
} | ||
|
||
fn read_full(&self, tpe: FileType, id: &Id) -> Result<Bytes> { | ||
self.be.read_full(tpe, id) | ||
} | ||
|
||
fn read_partial( | ||
&self, | ||
tpe: FileType, | ||
id: &Id, | ||
cacheable: bool, | ||
offset: u32, | ||
length: u32, | ||
) -> Result<Bytes> { | ||
self.be.read_partial(tpe, id, cacheable, offset, length) | ||
} | ||
|
||
fn list(&self, tpe: FileType) -> Result<Vec<Id>> { | ||
self.be.list(tpe) | ||
} | ||
|
||
fn needs_warm_up(&self) -> bool { | ||
self.be.needs_warm_up() | ||
} | ||
|
||
fn warm_up(&self, tpe: FileType, id: &Id) -> Result<()> { | ||
self.be.warm_up(tpe, id) | ||
} | ||
} | ||
|
||
fn path(tpe: FileType, id: &Id) -> String { | ||
let hex_id = id.to_hex(); | ||
match tpe { | ||
FileType::Config => "config".into(), | ||
FileType::Pack => format!("data/{}/{}", &hex_id[0..2], &*hex_id), | ||
_ => format!("{}/{}", tpe.dirname(), &*hex_id), | ||
} | ||
} | ||
|
||
impl WriteBackend for LockBackend { | ||
fn create(&self) -> Result<()> { | ||
self.be.create() | ||
} | ||
|
||
fn write_bytes(&self, tpe: FileType, id: &Id, cacheable: bool, buf: Bytes) -> Result<()> { | ||
self.be.write_bytes(tpe, id, cacheable, buf) | ||
} | ||
|
||
fn remove(&self, tpe: FileType, id: &Id, cacheable: bool) -> Result<()> { | ||
self.be.remove(tpe, id, cacheable) | ||
} | ||
|
||
fn can_lock(&self) -> bool { | ||
true | ||
} | ||
|
||
fn lock(&self, tpe: FileType, id: &Id, until: Option<DateTime<Local>>) -> Result<()> { | ||
let until = until.map_or_else(String::new, |u| u.to_rfc3339()); | ||
let path = path(tpe, id); | ||
let args = self.command.args().iter().map(|c| { | ||
c.replace("%id", &id.to_hex()) | ||
.replace("%type", tpe.dirname()) | ||
.replace("%path", &path) | ||
.replace("%until", &until) | ||
}); | ||
debug!("calling {:?}...", self.command); | ||
let status = Command::new(self.command.command()).args(args).status()?; | ||
if !status.success() { | ||
warn!("lock command was not successful for {tpe:?}, id: {id}. {status}"); | ||
} | ||
Ok(()) | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,75 @@ | ||
//! `lock` subcommand | ||
use chrono::{DateTime, Local}; | ||
use log::error; | ||
use rayon::ThreadPoolBuilder; | ||
|
||
use crate::{ | ||
error::{CommandErrorKind, RepositoryErrorKind, RusticResult}, | ||
progress::{Progress, ProgressBars}, | ||
repofile::{configfile::ConfigId, IndexId, KeyId, PackId, RepoId, SnapshotId}, | ||
repository::Repository, | ||
WriteBackend, | ||
}; | ||
|
||
pub(super) mod constants { | ||
/// The maximum number of reader threads to use for locking. | ||
pub(super) const MAX_LOCKER_THREADS_NUM: usize = 20; | ||
} | ||
|
||
pub fn lock_repo<P: ProgressBars, S>( | ||
repo: &Repository<P, S>, | ||
until: Option<DateTime<Local>>, | ||
) -> RusticResult<()> { | ||
lock_all_files::<P, S, ConfigId>(repo, until)?; | ||
lock_all_files::<P, S, KeyId>(repo, until)?; | ||
lock_all_files::<P, S, SnapshotId>(repo, until)?; | ||
lock_all_files::<P, S, IndexId>(repo, until)?; | ||
lock_all_files::<P, S, PackId>(repo, until)?; | ||
Ok(()) | ||
} | ||
|
||
pub fn lock_all_files<P: ProgressBars, S, ID: RepoId + std::fmt::Debug>( | ||
repo: &Repository<P, S>, | ||
until: Option<DateTime<Local>>, | ||
) -> RusticResult<()> { | ||
if !repo.be.can_lock() { | ||
return Err(CommandErrorKind::NoLockingConfigured.into()); | ||
} | ||
|
||
let p = &repo | ||
.pb | ||
.progress_spinner(format!("listing {:?} files..", ID::TYPE)); | ||
let ids: Vec<ID> = repo.list()?.collect(); | ||
p.finish(); | ||
lock_files(repo, &ids, until) | ||
} | ||
|
||
fn lock_files<P: ProgressBars, S, ID: RepoId + std::fmt::Debug>( | ||
repo: &Repository<P, S>, | ||
ids: &[ID], | ||
until: Option<DateTime<Local>>, | ||
) -> RusticResult<()> { | ||
let pool = ThreadPoolBuilder::new() | ||
.num_threads(constants::MAX_LOCKER_THREADS_NUM) | ||
.build() | ||
.map_err(RepositoryErrorKind::FromThreadPoolbilderError)?; | ||
let p = &repo | ||
.pb | ||
.progress_counter(format!("locking {:?} files..", ID::TYPE)); | ||
p.set_length(ids.len().try_into().unwrap()); | ||
let backend = &repo.be; | ||
pool.in_place_scope(|scope| { | ||
for id in ids { | ||
scope.spawn(move |_| { | ||
if let Err(e) = backend.lock(ID::TYPE, id, until) { | ||
// FIXME: Use error handling | ||
error!("lock failed for {:?} {id:?}. {e}", ID::TYPE); | ||
}; | ||
p.inc(1); | ||
}); | ||
} | ||
}); | ||
p.finish(); | ||
Ok(()) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.