Files
oceanbase/mittest/mtlenv/storage/test_macro_ref_cnt.cpp
2023-07-19 02:12:23 +00:00

364 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.
*/
#include <gtest/gtest.h>
#include <gmock/gmock.h>
#define USING_LOG_PREFIX STORAGE
#include <unordered_map>
#define protected public
#define private public
#include "storage/ls/ob_ls.h"
#include "storage/ls/ob_ls_tablet_service.h"
#include "storage/meta_mem/ob_tenant_meta_mem_mgr.h"
#include "storage/tablet/ob_tablet_persister.h"
#include "mittest/mtlenv/storage/blocksstable/ob_index_block_data_prepare.h"
#include "storage/blocksstable/ob_block_manager.h"
#include "storage/schema_utils.h"
#include "share/ob_rpc_struct.h"
namespace oceanbase
{
namespace storage
{
using namespace common;
using namespace blocksstable;
using namespace storage;
class TestTabletRefCnt : public TestIndexBlockDataPrepare
{
public:
TestTabletRefCnt();
~TestTabletRefCnt();
};
TestTabletRefCnt::TestTabletRefCnt()
: TestIndexBlockDataPrepare(
"Test Tablet Ref Cnt",
MINI_MERGE,
OB_DEFAULT_MACRO_BLOCK_SIZE,
10000,
65536)
{
}
TestTabletRefCnt::~TestTabletRefCnt()
{
}
void convert_ctx_to_map(
const common::ObSEArray<ObSharedBlocksWriteCtx, 16> &tablet_meta_write_ctxs,
const common::ObSEArray<ObSharedBlocksWriteCtx, 16> &sstable_meta_write_ctxs,
std::unordered_map<int64_t, int64_t> &ref_cnts)
{
MacroBlockId macro_id;
int64_t offset;
int64_t size;
ObBlockManager::BlockInfo block_info;
for (int64_t i = 0; i < tablet_meta_write_ctxs.count(); i++) {
ASSERT_EQ(OB_SUCCESS, tablet_meta_write_ctxs[i].addr_.get_block_addr(macro_id, offset, size));
if (ref_cnts.count(macro_id.block_index_) == 0) {
{
ObBucketHashWLockGuard lock_guard(OB_SERVER_BLOCK_MGR.bucket_lock_, macro_id.hash());
ASSERT_EQ(OB_SUCCESS, OB_SERVER_BLOCK_MGR.block_map_.get(macro_id, block_info));
}
ref_cnts[macro_id.block_index_] = block_info.ref_cnt_;
}
}
for (int64_t i = 0; i < tablet_meta_write_ctxs.count(); i++) {
ASSERT_EQ(OB_SUCCESS, tablet_meta_write_ctxs[i].addr_.get_block_addr(macro_id, offset, size));
ref_cnts[macro_id.block_index_]++;
}
for (int64_t i = 0; i < sstable_meta_write_ctxs.count(); i++) {
ASSERT_EQ(OB_SUCCESS, sstable_meta_write_ctxs[i].addr_.get_block_addr(macro_id, offset, size));
ref_cnts[macro_id.block_index_]++;
}
}
TEST_F(TestTabletRefCnt, test_persist_tablet)
{
ObTabletID tablet_id(TestIndexBlockDataPrepare::tablet_id_);
ObLSID ls_id(ls_id_);
ObLSHandle ls_handle;
ObTabletHandle tablet_handle;
ObLSService *ls_svr = MTL(ObLSService*);
ASSERT_EQ(OB_SUCCESS, ls_svr->get_ls(ls_id, ls_handle, ObLSGetMod::STORAGE_MOD));
ASSERT_EQ(OB_SUCCESS, ls_handle.get_ls()->get_tablet(tablet_id, tablet_handle));
common::ObArenaAllocator allocator;
common::ObSEArray<ObSharedBlocksWriteCtx, 16> tablet_meta_write_ctxs;
common::ObSEArray<ObSharedBlocksWriteCtx, 16> sstable_meta_write_ctxs;
ObTabletHandle new_tablet_handle;
std::unordered_map<int64_t, int64_t> ref_cnts;
ObBlockManager::BlockInfo block_info;
MacroBlockId macro_id;
int64_t offset;
int64_t size;
ObMacroBlockHandle macro_handle;
// persist 4k tablet
ASSERT_EQ(OB_SUCCESS, ObTabletPersister::recursively_persist(
*(tablet_handle.get_obj()), allocator, tablet_meta_write_ctxs, sstable_meta_write_ctxs, new_tablet_handle));
convert_ctx_to_map(tablet_meta_write_ctxs, sstable_meta_write_ctxs, ref_cnts);
ASSERT_EQ(OB_SUCCESS, ObTabletPersister::persist_4k_tablet(allocator, new_tablet_handle));
ASSERT_EQ(OB_SUCCESS, new_tablet_handle.get_obj()->tablet_addr_.get_block_addr(macro_id, offset, size));
ref_cnts[macro_id.block_index_]++; // tablet_meta_write_ctxs doesn't contain tablet_addr
// check ref cnt
{
ObBucketHashWLockGuard lock_guard(OB_SERVER_BLOCK_MGR.bucket_lock_, macro_id.hash());
ASSERT_EQ(OB_SUCCESS, OB_SERVER_BLOCK_MGR.block_map_.get(macro_id, block_info));
}
ASSERT_EQ(block_info.ref_cnt_, ref_cnts[macro_id.block_index_]);
for (int64_t i = 0; i < tablet_meta_write_ctxs.count(); i++) {
ASSERT_EQ(OB_SUCCESS, tablet_meta_write_ctxs[i].addr_.get_block_addr(macro_id, offset, size));
{
ObBucketHashWLockGuard lock_guard(OB_SERVER_BLOCK_MGR.bucket_lock_, macro_id.hash());
ASSERT_EQ(OB_SUCCESS, OB_SERVER_BLOCK_MGR.block_map_.get(macro_id, block_info));
}
ASSERT_EQ(block_info.ref_cnt_, ref_cnts[macro_id.block_index_]);
}
// transform memory
ObTabletHandle tmp_tablet_handle;
ObTabletMapKey key(ls_id, tablet_id);
ASSERT_EQ(OB_SUCCESS, ObTabletCreateDeleteHelper::acquire_tablet_from_pool(
ObTabletPoolType::TP_LARGE, key, tmp_tablet_handle));
ASSERT_EQ(OB_SUCCESS, ObTabletPersister::transform_tablet_memory_footprint(
*(new_tablet_handle.get_obj()), (char *)(tmp_tablet_handle.get_obj()), tmp_tablet_handle.get_buf_len()));
ASSERT_EQ(true, tmp_tablet_handle.get_obj()->hold_ref_cnt_);
tmp_tablet_handle.get_obj()->hold_ref_cnt_ = false;
}
TEST_F(TestTabletRefCnt, test_meta_ref_cnt)
{
int ret = OB_SUCCESS;
ObTabletID tablet_id(TestIndexBlockDataPrepare::tablet_id_);
ObLSID ls_id(ls_id_);
ObLSHandle ls_handle;
ObTabletHandle tablet_handle;
ObLSService *ls_svr = MTL(ObLSService*);
ASSERT_EQ(OB_SUCCESS, ls_svr->get_ls(ls_id, ls_handle, ObLSGetMod::STORAGE_MOD));
ASSERT_EQ(OB_SUCCESS, ls_handle.get_ls()->get_tablet(tablet_id, tablet_handle));
int64_t offset = 0;
int64_t size = 0;
ObBlockManager::BlockInfo block_info;
MacroBlockId table_store_id;
ObMacroBlockHandle macro_handle;
int64_t ref_cnt = 0;
ObTablet *tablet = tablet_handle.get_obj();
ObTabletHandle new_tablet_handle;
// persist 4k tablet
ASSERT_EQ(OB_SUCCESS, MTL(ObTenantCheckpointSlogHandler*)->get_shared_block_reader_writer().switch_block(macro_handle));
ASSERT_EQ(OB_SUCCESS, ObTabletPersister::persist_and_transform_tablet(*tablet, new_tablet_handle));
ASSERT_EQ(OB_SUCCESS, MTL(ObTenantCheckpointSlogHandler*)->get_shared_block_reader_writer().switch_block(macro_handle));
ObTablet *new_tablet = new_tablet_handle.get_obj();
ASSERT_EQ(OB_SUCCESS, new_tablet->table_store_addr_.addr_.get_block_addr(table_store_id, offset, size));
{
ObBucketHashWLockGuard lock_guard(OB_SERVER_BLOCK_MGR.bucket_lock_, table_store_id.hash());
ASSERT_EQ(OB_SUCCESS, OB_SERVER_BLOCK_MGR.block_map_.get(table_store_id, block_info));
}
ref_cnt = block_info.ref_cnt_;
// increase macro ref cnt
ASSERT_EQ(OB_SUCCESS, new_tablet->inc_macro_ref_cnt());
{
ObBucketHashWLockGuard lock_guard(OB_SERVER_BLOCK_MGR.bucket_lock_, table_store_id.hash());
ASSERT_EQ(OB_SUCCESS, OB_SERVER_BLOCK_MGR.block_map_.get(table_store_id, block_info));
}
ASSERT_EQ(ref_cnt * 2, block_info.ref_cnt_);
// decrease macro ref cnt
new_tablet->dec_macro_ref_cnt();
{
ObBucketHashWLockGuard lock_guard(OB_SERVER_BLOCK_MGR.bucket_lock_, table_store_id.hash());
ASSERT_EQ(OB_SUCCESS, OB_SERVER_BLOCK_MGR.block_map_.get(table_store_id, block_info));
}
ASSERT_EQ(ref_cnt, block_info.ref_cnt_);
// deserialize tablet
ObTenantCheckpointSlogHandler *ckpt_handler = MTL(ObTenantCheckpointSlogHandler*);
ObTabletHandle tmp_tablet_handle;
ObTabletMapKey key(ls_id, tablet_id);
char *buf = nullptr;
int64_t buf_len = 0;
int64_t pos = 0;
ObArenaAllocator allocator;
ASSERT_EQ(OB_SUCCESS, ckpt_handler->read_from_disk(new_tablet->tablet_addr_, allocator, buf, buf_len));
ASSERT_EQ(OB_SUCCESS, ObTabletCreateDeleteHelper::acquire_tmp_tablet(key, allocator, tmp_tablet_handle));
tmp_tablet_handle.get_obj()->tablet_addr_ = new_tablet->tablet_addr_;
ASSERT_EQ(OB_SUCCESS, tmp_tablet_handle.get_obj()->deserialize(allocator, buf, buf_len, pos));
{
ObBucketHashWLockGuard lock_guard(OB_SERVER_BLOCK_MGR.bucket_lock_, table_store_id.hash());
ASSERT_EQ(OB_SUCCESS, OB_SERVER_BLOCK_MGR.block_map_.get(table_store_id, block_info));
}
ASSERT_EQ(ref_cnt * 2, block_info.ref_cnt_);
}
TEST_F(TestTabletRefCnt, test_data_ref_cnt)
{
ObBlockManager::BlockInfo block_info;
MacroBlockId macro_id;
int64_t ref_cnt = 0;
common::ObArenaAllocator tmp_allocator("CacheSST");
ObSafeArenaAllocator safe_allocator(tmp_allocator);
ObSSTableMetaHandle meta_handle;
ObMacroIdIterator iterator;
ASSERT_EQ(OB_SUCCESS, sstable_.get_meta(meta_handle, &safe_allocator));
ASSERT_EQ(OB_SUCCESS, meta_handle.get_sstable_meta().get_macro_info().get_data_block_iter(iterator));
ASSERT_EQ(OB_SUCCESS, iterator.get_next_macro_id(macro_id));
{
ObBucketHashWLockGuard lock_guard(OB_SERVER_BLOCK_MGR.bucket_lock_, macro_id.hash());
ASSERT_EQ(OB_SUCCESS, OB_SERVER_BLOCK_MGR.block_map_.get(macro_id, block_info));
}
ref_cnt = block_info.ref_cnt_;
// increase macro ref cnt
bool inc_success;
ASSERT_EQ(OB_SUCCESS, sstable_.inc_macro_ref(inc_success));
{
ObBucketHashWLockGuard lock_guard(OB_SERVER_BLOCK_MGR.bucket_lock_, macro_id.hash());
ASSERT_EQ(OB_SUCCESS, OB_SERVER_BLOCK_MGR.block_map_.get(macro_id, block_info));
}
ASSERT_EQ(ref_cnt + 1, block_info.ref_cnt_);
// decrease macro ref cnt
sstable_.dec_macro_ref();
{
ObBucketHashWLockGuard lock_guard(OB_SERVER_BLOCK_MGR.bucket_lock_, macro_id.hash());
ASSERT_EQ(OB_SUCCESS, OB_SERVER_BLOCK_MGR.block_map_.get(macro_id, block_info));
}
ASSERT_EQ(ref_cnt, block_info.ref_cnt_);
}
TEST_F(TestTabletRefCnt, test_empty_shell_macro_ref_cnt)
{
int ret = OB_SUCCESS;
ObLSID ls_id(ls_id_);
ObTabletID tablet_id(10000009);
share::schema::ObTableSchema schema;
TestSchemaUtils::prepare_data_schema(schema);
ObTablet *tablet = nullptr;
ObLSHandle ls_handle;
ObLSService *ls_svr = MTL(ObLSService*);
ASSERT_EQ(OB_SUCCESS, ls_svr->get_ls(ls_id, ls_handle, ObLSGetMod::STORAGE_MOD));
ObLSTabletService *ls_tablet_svr = ls_handle.get_ls()->get_tablet_svr();
// create and get empty shell
ret = TestTabletHelper::create_tablet(ls_handle, tablet_id, schema, allocator_, ObTabletStatus::Status::DELETED);
ASSERT_EQ(OB_SUCCESS, ret);
ret = ls_tablet_svr->update_tablet_to_empty_shell(tablet_id);
ASSERT_EQ(OB_SUCCESS, ret);
ObTabletMapKey key(ls_id, tablet_id);
ObTabletHandle tablet_handle;
ret = ls_tablet_svr->get_tablet(tablet_id, tablet_handle, 0, ObMDSGetTabletMode::READ_WITHOUT_CHECK);
tablet = tablet_handle.get_obj();
// check increasing macro ref cnt for empty shell tablet with file addr
ASSERT_EQ(false, tablet->hold_ref_cnt_);
ASSERT_EQ(OB_SUCCESS, tablet->inc_macro_ref_cnt());
ASSERT_EQ(true, tablet->hold_ref_cnt_);
// check increasing macro ref cnt for empty shell tablet with file addr
MacroBlockId macro_id;
int64_t offset;
int64_t size;
ObBlockManager::BlockInfo block_info;
int64_t ref_cnt = 0;
ObTabletHandle new_tablet_handle;
ASSERT_EQ(OB_SUCCESS, ObTabletPersister::persist_and_transform_tablet(*tablet, new_tablet_handle));
ObTablet *new_tablet = new_tablet_handle.get_obj();
ASSERT_EQ(OB_SUCCESS, new_tablet->tablet_addr_.get_block_addr(macro_id, offset, size));
{
ObBucketHashWLockGuard lock_guard(OB_SERVER_BLOCK_MGR.bucket_lock_, macro_id.hash());
ASSERT_EQ(OB_SUCCESS, OB_SERVER_BLOCK_MGR.block_map_.get(macro_id, block_info));
}
ref_cnt = block_info.ref_cnt_;
ASSERT_EQ(OB_SUCCESS, new_tablet->inc_macro_ref_cnt());
{
ObBucketHashWLockGuard lock_guard(OB_SERVER_BLOCK_MGR.bucket_lock_, macro_id.hash());
ASSERT_EQ(OB_SUCCESS, OB_SERVER_BLOCK_MGR.block_map_.get(macro_id, block_info));
}
ASSERT_EQ(ref_cnt + 1, block_info.ref_cnt_);
new_tablet->dec_macro_ref_cnt();
{
ObBucketHashWLockGuard lock_guard(OB_SERVER_BLOCK_MGR.bucket_lock_, macro_id.hash());
ASSERT_EQ(OB_SUCCESS, OB_SERVER_BLOCK_MGR.block_map_.get(macro_id, block_info));
}
ASSERT_EQ(ref_cnt, block_info.ref_cnt_);
}
TEST_F(TestTabletRefCnt, test_linked_block_ref_cnt)
{
int ret = OB_SUCCESS;
ObMacroBlockHandle tmp_handle;
ObSharedBlockReaderWriter &shared_rw = MTL(ObTenantCheckpointSlogHandler*)->get_shared_block_reader_writer();
ASSERT_EQ(OB_SUCCESS, shared_rw.switch_block(tmp_handle));
common::ObArenaAllocator arena_allocator("unittest");
ObSharedBlocksWriteCtx write_ctx;
static const int64_t BLOCK_CNT = 10;
// write linked blocks and wait
char *buffer = static_cast<char*>(arena_allocator.alloc(4096));
ObSharedBlockWriteInfo write_info;
ObSharedBlockLinkHandle write_handle;
write_info.buffer_ = buffer;
write_info.offset_ = 0;
write_info.size_ = 4096;
write_info.io_desc_.set_wait_event(ObWaitEventIds::DB_FILE_COMPACT_WRITE);
for (int64_t i = 0; i < BLOCK_CNT; i++) {
ASSERT_EQ(OB_SUCCESS, shared_rw.async_link_write(write_info, write_handle));
}
ASSERT_EQ(OB_SUCCESS, write_handle.get_write_ctx(write_ctx));
// increase macro blocks' ref cnt and check
bool inc_success = false;
ObBlockManager::BlockInfo block_info;
MacroBlockId macro_id = write_ctx.addr_.block_id();
{
ObBucketHashWLockGuard lock_guard(OB_SERVER_BLOCK_MGR.bucket_lock_, macro_id.hash());
ASSERT_EQ(OB_SUCCESS, OB_SERVER_BLOCK_MGR.block_map_.get(macro_id, block_info));
}
int64_t ref_cnt = block_info.ref_cnt_;
ASSERT_EQ(OB_SUCCESS, ObTablet::inc_linked_block_ref_cnt(write_ctx.addr_, inc_success));
{
ObBucketHashWLockGuard lock_guard(OB_SERVER_BLOCK_MGR.bucket_lock_, macro_id.hash());
ASSERT_EQ(OB_SUCCESS, OB_SERVER_BLOCK_MGR.block_map_.get(macro_id, block_info));
}
ASSERT_EQ(ref_cnt + BLOCK_CNT, block_info.ref_cnt_);
}
} // storage
} // oceanbase
int main(int argc, char **argv)
{
system("rm -f test_tablet_ref_cnt.log*");
OB_LOGGER.set_file_name("test_tablet_ref_cnt.log", true, true);
oceanbase::common::ObLogger::get_logger().set_log_level("INFO");
oceanbase::common::ObClusterVersion::get_instance().init(CLUSTER_VERSION_4_1_0_0);
testing::InitGoogleTest(&argc, argv);
return RUN_ALL_TESTS();
}