oceanbase/unittest/storage/test_row_fuse.cpp
2023-05-22 03:41:34 +00:00

361 lines
13 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 "storage/ob_row_fuse.h"
#include "lib/allocator/page_arena.h"
#include "mockcontainer/mock_ob_iterator.h"
namespace oceanbase
{
using namespace common;
using namespace storage;
using namespace blocksstable;
namespace unittest
{
const static int64_t DEF_COL_NUM = 4;
void check_row_fuse(const char *input, const char *expect)
{
int ret = OB_SUCCESS;
common::ObArenaAllocator allocator("StTemp");
//const ObStoreRow *expect_row = NULL;
const ObStoreRow *input_row = NULL;
ObStoreRow *result = NULL;
ObMockStoreRowIterator iter;
ObMockStoreRowIterator expect_iter;
if (OB_FAIL(malloc_store_row(allocator, OB_ROW_MAX_COLUMNS_COUNT, result))) {
STORAGE_LOG(WARN, "no memory");
} else {
SCOPED_TRACE(expect);
SCOPED_TRACE(input);
result->row_val_.count_ = 0;
result->flag_.set_flag(ObDmlFlag::DF_NOT_EXIST);
ObNopPos nop_pos;
bool final_result = false;
// run row fuse
ASSERT_EQ(OB_SUCCESS, iter.from(input));
if (OB_SUCCESS != (ret = nop_pos.init(allocator, 256))) {
STORAGE_LOG(WARN, "nop position initialize error", K(ret));
}
while (OB_SUCCESS == ret && !final_result) {
if (OB_ITER_END != iter.get_next_row(input_row)) {
ret = ObRowFuse::fuse_row(*input_row, *result, nop_pos, final_result);
STORAGE_LOG(INFO, "fuse row", K(ret), KPC(input_row), KPC(result));
} else {
break;
}
}
ASSERT_EQ(OB_SUCCESS, ret);
// check result
ASSERT_EQ(OB_SUCCESS, expect_iter.from(expect));
//ASSERT_EQ(OB_SUCCESS, iter.get_next_row(expect_row));
//ASSERT_TRUE(expect_iter.equals(*expect_row));
STORAGE_LOG(INFO, "result row", K(ret), KPC(result));
ASSERT_TRUE(expect_iter.equals(*result));
free_store_row(allocator, result);
}
}
void check_simple_row_fuse(const char *input, const char *expect)
{
int ret = OB_SUCCESS;
common::ObArenaAllocator allocator("StTemp");
//const ObStoreRow *expect_row = NULL;
const ObStoreRow *input_row = NULL;
ObStoreRow *result = NULL;
ObMockStoreRowIterator iter;
ObMockStoreRowIterator expect_iter;
if (OB_FAIL(malloc_store_row(allocator, OB_ROW_MAX_COLUMNS_COUNT, result))) {
STORAGE_LOG(WARN, "no memory");
} else {
SCOPED_TRACE(expect);
SCOPED_TRACE(input);
result->row_val_.count_ = 0;
result->flag_.set_flag(ObDmlFlag::DF_NOT_EXIST);
ObNopPos nop_pos;
bool final_result = false;
// run row fuse
ASSERT_EQ(OB_SUCCESS, iter.from(input));
if (OB_SUCCESS != (ret = nop_pos.init(allocator, 256))) {
STORAGE_LOG(WARN, "nop position initialize error", K(ret));
}
while (OB_SUCCESS == ret && !final_result) {
if (OB_ITER_END != iter.get_next_row(input_row)) {
ret = ObRowFuse::fuse_row(*input_row, *result, nop_pos, final_result);
} else {
break;
}
}
ASSERT_EQ(OB_SUCCESS, ret);
// check result
ASSERT_EQ(OB_SUCCESS, expect_iter.from(expect));
//ASSERT_EQ(OB_SUCCESS, iter.get_next_row(expect_row));
//ASSERT_TRUE(expect_iter.equals(*expect_row));
ASSERT_TRUE(expect_iter.equals(*result));
free_store_row(allocator, result);
}
}
TEST(ObRowFuseTest, test_fuse_nomal)
{
const char *input = "int var num int int\n"
"1 NOP NOP NOP NOP\n"
"2 var2 NOP NOP NULL\n"
"3 var3 3.33 NOP 5555\n"
"4 var4 NOP NOP NOP\n"
"5 var9 9.99 MAX NULL\n";
const char *expect = "int var num int int\n"
"1 var2 3.33 MAX NULL\n";
check_row_fuse(input, expect);
check_simple_row_fuse(input, expect);
}
TEST(ObRowFuseTest, test_fuse_delete)
{
const char *input1 = "flag int var num int int\n"
"DELETE NOP NOP NOP NOP NOP\n"
"EXIST 1 NOP NOP NOP NOP\n"
"EXIST 2 var2 NOP NOP NULL\n"
"EXIST 3 var3 3.33 NOP 5555\n"
"EXIST 4 var4 NOP NOP NOP\n"
"EXIST 9 var9 9.99 MAX NULL\n";
const char *expect1 = "flag int var num int int\n"
"DELETE NOP NOP NOP NOP NOP\n";
check_row_fuse(input1, expect1);
check_simple_row_fuse(input1, expect1);
const char *input2 = "flag int var num int int\n"
"EXIST 1 NOP NOP NOP NOP\n"
"EXIST 2 var2 NOP NOP NULL\n"
"DELETE NOP NOP NOP NOP NOP\n"
"EXIST 3 var3 3.33 NOP 5555\n"
"DELETE NOP NOP NOP NOP NOP\n"
"EXIST 4 var4 NOP NOP NOP\n"
"EXIST 9 var9 9.99 MAX NULL\n";
const char *expect2 = "flag int var num int int\n"
"EXIST 1 var2 NOP NOP null\n";
check_row_fuse(input2, expect2);
check_simple_row_fuse(input2, expect2);
const char *input3 = "flag int var num int int\n"
"EXIST 1 NOP NOP NOP NOP\n"
"EXIST 2 var2 NOP NOP NULL\n"
"EXIST 3 var3 3.33 NOP 5555\n"
"EXIST 4 var4 NOP NOP NOP\n"
"EXIST 9 var9 9.99 MAX NULL\n"
"DELETE NOP NOP NOP NOP NOP\n";
const char *expect3 = "int var num int int\n"
"1 var2 3.33 MAX NULL\n";
check_row_fuse(input3, expect3);
check_simple_row_fuse(input3, expect3);
}
TEST(ObRowFuseTest, test_fuse_empty)
{
const char *input1 = "flag int var num int int\n"
"EMPTY NOP NOP NOP NOP NOP\n"
"EMPTY NOP NOP NOP NOP NOP\n"
"DELETE NOP NOP NOP NOP NOP\n"
"EXIST 1 NOP NOP NOP NOP\n"
"EXIST 2 var2 NOP NOP NULL\n"
"EXIST 3 var3 3.33 NOP 5555\n"
"EXIST 4 var4 NOP NOP NOP\n"
"EXIST 9 var9 9.99 MAX NULL\n";
const char *expect1 = "flag int var num int int\n"
"DELETE NOP NOP NOP NOP NOP\n";
check_row_fuse(input1, expect1);
check_simple_row_fuse(input1, expect1);
const char *input2 = "flag int var num int int\n"
"EMPTY NOP NOP NOP NOP NOP\n"
"EMPTY NOP NOP NOP NOP NOP\n"
"EXIST 1 NOP NOP NOP NOP\n"
"EMPTY NOP NOP NOP NOP NOP\n"
"EXIST 2 var2 NOP NOP NULL\n"
"EMPTY NOP NOP NOP NOP NOP\n"
"DELETE NOP NOP NOP NOP NOP\n"
"EXIST 3 var3 3.33 NOP 5555\n"
"EXIST 4 var4 NOP NOP NOP\n"
"EXIST 9 var9 9.99 MAX NULL\n";
const char *expect2 = "flag int var num int int\n"
"EXIST 1 var2 NOP NOP NULL\n";
check_row_fuse(input2, expect2);
check_simple_row_fuse(input2, expect2);
const char *input3 = "flag int var num int int\n"
"EMPTY NOP NOP NOP NOP NOP\n"
"EXIST 1 NOP NOP NOP NOP\n"
"EXIST 2 var2 NOP NOP NULL\n"
"EMPTY NOP NOP NOP NOP NOP\n"
"EMPTY NOP NOP NOP NOP NOP\n"
"EXIST 3 var3 3.33 NOP 5555\n"
"EXIST 4 var4 NOP NOP NOP\n"
"EXIST 9 var9 9.99 MAX NULL\n"
"EMPTY NOP NOP NOP NOP NOP\n"
"DELETE NOP NOP NOP NOP NOP\n"
"EMPTY NOP NOP NOP NOP NOP\n";
const char *expect3 = "flag int var num int int\n"
"EXIST 1 var2 3.33 MAX NULL\n";
check_row_fuse(input3, expect3);
check_simple_row_fuse(input3, expect3);
}
TEST(ObRowFuseTest, test_invalid_input_row)
{
common::ObArenaAllocator allocator("StTemp");
char *input_ptr = (char *)allocator.alloc(OB_ROW_MAX_COLUMNS_COUNT * sizeof(ObObj) + sizeof(ObStoreRow));
char *result_ptr = (char *)allocator.alloc(OB_ROW_MAX_COLUMNS_COUNT * sizeof(ObObj) + sizeof(ObStoreRow));
ObStoreRow *input_row = new (input_ptr) ObStoreRow;
ObStoreRow *result = new (result_ptr) ObStoreRow;
new (input_ptr + sizeof(ObStoreRow)) ObObj[OB_ROW_MAX_COLUMNS_COUNT];
new (result_ptr + sizeof(ObStoreRow)) ObObj[OB_ROW_MAX_COLUMNS_COUNT];
ASSERT_TRUE(NULL != input_row);
ASSERT_TRUE(NULL != result);
input_row->row_val_.cells_ = (ObObj *)(input_row + 1);
input_row->row_val_.count_ = OB_ROW_MAX_COLUMNS_COUNT;
input_row->flag_ = -1; // set invalid flag
result->row_val_.count_ = 0;
result->flag_.set_flag(ObDmlFlag::DF_NOT_EXIST);
ObNopPos nop_pos;
bool final_result = false;
ASSERT_EQ(OB_SUCCESS, nop_pos.init(allocator, 256));
ASSERT_EQ(OB_INVALID_ARGUMENT , ObRowFuse::fuse_row(*input_row, *result, nop_pos, final_result, NULL));
ASSERT_EQ(OB_INVALID_ARGUMENT , ObRowFuse::fuse_row(*input_row, *result, nop_pos, final_result));
}
TEST(ObRowFuseTest, test_invalid_argument)
{
common::ObArenaAllocator allocator("StTemp");
char *input_ptr = (char *)allocator.alloc(DEF_COL_NUM * sizeof(ObObj) + sizeof(ObStoreRow));
char *result_ptr = (char *)allocator.alloc(DEF_COL_NUM * sizeof(ObObj) + sizeof(ObStoreRow));
ObStoreRow *input_row = new (input_ptr) ObStoreRow;
ObStoreRow *result = new (result_ptr) ObStoreRow;
new (input_ptr + sizeof(ObStoreRow)) ObObj[DEF_COL_NUM];
new (result_ptr + sizeof(ObStoreRow)) ObObj[DEF_COL_NUM];
ASSERT_TRUE(NULL != input_row);
ASSERT_TRUE(NULL != result);
input_row->row_val_.cells_ = (ObObj *)(input_row + 1);
input_row->row_val_.count_ = DEF_COL_NUM;
result->row_val_.cells_ = NULL;
result->row_val_.count_ = 0;
ObNopPos nop_pos;
bool final_result = false;
ASSERT_EQ(OB_SUCCESS, nop_pos.init(allocator, 256));
ASSERT_EQ(OB_INVALID_ARGUMENT , ObRowFuse::fuse_row(*input_row, *result, nop_pos, final_result, NULL));
ASSERT_EQ(OB_INVALID_ARGUMENT , ObRowFuse::fuse_row(*input_row, *result, nop_pos, final_result));
}
TEST(ObRowFuseTest, test_err_unexpected)
{
common::ObArenaAllocator allocator("StTemp");
char *input_ptr = (char *)allocator.alloc(DEF_COL_NUM * sizeof(ObObj) + sizeof(ObStoreRow));
char *result_ptr = (char *)allocator.alloc(DEF_COL_NUM * sizeof(ObObj) + sizeof(ObStoreRow));
ObStoreRow *input_row = new (input_ptr) ObStoreRow;
ObStoreRow *result = new (result_ptr) ObStoreRow;
new (input_ptr + sizeof(ObStoreRow)) ObObj[DEF_COL_NUM];
new (result_ptr + sizeof(ObStoreRow)) ObObj[DEF_COL_NUM];
ASSERT_TRUE(NULL != input_row);
ASSERT_TRUE(NULL != result);
input_row->row_val_.cells_ = (ObObj *)(input_row + 1);
input_row->row_val_.count_ = DEF_COL_NUM;
result->row_val_.cells_ = (ObObj *)(result + 1);
result->row_val_.count_ = DEF_COL_NUM;
ObNopPos nop_pos;
ASSERT_EQ(OB_SUCCESS, nop_pos.init(allocator, 256));
}
TEST(ObRowFuseTest, test_nop_pos)
{
ObNopPos nop_pos;
common::ObArenaAllocator allocator("StTemp");
// ASSERT_EQ(OB_ALLOCATE_MEMORY_FAILED, nop_pos.init(LONG_MAX));
ASSERT_EQ(OB_SUCCESS, nop_pos.init(allocator, 256));
}
void check_fuse_row_flag(
const uint8_t old_flag,
const uint8_t input_flag,
const uint8_t expect_flag)
{
ObStoreRow row;
row.flag_ = old_flag;
row.flag_.fuse_flag(ObDmlRowFlag(input_flag));
if (expect_flag != row.flag_.whole_flag_) {
STORAGE_LOG_RET(WARN, OB_ERR_UNEXPECTED, "not equal", K(old_flag), K(input_flag),
K(expect_flag), "fused_flag", row.flag_);
}
}
TEST(ObRowFuseTest, test_row_flag_fuse)
{
check_fuse_row_flag(DF_UPDATE, DF_INSERT, DF_INSERT);
check_fuse_row_flag(DF_INSERT, DF_INSERT, DF_INSERT);
check_fuse_row_flag(DF_LOCK, DF_INSERT, DF_INSERT);
check_fuse_row_flag(DF_UPDATE, DF_UPDATE, DF_UPDATE);
check_fuse_row_flag(DF_INSERT, DF_UPDATE, DF_INSERT);
check_fuse_row_flag(DF_LOCK, DF_UPDATE, DF_LOCK);
check_fuse_row_flag(DF_UPDATE, DF_DELETE, DF_UPDATE);
check_fuse_row_flag(DF_INSERT, DF_DELETE, DF_INSERT);
check_fuse_row_flag(DF_LOCK, DF_DELETE, DF_LOCK);
check_fuse_row_flag(DF_UPDATE, DF_DELETE, DF_UPDATE);
check_fuse_row_flag(DF_INSERT, DF_DELETE, DF_INSERT);
check_fuse_row_flag(DF_LOCK, DF_DELETE, DF_LOCK);
check_fuse_row_flag(DF_DELETE | ObDmlRowFlag::OB_FLAG_TYPE_MASK, DF_DELETE, DF_DELETE);
check_fuse_row_flag(DF_DELETE, DF_DELETE | ObDmlRowFlag::OB_FLAG_TYPE_MASK, DF_DELETE);
check_fuse_row_flag(DF_DELETE | ObDmlRowFlag::OB_FLAG_TYPE_MASK,
DF_DELETE | ObDmlRowFlag::OB_FLAG_TYPE_MASK,
DF_DELETE | ObDmlRowFlag::OB_FLAG_TYPE_MASK);
}
} // namespace unittest
} // namespace oceanbase
int main(int argc, char **argv)
{
system("rm -rf test_row_fuse.log");
OB_LOGGER.set_file_name("test_row_fuse.log");
OB_LOGGER.set_log_level("INFO");
CLOG_LOG(INFO, "begin unittest: test_row_fuse");
::testing::InitGoogleTest(&argc, argv);
return RUN_ALL_TESTS();
}