@@ -3,7 +3,7 @@ use crate::{
33 graph:: { GraphRow , GraphWalker } ,
44 sync:: {
55 gix_repo, repo, CommitId , LogWalker , LogWalkerWithoutFilter ,
6- RepoPath , SharedCommitFilterFn , WalkEntry ,
6+ RepoPath , SharedCommitFilterFn ,
77 } ,
88 AsyncGitNotification , Error ,
99} ;
@@ -47,9 +47,10 @@ pub struct AsyncLog {
4747 filter : Option < SharedCommitFilterFn > ,
4848 partial_extract : AtomicBool ,
4949 repo : RepoPath ,
50- /// All walk entries collected by the background thread, in walk order.
51- /// The graph walker reads these lazily, only as far as the viewport requires.
52- walk_entries : Arc < Mutex < Vec < WalkEntry > > > ,
50+ /// All commit ids collected by the background thread, in walk order.
51+ /// The graph walker reads these lazily, only as far as the viewport
52+ /// requires, looking up each commit's parents on demand.
53+ walk_entries : Arc < Mutex < Vec < CommitId > > > ,
5354 graph_walker : Arc < Mutex < GraphWalker > > ,
5455}
5556
@@ -83,8 +84,8 @@ impl AsyncLog {
8384
8485 /// Computes graph rows for `commit_slice` starting at `global_start`.
8586 ///
86- /// Driven lazily. Processes only as many
87- /// [`WalkEntry`]s as the viewport requires .
87+ /// Driven lazily. Processes only as many walked commits as the
88+ /// viewport requires, resolving their parents on demand .
8889 ///
8990 /// Returns `None` when the background walk hasn't reached
9091 /// `global_start + commit_slice.len()` yet.
@@ -111,8 +112,18 @@ impl AsyncLog {
111112 // we know it is yet to have seen
112113 let processed =
113114 walker. processed_commits ( ) . min ( needed_end) ;
114- for entry in & entries[ processed..needed_end] {
115- walker. process ( entry. id , & entry. parents ) ;
115+
116+ // The graph only needs topology for the commits it is
117+ // about to fold in, so parents are looked up here on
118+ // demand instead of being carried along the whole walk.
119+ if processed < needed_end {
120+ let mut repo = gix_repo ( & self . repo ) . ok ( ) ?;
121+ repo. object_cache_size_if_unset ( 2_usize . pow ( 14 ) ) ;
122+
123+ for id in & entries[ processed..needed_end] {
124+ let parents = Self :: parents_of ( & repo, * id) . ok ( ) ?;
125+ walker. process ( * id, & parents) ;
126+ }
116127 }
117128 }
118129
@@ -125,6 +136,22 @@ impl AsyncLog {
125136 ) )
126137 }
127138
139+ /// Looks up a commit's (up to two) parents on demand.
140+ ///
141+ /// The graph caps support at two parents, ignoring octopus
142+ /// merges, so anything beyond the first two is dropped here.
143+ fn parents_of (
144+ repo : & gix:: Repository ,
145+ id : CommitId ,
146+ ) -> Result < Vec < CommitId > > {
147+ Ok ( repo
148+ . find_commit ( id) ?
149+ . parent_ids ( )
150+ . take ( 2 )
151+ . map ( Into :: into)
152+ . collect ( ) )
153+ }
154+
128155 ///
129156 pub fn count ( & self ) -> Result < usize > {
130157 Ok ( self . current . lock ( ) ?. commits . len ( ) )
@@ -252,7 +279,7 @@ impl AsyncLog {
252279 arc_current : & Arc < Mutex < AsyncLogResult > > ,
253280 arc_background : & Arc < AtomicBool > ,
254281 sender : & Sender < AsyncGitNotification > ,
255- arc_walk_entries : & Arc < Mutex < Vec < WalkEntry > > > ,
282+ arc_walk_entries : & Arc < Mutex < Vec < CommitId > > > ,
256283 filter : Option < SharedCommitFilterFn > ,
257284 ) -> Result < ( ) > {
258285 filter. map_or_else (
@@ -309,7 +336,7 @@ impl AsyncLog {
309336 arc_current : & Arc < Mutex < AsyncLogResult > > ,
310337 arc_background : & Arc < AtomicBool > ,
311338 sender : & Sender < AsyncGitNotification > ,
312- arc_walk_entries : & Arc < Mutex < Vec < WalkEntry > > > ,
339+ arc_walk_entries : & Arc < Mutex < Vec < CommitId > > > ,
313340 ) -> Result < ( ) > {
314341 let mut repo: gix:: Repository = gix_repo ( repo_path) ?;
315342 let mut walker =
@@ -332,23 +359,23 @@ impl AsyncLog {
332359 /// to `arc_current` and (when given) moving the full entries into
333360 /// `walk_entries` for the graph.
334361 fn walk_loop (
335- mut read : impl FnMut ( & mut Vec < WalkEntry > ) -> Result < usize > ,
362+ mut read : impl FnMut ( & mut Vec < CommitId > ) -> Result < usize > ,
336363 arc_current : & Arc < Mutex < AsyncLogResult > > ,
337364 arc_background : & Arc < AtomicBool > ,
338365 sender : & Sender < AsyncGitNotification > ,
339- walk_entries : Option < & Mutex < Vec < WalkEntry > > > ,
366+ walk_entries : Option < & Mutex < Vec < CommitId > > > ,
340367 ) -> Result < ( ) > {
341368 let start_time = Instant :: now ( ) ;
342369
343- let mut entries: Vec < WalkEntry > =
370+ let mut entries: Vec < CommitId > =
344371 Vec :: with_capacity ( LIMIT_COUNT ) ;
345372
346373 loop {
347374 let read_count = read ( & mut entries) ?;
348375
349376 {
350377 let mut current = arc_current. lock ( ) ?;
351- current. commits . extend ( entries. iter ( ) . map ( |e| e . id ) ) ;
378+ current. commits . extend ( entries. iter ( ) . copied ( ) ) ;
352379 current. duration = start_time. elapsed ( ) ;
353380 }
354381
0 commit comments