432 lines
		
	
	
		
			11 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
			
		
		
	
	
			432 lines
		
	
	
		
			11 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 <gtest/gtest.h>
 | |
| #include "lib/container/ob_seg_array.h"
 | |
| #include "clog/ob_file_id_cache.h"
 | |
| using namespace oceanbase::common;
 | |
| using namespace oceanbase::clog;
 | |
| 
 | |
| ObSmallAllocator small_allocator;
 | |
| 
 | |
| void init_env()
 | |
| {
 | |
|   const int64_t seg_size = ObSegArray<Log2File, ObFileIdList::SEG_STEP, ObFileIdList::SEG_COUNT>::get_seg_size();
 | |
|   small_allocator.init(seg_size,
 | |
|       ObModIds::OB_CSR_FILE_ID_CACHE_FILE_ITEM,
 | |
|       OB_SERVER_TENANT_ID,
 | |
|       OB_MALLOC_BIG_BLOCK_SIZE,
 | |
|       128,
 | |
|       4L * 1024L * 1024L * 1024L);
 | |
| }
 | |
| 
 | |
| class TestSegArray : public ::testing::Test {
 | |
|   public:
 | |
|   TestSegArray()
 | |
|   {}
 | |
|   virtual ~TestSegArray()
 | |
|   {}
 | |
| 
 | |
|   private:
 | |
|   DISALLOW_COPY_AND_ASSIGN(TestSegArray);
 | |
| };
 | |
| 
 | |
| struct Item {
 | |
|   int x;
 | |
|   int y;
 | |
| 
 | |
|   Item() : x(0), y(0)
 | |
|   {}
 | |
|   bool operator<=(const Item& that) const
 | |
|   {
 | |
|     return x <= that.x;
 | |
|   }
 | |
|   TO_STRING_KV(K(x), K(y));
 | |
| };
 | |
| 
 | |
| struct ItemLEFunctor {
 | |
|   bool operator()(const Item& a, const Item& b) const
 | |
|   {
 | |
|     return a <= b;
 | |
|   }
 | |
| };
 | |
| 
 | |
| struct ReverseForEachFunctor {
 | |
|   int64_t cnt_;
 | |
|   int operator()(const Item& item)
 | |
|   {
 | |
|     int ret = OB_SUCCESS;
 | |
|     LIB_LOG(INFO, "print", K(item), K(cnt_));
 | |
|     cnt_++;
 | |
|     return ret;
 | |
|   }
 | |
| };
 | |
| 
 | |
| TEST(TestSegArray, test_fix_rq)
 | |
| {
 | |
|   ObFixedRingDeque<Item, 20> q;
 | |
|   for (int i = 0; i < 10; i++) {
 | |
|     Item item;
 | |
|     item.x = i * 10;
 | |
|     item.y = i * 10;
 | |
|     ASSERT_EQ(OB_SUCCESS, q.push_back(item));
 | |
|   }
 | |
| 
 | |
|   q.debug_print();
 | |
| 
 | |
|   Item target;
 | |
|   target.x = -5;
 | |
|   target.y = -5;
 | |
|   Item prev;
 | |
|   Item next;
 | |
|   ItemLEFunctor le_functor;
 | |
|   ASSERT_EQ(OB_ERR_OUT_OF_LOWER_BOUND, q.search_boundary(target, prev, next, le_functor));
 | |
|   EXPECT_EQ(0, next.x);
 | |
|   EXPECT_EQ(0, next.y);
 | |
| 
 | |
|   for (int i = 0; i < 10; i++) {
 | |
|     Item target;
 | |
|     target.x = i * 10 + 5;
 | |
|     target.y = i * 10 + 5;
 | |
|     Item prev;
 | |
|     Item next;
 | |
|     int expect_err = i < 9 ? OB_SUCCESS : OB_ERR_OUT_OF_UPPER_BOUND;
 | |
|     int search_err = q.search_boundary(target, prev, next, le_functor);
 | |
|     ASSERT_EQ(expect_err, search_err);
 | |
|     ASSERT_TRUE(prev.x == target.x - 5);
 | |
|     if (i < 9) {
 | |
|       ASSERT_TRUE(next.x == target.x + 5);
 | |
|     }
 | |
|     LIB_LOG(INFO, "search", K(target), K(prev), K(next), K(search_err));
 | |
|   }
 | |
| 
 | |
|   for (int i = 0; i < 10; i++) {
 | |
|     Item item;
 | |
|     ASSERT_EQ(OB_SUCCESS, q.top_front(item));
 | |
|     ASSERT_EQ(item.x, i * 10);
 | |
|     LIB_LOG(INFO, "top_front", K(item));
 | |
|     ASSERT_EQ(OB_SUCCESS, q.pop_front(item));
 | |
|     ASSERT_EQ(item.x, i * 10);
 | |
|     LIB_LOG(INFO, "pop_front", K(item));
 | |
|   }
 | |
| 
 | |
|   do {
 | |
|     Item item;
 | |
|     ASSERT_EQ(OB_ENTRY_NOT_EXIST, q.top_front(item));
 | |
|     ASSERT_EQ(OB_ENTRY_NOT_EXIST, q.pop_front(item));
 | |
|   } while (0);
 | |
| 
 | |
|   for (int i = 0; i < 10; i++) {
 | |
|     Item item;
 | |
|     item.x = (9 - i) * 10;
 | |
|     item.y = (9 - i) * 10;
 | |
|     ASSERT_EQ(OB_SUCCESS, q.push_front(item));
 | |
|   }
 | |
| 
 | |
|   for (int i = 0; i < 10; i++) {
 | |
|     Item target;
 | |
|     target.x = i * 10 + 5;
 | |
|     target.y = i * 10 + 5;
 | |
|     Item prev;
 | |
|     Item next;
 | |
|     int expect_err = i < 9 ? OB_SUCCESS : OB_ERR_OUT_OF_UPPER_BOUND;
 | |
|     int search_err = q.search_boundary(target, prev, next, le_functor);
 | |
|     ASSERT_EQ(expect_err, search_err);
 | |
|     ASSERT_TRUE(prev.x == target.x - 5);
 | |
|     if (i < 9) {
 | |
|       ASSERT_TRUE(next.x == target.x + 5);
 | |
|     }
 | |
|     LIB_LOG(INFO, "search", K(target), K(prev), K(next), K(search_err));
 | |
|   }
 | |
| 
 | |
|   for (int i = 0; i < 10; i++) {
 | |
|     Item item;
 | |
|     ASSERT_EQ(OB_SUCCESS, q.top_back(item));
 | |
|     ASSERT_EQ(item.x, (9 - i) * 10);
 | |
|     LIB_LOG(INFO, "top_back", K(item));
 | |
|     ASSERT_EQ(OB_SUCCESS, q.pop_back(item));
 | |
|     ASSERT_EQ(item.x, (9 - i) * 10);
 | |
|     LIB_LOG(INFO, "pop_back", K(item));
 | |
|   }
 | |
| 
 | |
|   do {
 | |
|     Item item;
 | |
|     ASSERT_EQ(OB_ENTRY_NOT_EXIST, q.top_front(item));
 | |
|     ASSERT_EQ(OB_ENTRY_NOT_EXIST, q.pop_front(item));
 | |
|   } while (0);
 | |
| }
 | |
| 
 | |
| TEST(TestSegArray, test_fix_rq_wrapped)
 | |
| {
 | |
|   int ret = OB_SUCCESS;
 | |
|   ObFixedRingDeque<Item, 21> q;
 | |
|   for (int i = 0; i < 15; i++) {
 | |
|     Item item;
 | |
|     item.x = i * 2;
 | |
|     item.y = i * 2;
 | |
|     ASSERT_EQ(OB_SUCCESS, q.push_back(item));
 | |
|   }
 | |
|   q.debug_print();
 | |
| 
 | |
|   for (int i = 0; i < 10; i++) {
 | |
|     Item item;
 | |
|     item.x = -1;
 | |
|     item.y = -1;
 | |
|     ASSERT_EQ(OB_SUCCESS, q.pop_front(item));
 | |
|     LIB_LOG(INFO, "poped item", K(item));
 | |
|   }
 | |
|   q.debug_print();
 | |
| 
 | |
|   for (int i = 15; i < 20; i++) {
 | |
|     Item item;
 | |
|     item.x = i * 2;
 | |
|     item.y = i * 2;
 | |
|     ASSERT_EQ(OB_SUCCESS, q.push_back(item));
 | |
|   }
 | |
|   q.debug_print();
 | |
| 
 | |
|   for (int i = 20; i < 25; i++) {
 | |
|     Item item;
 | |
|     item.x = i * 2;
 | |
|     item.y = i * 2;
 | |
|     ASSERT_EQ(OB_SUCCESS, q.push_back(item));
 | |
|   }
 | |
|   q.debug_print();
 | |
| 
 | |
|   Item target;
 | |
|   target.x = 10;
 | |
|   target.y = 10;
 | |
|   Item prev;
 | |
|   Item next;
 | |
|   ItemLEFunctor le_functor;
 | |
|   ASSERT_EQ(OB_ERR_OUT_OF_LOWER_BOUND, q.search_boundary(target, prev, next, le_functor));
 | |
|   EXPECT_EQ(20, next.x);
 | |
|   EXPECT_EQ(20, next.y);
 | |
| 
 | |
|   for (int i = 20; i < 50; i++) {
 | |
|     Item target;
 | |
|     target.x = i;
 | |
|     target.y = i;
 | |
|     Item prev;
 | |
|     Item next;
 | |
|     int expect_err = i < 48 ? OB_SUCCESS : OB_ERR_OUT_OF_UPPER_BOUND;
 | |
|     ret = q.search_boundary(target, prev, next, le_functor);
 | |
|     ASSERT_EQ(expect_err, ret);
 | |
|     EXPECT_EQ((i / 2) * 2, prev.x);
 | |
|     if (i < 48) {
 | |
|       EXPECT_EQ((i / 2 + 1) * 2, next.x);
 | |
|     }
 | |
| 
 | |
|     LIB_LOG(INFO, "search", K(ret), K(i), K(target), K(prev), K(next));
 | |
|   }
 | |
| }
 | |
| 
 | |
| TEST(TestSegArray, test_seg_arr)
 | |
| {
 | |
|   int ret = OB_SUCCESS;
 | |
|   ObSegArray<Item, 10, 8> seg_array;
 | |
|   ASSERT_EQ(OB_SUCCESS, seg_array.init(&small_allocator));
 | |
| 
 | |
|   const int count = 65;
 | |
|   for (int i = 0; i < count; i++) {
 | |
|     Item item;
 | |
|     item.x = i * 10;
 | |
|     item.y = i * 10;
 | |
|     ASSERT_EQ(OB_SUCCESS, seg_array.push_back(item));
 | |
|     LIB_LOG(INFO, "push_back success", K(item));
 | |
|   }
 | |
|   LIB_LOG(INFO, "print seg_array");
 | |
|   seg_array.debug_print();
 | |
| 
 | |
|   for (int i = 5; i < 650; i = i + 10) {
 | |
|     Item target;
 | |
|     target.x = i;
 | |
|     target.y = i;
 | |
|     Item prev;
 | |
|     Item next;
 | |
|     int expect_err = i < 640 ? OB_SUCCESS : OB_ERR_OUT_OF_UPPER_BOUND;
 | |
|     ret = seg_array.search_boundary(target, prev, next);
 | |
|     LIB_LOG(INFO, "seg_array search_boundary: ", K(ret), K(target), K(prev), K(next));
 | |
|     EXPECT_EQ(expect_err, ret);
 | |
|     EXPECT_EQ((i / 10) * 10, prev.x);
 | |
|     if (i < 640) {
 | |
|       EXPECT_EQ((i / 10 + 1) * 10, next.x);
 | |
|     }
 | |
|     ASSERT_TRUE(prev.x + 5 == target.x);
 | |
|   }
 | |
| 
 | |
|   Item target;
 | |
|   target.x = -100;
 | |
|   target.y = -100;
 | |
|   Item prev;
 | |
|   Item next;
 | |
|   ret = seg_array.search_boundary(target, prev, next);
 | |
|   LIB_LOG(INFO, "search_boundary: ", K(ret), K(target), K(prev), K(next));
 | |
|   ASSERT_TRUE(OB_ERR_OUT_OF_LOWER_BOUND == ret);
 | |
|   EXPECT_EQ(0, next.x);
 | |
| 
 | |
|   LIB_LOG(INFO, "seg_array test pop_front and top_front");
 | |
|   for (int i = 0; i < count; i++) {
 | |
|     Item item;
 | |
|     ASSERT_EQ(OB_SUCCESS, seg_array.top_front(item));
 | |
|     ASSERT_EQ(item.x, i * 10);
 | |
|     LIB_LOG(INFO, "seg_array top_front", K(item), K(i));
 | |
|     ASSERT_EQ(OB_SUCCESS, seg_array.pop_front(item));
 | |
|     ASSERT_EQ(item.x, i * 10);
 | |
|     LIB_LOG(INFO, "seg_array pop_front", K(item), K(i));
 | |
|   }
 | |
| 
 | |
|   seg_array.debug_print();
 | |
| 
 | |
|   LIB_LOG(INFO, "test push_front");
 | |
|   for (int i = 0; i < count; i++) {
 | |
|     Item item;
 | |
|     item.x = (count - 1 - i) * 10;
 | |
|     item.y = (count - 1 - i) * 10;
 | |
|     ASSERT_EQ(OB_SUCCESS, seg_array.push_front(item));
 | |
|     LIB_LOG(INFO, "push_front", K(item));
 | |
|   }
 | |
| 
 | |
|   seg_array.debug_print();
 | |
| 
 | |
|   for (int i = 5; i < 650; i = i + 10) {
 | |
|     Item target;
 | |
|     target.x = i;
 | |
|     target.y = i;
 | |
|     Item prev;
 | |
|     Item next;
 | |
|     int expect_err = i < 640 ? OB_SUCCESS : OB_ERR_OUT_OF_UPPER_BOUND;
 | |
|     ret = seg_array.search_boundary(target, prev, next);
 | |
|     LIB_LOG(INFO, "seg_array search_boundary: ", K(ret), K(target), K(prev), K(next));
 | |
|     EXPECT_EQ(expect_err, ret);
 | |
|     EXPECT_EQ((i / 10) * 10, prev.x);
 | |
|     if (i < 640) {
 | |
|       EXPECT_EQ((i / 10 + 1) * 10, next.x);
 | |
|     }
 | |
|     ASSERT_TRUE(prev.x + 5 == target.x);
 | |
|   }
 | |
| 
 | |
|   seg_array.debug_print();
 | |
| 
 | |
|   for (int i = 0; i < count; i++) {
 | |
|     Item item;
 | |
|     ASSERT_EQ(OB_SUCCESS, seg_array.top_back(item));
 | |
|     LIB_LOG(INFO, "top_back", K(item), K(i));
 | |
|     ASSERT_EQ(item.x, (count - 1 - i) * 10);
 | |
|     ASSERT_EQ(OB_SUCCESS, seg_array.pop_back(item));
 | |
|     LIB_LOG(INFO, "pop_back", K(item), K(i));
 | |
|     ASSERT_EQ(item.x, (count - 1 - i) * 10);
 | |
|   }
 | |
| }
 | |
| 
 | |
| TEST(TestSegArray, test_seg_arr_pop)
 | |
| {
 | |
|   ObSegArray<Item, 5, 10> seg_array;
 | |
|   ASSERT_EQ(OB_SUCCESS, seg_array.init(&small_allocator));
 | |
|   for (int i = 0; i < 45; i++) {
 | |
|     Item item;
 | |
|     item.x = i * 2;
 | |
|     item.y = i * 2;
 | |
|     ASSERT_EQ(OB_SUCCESS, seg_array.push_back(item));
 | |
|   }
 | |
|   seg_array.debug_print();
 | |
| 
 | |
|   for (int i = 0; i < 45; i++) {
 | |
|     Item poped;
 | |
|     ASSERT_EQ(OB_SUCCESS, seg_array.pop_front(poped));
 | |
|   }
 | |
|   seg_array.debug_print();
 | |
| 
 | |
|   for (int i = 0; i < 45; i++) {
 | |
|     Item item;
 | |
|     item.x = i * 2;
 | |
|     item.y = i * 2;
 | |
|     ASSERT_EQ(OB_SUCCESS, seg_array.push_back(item));
 | |
|   }
 | |
|   seg_array.debug_print();
 | |
| 
 | |
|   for (int i = 0; i < 45; i++) {
 | |
|     Item poped;
 | |
|     ASSERT_EQ(OB_SUCCESS, seg_array.pop_front(poped));
 | |
|   }
 | |
|   seg_array.debug_print();
 | |
| }
 | |
| 
 | |
| TEST(TestSegArray, test_seg_arr_tail_size)
 | |
| {
 | |
|   ObSegArray<Item, 10, 8> seg_array;
 | |
|   ASSERT_EQ(OB_SUCCESS, seg_array.init(&small_allocator));
 | |
| 
 | |
|   int count = 5;
 | |
|   for (int i = 0; i < count; i++) {
 | |
|     Item item;
 | |
|     item.x = i * 2;
 | |
|     item.y = i * 2;
 | |
|     ASSERT_EQ(OB_SUCCESS, seg_array.push_back(item));
 | |
|   }
 | |
|   LIB_LOG(INFO, "print seg_array");
 | |
|   seg_array.debug_print();
 | |
| }
 | |
| 
 | |
| TEST(TestSegArray, test_seg_arr_destroy)
 | |
| {
 | |
|   ObSegArray<Item, 10, 8> seg_array;
 | |
|   ASSERT_EQ(OB_SUCCESS, seg_array.init(&small_allocator));
 | |
| 
 | |
|   int count = 5;
 | |
|   for (int i = 0; i < count; i++) {
 | |
|     Item item;
 | |
|     item.x = i * 2;
 | |
|     item.y = i * 2;
 | |
|     ASSERT_EQ(OB_SUCCESS, seg_array.push_back(item));
 | |
|   }
 | |
|   LIB_LOG(INFO, "print seg_array");
 | |
|   seg_array.debug_print();
 | |
|   seg_array.destroy();
 | |
| }
 | |
| 
 | |
| TEST(TestSegArray, test_reverse_for_each)
 | |
| {
 | |
|   ObSegArray<Item, 10, 8> seg_array;
 | |
|   ASSERT_EQ(OB_SUCCESS, seg_array.init(&small_allocator));
 | |
| 
 | |
|   int count = 50;
 | |
|   for (int i = 0; i < count; i++) {
 | |
|     Item item;
 | |
|     item.x = i;
 | |
|     item.y = i;
 | |
|     ASSERT_EQ(OB_SUCCESS, seg_array.push_back(item));
 | |
|   }
 | |
|   ReverseForEachFunctor fn;
 | |
|   fn.cnt_ = 0;
 | |
|   ASSERT_EQ(OB_SUCCESS, seg_array.reverse_for_each(fn));
 | |
|   ASSERT_EQ(50, fn.cnt_);
 | |
| 
 | |
|   count = 15;
 | |
|   fn.cnt_ = 0;
 | |
|   for (int i = 0; i < count; i++) {
 | |
|     Item item;
 | |
|     ASSERT_EQ(OB_SUCCESS, seg_array.pop_front(item));
 | |
|   }
 | |
|   ASSERT_EQ(OB_SUCCESS, seg_array.reverse_for_each(fn));
 | |
|   ASSERT_EQ(35, fn.cnt_);
 | |
| }
 | |
| 
 | |
| int main(int argc, char** argv)
 | |
| {
 | |
|   OB_LOGGER.set_log_level("INFO");
 | |
|   OB_LOGGER.set_file_name("test_seg_array.log", true, true);
 | |
|   init_env();
 | |
|   ::testing::InitGoogleTest(&argc, argv);
 | |
|   return RUN_ALL_TESTS();
 | |
| }
 | 
