@@ -10,6 +10,7 @@ use bloomfilter::Bloom;
10
10
use bloomfilter:: { deserialize, serialize} ;
11
11
use serde:: { Deserialize , Deserializer , Serialize } ;
12
12
use std:: sync:: atomic:: Ordering ;
13
+ use valkey_module:: ValkeyError ;
13
14
14
15
/// KeySpace Notification Events
15
16
pub const ADD_EVENT : & str = "bloom.add" ;
@@ -32,10 +33,16 @@ pub const CAPACITY_LARGER_THAN_0: &str = "ERR (capacity should be larger than 0)
32
33
pub const MAX_NUM_SCALING_FILTERS : & str = "ERR bloom object reached max number of filters" ;
33
34
pub const UNKNOWN_ARGUMENT : & str = "ERR unknown argument received" ;
34
35
pub const EXCEEDS_MAX_BLOOM_SIZE : & str = "ERR operation exceeds bloom object memory limit" ;
36
+ pub const WANTED_CAPACITY_EXCEEDS_MAX_SIZE : & str =
37
+ "ERR Wanted capacity would go beyond bloom object memory limit" ;
38
+ pub const WANTED_CAPACITY_FALSE_POSITIVE_INVALID : & str =
39
+ "ERR False positive degrades too much to reach wanted capacity" ;
35
40
pub const KEY_EXISTS : & str = "BUSYKEY Target key name already exists." ;
36
41
pub const DECODE_BLOOM_OBJECT_FAILED : & str = "ERR bloom object decoding failed" ;
37
42
pub const DECODE_UNSUPPORTED_VERSION : & str =
38
43
"ERR bloom object decoding failed. Unsupported version" ;
44
+ pub const NON_SCALING_AND_WANTED_CAPACITY_IS_INVALID : & str =
45
+ "ERR Specifying NONSCALING and ATLEASTCAPCITY is not allowed" ;
39
46
/// Logging Error messages
40
47
pub const ENCODE_BLOOM_OBJECT_FAILED : & str = "Failed to encode bloom object." ;
41
48
@@ -455,6 +462,44 @@ impl BloomObject {
455
462
_ => Err ( BloomError :: DecodeUnsupportedVersion ) ,
456
463
}
457
464
}
465
+
466
+ pub fn calculate_if_wanted_capacity_is_valid (
467
+ capacity : i64 ,
468
+ fp_rate : f64 ,
469
+ wanted_capacity : i64 ,
470
+ tightening_ratio : f64 ,
471
+ expansion : u32 ,
472
+ ) -> Result < ( ) , ValkeyError > {
473
+ let mut curr_capacity = capacity;
474
+ let mut curr_num_filters: u64 = 1 ;
475
+ let mut curr_fp_rate = fp_rate;
476
+ let mut filters_memory_usage = 0 ;
477
+ while curr_capacity < wanted_capacity {
478
+ curr_fp_rate = match BloomObject :: calculate_fp_rate (
479
+ curr_fp_rate,
480
+ curr_num_filters as i32 ,
481
+ tightening_ratio,
482
+ ) {
483
+ Ok ( rate) => rate,
484
+ Err ( _) => {
485
+ return Err ( ValkeyError :: Str ( WANTED_CAPACITY_FALSE_POSITIVE_INVALID ) ) ;
486
+ }
487
+ } ;
488
+ let curr_filter_size = BloomFilter :: compute_size ( curr_capacity, curr_fp_rate) ;
489
+ // For vectors of size < 4 the capacity of the vector is 4. However after that the capacity is always a power of two above or equal to the size
490
+ let curr_object_size = BloomObject :: compute_size (
491
+ std:: cmp:: max ( 4 , curr_num_filters) . next_power_of_two ( ) as usize ,
492
+ ) + filters_memory_usage
493
+ + curr_filter_size;
494
+ if !BloomObject :: validate_size ( curr_object_size) {
495
+ return Err ( ValkeyError :: Str ( WANTED_CAPACITY_EXCEEDS_MAX_SIZE ) ) ;
496
+ }
497
+ filters_memory_usage += curr_filter_size;
498
+ curr_capacity *= expansion as i64 ;
499
+ curr_num_filters += 1 ;
500
+ }
501
+ Ok ( ( ) )
502
+ }
458
503
}
459
504
460
505
/// Structure representing a single bloom filter. 200 Bytes.
0 commit comments