1
+ use std:: cell:: RefCell ;
1
2
use std:: {
2
3
convert:: Infallible ,
3
4
sync:: atomic:: { AtomicUsize , Ordering } ,
4
5
time:: Instant ,
5
6
} ;
6
7
7
8
use anyhow:: { anyhow, bail} ;
9
+ use gix:: objs:: find:: Error ;
8
10
use gix:: {
9
11
bstr:: { BStr , BString , ByteSlice } ,
10
12
features:: progress,
11
13
object:: tree:: diff:: rewrites:: CopySource ,
12
- odb:: FindExt ,
13
14
parallel:: { InOrderIter , SequenceId } ,
14
15
prelude:: ObjectIdExt ,
15
16
Count , Progress ,
@@ -150,13 +151,18 @@ pub fn update(
150
151
} ) ;
151
152
r
152
153
} ;
154
+
155
+ #[ derive( Clone ) ]
153
156
struct Task {
154
157
commit : gix:: hash:: ObjectId ,
155
158
parent_commit : Option < gix:: hash:: ObjectId > ,
156
159
compute_stats : bool ,
157
160
}
161
+
162
+ type Packet = ( SequenceId , Vec < Task > ) ;
163
+
158
164
let ( tx_tree_ids, stat_threads) = {
159
- let ( tx, rx) = crossbeam_channel:: unbounded :: < ( SequenceId , Vec < Task > ) > ( ) ;
165
+ let ( tx, rx) = crossbeam_channel:: unbounded :: < Packet > ( ) ;
160
166
let stat_workers = ( 0 ..threads)
161
167
. map ( |_| {
162
168
scope. spawn ( {
@@ -304,46 +310,94 @@ pub fn update(
304
310
} ;
305
311
drop ( tx_stats) ;
306
312
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 ( ) {
315
364
let res = {
316
365
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 ( ) ) ) ;
318
367
match parents. next ( ) {
319
368
Some ( _) => None ,
320
369
None => res,
321
370
}
322
371
} ;
323
372
if let Some ( ( first_parent, commit) ) = res {
324
- chunk. push ( Task {
373
+ self . chunk . borrow_mut ( ) . push ( Task {
325
374
parent_commit : first_parent,
326
375
commit,
327
376
compute_stats : true ,
328
377
} ) ;
329
378
} else {
330
- chunk. push ( Task {
379
+ self . chunk . borrow_mut ( ) . push ( Task {
331
380
parent_commit : None ,
332
- commit : oid . to_owned ( ) ,
381
+ commit : id . to_owned ( ) ,
333
382
compute_stats : false ,
334
383
} ) ;
335
384
}
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
+ ) )
339
391
. ok ( ) ;
340
- chunk_id += 1 ;
392
+ * self . chunk_id . borrow_mut ( ) += 1 ;
341
393
}
342
394
}
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" ) ) ;
347
401
let mut commits = Vec :: new ( ) ;
348
402
for c in commit_iter {
349
403
match c?. map ( |c| c. id ) {
@@ -354,15 +408,14 @@ pub fn update(
354
408
break ;
355
409
}
356
410
}
357
- Err ( gix:: traverse:: commit:: ancestors:: Error :: FindExisting { .. } ) => {
411
+ Err ( gix:: traverse:: commit:: ancestors:: Error :: Find { .. } ) => {
358
412
writeln ! ( err, "shallow repository - commit history is truncated" ) . ok ( ) ;
359
413
break ;
360
414
}
361
415
Err ( err) => return Err ( err. into ( ) ) ,
362
416
} ;
363
417
}
364
- tx_tree_ids. send ( ( chunk_id, chunk) ) . ok ( ) ;
365
- drop ( tx_tree_ids) ;
418
+ db. send_last_chunk ( ) ;
366
419
let saw_new_commits = !commits. is_empty ( ) ;
367
420
if saw_new_commits {
368
421
traverse_progress. show_throughput ( start) ;
0 commit comments