| 1 | pub struct Disk { |
| 2 | pub visible: Vec<u8>, |
| 3 | pub durable: Vec<u8>, |
| 4 | pub operation: usize, |
| 5 | pub fail_at: Option<usize>, |
| 6 | pub write_limit: usize, |
| 7 | pub random: u64, |
| 8 | } |
| 9 | |
| 10 | impl Disk { |
| 11 | fn interrupt(&mut self) -> std::io::Result<()> { |
| 12 | self.operation += 1; |
| 13 | if self.fail_at != Some(self.operation) { |
| 14 | return Ok(()); |
| 15 | } |
| 16 | self.durable.resize(self.visible.len(), 0); |
| 17 | for (durable, visible) in self.durable.iter_mut().zip(&self.visible) { |
| 18 | self.random ^= self.random << 13; |
| 19 | self.random ^= self.random >> 7; |
| 20 | self.random ^= self.random << 17; |
| 21 | if self.random & 1 != 0 { |
| 22 | *durable = *visible; |
| 23 | } |
| 24 | } |
| 25 | Err(std::io::Error::other("Injected storage interruption")) |
| 26 | } |
| 27 | } |
| 28 | |
| 29 | impl onestore::CommitIo for Disk { |
| 30 | fn read_at(&mut self, offset: u64, bytes: &mut [u8]) -> std::io::Result<usize> { |
| 31 | self.interrupt()?; |
| 32 | let offset = offset as usize; |
| 33 | let size = bytes |
| 34 | .len() |
| 35 | .min(193) |
| 36 | .min(self.visible.len().saturating_sub(offset)); |
| 37 | bytes[..size].copy_from_slice(&self.visible[offset..offset + size]); |
| 38 | Ok(size) |
| 39 | } |
| 40 | fn write_at(&mut self, offset: u64, bytes: &[u8]) -> std::io::Result<usize> { |
| 41 | let offset = offset as usize; |
| 42 | let size = bytes.len().min(self.write_limit); |
| 43 | self.visible |
| 44 | .resize(self.visible.len().max(offset + size), 0); |
| 45 | self.visible[offset..offset + size].copy_from_slice(&bytes[..size]); |
| 46 | self.interrupt()?; |
| 47 | Ok(size) |
| 48 | } |
| 49 | fn flush(&mut self) -> std::io::Result<()> { |
| 50 | self.interrupt()?; |
| 51 | self.durable.clone_from(&self.visible); |
| 52 | Ok(()) |
| 53 | } |
| 54 | } |