1
1
use filetime:: FileTime ;
2
2
3
- use crate :: { extension, State } ;
3
+ use crate :: { extension, Entry , State , Version } ;
4
4
5
5
mod entries;
6
6
pub mod header;
@@ -49,13 +49,13 @@ impl State {
49
49
Options {
50
50
object_hash,
51
51
thread_limit,
52
- min_extension_block_in_bytes_for_threading : _ ,
52
+ min_extension_block_in_bytes_for_threading,
53
53
} : Options ,
54
54
) -> Result < ( Self , git_hash:: ObjectId ) , Error > {
55
55
let ( version, num_entries, post_header_data) = header:: decode ( data, object_hash) ?;
56
56
let start_of_extensions = extension:: end_of_index_entry:: decode ( data, object_hash) ;
57
57
58
- let num_threads = git_features:: parallel:: num_threads ( thread_limit) ;
58
+ let mut num_threads = git_features:: parallel:: num_threads ( thread_limit) ;
59
59
let path_backing_buffer_size = entries:: estimate_path_storage_requirements_in_bytes (
60
60
num_entries,
61
61
data. len ( ) ,
@@ -66,37 +66,82 @@ impl State {
66
66
67
67
let ( entries, ext, data) = match start_of_extensions {
68
68
Some ( offset) if num_threads > 1 => {
69
- let start_of_extensions = & data[ offset..] ;
70
- let index_offsets_table = extension:: index_entry_offset_table:: find ( start_of_extensions, object_hash) ;
71
- let ( entries_res, ( ext, data) ) = git_features:: parallel:: threads ( |_scope| {
72
- match index_offsets_table {
69
+ let extensions_data = & data[ offset..] ;
70
+ let index_offsets_table = extension:: index_entry_offset_table:: find ( extensions_data, object_hash) ;
71
+ let ( entries_res, ( ext, data) ) = git_features:: parallel:: threads ( |scope| {
72
+ let extension_loading =
73
+ ( extensions_data. len ( ) > min_extension_block_in_bytes_for_threading) . then ( {
74
+ num_threads -= 1 ;
75
+ || scope. spawn ( |_| extension:: decode:: all ( extensions_data, object_hash) )
76
+ } ) ;
77
+ let entries_res = match index_offsets_table {
73
78
Some ( entry_offsets) => {
74
- dbg ! ( entry_offsets) ;
75
- todo ! ( "threaded entry loading if its worth it" )
79
+ let chunk_size = ( entry_offsets. len ( ) as f32 / num_threads as f32 ) . ceil ( ) as usize ;
80
+ let num_chunks = entry_offsets. chunks ( chunk_size) . count ( ) ;
81
+ let mut threads = Vec :: with_capacity ( num_chunks) ;
82
+ for ( id, chunks) in entry_offsets. chunks ( chunk_size) . enumerate ( ) {
83
+ let chunks = chunks. to_vec ( ) ;
84
+ threads. push ( scope. spawn ( move |_| {
85
+ let num_entries = chunks. iter ( ) . map ( |c| c. num_entries ) . sum :: < u32 > ( ) as usize ;
86
+ let mut entries = Vec :: with_capacity ( num_entries) ;
87
+ let path_backing_buffer_size = entries:: estimate_path_storage_requirements_in_bytes (
88
+ num_entries as u32 ,
89
+ data. len ( ) / num_chunks,
90
+ start_of_extensions. map ( |ofs| ofs / num_chunks) ,
91
+ object_hash,
92
+ version,
93
+ ) ;
94
+ let mut path_backing = Vec :: with_capacity ( path_backing_buffer_size) ;
95
+ let mut is_sparse = false ;
96
+ for offset in chunks {
97
+ let (
98
+ entries:: Outcome {
99
+ is_sparse : chunk_is_sparse,
100
+ } ,
101
+ _data,
102
+ ) = entries:: load_chunk (
103
+ & data[ offset. from_beginning_of_file as usize ..] ,
104
+ & mut entries,
105
+ & mut path_backing,
106
+ offset. num_entries ,
107
+ object_hash,
108
+ version,
109
+ ) ?;
110
+ is_sparse |= chunk_is_sparse;
111
+ }
112
+ Ok :: < _ , Error > ( (
113
+ id,
114
+ EntriesOutcome {
115
+ entries,
116
+ path_backing,
117
+ is_sparse,
118
+ } ,
119
+ ) )
120
+ } ) ) ;
121
+ }
122
+ todo ! ( "combined thread results in order " )
76
123
}
77
- None => {
78
- // TODO load all extensions in scoped, then get IEOT, then possibly multi-threaded entry parsing
79
- (
80
- entries:: load_all (
81
- post_header_data,
82
- num_entries,
83
- path_backing_buffer_size,
84
- object_hash,
85
- version,
86
- ) ,
87
- extension:: decode:: all ( start_of_extensions, object_hash) ,
88
- )
89
- }
90
- }
124
+ None => load_entries (
125
+ post_header_data,
126
+ path_backing_buffer_size,
127
+ num_entries,
128
+ object_hash,
129
+ version,
130
+ ) ,
131
+ } ;
132
+ let ext_res = extension_loading
133
+ . map ( |thread| thread. join ( ) . unwrap ( ) )
134
+ . unwrap_or_else ( || extension:: decode:: all ( extensions_data, object_hash) ) ;
135
+ ( entries_res, ext_res)
91
136
} )
92
137
. unwrap ( ) ; // this unwrap is for panics - if these happened we are done anyway.
93
138
( entries_res?. 0 , ext, data)
94
139
}
95
140
None | Some ( _) => {
96
- let ( entries, data) = entries :: load_all (
141
+ let ( entries, data) = load_entries (
97
142
post_header_data,
98
- num_entries,
99
143
path_backing_buffer_size,
144
+ num_entries,
100
145
object_hash,
101
146
version,
102
147
) ?;
@@ -113,7 +158,7 @@ impl State {
113
158
}
114
159
115
160
let checksum = git_hash:: ObjectId :: from ( data) ;
116
- let entries :: Outcome {
161
+ let EntriesOutcome {
117
162
entries,
118
163
path_backing,
119
164
is_sparse,
@@ -133,3 +178,38 @@ impl State {
133
178
) )
134
179
}
135
180
}
181
+
182
+ struct EntriesOutcome {
183
+ pub entries : Vec < Entry > ,
184
+ pub path_backing : Vec < u8 > ,
185
+ pub is_sparse : bool ,
186
+ }
187
+
188
+ fn load_entries (
189
+ post_header_data : & [ u8 ] ,
190
+ path_backing_buffer_size : usize ,
191
+ num_entries : u32 ,
192
+ object_hash : git_hash:: Kind ,
193
+ version : Version ,
194
+ ) -> Result < ( EntriesOutcome , & [ u8 ] ) , Error > {
195
+ let mut entries = Vec :: with_capacity ( num_entries as usize ) ;
196
+ let mut path_backing = Vec :: with_capacity ( path_backing_buffer_size) ;
197
+ entries:: load_chunk (
198
+ post_header_data,
199
+ & mut entries,
200
+ & mut path_backing,
201
+ num_entries,
202
+ object_hash,
203
+ version,
204
+ )
205
+ . map ( |( entries:: Outcome { is_sparse } , data) : ( entries:: Outcome , & [ u8 ] ) | {
206
+ (
207
+ EntriesOutcome {
208
+ entries,
209
+ path_backing,
210
+ is_sparse,
211
+ } ,
212
+ data,
213
+ )
214
+ } )
215
+ }
0 commit comments