Skip to content

Commit

Permalink
Update README and address all clippy warnings
Browse files Browse the repository at this point in the history
  • Loading branch information
KarthikSubbarao committed Apr 30, 2024
1 parent 398ea3d commit 61aa1fb
Show file tree
Hide file tree
Showing 4 changed files with 55 additions and 38 deletions.
3 changes: 3 additions & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,9 @@ bloomfilter = "1.0.13"
lazy_static = "1.4.0"
libc = "0.2"

[build-dependencies]
clippy = { version = "*", optional = true }

[lib]
crate-type = ["cdylib"]
name = "valkey_bloom"
Expand Down
21 changes: 19 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,13 +1,30 @@
# valkey-bloom

Tested on Linux so far.
Valkey-Bloom is a Rust Redis Module which brings a native and space efficient probabilistic Module data type to Valkey. With this, users can create filters (space-efficient probabilistic Module data type) to add elements, perform “check” operation to test whether an element exists, auto scale their filters, perform RDB Save and load operations, etc.

Valkey-Bloom is built using bloomfilter::Bloom (https://crates.io/crates/bloomfilter which has a BSD-2-Clause license).

It is compatible with the BloomFilter (BF.*) command APIs of the ReBloom Module from Redis Ltd.

The following commands are supported.
```
BF.EXISTS
BF.ADD
BF.MEXISTS
BF.MADD
BF.CARD
BF.RESERVE
BF.INFO
BF.INSERT
```

Build instructions for Linux.
```
curl https://sh.rustup.rs -sSf | sh
sudo yum install clang
git clone https://github.com/KarthikSubbarao/valkey-bloom.git
cd valkey-bloom
cargo build --all --all-targets --release
cargo build --features clippy --all --all-targets --release
find . -name "libvalkey_bloom.so"
valkey-server --loadmodule ./target/release/libvalkey_bloom.so
```
Expand Down
61 changes: 29 additions & 32 deletions src/commands/bloom.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ use crate::commands::bloom_util::{BloomFilterType, ERROR};
// TODO: Replace string literals in error messages with static
// TODO: Check all int / usize casting.

pub fn bloom_filter_add_value(ctx: &Context, input_args: &Vec<RedisString>, multi: bool) -> RedisResult {
pub fn bloom_filter_add_value(ctx: &Context, input_args: &[RedisString], multi: bool) -> RedisResult {
let argc = input_args.len();
if (!multi && argc != 3) || argc < 3 {
return Err(RedisError::WrongArity);
Expand All @@ -29,13 +29,12 @@ pub fn bloom_filter_add_value(ctx: &Context, input_args: &Vec<RedisString>, mult
match value {
Some(bf) => {
if !multi {
let item = &input_args[curr_cmd_idx];
let item = input_args[curr_cmd_idx].as_slice();
return Ok(RedisValue::Integer(bf.add_item(item)));
}
let mut result = Vec::new();
for idx in curr_cmd_idx..argc {
let item = &input_args[idx];
result.push(RedisValue::Integer(bf.add_item(item)));
for item in input_args.iter().take(argc).skip(curr_cmd_idx) {
result.push(RedisValue::Integer(bf.add_item(item.as_slice())));
}
Ok(RedisValue::Array(result))
}
Expand All @@ -49,14 +48,13 @@ pub fn bloom_filter_add_value(ctx: &Context, input_args: &Vec<RedisString>, mult
let result = match multi {
true => {
let mut result = Vec::new();
for idx in curr_cmd_idx..argc {
let item = &input_args[idx];
result.push(RedisValue::Integer(bf.add_item(item)));
for item in input_args.iter().take(argc).skip(curr_cmd_idx) {
result.push(RedisValue::Integer(bf.add_item(item.as_slice())));
}
Ok(RedisValue::Array(result))
}
false => {
let item = &input_args[curr_cmd_idx];
let item = input_args[curr_cmd_idx].as_slice();
Ok(RedisValue::Integer(bf.add_item(item)))
}
};
Expand All @@ -70,7 +68,7 @@ pub fn bloom_filter_add_value(ctx: &Context, input_args: &Vec<RedisString>, mult
}
}

pub fn bloom_filter_exists(ctx: &Context, input_args: &Vec<RedisString>, multi: bool) -> RedisResult {
pub fn bloom_filter_exists(ctx: &Context, input_args: &[RedisString], multi: bool) -> RedisResult {
let argc = input_args.len();
if (!multi && argc != 3) || argc < 3 {
return Err(RedisError::WrongArity);
Expand All @@ -88,12 +86,12 @@ pub fn bloom_filter_exists(ctx: &Context, input_args: &Vec<RedisString>, multi:
}
};
if !multi {
let item = &input_args[curr_cmd_idx];
let item = input_args[curr_cmd_idx].as_slice();
return Ok(bloom_filter_item_exists(value, item));
}
let mut result = Vec::new();
while curr_cmd_idx < argc {
let item = &input_args[curr_cmd_idx];
let item = input_args[curr_cmd_idx].as_slice();
result.push(bloom_filter_item_exists(value, item));
curr_cmd_idx += 1;
}
Expand All @@ -112,7 +110,7 @@ fn bloom_filter_item_exists(value: Option<&BloomFilterType>, item: &[u8]) -> Red
RedisValue::Integer(0)
}

pub fn bloom_filter_card(ctx: &Context, input_args: &Vec<RedisString>) -> RedisResult {
pub fn bloom_filter_card(ctx: &Context, input_args: &[RedisString]) -> RedisResult {
let argc = input_args.len();
if argc != 2 {
return Err(RedisError::WrongArity);
Expand All @@ -133,7 +131,7 @@ pub fn bloom_filter_card(ctx: &Context, input_args: &Vec<RedisString>) -> RedisR
}
}

pub fn bloom_filter_reserve(ctx: &Context, input_args: &Vec<RedisString>) -> RedisResult {
pub fn bloom_filter_reserve(ctx: &Context, input_args: &[RedisString]) -> RedisResult {
let argc = input_args.len();
if !(4..=6).contains(&argc) {
return Err(RedisError::WrongArity);
Expand Down Expand Up @@ -202,7 +200,7 @@ pub fn bloom_filter_reserve(ctx: &Context, input_args: &Vec<RedisString>) -> Red
}
}

pub fn bloom_filter_insert(ctx: &Context, input_args: &Vec<RedisString>) -> RedisResult {
pub fn bloom_filter_insert(ctx: &Context, input_args: &[RedisString]) -> RedisResult {
let argc = input_args.len();
// At the very least, we need: BF.INSERT <key> ITEM <item>
if argc < 4 {
Expand Down Expand Up @@ -276,9 +274,8 @@ pub fn bloom_filter_insert(ctx: &Context, input_args: &Vec<RedisString>) -> Redi
let mut result = Vec::new();
match value {
Some(bf) => {
for i in idx..argc {
let item = &input_args[i];
result.push(RedisValue::Integer(bf.add_item(item)));
for item in input_args.iter().take(argc).skip(idx) {
result.push(RedisValue::Integer(bf.add_item(item.as_slice())));
}
Ok(RedisValue::Array(result))
}
Expand All @@ -287,9 +284,8 @@ pub fn bloom_filter_insert(ctx: &Context, input_args: &Vec<RedisString>) -> Redi
return Err(RedisError::Str("ERR not found"));
}
let mut bf = BloomFilterType::new_reserved(fp_rate, capacity, expansion);
for i in idx..argc {
let item = &input_args[i];
result.push(RedisValue::Integer(bf.add_item(item)));
for item in input_args.iter().take(argc).skip(idx) {
result.push(RedisValue::Integer(bf.add_item(item.as_slice())));
}
match filter_key.set_value(&BLOOM_FILTER_TYPE, bf) {
Ok(_) => {
Expand All @@ -303,7 +299,7 @@ pub fn bloom_filter_insert(ctx: &Context, input_args: &Vec<RedisString>) -> Redi
}
}

pub fn bloom_filter_info(ctx: &Context, input_args: &Vec<RedisString>) -> RedisResult {
pub fn bloom_filter_info(ctx: &Context, input_args: &[RedisString]) -> RedisResult {
let argc = input_args.len();
if !(2..=3).contains(&argc) {
return Err(RedisError::WrongArity);
Expand Down Expand Up @@ -346,16 +342,17 @@ pub fn bloom_filter_info(ctx: &Context, input_args: &Vec<RedisString>) -> RedisR
}
}
Some(val) if argc == 2 => {
let mut result = Vec::new();
result.push(RedisValue::SimpleStringStatic("Capacity"));
result.push(RedisValue::Integer(val.capacity()));
result.push(RedisValue::SimpleStringStatic("Size"));
result.push(RedisValue::Integer(val.get_memory_usage() as i64));
result.push(RedisValue::SimpleStringStatic("Number of filters"));
result.push(RedisValue::Integer(val.filters.len() as i64));
result.push(RedisValue::SimpleStringStatic("Number of items inserted"));
result.push(RedisValue::Integer(val.cardinality()));
result.push(RedisValue::SimpleStringStatic("Expansion rate"));
let mut result = vec![
RedisValue::SimpleStringStatic("Capacity"),
RedisValue::Integer(val.capacity()),
RedisValue::SimpleStringStatic("Size"),
RedisValue::Integer(val.get_memory_usage() as i64),
RedisValue::SimpleStringStatic("Number of filters"),
RedisValue::Integer(val.filters.len() as i64),
RedisValue::SimpleStringStatic("Number of items inserted"),
RedisValue::Integer(val.cardinality()),
RedisValue::SimpleStringStatic("Expansion rate"),
];
if val.expansion == 0 {
result.push(RedisValue::Integer(-1));
} else {
Expand Down
8 changes: 4 additions & 4 deletions src/commands/bloom_util.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
use bloomfilter::Bloom;
use bloomfilter;

pub const ERROR: &str = "ERROR";

Expand Down Expand Up @@ -88,15 +88,15 @@ impl BloomFilterType {

// Structure representing a single bloom filter. 200 Bytes.
pub struct BloomFilter {
pub bloom: Bloom<[u8]>,
pub bloom: bloomfilter::Bloom<[u8]>,
pub num_items: u32,
pub capacity: u32,
}

impl BloomFilter {
pub fn new(fp_rate: f32, capacity: u32) -> BloomFilter {
// Instantiate empty bloom filter.
let bloom = Bloom::new_for_fp_rate(
let bloom = bloomfilter::Bloom::new_for_fp_rate(
capacity as usize,
fp_rate as f64,
);
Expand All @@ -108,7 +108,7 @@ impl BloomFilter {
}

pub fn from_existing(bitmap: &[u8], number_of_bits: u64, number_of_hash_functions: u32, sip_keys: [(u64, u64); 2], num_items: u32, capacity: u32) -> BloomFilter {
let bloom = Bloom::from_existing(
let bloom = bloomfilter::Bloom::from_existing(
bitmap,
number_of_bits,
number_of_hash_functions,
Expand Down

0 comments on commit 61aa1fb

Please sign in to comment.