mirror of https://github.com/facebook/rocksdb.git
Add DB property "rocksdb.estimate-table-readers-mem"
Summary: Add a DB Property "rocksdb.estimate-table-readers-mem" to return estimated memory usage by all loaded table readers, other than allocated from block cache. Refactor the property codes to allow getting property from a version, with DB mutex not acquired. Test Plan: Add several checks of this new property in existing codes for various cases. Reviewers: yhchiang, ljin Reviewed By: ljin Subscribers: xjin, igor, leveldb Differential Revision: https://reviews.facebook.net/D20733
This commit is contained in:
parent
606a126703
commit
1242bfcad7
130
db/db_impl.cc
130
db/db_impl.cc
|
@ -514,17 +514,21 @@ void DBImpl::MaybeDumpStats() {
|
||||||
// period in rare cases.
|
// period in rare cases.
|
||||||
last_stats_dump_time_microsec_ = now_micros;
|
last_stats_dump_time_microsec_ = now_micros;
|
||||||
|
|
||||||
DBPropertyType cf_property_type = GetPropertyType("rocksdb.cfstats");
|
bool tmp1 = false;
|
||||||
DBPropertyType db_property_type = GetPropertyType("rocksdb.dbstats");
|
bool tmp2 = false;
|
||||||
|
DBPropertyType cf_property_type =
|
||||||
|
GetPropertyType("rocksdb.cfstats", &tmp1, &tmp2);
|
||||||
|
DBPropertyType db_property_type =
|
||||||
|
GetPropertyType("rocksdb.dbstats", &tmp1, &tmp2);
|
||||||
std::string stats;
|
std::string stats;
|
||||||
{
|
{
|
||||||
MutexLock l(&mutex_);
|
MutexLock l(&mutex_);
|
||||||
for (auto cfd : *versions_->GetColumnFamilySet()) {
|
for (auto cfd : *versions_->GetColumnFamilySet()) {
|
||||||
cfd->internal_stats()->GetProperty(
|
cfd->internal_stats()->GetStringProperty(cf_property_type,
|
||||||
cf_property_type, "rocksdb.cfstats", &stats);
|
"rocksdb.cfstats", &stats);
|
||||||
}
|
}
|
||||||
default_cf_internal_stats_->GetProperty(
|
default_cf_internal_stats_->GetStringProperty(db_property_type,
|
||||||
db_property_type, "rocksdb.dbstats", &stats);
|
"rocksdb.dbstats", &stats);
|
||||||
}
|
}
|
||||||
Log(options_.info_log, "------- DUMPING STATS -------");
|
Log(options_.info_log, "------- DUMPING STATS -------");
|
||||||
Log(options_.info_log, "%s", stats.c_str());
|
Log(options_.info_log, "%s", stats.c_str());
|
||||||
|
@ -3321,15 +3325,7 @@ Status DBImpl::GetImpl(const ReadOptions& options,
|
||||||
}
|
}
|
||||||
|
|
||||||
// Acquire SuperVersion
|
// Acquire SuperVersion
|
||||||
SuperVersion* sv = nullptr;
|
SuperVersion* sv = GetAndRefSuperVersion(cfd);
|
||||||
// TODO(ljin): consider using GetReferencedSuperVersion() directly
|
|
||||||
if (LIKELY(options_.allow_thread_local)) {
|
|
||||||
sv = cfd->GetThreadLocalSuperVersion(&mutex_);
|
|
||||||
} else {
|
|
||||||
mutex_.Lock();
|
|
||||||
sv = cfd->GetSuperVersion()->Ref();
|
|
||||||
mutex_.Unlock();
|
|
||||||
}
|
|
||||||
|
|
||||||
// Prepare to store a list of merge operations if merge occurs.
|
// Prepare to store a list of merge operations if merge occurs.
|
||||||
MergeContext merge_context;
|
MergeContext merge_context;
|
||||||
|
@ -3356,22 +3352,7 @@ Status DBImpl::GetImpl(const ReadOptions& options,
|
||||||
|
|
||||||
PERF_TIMER_START(get_post_process_time);
|
PERF_TIMER_START(get_post_process_time);
|
||||||
|
|
||||||
bool unref_sv = true;
|
ReturnAndCleanupSuperVersion(cfd, sv);
|
||||||
if (LIKELY(options_.allow_thread_local)) {
|
|
||||||
unref_sv = !cfd->ReturnThreadLocalSuperVersion(sv);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (unref_sv) {
|
|
||||||
// Release SuperVersion
|
|
||||||
if (sv->Unref()) {
|
|
||||||
mutex_.Lock();
|
|
||||||
sv->Cleanup();
|
|
||||||
mutex_.Unlock();
|
|
||||||
delete sv;
|
|
||||||
RecordTick(stats_, NUMBER_SUPERVERSION_CLEANUPS);
|
|
||||||
}
|
|
||||||
RecordTick(stats_, NUMBER_SUPERVERSION_RELEASES);
|
|
||||||
}
|
|
||||||
|
|
||||||
RecordTick(stats_, NUMBER_KEYS_READ);
|
RecordTick(stats_, NUMBER_KEYS_READ);
|
||||||
RecordTick(stats_, BYTES_READ, value->size());
|
RecordTick(stats_, BYTES_READ, value->size());
|
||||||
|
@ -4372,21 +4353,92 @@ const Options& DBImpl::GetOptions(ColumnFamilyHandle* column_family) const {
|
||||||
|
|
||||||
bool DBImpl::GetProperty(ColumnFamilyHandle* column_family,
|
bool DBImpl::GetProperty(ColumnFamilyHandle* column_family,
|
||||||
const Slice& property, std::string* value) {
|
const Slice& property, std::string* value) {
|
||||||
|
bool is_int_property;
|
||||||
|
bool need_out_of_mutex;
|
||||||
|
DBPropertyType property_type =
|
||||||
|
GetPropertyType(property, &is_int_property, &need_out_of_mutex);
|
||||||
|
|
||||||
value->clear();
|
value->clear();
|
||||||
auto cfh = reinterpret_cast<ColumnFamilyHandleImpl*>(column_family);
|
if (is_int_property) {
|
||||||
auto cfd = cfh->cfd();
|
uint64_t int_value;
|
||||||
DBPropertyType property_type = GetPropertyType(property);
|
bool ret_value = GetIntPropertyInternal(column_family, property_type,
|
||||||
MutexLock l(&mutex_);
|
need_out_of_mutex, &int_value);
|
||||||
return cfd->internal_stats()->GetProperty(property_type, property, value);
|
if (ret_value) {
|
||||||
|
*value = std::to_string(int_value);
|
||||||
|
}
|
||||||
|
return ret_value;
|
||||||
|
} else {
|
||||||
|
auto cfh = reinterpret_cast<ColumnFamilyHandleImpl*>(column_family);
|
||||||
|
auto cfd = cfh->cfd();
|
||||||
|
MutexLock l(&mutex_);
|
||||||
|
return cfd->internal_stats()->GetStringProperty(property_type, property,
|
||||||
|
value);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
bool DBImpl::GetIntProperty(ColumnFamilyHandle* column_family,
|
bool DBImpl::GetIntProperty(ColumnFamilyHandle* column_family,
|
||||||
const Slice& property, uint64_t* value) {
|
const Slice& property, uint64_t* value) {
|
||||||
|
bool is_int_property;
|
||||||
|
bool need_out_of_mutex;
|
||||||
|
DBPropertyType property_type =
|
||||||
|
GetPropertyType(property, &is_int_property, &need_out_of_mutex);
|
||||||
|
if (!is_int_property) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return GetIntPropertyInternal(column_family, property_type, need_out_of_mutex,
|
||||||
|
value);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool DBImpl::GetIntPropertyInternal(ColumnFamilyHandle* column_family,
|
||||||
|
DBPropertyType property_type,
|
||||||
|
bool need_out_of_mutex, uint64_t* value) {
|
||||||
auto cfh = reinterpret_cast<ColumnFamilyHandleImpl*>(column_family);
|
auto cfh = reinterpret_cast<ColumnFamilyHandleImpl*>(column_family);
|
||||||
auto cfd = cfh->cfd();
|
auto cfd = cfh->cfd();
|
||||||
DBPropertyType property_type = GetPropertyType(property);
|
|
||||||
MutexLock l(&mutex_);
|
if (!need_out_of_mutex) {
|
||||||
return cfd->internal_stats()->GetIntProperty(property_type, property, value);
|
MutexLock l(&mutex_);
|
||||||
|
return cfd->internal_stats()->GetIntProperty(property_type, value);
|
||||||
|
} else {
|
||||||
|
SuperVersion* sv = GetAndRefSuperVersion(cfd);
|
||||||
|
|
||||||
|
bool ret = cfd->internal_stats()->GetIntPropertyOutOfMutex(
|
||||||
|
property_type, sv->current, value);
|
||||||
|
|
||||||
|
ReturnAndCleanupSuperVersion(cfd, sv);
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
SuperVersion* DBImpl::GetAndRefSuperVersion(ColumnFamilyData* cfd) {
|
||||||
|
// TODO(ljin): consider using GetReferencedSuperVersion() directly
|
||||||
|
if (LIKELY(options_.allow_thread_local)) {
|
||||||
|
return cfd->GetThreadLocalSuperVersion(&mutex_);
|
||||||
|
} else {
|
||||||
|
MutexLock l(&mutex_);
|
||||||
|
return cfd->GetSuperVersion()->Ref();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void DBImpl::ReturnAndCleanupSuperVersion(ColumnFamilyData* cfd,
|
||||||
|
SuperVersion* sv) {
|
||||||
|
bool unref_sv = true;
|
||||||
|
if (LIKELY(options_.allow_thread_local)) {
|
||||||
|
unref_sv = !cfd->ReturnThreadLocalSuperVersion(sv);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (unref_sv) {
|
||||||
|
// Release SuperVersion
|
||||||
|
if (sv->Unref()) {
|
||||||
|
{
|
||||||
|
MutexLock l(&mutex_);
|
||||||
|
sv->Cleanup();
|
||||||
|
}
|
||||||
|
delete sv;
|
||||||
|
RecordTick(stats_, NUMBER_SUPERVERSION_CLEANUPS);
|
||||||
|
}
|
||||||
|
RecordTick(stats_, NUMBER_SUPERVERSION_RELEASES);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void DBImpl::GetApproximateSizes(ColumnFamilyHandle* column_family,
|
void DBImpl::GetApproximateSizes(ColumnFamilyHandle* column_family,
|
||||||
|
|
14
db/db_impl.h
14
db/db_impl.h
|
@ -611,6 +611,16 @@ class DBImpl : public DB {
|
||||||
void InstallSuperVersion(ColumnFamilyData* cfd,
|
void InstallSuperVersion(ColumnFamilyData* cfd,
|
||||||
DeletionState& deletion_state);
|
DeletionState& deletion_state);
|
||||||
|
|
||||||
|
// Find Super version and reference it. Based on options, it might return
|
||||||
|
// the thread local cached one.
|
||||||
|
inline SuperVersion* GetAndRefSuperVersion(ColumnFamilyData* cfd);
|
||||||
|
|
||||||
|
// Un-reference the super version and return it to thread local cache if
|
||||||
|
// needed. If it is the last reference of the super version. Clean it up
|
||||||
|
// after un-referencing it.
|
||||||
|
inline void ReturnAndCleanupSuperVersion(ColumnFamilyData* cfd,
|
||||||
|
SuperVersion* sv);
|
||||||
|
|
||||||
#ifndef ROCKSDB_LITE
|
#ifndef ROCKSDB_LITE
|
||||||
using DB::GetPropertiesOfAllTables;
|
using DB::GetPropertiesOfAllTables;
|
||||||
virtual Status GetPropertiesOfAllTables(ColumnFamilyHandle* column_family,
|
virtual Status GetPropertiesOfAllTables(ColumnFamilyHandle* column_family,
|
||||||
|
@ -623,6 +633,10 @@ class DBImpl : public DB {
|
||||||
Status GetImpl(const ReadOptions& options, ColumnFamilyHandle* column_family,
|
Status GetImpl(const ReadOptions& options, ColumnFamilyHandle* column_family,
|
||||||
const Slice& key, std::string* value,
|
const Slice& key, std::string* value,
|
||||||
bool* value_found = nullptr);
|
bool* value_found = nullptr);
|
||||||
|
|
||||||
|
bool GetIntPropertyInternal(ColumnFamilyHandle* column_family,
|
||||||
|
DBPropertyType property_type,
|
||||||
|
bool need_out_of_mutex, uint64_t* value);
|
||||||
};
|
};
|
||||||
|
|
||||||
// Sanitize db options. The caller should delete result.info_log if
|
// Sanitize db options. The caller should delete result.info_log if
|
||||||
|
|
|
@ -1186,6 +1186,10 @@ TEST(DBTest, IndexAndFilterBlocksOfNewTableAddedToCache) {
|
||||||
ASSERT_EQ(2, /* only index/filter were added */
|
ASSERT_EQ(2, /* only index/filter were added */
|
||||||
TestGetTickerCount(options, BLOCK_CACHE_ADD));
|
TestGetTickerCount(options, BLOCK_CACHE_ADD));
|
||||||
ASSERT_EQ(0, TestGetTickerCount(options, BLOCK_CACHE_DATA_MISS));
|
ASSERT_EQ(0, TestGetTickerCount(options, BLOCK_CACHE_DATA_MISS));
|
||||||
|
uint64_t int_num;
|
||||||
|
ASSERT_TRUE(
|
||||||
|
dbfull()->GetIntProperty("rocksdb.estimate-table-readers-mem", &int_num));
|
||||||
|
ASSERT_EQ(int_num, 0U);
|
||||||
|
|
||||||
// Make sure filter block is in cache.
|
// Make sure filter block is in cache.
|
||||||
std::string value;
|
std::string value;
|
||||||
|
@ -2489,6 +2493,10 @@ TEST(DBTest, GetProperty) {
|
||||||
uint64_t int_num;
|
uint64_t int_num;
|
||||||
SetPerfLevel(kEnableTime);
|
SetPerfLevel(kEnableTime);
|
||||||
|
|
||||||
|
ASSERT_TRUE(
|
||||||
|
dbfull()->GetIntProperty("rocksdb.estimate-table-readers-mem", &int_num));
|
||||||
|
ASSERT_EQ(int_num, 0U);
|
||||||
|
|
||||||
ASSERT_OK(dbfull()->Put(writeOpt, "k1", big_value));
|
ASSERT_OK(dbfull()->Put(writeOpt, "k1", big_value));
|
||||||
ASSERT_TRUE(dbfull()->GetProperty("rocksdb.num-immutable-mem-table", &num));
|
ASSERT_TRUE(dbfull()->GetProperty("rocksdb.num-immutable-mem-table", &num));
|
||||||
ASSERT_EQ(num, "0");
|
ASSERT_EQ(num, "0");
|
||||||
|
@ -2525,6 +2533,10 @@ TEST(DBTest, GetProperty) {
|
||||||
ASSERT_TRUE(dbfull()->GetIntProperty("rocksdb.estimate-num-keys", &int_num));
|
ASSERT_TRUE(dbfull()->GetIntProperty("rocksdb.estimate-num-keys", &int_num));
|
||||||
ASSERT_EQ(int_num, 4U);
|
ASSERT_EQ(int_num, 4U);
|
||||||
|
|
||||||
|
ASSERT_TRUE(
|
||||||
|
dbfull()->GetIntProperty("rocksdb.estimate-table-readers-mem", &int_num));
|
||||||
|
ASSERT_EQ(int_num, 0U);
|
||||||
|
|
||||||
sleeping_task_high.WakeUp();
|
sleeping_task_high.WakeUp();
|
||||||
sleeping_task_high.WaitUntilDone();
|
sleeping_task_high.WaitUntilDone();
|
||||||
dbfull()->TEST_WaitForFlushMemTable();
|
dbfull()->TEST_WaitForFlushMemTable();
|
||||||
|
@ -2538,8 +2550,29 @@ TEST(DBTest, GetProperty) {
|
||||||
ASSERT_EQ(num, "1");
|
ASSERT_EQ(num, "1");
|
||||||
ASSERT_TRUE(dbfull()->GetProperty("rocksdb.estimate-num-keys", &num));
|
ASSERT_TRUE(dbfull()->GetProperty("rocksdb.estimate-num-keys", &num));
|
||||||
ASSERT_EQ(num, "4");
|
ASSERT_EQ(num, "4");
|
||||||
|
|
||||||
|
ASSERT_TRUE(
|
||||||
|
dbfull()->GetIntProperty("rocksdb.estimate-table-readers-mem", &int_num));
|
||||||
|
ASSERT_GT(int_num, 0U);
|
||||||
|
|
||||||
sleeping_task_low.WakeUp();
|
sleeping_task_low.WakeUp();
|
||||||
sleeping_task_low.WaitUntilDone();
|
sleeping_task_low.WaitUntilDone();
|
||||||
|
|
||||||
|
dbfull()->TEST_WaitForFlushMemTable();
|
||||||
|
options.max_open_files = 10;
|
||||||
|
Reopen(&options);
|
||||||
|
// After reopening, no table reader is loaded, so no memory for table readers
|
||||||
|
ASSERT_TRUE(
|
||||||
|
dbfull()->GetIntProperty("rocksdb.estimate-table-readers-mem", &int_num));
|
||||||
|
ASSERT_EQ(int_num, 0U);
|
||||||
|
ASSERT_TRUE(dbfull()->GetIntProperty("rocksdb.estimate-num-keys", &int_num));
|
||||||
|
ASSERT_GT(int_num, 0U);
|
||||||
|
|
||||||
|
// After reading a key, at least one table reader is loaded.
|
||||||
|
Get("k5");
|
||||||
|
ASSERT_TRUE(
|
||||||
|
dbfull()->GetIntProperty("rocksdb.estimate-table-readers-mem", &int_num));
|
||||||
|
ASSERT_GT(int_num, 0U);
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST(DBTest, FLUSH) {
|
TEST(DBTest, FLUSH) {
|
||||||
|
|
|
@ -86,12 +86,17 @@ void PrintLevelStats(char* buf, size_t len, const std::string& name,
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
DBPropertyType GetPropertyType(const Slice& property) {
|
DBPropertyType GetPropertyType(const Slice& property, bool* is_int_property,
|
||||||
|
bool* need_out_of_mutex) {
|
||||||
|
assert(is_int_property != nullptr);
|
||||||
|
assert(need_out_of_mutex != nullptr);
|
||||||
Slice in = property;
|
Slice in = property;
|
||||||
Slice prefix("rocksdb.");
|
Slice prefix("rocksdb.");
|
||||||
|
*need_out_of_mutex = false;
|
||||||
if (!in.starts_with(prefix)) return kUnknown;
|
if (!in.starts_with(prefix)) return kUnknown;
|
||||||
in.remove_prefix(prefix.size());
|
in.remove_prefix(prefix.size());
|
||||||
|
|
||||||
|
*is_int_property = false;
|
||||||
if (in.starts_with("num-files-at-level")) {
|
if (in.starts_with("num-files-at-level")) {
|
||||||
return kNumFilesAtLevel;
|
return kNumFilesAtLevel;
|
||||||
} else if (in == "levelstats") {
|
} else if (in == "levelstats") {
|
||||||
|
@ -104,7 +109,10 @@ DBPropertyType GetPropertyType(const Slice& property) {
|
||||||
return kDBStats;
|
return kDBStats;
|
||||||
} else if (in == "sstables") {
|
} else if (in == "sstables") {
|
||||||
return kSsTables;
|
return kSsTables;
|
||||||
} else if (in == "num-immutable-mem-table") {
|
}
|
||||||
|
|
||||||
|
*is_int_property = true;
|
||||||
|
if (in == "num-immutable-mem-table") {
|
||||||
return kNumImmutableMemTable;
|
return kNumImmutableMemTable;
|
||||||
} else if (in == "mem-table-flush-pending") {
|
} else if (in == "mem-table-flush-pending") {
|
||||||
return kMemtableFlushPending;
|
return kMemtableFlushPending;
|
||||||
|
@ -120,21 +128,32 @@ DBPropertyType GetPropertyType(const Slice& property) {
|
||||||
return kNumEntriesInImmutableMemtable;
|
return kNumEntriesInImmutableMemtable;
|
||||||
} else if (in == "estimate-num-keys") {
|
} else if (in == "estimate-num-keys") {
|
||||||
return kEstimatedNumKeys;
|
return kEstimatedNumKeys;
|
||||||
|
} else if (in == "estimate-table-readers-mem") {
|
||||||
|
*need_out_of_mutex = true;
|
||||||
|
return kEstimatedUsageByTableReaders;
|
||||||
}
|
}
|
||||||
return kUnknown;
|
return kUnknown;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool InternalStats::GetProperty(DBPropertyType property_type,
|
bool InternalStats::GetIntPropertyOutOfMutex(DBPropertyType property_type,
|
||||||
const Slice& property, std::string* value) {
|
Version* version,
|
||||||
if (property_type > kStartIntTypes) {
|
uint64_t* value) const {
|
||||||
uint64_t int_value;
|
assert(value != nullptr);
|
||||||
bool ret_value = GetIntProperty(property_type, property, &int_value);
|
if (property_type != kEstimatedUsageByTableReaders) {
|
||||||
if (ret_value) {
|
return false;
|
||||||
*value = std::to_string(int_value);
|
|
||||||
}
|
|
||||||
return ret_value;
|
|
||||||
}
|
}
|
||||||
|
if (version == nullptr) {
|
||||||
|
*value = 0;
|
||||||
|
} else {
|
||||||
|
*value = version->GetMemoryUsageByTableReaders();
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool InternalStats::GetStringProperty(DBPropertyType property_type,
|
||||||
|
const Slice& property,
|
||||||
|
std::string* value) {
|
||||||
|
assert(value != nullptr);
|
||||||
Version* current = cfd_->current();
|
Version* current = cfd_->current();
|
||||||
Slice in = property;
|
Slice in = property;
|
||||||
|
|
||||||
|
@ -169,10 +188,10 @@ bool InternalStats::GetProperty(DBPropertyType property_type,
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
case kStats: {
|
case kStats: {
|
||||||
if (!GetProperty(kCFStats, "rocksdb.cfstats", value)) {
|
if (!GetStringProperty(kCFStats, "rocksdb.cfstats", value)) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
if (!GetProperty(kDBStats, "rocksdb.dbstats", value)) {
|
if (!GetStringProperty(kDBStats, "rocksdb.dbstats", value)) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
|
@ -194,7 +213,6 @@ bool InternalStats::GetProperty(DBPropertyType property_type,
|
||||||
}
|
}
|
||||||
|
|
||||||
bool InternalStats::GetIntProperty(DBPropertyType property_type,
|
bool InternalStats::GetIntProperty(DBPropertyType property_type,
|
||||||
const Slice& property,
|
|
||||||
uint64_t* value) const {
|
uint64_t* value) const {
|
||||||
Version* current = cfd_->current();
|
Version* current = cfd_->current();
|
||||||
|
|
||||||
|
|
|
@ -41,9 +41,12 @@ enum DBPropertyType : uint32_t {
|
||||||
kNumEntriesInImmutableMemtable, // Return sum of number of entries in all
|
kNumEntriesInImmutableMemtable, // Return sum of number of entries in all
|
||||||
// the immutable mem tables.
|
// the immutable mem tables.
|
||||||
kEstimatedNumKeys, // Estimated total number of keys in the database.
|
kEstimatedNumKeys, // Estimated total number of keys in the database.
|
||||||
|
kEstimatedUsageByTableReaders, // Estimated memory by table readers.
|
||||||
};
|
};
|
||||||
|
|
||||||
extern DBPropertyType GetPropertyType(const Slice& property);
|
extern DBPropertyType GetPropertyType(const Slice& property,
|
||||||
|
bool* is_int_property,
|
||||||
|
bool* need_out_of_mutex);
|
||||||
|
|
||||||
class InternalStats {
|
class InternalStats {
|
||||||
public:
|
public:
|
||||||
|
@ -191,11 +194,13 @@ class InternalStats {
|
||||||
|
|
||||||
uint64_t BumpAndGetBackgroundErrorCount() { return ++bg_error_count_; }
|
uint64_t BumpAndGetBackgroundErrorCount() { return ++bg_error_count_; }
|
||||||
|
|
||||||
bool GetProperty(DBPropertyType property_type, const Slice& property,
|
bool GetStringProperty(DBPropertyType property_type, const Slice& property,
|
||||||
std::string* value);
|
std::string* value);
|
||||||
|
|
||||||
bool GetIntProperty(DBPropertyType property_type, const Slice& property,
|
bool GetIntProperty(DBPropertyType property_type, uint64_t* value) const;
|
||||||
uint64_t* value) const;
|
|
||||||
|
bool GetIntPropertyOutOfMutex(DBPropertyType property_type, Version* version,
|
||||||
|
uint64_t* value) const;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void DumpDBStats(std::string* value);
|
void DumpDBStats(std::string* value);
|
||||||
|
|
|
@ -347,11 +347,20 @@ TEST(PlainTableDBTest, Flush) {
|
||||||
NewPlainTableFactory(plain_table_options));
|
NewPlainTableFactory(plain_table_options));
|
||||||
}
|
}
|
||||||
DestroyAndReopen(&options);
|
DestroyAndReopen(&options);
|
||||||
|
uint64_t int_num;
|
||||||
|
ASSERT_TRUE(dbfull()->GetIntProperty(
|
||||||
|
"rocksdb.estimate-table-readers-mem", &int_num));
|
||||||
|
ASSERT_EQ(int_num, 0U);
|
||||||
|
|
||||||
ASSERT_OK(Put("1000000000000foo", "v1"));
|
ASSERT_OK(Put("1000000000000foo", "v1"));
|
||||||
ASSERT_OK(Put("0000000000000bar", "v2"));
|
ASSERT_OK(Put("0000000000000bar", "v2"));
|
||||||
ASSERT_OK(Put("1000000000000foo", "v3"));
|
ASSERT_OK(Put("1000000000000foo", "v3"));
|
||||||
dbfull()->TEST_FlushMemTable();
|
dbfull()->TEST_FlushMemTable();
|
||||||
|
|
||||||
|
ASSERT_TRUE(dbfull()->GetIntProperty(
|
||||||
|
"rocksdb.estimate-table-readers-mem", &int_num));
|
||||||
|
ASSERT_GT(int_num, 0U);
|
||||||
|
|
||||||
TablePropertiesCollection ptc;
|
TablePropertiesCollection ptc;
|
||||||
reinterpret_cast<DB*>(dbfull())->GetPropertiesOfAllTables(&ptc);
|
reinterpret_cast<DB*>(dbfull())->GetPropertiesOfAllTables(&ptc);
|
||||||
ASSERT_EQ(1U, ptc.size());
|
ASSERT_EQ(1U, ptc.size());
|
||||||
|
|
|
@ -92,6 +92,8 @@ public:
|
||||||
|
|
||||||
uint64_t ApproximateOffsetOf(const Slice& key) override;
|
uint64_t ApproximateOffsetOf(const Slice& key) override;
|
||||||
|
|
||||||
|
virtual size_t ApproximateMemoryUsage() const override { return 0; }
|
||||||
|
|
||||||
void SetupForCompaction() override;
|
void SetupForCompaction() override;
|
||||||
|
|
||||||
std::shared_ptr<const TableProperties> GetTableProperties() const override;
|
std::shared_ptr<const TableProperties> GetTableProperties() const override;
|
||||||
|
|
|
@ -185,6 +185,29 @@ Status TableCache::GetTableProperties(
|
||||||
return s;
|
return s;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
size_t TableCache::GetMemoryUsageByTableReader(
|
||||||
|
const EnvOptions& toptions,
|
||||||
|
const InternalKeyComparator& internal_comparator,
|
||||||
|
const FileDescriptor& fd) {
|
||||||
|
Status s;
|
||||||
|
auto table_reader = fd.table_reader;
|
||||||
|
// table already been pre-loaded?
|
||||||
|
if (table_reader) {
|
||||||
|
return table_reader->ApproximateMemoryUsage();
|
||||||
|
}
|
||||||
|
|
||||||
|
Cache::Handle* table_handle = nullptr;
|
||||||
|
s = FindTable(toptions, internal_comparator, fd, &table_handle, true);
|
||||||
|
if (!s.ok()) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
assert(table_handle);
|
||||||
|
auto table = GetTableReaderFromHandle(table_handle);
|
||||||
|
auto ret = table->ApproximateMemoryUsage();
|
||||||
|
ReleaseHandle(table_handle);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
void TableCache::Evict(Cache* cache, uint64_t file_number) {
|
void TableCache::Evict(Cache* cache, uint64_t file_number) {
|
||||||
cache->Erase(GetSliceForFileNumber(&file_number));
|
cache->Erase(GetSliceForFileNumber(&file_number));
|
||||||
}
|
}
|
||||||
|
|
|
@ -80,6 +80,13 @@ class TableCache {
|
||||||
std::shared_ptr<const TableProperties>* properties,
|
std::shared_ptr<const TableProperties>* properties,
|
||||||
bool no_io = false);
|
bool no_io = false);
|
||||||
|
|
||||||
|
// Return total memory usage of the table reader of the file.
|
||||||
|
// 0 of table reader of the file is not loaded.
|
||||||
|
size_t GetMemoryUsageByTableReader(
|
||||||
|
const EnvOptions& toptions,
|
||||||
|
const InternalKeyComparator& internal_comparator,
|
||||||
|
const FileDescriptor& fd);
|
||||||
|
|
||||||
// Release the handle from a cache
|
// Release the handle from a cache
|
||||||
void ReleaseHandle(Cache::Handle* handle);
|
void ReleaseHandle(Cache::Handle* handle);
|
||||||
|
|
||||||
|
|
|
@ -593,6 +593,18 @@ Status Version::GetPropertiesOfAllTables(TablePropertiesCollection* props) {
|
||||||
return Status::OK();
|
return Status::OK();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
size_t Version::GetMemoryUsageByTableReaders() {
|
||||||
|
size_t total_usage = 0;
|
||||||
|
for (auto& file_level : file_levels_) {
|
||||||
|
for (size_t i = 0; i < file_level.num_files; i++) {
|
||||||
|
total_usage += cfd_->table_cache()->GetMemoryUsageByTableReader(
|
||||||
|
vset_->storage_options_, cfd_->internal_comparator(),
|
||||||
|
file_level.files[i].fd);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return total_usage;
|
||||||
|
}
|
||||||
|
|
||||||
uint64_t Version::GetEstimatedActiveKeys() {
|
uint64_t Version::GetEstimatedActiveKeys() {
|
||||||
// Estimation will be not accurate when:
|
// Estimation will be not accurate when:
|
||||||
// (1) there is merge keys
|
// (1) there is merge keys
|
||||||
|
|
|
@ -234,6 +234,8 @@ class Version {
|
||||||
|
|
||||||
uint64_t GetEstimatedActiveKeys();
|
uint64_t GetEstimatedActiveKeys();
|
||||||
|
|
||||||
|
size_t GetMemoryUsageByTableReaders();
|
||||||
|
|
||||||
// used to sort files by size
|
// used to sort files by size
|
||||||
struct Fsize {
|
struct Fsize {
|
||||||
int index;
|
int index;
|
||||||
|
|
|
@ -359,4 +359,15 @@ void Block::SetBlockPrefixIndex(BlockPrefixIndex* prefix_index) {
|
||||||
prefix_index_.reset(prefix_index);
|
prefix_index_.reset(prefix_index);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
size_t Block::ApproximateMemoryUsage() const {
|
||||||
|
size_t usage = size();
|
||||||
|
if (hash_index_) {
|
||||||
|
usage += hash_index_->ApproximateMemoryUsage();
|
||||||
|
}
|
||||||
|
if (prefix_index_) {
|
||||||
|
usage += prefix_index_->ApproximateMemoryUsage();
|
||||||
|
}
|
||||||
|
return usage;
|
||||||
|
}
|
||||||
|
|
||||||
} // namespace rocksdb
|
} // namespace rocksdb
|
||||||
|
|
|
@ -50,6 +50,9 @@ class Block {
|
||||||
void SetBlockHashIndex(BlockHashIndex* hash_index);
|
void SetBlockHashIndex(BlockHashIndex* hash_index);
|
||||||
void SetBlockPrefixIndex(BlockPrefixIndex* prefix_index);
|
void SetBlockPrefixIndex(BlockPrefixIndex* prefix_index);
|
||||||
|
|
||||||
|
// Report an approximation of how much memory has been used.
|
||||||
|
size_t ApproximateMemoryUsage() const;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
const char* data_;
|
const char* data_;
|
||||||
size_t size_;
|
size_t size_;
|
||||||
|
|
|
@ -142,6 +142,10 @@ class BlockBasedTable::IndexReader {
|
||||||
// The size of the index.
|
// The size of the index.
|
||||||
virtual size_t size() const = 0;
|
virtual size_t size() const = 0;
|
||||||
|
|
||||||
|
// Report an approximation of how much memory has been used other than memory
|
||||||
|
// that was allocated in block cache.
|
||||||
|
virtual size_t ApproximateMemoryUsage() const = 0;
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
const Comparator* comparator_;
|
const Comparator* comparator_;
|
||||||
};
|
};
|
||||||
|
@ -176,6 +180,11 @@ class BinarySearchIndexReader : public IndexReader {
|
||||||
|
|
||||||
virtual size_t size() const override { return index_block_->size(); }
|
virtual size_t size() const override { return index_block_->size(); }
|
||||||
|
|
||||||
|
virtual size_t ApproximateMemoryUsage() const override {
|
||||||
|
assert(index_block_);
|
||||||
|
return index_block_->ApproximateMemoryUsage();
|
||||||
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
BinarySearchIndexReader(const Comparator* comparator, Block* index_block)
|
BinarySearchIndexReader(const Comparator* comparator, Block* index_block)
|
||||||
: IndexReader(comparator), index_block_(index_block) {
|
: IndexReader(comparator), index_block_(index_block) {
|
||||||
|
@ -292,6 +301,12 @@ class HashIndexReader : public IndexReader {
|
||||||
|
|
||||||
virtual size_t size() const override { return index_block_->size(); }
|
virtual size_t size() const override { return index_block_->size(); }
|
||||||
|
|
||||||
|
virtual size_t ApproximateMemoryUsage() const override {
|
||||||
|
assert(index_block_);
|
||||||
|
return index_block_->ApproximateMemoryUsage() +
|
||||||
|
prefixes_contents_.data.size();
|
||||||
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
HashIndexReader(const Comparator* comparator, Block* index_block)
|
HashIndexReader(const Comparator* comparator, Block* index_block)
|
||||||
: IndexReader(comparator),
|
: IndexReader(comparator),
|
||||||
|
@ -544,6 +559,17 @@ std::shared_ptr<const TableProperties> BlockBasedTable::GetTableProperties()
|
||||||
return rep_->table_properties;
|
return rep_->table_properties;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
size_t BlockBasedTable::ApproximateMemoryUsage() const {
|
||||||
|
size_t usage = 0;
|
||||||
|
if (rep_->filter) {
|
||||||
|
usage += rep_->filter->ApproximateMemoryUsage();
|
||||||
|
}
|
||||||
|
if (rep_->index_reader) {
|
||||||
|
usage += rep_->index_reader->ApproximateMemoryUsage();
|
||||||
|
}
|
||||||
|
return usage;
|
||||||
|
}
|
||||||
|
|
||||||
// Load the meta-block from the file. On success, return the loaded meta block
|
// Load the meta-block from the file. On success, return the loaded meta block
|
||||||
// and its iterator.
|
// and its iterator.
|
||||||
Status BlockBasedTable::ReadMetaBlock(
|
Status BlockBasedTable::ReadMetaBlock(
|
||||||
|
|
|
@ -96,6 +96,8 @@ class BlockBasedTable : public TableReader {
|
||||||
|
|
||||||
std::shared_ptr<const TableProperties> GetTableProperties() const override;
|
std::shared_ptr<const TableProperties> GetTableProperties() const override;
|
||||||
|
|
||||||
|
size_t ApproximateMemoryUsage() const override;
|
||||||
|
|
||||||
~BlockBasedTable();
|
~BlockBasedTable();
|
||||||
|
|
||||||
bool TEST_filter_block_preloaded() const;
|
bool TEST_filter_block_preloaded() const;
|
||||||
|
|
|
@ -268,5 +268,8 @@ Iterator* CuckooTableReader::NewIterator(const ReadOptions&, Arena* arena) {
|
||||||
}
|
}
|
||||||
return iter;
|
return iter;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
size_t CuckooTableReader::ApproximateMemoryUsage() const { return 0; }
|
||||||
|
|
||||||
} // namespace rocksdb
|
} // namespace rocksdb
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -47,6 +47,9 @@ class CuckooTableReader: public TableReader {
|
||||||
|
|
||||||
Iterator* NewIterator(const ReadOptions&, Arena* arena = nullptr) override;
|
Iterator* NewIterator(const ReadOptions&, Arena* arena = nullptr) override;
|
||||||
|
|
||||||
|
// Report an approximation of how much memory has been used.
|
||||||
|
size_t ApproximateMemoryUsage() const override;
|
||||||
|
|
||||||
// Following methods are not implemented for Cuckoo Table Reader
|
// Following methods are not implemented for Cuckoo Table Reader
|
||||||
uint64_t ApproximateOffsetOf(const Slice& key) override { return 0; }
|
uint64_t ApproximateOffsetOf(const Slice& key) override { return 0; }
|
||||||
void SetupForCompaction() override {}
|
void SetupForCompaction() override {}
|
||||||
|
|
|
@ -184,4 +184,7 @@ bool FilterBlockReader::MayMatch(uint64_t block_offset, const Slice& entry) {
|
||||||
return true; // Errors are treated as potential matches
|
return true; // Errors are treated as potential matches
|
||||||
}
|
}
|
||||||
|
|
||||||
|
size_t FilterBlockReader::ApproximateMemoryUsage() const {
|
||||||
|
return num_ * 4 + 5 + (offset_ - data_);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -74,6 +74,7 @@ class FilterBlockReader {
|
||||||
bool delete_contents_after_use = false);
|
bool delete_contents_after_use = false);
|
||||||
bool KeyMayMatch(uint64_t block_offset, const Slice& key);
|
bool KeyMayMatch(uint64_t block_offset, const Slice& key);
|
||||||
bool PrefixMayMatch(uint64_t block_offset, const Slice& prefix);
|
bool PrefixMayMatch(uint64_t block_offset, const Slice& prefix);
|
||||||
|
size_t ApproximateMemoryUsage() const;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
const FilterPolicy* policy_;
|
const FilterPolicy* policy_;
|
||||||
|
|
|
@ -78,6 +78,10 @@ class PlainTableReader: public TableReader {
|
||||||
return table_properties_;
|
return table_properties_;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
virtual size_t ApproximateMemoryUsage() const override {
|
||||||
|
return arena_.MemoryAllocatedBytes();
|
||||||
|
}
|
||||||
|
|
||||||
PlainTableReader(const Options& options, unique_ptr<RandomAccessFile>&& file,
|
PlainTableReader(const Options& options, unique_ptr<RandomAccessFile>&& file,
|
||||||
const EnvOptions& storage_options,
|
const EnvOptions& storage_options,
|
||||||
const InternalKeyComparator& internal_comparator,
|
const InternalKeyComparator& internal_comparator,
|
||||||
|
|
|
@ -52,6 +52,9 @@ class TableReader {
|
||||||
// Prepare work that can be done before the real Get()
|
// Prepare work that can be done before the real Get()
|
||||||
virtual void Prepare(const Slice& target) {}
|
virtual void Prepare(const Slice& target) {}
|
||||||
|
|
||||||
|
// Report an approximation of how much memory has been used.
|
||||||
|
virtual size_t ApproximateMemoryUsage() const = 0;
|
||||||
|
|
||||||
// Calls (*result_handler)(handle_context, ...) repeatedly, starting with
|
// Calls (*result_handler)(handle_context, ...) repeatedly, starting with
|
||||||
// the entry found after a call to Seek(key), until result_handler returns
|
// the entry found after a call to Seek(key), until result_handler returns
|
||||||
// false, where k is the actual internal key for a row found and v as the
|
// false, where k is the actual internal key for a row found and v as the
|
||||||
|
|
Loading…
Reference in New Issue