Skip to content

Commit db67a9f

Browse files
committed
Read blocks in bulk
1 parent 3acbe25 commit db67a9f

File tree

1 file changed

+50
-33
lines changed

1 file changed

+50
-33
lines changed

downstairs/src/extent_inner_raw.rs

Lines changed: 50 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -582,8 +582,9 @@ impl ExtentInner for RawInner {
582582
}
583583

584584
fn validate(&self) -> Result<(), CrucibleError> {
585-
let block_size = self.extent_size.block_size_in_bytes() as u64;
585+
let block_size = self.extent_size.block_size_in_bytes() as usize;
586586

587+
// Read context data to local arrays
587588
let ctx_a = self.layout.read_context_slots_contiguous(
588589
&self.file,
589590
0,
@@ -597,41 +598,57 @@ impl ExtentInner for RawInner {
597598
ContextSlot::B,
598599
)?;
599600

600-
for block in 0..self.extent_size.value {
601-
// Read the block data itself:
602-
let mut buf = vec![0; block_size as usize];
603-
pread_all(self.file.as_fd(), &mut buf, (block_size * block) as i64)
604-
.map_err(|e| {
605-
CrucibleError::IoError(format!(
606-
"extent {}: reading block {block} data failed: {e}",
607-
self.extent_number
608-
))
609-
})?;
610-
let hash = integrity_hash(&[&buf]);
601+
// Read blocks in bulk, 128 KiB at a time
602+
let nblocks = 128 * 1024 / block_size;
603+
let mut buf = vec![0; block_size * nblocks];
604+
for start_block in (0..self.extent_size.value).step_by(nblocks) {
605+
let num_blocks =
606+
((self.extent_size.value - start_block) as usize).min(nblocks);
611607

612-
// Read the active context slot, which is by definition contiguous
613-
let context = match self.active_context[block] {
614-
ContextSlot::A => &ctx_a,
615-
ContextSlot::B => &ctx_b,
616-
}[block as usize];
608+
// Read the block data itself:
609+
buf.resize(num_blocks * block_size, 0u8);
610+
pread_all(
611+
self.file.as_fd(),
612+
&mut buf,
613+
block_size as i64 * start_block as i64,
614+
)
615+
.map_err(|e| {
616+
CrucibleError::IoError(format!(
617+
"extent {}: reading block {start_block} data failed: {e}",
618+
self.extent_number
619+
))
620+
})?;
617621

618-
if let Some(context) = context {
619-
if context.on_disk_hash == hash {
620-
// great work, everyone
621-
} else {
622-
return Err(CrucibleError::GenericError(format!(
623-
"block {block} has an active slot with mismatched hash"
624-
)));
625-
}
626-
} else {
627-
// context slot is empty, hopefully data is as well!
628-
if buf.iter().all(|v| *v == 0u8) {
629-
// great work, everyone
622+
// Hash and check individual blocks against context slots
623+
for (i, data) in buf.chunks_exact(block_size).enumerate() {
624+
let block = start_block as usize + i;
625+
let hash = integrity_hash(&[data]);
626+
627+
// Pick out the active context slot
628+
let context = match self.active_context[block as u64] {
629+
ContextSlot::A => &ctx_a,
630+
ContextSlot::B => &ctx_b,
631+
}[block];
632+
633+
if let Some(context) = context {
634+
if context.on_disk_hash == hash {
635+
// great work, everyone
636+
} else {
637+
return Err(CrucibleError::GenericError(format!(
638+
"block {block} has an active slot \
639+
with mismatched hash"
640+
)));
641+
}
630642
} else {
631-
return Err(CrucibleError::GenericError(format!(
632-
"block {block} has an empty active slot, \
633-
but contains none-zero data"
634-
)));
643+
// context slot is empty, hopefully data is as well!
644+
if data.iter().all(|v| *v == 0u8) {
645+
// great work, everyone
646+
} else {
647+
return Err(CrucibleError::GenericError(format!(
648+
"block {block} has an empty active slot, \
649+
but contains none-zero data",
650+
)));
651+
}
635652
}
636653
}
637654
}

0 commit comments

Comments
 (0)