sketch_cuckoo.nx
buildroot/runtime/sketch_cuckoo.nx
about
sketch_cuckoo.nx -- Cuckoo Filter (Fan et al. 2014).
Approximate-set-membership primitive with DELETION support --
the headline capability Bloom filters lack. Each item gets one
of two candidate buckets (the second derived from the
fingerprint via XOR), so lookups check both buckets and inserts
fall back to relocation when both are full.
Versus Bloom (runtime/bloom.nx already shipped):
Bloom: k bit-sets per insert, no delete, false-positive rate
~ (1 - e^(-kn/m))^k
Cuckoo: fingerprint slots per bucket, supports delete, false-
positive rate ~ 2 * bucket_size / (2^fp_bits)
At the same memory + FP rate, Cuckoo is typically more
space-efficient than Bloom AND supports deletes.
Parameters:
n_buckets: power of 2 (for XOR-friendly indexing). Total
capacity is roughly 95% * n_buckets * 4.
bucket_size: we use 4 (canonical; trade-off well-studied).
fingerprint: 8 bits (1 byte per slot). False-positive rate
~ 2*4/256 = 3.1% at high load. 16-bit
fingerprints (0.024% FP) are queued for v2.
LOSSLESS-LANGUAGE DISCIPLINE (doc 20):
Membership query returns ApproxI64 with envelope_kind =
NX_ENV_ABS, param_a = 0 (false positives but NEVER false
negatives for items truly inserted), conf_ppb = 1e9 -
expected_fpr_ppb. Substrate's typed envelope precisely
declares "absent" is exact and "present" is bounded-uncertain.
dependencies 2 imports · 3 importers
imports: syscalls.nxsketch_types.nx
imported by: sketch_cb_vs_cuckoo_delete_bench.nxsketch_cuckoo_delete_vs_bloom_bench.nxsketch_cuckoo_test.nx
structs
| 45 | struct CuckooFilter { |
consts
| 35 | const NX_CUCKOO_BUCKET_SIZE: i64 = 4 |
| 36 | const NX_CUCKOO_FP_BITS: i64 = 8 |
| 37 | const NX_CUCKOO_MAX_KICKS: i64 = 500 |
| 38 | const NX_CUCKOO_EMPTY: i64 = 0 // fingerprint 0 = slot empty |
| 41 | const NX_CUCKOO_LCG_A: i64 = 1103515245 |
| 42 | const NX_CUCKOO_LCG_C: i64 = 12345 |
| 43 | const NX_CUCKOO_LCG_MOD: i64 = 0x7FFFFFFF |
functions
| 59 | func nx_cuckoo_fingerprint(hash: i64) -> i64 { |
| 73 | func nx_cuckoo_bucket1(c: *CuckooFilter, hash: i64) -> i64 { |
| 78 | func nx_cuckoo_fp_hash(fp: i64) -> i64 {
called by 1: nx_cuckoo_bucket2 |
| 83 | func nx_cuckoo_bucket2(c: *CuckooFilter, b1: i64, fp: i64) -> i64 { |
| 92 | func nx_cuckoo_alloc(n_buckets: i64, seed: i64) -> *CuckooFilter { |
| 114 | func nx_cuckoo_rng_next(c: *CuckooFilter) -> i64 {
called by 1: nx_cuckoo_insert |
| 122 | func nx_cuckoo_bucket_addr(c: *CuckooFilter, b: i64) -> *u8 { |
| 126 | func nx_cuckoo_try_insert_bucket(c: *CuckooFilter, b: i64, fp: i64) -> i64 { |
| 140 | func nx_cuckoo_bucket_contains(c: *CuckooFilter, b: i64, fp: i64) -> i64 { |
| 150 | func nx_cuckoo_bucket_remove(c: *CuckooFilter, b: i64, fp: i64) -> i64 { |
| 170 | func nx_cuckoo_insert(c: *CuckooFilter, hash: i64) -> i64 { |
| 210 | func nx_cuckoo_contains(c: *CuckooFilter, hash: i64) -> i64 { |
| 225 | func nx_cuckoo_delete(c: *CuckooFilter, hash: i64) -> i64 {
called by 3: mainmainmain calls 4: nx_cuckoo_fingerprintnx_cuckoo_bucket1nx_cuckoo_bucket_removenx_cuckoo_bucket2 |
| 247 | func nx_cuckoo_fpr_ppb() -> i64 {
called by 1: nx_cuckoo_query |
| 251 | func nx_cuckoo_query(c: *CuckooFilter, hash: i64) -> *ApproxI64 { |
| 264 | func nx_cuckoo_memory_bytes(c: *CuckooFilter) -> i64 { |
| 268 | func nx_cuckoo_total(c: *CuckooFilter) -> i64 { |
| 274 | func nx_cuckoo_load_ppt(c: *CuckooFilter) -> i64 { |