Conflicts: db/db_impl.cc db/db_impl.h db/db_impl_readonly.h db/db_test.cc include/rocksdb/db.h include/utilities/stackable_db.hmain
commit
28d1a0c6f5
@ -1,10 +1,11 @@ |
|||||||
{ |
{ |
||||||
"project_id" : "leveldb", |
"project_id" : "rocksdb", |
||||||
"conduit_uri" : "https://reviews.facebook.net/", |
"conduit_uri" : "https://reviews.facebook.net/", |
||||||
"copyright_holder" : "", |
"copyright_holder" : "Facebook", |
||||||
"load" : [ |
"load" : [ |
||||||
"linters/src/" |
"linters" |
||||||
], |
], |
||||||
"lint.engine" : "FacebookFbcodeLintEngine", |
"lint.engine" : "FacebookFbcodeLintEngine", |
||||||
"lint.engine.single.linter" : "FbcodeCppLinter" |
"lint.engine.single.linter" : "FbcodeCppLinter", |
||||||
|
"lint.cpplint.prefix" : "linters" |
||||||
} |
} |
||||||
|
@ -0,0 +1,173 @@ |
|||||||
|
// Copyright (c) 2013, Facebook, Inc. All rights reserved.
|
||||||
|
// This source code is licensed under the BSD-style license found in the
|
||||||
|
// LICENSE file in the root directory of this source tree. An additional grant
|
||||||
|
// of patent rights can be found in the PATENTS file in the same directory.
|
||||||
|
|
||||||
|
#include "db/tailing_iter.h" |
||||||
|
|
||||||
|
#include <string> |
||||||
|
#include <utility> |
||||||
|
#include "db/db_impl.h" |
||||||
|
|
||||||
|
namespace rocksdb { |
||||||
|
|
||||||
|
TailingIterator::TailingIterator(DBImpl* db, const ReadOptions& options, |
||||||
|
const Comparator* comparator) |
||||||
|
: db_(db), options_(options), comparator_(comparator), |
||||||
|
version_number_(0), current_(nullptr), |
||||||
|
status_(Status::InvalidArgument("Seek() not called on this iterator")) {} |
||||||
|
|
||||||
|
bool TailingIterator::Valid() const { |
||||||
|
return current_ != nullptr; |
||||||
|
} |
||||||
|
|
||||||
|
void TailingIterator::SeekToFirst() { |
||||||
|
if (!IsCurrentVersion()) { |
||||||
|
CreateIterators(); |
||||||
|
} |
||||||
|
|
||||||
|
mutable_->SeekToFirst(); |
||||||
|
immutable_->SeekToFirst(); |
||||||
|
UpdateCurrent(); |
||||||
|
} |
||||||
|
|
||||||
|
void TailingIterator::Seek(const Slice& target) { |
||||||
|
if (!IsCurrentVersion()) { |
||||||
|
CreateIterators(); |
||||||
|
} |
||||||
|
|
||||||
|
mutable_->Seek(target); |
||||||
|
|
||||||
|
// We maintain the interval (prev_key_, immutable_->key()] such that there
|
||||||
|
// are no records with keys within that range in immutable_ other than
|
||||||
|
// immutable_->key(). Since immutable_ can't change in this version, we don't
|
||||||
|
// need to do a seek if 'target' belongs to that interval (i.e. immutable_ is
|
||||||
|
// already at the correct position)!
|
||||||
|
//
|
||||||
|
// If options.prefix_seek is used and immutable_ is not valid, seek if target
|
||||||
|
// has a different prefix than prev_key.
|
||||||
|
//
|
||||||
|
// prev_key_ is updated by Next(). SeekImmutable() sets prev_key_ to
|
||||||
|
// 'target' -- in this case, prev_key_ is included in the interval, so
|
||||||
|
// prev_inclusive_ has to be set.
|
||||||
|
|
||||||
|
if (!is_prev_set_ || |
||||||
|
comparator_->Compare(prev_key_, target) >= !is_prev_inclusive_ || |
||||||
|
(immutable_->Valid() && |
||||||
|
comparator_->Compare(target, immutable_->key()) > 0) || |
||||||
|
(options_.prefix_seek && !IsSamePrefix(target))) { |
||||||
|
SeekImmutable(target); |
||||||
|
} |
||||||
|
|
||||||
|
UpdateCurrent(); |
||||||
|
} |
||||||
|
|
||||||
|
void TailingIterator::Next() { |
||||||
|
assert(Valid()); |
||||||
|
|
||||||
|
if (!IsCurrentVersion()) { |
||||||
|
// save the current key, create new iterators and then seek
|
||||||
|
std::string current_key = key().ToString(); |
||||||
|
Slice key_slice(current_key.data(), current_key.size()); |
||||||
|
|
||||||
|
CreateIterators(); |
||||||
|
Seek(key_slice); |
||||||
|
|
||||||
|
if (!Valid() || key().compare(key_slice) != 0) { |
||||||
|
// record with current_key no longer exists
|
||||||
|
return; |
||||||
|
} |
||||||
|
|
||||||
|
} else if (current_ == immutable_.get()) { |
||||||
|
// immutable iterator is advanced -- update prev_key_
|
||||||
|
prev_key_ = key().ToString(); |
||||||
|
is_prev_inclusive_ = false; |
||||||
|
is_prev_set_ = true; |
||||||
|
} |
||||||
|
|
||||||
|
current_->Next(); |
||||||
|
UpdateCurrent(); |
||||||
|
} |
||||||
|
|
||||||
|
Slice TailingIterator::key() const { |
||||||
|
assert(Valid()); |
||||||
|
return current_->key(); |
||||||
|
} |
||||||
|
|
||||||
|
Slice TailingIterator::value() const { |
||||||
|
assert(Valid()); |
||||||
|
return current_->value(); |
||||||
|
} |
||||||
|
|
||||||
|
Status TailingIterator::status() const { |
||||||
|
if (!status_.ok()) { |
||||||
|
return status_; |
||||||
|
} else if (!mutable_->status().ok()) { |
||||||
|
return mutable_->status(); |
||||||
|
} else { |
||||||
|
return immutable_->status(); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
void TailingIterator::Prev() { |
||||||
|
status_ = Status::NotSupported("This iterator doesn't support Prev()"); |
||||||
|
} |
||||||
|
|
||||||
|
void TailingIterator::SeekToLast() { |
||||||
|
status_ = Status::NotSupported("This iterator doesn't support SeekToLast()"); |
||||||
|
} |
||||||
|
|
||||||
|
void TailingIterator::CreateIterators() { |
||||||
|
std::pair<Iterator*, Iterator*> iters = |
||||||
|
db_->GetTailingIteratorPair(options_, &version_number_); |
||||||
|
|
||||||
|
assert(iters.first && iters.second); |
||||||
|
|
||||||
|
mutable_.reset(iters.first); |
||||||
|
immutable_.reset(iters.second); |
||||||
|
current_ = nullptr; |
||||||
|
is_prev_set_ = false; |
||||||
|
} |
||||||
|
|
||||||
|
void TailingIterator::UpdateCurrent() { |
||||||
|
current_ = nullptr; |
||||||
|
|
||||||
|
if (mutable_->Valid()) { |
||||||
|
current_ = mutable_.get(); |
||||||
|
} |
||||||
|
if (immutable_->Valid() && |
||||||
|
(current_ == nullptr || |
||||||
|
comparator_->Compare(immutable_->key(), current_->key()) < 0)) { |
||||||
|
current_ = immutable_.get(); |
||||||
|
} |
||||||
|
|
||||||
|
if (!status_.ok()) { |
||||||
|
// reset status that was set by Prev() or SeekToLast()
|
||||||
|
status_ = Status::OK(); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
bool TailingIterator::IsCurrentVersion() const { |
||||||
|
return mutable_ != nullptr && immutable_ != nullptr && |
||||||
|
version_number_ == db_->CurrentVersionNumber(); |
||||||
|
} |
||||||
|
|
||||||
|
bool TailingIterator::IsSamePrefix(const Slice& target) const { |
||||||
|
const SliceTransform* extractor = db_->options_.prefix_extractor; |
||||||
|
|
||||||
|
assert(extractor); |
||||||
|
assert(is_prev_set_); |
||||||
|
|
||||||
|
return extractor->Transform(target) |
||||||
|
.compare(extractor->Transform(prev_key_)) == 0; |
||||||
|
} |
||||||
|
|
||||||
|
void TailingIterator::SeekImmutable(const Slice& target) { |
||||||
|
prev_key_ = target.ToString(); |
||||||
|
is_prev_inclusive_ = true; |
||||||
|
is_prev_set_ = true; |
||||||
|
|
||||||
|
immutable_->Seek(target); |
||||||
|
} |
||||||
|
|
||||||
|
} // namespace rocksdb
|
@ -0,0 +1,88 @@ |
|||||||
|
// Copyright (c) 2013, Facebook, Inc. All rights reserved.
|
||||||
|
// This source code is licensed under the BSD-style license found in the
|
||||||
|
// LICENSE file in the root directory of this source tree. An additional grant
|
||||||
|
// of patent rights can be found in the PATENTS file in the same directory.
|
||||||
|
#pragma once |
||||||
|
|
||||||
|
#include <string> |
||||||
|
|
||||||
|
#include "rocksdb/db.h" |
||||||
|
#include "rocksdb/iterator.h" |
||||||
|
#include "rocksdb/options.h" |
||||||
|
|
||||||
|
namespace rocksdb { |
||||||
|
|
||||||
|
class DBImpl; |
||||||
|
|
||||||
|
/**
|
||||||
|
* TailingIterator is a special type of iterator that doesn't use an (implicit) |
||||||
|
* snapshot. In other words, it can be used to read data that was added to the |
||||||
|
* db after the iterator had been created. |
||||||
|
* |
||||||
|
* TailingIterator is optimized for sequential reading. It doesn't support |
||||||
|
* Prev() and SeekToLast() operations. |
||||||
|
*/ |
||||||
|
class TailingIterator : public Iterator { |
||||||
|
public: |
||||||
|
TailingIterator(DBImpl* db, const ReadOptions& options, |
||||||
|
const Comparator* comparator); |
||||||
|
virtual ~TailingIterator() {} |
||||||
|
|
||||||
|
virtual bool Valid() const override; |
||||||
|
virtual void SeekToFirst() override; |
||||||
|
virtual void SeekToLast() override; |
||||||
|
virtual void Seek(const Slice& target) override; |
||||||
|
virtual void Next() override; |
||||||
|
virtual void Prev() override; |
||||||
|
virtual Slice key() const override; |
||||||
|
virtual Slice value() const override; |
||||||
|
virtual Status status() const override; |
||||||
|
|
||||||
|
private: |
||||||
|
DBImpl* const db_; |
||||||
|
const ReadOptions options_; |
||||||
|
const Comparator* const comparator_; |
||||||
|
uint64_t version_number_; |
||||||
|
|
||||||
|
// TailingIterator merges the contents of the two iterators below (one using
|
||||||
|
// mutable memtable contents only, other over SSTs and immutable memtables).
|
||||||
|
// See DBIter::GetTailingIteratorPair().
|
||||||
|
std::unique_ptr<Iterator> mutable_; |
||||||
|
std::unique_ptr<Iterator> immutable_; |
||||||
|
|
||||||
|
// points to either mutable_ or immutable_
|
||||||
|
Iterator* current_; |
||||||
|
|
||||||
|
// key that precedes immutable iterator's current key
|
||||||
|
std::string prev_key_; |
||||||
|
|
||||||
|
// unless prev_set is true, prev_key/prev_head is not valid and shouldn't be
|
||||||
|
// used; reset by createIterators()
|
||||||
|
bool is_prev_set_; |
||||||
|
|
||||||
|
// prev_key_ was set by SeekImmutable(), which means that the interval of
|
||||||
|
// keys covered by immutable_ is [prev_key_, current], i.e. it includes the
|
||||||
|
// left endpoint
|
||||||
|
bool is_prev_inclusive_; |
||||||
|
|
||||||
|
// internal iterator status
|
||||||
|
Status status_; |
||||||
|
|
||||||
|
// check if this iterator's version matches DB's version
|
||||||
|
bool IsCurrentVersion() const; |
||||||
|
|
||||||
|
// check if SeekImmutable() is needed due to target having a different prefix
|
||||||
|
// than prev_key_ (used when options.prefix_seek is set)
|
||||||
|
bool IsSamePrefix(const Slice& target) const; |
||||||
|
|
||||||
|
// creates mutable_ and immutable_ iterators and updates version_number_
|
||||||
|
void CreateIterators(); |
||||||
|
|
||||||
|
// set current_ to be one of the iterators with the smallest key
|
||||||
|
void UpdateCurrent(); |
||||||
|
|
||||||
|
// seek on immutable_ and update prev_key
|
||||||
|
void SeekImmutable(const Slice& target); |
||||||
|
}; |
||||||
|
|
||||||
|
} // namespace rocksdb
|
File diff suppressed because it is too large
Load Diff
@ -1 +0,0 @@ |
|||||||
{"__symbol_cache_version__":8,"b937ad5f80a8bd1156038b730ff56ec5":{"have":{"class":{"FacebookFbcodeLintEngine":71}},"need":{"class":{"ArcanistLintEngine":104,"ArcanistGeneratedLinter":488,"ArcanistNoLintLinter":577,"ArcanistTextLinter":658,"ArcanistPEP8Linter":1227,"FbcodeCppLinter":1715,"PfffCppLinter":1759,"ArcanistSpellingLinter":1875,"ArcanistFilenameLinter":4207,"Filesystem":357,"ArcanistLintSeverity":778}},"xmap":{"FacebookFbcodeLintEngine":["ArcanistLintEngine"]}},"02e2a613e371424b2108d2d6cb849d39":{"have":{"class":{"PfffCppLinter":71}},"need":{"function":{"Futures":875},"class":{"ArcanistLinter":93,"ExecFuture":756,"ArcanistLintMessage":1270,"ArcanistLintSeverity":1607}},"xmap":{"PfffCppLinter":["ArcanistLinter"]}},"4443484928afb005f585843d07b04190":{"have":{"class":{"FbcodeCppLinter":13}},"need":{"function":{"Futures":1265},"class":{"ArcanistLinter":37,"ExecFuture":934,"ArcanistLintSeverity":1729}},"xmap":{"FbcodeCppLinter":["ArcanistLinter"]}}} |
|
Loading…
Reference in new issue