Skip to content

Commit 3868541

Browse files
authored
fix: fix prefix lookup in basickv and add corresponding test (#134)
1 parent a19fa4f commit 3868541

File tree

2 files changed

+100
-33
lines changed

2 files changed

+100
-33
lines changed

src/btree/BasicKV.cpp

+24-32
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,9 @@
1111
#include "leanstore/utils/Misc.hpp"
1212

1313
#include <format>
14+
#include <string>
15+
16+
#include <sys/types.h>
1417

1518
using namespace std;
1619
using namespace leanstore::storage;
@@ -178,42 +181,31 @@ OpCode BasicKV::Insert(Slice key, Slice val) {
178181
return OpCode::kOK;
179182
}
180183

181-
OpCode BasicKV::PrefixLookup(Slice key, PrefixLookupCallback callback) {
182-
while (true) {
183-
JUMPMU_TRY() {
184-
GuardedBufferFrame<BTreeNode> guardedLeaf;
185-
FindLeafCanJump(key, guardedLeaf);
186-
187-
bool isEqual = false;
188-
int16_t cur = guardedLeaf->LowerBound<false>(key, &isEqual);
189-
if (isEqual) {
190-
callback(key, guardedLeaf->Value(cur));
191-
guardedLeaf.JumpIfModifiedByOthers();
192-
JUMPMU_RETURN OpCode::kOK;
193-
}
194-
195-
if (cur < guardedLeaf->mNumSlots) {
196-
auto fullKeySize = guardedLeaf->GetFullKeyLen(cur);
197-
auto fullKeyBuf = utils::JumpScopedArray<uint8_t>(fullKeySize);
198-
guardedLeaf->CopyFullKey(cur, fullKeyBuf->get());
199-
guardedLeaf.JumpIfModifiedByOthers();
200-
201-
callback(Slice(fullKeyBuf->get(), fullKeySize), guardedLeaf->Value(cur));
202-
guardedLeaf.JumpIfModifiedByOthers();
203-
204-
JUMPMU_RETURN OpCode::kOK;
184+
OpCode BasicKV::PrefixLookup(Slice prefixKey, PrefixLookupCallback callback) {
185+
JUMPMU_TRY() {
186+
auto iter = GetIterator();
187+
if (iter.SeekToFirstGreaterEqual(prefixKey); !iter.Valid()) {
188+
JUMPMU_RETURN OpCode::kNotFound;
189+
}
190+
bool foundPrefixKey = false;
191+
uint16_t prefixSize = prefixKey.size();
192+
for (; iter.Valid(); iter.Next()) {
193+
iter.AssembleKey();
194+
auto key = iter.Key();
195+
auto value = iter.Val();
196+
if ((key.size() < prefixSize) || (bcmp(key.data(), prefixKey.data(), prefixSize) != 0)) {
197+
break;
205198
}
206-
207-
OpCode ret = ScanAsc(key, [&](Slice scannedKey, Slice scannedVal) {
208-
callback(scannedKey, scannedVal);
209-
return false;
210-
});
211-
JUMPMU_RETURN ret;
199+
callback(key, value);
200+
foundPrefixKey = true;
212201
}
213-
JUMPMU_CATCH() {
202+
if (!foundPrefixKey) {
203+
JUMPMU_RETURN OpCode::kNotFound;
214204
}
205+
JUMPMU_RETURN OpCode::kOK;
206+
}
207+
JUMPMU_CATCH() {
215208
}
216-
217209
UNREACHABLE();
218210
return OpCode::kOther;
219211
}

tests/btree/BasicKVTest.cpp

+76-1
Original file line numberDiff line numberDiff line change
@@ -299,7 +299,7 @@ TEST_F(BasicKVTest, SameKeyInsertRemoveMultiTimes) {
299299
btree = res.value();
300300
});
301301

302-
// insert 100 key-values to the btree
302+
// insert 1000 key-values to the btree
303303
size_t numKVs(1000);
304304
std::vector<std::pair<std::string, std::string>> kvToTest;
305305
for (size_t i = 0; i < numKVs; ++i) {
@@ -342,4 +342,79 @@ TEST_F(BasicKVTest, SameKeyInsertRemoveMultiTimes) {
342342
mStore->ExecSync(0, [&]() { EXPECT_EQ(btree->CountEntries(), numKVs); });
343343
}
344344

345+
TEST_F(BasicKVTest, PrefixLookup) {
346+
storage::btree::BasicKV* btree;
347+
mStore->ExecSync(0, [&]() {
348+
auto res = mStore->CreateBasicKV(genBtreeName("_tree1"));
349+
ASSERT_TRUE(res);
350+
ASSERT_NE(res.value(), nullptr);
351+
btree = res.value();
352+
});
353+
// callback function
354+
std::vector<std::tuple<std::string, std::string>> copiedKeyValue;
355+
auto copyKeyAndValueOut = [&](Slice key, Slice val) {
356+
copiedKeyValue.emplace_back(key.ToString(), val.ToString());
357+
};
358+
359+
{
360+
// not found valid prefix key
361+
std::string prefixString("key_");
362+
auto prefixKey = Slice(prefixString);
363+
EXPECT_EQ(btree->PrefixLookup(prefixKey, copyKeyAndValueOut), OpCode::kNotFound);
364+
}
365+
366+
{
367+
// insert key and value
368+
size_t numKVs(10);
369+
std::vector<std::pair<std::string, std::string>> kvToTest;
370+
for (size_t i = 0; i < numKVs; ++i) {
371+
std::string key("key_" + std::string(10, 'x') + std::to_string(i));
372+
std::string val("val_" + std::string(100, 'x') + std::to_string(i));
373+
mStore->ExecSync(0, [&]() { EXPECT_EQ(btree->Insert(key, val), OpCode::kOK); });
374+
kvToTest.emplace_back(std::move(key), std::move(val));
375+
}
376+
377+
// prefix lookup the full set
378+
auto prefixString("key_" + std::string(10, 'x'));
379+
auto prefixKey = Slice(prefixString);
380+
EXPECT_EQ(btree->PrefixLookup(prefixKey, copyKeyAndValueOut), OpCode::kOK);
381+
EXPECT_EQ(copiedKeyValue.size(), kvToTest.size());
382+
for (size_t i = 0; i < copiedKeyValue.size(); i++) {
383+
const auto& [key, expectedVal] = kvToTest[i];
384+
const auto& [copiedKey, copiedValue] = copiedKeyValue[i];
385+
EXPECT_EQ(copiedKey, key);
386+
EXPECT_EQ(copiedValue, expectedVal);
387+
}
388+
389+
// insert special key for prefix lookup
390+
std::vector<std::pair<std::string, std::string>> kvToTest2;
391+
for (size_t i = 0; i < numKVs; ++i) {
392+
std::string key("prefix_key_" + std::string(10, 'x') + std::to_string(i));
393+
std::string val("prefix_value_" + std::string(100, 'x') + std::to_string(i));
394+
mStore->ExecSync(0, [&]() { EXPECT_EQ(btree->Insert(key, val), OpCode::kOK); });
395+
kvToTest2.emplace_back(std::move(key), std::move(val));
396+
}
397+
398+
// prefix lookup the partial set
399+
copiedKeyValue.clear();
400+
auto prefixString2("prefix_key_" + std::string(10, 'x'));
401+
auto prefixKey2 = Slice(prefixString2);
402+
EXPECT_EQ(btree->PrefixLookup(prefixKey2, copyKeyAndValueOut), OpCode::kOK);
403+
EXPECT_EQ(copiedKeyValue.size(), kvToTest2.size());
404+
for (size_t i = 0; i < copiedKeyValue.size(); i++) {
405+
const auto& [key, expectedVal] = kvToTest2[i];
406+
const auto& [copiedKey, copiedValue] = copiedKeyValue[i];
407+
EXPECT_EQ(copiedKey, key);
408+
EXPECT_EQ(copiedValue, expectedVal);
409+
}
410+
}
411+
{
412+
// greater than the prefix key, but not a true prefix
413+
copiedKeyValue.clear();
414+
auto prefixString("prefix_kex_" + std::string(10, 'w'));
415+
auto prefixKey = Slice(prefixString);
416+
EXPECT_EQ(btree->PrefixLookup(prefixKey, copyKeyAndValueOut), OpCode::kNotFound);
417+
}
418+
}
419+
345420
} // namespace leanstore::test

0 commit comments

Comments
 (0)