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();
 | 
						|
}
 |