diff --git a/src/indexer/directory_lock.rs b/src/indexer/directory_lock.rs index abcd1fd04..991e46cbb 100644 --- a/src/indexer/directory_lock.rs +++ b/src/indexer/directory_lock.rs @@ -25,4 +25,3 @@ impl Drop for DirectoryLock { } } } - diff --git a/src/postings/docset.rs b/src/postings/docset.rs index c030b092b..8d5c36efb 100644 --- a/src/postings/docset.rs +++ b/src/postings/docset.rs @@ -34,6 +34,9 @@ pub trait DocSet { /// More specifically, if the docset is already positionned on the target /// skipping will advance to the next position and return SkipResult::Overstep. /// + /// If `.skip_next()` oversteps, then the docset must be positionned correctly + /// on an existing document. In other words, `.doc()` should return the first document + /// greater than `DocId`. fn skip_next(&mut self, target: DocId) -> SkipResult { if !self.advance() { return SkipResult::End; diff --git a/src/postings/intersection.rs b/src/postings/intersection.rs index 1a3501703..67dc8ecc3 100644 --- a/src/postings/intersection.rs +++ b/src/postings/intersection.rs @@ -32,37 +32,6 @@ impl IntersectionDocSet { } impl DocSet for IntersectionDocSet { - /// Returns the minimum `.size_hint()` of the intersected docsets. - fn size_hint(&self) -> u32 { - self.docsets - .iter() - .map(|docset| docset.size_hint()) - .min() - .unwrap() // safe as docsets cannot be empty. - } - - fn skip_next(&mut self, mut target: DocId) -> SkipResult { - let mut overstep = false; - for docset in &mut self.docsets { - match docset.skip_next(target) { - SkipResult::End => { - return SkipResult::End; - } - SkipResult::OverStep => { - overstep = true; - target = docset.doc(); - } - SkipResult::Reached => {} - } - } - if overstep { - SkipResult::OverStep - } else { - SkipResult::Reached - } - } - - #[allow(never_loop)] fn advance(&mut self) -> bool { if self.finished { @@ -102,13 +71,53 @@ impl DocSet for IntersectionDocSet { } } + fn skip_next(&mut self, mut target: DocId) -> SkipResult { + // We optimize skipping by skipping every single member + // of the intersection to target. + + // TODO fix BUG... + // what if we overstep on the second member of the intersection? + // The first member is not necessarily correct. + let mut overstep = false; + for docset in &mut self.docsets { + match docset.skip_next(target) { + SkipResult::End => { + return SkipResult::End; + } + SkipResult::OverStep => { + overstep = true; + // update the target + // for the remaining members of the intersection. + target = docset.doc(); + } + SkipResult::Reached => { + } + } + } + self.doc = target; + if overstep { + SkipResult::OverStep + } else { + SkipResult::Reached + } + } + + fn doc(&self) -> DocId { self.doc } + fn size_hint(&self) -> u32 { + self.docsets + .iter() + .map(|docset| docset.size_hint()) + .min() + .unwrap_or(0u32) + } } #[cfg(test)] mod tests { + use postings::SkipResult; use postings::{DocSet, IntersectionDocSet, VecPostings}; @@ -144,6 +153,23 @@ mod tests { assert_eq!(intersection.doc(), 0); } + #[test] + fn test_intersection_skip() { + let left = VecPostings::from(vec![4]); + let right = VecPostings::from(vec![2, 5]); + let mut intersection = IntersectionDocSet::from(vec![left, right]); + assert_eq!(intersection.skip_next(4), SkipResult::End); + } + + #[test] + fn test_intersection_skip_2() { + let left = VecPostings::from(vec![0, 1, 2, 4]); + let right = VecPostings::from(vec![2, 5]); + let mut intersection = IntersectionDocSet::from(vec![left, right]); + assert_eq!(intersection.skip_next(2), SkipResult::Reached); + assert_eq!(intersection.doc(), 2); + } + #[test] fn test_intersection_empty() { let a = VecPostings::from(vec![1, 3]);