| Index: content/browser/indexed_db/leveldb/leveldb_iterator_impl.cc
|
| diff --git a/content/browser/indexed_db/leveldb/leveldb_iterator_impl.cc b/content/browser/indexed_db/leveldb/leveldb_iterator_impl.cc
|
| index 2052f437168c65e580b49211ec45ff32d97d5384..b94a3d6150bee704eba43cefa3224682b9e08f60 100644
|
| --- a/content/browser/indexed_db/leveldb/leveldb_iterator_impl.cc
|
| +++ b/content/browser/indexed_db/leveldb/leveldb_iterator_impl.cc
|
| @@ -8,6 +8,7 @@
|
| #include <utility>
|
|
|
| #include "base/logging.h"
|
| +#include "content/browser/indexed_db/leveldb/leveldb_database.h"
|
|
|
| static leveldb::Slice MakeSlice(const base::StringPiece& s) {
|
| return leveldb::Slice(s.begin(), s.size());
|
| @@ -20,55 +21,102 @@ static base::StringPiece MakeStringPiece(const leveldb::Slice& s) {
|
| namespace content {
|
|
|
| LevelDBIteratorImpl::~LevelDBIteratorImpl() {
|
| + db_->OnIteratorDestroyed(this);
|
| }
|
|
|
| -LevelDBIteratorImpl::LevelDBIteratorImpl(std::unique_ptr<leveldb::Iterator> it)
|
| - : iterator_(std::move(it)) {}
|
| +LevelDBIteratorImpl::LevelDBIteratorImpl(std::unique_ptr<leveldb::Iterator> it,
|
| + LevelDBDatabase* db,
|
| + const leveldb::Snapshot* snapshot)
|
| + : iterator_(std::move(it)), db_(db), snapshot_(snapshot) {}
|
|
|
| -void LevelDBIteratorImpl::CheckStatus() {
|
| +leveldb::Status LevelDBIteratorImpl::CheckStatus() {
|
| + DCHECK(!IsDetached());
|
| const leveldb::Status& s = iterator_->status();
|
| if (!s.ok())
|
| LOG(ERROR) << "LevelDB iterator error: " << s.ToString();
|
| + return s;
|
| }
|
|
|
| bool LevelDBIteratorImpl::IsValid() const {
|
| - return iterator_->Valid();
|
| + return iterator_state_ == IteratorState::EVICTED_AND_VALID ||
|
| + iterator_->Valid();
|
| }
|
|
|
| leveldb::Status LevelDBIteratorImpl::SeekToLast() {
|
| + WillUseDBIterator();
|
| + DCHECK(iterator_);
|
| iterator_->SeekToLast();
|
| - CheckStatus();
|
| - return iterator_->status();
|
| + return CheckStatus();
|
| }
|
|
|
| leveldb::Status LevelDBIteratorImpl::Seek(const base::StringPiece& target) {
|
| + WillUseDBIterator();
|
| + DCHECK(iterator_);
|
| iterator_->Seek(MakeSlice(target));
|
| - CheckStatus();
|
| - return iterator_->status();
|
| + return CheckStatus();
|
| }
|
|
|
| leveldb::Status LevelDBIteratorImpl::Next() {
|
| DCHECK(IsValid());
|
| + WillUseDBIterator();
|
| + DCHECK(iterator_);
|
| iterator_->Next();
|
| - CheckStatus();
|
| - return iterator_->status();
|
| + return CheckStatus();
|
| }
|
|
|
| leveldb::Status LevelDBIteratorImpl::Prev() {
|
| DCHECK(IsValid());
|
| + WillUseDBIterator();
|
| + DCHECK(iterator_);
|
| iterator_->Prev();
|
| - CheckStatus();
|
| - return iterator_->status();
|
| + return CheckStatus();
|
| }
|
|
|
| base::StringPiece LevelDBIteratorImpl::Key() const {
|
| DCHECK(IsValid());
|
| + if (IsDetached())
|
| + return key_before_eviction_;
|
| return MakeStringPiece(iterator_->key());
|
| }
|
|
|
| base::StringPiece LevelDBIteratorImpl::Value() const {
|
| DCHECK(IsValid());
|
| + // Always need to update the LRU, so we always call this. Const-cast needed,
|
| + // as we're implementing a caching layer.
|
| + LevelDBIteratorImpl* non_const = const_cast<LevelDBIteratorImpl*>(this);
|
| + non_const->WillUseDBIterator();
|
| return MakeStringPiece(iterator_->value());
|
| }
|
|
|
| +void LevelDBIteratorImpl::Detach() {
|
| + DCHECK(!IsDetached());
|
| + if (iterator_->Valid()) {
|
| + iterator_state_ = IteratorState::EVICTED_AND_VALID;
|
| + key_before_eviction_ = iterator_->key().ToString();
|
| + } else {
|
| + iterator_state_ = IteratorState::EVICTED_AND_INVALID;
|
| + }
|
| + iterator_.reset();
|
| +}
|
| +
|
| +bool LevelDBIteratorImpl::IsDetached() const {
|
| + return iterator_state_ != IteratorState::ACTIVE;
|
| +}
|
| +
|
| +void LevelDBIteratorImpl::WillUseDBIterator() {
|
| + db_->OnIteratorUsed(this);
|
| + if (!IsDetached())
|
| + return;
|
| +
|
| + iterator_ = db_->CreateLevelDBIterator(snapshot_);
|
| + if (iterator_state_ == IteratorState::EVICTED_AND_VALID) {
|
| + iterator_->Seek(key_before_eviction_);
|
| + key_before_eviction_.clear();
|
| + DCHECK(IsValid());
|
| + } else {
|
| + DCHECK(!iterator_->Valid());
|
| + }
|
| + iterator_state_ = IteratorState::ACTIVE;
|
| +}
|
| +
|
| } // namespace content
|
|
|