Radish alpha
h
Radicle Heartwood Protocol & Stack
Radicle
Git (anonymous pull)
Log in to clone via SSH
node: run git gc on fetch
Fintan Halpenny committed 2 years ago
commit cf08a3f7315143a98dd2f6aa75e09c1035554f22
parent dd16356e4e1a53d26dcaa1c07da44faa080cac0d
3 files changed +67 -1
modified radicle-node/src/runtime.rs
@@ -256,6 +256,7 @@ impl Runtime {
            limit: FetchLimit::default(),
            info: git::UserInfo { alias, key: nid },
            local: nid,
+
            expiry: worker::garbage::Expiry::default(),
        };
        let pool = worker::Pool::with(
            worker_recv,
modified radicle-node/src/worker.rs
@@ -3,6 +3,7 @@ mod channels;
mod upload_pack;

pub mod fetch;
+
pub mod garbage;

use std::path::PathBuf;
use std::{io, time};
@@ -162,6 +163,9 @@ pub struct FetchConfig {
    pub info: git::UserInfo,
    /// Public key of the local peer.
    pub local: crypto::PublicKey,
+
    /// Configuration for `git gc` garbage collection. Defaults to `1
+
    /// hour ago`.
+
    pub expiry: garbage::Expiry,
}

/// A worker that replicates git objects.
@@ -279,6 +283,7 @@ impl Worker {
            limit,
            info,
            local,
+
            expiry,
        } = &self.fetch_config;
        let tracking =
            tracking::Config::new(*policy, *scope, tracking::Store::reader(tracking_db)?);
@@ -296,8 +301,15 @@ impl Worker {
            blocked,
            channels,
        )?;
+
        let result = handle.fetch(rid, &self.storage, *limit, remote, refs_at)?;

-
        Ok(handle.fetch(rid, &self.storage, *limit, remote, refs_at)?)
+
        if let Err(e) = garbage::collect(&self.storage, rid, *expiry) {
+
            // N.b. ensure that `git gc` works in debug mode.
+
            debug_assert!(false, "`git gc` failed: {e}");
+

+
            log::warn!(target: "worker", "Failed to run `git gc`: {e}");
+
        }
+
        Ok(result)
    }
}

added radicle-node/src/worker/garbage.rs
@@ -0,0 +1,53 @@
+
use std::process::{Command, ExitStatus, Stdio};
+
use std::{fmt, io};
+

+
use radicle::prelude::Id;
+
use radicle::storage::ReadStorage;
+

+
/// Default expiry time for objects.
+
pub const EXPIRY_DEFAULT: Expiry = Expiry::Hours(1);
+

+
/// Expiry of objects for garbage collector.
+
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
+
pub enum Expiry {
+
    Now,
+
    Seconds(usize),
+
    Hours(usize),
+
    Days(usize),
+
    Weeks(usize),
+
}
+

+
impl Default for Expiry {
+
    fn default() -> Self {
+
        EXPIRY_DEFAULT
+
    }
+
}
+

+
impl fmt::Display for Expiry {
+
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+
        match self {
+
            Self::Now => f.write_str("now"),
+
            Self::Seconds(s) => write!(f, "{s}.seconds.ago"),
+
            Self::Hours(s) => write!(f, "{s}.hours.ago"),
+
            Self::Days(s) => write!(f, "{s}.days.ago"),
+
            Self::Weeks(s) => write!(f, "{s}.weeks.ago"),
+
        }
+
    }
+
}
+

+
/// Run Git garbage collector.
+
pub fn collect(storage: &impl ReadStorage, rid: Id, expiry: Expiry) -> io::Result<ExitStatus> {
+
    let git_dir = storage.path_of(&rid);
+
    let mut gc = Command::new("git");
+
    gc.current_dir(git_dir)
+
        .env_clear()
+
        .envs(std::env::vars().filter(|(key, _)| key == "PATH" || key.starts_with("GIT_TRACE")))
+
        .args(["gc", &format!("--prune={expiry}"), "--auto"])
+
        .stdout(Stdio::piped())
+
        .stdin(Stdio::piped())
+
        .stderr(Stdio::inherit());
+
    let mut child = gc.spawn()?;
+
    let status = child.wait()?;
+

+
    Ok(status)
+
}