[FEAT MERGE] merge transfer
Co-authored-by: wxhwang <wxhwang@126.com> Co-authored-by: godyangfight <godyangfight@gmail.com> Co-authored-by: Tyshawn <tuyunshan@gmail.com>
This commit is contained in:
13
unittest/storage/multi_data_source/common_define.h
Normal file
13
unittest/storage/multi_data_source/common_define.h
Normal file
@ -0,0 +1,13 @@
|
||||
#ifndef UNITTEST_STORAGE_MULTI_DATA_SOURCE_COMMON_DEFINE_H
|
||||
#define UNITTEST_STORAGE_MULTI_DATA_SOURCE_COMMON_DEFINE_H
|
||||
#include "src/share/scn.h"
|
||||
#include "example_user_data_define.h"
|
||||
|
||||
namespace oceanbase {
|
||||
namespace unittest {
|
||||
|
||||
inline share::SCN mock_scn(int64_t val) { share::SCN scn; scn.convert_for_gts(val); return scn; }
|
||||
|
||||
}
|
||||
}
|
||||
#endif
|
||||
129
unittest/storage/multi_data_source/example_user_data_define.h
Normal file
129
unittest/storage/multi_data_source/example_user_data_define.h
Normal file
@ -0,0 +1,129 @@
|
||||
#ifndef UNITTEST_SHARE_MULTI_DATA_SOURCE_EXAMPLE_USER_DATA_DEFINE_H
|
||||
#define UNITTEST_SHARE_MULTI_DATA_SOURCE_EXAMPLE_USER_DATA_DEFINE_H
|
||||
#include "lib/ob_errno.h"
|
||||
#include "lib/utility/ob_print_utils.h"
|
||||
#include "lib/utility/ob_unify_serialize.h"
|
||||
#include "lib/utility/serialization.h"
|
||||
#include "meta_programming/ob_meta_serialization.h"
|
||||
#include "common_define.h"
|
||||
namespace oceanbase {
|
||||
namespace unittest {
|
||||
struct ExampleUserKey {
|
||||
OB_UNIS_VERSION(1);
|
||||
public:
|
||||
ExampleUserKey() : value_(0) {}
|
||||
ExampleUserKey(const int val) : value_(val) {}
|
||||
TO_STRING_KV(K_(value));
|
||||
bool operator<(const ExampleUserKey &rhs) const { return value_ < rhs.value_; }
|
||||
bool operator==(const ExampleUserKey &rhs) const { return value_ == rhs.value_; }
|
||||
int64_t value_;
|
||||
};
|
||||
|
||||
OB_SERIALIZE_MEMBER_TEMP(inline, ExampleUserKey, value_);
|
||||
struct ExampleUserData1 {// simple data structure
|
||||
OB_UNIS_VERSION(1);
|
||||
public:
|
||||
bool operator==(const ExampleUserData1 &rhs) const { return value_ == rhs.value_; }
|
||||
ExampleUserData1() : value_(0) {}
|
||||
ExampleUserData1(const int val) : value_(val) {}
|
||||
TO_STRING_KV(K_(value));
|
||||
int value_;
|
||||
};
|
||||
|
||||
OB_SERIALIZE_MEMBER_TEMP(inline, ExampleUserData1, value_);
|
||||
|
||||
struct ExampleUserData2 {// complicated data structure
|
||||
public:
|
||||
ExampleUserData2() : alloc_(nullptr) {}
|
||||
~ExampleUserData2() {
|
||||
if (OB_NOT_NULL(alloc_)) {
|
||||
if (!data_.empty()) {
|
||||
alloc_->free(data_.ptr());
|
||||
}
|
||||
}
|
||||
}
|
||||
int serialize(char *buf, const int64_t buf_len, int64_t &pos) const {
|
||||
int ret = OB_SUCCESS;
|
||||
if (OB_ISNULL(alloc_)) {
|
||||
} else if (OB_FAIL(serialization::encode(buf, buf_len, pos, (int64_t)data_.length()))) {
|
||||
} else {
|
||||
for (int64_t idx = 0; idx < data_.length() && OB_SUCC(ret); ++idx) {
|
||||
ret = serialization::encode(buf, buf_len, pos, data_.ptr()[idx]);
|
||||
}
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
int deserialize(ObIAllocator &alloc, const char *buf, const int64_t buf_len, int64_t &pos) {
|
||||
int ret = OB_SUCCESS;
|
||||
int64_t length = 0;
|
||||
char *buffer = nullptr;
|
||||
if (OB_FAIL(serialization::decode(buf, buf_len, pos, length))) {
|
||||
} else if (OB_ISNULL(buffer = (char *)alloc.alloc(length))) {
|
||||
ret = OB_ALLOCATE_MEMORY_FAILED;
|
||||
} else {
|
||||
for (int64_t idx = 0; idx < length && OB_SUCC(ret); ++idx) {
|
||||
ret = serialization::decode(buf, buf_len, pos, buffer[idx]);
|
||||
}
|
||||
if (OB_SUCC(ret)) {
|
||||
data_.assign(buffer, length);
|
||||
alloc_ = &alloc;
|
||||
}
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
int64_t get_serialize_size() const {
|
||||
int64_t total_size = 0;
|
||||
total_size += serialization::encoded_length((int64_t)data_.length());
|
||||
for (int64_t idx = 0; idx < data_.length(); ++idx) {
|
||||
total_size += serialization::encoded_length(data_.ptr()[idx]);
|
||||
}
|
||||
return total_size;
|
||||
}
|
||||
int assign(ObIAllocator &alloc, const char *str) {
|
||||
int ret = OB_SUCCESS;
|
||||
OB_ASSERT(OB_ISNULL(alloc_) && data_.empty());
|
||||
int64_t len = strlen(str);
|
||||
char *buffer = nullptr;
|
||||
if (OB_ISNULL(buffer = (char *)alloc.alloc(len))) {
|
||||
ret = OB_ALLOCATE_MEMORY_FAILED;
|
||||
} else {
|
||||
memcpy(buffer, str, len);
|
||||
alloc_ = &alloc;
|
||||
data_.assign(buffer, len);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
int assign(ObIAllocator &alloc, const ExampleUserData2 &rhs) {
|
||||
int ret = OB_SUCCESS;
|
||||
if (OB_NOT_NULL(rhs.alloc_)) {
|
||||
OB_ASSERT(OB_ISNULL(alloc_) && data_.empty());
|
||||
int64_t len = rhs.data_.length();
|
||||
char *buffer = nullptr;
|
||||
if (OB_ISNULL(buffer = (char *)alloc.alloc(len))) {
|
||||
ret = OB_ALLOCATE_MEMORY_FAILED;
|
||||
} else {
|
||||
memcpy(buffer, rhs.data_.ptr(), len);
|
||||
alloc_ = &alloc;
|
||||
data_.assign(buffer, len);
|
||||
}
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
// support move semantic
|
||||
ExampleUserData2(ExampleUserData2 &&rhs) {
|
||||
if (OB_NOT_NULL(rhs.alloc_)) {
|
||||
data_ = rhs.data_;
|
||||
alloc_ = rhs.alloc_;
|
||||
rhs.alloc_ = nullptr;
|
||||
rhs.data_.reset();
|
||||
MDS_LOG(INFO, "call move construction", K(*this));
|
||||
}
|
||||
}
|
||||
TO_STRING_KV(KP(data_.ptr()), K(data_.length()));
|
||||
ObIAllocator *alloc_;
|
||||
ObString data_;
|
||||
};
|
||||
|
||||
}
|
||||
}
|
||||
#endif
|
||||
@ -0,0 +1,123 @@
|
||||
#ifdef TEST_MDS_TRANSACTION
|
||||
#include "example_user_helper_define.h"
|
||||
#include "storage/multi_data_source/mds_table_handle.h"
|
||||
namespace oceanbase {
|
||||
namespace unittest {
|
||||
|
||||
using namespace storage;
|
||||
using namespace mds;
|
||||
|
||||
MdsTableHandle TestMdsTable;
|
||||
|
||||
const storage::mds::MdsWriter ExampleUserHelperCtx::get_writer() const
|
||||
{
|
||||
return storage::mds::MdsWriter(transaction::ObTransID(0));
|
||||
}
|
||||
|
||||
int ExampleUserHelperFunction1::on_register(const char* buf,
|
||||
const int64_t len,
|
||||
storage::mds::BufferCtx &ctx)
|
||||
{
|
||||
int ret = OB_SUCCESS;
|
||||
int64_t test_value;
|
||||
int64_t pos = 0;
|
||||
if (OB_FAIL(serialization::decode(buf, len, pos, test_value))) {
|
||||
MDS_LOG(ERROR, "[UNITTEST] ExampleUserHelperFunction1 fail to deserialize", KR(ret));
|
||||
} else {
|
||||
MDS_LOG(INFO, "[UNITTEST] ExampleUserHelperFunction1 call on_register with helper", K(test_value));
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
int ExampleUserHelperFunction1::on_replay(const char* buf,
|
||||
const int64_t len,
|
||||
const share::SCN &scn, // 日志scn
|
||||
storage::mds::BufferCtx &ctx)
|
||||
{
|
||||
UNUSED(scn);
|
||||
return on_register(buf, len, ctx);
|
||||
}
|
||||
|
||||
int ExampleUserHelperFunction2::on_register(const char* buf,
|
||||
const int64_t len,
|
||||
storage::mds::BufferCtx &ctx)
|
||||
{
|
||||
int ret = OB_SUCCESS;
|
||||
int64_t test_value;
|
||||
int64_t pos = 0;
|
||||
if (OB_FAIL(serialization::decode(buf, len, pos, test_value))) {
|
||||
MDS_LOG(ERROR, "[UNITTEST] ExampleUserHelperFunction2 fail to deserialize", KR(ret));
|
||||
} else {
|
||||
ExampleUserData1 data(test_value);
|
||||
MdsCtx &mds_ctx = dynamic_cast<MdsCtx &>(ctx);
|
||||
if (OB_FAIL(TestMdsTable.set(data, mds_ctx))) {
|
||||
MDS_LOG(ERROR, "[UNITTEST] ExampleUserHelperFunction2 fail to set mdstable", KR(ret));
|
||||
} else {
|
||||
MDS_LOG(INFO, "[UNITTEST] ExampleUserHelperFunction2 call on_register with helper", K(test_value));
|
||||
}
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
int ExampleUserHelperFunction2::on_replay(const char* buf,
|
||||
const int64_t len,
|
||||
const share::SCN &scn, // 日志scn
|
||||
storage::mds::BufferCtx &ctx)
|
||||
{
|
||||
UNUSED(scn);
|
||||
return on_register(buf, len, ctx);
|
||||
}
|
||||
|
||||
int ExampleUserHelperFunction3::on_register(const char* buf,
|
||||
const int64_t len,
|
||||
storage::mds::BufferCtx &ctx)
|
||||
{
|
||||
int ret = OB_SUCCESS;
|
||||
int64_t test_value;
|
||||
int64_t pos = 0;
|
||||
if (OB_FAIL(serialization::decode(buf, len, pos, test_value))) {
|
||||
MDS_LOG(ERROR, "[UNITTEST] ExampleUserHelperFunction3 fail to deserialize", KR(ret));
|
||||
} else {
|
||||
MDS_LOG(INFO, "[UNITTEST] ExampleUserHelperFunction3 call on_register with helper", K(test_value));
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
int ExampleUserHelperFunction3::on_replay(const char* buf,
|
||||
const int64_t len,
|
||||
const share::SCN &scn, // 日志scn
|
||||
storage::mds::BufferCtx &ctx)
|
||||
{
|
||||
UNUSED(scn);
|
||||
return on_register(buf, len, ctx);
|
||||
}
|
||||
|
||||
void ExampleUserHelperCtx::on_redo(const share::SCN &)
|
||||
{
|
||||
MDS_LOG(INFO, "[UNITTEST] call on_redo with ctx", K(++call_times_));
|
||||
}
|
||||
|
||||
void ExampleUserHelperCtx::before_prepare()
|
||||
{
|
||||
MDS_LOG(INFO, "[UNITTEST] call before_prepare with ctx", K(++call_times_));
|
||||
}
|
||||
|
||||
void ExampleUserHelperCtx::on_prepare(const share::SCN &prepare_version)
|
||||
{
|
||||
MDS_LOG(INFO, "[UNITTEST] call on_prepare with ctx", K(++call_times_));
|
||||
}
|
||||
|
||||
void ExampleUserHelperCtx::on_commit(const share::SCN &commit_version, const share::SCN &)
|
||||
{
|
||||
MDS_LOG(INFO, "[UNITTEST] call on_commit with ctx", K(++call_times_));
|
||||
}
|
||||
|
||||
void ExampleUserHelperCtx::on_abort(const share::SCN &end_scn)
|
||||
{
|
||||
MDS_LOG(INFO, "[UNITTEST] call on_abort with ctx", K(++call_times_), K(end_scn));
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
#endif
|
||||
151
unittest/storage/multi_data_source/example_user_helper_define.h
Normal file
151
unittest/storage/multi_data_source/example_user_helper_define.h
Normal file
@ -0,0 +1,151 @@
|
||||
#ifndef UNITTEST_SHARE_MULTI_DATA_SOURCE_EXAMPLE_USER_HELPER_DEFINE_H
|
||||
#define UNITTEST_SHARE_MULTI_DATA_SOURCE_EXAMPLE_USER_HELPER_DEFINE_H
|
||||
#include "storage/multi_data_source/buffer_ctx.h"
|
||||
#include "lib/oblog/ob_log_module.h"
|
||||
#include "lib/utility/serialization.h"
|
||||
#include "share/scn.h"
|
||||
#include "storage/multi_data_source/runtime_utility/common_define.h"
|
||||
|
||||
namespace oceanbase {
|
||||
namespace unittest {
|
||||
|
||||
struct ExampleUserHelperFunction1 {
|
||||
static int on_register(const char* buf,
|
||||
const int64_t len,
|
||||
storage::mds::BufferCtx &ctx); // 出参,将对应修改记录在Ctx中
|
||||
|
||||
static int on_replay(const char* buf,
|
||||
const int64_t len,
|
||||
const share::SCN &scn, // 日志scn
|
||||
storage::mds::BufferCtx &ctx); // 备机回放
|
||||
};
|
||||
|
||||
struct ExampleUserHelperFunction2 {
|
||||
static int on_register(const char* buf,
|
||||
const int64_t len,
|
||||
storage::mds::BufferCtx &ctx); // 出参,将对应修改记录在Ctx中
|
||||
|
||||
static int on_replay(const char* buf,
|
||||
const int64_t len,
|
||||
const share::SCN &scn, // 日志scn
|
||||
storage::mds::BufferCtx &ctx); // 备机回放
|
||||
};
|
||||
|
||||
struct ExampleUserHelperFunction3 {
|
||||
static int on_register(const char* buf,
|
||||
const int64_t len,
|
||||
storage::mds::BufferCtx &ctx); // 出参,将对应修改记录在Ctx中
|
||||
|
||||
static int on_replay(const char* buf,
|
||||
const int64_t len,
|
||||
const share::SCN &scn, // 日志scn
|
||||
storage::mds::BufferCtx &ctx); // 备机回放
|
||||
};
|
||||
|
||||
struct ExampleUserHelperCtx : public storage::mds::BufferCtx {
|
||||
ExampleUserHelperCtx() : call_times_(0) {}
|
||||
virtual const storage::mds::MdsWriter get_writer() const override;
|
||||
virtual void on_redo(const share::SCN &redo_scn) override;
|
||||
virtual void before_prepare() override;
|
||||
virtual void on_prepare(const share::SCN &prepare_version) override;
|
||||
virtual void on_commit(const share::SCN &commit_version, const share::SCN &scn) override;
|
||||
virtual void on_abort(const share::SCN &scn) override;
|
||||
int assign(const ExampleUserHelperCtx &rhs) {
|
||||
call_times_ = rhs.call_times_;
|
||||
return OB_SUCCESS;
|
||||
}
|
||||
int call_times_;// 这个类可以有自己的内部状态
|
||||
virtual int64_t to_string(char*, const int64_t buf_len) const { return 0; }
|
||||
// 同事务状态一起持久化以及恢复
|
||||
virtual int serialize(char*, const int64_t, int64_t&) const { return OB_SUCCESS; }
|
||||
virtual int deserialize(const char*, const int64_t, int64_t&) { return OB_SUCCESS; }
|
||||
virtual int64_t get_serialize_size(void) const { return 0; }
|
||||
};
|
||||
|
||||
#ifndef TEST_MDS_TRANSACTION
|
||||
|
||||
inline int ExampleUserHelperFunction1::on_register(const char* buf,
|
||||
const int64_t len,
|
||||
storage::mds::BufferCtx &ctx)
|
||||
{
|
||||
int ret = OB_SUCCESS;
|
||||
return ret;
|
||||
}
|
||||
|
||||
inline int ExampleUserHelperFunction1::on_replay(const char* buf,
|
||||
const int64_t len,
|
||||
const share::SCN &scn, // 日志scn
|
||||
storage::mds::BufferCtx &ctx)
|
||||
{
|
||||
int ret = OB_SUCCESS;
|
||||
return ret;
|
||||
}
|
||||
|
||||
inline int ExampleUserHelperFunction2::on_register(const char*,
|
||||
const int64_t,
|
||||
storage::mds::BufferCtx &)
|
||||
{
|
||||
int ret = OB_SUCCESS;
|
||||
return ret;
|
||||
}
|
||||
|
||||
inline int ExampleUserHelperFunction2::on_replay(const char*,
|
||||
const int64_t,
|
||||
const share::SCN &, // 日志scn
|
||||
storage::mds::BufferCtx &)
|
||||
{
|
||||
int ret = OB_SUCCESS;
|
||||
return ret;
|
||||
}
|
||||
|
||||
inline int ExampleUserHelperFunction3::on_register(const char*,
|
||||
const int64_t,
|
||||
storage::mds::BufferCtx &)
|
||||
{
|
||||
int ret = OB_SUCCESS;
|
||||
return ret;
|
||||
}
|
||||
|
||||
inline int ExampleUserHelperFunction3::on_replay(const char* buf,
|
||||
const int64_t len,
|
||||
const share::SCN &scn, // 日志scn
|
||||
storage::mds::BufferCtx &ctx)
|
||||
{
|
||||
UNUSED(scn);
|
||||
return on_register(buf, len, ctx);
|
||||
}
|
||||
|
||||
inline const storage::mds::MdsWriter ExampleUserHelperCtx::get_writer() const
|
||||
{
|
||||
return storage::mds::MdsWriter(storage::mds::WriterType::TRANSACTION, 1);
|
||||
}
|
||||
|
||||
inline void ExampleUserHelperCtx::on_redo(const share::SCN &redo_scn)
|
||||
{
|
||||
MDS_LOG(INFO, "[UNITTEST] call on_redo with ctx", K(++call_times_));
|
||||
}
|
||||
|
||||
inline void ExampleUserHelperCtx::before_prepare()
|
||||
{
|
||||
MDS_LOG(INFO, "[UNITTEST] call before_prepare with ctx", K(++call_times_));
|
||||
}
|
||||
|
||||
inline void ExampleUserHelperCtx::on_prepare(const share::SCN &prepare_version)
|
||||
{
|
||||
MDS_LOG(INFO, "[UNITTEST] call on_prepare with ctx", K(++call_times_));
|
||||
}
|
||||
|
||||
inline void ExampleUserHelperCtx::on_commit(const share::SCN &commit_version, const share::SCN &scn)
|
||||
{
|
||||
MDS_LOG(INFO, "[UNITTEST] call on_commit with ctx", K(++call_times_));
|
||||
}
|
||||
|
||||
inline void ExampleUserHelperCtx::on_abort(const share::SCN &scn)
|
||||
{
|
||||
MDS_LOG(INFO, "[UNITTEST] call on_abort with ctx", K(++call_times_));
|
||||
}
|
||||
#endif
|
||||
|
||||
}
|
||||
}
|
||||
#endif
|
||||
58
unittest/storage/multi_data_source/test_mds_compile.cpp
Normal file
58
unittest/storage/multi_data_source/test_mds_compile.cpp
Normal file
@ -0,0 +1,58 @@
|
||||
/**
|
||||
* 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 UNITTEST_DEBUG
|
||||
#include <gtest/gtest.h>
|
||||
#include <thread>
|
||||
#include <iostream>
|
||||
#include <vector>
|
||||
#include <chrono>
|
||||
#include "common/ob_clock_generator.h"
|
||||
#include "storage/multi_data_source/mds_table_handle.h"
|
||||
#include "storage/multi_data_source/compile_utility/compile_mapper.h"
|
||||
namespace oceanbase {
|
||||
namespace unittest {
|
||||
|
||||
using namespace common;
|
||||
using namespace std;
|
||||
|
||||
class TestMdsCompile: public ::testing::Test
|
||||
{
|
||||
public:
|
||||
TestMdsCompile() {};
|
||||
virtual ~TestMdsCompile() {};
|
||||
virtual void SetUp() {
|
||||
};
|
||||
virtual void TearDown() {
|
||||
};
|
||||
private:
|
||||
// disallow copy
|
||||
DISALLOW_COPY_AND_ASSIGN(TestMdsCompile);
|
||||
};
|
||||
|
||||
TEST_F(TestMdsCompile, basic) {
|
||||
ObTuple<int, double, char> tuple_;
|
||||
tuple_.element<int>() = 1;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
system("rm -rf test_ob_occam_timer.log");
|
||||
oceanbase::common::ObLogger &logger = oceanbase::common::ObLogger::get_logger();
|
||||
logger.set_file_name("test_ob_occam_timer.log", false);
|
||||
logger.set_log_level(OB_LOG_LEVEL_DEBUG);
|
||||
testing::InitGoogleTest(&argc, argv);
|
||||
return RUN_ALL_TESTS();
|
||||
}
|
||||
153
unittest/storage/multi_data_source/test_mds_dump_kv.cpp
Normal file
153
unittest/storage/multi_data_source/test_mds_dump_kv.cpp
Normal file
@ -0,0 +1,153 @@
|
||||
/**
|
||||
* 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 "share/ob_ls_id.h"
|
||||
#define UNITTEST_DEBUG
|
||||
#include <gtest/gtest.h>
|
||||
#define private public
|
||||
#define protected public
|
||||
#include "storage/multi_data_source/compile_utility/mds_dummy_key.h"
|
||||
#include "storage/multi_data_source/compile_utility/map_type_index_in_tuple.h"
|
||||
#include "common_define.h"
|
||||
#include "storage/multi_data_source/adapter_define/mds_dump_node.h"
|
||||
#include <thread>
|
||||
#include <iostream>
|
||||
#include <vector>
|
||||
#include <chrono>
|
||||
#include "storage/multi_data_source/runtime_utility/mds_factory.h"
|
||||
#include "common/ob_clock_generator.h"
|
||||
#include "storage/multi_data_source/mds_node.h"
|
||||
#include "example_user_helper_define.cpp"
|
||||
#include "storage/multi_data_source/mds_table_handle.h"
|
||||
#include "storage/tablet/ob_tablet_meta.h"
|
||||
namespace oceanbase {
|
||||
namespace storage
|
||||
{
|
||||
namespace mds
|
||||
{
|
||||
void *MdsAllocator::alloc(const int64_t size)
|
||||
{
|
||||
void *ptr = ob_malloc(size, "MDS");
|
||||
ATOMIC_INC(&alloc_times_);
|
||||
MDS_LOG(DEBUG, "alloc obj", KP(ptr), K(size), K(lbt()));
|
||||
return ptr;
|
||||
}
|
||||
void MdsAllocator::free(void *ptr) {
|
||||
ATOMIC_INC(&free_times_);
|
||||
MDS_LOG(DEBUG, "free obj", KP(ptr), K(lbt()));
|
||||
ob_free(ptr);
|
||||
}
|
||||
}
|
||||
}
|
||||
namespace unittest {
|
||||
|
||||
using namespace common;
|
||||
using namespace std;
|
||||
using namespace storage;
|
||||
using namespace mds;
|
||||
|
||||
class TestMdsDumpKV: public ::testing::Test
|
||||
{
|
||||
public:
|
||||
TestMdsDumpKV() {};
|
||||
virtual ~TestMdsDumpKV() {};
|
||||
virtual void SetUp() {
|
||||
};
|
||||
virtual void TearDown() {
|
||||
};
|
||||
static void test_dump_node_convert_and_serialize_and_compare();
|
||||
static void test_dump_dummy_key();
|
||||
private:
|
||||
// disallow copy
|
||||
DISALLOW_COPY_AND_ASSIGN(TestMdsDumpKV);
|
||||
};
|
||||
|
||||
void TestMdsDumpKV::test_dump_node_convert_and_serialize_and_compare()
|
||||
{
|
||||
ExampleUserData2 first_data;
|
||||
ASSERT_EQ(OB_SUCCESS, first_data.assign(MdsAllocator::get_instance(), "123"));
|
||||
UserMdsNode<DummyKey, ExampleUserData2> user_mds_node(nullptr, MdsNodeType::SET, WriterType::TRANSACTION, 1);
|
||||
ASSERT_EQ(OB_SUCCESS, meta::move_or_copy_or_assign(first_data, user_mds_node.user_data_, MdsAllocator::get_instance()));
|
||||
ASSERT_EQ(true, first_data.data_.ptr() != user_mds_node.user_data_.data_.ptr());
|
||||
ASSERT_EQ(0, memcmp(first_data.data_.ptr(), user_mds_node.user_data_.data_.ptr(), first_data.data_.length()));
|
||||
user_mds_node.try_on_redo(mock_scn(10));
|
||||
user_mds_node.try_before_prepare();
|
||||
user_mds_node.try_on_prepare(mock_scn(11));
|
||||
user_mds_node.try_on_commit(mock_scn(11), mock_scn(11));
|
||||
MdsDumpNode dump_node;
|
||||
ASSERT_EQ(OB_SUCCESS, dump_node.init(GET_MDS_TABLE_ID<NormalMdsTable>::value, GET_MDS_UNIT_ID<UnitTestMdsTable, DummyKey, ExampleUserData2>::value, user_mds_node, mds::MdsAllocator::get_instance()));
|
||||
constexpr int buf_len = 1024;
|
||||
char buffer[buf_len] = {0};
|
||||
int64_t pos = 0;
|
||||
ASSERT_EQ(OB_SUCCESS, dump_node.serialize(buffer, buf_len, pos));
|
||||
MdsDumpNode dump_node2;
|
||||
pos = 0;
|
||||
|
||||
ObArenaAllocator allocator;
|
||||
ASSERT_EQ(OB_SUCCESS, dump_node2.deserialize(allocator, buffer, buf_len, pos));
|
||||
OB_ASSERT(dump_node2.crc_check_number_ == dump_node2.generate_hash());
|
||||
ASSERT_EQ(dump_node2.generate_hash(), dump_node2.crc_check_number_);
|
||||
ASSERT_EQ(dump_node2.crc_check_number_, dump_node.crc_check_number_);
|
||||
UserMdsNode<DummyKey, ExampleUserData2> user_mds_node2;
|
||||
ASSERT_EQ(OB_SUCCESS, dump_node2.convert_to_user_mds_node(user_mds_node2, share::ObLSID(1), ObTabletID(1)));
|
||||
ASSERT_EQ(0, memcmp(user_mds_node.user_data_.data_.ptr(), user_mds_node2.user_data_.data_.ptr(), user_mds_node.user_data_.data_.length()));
|
||||
ASSERT_EQ(user_mds_node.redo_scn_, user_mds_node2.redo_scn_);
|
||||
ASSERT_EQ(user_mds_node.end_scn_, user_mds_node2.end_scn_);
|
||||
ASSERT_EQ(user_mds_node.trans_version_, user_mds_node2.trans_version_);
|
||||
ASSERT_EQ(user_mds_node.status_.union_.value_, user_mds_node2.status_.union_.value_);
|
||||
ASSERT_EQ(user_mds_node.seq_no_, user_mds_node2.seq_no_);
|
||||
}
|
||||
|
||||
void TestMdsDumpKV::test_dump_dummy_key()
|
||||
{
|
||||
DummyKey key;
|
||||
MdsDumpKey dump_key1, dump_key2;
|
||||
dump_key1.init(0, 0, key, MdsAllocator::get_instance());
|
||||
constexpr int buf_len = 1024;
|
||||
char buffer[buf_len] = {0};
|
||||
int64_t pos = 0;
|
||||
ASSERT_EQ(OB_SUCCESS, dump_key1.serialize(buffer, buf_len, pos));
|
||||
pos = 0;
|
||||
ASSERT_EQ(OB_SUCCESS, dump_key2.deserialize(buffer, buf_len, pos));
|
||||
int compare_result = 0;
|
||||
ASSERT_EQ(OB_SUCCESS, dump_key1.compare(dump_key2, compare_result));
|
||||
ASSERT_EQ(0, compare_result);
|
||||
}
|
||||
|
||||
|
||||
TEST_F(TestMdsDumpKV, test_convert_and_serialize_and_compare) { TestMdsDumpKV::test_dump_node_convert_and_serialize_and_compare(); }
|
||||
TEST_F(TestMdsDumpKV, test_dump_dummy_key) { TestMdsDumpKV::test_dump_dummy_key(); }
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
system("rm -rf test_mds_dump_kv.log");
|
||||
oceanbase::common::ObLogger &logger = oceanbase::common::ObLogger::get_logger();
|
||||
logger.set_file_name("test_mds_dump_kv.log", false);
|
||||
logger.set_log_level(OB_LOG_LEVEL_DEBUG);
|
||||
testing::InitGoogleTest(&argc, argv);
|
||||
oceanbase::observer::ObMdsEventBuffer::init();
|
||||
int ret = RUN_ALL_TESTS();
|
||||
oceanbase::observer::ObMdsEventBuffer::destroy();
|
||||
int64_t alloc_times = oceanbase::storage::mds::MdsAllocator::get_alloc_times();
|
||||
int64_t free_times = oceanbase::storage::mds::MdsAllocator::get_free_times();
|
||||
if (alloc_times != free_times) {
|
||||
MDS_LOG(ERROR, "memory may leak", K(free_times), K(alloc_times));
|
||||
ret = -1;
|
||||
} else {
|
||||
MDS_LOG(INFO, "all memory released", K(free_times), K(alloc_times));
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
206
unittest/storage/multi_data_source/test_mds_list.cpp
Normal file
206
unittest/storage/multi_data_source/test_mds_list.cpp
Normal file
@ -0,0 +1,206 @@
|
||||
/**
|
||||
* 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 UNITTEST_DEBUG
|
||||
#include "lib/utility/utility.h"
|
||||
#include <atomic>
|
||||
#include <cstdlib>
|
||||
#include <gtest/gtest.h>
|
||||
#define private public
|
||||
#define protected public
|
||||
#include "storage/multi_data_source/compile_utility/mds_dummy_key.h"
|
||||
#include "storage/multi_data_source/runtime_utility/common_define.h"
|
||||
#include <thread>
|
||||
#include <iostream>
|
||||
#include <vector>
|
||||
#include <chrono>
|
||||
#include "storage/multi_data_source/runtime_utility/mds_factory.h"
|
||||
#include "common/ob_clock_generator.h"
|
||||
#include "storage/multi_data_source/mds_node.h"
|
||||
#include "example_user_helper_define.cpp"
|
||||
#include "common/meta_programming/ob_type_traits.h"
|
||||
#include "storage/multi_data_source/mds_row.h"
|
||||
namespace oceanbase {
|
||||
namespace storage
|
||||
{
|
||||
namespace mds
|
||||
{
|
||||
void *MdsAllocator::alloc(const int64_t size)
|
||||
{
|
||||
void *ptr = ob_malloc(size, "MDS");
|
||||
ATOMIC_INC(&alloc_times_);
|
||||
MDS_LOG(DEBUG, "alloc obj", KP(ptr), K(size), K(lbt()));
|
||||
return ptr;
|
||||
}
|
||||
void MdsAllocator::free(void *ptr) {
|
||||
ATOMIC_INC(&free_times_);
|
||||
MDS_LOG(DEBUG, "free obj", KP(ptr), K(lbt()));
|
||||
ob_free(ptr);
|
||||
}
|
||||
}
|
||||
}
|
||||
namespace unittest {
|
||||
|
||||
using namespace common;
|
||||
using namespace std;
|
||||
using namespace storage;
|
||||
using namespace mds;
|
||||
|
||||
class TestMdsList: public ::testing::Test
|
||||
{
|
||||
public:
|
||||
TestMdsList() {};
|
||||
virtual ~TestMdsList() {};
|
||||
virtual void SetUp() {
|
||||
};
|
||||
virtual void TearDown() {
|
||||
};
|
||||
private:
|
||||
// disallow copy
|
||||
DISALLOW_COPY_AND_ASSIGN(TestMdsList);
|
||||
};
|
||||
|
||||
TEST_F(TestMdsList, del_from_tail) {
|
||||
SortedList<UserMdsNode<DummyKey, ExampleUserData1>, SORT_TYPE::DESC> list;
|
||||
for (int i = 0; i < 10; ++i) {
|
||||
ListNode<UserMdsNode<DummyKey, ExampleUserData1>> *new_node = new UserMdsNode<DummyKey, ExampleUserData1>();
|
||||
list.append(new_node);
|
||||
}
|
||||
list.for_each_node_from_tail_to_head_until_true([&list](const UserMdsNode<DummyKey, ExampleUserData1> &node) {
|
||||
list.del((ListNode<UserMdsNode<DummyKey, ExampleUserData1>> *)(&node));
|
||||
delete &node;
|
||||
return false;
|
||||
});
|
||||
ASSERT_EQ(list.empty(), true);
|
||||
}
|
||||
|
||||
TEST_F(TestMdsList, del_from_head) {
|
||||
SortedList<UserMdsNode<DummyKey, ExampleUserData1>, SORT_TYPE::DESC> list;
|
||||
for (int i = 0; i < 10; ++i) {
|
||||
ListNode<UserMdsNode<DummyKey, ExampleUserData1>> *new_node = new UserMdsNode<DummyKey, ExampleUserData1>();
|
||||
list.append(new_node);
|
||||
}
|
||||
list.for_each_node_from_head_to_tail_until_true([&list](const UserMdsNode<DummyKey, ExampleUserData1> &node) {
|
||||
list.del((ListNode<UserMdsNode<DummyKey, ExampleUserData1>> *)(&node));
|
||||
delete &node;
|
||||
return false;
|
||||
});
|
||||
ASSERT_EQ(list.empty(), true);
|
||||
}
|
||||
|
||||
TEST_F(TestMdsList, random_del) {
|
||||
for (int i = 0; i < 100; ++i) {
|
||||
SortedList<UserMdsNode<DummyKey, ExampleUserData1>, SORT_TYPE::DESC> list;
|
||||
vector<ListNode<UserMdsNode<DummyKey, ExampleUserData1>> *> v;
|
||||
for (int j = 0; j < 10; ++j) {
|
||||
ListNode<UserMdsNode<DummyKey, ExampleUserData1>> *new_node = new UserMdsNode<DummyKey, ExampleUserData1>();
|
||||
list.append(new_node);
|
||||
v.push_back(new_node);
|
||||
}
|
||||
int idx = rand() % 10;
|
||||
for (int k = 0; k < 10; ++k) {
|
||||
list.del(v[(idx + k) % 10]);
|
||||
}
|
||||
ASSERT_EQ(list.empty(), true);
|
||||
}
|
||||
}
|
||||
|
||||
TEST_F(TestMdsList, insert_to_tail) {
|
||||
SortedList<UserMdsNode<DummyKey, ExampleUserData1>, SORT_TYPE::DESC> list;
|
||||
for (int j = 0; j < 10; ++j) {
|
||||
UserMdsNode<DummyKey, ExampleUserData1> *new_node = new UserMdsNode<DummyKey, ExampleUserData1>();
|
||||
new_node->redo_scn_ = mock_scn(j);
|
||||
list.insert(new_node);
|
||||
}
|
||||
list.for_each_node_from_head_to_tail_until_true([&list](const UserMdsNode<DummyKey, ExampleUserData1> &node) {
|
||||
list.del((ListNode<UserMdsNode<DummyKey, ExampleUserData1>> *)(&node));
|
||||
delete &node;
|
||||
return false;
|
||||
});
|
||||
}
|
||||
|
||||
TEST_F(TestMdsList, insert_to_head) {
|
||||
SortedList<UserMdsNode<DummyKey, ExampleUserData1>, SORT_TYPE::DESC> list;
|
||||
for (int j = 0; j < 10; ++j) {
|
||||
UserMdsNode<DummyKey, ExampleUserData1> *new_node = new UserMdsNode<DummyKey, ExampleUserData1>();
|
||||
new_node->redo_scn_ = mock_scn(10 - j);
|
||||
list.insert(new_node);
|
||||
}
|
||||
list.for_each_node_from_head_to_tail_until_true([&list](const UserMdsNode<DummyKey, ExampleUserData1> &node) {
|
||||
list.del((ListNode<UserMdsNode<DummyKey, ExampleUserData1>> *)(&node));
|
||||
delete &node;
|
||||
return false;
|
||||
});
|
||||
}
|
||||
|
||||
TEST_F(TestMdsList, random_insert_del) {
|
||||
for (int i = 0; i < 100; ++i) {
|
||||
SortedList<UserMdsNode<DummyKey, ExampleUserData1>, SORT_TYPE::DESC> list;
|
||||
vector<ListNode<UserMdsNode<DummyKey, ExampleUserData1>> *> v;
|
||||
for (int j = 0; j < 10; ++j) {
|
||||
UserMdsNode<DummyKey, ExampleUserData1> *new_node = new UserMdsNode<DummyKey, ExampleUserData1>();
|
||||
new_node->redo_scn_ = mock_scn(rand() % 10);
|
||||
list.insert(new_node);
|
||||
v.push_back(new_node);
|
||||
}
|
||||
int idx = rand() % 10;
|
||||
for (int k = 0; k < 10; ++k) {
|
||||
list.del(v[(idx + k) % 10]);
|
||||
}
|
||||
ASSERT_EQ(list.empty(), true);
|
||||
}
|
||||
}
|
||||
|
||||
TEST_F(TestMdsList, fetch_and_insert) {
|
||||
SortedList<UserMdsNode<DummyKey, ExampleUserData1>, SORT_TYPE::DESC> list;
|
||||
UserMdsNode<DummyKey, ExampleUserData1> *new_node = new UserMdsNode<DummyKey, ExampleUserData1>();
|
||||
UserMdsNode<DummyKey, ExampleUserData1> *new_node2 = new UserMdsNode<DummyKey, ExampleUserData1>();
|
||||
list.insert_into_head(new_node);
|
||||
ListNode<UserMdsNode<DummyKey, ExampleUserData1>> *node = list.fetch_from_head();
|
||||
ASSERT_NE(nullptr, node);
|
||||
ASSERT_EQ(true, list.empty());
|
||||
list.insert_into_head(new_node);
|
||||
node = list.fetch_from_head();
|
||||
ASSERT_NE(nullptr, node);
|
||||
ASSERT_EQ(true, list.empty());
|
||||
list.insert_into_head(new_node);
|
||||
list.insert_into_head(new_node2);
|
||||
node = list.fetch_from_head();
|
||||
ASSERT_EQ(new_node2, node);
|
||||
ASSERT_EQ(false, list.empty());
|
||||
list.insert_into_head(new_node2);
|
||||
node = list.fetch_from_head();
|
||||
ASSERT_EQ(new_node2, node);
|
||||
delete new_node;
|
||||
delete new_node2;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
system("rm -rf test_mds_list.log");
|
||||
oceanbase::common::ObLogger &logger = oceanbase::common::ObLogger::get_logger();
|
||||
logger.set_file_name("test_mds_list.log", false);
|
||||
logger.set_log_level(OB_LOG_LEVEL_DEBUG);
|
||||
testing::InitGoogleTest(&argc, argv);
|
||||
int ret = RUN_ALL_TESTS();
|
||||
int64_t alloc_times = oceanbase::storage::mds::MdsAllocator::get_alloc_times();
|
||||
int64_t free_times = oceanbase::storage::mds::MdsAllocator::get_free_times();
|
||||
if (alloc_times != free_times) {
|
||||
MDS_LOG(ERROR, "memory may leak", K(free_times), K(alloc_times));
|
||||
ret = -1;
|
||||
} else {
|
||||
MDS_LOG(INFO, "all memory released", K(free_times), K(alloc_times));
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
237
unittest/storage/multi_data_source/test_mds_node.cpp
Normal file
237
unittest/storage/multi_data_source/test_mds_node.cpp
Normal file
@ -0,0 +1,237 @@
|
||||
/**
|
||||
* 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 UNITTEST_DEBUG
|
||||
#include "lib/utility/utility.h"
|
||||
#include <atomic>
|
||||
#include <gtest/gtest.h>
|
||||
#define private public
|
||||
#define protected public
|
||||
#include "storage/multi_data_source/compile_utility/mds_dummy_key.h"
|
||||
#include "storage/multi_data_source/runtime_utility/common_define.h"
|
||||
|
||||
#include <thread>
|
||||
#include <iostream>
|
||||
#include <vector>
|
||||
#include <chrono>
|
||||
#include "storage/multi_data_source/runtime_utility/mds_factory.h"
|
||||
#include "common/ob_clock_generator.h"
|
||||
#include "storage/multi_data_source/mds_node.h"
|
||||
#include "example_user_helper_define.cpp"
|
||||
#include "common/meta_programming/ob_type_traits.h"
|
||||
#include "storage/multi_data_source/mds_row.h"
|
||||
namespace oceanbase {
|
||||
namespace storage
|
||||
{
|
||||
namespace mds
|
||||
{
|
||||
void *MdsAllocator::alloc(const int64_t size)
|
||||
{
|
||||
void *ptr = ob_malloc(size, "MDS");
|
||||
ATOMIC_INC(&alloc_times_);
|
||||
MDS_LOG(DEBUG, "alloc obj", KP(ptr), K(size), K(lbt()));
|
||||
return ptr;
|
||||
}
|
||||
void MdsAllocator::free(void *ptr) {
|
||||
ATOMIC_INC(&free_times_);
|
||||
MDS_LOG(DEBUG, "free obj", KP(ptr), K(lbt()));
|
||||
ob_free(ptr);
|
||||
}
|
||||
}
|
||||
}
|
||||
namespace unittest {
|
||||
|
||||
using namespace common;
|
||||
using namespace std;
|
||||
using namespace storage;
|
||||
using namespace mds;
|
||||
|
||||
class TestMdsNode: public ::testing::Test
|
||||
{
|
||||
public:
|
||||
TestMdsNode() {};
|
||||
virtual ~TestMdsNode() {};
|
||||
virtual void SetUp() {
|
||||
};
|
||||
virtual void TearDown() {
|
||||
};
|
||||
private:
|
||||
// disallow copy
|
||||
DISALLOW_COPY_AND_ASSIGN(TestMdsNode);
|
||||
};
|
||||
|
||||
std::atomic_int call_on_set(0);
|
||||
std::atomic_int call_try_on_redo(0);
|
||||
std::atomic_int call_try_on_commit(0);
|
||||
std::atomic_int call_try_on_abort(0);
|
||||
|
||||
struct UserDataWithCallBack
|
||||
{
|
||||
UserDataWithCallBack() : val_(-1) {}
|
||||
UserDataWithCallBack(int val) : val_(val) {}
|
||||
void on_set() {
|
||||
static_assert(OB_TRAIT_HAS_ON_SET(UserDataWithCallBack), "compile check on_set will not be called be MDS");
|
||||
call_on_set++;
|
||||
}
|
||||
void on_redo(share::SCN redo_scn) {
|
||||
static_assert(OB_TRAIT_HAS_ON_REDO(UserDataWithCallBack), "compile check try_on_redo will not be called be MDS");
|
||||
call_try_on_redo++;
|
||||
}
|
||||
void on_commit(share::SCN commit_version, share::SCN commit_scn) {
|
||||
static_assert(OB_TRAIT_HAS_ON_COMMIT(UserDataWithCallBack), "compile check try_on_commit will not be called be MDS");
|
||||
ob_usleep(100_ms);
|
||||
call_try_on_commit++;
|
||||
}
|
||||
void on_abort(share::SCN abort_version) {
|
||||
static_assert(OB_TRAIT_HAS_ON_ABORT(UserDataWithCallBack), "compile check try_on_abort will not be called be MDS");
|
||||
call_try_on_abort++;
|
||||
}
|
||||
TO_STRING_KV("test", val_);
|
||||
int val_;
|
||||
};
|
||||
|
||||
TEST_F(TestMdsNode, call_user_method) {
|
||||
MdsRow<DummyKey, UserDataWithCallBack> row;
|
||||
MdsCtx ctx(mds::MdsWriter(transaction::ObTransID(100)));// commit finally
|
||||
ASSERT_EQ(OB_SUCCESS, row.set(UserDataWithCallBack(1), ctx, 0));
|
||||
ctx.on_redo(mock_scn(1));
|
||||
ctx.before_prepare();
|
||||
ctx.on_prepare(mock_scn(2));
|
||||
ctx.on_commit(mock_scn(3), mock_scn(3));
|
||||
ASSERT_NE(call_on_set, 0);
|
||||
ASSERT_NE(call_try_on_redo, 0);
|
||||
ASSERT_NE(call_try_on_commit, 0);
|
||||
ASSERT_EQ(call_try_on_abort, 0);
|
||||
}
|
||||
|
||||
TEST_F(TestMdsNode, release_node_while_node_in_ctx) {
|
||||
MdsRow<DummyKey, UserDataWithCallBack> row;
|
||||
MdsCtx ctx(mds::MdsWriter(transaction::ObTransID(100)));// commit finally
|
||||
ASSERT_EQ(OB_SUCCESS, row.set(UserDataWithCallBack(1), ctx, 0));
|
||||
ctx.on_redo(mock_scn(1));
|
||||
ctx.before_prepare();
|
||||
row.~MdsRow();
|
||||
ASSERT_EQ(true, ctx.write_list_.empty());
|
||||
ctx.on_prepare(mock_scn(2));
|
||||
ctx.on_commit(mock_scn(3), mock_scn(3));
|
||||
}
|
||||
|
||||
TEST_F(TestMdsNode, release_node_while_node_in_ctx_concurrent) {
|
||||
call_on_set = 0;
|
||||
call_try_on_redo = 0;
|
||||
call_try_on_commit = 0;
|
||||
call_try_on_abort = 0;
|
||||
MdsRow<DummyKey, UserDataWithCallBack> row;
|
||||
MdsCtx ctx(mds::MdsWriter(transaction::ObTransID(100)));// commit finally
|
||||
// 提交这些node将会耗时50ms
|
||||
ASSERT_EQ(OB_SUCCESS, row.set(UserDataWithCallBack(1), ctx, 0));
|
||||
ASSERT_EQ(OB_SUCCESS, row.set(UserDataWithCallBack(2), ctx, 0));
|
||||
ASSERT_EQ(OB_SUCCESS, row.set(UserDataWithCallBack(3), ctx, 0));
|
||||
ASSERT_EQ(OB_SUCCESS, row.set(UserDataWithCallBack(4), ctx, 0));
|
||||
ASSERT_EQ(OB_SUCCESS, row.set(UserDataWithCallBack(5), ctx, 0));
|
||||
|
||||
std::thread t1([&ctx]() {
|
||||
OCCAM_LOG(DEBUG, "t1 start");
|
||||
ctx.on_redo(mock_scn(1));
|
||||
ctx.before_prepare();
|
||||
ctx.on_prepare(mock_scn(2));
|
||||
ctx.on_commit(mock_scn(3), mock_scn(3));// will cost 500ms
|
||||
});
|
||||
std::thread t2([&row]() {
|
||||
OCCAM_LOG(DEBUG, "t2 start");
|
||||
ob_usleep(250_ms);
|
||||
row.~MdsRow();
|
||||
});
|
||||
t1.join();
|
||||
t2.join();
|
||||
ASSERT_EQ(5, call_on_set);
|
||||
ASSERT_EQ(5, call_try_on_redo);
|
||||
ASSERT_GE(call_try_on_commit, 0);
|
||||
ASSERT_LE(call_try_on_commit, 5);
|
||||
}
|
||||
|
||||
// TEST_F(TestMdsNode, test_prepare_version_with_commit) {
|
||||
// UserMdsNode<DummyKey, UserDataWithCallBack> node(nullptr, MdsNodeType::SET, WriterType::TRANSACTION, 1);
|
||||
// ASSERT_EQ(node.get_prepare_version_(), share::SCN::max_scn());
|
||||
// node.try_on_redo(mock_scn(1));
|
||||
// ASSERT_EQ(node.get_prepare_version_(), share::SCN::max_scn());
|
||||
// node.try_before_prepare();
|
||||
// ASSERT_EQ(node.get_prepare_version_(), share::SCN::min_scn());
|
||||
// node.try_on_prepare(mock_scn(2));
|
||||
// ASSERT_EQ(node.get_prepare_version_(), mock_scn(2)); // prepare version没有传下来
|
||||
// ASSERT_EQ(node.is_aborted_(), false);
|
||||
// ASSERT_EQ(node.is_committed_(), false);
|
||||
// ASSERT_EQ(node.is_decided_(), false);
|
||||
// node.try_on_commit(mock_scn(3), mock_scn(3));
|
||||
// ASSERT_EQ(node.is_aborted_(), false);
|
||||
// ASSERT_EQ(node.is_committed_(), true);
|
||||
// ASSERT_EQ(node.is_decided_(), true);
|
||||
// ASSERT_EQ(node.get_prepare_version_(), mock_scn(3));
|
||||
// }
|
||||
|
||||
// TEST_F(TestMdsNode, test_prepare_version_with_abort) {
|
||||
// UserMdsNode<DummyKey, UserDataWithCallBack> node(nullptr, MdsNodeType::SET, WriterType::TRANSACTION, 1);
|
||||
// ASSERT_EQ(node.is_aborted_(), false);
|
||||
// ASSERT_EQ(node.is_committed_(), false);
|
||||
// ASSERT_EQ(node.is_decided_(), false);
|
||||
// node.try_on_abort(share::SCN::max_scn());
|
||||
// ASSERT_EQ(node.is_aborted_(), true);
|
||||
// ASSERT_EQ(node.is_committed_(), false);
|
||||
// ASSERT_EQ(node.is_decided_(), true);
|
||||
// ASSERT_EQ(call_try_on_abort, true);
|
||||
// ASSERT_EQ(node.get_prepare_version_(), share::SCN::max_scn());
|
||||
// }
|
||||
|
||||
// TEST_F(TestMdsNode, test_commit_version_with_commit) {
|
||||
// UserMdsNode<DummyKey, UserDataWithCallBack> node(nullptr, MdsNodeType::SET, WriterType::TRANSACTION, 1);
|
||||
// ASSERT_EQ(node.get_commit_version_(), share::SCN::max_scn());
|
||||
// node.try_on_redo(mock_scn(1));
|
||||
// ASSERT_EQ(node.get_commit_version_(), share::SCN::max_scn());
|
||||
// node.try_before_prepare();
|
||||
// ASSERT_EQ(node.get_commit_version_(), share::SCN::max_scn());
|
||||
// node.try_on_prepare(mock_scn(2));
|
||||
// ASSERT_EQ(node.get_commit_version_(), share::SCN::max_scn());
|
||||
// node.try_on_commit(mock_scn(3), mock_scn(3));
|
||||
// ASSERT_EQ(node.get_commit_version_(), mock_scn(3));// only valid after commit
|
||||
// }
|
||||
|
||||
// TEST_F(TestMdsNode, test_commit_version_with_abort) {
|
||||
// UserMdsNode<DummyKey, UserDataWithCallBack> node(nullptr, MdsNodeType::SET, WriterType::TRANSACTION, 1);
|
||||
// node.try_on_abort(share::SCN::max_scn());
|
||||
// ASSERT_EQ(node.get_commit_version_(), share::SCN::max_scn());
|
||||
// }
|
||||
|
||||
TEST_F(TestMdsNode, test_node_print) {
|
||||
UserMdsNode<DummyKey, UserDataWithCallBack> node0(nullptr, MdsNodeType::SET, WriterType::TRANSACTION, 1);
|
||||
UserMdsNode<DummyKey, UserDataWithCallBack> node1(nullptr, MdsNodeType::SET, WriterType::TRANSACTION, 1);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
system("rm -rf test_mds_node.log");
|
||||
oceanbase::common::ObLogger &logger = oceanbase::common::ObLogger::get_logger();
|
||||
logger.set_file_name("test_mds_node.log", false);
|
||||
logger.set_log_level(OB_LOG_LEVEL_DEBUG);
|
||||
testing::InitGoogleTest(&argc, argv);
|
||||
int ret = RUN_ALL_TESTS();
|
||||
int64_t alloc_times = oceanbase::storage::mds::MdsAllocator::get_alloc_times();
|
||||
int64_t free_times = oceanbase::storage::mds::MdsAllocator::get_free_times();
|
||||
if (alloc_times != free_times) {
|
||||
MDS_LOG(ERROR, "memory may leak", K(free_times), K(alloc_times));
|
||||
ret = -1;
|
||||
} else {
|
||||
MDS_LOG(INFO, "all memory released", K(free_times), K(alloc_times));
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
229
unittest/storage/multi_data_source/test_mds_row.cpp
Normal file
229
unittest/storage/multi_data_source/test_mds_row.cpp
Normal file
@ -0,0 +1,229 @@
|
||||
/**
|
||||
* 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 UNITTEST_DEBUG
|
||||
#include <gtest/gtest.h>
|
||||
#include "lib/ob_errno.h"
|
||||
#include "share/ob_errno.h"
|
||||
#include <exception>
|
||||
#define private public
|
||||
#define protected public
|
||||
#include "common_define.h"
|
||||
#include "lib/allocator/ob_malloc.h"
|
||||
#include "storage/multi_data_source/mds_node.h"
|
||||
#include <thread>
|
||||
#include <iostream>
|
||||
#include <vector>
|
||||
#include <chrono>
|
||||
#include "common/ob_clock_generator.h"
|
||||
#include "storage/multi_data_source/mds_row.h"
|
||||
#include "example_user_helper_define.cpp"
|
||||
namespace oceanbase {
|
||||
namespace unittest {
|
||||
|
||||
using namespace common;
|
||||
using namespace std;
|
||||
using namespace storage;
|
||||
using namespace mds;
|
||||
|
||||
class TestMdsRowAndMdsCtx: public ::testing::Test
|
||||
{
|
||||
public:
|
||||
TestMdsRowAndMdsCtx() {};
|
||||
virtual ~TestMdsRowAndMdsCtx() {};
|
||||
virtual void SetUp() {
|
||||
};
|
||||
virtual void TearDown() {
|
||||
};
|
||||
static void mds_row_set_element();
|
||||
static void two_thread_set_conflict();
|
||||
static void get_uncommitted();
|
||||
static void get_latest();
|
||||
static void get_by_writer();
|
||||
static void get_snapshop_until_timeout();
|
||||
static void get_snapshop_disgard();
|
||||
static MdsRow<ExampleUserData2> row_;
|
||||
private:
|
||||
// disallow copy
|
||||
DISALLOW_COPY_AND_ASSIGN(TestMdsRowAndMdsCtx);
|
||||
};
|
||||
|
||||
MdsRow<ExampleUserData2> TestMdsRowAndMdsCtx::row_;
|
||||
|
||||
void TestMdsRowAndMdsCtx::mds_row_set_element() {
|
||||
ExampleUserData2 data1(1);
|
||||
MdsCtx ctx1(1);
|
||||
ASSERT_EQ(OB_SUCCESS, row_.set(data1, ctx1, 0));// copy user data
|
||||
UserMdsNode<ExampleUserData2> *user_node = dynamic_cast<UserMdsNode<ExampleUserData2> *>(row_.sorted_list_.list_.list_head_);
|
||||
ASSERT_NE(user_node->user_data_.data_.ptr(), data1.data_.ptr());
|
||||
auto p_data = data1.data_.ptr();
|
||||
ASSERT_EQ(OB_SUCCESS, row_.set(std::move(data1), ctx1, 0));// move user data
|
||||
user_node = dynamic_cast<UserMdsNode<ExampleUserData2> *>(row_.sorted_list_.list_.list_head_);
|
||||
ASSERT_EQ(user_node->user_data_.data_.ptr(), p_data);
|
||||
MdsCtx ctx2(2);
|
||||
ExampleUserData2 data2(2);
|
||||
ASSERT_EQ(OB_TRY_LOCK_ROW_CONFLICT, row_.set(data2, ctx2, 0));// 不设超时,报6005
|
||||
ASSERT_EQ(OB_ERR_EXCLUSIVE_LOCK_CONFLICT, row_.set(data2, ctx2, 200_ms));// 设超时,报6003
|
||||
ctx1.on_redo(mock_scn(1));
|
||||
ASSERT_EQ(OB_TRY_LOCK_ROW_CONFLICT, row_.set(data2, ctx2, 0));// 不设超时,报6005
|
||||
ctx1.before_prepare();
|
||||
ASSERT_EQ(OB_TRY_LOCK_ROW_CONFLICT, row_.set(data2, ctx2, 0));// 不设超时,报6005
|
||||
ctx1.on_prepare(mock_scn(2));
|
||||
ASSERT_EQ(OB_TRY_LOCK_ROW_CONFLICT, row_.set(data2, ctx2, 0));// 不设超时,报6005
|
||||
ctx1.on_commit(mock_scn(3));
|
||||
ASSERT_EQ(OB_SUCCESS, row_.set(data2, ctx2, 0));
|
||||
}
|
||||
|
||||
void TestMdsRowAndMdsCtx::two_thread_set_conflict() {
|
||||
std::thread t1([]() {
|
||||
ExampleUserData2 data(6);
|
||||
MdsCtx ctx(3);
|
||||
ASSERT_EQ(OB_SUCCESS, row_.set(data, ctx, 0));
|
||||
ob_usleep(500_ms);
|
||||
ctx.on_redo(mock_scn(6));
|
||||
ctx.before_prepare();
|
||||
ctx.on_prepare(mock_scn(6));
|
||||
ctx.on_commit(mock_scn(6));
|
||||
});
|
||||
std::thread t2([]() {
|
||||
ExampleUserData2 data(7);
|
||||
MdsCtx ctx(4);
|
||||
ob_usleep(100_ms);
|
||||
ASSERT_EQ(OB_TRY_LOCK_ROW_CONFLICT, row_.set(data, ctx, 0));
|
||||
ASSERT_EQ(OB_SUCCESS, row_.set(data, ctx, 1_s));
|
||||
ob_usleep(500_ms);
|
||||
ctx.on_redo(mock_scn(9));
|
||||
ctx.before_prepare();
|
||||
ctx.on_prepare(mock_scn(9));
|
||||
ctx.on_commit(mock_scn(9));
|
||||
});
|
||||
t1.join();
|
||||
t2.join();
|
||||
}
|
||||
|
||||
void TestMdsRowAndMdsCtx::get_uncommitted() {
|
||||
ExampleUserData2 data(12);
|
||||
MdsCtx ctx(5);
|
||||
ASSERT_EQ(OB_SUCCESS, row_.set(data, ctx, 0));
|
||||
MdsCtx ctx2(6);
|
||||
int64_t data_size = 0;
|
||||
ASSERT_EQ(OB_SUCCESS, row_.get_uncommitted([&data_size](const ExampleUserData2 &data) {
|
||||
data_size = data.data_.length();
|
||||
return OB_SUCCESS;
|
||||
}, 0));
|
||||
ASSERT_EQ(12, data_size);
|
||||
ctx.on_redo(mock_scn(10));
|
||||
ctx.before_prepare();
|
||||
ctx.on_prepare(mock_scn(10));
|
||||
ctx.on_commit(mock_scn(10));
|
||||
}
|
||||
|
||||
void TestMdsRowAndMdsCtx::get_latest() {
|
||||
int64_t data_size = 0;
|
||||
ASSERT_EQ(OB_SUCCESS, row_.get_snapshot([&data_size](const ExampleUserData2 &data) {
|
||||
data_size = data.data_.length();
|
||||
return OB_SUCCESS;
|
||||
}, share::SCN::max_scn(), 0, 0));
|
||||
ExampleUserData2 data(13);
|
||||
MdsCtx ctx(7);
|
||||
ASSERT_EQ(OB_SUCCESS, row_.set(data, ctx, 0));
|
||||
ASSERT_EQ(OB_ERR_SHARED_LOCK_CONFLICT, row_.get_snapshot([&data_size](const ExampleUserData2 &data) {
|
||||
data_size = data.data_.length();
|
||||
return OB_SUCCESS;
|
||||
}, share::SCN::max_scn(), 0, 0));
|
||||
ASSERT_EQ(12, data_size);
|
||||
}
|
||||
|
||||
void TestMdsRowAndMdsCtx::get_by_writer() {
|
||||
ExampleUserData2 data(13);
|
||||
MdsCtx ctx(9);
|
||||
int64_t data_size = 0;
|
||||
ASSERT_EQ(OB_SUCCESS, row_.get_by_writer([&data_size](const ExampleUserData2 &data) {
|
||||
data_size = data.data_.length();
|
||||
return OB_SUCCESS;
|
||||
}, 9, mock_scn(6), 0, 0));// read snapshot
|
||||
ASSERT_EQ(6, data_size);// read committed version
|
||||
|
||||
ASSERT_EQ(OB_SUCCESS, row_.set(data, ctx, 0));
|
||||
ASSERT_EQ(OB_SUCCESS, row_.get_by_writer([&data_size](const ExampleUserData2 &data) {
|
||||
data_size = data.data_.length();
|
||||
return OB_SUCCESS;
|
||||
}, 9, mock_scn(10)/*not affected*/, 0, 0));
|
||||
ASSERT_EQ(13, data_size);// read self write
|
||||
}
|
||||
|
||||
void TestMdsRowAndMdsCtx::get_snapshop_until_timeout() {
|
||||
ExampleUserData2 data(20);
|
||||
MdsCtx ctx(20);
|
||||
int64_t data_size = 0;
|
||||
ASSERT_EQ(OB_SUCCESS, row_.set(data, ctx, 0));
|
||||
ctx.before_prepare();// block all read operations
|
||||
ASSERT_EQ(OB_ERR_SHARED_LOCK_CONFLICT, row_.get_by_writer([&data_size](const ExampleUserData2 &data) {
|
||||
data_size = data.data_.length();
|
||||
return OB_SUCCESS;
|
||||
}, 10, mock_scn(6), 0, 500_ms));// read snapshot timeout
|
||||
ASSERT_EQ(OB_ERR_SHARED_LOCK_CONFLICT, row_.get_snapshot([&data_size](const ExampleUserData2 &data) {
|
||||
data_size = data.data_.length();
|
||||
return OB_SUCCESS;
|
||||
}, mock_scn(6), 0, 500_ms));// read snapshot timeout
|
||||
|
||||
ctx.on_redo(mock_scn(20));
|
||||
ctx.on_prepare(mock_scn(20));
|
||||
ctx.on_commit(mock_scn(20));
|
||||
|
||||
ASSERT_EQ(OB_SUCCESS, row_.get_snapshot([&data_size](const ExampleUserData2 &data) {
|
||||
data_size = data.data_.length();
|
||||
return OB_SUCCESS;
|
||||
}, mock_scn(6), 0, 500_ms));// read snapshot
|
||||
ASSERT_EQ(6, data_size);
|
||||
ASSERT_EQ(OB_SUCCESS, row_.get_snapshot([&data_size](const ExampleUserData2 &data) {
|
||||
data_size = data.data_.length();
|
||||
return OB_SUCCESS;
|
||||
}, mock_scn(21), 0, 500_ms));// read snapshot
|
||||
ASSERT_EQ(20, data_size);
|
||||
}
|
||||
|
||||
void TestMdsRowAndMdsCtx::get_snapshop_disgard() {
|
||||
ASSERT_EQ(OB_SNAPSHOT_DISCARDED, row_.get_snapshot([](const ExampleUserData2 &data) {
|
||||
return OB_SUCCESS;
|
||||
}, mock_scn(1), 0, 500_ms));// read snapshot timeout
|
||||
}
|
||||
|
||||
TEST_F(TestMdsRowAndMdsCtx, mds_row_set_element) { TestMdsRowAndMdsCtx::mds_row_set_element(); }
|
||||
TEST_F(TestMdsRowAndMdsCtx, two_thread_set_conflict) { TestMdsRowAndMdsCtx::two_thread_set_conflict(); }
|
||||
TEST_F(TestMdsRowAndMdsCtx, get_uncommitted) { TestMdsRowAndMdsCtx::get_uncommitted(); }
|
||||
TEST_F(TestMdsRowAndMdsCtx, get_latest) { TestMdsRowAndMdsCtx::get_latest(); }
|
||||
TEST_F(TestMdsRowAndMdsCtx, get_by_writer) { TestMdsRowAndMdsCtx::get_by_writer(); }
|
||||
TEST_F(TestMdsRowAndMdsCtx, get_snapshop_until_timeout) { TestMdsRowAndMdsCtx::get_snapshop_until_timeout(); }
|
||||
TEST_F(TestMdsRowAndMdsCtx, get_snapshop_disgard) { TestMdsRowAndMdsCtx::get_snapshop_disgard(); }
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
system("rm -rf test_mds_row.log");
|
||||
oceanbase::common::ObLogger &logger = oceanbase::common::ObLogger::get_logger();
|
||||
logger.set_file_name("test_mds_row.log", false);
|
||||
logger.set_log_level(OB_LOG_LEVEL_TRACE);
|
||||
testing::InitGoogleTest(&argc, argv);
|
||||
int ret = RUN_ALL_TESTS();
|
||||
oceanbase::unittest::TestMdsRowAndMdsCtx::row_.~MdsRow();
|
||||
int64_t alloc_times = oceanbase::storage::mds::MdsAllocator::get_alloc_times();
|
||||
int64_t free_times = oceanbase::storage::mds::MdsAllocator::get_free_times();
|
||||
if (alloc_times != free_times) {
|
||||
MDS_LOG(ERROR, "memory may leak", K(free_times), K(alloc_times));
|
||||
ret = -1;
|
||||
} else {
|
||||
MDS_LOG(INFO, "all memory released", K(free_times), K(alloc_times));
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
654
unittest/storage/multi_data_source/test_mds_table.cpp
Normal file
654
unittest/storage/multi_data_source/test_mds_table.cpp
Normal file
@ -0,0 +1,654 @@
|
||||
/**
|
||||
* 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 UNITTEST_DEBUG
|
||||
#include "lib/utility/utility.h"
|
||||
#include <gtest/gtest.h>
|
||||
#define private public
|
||||
#define protected public
|
||||
#include "multi_data_source/example_user_data_define.h"
|
||||
#include "share/ob_ls_id.h"
|
||||
#include "storage/multi_data_source/mds_writer.h"
|
||||
#include <thread>
|
||||
#include <iostream>
|
||||
#include <vector>
|
||||
#include <chrono>
|
||||
#include <exception>
|
||||
#include "common_define.h"
|
||||
#include "lib/ob_errno.h"
|
||||
#include "share/ob_errno.h"
|
||||
#include "storage/multi_data_source/adapter_define/mds_dump_node.h"
|
||||
#include "lib/allocator/ob_malloc.h"
|
||||
#include "storage/multi_data_source/mds_node.h"
|
||||
#include "common/ob_clock_generator.h"
|
||||
#include "storage/multi_data_source/mds_row.h"
|
||||
#include "storage/multi_data_source/mds_unit.h"
|
||||
#include "storage/multi_data_source/mds_table_handle.h"
|
||||
#include "storage/multi_data_source/mds_table_handler.h"
|
||||
#include "example_user_helper_define.cpp"
|
||||
#include "storage/tx/ob_trans_define.h"
|
||||
#include <algorithm>
|
||||
#include <numeric>
|
||||
#include "storage/multi_data_source/runtime_utility/mds_lock.h"
|
||||
#include "storage/tablet/ob_tablet_meta.h"
|
||||
namespace oceanbase {
|
||||
namespace storage
|
||||
{
|
||||
namespace mds
|
||||
{
|
||||
void *MdsAllocator::alloc(const int64_t size)
|
||||
{
|
||||
void *ptr = ob_malloc(size, "MDS");
|
||||
ATOMIC_INC(&alloc_times_);
|
||||
MDS_LOG(DEBUG, "alloc obj", KP(ptr), K(size), K(lbt()));
|
||||
return ptr;
|
||||
}
|
||||
void MdsAllocator::free(void *ptr) {
|
||||
ATOMIC_INC(&free_times_);
|
||||
MDS_LOG(DEBUG, "free obj", KP(ptr), K(lbt()));
|
||||
ob_free(ptr);
|
||||
}
|
||||
}
|
||||
}
|
||||
namespace unittest {
|
||||
|
||||
using namespace common;
|
||||
using namespace std;
|
||||
using namespace storage;
|
||||
using namespace mds;
|
||||
using namespace transaction;
|
||||
|
||||
class TestMdsTable: public ::testing::Test
|
||||
{
|
||||
public:
|
||||
TestMdsTable() {}
|
||||
virtual ~TestMdsTable() {}
|
||||
virtual void SetUp() {
|
||||
}
|
||||
virtual void TearDown() {
|
||||
}
|
||||
static void set();
|
||||
static void replay();
|
||||
static void get_latest();
|
||||
static void get_snapshot();
|
||||
static void get_snapshot_hung_1s();
|
||||
static void get_by_writer();
|
||||
static void insert_multi_row();
|
||||
static void get_multi_row();
|
||||
// static void for_each_scan();
|
||||
static void standard_iterator();
|
||||
static void OB_iterator();
|
||||
static void test_flush();
|
||||
static void test_is_locked_by_others();
|
||||
static void test_multi_key_remove();
|
||||
private:
|
||||
// disallow copy
|
||||
DISALLOW_COPY_AND_ASSIGN(TestMdsTable);
|
||||
};
|
||||
|
||||
ObMdsTableHandler mds_table_hanlder;
|
||||
MdsTableHandle &mds_table_ = mds_table_hanlder.mds_table_handle_;
|
||||
|
||||
/***********************************************Single Row*************************************************************/
|
||||
struct A { ObSpinLock lock_; };
|
||||
struct B { MdsLock lock_; };
|
||||
|
||||
#define GET_REAL_MDS_TABLE(mds_table) (*((MdsTableImpl<UnitTestMdsTable>*)(dynamic_cast<guard::LightDataBlock<MdsTableImpl<UnitTestMdsTable>>*>((mds_table.p_mds_table_base_.ctrl_ptr_->p_data_block_))->data_)))
|
||||
|
||||
void TestMdsTable::set() {
|
||||
ASSERT_EQ(OB_SUCCESS, mds_table_.init<UnitTestMdsTable>(MdsAllocator::get_instance(), ObTabletID(1), share::ObLSID(1), (ObTabletPointer*)0x111));
|
||||
MDS_LOG(INFO, "test sizeof", K(sizeof(MdsTableImpl<UnitTestMdsTable>)), K(sizeof(B)), K(mds_table_.p_mds_table_base_.ctrl_ptr_->ref_));
|
||||
ExampleUserData1 data1(1);
|
||||
ExampleUserData2 data2;
|
||||
ASSERT_EQ(OB_SUCCESS, data2.assign(MdsAllocator::get_instance(), "123"));
|
||||
MdsCtx ctx1(mds::MdsWriter(ObTransID(1)));// commit finally
|
||||
DummyKey key;
|
||||
ASSERT_EQ(OB_SUCCESS, mds_table_.set(data1, ctx1));
|
||||
ASSERT_EQ(OB_SUCCESS, mds_table_.set(data2, ctx1));
|
||||
ctx1.on_redo(mock_scn(10));
|
||||
ctx1.before_prepare();
|
||||
ctx1.on_prepare(mock_scn(10));
|
||||
ctx1.on_commit(mock_scn(10), mock_scn(10));
|
||||
ExampleUserData1 data3(3);
|
||||
MdsCtx ctx2(mds::MdsWriter(ObTransID(2)));// abort by RAII finally
|
||||
ASSERT_EQ(OB_SUCCESS, mds_table_.set(data1, ctx2));
|
||||
ctx2.on_abort(mock_scn(8));
|
||||
}
|
||||
// <DummyKey, ExampleUserData1>: (data:1, writer:1, ver:10)
|
||||
// <DummyKey, ExampleUserData2>: (data:2, writer:1, ver:10)
|
||||
|
||||
void TestMdsTable::replay() {
|
||||
ExampleUserData1 data1(3);
|
||||
MdsCtx ctx1(mds::MdsWriter(ObTransID(1)));// commit finally
|
||||
ASSERT_EQ(OB_SUCCESS, mds_table_.replay(data1, ctx1, mock_scn(9)));
|
||||
// ctx1.on_redo(mock_scn(9));// insert to tail on unit ExampleUserData1
|
||||
ctx1.before_prepare();
|
||||
ctx1.on_prepare(mock_scn(9));
|
||||
ctx1.on_commit(mock_scn(9), mock_scn(9));
|
||||
auto &unit = GET_REAL_MDS_TABLE(mds_table_).unit_tuple_.element<MdsUnit<DummyKey, ExampleUserData1>>();
|
||||
MDS_LOG(INFO, "xuwang test", K(unit.single_row_));
|
||||
|
||||
share::SCN recorde_scn = mock_scn(0);
|
||||
unit.single_row_.v_.sorted_list_.for_each_node_from_tail_to_head_until_true([&](const UserMdsNode<DummyKey, ExampleUserData1> &node) -> int {
|
||||
if (!node.is_aborted_()) {
|
||||
OB_ASSERT(node.redo_scn_ > recorde_scn);
|
||||
recorde_scn = node.redo_scn_;
|
||||
}
|
||||
return OB_SUCCESS;
|
||||
});
|
||||
}
|
||||
// <DummyKey, ExampleUserData1>: (data:1, writer:1, ver:10) -> (data:3, writer:1, ver:9)
|
||||
// <DummyKey, ExampleUserData2>: (data:2, writer:1, ver:10)
|
||||
|
||||
void TestMdsTable::get_latest()
|
||||
{
|
||||
ExampleUserData1 data1(5);
|
||||
MdsCtx ctx1(mds::MdsWriter(ObTransID(1)));// abort finally
|
||||
ASSERT_EQ(OB_SUCCESS, mds_table_.set(data1, ctx1));
|
||||
int value = 0;
|
||||
bool unused_committed_flag = false;
|
||||
ASSERT_EQ(OB_SUCCESS, mds_table_.get_latest<ExampleUserData1>([&value](const ExampleUserData1 &data) {
|
||||
value = data.value_;
|
||||
return OB_SUCCESS;
|
||||
}, unused_committed_flag));
|
||||
ASSERT_EQ(5, value);// read uncommitted
|
||||
ctx1.on_abort(mock_scn(11));
|
||||
}
|
||||
|
||||
void TestMdsTable::get_snapshot()
|
||||
{
|
||||
int value = 0;
|
||||
ASSERT_EQ(OB_SUCCESS, mds_table_.get_snapshot<ExampleUserData1>([&value](const ExampleUserData1 &data) {
|
||||
value = data.value_;
|
||||
return OB_SUCCESS;
|
||||
}, mock_scn(9)));
|
||||
ASSERT_EQ(3, value);// read snapshot
|
||||
}
|
||||
|
||||
void TestMdsTable::get_snapshot_hung_1s()
|
||||
{
|
||||
std::thread th1([&]() {
|
||||
MdsCtx ctx(mds::MdsWriter(ObTransID(1)));// abort finally
|
||||
ExampleUserData1 data(1);
|
||||
ASSERT_EQ(OB_SUCCESS, mds_table_.set(data, ctx));
|
||||
ctx.on_redo(mock_scn(3));
|
||||
ctx.before_prepare();
|
||||
this_thread::sleep_for(chrono::milliseconds(1200));
|
||||
ctx.on_abort(mock_scn(12));
|
||||
});
|
||||
|
||||
std::thread th2([&]() {
|
||||
this_thread::sleep_for(chrono::milliseconds(100));
|
||||
ExampleUserData1 data;
|
||||
int64_t start_ts = ObClockGenerator::getRealClock();
|
||||
ASSERT_EQ(OB_SUCCESS, mds_table_.get_snapshot<ExampleUserData1>([&data](const ExampleUserData1 &node_data) {
|
||||
data = node_data;
|
||||
return OB_SUCCESS;
|
||||
}, share::SCN::max_scn(), 0, 2_s));
|
||||
ASSERT_LE(1_s, ObClockGenerator::getRealClock() - start_ts);
|
||||
ASSERT_EQ(1, data.value_);// read snapshot
|
||||
});
|
||||
|
||||
th1.join();
|
||||
th2.join();
|
||||
}
|
||||
|
||||
void TestMdsTable::get_by_writer()
|
||||
{
|
||||
ExampleUserData1 data1(15);
|
||||
MdsCtx ctx1(mds::MdsWriter(ObTransID(15)));// abort finally
|
||||
ASSERT_EQ(OB_SUCCESS, mds_table_.set(data1, ctx1));
|
||||
ExampleUserData2 data2;
|
||||
ASSERT_EQ(OB_SUCCESS, data2.assign(MdsAllocator::get_instance(), "3456"));
|
||||
MdsCtx ctx2(mds::MdsWriter(ObTransID(20)));// commit finally with version 20
|
||||
ASSERT_EQ(OB_SUCCESS, mds_table_.set(data2, ctx2));
|
||||
ctx2.on_redo(mock_scn(20));
|
||||
ctx2.before_prepare();
|
||||
ctx2.on_prepare(mock_scn(20));
|
||||
ctx2.on_commit(mock_scn(20), mock_scn(20));
|
||||
int value = 0;
|
||||
ASSERT_EQ(OB_SUCCESS, mds_table_.get_by_writer<ExampleUserData1>([&value](const ExampleUserData1 &data) {
|
||||
value = data.value_;
|
||||
return OB_SUCCESS;
|
||||
}, mds::MdsWriter(ObTransID(15)), mock_scn(15)));// read self uncommitted change
|
||||
ASSERT_EQ(15, value);// read uncommitted
|
||||
ASSERT_EQ(OB_SUCCESS, mds_table_.get_by_writer<ExampleUserData2>([&value](const ExampleUserData2 &data) {
|
||||
value = data.data_.length();
|
||||
return OB_SUCCESS;
|
||||
}, mds::MdsWriter(ObTransID(15)), mock_scn(15)));// read others committed change
|
||||
ASSERT_EQ(3, value);// read last committed
|
||||
ctx1.on_abort(mock_scn(20));
|
||||
}
|
||||
// <DummyKey, ExampleUserData1>: (data:1, writer:1, ver:10) -> (data:3, writer:1, ver:9)
|
||||
// <DummyKey, ExampleUserData2>: (data:20, writer:20, ver:20) -> (data:2, writer:1, ver:10)
|
||||
|
||||
|
||||
/***********************************************Multi Row**************************************************************/
|
||||
|
||||
void TestMdsTable::insert_multi_row() {
|
||||
ExampleUserKey key(1);
|
||||
ExampleUserData1 data1(1);
|
||||
MdsCtx ctx(mds::MdsWriter(ObTransID(1)));// commit finally
|
||||
ASSERT_EQ(OB_SUCCESS, mds_table_.set(key, data1, ctx));
|
||||
ctx.on_redo(mock_scn(1));
|
||||
ctx.before_prepare();
|
||||
ctx.on_prepare(mock_scn(1));
|
||||
ctx.on_commit(mock_scn(1), mock_scn(1));
|
||||
|
||||
ExampleUserKey key2(2);
|
||||
ExampleUserData1 data2(2);
|
||||
MdsCtx ctx2(mds::MdsWriter(ObTransID(2)));// commit finally
|
||||
ASSERT_EQ(OB_SUCCESS, mds_table_.set(key2, data2, ctx2));
|
||||
ASSERT_EQ(OB_SUCCESS, mds_table_.set(key, data2, ctx2));// 因为只存储单版本,所以data1读不到了
|
||||
ctx2.on_redo(mock_scn(2));
|
||||
ctx2.before_prepare();
|
||||
ctx2.on_prepare(mock_scn(2));
|
||||
ctx2.on_commit(mock_scn(2), mock_scn(2));
|
||||
}
|
||||
// <DummyKey, ExampleUserData1>: (data:1, writer:1, ver:10) -> (data:3, writer:1, ver:9)
|
||||
// <DummyKey, ExampleUserData2>: (data:20, writer:20, ver:20) -> (data:2, writer:1, ver:10)
|
||||
// <ExampleUserKey, ExampleUserData1> : <1> : (data:2, writer:2, ver:2) -> (data:1, writer:1, ver:1)
|
||||
// <2> : (data:2, writer:2, ver:2)
|
||||
|
||||
void TestMdsTable::get_multi_row() {
|
||||
ExampleUserData1 read_data;
|
||||
ExampleUserKey key(1);
|
||||
ExampleUserData1 data3(3);
|
||||
MdsCtx ctx3(mds::MdsWriter(ObTransID(3)));// abort finally
|
||||
ASSERT_EQ(OB_SUCCESS, mds_table_.set(key, data3, ctx3));
|
||||
auto read_op = [&read_data](const ExampleUserData1 &data) { read_data = data; return OB_SUCCESS; };
|
||||
int ret = mds_table_.get_snapshot<ExampleUserKey, ExampleUserData1>(ExampleUserKey(1), read_op, mock_scn(2));
|
||||
ASSERT_EQ(OB_SUCCESS, ret);
|
||||
ASSERT_EQ(2, read_data.value_);
|
||||
ret = mds_table_.get_snapshot<ExampleUserKey, ExampleUserData1>(ExampleUserKey(1), read_op, mock_scn(1));// 没有转储,旧版本还是保留的
|
||||
ASSERT_EQ(OB_SUCCESS, ret);
|
||||
ASSERT_EQ(1, read_data.value_);
|
||||
|
||||
bool unused_committed_flag = false;
|
||||
ret = mds_table_.get_latest<ExampleUserKey, ExampleUserData1>(ExampleUserKey(1), read_op, unused_committed_flag);
|
||||
ASSERT_EQ(OB_SUCCESS, ret);
|
||||
ASSERT_EQ(3, read_data.value_);
|
||||
ctx3.on_abort(mock_scn(3));
|
||||
}
|
||||
|
||||
struct ScanOp {
|
||||
ScanOp() : valid_count_(0), total_count_(0) {}
|
||||
int operator()(const MdsNode &node) {
|
||||
if (!node.is_aborted_())
|
||||
++valid_count_;
|
||||
return OB_SUCCESS;
|
||||
}
|
||||
int valid_count_;
|
||||
int total_count_;
|
||||
};
|
||||
|
||||
// void TestMdsTable::for_each_scan() {
|
||||
// ScanOp op;
|
||||
// ASSERT_EQ(OB_SUCCESS, mds_table_.for_each_scan_node(op));
|
||||
// ASSERT_EQ(op.valid_count_, 7);
|
||||
// }
|
||||
|
||||
void TestMdsTable::standard_iterator() {
|
||||
// iter kv unit, range for
|
||||
MdsUnit<ExampleUserKey, ExampleUserData1> *p_mds_unit = nullptr;
|
||||
ASSERT_EQ(OB_SUCCESS, mds_table_.get_mds_unit(p_mds_unit));// need handle protect table life
|
||||
{
|
||||
MdsRLockGuard lg(p_mds_unit->lock_);// lock unit
|
||||
for (auto &kv_row : *p_mds_unit) {
|
||||
MdsRLockGuard lg(kv_row.v_.lock_);// lock row
|
||||
for (auto &mds_node : kv_row.v_) {
|
||||
MDS_LOG(INFO, "print iter mds node", K(mds_node));
|
||||
}
|
||||
}
|
||||
}
|
||||
// iter dummy key unit, reverse iter
|
||||
MdsUnit<DummyKey, ExampleUserData1> *p_mds_unit2 = nullptr;
|
||||
ASSERT_EQ(OB_SUCCESS, mds_table_.get_mds_unit(p_mds_unit2));// need handle protect table life
|
||||
{
|
||||
int64_t cnt_committed = 0;
|
||||
// using KvRowIter = MdsUnit<DummyKey, ExampleUserData2>::iterator;
|
||||
// using NodeIter = KvRowIter::row_type::iterator;
|
||||
using KvRowIter = MdsUnit<DummyKey, ExampleUserData1>::reverse_iterator;
|
||||
using NodeIter = KvRowIter::row_type::reverse_iterator;
|
||||
MdsRLockGuard lg(p_mds_unit->lock_);// lock unit
|
||||
for (KvRowIter iter1 = p_mds_unit2->rbegin(); iter1 != p_mds_unit2->rend(); ++iter1) {// there is actually only one
|
||||
MdsRLockGuard lg(iter1->v_.lock_);// lock row
|
||||
for (NodeIter iter2 = iter1->v_.rbegin(); iter2 != iter1->v_.rend(); ++iter2) {
|
||||
if (iter2->is_committed_()) {
|
||||
cnt_committed += 1;
|
||||
}
|
||||
}
|
||||
int64_t cnt = std::count_if(iter1->v_.begin(), iter1->v_.end(), [](UserMdsNode<DummyKey, ExampleUserData1> &node){ return node.is_committed_(); });
|
||||
ASSERT_EQ(cnt_committed, cnt);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void TestMdsTable::OB_iterator() {
|
||||
ObMdsUnitRowNodeScanIterator<ExampleUserKey, ExampleUserData1> iter;
|
||||
ExampleUserKey key;
|
||||
UserMdsNode<ExampleUserKey, ExampleUserData1> *p_node = nullptr;
|
||||
ASSERT_EQ(OB_SUCCESS, iter.init(mds_table_));
|
||||
ASSERT_EQ(OB_SUCCESS, iter.get_next(key, p_node));
|
||||
MDS_LOG(INFO, "print iter kv", K(key), K(*p_node));
|
||||
ASSERT_EQ(ExampleUserKey(1), key);
|
||||
{
|
||||
ASSERT_EQ(ExampleUserData1(2), p_node->user_data_);
|
||||
ASSERT_EQ(true, p_node->is_committed_());
|
||||
ASSERT_EQ(mock_scn(2), p_node->get_commit_version_());
|
||||
}
|
||||
ASSERT_EQ(OB_SUCCESS, iter.get_next(key, p_node));
|
||||
MDS_LOG(INFO, "print iter kv", K(key), K(*p_node));
|
||||
ASSERT_EQ(ExampleUserKey(1), key);
|
||||
{
|
||||
ASSERT_EQ(ExampleUserData1(1), p_node->user_data_);
|
||||
ASSERT_EQ(true, p_node->is_committed_());
|
||||
ASSERT_EQ(mock_scn(1), p_node->get_commit_version_());
|
||||
}
|
||||
ASSERT_EQ(OB_SUCCESS, iter.get_next(key, p_node));
|
||||
ASSERT_EQ(ExampleUserKey(2), key);
|
||||
ASSERT_EQ(OB_ITER_END, iter.get_next(key, p_node));
|
||||
}
|
||||
|
||||
// <DummyKey, ExampleUserData1>: (data:1, writer:1, ver:10) -> (data:3, writer:1, ver:9)
|
||||
// <DummyKey, ExampleUserData2>: (data:20, writer:20, ver:20) -> (data:2, writer:1, ver:10)
|
||||
// <ExampleUserKey, ExampleUserData1> : <1> : (data:100, writer:100, ver:19001) -> (data:2, writer:2, ver:2) -> (data:1, writer:1, ver:1)
|
||||
// <2> : (data:200, writer:200, ver:MAX)
|
||||
void TestMdsTable::test_flush() {
|
||||
ExampleUserKey key(1);
|
||||
ExampleUserData1 data1(100);
|
||||
MdsCtx ctx(mds::MdsWriter(ObTransID(100)));// commit finally
|
||||
ASSERT_EQ(OB_SUCCESS, mds_table_.set(key, data1, ctx));
|
||||
ctx.on_redo(mock_scn(19001));
|
||||
ctx.before_prepare();
|
||||
ctx.on_prepare(mock_scn(19001));
|
||||
ctx.on_commit(mock_scn(19002), mock_scn(19002));
|
||||
|
||||
ExampleUserKey key2(2);
|
||||
ExampleUserData1 data2(200);
|
||||
MdsCtx ctx2(mds::MdsWriter(ObTransID(200)));// abort finally
|
||||
ASSERT_EQ(OB_SUCCESS, mds_table_.set(key2, data2, ctx2));
|
||||
ctx2.on_redo(mock_scn(200));
|
||||
|
||||
int idx = 0;
|
||||
ASSERT_EQ(OB_SUCCESS, mds_table_.flush(mock_scn(300)));// 1. 以300为版本号进行flush动作
|
||||
ASSERT_EQ(mock_scn(199), mds_table_.p_mds_table_base_->flushing_scn_);// 2. 实际上以199为版本号进行flush动作
|
||||
ASSERT_EQ(OB_SUCCESS, mds_table_.for_each_unit_from_small_key_to_big_from_old_node_to_new_to_dump(
|
||||
[&idx](const MdsDumpKV &kv) -> int {// 2. 转储时扫描mds table
|
||||
OB_ASSERT(kv.v_.end_scn_ < mock_scn(199));// 扫描时看不到199版本以上的提交
|
||||
OB_ASSERT(idx < 10);
|
||||
MDS_LOG(INFO, "print dump node kv", K(kv));
|
||||
return OB_SUCCESS;
|
||||
}, true)
|
||||
);
|
||||
mds_table_.on_flush(mock_scn(199), OB_SUCCESS);// 3. 推大rec_scn【至少】到200
|
||||
share::SCN rec_scn;
|
||||
ASSERT_EQ(OB_SUCCESS, mds_table_.get_rec_scn(rec_scn));
|
||||
MDS_LOG(INFO, "print rec scn", K(rec_scn));
|
||||
ASSERT_EQ(rec_scn, mock_scn(200));
|
||||
MdsCtx ctx3(mds::MdsWriter(ObTransID(101)));// abort finally
|
||||
ASSERT_EQ(OB_SUCCESS, mds_table_.replay(ExampleUserKey(111), ExampleUserData1(111), ctx3, mock_scn(100)));
|
||||
ASSERT_EQ(OB_SUCCESS, mds_table_.get_rec_scn(rec_scn));
|
||||
ASSERT_EQ(rec_scn, mock_scn(100));
|
||||
ctx3.on_abort(mock_scn(100));
|
||||
|
||||
ScanOp op;
|
||||
// 未转储:一个已决node + 一个未决node
|
||||
MDS_LOG(INFO, "print free times", K(oceanbase::storage::mds::MdsAllocator::get_alloc_times()), K(oceanbase::storage::mds::MdsAllocator::get_free_times()));// 回收已转储的node
|
||||
ASSERT_EQ(OB_SUCCESS, mds_table_.try_recycle(mock_scn(200)));
|
||||
// ASSERT_EQ(OB_SUCCESS, mds_table_.for_each_scan_node(op));
|
||||
// ASSERT_EQ(op.valid_count_, 2);
|
||||
ctx2.on_abort(mock_scn(200));
|
||||
MDS_LOG(INFO, "print free times", K(oceanbase::storage::mds::MdsAllocator::get_free_times()));// 回收已转储的node
|
||||
}
|
||||
// <ExampleUserKey, ExampleUserData1> : <1> : (data:100, writer:100, ver:19001)
|
||||
|
||||
void TestMdsTable::test_is_locked_by_others() {
|
||||
int ret = OB_SUCCESS;
|
||||
bool is_locked = false;
|
||||
ret = mds_table_.is_locked_by_others<ExampleUserKey, ExampleUserData1>(ExampleUserKey(1), is_locked);
|
||||
ASSERT_EQ(OB_SUCCESS, ret);
|
||||
ASSERT_EQ(false, is_locked);
|
||||
ExampleUserData1 data1(300);
|
||||
MdsCtx ctx(mds::MdsWriter(ObTransID(100)));// abort finally
|
||||
ASSERT_EQ(OB_SUCCESS, mds_table_.set(ExampleUserKey(1), data1, ctx));
|
||||
ret = mds_table_.is_locked_by_others<ExampleUserKey, ExampleUserData1>(ExampleUserKey(1), is_locked);
|
||||
ASSERT_EQ(OB_SUCCESS, ret);
|
||||
ASSERT_EQ(true, is_locked);
|
||||
ret = mds_table_.is_locked_by_others<ExampleUserKey, ExampleUserData1>(ExampleUserKey(1), is_locked, mds::MdsWriter(ObTransID(100)));
|
||||
ASSERT_EQ(OB_SUCCESS, ret);
|
||||
ASSERT_EQ(false, is_locked);
|
||||
}
|
||||
|
||||
// <ExampleUserKey, ExampleUserData1> : <1> : (data:100, writer:100, ver:19001)
|
||||
void TestMdsTable::test_multi_key_remove() {
|
||||
bool is_committed = false;
|
||||
int ret = mds_table_.get_latest<ExampleUserKey, ExampleUserData1>(ExampleUserKey(1), [](const ExampleUserData1 &data){
|
||||
return OB_SUCCESS;
|
||||
}, is_committed);
|
||||
ASSERT_EQ(OB_SUCCESS, ret);
|
||||
ASSERT_EQ(OB_SUCCESS, mds_table_.flush(mock_scn(200)));
|
||||
ASSERT_EQ(OB_SUCCESS, mds_table_.try_recycle(mock_scn(200)));
|
||||
ret = mds_table_.get_latest<ExampleUserKey, ExampleUserData1>(ExampleUserKey(2), [](const ExampleUserData1 &data){
|
||||
return OB_SUCCESS;
|
||||
}, is_committed);
|
||||
ASSERT_EQ(OB_ENTRY_NOT_EXIST, ret);
|
||||
MdsCtx ctx(mds::MdsWriter(ObTransID(1)));
|
||||
ret = mds_table_.remove<ExampleUserKey, ExampleUserData1>(ExampleUserKey(1), ctx);
|
||||
ASSERT_EQ(OB_SUCCESS, ret);
|
||||
ret = mds_table_.get_latest<ExampleUserKey, ExampleUserData1>(ExampleUserKey(1), [](const ExampleUserData1 &data){
|
||||
return OB_SUCCESS;
|
||||
}, is_committed);
|
||||
ASSERT_EQ(OB_ENTRY_NOT_EXIST, ret);
|
||||
}
|
||||
|
||||
TEST_F(TestMdsTable, set) { TestMdsTable::set(); }
|
||||
TEST_F(TestMdsTable, replay) { TestMdsTable::replay(); }
|
||||
TEST_F(TestMdsTable, get_latest) { TestMdsTable::get_latest(); }
|
||||
TEST_F(TestMdsTable, get_snapshot) { TestMdsTable::get_snapshot(); }
|
||||
TEST_F(TestMdsTable, get_snapshot_hung_1s) { TestMdsTable::get_snapshot_hung_1s(); }
|
||||
TEST_F(TestMdsTable, get_by_writer) { TestMdsTable::get_by_writer(); }
|
||||
TEST_F(TestMdsTable, insert_multi_row) { TestMdsTable::insert_multi_row(); }
|
||||
TEST_F(TestMdsTable, get_multi_row) { TestMdsTable::get_multi_row(); }
|
||||
TEST_F(TestMdsTable, test_standard_style_iterator) { TestMdsTable::standard_iterator(); }
|
||||
TEST_F(TestMdsTable, test_OB_style_iterator) { TestMdsTable::OB_iterator(); }
|
||||
TEST_F(TestMdsTable, test_flush) { TestMdsTable::test_flush(); }
|
||||
TEST_F(TestMdsTable, test_is_locked_by_others) { TestMdsTable::test_is_locked_by_others(); }
|
||||
TEST_F(TestMdsTable, test_multi_key_remove) { TestMdsTable::test_multi_key_remove(); }
|
||||
|
||||
TEST_F(TestMdsTable, basic_trans_example) {
|
||||
MdsTableHandle mth;
|
||||
// 1. 初始化为UnitTestMdsTable
|
||||
ASSERT_EQ(OB_SUCCESS, mth.init<UnitTestMdsTable>(mds::DefaultAllocator::get_instance(),
|
||||
ObTabletID(1),
|
||||
share::ObLSID(1),
|
||||
nullptr));
|
||||
MdsTableHandle mth2 = mth;// 两个引用计数
|
||||
MdsCtx ctx(mds::MdsWriter(ObTransID(123)));// 创建一个写入句柄,接入多源事务,ctx由事务层创建
|
||||
// 2. 写入数据
|
||||
ASSERT_EQ(OB_SUCCESS, mth.set(ExampleUserData1(1), ctx));// 写入第一个数据单元,成功
|
||||
ASSERT_EQ(OB_OBJ_TYPE_ERROR, mth.set((int)54321, ctx));// 写入第二个数据单元,但UnitTestMdsTable并未注册该类型数据,Type ERROR
|
||||
// 3. 对写入数据写CLOG并进行两阶段提交,接入多源事务,则该流程由事务层代为执行, 用户无感知
|
||||
ctx.on_redo(mock_scn(100));
|
||||
ctx.before_prepare();
|
||||
ctx.on_prepare(mock_scn(100));
|
||||
ctx.on_commit(mock_scn(100), mock_scn(100));
|
||||
// 4. 读取最新已提交数据
|
||||
ASSERT_EQ(OB_SUCCESS, mth.get_snapshot<ExampleUserData1>([](const ExampleUserData1 &data) {
|
||||
return data.value_ != 1 ? OB_ERR_UNEXPECTED : OB_SUCCESS;
|
||||
}));
|
||||
}// 5. 最后一个Handle析构的时候,MdsTable发生真正的析构行为
|
||||
|
||||
TEST_F(TestMdsTable, basic_non_trans_example) {
|
||||
MdsTableHandle mth;
|
||||
// 1. 初始化为UnitTestMdsTable
|
||||
ASSERT_EQ(OB_SUCCESS, mth.init<UnitTestMdsTable>(mds::DefaultAllocator::get_instance(),
|
||||
ObTabletID(1),
|
||||
share::ObLSID(1),
|
||||
nullptr));
|
||||
MdsTableHandle mth2 = mth;// 两个引用计数
|
||||
MdsCtx ctx(MdsWriter(WriterType::AUTO_INC_SEQ, 1));// 创建一个写入句柄,不接入事务,自己写日志
|
||||
// 2. 写入数据
|
||||
ASSERT_EQ(OB_SUCCESS, mth.set(ExampleUserData1(1), ctx));// 写入第一个数据单元,成功
|
||||
ASSERT_EQ(OB_OBJ_TYPE_ERROR, mth.set((int)54321, ctx));// 写入第二个数据单元,但UnitTestMdsTable并未注册该类型数据,Type ERROR
|
||||
// 3. 对写入数据写CLOG并进行单条日志提交
|
||||
ctx.single_log_commit(mock_scn(100), mock_scn(100));
|
||||
// 4. 读取最新已提交数据
|
||||
ASSERT_EQ(OB_SUCCESS, mth.get_snapshot<ExampleUserData1>([](const ExampleUserData1 &data) {
|
||||
return data.value_ != 1 ? OB_ERR_UNEXPECTED : OB_SUCCESS;
|
||||
}));
|
||||
}// 5. 最后一个Handle析构的时候,MdsTable发生真正的析构行为
|
||||
|
||||
TEST_F(TestMdsTable, test_recycle) {
|
||||
int64_t alloc_times = oceanbase::storage::mds::MdsAllocator::get_alloc_times();
|
||||
int64_t free_times = oceanbase::storage::mds::MdsAllocator::get_free_times();
|
||||
ASSERT_NE(alloc_times, free_times);
|
||||
ASSERT_EQ(OB_SUCCESS, mds_table_.try_recycle(mock_scn(20000)));
|
||||
int64_t valid_cnt = 0;
|
||||
ASSERT_EQ(OB_SUCCESS, mds_table_.get_node_cnt(valid_cnt));
|
||||
ASSERT_EQ(1, valid_cnt);// 此时还有一个19001版本的已提交数据,因为rec_scn没有推上去
|
||||
ASSERT_EQ(OB_SUCCESS, mds_table_.flush(mock_scn(20000)));
|
||||
mds_table_.for_each_unit_from_small_key_to_big_from_old_node_to_new_to_dump([](const MdsDumpKV &){
|
||||
return OB_SUCCESS;
|
||||
}, true);
|
||||
mds_table_.on_flush(mock_scn(20000), OB_SUCCESS);
|
||||
share::SCN rec_scn;
|
||||
ASSERT_EQ(OB_SUCCESS, mds_table_.get_rec_scn(rec_scn));
|
||||
MDS_LOG(INFO, "print rec scn", K(rec_scn));
|
||||
ASSERT_EQ(share::SCN::max_scn(), rec_scn);
|
||||
ASSERT_EQ(OB_SUCCESS, mds_table_.try_recycle(mock_scn(20000)));
|
||||
ASSERT_EQ(OB_SUCCESS, mds_table_.get_node_cnt(valid_cnt));
|
||||
ASSERT_EQ(0, valid_cnt);// 此时还有一个19001版本的已提交数据,因为rec_scn没有推上去
|
||||
}
|
||||
|
||||
TEST_F(TestMdsTable, test_recalculate_flush_scn_op) {
|
||||
MdsTableHandle mds_table;
|
||||
ASSERT_EQ(OB_SUCCESS, mds_table.init<UnitTestMdsTable>(MdsAllocator::get_instance(), ObTabletID(1), share::ObLSID(1), (ObTabletPointer*)0x111));
|
||||
MdsCtx ctx1(mds::MdsWriter(ObTransID(1)));
|
||||
MdsCtx ctx2(mds::MdsWriter(ObTransID(2)));
|
||||
MdsCtx ctx3(mds::MdsWriter(ObTransID(3)));
|
||||
ASSERT_EQ(OB_SUCCESS, mds_table.set(ExampleUserData1(1), ctx1));
|
||||
ctx1.on_redo(mock_scn(1));
|
||||
ctx1.on_commit(mock_scn(3), mock_scn(3));
|
||||
ASSERT_EQ(OB_SUCCESS, mds_table.set(ExampleUserData1(2), ctx2));
|
||||
ctx2.on_redo(mock_scn(5));
|
||||
ctx2.on_commit(mock_scn(7), mock_scn(7));
|
||||
ASSERT_EQ(OB_SUCCESS, mds_table.set(ExampleUserData1(3), ctx3));
|
||||
ctx3.on_redo(mock_scn(9));
|
||||
ctx3.on_commit(mock_scn(11), mock_scn(11));
|
||||
ASSERT_EQ(OB_SUCCESS, mds_table.flush(mock_scn(4)));
|
||||
ASSERT_EQ(mock_scn(4), mds_table.p_mds_table_base_->flushing_scn_);
|
||||
mds_table.on_flush(mock_scn(4), OB_SUCCESS);
|
||||
ASSERT_EQ(OB_SUCCESS, mds_table.flush(mock_scn(5)));// no need do flush, directly advance rec_scn
|
||||
ASSERT_EQ(false, mds_table.p_mds_table_base_->flushing_scn_.is_valid());
|
||||
ASSERT_EQ(OB_SUCCESS, mds_table.flush(mock_scn(6)));// no need do flush, directly advance rec_scn
|
||||
ASSERT_EQ(false, mds_table.p_mds_table_base_->flushing_scn_.is_valid());
|
||||
ASSERT_EQ(OB_SUCCESS, mds_table.flush(mock_scn(7)));
|
||||
ASSERT_EQ(mock_scn(7), mds_table.p_mds_table_base_->flushing_scn_);
|
||||
mds_table.on_flush(mock_scn(7), OB_SUCCESS);
|
||||
ASSERT_EQ(OB_SUCCESS, mds_table.flush(mock_scn(8)));
|
||||
ASSERT_EQ(false, mds_table.p_mds_table_base_->flushing_scn_.is_valid());
|
||||
ASSERT_EQ(mock_scn(9), mds_table.p_mds_table_base_->rec_scn_);
|
||||
}
|
||||
|
||||
// TEST_F(TestMdsTable, test_node_commit_in_row) {
|
||||
// MdsRow<DummyKey, ExampleUserData1> row;
|
||||
// MdsCtx ctx1(mds::MdsWriter(WriterType::AUTO_INC_SEQ, 1));
|
||||
// ASSERT_EQ(OB_SUCCESS, row.set(ExampleUserData1(1), ctx1, 0));
|
||||
// ctx1.single_log_commit(mock_scn(1), mock_scn(1));
|
||||
// MdsCtx ctx2(mds::MdsWriter(WriterType::AUTO_INC_SEQ, 2));
|
||||
// ASSERT_EQ(OB_SUCCESS, row.set(ExampleUserData1(2), ctx2, 0));
|
||||
// ctx1.single_log_commit(mock_scn(2), mock_scn(2));// won't release last committed node
|
||||
// int node_cnt = 0;
|
||||
// row.sorted_list_.for_each_node_from_head_to_tail_until_true([&node_cnt](const UserMdsNode<DummyKey, ExampleUserData1> &){ ++node_cnt; return false; });
|
||||
// ASSERT_EQ(2, node_cnt);
|
||||
// }
|
||||
|
||||
TEST_F(TestMdsTable, test_rw_lock_rrlock) {
|
||||
MdsLock lock;
|
||||
std::thread t1([&lock]() {
|
||||
MdsRLockGuard lg(lock);
|
||||
ob_usleep(1_s);
|
||||
});
|
||||
std::thread t2([&lock]() {
|
||||
MdsRLockGuard lg(lock);
|
||||
ob_usleep(1_s);
|
||||
});
|
||||
t1.join();
|
||||
t2.join();
|
||||
}
|
||||
|
||||
TEST_F(TestMdsTable, test_rw_lock_wrlock) {
|
||||
MdsLock lock;
|
||||
std::thread t1([&lock]() {
|
||||
MdsWLockGuard lg(lock);
|
||||
ob_usleep(1_s);
|
||||
});
|
||||
std::thread t2([&lock]() {
|
||||
ob_usleep(200_ms);
|
||||
MdsRLockGuard lg(lock);
|
||||
ob_usleep(1_s);
|
||||
});
|
||||
t1.join();
|
||||
t2.join();
|
||||
}
|
||||
|
||||
TEST_F(TestMdsTable, test_rw_lock_rwlock) {
|
||||
MdsLock lock;
|
||||
std::thread t1([&lock]() {
|
||||
ob_usleep(200_ms);
|
||||
MdsWLockGuard lg(lock);
|
||||
ob_usleep(1_s);
|
||||
});
|
||||
std::thread t2([&lock]() {
|
||||
MdsRLockGuard lg(lock);
|
||||
ob_usleep(1_s);
|
||||
});
|
||||
t1.join();
|
||||
t2.join();
|
||||
}
|
||||
|
||||
TEST_F(TestMdsTable, test_rw_lock_wwlock) {
|
||||
MdsLock lock;
|
||||
std::thread t1([&lock]() {
|
||||
MdsWLockGuard lg(lock);
|
||||
ob_usleep(1_s);
|
||||
});
|
||||
std::thread t2([&lock]() {
|
||||
MdsWLockGuard lg(lock);
|
||||
ob_usleep(1_s);
|
||||
});
|
||||
t1.join();
|
||||
t2.join();
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
system("rm -rf test_mds_table.log");
|
||||
oceanbase::common::ObLogger &logger = oceanbase::common::ObLogger::get_logger();
|
||||
logger.set_file_name("test_mds_table.log", false);
|
||||
logger.set_log_level(OB_LOG_LEVEL_DEBUG);
|
||||
testing::InitGoogleTest(&argc, argv);
|
||||
int ret = RUN_ALL_TESTS();
|
||||
oceanbase::unittest::mds_table_.~MdsTableHandle();
|
||||
int64_t alloc_times = oceanbase::storage::mds::MdsAllocator::get_alloc_times();
|
||||
int64_t free_times = oceanbase::storage::mds::MdsAllocator::get_free_times();
|
||||
if (alloc_times != free_times) {
|
||||
MDS_LOG(ERROR, "memory may leak", K(free_times), K(alloc_times));
|
||||
ret = -1;
|
||||
} else {
|
||||
MDS_LOG(INFO, "all memory released", K(free_times), K(alloc_times));
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
256
unittest/storage/multi_data_source/test_mds_table_flush.cpp
Normal file
256
unittest/storage/multi_data_source/test_mds_table_flush.cpp
Normal file
@ -0,0 +1,256 @@
|
||||
/**
|
||||
* 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 "lib/utility/utility.h"
|
||||
#include "storage/multi_data_source/compile_utility/mds_dummy_key.h"
|
||||
#include <gtest/gtest.h>
|
||||
#define private public
|
||||
#define protected public
|
||||
#include "multi_data_source/example_user_data_define.h"
|
||||
#include "share/ob_ls_id.h"
|
||||
#include "storage/multi_data_source/mds_writer.h"
|
||||
#include <thread>
|
||||
#include <iostream>
|
||||
#include <vector>
|
||||
#include <chrono>
|
||||
#include <exception>
|
||||
#include "common_define.h"
|
||||
#include "lib/ob_errno.h"
|
||||
#include "share/ob_errno.h"
|
||||
#include "storage/multi_data_source/adapter_define/mds_dump_node.h"
|
||||
#include "lib/allocator/ob_malloc.h"
|
||||
#include "storage/multi_data_source/mds_node.h"
|
||||
#include "common/ob_clock_generator.h"
|
||||
#include "storage/multi_data_source/mds_row.h"
|
||||
#include "storage/multi_data_source/mds_unit.h"
|
||||
#include "storage/multi_data_source/mds_table_handle.h"
|
||||
#include "storage/multi_data_source/mds_table_handler.h"
|
||||
#include "example_user_helper_define.cpp"
|
||||
#include "storage/tx/ob_trans_define.h"
|
||||
#include <algorithm>
|
||||
#include <numeric>
|
||||
#include "storage/multi_data_source/runtime_utility/mds_lock.h"
|
||||
#include "storage/tablet/ob_tablet_meta.h"
|
||||
namespace oceanbase {
|
||||
namespace storage
|
||||
{
|
||||
|
||||
share::SCN MOCK_MAX_CONSEQUENT_CALLBACKED_SCN;
|
||||
share::SCN MOCK_FLUSHING_SCN;
|
||||
|
||||
namespace mds
|
||||
{
|
||||
void *MdsAllocator::alloc(const int64_t size)
|
||||
{
|
||||
void *ptr = ob_malloc(size, "MDS");
|
||||
ATOMIC_INC(&alloc_times_);
|
||||
MDS_LOG(DEBUG, "alloc obj", KP(ptr), K(size), K(lbt()));
|
||||
return ptr;
|
||||
}
|
||||
void MdsAllocator::free(void *ptr) {
|
||||
ATOMIC_INC(&free_times_);
|
||||
MDS_LOG(DEBUG, "free obj", KP(ptr), K(lbt()));
|
||||
ob_free(ptr);
|
||||
}
|
||||
|
||||
int MdsTableBase::get_ls_max_consequent_callbacked_scn_(share::SCN &max_consequent_callbacked_scn) const
|
||||
{
|
||||
max_consequent_callbacked_scn = MOCK_MAX_CONSEQUENT_CALLBACKED_SCN;
|
||||
return OB_SUCCESS;
|
||||
}
|
||||
|
||||
int MdsTableBase::merge(const share::SCN &flushing_scn)
|
||||
{
|
||||
MOCK_FLUSHING_SCN = flushing_scn;
|
||||
return OB_SUCCESS;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
namespace unittest {
|
||||
|
||||
using namespace common;
|
||||
using namespace std;
|
||||
using namespace storage;
|
||||
using namespace mds;
|
||||
using namespace transaction;
|
||||
|
||||
class TestMdsTableFlush: public ::testing::Test
|
||||
{
|
||||
public:
|
||||
TestMdsTableFlush() {}
|
||||
virtual ~TestMdsTableFlush() {}
|
||||
virtual void SetUp() {
|
||||
}
|
||||
virtual void TearDown() {
|
||||
}
|
||||
private:
|
||||
// disallow copy
|
||||
DISALLOW_COPY_AND_ASSIGN(TestMdsTableFlush);
|
||||
};
|
||||
|
||||
|
||||
// max_decided_scn:475
|
||||
// │
|
||||
// │
|
||||
// │
|
||||
// ┌──────────┐ │ ┌──────────┐ ┌──────────┐
|
||||
// MdsUnit<DummyKey, ExampleUserData1> │(MAX, 500]│◄─┼──────────────────────┤[300, 250]│◄──────────────────────────┤(100, 50]│
|
||||
// └──────────┘ │ └──────────┘ └──────────┘
|
||||
// │
|
||||
// │
|
||||
// │
|
||||
// │
|
||||
// │ ┌──────────┐ ┌──────────┐
|
||||
// MdsUnit<DummyKey, ExampleUserData2> │ │[400, 350]│◄──────────────────────────┤[225, 200]│
|
||||
// │ └──────────┘ └──────────┘
|
||||
// │
|
||||
// │
|
||||
// │
|
||||
// │
|
||||
int construct_tested_mds_table(MdsTableHandle &handle) {
|
||||
int ret = OB_SUCCESS;
|
||||
handle.reset();
|
||||
vector<MdsCtx*> v_ctx;
|
||||
for (int i = 0; i < 7; ++i) {
|
||||
v_ctx.push_back(new MdsCtx(MdsWriter(transaction::ObTransID(i))));
|
||||
}
|
||||
if (OB_FAIL(handle.init<UnitTestMdsTable>(MdsAllocator::get_instance(), ObTabletID(1), share::ObLSID(1), (ObTabletPointer*)0x111))) {
|
||||
} else if (OB_FAIL(handle.set<ExampleUserData1>(1, *v_ctx[0]))) {
|
||||
} else if (FALSE_IT(v_ctx[0]->on_redo(mock_scn(50)))) {
|
||||
} else if (FALSE_IT(v_ctx[0]->on_commit(mock_scn(100), mock_scn(100)))) {
|
||||
} else if (OB_FAIL(handle.set<ExampleUserData1>(2, *v_ctx[1]))) {
|
||||
} else if (FALSE_IT(v_ctx[1]->on_redo(mock_scn(250)))) {
|
||||
} else if (FALSE_IT(v_ctx[1]->on_commit(mock_scn(300), mock_scn(300)))) {
|
||||
} else if (OB_FAIL(handle.set<ExampleUserData1>(3, *v_ctx[2]))) {
|
||||
} else if (FALSE_IT(v_ctx[2]->on_redo(mock_scn(500)))) {
|
||||
} else if (OB_FAIL(handle.set<ExampleUserData2>(ExampleUserData2(), *v_ctx[3]))) {
|
||||
} else if (FALSE_IT(v_ctx[3]->on_redo(mock_scn(200)))) {
|
||||
} else if (FALSE_IT(v_ctx[3]->on_commit(mock_scn(225), mock_scn(225)))) {
|
||||
} else if (OB_FAIL(handle.set<ExampleUserData2>(ExampleUserData2(), *v_ctx[4]))) {
|
||||
} else if (FALSE_IT(v_ctx[4]->on_redo(mock_scn(350)))) {
|
||||
} else if (FALSE_IT(v_ctx[4]->on_commit(mock_scn(400), mock_scn(400)))) {
|
||||
} else if (OB_SUCCESS != (ret = handle.set<ExampleUserKey, ExampleUserData1>(ExampleUserKey(1), ExampleUserData1(1), *v_ctx[5]))) {
|
||||
} else if (OB_SUCCESS != (ret = handle.set<ExampleUserKey, ExampleUserData1>(ExampleUserKey(2), ExampleUserData1(2), *v_ctx[6]))) {
|
||||
}
|
||||
v_ctx[6]->on_abort(mock_scn(10));
|
||||
return ret;
|
||||
}
|
||||
|
||||
TEST_F(TestMdsTableFlush, normal_flush) {
|
||||
MOCK_MAX_CONSEQUENT_CALLBACKED_SCN = mock_scn(125);// 只转储一个node
|
||||
MdsTableHandle handle;
|
||||
ASSERT_EQ(OB_SUCCESS, construct_tested_mds_table(handle));
|
||||
share::SCN rec_scn;
|
||||
ASSERT_EQ(OB_SUCCESS, handle.get_rec_scn(rec_scn));
|
||||
ASSERT_EQ(mock_scn(50), rec_scn);// 没转储的时候是最小的node的redo scn值
|
||||
|
||||
// 第一次转储
|
||||
ASSERT_EQ(OB_SUCCESS, handle.flush(mock_scn(1000)));// 因为max_decided_scn较小,所以会用125做flush
|
||||
bool is_flusing = false;
|
||||
ASSERT_EQ(OB_SUCCESS, handle.is_flushing(is_flusing));// 在flush流程中
|
||||
ASSERT_EQ(true, is_flusing);
|
||||
ASSERT_EQ(mock_scn(125), handle.p_mds_table_base_->flushing_scn_);
|
||||
int scan_cnt = 0;
|
||||
ASSERT_EQ(OB_SUCCESS, handle.for_each_unit_from_small_key_to_big_from_old_node_to_new_to_dump([&scan_cnt](const MdsDumpKV &kv) -> int {
|
||||
scan_cnt++;
|
||||
return OB_SUCCESS;
|
||||
}, true));
|
||||
ASSERT_EQ(1, scan_cnt);
|
||||
handle.on_flush(MOCK_FLUSHING_SCN, OB_SUCCESS);
|
||||
ASSERT_EQ(OB_SUCCESS, handle.get_rec_scn(rec_scn));
|
||||
OCCAM_LOG(INFO, "print rec scn", K(rec_scn));
|
||||
ASSERT_EQ(mock_scn(200), rec_scn);
|
||||
|
||||
// 第二次转储
|
||||
MOCK_MAX_CONSEQUENT_CALLBACKED_SCN = mock_scn(140);// 对这个MdsTable没有影响
|
||||
ASSERT_EQ(OB_SUCCESS, handle.flush(mock_scn(1000)));
|
||||
ASSERT_EQ(OB_SUCCESS, handle.is_flushing(is_flusing));
|
||||
ASSERT_EQ(false, is_flusing);// 没转储
|
||||
ASSERT_EQ(OB_SUCCESS, handle.get_rec_scn(rec_scn));
|
||||
OCCAM_LOG(INFO, "print rec scn", K(rec_scn));
|
||||
ASSERT_EQ(mock_scn(200), rec_scn);// 没变化
|
||||
|
||||
// 第三次转储
|
||||
MOCK_MAX_CONSEQUENT_CALLBACKED_SCN = mock_scn(275);// 多转一个node
|
||||
ASSERT_EQ(OB_SUCCESS, handle.flush(mock_scn(1000)));
|
||||
ASSERT_EQ(OB_SUCCESS, handle.is_flushing(is_flusing));// 在flush流程中
|
||||
ASSERT_EQ(true, is_flusing);
|
||||
ASSERT_EQ(mock_scn(249), handle.p_mds_table_base_->flushing_scn_);
|
||||
scan_cnt = 0;
|
||||
ASSERT_EQ(OB_SUCCESS, handle.for_each_unit_from_small_key_to_big_from_old_node_to_new_to_dump([&scan_cnt](const MdsDumpKV &kv) -> int {
|
||||
scan_cnt++;
|
||||
return OB_SUCCESS;
|
||||
}, true));
|
||||
ASSERT_EQ(1, scan_cnt);
|
||||
handle.on_flush(MOCK_FLUSHING_SCN, OB_SUCCESS);
|
||||
ASSERT_EQ(OB_SUCCESS, handle.get_rec_scn(rec_scn));
|
||||
OCCAM_LOG(INFO, "print rec scn", K(rec_scn));
|
||||
ASSERT_EQ(mock_scn(250), rec_scn);
|
||||
|
||||
// 第四次转储
|
||||
MOCK_MAX_CONSEQUENT_CALLBACKED_SCN = mock_scn(550);// 都转下去
|
||||
ASSERT_EQ(OB_SUCCESS, handle.flush(mock_scn(1000)));
|
||||
ASSERT_EQ(OB_SUCCESS, handle.is_flushing(is_flusing));// 在flush流程中
|
||||
ASSERT_EQ(true, is_flusing);
|
||||
ASSERT_EQ(mock_scn(499), handle.p_mds_table_base_->flushing_scn_);
|
||||
scan_cnt = 0;
|
||||
ASSERT_EQ(OB_SUCCESS, handle.for_each_unit_from_small_key_to_big_from_old_node_to_new_to_dump([&scan_cnt](const MdsDumpKV &kv) -> int {
|
||||
scan_cnt++;
|
||||
return OB_SUCCESS;
|
||||
}, true));
|
||||
ASSERT_EQ(2, scan_cnt);
|
||||
handle.on_flush(MOCK_FLUSHING_SCN, OB_SUCCESS);
|
||||
ASSERT_EQ(OB_SUCCESS, handle.get_rec_scn(rec_scn));
|
||||
OCCAM_LOG(INFO, "print rec scn", K(rec_scn));
|
||||
ASSERT_EQ(mock_scn(500), rec_scn);
|
||||
|
||||
// 第五次转储
|
||||
MOCK_MAX_CONSEQUENT_CALLBACKED_SCN = mock_scn(600);// 对这个MdsTable没有影响
|
||||
ASSERT_EQ(OB_SUCCESS, handle.flush(mock_scn(1000)));
|
||||
ASSERT_EQ(OB_SUCCESS, handle.is_flushing(is_flusing));
|
||||
ASSERT_EQ(false, is_flusing);// 没转储
|
||||
ASSERT_EQ(OB_SUCCESS, handle.get_rec_scn(rec_scn));
|
||||
OCCAM_LOG(INFO, "print rec scn", K(rec_scn));
|
||||
ASSERT_EQ(mock_scn(500), rec_scn);// 没变化
|
||||
|
||||
// 第六次转储
|
||||
MOCK_MAX_CONSEQUENT_CALLBACKED_SCN = mock_scn(590);// 直接被过滤掉了
|
||||
ASSERT_EQ(OB_SUCCESS, handle.flush(mock_scn(1000)));
|
||||
ASSERT_EQ(OB_SUCCESS, handle.is_flushing(is_flusing));
|
||||
ASSERT_EQ(false, is_flusing);// 没转储
|
||||
ASSERT_EQ(OB_SUCCESS, handle.get_rec_scn(rec_scn));
|
||||
OCCAM_LOG(INFO, "print rec scn", K(rec_scn));
|
||||
ASSERT_EQ(mock_scn(500), rec_scn);// 没变化
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
system("rm -rf test_mds_table_flush.log");
|
||||
oceanbase::common::ObLogger &logger = oceanbase::common::ObLogger::get_logger();
|
||||
logger.set_file_name("test_mds_table_flush.log", false);
|
||||
logger.set_log_level(OB_LOG_LEVEL_DEBUG);
|
||||
testing::InitGoogleTest(&argc, argv);
|
||||
int ret = RUN_ALL_TESTS();
|
||||
int64_t alloc_times = oceanbase::storage::mds::MdsAllocator::get_alloc_times();
|
||||
int64_t free_times = oceanbase::storage::mds::MdsAllocator::get_free_times();
|
||||
if (alloc_times != free_times) {
|
||||
MDS_LOG(ERROR, "memory may leak", K(free_times), K(alloc_times));
|
||||
ret = -1;
|
||||
} else {
|
||||
MDS_LOG(INFO, "all memory released", K(free_times), K(alloc_times));
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
82
unittest/storage/multi_data_source/test_mds_table_handle.cpp
Normal file
82
unittest/storage/multi_data_source/test_mds_table_handle.cpp
Normal file
@ -0,0 +1,82 @@
|
||||
/**
|
||||
* 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 "multi_data_source/example_user_data_define.h"
|
||||
#include "share/ob_errno.h"
|
||||
#include <gtest/gtest.h>
|
||||
|
||||
#define USING_LOG_PREFIX STORAGE
|
||||
|
||||
#define protected public
|
||||
#define private public
|
||||
|
||||
#include "lib/guard/ob_light_shared_gaurd.h"
|
||||
#include "storage/multi_data_source/mds_table_impl.h"
|
||||
#include "storage/tablet/ob_tablet_meta.h"
|
||||
|
||||
namespace oceanbase
|
||||
{
|
||||
//using namespace share;
|
||||
namespace storage
|
||||
{
|
||||
namespace mds
|
||||
{
|
||||
void *MdsAllocator::alloc(const int64_t size)
|
||||
{
|
||||
void *ptr = ob_malloc(size, "MDS");
|
||||
ATOMIC_INC(&alloc_times_);
|
||||
MDS_LOG(DEBUG, "alloc obj", KP(ptr), K(lbt()));
|
||||
return ptr;
|
||||
}
|
||||
void MdsAllocator::free(void *ptr) {
|
||||
ATOMIC_INC(&free_times_);
|
||||
MDS_LOG(DEBUG, "free obj", KP(ptr), K(lbt()));
|
||||
ob_free(ptr);
|
||||
}
|
||||
}
|
||||
class TestMdsTableHandle : public ::testing::Test
|
||||
{
|
||||
public:
|
||||
TestMdsTableHandle() {}
|
||||
virtual ~TestMdsTableHandle() = default;
|
||||
virtual void SetUp() override {}
|
||||
virtual void TearDown() override {}
|
||||
};
|
||||
|
||||
TEST_F(TestMdsTableHandle, normal) {
|
||||
ObLightSharedPtr<unittest::ExampleUserData1> lsp;
|
||||
lsp.construct(mds::MdsAllocator::get_instance());
|
||||
ObLightSharedPtr<unittest::ExampleUserData1> lsp2 = lsp;
|
||||
}
|
||||
|
||||
} // end namespace storage
|
||||
} // end namespace oceanbase
|
||||
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
int ret = 0;
|
||||
system("rm -f test_mds_table_handle.log*");
|
||||
OB_LOGGER.set_file_name("test_mds_table_handle.log", true);
|
||||
OB_LOGGER.set_log_level("INFO");
|
||||
signal(49, SIG_IGN);
|
||||
testing::InitGoogleTest(&argc, argv);
|
||||
ret = RUN_ALL_TESTS();
|
||||
int64_t alloc_times = oceanbase::storage::mds::MdsAllocator::get_alloc_times();
|
||||
int64_t free_times = oceanbase::storage::mds::MdsAllocator::get_free_times();
|
||||
if (alloc_times != free_times) {
|
||||
MDS_LOG(ERROR, "memory may leak", K(free_times), K(alloc_times));
|
||||
ret = -1;
|
||||
} else {
|
||||
MDS_LOG(INFO, "all memory released", K(free_times), K(alloc_times));
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
92
unittest/storage/multi_data_source/test_mds_unit.cpp
Normal file
92
unittest/storage/multi_data_source/test_mds_unit.cpp
Normal file
@ -0,0 +1,92 @@
|
||||
/**
|
||||
* 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 UNITTEST_DEBUG
|
||||
#include <gtest/gtest.h>
|
||||
#include "lib/ob_errno.h"
|
||||
#include "lib/utility/utility.h"
|
||||
#include "share/ob_errno.h"
|
||||
#include <exception>
|
||||
#include "common_define.h"
|
||||
#include "lib/allocator/ob_malloc.h"
|
||||
#include "storage/multi_data_source/mds_node.h"
|
||||
#include <thread>
|
||||
#include <iostream>
|
||||
#include <vector>
|
||||
#include <chrono>
|
||||
#include "common/ob_clock_generator.h"
|
||||
#include "storage/multi_data_source/mds_row.h"
|
||||
#include "storage/multi_data_source/mds_unit.h"
|
||||
#include "example_user_helper_define.cpp"
|
||||
namespace oceanbase {
|
||||
namespace unittest {
|
||||
|
||||
using namespace common;
|
||||
using namespace std;
|
||||
using namespace storage;
|
||||
using namespace mds;
|
||||
|
||||
class TestMdsUnit: public ::testing::Test
|
||||
{
|
||||
public:
|
||||
TestMdsUnit() {};
|
||||
virtual ~TestMdsUnit() {};
|
||||
virtual void SetUp() {
|
||||
};
|
||||
virtual void TearDown() {
|
||||
};
|
||||
static void set_single_row();
|
||||
static void get_single_row();
|
||||
static MdsUnit<DummyKey, ExampleUserData2> signle_row_unit_;
|
||||
private:
|
||||
// disallow copy
|
||||
DISALLOW_COPY_AND_ASSIGN(TestMdsUnit);
|
||||
};
|
||||
|
||||
MdsUnit<DummyKey, ExampleUserData2> TestMdsUnit::signle_row_unit_;
|
||||
|
||||
void TestMdsUnit::set_single_row() {
|
||||
ExampleUserData2 data(1);
|
||||
MdsCtx ctx(1);
|
||||
|
||||
}
|
||||
|
||||
void TestMdsUnit::get_single_row() {
|
||||
|
||||
}
|
||||
|
||||
TEST_F(TestMdsUnit, set_single_row) { TestMdsUnit::set_single_row(); }
|
||||
TEST_F(TestMdsUnit, get_single_row) { TestMdsUnit::get_single_row(); }
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
system("rm -rf test_mds_unit.log");
|
||||
oceanbase::common::ObLogger &logger = oceanbase::common::ObLogger::get_logger();
|
||||
logger.set_file_name("test_mds_unit.log", false);
|
||||
logger.set_log_level(OB_LOG_LEVEL_TRACE);
|
||||
testing::InitGoogleTest(&argc, argv);
|
||||
int ret = RUN_ALL_TESTS();
|
||||
oceanbase::unittest::TestMdsUnit::signle_row_unit_.~MdsUnit();
|
||||
int64_t alloc_times = oceanbase::storage::mds::MdsAllocator::get_alloc_times();
|
||||
int64_t free_times = oceanbase::storage::mds::MdsAllocator::get_free_times();
|
||||
if (alloc_times != free_times) {
|
||||
MDS_LOG(ERROR, "memory may leak", K(free_times), K(alloc_times));
|
||||
if (ret == 0) {
|
||||
ret = -1;
|
||||
}
|
||||
} else {
|
||||
MDS_LOG(INFO, "all memory released", K(free_times), K(alloc_times));
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
Reference in New Issue
Block a user