Files
oceanbase/mittest/mtlenv/storage/test_auto_partition_scan_table.cpp
2024-09-25 17:46:59 +00:00

383 lines
14 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 <gmock/gmock.h>
#define private public
#define protected public
#include "share/schema/ob_table_param.h"
#include "share/schema/ob_table_dml_param.h"
#include "mtlenv/storage/blocksstable/ob_index_block_data_prepare.h"
/*
0. 用主表模拟局部索引表扫描,两者差别在于主表会进行范围切割,局部索引表会进行 行过滤
1. 创建分区
2. 设置分区为split状态,把自己设置为局部索引,并且把origin tablet id设置为自己
3. 启动table_scan
4. 预期逻辑
1)同时获取origin table的tables ;
2)不会cut range;
3)根据当前tablet id 过滤数据,当然当前代码里分裂后的schema没有变更,计算分区方式也没有改变,因此数据全部符合
*/
namespace oceanbase
{
using namespace common;
using namespace storage;
using namespace share;
namespace unittest
{
class FakeObScanTable : public ::testing::Test
{
public:
FakeObScanTable() :
tenant_id_(OB_SYS_TENANT_ID),
ls_id_(TestDmlCommon::TEST_LS_ID),
tablet_id_(TestDmlCommon::TEST_DATA_TABLE_ID),
orig_tablet_id_(51)
{}
~FakeObScanTable(){}
static void SetUpTestCase();
static void TearDownTestCase();
void table_scan(ObAccessService *access_service, ObNewRowIterator *&result);
void insert_data_to_tablet(MockObAccessService *access_service, ObTabletID &tablet_id, const char *data);
int set_tablet_split_info(ObTabletID &src_tablet_id, ObTabletSplitType split_type, const int64_t split_cnt);
int gen_datum_rowkey(const int64_t key_val, const int64_t key_cnt, ObDatumRowkey &datum_rowkey);
ObDatumRowkey &get_start_key() { return start_key_; }
ObDatumRowkey &get_end_key() { return end_key_; }
protected:
uint64_t tenant_id_;
share::ObLSID ls_id_;
common::ObTabletID tablet_id_;
common::ObTabletID orig_tablet_id_;
private:
ObArenaAllocator allocator_;
ObRowkey start_key_;
ObRowkey end_key_;
public:
static constexpr const char *data_row_str_01 =
"bigint bigint bigint var var dml \n"
"1 62 20 Houston Rockets T_DML_INSERT \n"
"2 65 17 SanAntonio Spurs T_DML_INSERT \n"
"3 58 24 Dallas Mavericks T_DML_INSERT \n"
"4 51 31 LosAngeles Lakers T_DML_INSERT \n"
"5 57 25 Phoenix Suns T_DML_INSERT \n"
"6 32 50 NewJersey Nets T_DML_INSERT \n"
"7 44 38 Miami Heats T_DML_INSERT \n"
"8 21 61 Chicago Bulls T_DML_INSERT \n"
"9 47 35 Cleveland Cavaliers T_DML_INSERT \n"
"10 59 23 Detroit Pistons T_DML_INSERT \n"
"11 40 42 Utah Jazz T_DML_INSERT \n"
"12 50 32 Boston Celtics T_DML_INSERT \n";
static constexpr const char *data_row_str_02 =
"bigint bigint bigint var var dml \n"
"13 62 20 Houston Rockets T_DML_INSERT \n"
"14 65 17 SanAntonio Spurs T_DML_INSERT \n"
"15 58 24 Dallas Mavericks T_DML_INSERT \n"
"16 51 31 LosAngeles Lakers T_DML_INSERT \n"
"17 57 25 Phoenix Suns T_DML_INSERT \n"
"18 32 50 NewJersey Nets T_DML_INSERT \n"
"19 44 38 Miami Heats T_DML_INSERT \n"
"20 21 61 Chicago Bulls T_DML_INSERT \n"
"21 47 35 Cleveland Cavaliers T_DML_INSERT \n"
"22 59 23 Detroit Pistons T_DML_INSERT \n"
"23 40 42 Utah Jazz T_DML_INSERT \n"
"24 50 32 Boston Celtics T_DML_INSERT \n";
};
void FakeObScanTable::SetUpTestCase()
{
ASSERT_EQ(OB_SUCCESS, MockTenantModuleEnv::get_instance().init());
MTL(transaction::ObTransService*)->tx_desc_mgr_.tx_id_allocator_ =
[](transaction::ObTransID &tx_id) { tx_id = transaction::ObTransID(1001); return OB_SUCCESS; };
ObServerCheckpointSlogHandler::get_instance().is_started_ = true;
}
void FakeObScanTable::TearDownTestCase()
{
MockTenantModuleEnv::get_instance().destroy();
}
int FakeObScanTable::set_tablet_split_info(
ObTabletID &src_tablet_id,
ObTabletSplitType split_type,
const int64_t split_cnt)
{
int ret = OB_SUCCESS;
ObTabletHandle tablet_handle;
ObTabletSplitTscInfo split_info;
ObLSHandle ls_handle;
ObLSID test_ls_id(ls_id_);
if (OB_FAIL(MTL(ObLSService *)->get_ls(test_ls_id, ls_handle, ObLSGetMod::STORAGE_MOD))) {
STORAGE_LOG(WARN, "fail to get log stream", K(ret), K(ls_handle));
} else if (OB_UNLIKELY(nullptr == ls_handle.get_ls())) {
ret = OB_ERR_UNEXPECTED;
STORAGE_LOG(WARN, "ls is null", K(ret), K(ls_handle));
} else if (OB_FAIL(ls_handle.get_ls()->get_tablet(src_tablet_id, tablet_handle))) {
STORAGE_LOG(WARN, "fail to get tablet", K(ret), K(src_tablet_id));
} else if (OB_ISNULL(tablet_handle.get_obj())) {
ret = OB_ERR_UNEXPECTED;
STORAGE_LOG(WARN, "tablet handle obj is null", K(ret), K(tablet_handle));
} else {
split_info.split_cnt_= split_cnt;
split_info.split_type_ = split_type;
split_info.start_key_ = start_key_; // not set is invalid
split_info.end_key_ = end_key_; // not set is invalid
split_info.src_tablet_handle_ = tablet_handle;
// tablet_handle.get_obj()->set_split_info(split_info);
}
return ret;
}
int FakeObScanTable::gen_datum_rowkey(const int64_t key_val, const int64_t key_cnt, ObDatumRowkey &datum_rowkey)
{
int ret = OB_SUCCESS;
ObObj *key_val_obj = NULL;
ObRowkey rowkey;
if (NULL == (key_val_obj = static_cast<ObObj*>(allocator_.alloc(sizeof(ObObj) * key_cnt)))) {
ret = OB_ALLOCATE_MEMORY_FAILED;
STORAGE_LOG(WARN, "out of memory", K(ret));
} else {
for (int64_t i = 0; i < key_cnt; ++i) {
key_val_obj[i].set_int(key_val);
// key_val_obj[i].set_min();
}
rowkey.assign(key_val_obj, key_cnt);
if (OB_FAIL(datum_rowkey.from_rowkey(rowkey, allocator_))) {
STORAGE_LOG(WARN, "fail to from rowkey", K(ret));
}
}
return ret;
}
void FakeObScanTable::insert_data_to_tablet(MockObAccessService *access_service, ObTabletID &tablet_id, const char *data)
{
ASSERT_NE(nullptr, access_service);
ASSERT_NE(nullptr, data);
ObLSHandle ls_handle;
ObTabletHandle tablet_handle;
ObLSService *ls_svr = MTL(ObLSService*);
ASSERT_EQ(OB_SUCCESS, ls_svr->get_ls(ls_id_, ls_handle, ObLSGetMod::STORAGE_MOD));
ObLS *ls = ls_handle.get_ls();
ASSERT_NE(nullptr, ls);
ASSERT_EQ(OB_SUCCESS, ls->get_tablet(tablet_id, tablet_handle));
ObTablet *tablet = tablet_handle.get_obj();
ASSERT_NE(nullptr, tablet);
// insert rows
ObMockNewRowIterator mock_iter;
ObSEArray<uint64_t, 512> column_ids;
column_ids.push_back(OB_APP_MIN_COLUMN_ID + 0); // pk
column_ids.push_back(OB_APP_MIN_COLUMN_ID + 1); // c1
column_ids.push_back(OB_APP_MIN_COLUMN_ID + 2); // c2
column_ids.push_back(OB_APP_MIN_COLUMN_ID + 3); // c3
column_ids.push_back(OB_APP_MIN_COLUMN_ID + 4); // c4
ASSERT_EQ(OB_SUCCESS, mock_iter.from(data));
transaction::ObTransService *tx_service = MTL(transaction::ObTransService*);
// 1. get tx desc
transaction::ObTxDesc *tx_desc = nullptr;
ASSERT_EQ(OB_SUCCESS, TestDmlCommon::build_tx_desc(tenant_id_, tx_desc));
// 2. create savepoint (can be rollbacked)
ObTxParam tx_param;
TestDmlCommon::build_tx_param(tx_param);
int64_t savepoint = 0;
ASSERT_EQ(OB_SUCCESS, tx_service->create_implicit_savepoint(*tx_desc, tx_param, savepoint, true));
// 3. acquire snapshot (write also need snapshot)
ObTxIsolationLevel isolation = ObTxIsolationLevel::RC;
int64_t expire_ts = ObTimeUtility::current_time() + TestDmlCommon::TX_EXPIRE_TIME_US;
ObTxReadSnapshot read_snapshot;
ASSERT_EQ(OB_SUCCESS, tx_service->get_read_snapshot(*tx_desc, isolation, expire_ts, read_snapshot));
// 4. storage dml
ObDMLBaseParam dml_param;
dml_param.timeout_ = ObTimeUtility::current_time() + TestDmlCommon::TX_EXPIRE_TIME_US;
dml_param.is_total_quantity_log_ = false;
dml_param.tz_info_ = NULL;
dml_param.sql_mode_ = SMO_DEFAULT;
dml_param.schema_version_ = share::OB_CORE_SCHEMA_VERSION + 1;
dml_param.tenant_schema_version_ = share::OB_CORE_SCHEMA_VERSION + 1;
dml_param.encrypt_meta_ = &dml_param.encrypt_meta_legacy_;
dml_param.snapshot_ = read_snapshot;
ObArenaAllocator allocator;
share::schema::ObTableDMLParam table_dml_param(allocator);
share::schema::ObTableSchema table_schema;
TestDmlCommon::build_data_table_schema(tenant_id_, table_schema);
ASSERT_EQ(OB_SUCCESS, table_dml_param.convert(&table_schema, 1, column_ids));
dml_param.table_param_ = &table_dml_param;
int64_t affected_rows = 0;
ASSERT_EQ(OB_SUCCESS, access_service->insert_rows(ls_id_, tablet_id,
*tx_desc, dml_param, column_ids, &mock_iter, affected_rows));
ASSERT_EQ(12, affected_rows);
// 5. submit transaction, or rollback
expire_ts = ObTimeUtility::current_time() + TestDmlCommon::TX_EXPIRE_TIME_US;
ASSERT_EQ(OB_SUCCESS, tx_service->commit_tx(*tx_desc, expire_ts));
// 6. release tx desc
tx_service->release_tx(*tx_desc);
}
void FakeObScanTable::table_scan(
ObAccessService *access_service,
ObNewRowIterator *&result)
{
// prepare table schema
share::schema::ObTableSchema table_schema;
TestDmlCommon::build_data_table_schema(tenant_id_, table_schema);
// 1. get tx desc
transaction::ObTxDesc *tx_desc = nullptr;
ASSERT_EQ(OB_SUCCESS, TestDmlCommon::build_tx_desc(tenant_id_, tx_desc));
// 2. get read snapshot
ObTxIsolationLevel isolation = ObTxIsolationLevel::RC;
int64_t expire_ts = ObTimeUtility::current_time() + TestDmlCommon::TX_EXPIRE_TIME_US;
ObTxReadSnapshot read_snapshot;
transaction::ObTransService *tx_service = MTL(transaction::ObTransService*);
ASSERT_EQ(OB_SUCCESS, tx_service->get_read_snapshot(*tx_desc, isolation, expire_ts, read_snapshot));
// 3. storage dml
// build table param
ObArenaAllocator allocator;
share::schema::ObTableParam table_param(allocator);
ObSArray<uint64_t> colunm_ids;
colunm_ids.push_back(OB_APP_MIN_COLUMN_ID + 0);
colunm_ids.push_back(OB_APP_MIN_COLUMN_ID + 1);
colunm_ids.push_back(OB_APP_MIN_COLUMN_ID + 2);
colunm_ids.push_back(OB_APP_MIN_COLUMN_ID + 3);
colunm_ids.push_back(OB_APP_MIN_COLUMN_ID + 4);
ASSERT_EQ(OB_SUCCESS, TestDmlCommon::build_table_param(table_schema, colunm_ids, table_param));
ObTableScanParam scan_param;
ASSERT_EQ(OB_SUCCESS, TestDmlCommon::build_table_scan_param(tenant_id_, read_snapshot, table_param, scan_param));
const share::ObLSID ls_id(TestDmlCommon::TEST_LS_ID);
ASSERT_EQ(OB_SUCCESS, access_service->table_scan(scan_param, result));
ASSERT_TRUE(nullptr != result);
// print data
int ret = OB_SUCCESS;
int cnt = 0;
ObNewRow *row = nullptr;
while (OB_SUCC(ret)) {
ret = result->get_next_row(row);
if (OB_SUCCESS == ret) {
++cnt;
}
STORAGE_LOG(WARN, "table scan row", KPC(row));
}
ASSERT_EQ(24, cnt);
// 4. submit transaction, or rollback
expire_ts = ObTimeUtility::current_time() + TestDmlCommon::TX_EXPIRE_TIME_US;
ASSERT_EQ(OB_SUCCESS, tx_service->commit_tx(*tx_desc, expire_ts));
// 5. release tx desc
tx_service->release_tx(*tx_desc);
}
TEST_F(FakeObScanTable, table_scan_pure_data_table)
{
int ret = OB_SUCCESS;
ObLSHandle ls_handle;
ret = TestDmlCommon::create_ls(tenant_id_, ls_id_, ls_handle);
ASSERT_EQ(OB_SUCCESS, ret);
// mock ls tablet service and access service
ObLSTabletService *tablet_service = nullptr;
ret = TestDmlCommon::mock_ls_tablet_service(ls_id_, tablet_service);
ASSERT_EQ(OB_SUCCESS, ret);
ASSERT_NE(nullptr, tablet_service);
MockObAccessService *access_service = nullptr;
ret = TestDmlCommon::mock_access_service(tablet_service, access_service);
ASSERT_EQ(OB_SUCCESS, ret);
ASSERT_NE(nullptr, access_service);
ObTableSchema table_schema;
TestDmlCommon::build_data_table_schema(tenant_id_, table_schema);
ASSERT_EQ(OB_SUCCESS, TestTabletHelper::create_tablet(ls_handle, tablet_id_, table_schema, allocator_));
TestDmlCommon::build_data_table_schema(tenant_id_, table_schema);
ASSERT_EQ(OB_SUCCESS, TestTabletHelper::create_tablet(ls_handle, orig_tablet_id_, table_schema, allocator_));
insert_data_to_tablet(access_service, tablet_id_, data_row_str_01);
insert_data_to_tablet(access_service, orig_tablet_id_, data_row_str_02);
// set split info
ObTabletID src_tablet_id(TestDmlCommon::TEST_DATA_TABLE_ID);
ObTabletID ori_tablet_id(51);
int64_t split_cnt = 1.0;
int64_t start_val = 0; // not include eage
int64_t end_val = 26; // not include eage
int64_t key_cnt = 1;
ret = gen_datum_rowkey(start_val, key_cnt, get_start_key());
ASSERT_EQ(OB_SUCCESS, ret);
ret = gen_datum_rowkey(end_val, key_cnt, get_end_key());
ASSERT_EQ(OB_SUCCESS, ret);
ret = set_tablet_split_info(src_tablet_id, ObTabletSplitType::RANGE, split_cnt);
ASSERT_EQ(OB_SUCCESS, ret);
// table scan
ObNewRowIterator *iter = nullptr;
table_scan(access_service, iter);
// clean env
TestDmlCommon::delete_mocked_access_service(access_service);
TestDmlCommon::delete_mocked_ls_tablet_service(tablet_service);
// for exist
// the iter has store ctx and store ctx has one ls handle.
iter->reset();
ASSERT_EQ(OB_SUCCESS, MTL(ObLSService*)->remove_ls(ls_id_, false));
}
} // namespace unittest
} // namespace oceanbase
int main(int argc, char **argv)
{
system("rm -rf test_auto_partition_scan_table.log");
OB_LOGGER.set_file_name("test_auto_partition_scan_table.log", true);
OB_LOGGER.set_log_level("WARN");
CLOG_LOG(INFO, "begin unittest: test_auto_partition_scan_table");
::testing::InitGoogleTest(&argc, argv);
return RUN_ALL_TESTS();
}