From 94880f311e82572651b207d12e21b310d20ff023 Mon Sep 17 00:00:00 2001 From: soruh Date: Thu, 3 Aug 2023 04:23:30 +0200 Subject: [PATCH] extend coverage map --- src/lib.rs | 106 ++++++++++++++++++++++++++++++++++++----------------- 1 file changed, 72 insertions(+), 34 deletions(-) diff --git a/src/lib.rs b/src/lib.rs index 491ed38..ef3b10b 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -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, data_1: Vec, + data_2: Vec, 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::::header_ptr().range(), CoverageKind::Metadata); + coverage.set_range(Db::::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::::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());