219 lines
7.7 KiB
C++
219 lines
7.7 KiB
C++
#include <chrono>
|
|
#include <gtest/gtest.h>
|
|
#include <thread>
|
|
#define protected public
|
|
#define private public
|
|
#include "share/ob_table_access_helper.h"
|
|
#include "lib/ob_define.h"
|
|
#include "observer/ob_server_struct.h"
|
|
#include "share/rc/ob_tenant_base.h"
|
|
#include "storage/ls/ob_ls_meta.h"
|
|
#include "storage/ls/ob_ls.h"
|
|
#include "storage/tx_storage/ob_ls_service.h"
|
|
#include "env/ob_simple_cluster_test_base.h"
|
|
#include "lib/mysqlclient/ob_mysql_result.h"
|
|
#include "storage/tx_storage/ob_ls_handle.h"
|
|
#include <iostream>
|
|
|
|
#include "rewrite_function_for_test_big_tx_data.cpp"
|
|
|
|
using namespace std;
|
|
|
|
namespace oceanbase
|
|
{
|
|
using namespace storage;
|
|
namespace unittest
|
|
{
|
|
|
|
using namespace oceanbase::transaction;
|
|
using namespace oceanbase::storage;
|
|
|
|
class TestRunCtx
|
|
{
|
|
public:
|
|
uint64_t tenant_id_ = 0;
|
|
int time_sec_ = 0;
|
|
};
|
|
|
|
TestRunCtx RunCtx;
|
|
|
|
class TestBigTxData : public ObSimpleClusterTestBase
|
|
{
|
|
public:
|
|
// 指定case运行目录前缀 test_ob_simple_cluster_
|
|
void minor_freeze_and_wait();
|
|
TestBigTxData() : ObSimpleClusterTestBase("test_big_tx_data_") {}
|
|
};
|
|
|
|
#define DO(stmt) /*cout << "before do line:" << __LINE__ << endl;*/ASSERT_EQ((stmt), OB_SUCCESS);/*cout << "after do line:" << __LINE__ << endl;*/
|
|
#define EXEC_SQL(sql) connection->execute_write(OB_SYS_TENANT_ID, sql, affected_rows)
|
|
|
|
class DoNothingOP : public ObITxDataCheckFunctor
|
|
{
|
|
virtual int operator()(const ObTxData &tx_data, ObTxCCCtx *tx_cc_ctx = nullptr) {
|
|
UNUSED(tx_cc_ctx);
|
|
cout << "read tx data:" << tx_data.tx_id_.get_id() << ", undo cnt:" << tx_data.undo_status_list_.undo_node_cnt_ << endl;
|
|
STORAGE_LOG_RET(INFO, 0, "read tx data", K(tx_data.tx_id_), K(lbt()));
|
|
return OB_SUCCESS;
|
|
}
|
|
};
|
|
|
|
TEST_F(TestBigTxData, big_tx_data)
|
|
{
|
|
int ret = OB_SUCCESS;
|
|
MTL_SWITCH(OB_SYS_TENANT_ID) {
|
|
int64_t affected_rows = 0;
|
|
sqlclient::ObISQLConnection *connection = nullptr;
|
|
// 1,开启事务,生成一些savepoint
|
|
ASSERT_EQ(OB_SUCCESS, get_curr_simple_server().get_sql_proxy().acquire(connection));
|
|
DO(EXEC_SQL("set ob_trx_timeout = 6000000000"));
|
|
DO(EXEC_SQL("set ob_trx_idle_timeout = 6000000000"));
|
|
DO(EXEC_SQL("alter system set _fast_commit_callback_count = 0"));// disallow fast commit
|
|
DO(EXEC_SQL("create table test_big_tx_data (a int primary key, b int)"));
|
|
DO(EXEC_SQL("alter system set _private_buffer_size = '1B'"));
|
|
DO(EXEC_SQL("begin"));
|
|
constexpr int64_t savepoint_size = 12;
|
|
for (int64_t idx = 0; idx < savepoint_size; ++idx) {
|
|
ObSqlString sql;
|
|
DO(sql.append_fmt("insert into test_big_tx_data values(%ld, 1)", idx));
|
|
DO(EXEC_SQL(sql.ptr()));
|
|
sql.reset();
|
|
DO(sql.append_fmt("savepoint s%ld", idx));
|
|
DO(EXEC_SQL(sql.ptr()));
|
|
}
|
|
// 2,获取本事务ID,这个事务的tx data足够大
|
|
HEAP_VAR(ObMySQLProxy::MySQLResult, res) {
|
|
int64_t sess_id = 0;
|
|
int64_t tx_id;
|
|
DO(connection->execute_read(OB_SYS_TENANT_ID, "select connection_id()", res));
|
|
common::sqlclient::ObMySQLResult *result = res.mysql_result();
|
|
DO(result->next());
|
|
result->get_int("connection_id()", sess_id);
|
|
ObSqlString sql;
|
|
DO(sql.append_fmt("select trans_id from oceanbase.__all_virtual_processlist where id=%ld", sess_id));
|
|
res.reset();
|
|
DO(connection->execute_read(OB_SYS_TENANT_ID, sql.ptr(), res));
|
|
result = res.mysql_result();
|
|
DO(result->next());
|
|
result->get_int("trans_id", tx_id);
|
|
ASSERT_EQ(OB_ITER_END, result->next());
|
|
ATOMIC_STORE(&TEST_TX_ID, tx_id);
|
|
std::cout << "tx_id:" << tx_id << std::endl;
|
|
}
|
|
// 3,写日志才可以生成undo status
|
|
cout << "alter system minor freeze 1" << endl;
|
|
minor_freeze_and_wait();
|
|
// 4,回滚生成undo status
|
|
for (int64_t idx = savepoint_size - 1; idx >= 0; --idx) {
|
|
ObSqlString sql;
|
|
DO(sql.append_fmt("rollback to s%ld", idx));
|
|
DO(EXEC_SQL(sql.ptr()));
|
|
}
|
|
DO(EXEC_SQL("commit"));
|
|
::sleep(10);
|
|
// 5,把tx data转下去
|
|
cout << "alter system minor freeze 2" << endl;
|
|
minor_freeze_and_wait();
|
|
ASSERT_EQ(ATOMIC_LOAD(&DUMP_BIG_TX_DATA), true);// 确保tx data已经走过了序列化逻辑
|
|
// 6, 读一次这个tx data
|
|
DoNothingOP op;
|
|
ObLSService *ls_service = MTL(ObLSService*);
|
|
ObLSHandle handle;
|
|
DO(ls_service->get_ls(ObLSID(1), handle, storage::ObLSGetMod::DEADLOCK_MOD));
|
|
fprintf(stdout, "start read tx data from sstable, test_tx_id = %ld\n", TEST_TX_ID);
|
|
ObTxDataMiniCache fake_cache;
|
|
ObReadTxDataArg read_arg(ObTransID(ATOMIC_LOAD(&TEST_TX_ID)), 0, fake_cache);
|
|
DO(handle.get_ls()->tx_table_.check_with_tx_data(read_arg, op));
|
|
// 7,检查被测事务的tx data已经经过了deserialize
|
|
ASSERT_EQ(ATOMIC_LOAD(&LOAD_BIG_TX_DATA), true);
|
|
}
|
|
}
|
|
|
|
void TestBigTxData::minor_freeze_and_wait()
|
|
{
|
|
int ret = OB_SUCCESS;
|
|
MTL_SWITCH(OB_SYS_TENANT_ID) {
|
|
int64_t affected_rows = 0;
|
|
int64_t retry_times = 40;
|
|
ObLSService *ls_service = MTL(ObLSService*);
|
|
ObLSHandle handle;
|
|
DO(ls_service->get_ls(ObLSID(1), handle, storage::ObLSGetMod::DEADLOCK_MOD));
|
|
ObTxDataMemtableMgr *mgr = handle.get_ls()->tx_table_.tx_data_table_.memtable_mgr_;
|
|
ASSERT_NE(nullptr, mgr);
|
|
|
|
int64_t head_before_freeze = -1;
|
|
int64_t tail_before_freeze = -1;
|
|
int64_t head_after_freeze = -1;
|
|
int64_t tail_after_freeze = -1;
|
|
while (--retry_times > 0) {
|
|
DO(mgr->get_memtable_range(head_before_freeze, tail_before_freeze));
|
|
ASSERT_GE(head_before_freeze, 0);
|
|
ASSERT_GE(tail_before_freeze, 0);
|
|
if (head_before_freeze + 1 != tail_before_freeze) {
|
|
::sleep(1);
|
|
cout << "waiting last minor freeze done ... "
|
|
<< "head_before_freeze = " << head_before_freeze << " tail_before_freeze = " << tail_before_freeze << endl;
|
|
} else {
|
|
break;
|
|
}
|
|
}
|
|
ASSERT_EQ(head_before_freeze + 1, tail_before_freeze);
|
|
cout << "head_before_freeze : " << head_before_freeze << " tail_before_freeze" << tail_before_freeze << endl;
|
|
|
|
// minor freeze once
|
|
DO(get_curr_simple_server().get_sql_proxy().write("alter system minor freeze", affected_rows));
|
|
|
|
retry_times = 60;
|
|
while (--retry_times > 0)
|
|
{
|
|
DO(handle.get_ls()->tx_table_.tx_data_table_.memtable_mgr_->get_memtable_range(head_after_freeze, tail_after_freeze));
|
|
ASSERT_GE(head_after_freeze, 0);
|
|
ASSERT_GE(tail_after_freeze, 0);
|
|
if (head_after_freeze > head_before_freeze && tail_after_freeze > tail_before_freeze && head_after_freeze + 1 == tail_after_freeze) {
|
|
fprintf(stdout,
|
|
"head_after_freeze : %ld, head_before_freeze : %ld, tail_after_freeze : %ld, tail_before_freeze : %ld\n",
|
|
head_after_freeze,
|
|
head_before_freeze,
|
|
tail_after_freeze,
|
|
tail_before_freeze);
|
|
break;
|
|
} else {
|
|
::sleep(1);
|
|
cout << "waiting this minor freeze done, head_after_freeze: " << head_after_freeze << " tail_after_freeze " << tail_after_freeze << endl;
|
|
}
|
|
}
|
|
ASSERT_GT(head_after_freeze, head_before_freeze);
|
|
ASSERT_GT(tail_after_freeze, tail_before_freeze);
|
|
ASSERT_EQ(head_after_freeze + 1, tail_after_freeze);
|
|
}
|
|
}
|
|
} // end unittest
|
|
} // end oceanbase
|
|
|
|
|
|
int main(int argc, char **argv)
|
|
{
|
|
int c = 0;
|
|
int time_sec = 0;
|
|
char *log_level = (char*)"INFO";
|
|
while(EOF != (c = getopt(argc,argv,"t:l:"))) {
|
|
switch(c) {
|
|
case 't':
|
|
time_sec = atoi(optarg);
|
|
break;
|
|
case 'l':
|
|
log_level = optarg;
|
|
oceanbase::unittest::ObSimpleClusterTestBase::enable_env_warn_log_ = false;
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
oceanbase::unittest::init_log_and_gtest(argc, argv);
|
|
OB_LOGGER.set_log_level(log_level);
|
|
|
|
oceanbase::unittest::RunCtx.time_sec_ = time_sec;
|
|
::testing::InitGoogleTest(&argc, argv);
|
|
return RUN_ALL_TESTS();
|
|
}
|