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]>>(
100 &mut self,
101 data_block: &mut DataBlock<T>,
102 configuration: &CuckooConfiguration,
103 lru_config: &(LruConfig, DataBlockFieldConfiguration),
104 new_item: bool,
105 ) -> bool {
106 let mut min = data_block.get_lru_counter(lru_config);
107 if new_item {
108 min = u32::MAX;
109 }
110 let mut pos = configuration.bucket_size;
111 for i in 0..configuration.bucket_size {
112 let data = self.get_data_block(i, configuration);
113 let counter = data.get_lru_counter(lru_config);
114 if counter < min {
115 min = counter;
116 pos = i;
117 }
118 }
119
120 if pos < configuration.bucket_size {
121 self.get_data_block(pos, configuration).swap(data_block);
122 true
123 } else {
124 false
125 }
126 }
127
128 pub(crate) fn contains(
134 &mut self,
135 fingerprint: &Fingerprint,
136 configuration: &CuckooConfiguration,
137 update: &LookupValues,
138 ) -> bool {
139 for i in 0..configuration.bucket_size {
140 let mut data = self.get_data_block(i, configuration);
141 let stored = data.get_fingerprint(configuration);
142
143 if stored == *fingerprint {
144 if let Some(counter_config) = configuration.counter_field_config.as_ref() {
145 data.update_counter(
146 counter_config,
147 update
148 .counter_diff
149 .unwrap_or(counter_config.0.change_on_lookup),
150 );
151 }
152 if let Some(ttl_config) = configuration.ttl_field_config.as_ref()
153 && let Some(ttl) = update.ttl
154 {
155 data.set_ttl(ttl_config, ttl);
156 }
157 if let Some(lru_config) = configuration.lru_field_config.as_ref() {
158 data.inc_lru_counter(lru_config);
159 }
160 return true;
161 }
162 }
163 false
164 }
165
166 pub(crate) fn get_associated_data(
170 &mut self,
171 fingerprint: &Fingerprint,
172 configuration: &CuckooConfiguration,
173 update: &LookupValues,
174 ) -> Option<AssociatedData> {
175 for i in 0..configuration.bucket_size {
176 let mut data = self.get_data_block(i, configuration);
177 let stored = data.get_fingerprint(configuration);
178
179 if stored == *fingerprint {
180 if let Some(counter_config) = configuration.counter_field_config.as_ref() {
181 data.update_counter(
182 counter_config,
183 update
184 .counter_diff
185 .unwrap_or(counter_config.0.change_on_lookup),
186 );
187 }
188 if let Some(ttl_config) = configuration.ttl_field_config.as_ref()
189 && let Some(ttl) = update.ttl
190 {
191 data.set_ttl(ttl_config, ttl);
192 }
193 if let Some(lru_config) = configuration.lru_field_config.as_ref() {
194 data.inc_lru_counter(lru_config);
195 }
196 return Some(AssociatedData::new(
197 self.get_data_block(i, configuration),
198 configuration.clone(),
199 ));
200 }
201 }
202 None
203 }
204
205 pub(crate) fn remove(
209 &mut self,
210 fingerprint: &Fingerprint,
211 configuration: &CuckooConfiguration,
212 ) -> bool {
213 for i in 0..configuration.bucket_size {
214 let mut data = self.get_data_block(i, configuration);
215 let stored = data.get_fingerprint(configuration);
216
217 if stored == *fingerprint {
218 data.reset();
219 return true;
220 }
221 }
222 false
223 }
224
225 pub(crate) fn age_lru_counters(
227 &mut self,
228 configuration: &CuckooConfiguration,
229 lru_config: &(LruConfig, DataBlockFieldConfiguration),
230 ) -> usize {
231 let mut removed = 0;
232 for i in 0..configuration.bucket_size {
233 let db = self.get_data_block(i, configuration);
234 if db.occupied(configuration) {
235 removed += if self
236 .get_data_block(i, configuration)
237 .age_lru_counter(lru_config)
238 {
239 1
240 } else {
241 0
242 }
243 }
244 }
245 removed
246 }
247
248 pub(crate) fn age_ttl_counters(
252 &mut self,
253 configuration: &CuckooConfiguration,
254 ttl_config: &(TtlConfig, DataBlockFieldConfiguration),
255 ) -> usize {
256 let mut removed = 0;
257 for i in 0..configuration.bucket_size {
258 let db = self.get_data_block(i, configuration);
259 if db.occupied(configuration) {
260 removed += if self
261 .get_data_block(i, configuration)
262 .age_ttl_counter(ttl_config)
263 {
264 1
265 } else {
266 0
267 }
268 }
269 }
270 removed
271 }
272
273 pub(crate) fn occupied_count(&self, configuration: &CuckooConfiguration) -> usize {
274 (0..configuration.bucket_size)
275 .map(|i| {
276 let size = configuration.data_block_size;
277 DataBlock::from(&self.data[(i * size)..((i + 1) * size)])
278 })
279 .filter(|db| db.occupied(configuration))
280 .count()
281 }
282
283 pub(crate) fn export(&self, mut writer: impl Write) -> std::io::Result<()> {
284 writer.write_all(&self.data)
285 }
286
287 fn get_data_block(
288 &mut self,
289 index: usize,
290 configuration: &CuckooConfiguration,
291 ) -> DataBlock<&mut [u8]> {
292 let size = configuration.data_block_size;
293 (&mut self.data[(index * size)..((index + 1) * size)]).into()
294 }
295}
296
297#[derive(Default)]
299pub struct InsertValues {
300 pub ttl: Option<u32>,
303 pub counter: Option<i32>,
306}
307
308#[derive(Default)]
310pub struct LookupValues {
311 pub ttl: Option<u32>,
314 pub counter_diff: Option<i32>,
317}