Switch to an iterative algorithm for find_changed_parents

This commit is contained in:
Louis Dureuil 2025-01-08 14:57:14 +01:00
parent 8ee3793259
commit b4005593f4
No known key found for this signature in database

View File

@ -63,18 +63,14 @@ impl FacetsUpdateIncremental {
} }
self.delta_data.sort_unstable_by( self.delta_data.sort_unstable_by(
|FacetFieldIdChange { facet_value: left, .. }, |FacetFieldIdChange { facet_value: left, .. },
FacetFieldIdChange { facet_value: right, .. }| left.cmp(right), FacetFieldIdChange { facet_value: right, .. }| {
left.cmp(right)
// sort in **reverse** lexicographic order
.reverse()
},
); );
self.inner.find_changed_parents( self.inner.find_changed_parents(wtxn, self.delta_data)?;
wtxn,
0,
self.delta_data
.into_iter()
// reverse lexicographic order
.rev()
.map(|change| change.facet_value.into()),
)?;
self.inner.add_or_delete_level(wtxn) self.inner.add_or_delete_level(wtxn)
} }
@ -85,24 +81,25 @@ impl FacetsUpdateIncrementalInner {
fn find_changed_parents( fn find_changed_parents(
&self, &self,
wtxn: &mut RwTxn, wtxn: &mut RwTxn,
child_level: u8, mut changed_children: Vec<FacetFieldIdChange>,
mut changed_children: impl Iterator<Item = Vec<u8>>,
) -> Result<()> { ) -> Result<()> {
let mut changed_parents = vec![]; let mut changed_parents = vec![];
let Some(parent_level) = child_level.checked_add(1) else { return Ok(()) }; for child_level in 0u8..u8::MAX {
// child_level < u8::MAX by construction
let parent_level = child_level + 1;
let parent_level_left_bound: FacetGroupKey<&[u8]> = let parent_level_left_bound: FacetGroupKey<&[u8]> =
FacetGroupKey { field_id: self.field_id, level: parent_level, left_bound: &[] }; FacetGroupKey { field_id: self.field_id, level: parent_level, left_bound: &[] };
let mut last_parent: Option<Vec<u8>> = None; let mut last_parent: Option<Box<[u8]>> = None;
let mut child_it = changed_children.drain(..);
for child in &mut changed_children { 'current_level: while let Some(child) = child_it.next() {
if !valid_facet_value(&child) { if !valid_facet_value(&child.facet_value) {
continue; continue;
} }
if let Some(last_parent) = &last_parent { if let Some(last_parent) = &last_parent {
if child.as_slice() >= last_parent.as_slice() { if &child.facet_value >= last_parent {
self.compute_parent_group(wtxn, child_level, child)?; self.compute_parent_group(wtxn, child_level, child.facet_value)?;
continue; continue;
} }
} }
@ -111,7 +108,7 @@ impl FacetsUpdateIncrementalInner {
let parent_key_prefix = FacetGroupKey { let parent_key_prefix = FacetGroupKey {
field_id: self.field_id, field_id: self.field_id,
level: parent_level, level: parent_level,
left_bound: child.as_slice(), left_bound: &*child.facet_value,
}; };
let parent = self let parent = self
@ -129,65 +126,90 @@ impl FacetsUpdateIncrementalInner {
match parent { match parent {
Some(Ok((parent_key, _parent_value))) => { Some(Ok((parent_key, _parent_value))) => {
// found parent, cache it for next keys // found parent, cache it for next keys
last_parent = Some(parent_key.left_bound.to_owned()); last_parent = Some(parent_key.left_bound.to_owned().into_boxed_slice());
// add to modified list for parent level // add to modified list for parent level
changed_parents.push(parent_key.left_bound.to_owned()); changed_parents.push(FacetFieldIdChange {
self.compute_parent_group(wtxn, child_level, child)?; facet_value: parent_key.left_bound.to_owned().into_boxed_slice(),
});
self.compute_parent_group(wtxn, child_level, child.facet_value)?;
} }
Some(Err(err)) => return Err(err.into()), Some(Err(err)) => return Err(err.into()),
None => { None => {
self.compute_parent_group(wtxn, child_level, child)?; self.compute_parent_group(wtxn, child_level, child.facet_value)?;
break;
}
}
}
// do we have children without parents? // do we have children without parents?
if let Some(child) = changed_children.next() { if let Some(child) = child_it.next() {
// no parent for that key // no parent for that key
let mut it = self let mut parent_it = self
.db .db
.remap_data_type::<DecodeIgnore>() .remap_data_type::<DecodeIgnore>()
.prefix_iter_mut(wtxn, &parent_level_left_bound)?; .prefix_iter_mut(wtxn, &parent_level_left_bound)?;
match it.next() { match parent_it.next() {
// 1. left of the current left bound, or // 1. left of the current left bound, or
Some(Ok((first_key, _first_value))) => 'change_left_bound: { Some(Ok((first_key, _first_value))) => 'change_left_bound: {
// make sure we don't spill on the neighboring fid (level also included defensively) // make sure we don't spill on the neighboring fid (level also included defensively)
if first_key.field_id != self.field_id || first_key.level != parent_level { if first_key.field_id != self.field_id
|| first_key.level != parent_level
{
break 'change_left_bound; break 'change_left_bound;
} }
// remove old left bound // remove old left bound
unsafe { it.del_current()? }; unsafe { parent_it.del_current()? };
drop(it); drop(parent_it);
// pop all elements and order to visit the new left bound // pop all elements and order to visit the new left bound
changed_parents.push(child.clone()); changed_parents.push(FacetFieldIdChange {
self.compute_parent_group(wtxn, child_level, child)?; facet_value: child.facet_value.clone(),
for child in changed_children { });
let new_left_bound = changed_parents.last_mut().unwrap(); self.compute_parent_group(
new_left_bound.clear(); wtxn,
new_left_bound.extend_from_slice(&child); child_level,
self.compute_parent_group(wtxn, child_level, child)?; child.facet_value,
)?;
for child in child_it.by_ref() {
let new_left_bound =
&mut changed_parents.last_mut().unwrap().facet_value;
new_left_bound.clone_from(&child.facet_value);
self.compute_parent_group(
wtxn,
child_level,
child.facet_value,
)?;
} }
break 'current_level;
} }
Some(Err(err)) => return Err(err.into()), Some(Err(err)) => return Err(err.into()),
// 2. max level reached, exit // 2. max level reached, exit
None => { None => {
drop(it); drop(parent_it);
self.compute_parent_group(wtxn, child_level, child)?; self.compute_parent_group(
for child in changed_children {
self.compute_parent_group(wtxn, child_level, child)?;
}
}
}
}
if !changed_parents.is_empty() {
self.find_changed_parents(
wtxn, wtxn,
parent_level, child_level,
changed_parents child.facet_value,
// no need to `rev` here because the parents were already visited in reverse order
.into_iter(),
)?; )?;
for child in child_it.by_ref() {
self.compute_parent_group(
wtxn,
child_level,
child.facet_value,
)?;
}
return Ok(());
}
}
}
}
}
}
if changed_parents.is_empty() {
return Ok(());
}
drop(child_it);
std::mem::swap(&mut changed_children, &mut changed_parents);
// changed_parents is now empty because changed_children was emptied by the drain
} }
Ok(()) Ok(())
} }
@ -196,9 +218,9 @@ impl FacetsUpdateIncrementalInner {
&self, &self,
wtxn: &mut RwTxn<'_>, wtxn: &mut RwTxn<'_>,
parent_level: u8, parent_level: u8,
parent_left_bound: Vec<u8>, parent_left_bound: Box<[u8]>,
) -> Result<()> { ) -> Result<()> {
let mut range_left_bound = parent_left_bound; let mut range_left_bound: Vec<u8> = parent_left_bound.into();
if parent_level == 0 { if parent_level == 0 {
return Ok(()); return Ok(());
} }
@ -207,7 +229,7 @@ impl FacetsUpdateIncrementalInner {
let parent_key = FacetGroupKey { let parent_key = FacetGroupKey {
field_id: self.field_id, field_id: self.field_id,
level: parent_level, level: parent_level,
left_bound: range_left_bound.as_slice(), left_bound: &*range_left_bound,
}; };
let child_right_bound = self let child_right_bound = self
.db .db
@ -241,7 +263,7 @@ impl FacetsUpdateIncrementalInner {
let child_left_key = FacetGroupKey { let child_left_key = FacetGroupKey {
field_id: self.field_id, field_id: self.field_id,
level: child_level, level: child_level,
left_bound: range_left_bound.as_slice(), left_bound: &*range_left_bound,
}; };
let mut child_left_bound = Bound::Included(child_left_key); let mut child_left_bound = Bound::Included(child_left_key);
@ -300,7 +322,7 @@ impl FacetsUpdateIncrementalInner {
let update_key = FacetGroupKey { let update_key = FacetGroupKey {
field_id: self.field_id, field_id: self.field_id,
level: parent_level, level: parent_level,
left_bound: range_left_bound.as_slice(), left_bound: &*range_left_bound,
}; };
drop(child_it); drop(child_it);
if let Bound::Included(_) = child_left_bound { if let Bound::Included(_) = child_left_bound {