diff --git a/src/storage/tablet/ob_table_store_util.h b/src/storage/tablet/ob_table_store_util.h index 88abc04100..d6b258240b 100644 --- a/src/storage/tablet/ob_table_store_util.h +++ b/src/storage/tablet/ob_table_store_util.h @@ -169,7 +169,7 @@ public: ddl_kvs_ = nullptr; count_ = 0; } - OB_INLINE bool count() const { return count_; } + OB_INLINE int64_t count() const { return count_; } OB_INLINE bool empty() const { return 0 == count_; } OB_INLINE bool is_valid() const { return 1 == count_ || (is_inited_ && count_ > 1 && nullptr != ddl_kvs_); } OB_INLINE int64_t get_deep_copy_size() const { return count_ * sizeof(ObITable *); } diff --git a/src/storage/tablet/ob_tablet.cpp b/src/storage/tablet/ob_tablet.cpp index d6f5864293..9735d4dabf 100644 --- a/src/storage/tablet/ob_tablet.cpp +++ b/src/storage/tablet/ob_tablet.cpp @@ -428,6 +428,13 @@ int ObTablet::init_for_merge( ddl_kvs_ = ddl_kvs_addr; ddl_kv_count_ = ddl_kv_count; ALLOC_AND_INIT(allocator, table_store_addr_, (*this), param, (*old_table_store)); + if (OB_UNLIKELY(ddl_kv_count_ != ddl_kv_count + || ddl_kv_count != table_store_addr_.get_ptr()->get_ddl_memtable_count())) { + // This is defense code. If it runs at here, it must be a bug. + ret = OB_ERR_UNEXPECTED; + LOG_ERROR("It encounters a ddl kv array bug, please pay attention", K(ret), K(ddl_kv_count), K(ddl_kv_count_), + "table store ddl kv count", table_store_addr_.get_ptr()->get_ddl_memtable_count()); + } } if (FAILEDx(table_store_cache_.init(table_store_addr_.get_ptr()->get_major_sstables(), diff --git a/unittest/storage/tablet/test_tablet.cpp b/unittest/storage/tablet/test_tablet.cpp index bddd3e6e56..c9cd25bb5e 100644 --- a/unittest/storage/tablet/test_tablet.cpp +++ b/unittest/storage/tablet/test_tablet.cpp @@ -27,6 +27,7 @@ #include "storage/tablet/ob_tablet_binding_helper.h" #include "storage/tablet/ob_tablet_binding_info.h" #include "storage/tablet/ob_tablet_table_store_flag.h" +#include "storage/ddl/ob_tablet_ddl_kv.h" namespace oceanbase { @@ -37,6 +38,17 @@ using namespace storage; using namespace common; using namespace share; +#define ALLOC_AND_INIT(allocator, addr, args...) \ + do { \ + if (OB_SUCC(ret)) { \ + if (OB_FAIL(ObTabletObjLoadHelper::alloc_and_new(allocator, addr.ptr_))) { \ + LOG_WARN("fail to allocate and new object", K(ret)); \ + } else if (OB_FAIL(addr.get_ptr()->init(allocator, args))) { \ + LOG_WARN("fail to initialize tablet member", K(ret), K(addr)); \ + } \ + } \ + } while (false) \ + class ObTabletMetaV1 final { public: @@ -378,11 +390,23 @@ public: virtual ~TestTablet(); virtual void SetUp(); virtual void TearDown(); + void pull_ddl_memtables(ObIArray &ddl_kvs) + { + for (int64_t i = 0; i < ddl_kv_count_; ++i) { + ASSERT_EQ(OB_SUCCESS, ddl_kvs.push_back(ddl_kvs_[i])); + } + std::cout<< "pull ddl memtables:" << ddl_kv_count_ << std::endl; + } + void reproducing_bug(); private: ObArenaAllocator allocator_; + ObITable **ddl_kvs_; + volatile int64_t ddl_kv_count_; }; TestTablet::TestTablet() + : ddl_kvs_(nullptr), + ddl_kv_count_(0) { } @@ -514,6 +538,68 @@ TEST_F(TestTablet, test_serialize_mig_param_compat) } +class TestTableStore +{ +public: + int init(ObArenaAllocator &allocator, TestTablet &tablet) + { + int ret = OB_SUCCESS; + ObArray ddl_kvs; + tablet.pull_ddl_memtables(ddl_kvs); + ret = ddl_kvs_.init(allocator, ddl_kvs); + const int64_t count = ddl_kvs_.count(); + std::cout<< "init table store:" << ddl_kvs.count() << ", " << count < ddl_kvs; + for (int64_t i = 0; i < 3; ++i) { + ObITable *ddl_kv = new ObDDLKV(); + ddl_kv->key_.table_type_ = ObITable::TableType::DDL_MEM_SSTABLE; + ddl_kvs.push_back(ddl_kv); + } + ddl_kvs_.init(allocator, ddl_kvs); + const int64_t count = ddl_kvs_.count(); + std::cout<< "table store reproducing_bug:" << ddl_kvs.count() << ", " << count < table_store_addr; + ddl_kvs_ = static_cast(allocator_.alloc(sizeof(ObITable*) * ObTablet::DDL_KV_ARRAY_SIZE)); + ASSERT_TRUE(nullptr != ddl_kvs_); + ddl_kvs_[0] = new ObDDLKV(); + ddl_kvs_[0]->key_.table_type_ = ObITable::TableType::DDL_MEM_SSTABLE; + ddl_kvs_[1] = new ObDDLKV(); + ddl_kvs_[1]->key_.table_type_ = ObITable::TableType::DDL_MEM_SSTABLE; + ddl_kvs_[2] = new ObDDLKV(); + ddl_kvs_[2]->key_.table_type_ = ObITable::TableType::DDL_MEM_SSTABLE; + std::cout<< "reproducing_bug 1:" << ddl_kv_count_ << std::endl; + ddl_kv_count_ = 3; + std::cout<< "reproducing_bug 2:" << ddl_kv_count_ << std::endl; + ALLOC_AND_INIT(allocator_, table_store_addr, (*this)); + if (ddl_kv_count_ != table_store_addr.get_ptr()->ddl_kvs_.count()) { + std::cout<< "reproducing_bug 3:" << ddl_kv_count_ << ", " << table_store_addr.get_ptr()->ddl_kvs_.count() << std::endl; + // This is defense code. If it runs at here, it must be a bug. And, just abort to preserve the enviroment + // for debugging. Please remove me, after the problem is found. + ob_abort(); + } +} + +TEST_F(TestTablet, reproducing_bug_53174886) +{ + TestTableStore table_store; + table_store.reproducing_bug(allocator_); + reproducing_bug(); +} + } // end namespace unittest } // end namespace oceanbase