oceanbase/unittest/share/test_debug_sync.cpp
obdev 81b8923b14 [FEAT MERGE] system resource optimization
Co-authored-by: tushicheng <18829573815@163.com>
Co-authored-by: HaHaJeff <jeffzhouhhh@gmail.com>
Co-authored-by: dimstars <liangjinrongcm@gmail.com>
2023-08-29 10:41:01 +00:00

460 lines
14 KiB
C++

/**
* Copyright (c) 2021 OceanBase
* OceanBase CE is licensed under Mulan PubL v2.
* You can use this software according to the terms and conditions of the Mulan PubL v2.
* You may obtain a copy of Mulan PubL v2 at:
* http://license.coscl.org.cn/MulanPubL-2.0
* THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
* EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
* MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
* See the Mulan PubL v2 for more details.
*/
#define USING_LOG_PREFIX COMMON
#include <gtest/gtest.h>
#include <gmock/gmock.h>
#include "share/ob_debug_sync.h"
#include "lib/string/ob_sql_string.h"
#include "lib/container/ob_array.h"
#include "lib/container/ob_array_iterator.h"
#include "rpc/mock_ob_common_rpc_proxy.h"
#include "share/config/ob_server_config.h"
#include <pthread.h>
namespace oceanbase
{
namespace common
{
using namespace obrpc;
using testing::_;
using testing::Return;
TEST(common, ObDebugSyncAction)
{
ObDebugSyncAction a;
ASSERT_FALSE(a.is_valid());
a.sync_point_ = NOW;
a.execute_ = 1;
ASSERT_FALSE(a.is_valid());
a.signal_ = "a";
ASSERT_TRUE(a.is_valid());
a.wait_ = "b";
ASSERT_TRUE(a.is_valid());
a.execute_ = 0;
ASSERT_FALSE(a.is_valid());
a.execute_ = 1;
ASSERT_TRUE(a.is_valid());
a.signal_ = "";
ASSERT_TRUE(a.is_valid());
a.timeout_ = 1024;
a.no_clear_ = true;
a.signal_ = "signal";
int64_t len = a.get_serialize_size();
char buf[len];
LOG_INFO("action serialize size", K(len));
int64_t pos = 0;
ASSERT_EQ(OB_SUCCESS, a.serialize(buf, len, pos));
ASSERT_EQ(pos, len);
pos = 0;
ObDebugSyncAction b;
ASSERT_EQ(OB_SUCCESS, b.deserialize(buf, len, pos));
ASSERT_EQ(a.sync_point_, b.sync_point_);
ASSERT_EQ(a.timeout_, b.timeout_);
ASSERT_EQ(a.signal_, b.signal_);
ASSERT_EQ(a.wait_, b.wait_);
ASSERT_EQ(a.no_clear_, b.no_clear_);
}
TEST(common, ObDSActionArray)
{
ObDSActionArray aa;
ASSERT_TRUE(aa.is_empty());
ASSERT_FALSE(aa.is_active(NOW));
ObDebugSyncAction a;
a.sync_point_ = NOW;
a.execute_ = 2;
a.wait_ = "abc";
a.timeout_ = 1024000;
ASSERT_EQ(OB_SUCCESS, aa.add_action(a));
ASSERT_TRUE(aa.is_active(NOW));
ObDebugSyncAction b;
aa.copy_action(NOW, b);
ASSERT_EQ(a.get_serialize_size(), b.get_serialize_size());
// fetch to empty
ASSERT_EQ(OB_SUCCESS, aa.fetch_action(NOW, b));
ASSERT_FALSE(aa.is_empty());
ASSERT_EQ(OB_SUCCESS, aa.fetch_action(NOW, b));
ASSERT_TRUE(aa.is_empty());
ASSERT_EQ(OB_ENTRY_NOT_EXIST, aa.fetch_action(NOW, b));
ASSERT_EQ(OB_SUCCESS, aa.add_action(a));
ASSERT_EQ(OB_SUCCESS, aa.fetch_action(NOW, b));
// over write
ASSERT_EQ(OB_SUCCESS, aa.add_action(a));
ASSERT_EQ(OB_SUCCESS, aa.fetch_action(NOW, b));
ASSERT_EQ(OB_SUCCESS, aa.fetch_action(NOW, b));
ASSERT_TRUE(aa.is_empty());
ASSERT_EQ(OB_SUCCESS, aa.add_action(a));
ASSERT_FALSE(aa.is_empty());
aa.clear(NOW);
ASSERT_TRUE(aa.is_empty());
ASSERT_EQ(OB_SUCCESS, aa.add_action(a));
aa.clear_all();
ASSERT_TRUE(aa.is_empty());
ObDSActionArray ba;
ASSERT_EQ(OB_SUCCESS, ba.add_action(a));
const static int64_t BUF_SIZE = 1024;
char buf[BUF_SIZE];
int64_t len = aa.get_serialize_size();
LOG_INFO("empty debug sync array actions overhead", K(len));
int64_t pos = 0;
ASSERT_EQ(OB_SUCCESS, aa.serialize(buf, len, pos));
ASSERT_EQ(pos, len);
pos = 0;
ASSERT_EQ(OB_SUCCESS, ba.deserialize(buf, len, pos));
ASSERT_TRUE(ba.is_empty());
ASSERT_EQ(OB_SUCCESS, aa.add_action(a));
a.sync_point_ = MAJOR_FREEZE_BEFORE_SYS_COORDINATE_COMMIT;
ASSERT_EQ(OB_SUCCESS, aa.add_action(a));
len = aa.get_serialize_size();
pos = 0;
ASSERT_EQ(OB_SUCCESS, aa.serialize(buf, len, pos));
ASSERT_EQ(pos, len);
pos = 0;
ASSERT_EQ(OB_SUCCESS, ba.deserialize(buf, len, pos));
ASSERT_EQ(pos, len);
ASSERT_TRUE(ba.is_active(NOW));
ASSERT_TRUE(ba.is_active(MAJOR_FREEZE_BEFORE_SYS_COORDINATE_COMMIT));
// const action array will always be empty
const bool is_const = true;
ObDSActionArray ca(is_const);
pos = 0;
ASSERT_EQ(OB_SUCCESS, ca.deserialize(buf, len, pos));
ASSERT_EQ(pos, len);
ASSERT_FALSE(ca.is_active(NOW));
ASSERT_FALSE(ca.is_active(MAJOR_FREEZE_BEFORE_SYS_COORDINATE_COMMIT));
ASSERT_TRUE(ca.is_empty());
}
TEST(common, ObDSSessionActions)
{
ObMalloc allocator;
ObDSSessionActions sa;
ObDebugSyncAction a;
a.sync_point_ = NOW;
a.signal_ = "abc";
a.execute_ = 1024;
ASSERT_NE(OB_SUCCESS, sa.add_action(a));
ASSERT_EQ(OB_SUCCESS, sa.init(1024, allocator));
ASSERT_TRUE(sa.is_inited());
ASSERT_EQ(OB_SUCCESS, sa.add_action(a));
ObDSActionArray aa;
sa.to_thread_local(aa);
ASSERT_FALSE(aa.is_empty());
ASSERT_TRUE(aa.is_active(NOW));
aa.clear_all();
sa.get_thread_local_result(aa);
sa.to_thread_local(aa);
ASSERT_TRUE(aa.is_empty());
ASSERT_EQ(OB_SUCCESS, sa.add_action(a));
a.sync_point_ = MAJOR_FREEZE_BEFORE_SYS_COORDINATE_COMMIT;
ASSERT_EQ(OB_SUCCESS, aa.add_action(a));
sa.to_thread_local(aa);
ASSERT_TRUE(aa.is_active(NOW));
ASSERT_FALSE(aa.is_active(MAJOR_FREEZE_BEFORE_SYS_COORDINATE_COMMIT));
ASSERT_EQ(OB_SUCCESS, sa.add_action(a));
sa.clear(NOW);
sa.to_thread_local(aa);
ASSERT_FALSE(aa.is_active(NOW));
ASSERT_TRUE(aa.is_active(MAJOR_FREEZE_BEFORE_SYS_COORDINATE_COMMIT));
sa.clear_all();
sa.to_thread_local(aa);
ASSERT_TRUE(aa.is_empty());
}
class Timer
{
public:
Timer() { begin_ = ::oceanbase::common::ObTimeUtility::current_time(); }
int64_t used() const { return ::oceanbase::common::ObTimeUtility::current_time() - begin_; }
public:
int64_t begin_;
};
static ObDSEventControl global_event_control; // avoid large stack object
#define WAIT_TIME 200000
#define WAIT_TIME_SAFE (WAIT_TIME * 9 / 10)
#define TO_STRING_(x) #x
#define TO_STRING(x) "" TO_STRING_(x)
void *run_wait(void *arg)
{
ObDSEventControl *ec = static_cast<ObDSEventControl *>(arg);
ec->wait("multi-thread-event", WAIT_TIME, true);
return NULL;
}
TEST(common, ObDSEventControl)
{
ObDSEventControl &ec = global_event_control;
ASSERT_NE(OB_SUCCESS, ec.signal(""));
ObSqlString event;
for (int64_t i = 0; i < ec.MAX_EVENT_CNT; ++i) {
ASSERT_EQ(OB_SUCCESS, event.assign_fmt("%ld", i));
ASSERT_EQ(OB_SUCCESS, ec.signal(event.ptr())) << "event: " << event.ptr() << std::endl;
}
ASSERT_NE(OB_SUCCESS, ec.signal("e"));
ec.clear_event();
ASSERT_EQ(OB_SUCCESS, ec.signal("e"));
const bool DO_CLEAR = true;
const bool NO_CLEAR = false;
{
Timer t;
ASSERT_EQ(OB_SUCCESS, ec.wait("e", WAIT_TIME, NO_CLEAR));
ASSERT_LT(t.used(), WAIT_TIME_SAFE);
}
ASSERT_EQ(OB_SUCCESS, ec.signal("e"));
{
Timer t;
ASSERT_EQ(OB_SUCCESS, ec.wait("e", WAIT_TIME, DO_CLEAR));
ASSERT_EQ(OB_SUCCESS, ec.wait("e", WAIT_TIME, DO_CLEAR));
ASSERT_LT(t.used(), WAIT_TIME_SAFE);
}
{
Timer t;
ASSERT_EQ(OB_SUCCESS, ec.wait("e", WAIT_TIME, DO_CLEAR));
ASSERT_GT(t.used(), WAIT_TIME_SAFE);
}
{
Timer t;
ObArray<pthread_t> tids;
const int64_t MAX_THREAD_CNT = 10;
int64_t n = 0;
for (; n < MAX_THREAD_CNT / 2; ++n) {
ASSERT_EQ(OB_SUCCESS, ec.signal("multi-thread-event"));
}
for (int64_t i = 0; i < MAX_THREAD_CNT; ++i) {
pthread_t tid;
ASSERT_EQ(0, pthread_create(&tid, NULL, run_wait, &ec));
ASSERT_EQ(OB_SUCCESS, tids.push_back(tid));
}
for (; n < MAX_THREAD_CNT; ++n) {
ASSERT_EQ(OB_SUCCESS, ec.signal("multi-thread-event"));
}
for (int64_t i = 0; i < MAX_THREAD_CNT; ++i) {
pthread_join(tids.at(i), NULL);
}
ASSERT_LT(t.used(), WAIT_TIME_SAFE);
}
{
Timer t;
pthread_t tid;
ASSERT_EQ(0, pthread_create(&tid, NULL, run_wait, &ec));
ec.stop();
pthread_join(tid, NULL);
ASSERT_LT(t.used(), WAIT_TIME_SAFE);
}
}
TEST(debug_sync, ObDebugSync)
{
MockObCommonRpcProxy rpc;
GDS.set_rpc_proxy(&rpc);
ObMalloc allocator;
ObDSSessionActions sa;
ASSERT_EQ(OB_SUCCESS, sa.init(1024, allocator));
GCONF.debug_sync_timeout.set_value("0");
ASSERT_FALSE(GCONF.is_debug_sync_enabled());
ASSERT_NE(&GDS.rpc_spread_actions(), GDS.thread_local_actions());
// test debug sync parser
const bool L = false; // local
ASSERT_EQ(OB_SUCCESS, GDS.add_debug_sync(" reset ", L, sa));
ASSERT_EQ(OB_SUCCESS, GDS.add_debug_sync(" now clear ", L, sa));
ASSERT_EQ(OB_SUCCESS, GDS.add_debug_sync("now signal x", L, sa));
ASSERT_EQ(OB_SUCCESS, GDS.add_debug_sync(" now SIGNAL x-y execute 1024 ", L, sa));
ASSERT_EQ(OB_SUCCESS, GDS.add_debug_sync(" NOW signal x-y execute 1024 ", L, sa));
ASSERT_EQ(OB_SUCCESS, GDS.add_debug_sync(" now wait_for x-y ", L, sa));
ASSERT_EQ(OB_SUCCESS, GDS.add_debug_sync("now wait_for x-y no_clear_event", L, sa));
ASSERT_EQ(OB_SUCCESS, GDS.add_debug_sync(" now wait_for x-y no_clear_event execute 2 ", L, sa));
ASSERT_EQ(OB_SUCCESS, GDS.add_debug_sync(" now wait_for x-y timeout 1024 no_clear_event execute 2 ", L, sa));
ASSERT_EQ(OB_SUCCESS, GDS.add_debug_sync(" now wait_for x-y no_clear_event timeout 1024 execute 2 ", L, sa));
ASSERT_EQ(OB_SUCCESS, GDS.add_debug_sync(" now signal xxx wait_for x-y timeout 0 no_clear_event execute 2 ", L, sa));
ASSERT_NE(OB_SUCCESS, GDS.add_debug_sync(" reset a", L, sa));
ASSERT_NE(OB_SUCCESS, GDS.add_debug_sync(" signal b ", L, sa));
ASSERT_NE(OB_SUCCESS, GDS.add_debug_sync(" not_exist_sync_point signal b ", L, sa));
ASSERT_NE(OB_SUCCESS, GDS.add_debug_sync("now signal not-support-too-long-event-name-bigger-than-32-byte ", L, sa));
ASSERT_NE(OB_SUCCESS, GDS.add_debug_sync("now signal xyz execute 0", L, sa));
ASSERT_NE(OB_SUCCESS, GDS.add_debug_sync("now signal xyc unknow_parameters", L, sa));
ASSERT_NE(OB_SUCCESS, GDS.add_debug_sync("now clear unknow_parameters", L, sa));
ASSERT_NE(OB_SUCCESS, GDS.add_debug_sync("now wait_for xyc unknow_parameters", L, sa));
ASSERT_EQ(OB_SUCCESS, GDS.add_debug_sync(" reset ", L, sa));
GCONF.debug_sync_timeout.set_value("100000000");
ASSERT_TRUE(GCONF.is_debug_sync_enabled());
ASSERT_EQ(&GDS.rpc_spread_actions(), GDS.thread_local_actions());
// test set to thread local and collect result
ASSERT_EQ(OB_SUCCESS, GDS.add_debug_sync("reset", L, sa));
ASSERT_EQ(OB_SUCCESS, GDS.add_debug_sync("MAJOR_FREEZE_BEFORE_SYS_COORDINATE_COMMIT signal xyz", L, sa));
ASSERT_TRUE(GDS.rpc_spread_actions().is_active(MAJOR_FREEZE_BEFORE_SYS_COORDINATE_COMMIT));
ASSERT_EQ(OB_SUCCESS, GDS.add_debug_sync("MAJOR_FREEZE_BEFORE_SYS_COORDINATE_COMMIT clear", L, sa));
ASSERT_FALSE(GDS.rpc_spread_actions().is_active(MAJOR_FREEZE_BEFORE_SYS_COORDINATE_COMMIT));
ASSERT_EQ(OB_SUCCESS, GDS.add_debug_sync("MAJOR_FREEZE_BEFORE_SYS_COORDINATE_COMMIT signal xyz", L, sa));
GDS.rpc_spread_actions().clear_all();
GDS.set_thread_local_actions(sa);
ASSERT_TRUE(GDS.rpc_spread_actions().is_active(MAJOR_FREEZE_BEFORE_SYS_COORDINATE_COMMIT));
GDS.rpc_spread_actions().clear_all();
GDS.collect_result_actions(sa);
GDS.set_thread_local_actions(sa);
ASSERT_FALSE(GDS.rpc_spread_actions().is_active(MAJOR_FREEZE_BEFORE_SYS_COORDINATE_COMMIT));
// test execute
ASSERT_EQ(OB_SUCCESS, GDS.add_debug_sync("reset", L, sa));
{
Timer t;
ASSERT_EQ(OB_SUCCESS, GDS.add_debug_sync("now wait_for xyz timeout " TO_STRING(WAIT_TIME), L, sa));
ASSERT_GT(t.used(), WAIT_TIME_SAFE);
}
ASSERT_TRUE(GDS.rpc_spread_actions().is_empty());
ASSERT_EQ(OB_SUCCESS, GDS.add_debug_sync("MAJOR_FREEZE_BEFORE_SYS_COORDINATE_COMMIT signal xyz execute 2", L, sa));
DEBUG_SYNC(MAJOR_FREEZE_BEFORE_SYS_COORDINATE_COMMIT);
DEBUG_SYNC(MAJOR_FREEZE_BEFORE_SYS_COORDINATE_COMMIT);
DEBUG_SYNC(MAJOR_FREEZE_BEFORE_SYS_COORDINATE_COMMIT);
ASSERT_EQ(OB_SUCCESS, GDS.add_debug_sync("MAJOR_FREEZE_BEFORE_SYS_COORDINATE_COMMIT signal def wait_for xyz TIMEOUT " TO_STRING(WAIT_TIME) " execute 3", L, sa));
{
// get xyz
Timer t;
DEBUG_SYNC(MAJOR_FREEZE_BEFORE_SYS_COORDINATE_COMMIT);
DEBUG_SYNC(MAJOR_FREEZE_BEFORE_SYS_COORDINATE_COMMIT);
ASSERT_LT(t.used(), WAIT_TIME_SAFE);
}
{
// timeout
Timer t;
DEBUG_SYNC(MAJOR_FREEZE_BEFORE_SYS_COORDINATE_COMMIT);
ASSERT_GT(t.used(), WAIT_TIME_SAFE);
}
{
// not active
Timer t;
DEBUG_SYNC(MAJOR_FREEZE_BEFORE_SYS_COORDINATE_COMMIT);
ASSERT_LT(t.used(), WAIT_TIME_SAFE);
}
{
// get def
Timer t;
ASSERT_EQ(OB_SUCCESS, GDS.add_debug_sync("NOW wait_for def TIMEout " TO_STRING(WAIT_TIME), L, sa));
ASSERT_EQ(OB_SUCCESS, GDS.add_debug_sync("NOW wait_for def TIMEout " TO_STRING(WAIT_TIME), L, sa));
ASSERT_EQ(OB_SUCCESS, GDS.add_debug_sync("NOW wait_for def TIMEout " TO_STRING(WAIT_TIME), L, sa));
ASSERT_LT(t.used(), WAIT_TIME_SAFE);
}
{
// timeout
Timer t;
ASSERT_EQ(OB_SUCCESS, GDS.add_debug_sync("NOW wait_for def TIMEout " TO_STRING(WAIT_TIME), L, sa));
ASSERT_GT(t.used(), WAIT_TIME_SAFE);
}
// global actions
const bool G = true; // global
{
ASSERT_EQ(OB_SUCCESS, GDS.add_debug_sync("reset", L, sa));
EXPECT_CALL(rpc, broadcast_ds_action(_, _)).Times(3).WillRepeatedly(Return(OB_SUCCESS));
ASSERT_EQ(OB_SUCCESS, GDS.add_debug_sync("reset", G, sa));
ASSERT_EQ(OB_SUCCESS, GDS.add_debug_sync("now clear", G, sa));
ASSERT_EQ(OB_SUCCESS, GDS.add_debug_sync("now signal x", G, sa));
}
{
// mock rpc will not wait
Timer t;
EXPECT_CALL(rpc, broadcast_ds_action(_, _)).Times(2).WillRepeatedly(Return(OB_SUCCESS));
ASSERT_EQ(OB_SUCCESS, GDS.add_debug_sync("reset", G, sa));
ASSERT_EQ(OB_SUCCESS, GDS.add_debug_sync("NOW wait_for def TIMEout " TO_STRING(WAIT_TIME), G, sa));
ASSERT_LT(t.used(), WAIT_TIME_SAFE);
}
}
TEST(debug_sync, debug_sync_action_overflow)
{
ObDSActionArray dsa;
ObDebugSyncAction action;
action.sync_point_ = NOW;
action.signal_ = "a";
action.wait_ = "b";
action.execute_ = 1;
ASSERT_TRUE(action.is_valid());
for (int i = 0; i < ObDSActionArray::MAX_DEBUG_SYNC_CACHED_POINT; i++) {
action.sync_point_ = (oceanbase::common::ObDebugSyncPoint)(i + 1);
ASSERT_EQ(OB_SUCCESS, dsa.add_action(action));
ASSERT_TRUE(dsa.is_active((oceanbase::common::ObDebugSyncPoint)(i + 1 )));
}
action.sync_point_ = (oceanbase::common::ObDebugSyncPoint)(ObDSActionArray::MAX_DEBUG_SYNC_CACHED_POINT + 1);
ASSERT_EQ(OB_SIZE_OVERFLOW, dsa.add_action(action));
ASSERT_FALSE(dsa.is_active((oceanbase::common::ObDebugSyncPoint)(ObDSActionArray::MAX_DEBUG_SYNC_CACHED_POINT + 1)));
}
}
}
int main(int argc, char **argv)
{
oceanbase::common::ObLogger::get_logger().set_log_level("INFO");
OB_LOGGER.set_log_level("INFO");
::testing::InitGoogleTest(&argc,argv);
return RUN_ALL_TESTS();
}