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

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: 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_) {
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 186 matching lines...) Expand 10 before | Expand all | Expand 10 after
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_;
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_ == db_iterator_.get() && is_evicted_) {
366 return key_after_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 {
361 DCHECK(IsValid()); 372 DCHECK(IsValid());
362 if (data_changed_) 373 if (data_changed_)
363 RefreshDataIterator(); 374 RefreshDataIterator();
375 if (current_ == db_iterator_.get()) {
376 const_cast<LevelDBTransaction::TransactionIterator*>(this)
377 ->LoadDBIteratorIfEvicted();
378 }
364 return current_->Value(); 379 return current_->Value();
365 } 380 }
366 381
382 void LevelDBTransaction::TransactionIterator::EvictWorkingMemory() {
383 DCHECK(!is_evicted_);
384 is_evicted_ = true;
385 key_after_eviction_ = db_iterator_->Key().as_string();
386 db_iterator_.reset();
387 }
388
367 void LevelDBTransaction::TransactionIterator::DataChanged() { 389 void LevelDBTransaction::TransactionIterator::DataChanged() {
368 data_changed_ = true; 390 data_changed_ = true;
369 } 391 }
370 392
371 void LevelDBTransaction::TransactionIterator::Delete() { 393 void LevelDBTransaction::TransactionIterator::Delete() {
372 DCHECK(IsValid()); 394 DCHECK(IsValid());
373 if (current_ == data_iterator_.get()) { 395 if (current_ == data_iterator_.get()) {
374 data_iterator_->Delete(); 396 data_iterator_->Delete();
375 } else { 397 } else {
376 std::unique_ptr<Record> record = base::MakeUnique<Record>(); 398 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. 426 // If going backward, seek to a key less than the db iterator.
405 DCHECK_EQ(REVERSE, direction_); 427 DCHECK_EQ(REVERSE, direction_);
406 data_iterator_->Seek(db_iterator_->Key()); 428 data_iterator_->Seek(db_iterator_->Key());
407 if (data_iterator_->IsValid()) 429 if (data_iterator_->IsValid())
408 data_iterator_->Prev(); 430 data_iterator_->Prev();
409 } 431 }
410 } 432 }
411 } 433 }
412 434
413 bool LevelDBTransaction::TransactionIterator::DataIteratorIsLower() const { 435 bool LevelDBTransaction::TransactionIterator::DataIteratorIsLower() const {
436 DCHECK(!is_evicted_);
414 return comparator_->Compare(data_iterator_->Key(), db_iterator_->Key()) < 0; 437 return comparator_->Compare(data_iterator_->Key(), db_iterator_->Key()) < 0;
415 } 438 }
416 439
417 bool LevelDBTransaction::TransactionIterator::DataIteratorIsHigher() const { 440 bool LevelDBTransaction::TransactionIterator::DataIteratorIsHigher() const {
441 DCHECK(!is_evicted_);
418 return comparator_->Compare(data_iterator_->Key(), db_iterator_->Key()) > 0; 442 return comparator_->Compare(data_iterator_->Key(), db_iterator_->Key()) > 0;
419 } 443 }
420 444
445 void LevelDBTransaction::TransactionIterator::LoadDBIteratorIfEvicted() {
446 transaction_->db_->NotifyIteratorUsed(this);
447 if (!is_evicted_)
448 return;
449
450 db_iterator_ = transaction_->db_->CreateIterator(&transaction_->snapshot_);
451 db_iterator_->Seek(key_after_eviction_);
452 key_after_eviction_.clear();
453 is_evicted_ = false;
454 }
455
421 void LevelDBTransaction::TransactionIterator::HandleConflictsAndDeletes() { 456 void LevelDBTransaction::TransactionIterator::HandleConflictsAndDeletes() {
457 LoadDBIteratorIfEvicted();
422 bool loop = true; 458 bool loop = true;
423 459
424 while (loop) { 460 while (loop) {
425 loop = false; 461 loop = false;
426 462
427 if (data_iterator_->IsValid() && db_iterator_->IsValid() && 463 if (data_iterator_->IsValid() && db_iterator_->IsValid() &&
428 !comparator_->Compare(data_iterator_->Key(), db_iterator_->Key())) { 464 !comparator_->Compare(data_iterator_->Key(), db_iterator_->Key())) {
429 // For equal keys, the data iterator takes precedence, so move the 465 // For equal keys, the data iterator takes precedence, so move the
430 // database iterator another step. 466 // database iterator another step.
431 if (direction_ == FORWARD) 467 if (direction_ == FORWARD)
(...skipping 13 matching lines...) Expand all
445 (!db_iterator_->IsValid() || DataIteratorIsHigher())) { 481 (!db_iterator_->IsValid() || DataIteratorIsHigher())) {
446 data_iterator_->Prev(); 482 data_iterator_->Prev();
447 loop = true; 483 loop = true;
448 } 484 }
449 } 485 }
450 } 486 }
451 } 487 }
452 488
453 void 489 void
454 LevelDBTransaction::TransactionIterator::SetCurrentIteratorToSmallestKey() { 490 LevelDBTransaction::TransactionIterator::SetCurrentIteratorToSmallestKey() {
491 DCHECK(!is_evicted_);
455 LevelDBIterator* smallest = nullptr; 492 LevelDBIterator* smallest = nullptr;
456 493
457 if (data_iterator_->IsValid()) 494 if (data_iterator_->IsValid())
458 smallest = data_iterator_.get(); 495 smallest = data_iterator_.get();
459 496
460 if (db_iterator_->IsValid()) { 497 if (db_iterator_->IsValid()) {
461 if (!smallest || 498 if (!smallest ||
462 comparator_->Compare(db_iterator_->Key(), smallest->Key()) < 0) 499 comparator_->Compare(db_iterator_->Key(), smallest->Key()) < 0)
463 smallest = db_iterator_.get(); 500 smallest = db_iterator_.get();
464 } 501 }
(...skipping 17 matching lines...) Expand all
482 } 519 }
483 520
484 void LevelDBTransaction::RegisterIterator(TransactionIterator* iterator) { 521 void LevelDBTransaction::RegisterIterator(TransactionIterator* iterator) {
485 DCHECK(iterators_.find(iterator) == iterators_.end()); 522 DCHECK(iterators_.find(iterator) == iterators_.end());
486 iterators_.insert(iterator); 523 iterators_.insert(iterator);
487 } 524 }
488 525
489 void LevelDBTransaction::UnregisterIterator(TransactionIterator* iterator) { 526 void LevelDBTransaction::UnregisterIterator(TransactionIterator* iterator) {
490 DCHECK(iterators_.find(iterator) != iterators_.end()); 527 DCHECK(iterators_.find(iterator) != iterators_.end());
491 iterators_.erase(iterator); 528 iterators_.erase(iterator);
529 db_->NotifyIteratorDestroyed(iterator);
492 } 530 }
493 531
494 void LevelDBTransaction::NotifyIterators() { 532 void LevelDBTransaction::NotifyIterators() {
495 for (auto* transaction_iterator : iterators_) 533 for (auto* transaction_iterator : iterators_)
496 transaction_iterator->DataChanged(); 534 transaction_iterator->DataChanged();
497 } 535 }
498 536
499 std::unique_ptr<LevelDBDirectTransaction> LevelDBDirectTransaction::Create( 537 std::unique_ptr<LevelDBDirectTransaction> LevelDBDirectTransaction::Create(
500 LevelDBDatabase* db) { 538 LevelDBDatabase* db) {
501 return base::WrapUnique(new LevelDBDirectTransaction(db)); 539 return base::WrapUnique(new LevelDBDirectTransaction(db));
(...skipping 34 matching lines...) Expand 10 before | Expand all | Expand 10 after
536 574
537 leveldb::Status s = db_->Write(*write_batch_); 575 leveldb::Status s = db_->Write(*write_batch_);
538 if (s.ok()) { 576 if (s.ok()) {
539 finished_ = true; 577 finished_ = true;
540 write_batch_->Clear(); 578 write_batch_->Clear();
541 } 579 }
542 return s; 580 return s;
543 } 581 }
544 582
545 } // namespace content 583 } // namespace content
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698