Files
markbase/markbase-core/src/vfs/raid.rs
Warren 9b02bbac27
Some checks failed
Test / test (push) Has been cancelled
Test / build (push) Has been cancelled
A: Code quality improvements - fix clippy warnings
- Remove unused imports in server.rs (Body, HeaderValue, RwLock)
- Remove unused imports in forward_acl.rs (tests still need Ipv4Addr)
- Remove unused imports in host_key.rs (Read, Write)
- Remove unused imports in kex_exchange.rs (HostKeyType)
- Remove unused imports in known_hosts.rs (tests need Ipv4Addr)
- Remove unused imports in multiplex.rs (Arc)
- Auto-fix other unused imports via clippy --fix

Tests: 303 passed, 0 failed (4 new tests added)
2026-06-21 23:08:07 +08:00

214 lines
5.9 KiB
Rust

use super::{VfsBackend, VfsDirEntry, VfsError, VfsFile, VfsStat, VfsRaidConfig, VfsRaidLevel};
use std::path::{Path, PathBuf};
pub struct VfsRaidBackend {
config: VfsRaidConfig,
backends: Vec<Box<dyn VfsBackend>>,
stripe_size: usize,
}
impl VfsRaidBackend {
pub fn new(config: VfsRaidConfig, backends: Vec<Box<dyn VfsBackend>>) -> Result<Self, VfsError> {
let min_disks = match config.level {
VfsRaidLevel::Single => 1,
VfsRaidLevel::RaidZ1 => 2,
VfsRaidLevel::RaidZ2 => 3,
VfsRaidLevel::RaidZ3 => 4,
};
if backends.len() < min_disks {
return Err(VfsError::Io(format!("RAID level {} requires at least {} disks",
config.level, min_disks)));
}
let stripe_size = config.stripe_size;
Ok(Self {
config,
backends,
stripe_size,
})
}
pub fn data_disks(&self) -> usize {
match self.config.level {
VfsRaidLevel::Single => self.backends.len(),
VfsRaidLevel::RaidZ1 => self.backends.len() - 1,
VfsRaidLevel::RaidZ2 => self.backends.len() - 2,
VfsRaidLevel::RaidZ3 => self.backends.len() - 3,
}
}
pub fn parity_disks(&self) -> usize {
match self.config.level {
VfsRaidLevel::Single => 0,
VfsRaidLevel::RaidZ1 => 1,
VfsRaidLevel::RaidZ2 => 2,
VfsRaidLevel::RaidZ3 => 3,
}
}
fn calculate_parity_p(data: &[u8]) -> Vec<u8> {
data.iter().fold(vec![0u8; data.len()], |mut p, byte| {
for i in 0..p.len() {
p[i] ^= byte;
}
p
})
}
fn calculate_parity_q(data: &[u8]) -> Vec<u8> {
let mut q = vec![0u8; data.len()];
for (i, byte) in data.iter().enumerate() {
let gf_exp = Self::gf_exp(i);
for j in 0..q.len() {
q[j] ^= Self::gf_mul(byte, gf_exp);
}
}
q
}
fn calculate_parity_r(data: &[u8]) -> Vec<u8> {
let mut r = vec![0u8; data.len()];
for (i, byte) in data.iter().enumerate() {
let gf_exp = Self::gf_exp(i * i);
for j in 0..r.len() {
r[j] ^= Self::gf_mul(byte, gf_exp);
}
}
r
}
fn gf_exp(n: usize) -> u8 {
let mut result = 1;
for _ in 0..n % 255 {
result = Self::gf_mul(&result, 2);
}
result
}
fn gf_mul(a: &u8, b: u8) -> u8 {
let mut p = 0u8;
let mut a = *a;
let mut b = b;
for _ in 0..8 {
if b & 1 != 0 {
p ^= a;
}
let hi_bit = a & 0x80;
a <<= 1;
if hi_bit != 0 {
a ^= 0x1b;
}
b >>= 1;
}
p
}
fn stripe_index(&self, offset: u64) -> usize {
(offset / self.stripe_size as u64) as usize % self.backends.len()
}
fn rebuild_disk(&self, _failed_disk_index: usize) -> Result<(), VfsError> {
if self.config.level == VfsRaidLevel::Single {
return Err(VfsError::Io("Cannot rebuild single disk RAID".to_string()));
}
for backend in &self.backends {
backend.create_dir_all(&PathBuf::from("/"), 0o755)?;
}
Ok(())
}
}
impl VfsBackend for VfsRaidBackend {
fn clone_boxed(&self) -> Box<dyn VfsBackend> {
Box::new(Self {
config: self.config.clone(),
backends: self.backends.iter().map(|b| b.clone_boxed()).collect(),
stripe_size: self.stripe_size,
})
}
fn read_dir(&self, path: &Path) -> Result<Vec<VfsDirEntry>, VfsError> {
self.backends[0].read_dir(path)
}
fn open_file(&self, path: &Path, flags: &super::open_flags::OpenFlags) -> Result<Box<dyn VfsFile>, VfsError> {
self.backends[0].open_file(path, flags)
}
fn stat(&self, path: &Path) -> Result<VfsStat, VfsError> {
self.backends[0].stat(path)
}
fn lstat(&self, path: &Path) -> Result<VfsStat, VfsError> {
self.backends[0].lstat(path)
}
fn create_dir(&self, path: &Path, mode: u32) -> Result<(), VfsError> {
for backend in &self.backends {
backend.create_dir(path, mode)?;
}
Ok(())
}
fn create_dir_all(&self, path: &Path, mode: u32) -> Result<(), VfsError> {
for backend in &self.backends {
backend.create_dir_all(path, mode)?;
}
Ok(())
}
fn remove_dir(&self, path: &Path) -> Result<(), VfsError> {
for backend in &self.backends {
backend.remove_dir(path)?;
}
Ok(())
}
fn remove_file(&self, path: &Path) -> Result<(), VfsError> {
for backend in &self.backends {
backend.remove_file(path)?;
}
Ok(())
}
fn rename(&self, from: &Path, to: &Path) -> Result<(), VfsError> {
for backend in &self.backends {
backend.rename(from, to)?;
}
Ok(())
}
fn set_stat(&self, path: &Path, stat: &VfsStat) -> Result<(), VfsError> {
for backend in &self.backends {
backend.set_stat(path, stat)?;
}
Ok(())
}
fn read_link(&self, path: &Path) -> Result<PathBuf, VfsError> {
self.backends[0].read_link(path)
}
fn create_symlink(&self, target: &Path, link: &Path) -> Result<(), VfsError> {
self.backends[0].create_symlink(target, link)
}
fn real_path(&self, path: &Path) -> Result<PathBuf, VfsError> {
self.backends[0].real_path(path)
}
fn exists(&self, path: &Path) -> bool {
self.backends[0].exists(path)
}
fn hard_link(&self, original: &Path, link: &Path) -> Result<(), VfsError> {
for backend in &self.backends {
backend.hard_link(original, link)?;
}
Ok(())
}
}