diff --git a/storage/src/nodestore.rs b/storage/src/nodestore.rs index 44d51db81..4c011d70b 100644 --- a/storage/src/nodestore.rs +++ b/storage/src/nodestore.rs @@ -66,37 +66,68 @@ use super::linear::WritableStorage; /// [NodeStore] divides the linear store into blocks of different sizes. /// [AREA_SIZES] is every valid block size. -const AREA_SIZES: [u64; 21] = [ - 1 << MIN_AREA_SIZE_LOG, // Min block size is 8 - 1 << 4, - 1 << 5, - 1 << 6, - 1 << 7, - 1 << 8, - 1 << 9, - 1 << 10, - 1 << 11, - 1 << 12, - 1 << 13, - 1 << 14, - 1 << 15, - 1 << 16, - 1 << 17, - 1 << 18, - 1 << 19, - 1 << 20, - 1 << 21, - 1 << 22, - 1 << 23, // 16 MiB +const AREA_SIZES: [u64; 23] = [ + 16, // Min block size + 32, + 64, + 96, + 128, + 256, + 512, + 768, + 1024, + 1024 << 1, + 1024 << 2, + 1024 << 3, + 1024 << 4, + 1024 << 5, + 1024 << 6, + 1024 << 7, + 1024 << 8, + 1024 << 9, + 1024 << 10, + 1024 << 11, + 1024 << 12, + 1024 << 13, + 1024 << 14, ]; +// TODO: automate this, must stay in sync with above +fn index_name(index: AreaIndex) -> &'static str { + match index { + 0 => "16", + 1 => "32", + 2 => "64", + 3 => "96", + 4 => "128", + 5 => "256", + 6 => "512", + 7 => "768", + 8 => "1024", + 9 => "2048", + 10 => "4096", + 11 => "8192", + 12 => "16384", + 13 => "32768", + 14 => "65536", + 15 => "131072", + 16 => "262144", + 17 => "524288", + 18 => "1048576", + 19 => "2097152", + 20 => "4194304", + 21 => "8388608", + 22 => "16777216", + _ => "unknown", + } +} + /// The type of an index into the [AREA_SIZES] array /// This is not usize because we can store this as a single byte pub type AreaIndex = u8; // TODO danlaine: have type for index in AREA_SIZES // Implement try_into() for it. -const MIN_AREA_SIZE_LOG: AreaIndex = 3; const NUM_AREA_SIZES: usize = AREA_SIZES.len(); const MIN_AREA_SIZE: u64 = AREA_SIZES[0]; const MAX_AREA_SIZE: u64 = AREA_SIZES[NUM_AREA_SIZES - 1]; @@ -114,13 +145,16 @@ fn area_size_to_index(n: u64) -> Result { return Ok(0); } - let mut log = n.ilog2(); - // If n is not a power of 2, we need to round up to the next power of 2. - if n != 1 << log { - log += 1; - } - - Ok(log as AreaIndex - MIN_AREA_SIZE_LOG) + AREA_SIZES + .iter() + .position(|&size| size >= n) + .map(|index| index as AreaIndex) + .ok_or_else(|| { + Error::new( + ErrorKind::InvalidData, + format!("Node size {} is too large", n), + ) + }) } /// Objects cannot be stored at the zero address, so a [LinearAddress] is guaranteed not @@ -413,8 +447,10 @@ impl NodeStore, S> { *free_stored_area_addr = free_head.next_free_block; } - counter!("firewood.space.reused").increment(AREA_SIZES[index]); - counter!("firewood.space.wasted").increment(AREA_SIZES[index] - n); + counter!("firewood.space.reused", "index" => index_name(index as u8)) + .increment(AREA_SIZES[index]); + counter!("firewood.space.wasted", "index" => index_name(index as u8)) + .increment(AREA_SIZES[index] - n); // Return the address of the newly allocated block. trace!( @@ -425,7 +461,8 @@ impl NodeStore, S> { } trace!("No free blocks of sufficient size {index_wanted} found"); - counter!("firewood.space.notfree").increment(AREA_SIZES[index_wanted as usize]); + counter!("firewood.space.from_end", "index" => index_name(index_wanted as u8)) + .increment(AREA_SIZES[index_wanted as usize]); Ok(None) } @@ -474,8 +511,9 @@ impl NodeStore { let (area_size_index, _) = self.area_index_and_size(addr)?; trace!("Deleting node at {addr:?} of size {}", area_size_index); - counter!("firewood.delete_node").increment(1); - counter!("firewood.space.freed").increment(AREA_SIZES[area_size_index as usize]); + counter!("firewood.delete_node", "index" => index_name(area_size_index)).increment(1); + counter!("firewood.space.freed", "index" => index_name(area_size_index)) + .increment(AREA_SIZES[area_size_index as usize]); // The area that contained the node is now free. let area: Area = Area::Free(FreeArea {