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..8804a680b1ee856d5ae45194c4feadefce188495 100644 |
--- a/content/browser/indexed_db/leveldb/leveldb_database.cc |
+++ b/content/browser/indexed_db/leveldb/leveldb_database.cc |
@@ -41,6 +41,7 @@ |
using base::StringPiece; |
namespace content { |
+static const size_t kDefaultMaxOpenIteratorsPerDatabase = 50; |
jsbell
2017/03/22 23:55:32
We should note that this applies only to iterators
dmurph
2017/03/23 20:56:48
Done.
|
// Forcing flushes to disk at the end of a transaction guarantees that the |
// data hit disk, but drastically impacts throughput when the filesystem is |
@@ -92,9 +93,15 @@ LevelDBSnapshot::LevelDBSnapshot(LevelDBDatabase* db) |
LevelDBSnapshot::~LevelDBSnapshot() { db_->ReleaseSnapshot(snapshot_); } |
-LevelDBDatabase::LevelDBDatabase() {} |
+LevelDBDatabase::LevelDBDatabase() |
+ : iterator_lru_(kDefaultMaxOpenIteratorsPerDatabase) {} |
+ |
+LevelDBDatabase::LevelDBDatabase(size_t max_open_iterators) |
+ : iterator_lru_(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. |
@@ -285,6 +292,43 @@ static void HistogramLevelDBError(const std::string& histogram_name, |
ParseAndHistogramCorruptionDetails(histogram_name, s); |
} |
+leveldb::Status LevelDBDatabase::OpenForTesting( |
jsbell
2017/03/22 23:55:32
Too much duplicated code. :( Can we refactor?
I d
dmurph
2017/03/23 20:56:48
Done.
|
+ const base::FilePath& file_name, |
+ const LevelDBComparator* comparator, |
+ std::unique_ptr<LevelDBDatabase>* result, |
+ size_t max_open_cursors) { |
+ IDB_TRACE("LevelDBDatabase::Open"); |
+ base::TimeTicks begin_time = base::TimeTicks::Now(); |
+ |
+ std::unique_ptr<ComparatorAdapter> comparator_adapter( |
+ base::MakeUnique<ComparatorAdapter>(comparator)); |
+ |
+ std::unique_ptr<leveldb::DB> db; |
+ std::unique_ptr<const leveldb::FilterPolicy> filter_policy; |
+ const leveldb::Status s = OpenDB(comparator_adapter.get(), LevelDBEnv::Get(), |
+ file_name, &db, &filter_policy); |
+ |
+ if (!s.ok()) { |
+ HistogramLevelDBError("WebCore.IndexedDB.LevelDBOpenErrors", s); |
+ LOG(ERROR) << "Failed to open LevelDB database from " |
+ << file_name.AsUTF8Unsafe() << "," << s.ToString(); |
+ return s; |
+ } |
+ |
+ UMA_HISTOGRAM_MEDIUM_TIMES("WebCore.IndexedDB.LevelDB.OpenTime", |
+ base::TimeTicks::Now() - begin_time); |
+ |
+ CheckFreeSpace("Success", file_name); |
+ |
+ (*result) = base::WrapUnique(new LevelDBDatabase(max_open_cursors)); |
+ (*result)->db_ = std::move(db); |
+ (*result)->comparator_adapter_ = std::move(comparator_adapter); |
+ (*result)->comparator_ = comparator; |
+ (*result)->filter_policy_ = std::move(filter_policy); |
+ (*result)->file_name_for_tracing = file_name.BaseName().AsUTF8Unsafe(); |
+ return s; |
+} |
+ |
leveldb::Status LevelDBDatabase::Open(const base::FilePath& file_name, |
const LevelDBComparator* comparator, |
std::unique_ptr<LevelDBDatabase>* result, |
@@ -479,4 +523,30 @@ bool LevelDBDatabase::OnMemoryDump( |
return true; |
} |
+void LevelDBDatabase::NotifyIteratorCreated(LevelDBIterator* iter) { |
+ num_iterators_++; |
+ max_iterators_ = std::max(max_iterators_, num_iterators_); |
+} |
+ |
+void LevelDBDatabase::NotifyIteratorUsed(LevelDBIterator* iter) { |
+ // This line updates the LRU if the item exists. |
+ if (iterator_lru_.Get(iter) != iterator_lru_.end()) |
+ return; |
+ if (iterator_lru_.size() == iterator_lru_.max_size()) { |
+ auto to_evict_iter = iterator_lru_.rbegin(); |
+ LevelDBIterator* to_evict = to_evict_iter->first; |
+ to_evict->PurgeMemory(); |
+ iterator_lru_.Erase(to_evict_iter); |
+ } |
+ iterator_lru_.Put(iter, iter); |
+} |
+ |
+void LevelDBDatabase::NotifyIteratorDestroyed(LevelDBIterator* iter) { |
+ DCHECK_GT(num_iterators_, 0u); |
+ --num_iterators_; |
+ auto it = iterator_lru_.Get(iter); |
jsbell
2017/03/22 23:55:32
Peek() instead of Get(), since we don't need to me
dmurph
2017/03/23 20:56:47
Done.
|
+ if (it == iterator_lru_.end()) |
+ return; |
+ iterator_lru_.Erase(it); |
+} |
} // namespace content |