274 lines
8.7 KiB
C++
274 lines
8.7 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.
|
|
*/
|
|
|
|
#define USING_LOG_PREFIX SHARE
|
|
#include <gtest/gtest.h>
|
|
#define private public
|
|
#include "lib/oblog/ob_log.h"
|
|
#include "lib/time/ob_time_utility.h"
|
|
#include "lib/random/ob_random.h"
|
|
#define private public
|
|
#include "share/schema/ob_schema_mgr.h"
|
|
#include "share/schema/ob_schema_mem_mgr.h"
|
|
|
|
namespace oceanbase
|
|
{
|
|
using namespace share::schema;
|
|
|
|
namespace common
|
|
{
|
|
|
|
class TestSchemaMemMgr: public ::testing::Test
|
|
{
|
|
};
|
|
|
|
TEST_F(TestSchemaMemMgr, basic_test)
|
|
{
|
|
int ret = OB_SUCCESS;
|
|
ObSchemaMgr *mgr = NULL;
|
|
int pos = -1;
|
|
|
|
void *ptr = NULL;
|
|
ObIAllocator *allocator = NULL;
|
|
ObSchemaMemMgr mem_mgr;
|
|
// not init when alloc
|
|
ret = mem_mgr.alloc(sizeof(ObSchemaMgr), ptr, &allocator);
|
|
ASSERT_EQ(OB_INNER_STAT_ERROR, ret);
|
|
ret = mem_mgr.init(ObModIds::OB_SCHEMA_MGR);
|
|
ASSERT_EQ(OB_SUCCESS, ret);
|
|
// invalid arg when alloc
|
|
ret = mem_mgr.alloc(-1, ptr, &allocator);
|
|
ASSERT_EQ(OB_INVALID_ARGUMENT, ret);
|
|
ret = mem_mgr.alloc(0, ptr, &allocator);
|
|
ASSERT_EQ(OB_INVALID_ARGUMENT, ret);
|
|
|
|
ret = mem_mgr.alloc(sizeof(ObSchemaMgr), ptr, &allocator);
|
|
ASSERT_EQ(OB_SUCCESS, ret);
|
|
ASSERT_TRUE(NULL != ptr && NULL != allocator);
|
|
pos = mem_mgr.pos_;
|
|
ASSERT_EQ(1, mem_mgr.ptrs_[pos].count());
|
|
ASSERT_EQ(0, mem_mgr.ptrs_[1 - pos].count());
|
|
ASSERT_EQ(ptr, mem_mgr.ptrs_[pos].at(0));
|
|
ASSERT_EQ(allocator, &mem_mgr.allocer_[pos]);
|
|
mgr = new (ptr) ObSchemaMgr(*allocator);
|
|
mgr->dump();
|
|
|
|
// not init when free
|
|
mem_mgr.is_inited_ = false;
|
|
ret = mem_mgr.free(static_cast<void *>(mgr));
|
|
ASSERT_EQ(OB_INNER_STAT_ERROR, ret);
|
|
mem_mgr.is_inited_ = true;
|
|
// invalid arg when free
|
|
ret = mem_mgr.free(NULL);
|
|
ASSERT_EQ(OB_INVALID_ARGUMENT, ret);
|
|
|
|
ret = mem_mgr.free(static_cast<void *>(mgr));
|
|
ASSERT_EQ(OB_SUCCESS, ret);
|
|
ASSERT_EQ(0, mem_mgr.ptrs_[pos].count());
|
|
int64_t alloc_cnt = 0;
|
|
ret = mem_mgr.get_cur_alloc_cnt(alloc_cnt);
|
|
ASSERT_EQ(OB_SUCCESS, ret);
|
|
ASSERT_EQ(1, alloc_cnt);
|
|
ret = mem_mgr.free(static_cast<void *>(mgr));
|
|
ASSERT_EQ(OB_SUCCESS, ret);
|
|
ASSERT_EQ(0, mem_mgr.ptrs_[pos].count());
|
|
ret = mem_mgr.get_cur_alloc_cnt(alloc_cnt);
|
|
ASSERT_EQ(OB_SUCCESS, ret);
|
|
ASSERT_EQ(1, alloc_cnt);
|
|
ASSERT_TRUE(0 != mem_mgr.allocer_[pos].used());
|
|
bool can_switch = false;
|
|
ret = mem_mgr.check_can_switch_allocer(can_switch);
|
|
ASSERT_TRUE(can_switch);
|
|
ret = mem_mgr.switch_allocer();
|
|
ASSERT_EQ(OB_SUCCESS, ret);
|
|
ASSERT_TRUE(0 != mem_mgr.allocer_[pos].used());
|
|
ret = mem_mgr.check_can_switch_allocer(can_switch);
|
|
ASSERT_TRUE(can_switch);
|
|
ret = mem_mgr.switch_allocer();
|
|
ASSERT_EQ(OB_SUCCESS, ret);
|
|
ASSERT_TRUE(0 == mem_mgr.allocer_[pos].used());
|
|
mem_mgr.dump();
|
|
}
|
|
|
|
TEST_F(TestSchemaMemMgr, NULL_ptr)
|
|
{
|
|
int ret = OB_SUCCESS;
|
|
|
|
ObSchemaMemMgr mem_mgr;
|
|
ret = mem_mgr.init(ObModIds::OB_SCHEMA_MGR);
|
|
ASSERT_EQ(OB_SUCCESS, ret);
|
|
|
|
// free when ptrs array contains NULL ptr.
|
|
mem_mgr.ptrs_[0].push_back(NULL);
|
|
ret = mem_mgr.free(static_cast<void *>(this));
|
|
ASSERT_EQ(OB_ERR_UNEXPECTED, ret);
|
|
mem_mgr.ptrs_[0].reset();
|
|
|
|
// free when two ptrs array have the same ptr.
|
|
mem_mgr.ptrs_[0].push_back(static_cast<void *>(this));
|
|
mem_mgr.ptrs_[1].push_back(static_cast<void *>(this));
|
|
ret = mem_mgr.free(static_cast<void *>(this));
|
|
ASSERT_EQ(OB_ERR_UNEXPECTED, ret);
|
|
}
|
|
|
|
TEST_F(TestSchemaMemMgr, check_can_switch_allocer)
|
|
{
|
|
int ret = OB_SUCCESS;
|
|
|
|
ObSchemaMemMgr mem_mgr;
|
|
bool can_switch = false;
|
|
// not init
|
|
ret = mem_mgr.check_can_switch_allocer(can_switch);
|
|
ASSERT_EQ(OB_INNER_STAT_ERROR, ret);
|
|
ret = mem_mgr.init(ObModIds::OB_SCHEMA_MGR);
|
|
ASSERT_EQ(OB_SUCCESS, ret);
|
|
// can switch
|
|
ret = mem_mgr.check_can_switch_allocer(can_switch);
|
|
ASSERT_EQ(OB_SUCCESS, ret);
|
|
ASSERT_TRUE(can_switch);
|
|
// cannot switch
|
|
mem_mgr.ptrs_[1].push_back(static_cast<void *>(this));
|
|
ret = mem_mgr.check_can_switch_allocer(can_switch);
|
|
ASSERT_EQ(OB_SUCCESS, ret);
|
|
ASSERT_FALSE(can_switch);
|
|
|
|
}
|
|
|
|
TEST_F(TestSchemaMemMgr, switch_allocer)
|
|
{
|
|
int ret = OB_SUCCESS;
|
|
|
|
ObSchemaMemMgr mem_mgr;
|
|
ret = mem_mgr.switch_allocer();
|
|
ASSERT_EQ(OB_INNER_STAT_ERROR, ret);
|
|
// not init
|
|
ret = mem_mgr.init(ObModIds::OB_SCHEMA_MGR);
|
|
ASSERT_EQ(OB_SUCCESS, ret);
|
|
|
|
mem_mgr.ptrs_[1].push_back(static_cast<void *>(this));
|
|
mem_mgr.all_ptrs_[1].push_back(static_cast<void *>(this));
|
|
ret = mem_mgr.switch_allocer();
|
|
ASSERT_EQ(OB_ERR_UNEXPECTED, ret);
|
|
mem_mgr.ptrs_[1].reset();
|
|
ret = mem_mgr.switch_allocer();
|
|
ASSERT_EQ(OB_SUCCESS, ret);
|
|
ASSERT_EQ(0, mem_mgr.all_ptrs_[1].count());
|
|
|
|
// free when two ptrs array have the same ptr.
|
|
mem_mgr.ptrs_[0].push_back(static_cast<void *>(this));
|
|
mem_mgr.ptrs_[1].push_back(static_cast<void *>(this));
|
|
ret = mem_mgr.free(static_cast<void *>(this));
|
|
ASSERT_EQ(OB_ERR_UNEXPECTED, ret);
|
|
}
|
|
|
|
// It's not matched with the real elimination strategy of increment schema refresh.
|
|
// Eliminate a random ObSchemaMgr at a time.
|
|
TEST_F(TestSchemaMemMgr, simulate_increment_refresh_schema)
|
|
{
|
|
int ret = OB_SUCCESS;
|
|
|
|
static const int min_switch_alloc_cnt = 32;
|
|
static const int cache_size = 8;
|
|
ObSchemaMgr *schema_mgr_for_cache = NULL;
|
|
ObSchemaMgr *mgr_cache[cache_size];
|
|
memset(mgr_cache, 0, sizeof(ObSchemaMgr*) * cache_size);
|
|
ObSchemaMemMgr mem_mgr;
|
|
ret = mem_mgr.init(ObModIds::OB_SCHEMA_MGR);
|
|
ASSERT_EQ(OB_SUCCESS, ret);
|
|
const int alloc_size = sizeof(ObSchemaMgr);
|
|
ObSchemaMgr *mgr = NULL;
|
|
// init schema_mgr_for_cache
|
|
void *tmp_ptr = NULL;
|
|
ObIAllocator *allocator = NULL;
|
|
ret = mem_mgr.alloc(alloc_size, tmp_ptr, &allocator);
|
|
ASSERT_EQ(OB_SUCCESS, ret);
|
|
schema_mgr_for_cache = new (tmp_ptr) ObSchemaMgr(*allocator);
|
|
|
|
static const int refresh_times = 1024;
|
|
int64_t switch_cnt = 0;
|
|
for (int64_t i = 0; i < refresh_times; ++i) {
|
|
schema_mgr_for_cache->set_schema_version(1);
|
|
// eliminate randomly
|
|
int64_t eli_pos = ObRandom::rand(0, cache_size - 1);
|
|
void *eli_ptr = static_cast<void *>(mgr_cache[eli_pos]);
|
|
ret = mem_mgr.alloc(alloc_size, tmp_ptr);
|
|
ASSERT_EQ(OB_SUCCESS, ret);
|
|
mgr = new (tmp_ptr) ObSchemaMgr;
|
|
mgr->assign(*schema_mgr_for_cache);
|
|
mgr_cache[eli_pos] = mgr;
|
|
if (NULL != eli_ptr) {
|
|
bool can_switch = false;
|
|
int64_t alloc_cnt = 0;
|
|
ret = mem_mgr.free(eli_ptr);
|
|
ASSERT_EQ(OB_SUCCESS, ret);
|
|
ret = mem_mgr.check_can_switch_allocer(can_switch);
|
|
ASSERT_EQ(OB_SUCCESS, ret);
|
|
ret = mem_mgr.get_cur_alloc_cnt(alloc_cnt);
|
|
ASSERT_EQ(OB_SUCCESS, ret);
|
|
LOG_INFO("debug", K(tmp_ptr), K(eli_pos), K(eli_ptr), K(alloc_cnt),
|
|
K(mem_mgr.ptrs_[0].count()), K(mem_mgr.ptrs_[1].count()));
|
|
if (can_switch && alloc_cnt > min_switch_alloc_cnt) {
|
|
LOG_INFO("switch allocator");
|
|
++switch_cnt;
|
|
// overwrite schema_mgr_for_cache
|
|
void *tmp_ptr = NULL;
|
|
ObIAllocator *allocator = NULL;
|
|
ObSchemaMgr *old_mgr = schema_mgr_for_cache;
|
|
ObSchemaMgr *new_mgr = NULL;
|
|
ret = mem_mgr.switch_allocer();
|
|
ASSERT_EQ(OB_SUCCESS, ret);
|
|
ret = mem_mgr.alloc(alloc_size, tmp_ptr, &allocator);
|
|
ASSERT_EQ(OB_SUCCESS, ret);
|
|
new_mgr = new (tmp_ptr) ObSchemaMgr(*allocator);
|
|
new_mgr->deep_copy(*old_mgr);
|
|
ret = mem_mgr.free(static_cast<void *> (old_mgr));
|
|
ASSERT_EQ(OB_SUCCESS, ret);
|
|
schema_mgr_for_cache = new_mgr;
|
|
// expect no core
|
|
schema_mgr_for_cache->dump();
|
|
}
|
|
}
|
|
}
|
|
// check
|
|
for (int64_t i = 0; i < cache_size; ++i) {
|
|
ObSchemaMgr *mgr = mgr_cache[i];
|
|
bool exist = false;
|
|
for (int64_t j = 0; j < mem_mgr.ptrs_[0].count() && !exist; ++j) {
|
|
exist = mgr == mem_mgr.ptrs_[0].at(j);
|
|
}
|
|
for (int64_t j = 0; j < mem_mgr.ptrs_[1].count() && !exist; ++j) {
|
|
exist = mgr == mem_mgr.ptrs_[1].at(j);
|
|
}
|
|
ASSERT_TRUE(exist);
|
|
}
|
|
bool exist = false;
|
|
for (int64_t j = 0; j < mem_mgr.ptrs_[0].count() && !exist; ++j) {
|
|
exist = schema_mgr_for_cache == mem_mgr.ptrs_[0].at(j);
|
|
}
|
|
for (int64_t j = 0; j < mem_mgr.ptrs_[1].count() && !exist; ++j) {
|
|
exist = schema_mgr_for_cache == mem_mgr.ptrs_[1].at(j);
|
|
}
|
|
ASSERT_TRUE(exist);
|
|
ASSERT_TRUE(switch_cnt > 10);
|
|
}
|
|
|
|
} // common
|
|
} // oceanbase
|
|
|
|
int main(int argc, char** argv)
|
|
{
|
|
oceanbase::common::ObLogger::get_logger().set_log_level("INFO");
|
|
OB_LOGGER.set_file_name("test_schema_mem_mgr.log", true);
|
|
testing::InitGoogleTest(&argc, argv);
|
|
return RUN_ALL_TESTS();
|
|
}
|