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

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

Issue 2760163002: [IndexedDB] Pool and evict leveldb iterators, to save memory (Closed)
Patch Set: compile fixed 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_transaction.h" 5 #include "content/browser/indexed_db/leveldb/leveldb_transaction.h"
6 6
7 #include "base/logging.h" 7 #include "base/logging.h"
8 #include "base/memory/ptr_util.h" 8 #include "base/memory/ptr_util.h"
9 #include "base/metrics/histogram_macros.h" 9 #include "base/metrics/histogram_macros.h"
10 #include "base/time/time.h" 10 #include "base/time/time.h"
(...skipping 23 matching lines...) Expand all
34 LevelDBTransaction::LevelDBTransaction(LevelDBDatabase* db) 34 LevelDBTransaction::LevelDBTransaction(LevelDBDatabase* db)
35 : db_(db), 35 : db_(db),
36 snapshot_(db), 36 snapshot_(db),
37 comparator_(db->Comparator()), 37 comparator_(db->Comparator()),
38 data_comparator_(comparator_), 38 data_comparator_(comparator_),
39 data_(data_comparator_) {} 39 data_(data_comparator_) {}
40 40
41 LevelDBTransaction::Record::Record() {} 41 LevelDBTransaction::Record::Record() {}
42 LevelDBTransaction::Record::~Record() {} 42 LevelDBTransaction::Record::~Record() {}
43 43
44 LevelDBTransaction::~LevelDBTransaction() {} 44 LevelDBTransaction::~LevelDBTransaction() {
45 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.
46 db_->NotifyIteratorDestroyed(iter);
47 }
48 }
45 49
46 void LevelDBTransaction::Set(const StringPiece& key, 50 void LevelDBTransaction::Set(const StringPiece& key,
47 std::string* value, 51 std::string* value,
48 bool deleted) { 52 bool deleted) {
49 DCHECK(!finished_); 53 DCHECK(!finished_);
50 DataType::iterator it = data_.find(key); 54 DataType::iterator it = data_.find(key);
51 55
52 if (it == data_.end()) { 56 if (it == data_.end()) {
53 std::unique_ptr<Record> record = base::MakeUnique<Record>(); 57 std::unique_ptr<Record> record = base::MakeUnique<Record>();
54 record->key.assign(key.begin(), key.end() - key.begin()); 58 record->key.assign(key.begin(), key.end() - key.begin());
(...skipping 182 matching lines...) Expand 10 before | Expand all | Expand 10 after
237 db_iterator_( 241 db_iterator_(
238 transaction_->db_->CreateIterator(&transaction_->snapshot_)) { 242 transaction_->db_->CreateIterator(&transaction_->snapshot_)) {
239 transaction_->RegisterIterator(this); 243 transaction_->RegisterIterator(this);
240 } 244 }
241 245
242 LevelDBTransaction::TransactionIterator::~TransactionIterator() { 246 LevelDBTransaction::TransactionIterator::~TransactionIterator() {
243 transaction_->UnregisterIterator(this); 247 transaction_->UnregisterIterator(this);
244 } 248 }
245 249
246 bool LevelDBTransaction::TransactionIterator::IsValid() const { 250 bool LevelDBTransaction::TransactionIterator::IsValid() const {
247 return !!current_; 251 return !!current_ || db_iterator_state_ == DBIteratorState::EVICTED_AND_VALID;
248 } 252 }
249 253
250 leveldb::Status LevelDBTransaction::TransactionIterator::SeekToLast() { 254 leveldb::Status LevelDBTransaction::TransactionIterator::SeekToLast() {
255 LoadDBIteratorIfEvicted();
251 leveldb::Status s = data_iterator_->SeekToLast(); 256 leveldb::Status s = data_iterator_->SeekToLast();
252 DCHECK(s.ok()); 257 DCHECK(s.ok());
253 s = db_iterator_->SeekToLast(); 258 s = db_iterator_->SeekToLast();
254 if (!s.ok()) 259 if (!s.ok())
255 return s; 260 return s;
256 direction_ = REVERSE; 261 direction_ = REVERSE;
257 262
258 HandleConflictsAndDeletes(); 263 HandleConflictsAndDeletes();
259 SetCurrentIteratorToLargestKey(); 264 SetCurrentIteratorToLargestKey();
260 return s; 265 return s;
261 } 266 }
262 267
263 leveldb::Status LevelDBTransaction::TransactionIterator::Seek( 268 leveldb::Status LevelDBTransaction::TransactionIterator::Seek(
264 const StringPiece& target) { 269 const StringPiece& target) {
270 LoadDBIteratorIfEvicted();
265 leveldb::Status s = data_iterator_->Seek(target); 271 leveldb::Status s = data_iterator_->Seek(target);
266 DCHECK(s.ok()); 272 DCHECK(s.ok());
267 s = db_iterator_->Seek(target); 273 s = db_iterator_->Seek(target);
268 if (!s.ok()) 274 if (!s.ok())
269 return s; 275 return s;
270 direction_ = FORWARD; 276 direction_ = FORWARD;
271 277
272 HandleConflictsAndDeletes(); 278 HandleConflictsAndDeletes();
273 SetCurrentIteratorToSmallestKey(); 279 SetCurrentIteratorToSmallestKey();
274 return s; 280 return s;
275 } 281 }
276 282
277 leveldb::Status LevelDBTransaction::TransactionIterator::Next() { 283 leveldb::Status LevelDBTransaction::TransactionIterator::Next() {
284 LoadDBIteratorIfEvicted();
278 DCHECK(IsValid()); 285 DCHECK(IsValid());
279 if (data_changed_) 286 if (data_changed_)
280 RefreshDataIterator(); 287 RefreshDataIterator();
281 288
282 leveldb::Status s; 289 leveldb::Status s;
283 if (direction_ != FORWARD) { 290 if (direction_ != FORWARD) {
284 // Ensure the non-current iterator is positioned after Key(). 291 // Ensure the non-current iterator is positioned after Key().
285 292
286 LevelDBIterator* non_current = (current_ == db_iterator_.get()) 293 LevelDBIterator* non_current = (current_ == db_iterator_.get())
287 ? data_iterator_.get() 294 ? data_iterator_.get()
(...skipping 16 matching lines...) Expand all
304 311
305 s = current_->Next(); 312 s = current_->Next();
306 if (!s.ok()) 313 if (!s.ok())
307 return s; 314 return s;
308 HandleConflictsAndDeletes(); 315 HandleConflictsAndDeletes();
309 SetCurrentIteratorToSmallestKey(); 316 SetCurrentIteratorToSmallestKey();
310 return leveldb::Status::OK(); 317 return leveldb::Status::OK();
311 } 318 }
312 319
313 leveldb::Status LevelDBTransaction::TransactionIterator::Prev() { 320 leveldb::Status LevelDBTransaction::TransactionIterator::Prev() {
321 LoadDBIteratorIfEvicted();
314 DCHECK(IsValid()); 322 DCHECK(IsValid());
315 leveldb::Status s; 323 leveldb::Status s;
316 if (data_changed_) 324 if (data_changed_)
317 RefreshDataIterator(); 325 RefreshDataIterator();
318 326
319 if (direction_ != REVERSE) { 327 if (direction_ != REVERSE) {
320 // Ensure the non-current iterator is positioned before Key(). 328 // Ensure the non-current iterator is positioned before Key().
321 329
322 LevelDBIterator* non_current = (current_ == db_iterator_.get()) 330 LevelDBIterator* non_current = (current_ == db_iterator_.get())
323 ? data_iterator_.get() 331 ? data_iterator_.get()
(...skipping 23 matching lines...) Expand all
347 return s; 355 return s;
348 HandleConflictsAndDeletes(); 356 HandleConflictsAndDeletes();
349 SetCurrentIteratorToLargestKey(); 357 SetCurrentIteratorToLargestKey();
350 return leveldb::Status::OK(); 358 return leveldb::Status::OK();
351 } 359 }
352 360
353 StringPiece LevelDBTransaction::TransactionIterator::Key() const { 361 StringPiece LevelDBTransaction::TransactionIterator::Key() const {
354 DCHECK(IsValid()); 362 DCHECK(IsValid());
355 if (data_changed_) 363 if (data_changed_)
356 RefreshDataIterator(); 364 RefreshDataIterator();
365 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.
366 return db_key_before_eviction_;
367 }
357 return current_->Key(); 368 return current_->Key();
358 } 369 }
359 370
360 StringPiece LevelDBTransaction::TransactionIterator::Value() const { 371 StringPiece LevelDBTransaction::TransactionIterator::Value() const {
372 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.
373 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.
374 ->LoadDBIteratorIfEvicted();
375 }
376 DCHECK(current_);
361 DCHECK(IsValid()); 377 DCHECK(IsValid());
362 if (data_changed_) 378 if (data_changed_)
363 RefreshDataIterator(); 379 RefreshDataIterator();
364 return current_->Value(); 380 return current_->Value();
365 } 381 }
366 382
383 void LevelDBTransaction::TransactionIterator::PurgeMemory() {
384 DCHECK_EQ(db_iterator_state_, DBIteratorState::ACTIVE);
385 if (db_iterator_->IsValid()) {
386 db_iterator_state_ = DBIteratorState::EVICTED_AND_VALID;
387 db_key_before_eviction_ = db_iterator_->Key().as_string();
388 } else {
389 db_iterator_state_ = DBIteratorState::EVICTED_AND_INVALID;
390 }
391 if (current_ == db_iterator_.get())
392 current_ = nullptr;
393 db_iterator_.reset();
394 }
395
396 bool LevelDBTransaction::TransactionIterator::IsMemoryPurged() const {
397 return db_iterator_state_ != DBIteratorState::ACTIVE;
398 };
399
367 void LevelDBTransaction::TransactionIterator::DataChanged() { 400 void LevelDBTransaction::TransactionIterator::DataChanged() {
368 data_changed_ = true; 401 data_changed_ = true;
369 } 402 }
370 403
371 void LevelDBTransaction::TransactionIterator::Delete() { 404 void LevelDBTransaction::TransactionIterator::Delete() {
372 DCHECK(IsValid()); 405 DCHECK(IsValid());
373 if (current_ == data_iterator_.get()) { 406 if (current_ == data_iterator_.get()) {
374 data_iterator_->Delete(); 407 data_iterator_->Delete();
375 } else { 408 } else {
376 std::unique_ptr<Record> record = base::MakeUnique<Record>(); 409 std::unique_ptr<Record> record = base::MakeUnique<Record>();
(...skipping 27 matching lines...) Expand all
404 // If going backward, seek to a key less than the db iterator. 437 // If going backward, seek to a key less than the db iterator.
405 DCHECK_EQ(REVERSE, direction_); 438 DCHECK_EQ(REVERSE, direction_);
406 data_iterator_->Seek(db_iterator_->Key()); 439 data_iterator_->Seek(db_iterator_->Key());
407 if (data_iterator_->IsValid()) 440 if (data_iterator_->IsValid())
408 data_iterator_->Prev(); 441 data_iterator_->Prev();
409 } 442 }
410 } 443 }
411 } 444 }
412 445
413 bool LevelDBTransaction::TransactionIterator::DataIteratorIsLower() const { 446 bool LevelDBTransaction::TransactionIterator::DataIteratorIsLower() const {
447 DCHECK_EQ(db_iterator_state_, DBIteratorState::ACTIVE);
414 return comparator_->Compare(data_iterator_->Key(), db_iterator_->Key()) < 0; 448 return comparator_->Compare(data_iterator_->Key(), db_iterator_->Key()) < 0;
415 } 449 }
416 450
417 bool LevelDBTransaction::TransactionIterator::DataIteratorIsHigher() const { 451 bool LevelDBTransaction::TransactionIterator::DataIteratorIsHigher() const {
452 DCHECK_EQ(db_iterator_state_, DBIteratorState::ACTIVE);
418 return comparator_->Compare(data_iterator_->Key(), db_iterator_->Key()) > 0; 453 return comparator_->Compare(data_iterator_->Key(), db_iterator_->Key()) > 0;
419 } 454 }
420 455
456 void LevelDBTransaction::TransactionIterator::LoadDBIteratorIfEvicted() {
457 transaction_->db_->NotifyIteratorUsed(this);
458
459 if (db_iterator_state_ == DBIteratorState::ACTIVE)
460 return;
461
462 db_iterator_ = transaction_->db_->CreateIterator(&transaction_->snapshot_);
463 if (db_iterator_state_ == DBIteratorState::EVICTED_AND_VALID) {
464 db_iterator_->Seek(db_key_before_eviction_);
465 db_key_before_eviction_.clear();
466 }
467 if (current_ == nullptr)
468 current_ = db_iterator_.get();
469 db_iterator_state_ = DBIteratorState::ACTIVE;
470 }
471
421 void LevelDBTransaction::TransactionIterator::HandleConflictsAndDeletes() { 472 void LevelDBTransaction::TransactionIterator::HandleConflictsAndDeletes() {
473 LoadDBIteratorIfEvicted();
422 bool loop = true; 474 bool loop = true;
423 475
424 while (loop) { 476 while (loop) {
425 loop = false; 477 loop = false;
426 478
427 if (data_iterator_->IsValid() && db_iterator_->IsValid() && 479 if (data_iterator_->IsValid() && db_iterator_->IsValid() &&
428 !comparator_->Compare(data_iterator_->Key(), db_iterator_->Key())) { 480 !comparator_->Compare(data_iterator_->Key(), db_iterator_->Key())) {
429 // For equal keys, the data iterator takes precedence, so move the 481 // For equal keys, the data iterator takes precedence, so move the
430 // database iterator another step. 482 // database iterator another step.
431 if (direction_ == FORWARD) 483 if (direction_ == FORWARD)
(...skipping 13 matching lines...) Expand all
445 (!db_iterator_->IsValid() || DataIteratorIsHigher())) { 497 (!db_iterator_->IsValid() || DataIteratorIsHigher())) {
446 data_iterator_->Prev(); 498 data_iterator_->Prev();
447 loop = true; 499 loop = true;
448 } 500 }
449 } 501 }
450 } 502 }
451 } 503 }
452 504
453 void 505 void
454 LevelDBTransaction::TransactionIterator::SetCurrentIteratorToSmallestKey() { 506 LevelDBTransaction::TransactionIterator::SetCurrentIteratorToSmallestKey() {
507 DCHECK_EQ(db_iterator_state_, DBIteratorState::ACTIVE);
455 LevelDBIterator* smallest = nullptr; 508 LevelDBIterator* smallest = nullptr;
456 509
457 if (data_iterator_->IsValid()) 510 if (data_iterator_->IsValid())
458 smallest = data_iterator_.get(); 511 smallest = data_iterator_.get();
459 512
460 if (db_iterator_->IsValid()) { 513 if (db_iterator_->IsValid()) {
461 if (!smallest || 514 if (!smallest ||
462 comparator_->Compare(db_iterator_->Key(), smallest->Key()) < 0) 515 comparator_->Compare(db_iterator_->Key(), smallest->Key()) < 0)
463 smallest = db_iterator_.get(); 516 smallest = db_iterator_.get();
464 } 517 }
(...skipping 12 matching lines...) Expand all
477 comparator_->Compare(db_iterator_->Key(), largest->Key()) > 0) 530 comparator_->Compare(db_iterator_->Key(), largest->Key()) > 0)
478 largest = db_iterator_.get(); 531 largest = db_iterator_.get();
479 } 532 }
480 533
481 current_ = largest; 534 current_ = largest;
482 } 535 }
483 536
484 void LevelDBTransaction::RegisterIterator(TransactionIterator* iterator) { 537 void LevelDBTransaction::RegisterIterator(TransactionIterator* iterator) {
485 DCHECK(iterators_.find(iterator) == iterators_.end()); 538 DCHECK(iterators_.find(iterator) == iterators_.end());
486 iterators_.insert(iterator); 539 iterators_.insert(iterator);
540 db_->NotifyIteratorCreated(iterator);
487 } 541 }
488 542
489 void LevelDBTransaction::UnregisterIterator(TransactionIterator* iterator) { 543 void LevelDBTransaction::UnregisterIterator(TransactionIterator* iterator) {
490 DCHECK(iterators_.find(iterator) != iterators_.end()); 544 DCHECK(iterators_.find(iterator) != iterators_.end());
491 iterators_.erase(iterator); 545 iterators_.erase(iterator);
546 db_->NotifyIteratorDestroyed(iterator);
492 } 547 }
493 548
494 void LevelDBTransaction::NotifyIterators() { 549 void LevelDBTransaction::NotifyIterators() {
495 for (auto* transaction_iterator : iterators_) 550 for (auto* transaction_iterator : iterators_)
496 transaction_iterator->DataChanged(); 551 transaction_iterator->DataChanged();
497 } 552 }
498 553
499 std::unique_ptr<LevelDBDirectTransaction> LevelDBDirectTransaction::Create( 554 std::unique_ptr<LevelDBDirectTransaction> LevelDBDirectTransaction::Create(
500 LevelDBDatabase* db) { 555 LevelDBDatabase* db) {
501 return base::WrapUnique(new LevelDBDirectTransaction(db)); 556 return base::WrapUnique(new LevelDBDirectTransaction(db));
(...skipping 34 matching lines...) Expand 10 before | Expand all | Expand 10 after
536 591
537 leveldb::Status s = db_->Write(*write_batch_); 592 leveldb::Status s = db_->Write(*write_batch_);
538 if (s.ok()) { 593 if (s.ok()) {
539 finished_ = true; 594 finished_ = true;
540 write_batch_->Clear(); 595 write_batch_->Clear();
541 } 596 }
542 return s; 597 return s;
543 } 598 }
544 599
545 } // namespace content 600 } // namespace content
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698