1use std::{
2 borrow::{Borrow, BorrowMut},
3 io::{Read, Write},
4};
5
6use crate::{
7 associated_data::AssociatedData,
8 config::{CuckooConfiguration, LruConfig, TtlConfig},
9 data_block::{DataBlock, DataBlockFieldConfiguration, Fingerprint},
10};
11
12pub(crate) struct Bucket {
16 data: Vec<u8>,
17}
18
19impl Bucket {
20 pub(crate) fn new(configuration: &CuckooConfiguration) -> Self {
26 Self {
27 data: vec![0; configuration.bucket_byte_size],
28 }
29 }
30
31 pub(crate) fn take_from(
37 mut reader: impl Read,
38 configuration: &CuckooConfiguration,
39 ) -> std::io::Result<Self> {
40 let mut data = vec![0; configuration.bucket_byte_size];
41 reader.read_exact(&mut data)?;
42 Ok(Self { data })
43 }
44
45 pub(crate) fn insert<T: Borrow<[u8]>>(
54 &mut self,
55 data_block: &DataBlock<T>,
56 configuration: &CuckooConfiguration,
57 ) -> bool {
58 let fingerprint = data_block.get_fingerprint(configuration);
59 for i in 0..configuration.bucket_size {
60 let mut data = self.get_data_block(i, configuration);
61 let stored = data.get_fingerprint(configuration);
62
63 let reinsert = stored == fingerprint;
64
65 if !reinsert {
66 if stored.is_empty() {
67 data.copy_from(data_block);
68 } else {
69 continue;
70 }
71 } else {
72 data.merge_associated_from(data_block, configuration);
73 }
74 return true;
75 }
76 false
77 }
78
79 pub(crate) fn kick_random<T: BorrowMut<[u8]>>(
85 &mut self,
86 data_block: &mut DataBlock<T>,
87 configuration: &CuckooConfiguration,
88 ) {
89 let index = rand::random_range(0..configuration.bucket_size);
90 self.get_data_block(index, configuration).swap(data_block);
91 }
92
93 pub(crate) fn kick_lru<T: BorrowMut<[u8]>>(
101 &mut self,
102 data_block: &mut DataBlock<T>,
103 configuration: &CuckooConfiguration,
104 lru_config: &(LruConfig, DataBlockFieldConfiguration),
105 ) -> bool {
106 let mut min = data_block.get_lru_counter(lru_config);
107 if min == 1 {
108 min = u32::MAX;
111 }
112 let mut pos = configuration.bucket_size;
113 for i in 0..configuration.bucket_size {
114 let data = self.get_data_block(i, configuration);
115 let counter = data.get_lru_counter(lru_config);
116 if counter < min {
117 min = counter;
118 pos = i;
119 }
120 }
121
122 if pos < configuration.bucket_size {
123 self.get_data_block(pos, configuration).swap(data_block);
124 true
125 } else {
126 false
127 }
128 }
129
130 pub(crate) fn contains(
136 &mut self,
137 fingerprint: &Fingerprint,
138 configuration: &CuckooConfiguration,
139 update: &LookupValues,
140 ) -> bool {
141 for i in 0..configuration.bucket_size {
142 let mut data = self.get_data_block(i, configuration);
143 let stored = data.get_fingerprint(configuration);
144
145 if stored == *fingerprint {
146 if let Some(counter_config) = configuration.counter_field_config.as_ref() {
147 data.update_counter(
148 counter_config,
149 update
150 .counter_diff
151 .unwrap_or(counter_config.0.change_on_lookup),
152 );
153 }
154 if let Some(ttl_config) = configuration.ttl_field_config.as_ref()
155 && let Some(ttl) = update.ttl
156 {
157 data.set_ttl(ttl_config, ttl);
158 }
159 if let Some(lru_config) = configuration.lru_field_config.as_ref() {
160 data.inc_lru_counter(lru_config);
161 }
162 return true;
163 }
164 }
165 false
166 }
167
168 pub(crate) fn get_associated_data(
172 &mut self,
173 fingerprint: &Fingerprint,
174 configuration: &CuckooConfiguration,
175 update: &LookupValues,
176 ) -> Option<AssociatedData> {
177 for i in 0..configuration.bucket_size {
178 let mut data = self.get_data_block(i, configuration);
179 let stored = data.get_fingerprint(configuration);
180
181 if stored == *fingerprint {
182 if let Some(counter_config) = configuration.counter_field_config.as_ref() {
183 data.update_counter(
184 counter_config,
185 update
186 .counter_diff
187 .unwrap_or(counter_config.0.change_on_lookup),
188 );
189 }
190 if let Some(ttl_config) = configuration.ttl_field_config.as_ref()
191 && let Some(ttl) = update.ttl
192 {
193 data.set_ttl(ttl_config, ttl);
194 }
195 if let Some(lru_config) = configuration.lru_field_config.as_ref() {
196 data.inc_lru_counter(lru_config);
197 }
198 return Some(AssociatedData::new(
199 self.get_data_block(i, configuration),
200 configuration.clone(),
201 ));
202 }
203 }
204 None
205 }
206
207 pub(crate) fn remove(
211 &mut self,
212 fingerprint: &Fingerprint,
213 configuration: &CuckooConfiguration,
214 ) -> bool {
215 for i in 0..configuration.bucket_size {
216 let mut data = self.get_data_block(i, configuration);
217 let stored = data.get_fingerprint(configuration);
218
219 if stored == *fingerprint {
220 data.reset();
221 return true;
222 }
223 }
224 false
225 }
226
227 pub(crate) fn age_lru_counters(
229 &mut self,
230 configuration: &CuckooConfiguration,
231 lru_config: &(LruConfig, DataBlockFieldConfiguration),
232 ) {
233 for i in 0..configuration.bucket_size {
234 self.get_data_block(i, configuration)
235 .age_lru_counter(lru_config);
236 }
237 }
238
239 pub(crate) fn age_ttl_counters(
243 &mut self,
244 configuration: &CuckooConfiguration,
245 ttl_config: &(TtlConfig, DataBlockFieldConfiguration),
246 ) -> usize {
247 let mut removed = 0;
248 for i in 0..configuration.bucket_size {
249 let db = self.get_data_block(i, configuration);
250 if db.occupied(configuration) {
251 removed += if self
252 .get_data_block(i, configuration)
253 .age_ttl_counter(ttl_config)
254 {
255 1
256 } else {
257 0
258 }
259 }
260 }
261 removed
262 }
263
264 pub(crate) fn occupied_count(&self, configuration: &CuckooConfiguration) -> usize {
265 (0..configuration.bucket_size)
266 .map(|i| {
267 let size = configuration.data_block_size;
268 DataBlock::from(&self.data[(i * size)..((i + 1) * size)])
269 })
270 .filter(|db| db.occupied(configuration))
271 .count()
272 }
273
274 pub(crate) fn export(&self, mut writer: impl Write) -> std::io::Result<()> {
275 writer.write_all(&self.data)
276 }
277
278 fn get_data_block(
279 &mut self,
280 index: usize,
281 configuration: &CuckooConfiguration,
282 ) -> DataBlock<&mut [u8]> {
283 let size = configuration.data_block_size;
284 (&mut self.data[(index * size)..((index + 1) * size)]).into()
285 }
286}
287
288#[derive(Default)]
290pub struct InsertValues {
291 pub ttl: Option<u32>,
294 pub counter: Option<i32>,
297}
298
299#[derive(Default)]
301pub struct LookupValues {
302 pub ttl: Option<u32>,
305 pub counter_diff: Option<i32>,
308}