874 lines
23 KiB
Rust
874 lines
23 KiB
Rust
use std::fs::File;
|
|
use std::io::Write;
|
|
|
|
use super::{Cluster, Domain, DomainOverlap, Stage};
|
|
|
|
use anyhow;
|
|
use ron::de::from_reader;
|
|
use ron::error::SpannedError;
|
|
use serde::{Deserialize, Serialize};
|
|
|
|
#[derive(Clone, Debug, Serialize, Deserialize, PartialEq)]
|
|
pub struct MapFile {
|
|
pub sector_size: usize,
|
|
pub domain: Domain,
|
|
pub map: Vec<Cluster>,
|
|
}
|
|
|
|
impl TryFrom<File> for MapFile {
|
|
type Error = SpannedError;
|
|
|
|
fn try_from(file: File) -> Result<Self, Self::Error> {
|
|
from_reader(file)
|
|
}
|
|
}
|
|
|
|
impl Default for MapFile {
|
|
fn default() -> Self {
|
|
MapFile {
|
|
sector_size: crate::FB_SECTOR_SIZE,
|
|
domain: Domain::default(),
|
|
map: vec![Cluster {
|
|
domain: Domain::default(),
|
|
stage: Stage::Untested,
|
|
}],
|
|
}
|
|
}
|
|
}
|
|
|
|
impl MapFile {
|
|
pub fn new(sector_size: usize) -> Self {
|
|
MapFile::default().set_sector_size(sector_size).to_owned()
|
|
}
|
|
|
|
pub fn set_sector_size(&mut self, sector_size: usize) -> &mut Self {
|
|
self.sector_size = sector_size;
|
|
self
|
|
}
|
|
|
|
/// Recalculate cluster mappings.
|
|
pub fn update(&mut self, new: Cluster) -> &mut Self {
|
|
let mut map: Vec<Cluster> = vec![Cluster::from(new.clone())];
|
|
|
|
for old in self.map.iter() {
|
|
let mut old = *old;
|
|
|
|
match new.domain.overlap(old.domain) {
|
|
DomainOverlap::None => map.push(old),
|
|
DomainOverlap::SelfEngulfsOther => (),
|
|
DomainOverlap::OtherEngulfsSelf => {
|
|
other_engulfs_self_update(new, &mut old, &mut map)
|
|
}
|
|
DomainOverlap::OtherOverlapsEnd => {
|
|
// Case 1
|
|
old.domain.start = new.domain.end;
|
|
map.push(old);
|
|
}
|
|
DomainOverlap::OtherOverlapsStart => {
|
|
// Case 2
|
|
old.domain.end = new.domain.start;
|
|
map.push(old);
|
|
}
|
|
};
|
|
}
|
|
|
|
self.map = map;
|
|
self
|
|
}
|
|
|
|
/// Get current recovery stage.
|
|
pub fn get_stage(&self) -> Stage {
|
|
let mut recover_stage = Stage::Damaged;
|
|
|
|
for cluster in self.map.iter() {
|
|
match cluster.stage {
|
|
Stage::Untested => return Stage::Untested,
|
|
Stage::ForIsolation { .. } => {
|
|
if recover_stage == Stage::Damaged || cluster.stage < recover_stage {
|
|
// Note that recover_stage after first condition is
|
|
// only ever Stage::ForIsolation(_), thus PartialEq,
|
|
// PartialOrd are useful for comparing the internal value.
|
|
recover_stage = cluster.stage
|
|
}
|
|
}
|
|
Stage::Damaged => (),
|
|
Stage::Intact => (),
|
|
}
|
|
}
|
|
|
|
recover_stage
|
|
}
|
|
|
|
/// Get clusters of common stage.
|
|
pub fn get_clusters(&self, stage: Stage) -> Vec<Cluster> {
|
|
self.map
|
|
.iter()
|
|
.filter_map(|mc| {
|
|
if mc.stage == stage {
|
|
Some(mc.to_owned())
|
|
} else {
|
|
None
|
|
}
|
|
})
|
|
.collect()
|
|
}
|
|
|
|
/// Defragments cluster groups.
|
|
/// I.E. check forwards every cluster from current until stage changes,
|
|
/// then group at once.
|
|
pub fn defrag(&mut self) -> &mut Self {
|
|
let mut new_map: Vec<Cluster> = vec![];
|
|
|
|
// Fetch first cluster.
|
|
let mut start_cluster = self.map.iter().find(|c| c.domain.start == 0).unwrap();
|
|
|
|
// Even though this would be initialized by its first read,
|
|
// the compiler won't stop whining, and idk how to assert that to it.
|
|
let mut end_cluster = Cluster::default();
|
|
let mut new_cluster: Cluster;
|
|
|
|
let mut stage_common: bool;
|
|
let mut is_finished = false;
|
|
|
|
while !is_finished {
|
|
stage_common = true;
|
|
|
|
// Start a new cluster based on the cluster following
|
|
// the end of last new_cluster.
|
|
new_cluster = start_cluster.to_owned();
|
|
|
|
// While stage is common, and not finished,
|
|
// find each trailing cluster.
|
|
while stage_common && !is_finished {
|
|
end_cluster = start_cluster.to_owned();
|
|
|
|
if end_cluster.domain.end != self.domain.end {
|
|
start_cluster = self
|
|
.map
|
|
.iter()
|
|
.find(|c| end_cluster.domain.end == c.domain.start)
|
|
.unwrap();
|
|
|
|
stage_common = new_cluster.stage == start_cluster.stage
|
|
} else {
|
|
is_finished = true;
|
|
}
|
|
}
|
|
|
|
// Set the new ending, encapsulating any clusters of common stage.
|
|
new_cluster.domain.end = end_cluster.domain.end;
|
|
new_map.push(new_cluster);
|
|
}
|
|
|
|
self.map = new_map;
|
|
self
|
|
}
|
|
|
|
/// Extend the domain of the MapFile.
|
|
/// Returns None if the domain cannot be changed or is unchanged.
|
|
/// Returns the delta of the previous domain end and the new end.
|
|
pub fn extend(&mut self, end: usize) -> Option<usize> {
|
|
if end <= self.domain.end {
|
|
return None;
|
|
}
|
|
|
|
let old_end = self.domain.end;
|
|
let delta = end - old_end;
|
|
self.domain.end = end;
|
|
|
|
// Add new data as untested.
|
|
self.update(Cluster {
|
|
domain: Domain {
|
|
start: old_end,
|
|
end: self.domain.end,
|
|
},
|
|
..Default::default()
|
|
});
|
|
Some(delta)
|
|
}
|
|
|
|
/// Writes the map to the provided item implementing `Write` trait.
|
|
/// Usually a file.
|
|
pub fn write_to<W: Write>(&mut self, file: &mut W) -> anyhow::Result<usize> {
|
|
self.defrag();
|
|
|
|
let written_bytes = file.write(
|
|
ron::ser::to_string_pretty(
|
|
self,
|
|
ron::ser::PrettyConfig::new()
|
|
.new_line("\n".to_string())
|
|
.struct_names(true),
|
|
)?
|
|
.as_bytes(),
|
|
)?;
|
|
|
|
Ok(written_bytes)
|
|
}
|
|
}
|
|
|
|
// This is split out for a shred of readability.
|
|
fn other_engulfs_self_update(new: Cluster, old: &mut Cluster, map: &mut Vec<Cluster>) {
|
|
if new.domain.start == old.domain.start {
|
|
// Case 6 of map::tests::test_update
|
|
old.domain.start = new.domain.end;
|
|
} else {
|
|
// Case 4 and part of 10
|
|
|
|
let old_end = old.domain.end;
|
|
old.domain.end = new.domain.start;
|
|
|
|
if new.domain.end != old_end {
|
|
// Case 10 of map::tests::test_update
|
|
map.push(Cluster {
|
|
domain: Domain {
|
|
start: new.domain.end,
|
|
end: old_end,
|
|
},
|
|
stage: old.stage,
|
|
})
|
|
}
|
|
}
|
|
|
|
map.push(old.to_owned())
|
|
}
|
|
|
|
#[cfg(test)]
|
|
mod tests {
|
|
use super::*;
|
|
|
|
/// Test for MapFile::update()
|
|
#[test]
|
|
fn update_1_new_overlaps_start() {
|
|
// Case 1:
|
|
// |----new----|
|
|
// |----old----|
|
|
//
|
|
// | --> |-old-|
|
|
// Solution: old.start = new.end
|
|
|
|
let mut map = MapFile {
|
|
map: vec![Cluster {
|
|
domain: Domain { start: 1, end: 3 },
|
|
..Default::default()
|
|
}],
|
|
..Default::default()
|
|
};
|
|
|
|
map.update(Cluster {
|
|
domain: Domain { start: 0, end: 2 },
|
|
..Default::default()
|
|
});
|
|
map.map.sort();
|
|
|
|
assert_eq!(
|
|
map.map,
|
|
vec![
|
|
Cluster {
|
|
domain: Domain { start: 0, end: 2 },
|
|
..Default::default()
|
|
},
|
|
Cluster {
|
|
domain: Domain { start: 2, end: 3 },
|
|
..Default::default()
|
|
}
|
|
]
|
|
);
|
|
}
|
|
|
|
/// Test for MapFile::update()
|
|
#[test]
|
|
fn update_2_new_overlaps_end() {
|
|
// Case 2:
|
|
// |----new----|
|
|
// |----old----|
|
|
//
|
|
// |-old-| <-- |
|
|
// Solution: old.end = new.start
|
|
|
|
let mut map = MapFile {
|
|
map: vec![Cluster {
|
|
domain: Domain { start: 0, end: 2 },
|
|
..Default::default()
|
|
}],
|
|
..Default::default()
|
|
};
|
|
|
|
map.update(Cluster {
|
|
domain: Domain { start: 1, end: 3 },
|
|
..Default::default()
|
|
});
|
|
map.map.sort();
|
|
|
|
assert_eq!(
|
|
map.map,
|
|
vec![
|
|
Cluster {
|
|
domain: Domain { start: 0, end: 1 },
|
|
..Default::default()
|
|
},
|
|
Cluster {
|
|
domain: Domain { start: 1, end: 3 },
|
|
..Default::default()
|
|
}
|
|
]
|
|
);
|
|
}
|
|
|
|
/// Test for MapFile::update()
|
|
#[test]
|
|
fn update_3_new_engulfs_common_end() {
|
|
// Case 3:
|
|
// |----new----|
|
|
// |--old--|
|
|
//
|
|
// Solution: Remove old.
|
|
|
|
let mut map = MapFile {
|
|
map: vec![Cluster {
|
|
domain: Domain { start: 1, end: 3 },
|
|
..Default::default()
|
|
}],
|
|
..Default::default()
|
|
};
|
|
|
|
map.update(Cluster {
|
|
domain: Domain { start: 0, end: 3 },
|
|
..Default::default()
|
|
});
|
|
map.map.sort();
|
|
|
|
assert_eq!(
|
|
map.map,
|
|
vec![Cluster {
|
|
domain: Domain { start: 0, end: 3 },
|
|
..Default::default()
|
|
}]
|
|
);
|
|
}
|
|
|
|
/// Test for MapFile::update()
|
|
#[test]
|
|
fn update_4_old_engulfs_common_end() {
|
|
// Case 4:
|
|
// |--new--|
|
|
// |-----old-----|
|
|
//
|
|
// |-old-| <---- |
|
|
// Solution: old.end = new.start
|
|
|
|
let mut map = MapFile {
|
|
map: vec![Cluster {
|
|
domain: Domain { start: 0, end: 3 },
|
|
..Default::default()
|
|
}],
|
|
..Default::default()
|
|
};
|
|
|
|
map.update(Cluster {
|
|
domain: Domain { start: 1, end: 3 },
|
|
..Default::default()
|
|
});
|
|
map.map.sort();
|
|
|
|
assert_eq!(
|
|
map.map,
|
|
vec![
|
|
Cluster {
|
|
domain: Domain { start: 0, end: 1 },
|
|
..Default::default()
|
|
},
|
|
Cluster {
|
|
domain: Domain { start: 1, end: 3 },
|
|
..Default::default()
|
|
}
|
|
]
|
|
);
|
|
}
|
|
|
|
/// Test for MapFile::update()
|
|
#[test]
|
|
fn update_5_new_engulfs_common_start() {
|
|
// Case 5:
|
|
// |-----new----|
|
|
// |--old--|
|
|
//
|
|
// Solution: Remove old.
|
|
|
|
let mut map = MapFile {
|
|
map: vec![Cluster {
|
|
domain: Domain { start: 0, end: 2 },
|
|
..Default::default()
|
|
}],
|
|
..Default::default()
|
|
};
|
|
|
|
map.update(Cluster {
|
|
domain: Domain { start: 0, end: 3 },
|
|
..Default::default()
|
|
});
|
|
map.map.sort();
|
|
|
|
assert_eq!(
|
|
map.map,
|
|
vec![Cluster {
|
|
domain: Domain { start: 0, end: 3 },
|
|
..Default::default()
|
|
}]
|
|
);
|
|
}
|
|
|
|
/// Test for MapFile::update()
|
|
#[test]
|
|
fn update_6_old_engulfs_common_start() {
|
|
// Case 6:
|
|
// |--new--|
|
|
// |-----old-----|
|
|
//
|
|
// | ----> |-old-|
|
|
// Solution: old.start = new.end
|
|
|
|
let mut map = MapFile {
|
|
map: vec![Cluster {
|
|
domain: Domain { start: 0, end: 3 },
|
|
..Default::default()
|
|
}],
|
|
..Default::default()
|
|
};
|
|
|
|
map.update(Cluster {
|
|
domain: Domain { start: 0, end: 2 },
|
|
..Default::default()
|
|
});
|
|
map.map.sort();
|
|
|
|
assert_eq!(
|
|
map.map,
|
|
vec![
|
|
Cluster {
|
|
domain: Domain { start: 0, end: 2 },
|
|
..Default::default()
|
|
},
|
|
Cluster {
|
|
domain: Domain { start: 2, end: 3 },
|
|
..Default::default()
|
|
}
|
|
]
|
|
);
|
|
}
|
|
|
|
/// Test for MapFile::update()
|
|
#[test]
|
|
fn update_7_new_precedes() {
|
|
// Case 7:
|
|
// |--new--|
|
|
// |--old--|
|
|
//
|
|
// Solution: Leave unchanged.
|
|
|
|
let mut map = MapFile {
|
|
map: vec![Cluster {
|
|
domain: Domain { start: 2, end: 3 },
|
|
..Default::default()
|
|
}],
|
|
..Default::default()
|
|
};
|
|
|
|
map.update(Cluster {
|
|
domain: Domain { start: 0, end: 2 },
|
|
..Default::default()
|
|
});
|
|
map.map.sort();
|
|
|
|
assert_eq!(
|
|
map.map,
|
|
vec![
|
|
Cluster {
|
|
domain: Domain { start: 0, end: 2 },
|
|
..Default::default()
|
|
},
|
|
Cluster {
|
|
domain: Domain { start: 2, end: 3 },
|
|
..Default::default()
|
|
}
|
|
]
|
|
);
|
|
}
|
|
|
|
/// Test for MapFile::update()
|
|
#[test]
|
|
fn update_8_new_trails() {
|
|
// Case 8:
|
|
// |--new--|
|
|
// |--old--|
|
|
// Solution: Leave unchanged.
|
|
|
|
let mut map = MapFile {
|
|
map: vec![Cluster {
|
|
domain: Domain { start: 0, end: 2 },
|
|
..Default::default()
|
|
}],
|
|
..Default::default()
|
|
};
|
|
|
|
map.update(Cluster {
|
|
domain: Domain { start: 2, end: 3 },
|
|
..Default::default()
|
|
});
|
|
map.map.sort();
|
|
|
|
assert_eq!(
|
|
map.map,
|
|
vec![
|
|
Cluster {
|
|
domain: Domain { start: 0, end: 2 },
|
|
..Default::default()
|
|
},
|
|
Cluster {
|
|
domain: Domain { start: 2, end: 3 },
|
|
..Default::default()
|
|
}
|
|
]
|
|
);
|
|
}
|
|
|
|
/// Test for MapFile::update()
|
|
#[test]
|
|
fn update_9_new_engulfs() {
|
|
// Case 9:
|
|
// |-----new-----|
|
|
// |--old--|
|
|
//
|
|
// Solution: Remove old.
|
|
|
|
let mut map = MapFile {
|
|
map: vec![Cluster {
|
|
domain: Domain { start: 1, end: 2 },
|
|
..Default::default()
|
|
}],
|
|
..Default::default()
|
|
};
|
|
|
|
map.update(Cluster {
|
|
domain: Domain { start: 0, end: 3 },
|
|
..Default::default()
|
|
});
|
|
map.map.sort();
|
|
|
|
assert_eq!(
|
|
map.map,
|
|
vec![Cluster {
|
|
domain: Domain { start: 0, end: 3 },
|
|
..Default::default()
|
|
}]
|
|
);
|
|
}
|
|
|
|
/// Test for MapFile::update()
|
|
#[test]
|
|
fn update_10_old_engulfs() {
|
|
// Case 10:
|
|
// |--new--|
|
|
// |--------------old--------------|
|
|
//
|
|
// |----old----| <---- |
|
|
// + |--fracture-|
|
|
// Solution: old.end = new.start
|
|
// && fracture:
|
|
// with fracture.start = new.end
|
|
// && fracture.end = old.original_end
|
|
|
|
let mut map = MapFile {
|
|
map: vec![Cluster {
|
|
domain: Domain { start: 0, end: 3 },
|
|
..Default::default()
|
|
}],
|
|
..Default::default()
|
|
};
|
|
|
|
map.update(Cluster {
|
|
domain: Domain { start: 1, end: 2 },
|
|
..Default::default()
|
|
});
|
|
map.map.sort();
|
|
|
|
assert_eq!(
|
|
map.map,
|
|
vec![
|
|
Cluster {
|
|
domain: Domain { start: 0, end: 1 },
|
|
..Default::default()
|
|
},
|
|
Cluster {
|
|
domain: Domain { start: 1, end: 2 },
|
|
..Default::default()
|
|
},
|
|
Cluster {
|
|
domain: Domain { start: 2, end: 3 },
|
|
..Default::default()
|
|
}
|
|
]
|
|
);
|
|
}
|
|
|
|
/// Test for MapFile::update()
|
|
#[test]
|
|
fn update_11_common_start_and_end() {
|
|
// Case 11:
|
|
// |--new--|
|
|
// |--old--|
|
|
//
|
|
// Solution: Remove old.
|
|
|
|
let mut map = MapFile {
|
|
map: vec![Cluster {
|
|
domain: Domain { start: 0, end: 3 },
|
|
stage: Stage::Untested,
|
|
}],
|
|
..Default::default()
|
|
};
|
|
|
|
map.update(Cluster {
|
|
domain: Domain { start: 0, end: 3 },
|
|
stage: Stage::Intact,
|
|
});
|
|
map.map.sort();
|
|
|
|
assert_eq!(
|
|
map.map,
|
|
vec![Cluster {
|
|
domain: Domain { start: 0, end: 3 },
|
|
stage: Stage::Intact
|
|
}]
|
|
);
|
|
}
|
|
|
|
/// Test for MapFile::update()
|
|
#[test]
|
|
fn update_12_new_out_of_range_preceding() {
|
|
// Case 12:
|
|
// |--new--|
|
|
// |--old--|
|
|
//
|
|
// Solution: Leave Unchanged.
|
|
|
|
let mut map = MapFile {
|
|
map: vec![Cluster {
|
|
domain: Domain { start: 2, end: 3 },
|
|
..Default::default()
|
|
}],
|
|
..Default::default()
|
|
};
|
|
|
|
map.update(Cluster {
|
|
domain: Domain { start: 0, end: 1 },
|
|
..Default::default()
|
|
});
|
|
map.map.sort();
|
|
|
|
assert_eq!(
|
|
map.map,
|
|
vec![
|
|
Cluster {
|
|
domain: Domain { start: 0, end: 1 },
|
|
..Default::default()
|
|
},
|
|
Cluster {
|
|
domain: Domain { start: 2, end: 3 },
|
|
..Default::default()
|
|
}
|
|
]
|
|
);
|
|
}
|
|
|
|
/// Test for MapFile::update()
|
|
#[test]
|
|
fn update_13_new_out_of_range_trailing() {
|
|
// Case 13:
|
|
// |--new--|
|
|
// |--old--|
|
|
//
|
|
// Solution: Leave Unchanged.
|
|
|
|
let mut map = MapFile {
|
|
map: vec![Cluster {
|
|
domain: Domain { start: 0, end: 1 },
|
|
..Default::default()
|
|
}],
|
|
..Default::default()
|
|
};
|
|
|
|
map.update(Cluster {
|
|
domain: Domain { start: 2, end: 3 },
|
|
..Default::default()
|
|
});
|
|
map.map.sort();
|
|
|
|
assert_eq!(
|
|
map.map,
|
|
vec![
|
|
Cluster {
|
|
domain: Domain { start: 0, end: 1 },
|
|
..Default::default()
|
|
},
|
|
Cluster {
|
|
domain: Domain { start: 2, end: 3 },
|
|
..Default::default()
|
|
}
|
|
]
|
|
);
|
|
}
|
|
|
|
/// Test for MapFile::get_stage()
|
|
#[test]
|
|
fn get_stage() {
|
|
let mut mf = MapFile::default();
|
|
let mut mf_stage = mf.get_stage();
|
|
|
|
// If this fails here, there's something SERIOUSLY wrong.
|
|
assert!(
|
|
mf_stage == Stage::Untested,
|
|
"Determined stage to be {:?}, when {:?} was expeccted.",
|
|
mf_stage,
|
|
Stage::Untested
|
|
);
|
|
|
|
let stages = vec![
|
|
Stage::Damaged,
|
|
Stage::ForIsolation { level: 1 },
|
|
Stage::ForIsolation { level: 0 },
|
|
Stage::Untested,
|
|
];
|
|
|
|
mf.map = vec![];
|
|
|
|
for stage in stages {
|
|
mf.map.push(*Cluster::default().set_stage(stage));
|
|
|
|
mf_stage = mf.get_stage();
|
|
|
|
assert!(
|
|
stage == mf_stage,
|
|
"Expected stage to be {:?}, determined {:?} instead.",
|
|
stage,
|
|
mf_stage
|
|
)
|
|
}
|
|
}
|
|
|
|
/// Test for MapFile::get_clusters()
|
|
#[test]
|
|
fn get_clusters() {
|
|
let mut mf = MapFile::default();
|
|
|
|
mf.map = vec![
|
|
*Cluster::default().set_stage(Stage::Damaged),
|
|
*Cluster::default().set_stage(Stage::ForIsolation { level: 0 }),
|
|
*Cluster::default().set_stage(Stage::ForIsolation { level: 1 }),
|
|
Cluster::default(),
|
|
Cluster::default(),
|
|
*Cluster::default().set_stage(Stage::ForIsolation { level: 1 }),
|
|
*Cluster::default().set_stage(Stage::ForIsolation { level: 0 }),
|
|
*Cluster::default().set_stage(Stage::Damaged),
|
|
];
|
|
|
|
let stages = vec![
|
|
Stage::Damaged,
|
|
Stage::ForIsolation { level: 1 },
|
|
Stage::ForIsolation { level: 0 },
|
|
Stage::Untested,
|
|
];
|
|
|
|
for stage in stages {
|
|
let expected = vec![
|
|
*Cluster::default().set_stage(stage),
|
|
*Cluster::default().set_stage(stage),
|
|
];
|
|
let received = mf.get_clusters(stage);
|
|
|
|
assert!(
|
|
expected == received,
|
|
"Expected clusters {:?}, got {:?}.",
|
|
expected,
|
|
received
|
|
)
|
|
}
|
|
}
|
|
|
|
/// Test for MapFile::defrag()
|
|
#[test]
|
|
fn defrag() {
|
|
let mut mf = MapFile {
|
|
sector_size: 1,
|
|
domain: Domain { start: 0, end: 8 },
|
|
map: vec![
|
|
Cluster {
|
|
domain: Domain { start: 0, end: 1 },
|
|
stage: Stage::Untested,
|
|
},
|
|
Cluster {
|
|
domain: Domain { start: 1, end: 2 },
|
|
stage: Stage::Untested,
|
|
},
|
|
Cluster {
|
|
domain: Domain { start: 2, end: 3 },
|
|
stage: Stage::Untested,
|
|
},
|
|
Cluster {
|
|
domain: Domain { start: 3, end: 4 },
|
|
stage: Stage::ForIsolation { level: 0 },
|
|
},
|
|
Cluster {
|
|
domain: Domain { start: 4, end: 5 },
|
|
stage: Stage::ForIsolation { level: 0 },
|
|
},
|
|
Cluster {
|
|
domain: Domain { start: 5, end: 6 },
|
|
stage: Stage::ForIsolation { level: 1 },
|
|
},
|
|
Cluster {
|
|
domain: Domain { start: 6, end: 7 },
|
|
stage: Stage::ForIsolation { level: 0 },
|
|
},
|
|
Cluster {
|
|
domain: Domain { start: 7, end: 8 },
|
|
stage: Stage::Damaged,
|
|
},
|
|
],
|
|
};
|
|
|
|
let expected = vec![
|
|
Cluster {
|
|
domain: Domain { start: 0, end: 3 },
|
|
stage: Stage::Untested,
|
|
},
|
|
Cluster {
|
|
domain: Domain { start: 3, end: 5 },
|
|
stage: Stage::ForIsolation { level: 0 },
|
|
},
|
|
Cluster {
|
|
domain: Domain { start: 5, end: 6 },
|
|
stage: Stage::ForIsolation { level: 1 },
|
|
},
|
|
Cluster {
|
|
domain: Domain { start: 6, end: 7 },
|
|
stage: Stage::ForIsolation { level: 0 },
|
|
},
|
|
Cluster {
|
|
domain: Domain { start: 7, end: 8 },
|
|
stage: Stage::Damaged,
|
|
},
|
|
];
|
|
|
|
mf.defrag();
|
|
|
|
let received = mf.map;
|
|
|
|
assert!(
|
|
expected == received,
|
|
"Expected {:?} after defragging, got {:?}.",
|
|
expected,
|
|
received
|
|
)
|
|
}
|
|
}
|