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 |