Radish alpha
h
rad:z3gqcJUoA1n9HaHKufZs5FCSGazv5
Radicle Heartwood Protocol & Stack
Radicle
Git
radicle: separate out the start of ReadOdb
Archived fintohaps opened 2 years ago

The ReadRepository::contains method can be wasteful since it opens and ODB handle and immediately closes it, while its usage may reuqire checking multiple OIDs in a batch, e.g. in the RefsStatus calculation.

Instead, introduce a ReadOdb trait, an Odb associated type to ReadRepository, and a new method ReadRepository::odb for getting the ReadOdb type.

The use of contains in RefsStatus uses the ReadOdb instead to improve the usage performance.

ReadRepository::contains remains a part of the trait as a follow-up task.

6 files changed +80 -22 9cdf0aa1 a9a15500
modified flake.lock
@@ -3,11 +3,11 @@
    "advisory-db": {
      "flake": false,
      "locked": {
-
        "lastModified": 1701193254,
-
        "narHash": "sha256-Hr7efA3GjwqBkGYKmd3XmGckdPQikbcCmOrq7fmTp3A=",
+
        "lastModified": 1711359280,
+
        "narHash": "sha256-Yri+Uexb2h9tN5Rk4hZCfB7dBjy+tOECl4Kor7VgJFI=",
        "owner": "rustsec",
        "repo": "advisory-db",
-
        "rev": "43af5fef0591531a72ebb86c5f1c623ee95c62fe",
+
        "rev": "aa8e65c812517eae85190715fa63f312aa875773",
        "type": "github"
      },
      "original": {
@@ -23,11 +23,11 @@
        ]
      },
      "locked": {
-
        "lastModified": 1701622587,
-
        "narHash": "sha256-o3XhxCCyrUHZ0tlta2W7/MuXzy+n0+BUt3rKFK3DIK4=",
+
        "lastModified": 1711407199,
+
        "narHash": "sha256-A/nB4j3JHL51ztlMQdfKw6y8tUJJzai3bLsZUEEaBxY=",
        "owner": "ipetkov",
        "repo": "crane",
-
        "rev": "c09d2cbe84cc2adfe1943cb2a0b55a71c835ca9a",
+
        "rev": "7e468a455506f2e65550e08dfd45092f0857a009",
        "type": "github"
      },
      "original": {
@@ -41,11 +41,11 @@
        "systems": "systems"
      },
      "locked": {
-
        "lastModified": 1701680307,
-
        "narHash": "sha256-kAuep2h5ajznlPMD9rnQyffWG8EM/C73lejGofXvdM8=",
+
        "lastModified": 1710146030,
+
        "narHash": "sha256-SZ5L6eA7HJ/nmkzGG7/ISclqe6oZdOZTNoesiInkXPQ=",
        "owner": "numtide",
        "repo": "flake-utils",
-
        "rev": "4022d587cbbfd70fe950c1e2083a02621806a725",
+
        "rev": "b1d9ab70662946ef0850d488da1c9019f3a9752a",
        "type": "github"
      },
      "original": {
@@ -56,11 +56,11 @@
    },
    "nixpkgs": {
      "locked": {
-
        "lastModified": 1701961404,
-
        "narHash": "sha256-ieWHyh6kJtabQYUam/dXXi22MgcgLQvl+f2x/95n+us=",
+
        "lastModified": 1711460390,
+
        "narHash": "sha256-akSgjDZL6pVHEfSE6sz1DNSXuYX6hq+P/1Z5IoYWs7E=",
        "owner": "NixOS",
        "repo": "nixpkgs",
-
        "rev": "8fef9eee026f0d95c06b5880ef9c1af0f643aadf",
+
        "rev": "44733514b72e732bd49f5511bd0203dea9b9a434",
        "type": "github"
      },
      "original": {
@@ -89,11 +89,11 @@
        ]
      },
      "locked": {
-
        "lastModified": 1708308739,
-
        "narHash": "sha256-FtKWP6d51kz8282jfziNNcCBpAvEzv2TtKH6dYIXCuA=",
+
        "lastModified": 1711419061,
+
        "narHash": "sha256-+5M/czgYGqs/jKmi8bvYC+JUYboUKNTfkRiesXopeXQ=",
        "owner": "oxalica",
        "repo": "rust-overlay",
-
        "rev": "d45281ce1027a401255db01ea44972afbc569b7e",
+
        "rev": "4c11d2f698ff1149f76b69e72852d5d75f492d0c",
        "type": "github"
      },
      "original": {
modified radicle-node/src/service/message.rs
@@ -2,7 +2,7 @@ use std::{fmt, io, mem};

use radicle::git;
use radicle::storage::refs::{RefsAt, SignedRefsUpdate};
-
use radicle::storage::ReadRepository;
+
use radicle::storage::{ReadOdb, ReadRepository};

use crate::crypto;
use crate::identity::RepoId;
@@ -205,21 +205,23 @@ impl RefsStatus {
            Ok(r) => r,
        };

+
        let odb = repo.odb()?;
        let mut status = RefsStatus::default();
        for theirs in refs.iter() {
-
            status.insert(*theirs, &repo)?;
+
            status.insert(*theirs, &repo, &odb)?;
        }
        Ok(status)
    }

-
    fn insert<S: ReadRepository>(
+
    fn insert<S: ReadRepository, O: ReadOdb>(
        &mut self,
        theirs: RefsAt,
        repo: &S,
+
        odb: &O,
    ) -> Result<(), storage::Error> {
        match RefsAt::new(repo, theirs.remote) {
            Ok(ours) => {
-
                if Self::is_fresh(repo, theirs.at, ours.at)? {
+
                if Self::is_fresh(repo, odb, theirs.at, ours.at)? {
                    self.fresh.push(SignedRefsUpdate {
                        remote: theirs.remote,
                        old: Some(ours.at),
@@ -247,12 +249,13 @@ impl RefsStatus {
    /// If `theirs` is not the same as `ours` and we have not seen
    /// `theirs` before, i.e. it's not a previous `rad/sigrefs`, then
    /// we can consider `theirs` a fresh update.
-
    fn is_fresh<S: ReadRepository>(
+
    fn is_fresh<S: ReadRepository, O: ReadOdb>(
        repo: &S,
+
        odb: &O,
        theirs: git::Oid,
        ours: git::Oid,
    ) -> Result<bool, git::ext::Error> {
-
        if repo.contains(theirs)? {
+
        if odb.contains(theirs) {
            Ok(theirs != ours && !repo.is_ancestor_of(theirs, ours)?)
        } else {
            Ok(true)
modified radicle/src/storage.rs
@@ -419,8 +419,20 @@ impl<T: ReadRepository> HasRepoId for T {
    }
}

+
pub trait ReadOdb: Sized {
+
    /// Check if the underlying ODB contains the given `oid`.
+
    fn contains(&self, oid: Oid) -> bool;
+
}
+

/// Allows read-only access to a repository.
pub trait ReadRepository: Sized + ValidateRepository {
+
    type Odb<'a>: ReadOdb
+
    where
+
        Self: 'a;
+

+
    /// Provide a handle to the ODB
+
    fn odb(&self) -> Result<Self::Odb<'_>, git2::Error>;
+

    /// Return the repository id.
    fn id(&self) -> RepoId;

modified radicle/src/storage/git.rs
@@ -29,7 +29,7 @@ pub use crate::git::{
};
pub use crate::storage::Error;

-
use super::{RemoteId, RemoteRepository, ValidateRepository};
+
use super::{ReadOdb, RemoteId, RemoteRepository, ValidateRepository};

pub static NAMESPACES_GLOB: Lazy<git::refspec::PatternString> =
    Lazy::new(|| git::refspec::pattern!("refs/namespaces/*"));
@@ -328,6 +328,13 @@ pub struct Repository {
    pub backend: git2::Repository,
}

+
/// Limited handle to a `git2::Odb`
+
///
+
/// See [`ReadOdb`].
+
pub struct Odb<'a> {
+
    pub(crate) backend: git2::Odb<'a>,
+
}
+

/// A set of [`Validation`] errors that a caller **must use**.
#[must_use]
#[derive(Debug, Default)]
@@ -565,6 +572,12 @@ impl Repository {
    }
}

+
impl<'a> ReadOdb for Odb<'a> {
+
    fn contains(&self, oid: Oid) -> bool {
+
        self.backend.exists(*oid)
+
    }
+
}
+

impl RemoteRepository for Repository {
    fn remotes(&self) -> Result<Remotes<Verified>, refs::Error> {
        let mut remotes = Vec::new();
@@ -628,6 +641,12 @@ impl ValidateRepository for Repository {
}

impl ReadRepository for Repository {
+
    type Odb<'a> = Odb<'a>;
+

+
    fn odb(&self) -> Result<Self::Odb<'_>, git2::Error> {
+
        self.backend.odb().map(|backend| Odb { backend })
+
    }
+

    fn id(&self) -> RepoId {
        self.id
    }
modified radicle/src/storage/git/cob.rs
@@ -250,6 +250,14 @@ impl<'a, R: storage::ValidateRepository> ValidateRepository for DraftStore<'a, R
}

impl<'a, R: storage::ReadRepository> ReadRepository for DraftStore<'a, R> {
+
    type Odb<'b> = R::Odb<'b>
+
    where
+
        Self: 'b;
+

+
    fn odb(&self) -> Result<Self::Odb<'_>, raw::Error> {
+
        self.repo.odb()
+
    }
+

    fn id(&self) -> identity::RepoId {
        self.repo.id()
    }
modified radicle/src/test/storage.rs
@@ -163,7 +163,23 @@ impl ValidateRepository for MockRepository {
    }
}

+
impl ReadOdb for MockRepository {
+
    fn contains(&self, oid: Oid) -> bool {
+
        self.remotes
+
            .values()
+
            .any(|sigrefs| sigrefs.at == oid || sigrefs.refs.values().any(|oid_| *oid_ == oid))
+
    }
+
}
+

impl ReadRepository for MockRepository {
+
    type Odb<'a> = Self
+
    where
+
        Self: 'a;
+

+
    fn odb(&self) -> Result<Self::Odb<'_>, git2::Error> {
+
        Ok(self.clone())
+
    }
+

    fn id(&self) -> RepoId {
        self.id
    }