Skip to content
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
76 changes: 40 additions & 36 deletions src/executor.rs
Original file line number Diff line number Diff line change
Expand Up @@ -393,11 +393,20 @@ impl<'a> QueryExecutor<'a> {
if field == "id" { return None; }
let ff = self.filters.get_field(field)?;
let key = self.resolve_value_key(field, value)?;
let vb = ff.get_versioned(key)?;
// AND accumulator directly with the base/fused bitmap by reference
let cow = vb.fused_cow();
*acc &= cow.as_ref();
Some(Ok(()))
// Apr 13 2026: Use apply_diff_eq instead of get_versioned + fused_cow.
// fused_cow clones the entire base bitmap (~13MB) when dirty.
// apply_diff_eq computes (candidates & fused) at O(candidates) cost,
// avoiding the base clone entirely. 2-10x faster for dirty bitmaps
// when the accumulator is already narrowed by prior clauses.
if let Some(result) = ff.apply_diff_eq(key, acc) {
*acc = result;
Some(Ok(()))
} else {
// Value has no bitmap — no documents match.
// Same as old path: get_versioned returned None → acc &= empty
*acc = RoaringBitmap::new();
Some(Ok(()))
}
}
FilterClause::In(field, values) => {
if field == "id" { return None; }
Expand Down Expand Up @@ -439,23 +448,18 @@ impl<'a> QueryExecutor<'a> {
false
};
if use_complement {
for &key in &complement_keys {
if let Some(vb) = ff.get_versioned(key) {
*acc -= vb.fused_cow().as_ref();
}
}
if let Some(null_vb) = ff.get_versioned(crate::filter::NULL_BITMAP_KEY) {
*acc -= null_vb.fused_cow().as_ref();
}
// Apr 13 2026: Use union_with_diff for complement to avoid
// N × 13MB base clones on dirty bitmaps. Build the union of
// complement values intersected with acc, then subtract once.
let mut exclude_keys = complement_keys.clone();
exclude_keys.push(crate::filter::NULL_BITMAP_KEY);
let to_exclude = ff.union_with_diff(&exclude_keys, acc);
*acc -= &to_exclude;
} else {
let mut union = RoaringBitmap::new();
for &key in &in_keys {
if let Some(vb) = ff.get_versioned(key) {
let cow = vb.fused_cow();
union |= &*acc & cow.as_ref();
}
}
*acc = union;
// Apr 13 2026: Use union_with_diff instead of per-value
// get_versioned + fused_cow. Avoids N × 13MB base clones
// for dirty bitmaps. Single lock acquisition for all values.
*acc = ff.union_with_diff(&in_keys, acc);
}
Some(Ok(()))
}
Expand All @@ -476,26 +480,26 @@ impl<'a> QueryExecutor<'a> {
}
FilterClause::NotEq(field, value) => {
if field == "id" { return None; }
if let Some(ff) = self.filters.get_field(field) {
if let Some(key) = self.resolve_value_key(field, value) {
if let Some(vb) = ff.get_versioned(key) {
*acc -= vb.fused_cow().as_ref();
return Some(Ok(()));
}
}
let ff = self.filters.get_field(field)?;
let key = self.resolve_value_key(field, value)?;
// Diff-aware: compute (acc & value_bitmap) then subtract.
// Avoids 13MB base clone for dirty bitmaps.
if let Some(hits) = ff.apply_diff_eq(key, acc) {
*acc -= &hits;
}
None
Some(Ok(()))
}
FilterClause::NotIn(field, values) => {
if field == "id" { return None; }
if let Some(ff) = self.filters.get_field(field) {
for v in values {
if let Some(key) = self.resolve_value_key(field, v) {
if let Some(vb) = ff.get_versioned(key) {
*acc -= vb.fused_cow().as_ref();
}
}
}
let keys: Vec<u64> = values
.iter()
.filter_map(|v| self.resolve_value_key(field, v))
.collect();
// Diff-aware: union all excluded values intersected with
// acc, then subtract once. Single lock acquisition.
let to_exclude = ff.union_with_diff(&keys, acc);
*acc -= &to_exclude;
return Some(Ok(()));
}
None
Expand Down
Loading