@@ -9,9 +9,9 @@ use std::sync::{LazyLock, RwLock};
99pub ( crate ) const CACHE_VERSION : u64 = 24 ;
1010
1111pub trait CacheBackend : Send + Sync {
12- fn read ( & self , filter : filter:: Filter , from : git2:: Oid ) -> JoshResult < Option < git2:: Oid > > ;
12+ fn read ( & self , filter : filter:: Filter , from : git2:: Oid , np : u128 ) -> JoshResult < Option < git2:: Oid > > ;
1313
14- fn write ( & self , filter : filter:: Filter , from : git2:: Oid , to : git2:: Oid ) -> JoshResult < ( ) > ;
14+ fn write ( & self , filter : filter:: Filter , from : git2:: Oid , to : git2:: Oid , np : u128 ) -> JoshResult < ( ) > ;
1515}
1616
1717pub trait FilterHook {
@@ -323,6 +323,7 @@ impl Transaction {
323323 }
324324
325325 pub fn insert ( & self , filter : filter:: Filter , from : git2:: Oid , to : git2:: Oid , store : bool ) {
326+ let np = if filter != filter:: n_parents_f ( ) { n_parents ( self , from) . unwrap ( ) } else { 0 } ;
326327 let mut t2 = self . t2 . borrow_mut ( ) ;
327328 t2. commit_map
328329 . entry ( filter. id ( ) )
@@ -334,14 +335,14 @@ impl Transaction {
334335 // the history length by a very large factor.
335336 if store || from. as_bytes ( ) [ 0 ] == 0 {
336337 t2. cache
337- . write_all ( filter, from, to)
338+ . write_all ( filter, from, to, np )
338339 . expect ( "Failed to write cache" ) ;
339340 }
340341 }
341342
342343 pub fn get_missing ( & self ) -> Vec < ( filter:: Filter , git2:: Oid ) > {
343344 let mut missing = self . t2 . borrow ( ) . missing . clone ( ) ;
344- missing. sort_by_key ( |( f, i) | ( filter:: nesting ( * f) , * f, * i) ) ;
345+ /* missing.sort_by_key(|(f, i)| (filter::nesting(*f), *f, *i)); */
345346 missing. dedup ( ) ;
346347 missing. retain ( |( f, i) | !self . known ( * f, * i) ) ;
347348 self . t2 . borrow_mut ( ) . missing = missing. clone ( ) ;
@@ -358,7 +359,10 @@ impl Transaction {
358359 } else {
359360 let mut t2 = self . t2 . borrow_mut ( ) ;
360361 t2. misses += 1 ;
361- t2. missing . push ( ( filter, from) ) ;
362+ if !t2. missing . contains ( & ( filter, from) ) {
363+ t2. missing . insert ( 0 , ( filter, from) ) ;
364+ /* eprintln!("N MISSING {}", t2.missing.len()); */
365+ }
362366 None
363367 }
364368 }
@@ -367,6 +371,7 @@ impl Transaction {
367371 if filter == filter:: nop ( ) {
368372 return Some ( from) ;
369373 }
374+ let np = if filter != filter:: n_parents_f ( ) { n_parents ( self , from) . unwrap ( ) } else { 0 } ;
370375 let t2 = self . t2 . borrow_mut ( ) ;
371376 if let Some ( m) = t2. commit_map . get ( & filter. id ( ) ) {
372377 if let Some ( oid) = m. get ( & from) . cloned ( ) {
@@ -376,7 +381,7 @@ impl Transaction {
376381
377382 let oid = t2
378383 . cache
379- . read_propagate ( filter, from)
384+ . read_propagate ( filter, from, np )
380385 . expect ( "Failed to read from cache backend" ) ;
381386
382387 let oid = if let Some ( oid) = oid { Some ( oid) } else { None } ;
@@ -385,6 +390,9 @@ impl Transaction {
385390 if oid == git2:: Oid :: zero ( ) {
386391 return Some ( oid) ;
387392 }
393+ if filter == filter:: n_parents_f ( ) {
394+ return Some ( oid) ;
395+ }
388396
389397 if self . repo . odb ( ) . unwrap ( ) . exists ( oid) {
390398 // Only report an object as cached if it exists in the object database.
@@ -396,3 +404,61 @@ impl Transaction {
396404 None
397405 }
398406}
407+
408+
409+ /// Encode a `u128` into a 20-byte git OID (SHA-1 sized).
410+ /// The high 4 bytes of the OID are zero; the low 16 bytes
411+ /// contain the big-endian integer.
412+ pub fn oid_from_u128 ( n : u128 ) -> git2:: Oid {
413+ let mut bytes = [ 0u8 ; 20 ] ;
414+ // place the 16 integer bytes at the end (big-endian)
415+ bytes[ 20 - 16 ..] . copy_from_slice ( & n. to_be_bytes ( ) ) ;
416+ // Safe: length is exactly 20
417+ git2:: Oid :: from_bytes ( & bytes) . expect ( "20-byte OID construction cannot fail" )
418+ }
419+
420+ /// Decode a `u128` previously encoded by `oid_from_u128`.
421+ pub fn u128_from_oid ( oid : git2:: Oid ) -> u128 {
422+ let b = oid. as_bytes ( ) ;
423+ let mut n = [ 0u8 ; 16 ] ;
424+ n. copy_from_slice ( & b[ 20 - 16 ..] ) ; // take the last 16 bytes
425+ u128:: from_be_bytes ( n)
426+ }
427+
428+ pub fn n_parents ( transaction : & cache:: Transaction , input : git2:: Oid ) -> JoshResult < u128 >
429+ {
430+ /* return Ok(0); */
431+ if let Some ( count) = transaction. get ( filter:: n_parents_f ( ) , input) {
432+ return Ok ( u128_from_oid ( count) ) ;
433+ }
434+ eprintln ! ( "n_parents {:?}" , input) ;
435+
436+ let commit = transaction. repo ( ) . find_commit ( input) ?;
437+ if let Some ( p) = commit. parent_ids ( ) . next ( ) {
438+ if let Some ( count) = transaction. get ( filter:: n_parents_f ( ) , p) {
439+ let pc = u128_from_oid ( count) ;
440+ transaction. insert ( filter:: n_parents_f ( ) , input, oid_from_u128 ( pc+1 ) , true ) ;
441+ return n_parents ( transaction, input) ;
442+ }
443+ }
444+
445+ let mut walk = transaction. repo ( ) . revwalk ( ) ?;
446+ /* walk.simplify_first_parent()?; */
447+ walk. set_sorting ( git2:: Sort :: REVERSE | git2:: Sort :: TOPOLOGICAL ) ?;
448+ walk. push ( input) ?;
449+ eprintln ! ( "n_parents walk" ) ;
450+
451+ for c in walk {
452+ let commit = transaction. repo ( ) . find_commit ( c?) ?;
453+ let pc = if let Some ( p) = commit. parent_ids ( ) . next ( ) {
454+ n_parents ( transaction, p) ?
455+ }
456+ else {
457+ 0
458+ } ;
459+
460+ transaction. insert ( filter:: n_parents_f ( ) , commit. id ( ) , oid_from_u128 ( pc+1 ) , true ) ;
461+ }
462+ n_parents ( transaction, input)
463+ }
464+
0 commit comments