use super::controller::RaidArray; use super::{MemberStatus, RaidAlgorithm, RaidError, RaidLevel}; use std::sync::Arc; pub struct Raid0 { array: Arc, } impl Raid0 { pub fn new(array: Arc) -> Self { Raid0 { array } } fn locate_block(&self, block_offset: u64) -> (usize, u64) { let stripe_index = block_offset / self.array.stripe_size; let member_index = stripe_index % self.array.members.len() as u64; let member_offset = (stripe_index / self.array.members.len() as u64) * self.array.stripe_size; (member_index as usize, member_offset) } } impl RaidAlgorithm for Raid0 { fn read(&mut self, block_offset: u64, size: u64) -> Result, RaidError> { let mut result = Vec::with_capacity(size as usize); let mut current_offset = block_offset; while result.len() < size as usize { let (member_index, member_offset) = self.locate_block(current_offset); let member = &self.array.members[member_index]; if member.status != MemberStatus::Online { return Err("Member offline".into()); } let chunk_size = std::cmp::min(self.array.stripe_size, size - result.len() as u64); let file = std::fs::File::open(&member.device_path)?; use std::io::{Read, Seek}; let mut file = file; file.seek(std::io::SeekFrom::Start( member_offset + current_offset % self.array.stripe_size, ))?; let mut chunk = vec![0u8; chunk_size as usize]; file.read_exact(&mut chunk)?; result.extend_from_slice(&chunk); current_offset += chunk_size; } Ok(result) } fn write(&mut self, block_offset: u64, data: &[u8]) -> Result<(), RaidError> { let mut current_offset = block_offset; let mut data_offset = 0; while data_offset < data.len() { let (member_index, member_offset) = self.locate_block(current_offset); let member = &self.array.members[member_index]; if member.status != MemberStatus::Online { return Err("Member offline".into()); } let chunk_size = std::cmp::min(self.array.stripe_size as usize, data.len() - data_offset); let file = std::fs::OpenOptions::new() .write(true) .open(&member.device_path)?; use std::io::{Seek, Write}; let mut file = file; file.seek(std::io::SeekFrom::Start( member_offset + current_offset % self.array.stripe_size, ))?; file.write_all(&data[data_offset..data_offset + chunk_size])?; current_offset += chunk_size as u64; data_offset += chunk_size; } Ok(()) } fn get_total_size(&self) -> u64 { self.array.total_size } fn get_level(&self) -> RaidLevel { RaidLevel::RAID0 } }