Skip to content

Commit 57efb50

Browse files
authored
Handle empty data nodes when finding last key (#19)
- Traverse backward in Alex<>::get_payload_last_no_greater_than() and Alex<>::find_last_no_greater_than(). - Add test that fails on `master`.
1 parent 2dd4068 commit 57efb50

File tree

2 files changed

+65
-20
lines changed

2 files changed

+65
-20
lines changed

src/core/alex.h

Lines changed: 24 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -994,18 +994,20 @@ class Alex {
994994
typename self_type::Iterator find_last_no_greater_than(const T& key) {
995995
stats_.num_lookups++;
996996
data_node_type* leaf = get_leaf(key);
997-
int idx = leaf->upper_bound(key) - 1;
998-
if (idx == -1) {
999-
if (leaf->prev_leaf_) {
1000-
// Edge case: need to check previous data node
1001-
data_node_type* prev_leaf = leaf->prev_leaf_;
1002-
int last_pos = prev_leaf->last_pos();
1003-
return Iterator(prev_leaf, last_pos);
1004-
} else {
997+
const int idx = leaf->upper_bound(key) - 1;
998+
if (idx >= 0) {
999+
return Iterator(leaf, idx);
1000+
}
1001+
1002+
// Edge case: need to check previous data node(s)
1003+
while (true) {
1004+
if (leaf->prev_leaf_ == nullptr) {
10051005
return Iterator(leaf, 0);
10061006
}
1007-
} else {
1008-
return Iterator(leaf, idx);
1007+
leaf = leaf->prev_leaf_;
1008+
if (leaf->num_keys_ > 0) {
1009+
return Iterator(leaf, leaf->last_pos());
1010+
}
10091011
}
10101012
}
10111013

@@ -1015,17 +1017,20 @@ class Alex {
10151017
P* get_payload_last_no_greater_than(const T& key) {
10161018
stats_.num_lookups++;
10171019
data_node_type* leaf = get_leaf(key);
1018-
int idx = leaf->upper_bound(key) - 1;
1019-
if (idx == -1) {
1020-
if (leaf->prev_leaf_) {
1021-
// Edge case: need to check previous data node
1022-
data_node_type* prev_leaf = leaf->prev_leaf_;
1023-
return &(prev_leaf->get_payload(prev_leaf->last_pos()));
1024-
} else {
1020+
const int idx = leaf->upper_bound(key) - 1;
1021+
if (idx >= 0) {
1022+
return &(leaf->get_payload(idx));
1023+
}
1024+
1025+
// Edge case: Need to check previous data node(s)
1026+
while (true) {
1027+
if (leaf->prev_leaf_ == nullptr) {
10251028
return &(leaf->get_payload(leaf->first_pos()));
10261029
}
1027-
} else {
1028-
return &(leaf->get_payload(idx));
1030+
leaf = leaf->prev_leaf_;
1031+
if (leaf->num_keys_ > 0) {
1032+
return &(leaf->get_payload(leaf->last_pos()));
1033+
}
10291034
}
10301035
}
10311036

test/unittest_alex.h

Lines changed: 41 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -297,6 +297,46 @@ TEST_CASE("TestFindLastNoGreaterThan") {
297297
CHECK_EQ(values[0].first, it.key());
298298
}
299299

300+
TEST_CASE("TestLargeFindLastNoGreaterThan") {
301+
Alex<uint64_t, uint64_t> index;
302+
index.insert(std::make_pair(0ULL, 0ULL));
303+
304+
const uint64_t keys_per_segment = 80523;
305+
const uint64_t step_size = 43206176;
306+
const uint64_t num_segments = 16;
307+
const uint64_t start_keys[] = {698631712, 658125922, 660826308, 663526694,
308+
666227080, 668927466, 671627852, 674328238,
309+
677028624, 679729010, 682429396, 685129782,
310+
687830168, 690530554, 693230940, 695931326};
311+
312+
uint64_t max_key = 0;
313+
uint64_t max_key_value = 0;
314+
for (uint64_t segment = 0; segment < num_segments; ++segment) {
315+
uint64_t curr_key = start_keys[segment];
316+
for (uint64_t i = 0; i < keys_per_segment; ++i) {
317+
if (curr_key > max_key) {
318+
max_key = curr_key;
319+
max_key_value = i + 1;
320+
}
321+
322+
index.insert(curr_key, i + 1);
323+
curr_key += step_size;
324+
}
325+
}
326+
327+
// This key is larger than all keys in the index.
328+
const uint64_t test_key = 3650322694401;
329+
CHECK_GT(test_key, max_key);
330+
331+
auto it = index.find_last_no_greater_than(test_key);
332+
CHECK(!it.is_end());
333+
CHECK_EQ(max_key, it.key());
334+
335+
const uint64_t *p = index.get_payload_last_no_greater_than(test_key);
336+
CHECK(p);
337+
CHECK_EQ(max_key_value, *p);
338+
}
339+
300340
TEST_CASE("TestReadModifyWrite") {
301341
Alex<int, int> index;
302342

@@ -482,4 +522,4 @@ TEST_CASE("TestRangeScan") {
482522
CHECK_EQ(results2.size(), 90);
483523
CHECK_EQ(sum2, 4905);
484524
}
485-
};
525+
};

0 commit comments

Comments
 (0)