diff --git a/db/db_properties_test.cc b/db/db_properties_test.cc index 5ce6fb8d7..41a4db82f 100644 --- a/db/db_properties_test.cc +++ b/db/db_properties_test.cc @@ -1300,6 +1300,18 @@ TEST_F(DBPropertiesTest, NeedCompactHintPersistentTest) { SetPerfLevel(kDisable); } } + +TEST_F(DBPropertiesTest, EstimateNumKeysUnderflow) { + Options options; + Reopen(options); + Put("foo", "bar"); + Delete("foo"); + Delete("foo"); + uint64_t num_keys = 0; + ASSERT_TRUE(dbfull()->GetIntProperty("rocksdb.estimate-num-keys", &num_keys)); + ASSERT_EQ(0, num_keys); +} + #endif // ROCKSDB_LITE } // namespace rocksdb diff --git a/db/internal_stats.cc b/db/internal_stats.cc index 5de370e18..faec981a5 100644 --- a/db/internal_stats.cc +++ b/db/internal_stats.cc @@ -677,12 +677,14 @@ bool InternalStats::HandleEstimateNumKeys(uint64_t* value, DBImpl* db, // Estimate number of entries in the column family: // Use estimated entries in tables + total entries in memtables. const auto* vstorage = cfd_->current()->storage_info(); - *value = cfd_->mem()->num_entries() + - cfd_->imm()->current()->GetTotalNumEntries() - - (cfd_->mem()->num_deletes() + - cfd_->imm()->current()->GetTotalNumDeletes()) * - 2 + - vstorage->GetEstimatedActiveKeys(); + uint64_t estimate_keys = cfd_->mem()->num_entries() + + cfd_->imm()->current()->GetTotalNumEntries() + + vstorage->GetEstimatedActiveKeys(); + uint64_t estimate_deletes = + cfd_->mem()->num_deletes() + cfd_->imm()->current()->GetTotalNumDeletes(); + *value = estimate_keys > estimate_deletes * 2 + ? estimate_keys - (estimate_deletes * 2) + : 0; return true; }