Summary: Pull Request resolved: https://github.com/facebook/rocksdb/pull/4124 Differential Revision: D8829910 Pulled By: siying fbshipit-source-id: f3e952ccf3a631071a5d77c48e327046f8abb560main
parent
995fcf7573
commit
ddc07b40fc
@ -1,254 +0,0 @@ |
|||||||
// Copyright (c) 2011-present, Facebook, Inc. All rights reserved.
|
|
||||||
// This source code is licensed under both the GPLv2 (found in the
|
|
||||||
// COPYING file in the root directory) and Apache 2.0 License
|
|
||||||
// (found in the LICENSE.Apache file in the root directory).
|
|
||||||
|
|
||||||
#ifndef ROCKSDB_LITE |
|
||||||
|
|
||||||
#include "db/managed_iterator.h" |
|
||||||
|
|
||||||
#include <limits> |
|
||||||
#include <string> |
|
||||||
#include <utility> |
|
||||||
|
|
||||||
#include "db/column_family.h" |
|
||||||
#include "db/db_impl.h" |
|
||||||
#include "db/db_iter.h" |
|
||||||
#include "db/dbformat.h" |
|
||||||
#include "rocksdb/env.h" |
|
||||||
#include "rocksdb/slice.h" |
|
||||||
#include "rocksdb/slice_transform.h" |
|
||||||
#include "table/merging_iterator.h" |
|
||||||
|
|
||||||
namespace rocksdb { |
|
||||||
|
|
||||||
namespace { |
|
||||||
// Helper class that locks a mutex on construction and unlocks the mutex when
|
|
||||||
// the destructor of the MutexLock object is invoked.
|
|
||||||
//
|
|
||||||
// Typical usage:
|
|
||||||
//
|
|
||||||
// void MyClass::MyMethod() {
|
|
||||||
// MILock l(&mu_); // mu_ is an instance variable
|
|
||||||
// ... some complex code, possibly with multiple return paths ...
|
|
||||||
// }
|
|
||||||
|
|
||||||
class MILock { |
|
||||||
public: |
|
||||||
explicit MILock(std::mutex* mu, ManagedIterator* mi) : mu_(mu), mi_(mi) { |
|
||||||
this->mu_->lock(); |
|
||||||
} |
|
||||||
~MILock() { |
|
||||||
this->mu_->unlock(); |
|
||||||
} |
|
||||||
ManagedIterator* GetManagedIterator() { return mi_; } |
|
||||||
|
|
||||||
private: |
|
||||||
std::mutex* const mu_; |
|
||||||
ManagedIterator* mi_; |
|
||||||
// No copying allowed
|
|
||||||
MILock(const MILock&) = delete; |
|
||||||
void operator=(const MILock&) = delete; |
|
||||||
}; |
|
||||||
} // anonymous namespace
|
|
||||||
|
|
||||||
//
|
|
||||||
// Synchronization between modifiers, releasers, creators
|
|
||||||
// If iterator operation, wait till (!in_use), set in_use, do op, reset in_use
|
|
||||||
// if modifying mutable_iter, atomically exchange in_use:
|
|
||||||
// return if in_use set / otherwise set in use,
|
|
||||||
// atomically replace new iter with old , reset in use
|
|
||||||
// The releaser is the new operation and it holds a lock for a very short time
|
|
||||||
// The existing non-const iterator operations are supposed to be single
|
|
||||||
// threaded and hold the lock for the duration of the operation
|
|
||||||
// The existing const iterator operations use the cached key/values
|
|
||||||
// and don't do any locking.
|
|
||||||
ManagedIterator::ManagedIterator(DBImpl* db, const ReadOptions& read_options, |
|
||||||
ColumnFamilyData* cfd) |
|
||||||
: db_(db), |
|
||||||
read_options_(read_options), |
|
||||||
cfd_(cfd), |
|
||||||
svnum_(cfd->GetSuperVersionNumber()), |
|
||||||
mutable_iter_(nullptr), |
|
||||||
valid_(false), |
|
||||||
snapshot_created_(false), |
|
||||||
release_supported_(true) { |
|
||||||
read_options_.managed = false; |
|
||||||
if ((!read_options_.tailing) && (read_options_.snapshot == nullptr)) { |
|
||||||
assert(nullptr != (read_options_.snapshot = db_->GetSnapshot())); |
|
||||||
snapshot_created_ = true; |
|
||||||
} |
|
||||||
cfh_.SetCFD(cfd); |
|
||||||
mutable_iter_ = unique_ptr<Iterator>(db->NewIterator(read_options_, &cfh_)); |
|
||||||
} |
|
||||||
|
|
||||||
ManagedIterator::~ManagedIterator() { |
|
||||||
Lock(); |
|
||||||
if (snapshot_created_) { |
|
||||||
db_->ReleaseSnapshot(read_options_.snapshot); |
|
||||||
snapshot_created_ = false; |
|
||||||
read_options_.snapshot = nullptr; |
|
||||||
} |
|
||||||
UnLock(); |
|
||||||
} |
|
||||||
|
|
||||||
bool ManagedIterator::Valid() const { return valid_; } |
|
||||||
|
|
||||||
void ManagedIterator::SeekToLast() { |
|
||||||
MILock l(&in_use_, this); |
|
||||||
if (NeedToRebuild()) { |
|
||||||
RebuildIterator(); |
|
||||||
} |
|
||||||
assert(mutable_iter_ != nullptr); |
|
||||||
mutable_iter_->SeekToLast(); |
|
||||||
UpdateCurrent(); |
|
||||||
} |
|
||||||
|
|
||||||
void ManagedIterator::SeekToFirst() { |
|
||||||
MILock l(&in_use_, this); |
|
||||||
SeekInternal(Slice(), true); |
|
||||||
} |
|
||||||
|
|
||||||
void ManagedIterator::Seek(const Slice& user_key) { |
|
||||||
MILock l(&in_use_, this); |
|
||||||
SeekInternal(user_key, false); |
|
||||||
} |
|
||||||
|
|
||||||
void ManagedIterator::SeekForPrev(const Slice& user_key) { |
|
||||||
MILock l(&in_use_, this); |
|
||||||
if (NeedToRebuild()) { |
|
||||||
RebuildIterator(); |
|
||||||
} |
|
||||||
assert(mutable_iter_ != nullptr); |
|
||||||
mutable_iter_->SeekForPrev(user_key); |
|
||||||
UpdateCurrent(); |
|
||||||
} |
|
||||||
|
|
||||||
void ManagedIterator::SeekInternal(const Slice& user_key, bool seek_to_first) { |
|
||||||
if (NeedToRebuild()) { |
|
||||||
RebuildIterator(); |
|
||||||
} |
|
||||||
assert(mutable_iter_ != nullptr); |
|
||||||
if (seek_to_first) { |
|
||||||
mutable_iter_->SeekToFirst(); |
|
||||||
} else { |
|
||||||
mutable_iter_->Seek(user_key); |
|
||||||
} |
|
||||||
UpdateCurrent(); |
|
||||||
} |
|
||||||
|
|
||||||
void ManagedIterator::Prev() { |
|
||||||
if (!valid_) { |
|
||||||
status_ = Status::InvalidArgument("Iterator value invalid"); |
|
||||||
return; |
|
||||||
} |
|
||||||
MILock l(&in_use_, this); |
|
||||||
if (NeedToRebuild()) { |
|
||||||
RebuildIterator(true); |
|
||||||
if (!valid_) { |
|
||||||
return; |
|
||||||
} |
|
||||||
} |
|
||||||
mutable_iter_->Prev(); |
|
||||||
UpdateCurrent(); |
|
||||||
} |
|
||||||
|
|
||||||
void ManagedIterator::Next() { |
|
||||||
if (!valid_) { |
|
||||||
status_ = Status::InvalidArgument("Iterator value invalid"); |
|
||||||
return; |
|
||||||
} |
|
||||||
MILock l(&in_use_, this); |
|
||||||
if (NeedToRebuild()) { |
|
||||||
RebuildIterator(true); |
|
||||||
if (!valid_) { |
|
||||||
return; |
|
||||||
} |
|
||||||
} |
|
||||||
mutable_iter_->Next(); |
|
||||||
UpdateCurrent(); |
|
||||||
} |
|
||||||
|
|
||||||
Slice ManagedIterator::key() const { |
|
||||||
assert(valid_); |
|
||||||
return cached_key_.GetUserKey(); |
|
||||||
} |
|
||||||
|
|
||||||
Slice ManagedIterator::value() const { |
|
||||||
assert(valid_); |
|
||||||
return cached_value_.GetUserKey(); |
|
||||||
} |
|
||||||
|
|
||||||
Status ManagedIterator::status() const { return status_; } |
|
||||||
|
|
||||||
void ManagedIterator::RebuildIterator(bool reseek) { |
|
||||||
std::string current_key; |
|
||||||
if (reseek) { |
|
||||||
current_key = key().ToString(); |
|
||||||
} |
|
||||||
|
|
||||||
svnum_ = cfd_->GetSuperVersionNumber(); |
|
||||||
mutable_iter_ = unique_ptr<Iterator>(db_->NewIterator(read_options_, &cfh_)); |
|
||||||
|
|
||||||
if (reseek) { |
|
||||||
Slice old_key(current_key.data(), current_key.size()); |
|
||||||
SeekInternal(old_key, false); |
|
||||||
UpdateCurrent(); |
|
||||||
if (!valid_ || key().compare(old_key) != 0) { |
|
||||||
valid_ = false; |
|
||||||
status_ = Status::Incomplete( |
|
||||||
"Next/Prev failed because current key has " |
|
||||||
"been removed"); |
|
||||||
} |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
void ManagedIterator::UpdateCurrent() { |
|
||||||
assert(mutable_iter_ != nullptr); |
|
||||||
|
|
||||||
valid_ = mutable_iter_->Valid(); |
|
||||||
status_ = mutable_iter_->status(); |
|
||||||
|
|
||||||
if (!valid_) { |
|
||||||
return; |
|
||||||
} |
|
||||||
|
|
||||||
cached_key_.SetUserKey(mutable_iter_->key()); |
|
||||||
cached_value_.SetUserKey(mutable_iter_->value()); |
|
||||||
} |
|
||||||
|
|
||||||
void ManagedIterator::ReleaseIter(bool only_old) { |
|
||||||
if ((mutable_iter_ == nullptr) || (!release_supported_)) { |
|
||||||
return; |
|
||||||
} |
|
||||||
if (svnum_ != cfd_->GetSuperVersionNumber() || !only_old) { |
|
||||||
if (!TryLock()) { // Don't release iter if in use
|
|
||||||
return; |
|
||||||
} |
|
||||||
mutable_iter_ = nullptr; // in_use for a very short time
|
|
||||||
UnLock(); |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
bool ManagedIterator::NeedToRebuild() { |
|
||||||
if ((mutable_iter_ == nullptr) || (status_.IsIncomplete()) || |
|
||||||
(!only_drop_old_ && (svnum_ != cfd_->GetSuperVersionNumber()))) { |
|
||||||
return true; |
|
||||||
} |
|
||||||
return false; |
|
||||||
} |
|
||||||
|
|
||||||
void ManagedIterator::Lock() { |
|
||||||
in_use_.lock(); |
|
||||||
return; |
|
||||||
} |
|
||||||
|
|
||||||
bool ManagedIterator::TryLock() { return in_use_.try_lock(); } |
|
||||||
|
|
||||||
void ManagedIterator::UnLock() { |
|
||||||
in_use_.unlock(); |
|
||||||
} |
|
||||||
|
|
||||||
} // namespace rocksdb
|
|
||||||
|
|
||||||
#endif // ROCKSDB_LITE
|
|
@ -1,85 +0,0 @@ |
|||||||
// Copyright (c) 2011-present, Facebook, Inc. All rights reserved.
|
|
||||||
// This source code is licensed under both the GPLv2 (found in the
|
|
||||||
// COPYING file in the root directory) and Apache 2.0 License
|
|
||||||
// (found in the LICENSE.Apache file in the root directory).
|
|
||||||
#pragma once |
|
||||||
|
|
||||||
#ifndef ROCKSDB_LITE |
|
||||||
|
|
||||||
#include <mutex> |
|
||||||
#include <queue> |
|
||||||
#include <string> |
|
||||||
#include <vector> |
|
||||||
|
|
||||||
#include "db/column_family.h" |
|
||||||
#include "rocksdb/db.h" |
|
||||||
#include "rocksdb/iterator.h" |
|
||||||
#include "rocksdb/options.h" |
|
||||||
#include "util/arena.h" |
|
||||||
|
|
||||||
namespace rocksdb { |
|
||||||
|
|
||||||
class DBImpl; |
|
||||||
struct SuperVersion; |
|
||||||
class ColumnFamilyData; |
|
||||||
|
|
||||||
/**
|
|
||||||
* ManagedIterator is a special type of iterator that supports freeing the |
|
||||||
* underlying iterator and still being able to access the current key/value |
|
||||||
* pair. This is done by copying the key/value pair so that clients can |
|
||||||
* continue to access the data without getting a SIGSEGV. |
|
||||||
* The underlying iterator can be freed manually through the call to |
|
||||||
* ReleaseIter or automatically (as needed on space pressure or age.) |
|
||||||
* The iterator is recreated using the saved original arguments. |
|
||||||
*/ |
|
||||||
class ManagedIterator : public Iterator { |
|
||||||
public: |
|
||||||
ManagedIterator(DBImpl* db, const ReadOptions& read_options, |
|
||||||
ColumnFamilyData* cfd); |
|
||||||
virtual ~ManagedIterator(); |
|
||||||
|
|
||||||
virtual void SeekToLast() override; |
|
||||||
virtual void Prev() override; |
|
||||||
virtual bool Valid() const override; |
|
||||||
void SeekToFirst() override; |
|
||||||
virtual void Seek(const Slice& target) override; |
|
||||||
virtual void SeekForPrev(const Slice& target) override; |
|
||||||
virtual void Next() override; |
|
||||||
virtual Slice key() const override; |
|
||||||
virtual Slice value() const override; |
|
||||||
virtual Status status() const override; |
|
||||||
void ReleaseIter(bool only_old); |
|
||||||
void SetDropOld(bool only_old) { |
|
||||||
only_drop_old_ = read_options_.tailing || only_old; |
|
||||||
} |
|
||||||
|
|
||||||
private: |
|
||||||
void RebuildIterator(bool reseek = false); |
|
||||||
void UpdateCurrent(); |
|
||||||
void SeekInternal(const Slice& user_key, bool seek_to_first); |
|
||||||
bool NeedToRebuild(); |
|
||||||
void Lock(); |
|
||||||
bool TryLock(); |
|
||||||
void UnLock(); |
|
||||||
DBImpl* const db_; |
|
||||||
ReadOptions read_options_; |
|
||||||
ColumnFamilyData* const cfd_; |
|
||||||
ColumnFamilyHandleInternal cfh_; |
|
||||||
|
|
||||||
uint64_t svnum_; |
|
||||||
std::unique_ptr<Iterator> mutable_iter_; |
|
||||||
// internal iterator status
|
|
||||||
Status status_; |
|
||||||
bool valid_; |
|
||||||
|
|
||||||
IterKey cached_key_; |
|
||||||
IterKey cached_value_; |
|
||||||
|
|
||||||
bool only_drop_old_ = true; |
|
||||||
bool snapshot_created_; |
|
||||||
bool release_supported_; |
|
||||||
std::mutex in_use_; // is managed iterator in use
|
|
||||||
}; |
|
||||||
|
|
||||||
} // namespace rocksdb
|
|
||||||
#endif // !ROCKSDB_LITE
|
|
Loading…
Reference in new issue