Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(79)

Side by Side Diff: content/browser/indexed_db/leveldb/leveldb_database.cc

Issue 2760163002: [IndexedDB] Pool and evict leveldb iterators, to save memory (Closed)
Patch Set: comments & lifetime fix Created 3 years, 9 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
1 // Copyright (c) 2013 The Chromium Authors. All rights reserved. 1 // Copyright (c) 2013 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 #include "content/browser/indexed_db/leveldb/leveldb_database.h" 5 #include "content/browser/indexed_db/leveldb/leveldb_database.h"
6 6
7 #include <inttypes.h> 7 #include <inttypes.h>
8 #include <stdint.h> 8 #include <stdint.h>
9 9
10 #include <cerrno> 10 #include <cerrno>
(...skipping 74 matching lines...) Expand 10 before | Expand all | Expand 10 after
85 const leveldb::Slice& limit) const {} 85 const leveldb::Slice& limit) const {}
86 86
87 void LevelDBDatabase::ComparatorAdapter::FindShortSuccessor( 87 void LevelDBDatabase::ComparatorAdapter::FindShortSuccessor(
88 std::string* key) const {} 88 std::string* key) const {}
89 89
90 LevelDBSnapshot::LevelDBSnapshot(LevelDBDatabase* db) 90 LevelDBSnapshot::LevelDBSnapshot(LevelDBDatabase* db)
91 : db_(db->db_.get()), snapshot_(db_->GetSnapshot()) {} 91 : db_(db->db_.get()), snapshot_(db_->GetSnapshot()) {}
92 92
93 LevelDBSnapshot::~LevelDBSnapshot() { db_->ReleaseSnapshot(snapshot_); } 93 LevelDBSnapshot::~LevelDBSnapshot() { db_->ReleaseSnapshot(snapshot_); }
94 94
95 LevelDBDatabase::LevelDBDatabase() {} 95 LevelDBDatabase::LevelDBDatabase(size_t max_open_iterators)
96 : eviction_enabled_(max_open_iterators != NO_CURSOR_EVICTION),
97 iterator_lru_(max_open_iterators) {}
pwnall 2017/03/24 09:16:02 Shouldn't the MRUCache be initialized with NO_AUTO
dmurph 2017/03/24 23:33:39 Creating our own struct so we do correct eviction.
96 98
97 LevelDBDatabase::~LevelDBDatabase() { 99 LevelDBDatabase::~LevelDBDatabase() {
100 LOCAL_HISTOGRAM_COUNTS_10000("Storage.IndexedDB.LevelDB.MaxIterators",
101 max_iterators_);
98 base::trace_event::MemoryDumpManager::GetInstance()->UnregisterDumpProvider( 102 base::trace_event::MemoryDumpManager::GetInstance()->UnregisterDumpProvider(
99 this); 103 this);
100 // db_'s destructor uses comparator_adapter_; order of deletion is important. 104 // db_'s destructor uses comparator_adapter_; order of deletion is important.
101 CloseDatabase(); 105 CloseDatabase();
102 comparator_adapter_.reset(); 106 comparator_adapter_.reset();
103 env_.reset(); 107 env_.reset();
104 } 108 }
105 109
106 void LevelDBDatabase::CloseDatabase() { 110 void LevelDBDatabase::CloseDatabase() {
107 if (db_) { 111 if (db_) {
(...skipping 173 matching lines...) Expand 10 before | Expand all | Expand 10 after
281 ->Add(leveldb_error); 285 ->Add(leveldb_error);
282 if (s.IsIOError()) 286 if (s.IsIOError())
283 ParseAndHistogramIOErrorDetails(histogram_name, s); 287 ParseAndHistogramIOErrorDetails(histogram_name, s);
284 else 288 else
285 ParseAndHistogramCorruptionDetails(histogram_name, s); 289 ParseAndHistogramCorruptionDetails(histogram_name, s);
286 } 290 }
287 291
288 leveldb::Status LevelDBDatabase::Open(const base::FilePath& file_name, 292 leveldb::Status LevelDBDatabase::Open(const base::FilePath& file_name,
289 const LevelDBComparator* comparator, 293 const LevelDBComparator* comparator,
290 std::unique_ptr<LevelDBDatabase>* result, 294 std::unique_ptr<LevelDBDatabase>* result,
295 size_t max_open_cursors,
291 bool* is_disk_full) { 296 bool* is_disk_full) {
292 IDB_TRACE("LevelDBDatabase::Open"); 297 IDB_TRACE("LevelDBDatabase::Open");
293 base::TimeTicks begin_time = base::TimeTicks::Now(); 298 base::TimeTicks begin_time = base::TimeTicks::Now();
294 299
295 std::unique_ptr<ComparatorAdapter> comparator_adapter( 300 std::unique_ptr<ComparatorAdapter> comparator_adapter(
296 base::MakeUnique<ComparatorAdapter>(comparator)); 301 base::MakeUnique<ComparatorAdapter>(comparator));
297 302
298 std::unique_ptr<leveldb::DB> db; 303 std::unique_ptr<leveldb::DB> db;
299 std::unique_ptr<const leveldb::FilterPolicy> filter_policy; 304 std::unique_ptr<const leveldb::FilterPolicy> filter_policy;
300 const leveldb::Status s = OpenDB(comparator_adapter.get(), LevelDBEnv::Get(), 305 const leveldb::Status s = OpenDB(comparator_adapter.get(), LevelDBEnv::Get(),
(...skipping 10 matching lines...) Expand all
311 LOG(ERROR) << "Failed to open LevelDB database from " 316 LOG(ERROR) << "Failed to open LevelDB database from "
312 << file_name.AsUTF8Unsafe() << "," << s.ToString(); 317 << file_name.AsUTF8Unsafe() << "," << s.ToString();
313 return s; 318 return s;
314 } 319 }
315 320
316 UMA_HISTOGRAM_MEDIUM_TIMES("WebCore.IndexedDB.LevelDB.OpenTime", 321 UMA_HISTOGRAM_MEDIUM_TIMES("WebCore.IndexedDB.LevelDB.OpenTime",
317 base::TimeTicks::Now() - begin_time); 322 base::TimeTicks::Now() - begin_time);
318 323
319 CheckFreeSpace("Success", file_name); 324 CheckFreeSpace("Success", file_name);
320 325
321 (*result) = base::WrapUnique(new LevelDBDatabase()); 326 (*result) = base::WrapUnique(new LevelDBDatabase(max_open_cursors));
322 (*result)->db_ = std::move(db); 327 (*result)->db_ = std::move(db);
323 (*result)->comparator_adapter_ = std::move(comparator_adapter); 328 (*result)->comparator_adapter_ = std::move(comparator_adapter);
324 (*result)->comparator_ = comparator; 329 (*result)->comparator_ = comparator;
325 (*result)->filter_policy_ = std::move(filter_policy); 330 (*result)->filter_policy_ = std::move(filter_policy);
326 (*result)->file_name_for_tracing = file_name.BaseName().AsUTF8Unsafe(); 331 (*result)->file_name_for_tracing = file_name.BaseName().AsUTF8Unsafe();
327 332
328 return s; 333 return s;
329 } 334 }
330 335
331 std::unique_ptr<LevelDBDatabase> LevelDBDatabase::OpenInMemory( 336 std::unique_ptr<LevelDBDatabase> LevelDBDatabase::OpenInMemory(
332 const LevelDBComparator* comparator) { 337 const LevelDBComparator* comparator) {
333 std::unique_ptr<ComparatorAdapter> comparator_adapter( 338 std::unique_ptr<ComparatorAdapter> comparator_adapter(
334 base::MakeUnique<ComparatorAdapter>(comparator)); 339 base::MakeUnique<ComparatorAdapter>(comparator));
335 std::unique_ptr<leveldb::Env> in_memory_env( 340 std::unique_ptr<leveldb::Env> in_memory_env(
336 leveldb::NewMemEnv(LevelDBEnv::Get())); 341 leveldb::NewMemEnv(LevelDBEnv::Get()));
337 342
338 std::unique_ptr<leveldb::DB> db; 343 std::unique_ptr<leveldb::DB> db;
339 std::unique_ptr<const leveldb::FilterPolicy> filter_policy; 344 std::unique_ptr<const leveldb::FilterPolicy> filter_policy;
340 const leveldb::Status s = OpenDB(comparator_adapter.get(), 345 const leveldb::Status s = OpenDB(comparator_adapter.get(),
341 in_memory_env.get(), 346 in_memory_env.get(),
342 base::FilePath(), 347 base::FilePath(),
343 &db, 348 &db,
344 &filter_policy); 349 &filter_policy);
345 350
346 if (!s.ok()) { 351 if (!s.ok()) {
347 LOG(ERROR) << "Failed to open in-memory LevelDB database: " << s.ToString(); 352 LOG(ERROR) << "Failed to open in-memory LevelDB database: " << s.ToString();
348 return std::unique_ptr<LevelDBDatabase>(); 353 return std::unique_ptr<LevelDBDatabase>();
349 } 354 }
350 355
356 // Since the database is in-memory, cursor pooling is pointless.
351 std::unique_ptr<LevelDBDatabase> result = 357 std::unique_ptr<LevelDBDatabase> result =
352 base::WrapUnique(new LevelDBDatabase()); 358 base::WrapUnique(new LevelDBDatabase(NO_CURSOR_EVICTION));
353 result->env_ = std::move(in_memory_env); 359 result->env_ = std::move(in_memory_env);
354 result->db_ = std::move(db); 360 result->db_ = std::move(db);
355 result->comparator_adapter_ = std::move(comparator_adapter); 361 result->comparator_adapter_ = std::move(comparator_adapter);
356 result->comparator_ = comparator; 362 result->comparator_ = comparator;
357 result->filter_policy_ = std::move(filter_policy); 363 result->filter_policy_ = std::move(filter_policy);
358 result->file_name_for_tracing = "in-memory-database"; 364 result->file_name_for_tracing = "in-memory-database";
359 365
360 return result; 366 return result;
361 } 367 }
362 368
(...skipping 63 matching lines...) Expand 10 before | Expand all | Expand 10 after
426 return s; 432 return s;
427 } 433 }
428 434
429 std::unique_ptr<LevelDBIterator> LevelDBDatabase::CreateIterator( 435 std::unique_ptr<LevelDBIterator> LevelDBDatabase::CreateIterator(
430 const LevelDBSnapshot* snapshot) { 436 const LevelDBSnapshot* snapshot) {
431 leveldb::ReadOptions read_options; 437 leveldb::ReadOptions read_options;
432 read_options.verify_checksums = true; // TODO(jsbell): Disable this if the 438 read_options.verify_checksums = true; // TODO(jsbell): Disable this if the
433 // performance impact is too great. 439 // performance impact is too great.
434 read_options.snapshot = snapshot ? snapshot->snapshot_ : 0; 440 read_options.snapshot = snapshot ? snapshot->snapshot_ : 0;
435 441
442 num_iterators_++;
443 max_iterators_ = std::max(max_iterators_, num_iterators_);
436 std::unique_ptr<leveldb::Iterator> i(db_->NewIterator(read_options)); 444 std::unique_ptr<leveldb::Iterator> i(db_->NewIterator(read_options));
437 return std::unique_ptr<LevelDBIterator>( 445 return std::unique_ptr<LevelDBIterator>(
438 IndexedDBClassFactory::Get()->CreateIteratorImpl(std::move(i))); 446 IndexedDBClassFactory::Get()->CreateIteratorImpl(std::move(i), this,
447 read_options.snapshot));
pwnall 2017/03/24 09:16:02 Why doesn't the newly created iterator get added t
dmurph 2017/03/24 23:33:39 We don't actually allocated memory in the iterator
pwnall 2017/03/27 17:08:03 I would at the very least document the assumption.
dmurph 2017/03/27 21:32:04 Done.
439 } 448 }
440 449
441 const LevelDBComparator* LevelDBDatabase::Comparator() const { 450 const LevelDBComparator* LevelDBDatabase::Comparator() const {
442 return comparator_; 451 return comparator_;
443 } 452 }
444 453
445 void LevelDBDatabase::Compact(const base::StringPiece& start, 454 void LevelDBDatabase::Compact(const base::StringPiece& start,
446 const base::StringPiece& stop) { 455 const base::StringPiece& stop) {
447 IDB_TRACE("LevelDBDatabase::Compact"); 456 IDB_TRACE("LevelDBDatabase::Compact");
448 const leveldb::Slice start_slice = MakeSlice(start); 457 const leveldb::Slice start_slice = MakeSlice(start);
(...skipping 23 matching lines...) Expand all
472 base::trace_event::MemoryAllocatorDump::kUnitsBytes, size); 481 base::trace_event::MemoryAllocatorDump::kUnitsBytes, size);
473 dump->AddString("file_name", "", file_name_for_tracing); 482 dump->AddString("file_name", "", file_name_for_tracing);
474 483
475 // Memory is allocated from system allocator (malloc). 484 // Memory is allocated from system allocator (malloc).
476 pmd->AddSuballocation(dump->guid(), 485 pmd->AddSuballocation(dump->guid(),
477 base::trace_event::MemoryDumpManager::GetInstance() 486 base::trace_event::MemoryDumpManager::GetInstance()
478 ->system_allocator_pool_name()); 487 ->system_allocator_pool_name());
479 return true; 488 return true;
480 } 489 }
481 490
491 std::unique_ptr<leveldb::Iterator> LevelDBDatabase::CreateLevelDBIterator(
492 const leveldb::Snapshot* snapshot) {
493 leveldb::ReadOptions read_options;
494 read_options.verify_checksums = true;
495 read_options.snapshot = snapshot;
496 return std::unique_ptr<leveldb::Iterator>(db_->NewIterator(read_options));
497 }
498
499 void LevelDBDatabase::NotifyIteratorUsed(LevelDBIterator* iter) {
500 // This line updates the LRU if the item exists.
501 if (!eviction_enabled_ || iterator_lru_.Get(iter) != iterator_lru_.end())
502 return;
503 if (iterator_lru_.size() == iterator_lru_.max_size()) {
504 auto to_evict_iter = iterator_lru_.rbegin();
505 LevelDBIterator* to_evict = to_evict_iter->first;
506 to_evict->PurgeMemory();
507 iterator_lru_.Erase(to_evict_iter);
508 }
509 iterator_lru_.Put(iter, iter);
510 }
511
512 void LevelDBDatabase::NotifyIteratorDestroyed(LevelDBIterator* iter) {
513 DCHECK_GT(num_iterators_, 0u);
514 --num_iterators_;
515 if (!eviction_enabled_)
516 return;
517 auto it = iterator_lru_.Peek(iter);
518 if (it == iterator_lru_.end())
519 return;
520 iterator_lru_.Erase(it);
521 }
482 } // namespace content 522 } // namespace content
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698