461 lines
19 KiB
C++
461 lines
19 KiB
C++
// owner: shenyunlong.syl
|
|
// owner group: shenzhen
|
|
|
|
/**
|
|
* Copyright (c) 2022 OceanBase
|
|
* OceanBase CE is licensed under Mulan PubL v2.
|
|
* You can use this software according to the terms and conditions of the Mulan PubL v2.
|
|
* You may obtain a copy of Mulan PubL v2 at:
|
|
* http://license.coscl.org.cn/MulanPubL-2.0
|
|
* THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
|
|
* EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
|
|
* MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
|
|
* See the Mulan PubL v2 for more details.
|
|
*/
|
|
|
|
#include <gtest/gtest.h>
|
|
#define private public
|
|
#define protected public
|
|
#include "mock_tenant_module_env.h"
|
|
|
|
using namespace oceanbase;
|
|
using namespace oceanbase::common;
|
|
using namespace oceanbase::table;
|
|
using namespace oceanbase::transaction;
|
|
using namespace oceanbase::share;
|
|
|
|
class TestHTableLock: public ::testing::Test
|
|
{
|
|
public:
|
|
TestHTableLock() {}
|
|
static void SetUpTestCase()
|
|
{
|
|
EXPECT_EQ(OB_SUCCESS, MockTenantModuleEnv::get_instance().init());
|
|
}
|
|
static void TearDownTestCase()
|
|
{
|
|
MockTenantModuleEnv::get_instance().destroy();
|
|
}
|
|
void SetUp()
|
|
{
|
|
ASSERT_TRUE(MockTenantModuleEnv::get_instance().is_inited());
|
|
}
|
|
virtual ~TestHTableLock() {}
|
|
private:
|
|
DISALLOW_COPY_AND_ASSIGN(TestHTableLock);
|
|
};
|
|
|
|
class TestConcurrentHTableLock : public ObThreadPool
|
|
{
|
|
public:
|
|
explicit TestConcurrentHTableLock(ObHTableLockMgr* mgr, const int64_t thread_cnt, const uint64_t table_id, const ObString &key, ObHTableLockMode mode, bool can_retry = false)
|
|
: mgr(mgr),
|
|
thread_cnt_(thread_cnt),
|
|
table_id_(table_id),
|
|
key_(key),
|
|
mode_(mode),
|
|
fake_addr_(),
|
|
can_retry_(can_retry)
|
|
{
|
|
set_thread_count(thread_cnt);
|
|
}
|
|
virtual ~TestConcurrentHTableLock() {};
|
|
virtual void run1();
|
|
virtual void process() = 0;
|
|
|
|
private:
|
|
ObHTableLockMgr* mgr;
|
|
const int64_t thread_cnt_;
|
|
const uint64_t table_id_;
|
|
const ObString key_;
|
|
ObHTableLockMode mode_;
|
|
ObAddr fake_addr_;
|
|
bool can_retry_;
|
|
};
|
|
|
|
void TestConcurrentHTableLock::run1()
|
|
{
|
|
ObArenaAllocator alloc;
|
|
ObTransID fake_tx_id;
|
|
ObString local_key;
|
|
ObHTableLockHandle *lock_handle = nullptr;
|
|
ASSERT_EQ(OB_SUCCESS, ob_write_string(alloc, key_, local_key));
|
|
ASSERT_EQ(OB_SUCCESS, mgr->acquire_handle(fake_tx_id, lock_handle));
|
|
int ret = OB_SUCCESS;
|
|
ret = mgr->lock_row(table_id_, local_key, mode_, *lock_handle);
|
|
if (can_retry_) {
|
|
while (ret == OB_TRY_LOCK_ROW_CONFLICT) {
|
|
ret = mgr->lock_row(table_id_, local_key, mode_, *lock_handle);
|
|
}
|
|
}
|
|
ASSERT_EQ(OB_SUCCESS, ret);
|
|
process();
|
|
ASSERT_EQ(OB_SUCCESS, mgr->release_handle(*lock_handle));
|
|
}
|
|
|
|
class TestConcurrentHTableSLock : public TestConcurrentHTableLock
|
|
{
|
|
public:
|
|
TestConcurrentHTableSLock(ObHTableLockMgr* mgr, const int64_t thread_cnt, const uint64_t table_id, const ObString &key, bool can_retry = false)
|
|
: TestConcurrentHTableLock(mgr, thread_cnt, table_id, key, ObHTableLockMode::SHARED, can_retry)
|
|
{}
|
|
virtual ~TestConcurrentHTableSLock() {};
|
|
virtual void process() override;
|
|
};
|
|
|
|
void TestConcurrentHTableSLock::process()
|
|
{
|
|
usleep(1*1000); // 1ms, for processing
|
|
}
|
|
|
|
class TestConcurrentHTableXLock : public TestConcurrentHTableLock
|
|
{
|
|
public:
|
|
TestConcurrentHTableXLock(ObHTableLockMgr* mgr, const int64_t thread_cnt, const uint64_t table_id, const ObString &key)
|
|
: TestConcurrentHTableLock(mgr, thread_cnt, table_id, key, ObHTableLockMode::EXCLUSIVE, true),
|
|
value_(0)
|
|
{}
|
|
virtual ~TestConcurrentHTableXLock() {};
|
|
virtual void process() override;
|
|
void check_result();
|
|
|
|
private:
|
|
uint64_t value_;
|
|
};
|
|
|
|
void TestConcurrentHTableXLock::process()
|
|
{
|
|
uint64_t value = value_;
|
|
usleep(1*1000); // 1ms, for processing
|
|
value_ = value + 1;
|
|
}
|
|
|
|
void TestConcurrentHTableXLock::check_result()
|
|
{
|
|
ASSERT_EQ(value_, thread_cnt_);
|
|
}
|
|
|
|
TEST_F(TestHTableLock, basic_test)
|
|
{
|
|
EXPECT_EQ(OB_SYS_TENANT_ID, MTL_ID());
|
|
ObTransID fake_tx_id;
|
|
ObHTableLockHandle *lock_handle = nullptr;
|
|
uint64_t fake_table_id = 1;
|
|
ObString fake_key = ObString::make_string("k1");
|
|
// 1. acquire htable lock handle for a running tx
|
|
ASSERT_EQ(OB_SUCCESS, HTABLE_LOCK_MGR->acquire_handle(fake_tx_id, lock_handle));
|
|
ASSERT_TRUE(lock_handle != nullptr);
|
|
// 2. add htable lock on htable row in demand during tx
|
|
ASSERT_EQ(OB_SUCCESS, HTABLE_LOCK_MGR->lock_row(fake_table_id, fake_key, ObHTableLockMode::SHARED, *lock_handle));
|
|
// 3. release htable lock handle after transaction commit or rollback
|
|
ASSERT_EQ(OB_SUCCESS, HTABLE_LOCK_MGR->release_handle(*lock_handle));
|
|
}
|
|
|
|
TEST_F(TestHTableLock, lock_different_keys)
|
|
{
|
|
EXPECT_EQ(OB_SYS_TENANT_ID, MTL_ID());
|
|
ObTransID fake_tx_id;
|
|
ObHTableLockHandle *lock_handle = nullptr;
|
|
uint64_t fake_table_id = 1;
|
|
ObString fake_key1 = ObString::make_string("k1");
|
|
ObString fake_key2 = ObString::make_string("k2");
|
|
ObHTableLockKey lock_key1(fake_table_id, fake_key1);
|
|
ObHTableLockKey lock_key2(fake_table_id, fake_key2);
|
|
ObHTableLockKey *tmp_lock_key = nullptr;
|
|
ObHTableLock *tmp_lock = nullptr;
|
|
|
|
ASSERT_EQ(OB_SUCCESS, HTABLE_LOCK_MGR->acquire_handle(fake_tx_id, lock_handle));
|
|
ASSERT_TRUE(lock_handle != nullptr);
|
|
ASSERT_EQ(fake_tx_id, lock_handle->tx_id_);
|
|
ASSERT_EQ(nullptr, lock_handle->lock_nodes_);
|
|
|
|
// lock fake_key1 in share mode
|
|
ASSERT_EQ(OB_SUCCESS, HTABLE_LOCK_MGR->lock_row(fake_table_id, fake_key1, ObHTableLockMode::SHARED, *lock_handle));
|
|
// check lock handle
|
|
ASSERT_EQ(ObHTableLockMode::SHARED, lock_handle->lock_nodes_->lock_mode_);
|
|
ASSERT_EQ(fake_table_id, lock_handle->lock_nodes_->lock_key_->table_id_);
|
|
ASSERT_EQ(fake_key1, lock_handle->lock_nodes_->lock_key_->key_);
|
|
// check lock map
|
|
ASSERT_EQ(1, HTABLE_LOCK_MGR->lock_map_.count());
|
|
ObHTableLockMgr::ObHTableLockMap::BlurredIterator it(HTABLE_LOCK_MGR->lock_map_);
|
|
ASSERT_EQ(OB_SUCCESS, it.next(tmp_lock_key, tmp_lock));
|
|
ASSERT_TRUE(tmp_lock_key != nullptr);
|
|
ASSERT_EQ(lock_key1, *tmp_lock_key);
|
|
ASSERT_TRUE(tmp_lock_key->key_.ptr() != fake_key1.ptr()); // ensure it's deep copy
|
|
ASSERT_EQ(lock_handle->lock_nodes_->lock_key_->key_.ptr(), tmp_lock_key->key_.ptr());
|
|
ASSERT_TRUE(tmp_lock->is_locked());
|
|
ASSERT_TRUE(tmp_lock->is_rdlocked());
|
|
ASSERT_TRUE(tmp_lock->can_escalate_lock());
|
|
ASSERT_TRUE(!tmp_lock->is_wrlocked());
|
|
|
|
// lock fake_key2 in exclusive mode
|
|
ASSERT_EQ(OB_SUCCESS, HTABLE_LOCK_MGR->lock_row(fake_table_id, fake_key2, ObHTableLockMode::EXCLUSIVE, *lock_handle));
|
|
// check lock handle
|
|
ASSERT_EQ(ObHTableLockMode::EXCLUSIVE, lock_handle->lock_nodes_->lock_mode_);
|
|
ASSERT_EQ(fake_table_id, lock_handle->lock_nodes_->lock_key_->table_id_);
|
|
ASSERT_EQ(fake_key2, lock_handle->lock_nodes_->lock_key_->key_);
|
|
ASSERT_EQ(ObHTableLockMode::SHARED, lock_handle->lock_nodes_->next_->lock_mode_);
|
|
ASSERT_EQ(fake_table_id, lock_handle->lock_nodes_->next_->lock_key_->table_id_);
|
|
ASSERT_EQ(fake_key1, lock_handle->lock_nodes_->next_->lock_key_->key_);
|
|
// check lock map
|
|
tmp_lock = nullptr;
|
|
ASSERT_EQ(2, HTABLE_LOCK_MGR->lock_map_.count());
|
|
ASSERT_EQ(OB_SUCCESS, HTABLE_LOCK_MGR->lock_map_.get(&lock_key1, tmp_lock));
|
|
ASSERT_TRUE(tmp_lock != nullptr);
|
|
ASSERT_TRUE(tmp_lock->is_locked());
|
|
ASSERT_TRUE(tmp_lock->is_rdlocked());
|
|
ASSERT_TRUE(tmp_lock->can_escalate_lock());
|
|
ASSERT_TRUE(!tmp_lock->is_wrlocked());
|
|
tmp_lock = nullptr;
|
|
ASSERT_EQ(OB_SUCCESS, HTABLE_LOCK_MGR->lock_map_.get(&lock_key2, tmp_lock));
|
|
ASSERT_TRUE(tmp_lock != nullptr);
|
|
ASSERT_TRUE(tmp_lock->is_locked());
|
|
ASSERT_TRUE(!tmp_lock->is_rdlocked());
|
|
ASSERT_TRUE(!tmp_lock->can_escalate_lock());
|
|
ASSERT_TRUE(tmp_lock->is_wrlocked());
|
|
|
|
ASSERT_EQ(OB_SUCCESS, HTABLE_LOCK_MGR->release_handle(*lock_handle));
|
|
}
|
|
|
|
TEST_F(TestHTableLock, share_share)
|
|
{
|
|
EXPECT_EQ(OB_SYS_TENANT_ID, MTL_ID());
|
|
ObTransID fake_tx_id1(1);
|
|
ObTransID fake_tx_id2(2);
|
|
ObHTableLockHandle *lock_handle1 = nullptr;
|
|
ObHTableLockHandle *lock_handle2 = nullptr;
|
|
uint64_t fake_table_id = 1;
|
|
ObString fake_key = ObString::make_string("k1");
|
|
ObHTableLockKey lock_key(fake_table_id, fake_key);
|
|
ObHTableLockKey *tmp_lock_key = nullptr;
|
|
ObHTableLock *tmp_lock = nullptr;
|
|
|
|
ASSERT_EQ(OB_SUCCESS, HTABLE_LOCK_MGR->acquire_handle(fake_tx_id1, lock_handle1));
|
|
ASSERT_TRUE(lock_handle1 != nullptr);
|
|
ASSERT_EQ(OB_SUCCESS, HTABLE_LOCK_MGR->acquire_handle(fake_tx_id2, lock_handle2));
|
|
ASSERT_TRUE(lock_handle2 != nullptr);
|
|
|
|
// two lock handles try to add share lock on one row concurrently return success
|
|
ASSERT_EQ(OB_SUCCESS, HTABLE_LOCK_MGR->lock_row(fake_table_id, fake_key, ObHTableLockMode::SHARED, *lock_handle1));
|
|
ASSERT_EQ(OB_SUCCESS, HTABLE_LOCK_MGR->lock_row(fake_table_id, fake_key, ObHTableLockMode::SHARED, *lock_handle2));
|
|
|
|
ASSERT_EQ(OB_SUCCESS, HTABLE_LOCK_MGR->release_handle(*lock_handle1));
|
|
ASSERT_EQ(OB_SUCCESS, HTABLE_LOCK_MGR->release_handle(*lock_handle2));
|
|
}
|
|
|
|
TEST_F(TestHTableLock, share_exclusive)
|
|
{
|
|
EXPECT_EQ(OB_SYS_TENANT_ID, MTL_ID());
|
|
ObTransID fake_tx_id1(1);
|
|
ObTransID fake_tx_id2(2);
|
|
ObHTableLockHandle *lock_handle1 = nullptr;
|
|
ObHTableLockHandle *lock_handle2 = nullptr;
|
|
uint64_t fake_table_id = 1;
|
|
ObString fake_key = ObString::make_string("k1");
|
|
ObHTableLockKey lock_key(fake_table_id, fake_key);
|
|
ObHTableLockKey *tmp_lock_key = nullptr;
|
|
ObHTableLock *tmp_lock = nullptr;
|
|
|
|
// acquire lock handle1 and lock handle2
|
|
ASSERT_EQ(OB_SUCCESS, HTABLE_LOCK_MGR->acquire_handle(fake_tx_id1, lock_handle1));
|
|
ASSERT_TRUE(lock_handle1 != nullptr);
|
|
ASSERT_EQ(OB_SUCCESS, HTABLE_LOCK_MGR->acquire_handle(fake_tx_id2, lock_handle2));
|
|
ASSERT_TRUE(lock_handle2 != nullptr);
|
|
|
|
// lock handle1 add share lock, and lock handle2 add exclusive lock
|
|
ASSERT_EQ(OB_SUCCESS, HTABLE_LOCK_MGR->lock_row(fake_table_id, fake_key, ObHTableLockMode::SHARED, *lock_handle1));
|
|
ASSERT_EQ(OB_TRY_LOCK_ROW_CONFLICT, HTABLE_LOCK_MGR->lock_row(fake_table_id, fake_key, ObHTableLockMode::EXCLUSIVE, *lock_handle2));
|
|
|
|
// release lock handle1 and handle2 and acquire again
|
|
ASSERT_EQ(OB_SUCCESS, HTABLE_LOCK_MGR->release_handle(*lock_handle1));
|
|
ASSERT_EQ(OB_SUCCESS, HTABLE_LOCK_MGR->release_handle(*lock_handle2));
|
|
lock_handle1 = nullptr;
|
|
lock_handle2 = nullptr;
|
|
ASSERT_EQ(OB_SUCCESS, HTABLE_LOCK_MGR->acquire_handle(fake_tx_id1, lock_handle1));
|
|
ASSERT_TRUE(lock_handle1 != nullptr);
|
|
ASSERT_EQ(OB_SUCCESS, HTABLE_LOCK_MGR->acquire_handle(fake_tx_id2, lock_handle2));
|
|
ASSERT_TRUE(lock_handle2 != nullptr);
|
|
|
|
// lock handle1 add exclusive lock, and lock handle2 add share lock
|
|
ASSERT_EQ(OB_SUCCESS, HTABLE_LOCK_MGR->lock_row(fake_table_id, fake_key, ObHTableLockMode::EXCLUSIVE, *lock_handle1));
|
|
ASSERT_EQ(OB_TRY_LOCK_ROW_CONFLICT, HTABLE_LOCK_MGR->lock_row(fake_table_id, fake_key, ObHTableLockMode::SHARED, *lock_handle2));
|
|
|
|
ASSERT_EQ(OB_SUCCESS, HTABLE_LOCK_MGR->release_handle(*lock_handle1));
|
|
ASSERT_EQ(OB_SUCCESS, HTABLE_LOCK_MGR->release_handle(*lock_handle2));
|
|
}
|
|
|
|
TEST_F(TestHTableLock, exclusive_exclusive)
|
|
{
|
|
EXPECT_EQ(OB_SYS_TENANT_ID, MTL_ID());
|
|
ObTransID fake_tx_id1(1);
|
|
ObTransID fake_tx_id2(2);
|
|
ObHTableLockHandle *lock_handle1 = nullptr;
|
|
ObHTableLockHandle *lock_handle2 = nullptr;
|
|
uint64_t fake_table_id = 1;
|
|
ObString fake_key = ObString::make_string("k1");
|
|
ObHTableLockKey lock_key(fake_table_id, fake_key);
|
|
ObHTableLockKey *tmp_lock_key = nullptr;
|
|
ObHTableLock *tmp_lock = nullptr;
|
|
|
|
ASSERT_EQ(OB_SUCCESS, HTABLE_LOCK_MGR->acquire_handle(fake_tx_id1, lock_handle1));
|
|
ASSERT_TRUE(lock_handle1 != nullptr);
|
|
ASSERT_EQ(OB_SUCCESS, HTABLE_LOCK_MGR->acquire_handle(fake_tx_id2, lock_handle2));
|
|
ASSERT_TRUE(lock_handle2 != nullptr);
|
|
|
|
// lock handle1 add exclusive lock, and lock handle2 add exclusive lock
|
|
ASSERT_EQ(OB_SUCCESS, HTABLE_LOCK_MGR->lock_row(fake_table_id, fake_key, ObHTableLockMode::EXCLUSIVE, *lock_handle1));
|
|
ASSERT_EQ(OB_TRY_LOCK_ROW_CONFLICT, HTABLE_LOCK_MGR->lock_row(fake_table_id, fake_key, ObHTableLockMode::EXCLUSIVE, *lock_handle2));
|
|
|
|
// release lock handle1
|
|
ASSERT_EQ(OB_SUCCESS, HTABLE_LOCK_MGR->release_handle(*lock_handle1));
|
|
// lock handle2 try to add exclusive lock again
|
|
ASSERT_EQ(OB_SUCCESS, HTABLE_LOCK_MGR->lock_row(fake_table_id, fake_key, ObHTableLockMode::EXCLUSIVE, *lock_handle2));
|
|
// release lock handle2
|
|
ASSERT_EQ(OB_SUCCESS, HTABLE_LOCK_MGR->release_handle(*lock_handle2));
|
|
}
|
|
|
|
|
|
TEST_F(TestHTableLock, repeat_lock_one_row)
|
|
{
|
|
EXPECT_EQ(OB_SYS_TENANT_ID, MTL_ID());
|
|
ObTransID fake_tx_id;
|
|
ObHTableLockHandle *lock_handle = nullptr;
|
|
ObHTableLockHandle *lock_handle2 = nullptr;
|
|
uint64_t fake_table_id = 1;
|
|
ObString fake_key = ObString::make_string("k1");
|
|
ObHTableLockKey lock_key(fake_table_id, fake_key);
|
|
ASSERT_EQ(OB_SUCCESS, HTABLE_LOCK_MGR->acquire_handle(fake_tx_id, lock_handle));
|
|
ASSERT_EQ(OB_SUCCESS, HTABLE_LOCK_MGR->acquire_handle(fake_tx_id, lock_handle2));
|
|
ASSERT_TRUE(lock_handle != nullptr);
|
|
ASSERT_TRUE(lock_handle2 != nullptr);
|
|
|
|
// add intial share lock
|
|
ASSERT_EQ(OB_SUCCESS, HTABLE_LOCK_MGR->lock_row(fake_table_id, fake_key, ObHTableLockMode::SHARED, *lock_handle));
|
|
|
|
// 1. share -> share, noting changed
|
|
ASSERT_EQ(OB_SUCCESS, HTABLE_LOCK_MGR->lock_row(fake_table_id, fake_key, ObHTableLockMode::SHARED, *lock_handle));
|
|
ASSERT_TRUE(lock_handle->lock_nodes_ != nullptr);
|
|
ASSERT_EQ(ObHTableLockMode::SHARED, lock_handle->lock_nodes_->lock_mode_);
|
|
ASSERT_EQ(nullptr, lock_handle->lock_nodes_->next_);
|
|
ASSERT_EQ(lock_key, *lock_handle->lock_nodes_->lock_key_);
|
|
// the others try to add lock
|
|
ASSERT_EQ(OB_TRY_LOCK_ROW_CONFLICT, HTABLE_LOCK_MGR->lock_row(fake_table_id, fake_key, ObHTableLockMode::EXCLUSIVE, *lock_handle2));
|
|
ASSERT_EQ(OB_SUCCESS, HTABLE_LOCK_MGR->lock_row(fake_table_id, fake_key, ObHTableLockMode::SHARED, *lock_handle2));
|
|
|
|
// 2. share -> exclusive, will escalate share lock to exclusive lock when no one else holds the lock
|
|
// lock handle2 hold the share lock too, escalate lock failed
|
|
ASSERT_EQ(OB_TRY_LOCK_ROW_CONFLICT, HTABLE_LOCK_MGR->lock_row(fake_table_id, fake_key, ObHTableLockMode::EXCLUSIVE, *lock_handle));
|
|
ASSERT_EQ(OB_SUCCESS, HTABLE_LOCK_MGR->release_handle(*lock_handle2));
|
|
lock_handle2 = nullptr;
|
|
// lock handle2 release the shared lock, escalate lock success
|
|
ASSERT_EQ(OB_SUCCESS, HTABLE_LOCK_MGR->lock_row(fake_table_id, fake_key, ObHTableLockMode::EXCLUSIVE, *lock_handle));
|
|
ASSERT_EQ(ObHTableLockMode::EXCLUSIVE, lock_handle->lock_nodes_->lock_mode_);
|
|
ASSERT_EQ(nullptr, lock_handle->lock_nodes_->next_);
|
|
ASSERT_EQ(lock_key, *lock_handle->lock_nodes_->lock_key_);
|
|
// the others try to add lock
|
|
ASSERT_EQ(OB_SUCCESS, HTABLE_LOCK_MGR->acquire_handle(fake_tx_id, lock_handle2));
|
|
ASSERT_TRUE(lock_handle2 != nullptr);
|
|
ASSERT_EQ(OB_TRY_LOCK_ROW_CONFLICT, HTABLE_LOCK_MGR->lock_row(fake_table_id, fake_key, ObHTableLockMode::EXCLUSIVE, *lock_handle2));
|
|
ASSERT_EQ(OB_TRY_LOCK_ROW_CONFLICT, HTABLE_LOCK_MGR->lock_row(fake_table_id, fake_key, ObHTableLockMode::SHARED, *lock_handle2));
|
|
|
|
// 3. exclusive -> share, still hold exclusive lock
|
|
ASSERT_EQ(OB_SUCCESS, HTABLE_LOCK_MGR->lock_row(fake_table_id, fake_key, ObHTableLockMode::SHARED, *lock_handle));
|
|
ASSERT_TRUE(lock_handle->lock_nodes_ != nullptr);
|
|
ASSERT_EQ(ObHTableLockMode::EXCLUSIVE, lock_handle->lock_nodes_->lock_mode_);
|
|
ASSERT_EQ(nullptr, lock_handle->lock_nodes_->next_);
|
|
ASSERT_EQ(lock_key, *lock_handle->lock_nodes_->lock_key_);
|
|
// the others try to add lock
|
|
ASSERT_TRUE(lock_handle->lock_nodes_ != nullptr);
|
|
ASSERT_EQ(OB_TRY_LOCK_ROW_CONFLICT, HTABLE_LOCK_MGR->lock_row(fake_table_id, fake_key, ObHTableLockMode::EXCLUSIVE, *lock_handle2));
|
|
ASSERT_EQ(OB_TRY_LOCK_ROW_CONFLICT, HTABLE_LOCK_MGR->lock_row(fake_table_id, fake_key, ObHTableLockMode::SHARED, *lock_handle2));
|
|
|
|
// 4. exclusive -> exclusive, nothing changed
|
|
ASSERT_EQ(OB_SUCCESS, HTABLE_LOCK_MGR->lock_row(fake_table_id, fake_key, ObHTableLockMode::SHARED, *lock_handle));
|
|
ASSERT_TRUE(lock_handle->lock_nodes_ != nullptr);
|
|
ASSERT_EQ(ObHTableLockMode::EXCLUSIVE, lock_handle->lock_nodes_->lock_mode_);
|
|
ASSERT_EQ(nullptr, lock_handle->lock_nodes_->next_);
|
|
ASSERT_EQ(lock_key, *lock_handle->lock_nodes_->lock_key_);
|
|
// the others try to add lock
|
|
ASSERT_EQ(OB_TRY_LOCK_ROW_CONFLICT, HTABLE_LOCK_MGR->lock_row(fake_table_id, fake_key, ObHTableLockMode::EXCLUSIVE, *lock_handle2));
|
|
ASSERT_EQ(OB_TRY_LOCK_ROW_CONFLICT, HTABLE_LOCK_MGR->lock_row(fake_table_id, fake_key, ObHTableLockMode::SHARED, *lock_handle2));
|
|
|
|
ASSERT_EQ(OB_SUCCESS, HTABLE_LOCK_MGR->release_handle(*lock_handle));
|
|
ASSERT_EQ(OB_SUCCESS, HTABLE_LOCK_MGR->release_handle(*lock_handle2));
|
|
}
|
|
|
|
TEST_F(TestHTableLock, concurrent_shared_lock)
|
|
{
|
|
EXPECT_EQ(OB_SYS_TENANT_ID, MTL_ID());
|
|
const uint64_t thread_cnt = 2048;
|
|
const uint64_t fake_table_id = 1;
|
|
ObString key = ObString::make_string("k1");
|
|
const int64_t start = ObTimeUtility::current_time();
|
|
TestConcurrentHTableSLock multi_thread(HTABLE_LOCK_MGR, thread_cnt, fake_table_id, key);
|
|
ASSERT_EQ(OB_SUCCESS, multi_thread.start());
|
|
multi_thread.wait();
|
|
const int64_t duration = ObTimeUtility::current_time() - start;
|
|
printf("thread_cnt: %ld, time elapsed: %ldms\n", thread_cnt, duration/1000);
|
|
}
|
|
|
|
TEST_F(TestHTableLock, concurrent_exclusive_lock)
|
|
{
|
|
EXPECT_EQ(OB_SYS_TENANT_ID, MTL_ID());
|
|
const uint64_t thread_cnt = 100;
|
|
const uint64_t fake_table_id = 1;
|
|
ObString key = ObString::make_string("k1");
|
|
const int64_t start = ObTimeUtility::current_time();
|
|
TestConcurrentHTableXLock multi_thread(HTABLE_LOCK_MGR, thread_cnt, fake_table_id, key);
|
|
ASSERT_EQ(OB_SUCCESS, multi_thread.start());
|
|
multi_thread.wait();
|
|
multi_thread.check_result();
|
|
const int64_t duration = ObTimeUtility::current_time() - start;
|
|
printf("thread_cnt: %ld, time elapsed: %ldms\n", thread_cnt, duration/1000);
|
|
}
|
|
|
|
TEST_F(TestHTableLock, concurrent_exclusive_shared_lock)
|
|
{
|
|
EXPECT_EQ(OB_SYS_TENANT_ID, MTL_ID());
|
|
const uint64_t xthread_cnt = 100;
|
|
const uint64_t sthread_cnt = 1024;
|
|
const uint64_t fake_table_id = 1;
|
|
ObString key = ObString::make_string("k1");
|
|
const int64_t start = ObTimeUtility::current_time();
|
|
TestConcurrentHTableXLock multi_xthread(HTABLE_LOCK_MGR, xthread_cnt, fake_table_id, key);
|
|
TestConcurrentHTableSLock multi_sthread1(HTABLE_LOCK_MGR, sthread_cnt, fake_table_id, key, true);
|
|
ASSERT_EQ(OB_SUCCESS, multi_xthread.start());
|
|
ASSERT_EQ(OB_SUCCESS, multi_sthread1.start());
|
|
sleep(3);
|
|
TestConcurrentHTableSLock multi_sthread2(HTABLE_LOCK_MGR, sthread_cnt, fake_table_id, key, true);
|
|
ASSERT_EQ(OB_SUCCESS, multi_sthread2.start());
|
|
sleep(3);
|
|
TestConcurrentHTableSLock multi_sthread3(HTABLE_LOCK_MGR, sthread_cnt, fake_table_id, key, true);
|
|
ASSERT_EQ(OB_SUCCESS, multi_sthread3.start());
|
|
multi_xthread.wait();
|
|
multi_sthread1.wait();
|
|
multi_sthread2.wait();
|
|
multi_sthread3.wait();
|
|
multi_xthread.check_result();
|
|
const int64_t duration = ObTimeUtility::current_time() - start;
|
|
printf("exclusive thread cnt: %ld, shared thread cnt: %ld, time elapsed: %ldms\n",
|
|
xthread_cnt, sthread_cnt, duration/1000);
|
|
}
|
|
|
|
// NOTE: Put this test at the end of the whole test case to check whether memory leak exists or not
|
|
TEST_F(TestHTableLock, check_mem)
|
|
{
|
|
EXPECT_EQ(OB_SYS_TENANT_ID, MTL_ID());
|
|
ASSERT_EQ(0, HTABLE_LOCK_MGR->allocator_.normal_used_);
|
|
ASSERT_EQ(0, HTABLE_LOCK_MGR->allocator_.special_total_);
|
|
ASSERT_EQ(1, HTABLE_LOCK_MGR->allocator_.current_using_->ref_count_);
|
|
ASSERT_EQ(0, HTABLE_LOCK_MGR->allocator_.special_page_list_.size_);
|
|
ASSERT_EQ(0, HTABLE_LOCK_MGR->allocator_.using_page_list_.size_);
|
|
}
|
|
|
|
int main(int argc, char **argv)
|
|
{
|
|
OB_LOGGER.set_log_level("INFO");
|
|
OB_LOGGER.set_file_name("test_htable_lock.log", true);
|
|
::testing::InitGoogleTest(&argc,argv);
|
|
return RUN_ALL_TESTS();
|
|
}
|