@@ -17,184 +17,14 @@ pub mod traverse;
17
17
///
18
18
pub mod from_offsets;
19
19
20
- /// An item stored within the [`Tree`] whose data is stored in a pack file, identified by
21
- /// the offset of its first (`offset`) and last (`next_offset`) bytes.
22
- ///
23
- /// It represents either a root entry, or one that relies on a base to be resolvable,
24
- /// alongside associated `data` `T`.
25
- pub struct Item < T > {
26
- /// The offset into the pack file at which the pack entry's data is located.
27
- pub offset : crate :: data:: Offset ,
28
- /// The offset of the next item in the pack file.
29
- pub next_offset : crate :: data:: Offset ,
30
- /// Data to store with each Item, effectively data associated with each entry in a pack.
31
- pub data : T ,
32
- /// Indices into our Tree's `items`, one for each pack entry that depends on us.
33
- ///
34
- /// Limited to u32 as that's the maximum amount of objects in a pack.
35
- children : Vec < u32 > ,
36
- }
20
+ /// Tree datastructure
21
+ // kept in separate module to encapsulate unsafety (it has field invariants)
22
+ mod tree;
37
23
38
- /// Identify what kind of node we have last seen
39
- enum NodeKind {
40
- Root ,
41
- Child ,
42
- }
43
-
44
- /// A tree that allows one-time iteration over all nodes and their children, consuming it in the process,
45
- /// while being shareable among threads without a lock.
46
- /// It does this by making the guarantee that iteration only happens once.
47
- pub struct Tree < T > {
48
- /// The root nodes, i.e. base objects
49
- root_items : Vec < Item < T > > ,
50
- /// The child nodes, i.e. those that rely a base object, like ref and ofs delta objects
51
- child_items : Vec < Item < T > > ,
52
- /// The last encountered node was either a root or a child.
53
- last_seen : Option < NodeKind > ,
54
- /// Future child offsets, associating their offset into the pack with their index in the items array.
55
- /// (parent_offset, child_index)
56
- future_child_offsets : Vec < ( crate :: data:: Offset , usize ) > ,
57
- }
58
-
59
- impl < T > Tree < T > {
60
- /// Instantiate a empty tree capable of storing `num_objects` amounts of items.
61
- pub fn with_capacity ( num_objects : usize ) -> Result < Self , Error > {
62
- Ok ( Tree {
63
- root_items : Vec :: with_capacity ( num_objects / 2 ) ,
64
- child_items : Vec :: with_capacity ( num_objects / 2 ) ,
65
- last_seen : None ,
66
- future_child_offsets : Vec :: new ( ) ,
67
- } )
68
- }
69
-
70
- fn num_items ( & self ) -> usize {
71
- self . root_items . len ( ) + self . child_items . len ( )
72
- }
73
-
74
- fn assert_is_incrementing_and_update_next_offset ( & mut self , offset : crate :: data:: Offset ) -> Result < ( ) , Error > {
75
- let items = match & self . last_seen {
76
- Some ( NodeKind :: Root ) => & mut self . root_items ,
77
- Some ( NodeKind :: Child ) => & mut self . child_items ,
78
- None => return Ok ( ( ) ) ,
79
- } ;
80
- let item = & mut items. last_mut ( ) . expect ( "last seen won't lie" ) ;
81
- if offset <= item. offset {
82
- return Err ( Error :: InvariantIncreasingPackOffset {
83
- last_pack_offset : item. offset ,
84
- pack_offset : offset,
85
- } ) ;
86
- }
87
- item. next_offset = offset;
88
- Ok ( ( ) )
89
- }
90
-
91
- fn set_pack_entries_end_and_resolve_ref_offsets (
92
- & mut self ,
93
- pack_entries_end : crate :: data:: Offset ,
94
- ) -> Result < ( ) , traverse:: Error > {
95
- if !self . future_child_offsets . is_empty ( ) {
96
- for ( parent_offset, child_index) in self . future_child_offsets . drain ( ..) {
97
- if let Ok ( i) = self . child_items . binary_search_by_key ( & parent_offset, |i| i. offset ) {
98
- self . child_items [ i] . children . push ( child_index as u32 ) ;
99
- } else if let Ok ( i) = self . root_items . binary_search_by_key ( & parent_offset, |i| i. offset ) {
100
- self . root_items [ i] . children . push ( child_index as u32 ) ;
101
- } else {
102
- return Err ( traverse:: Error :: OutOfPackRefDelta {
103
- base_pack_offset : parent_offset,
104
- } ) ;
105
- }
106
- }
107
- }
108
-
109
- self . assert_is_incrementing_and_update_next_offset ( pack_entries_end)
110
- . expect ( "BUG: pack now is smaller than all previously seen entries" ) ;
111
- Ok ( ( ) )
112
- }
113
-
114
- /// Add a new root node, one that only has children but is not a child itself, at the given pack `offset` and associate
115
- /// custom `data` with it.
116
- pub fn add_root ( & mut self , offset : crate :: data:: Offset , data : T ) -> Result < ( ) , Error > {
117
- self . assert_is_incrementing_and_update_next_offset ( offset) ?;
118
- self . last_seen = NodeKind :: Root . into ( ) ;
119
- self . root_items . push ( Item {
120
- offset,
121
- next_offset : 0 ,
122
- data,
123
- children : Default :: default ( ) ,
124
- } ) ;
125
- Ok ( ( ) )
126
- }
127
-
128
- /// Add a child of the item at `base_offset` which itself resides at pack `offset` and associate custom `data` with it.
129
- pub fn add_child (
130
- & mut self ,
131
- base_offset : crate :: data:: Offset ,
132
- offset : crate :: data:: Offset ,
133
- data : T ,
134
- ) -> Result < ( ) , Error > {
135
- self . assert_is_incrementing_and_update_next_offset ( offset) ?;
136
-
137
- let next_child_index = self . child_items . len ( ) ;
138
- if let Ok ( i) = self . child_items . binary_search_by_key ( & base_offset, |i| i. offset ) {
139
- self . child_items [ i] . children . push ( next_child_index as u32 ) ;
140
- } else if let Ok ( i) = self . root_items . binary_search_by_key ( & base_offset, |i| i. offset ) {
141
- self . root_items [ i] . children . push ( next_child_index as u32 ) ;
142
- } else {
143
- self . future_child_offsets . push ( ( base_offset, next_child_index) ) ;
144
- }
145
-
146
- self . last_seen = NodeKind :: Child . into ( ) ;
147
- self . child_items . push ( Item {
148
- offset,
149
- next_offset : 0 ,
150
- data,
151
- children : Default :: default ( ) ,
152
- } ) ;
153
- Ok ( ( ) )
154
- }
155
- }
24
+ pub use tree:: { Item , Tree } ;
156
25
157
26
#[ cfg( test) ]
158
27
mod tests {
159
- mod tree {
160
- mod from_offsets_in_pack {
161
- use std:: sync:: atomic:: AtomicBool ;
162
-
163
- use crate as pack;
164
-
165
- const SMALL_PACK_INDEX : & str = "objects/pack/pack-a2bf8e71d8c18879e499335762dd95119d93d9f1.idx" ;
166
- const SMALL_PACK : & str = "objects/pack/pack-a2bf8e71d8c18879e499335762dd95119d93d9f1.pack" ;
167
-
168
- const INDEX_V1 : & str = "objects/pack/pack-c0438c19fb16422b6bbcce24387b3264416d485b.idx" ;
169
- const PACK_FOR_INDEX_V1 : & str = "objects/pack/pack-c0438c19fb16422b6bbcce24387b3264416d485b.pack" ;
170
-
171
- use gix_testtools:: fixture_path;
172
-
173
- #[ test]
174
- fn v1 ( ) -> Result < ( ) , Box < dyn std:: error:: Error > > {
175
- tree ( INDEX_V1 , PACK_FOR_INDEX_V1 )
176
- }
177
-
178
- #[ test]
179
- fn v2 ( ) -> Result < ( ) , Box < dyn std:: error:: Error > > {
180
- tree ( SMALL_PACK_INDEX , SMALL_PACK )
181
- }
182
-
183
- fn tree ( index_path : & str , pack_path : & str ) -> Result < ( ) , Box < dyn std:: error:: Error > > {
184
- let idx = pack:: index:: File :: at ( fixture_path ( index_path) , gix_hash:: Kind :: Sha1 ) ?;
185
- crate :: cache:: delta:: Tree :: from_offsets_in_pack (
186
- & fixture_path ( pack_path) ,
187
- idx. sorted_offsets ( ) . into_iter ( ) ,
188
- & |ofs| * ofs,
189
- & |id| idx. lookup ( id) . map ( |index| idx. pack_offset_at_index ( index) ) ,
190
- & mut gix_features:: progress:: Discard ,
191
- & AtomicBool :: new ( false ) ,
192
- gix_hash:: Kind :: Sha1 ,
193
- ) ?;
194
- Ok ( ( ) )
195
- }
196
- }
197
- }
198
28
199
29
#[ test]
200
30
fn size_of_pack_tree_item ( ) {
0 commit comments