OLD | NEW |
---|---|
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 Loading... | |
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 Loading... | |
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 Loading... | |
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 Loading... | |
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 Loading... | |
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 Loading... | |
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 Loading... | |
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 Loading... | |
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 |
OLD | NEW |