extend coverage map

This commit is contained in:
soruh 2023-08-03 04:23:30 +02:00
parent 42a2aef527
commit 94880f311e

View File

@ -901,12 +901,6 @@ mod tests {
coverage.set_allocated(next.range());
next = snaphot.read(next).next;
}
for SnapshotAndFreeList { to_free, .. } in &db.snapshots {
for &range in to_free {
coverage.set_range(range, CoverageKind::Free);
}
}
});
snapshots.push_back(db.create_reader().state.get());
@ -953,11 +947,14 @@ mod tests {
#[repr(u8)]
#[derive(Clone, Copy)]
#[rustfmt::skip]
enum CoverageKind {
Unaccounted = 0b00,
Allocated = 0b01,
Free = 0b10,
Metadata = 0b11,
Unaccounted = 0b000,
Allocated = 0b001,
Free = 0b010,
Retired = 0b011,
SlabMetadata = 0b100,
FileMetadata = 0b101,
}
impl CoverageKind {
@ -966,31 +963,42 @@ mod tests {
CoverageKind::Unaccounted => "31",
CoverageKind::Allocated => "32",
CoverageKind::Free => "34",
CoverageKind::Metadata => "35",
CoverageKind::Retired => "36",
CoverageKind::SlabMetadata => "35",
CoverageKind::FileMetadata => "93",
}
}
}
impl CoverageKind {
fn from_bits(a: bool, b: bool) -> Self {
let res = match (a, b) {
(false, false) => Self::Unaccounted,
(false, true) => Self::Allocated,
(true, false) => Self::Free,
(true, true) => Self::Metadata,
#[rustfmt::skip]
fn from_bits(a: bool, b: bool, c: bool) -> Self {
let res = match (a, b, c) {
(false, false, false) => Self::Unaccounted,
(false, false, true) => Self::Allocated,
(false, true, false) => Self::Free,
(false, true, true) => Self::Retired,
( true, false, false) => Self::SlabMetadata,
( true, false, true) => Self::FileMetadata,
_ => panic!(),
};
assert_eq!(res as u8, ((a as u8) << 1) + b as u8);
assert_eq!(res as u8, ((a as u8) << 2) + ((b as u8) << 1) + c as u8);
res
}
fn to_bits(self) -> (bool, bool) {
(self as u8 & 0b10 != 0, self as u8 & 0b01 != 0)
fn to_bits(self) -> (bool, bool, bool) {
(
self as u8 & 0b100 != 0,
self as u8 & 0b010 != 0,
self as u8 & 0b001 != 0,
)
}
}
struct CoverageMap {
data_0: Vec<u8>,
data_1: Vec<u8>,
data_2: Vec<u8>,
empty_bits: u8,
}
@ -1000,6 +1008,7 @@ mod tests {
Self {
data_0: vec![0; bits],
data_1: vec![0; bits],
data_2: vec![0; bits],
empty_bits: (8 - len % 8) as u8,
}
}
@ -1010,20 +1019,21 @@ mod tests {
let i_bit = i % 8;
let mask = 1 << i_bit;
let (set_0, set_1) = kind.to_bits();
let (set_0, set_1, set_2) = kind.to_bits();
if i_byte >= self.data_0.len() {
return false;
}
let is_set = self.data_0[i_byte] & mask != 0 || self.data_1[i_byte] & mask != 0;
let byte = self.data_0[i_byte] | self.data_1[i_byte] | self.data_2[i_byte];
if is_set {
if byte & mask != 0 {
return false;
}
self.data_0[i_byte] |= mask * set_0 as u8;
self.data_1[i_byte] |= mask * set_1 as u8;
self.data_2[i_byte] |= mask * set_2 as u8;
true
}
@ -1046,8 +1056,14 @@ mod tests {
fn all_covered(&self) -> bool {
let len = self.data_0.len();
for (i, (&byte_0, &byte_1)) in self.data_0.iter().zip(self.data_1.iter()).enumerate() {
let byte = byte_0 | byte_1;
for (i, ((&byte_0, &byte_1), &byte_2)) in self
.data_0
.iter()
.zip(self.data_1.iter())
.zip(self.data_2.iter())
.enumerate()
{
let byte = byte_0 | byte_1 | byte_2;
if i == len - 1 {
if byte != u8::MAX.overflowing_shl(self.empty_bits as u32).0 {
return false;
@ -1069,22 +1085,34 @@ mod tests {
let mut res = String::new();
let mut prev = "";
for (i, (&byte_0, &byte_1)) in self.data_0.iter().zip(self.data_1.iter()).enumerate() {
let byte = byte_0 | byte_1;
for (i, ((&byte_0, &byte_1), &byte_2)) in self
.data_0
.iter()
.zip(self.data_1.iter())
.zip(self.data_2.iter())
.enumerate()
{
let byte = byte_0 | byte_1 | byte_2;
fn all_equal(bits: u8) -> bool {
bits == 0 || bits == u8::MAX
}
let kind = if all_equal(byte_0) && all_equal(byte_1) {
Some(CoverageKind::from_bits(byte_0 & 1 == 1, byte_1 & 1 == 1))
let kind = if all_equal(byte_0) && all_equal(byte_1) && all_equal(byte_2) {
Some(CoverageKind::from_bits(
byte_0 & 1 == 1,
byte_1 & 1 == 1,
byte_2 & 1 == 1,
))
} else {
None
};
if i != 0 {
if i as u64 % (PAGE_SIZE / 8 / 8) == 0 {
Self::set_color(&mut res, "");
res.push('\n');
Self::set_color(&mut res, prev);
}
if i as u64 % (PAGE_SIZE / 8) == 0 {
Self::set_color(&mut res, "");
@ -1095,7 +1123,6 @@ mod tests {
}
let color = kind.map(CoverageKind::color).unwrap_or("33");
if color != prev {
Self::set_color(&mut res, color);
}
@ -1122,7 +1149,9 @@ mod tests {
fn coverage_map_works() {
let mut coverage = CoverageMap::new(40);
assert!(!coverage.all_covered());
assert!(coverage.try_set_range(RawFilePointer::null().range(20), CoverageKind::Metadata));
assert!(
coverage.try_set_range(RawFilePointer::null().range(20), CoverageKind::FileMetadata)
);
assert!(!coverage.all_covered());
assert!(coverage.try_set_range((RawFilePointer::null() + 20).range(20), CoverageKind::Free));
assert!(coverage.all_covered());
@ -1141,7 +1170,7 @@ mod tests {
let snapshot = &*db.state.get();
coverage.set_range(Db::<R>::header_ptr().range(), CoverageKind::Metadata);
coverage.set_range(Db::<R>::header_ptr().range(), CoverageKind::FileMetadata);
// general purpose
{
@ -1165,7 +1194,7 @@ mod tests {
.0
.into_raw()
.range(slabs.read_header(db).size() as u64),
CoverageKind::Metadata,
CoverageKind::SlabMetadata,
);
next = slabs.next(db);
@ -1182,7 +1211,7 @@ mod tests {
let header =
FilePointer::<RelativeFreeListHeader>::new(page.start());
coverage.set_range(header.range(), CoverageKind::Metadata);
coverage.set_range(header.range(), CoverageKind::SlabMetadata);
let header = snapshot.read(header);
@ -1219,6 +1248,15 @@ mod tests {
}
}
// retired objects
{
for SnapshotAndFreeList { to_free, .. } in &db.snapshots {
for &range in to_free {
coverage.set_range(range, CoverageKind::Retired);
}
}
}
f(snapshot, &mut coverage);
print!("{}", coverage.print());