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