Index: content/browser/indexed_db/leveldb/leveldb_transaction.cc |
diff --git a/content/browser/indexed_db/leveldb/leveldb_transaction.cc b/content/browser/indexed_db/leveldb/leveldb_transaction.cc |
index 1722549384aeec3bb98b4a0d8afc4ac75507d778..4fba3224bd0bf24b7484160397f609f20e8a5bb9 100644 |
--- a/content/browser/indexed_db/leveldb/leveldb_transaction.cc |
+++ b/content/browser/indexed_db/leveldb/leveldb_transaction.cc |
@@ -41,7 +41,11 @@ LevelDBTransaction::LevelDBTransaction(LevelDBDatabase* db) |
LevelDBTransaction::Record::Record() {} |
LevelDBTransaction::Record::~Record() {} |
-LevelDBTransaction::~LevelDBTransaction() {} |
+LevelDBTransaction::~LevelDBTransaction() { |
+ for (TransactionIterator* iter : iterators_) { |
jsbell
2017/03/22 23:55:32
I left a comment before... can this be a DCHECK si
dmurph
2017/03/23 20:56:48
removed.
|
+ db_->NotifyIteratorDestroyed(iter); |
+ } |
+} |
void LevelDBTransaction::Set(const StringPiece& key, |
std::string* value, |
@@ -244,10 +248,11 @@ LevelDBTransaction::TransactionIterator::~TransactionIterator() { |
} |
bool LevelDBTransaction::TransactionIterator::IsValid() const { |
- return !!current_; |
+ return !!current_ || db_iterator_state_ == DBIteratorState::EVICTED_AND_VALID; |
} |
leveldb::Status LevelDBTransaction::TransactionIterator::SeekToLast() { |
+ LoadDBIteratorIfEvicted(); |
leveldb::Status s = data_iterator_->SeekToLast(); |
DCHECK(s.ok()); |
s = db_iterator_->SeekToLast(); |
@@ -262,6 +267,7 @@ leveldb::Status LevelDBTransaction::TransactionIterator::SeekToLast() { |
leveldb::Status LevelDBTransaction::TransactionIterator::Seek( |
const StringPiece& target) { |
+ LoadDBIteratorIfEvicted(); |
leveldb::Status s = data_iterator_->Seek(target); |
DCHECK(s.ok()); |
s = db_iterator_->Seek(target); |
@@ -275,6 +281,7 @@ leveldb::Status LevelDBTransaction::TransactionIterator::Seek( |
} |
leveldb::Status LevelDBTransaction::TransactionIterator::Next() { |
+ LoadDBIteratorIfEvicted(); |
DCHECK(IsValid()); |
if (data_changed_) |
RefreshDataIterator(); |
@@ -311,6 +318,7 @@ leveldb::Status LevelDBTransaction::TransactionIterator::Next() { |
} |
leveldb::Status LevelDBTransaction::TransactionIterator::Prev() { |
+ LoadDBIteratorIfEvicted(); |
DCHECK(IsValid()); |
leveldb::Status s; |
if (data_changed_) |
@@ -354,16 +362,41 @@ StringPiece LevelDBTransaction::TransactionIterator::Key() const { |
DCHECK(IsValid()); |
if (data_changed_) |
RefreshDataIterator(); |
+ if (current_ == nullptr && db_iterator_state_ != DBIteratorState::ACTIVE) { |
jsbell
2017/03/22 23:55:32
Nit: no need for {} on single line.
or do we want
dmurph
2017/03/23 20:56:48
Changed due to moving to impl.
|
+ return db_key_before_eviction_; |
+ } |
return current_->Key(); |
} |
StringPiece LevelDBTransaction::TransactionIterator::Value() const { |
+ if (db_iterator_state_ != DBIteratorState::ACTIVE && current_ == nullptr) { |
jsbell
2017/03/22 23:55:32
This logic is subtle and probably deserves a comme
dmurph
2017/03/23 20:56:48
Made better by moving to impl.
|
+ const_cast<LevelDBTransaction::TransactionIterator*>(this) |
jsbell
2017/03/22 23:55:32
Comment about the const_cast
Explain (for future
dmurph
2017/03/23 20:56:48
done.
|
+ ->LoadDBIteratorIfEvicted(); |
+ } |
+ DCHECK(current_); |
DCHECK(IsValid()); |
if (data_changed_) |
RefreshDataIterator(); |
return current_->Value(); |
} |
+void LevelDBTransaction::TransactionIterator::PurgeMemory() { |
+ DCHECK_EQ(db_iterator_state_, DBIteratorState::ACTIVE); |
+ if (db_iterator_->IsValid()) { |
+ db_iterator_state_ = DBIteratorState::EVICTED_AND_VALID; |
+ db_key_before_eviction_ = db_iterator_->Key().as_string(); |
+ } else { |
+ db_iterator_state_ = DBIteratorState::EVICTED_AND_INVALID; |
+ } |
+ if (current_ == db_iterator_.get()) |
+ current_ = nullptr; |
+ db_iterator_.reset(); |
+} |
+ |
+bool LevelDBTransaction::TransactionIterator::IsMemoryPurged() const { |
+ return db_iterator_state_ != DBIteratorState::ACTIVE; |
+}; |
+ |
void LevelDBTransaction::TransactionIterator::DataChanged() { |
data_changed_ = true; |
} |
@@ -411,14 +444,33 @@ void LevelDBTransaction::TransactionIterator::RefreshDataIterator() const { |
} |
bool LevelDBTransaction::TransactionIterator::DataIteratorIsLower() const { |
+ DCHECK_EQ(db_iterator_state_, DBIteratorState::ACTIVE); |
return comparator_->Compare(data_iterator_->Key(), db_iterator_->Key()) < 0; |
} |
bool LevelDBTransaction::TransactionIterator::DataIteratorIsHigher() const { |
+ DCHECK_EQ(db_iterator_state_, DBIteratorState::ACTIVE); |
return comparator_->Compare(data_iterator_->Key(), db_iterator_->Key()) > 0; |
} |
+void LevelDBTransaction::TransactionIterator::LoadDBIteratorIfEvicted() { |
+ transaction_->db_->NotifyIteratorUsed(this); |
+ |
+ if (db_iterator_state_ == DBIteratorState::ACTIVE) |
+ return; |
+ |
+ db_iterator_ = transaction_->db_->CreateIterator(&transaction_->snapshot_); |
+ if (db_iterator_state_ == DBIteratorState::EVICTED_AND_VALID) { |
+ db_iterator_->Seek(db_key_before_eviction_); |
+ db_key_before_eviction_.clear(); |
+ } |
+ if (current_ == nullptr) |
+ current_ = db_iterator_.get(); |
+ db_iterator_state_ = DBIteratorState::ACTIVE; |
+} |
+ |
void LevelDBTransaction::TransactionIterator::HandleConflictsAndDeletes() { |
+ LoadDBIteratorIfEvicted(); |
bool loop = true; |
while (loop) { |
@@ -452,6 +504,7 @@ void LevelDBTransaction::TransactionIterator::HandleConflictsAndDeletes() { |
void |
LevelDBTransaction::TransactionIterator::SetCurrentIteratorToSmallestKey() { |
+ DCHECK_EQ(db_iterator_state_, DBIteratorState::ACTIVE); |
LevelDBIterator* smallest = nullptr; |
if (data_iterator_->IsValid()) |
@@ -484,11 +537,13 @@ void LevelDBTransaction::TransactionIterator::SetCurrentIteratorToLargestKey() { |
void LevelDBTransaction::RegisterIterator(TransactionIterator* iterator) { |
DCHECK(iterators_.find(iterator) == iterators_.end()); |
iterators_.insert(iterator); |
+ db_->NotifyIteratorCreated(iterator); |
} |
void LevelDBTransaction::UnregisterIterator(TransactionIterator* iterator) { |
DCHECK(iterators_.find(iterator) != iterators_.end()); |
iterators_.erase(iterator); |
+ db_->NotifyIteratorDestroyed(iterator); |
} |
void LevelDBTransaction::NotifyIterators() { |