diff --git a/mittest/mtlenv/storage/test_ls_tablet_service.cpp b/mittest/mtlenv/storage/test_ls_tablet_service.cpp index 98d4b5a019..1ad522c2fd 100644 --- a/mittest/mtlenv/storage/test_ls_tablet_service.cpp +++ b/mittest/mtlenv/storage/test_ls_tablet_service.cpp @@ -1009,6 +1009,45 @@ TEST_F(TestLSTabletService, test_update_empty_shell) ASSERT_EQ(OB_SUCCESS, ret); } +TEST_F(TestLSTabletService, test_update_tablet_release_memtable) +{ + int ret = OB_SUCCESS; + const int64_t inner_tablet_count = INNER_TABLET_CNT; + ObTabletID data_tablet_id(9000000111); + share::schema::ObTableSchema data_schema; + + TestSchemaUtils::prepare_data_schema(data_schema); + + ObLSHandle ls_handle; + ObLSService *ls_svr = MTL(ObLSService*); + ret = ls_svr->get_ls(ls_id_, ls_handle, ObLSGetMod::STORAGE_MOD); + ret = TestTabletHelper::create_tablet(ls_handle, data_tablet_id, data_schema, allocator_); + ASSERT_EQ(OB_SUCCESS, ret); + valid_tablet_num(inner_tablet_count); + ASSERT_EQ(1 + INNER_TABLET_CNT, MTL(ObTenantMetaMemMgr*)->tablet_map_.map_.size()); + ret = TestTabletHelper::create_tablet(ls_handle, data_tablet_id, data_schema, allocator_); + ASSERT_EQ(OB_ENTRY_EXIST, ret); + valid_tablet_num(inner_tablet_count); + ASSERT_EQ(1 + INNER_TABLET_CNT, MTL(ObTenantMetaMemMgr*)->tablet_map_.map_.size()); + + ObTabletHandle tablet_handle; + ASSERT_EQ(OB_SUCCESS, ls_handle.get_ls()->get_tablet_svr()->get_tablet(data_tablet_id, tablet_handle)); + ASSERT_EQ(0, tablet_handle.get_obj()->memtable_count_); + ASSERT_EQ(OB_SUCCESS, ls_handle.get_ls()->get_tablet_svr()->create_memtable(data_tablet_id, 100)); + ASSERT_EQ(1, tablet_handle.get_obj()->memtable_count_); + + ASSERT_EQ(OB_SUCCESS, ls_handle.get_ls()->get_tablet_svr()->update_tablet_release_memtable(data_tablet_id, SCN::max_scn())); + ASSERT_EQ(OB_SUCCESS, ls_handle.get_ls()->get_tablet_svr()->update_tablet_release_memtable(data_tablet_id, SCN::max_scn())); + + MTL(ObTenantCheckpointSlogHandler *)->shared_block_rwriter_.macro_handle_.reset(); + + ObTabletMapKey key; + key.ls_id_ = ls_id_; + key.tablet_id_ = data_tablet_id; + ret = MTL(ObTenantMetaMemMgr*)->del_tablet(key); + ASSERT_EQ(OB_SUCCESS, ret); +} + } // end storage } // end oceanbase diff --git a/src/storage/ls/ob_ls_tablet_service.cpp b/src/storage/ls/ob_ls_tablet_service.cpp index 0e62e525b7..b89f6ec87e 100755 --- a/src/storage/ls/ob_ls_tablet_service.cpp +++ b/src/storage/ls/ob_ls_tablet_service.cpp @@ -1464,6 +1464,60 @@ int ObLSTabletService::build_new_tablet_from_mds_table( return ret; } +int ObLSTabletService::update_tablet_release_memtable( + const common::ObTabletID &tablet_id, + const SCN scn) +{ + int ret = OB_SUCCESS; + const ObTabletMapKey key(ls_->get_ls_id(), tablet_id); + ObTabletHandle tablet_handle; + ObTimeGuard time_guard("ObLSTabletService::update_tablet_release_memtable", 1_s); + ObBucketHashWLockGuard lock_guard(bucket_lock_, tablet_id.hash()); + time_guard.click("Lock"); + if (IS_NOT_INIT) { + ret = OB_NOT_INIT; + LOG_WARN("not inited", K(ret), K_(is_inited)); + } else if (OB_UNLIKELY(!tablet_id.is_valid() || !scn.is_valid())) { + ret = OB_INVALID_ARGUMENT; + LOG_WARN("invalid arguments", K(ret), K(tablet_id), K(scn)); + } else if (OB_FAIL(ObTabletCreateDeleteHelper::get_tablet(key, tablet_handle))) { + LOG_WARN("fail to direct get tablet", K(ret), K(key)); + } else { + time_guard.click("get_tablet"); + ObTablet *tablet = tablet_handle.get_obj(); + ObTabletHandle new_tablet_handle; + ObTenantMetaMemMgr *t3m = MTL(ObTenantMetaMemMgr*); + const bool need_persist = nullptr != tablet_handle.get_allocator(); + ObMetaDiskAddr disk_addr; + if (!need_persist) { + if (OB_FAIL(ObTabletPersister::copy_from_old_tablet(*tablet, new_tablet_handle))) { + LOG_WARN("fail to copy from old tablet", K(ret), KPC(tablet)); + } else { + time_guard.click("CpTablet"); + } + } else if (OB_FAIL(ObTabletPersister::persist_and_transform_tablet(*tablet, new_tablet_handle))) { + LOG_WARN("fail to persist and transform tablet", K(ret), KPC(tablet), K(new_tablet_handle)); + } else if (FALSE_IT(time_guard.click("Persist"))) { + } else if (FALSE_IT(disk_addr = new_tablet_handle.get_obj()->tablet_addr_)) { + } else if (OB_FAIL(ObTabletSlogHelper::write_update_tablet_slog(key.ls_id_, tablet_id, disk_addr))) { + LOG_WARN("failed to write update tablet slog", K(ret), K(key), K(disk_addr)); + } else { + time_guard.click("WrSlog"); + } + if (FAILEDx(new_tablet_handle.get_obj()->rebuild_memtables(scn))) { + LOG_WARN("fail to rebuild memtables", K(ret), K(scn), K(new_tablet_handle)); + } else if (OB_FAIL(t3m->compare_and_swap_tablet(key, tablet_handle, new_tablet_handle))) { + LOG_ERROR("failed to compare and swap tablet", K(ret), K(key), K(tablet_handle), K(new_tablet_handle)); + ob_usleep(1000 * 1000); + ob_abort(); + } else { + time_guard.click("CASwap"); + LOG_INFO("succeeded to build new tablet", K(ret), K(key), K(disk_addr), K(tablet_handle)); + } + } + return ret; +} + int ObLSTabletService::update_tablet_report_status(const common::ObTabletID &tablet_id) { int ret = OB_SUCCESS; diff --git a/src/storage/ls/ob_ls_tablet_service.h b/src/storage/ls/ob_ls_tablet_service.h index fc3a363782..2737959cc5 100755 --- a/src/storage/ls/ob_ls_tablet_service.h +++ b/src/storage/ls/ob_ls_tablet_service.h @@ -242,6 +242,9 @@ public: const common::ObTabletID &tablet_id, const int64_t mds_construct_sequence, const share::SCN &flush_scn); + int update_tablet_release_memtable( + const common::ObTabletID &tablet_id, + const SCN scn); int update_tablet_report_status(const common::ObTabletID &tablet_id); int update_tablet_restore_status( const common::ObTabletID &tablet_id, diff --git a/src/storage/tablet/ob_tablet.cpp b/src/storage/tablet/ob_tablet.cpp index 2c5a77b2d3..434dac6116 100755 --- a/src/storage/tablet/ob_tablet.cpp +++ b/src/storage/tablet/ob_tablet.cpp @@ -3506,6 +3506,33 @@ int ObTablet::inner_get_memtables(common::ObIArray &memtabl return ret; } +int ObTablet::rebuild_memtables(const share::SCN scn) +{ + int ret = OB_SUCCESS; + if (OB_FAIL(release_memtables(scn))) { + LOG_WARN("fail to release memtables", K(ret), K(scn)); + } else { + reset_memtable(); + if (OB_FAIL(pull_memtables_without_ddl())) { + LOG_WARN("fail to pull memtables without ddl", K(ret)); + } else { + tablet_addr_.inc_seq(); + table_store_addr_.addr_.inc_seq(); + if (table_store_addr_.is_memory_object()) { + ObSEArray memtable_array; + if (OB_FAIL(inner_get_memtables(memtable_array, true/*need_active*/))) { + LOG_WARN("inner get memtables fail", K(ret), K(*this)); + } else if (OB_FAIL(table_store_addr_.get_ptr()->update_memtables(memtable_array))) { + LOG_WARN("table store update memtables fail", K(ret), K(memtable_array)); + } else { + LOG_INFO("table store update memtable success", KPC(this)); + } + } + } + } + return ret; +} + int ObTablet::release_memtables(const SCN scn) { int ret = OB_SUCCESS; diff --git a/src/storage/tablet/ob_tablet.h b/src/storage/tablet/ob_tablet.h index 3d9852fd4a..da540adc56 100755 --- a/src/storage/tablet/ob_tablet.h +++ b/src/storage/tablet/ob_tablet.h @@ -309,10 +309,18 @@ public: // get the active memtable for write or replay. int get_active_memtable(ObTableHandleV2 &handle) const; + + // ATTENTION!!! + // 1. release memtables from memtable manager and this tablet. + // 2. If a tablet may be being accessed, shouldn't call this function. + int rebuild_memtables(const share::SCN scn); + + // ATTENTION!!! The following two interfaces only release memtable from memtable manager. int release_memtables(const share::SCN scn); // force release all memtables // just for rebuild or migrate retry. int release_memtables(); + int wait_release_memtables(); // multi-source data operation diff --git a/src/storage/tablet/ob_tablet_persister.cpp b/src/storage/tablet/ob_tablet_persister.cpp index 98335352ae..d51176f23d 100644 --- a/src/storage/tablet/ob_tablet_persister.cpp +++ b/src/storage/tablet/ob_tablet_persister.cpp @@ -118,6 +118,31 @@ int ObTabletPersister::persist_and_transform_tablet( return ret; } +/*static*/int ObTabletPersister::copy_from_old_tablet( + const ObTablet &old_tablet, + ObTabletHandle &new_handle) +{ + int ret = OB_SUCCESS; + if (OB_NOT_NULL(old_tablet.allocator_)) { + ret = OB_NOT_SUPPORTED; + LOG_WARN("this isn't supported for the tablet from allocator", K(ret), K(old_tablet)); + } else { + const ObTabletMeta &tablet_meta = old_tablet.get_tablet_meta(); + const ObTabletMapKey key(tablet_meta.ls_id_, tablet_meta.tablet_id_); + const char* buf = reinterpret_cast(&old_tablet); + ObMetaObjBufferHeader &buf_header = ObMetaObjBufferHelper::get_buffer_header(const_cast(buf)); + ObTabletPoolType type; + if (OB_FAIL(ObTenantMetaMemMgr::get_tablet_pool_type(buf_header.buf_len_, type))) { + LOG_WARN("fail to get tablet pool type", K(ret), K(buf_header)); + } else if (OB_FAIL(acquire_tablet(type, key, true/*try_smaller_pool*/, new_handle))) { + LOG_WARN("fail to acqurie tablet", K(ret), K(type), K(new_handle)); + } else if (OB_FAIL(transform_tablet_memory_footprint(old_tablet, new_handle.get_buf(), new_handle.get_buf_len()))) { + LOG_WARN("fail to transform tablet memory footprint", K(ret), K(old_tablet), K(type)); + } + } + return ret; +} + int ObTabletPersister::recursively_persist( const ObTablet &old_tablet, common::ObArenaAllocator &allocator, diff --git a/src/storage/tablet/ob_tablet_persister.h b/src/storage/tablet/ob_tablet_persister.h index db5e8ebe87..bdff1cbf9a 100644 --- a/src/storage/tablet/ob_tablet_persister.h +++ b/src/storage/tablet/ob_tablet_persister.h @@ -83,6 +83,10 @@ public: static int persist_and_transform_tablet( const ObTablet &old_tablet, ObTabletHandle &new_handle); + // copy from old tablet + static int copy_from_old_tablet( + const ObTablet &old_tablet, + ObTabletHandle &new_handle); // change tablet memory footprint // - degrade larger tablet objects to relatively smaller tablet objects, reducing the memory footprint. // - upgrade smaller tablet objects to relatively larger tablet objects, achieving more performance.