summaryrefslogtreecommitdiffstats
path: root/searchlib
diff options
context:
space:
mode:
authorHenning Baldersheim <balder@yahoo-inc.com>2020-05-07 21:14:40 +0000
committerHenning Baldersheim <balder@yahoo-inc.com>2020-05-07 21:14:40 +0000
commitb42b06208f31a120009adade2238d34ce228ed18 (patch)
tree422b773e5c38fc34839234a8cfba1845e16494cb /searchlib
parent90e3dc358cad438b12e59489302c746541c1dda9 (diff)
In order to handle and/or/andnot where the left hand side is longer than the right hand size,
we handle it as if it had been false padded. This is to handle the case where you end up below a SourceBlender, where the disk indexes have different ages and docId limits. These padded bits will never be accessed, as they will never be chosen by the source blender. But having well defined behavior is always good.
Diffstat (limited to 'searchlib')
-rw-r--r--searchlib/src/tests/common/bitvector/bitvector_test.cpp41
-rw-r--r--searchlib/src/vespa/searchlib/common/bitvector.cpp34
2 files changed, 69 insertions, 6 deletions
diff --git a/searchlib/src/tests/common/bitvector/bitvector_test.cpp b/searchlib/src/tests/common/bitvector/bitvector_test.cpp
index db29ab9881f..a0e46870741 100644
--- a/searchlib/src/tests/common/bitvector/bitvector_test.cpp
+++ b/searchlib/src/tests/common/bitvector/bitvector_test.cpp
@@ -300,15 +300,54 @@ TEST("requireThatInitRangeStaysWithinBounds") {
EXPECT_TRUE(it->isAtEnd());
}
+void
+setEveryNthBit(uint32_t n, BitVector & bv, uint32_t offset, uint32_t end) {
+ for (uint32_t i(0); i < (end - offset); i++) {
+ if ((i % n) == 0) {
+ bv.setBit(offset + i);
+ } else {
+ bv.clearBit(offset + i);
+ }
+ }
+ bv.invalidateCachedCount();
+}
+BitVector::UP
+createEveryNthBitSet(uint32_t n, uint32_t end) {
+ BitVector::UP bv(BitVector::create(0, end));
+ setEveryNthBit(n, *bv, 0, end);
+ return bv;
+}
+
+template<typename Func>
+void
+verifyThatLongerWithShorterWorksAsZeroPadded(uint32_t sz1, uint32_t sz2, Func func) {
+ BitVector::UP aLarger = createEveryNthBitSet(2, sz2);
+
+ BitVector::UP bSmall = createEveryNthBitSet(3, sz1);
+ BitVector::UP bLarger = createEveryNthBitSet(3, sz2);
+ bLarger->clearInterval(sz1, sz2);
+ EXPECT_EQUAL(bSmall->countTrueBits(), bLarger->countTrueBits());
+
+ BitVector::UP aLarger2 = BitVector::create(*aLarger);
+ EXPECT_TRUE(*aLarger == *aLarger2);
+ func(*aLarger, *bLarger);
+ func(*aLarger2, *bSmall);
+ EXPECT_TRUE(*aLarger == *aLarger2);
+}
+
TEST("requireThatAndWorks") {
for (uint32_t offset(0); offset < 100; offset++) {
testAnd(offset);
+ verifyThatLongerWithShorterWorksAsZeroPadded(offset+256, offset+256 + offset + 3,
+ [](BitVector & a, const BitVector & b) { a.andWith(b); });
}
}
TEST("requireThatOrWorks") {
for (uint32_t offset(0); offset < 100; offset++) {
testOr(offset);
+ verifyThatLongerWithShorterWorksAsZeroPadded(offset+256, offset+256 + offset + 3,
+ [](BitVector & a, const BitVector & b) { a.orWith(b); });
}
}
@@ -316,6 +355,8 @@ TEST("requireThatOrWorks") {
TEST("requireThatAndNotWorks") {
for (uint32_t offset(0); offset < 100; offset++) {
testAndNot(offset);
+ verifyThatLongerWithShorterWorksAsZeroPadded(offset+256, offset+256 + offset + 3,
+ [](BitVector & a, const BitVector & b) { a.andNotWith(b); });
}
}
diff --git a/searchlib/src/vespa/searchlib/common/bitvector.cpp b/searchlib/src/vespa/searchlib/common/bitvector.cpp
index 2e70e9f2603..617e7537c7c 100644
--- a/searchlib/src/vespa/searchlib/common/bitvector.cpp
+++ b/searchlib/src/vespa/searchlib/common/bitvector.cpp
@@ -24,7 +24,7 @@ void verifyContains(const search::BitVector & a, const search::BitVector & b) __
void verifyContains(const search::BitVector & a, const search::BitVector & b)
{
- if ((a.getStartIndex() < b.getStartIndex()) || (a.size() > b.size())) {
+ if (a.getStartIndex() < b.getStartIndex()) {
throw IllegalArgumentException(make_string("[%d, %d] is not contained in [%d, %d]",
a.getStartIndex(), a.size(), b.getStartIndex(), b.size()),
VESPA_STRLOC);
@@ -178,8 +178,17 @@ void
BitVector::orWith(const BitVector & right)
{
verifyContains(*this, right);
- IAccelrated::getAccelrator().orBit(getActiveStart(), right.getWordIndex(getStartIndex()), getActiveBytes());
+ if (right.size() < size()) {
+ ssize_t commonBytes = numActiveBytes(getStartIndex(), right.size()) - sizeof(Word);
+ if (commonBytes > 0) {
+ IAccelrated::getAccelrator().orBit(getActiveStart(), right.getWordIndex(getStartIndex()), commonBytes);
+ }
+ Index last(right.size() - 1);
+ getWordIndex(last)[0] |= (right.getWordIndex(last)[0] & ~endBits(last));
+ } else {
+ IAccelrated::getAccelrator().orBit(getActiveStart(), right.getWordIndex(getStartIndex()), getActiveBytes());
+ }
repairEnds();
invalidateCachedCount();
}
@@ -201,9 +210,13 @@ BitVector::andWith(const BitVector & right)
{
verifyContains(*this, right);
- IAccelrated::getAccelrator().andBit(getActiveStart(), right.getWordIndex(getStartIndex()), getActiveBytes());
+ uint32_t commonBytes = std::min(getActiveBytes(), numActiveBytes(getStartIndex(), right.size()));
+ IAccelrated::getAccelrator().andBit(getActiveStart(), right.getWordIndex(getStartIndex()), commonBytes);
+ if (right.size() < size()) {
+ clearInterval(right.size(), size());
+ }
- setGuardBit();
+ repairEnds();
invalidateCachedCount();
}
@@ -213,9 +226,18 @@ BitVector::andNotWith(const BitVector& right)
{
verifyContains(*this, right);
- IAccelrated::getAccelrator().andNotBit(getActiveStart(), right.getWordIndex(getStartIndex()), getActiveBytes());
+ if (right.size() < size()) {
+ ssize_t commonBytes = numActiveBytes(getStartIndex(), right.size()) - sizeof(Word);
+ if (commonBytes > 0) {
+ IAccelrated::getAccelrator().andNotBit(getActiveStart(), right.getWordIndex(getStartIndex()), commonBytes);
+ }
+ Index last(right.size() - 1);
+ getWordIndex(last)[0] &= ~(right.getWordIndex(last)[0] & ~endBits(last));
+ } else {
+ IAccelrated::getAccelrator().andNotBit(getActiveStart(), right.getWordIndex(getStartIndex()), getActiveBytes());
+ }
- setGuardBit();
+ repairEnds();
invalidateCachedCount();
}