Skip to content

Commit 29e4793

Browse files
committed
fix: increase coverage for scanAsc and scanDesc
1 parent 3d3b882 commit 29e4793

File tree

2 files changed

+100
-6
lines changed

2 files changed

+100
-6
lines changed

src/btree/BasicKV.cpp

+9-6
Original file line numberDiff line numberDiff line change
@@ -91,14 +91,18 @@ OpCode BasicKV::ScanAsc(Slice startKey, ScanCallback callback) {
9191

9292
JUMPMU_TRY() {
9393
auto iter = GetIterator();
94-
for (iter.SeekToFirstGreaterEqual(startKey); iter.Valid(); iter.Next()) {
94+
if (iter.SeekToFirstGreaterEqual(startKey); !iter.Valid()) {
95+
JUMPMU_RETURN OpCode::kNotFound;
96+
}
97+
for (; iter.Valid(); iter.Next()) {
9598
iter.AssembleKey();
9699
auto key = iter.Key();
97100
auto value = iter.Val();
98101
if (!callback(key, value)) {
99102
break;
100103
}
101104
}
105+
102106
JUMPMU_RETURN OpCode::kOK;
103107
}
104108
JUMPMU_CATCH() {
@@ -116,17 +120,16 @@ OpCode BasicKV::ScanDesc(Slice scanKey, ScanCallback callback) {
116120
if (iter.SeekToLastLessEqual(scanKey); !iter.Valid()) {
117121
JUMPMU_RETURN OpCode::kNotFound;
118122
}
119-
while (true) {
123+
for (; iter.Valid(); iter.Prev()) {
120124
iter.AssembleKey();
121125
auto key = iter.Key();
122126
auto value = iter.Val();
123127
if (!callback(key, value)) {
124-
JUMPMU_RETURN OpCode::kOK;
125-
}
126-
if (iter.Prev(); !iter.Valid()) {
127-
JUMPMU_RETURN OpCode::kNotFound;
128+
break;
128129
}
129130
}
131+
132+
JUMPMU_RETURN OpCode::kOK;
130133
}
131134
JUMPMU_CATCH() {
132135
}

tests/BasicKVTest.cpp

+91
Original file line numberDiff line numberDiff line change
@@ -193,5 +193,96 @@ TEST_F(BasicKVTest, BasicKVInsertDuplicatedKey) {
193193
}
194194
});
195195
}
196+
TEST_F(BasicKVTest, BasicKVScanAscAndScanDesc) {
197+
storage::btree::BasicKV* btree;
198+
// prepare key-value pairs to insert
199+
size_t numKVs(10);
200+
std::vector<std::tuple<std::string, std::string>> kvToTest;
201+
const auto keySize = sizeof(size_t);
202+
uint8_t keyBuffer[keySize];
203+
for (size_t i = 0; i < numKVs; ++i) {
204+
utils::Fold(keyBuffer, i);
205+
std::string key("key_btree_LL_xxxxxxxxxxxx_" +
206+
std::string(reinterpret_cast<char*>(keyBuffer), keySize));
207+
std::string val("VAL_BTREE_LL_YYYYYYYYYYYY_" +
208+
std::string(reinterpret_cast<char*>(keyBuffer), keySize));
209+
kvToTest.push_back(std::make_tuple(key, val));
210+
}
211+
212+
// create leanstore btree for table records
213+
auto* curTest = ::testing::UnitTest::GetInstance()->current_test_info();
214+
auto btreeName = std::string(curTest->test_case_name()) + "_" + std::string(curTest->name());
215+
216+
mStore->ExecSync(0, [&]() {
217+
auto res = mStore->CreateBasicKV(btreeName);
218+
EXPECT_TRUE(res);
219+
EXPECT_NE(res.value(), nullptr);
220+
221+
btree = res.value();
222+
for (size_t i = 0; i < numKVs; ++i) {
223+
const auto& [key, val] = kvToTest[i];
224+
EXPECT_EQ(btree->Insert(Slice(key), Slice(val)), OpCode::kOK);
225+
}
226+
227+
std::vector<std::tuple<std::string, std::string>> copiedKeyValue;
228+
auto copyKeyAndValueOut = [&](Slice key, Slice val) {
229+
copiedKeyValue.emplace_back(key.ToString(), val.ToString());
230+
return true;
231+
};
232+
233+
size_t startIndex = 5;
234+
auto startKey = Slice(std::get<0>(kvToTest[startIndex]));
235+
auto callbackReturnFalse = [&]([[maybe_unused]] Slice key, [[maybe_unused]] Slice val) {
236+
return false;
237+
};
238+
239+
// ScanAsc
240+
{
241+
// no bigger than largestLexicographicalOrderKey in ScanAsc should return OpCode::kNotFound
242+
Slice largestLexicographicalOrderKey("zzzzzzz");
243+
EXPECT_EQ(btree->ScanAsc(largestLexicographicalOrderKey, copyKeyAndValueOut),
244+
OpCode::kNotFound);
245+
EXPECT_EQ(btree->ScanAsc(largestLexicographicalOrderKey, callbackReturnFalse),
246+
OpCode::kNotFound);
196247

248+
// callback return false should terminate scan
249+
EXPECT_EQ(btree->ScanAsc(startKey, callbackReturnFalse), OpCode::kOK);
250+
251+
// query on ScanAsc
252+
EXPECT_EQ(btree->ScanAsc(startKey, copyKeyAndValueOut), OpCode::kOK);
253+
EXPECT_EQ(copiedKeyValue.size(), 5);
254+
for (size_t i = startIndex, j = 0; i < numKVs && j < copiedKeyValue.size(); i++, j++) {
255+
const auto& [key, expectedVal] = kvToTest[i];
256+
const auto& [copiedKey, copiedValue] = copiedKeyValue[j];
257+
EXPECT_EQ(copiedKey, key);
258+
EXPECT_EQ(copiedValue, expectedVal);
259+
}
260+
}
261+
262+
// ScanDesc
263+
{
264+
// no smaller than key in ScanDesc should return OpCode::kNotFound
265+
Slice smallestLexicographicalOrderKey("aaaaaaaa");
266+
EXPECT_EQ(btree->ScanDesc(smallestLexicographicalOrderKey, copyKeyAndValueOut),
267+
OpCode::kNotFound);
268+
EXPECT_EQ(btree->ScanDesc(smallestLexicographicalOrderKey, callbackReturnFalse),
269+
OpCode::kNotFound);
270+
271+
// callback return false should terminate scan
272+
EXPECT_EQ(btree->ScanDesc(startKey, callbackReturnFalse), OpCode::kOK);
273+
274+
// query on ScanDesc
275+
copiedKeyValue.clear();
276+
EXPECT_EQ(btree->ScanDesc(startKey, copyKeyAndValueOut), OpCode::kOK);
277+
EXPECT_EQ(copiedKeyValue.size(), 6);
278+
for (int i = startIndex, j = 0; i >= 0 && j < static_cast<int>(copiedKeyValue.size());
279+
i--, j++) {
280+
const auto& [key, expectedVal] = kvToTest[i];
281+
const auto& [copiedKey, copiedValue] = copiedKeyValue[j];
282+
EXPECT_EQ(copiedKey, key);
283+
EXPECT_EQ(copiedValue, expectedVal);
284+
}
285+
}
286+
});
287+
}
197288
} // namespace leanstore::test

0 commit comments

Comments
 (0)