oxedyne/fe2o3/fe2o3_hash/tests/map.rs
3.8 KiB, 28 runs
created by r1870400018:367, which is this file's identity for as long as the history lasts, whatever it is later renamed to
download · who wrote it · its history
| 1 | use oxedyne_fe2o3_core::{ |
| 2 | prelude::*, |
| 3 | map::MapMut, |
| 4 | rand::Rand, |
| 5 | }; |
| 6 | use oxedyne_fe2o3_hash::{ |
| 7 | hash::HashScheme, |
| 8 | map::ShardMap, |
| 9 | }; |
| 10 | use oxedyne_fe2o3_iop_hash::{ |
| 11 | api::{ |
| 12 | Hasher, |
| 13 | HashForm, |
| 14 | }, |
| 15 | }; |
| 16 | |
| 17 | use std::{ |
| 18 | collections::BTreeMap, |
| 19 | fmt::Debug, |
| 20 | sync::Arc, |
| 21 | thread, |
| 22 | }; |
| 23 | |
| 24 | const MAX_SHARDS: usize = 20; |
| 25 | const N1: u32 = 4; |
| 26 | const N2: u32 = 13; |
| 27 | const N_THREADS: usize = 5; |
| 28 | const KEY_LEN: usize = 4; |
| 29 | const VALS_PER_THREAD: u8 = 10; |
| 30 | const SALT_SIZE: usize = 5; |
| 31 | const SALT: [u8; SALT_SIZE] = [1u8, 2, 3, 4, 5]; |
| 32 | const STACK_SIZE: usize = 2 * 1024 * 1024; |
| 33 | |
| 34 | #[derive(Clone, Debug, Eq, PartialEq)] |
| 35 | struct TestStruct { |
| 36 | ord: u8, |
| 37 | thread: usize, |
| 38 | } |
| 39 | |
| 40 | fn dump_shards< |
| 41 | const C: usize, |
| 42 | const S: usize, |
| 43 | V: Clone + Debug, |
| 44 | M: MapMut<HashForm, V> + Clone + Debug, |
| 45 | H: Hasher + Send + Sync + 'static, |
| 46 | >( |
| 47 | shardmap: &ShardMap<C, S, V, M, H>, |
| 48 | ) |
| 49 | -> Outcome<()> |
| 50 | { |
| 51 | for i in 0..shardmap.n { |
| 52 | if let Some(locked_map) = &shardmap.shards[i] { |
| 53 | let unlocked_map = lock_read!(locked_map); |
| 54 | debug!("Map {}, len {}", i, unlocked_map.len()); |
| 55 | for (k, v) in (*unlocked_map).iter() { |
| 56 | debug!(" k={:02x?} v={:?}", k, v); |
| 57 | } |
| 58 | } |
| 59 | } |
| 60 | Ok(()) |
| 61 | } |
| 62 | |
| 63 | fn doer< |
| 64 | const C: usize, |
| 65 | const S: usize, |
| 66 | M: MapMut<HashForm, TestStruct> + Clone + Debug, |
| 67 | H: Hasher + Send + Sync + 'static, |
| 68 | >( |
| 69 | t: usize, |
| 70 | shardmap: Arc<ShardMap<C, S, TestStruct, M, H>>, |
| 71 | ) |
| 72 | -> Outcome<Vec<(Vec<u8>, TestStruct)>> |
| 73 | { |
| 74 | let mut data = Vec::new(); |
| 75 | for j in 0..VALS_PER_THREAD { |
| 76 | let mut p = [0u8; KEY_LEN]; |
| 77 | Rand::fill_u8(&mut p); |
| 78 | let v = TestStruct { ord: j, thread: t }; |
| 79 | res!((*shardmap).insert(&p, v.clone())); |
| 80 | data.push((p.to_vec(), v)); |
| 81 | } |
| 82 | test!("Thread {} finished doing.", t); |
| 83 | Ok(data) |
| 84 | } |
| 85 | |
| 86 | pub fn test_map(filter: &'static str) -> Outcome<()> { |
| 87 | |
| 88 | match filter { |
| 89 | "all" | "shardmap" => { |
| 90 | let shardmap = Arc::new(res!(ShardMap::<MAX_SHARDS, SALT_SIZE, _, _, _>::new( |
| 91 | N1, |
| 92 | SALT, |
| 93 | BTreeMap::<_, TestStruct>::new(), |
| 94 | HashScheme::new_seahash(), |
| 95 | ))); |
| 96 | let mut handles = Vec::new(); |
| 97 | for t in 0..N_THREADS { |
| 98 | let builder = thread::Builder::new() |
| 99 | .name(fmt!("maps_test")) |
| 100 | .stack_size(STACK_SIZE); |
| 101 | let shardmap_clone = shardmap.clone(); |
| 102 | handles.push(res!(builder.spawn( move || doer(t, shardmap_clone) ))); |
| 103 | } |
| 104 | |
| 105 | let mut data = Vec::new(); |
| 106 | for handle in handles { |
| 107 | let thread_data = match handle.join() { |
| 108 | Ok(outcome) => res!(outcome), |
| 109 | Err(_) => return Err(err!( |
| 110 | "A ShardMap worker thread panicked."; Test, Thread)), |
| 111 | }; |
| 112 | for pair in thread_data { |
| 113 | data.push(pair); |
| 114 | } |
| 115 | } |
| 116 | |
| 117 | res!(dump_shards(&shardmap)); |
| 118 | req!(data.len(), N_THREADS * (VALS_PER_THREAD as usize)); |
| 119 | for (p, v) in &data { |
| 120 | let locked_map = res!(shardmap.get_shard(p)); |
| 121 | let unlocked_map = lock_read!(locked_map); |
| 122 | req!(unlocked_map.get(&shardmap.key(p)), Some(v)); |
| 123 | } |
| 124 | let maps2 = res!(shardmap.remap(N2)); |
| 125 | test!("Remap from {} to {} shards...", N1, N2); |
| 126 | res!(dump_shards(&maps2)); |
| 127 | // Every key must still be found after the remapping. |
| 128 | for (p, v) in &data { |
| 129 | req!(res!(maps2.get_clone(p)), Some(v.clone())); |
| 130 | } |
| 131 | }, |
| 132 | _ => (), |
| 133 | } |
| 134 | |
| 135 | Ok(()) |
| 136 | } |