Skip to main content

leveldb/database/
filter_policy.rs

1//! Filter policy implementations for LevelDB.
2//!
3//! Filter policies are used to reduce the number of disk reads during
4//! LevelDB queries by quickly skipping data blocks in which target keys don't exist.
5
6use crate::binding::{
7    leveldb_filterpolicy_create, leveldb_filterpolicy_create_bloom, leveldb_filterpolicy_destroy,
8    leveldb_filterpolicy_t,
9};
10use libc::{c_char, c_uchar, c_void};
11use std::ffi::CString;
12use std::os::raw::c_int;
13use std::slice;
14
15/// Common trait for all filter policy implementations
16pub trait LevelDBFilterPolicy {
17    /// Get the raw pointer to the LevelDB filter policy
18    fn raw_ptr(&self) -> *mut leveldb_filterpolicy_t;
19}
20
21/// BloomFilterPolicy wraps LevelDB's built-in bloom filter policy
22pub struct BloomFilterPolicy {
23    ptr: *mut leveldb_filterpolicy_t,
24}
25
26impl BloomFilterPolicy {
27    /// Create a new BloomFilterPolicy with the given bits per key
28    pub fn new(bits_per_key: i32) -> BloomFilterPolicy {
29        let ptr = unsafe { leveldb_filterpolicy_create_bloom(bits_per_key) };
30        BloomFilterPolicy { ptr }
31    }
32}
33
34impl LevelDBFilterPolicy for BloomFilterPolicy {
35    /// Get the raw pointer to the LevelDB filter policy
36    fn raw_ptr(&self) -> *mut leveldb_filterpolicy_t {
37        self.ptr
38    }
39}
40
41impl Drop for BloomFilterPolicy {
42    fn drop(&mut self) {
43        unsafe {
44            leveldb_filterpolicy_destroy(self.ptr);
45        }
46    }
47}
48
49/// Trait for custom filter policies that can be used with LevelDB
50pub trait FilterPolicy {
51    /// Create a filter for given keys
52    fn create_filter(&self, keys: &[&[u8]]) -> Vec<u8>;
53
54    /// Check if a key matches with the filter
55    fn key_may_match(&self, key: &[u8], filter: &[u8]) -> bool;
56
57    /// Get the name of this filter policy
58    fn name(&self) -> &'static str;
59}
60
61/// Wrapper for custom filter policy that implements the LevelDB FFI interface
62pub struct CustomFilterPolicy<T: FilterPolicy> {
63    ptr: *mut leveldb_filterpolicy_t,
64    policy: T,
65}
66
67impl<T: FilterPolicy> CustomFilterPolicy<T> {
68    /// Create a new custom filter policy
69    pub fn new(policy: T) -> Self {
70        let boxed_policy = Box::new(policy);
71        let state = Box::into_raw(boxed_policy) as *mut c_void;
72
73        extern "C" fn destructor<T: FilterPolicy>(state: *mut c_void) {
74            unsafe {
75                let _ = Box::from_raw(state as *mut T);
76            }
77        }
78
79        extern "C" fn create_filter<T: FilterPolicy>(
80            state: *mut c_void,
81            key_array: *const *const c_char,
82            key_length_array: *const usize,
83            num_keys: c_int,
84            filter_length: *mut usize,
85        ) -> *mut c_char {
86            unsafe {
87                let policy = &*(state as *const T);
88                let keys: Vec<&[u8]> = (0..num_keys as usize)
89                    .map(|i| {
90                        let key_ptr = *key_array.add(i);
91                        let key_len = *key_length_array.add(i);
92                        slice::from_raw_parts(key_ptr as *const u8, key_len)
93                    })
94                    .collect();
95
96                let filter_data = policy.create_filter(&keys);
97                *filter_length = filter_data.len();
98
99                let mut boxed_filter = filter_data.into_boxed_slice();
100                let ptr = boxed_filter.as_mut_ptr() as *mut c_char;
101                let _ = Box::into_raw(boxed_filter);
102                ptr
103            }
104        }
105
106        extern "C" fn key_may_match<T: FilterPolicy>(
107            state: *mut c_void,
108            key: *const c_char,
109            key_length: usize,
110            filter: *const c_char,
111            filter_length: usize,
112        ) -> c_uchar {
113            unsafe {
114                let policy = &*(state as *const T);
115                let key_slice = slice::from_raw_parts(key as *const u8, key_length);
116                let filter_slice = slice::from_raw_parts(filter as *const u8, filter_length);
117
118                policy.key_may_match(key_slice, filter_slice) as c_uchar
119            }
120        }
121
122        extern "C" fn name<T: FilterPolicy>(state: *mut c_void) -> *const c_char {
123            unsafe {
124                let policy = &*(state as *const T);
125                let name_str = policy.name();
126                let cstring = CString::new(name_str).unwrap();
127                cstring.into_raw()
128            }
129        }
130
131        let ptr = unsafe {
132            leveldb_filterpolicy_create(
133                state,
134                destructor::<T>,
135                create_filter::<T>,
136                key_may_match::<T>,
137                name::<T>,
138            )
139        };
140
141        let policy = unsafe { *Box::from_raw(state as *mut T) };
142
143        CustomFilterPolicy { ptr, policy }
144    }
145
146    /// Get a reference to the underlying filter policy
147    pub fn policy(&self) -> &T {
148        &self.policy
149    }
150}
151
152impl<T: FilterPolicy> LevelDBFilterPolicy for CustomFilterPolicy<T> {
153    /// Get the raw pointer to the LevelDB filter policy
154    fn raw_ptr(&self) -> *mut leveldb_filterpolicy_t {
155        self.ptr
156    }
157}
158
159impl<T: FilterPolicy> Drop for CustomFilterPolicy<T> {
160    fn drop(&mut self) {
161        unsafe {
162            leveldb_filterpolicy_destroy(self.ptr);
163        }
164    }
165}