Nothing to see here, move along
at main 131 lines 3.3 kB view raw
1use crate::block_io::BlockIo; 2use crate::btree; 3use crate::cache::BlockCache; 4use crate::error::FsError; 5use crate::pool::NodePool; 6use lancer_core::fs::BlockRef; 7 8pub enum DedupResult { 9 Reused(BlockRef), 10 Unique, 11} 12 13pub fn dedup_check( 14 pool: &mut NodePool, 15 cache: &mut BlockCache, 16 bio: &mut BlockIo, 17 dedup_root: &BlockRef, 18 content_hash: u128, 19) -> Result<DedupResult, FsError> { 20 let key = dedup_key(content_hash); 21 22 let existing = btree::btree_lookup(pool, cache, bio, dedup_root, key, None)?; 23 24 match existing { 25 None => Ok(DedupResult::Unique), 26 Some(ref entry) => match entry.content_hash_u128() == content_hash { 27 true => Ok(DedupResult::Reused(*entry)), 28 false => Ok(DedupResult::Unique), 29 }, 30 } 31} 32 33pub fn dedup_insert( 34 pool: &mut NodePool, 35 cache: &mut BlockCache, 36 bio: &mut BlockIo, 37 dedup_root: &BlockRef, 38 content_hash: u128, 39 block_ref: &BlockRef, 40 txn: u64, 41) -> Result<BlockRef, FsError> { 42 let key = dedup_key(content_hash); 43 44 let mut entry = *block_ref; 45 entry.content_hash = content_hash.to_le_bytes(); 46 47 match btree::btree_insert(pool, cache, bio, dedup_root, key, entry, txn) { 48 Err(FsError::DuplicateKey) => Ok(*dedup_root), 49 other => other, 50 } 51} 52 53pub fn dedup_shard(content_hash: u128) -> usize { 54 (content_hash >> 124) as usize & 0xF 55} 56 57fn dedup_key(hash: u128) -> u64 { 58 (hash >> 64) as u64 59} 60 61#[cfg(test)] 62mod tests { 63 use super::*; 64 65 #[test] 66 fn dedup_key_extracts_upper_64() { 67 let hash: u128 = 0xDEAD_BEEF_CAFE_BABE_1234_5678_9ABC_DEF0; 68 assert_eq!(dedup_key(hash), 0xDEAD_BEEF_CAFE_BABE); 69 } 70 71 #[test] 72 fn dedup_key_zero_hash() { 73 assert_eq!(dedup_key(0), 0); 74 } 75 76 #[test] 77 fn dedup_key_max_hash() { 78 assert_eq!(dedup_key(u128::MAX), u64::MAX); 79 } 80 81 #[test] 82 fn dedup_key_lower_half_ignored() { 83 let a: u128 = 0xAAAA_BBBB_CCCC_DDDD_0000_0000_0000_0001; 84 let b: u128 = 0xAAAA_BBBB_CCCC_DDDD_FFFF_FFFF_FFFF_FFFF; 85 assert_eq!(dedup_key(a), dedup_key(b)); 86 } 87 88 #[test] 89 fn dedup_shard_extracts_top_4_bits() { 90 let hash: u128 = 0xA000_0000_0000_0000_0000_0000_0000_0000; 91 assert_eq!(dedup_shard(hash), 0xA); 92 } 93 94 #[test] 95 fn dedup_shard_zero() { 96 assert_eq!(dedup_shard(0), 0); 97 } 98 99 #[test] 100 fn dedup_shard_max() { 101 assert_eq!(dedup_shard(u128::MAX), 0xF); 102 } 103 104 #[test] 105 fn dedup_shard_all_values() { 106 (0u8..16).for_each(|s| { 107 let hash = (s as u128) << 124; 108 assert_eq!(dedup_shard(hash), s as usize); 109 }); 110 } 111 112 #[test] 113 fn dedup_check_empty_tree_returns_unique() { 114 let mut pool = crate::test_helpers::make_pool(); 115 let mut cache = crate::test_helpers::make_cache(); 116 let mut bio = crate::test_helpers::make_bio(256); 117 118 let result = dedup_check( 119 &mut pool, 120 &mut cache, 121 &mut bio, 122 &BlockRef::ZERO, 123 0x1234_5678_9ABC_DEF0, 124 ) 125 .unwrap(); 126 match result { 127 DedupResult::Unique => {} 128 DedupResult::Reused(_) => panic!("expected Unique on empty tree"), 129 } 130 } 131}