[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
main
Haobo Xu 11 years ago
parent dae7379050
commit 013e9ebbf1
  1. 22
      db/db_impl.cc
  2. 20
      db/version_set.cc
  3. 3
      db/version_set.h

@ -11,6 +11,7 @@
#include <string>
#include <stdint.h>
#include <vector>
#include <unordered_set>
#include "db/builder.h"
#include "db/db_iter.h"
@ -91,8 +92,8 @@ struct DBImpl::CompactionState {
struct DBImpl::DeletionState {
// the set of all live files that cannot be deleted
std::set<uint64_t> live;
// the list of all live files that cannot be deleted
std::vector<uint64_t> live;
// a list of all siles that exists in the db directory
std::vector<std::string> allfiles;
@ -101,7 +102,7 @@ struct DBImpl::DeletionState {
// that corresponds to the set of files in 'live'.
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;
};
@ -319,8 +320,10 @@ void DBImpl::FindObsoleteFiles(DeletionState& deletion_state) {
delete_obsolete_files_last_run_ = now_micros;
}
// Make a set of all of the live files
deletion_state.live = pending_outputs_;
// Make a list of all of the live files; set is slow, should not
// be used.
deletion_state.live.assign(pending_outputs_.begin(),
pending_outputs_.end());
versions_->AddLiveFiles(&deletion_state.live);
// set of all files in the directory
@ -341,6 +344,11 @@ void DBImpl::PurgeObsoleteFiles(DeletionState& state) {
FileType type;
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++) {
if (ParseFileName(state.allfiles[i], &number, &type)) {
bool keep = true;
@ -355,12 +363,12 @@ void DBImpl::PurgeObsoleteFiles(DeletionState& state) {
keep = (number >= state.filenumber);
break;
case kTableFile:
keep = (state.live.find(number) != state.live.end());
keep = (live_set.find(number) != live_set.end());
break;
case kTempFile:
// Any temp files that are currently being written to must
// 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;
case kInfoLogFile:
keep = true;

@ -1643,14 +1643,26 @@ uint64_t VersionSet::ApproximateOffsetOf(Version* v, const InternalKey& ikey) {
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_;
v != &dummy_versions_;
v = v->next_) {
for (int level = 0; level < NumberLevels(); level++) {
const std::vector<FileMetaData*>& files = v->files_[level];
for (size_t i = 0; i < files.size(); i++) {
live->insert(files[i]->number);
total_files += v->files_[level].size();
}
}
// 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.
// May also mutate some internal state.
void AddLiveFiles(std::set<uint64_t>* live);
void AddLiveFiles(std::vector<uint64_t>* live_list);
// Add all files listed in the current version to *live.
void AddLiveFilesCurrentVersion(std::set<uint64_t>* live);

Loading…
Cancel
Save