Skip to content

Commit c8bd660

Browse files
committed
Merge branch 'gix-object-find'
2 parents 9158ffc + 82b01c2 commit c8bd660

File tree

109 files changed

+1219
-1264
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

109 files changed

+1219
-1264
lines changed

gitoxide-core/src/hours/mod.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -140,7 +140,7 @@ where
140140
let mut skipped_merge_commits = 0;
141141
const CHUNK_SIZE: usize = 50;
142142
let mut chunk = Vec::with_capacity(CHUNK_SIZE);
143-
let mut commit_iter = commit_id.ancestors(|oid, buf| repo.objects.find_commit_iter(oid, buf));
143+
let mut commit_iter = commit_id.ancestors(&repo.objects);
144144
let mut is_shallow = false;
145145
while let Some(c) = commit_iter.next() {
146146
progress.inc();
@@ -175,7 +175,7 @@ where
175175
}
176176
commit_idx += 1;
177177
}
178-
Err(gix::traverse::commit::ancestors::Error::FindExisting { .. }) => {
178+
Err(gix::traverse::commit::ancestors::Error::Find { .. }) => {
179179
is_shallow = true;
180180
break;
181181
}

gitoxide-core/src/index/checkout.rs

+44-19
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,8 @@ use std::{
44
};
55

66
use anyhow::bail;
7-
use gix::{odb::FindExt, worktree::state::checkout, NestedProgress, Progress};
7+
use gix::objs::find::Error;
8+
use gix::{worktree::state::checkout, NestedProgress, Progress};
89

910
use crate::{
1011
index,
@@ -89,20 +90,9 @@ pub fn checkout_exclusive(
8990
Some(repo) => gix::worktree::state::checkout(
9091
&mut index,
9192
dest_directory,
92-
{
93-
let objects = repo.objects.into_arc()?;
94-
move |oid, buf| {
95-
objects.find_blob(oid, buf).ok();
96-
if empty_files {
97-
// We always want to query the ODB here…
98-
objects.find_blob(oid, buf)?;
99-
buf.clear();
100-
// …but write nothing
101-
Ok(gix::objs::BlobRef { data: buf })
102-
} else {
103-
objects.find_blob(oid, buf)
104-
}
105-
}
93+
EmptyOrDb {
94+
empty_files,
95+
db: repo.objects.into_arc()?,
10696
},
10797
&files,
10898
&bytes,
@@ -112,10 +102,7 @@ pub fn checkout_exclusive(
112102
None => gix::worktree::state::checkout(
113103
&mut index,
114104
dest_directory,
115-
|_, buf| {
116-
buf.clear();
117-
Ok(gix::objs::BlobRef { data: buf })
118-
},
105+
Empty,
119106
&files,
120107
&bytes,
121108
should_interrupt,
@@ -184,3 +171,41 @@ pub fn checkout_exclusive(
184171
}
185172
Ok(())
186173
}
174+
175+
#[derive(Clone)]
176+
struct EmptyOrDb<Find> {
177+
empty_files: bool,
178+
db: Find,
179+
}
180+
181+
impl<Find> gix::objs::Find for EmptyOrDb<Find>
182+
where
183+
Find: gix::objs::Find,
184+
{
185+
fn try_find<'a>(&self, id: &gix::oid, buf: &'a mut Vec<u8>) -> Result<Option<gix::objs::Data<'a>>, Error> {
186+
if self.empty_files {
187+
// We always want to query the ODB here…
188+
let Some(kind) = self.db.try_find(id, buf)?.map(|d| d.kind) else {
189+
return Ok(None);
190+
};
191+
buf.clear();
192+
// …but write nothing
193+
Ok(Some(gix::objs::Data { kind, data: buf }))
194+
} else {
195+
self.db.try_find(id, buf)
196+
}
197+
}
198+
}
199+
200+
#[derive(Clone)]
201+
struct Empty;
202+
203+
impl gix::objs::Find for Empty {
204+
fn try_find<'a>(&self, _id: &gix::oid, buffer: &'a mut Vec<u8>) -> Result<Option<gix::objs::Data<'a>>, Error> {
205+
buffer.clear();
206+
Ok(Some(gix::objs::Data {
207+
kind: gix::object::Kind::Blob,
208+
data: buffer,
209+
}))
210+
}
211+
}

gitoxide-core/src/index/mod.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,7 @@ pub fn verify(
3535
let file = parse_file(index_path, object_hash)?;
3636
file.verify_integrity()?;
3737
file.verify_entries()?;
38-
file.verify_extensions(false, gix::index::verify::extensions::no_find)?;
38+
file.verify_extensions(false, gix::objs::find::Never)?;
3939
#[cfg_attr(not(feature = "serde"), allow(irrefutable_let_patterns))]
4040
if let crate::OutputFormat::Human = format {
4141
writeln!(out, "OK").ok();

gitoxide-core/src/pack/create.rs

+4-13
Original file line numberDiff line numberDiff line change
@@ -2,13 +2,7 @@ use std::{ffi::OsStr, io, path::Path, str::FromStr, time::Instant};
22

33
use anyhow::anyhow;
44
use gix::{
5-
hash,
6-
hash::ObjectId,
7-
interrupt,
8-
objs::bstr::ByteVec,
9-
odb::{pack, pack::FindExt},
10-
parallel::InOrderIter,
11-
prelude::Finalize,
5+
hash, hash::ObjectId, interrupt, objs::bstr::ByteVec, odb::pack, parallel::InOrderIter, prelude::Finalize,
126
progress, traverse, Count, NestedProgress, Progress,
137
};
148

@@ -136,12 +130,9 @@ where
136130
.collect::<Result<Vec<_>, _>>()?;
137131
let handle = repo.objects.into_shared_arc().to_cache_arc();
138132
let iter = Box::new(
139-
traverse::commit::Ancestors::new(tips, traverse::commit::ancestors::State::default(), {
140-
let handle = handle.clone();
141-
move |oid, buf| handle.find_commit_iter(oid, buf).map(|t| t.0)
142-
})
143-
.map(|res| res.map_err(|err| Box::new(err) as Box<_>).map(|c| c.id))
144-
.inspect(move |_| progress.inc()),
133+
traverse::commit::Ancestors::new(tips, traverse::commit::ancestors::State::default(), handle.clone())
134+
.map(|res| res.map_err(|err| Box::new(err) as Box<_>).map(|c| c.id))
135+
.inspect(move |_| progress.inc()),
145136
);
146137
(handle, iter)
147138
}

gitoxide-core/src/pack/index.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -95,7 +95,7 @@ pub fn from_pack(
9595
directory,
9696
&mut progress,
9797
ctx.should_interrupt,
98-
None,
98+
None::<gix::objs::find::Never>,
9999
options,
100100
)
101101
}
@@ -105,7 +105,7 @@ pub fn from_pack(
105105
directory,
106106
&mut progress,
107107
ctx.should_interrupt,
108-
None,
108+
None::<gix::objs::find::Never>,
109109
options,
110110
),
111111
}

gitoxide-core/src/pack/receive.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -396,7 +396,7 @@ fn receive_pack_blocking<W: io::Write>(
396396
directory.take().as_deref(),
397397
&mut progress,
398398
&ctx.should_interrupt,
399-
None,
399+
None::<gix::objs::find::Never>,
400400
options,
401401
)
402402
.map_err(|err| io::Error::new(io::ErrorKind::Other, err))?;

gitoxide-core/src/query/engine/update.rs

+78-25
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,16 @@
1+
use std::cell::RefCell;
12
use std::{
23
convert::Infallible,
34
sync::atomic::{AtomicUsize, Ordering},
45
time::Instant,
56
};
67

78
use anyhow::{anyhow, bail};
9+
use gix::objs::find::Error;
810
use gix::{
911
bstr::{BStr, BString, ByteSlice},
1012
features::progress,
1113
object::tree::diff::rewrites::CopySource,
12-
odb::FindExt,
1314
parallel::{InOrderIter, SequenceId},
1415
prelude::ObjectIdExt,
1516
Count, Progress,
@@ -150,13 +151,18 @@ pub fn update(
150151
});
151152
r
152153
};
154+
155+
#[derive(Clone)]
153156
struct Task {
154157
commit: gix::hash::ObjectId,
155158
parent_commit: Option<gix::hash::ObjectId>,
156159
compute_stats: bool,
157160
}
161+
162+
type Packet = (SequenceId, Vec<Task>);
163+
158164
let (tx_tree_ids, stat_threads) = {
159-
let (tx, rx) = crossbeam_channel::unbounded::<(SequenceId, Vec<Task>)>();
165+
let (tx, rx) = crossbeam_channel::unbounded::<Packet>();
160166
let stat_workers = (0..threads)
161167
.map(|_| {
162168
scope.spawn({
@@ -304,46 +310,94 @@ pub fn update(
304310
};
305311
drop(tx_stats);
306312

307-
const CHUNK_SIZE: usize = 50;
308-
let mut chunk = Vec::with_capacity(CHUNK_SIZE);
309-
let mut chunk_id: SequenceId = 0;
310-
let commit_iter = gix::interrupt::Iter::new(
311-
commit_id.ancestors(|oid, buf| -> Result<_, gix::object::find::existing::Error> {
312-
let obj = repo.objects.find(oid, buf)?;
313-
traverse_progress.inc();
314-
if known_commits.binary_search(&oid.to_owned()).is_err() {
313+
#[derive(Clone)]
314+
struct Db<'a, Find: Clone> {
315+
inner: &'a Find,
316+
progress: &'a dyn gix::progress::Count,
317+
chunk: std::cell::RefCell<Vec<Task>>,
318+
chunk_id: std::cell::RefCell<SequenceId>,
319+
chunk_size: usize,
320+
tx: crossbeam_channel::Sender<Packet>,
321+
known_commits: &'a [gix::ObjectId],
322+
}
323+
324+
impl<'a, Find> Db<'a, Find>
325+
where
326+
Find: gix::prelude::Find + Clone,
327+
{
328+
fn new(
329+
inner: &'a Find,
330+
progress: &'a dyn gix::progress::Count,
331+
chunk_size: usize,
332+
tx: crossbeam_channel::Sender<Packet>,
333+
known_commits: &'a [gix::ObjectId],
334+
) -> Self {
335+
Self {
336+
inner,
337+
progress,
338+
known_commits,
339+
tx,
340+
chunk_size,
341+
chunk_id: 0.into(),
342+
chunk: RefCell::new(Vec::with_capacity(chunk_size)),
343+
}
344+
}
345+
346+
fn send_last_chunk(self) {
347+
self.tx.send((self.chunk_id.into_inner(), self.chunk.into_inner())).ok();
348+
}
349+
}
350+
351+
impl<'a, Find> gix::prelude::Find for Db<'a, Find>
352+
where
353+
Find: gix::prelude::Find + Clone,
354+
{
355+
fn try_find<'b>(&self, id: &gix::oid, buf: &'b mut Vec<u8>) -> Result<Option<gix::objs::Data<'b>>, Error> {
356+
let obj = self.inner.try_find(id, buf)?;
357+
let Some(obj) = obj else { return Ok(None) };
358+
if !obj.kind.is_commit() {
359+
return Ok(None);
360+
}
361+
362+
self.progress.inc();
363+
if self.known_commits.binary_search(&id.to_owned()).is_err() {
315364
let res = {
316365
let mut parents = gix::objs::CommitRefIter::from_bytes(obj.data).parent_ids();
317-
let res = parents.next().map(|first_parent| (Some(first_parent), oid.to_owned()));
366+
let res = parents.next().map(|first_parent| (Some(first_parent), id.to_owned()));
318367
match parents.next() {
319368
Some(_) => None,
320369
None => res,
321370
}
322371
};
323372
if let Some((first_parent, commit)) = res {
324-
chunk.push(Task {
373+
self.chunk.borrow_mut().push(Task {
325374
parent_commit: first_parent,
326375
commit,
327376
compute_stats: true,
328377
});
329378
} else {
330-
chunk.push(Task {
379+
self.chunk.borrow_mut().push(Task {
331380
parent_commit: None,
332-
commit: oid.to_owned(),
381+
commit: id.to_owned(),
333382
compute_stats: false,
334383
});
335384
}
336-
if chunk.len() == CHUNK_SIZE {
337-
tx_tree_ids
338-
.send((chunk_id, std::mem::replace(&mut chunk, Vec::with_capacity(CHUNK_SIZE))))
385+
if self.chunk.borrow().len() == self.chunk_size {
386+
self.tx
387+
.send((
388+
*self.chunk_id.borrow(),
389+
std::mem::replace(&mut self.chunk.borrow_mut(), Vec::with_capacity(self.chunk_size)),
390+
))
339391
.ok();
340-
chunk_id += 1;
392+
*self.chunk_id.borrow_mut() += 1;
341393
}
342394
}
343-
Ok(gix::objs::CommitRefIter::from_bytes(obj.data))
344-
}),
345-
|| anyhow!("Cancelled by user"),
346-
);
395+
Ok(Some(obj))
396+
}
397+
}
398+
399+
let db = Db::new(&repo.objects, &traverse_progress, 50, tx_tree_ids, &known_commits);
400+
let commit_iter = gix::interrupt::Iter::new(commit_id.ancestors(&db), || anyhow!("Cancelled by user"));
347401
let mut commits = Vec::new();
348402
for c in commit_iter {
349403
match c?.map(|c| c.id) {
@@ -354,15 +408,14 @@ pub fn update(
354408
break;
355409
}
356410
}
357-
Err(gix::traverse::commit::ancestors::Error::FindExisting { .. }) => {
411+
Err(gix::traverse::commit::ancestors::Error::Find { .. }) => {
358412
writeln!(err, "shallow repository - commit history is truncated").ok();
359413
break;
360414
}
361415
Err(err) => return Err(err.into()),
362416
};
363417
}
364-
tx_tree_ids.send((chunk_id, chunk)).ok();
365-
drop(tx_tree_ids);
418+
db.send_last_chunk();
366419
let saw_new_commits = !commits.is_empty();
367420
if saw_new_commits {
368421
traverse_progress.show_throughput(start);

gitoxide-core/src/repository/status.rs

+1-5
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,6 @@ use crate::OutputFormat;
22
use anyhow::{bail, Context};
33
use gix::bstr::{BStr, BString};
44
use gix::index::Entry;
5-
use gix::prelude::FindExt;
65
use gix::Progress;
76
use gix_status::index_as_worktree::traits::FastEq;
87
use gix_status::index_as_worktree::{Change, Conflict, EntryStatus};
@@ -80,10 +79,7 @@ pub fn show(
8079
&mut printer,
8180
FastEq,
8281
Submodule,
83-
{
84-
let odb = repo.objects.clone().into_arc()?;
85-
move |id, buf| odb.find_blob(id, buf)
86-
},
82+
repo.objects.clone().into_arc()?,
8783
&mut progress,
8884
pathspec.detach()?,
8985
repo.filter_pipeline(Some(gix::hash::ObjectId::empty_tree(repo.object_hash())))?

gitoxide-core/src/repository/verify.rs

+1-5
Original file line numberDiff line numberDiff line change
@@ -43,11 +43,7 @@ pub fn integrity(
4343
if let Some(index) = repo.worktree().map(|wt| wt.index()).transpose()? {
4444
index.verify_integrity()?;
4545
index.verify_entries()?;
46-
index.verify_extensions(true, {
47-
use gix::odb::FindExt;
48-
let objects = repo.objects;
49-
move |oid, buf: &mut Vec<u8>| objects.find_tree_iter(oid, buf).ok()
50-
})?;
46+
index.verify_extensions(true, repo.objects)?;
5147
progress.info(format!("Index at '{}' OK", index.path().display()));
5248
}
5349
match output_statistics {

0 commit comments

Comments
 (0)