|
|
@ -2695,34 +2695,29 @@ Status DBImpl::DoCompactionWork(CompactionState* compact, |
|
|
|
|
|
|
|
|
|
|
|
namespace { |
|
|
|
namespace { |
|
|
|
struct IterState { |
|
|
|
struct IterState { |
|
|
|
|
|
|
|
IterState(DBImpl* db, port::Mutex* mu, SuperVersion* super_version) |
|
|
|
|
|
|
|
: db(db), mu(mu), super_version(super_version) {} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
DBImpl* db; |
|
|
|
port::Mutex* mu; |
|
|
|
port::Mutex* mu; |
|
|
|
Version* version = nullptr; |
|
|
|
SuperVersion* super_version; |
|
|
|
MemTable* mem = nullptr; |
|
|
|
|
|
|
|
MemTableListVersion* imm = nullptr; |
|
|
|
|
|
|
|
DBImpl *db; |
|
|
|
|
|
|
|
}; |
|
|
|
}; |
|
|
|
|
|
|
|
|
|
|
|
static void CleanupIteratorState(void* arg1, void* arg2) { |
|
|
|
static void CleanupIteratorState(void* arg1, void* arg2) { |
|
|
|
IterState* state = reinterpret_cast<IterState*>(arg1); |
|
|
|
IterState* state = reinterpret_cast<IterState*>(arg1); |
|
|
|
DBImpl::DeletionState deletion_state(state->db->GetOptions(). |
|
|
|
DBImpl::DeletionState deletion_state(state->db->GetOptions(). |
|
|
|
max_write_buffer_number); |
|
|
|
max_write_buffer_number); |
|
|
|
state->mu->Lock(); |
|
|
|
|
|
|
|
if (state->mem) { // not set for immutable iterator
|
|
|
|
bool need_cleanup = state->super_version->Unref(); |
|
|
|
MemTable* m = state->mem->Unref(); |
|
|
|
if (need_cleanup) { |
|
|
|
if (m != nullptr) { |
|
|
|
state->mu->Lock(); |
|
|
|
deletion_state.memtables_to_free.push_back(m); |
|
|
|
state->super_version->Cleanup(); |
|
|
|
} |
|
|
|
state->db->FindObsoleteFiles(deletion_state, false, true); |
|
|
|
} |
|
|
|
state->mu->Unlock(); |
|
|
|
if (state->version) { // not set for memtable-only iterator
|
|
|
|
|
|
|
|
state->version->Unref(); |
|
|
|
delete state->super_version; |
|
|
|
} |
|
|
|
state->db->PurgeObsoleteFiles(deletion_state); |
|
|
|
if (state->imm) { // not set for memtable-only iterator
|
|
|
|
|
|
|
|
state->imm->Unref(&deletion_state.memtables_to_free); |
|
|
|
|
|
|
|
} |
|
|
|
} |
|
|
|
// fast path FindObsoleteFiles
|
|
|
|
|
|
|
|
state->db->FindObsoleteFiles(deletion_state, false, true); |
|
|
|
|
|
|
|
state->mu->Unlock(); |
|
|
|
|
|
|
|
state->db->PurgeObsoleteFiles(deletion_state); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
delete state; |
|
|
|
delete state; |
|
|
|
} |
|
|
|
} |
|
|
@ -2730,36 +2725,24 @@ static void CleanupIteratorState(void* arg1, void* arg2) { |
|
|
|
|
|
|
|
|
|
|
|
Iterator* DBImpl::NewInternalIterator(const ReadOptions& options, |
|
|
|
Iterator* DBImpl::NewInternalIterator(const ReadOptions& options, |
|
|
|
SequenceNumber* latest_snapshot) { |
|
|
|
SequenceNumber* latest_snapshot) { |
|
|
|
IterState* cleanup = new IterState; |
|
|
|
|
|
|
|
MemTable* mutable_mem; |
|
|
|
|
|
|
|
MemTableListVersion* immutable_mems; |
|
|
|
|
|
|
|
Version* version; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// Collect together all needed child iterators for mem
|
|
|
|
|
|
|
|
mutex_.Lock(); |
|
|
|
mutex_.Lock(); |
|
|
|
*latest_snapshot = versions_->LastSequence(); |
|
|
|
*latest_snapshot = versions_->LastSequence(); |
|
|
|
mutable_mem = default_cfd_->mem(); |
|
|
|
SuperVersion* super_version = default_cfd_->GetSuperVersion()->Ref(); |
|
|
|
mutable_mem->Ref(); |
|
|
|
|
|
|
|
immutable_mems = default_cfd_->imm()->current(); |
|
|
|
|
|
|
|
immutable_mems->Ref(); |
|
|
|
|
|
|
|
version = default_cfd_->current(); |
|
|
|
|
|
|
|
version->Ref(); |
|
|
|
|
|
|
|
mutex_.Unlock(); |
|
|
|
mutex_.Unlock(); |
|
|
|
|
|
|
|
|
|
|
|
std::vector<Iterator*> iterator_list; |
|
|
|
std::vector<Iterator*> iterator_list; |
|
|
|
iterator_list.push_back(mutable_mem->NewIterator(options)); |
|
|
|
// Collect iterator for mutable mem
|
|
|
|
cleanup->mem = mutable_mem; |
|
|
|
iterator_list.push_back(super_version->mem->NewIterator(options)); |
|
|
|
cleanup->imm = immutable_mems; |
|
|
|
|
|
|
|
// Collect all needed child iterators for immutable memtables
|
|
|
|
// Collect all needed child iterators for immutable memtables
|
|
|
|
immutable_mems->AddIterators(options, &iterator_list); |
|
|
|
super_version->imm->AddIterators(options, &iterator_list); |
|
|
|
// Collect iterators for files in L0 - Ln
|
|
|
|
// Collect iterators for files in L0 - Ln
|
|
|
|
version->AddIterators(options, storage_options_, &iterator_list); |
|
|
|
super_version->current->AddIterators(options, storage_options_, |
|
|
|
|
|
|
|
&iterator_list); |
|
|
|
Iterator* internal_iter = |
|
|
|
Iterator* internal_iter = |
|
|
|
NewMergingIterator(&default_cfd_->internal_comparator(), |
|
|
|
NewMergingIterator(&default_cfd_->internal_comparator(), |
|
|
|
&iterator_list[0], iterator_list.size()); |
|
|
|
&iterator_list[0], iterator_list.size()); |
|
|
|
cleanup->version = version; |
|
|
|
|
|
|
|
cleanup->mu = &mutex_; |
|
|
|
IterState* cleanup = new IterState(this, &mutex_, super_version); |
|
|
|
cleanup->db = this; |
|
|
|
|
|
|
|
internal_iter->RegisterCleanup(CleanupIteratorState, cleanup, nullptr); |
|
|
|
internal_iter->RegisterCleanup(CleanupIteratorState, cleanup, nullptr); |
|
|
|
|
|
|
|
|
|
|
|
return internal_iter; |
|
|
|
return internal_iter; |
|
|
@ -2774,53 +2757,36 @@ std::pair<Iterator*, Iterator*> DBImpl::GetTailingIteratorPair( |
|
|
|
const ReadOptions& options, |
|
|
|
const ReadOptions& options, |
|
|
|
uint64_t* superversion_number) { |
|
|
|
uint64_t* superversion_number) { |
|
|
|
|
|
|
|
|
|
|
|
MemTable* mutable_mem; |
|
|
|
|
|
|
|
MemTableListVersion* immutable_mems; |
|
|
|
|
|
|
|
Version* version; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// get all child iterators and bump their refcounts under lock
|
|
|
|
|
|
|
|
mutex_.Lock(); |
|
|
|
mutex_.Lock(); |
|
|
|
mutable_mem = default_cfd_->mem(); |
|
|
|
SuperVersion* super_version = default_cfd_->GetSuperVersion()->Ref(); |
|
|
|
mutable_mem->Ref(); |
|
|
|
|
|
|
|
immutable_mems = default_cfd_->imm()->current(); |
|
|
|
|
|
|
|
immutable_mems->Ref(); |
|
|
|
|
|
|
|
version = default_cfd_->current(); |
|
|
|
|
|
|
|
version->Ref(); |
|
|
|
|
|
|
|
if (superversion_number != nullptr) { |
|
|
|
if (superversion_number != nullptr) { |
|
|
|
*superversion_number = CurrentVersionNumber(); |
|
|
|
*superversion_number = CurrentVersionNumber(); |
|
|
|
} |
|
|
|
} |
|
|
|
mutex_.Unlock(); |
|
|
|
mutex_.Unlock(); |
|
|
|
|
|
|
|
|
|
|
|
Iterator* mutable_iter = mutable_mem->NewIterator(options); |
|
|
|
Iterator* mutable_iter = super_version->mem->NewIterator(options); |
|
|
|
IterState* mutable_cleanup = new IterState(); |
|
|
|
|
|
|
|
mutable_cleanup->mem = mutable_mem; |
|
|
|
|
|
|
|
mutable_cleanup->db = this; |
|
|
|
|
|
|
|
mutable_cleanup->mu = &mutex_; |
|
|
|
|
|
|
|
mutable_iter->RegisterCleanup(CleanupIteratorState, mutable_cleanup, nullptr); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// create a DBIter that only uses memtable content; see NewIterator()
|
|
|
|
// create a DBIter that only uses memtable content; see NewIterator()
|
|
|
|
mutable_iter = NewDBIterator(&dbname_, env_, options_, user_comparator(), |
|
|
|
mutable_iter = NewDBIterator(&dbname_, env_, options_, user_comparator(), |
|
|
|
mutable_iter, kMaxSequenceNumber); |
|
|
|
mutable_iter, kMaxSequenceNumber); |
|
|
|
|
|
|
|
|
|
|
|
Iterator* immutable_iter; |
|
|
|
|
|
|
|
IterState* immutable_cleanup = new IterState(); |
|
|
|
|
|
|
|
std::vector<Iterator*> list; |
|
|
|
std::vector<Iterator*> list; |
|
|
|
immutable_mems->AddIterators(options, &list); |
|
|
|
super_version->imm->AddIterators(options, &list); |
|
|
|
immutable_cleanup->imm = immutable_mems; |
|
|
|
super_version->current->AddIterators(options, storage_options_, &list); |
|
|
|
version->AddIterators(options, storage_options_, &list); |
|
|
|
Iterator* immutable_iter = NewMergingIterator( |
|
|
|
immutable_cleanup->version = version; |
|
|
|
&default_cfd_->internal_comparator(), &list[0], list.size()); |
|
|
|
immutable_cleanup->db = this; |
|
|
|
|
|
|
|
immutable_cleanup->mu = &mutex_; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
immutable_iter = NewMergingIterator(&default_cfd_->internal_comparator(), |
|
|
|
|
|
|
|
&list[0], list.size()); |
|
|
|
|
|
|
|
immutable_iter->RegisterCleanup(CleanupIteratorState, immutable_cleanup, |
|
|
|
|
|
|
|
nullptr); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// create a DBIter that only uses memtable content; see NewIterator()
|
|
|
|
// create a DBIter that only uses memtable content; see NewIterator()
|
|
|
|
immutable_iter = NewDBIterator(&dbname_, env_, options_, user_comparator(), |
|
|
|
immutable_iter = NewDBIterator(&dbname_, env_, options_, user_comparator(), |
|
|
|
immutable_iter, kMaxSequenceNumber); |
|
|
|
immutable_iter, kMaxSequenceNumber); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// register cleanups
|
|
|
|
|
|
|
|
mutable_iter->RegisterCleanup(CleanupIteratorState, |
|
|
|
|
|
|
|
new IterState(this, &mutex_, super_version), nullptr); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// bump the ref one more time since it will be Unref'ed twice
|
|
|
|
|
|
|
|
immutable_iter->RegisterCleanup(CleanupIteratorState, |
|
|
|
|
|
|
|
new IterState(this, &mutex_, super_version->Ref()), nullptr); |
|
|
|
|
|
|
|
|
|
|
|
return std::make_pair(mutable_iter, immutable_iter); |
|
|
|
return std::make_pair(mutable_iter, immutable_iter); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
@ -2943,7 +2909,6 @@ std::vector<Status> DBImpl::MultiGet( |
|
|
|
|
|
|
|
|
|
|
|
StopWatch sw(env_, options_.statistics.get(), DB_MULTIGET, false); |
|
|
|
StopWatch sw(env_, options_.statistics.get(), DB_MULTIGET, false); |
|
|
|
SequenceNumber snapshot; |
|
|
|
SequenceNumber snapshot; |
|
|
|
std::vector<MemTable*> to_delete; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
mutex_.Lock(); |
|
|
|
mutex_.Lock(); |
|
|
|
if (options.snapshot != nullptr) { |
|
|
|
if (options.snapshot != nullptr) { |
|
|
@ -2952,17 +2917,9 @@ std::vector<Status> DBImpl::MultiGet( |
|
|
|
snapshot = versions_->LastSequence(); |
|
|
|
snapshot = versions_->LastSequence(); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
// TODO only works for default column family
|
|
|
|
SuperVersion* get_version = default_cfd_->GetSuperVersion()->Ref(); |
|
|
|
MemTable* mem = default_cfd_->mem(); |
|
|
|
|
|
|
|
MemTableListVersion* imm = default_cfd_->imm()->current(); |
|
|
|
|
|
|
|
Version* current = default_cfd_->current(); |
|
|
|
|
|
|
|
mem->Ref(); |
|
|
|
|
|
|
|
imm->Ref(); |
|
|
|
|
|
|
|
current->Ref(); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// Unlock while reading from files and memtables
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
mutex_.Unlock(); |
|
|
|
mutex_.Unlock(); |
|
|
|
|
|
|
|
|
|
|
|
bool have_stat_update = false; |
|
|
|
bool have_stat_update = false; |
|
|
|
Version::GetStats stats; |
|
|
|
Version::GetStats stats; |
|
|
|
|
|
|
|
|
|
|
@ -2987,12 +2944,14 @@ std::vector<Status> DBImpl::MultiGet( |
|
|
|
std::string* value = &(*values)[i]; |
|
|
|
std::string* value = &(*values)[i]; |
|
|
|
|
|
|
|
|
|
|
|
LookupKey lkey(keys[i], snapshot); |
|
|
|
LookupKey lkey(keys[i], snapshot); |
|
|
|
if (mem->Get(lkey, value, &s, merge_context, options_)) { |
|
|
|
if (get_version->mem->Get(lkey, value, &s, merge_context, options_)) { |
|
|
|
// Done
|
|
|
|
// Done
|
|
|
|
} else if (imm->Get(lkey, value, &s, merge_context, options_)) { |
|
|
|
} else if (get_version->imm->Get(lkey, value, &s, merge_context, |
|
|
|
|
|
|
|
options_)) { |
|
|
|
// Done
|
|
|
|
// Done
|
|
|
|
} else { |
|
|
|
} else { |
|
|
|
current->Get(options, lkey, value, &s, &merge_context, &stats, options_); |
|
|
|
get_version->current->Get(options, lkey, value, &s, &merge_context, |
|
|
|
|
|
|
|
&stats, options_); |
|
|
|
have_stat_update = true; |
|
|
|
have_stat_update = true; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
@ -3001,20 +2960,28 @@ std::vector<Status> DBImpl::MultiGet( |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
// Post processing (decrement reference counts and record statistics)
|
|
|
|
bool delete_get_version = false; |
|
|
|
mutex_.Lock(); |
|
|
|
if (!options_.disable_seek_compaction && have_stat_update) { |
|
|
|
if (!options_.disable_seek_compaction && |
|
|
|
mutex_.Lock(); |
|
|
|
have_stat_update && current->UpdateStats(stats)) { |
|
|
|
if (get_version->current->UpdateStats(stats)) { |
|
|
|
MaybeScheduleFlushOrCompaction(); |
|
|
|
MaybeScheduleFlushOrCompaction(); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
if (get_version->Unref()) { |
|
|
|
|
|
|
|
get_version->Cleanup(); |
|
|
|
|
|
|
|
delete_get_version = true; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
mutex_.Unlock(); |
|
|
|
|
|
|
|
} else { |
|
|
|
|
|
|
|
if (get_version->Unref()) { |
|
|
|
|
|
|
|
mutex_.Lock(); |
|
|
|
|
|
|
|
get_version->Cleanup(); |
|
|
|
|
|
|
|
mutex_.Unlock(); |
|
|
|
|
|
|
|
delete_get_version = true; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
if (delete_get_version) { |
|
|
|
|
|
|
|
delete get_version; |
|
|
|
} |
|
|
|
} |
|
|
|
MemTable* m = mem->Unref(); |
|
|
|
|
|
|
|
imm->Unref(&to_delete); |
|
|
|
|
|
|
|
current->Unref(); |
|
|
|
|
|
|
|
mutex_.Unlock(); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// free up all obsolete memtables outside the mutex
|
|
|
|
|
|
|
|
delete m; |
|
|
|
|
|
|
|
for (MemTable* v: to_delete) delete v; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
RecordTick(options_.statistics.get(), NUMBER_MULTIGET_CALLS); |
|
|
|
RecordTick(options_.statistics.get(), NUMBER_MULTIGET_CALLS); |
|
|
|
RecordTick(options_.statistics.get(), NUMBER_MULTIGET_KEYS_READ, numKeys); |
|
|
|
RecordTick(options_.statistics.get(), NUMBER_MULTIGET_KEYS_READ, numKeys); |
|
|
|