486 lines
15 KiB
C++
486 lines
15 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 "common/row/ob_row_store.h"
|
|
#include "lib/utility/ob_test_util.h"
|
|
#include <gtest/gtest.h>
|
|
using namespace oceanbase::common;
|
|
|
|
class TestRowStore: public ::testing::Test
|
|
{
|
|
public:
|
|
TestRowStore();
|
|
virtual ~TestRowStore();
|
|
virtual void SetUp();
|
|
virtual void TearDown();
|
|
private:
|
|
// disallow copy
|
|
TestRowStore(const TestRowStore &other);
|
|
TestRowStore& operator=(const TestRowStore &other);
|
|
protected:
|
|
void add_row(int32_t i, int64_t COL_NUM, ObRowStore &store, int expect_ret = OB_SUCCESS);
|
|
void add_rows(int64_t COL_NUM, int64_t ROW_NUM, ObRowStore &store);
|
|
void verify_rows(int64_t COL_NUM, int64_t ROW_NUM, ObRowStore &store);
|
|
void add_rows_payload(int64_t COL_NUM, int64_t ROW_NUM, ObRowStore &store);
|
|
void verify_rows_payload(int64_t COL_NUM, int64_t ROW_NUM, ObRowStore &store);
|
|
void verify_rows_by_deep_copy(int64_t COL_NUM, int64_t ROW_NUM, ObRowStore &store);
|
|
// data members
|
|
};
|
|
|
|
TestRowStore::TestRowStore()
|
|
{
|
|
}
|
|
|
|
TestRowStore::~TestRowStore()
|
|
{
|
|
}
|
|
|
|
void TestRowStore::SetUp()
|
|
{
|
|
}
|
|
|
|
void TestRowStore::TearDown()
|
|
{
|
|
}
|
|
|
|
void TestRowStore::add_row(int32_t i, int64_t COL_NUM, ObRowStore &store, int expect_ret /*=OB_SUCCESS*/)
|
|
{
|
|
// 1. fill data
|
|
ObNewRow row;
|
|
ObObj objs[COL_NUM];
|
|
row.cells_ = objs;
|
|
row.count_ = COL_NUM;
|
|
int ret = OB_SUCCESS;
|
|
for (int j = 0; OB_SUCC(ret) && j < COL_NUM; ++j) {
|
|
row.cells_[j].set_int(i*COL_NUM+j);
|
|
} // end for
|
|
ASSERT_EQ(expect_ret, store.add_row(row));
|
|
//_OB_LOG(INFO, "row=%s", S(row));
|
|
}
|
|
|
|
void TestRowStore::add_rows(int64_t COL_NUM, int64_t ROW_NUM, ObRowStore &store)
|
|
{
|
|
// 1. fill data
|
|
int ret = OB_SUCCESS;
|
|
for (int i = 0; OB_SUCC(ret) && i < ROW_NUM; ++i) {
|
|
add_row(i, COL_NUM, store);
|
|
} // end for
|
|
_OB_LOG(INFO, "store=%s", S(store));
|
|
ASSERT_EQ(ROW_NUM, store.get_row_count());
|
|
}
|
|
|
|
void TestRowStore::verify_rows(int64_t COL_NUM, int64_t ROW_NUM, ObRowStore &store)
|
|
{
|
|
int ret = OB_SUCCESS;
|
|
ObRowStore::Iterator it = store.begin();
|
|
ObNewRow row2;
|
|
ObObj objs[COL_NUM];
|
|
ASSERT_EQ(OB_INVALID_ARGUMENT, it.get_next_row(row2));
|
|
for (int round = 0; round < 3; ++round) {
|
|
row2.count_ = COL_NUM;
|
|
row2.cells_ = objs;
|
|
for (int i = 0; OB_SUCC(ret) && i < ROW_NUM; ++i) {
|
|
OK(it.get_next_row(row2));
|
|
ASSERT_EQ(COL_NUM, row2.count_);
|
|
for (int j = 0; OB_SUCC(ret) && j < COL_NUM; ++j) {
|
|
ASSERT_EQ(row2.cells_[j].get_int(), i*COL_NUM+j);;
|
|
} // end for
|
|
} // end for
|
|
ASSERT_EQ(OB_ITER_END, it.get_next_row(row2));
|
|
ASSERT_EQ(OB_ITER_END, it.get_next_row(row2));
|
|
// test iterator reset
|
|
it.reset();
|
|
}
|
|
}
|
|
|
|
TEST_F(TestRowStore, serialization_2)
|
|
{
|
|
ObRowStore store;
|
|
ObRowStore s;
|
|
const int64_t BUF_SIZE = store.get_serialize_size();
|
|
char* buf = static_cast<char*>(ob_malloc(BUF_SIZE, ObModIds::TEST));
|
|
ASSERT_TRUE(NULL != buf);
|
|
int64_t pos = 0;
|
|
OK(store.serialize(buf, BUF_SIZE, pos));
|
|
pos = 0;
|
|
OK(s.deserialize(buf, BUF_SIZE, pos));
|
|
}
|
|
|
|
TEST_F(TestRowStore, serialization_3)
|
|
{
|
|
//the data_buffer_size of BlockInfo is 8157,between 8152 and 8196
|
|
int ret = OB_SUCCESS;
|
|
ObRowStore store;
|
|
ObNewRow row;
|
|
ObObj objs[2756];
|
|
for (int64_t i = 0; i < 2756; ++i) {
|
|
objs[i].set_int(i);
|
|
}
|
|
row.cells_ = const_cast<ObObj *>(objs);
|
|
row.count_ = 2756;
|
|
|
|
ret = store.add_row(row);
|
|
ASSERT_EQ(OB_SUCCESS, ret);
|
|
|
|
//serialize
|
|
int64_t serialize_size = store.get_serialize_size();
|
|
char *buf = static_cast<char*>(ob_malloc(serialize_size, ObModIds::TEST));
|
|
int64_t pos = 0;
|
|
ret = store.serialize(buf, serialize_size, pos);
|
|
ASSERT_EQ(OB_SUCCESS, ret);
|
|
|
|
//deserialize
|
|
ObRowStore store_des;
|
|
int64_t pos_des = 0;
|
|
ret = store_des.deserialize(buf, serialize_size, pos_des);
|
|
ASSERT_EQ(OB_SUCCESS, ret);
|
|
}
|
|
|
|
TEST_F(TestRowStore, add_row)
|
|
{
|
|
static const int64_t COL_NUM = 18;
|
|
static const int64_t ROW_NUM = 10240;
|
|
|
|
ObRowStore store1;
|
|
ASSERT_EQ(0, store1.get_used_mem_size());
|
|
ASSERT_EQ(0, store1.get_block_count());
|
|
ASSERT_TRUE(!store1.is_read_only());
|
|
|
|
for (int32_t round = 0; round < 8; ++round) {
|
|
_OB_LOG(INFO, "round %d", round);
|
|
ASSERT_TRUE(!store1.is_read_only());
|
|
ASSERT_EQ(0, store1.get_data_size());
|
|
ASSERT_TRUE(store1.is_empty());
|
|
ASSERT_EQ(0, store1.get_row_count());
|
|
ASSERT_EQ(0, store1.get_col_count());
|
|
add_rows(COL_NUM, ROW_NUM, store1);
|
|
|
|
ASSERT_TRUE(!store1.is_read_only());
|
|
ASSERT_TRUE(!store1.is_empty());
|
|
ASSERT_NE(0, store1.get_used_mem_size());
|
|
ASSERT_NE(0, store1.get_block_count());
|
|
ASSERT_EQ(COL_NUM, store1.get_col_count());
|
|
ASSERT_EQ(ROW_NUM, store1.get_row_count());
|
|
// 2. verify
|
|
verify_rows(COL_NUM, ROW_NUM, store1);
|
|
// reset & reuse
|
|
if (0 == round % 2) {
|
|
store1.reset();
|
|
} else {
|
|
store1.reuse();
|
|
}
|
|
}
|
|
}
|
|
|
|
void TestRowStore::add_rows_payload(int64_t COL_NUM, int64_t ROW_NUM, ObRowStore &store)
|
|
{
|
|
ASSERT_EQ(OB_SUCCESS, store.init_reserved_column_count(5));
|
|
ASSERT_EQ(OB_INVALID_ARGUMENT, store.add_reserved_column(-1));
|
|
OK(store.add_reserved_column(1));
|
|
OK(store.add_reserved_column(3));
|
|
OK(store.add_reserved_column(5));
|
|
OK(store.add_reserved_column(7));
|
|
OK(store.add_reserved_column(9));
|
|
ASSERT_EQ(5, store.get_reserved_column_count());
|
|
// 1. fill data
|
|
ObNewRow row;
|
|
ObObj objs[COL_NUM];
|
|
row.cells_ = objs;
|
|
row.count_ = COL_NUM;
|
|
int ret = OB_SUCCESS;
|
|
const ObRowStore::StoredRow *stored_row = NULL;
|
|
for (int i = 0; OB_SUCC(ret) && i < ROW_NUM; ++i) {
|
|
for (int j = 0; OB_SUCC(ret) && j < COL_NUM; ++j) {
|
|
row.cells_[j].set_int(i*COL_NUM+j);
|
|
} // end for
|
|
OK(store.add_row(row, stored_row, i, true));
|
|
ASSERT_EQ(5, stored_row->reserved_cells_count_);
|
|
} // end for
|
|
_OB_LOG(INFO, "store=%s", S(store));
|
|
ASSERT_EQ(ROW_NUM, store.get_row_count());
|
|
}
|
|
|
|
void TestRowStore::verify_rows_payload(int64_t COL_NUM, int64_t ROW_NUM, ObRowStore &store)
|
|
{
|
|
_OB_LOG(INFO, "verify rows payload");
|
|
int ret = OB_SUCCESS;
|
|
ObRowStore::Iterator it = store.begin();
|
|
ObNewRow row2;
|
|
ObObj objs[COL_NUM];
|
|
ObString compact_row;
|
|
ObRowStore::StoredRow *stored_row = NULL;
|
|
ASSERT_EQ(OB_INVALID_ARGUMENT, it.get_next_row(row2));
|
|
for (int round = 0; round < 3; ++round) {
|
|
row2.count_ = COL_NUM;
|
|
row2.cells_ = objs;
|
|
for (int i = 0; OB_SUCC(ret) && i < ROW_NUM; ++i) {
|
|
OK(it.get_next_row(row2, &compact_row, &stored_row));
|
|
ASSERT_EQ(COL_NUM, row2.count_);
|
|
ASSERT_NE(0, compact_row.length());
|
|
ASSERT_EQ(5, stored_row->reserved_cells_count_);
|
|
ASSERT_EQ(i*COL_NUM+1, stored_row->reserved_cells_[0].get_int());
|
|
ASSERT_EQ(i*COL_NUM+3, stored_row->reserved_cells_[1].get_int());
|
|
ASSERT_EQ(i*COL_NUM+5, stored_row->reserved_cells_[2].get_int());
|
|
ASSERT_EQ(i*COL_NUM+7, stored_row->reserved_cells_[3].get_int());
|
|
ASSERT_EQ(i*COL_NUM+9, stored_row->reserved_cells_[4].get_int());
|
|
ASSERT_EQ(i, stored_row->payload_);
|
|
// verify row data
|
|
for (int j = 0; OB_SUCC(ret) && j < COL_NUM; ++j) {
|
|
ASSERT_EQ(row2.cells_[j].get_int(), i*COL_NUM+j);;
|
|
} // end for
|
|
} // end for
|
|
ASSERT_EQ(OB_ITER_END, it.get_next_row(row2));
|
|
ASSERT_EQ(OB_ITER_END, it.get_next_row(row2));
|
|
// test iterator reset
|
|
it.reset();
|
|
}
|
|
}
|
|
|
|
TEST_F(TestRowStore, add_row_with_payload)
|
|
{
|
|
static const int64_t COL_NUM = 18;
|
|
static const int64_t ROW_NUM = 10;
|
|
ObRowStore store1;
|
|
add_rows_payload(COL_NUM, ROW_NUM, store1);
|
|
store1.dump();
|
|
verify_rows_payload(COL_NUM, ROW_NUM, store1);
|
|
// clear rows
|
|
store1.clear_rows();
|
|
ASSERT_TRUE(store1.is_empty());
|
|
ASSERT_EQ(5, store1.get_reserved_column_count());
|
|
}
|
|
|
|
TEST_F(TestRowStore, rollback_get_last_row)
|
|
{
|
|
static const int64_t COL_NUM = 18;
|
|
int ret = OB_SUCCESS;
|
|
ObRowStore store1;
|
|
const ObRowStore::StoredRow *stored_row = NULL;
|
|
ASSERT_EQ(OB_ENTRY_NOT_EXIST, store1.get_last_row(stored_row));
|
|
// add->get->rollback->add->get->rollback
|
|
for (int round = 1; OB_SUCC(ret) && round < 1024; ++round) {
|
|
_OB_LOG(INFO, "round=%d", round);
|
|
for (int i = 0; i < round; ++i) {
|
|
add_row(i, COL_NUM, store1);
|
|
OK(store1.get_last_row(stored_row));
|
|
ASSERT_TRUE(0 < stored_row->compact_row_size_);
|
|
OK(store1.rollback_last_row());
|
|
add_row(i, COL_NUM, store1);
|
|
OK(store1.get_last_row(stored_row));
|
|
ASSERT_TRUE(0 < stored_row->compact_row_size_);
|
|
}
|
|
ASSERT_EQ(round, store1.get_row_count());
|
|
ASSERT_EQ(COL_NUM, store1.get_col_count());
|
|
OK(store1.rollback_last_row());
|
|
if (1 == round) {
|
|
ASSERT_TRUE(store1.is_empty());
|
|
ASSERT_EQ(OB_ENTRY_NOT_EXIST, store1.get_last_row(stored_row));
|
|
} else {
|
|
OK(store1.get_last_row(stored_row));
|
|
ASSERT_TRUE(0 < stored_row->compact_row_size_);
|
|
}
|
|
if (2 == round) {
|
|
OK(store1.rollback_last_row());
|
|
ASSERT_TRUE(store1.is_empty());
|
|
} else {
|
|
ASSERT_EQ(OB_NOT_SUPPORTED, store1.rollback_last_row());
|
|
}
|
|
store1.clear_rows();
|
|
} // end for
|
|
}
|
|
|
|
TEST_F(TestRowStore, serialization_etc)
|
|
{
|
|
static const int64_t COL_NUM = 18;
|
|
static const int64_t ROW_NUM = 10240;
|
|
ObRowStore store1;
|
|
add_rows_payload(COL_NUM, ROW_NUM, store1);
|
|
ASSERT_TRUE(!store1.is_read_only());
|
|
// column consistency check
|
|
add_row(0, COL_NUM-1, store1, OB_INVALID_ARGUMENT);
|
|
// serialize
|
|
const int64_t BUF_SIZE = store1.get_serialize_size();
|
|
char* buf = static_cast<char*>(ob_malloc(BUF_SIZE, ObModIds::TEST));
|
|
ASSERT_TRUE(NULL != buf);
|
|
int64_t pos = 0;
|
|
OK(store1.serialize(buf, BUF_SIZE, pos));
|
|
// deserialize
|
|
ObRowStore store2;
|
|
int64_t len = pos;
|
|
pos = 0;
|
|
OK(store2.deserialize(buf, len, pos));
|
|
verify_rows_payload(COL_NUM, ROW_NUM, store2);
|
|
// get_last_row
|
|
const ObRowStore::StoredRow *stored_row = NULL;
|
|
OK(store2.get_last_row(stored_row));
|
|
ASSERT_TRUE(0 < stored_row->compact_row_size_);
|
|
// read only
|
|
ASSERT_TRUE(!store2.is_read_only());
|
|
//add_row(0, COL_NUM, store2, OB_ERR_READ_ONLY);
|
|
ob_free(buf);
|
|
}
|
|
|
|
TEST_F(TestRowStore, KVCacheAPIs)
|
|
{
|
|
static const int64_t COL_NUM = 18;
|
|
static const int64_t ROW_NUM = 10240;
|
|
ObRowStore store1;
|
|
add_rows_payload(COL_NUM, ROW_NUM, store1);
|
|
static const int64_t BUF_SIZE = 1024*1024*10;
|
|
char* buf = static_cast<char*>(ob_malloc(BUF_SIZE, ObModIds::TEST));
|
|
ASSERT_TRUE(NULL != buf);
|
|
// clone
|
|
_OB_LOG(INFO, "meta_size=%d copy_size=%d", store1.get_meta_size(), store1.get_copy_size());
|
|
ObRowStore *store2 = store1.clone(buf, BUF_SIZE);
|
|
ASSERT_TRUE(NULL == store2);
|
|
store2 = store1.clone(NULL, BUF_SIZE);
|
|
ASSERT_TRUE(NULL == store2);
|
|
|
|
store1.reset();
|
|
add_rows(COL_NUM, ROW_NUM, store1);
|
|
ObRowStore *store3 = store1.clone(buf, BUF_SIZE);
|
|
ASSERT_TRUE(NULL != store3);
|
|
ASSERT_TRUE(store3->is_read_only());
|
|
verify_rows(COL_NUM, ROW_NUM, *store3);
|
|
ASSERT_EQ(store1.get_row_count(), store3->get_row_count());
|
|
ASSERT_EQ(store1.get_col_count(), store3->get_col_count());
|
|
ASSERT_EQ(store1.get_data_size(), store3->get_data_size());
|
|
ASSERT_EQ(store1.get_label(), store3->get_label());
|
|
ASSERT_EQ(store1.get_block_size(), store3->get_block_size());
|
|
ASSERT_EQ(store1.get_copy_size(), store3->get_copy_size());
|
|
ASSERT_EQ(store1.get_meta_size(), store3->get_meta_size());
|
|
ASSERT_EQ(store1.get_reserved_column_count(), store3->get_reserved_column_count());
|
|
ASSERT_TRUE(store1.get_used_mem_size() >= store3->get_used_mem_size());
|
|
|
|
ob_free(buf);
|
|
}
|
|
|
|
TEST_F(TestRowStore, empty_store)
|
|
{
|
|
ObRowStore store1;
|
|
ASSERT_TRUE(store1.is_empty());
|
|
ObRowStore::Iterator it;
|
|
ObNewRow row;
|
|
ObObj objs[3];
|
|
row.cells_ = objs;
|
|
row.count_ = 3;
|
|
ASSERT_EQ(OB_ERR_UNEXPECTED, it.get_next_row(row));
|
|
it = store1.begin();
|
|
ASSERT_EQ(OB_ITER_END, it.get_next_row(row));
|
|
}
|
|
|
|
TEST_F(TestRowStore, mem_block_management)
|
|
{
|
|
ObRowStore store1;
|
|
ASSERT_EQ(OB_MALLOC_NORMAL_BLOCK_SIZE, store1.get_block_size());
|
|
|
|
ObNewRow row;
|
|
ObObj objs[1];
|
|
row.cells_ = objs;
|
|
row.count_ = 1;
|
|
objs[0].set_int(100);
|
|
OK(store1.add_row(row));
|
|
|
|
static const int64_t BUF_1K = 1024; // 1K
|
|
char* buf1k = (char*)ob_malloc(BUF_1K, ObModIds::TEST);
|
|
ObString str1k(BUF_1K, BUF_1K, buf1k);
|
|
objs[0].set_varchar(str1k);
|
|
int ret = OB_SUCCESS;
|
|
for (int32_t i = 0; OB_SUCC(ret) && i < 128; ++i) {
|
|
OK(store1.add_row(row));
|
|
} // end for
|
|
|
|
// 256K buffer
|
|
static const int64_t BUF_256K = 256*1024L; // 256K
|
|
char* buf256k = (char*)ob_malloc(BUF_256K, ObModIds::TEST);
|
|
ObString str256k(BUF_256K, BUF_256K, buf256k);
|
|
objs[0].set_varchar(str256k);
|
|
OK(store1.add_row(row));
|
|
|
|
// 2M buffer
|
|
static const int64_t BUF_2M = 2*1024*1024; // 2M
|
|
char* buf2m = (char*)ob_malloc(BUF_2M, ObModIds::TEST);
|
|
ObString str2m(BUF_2M, BUF_2M, buf2m);
|
|
objs[0].set_varchar(str2m);
|
|
ASSERT_EQ(OB_SIZE_OVERFLOW, store1.add_row(row));
|
|
|
|
// teardown
|
|
ob_free(buf1k);
|
|
ob_free(buf256k);
|
|
ob_free(buf2m);
|
|
}
|
|
|
|
void TestRowStore::verify_rows_by_deep_copy(int64_t COL_NUM, int64_t ROW_NUM, ObRowStore &store)
|
|
{
|
|
int ret = OB_SUCCESS;
|
|
ObRowStore::Iterator it = store.begin();
|
|
ObNewRow *row2 = NULL;
|
|
for (int round = 0; round < 3; ++round) {
|
|
for (int i = 0; OB_SUCC(ret) && i < ROW_NUM; ++i) {
|
|
OK(it.get_next_row(row2, NULL));
|
|
ASSERT_EQ(COL_NUM, row2->count_);
|
|
for (int j = 0; OB_SUCC(ret) && j < COL_NUM; ++j) {
|
|
ASSERT_EQ(row2->cells_[j].get_int(), i*COL_NUM+j);;
|
|
} // end for
|
|
} // end for
|
|
ASSERT_EQ(OB_ITER_END, it.get_next_row(row2, NULL));
|
|
ASSERT_EQ(OB_ITER_END, it.get_next_row(row2, NULL));
|
|
// test iterator reset
|
|
it.reset();
|
|
}
|
|
}
|
|
|
|
TEST_F(TestRowStore, row_store_by_deep_copy)
|
|
{
|
|
static const int64_t COL_NUM = 18;
|
|
static const int64_t ROW_NUM = 10240;
|
|
|
|
ObRowStore store1(ObModIds::TEST,
|
|
OB_SERVER_TENANT_ID,
|
|
false);
|
|
ASSERT_EQ(0, store1.get_used_mem_size());
|
|
ASSERT_EQ(0, store1.get_block_count());
|
|
ASSERT_TRUE(!store1.is_read_only());
|
|
|
|
for (int32_t round = 0; round < 8; ++round) {
|
|
_OB_LOG(INFO, "round %d", round);
|
|
ASSERT_TRUE(!store1.is_read_only());
|
|
ASSERT_EQ(0, store1.get_data_size());
|
|
ASSERT_TRUE(store1.is_empty());
|
|
ASSERT_EQ(0, store1.get_row_count());
|
|
ASSERT_EQ(0, store1.get_col_count());
|
|
add_rows(COL_NUM, ROW_NUM, store1);
|
|
|
|
ASSERT_TRUE(!store1.is_read_only());
|
|
ASSERT_TRUE(!store1.is_empty());
|
|
ASSERT_NE(0, store1.get_used_mem_size());
|
|
ASSERT_NE(0, store1.get_block_count());
|
|
ASSERT_EQ(COL_NUM, store1.get_col_count());
|
|
ASSERT_EQ(ROW_NUM, store1.get_row_count());
|
|
// 2. verify
|
|
verify_rows_by_deep_copy(COL_NUM, ROW_NUM, store1);
|
|
// reset & reuse
|
|
if (0 == round % 2) {
|
|
store1.reset();
|
|
} else {
|
|
store1.reuse();
|
|
}
|
|
}
|
|
}
|
|
|
|
int main(int argc, char **argv)
|
|
{
|
|
OB_LOGGER.set_log_level("INFO", "WARN");
|
|
::testing::InitGoogleTest(&argc,argv);
|
|
return RUN_ALL_TESTS();
|
|
}
|