440 lines
		
	
	
		
			12 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
			
		
		
	
	
			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();
 | |
| }
 | 
