• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

getdozer / dozer / 4382580286

pending completion
4382580286

push

github

GitHub
feat: Separate cache operation log environment and index environments (#1199)

1370 of 1370 new or added lines in 33 files covered. (100.0%)

28671 of 41023 relevant lines covered (69.89%)

51121.29 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

97.06
/dozer-cache/src/cache/lmdb/comparator.rs
1
use dozer_storage::errors::StorageError;
2
use dozer_storage::lmdb::{Database, Transaction};
3
use dozer_storage::lmdb_sys::{mdb_set_compare, MDB_cmp_func, MDB_val, MDB_SUCCESS};
4

5
use crate::cache::index::compare_composite_secondary_index;
6

7
pub fn set_sorted_inverted_comparator<T: Transaction>(
2,693✔
8
    txn: &T,
2,693✔
9
    db: Database,
2,693✔
10
    fields: &[usize],
2,693✔
11
) -> Result<(), StorageError> {
2,693✔
12
    let comparator: MDB_cmp_func = if fields.len() == 1 {
2,693✔
13
        None
2,591✔
14
    } else {
15
        Some(compare_composite_key)
102✔
16
    };
17

18
    if let Some(comparator) = comparator {
2,693✔
19
        unsafe {
20
            assert_eq!(
102✔
21
                mdb_set_compare(txn.txn(), db.dbi(), Some(comparator)),
102✔
22
                MDB_SUCCESS
102✔
23
            );
102✔
24
        }
25
    }
2,591✔
26
    Ok(())
2,693✔
27
}
2,693✔
28

29
unsafe fn mdb_val_to_slice(val: &MDB_val) -> &[u8] {
5,569,002✔
30
    std::slice::from_raw_parts(val.mv_data as *const u8, val.mv_size)
5,569,002✔
31
}
5,569,002✔
32

33
unsafe extern "C" fn compare_composite_key(
2,784,501✔
34
    a: *const MDB_val,
2,784,501✔
35
    b: *const MDB_val,
2,784,501✔
36
) -> std::ffi::c_int {
2,784,501✔
37
    match compare_composite_secondary_index(mdb_val_to_slice(&*a), mdb_val_to_slice(&*b)) {
2,784,501✔
38
        Ok(ordering) => ordering as std::ffi::c_int,
2,784,501✔
39
        Err(e) => {
×
40
            dozer_types::log::error!("Error deserializing secondary index key: {}", e);
×
41
            0
×
42
        }
43
    }
44
}
2,784,501✔
45

46
#[cfg(test)]
47
mod tests {
48
    use std::cmp::Ordering::{self, Equal, Greater, Less};
49

50
    use dozer_storage::{
51
        lmdb::DatabaseFlags,
52
        lmdb_storage::{CreateDatabase, LmdbEnvironmentManager},
53
        lmdb_sys::mdb_cmp,
54
    };
55
    use dozer_types::{
56
        chrono::{DateTime, NaiveDate, TimeZone, Utc},
57
        ordered_float::OrderedFloat,
58
        rust_decimal::Decimal,
59
        types::Field,
60
    };
61

62
    use crate::cache::{index::get_secondary_index, lmdb::utils};
63

64
    use super::*;
65

66
    fn check_test_cases(mut checker: impl FnMut(&[i64], &[i64], Ordering)) {
2✔
67
        checker(&[1, 1], &[1, 1], Equal);
2✔
68
        checker(&[1, 1], &[1, 2], Less);
2✔
69
        checker(&[1, 1], &[2, 1], Less);
2✔
70
        checker(&[1, 1], &[2, 2], Less);
2✔
71
        checker(&[1, 1], &[1], Greater);
2✔
72
        checker(&[1, 1], &[2], Less);
2✔
73
        checker(&[1, 2], &[1, 1], Greater);
2✔
74
        checker(&[1, 2], &[1, 2], Equal);
2✔
75
        checker(&[1, 2], &[2, 1], Less);
2✔
76
        checker(&[1, 2], &[2, 2], Less);
2✔
77
        checker(&[1, 2], &[1], Greater);
2✔
78
        checker(&[1, 2], &[2], Less);
2✔
79
        checker(&[2, 1], &[1, 1], Greater);
2✔
80
        checker(&[2, 1], &[1, 2], Greater);
2✔
81
        checker(&[2, 1], &[2, 1], Equal);
2✔
82
        checker(&[2, 1], &[2, 2], Less);
2✔
83
        checker(&[2, 1], &[1], Greater);
2✔
84
        checker(&[2, 1], &[2], Greater);
2✔
85
        checker(&[2, 2], &[1, 1], Greater);
2✔
86
        checker(&[2, 2], &[1, 2], Greater);
2✔
87
        checker(&[2, 2], &[2, 1], Greater);
2✔
88
        checker(&[2, 2], &[2, 2], Equal);
2✔
89
        checker(&[2, 2], &[1], Greater);
2✔
90
        checker(&[2, 2], &[2], Greater);
2✔
91
        checker(&[1], &[1, 1], Less);
2✔
92
        checker(&[1], &[1, 2], Less);
2✔
93
        checker(&[1], &[2, 1], Less);
2✔
94
        checker(&[1], &[2, 2], Less);
2✔
95
        checker(&[1], &[1], Equal);
2✔
96
        checker(&[1], &[2], Less);
2✔
97
        checker(&[2], &[1, 1], Greater);
2✔
98
        checker(&[2], &[1, 2], Greater);
2✔
99
        checker(&[2], &[2, 1], Less);
2✔
100
        checker(&[2], &[2, 2], Less);
2✔
101
        checker(&[2], &[1], Greater);
2✔
102
        checker(&[2], &[2], Equal);
2✔
103
    }
2✔
104

×
105
    #[test]
1✔
106
    fn test_compare_composite_key() {
1✔
107
        let check = |a: &[i64], b: &[i64], expected: Ordering| {
36✔
108
            let serialize = |a: &[i64]| {
72✔
109
                let a = a.iter().map(|x| Field::Int(*x)).collect::<Vec<_>>();
120✔
110
                let a = a.iter().collect::<Vec<_>>();
72✔
111
                get_secondary_index(&a, false)
72✔
112
            };
72✔
113
            let a = serialize(a);
36✔
114
            let b = serialize(b);
36✔
115
            let a = MDB_val {
36✔
116
                mv_size: a.len() as _,
36✔
117
                mv_data: a.as_ptr() as _,
36✔
118
            };
36✔
119
            let b = MDB_val {
36✔
120
                mv_size: b.len() as _,
36✔
121
                mv_data: b.as_ptr() as _,
36✔
122
            };
36✔
123
            assert_eq!(unsafe { compare_composite_key(&a, &b) }, expected as i32,);
36✔
124
        };
36✔
125

1✔
126
        check_test_cases(check);
1✔
127
    }
1✔
128

×
129
    #[test]
1✔
130
    fn test_set_sorted_inverted_comparator() {
1✔
131
        let mut check_single = get_single_key_checker();
1✔
132
        check_single(Some(1), Some(1), Equal);
1✔
133
        check_single(Some(1), Some(2), Less);
1✔
134
        check_single(Some(2), Some(1), Greater);
1✔
135
        check_single(Some(1), None, Less);
1✔
136
        check_single(None, Some(1), Greater);
1✔
137
        check_single(None, None, Equal);
1✔
138

1✔
139
        let check_composite = get_composite_key_checker(2);
1✔
140
        check_test_cases(check_composite);
1✔
141
    }
1✔
142

×
143
    fn setup(num_fields: usize) -> (LmdbEnvironmentManager, Database) {
3✔
144
        let mut env = utils::init_env(&Default::default(), Some(Default::default()))
3✔
145
            .unwrap()
3✔
146
            .0;
3✔
147
        let db = env
3✔
148
            .create_database(Some("test"), Some(DatabaseFlags::DUP_SORT))
3✔
149
            .unwrap();
3✔
150
        let fields = (0..num_fields).collect::<Vec<_>>();
3✔
151
        let txn = env.begin_ro_txn().unwrap();
3✔
152
        set_sorted_inverted_comparator(&txn, db, &fields).unwrap();
3✔
153
        txn.commit().unwrap();
3✔
154
        (env, db)
3✔
155
    }
3✔
156

157
    fn get_single_key_checker() -> impl FnMut(Option<i64>, Option<i64>, Ordering) {
1✔
158
        let (env, db) = setup(1);
1✔
159
        move |a: Option<i64>, b: Option<i64>, expected: Ordering| {
6✔
160
            let serialize =
6✔
161
                |a: Option<i64>| get_secondary_index(&[&a.map_or(Field::Null, Field::Int)], true);
12✔
162
            let a = serialize(a);
6✔
163
            let b = serialize(b);
6✔
164
            let a = MDB_val {
6✔
165
                mv_size: a.len() as _,
6✔
166
                mv_data: a.as_ptr() as *mut _,
6✔
167
            };
6✔
168
            let b = MDB_val {
6✔
169
                mv_size: b.len() as _,
6✔
170
                mv_data: b.as_ptr() as *mut _,
6✔
171
            };
6✔
172
            let txn = env.begin_ro_txn().unwrap();
6✔
173
            assert_eq!(
6✔
174
                unsafe { mdb_cmp(txn.txn(), db.dbi(), &a, &b) }.cmp(&0),
6✔
175
                expected
6✔
176
            );
6✔
177
        }
6✔
178
    }
1✔
179

180
    fn get_composite_key_checker<'a>(
1✔
181
        num_fields: usize,
1✔
182
    ) -> impl FnMut(&[i64], &[i64], Ordering) + 'a {
1✔
183
        let (env, db) = setup(num_fields);
1✔
184
        move |a: &[i64], b: &[i64], expected: Ordering| {
36✔
185
            let serialize = |a: &[i64]| {
72✔
186
                let fields = a.iter().map(|a| Field::Int(*a)).collect::<Vec<_>>();
120✔
187
                let fields = fields.iter().collect::<Vec<_>>();
72✔
188
                get_secondary_index(&fields, false)
72✔
189
            };
72✔
190
            let a = serialize(a);
36✔
191
            let b = serialize(b);
36✔
192
            let a = MDB_val {
36✔
193
                mv_size: a.len() as _,
36✔
194
                mv_data: a.as_ptr() as *mut _,
36✔
195
            };
36✔
196
            let b = MDB_val {
36✔
197
                mv_size: b.len() as _,
36✔
198
                mv_data: b.as_ptr() as *mut _,
36✔
199
            };
36✔
200
            let txn = env.begin_ro_txn().unwrap();
36✔
201
            assert_eq!(
36✔
202
                unsafe { mdb_cmp(txn.txn(), db.dbi(), &a, &b) }.cmp(&0),
36✔
203
                expected
36✔
204
            );
36✔
205
        }
36✔
206
    }
1✔
207

208
    #[test]
1✔
209
    fn null_is_greater_than_other_thing() {
1✔
210
        let (env, db) = setup(1);
1✔
211
        let txn = env.begin_ro_txn().unwrap();
1✔
212
        let check = |field: &Field| {
11✔
213
            let serialize = |a| get_secondary_index(&[a], true);
22✔
214
            let a = serialize(field);
11✔
215
            let b = serialize(&Field::Null);
11✔
216
            let a = MDB_val {
11✔
217
                mv_size: a.len() as _,
11✔
218
                mv_data: a.as_ptr() as *mut _,
11✔
219
            };
11✔
220
            let b = MDB_val {
11✔
221
                mv_size: b.len() as _,
11✔
222
                mv_data: b.as_ptr() as *mut _,
11✔
223
            };
11✔
224
            assert!(unsafe { mdb_cmp(txn.txn(), db.dbi(), &a, &b) } < 0);
11✔
225
            assert_eq!(field.cmp(&Field::Null), Ordering::Less);
11✔
226
        };
11✔
227

228
        let test_cases = [
1✔
229
            Field::UInt(u64::MAX),
1✔
230
            Field::Int(i64::MAX),
1✔
231
            Field::Float(OrderedFloat(f64::MAX)),
1✔
232
            Field::Boolean(true),
1✔
233
            Field::String("a".to_string()),
1✔
234
            Field::Text("a".to_string()),
1✔
235
            Field::Binary(vec![255]),
1✔
236
            Field::Decimal(Decimal::new(i64::MAX, 0)),
1✔
237
            Field::Timestamp(DateTime::from(Utc.timestamp_millis_opt(1).unwrap())),
1✔
238
            Field::Date(NaiveDate::from_ymd_opt(2020, 1, 2).unwrap()),
1✔
239
            Field::Bson(vec![255]),
1✔
240
        ];
1✔
241
        for a in test_cases.iter() {
11✔
242
            check(a);
11✔
243
        }
11✔
244
    }
1✔
245
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc