Index: content/browser/indexed_db/leveldb/leveldb_database.cc |
diff --git a/content/browser/indexed_db/leveldb/leveldb_database.cc b/content/browser/indexed_db/leveldb/leveldb_database.cc |
index 7eaa89405cb23782b5c070ca97947a64edb9f3ef..f157f5ef29d708506f8e6f00677732f1f23d56d3 100644 |
--- a/content/browser/indexed_db/leveldb/leveldb_database.cc |
+++ b/content/browser/indexed_db/leveldb/leveldb_database.cc |
@@ -92,9 +92,14 @@ LevelDBSnapshot::LevelDBSnapshot(LevelDBDatabase* db) |
LevelDBSnapshot::~LevelDBSnapshot() { db_->ReleaseSnapshot(snapshot_); } |
-LevelDBDatabase::LevelDBDatabase() {} |
+LevelDBDatabase::LevelDBDatabase(size_t max_open_iterators) |
+ : iterator_lru_(max_open_iterators) { |
+ DCHECK(max_open_iterators); |
+} |
LevelDBDatabase::~LevelDBDatabase() { |
+ LOCAL_HISTOGRAM_COUNTS_10000("Storage.IndexedDB.LevelDB.MaxIterators", |
+ max_iterators_); |
base::trace_event::MemoryDumpManager::GetInstance()->UnregisterDumpProvider( |
this); |
// db_'s destructor uses comparator_adapter_; order of deletion is important. |
@@ -287,6 +292,7 @@ static void HistogramLevelDBError(const std::string& histogram_name, |
leveldb::Status LevelDBDatabase::Open(const base::FilePath& file_name, |
const LevelDBComparator* comparator, |
+ size_t max_open_cursors, |
std::unique_ptr<LevelDBDatabase>* result, |
bool* is_disk_full) { |
IDB_TRACE("LevelDBDatabase::Open"); |
@@ -318,7 +324,7 @@ leveldb::Status LevelDBDatabase::Open(const base::FilePath& file_name, |
CheckFreeSpace("Success", file_name); |
- (*result) = base::WrapUnique(new LevelDBDatabase()); |
+ (*result) = base::WrapUnique(new LevelDBDatabase(max_open_cursors)); |
(*result)->db_ = std::move(db); |
(*result)->comparator_adapter_ = std::move(comparator_adapter); |
(*result)->comparator_ = comparator; |
@@ -348,8 +354,8 @@ std::unique_ptr<LevelDBDatabase> LevelDBDatabase::OpenInMemory( |
return std::unique_ptr<LevelDBDatabase>(); |
} |
- std::unique_ptr<LevelDBDatabase> result = |
- base::WrapUnique(new LevelDBDatabase()); |
+ std::unique_ptr<LevelDBDatabase> result = base::WrapUnique( |
+ new LevelDBDatabase(kDefaultMaxOpenIteratorsPerDatabase)); |
result->env_ = std::move(in_memory_env); |
result->db_ = std::move(db); |
result->comparator_adapter_ = std::move(comparator_adapter); |
@@ -433,9 +439,14 @@ std::unique_ptr<LevelDBIterator> LevelDBDatabase::CreateIterator( |
// performance impact is too great. |
read_options.snapshot = snapshot ? snapshot->snapshot_ : 0; |
+ num_iterators_++; |
+ max_iterators_ = std::max(max_iterators_, num_iterators_); |
+ // Iterator isn't added to lru cache until it is used, as memory isn't loaded |
+ // for the iterator until it's first Seek call. |
std::unique_ptr<leveldb::Iterator> i(db_->NewIterator(read_options)); |
return std::unique_ptr<LevelDBIterator>( |
- IndexedDBClassFactory::Get()->CreateIteratorImpl(std::move(i))); |
+ IndexedDBClassFactory::Get()->CreateIteratorImpl(std::move(i), this, |
+ read_options.snapshot)); |
} |
const LevelDBComparator* LevelDBDatabase::Comparator() const { |
@@ -479,4 +490,34 @@ bool LevelDBDatabase::OnMemoryDump( |
return true; |
} |
+std::unique_ptr<leveldb::Iterator> LevelDBDatabase::CreateLevelDBIterator( |
+ const leveldb::Snapshot* snapshot) { |
+ leveldb::ReadOptions read_options; |
+ read_options.verify_checksums = true; |
+ read_options.snapshot = snapshot; |
+ return std::unique_ptr<leveldb::Iterator>(db_->NewIterator(read_options)); |
+} |
+ |
+LevelDBDatabase::DetachIteratorOnDestruct::~DetachIteratorOnDestruct() { |
+ if (it_) |
+ it_->Detach(); |
+} |
+ |
+void LevelDBDatabase::OnIteratorUsed(LevelDBIterator* iter) { |
+ // This line updates the LRU if the item exists. |
+ if (iterator_lru_.Get(iter) != iterator_lru_.end()) |
+ return; |
+ DetachIteratorOnDestruct purger(iter); |
+ iterator_lru_.Put(iter, std::move(purger)); |
+} |
+ |
+void LevelDBDatabase::OnIteratorDestroyed(LevelDBIterator* iter) { |
+ DCHECK_GT(num_iterators_, 0u); |
+ --num_iterators_; |
+ auto it = iterator_lru_.Peek(iter); |
+ if (it == iterator_lru_.end()) |
+ return; |
+ iterator_lru_.Erase(it); |
+} |
+ |
} // namespace content |