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_) { |
| 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 Loading... |
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 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_ == 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 Loading... |
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 Loading... |
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 Loading... |
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 Loading... |
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 |
OLD | NEW |