@@ -319,18 +319,15 @@ impl ExtentInner for RawInner {
319
319
cdt:: extent__read__get__contexts__start!( || {
320
320
( job_id. 0 , self . extent_number. 0 , num_blocks)
321
321
} ) ;
322
- let block_contexts =
323
- self . get_block_contexts ( req. offset . value , num_blocks) ?;
322
+ let blocks = self . get_block_contexts_inner (
323
+ req. offset . value ,
324
+ num_blocks,
325
+ |ctx, _block| ctx. map ( |c| c. block_context ) ,
326
+ ) ?;
324
327
cdt:: extent__read__get__contexts__done!( || {
325
328
( job_id. 0 , self . extent_number. 0 , num_blocks)
326
329
} ) ;
327
330
328
- // Convert from DownstairsBlockContext -> BlockContext
329
- let blocks = block_contexts
330
- . into_iter ( )
331
- . map ( |b| b. map ( |b| b. block_context ) )
332
- . collect ( ) ;
333
-
334
331
// To avoid a `memset`, we're reading directly into uninitialized
335
332
// memory in the buffer. This is fine; we sized the buffer
336
333
// appropriately in advance (and will panic here if we messed up).
@@ -883,7 +880,26 @@ impl RawInner {
883
880
block : u64 ,
884
881
count : u64 ,
885
882
) -> Result < Vec < Option < DownstairsBlockContext > > , CrucibleError > {
886
- let mut out = vec ! [ ] ;
883
+ self . get_block_contexts_inner ( block, count, |ctx, block| {
884
+ ctx. map ( |c| DownstairsBlockContext {
885
+ block,
886
+ block_context : c. block_context ,
887
+ on_disk_hash : c. on_disk_hash ,
888
+ } )
889
+ } )
890
+ }
891
+
892
+ /// Maps a function across block contexts, return a `Vec<T>`
893
+ fn get_block_contexts_inner < F , T > (
894
+ & mut self ,
895
+ block : u64 ,
896
+ count : u64 ,
897
+ f : F ,
898
+ ) -> Result < Vec < T > , CrucibleError >
899
+ where
900
+ F : Fn ( Option < OnDiskDownstairsBlockContext > , u64 ) -> T ,
901
+ {
902
+ let mut out = Vec :: with_capacity ( count as usize ) ;
887
903
let mut reads = 0u64 ;
888
904
for ( slot, group) in ( block..block + count)
889
905
. group_by ( |block| self . active_context [ * block as usize ] )
@@ -892,12 +908,14 @@ impl RawInner {
892
908
let mut group = group. peekable ( ) ;
893
909
let start = * group. peek ( ) . unwrap ( ) ;
894
910
let count = group. count ( ) ;
895
- out . extend ( self . layout . read_context_slots_contiguous (
911
+ self . layout . read_context_slots_contiguous_inner (
896
912
& self . file ,
897
913
start,
898
914
count as u64 ,
899
915
slot,
900
- ) ?) ;
916
+ & f,
917
+ & mut out,
918
+ ) ?;
901
919
reads += 1 ;
902
920
}
903
921
if let Some ( reads) = reads. checked_sub ( 1 ) {
@@ -1205,6 +1223,40 @@ impl RawLayout {
1205
1223
block_count : u64 ,
1206
1224
slot : ContextSlot ,
1207
1225
) -> Result < Vec < Option < DownstairsBlockContext > > , CrucibleError > {
1226
+ let mut out = Vec :: with_capacity ( block_count as usize ) ;
1227
+ self . read_context_slots_contiguous_inner (
1228
+ file,
1229
+ block_start,
1230
+ block_count,
1231
+ slot,
1232
+ |ctx, block| {
1233
+ ctx. map ( |c| DownstairsBlockContext {
1234
+ block,
1235
+ block_context : c. block_context ,
1236
+ on_disk_hash : c. on_disk_hash ,
1237
+ } )
1238
+ } ,
1239
+ & mut out,
1240
+ ) ?;
1241
+ Ok ( out)
1242
+ }
1243
+
1244
+ /// Low-level function to read context slots
1245
+ ///
1246
+ /// This function takes a generic transform function and writes to a
1247
+ /// user-provided array, to minimize allocations.
1248
+ fn read_context_slots_contiguous_inner < F , T > (
1249
+ & self ,
1250
+ file : & File ,
1251
+ block_start : u64 ,
1252
+ block_count : u64 ,
1253
+ slot : ContextSlot ,
1254
+ f : F ,
1255
+ out : & mut Vec < T > ,
1256
+ ) -> Result < ( ) , CrucibleError >
1257
+ where
1258
+ F : Fn ( Option < OnDiskDownstairsBlockContext > , u64 ) -> T ,
1259
+ {
1208
1260
let mut buf =
1209
1261
vec ! [ 0u8 ; ( BLOCK_CONTEXT_SLOT_SIZE_BYTES * block_count) as usize ] ;
1210
1262
@@ -1213,7 +1265,6 @@ impl RawLayout {
1213
1265
CrucibleError :: IoError ( format ! ( "reading context slots failed: {e}" ) )
1214
1266
} ) ?;
1215
1267
1216
- let mut out = vec ! [ ] ;
1217
1268
for ( i, chunk) in buf
1218
1269
. chunks_exact ( BLOCK_CONTEXT_SLOT_SIZE_BYTES as usize )
1219
1270
. enumerate ( )
@@ -1222,13 +1273,10 @@ impl RawLayout {
1222
1273
bincode:: deserialize ( chunk) . map_err ( |e| {
1223
1274
CrucibleError :: BadContextSlot ( e. to_string ( ) )
1224
1275
} ) ?;
1225
- out. push ( ctx. map ( |c| DownstairsBlockContext {
1226
- block : block_start + i as u64 ,
1227
- block_context : c. block_context ,
1228
- on_disk_hash : c. on_disk_hash ,
1229
- } ) ) ;
1276
+ let v = f ( ctx, block_start + i as u64 ) ;
1277
+ out. push ( v) ;
1230
1278
}
1231
- Ok ( out )
1279
+ Ok ( ( ) )
1232
1280
}
1233
1281
1234
1282
/// Write out the active context array and metadata section of the file
0 commit comments