oceanbase/unittest/storage/test_simple_rows_merger.cpp

440 lines
12 KiB
C++

/**
* Copyright (c) 2021 OceanBase
* OceanBase CE is licensed under Mulan PubL v2.
* You can use this software according to the terms and conditions of the Mulan PubL v2.
* You may obtain a copy of Mulan PubL v2 at:
* http://license.coscl.org.cn/MulanPubL-2.0
* THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
* EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
* MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
* See the Mulan PubL v2 for more details.
*/
#include "storage/access/ob_simple_rows_merger.h"
#include "lib/container/ob_se_array.h"
#include <gtest/gtest.h>
using namespace oceanbase::storage;
class ObSimpleRowsMergerTest: public ::testing::Test
{
public:
ObSimpleRowsMergerTest() {};
virtual ~ObSimpleRowsMergerTest() {};
virtual void SetUp() {};
virtual void TearDown() {};
private:
// disallow copy
ObSimpleRowsMergerTest(const ObSimpleRowsMergerTest &other);
ObSimpleRowsMergerTest& operator=(const ObSimpleRowsMergerTest &other);
private:
// data members
};
struct TestItem
{
TestItem() = default;
TestItem(int64_t v) : v_(v), iter_idx_(0), equal_with_next_(false) {}
TestItem(int64_t v, int64_t idx) : v_(v), iter_idx_(idx), equal_with_next_(false) {}
TO_STRING_KV(K(v_), K(iter_idx_), K(equal_with_next_));
int64_t v_;
int64_t iter_idx_;
bool equal_with_next_;
};
class TestCompator
{
public:
int cmp(const TestItem &a, const TestItem &b, int64_t &cmp_ret)
{
cmp_ret = 0;
if (a.v_ < b.v_) {
cmp_ret = -1;
} else if (a.v_ > b.v_) {
cmp_ret = 1;
}
return OB_SUCCESS;
}
};
TEST_F(ObSimpleRowsMergerTest, single)
{
int ret = 0;
TestCompator tc;
ObArenaAllocator allocator;
ObSimpleRowsMerger<TestItem, TestCompator> merger(tc);
TestItem data(2021);
// not init
ret = merger.push(data);
ASSERT_EQ(ret, OB_NOT_INIT);
ret = merger.pop();
ASSERT_EQ(ret, OB_NOT_INIT);
ASSERT_EQ(0, merger.count());
ASSERT_TRUE(merger.is_unique_champion());
// 0 player
ret = merger.init(0, allocator);
ASSERT_EQ(ret, OB_INVALID_ARGUMENT);
// init twice
ret = merger.init(1, allocator);
ASSERT_EQ(ret, OB_SUCCESS);
ASSERT_TRUE(merger.is_unique_champion());
ret = merger.init(1, allocator);
ASSERT_EQ(ret, OB_INIT_TWICE);
ASSERT_EQ(0, merger.count());
// push twice
ret = merger.push(data);
ASSERT_EQ(ret, OB_SUCCESS);
ASSERT_EQ(1, merger.count());
ASSERT_TRUE(merger.is_unique_champion());
ret = merger.push(data);
ASSERT_EQ(ret, OB_SIZE_OVERFLOW);
ASSERT_EQ(1, merger.count());
// top twice
const TestItem *top = nullptr;
ASSERT_TRUE(merger.is_unique_champion());
ret = merger.top(top);
ASSERT_EQ(ret, OB_SUCCESS);
ASSERT_EQ(data.v_, top->v_);
ASSERT_TRUE(merger.is_unique_champion());
ret = merger.top(top);
ASSERT_EQ(ret, OB_SUCCESS);
ASSERT_EQ(data.v_, top->v_);
ASSERT_EQ(1, merger.count());
ASSERT_TRUE(merger.is_unique_champion());
ret = merger.pop();
ASSERT_EQ(ret, OB_SUCCESS);
ASSERT_TRUE(merger.is_unique_champion());
ret = merger.pop();
ASSERT_EQ(ret, OB_EMPTY_RESULT);
ASSERT_EQ(0, merger.count());
ret = merger.top(top);
ASSERT_EQ(ret, OB_EMPTY_RESULT);
ASSERT_EQ(0, merger.count());
}
TEST_F(ObSimpleRowsMergerTest, one_iter)
{
int ret = 0;
TestCompator tc;
ObArenaAllocator allocator;
ObSimpleRowsMerger<TestItem, TestCompator> merger(tc);
const int64_t DATA_CNT = 7;
TestItem data[DATA_CNT] = {4, 3, 2, 1, 5, 7, 6};
ret = merger.init(DATA_CNT, allocator);
ASSERT_EQ(ret, OB_SUCCESS);
for (int64_t i = 0; i < DATA_CNT; ++i) {
ret = merger.push(data[i]);
ASSERT_EQ(ret, OB_SUCCESS);
}
// {4, 3, 2, 1, 5, 7, 6}
ASSERT_TRUE(merger.is_unique_champion());
ret = merger.pop();
ASSERT_EQ(ret, OB_SUCCESS);
// {4, 3, 2, 5, 7, 6}
ASSERT_TRUE(merger.is_unique_champion());
ret = merger.pop();
ASSERT_EQ(ret, OB_SUCCESS);
// {4, 3, 5, 7, 6}
ASSERT_TRUE(merger.is_unique_champion());
ret = merger.pop();
ASSERT_EQ(ret, OB_SUCCESS);
// {4, 5, 7, 6}
ASSERT_TRUE(merger.is_unique_champion());
ret = merger.pop();
ASSERT_EQ(ret, OB_SUCCESS);
// {5, 7, 6}
ASSERT_TRUE(merger.is_unique_champion());
ret = merger.push(-1);
ASSERT_EQ(ret, OB_SUCCESS);
// {5, 7, 6, -1}
ASSERT_TRUE(merger.is_unique_champion());
ret = merger.push(10);
ASSERT_EQ(ret, OB_SUCCESS);
// {5, 7, 6, -1, 10}
ASSERT_TRUE(merger.is_unique_champion());
// {{10,0}}
const TestItem *top = nullptr;
ret = merger.top(top);
ASSERT_EQ(ret, OB_SUCCESS);
ASSERT_EQ(-1, top->v_);
ASSERT_EQ(5, merger.count());
ASSERT_TRUE(merger.is_unique_champion());
}
TEST_F(ObSimpleRowsMergerTest, two_iters)
{
int ret = 0;
TestCompator tc;
ObArenaAllocator allocator;
ObSimpleRowsMerger<TestItem, TestCompator> merger(tc);
const int64_t DATA_CNT = 8;
TestItem data[DATA_CNT] = {{1,0}, {1,1}, {2,1}, {2,0}, {3,1}, {3,0}, {5,0}, {4,1}};
ret = merger.init(DATA_CNT, allocator);
ASSERT_EQ(ret, OB_SUCCESS);
for (int64_t i = 0; i < DATA_CNT; ++i) {
ret = merger.push(data[i]);
ASSERT_EQ(ret, OB_SUCCESS);
}
// {{1,0}, {1,1}, {2,1}, {2,0}, {3,1}, {3,0}, {5,0}, {4,1}}
ASSERT_FALSE(merger.is_unique_champion());
ret = merger.pop();
ASSERT_EQ(ret, OB_SUCCESS);
// {{1,1}, {2,1}, {2,0}, {3,1}, {3,0}, {5,0}, {4,1}}
ASSERT_TRUE(merger.is_unique_champion());
ret = merger.pop();
ASSERT_EQ(ret, OB_SUCCESS);
// {{2,1}, {2,0}, {3,1}, {3,0}, {5,0}, {4,1}}
ASSERT_FALSE(merger.is_unique_champion());
ret = merger.pop();
ASSERT_EQ(ret, OB_SUCCESS);
// {{2,1}, {3,1}, {3,0}, {5,0}, {4,1}}
ASSERT_TRUE(merger.is_unique_champion());
ret = merger.pop();
ASSERT_EQ(ret, OB_SUCCESS);
// {{3,1}, {3,0}, {5,0}, {4,1}}
ASSERT_FALSE(merger.is_unique_champion());
ret = merger.pop();
ASSERT_EQ(ret, OB_SUCCESS);
// {{3,1}, {5,0}, {4,1}}
ASSERT_TRUE(merger.is_unique_champion());
ret = merger.push({-1,0});
ASSERT_EQ(ret, OB_SUCCESS);
// {{-1,0}, {3,1}, {5,0}, {4,1}}
ASSERT_TRUE(merger.is_unique_champion());
ret = merger.pop();
ASSERT_EQ(ret, OB_SUCCESS);
// {{3,1}, {5,0}, {4,1}}
ASSERT_TRUE(merger.is_unique_champion());
ret = merger.pop();
ASSERT_EQ(ret, OB_SUCCESS);
// {{5,0}, {4,1}}
ASSERT_TRUE(merger.is_unique_champion());
ret = merger.pop();
ASSERT_EQ(ret, OB_SUCCESS);
// {{5,0}}
ASSERT_TRUE(merger.is_unique_champion());
ret = merger.push({10,0});
ASSERT_EQ(ret, OB_SUCCESS);
// {{5,0}, {10,0}}
ASSERT_TRUE(merger.is_unique_champion());
ret = merger.pop();
ASSERT_EQ(ret, OB_SUCCESS);
// {{10,0}}
ASSERT_TRUE(merger.is_unique_champion());
// {{10,0}}
const TestItem *top = nullptr;
ret = merger.top(top);
ASSERT_EQ(ret, OB_SUCCESS);
ASSERT_EQ(10, top->v_);
ASSERT_EQ(1, merger.count());
ASSERT_TRUE(merger.is_unique_champion());
// {}
ret = merger.pop();
ASSERT_EQ(ret, OB_SUCCESS);
ASSERT_TRUE(merger.empty());
}
TEST_F(ObSimpleRowsMergerTest, three_iters)
{
int ret = 0;
TestCompator tc;
ObArenaAllocator allocator;
ObSimpleRowsMerger<TestItem, TestCompator> merger(tc);
const int64_t DATA_CNT = 8;
TestItem data[DATA_CNT] = {{1,0}, {1,1}, {1,2}, {2,2}, {2,0}, {3,1}, {4,0}, {4,2}};
ret = merger.init(DATA_CNT, allocator);
ASSERT_EQ(ret, OB_SUCCESS);
for (int64_t i = 0; i < DATA_CNT; ++i) {
ret = merger.push(data[i]);
ASSERT_EQ(ret, OB_SUCCESS);
}
// {{1,0}, {1,1}, {1,2}, {2,2}, {2,0}, {3,1}, {4,0}, {4,2}}
ASSERT_FALSE(merger.is_unique_champion());
ret = merger.pop();
ASSERT_EQ(ret, OB_SUCCESS);
// {{1,1}, {1,2}, {2,2}, {2,0}, {3,1}, {4,0}, {4,2}}
ASSERT_FALSE(merger.is_unique_champion());
ret = merger.pop();
ASSERT_EQ(ret, OB_SUCCESS);
// {{1,2}, {2,2}, {2,0}, {3,1}, {4,0}, {4,2}}
ASSERT_TRUE(merger.is_unique_champion());
ret = merger.pop();
ASSERT_EQ(ret, OB_SUCCESS);
// {{2,2}, {2,0}, {3,1}, {4,0}, {4,2}}
ASSERT_FALSE(merger.is_unique_champion());
ret = merger.pop();
ASSERT_EQ(ret, OB_SUCCESS);
// {{2,2}, {3,1}, {4,0}, {4,2}}
ASSERT_TRUE(merger.is_unique_champion());
ret = merger.pop();
ASSERT_EQ(ret, OB_SUCCESS);
// {{3,1}, {4,0}, {4,2}}
ASSERT_TRUE(merger.is_unique_champion());
ret = merger.push({3,0});
ASSERT_EQ(ret, OB_SUCCESS);
// {{3,1}, {4,0}, {4,2}, {3,0}}
ASSERT_FALSE(merger.is_unique_champion());
ret = merger.push({3,2});
ASSERT_EQ(ret, OB_SUCCESS);
// {{3,1}, {4,0}, {4,2}, {3,0}, {3,2}}
ASSERT_FALSE(merger.is_unique_champion());
ret = merger.pop();
ASSERT_EQ(ret, OB_SUCCESS);
// {{3,1}, {4,0}, {4,2}, {3,2}}
ASSERT_FALSE(merger.is_unique_champion());
ret = merger.pop();
ASSERT_EQ(ret, OB_SUCCESS);
// {{4,0}, {4,2}, {3,2}}
ASSERT_TRUE(merger.is_unique_champion());
ret = merger.pop();
ASSERT_EQ(ret, OB_SUCCESS);
// {{4,0}, {4,2}}
ASSERT_FALSE(merger.is_unique_champion());
ret = merger.pop();
ASSERT_EQ(ret, OB_SUCCESS);
// {{4,2}}
ASSERT_TRUE(merger.is_unique_champion());
ret = merger.push({10,2});
ASSERT_EQ(ret, OB_SUCCESS);
// {{4,2}, {10,2}}
ASSERT_TRUE(merger.is_unique_champion());
ret = merger.pop();
ASSERT_EQ(ret, OB_SUCCESS);
// {{10,2}}
ASSERT_TRUE(merger.is_unique_champion());
// {{10,2}}
const TestItem *top = nullptr;
ret = merger.top(top);
ASSERT_EQ(ret, OB_SUCCESS);
ASSERT_EQ(10, top->v_);
ASSERT_EQ(1, merger.count());
ASSERT_TRUE(merger.is_unique_champion());
// {}
ret = merger.pop();
ASSERT_EQ(ret, OB_SUCCESS);
ASSERT_TRUE(merger.empty());
}
TEST_F(ObSimpleRowsMergerTest, reset_range)
{
int ret = 0;
TestCompator tc;
ObArenaAllocator allocator;
ObSimpleRowsMerger<TestItem, TestCompator> merger(tc);
const int64_t DATA_CNT = 5;
TestItem data[DATA_CNT] = {{1,0}, {1,1}, {1,2}, {2,2}, {2,0}};
ret = merger.init(DATA_CNT, allocator);
ASSERT_EQ(ret, OB_SUCCESS);
for (int64_t i = 0; i < DATA_CNT; ++i) {
ret = merger.push(data[i]);
ASSERT_EQ(ret, OB_SUCCESS);
}
// {{1,0}, {1,1}, {1,2}, {2,0}, {2,2}}
ASSERT_FALSE(merger.is_unique_champion());
ret = merger.pop();
ASSERT_EQ(ret, OB_SUCCESS);
// {{1,1}, {1,2}, {2,2}, {2,0}}
ASSERT_FALSE(merger.is_unique_champion());
int64_t gap_idx = 1;
TestItem gap_item(3,1);
const TestItem *top_item;
TestItem items[10];
int64_t remain_item = 0;
while(OB_SUCC(ret) && !merger.empty()) {
if (OB_FAIL(merger.top(top_item))) {
STORAGE_LOG(WARN, "get loser tree top item fail", K(ret), K(merger));
} else if (nullptr == top_item) {
ret = OB_ERR_UNEXPECTED;
STORAGE_LOG(WARN, "item or row is null", K(ret), KP(top_item));
} else {
int64_t tree_ret = 0;
ASSERT_EQ(tc.cmp(gap_item, *top_item, tree_ret), OB_SUCCESS);
if (top_item->iter_idx_ < gap_idx || tree_ret < 0) {
items[remain_item++] = *top_item;
// must set to false if using simple row merger
items[remain_item - 1].equal_with_next_ = false;
}
if (OB_FAIL(merger.pop())) {
STORAGE_LOG(WARN, "pop loser tree fail", K(ret), K(merger));
}
}
}
ASSERT_EQ(ret, OB_SUCCESS);
for (int64_t i = remain_item - 1; i >= 0 ; --i) {
ret = merger.push(items[i]);
ASSERT_EQ(ret, OB_SUCCESS);
}
// {{2,0}}
ASSERT_EQ(1, merger.count());
ASSERT_TRUE(merger.is_unique_champion());
const TestItem *top = nullptr;
ret = merger.top(top);
ASSERT_EQ(ret, OB_SUCCESS);
ASSERT_EQ(2, top->v_);
ASSERT_EQ(0, top->iter_idx_);
ASSERT_TRUE(merger.is_unique_champion());
// {}
ret = merger.pop();
ASSERT_EQ(ret, OB_SUCCESS);
ASSERT_TRUE(merger.empty());
}
int main(int argc, char **argv)
{
::testing::InitGoogleTest(&argc,argv);
return RUN_ALL_TESTS();
}