Chromium Code Reviews| 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 |