Files
oceanbase/unittest/storage/column_store/test_co_sstable.cpp

474 lines
15 KiB
C++

/**
* Copyright (c) 2022 OceanBase
* OceanBase 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 STORAGE
#include <gmock/gmock.h>
#define private public
#define protected public
#include "storage/schema_utils.h"
#include "mtlenv/mock_tenant_module_env.h"
namespace oceanbase
{
using namespace common;
using namespace storage;
using namespace blocksstable;
using namespace share;
using namespace share::schema;
namespace common
{
int ObIOTuner::init()
{
int ret = OB_SUCCESS;
is_inited_ = true;
return ret;
}
void ObIOTuner::run1()
{
// do nothing
}
}
namespace unittest
{
class TestCOSSTable: public ::testing::Test
{
public:
static void generate_table_key(
const ObITable::TableType &type,
const int64_t base_version,
const int64_t snapshot_version,
ObITable::TableKey &table_key);
static int mock_major_sstable(
const ObITable::TableType &type,
ObArenaAllocator &allocator,
const int64_t base_version,
const int64_t snapshot_version,
const int64_t column_group_cnt,
ObTableHandleV2 &table_handle);
static int mock_column_store_schema(
common::ObIAllocator &allocator,
const bool with_all_cg,
ObStorageSchema &storage_schema);
public:
TestCOSSTable();
~TestCOSSTable() = default;
public:
virtual void SetUp() override;
virtual void TearDown() override;
static void SetUpTestCase();
static void TearDownTestCase();
public:
static constexpr int64_t TEST_TENANT_ID = 1;
static constexpr int64_t TEST_TABLET_ID = 2323233;
ObTabletID tablet_id_;
ObArenaAllocator allocator_;
};
TestCOSSTable::TestCOSSTable()
: tablet_id_(TEST_TABLET_ID),
allocator_()
{
}
void TestCOSSTable::SetUp()
{
int ret = OB_SUCCESS;
ObTenantMetaMemMgr *t3m = MTL(ObTenantMetaMemMgr*);
t3m->stop();
t3m->wait();
t3m->destroy();
ret = t3m->init();
ASSERT_EQ(OB_SUCCESS, ret);
}
void TestCOSSTable::TearDown()
{
ObTenantMetaMemMgr *t3m = MTL(ObTenantMetaMemMgr*);
t3m->stop();
t3m->wait();
t3m->destroy();
}
void TestCOSSTable::SetUpTestCase()
{
int ret = OB_SUCCESS;
ret = MockTenantModuleEnv::get_instance().init();
ASSERT_EQ(OB_SUCCESS, ret);
}
void TestCOSSTable::TearDownTestCase()
{
MockTenantModuleEnv::get_instance().destroy();
}
void TestCOSSTable::generate_table_key(
const ObITable::TableType &type,
const int64_t base_version,
const int64_t snapshot_version,
ObITable::TableKey &table_key)
{
table_key.reset();
table_key.tablet_id_ = TEST_TABLET_ID;
table_key.table_type_ = type;
table_key.version_range_.base_version_ = base_version;
table_key.version_range_.snapshot_version_ = snapshot_version;
}
int TestCOSSTable::mock_major_sstable(
const ObITable::TableType &type,
ObArenaAllocator &allocator,
const int64_t base_version,
const int64_t snapshot_version,
const int64_t column_group_cnt,
ObTableHandleV2 &table_handle)
{
int ret = OB_SUCCESS;
ObTableSchema table_schema;
TestSchemaUtils::prepare_data_schema(table_schema);
ObITable::TableKey table_key;
generate_table_key(type, base_version, snapshot_version, table_key);
ObTabletID tablet_id;
tablet_id = TEST_TABLET_ID;
ObTabletCreateSSTableParam param;
ObSSTable *sstable = nullptr;
ObStorageSchema storage_schema;
if (OB_FAIL(storage_schema.init(allocator, table_schema, lib::Worker::CompatMode::MYSQL))) {
LOG_WARN("failed to init storage schema", K(ret));
} else if (OB_FAIL(param.init_for_empty_major_sstable(tablet_id, storage_schema, snapshot_version, -1, false))) {
LOG_WARN("failed to build create sstable param", K(ret), K(table_key));
} else if (FALSE_IT(param.table_key_ = table_key)) {
} else if (FALSE_IT(param.column_group_cnt_ = column_group_cnt)) {
} else if (ObITable::TableType::COLUMN_ORIENTED_SSTABLE == type) {
param.co_base_type_ = ObCOSSTableBaseType::ALL_CG_TYPE;
if (OB_FAIL(ObTabletCreateDeleteHelper::create_sstable<ObCOSSTableV2>(param, allocator, table_handle))) {
LOG_WARN("failed to create sstable", K(param));
}
} else if (OB_FAIL(ObTabletCreateDeleteHelper::create_sstable(param, allocator, table_handle))) {
LOG_WARN("failed to create sstable", K(param));
}
if (FAILEDx(table_handle.get_sstable(sstable))) {
LOG_WARN("failed to get sstable", K(ret), K(table_handle));
}
return ret;
}
int TestCOSSTable::mock_column_store_schema(
common::ObIAllocator &allocator,
const bool with_all_cg,
ObStorageSchema &storage_schema)
{
int ret = OB_SUCCESS;
ObTableSchema table_schema;
TestSchemaUtils::prepare_data_schema(table_schema);
ObArray<ObColDesc> col_ids;
ObArray<ObColDesc> rowkey_col_ids;
int64_t store_column_count;
if (OB_FAIL(table_schema.get_store_column_ids(col_ids))) {
LOG_WARN("failed to get store column ids", K(ret));
} else if (OB_FAIL(table_schema.get_rowkey_column_ids(rowkey_col_ids))) {
LOG_WARN("failed to get rowkey column ids", K(ret));
} else if (OB_FAIL(table_schema.get_store_column_count(store_column_count))) {
LOG_WARN("failed to get store column count", K(ret));
} else if (store_column_count != col_ids.count()) {
ret = OB_ERR_UNEXPECTED;
LOG_WARN("get unexpected col cnt", K(store_column_count), K(col_ids.count()), K(col_ids));
} else {
// build base cg schema
ObColumnGroupSchema base_cg;
base_cg.column_group_type_ = with_all_cg
? ObColumnGroupType::ALL_COLUMN_GROUP
: ObColumnGroupType::ROWKEY_COLUMN_GROUP;
base_cg.column_group_id_ = store_column_count;
base_cg.column_id_cnt_ = with_all_cg
? store_column_count
: table_schema.get_rowkey_column_num();
uint64_t *base_cg_ids = static_cast<uint64_t *>(allocator.alloc(base_cg.column_id_cnt_ * sizeof(uint64_t)));
const ObArray<ObColDesc> &base_column_ids = with_all_cg
? col_ids
: rowkey_col_ids;
for(int64_t i = 0; i < base_cg.column_id_cnt_; ++i) {
base_cg_ids[i] = base_column_ids.at(i).col_id_;
}
base_cg.column_id_arr_ = base_cg_ids;
base_cg.column_group_name_ = "test_all";
base_cg.row_store_type_ = FLAT_ROW_STORE;
table_schema.add_column_group(base_cg);
//add normal cg
for(int64_t i = 0; i < store_column_count; i++) {
ObColumnGroupSchema normal_cg;
normal_cg.column_group_type_ = ObColumnGroupType::SINGLE_COLUMN_GROUP;
normal_cg.column_group_id_ = i;
char c = i + '0';
normal_cg.column_group_name_ = &c;
normal_cg.column_id_cnt_ = 1;
normal_cg.column_id_arr_capacity_ = 1;
uint64_t column_ids[1] = { col_ids.at(i).col_id_ };
normal_cg.column_id_arr_ = column_ids;
normal_cg.row_store_type_ = FLAT_ROW_STORE;
table_schema.add_column_group(normal_cg);
}
}
if (OB_FAIL(storage_schema.init(allocator, table_schema, lib::Worker::CompatMode::MYSQL))) {
LOG_WARN("failed to init storage schema", K(ret));
}
return ret;
}
TEST_F(TestCOSSTable, co_table_basic_test)
{
int ret = OB_SUCCESS;
ObTenantMetaMemMgr *t3m = MTL(ObTenantMetaMemMgr *);
ASSERT_NE(nullptr, t3m);
// create co sstable
const int64_t base_version = 0;
const int64_t snapshot_version = 100;
ObTableHandleV2 co_handle;
ret = TestCOSSTable::mock_major_sstable(ObITable::COLUMN_ORIENTED_SSTABLE, allocator_, base_version, snapshot_version, 2, co_handle);
ASSERT_EQ(OB_SUCCESS, ret);
ObITable *co_table = co_handle.get_table();
ASSERT_EQ(true, co_table->is_co_sstable());
// create cg sstable
ObTableHandleV2 cg_handle;
ret = TestCOSSTable::mock_major_sstable(ObITable::NORMAL_COLUMN_GROUP_SSTABLE, allocator_, base_version, snapshot_version, 1, cg_handle);
ASSERT_EQ(OB_SUCCESS, ret);
ObITable *cg_table = cg_handle.get_table();
ASSERT_EQ(true, cg_table->is_cg_sstable());
// add cg table to co sstable
ObCOSSTableV2 *co_sstable = static_cast<ObCOSSTableV2 *>(co_table);
ObSEArray<ObITable *, 1> cg_sstables;
ret = cg_sstables.push_back(cg_table);
ASSERT_EQ(OB_SUCCESS, ret);
ret = co_sstable->fill_cg_sstables(cg_sstables);
ASSERT_EQ(OB_SUCCESS, ret);
EXPECT_EQ(true, co_sstable->valid_for_cs_reading_);
// serialize co sstable
const int64_t buf_len = co_sstable->get_serialize_size();
char * encode_buf = static_cast<char *>(allocator_.alloc(sizeof(char) * buf_len));
int64_t pos = 0;
ret = co_sstable->serialize(encode_buf, buf_len, pos);
EXPECT_EQ(OB_SUCCESS, ret);
// deserialize co sstable
void* decode_buf = allocator_.alloc(sizeof(ObCOSSTableV2));
ObCOSSTableV2 *decode_table = new (decode_buf) ObCOSSTableV2();
pos = 0;
ret = decode_table->deserialize(allocator_, encode_buf, buf_len, pos);
ASSERT_EQ(OB_SUCCESS, ret);
ASSERT_EQ(buf_len, pos);
}
TEST_F(TestCOSSTable, get_cg_table_test)
{
int ret = OB_SUCCESS;
ObTenantMetaMemMgr *t3m = MTL(ObTenantMetaMemMgr *);
ASSERT_NE(nullptr, t3m);
// create co sstable
const int64_t base_version = 0;
const int64_t snapshot_version = 100;
ObTableHandleV2 co_handle;
ret = TestCOSSTable::mock_major_sstable(ObITable::COLUMN_ORIENTED_SSTABLE, allocator_, base_version, snapshot_version, 3, co_handle);
ASSERT_EQ(OB_SUCCESS, ret);
ObITable *co_table = co_handle.get_table();
ASSERT_EQ(true, co_table->is_co_sstable());
co_table->key_.column_group_idx_ = 1;
static_cast<ObCOSSTableV2 *>(co_table)->base_type_ = ObCOSSTableBaseType::ALL_CG_TYPE;
// create cg sstables
ObTableHandleV2 cg_handle1;
ret = TestCOSSTable::mock_major_sstable(ObITable::NORMAL_COLUMN_GROUP_SSTABLE, allocator_, base_version, snapshot_version, 1, cg_handle1);
ASSERT_EQ(OB_SUCCESS, ret);
ObITable *cg_table1 = cg_handle1.get_table();
ASSERT_EQ(true, cg_table1->is_cg_sstable());
cg_table1->key_.column_group_idx_ = 0;
ObTableHandleV2 cg_handle2;
ret = TestCOSSTable::mock_major_sstable(ObITable::NORMAL_COLUMN_GROUP_SSTABLE, allocator_, base_version, snapshot_version, 1, cg_handle2);
ASSERT_EQ(OB_SUCCESS, ret);
ObITable *cg_table2 = cg_handle2.get_table();
ASSERT_EQ(true, cg_table2->is_cg_sstable());
cg_table2->key_.column_group_idx_ = 2;
// add cg table to co sstable
ObCOSSTableV2 *co_sstable = static_cast<ObCOSSTableV2 *>(co_table);
ObSEArray<ObITable *, 2> cg_sstables;
ret = cg_sstables.push_back(cg_table1);
ret = cg_sstables.push_back(cg_table2);
ASSERT_EQ(OB_SUCCESS, ret);
ret = co_sstable->fill_cg_sstables(cg_sstables);
ASSERT_EQ(OB_SUCCESS, ret);
EXPECT_EQ(true, co_sstable->valid_for_cs_reading_);
ObSSTableWrapper get_cg_table1;
ret = co_sstable->get_cg_sstable(1, get_cg_table1);
EXPECT_EQ(co_sstable->key_.column_group_idx_, get_cg_table1.sstable_->key_.column_group_idx_);
ObSSTableWrapper get_cg_table2;
ret = co_sstable->get_cg_sstable(0, get_cg_table2);
EXPECT_EQ(cg_table1->key_.column_group_idx_, get_cg_table2.sstable_->key_.column_group_idx_);
ObSSTableWrapper get_cg_table3;
ret = co_sstable->get_cg_sstable(2, get_cg_table3);
EXPECT_EQ(cg_table2->key_.column_group_idx_, get_cg_table3.sstable_->key_.column_group_idx_);
ObSSTableWrapper get_cg_table4;
ret = co_sstable->get_cg_sstable(3, get_cg_table4);
EXPECT_EQ(OB_INVALID_ARGUMENT, ret);
}
TEST_F(TestCOSSTable, without_all_cg_test)
{
int ret = OB_SUCCESS;
ObTenantMetaMemMgr *t3m = MTL(ObTenantMetaMemMgr *);
ASSERT_NE(nullptr, t3m);
ObArenaAllocator allocator;
ObStorageSchema storage_schema;
ret = mock_column_store_schema(allocator, false/*with all cg*/, storage_schema);
EXPECT_EQ(OB_SUCCESS, ret);
ObTableHandleV2 co_table_handle;
int64_t snapshot_version = 100;
ObTabletID tablet_id;
tablet_id.id_ = TEST_TABLET_ID;
ret = ObTabletCreateDeleteHelper::create_empty_sstable(
allocator,
storage_schema,
tablet_id,
snapshot_version,
co_table_handle);
EXPECT_EQ(OB_SUCCESS, ret);
ObCOSSTableV2 *co_table = static_cast<ObCOSSTableV2 *>(co_table_handle.get_table());
ASSERT_TRUE(co_table->is_rowkey_cg_base());
}
TEST_F(TestCOSSTable, empty_co_table_test)
{
int ret = OB_SUCCESS;
ObTenantMetaMemMgr *t3m = MTL(ObTenantMetaMemMgr *);
ASSERT_NE(nullptr, t3m);
ObArenaAllocator allocator;
ObStorageSchema storage_schema;
ret = mock_column_store_schema(allocator, true/*with all cg*/, storage_schema);
EXPECT_EQ(OB_SUCCESS, ret);
ObTableHandleV2 co_table_handle;
int64_t snapshot_version = 100;
ObTabletID tablet_id;
tablet_id.id_ = TEST_TABLET_ID;
ret = ObTabletCreateDeleteHelper::create_empty_sstable(
allocator,
storage_schema,
tablet_id,
snapshot_version,
co_table_handle);
EXPECT_EQ(OB_SUCCESS, ret);
ObCOSSTableV2 *co_table = static_cast<ObCOSSTableV2 *>(co_table_handle.get_table());
EXPECT_EQ(0, co_table->meta_->cg_sstables_.count());
EXPECT_EQ(true, co_table->is_empty());
EXPECT_EQ(storage_schema.get_column_group_count(), co_table->get_cs_meta().column_group_cnt_);
}
TEST_F(TestCOSSTable, copy_from_old_sstable_test)
{
int ret = OB_SUCCESS;
ObTenantMetaMemMgr *t3m = MTL(ObTenantMetaMemMgr *);
ASSERT_NE(nullptr, t3m);
// create co sstable
const int64_t base_version = 0;
const int64_t snapshot_version = 100;
ObTableHandleV2 co_handle;
ret = TestCOSSTable::mock_major_sstable(ObITable::COLUMN_ORIENTED_SSTABLE, allocator_, base_version, snapshot_version, 2, co_handle);
ASSERT_EQ(OB_SUCCESS, ret);
ObITable *co_table = co_handle.get_table();
ASSERT_EQ(true, co_table->is_co_sstable());
// create cg sstable
ObTableHandleV2 cg_handle;
ret = TestCOSSTable::mock_major_sstable(ObITable::NORMAL_COLUMN_GROUP_SSTABLE, allocator_, base_version, snapshot_version, 1, cg_handle);
ASSERT_EQ(OB_SUCCESS, ret);
ObITable *cg_table = cg_handle.get_table();
ASSERT_EQ(true, cg_table->is_cg_sstable());
// add cg table to co sstable
ObCOSSTableV2 *co_sstable = static_cast<ObCOSSTableV2 *>(co_table);
ObSEArray<ObITable *, 1> cg_sstables;
ret = cg_sstables.push_back(cg_table);
ASSERT_EQ(OB_SUCCESS, ret);
ret = co_sstable->fill_cg_sstables(cg_sstables);
ASSERT_EQ(OB_SUCCESS, ret);
EXPECT_EQ(true, co_sstable->valid_for_cs_reading_);
// copy old sstable and test
ObSSTable *copied_sstable = nullptr;
ObSSTable::copy_from_old_sstable(*co_sstable, allocator_, copied_sstable);
ASSERT_TRUE(copied_sstable->is_tmp_sstable_);
ASSERT_EQ(1, copied_sstable->meta_->cg_sstables_.count());
ASSERT_TRUE(static_cast<ObSSTable *>(copied_sstable->meta_->cg_sstables_.at(0))->is_tmp_sstable_);
}
} //namespace unittest
} //namespace oceanbase
int main(int argc, char **argv)
{
system("rm -rf test_co_sstable.log");
OB_LOGGER.set_file_name("test_co_sstable.log", true);
OB_LOGGER.set_log_level("INFO");
CLOG_LOG(INFO, "begin unittest: test_co_sstable");
::testing::InitGoogleTest(&argc, argv);
return RUN_ALL_TESTS();
}