diff --git a/src/storage/ls/ob_ls_tablet_service.cpp b/src/storage/ls/ob_ls_tablet_service.cpp index 017ed38d86..9d3c9ea4e6 100644 --- a/src/storage/ls/ob_ls_tablet_service.cpp +++ b/src/storage/ls/ob_ls_tablet_service.cpp @@ -1439,6 +1439,21 @@ int ObLSTabletService::update_tablet_release_memtable_for_offline( return ret; } +int ObLSTabletService::ObUpdateDDLCommitSCN::modify_tablet_meta(ObTabletMeta &meta) +{ + int ret = OB_SUCCESS; + if (!ddl_commit_scn_.is_valid()) { + ret = OB_INVALID_ARGUMENT; + LOG_WARN("invalid argument", K(ret), K(ddl_commit_scn_)); + } else if (meta.ddl_commit_scn_.is_valid_and_not_min() && ddl_commit_scn_ != meta.ddl_commit_scn_) { + ret = OB_ERR_SYS; + LOG_WARN("ddl commit scn already set", K(ret), K(meta), K(ddl_commit_scn_)); + } else { + meta.ddl_commit_scn_ = ddl_commit_scn_; + } + return ret; +} + int ObLSTabletService::update_tablet_ddl_commit_scn( const common::ObTabletID &tablet_id, const SCN ddl_commit_scn) @@ -1452,7 +1467,7 @@ int ObLSTabletService::update_tablet_ddl_commit_scn( 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() || !ddl_commit_scn.is_valid())) { + } else if (OB_UNLIKELY(!tablet_id.is_valid() || !ddl_commit_scn.is_valid_and_not_min())) { ret = OB_INVALID_ARGUMENT; LOG_WARN("invalid arguments", K(ret), K(tablet_id), K(ddl_commit_scn)); } else if (OB_FAIL(ObTabletCreateDeleteHelper::get_tablet(key, old_handle))) { diff --git a/src/storage/ls/ob_ls_tablet_service.h b/src/storage/ls/ob_ls_tablet_service.h index f869eaea6c..495a814e31 100644 --- a/src/storage/ls/ob_ls_tablet_service.h +++ b/src/storage/ls/ob_ls_tablet_service.h @@ -483,11 +483,7 @@ private: public: explicit ObUpdateDDLCommitSCN(const share::SCN ddl_commit_scn) : ddl_commit_scn_(ddl_commit_scn) {} virtual ~ObUpdateDDLCommitSCN() = default; - virtual int modify_tablet_meta(ObTabletMeta &meta) override - { - meta.ddl_commit_scn_ = ddl_commit_scn_; - return OB_SUCCESS; - } + virtual int modify_tablet_meta(ObTabletMeta &meta) override; private: const share::SCN ddl_commit_scn_; DISALLOW_COPY_AND_ASSIGN(ObUpdateDDLCommitSCN); diff --git a/src/storage/tablet/ob_tablet.cpp b/src/storage/tablet/ob_tablet.cpp index c8373984e7..1f7bfb0241 100644 --- a/src/storage/tablet/ob_tablet.cpp +++ b/src/storage/tablet/ob_tablet.cpp @@ -7423,5 +7423,38 @@ int ObTablet::get_protected_memtable_mgr_handle(ObProtectedMemtableMgrHandle *&h return ret; } +int ObTablet::get_ready_for_read_param(ObReadyForReadParam ¶m) const +{ + int ret = OB_SUCCESS; + param.ddl_commit_scn_ = tablet_meta_.ddl_commit_scn_; + param.clog_checkpoint_scn_ = tablet_meta_.clog_checkpoint_scn_; + return ret; +} + +int ObTablet::check_ready_for_read_if_need(const ObTablet &old_tablet) +{ + int ret = OB_SUCCESS; + ObReadyForReadParam old_param; + ObReadyForReadParam new_param; + if (OB_FAIL(old_tablet.get_ready_for_read_param(old_param))) { + LOG_WARN("fail to get ready for read param", K(ret), K(old_tablet)); + } else if (OB_FAIL(get_ready_for_read_param(new_param))) { + LOG_WARN("fail to get ready for read param", K(ret), KPC(this)); + } else if (old_param == new_param) { + // no change, nothing to do + } else if (table_store_addr_.is_memory_object()) { + if (OB_FAIL(table_store_addr_.get_ptr()->check_ready_for_read(new_param))) { + if (OB_SIZE_OVERFLOW == ret) { + ObTabletTableStore::diagnose_table_count_unsafe(*this); + } else { + LOG_WARN("table store check ready for read failed", K(ret), KPC(this)); + } + } + } else { + // invalid the cache to force reload table store from disk, for updating the ready_for_read flag + table_store_addr_.addr_.inc_seq(); + } + return ret; +} } // namespace storage } // namespace oceanbase diff --git a/src/storage/tablet/ob_tablet.h b/src/storage/tablet/ob_tablet.h index 5b6723f9fd..2a1e040e1a 100644 --- a/src/storage/tablet/ob_tablet.h +++ b/src/storage/tablet/ob_tablet.h @@ -265,6 +265,7 @@ public: bool is_empty_shell() const; // major merge or medium merge call bool is_data_complete() const; + int get_ready_for_read_param(ObReadyForReadParam &parm) const; // serialize & deserialize // TODO: change the impl of serialize and get_serialize_size after rebase @@ -822,6 +823,7 @@ private: ObUpdateTabletPointerParam ¶m, const bool need_tablet_attr = true) const; int calc_tablet_attr(ObTabletAttr &attr) const; + int check_ready_for_read_if_need(const ObTablet &old_tablet); private: // ObTabletDDLKvMgr::MAX_DDL_KV_CNT_IN_STORAGE // Array size is too large, need to shrink it if possible diff --git a/src/storage/tablet/ob_tablet_persister.cpp b/src/storage/tablet/ob_tablet_persister.cpp index d80a4e76cd..cb95d48cc5 100644 --- a/src/storage/tablet/ob_tablet_persister.cpp +++ b/src/storage/tablet/ob_tablet_persister.cpp @@ -404,6 +404,8 @@ int ObTabletPersister::modify_and_fill_tablet( } else if (FALSE_IT(new_handle.get_obj()->set_next_tablet_guard(old_tablet.next_tablet_guard_))) { } else if (OB_FAIL(modifier.modify_tablet_meta(new_handle.get_obj()->tablet_meta_))) { LOG_WARN("fail to modify tablet meta", K(ret), KPC(new_handle.get_obj())); + } else if (OB_FAIL(new_handle.get_obj()->check_ready_for_read_if_need(old_tablet))) { + LOG_WARN("fail to check ready for read if need", K(ret), K(old_tablet), K(new_handle)); } else { time_stats->click("transform_and_modify"); } diff --git a/src/storage/tablet/ob_tablet_table_store.cpp b/src/storage/tablet/ob_tablet_table_store.cpp index 7df89edeb8..5ec7a5d237 100644 --- a/src/storage/tablet/ob_tablet_table_store.cpp +++ b/src/storage/tablet/ob_tablet_table_store.cpp @@ -704,7 +704,7 @@ int ObTabletTableStore::calculate_read_tables( if (OB_FAIL(iterator.add_table(meta_major_tables_.at(0)))) { LOG_WARN("failed to add meta major table to iterator", K(ret), K(meta_major_tables_)); } - } else if (!is_major_sstable_empty(tablet)) { + } else if (!is_major_sstable_empty(tablet.get_tablet_meta().ddl_commit_scn_)) { if (!major_tables_.empty()) { for (int64_t i = major_tables_.count() - 1; OB_SUCC(ret) && i >= 0; --i) { if (major_tables_[i]->get_snapshot_version() <= snapshot_version) { @@ -773,7 +773,7 @@ int ObTabletTableStore::calculate_read_tables( } } else { // not find base table if (!allow_no_ready_read) { - if (is_major_sstable_empty(tablet)) { + if (is_major_sstable_empty(tablet.get_tablet_meta().ddl_commit_scn_)) { ret = OB_REPLICA_NOT_READABLE; LOG_WARN("no base table, not allow no ready read, tablet is not readable", K(ret), K(snapshot_version), K(allow_no_ready_read), K(PRINT_TS(*this))); @@ -950,7 +950,8 @@ int ObTabletTableStore::get_read_tables( if (OB_UNLIKELY(snapshot_version < 0)) { ret = OB_INVALID_ARGUMENT; LOG_WARN("invalid argument", K(ret), K(snapshot_version)); - } else if (OB_UNLIKELY(is_major_sstable_empty(tablet) && minor_tables_.empty() && allow_no_ready_read)) { + } else if (OB_UNLIKELY(is_major_sstable_empty(tablet.get_tablet_meta().ddl_commit_scn_) + && minor_tables_.empty() && allow_no_ready_read)) { if (memtables_.empty()) { LOG_INFO("no table in table store, cannot read", K(ret), K(*this)); } else if (OB_FAIL(iterator.add_tables(memtables_))) { @@ -1487,10 +1488,10 @@ int ObTabletTableStore::build_meta_major_table( return ret; } -bool ObTabletTableStore::is_major_sstable_empty(const ObTablet &tablet) const +bool ObTabletTableStore::is_major_sstable_empty(const share::SCN &ddl_commit_scn) const { return major_tables_.empty() - && !tablet.get_tablet_meta().ddl_commit_scn_.is_valid_and_not_min(); // ddl logic major sstable require commit scn valid + && !ddl_commit_scn.is_valid_and_not_min(); // ddl logic major sstable require commit scn valid } int ObTabletTableStore::get_ddl_major_sstables(ObIArray &ddl_major_sstables) const @@ -1643,6 +1644,28 @@ int ObTabletTableStore::build_memtable_array(const ObTablet &tablet) } int ObTabletTableStore::check_ready_for_read(const ObTablet &tablet) +{ + int ret = OB_SUCCESS; + ObReadyForReadParam param; + if (OB_FAIL(tablet.get_ready_for_read_param(param))) { + LOG_WARN("fail to get ready for read param", K(ret), K(tablet)); + } else if (OB_FAIL(check_ready_for_read(param))) { + if (OB_SIZE_OVERFLOW == ret) { + diagnose_table_count_unsafe(tablet); + } else { + LOG_WARN("fail to check ready for read", K(ret), K(tablet)); + } + } + return ret; +} + +void ObTabletTableStore::diagnose_table_count_unsafe(const ObTablet &tablet) +{ + compaction::ObPartitionMergePolicy::diagnose_table_count_unsafe(compaction::MAJOR_MERGE, ObDiagnoseTabletType::TYPE_SPECIAL, tablet); + MTL(concurrency_control::ObMultiVersionGarbageCollector *)->report_sstable_overflow(); +} + +int ObTabletTableStore::check_ready_for_read(const ObReadyForReadParam ¶m) { int ret = OB_SUCCESS; is_ready_for_read_ = false; @@ -1650,30 +1673,25 @@ int ObTabletTableStore::check_ready_for_read(const ObTablet &tablet) if (IS_NOT_INIT) { ret = OB_NOT_INIT; LOG_WARN("not init", K(ret), KPC(this)); - } else if (is_major_sstable_empty(tablet)) { + } else if (is_major_sstable_empty(param.ddl_commit_scn_)) { LOG_INFO("no valid major sstable, not ready for read", K(*this)); } else if (OB_FAIL(check_continuous())) { LOG_WARN("failed to check continuous of tables", K(ret)); } else if (minor_tables_.count() + 1 > MAX_SSTABLE_CNT_IN_STORAGE) { ret = OB_SIZE_OVERFLOW; - LOG_WARN("Too Many sstables in table store", K(ret), KPC(this), K(tablet)); - compaction::ObPartitionMergePolicy::diagnose_table_count_unsafe( - compaction::MAJOR_MERGE, ObDiagnoseTabletType::TYPE_SPECIAL, tablet); - MTL(concurrency_control::ObMultiVersionGarbageCollector *)->report_sstable_overflow(); + LOG_WARN("Too Many sstables in table store", K(ret), KPC(this)); } else if (get_table_count() > ObTabletTableStore::MAX_SSTABLE_CNT) { ret = OB_SIZE_OVERFLOW; - LOG_WARN("Too Many sstables, cannot add another sstable any more", K(ret), KPC(this), K(tablet)); - compaction::ObPartitionMergePolicy::diagnose_table_count_unsafe(compaction::MAJOR_MERGE, ObDiagnoseTabletType::TYPE_SPECIAL, tablet); - MTL(concurrency_control::ObMultiVersionGarbageCollector *)->report_sstable_overflow(); + LOG_WARN("Too Many sstables, cannot add another sstable any more", K(ret), KPC(this)); } else if (minor_tables_.empty()) { is_ready_for_read_ = true; } else { - const SCN &clog_checkpoint_scn = tablet.get_clog_checkpoint_scn(); + const SCN &clog_checkpoint_scn = param.clog_checkpoint_scn_; const SCN &last_minor_end_scn = minor_tables_.get_boundary_table(true/*last*/)->get_end_scn(); if (OB_UNLIKELY(clog_checkpoint_scn != last_minor_end_scn)) { ret = OB_ERR_UNEXPECTED; LOG_WARN("last minor table's end_scn must be equal to clog_checkpoint_scn", - K(ret), K(last_minor_end_scn), K(clog_checkpoint_scn), KPC(this), K(tablet)); + K(ret), K(last_minor_end_scn), K(clog_checkpoint_scn), KPC(this)); } else { is_ready_for_read_ = true; } diff --git a/src/storage/tablet/ob_tablet_table_store.h b/src/storage/tablet/ob_tablet_table_store.h index 9fdf39be26..fe418124d5 100644 --- a/src/storage/tablet/ob_tablet_table_store.h +++ b/src/storage/tablet/ob_tablet_table_store.h @@ -30,6 +30,42 @@ class ObTableStoreIterator; class ObCachedTableHandle; class ObStorageMetaHandle; +class ObReadyForReadParam final +{ +// if you want to add a member variable, please add here. +#define LIST_MEMBERS \ + DO_SOMETHING(share::SCN, ddl_commit_scn_) \ + DO_SOMETHING(share::SCN, clog_checkpoint_scn_) +public: + ObReadyForReadParam() = default; + ~ObReadyForReadParam() = default; + int assign(const ObReadyForReadParam &other) + { + int ret = OB_SUCCESS; +#define DO_SOMETHING(type, name) name = other.name; + LIST_MEMBERS +#undef DO_SOMETHING + return ret; + } + bool operator==(const ObReadyForReadParam &other) const + { + bool is_equal = false; + // check for equality; +#define DO_SOMETHING(type, name) is_equal = is_equal && (name == other.name); + LIST_MEMBERS +#undef DO_SOMETHING + return is_equal; + } + bool operator!=(const ObReadyForReadParam &other) const { return !(*this == other); } +public: +// define member variables +#define DO_SOMETHING(type, name) type name; + LIST_MEMBERS +#undef DO_SOMETHING +private: + DISALLOW_COPY_AND_ASSIGN(ObReadyForReadParam); +}; + class ObTabletTableStore : public ObIStorageMetaObj { public: @@ -145,6 +181,8 @@ public: blocksstable::ObSSTableMetaHandle &meta_handle, blocksstable::ObSSTable *sstable, int64_t &remain_size); + int check_ready_for_read(const ObReadyForReadParam ¶m); + static void diagnose_table_count_unsafe(const ObTablet &tablet); int64_t to_string(char *buf, const int64_t buf_len) const; // Load sstable with @addr, loaded object lifetime guaranteed by @handle @@ -302,7 +340,7 @@ private: const blocksstable::ObSSTable *new_sstable, const bool keep_old_ddl_sstable, const ObTabletTableStore &old_store); - bool is_major_sstable_empty(const ObTablet &tablet) const; + bool is_major_sstable_empty(const share::SCN &ddl_commit_scn) const; int get_ddl_major_sstables(ObIArray &ddl_major_sstables) const; int inner_replace_sstables(