2828//! seen.
2929//! * Bands might be deleted, so their numbers are not contiguous.
3030
31- use tracing:: warn ;
31+ use tracing:: { error , trace } ;
3232
33- use crate :: index:: IndexEntryIter ;
33+ use crate :: index:: { IndexEntryIter , IndexHunkIter } ;
3434use crate :: * ;
3535
3636pub struct IterStitchedIndexHunks {
37- /// Current band_id: initially the requested band_id.
38- /// This moves back to earlier bands when we reach the end of an incomplete band.
39- /// Might be none, if no more bands are available.
40- band_id : Option < BandId > ,
41-
4237 /// The latest (and highest-ordered) apath we have already yielded.
4338 last_apath : Option < Apath > ,
4439
45- /// Currently pending index hunks.
46- index_hunks : Option < crate :: index:: IndexHunkIter > ,
47-
4840 archive : Archive ,
41+
42+ state : State ,
43+ }
44+
45+ /// What state is a stitch iter in, and what should happen next?
46+ enum State {
47+ /// We've read to the end of a finished band, or to the earliest existing band, and there is no more content.
48+ Done ,
49+
50+ /// We have know the band to read and have not yet read it at all.
51+ BeforeBand ( BandId ) ,
52+
53+ /// We have some index hunks from a band and can return them gradually.
54+ InBand {
55+ band_id : BandId ,
56+ index_hunks : IndexHunkIter ,
57+ } ,
58+
59+ /// We finished reading a band
60+ AfterBand ( BandId ) ,
4961}
5062
5163impl IterStitchedIndexHunks {
@@ -58,12 +70,19 @@ impl IterStitchedIndexHunks {
5870 /// the same point in the previous band, continuing backwards recursively
5971 /// until either there are no more previous indexes, or a complete index
6072 /// is found.
61- pub ( crate ) fn new ( archive : & Archive , band_id : Option < BandId > ) -> IterStitchedIndexHunks {
73+ pub ( crate ) fn new ( archive : & Archive , band_id : BandId ) -> IterStitchedIndexHunks {
6274 IterStitchedIndexHunks {
6375 archive : archive. clone ( ) ,
64- band_id,
6576 last_apath : None ,
66- index_hunks : None ,
77+ state : State :: BeforeBand ( band_id) ,
78+ }
79+ }
80+
81+ pub ( crate ) fn empty ( archive : & Archive ) -> IterStitchedIndexHunks {
82+ IterStitchedIndexHunks {
83+ archive : archive. clone ( ) ,
84+ last_apath : None ,
85+ state : State :: Done ,
6786 }
6887 }
6988
@@ -81,51 +100,60 @@ impl Iterator for IterStitchedIndexHunks {
81100
82101 fn next ( & mut self ) -> Option < Self :: Item > {
83102 loop {
84- // Until we find the next hunk or run out of bands.
85- // If we're already reading an index, and it has more content, return that.
86- if let Some ( index_hunks) = & mut self . index_hunks {
87- // An index iterator must be assigned to a band.
88- debug_assert ! ( self . band_id. is_some( ) ) ;
89-
90- for hunk in index_hunks {
91- if let Some ( last_entry) = hunk. last ( ) {
92- self . last_apath = Some ( last_entry. apath ( ) . clone ( ) ) ;
103+ self . state = match & mut self . state {
104+ State :: Done => return None ,
105+ State :: InBand {
106+ band_id,
107+ index_hunks,
108+ } => {
109+ if let Some ( hunk) = index_hunks. next ( ) {
110+ if let Some ( last_apath) = hunk. last ( ) . map ( |entry| entry. apath . clone ( ) ) {
111+ trace ! ( %last_apath, "return hunk" ) ;
112+ self . last_apath = Some ( last_apath) ;
113+ } else {
114+ trace ! ( "return empty hunk" ) ;
115+ }
93116 return Some ( hunk) ;
94- } // otherwise, empty, try the next
117+ } else {
118+ State :: AfterBand ( * band_id)
119+ }
95120 }
96- // There are no more index hunks in the current band.
97- self . index_hunks = None ;
98-
99- let band_id = self . band_id . take ( ) . expect ( "last band id should be present" ) ;
100- if self . archive . band_is_closed ( band_id) . unwrap_or ( false ) {
101- // We reached the end of a complete index in this band,
102- // so there's no need to look at any earlier bands, and we're done iterating.
103- return None ;
121+ State :: BeforeBand ( band_id) => {
122+ // Start reading this new index and skip forward until after last_apath
123+ match Band :: open ( & self . archive , * band_id) {
124+ Ok ( band) => {
125+ let mut index_hunks = band. index ( ) . iter_hunks ( ) ;
126+ if let Some ( last) = & self . last_apath {
127+ index_hunks = index_hunks. advance_to_after ( last)
128+ }
129+ State :: InBand {
130+ band_id : * band_id,
131+ index_hunks,
132+ }
133+ }
134+ Err ( err) => {
135+ error ! ( ?band_id, ?err, "Failed to open next band" ) ;
136+ State :: AfterBand ( * band_id)
137+ }
138+ }
104139 }
105-
106- // self.band_id might be None afterwards, if there is no previous band.
107- // If so, we're done.
108- self . band_id = previous_existing_band ( & self . archive , band_id) ;
109- }
110-
111- if let Some ( band_id) = self . band_id {
112- let band = match Band :: open ( & self . archive , band_id) {
113- Ok ( band) => band,
114- Err ( err) => {
115- warn ! ( ?err, ?band_id, "Failed to open band, skipping it" ) ;
116- self . band_id = previous_existing_band ( & self . archive , band_id) ;
117- continue ;
140+ State :: AfterBand ( band_id) => {
141+ if self . archive . band_is_closed ( * band_id) . unwrap_or ( false ) {
142+ trace ! ( ?band_id, "band is closed; stitched iteration complete" ) ;
143+ State :: Done
144+ } else if let Some ( prev_band_id) =
145+ previous_existing_band ( & self . archive , * band_id)
146+ {
147+ trace ! ( ?band_id, ?prev_band_id, "moving back to previous band" ) ;
148+ State :: BeforeBand ( prev_band_id)
149+ } else {
150+ trace ! (
151+ ?band_id,
152+ "no previous band to stitch; stitched iteration is complete"
153+ ) ;
154+ State :: Done
118155 }
119- } ;
120- // Start reading this new index and skip forward until after last_apath
121- let mut iter_hunks = band. index ( ) . iter_hunks ( ) ;
122- if let Some ( last) = & self . last_apath {
123- iter_hunks = iter_hunks. advance_to_after ( last)
124156 }
125- self . index_hunks = Some ( iter_hunks) ;
126- } else {
127- // We got no more bands with possible new index information.
128- return None ;
129157 }
130158 }
131159 }
@@ -136,9 +164,10 @@ fn previous_existing_band(archive: &Archive, mut band_id: BandId) -> Option<Band
136164 // TODO: It might be faster to list the present bands and calculate
137165 // from that, rather than walking backwards one at a time...
138166 if let Some ( prev_band_id) = band_id. previous ( ) {
139- band_id = prev_band_id;
140- if archive. band_exists ( band_id) . unwrap_or ( false ) {
141- return Some ( band_id) ;
167+ if archive. band_exists ( prev_band_id) . unwrap_or ( false ) {
168+ return Some ( prev_band_id) ;
169+ } else {
170+ band_id = prev_band_id;
142171 }
143172 } else {
144173 return None ;
@@ -167,7 +196,7 @@ mod test {
167196 }
168197
169198 fn simple_ls ( archive : & Archive , band_id : BandId ) -> String {
170- let strs: Vec < String > = IterStitchedIndexHunks :: new ( archive, Some ( band_id) )
199+ let strs: Vec < String > = IterStitchedIndexHunks :: new ( archive, band_id)
171200 . flatten ( )
172201 . map ( |entry| format ! ( "{}:{}" , & entry. apath, entry. target. unwrap( ) ) )
173202 . collect ( ) ;
@@ -301,7 +330,7 @@ mod test {
301330
302331 let band_id = band_ids. first ( ) . expect ( "expected at least one band" ) ;
303332
304- let mut iter = IterStitchedIndexHunks :: new ( & af, Some ( * band_id) ) ;
333+ let mut iter = IterStitchedIndexHunks :: new ( & af, * band_id) ;
305334 // Get the first and only index entry.
306335 // `index_hunks` and `band_id` should be `Some`.
307336 assert ! ( iter. next( ) . is_some( ) ) ;
0 commit comments