1use crate::hll::{self, Encoding};
31use crate::keyspace::Keyspace;
32use crate::strings::check_len;
33use crate::value::{self, Str};
34use yo_common::{Code, Error, Result};
35use yo_index::RawMap;
36
37const NO_SUCH_KEY: &str = "The specified key does not exist";
39const NOT_SPARSE: &str = "HLL encoding is not sparse";
41
42impl Keyspace {
43 pub fn pfadd<'e, I>(&mut self, key: &[u8], eles: I) -> Result<bool>
50 where
51 I: Iterator<Item = &'e [u8]>,
52 {
53 self.reap(key);
54 self.string_only(key)?;
55 self.thaw(key)?;
56 check_len(key, hll::DENSE)?;
57
58 let mut buf = std::mem::take(&mut self.scratch);
59 buf.clear();
60 let (deadline, fresh) = match self.map.get(key) {
61 Some(rec) => {
62 value::read(rec).write_to(&mut buf);
63 (value::expire_at(rec), false)
64 }
65 None => (None, true),
66 };
67 if fresh {
68 hll::empty(&mut buf);
69 }
70
71 let outcome = 'work: {
72 if let Err(e) = hll::check(&buf) {
73 break 'work Err(e);
74 }
75 let mut changed = fresh;
76 for ele in eles {
77 let (index, count) = hll::place(ele);
78 match hll::set(&mut buf, index, count) {
79 Some(hit) => changed |= hit,
80 None => break 'work Err(hll::corrupt()),
81 }
82 }
83 Ok(changed)
84 };
85
86 if matches!(outcome, Ok(true)) {
92 hll::invalidate(&mut buf);
93 self.store_raw(key, &buf, deadline);
94 }
95 self.scratch = buf;
96 outcome
97 }
98
99 pub fn pfcount<'k, I>(&mut self, keys: I) -> Result<u64>
109 where
110 I: Iterator<Item = &'k [u8]> + Clone,
111 {
112 for key in keys.clone() {
113 self.reap(key);
114 self.string_only(key)?;
115 self.thaw(key)?;
121 }
122 let mut one = keys.clone();
123 if let (Some(key), None) = (one.next(), one.next()) {
124 return self.count_one(key);
125 }
126
127 let mut max = [0u8; hll::REGISTERS];
132 for key in keys {
133 let Some(bytes) = self.sketch(key)? else {
134 continue;
135 };
136 let enc = hll::check(bytes)?;
137 if !hll::merge(&mut max, bytes, enc) {
138 return Err(hll::corrupt());
139 }
140 }
141 let mut hist = [0u32; 64];
142 for &val in &max {
143 hist[val as usize] += 1;
144 }
145 Ok(hll::estimate(&hist))
146 }
147
148 pub fn pfmerge<'k, I>(&mut self, dest: &'k [u8], srcs: I) -> Result<()>
158 where
159 I: Iterator<Item = &'k [u8]> + Clone,
160 {
161 self.reap(dest);
162 self.string_only(dest)?;
163 self.thaw(dest)?;
164 check_len(dest, hll::DENSE)?;
165 for src in srcs.clone() {
166 self.reap(src);
167 self.string_only(src)?;
168 self.thaw(src)?;
169 }
170
171 let mut max = [0u8; hll::REGISTERS];
175 let mut dense = false;
176 for key in std::iter::once(dest).chain(srcs) {
177 let Some(bytes) = self.sketch(key)? else {
178 continue;
179 };
180 let enc = hll::check(bytes)?;
181 dense |= enc == Encoding::Dense;
182 if !hll::merge(&mut max, bytes, enc) {
183 return Err(hll::corrupt());
184 }
185 }
186
187 let mut buf = std::mem::take(&mut self.scratch);
188 buf.clear();
189 let deadline = match self.map.get(dest) {
190 Some(rec) => {
191 value::read(rec).write_to(&mut buf);
192 value::expire_at(rec)
193 }
194 None => {
195 hll::empty(&mut buf);
196 None
197 }
198 };
199
200 let outcome = 'work: {
201 if dense && !hll::to_dense(&mut buf) {
206 break 'work Err(hll::corrupt());
207 }
208 for (i, &val) in max.iter().enumerate() {
209 if val != 0 && hll::set(&mut buf, i, val).is_none() {
210 break 'work Err(hll::corrupt());
211 }
212 }
213 Ok(())
214 };
215
216 if outcome.is_ok() {
217 hll::invalidate(&mut buf);
218 self.store_raw(dest, &buf, deadline);
219 }
220 self.scratch = buf;
221 outcome
222 }
223
224 pub fn pfgetreg(&mut self, key: &[u8], regs: &mut [u8; hll::REGISTERS]) -> Result<()> {
231 self.pftodense(key)?;
232 let bytes = self.sketch(key)?.ok_or_else(no_such_key)?;
233 let body = &bytes[hll::HDR..];
234 for (i, slot) in regs.iter_mut().enumerate() {
235 *slot = hll::dense_get(body, i);
236 }
237 Ok(())
238 }
239
240 pub fn pftodense(&mut self, key: &[u8]) -> Result<bool> {
242 self.reap(key);
243 self.string_only(key)?;
244 self.thaw(key)?;
245 let bytes = self.sketch(key)?.ok_or_else(no_such_key)?;
246 if hll::check(bytes)? == Encoding::Dense {
247 return Ok(false);
248 }
249
250 let mut buf = std::mem::take(&mut self.scratch);
251 buf.clear();
252 let deadline = match self.map.get(key) {
253 Some(rec) => {
254 value::read(rec).write_to(&mut buf);
255 value::expire_at(rec)
256 }
257 None => None,
258 };
259 let outcome = if hll::to_dense(&mut buf) {
260 self.store_raw(key, &buf, deadline);
261 Ok(true)
262 } else {
263 Err(hll::corrupt())
264 };
265 self.scratch = buf;
266 outcome
267 }
268
269 pub fn pfencoding(&mut self, key: &[u8]) -> Result<Encoding> {
271 self.reap(key);
272 self.string_only(key)?;
273 self.warm(key)?;
274 let bytes = self.sketch(key)?.ok_or_else(no_such_key)?;
275 hll::check(bytes)
276 }
277
278 pub fn pfdecode<T>(&mut self, key: &[u8], run: impl FnOnce(&[u8]) -> T) -> Result<T> {
284 self.reap(key);
285 self.string_only(key)?;
286 self.warm(key)?;
287
288 let mut buf = std::mem::take(&mut self.scratch);
292 buf.clear();
293 let outcome = 'work: {
294 let bytes = match self.sketch(key) {
295 Ok(Some(bytes)) => bytes,
296 Ok(None) => break 'work Err(no_such_key()),
297 Err(e) => break 'work Err(e),
298 };
299 match hll::check(bytes) {
300 Ok(Encoding::Sparse) => hll::decode(bytes, &mut buf),
301 Ok(Encoding::Dense) => break 'work Err(Error::new(Code::Invalid, NOT_SPARSE)),
302 Err(e) => break 'work Err(e),
303 }
304 Ok(())
305 };
306 let out = outcome.map(|()| run(&buf));
307 self.scratch = buf;
308 out
309 }
310
311 fn count_one(&mut self, key: &[u8]) -> Result<u64> {
313 let Some(bytes) = self.sketch(key)? else {
314 return Ok(0);
315 };
316 let enc = hll::check(bytes)?;
317 if let Some(n) = hll::cached(bytes) {
318 return Ok(n);
319 }
320 let n = hll::count(bytes, enc)?;
321
322 let hash = RawMap::hash_of(key);
326 if let Some(rec) = self.map.value_mut_hashed(hash, key)
327 && let Some(val) = value::raw_in_place(rec)
328 {
329 hll::cache(val, n);
330 }
331 Ok(n)
332 }
333
334 fn sketch(&self, key: &[u8]) -> Result<Option<&[u8]>> {
341 match self.peek(key) {
342 None => Ok(None),
343 Some(Str::Bytes(b)) => Ok(Some(b)),
344 Some(Str::Int(_)) => Err(hll::not_hll()),
345 }
346 }
347}
348
349fn no_such_key() -> Error {
351 Error::new(Code::NotFound, NO_SUCH_KEY)
352}
353
354#[cfg(test)]
355mod tests {
356 use super::*;
357 use crate::keyspace::Keyspace;
358
359 fn db() -> Keyspace {
360 Keyspace::new()
361 }
362
363 fn names<'k>(list: &'k [&'k [u8]]) -> impl Iterator<Item = &'k [u8]> + Clone {
365 list.iter().copied()
366 }
367
368 fn bytes(db: &mut Keyspace, key: &[u8]) -> Vec<u8> {
370 db.get(key).expect("a value").expect("bytes").to_vec()
371 }
372
373 #[test]
375 fn a_sketch_a_client_reads_is_the_one_a_real_server_wrote() {
376 let mut db = db();
377 assert!(db.pfadd(b"h", names(&[b"a", b"b", b"c"])).expect("an add"));
378 assert_eq!(
379 bytes(&mut db, b"h"),
380 b"HYLL\x01\0\0\0\0\0\0\0\0\0\0\x80\x60\xf3\x80\x50\xb1\x84\x4b\xfb\x80\x42\x5a"
381 );
382 assert_eq!(db.pfcount(names(&[b"h"])).expect("a count"), 3);
383 assert_eq!(bytes(&mut db, b"h")[8..16], [3, 0, 0, 0, 0, 0, 0, 0]);
385 }
386
387 #[test]
389 fn adding_nothing_still_creates_the_key() {
390 let mut db = db();
391 assert!(db.pfadd(b"h", names(&[])).expect("an add"));
392 assert!(db.exists(b"h"));
393 assert_eq!(db.strlen(b"h").expect("a length"), 18);
394 assert!(!db.pfadd(b"h", names(&[])).expect("an add"));
395 assert_eq!(db.pfcount(names(&[b"h"])).expect("a count"), 0);
396 }
397
398 #[test]
400 fn adding_an_element_twice_leaves_the_value_alone() {
401 let mut db = db();
402 db.pfadd(b"h", names(&[b"a"])).expect("an add");
403 let before = bytes(&mut db, b"h");
404 assert!(!db.pfadd(b"h", names(&[b"a"])).expect("an add"));
405 assert_eq!(bytes(&mut db, b"h"), before);
406 }
407
408 #[test]
410 fn the_count_is_the_number_a_real_server_gives() {
411 for (n, want) in [(100usize, 100u64), (1000, 995), (10_000, 10_077)] {
412 let mut db = db();
413 for i in 0..n {
414 let ele = format!("e:{i}");
415 db.pfadd(b"h", names(&[ele.as_bytes()])).expect("an add");
416 }
417 assert_eq!(db.pfcount(names(&[b"h"])).expect("a count"), want, "{n}");
418 }
419 }
420
421 #[test]
423 fn a_sketch_is_sparse_until_it_is_not() {
424 let mut db = db();
425 for i in 0..1000 {
426 let ele = format!("e:{i}");
427 db.pfadd(b"k1", names(&[ele.as_bytes()])).expect("an add");
428 }
429 assert_eq!(db.strlen(b"k1").expect("a length"), 1880);
430 assert_eq!(db.pfencoding(b"k1").expect("an encoding"), Encoding::Sparse);
431 const { assert!(1880 <= hll::SPARSE_MAX) };
432
433 for i in 0..10_000 {
434 let ele = format!("e:{i}");
435 db.pfadd(b"k2", names(&[ele.as_bytes()])).expect("an add");
436 }
437 assert_eq!(db.strlen(b"k2").expect("a length"), 12304);
438 assert_eq!(db.pfencoding(b"k2").expect("an encoding"), Encoding::Dense);
439 }
440
441 #[test]
448 fn counting_several_keys_counts_their_union() {
449 let mut db = db();
450 for i in 0..200 {
451 let ele = format!("e:{i}");
452 let key: &[u8] = if i < 150 { b"a" } else { b"b" };
453 db.pfadd(key, names(&[ele.as_bytes()])).expect("an add");
454 }
455 assert_eq!(db.pfcount(names(&[b"a"])).expect("a count"), 151);
456 assert_eq!(db.pfcount(names(&[b"b"])).expect("a count"), 49);
457 assert_eq!(db.pfcount(names(&[b"a", b"b"])).expect("a count"), 199);
458 assert_eq!(db.pfcount(names(&[b"gone"])).expect("a count"), 0);
460 assert_eq!(db.pfcount(names(&[b"a", b"gone"])).expect("a count"), 151);
461 assert!(!db.exists(b"gone"));
462 }
463
464 #[test]
466 fn a_merge_is_a_union_and_keeps_the_smaller_form() {
467 let mut db = db();
468 for i in 0..100 {
469 let ele = format!("e:{i}");
470 db.pfadd(b"s1", names(&[ele.as_bytes()])).expect("an add");
471 db.pfadd(b"s2", names(&[ele.as_bytes()])).expect("an add");
472 }
473 db.pfmerge(b"m", names(&[b"s1", b"s2"])).expect("a merge");
474 assert_eq!(db.strlen(b"m").expect("a length"), 279);
475 assert_eq!(db.pfencoding(b"m").expect("an encoding"), Encoding::Sparse);
476 assert_eq!(db.pfcount(names(&[b"m"])).expect("a count"), 100);
477
478 for i in 100..200 {
480 let ele = format!("e:{i}");
481 db.pfadd(b"s3", names(&[ele.as_bytes()])).expect("an add");
482 }
483 db.pfmerge(b"m", names(&[b"s3"])).expect("a merge");
484 assert_eq!(db.pfcount(names(&[b"m"])).expect("a count"), 199);
485 assert_eq!(db.strlen(b"m").expect("a length"), 499);
486
487 let before = bytes(&mut db, b"m");
489 db.pfmerge(b"m", names(&[])).expect("a merge");
490 assert_eq!(bytes(&mut db, b"m")[..8], before[..8]);
491 assert_eq!(db.pfcount(names(&[b"m"])).expect("a count"), 199);
492 }
493
494 #[test]
496 fn a_dense_source_makes_the_result_dense() {
497 let mut db = db();
498 for i in 0..100 {
499 let ele = format!("e:{i}");
500 db.pfadd(b"small", names(&[ele.as_bytes()]))
501 .expect("an add");
502 }
503 for i in 0..20_000 {
504 let ele = format!("e:{i}");
505 db.pfadd(b"big", names(&[ele.as_bytes()])).expect("an add");
506 }
507 db.pfmerge(b"m", names(&[b"small", b"big"]))
508 .expect("a merge");
509 assert_eq!(db.strlen(b"m").expect("a length"), 12304);
510 assert_eq!(db.pfencoding(b"m").expect("an encoding"), Encoding::Dense);
511 assert_eq!(db.pfcount(names(&[b"m"])).expect("a count"), 20096);
512 }
513
514 #[test]
516 fn a_write_keeps_the_deadline() {
517 let mut db = db();
518 let mut fresh = Vec::new();
519 hll::empty(&mut fresh);
520 db.setex(b"h", 100, &fresh).expect("a set");
521 let had = db.expire_at(b"h").expect("a deadline");
522 db.pfadd(b"h", names(&[b"a"])).expect("an add");
523 assert_eq!(db.expire_at(b"h"), Some(had));
524 db.pfmerge(b"h", names(&[])).expect("a merge");
525 assert_eq!(db.expire_at(b"h"), Some(had));
526 db.pftodense(b"h").expect("a conversion");
527 assert_eq!(db.expire_at(b"h"), Some(had));
528 assert_eq!(db.pfcount(names(&[b"h"])).expect("a count"), 1);
529 }
530
531 #[test]
533 fn the_debug_commands_say_what_a_real_server_says() {
534 let mut db = db();
535 db.pfadd(b"h", names(&[b"a", b"b", b"c"])).expect("an add");
536 let text = db.pfdecode(b"h", <[u8]>::to_vec).expect("a decode");
537 assert_eq!(text, b"Z:8436 v:1,1 Z:4274 v:2,1 Z:3068 v:1,1 Z:603");
538
539 let mut regs = [0u8; hll::REGISTERS];
542 db.pfgetreg(b"h", &mut regs).expect("the registers");
543 assert_eq!(regs[8436], 1);
544 assert_eq!(regs[12711], 2);
545 assert_eq!(regs[15780], 1);
546 assert_eq!(regs.iter().filter(|&&v| v != 0).count(), 3);
547 assert_eq!(db.pfencoding(b"h").expect("an encoding"), Encoding::Dense);
548 assert_eq!(db.strlen(b"h").expect("a length"), 12304);
549 assert_eq!(db.pfcount(names(&[b"h"])).expect("a count"), 3);
550
551 assert!(db.pfdecode(b"h", <[u8]>::to_vec).is_err());
553 assert!(!db.pftodense(b"h").expect("a conversion"));
554 }
555
556 #[test]
558 fn a_string_that_is_not_a_sketch_is_refused() {
559 let mut db = db();
560 db.set_plain(b"plain", b"not a sketch at all")
561 .expect("a set");
562 assert!(db.pfadd(b"plain", names(&[b"a"])).is_err());
563 assert!(db.pfcount(names(&[b"plain"])).is_err());
564 assert!(db.pfmerge(b"plain", names(&[])).is_err());
565 assert!(db.pfencoding(b"plain").is_err());
566 db.set_plain(b"n", b"12345").expect("a set");
568 assert!(db.pfcount(names(&[b"n"])).is_err());
569
570 assert!(db.pfencoding(b"gone").is_err());
573 assert!(db.pftodense(b"gone").is_err());
574 assert!(db.pfdecode(b"gone", <[u8]>::to_vec).is_err());
575 let mut regs = [0u8; hll::REGISTERS];
576 assert!(db.pfgetreg(b"gone", &mut regs).is_err());
577 }
578
579 #[test]
581 fn a_corrupted_sketch_is_reported() {
582 let mut db = db();
583 db.pfadd(b"h", names(&[b"a", b"b", b"c"])).expect("an add");
584 let mut short = bytes(&mut db, b"h");
585 short.pop();
586 db.set_plain(b"h", &short).expect("a set");
587 let err = db.pfcount(names(&[b"h"])).expect_err("a complaint");
588 assert_eq!(err.code(), Code::Corrupt);
589 assert!(db.pfcount(names(&[b"h", b"h"])).is_err());
590 assert!(db.pfmerge(b"m", names(&[b"h"])).is_err());
591 }
592}