rad:z3gqcJUoA1n9HaHKufZs5FCSGazv5 heartwooda9a155006d194008034cc9e01810ae6ea236962f
{
"request": "trigger",
"version": 1,
"event_type": "patch",
"repository": {
"id": "rad:z3gqcJUoA1n9HaHKufZs5FCSGazv5",
"name": "heartwood",
"description": "Radicle Heartwood Protocol & Stack",
"private": false,
"default_branch": "master",
"delegates": [
"did:key:z6MksFqXN3Yhqk8pTJdUGLwATkRfQvwZXPqR2qMEhbS9wzpT",
"did:key:z6MkireRatUThvd3qzfKht1S44wpm4FEWSSa4PRMTSQZ3voM",
"did:key:z6MkkPvBfjP4bQmco5Dm7UGsX2ruDBieEHi8n9DVJWX5sTEz"
]
},
"action": "Created",
"patch": {
"id": "9a456c56be6ccaca41ac88b9c63e71e1b1a81cd5",
"author": {
"id": "did:key:z6MkireRatUThvd3qzfKht1S44wpm4FEWSSa4PRMTSQZ3voM",
"alias": null
},
"title": "radicle: separate out the start of ReadOdb",
"state": {
"status": "archived",
"conflicts": []
},
"before": "9cdf0aa1fdaff9f5a81b399ffbe8ac7a74b747c8",
"after": "a9a155006d194008034cc9e01810ae6ea236962f",
"commits": [
"a9a155006d194008034cc9e01810ae6ea236962f",
"5bca35647d7f5f025fa89f4e78db2ffcc8742daa"
],
"target": "3fc92f83fe089263c470b328414d923227cf0e4a",
"labels": [],
"assignees": [],
"revisions": [
{
"id": "9a456c56be6ccaca41ac88b9c63e71e1b1a81cd5",
"author": {
"id": "did:key:z6MkireRatUThvd3qzfKht1S44wpm4FEWSSa4PRMTSQZ3voM",
"alias": null
},
"description": "The `ReadRepository::contains` method can be wasteful since it opens\nand ODB handle and immediately closes it, while its usage may reuqire\nchecking multiple OIDs in a batch, e.g. in the `RefsStatus`\ncalculation.\n\nInstead, introduce a `ReadOdb` trait, an `Odb` associated type to\n`ReadRepository`, and a new method `ReadRepository::odb` for getting\nthe `ReadOdb` type.\n\nThe use of `contains` in `RefsStatus` uses the `ReadOdb` instead to\nimprove the usage performance.\n\n`ReadRepository::contains` remains a part of the trait as a follow-up\ntask.",
"base": "9cdf0aa1fdaff9f5a81b399ffbe8ac7a74b747c8",
"oid": "b64ca5a44d53db24f3a335aebb6001ac09fe4784",
"timestamp": 1711465845
},
{
"id": "63a50e7517c86128f9388b0e7d3c66bd40714925",
"author": {
"id": "did:key:z6MkireRatUThvd3qzfKht1S44wpm4FEWSSa4PRMTSQZ3voM",
"alias": null
},
"description": "Changes:\n- Move getting the Odb handle outside the loop for each `insert`.",
"base": "9cdf0aa1fdaff9f5a81b399ffbe8ac7a74b747c8",
"oid": "1654adf67a87cc6301bbd1566d1efe633520bcf1",
"timestamp": 1711466487
},
{
"id": "cf705ed50baebc363a4de4b2345575cbcef5f7ec",
"author": {
"id": "did:key:z6MkireRatUThvd3qzfKht1S44wpm4FEWSSa4PRMTSQZ3voM",
"alias": null
},
"description": "Changes:\n- Update commit message title",
"base": "9cdf0aa1fdaff9f5a81b399ffbe8ac7a74b747c8",
"oid": "a9a155006d194008034cc9e01810ae6ea236962f",
"timestamp": 1711471929
}
]
}
}
{
"response": "triggered",
"run_id": {
"id": "a300c18f-aefb-4bd4-bad5-da6bdd216615"
},
"info_url": "https://cci.rad.levitte.org//a300c18f-aefb-4bd4-bad5-da6bdd216615.html"
}
Started at: 2026-09-08 01:28:24.367527+02:00
Commands:
$ rad clone rad:z3gqcJUoA1n9HaHKufZs5FCSGazv5 .
✓ Creating checkout in ./...
✓ Remote cloudhead@z6MksFqXN3Yhqk8pTJdUGLwATkRfQvwZXPqR2qMEhbS9wzpT added
✓ Remote-tracking branch cloudhead@z6MksFqXN3Yhqk8pTJdUGLwATkRfQvwZXPqR2qMEhbS9wzpT/master created for z6MksFqXN3Yhqk8pTJdUGLwATkRfQvwZXPqR2qMEhbS9wzpT
✓ Remote fintohaps@z6MkireRatUThvd3qzfKht1S44wpm4FEWSSa4PRMTSQZ3voM added
✓ Remote-tracking branch fintohaps@z6MkireRatUThvd3qzfKht1S44wpm4FEWSSa4PRMTSQZ3voM/master created for z6MkireRatUThvd3qzfKht1S44wpm4FEWSSa4PRMTSQZ3voM
✓ Remote lorenz@z6MkkPvBfjP4bQmco5Dm7UGsX2ruDBieEHi8n9DVJWX5sTEz added
✓ Remote-tracking branch lorenz@z6MkkPvBfjP4bQmco5Dm7UGsX2ruDBieEHi8n9DVJWX5sTEz/master created for z6MkkPvBfjP4bQmco5Dm7UGsX2ruDBieEHi8n9DVJWX5sTEz
✓ Repository successfully cloned under /opt/radcis/ci.rad.levitte.org/cci/state/a300c18f-aefb-4bd4-bad5-da6bdd216615/w/
╭────────────────────────────────────╮
│ heartwood │
│ Radicle Heartwood Protocol & Stack │
│ 189 issues · 38 patches │
╰────────────────────────────────────╯
Run `cd ./.` to go to the repository directory.
Exit code: 0
$ rad patch checkout 9a456c56be6ccaca41ac88b9c63e71e1b1a81cd5
✓ Switched to branch patch/9a456c5 at revision cf705ed
✓ Branch patch/9a456c5 setup to track rad/patches/9a456c56be6ccaca41ac88b9c63e71e1b1a81cd5
Exit code: 0
$ git config advice.detachedHead false
Exit code: 0
$ git checkout a9a155006d194008034cc9e01810ae6ea236962f
HEAD is now at a9a15500 radicle: introduce ReadOdb
Exit code: 0
$ rad patch show 9a456c56be6ccaca41ac88b9c63e71e1b1a81cd5 -p
╭────────────────────────────────────────────────────────────────────────────────╮
│ Title radicle: separate out the start of ReadOdb │
│ Patch 9a456c56be6ccaca41ac88b9c63e71e1b1a81cd5 │
│ Author fintohaps z6Mkire…SQZ3voM │
│ Head a9a155006d194008034cc9e01810ae6ea236962f │
│ Base 9cdf0aa1fdaff9f5a81b399ffbe8ac7a74b747c8 │
│ Target master │
│ Branches patch/9a456c5 │
│ Commits ahead 2, behind 1483 │
│ Status archived │
│ │
│ 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. │
├────────────────────────────────────────────────────────────────────────────────┤
│ a9a1550 radicle: introduce ReadOdb │
│ 5bca356 nix: nix flake update for rustc-1.77 │
├────────────────────────────────────────────────────────────────────────────────┤
│ ● Revision 9a456c5 @ 9cdf0aa..b64ca5a by fintohaps z6Mkire…SQZ3voM 2 years ago │
│ ↑ Revision 63a50e7 @ 9cdf0aa..1654adf by fintohaps z6Mkire…SQZ3voM 2 years ago │
│ ↑ Revision cf705ed @ 9cdf0aa..a9a1550 by fintohaps z6Mkire…SQZ3voM 2 years ago │
╰────────────────────────────────────────────────────────────────────────────────╯
commit a9a155006d194008034cc9e01810ae6ea236962f
Author: Fintan Halpenny <fintan.halpenny@gmail.com>
Date: Tue Mar 26 14:41:13 2024 +0000
radicle: introduce ReadOdb
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.
Signed-off-by: Fintan Halpenny <fintan.halpenny@gmail.com>
X-Clacks-Overhead: GNU Terry Pratchett
diff --git a/radicle-node/src/service/message.rs b/radicle-node/src/service/message.rs
index d748e1b17..807cc2960 100644
--- a/radicle-node/src/service/message.rs
+++ b/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)
diff --git a/radicle/src/storage.rs b/radicle/src/storage.rs
index 1417457ab..b0ce31d60 100644
--- a/radicle/src/storage.rs
+++ b/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;
diff --git a/radicle/src/storage/git.rs b/radicle/src/storage/git.rs
index f93f36843..c91e88e23 100644
--- a/radicle/src/storage/git.rs
+++ b/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
}
diff --git a/radicle/src/storage/git/cob.rs b/radicle/src/storage/git/cob.rs
index e7c20c0f5..a7af0c248 100644
--- a/radicle/src/storage/git/cob.rs
+++ b/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()
}
diff --git a/radicle/src/test/storage.rs b/radicle/src/test/storage.rs
index 5b5723491..aecd45cf8 100644
--- a/radicle/src/test/storage.rs
+++ b/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
}
commit 5bca35647d7f5f025fa89f4e78db2ffcc8742daa
Author: Fintan Halpenny <fintan.halpenny@gmail.com>
Date: Tue Mar 26 15:03:15 2024 +0000
nix: nix flake update for rustc-1.77
Update the `flake.lock` to get the latest rustc version for
development.
Signed-off-by: Fintan Halpenny <fintan.halpenny@gmail.com>
X-Clacks-Overhead: GNU Terry Pratchett
diff --git a/flake.lock b/flake.lock
index 9e7bcddec..8d1fe94f4 100644
--- a/flake.lock
+++ b/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": {
Exit code: 0
shell: 'cargo --version rustc --version cargo fmt --check cargo clippy --all-targets --workspace -- --deny clippy::all cargo build --all-targets --workspace cargo doc --workspace cargo test --workspace --no-fail-fast '
Commands:
$ podman run --name a300c18f-aefb-4bd4-bad5-da6bdd216615 -v /opt/radcis/ci.rad.levitte.org/cci/state/a300c18f-aefb-4bd4-bad5-da6bdd216615/s:/a300c18f-aefb-4bd4-bad5-da6bdd216615/s:ro -v /opt/radcis/ci.rad.levitte.org/cci/state/a300c18f-aefb-4bd4-bad5-da6bdd216615/w:/a300c18f-aefb-4bd4-bad5-da6bdd216615/w -w /a300c18f-aefb-4bd4-bad5-da6bdd216615/w -v /opt/radcis/ci.rad.levitte.org/.radicle:/${id}/.radicle:ro -e RAD_HOME=/${id}/.radicle rust:trixie bash /a300c18f-aefb-4bd4-bad5-da6bdd216615/s/script.sh
+ cargo --version
info: syncing channel updates for '1.77-x86_64-unknown-linux-gnu'
info: latest update on 2024-04-09, rust version 1.77.2 (25ef9e3d8 2024-04-09)
info: downloading component 'cargo'
info: downloading component 'rust-std'
info: downloading component 'rustc'
info: installing component 'cargo'
info: installing component 'rust-std'
info: installing component 'rustc'
cargo 1.77.2 (e52e36006 2024-03-26)
+ rustc --version
rustc 1.77.2 (25ef9e3d8 2024-04-09)
+ cargo fmt --check
error: 'cargo-fmt' is not installed for the toolchain '1.77-x86_64-unknown-linux-gnu'.
To install, run `rustup component add --toolchain 1.77-x86_64-unknown-linux-gnu rustfmt`
Exit code: 1
{
"response": "finished",
"result": "failure"
}