[RocksDB] [Performance] Speed up FindObsoleteFiles
Summary: FindObsoleteFiles was slow, holding the single big lock, resulted in bad p99 behavior. Didn't profile anything, but several things could be improved: 1. VersionSet::AddLiveFiles works with std::set, which is by itself slow (a tree). You also don't know how many dynamic allocations occur just for building up this tree. switched to std::vector, also added logic to pre-calculate total size and do just one allocation 2. Don't see why env_->GetChildren() needs to be mutex proteced, moved to PurgeObsoleteFiles where mutex could be unlocked. 3. switched std::set to std:unordered_set, the conversion from vector is also inside PurgeObsoleteFiles I have a feeling this should pretty much fix it. Test Plan: make check; db_stress Reviewers: dhruba, heyongqiang, MarkCallaghan Reviewed By: dhruba CC: leveldb, zshao Differential Revision: https://reviews.facebook.net/D10197
This commit is contained in:
parent
dae7379050
commit
013e9ebbf1
@ -11,6 +11,7 @@
|
|||||||
#include <string>
|
#include <string>
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
#include <unordered_set>
|
||||||
|
|
||||||
#include "db/builder.h"
|
#include "db/builder.h"
|
||||||
#include "db/db_iter.h"
|
#include "db/db_iter.h"
|
||||||
@ -91,8 +92,8 @@ struct DBImpl::CompactionState {
|
|||||||
|
|
||||||
struct DBImpl::DeletionState {
|
struct DBImpl::DeletionState {
|
||||||
|
|
||||||
// the set of all live files that cannot be deleted
|
// the list of all live files that cannot be deleted
|
||||||
std::set<uint64_t> live;
|
std::vector<uint64_t> live;
|
||||||
|
|
||||||
// a list of all siles that exists in the db directory
|
// a list of all siles that exists in the db directory
|
||||||
std::vector<std::string> allfiles;
|
std::vector<std::string> allfiles;
|
||||||
@ -101,7 +102,7 @@ struct DBImpl::DeletionState {
|
|||||||
// that corresponds to the set of files in 'live'.
|
// that corresponds to the set of files in 'live'.
|
||||||
uint64_t filenumber, lognumber, prevlognumber;
|
uint64_t filenumber, lognumber, prevlognumber;
|
||||||
|
|
||||||
// the list of all files to be evicted from the table cahce
|
// the list of all files to be evicted from the table cache
|
||||||
std::vector<uint64_t> files_to_evict;
|
std::vector<uint64_t> files_to_evict;
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -319,8 +320,10 @@ void DBImpl::FindObsoleteFiles(DeletionState& deletion_state) {
|
|||||||
delete_obsolete_files_last_run_ = now_micros;
|
delete_obsolete_files_last_run_ = now_micros;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Make a set of all of the live files
|
// Make a list of all of the live files; set is slow, should not
|
||||||
deletion_state.live = pending_outputs_;
|
// be used.
|
||||||
|
deletion_state.live.assign(pending_outputs_.begin(),
|
||||||
|
pending_outputs_.end());
|
||||||
versions_->AddLiveFiles(&deletion_state.live);
|
versions_->AddLiveFiles(&deletion_state.live);
|
||||||
|
|
||||||
// set of all files in the directory
|
// set of all files in the directory
|
||||||
@ -341,6 +344,11 @@ void DBImpl::PurgeObsoleteFiles(DeletionState& state) {
|
|||||||
FileType type;
|
FileType type;
|
||||||
std::vector<std::string> old_log_files;
|
std::vector<std::string> old_log_files;
|
||||||
|
|
||||||
|
// Now, convert live list to an unordered set, WITHOUT mutex held;
|
||||||
|
// set is slow.
|
||||||
|
std::unordered_set<uint64_t> live_set(state.live.begin(),
|
||||||
|
state.live.end());
|
||||||
|
|
||||||
for (size_t i = 0; i < state.allfiles.size(); i++) {
|
for (size_t i = 0; i < state.allfiles.size(); i++) {
|
||||||
if (ParseFileName(state.allfiles[i], &number, &type)) {
|
if (ParseFileName(state.allfiles[i], &number, &type)) {
|
||||||
bool keep = true;
|
bool keep = true;
|
||||||
@ -355,12 +363,12 @@ void DBImpl::PurgeObsoleteFiles(DeletionState& state) {
|
|||||||
keep = (number >= state.filenumber);
|
keep = (number >= state.filenumber);
|
||||||
break;
|
break;
|
||||||
case kTableFile:
|
case kTableFile:
|
||||||
keep = (state.live.find(number) != state.live.end());
|
keep = (live_set.find(number) != live_set.end());
|
||||||
break;
|
break;
|
||||||
case kTempFile:
|
case kTempFile:
|
||||||
// Any temp files that are currently being written to must
|
// Any temp files that are currently being written to must
|
||||||
// be recorded in pending_outputs_, which is inserted into "live"
|
// be recorded in pending_outputs_, which is inserted into "live"
|
||||||
keep = (state.live.find(number) != state.live.end());
|
keep = (live_set.find(number) != live_set.end());
|
||||||
break;
|
break;
|
||||||
case kInfoLogFile:
|
case kInfoLogFile:
|
||||||
keep = true;
|
keep = true;
|
||||||
|
@ -1643,14 +1643,26 @@ uint64_t VersionSet::ApproximateOffsetOf(Version* v, const InternalKey& ikey) {
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
void VersionSet::AddLiveFiles(std::set<uint64_t>* live) {
|
void VersionSet::AddLiveFiles(std::vector<uint64_t>* live_list) {
|
||||||
|
// pre-calculate space requirement
|
||||||
|
int64_t total_files = 0;
|
||||||
for (Version* v = dummy_versions_.next_;
|
for (Version* v = dummy_versions_.next_;
|
||||||
v != &dummy_versions_;
|
v != &dummy_versions_;
|
||||||
v = v->next_) {
|
v = v->next_) {
|
||||||
for (int level = 0; level < NumberLevels(); level++) {
|
for (int level = 0; level < NumberLevels(); level++) {
|
||||||
const std::vector<FileMetaData*>& files = v->files_[level];
|
total_files += v->files_[level].size();
|
||||||
for (size_t i = 0; i < files.size(); i++) {
|
}
|
||||||
live->insert(files[i]->number);
|
}
|
||||||
|
|
||||||
|
// just one time extension to the right size
|
||||||
|
live_list->reserve(live_list->size() + total_files);
|
||||||
|
|
||||||
|
for (Version* v = dummy_versions_.next_;
|
||||||
|
v != &dummy_versions_;
|
||||||
|
v = v->next_) {
|
||||||
|
for (int level = 0; level < NumberLevels(); level++) {
|
||||||
|
for (const auto& f : v->files_[level]) {
|
||||||
|
live_list->push_back(f->number);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -326,8 +326,7 @@ class VersionSet {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Add all files listed in any live version to *live.
|
// Add all files listed in any live version to *live.
|
||||||
// May also mutate some internal state.
|
void AddLiveFiles(std::vector<uint64_t>* live_list);
|
||||||
void AddLiveFiles(std::set<uint64_t>* live);
|
|
||||||
|
|
||||||
// Add all files listed in the current version to *live.
|
// Add all files listed in the current version to *live.
|
||||||
void AddLiveFilesCurrentVersion(std::set<uint64_t>* live);
|
void AddLiveFilesCurrentVersion(std::set<uint64_t>* live);
|
||||||
|
Loading…
Reference in New Issue
Block a user