| OLD | NEW |
| 1 // Copyright (c) 2006-2010 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2006-2010 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 "net/disk_cache/entry_impl.h" | 5 #include "net/disk_cache/entry_impl.h" |
| 6 | 6 |
| 7 #include "base/message_loop.h" | 7 #include "base/message_loop.h" |
| 8 #include "base/metrics/histogram.h" | 8 #include "base/metrics/histogram.h" |
| 9 #include "base/string_util.h" | 9 #include "base/string_util.h" |
| 10 #include "base/values.h" | 10 #include "base/values.h" |
| (...skipping 357 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 368 EntryImpl::EntryImpl(BackendImpl* backend, Addr address, bool read_only) | 368 EntryImpl::EntryImpl(BackendImpl* backend, Addr address, bool read_only) |
| 369 : entry_(NULL, Addr(0)), node_(NULL, Addr(0)), read_only_(read_only) { | 369 : entry_(NULL, Addr(0)), node_(NULL, Addr(0)), read_only_(read_only) { |
| 370 entry_.LazyInit(backend->File(address), address); | 370 entry_.LazyInit(backend->File(address), address); |
| 371 doomed_ = false; | 371 doomed_ = false; |
| 372 backend_ = backend; | 372 backend_ = backend; |
| 373 for (int i = 0; i < kNumStreams; i++) { | 373 for (int i = 0; i < kNumStreams; i++) { |
| 374 unreported_size_[i] = 0; | 374 unreported_size_[i] = 0; |
| 375 } | 375 } |
| 376 } | 376 } |
| 377 | 377 |
| 378 // When an entry is deleted from the cache, we clean up all the data associated | |
| 379 // with it for two reasons: to simplify the reuse of the block (we know that any | |
| 380 // unused block is filled with zeros), and to simplify the handling of write / | |
| 381 // read partial information from an entry (don't have to worry about returning | |
| 382 // data related to a previous cache entry because the range was not fully | |
| 383 // written before). | |
| 384 EntryImpl::~EntryImpl() { | |
| 385 Log("~EntryImpl in"); | |
| 386 | |
| 387 // Save the sparse info to disk. This will generate IO for this entry and | |
| 388 // maybe for a child entry, so it is important to do it before deleting this | |
| 389 // entry. | |
| 390 sparse_.reset(); | |
| 391 | |
| 392 // Remove this entry from the list of open entries. | |
| 393 backend_->OnEntryDestroyBegin(entry_.address()); | |
| 394 | |
| 395 if (doomed_) { | |
| 396 DeleteEntryData(true); | |
| 397 } else { | |
| 398 net_log_.AddEvent(net::NetLog::TYPE_DISK_CACHE_CLOSE, NULL); | |
| 399 bool ret = true; | |
| 400 for (int index = 0; index < kNumStreams; index++) { | |
| 401 if (user_buffers_[index].get()) { | |
| 402 if (!(ret = Flush(index, 0))) | |
| 403 LOG(ERROR) << "Failed to save user data"; | |
| 404 } | |
| 405 if (unreported_size_[index]) { | |
| 406 backend_->ModifyStorageSize( | |
| 407 entry_.Data()->data_size[index] - unreported_size_[index], | |
| 408 entry_.Data()->data_size[index]); | |
| 409 } | |
| 410 } | |
| 411 | |
| 412 if (!ret) { | |
| 413 // There was a failure writing the actual data. Mark the entry as dirty. | |
| 414 int current_id = backend_->GetCurrentEntryId(); | |
| 415 node_.Data()->dirty = current_id == 1 ? -1 : current_id - 1; | |
| 416 node_.Store(); | |
| 417 } else if (node_.HasData() && node_.Data()->dirty) { | |
| 418 node_.Data()->dirty = 0; | |
| 419 node_.Store(); | |
| 420 } | |
| 421 } | |
| 422 | |
| 423 Trace("~EntryImpl out 0x%p", reinterpret_cast<void*>(this)); | |
| 424 net_log_.EndEvent(net::NetLog::TYPE_DISK_CACHE_ENTRY, NULL); | |
| 425 backend_->OnEntryDestroyEnd(); | |
| 426 } | |
| 427 | |
| 428 void EntryImpl::Doom() { | |
| 429 backend_->background_queue()->DoomEntryImpl(this); | |
| 430 } | |
| 431 | |
| 432 void EntryImpl::Close() { | |
| 433 backend_->background_queue()->CloseEntryImpl(this); | |
| 434 } | |
| 435 | |
| 436 std::string EntryImpl::GetKey() const { | |
| 437 CacheEntryBlock* entry = const_cast<CacheEntryBlock*>(&entry_); | |
| 438 if (entry->Data()->key_len <= kMaxInternalKeyLength) | |
| 439 return std::string(entry->Data()->key); | |
| 440 | |
| 441 // We keep a copy of the key so that we can always return it, even if the | |
| 442 // backend is disabled. | |
| 443 if (!key_.empty()) | |
| 444 return key_; | |
| 445 | |
| 446 Addr address(entry->Data()->long_key); | |
| 447 DCHECK(address.is_initialized()); | |
| 448 size_t offset = 0; | |
| 449 if (address.is_block_file()) | |
| 450 offset = address.start_block() * address.BlockSize() + kBlockHeaderSize; | |
| 451 | |
| 452 COMPILE_ASSERT(kNumStreams == kKeyFileIndex, invalid_key_index); | |
| 453 File* key_file = const_cast<EntryImpl*>(this)->GetBackingFile(address, | |
| 454 kKeyFileIndex); | |
| 455 | |
| 456 if (!key_file || | |
| 457 !key_file->Read(WriteInto(&key_, entry->Data()->key_len + 1), | |
| 458 entry->Data()->key_len + 1, offset)) | |
| 459 key_.clear(); | |
| 460 return key_; | |
| 461 } | |
| 462 | |
| 463 Time EntryImpl::GetLastUsed() const { | |
| 464 CacheRankingsBlock* node = const_cast<CacheRankingsBlock*>(&node_); | |
| 465 return Time::FromInternalValue(node->Data()->last_used); | |
| 466 } | |
| 467 | |
| 468 Time EntryImpl::GetLastModified() const { | |
| 469 CacheRankingsBlock* node = const_cast<CacheRankingsBlock*>(&node_); | |
| 470 return Time::FromInternalValue(node->Data()->last_modified); | |
| 471 } | |
| 472 | |
| 473 int32 EntryImpl::GetDataSize(int index) const { | |
| 474 if (index < 0 || index >= kNumStreams) | |
| 475 return 0; | |
| 476 | |
| 477 CacheEntryBlock* entry = const_cast<CacheEntryBlock*>(&entry_); | |
| 478 return entry->Data()->data_size[index]; | |
| 479 } | |
| 480 | |
| 481 int EntryImpl::ReadData(int index, int offset, net::IOBuffer* buf, int buf_len, | |
| 482 net::CompletionCallback* callback) { | |
| 483 if (!callback) | |
| 484 return ReadDataImpl(index, offset, buf, buf_len, callback); | |
| 485 | |
| 486 DCHECK(node_.Data()->dirty || read_only_); | |
| 487 if (index < 0 || index >= kNumStreams) | |
| 488 return net::ERR_INVALID_ARGUMENT; | |
| 489 | |
| 490 int entry_size = entry_.Data()->data_size[index]; | |
| 491 if (offset >= entry_size || offset < 0 || !buf_len) | |
| 492 return 0; | |
| 493 | |
| 494 if (buf_len < 0) | |
| 495 return net::ERR_INVALID_ARGUMENT; | |
| 496 | |
| 497 backend_->background_queue()->ReadData(this, index, offset, buf, buf_len, | |
| 498 callback); | |
| 499 return net::ERR_IO_PENDING; | |
| 500 } | |
| 501 | |
| 502 int EntryImpl::WriteData(int index, int offset, net::IOBuffer* buf, int buf_len, | |
| 503 CompletionCallback* callback, bool truncate) { | |
| 504 if (!callback) | |
| 505 return WriteDataImpl(index, offset, buf, buf_len, callback, truncate); | |
| 506 | |
| 507 DCHECK(node_.Data()->dirty || read_only_); | |
| 508 if (index < 0 || index >= kNumStreams) | |
| 509 return net::ERR_INVALID_ARGUMENT; | |
| 510 | |
| 511 if (offset < 0 || buf_len < 0) | |
| 512 return net::ERR_INVALID_ARGUMENT; | |
| 513 | |
| 514 backend_->background_queue()->WriteData(this, index, offset, buf, buf_len, | |
| 515 truncate, callback); | |
| 516 return net::ERR_IO_PENDING; | |
| 517 } | |
| 518 | |
| 519 int EntryImpl::ReadSparseData(int64 offset, net::IOBuffer* buf, int buf_len, | |
| 520 net::CompletionCallback* callback) { | |
| 521 if (!callback) | |
| 522 return ReadSparseDataImpl(offset, buf, buf_len, callback); | |
| 523 | |
| 524 backend_->background_queue()->ReadSparseData(this, offset, buf, buf_len, | |
| 525 callback); | |
| 526 return net::ERR_IO_PENDING; | |
| 527 } | |
| 528 | |
| 529 int EntryImpl::WriteSparseData(int64 offset, net::IOBuffer* buf, int buf_len, | |
| 530 net::CompletionCallback* callback) { | |
| 531 if (!callback) | |
| 532 return WriteSparseDataImpl(offset, buf, buf_len, callback); | |
| 533 | |
| 534 backend_->background_queue()->WriteSparseData(this, offset, buf, buf_len, | |
| 535 callback); | |
| 536 return net::ERR_IO_PENDING; | |
| 537 } | |
| 538 | |
| 539 int EntryImpl::GetAvailableRange(int64 offset, int len, int64* start, | |
| 540 CompletionCallback* callback) { | |
| 541 backend_->background_queue()->GetAvailableRange(this, offset, len, start, | |
| 542 callback); | |
| 543 return net::ERR_IO_PENDING; | |
| 544 } | |
| 545 | |
| 546 bool EntryImpl::CouldBeSparse() const { | |
| 547 if (sparse_.get()) | |
| 548 return true; | |
| 549 | |
| 550 scoped_ptr<SparseControl> sparse; | |
| 551 sparse.reset(new SparseControl(const_cast<EntryImpl*>(this))); | |
| 552 return sparse->CouldBeSparse(); | |
| 553 } | |
| 554 | |
| 555 void EntryImpl::CancelSparseIO() { | |
| 556 backend_->background_queue()->CancelSparseIO(this); | |
| 557 } | |
| 558 | |
| 559 int EntryImpl::ReadyForSparseIO(net::CompletionCallback* callback) { | |
| 560 if (!sparse_.get()) | |
| 561 return net::OK; | |
| 562 | |
| 563 backend_->background_queue()->ReadyForSparseIO(this, callback); | |
| 564 return net::ERR_IO_PENDING; | |
| 565 } | |
| 566 | |
| 567 // ------------------------------------------------------------------------ | |
| 568 | |
| 569 void EntryImpl::DoomImpl() { | 378 void EntryImpl::DoomImpl() { |
| 570 if (doomed_) | 379 if (doomed_) |
| 571 return; | 380 return; |
| 572 | 381 |
| 573 SetPointerForInvalidEntry(backend_->GetCurrentEntryId()); | 382 SetPointerForInvalidEntry(backend_->GetCurrentEntryId()); |
| 574 backend_->InternalDoomEntry(this); | 383 backend_->InternalDoomEntry(this); |
| 575 } | 384 } |
| 576 | 385 |
| 577 int EntryImpl::ReadDataImpl(int index, int offset, net::IOBuffer* buf, | 386 int EntryImpl::ReadDataImpl(int index, int offset, net::IOBuffer* buf, |
| 578 int buf_len, CompletionCallback* callback) { | 387 int buf_len, CompletionCallback* callback) { |
| (...skipping 28 matching lines...) Expand all Loading... |
| 607 truncate); | 416 truncate); |
| 608 | 417 |
| 609 if (result != net::ERR_IO_PENDING && net_log_.IsLoggingAllEvents()) { | 418 if (result != net::ERR_IO_PENDING && net_log_.IsLoggingAllEvents()) { |
| 610 net_log_.EndEvent( | 419 net_log_.EndEvent( |
| 611 net::NetLog::TYPE_DISK_CACHE_WRITE_DATA, | 420 net::NetLog::TYPE_DISK_CACHE_WRITE_DATA, |
| 612 make_scoped_refptr(new FileIOCompleteParameters(result))); | 421 make_scoped_refptr(new FileIOCompleteParameters(result))); |
| 613 } | 422 } |
| 614 return result; | 423 return result; |
| 615 } | 424 } |
| 616 | 425 |
| 617 int EntryImpl::InternalReadData(int index, int offset, net::IOBuffer* buf, | |
| 618 int buf_len, CompletionCallback* callback) { | |
| 619 DCHECK(node_.Data()->dirty || read_only_); | |
| 620 DVLOG(2) << "Read from " << index << " at " << offset << " : " << buf_len; | |
| 621 if (index < 0 || index >= kNumStreams) | |
| 622 return net::ERR_INVALID_ARGUMENT; | |
| 623 | |
| 624 int entry_size = entry_.Data()->data_size[index]; | |
| 625 if (offset >= entry_size || offset < 0 || !buf_len) | |
| 626 return 0; | |
| 627 | |
| 628 if (buf_len < 0) | |
| 629 return net::ERR_INVALID_ARGUMENT; | |
| 630 | |
| 631 TimeTicks start = TimeTicks::Now(); | |
| 632 | |
| 633 if (offset + buf_len > entry_size) | |
| 634 buf_len = entry_size - offset; | |
| 635 | |
| 636 UpdateRank(false); | |
| 637 | |
| 638 backend_->OnEvent(Stats::READ_DATA); | |
| 639 backend_->OnRead(buf_len); | |
| 640 | |
| 641 Addr address(entry_.Data()->data_addr[index]); | |
| 642 int eof = address.is_initialized() ? entry_size : 0; | |
| 643 if (user_buffers_[index].get() && | |
| 644 user_buffers_[index]->PreRead(eof, offset, &buf_len)) { | |
| 645 // Complete the operation locally. | |
| 646 buf_len = user_buffers_[index]->Read(offset, buf, buf_len); | |
| 647 ReportIOTime(kRead, start); | |
| 648 return buf_len; | |
| 649 } | |
| 650 | |
| 651 address.set_value(entry_.Data()->data_addr[index]); | |
| 652 DCHECK(address.is_initialized()); | |
| 653 if (!address.is_initialized()) | |
| 654 return net::ERR_FAILED; | |
| 655 | |
| 656 File* file = GetBackingFile(address, index); | |
| 657 if (!file) | |
| 658 return net::ERR_FAILED; | |
| 659 | |
| 660 size_t file_offset = offset; | |
| 661 if (address.is_block_file()) { | |
| 662 DCHECK_LE(offset + buf_len, kMaxBlockSize); | |
| 663 file_offset += address.start_block() * address.BlockSize() + | |
| 664 kBlockHeaderSize; | |
| 665 } | |
| 666 | |
| 667 SyncCallback* io_callback = NULL; | |
| 668 if (callback) { | |
| 669 io_callback = new SyncCallback(this, buf, callback, | |
| 670 net::NetLog::TYPE_DISK_CACHE_READ_DATA); | |
| 671 } | |
| 672 | |
| 673 bool completed; | |
| 674 if (!file->Read(buf->data(), buf_len, file_offset, io_callback, &completed)) { | |
| 675 if (io_callback) | |
| 676 io_callback->Discard(); | |
| 677 return net::ERR_FAILED; | |
| 678 } | |
| 679 | |
| 680 if (io_callback && completed) | |
| 681 io_callback->Discard(); | |
| 682 | |
| 683 ReportIOTime(kRead, start); | |
| 684 return (completed || !callback) ? buf_len : net::ERR_IO_PENDING; | |
| 685 } | |
| 686 | |
| 687 int EntryImpl::InternalWriteData(int index, int offset, net::IOBuffer* buf, | |
| 688 int buf_len, CompletionCallback* callback, | |
| 689 bool truncate) { | |
| 690 DCHECK(node_.Data()->dirty || read_only_); | |
| 691 DVLOG(2) << "Write to " << index << " at " << offset << " : " << buf_len; | |
| 692 if (index < 0 || index >= kNumStreams) | |
| 693 return net::ERR_INVALID_ARGUMENT; | |
| 694 | |
| 695 if (offset < 0 || buf_len < 0) | |
| 696 return net::ERR_INVALID_ARGUMENT; | |
| 697 | |
| 698 int max_file_size = backend_->MaxFileSize(); | |
| 699 | |
| 700 // offset or buf_len could be negative numbers. | |
| 701 if (offset > max_file_size || buf_len > max_file_size || | |
| 702 offset + buf_len > max_file_size) { | |
| 703 int size = offset + buf_len; | |
| 704 if (size <= max_file_size) | |
| 705 size = kint32max; | |
| 706 backend_->TooMuchStorageRequested(size); | |
| 707 return net::ERR_FAILED; | |
| 708 } | |
| 709 | |
| 710 TimeTicks start = TimeTicks::Now(); | |
| 711 | |
| 712 // Read the size at this point (it may change inside prepare). | |
| 713 int entry_size = entry_.Data()->data_size[index]; | |
| 714 bool extending = entry_size < offset + buf_len; | |
| 715 truncate = truncate && entry_size > offset + buf_len; | |
| 716 Trace("To PrepareTarget 0x%x", entry_.address().value()); | |
| 717 if (!PrepareTarget(index, offset, buf_len, truncate)) | |
| 718 return net::ERR_FAILED; | |
| 719 | |
| 720 Trace("From PrepareTarget 0x%x", entry_.address().value()); | |
| 721 if (extending || truncate) | |
| 722 UpdateSize(index, entry_size, offset + buf_len); | |
| 723 | |
| 724 UpdateRank(true); | |
| 725 | |
| 726 backend_->OnEvent(Stats::WRITE_DATA); | |
| 727 backend_->OnWrite(buf_len); | |
| 728 | |
| 729 if (user_buffers_[index].get()) { | |
| 730 // Complete the operation locally. | |
| 731 user_buffers_[index]->Write(offset, buf, buf_len); | |
| 732 ReportIOTime(kWrite, start); | |
| 733 return buf_len; | |
| 734 } | |
| 735 | |
| 736 Addr address(entry_.Data()->data_addr[index]); | |
| 737 if (offset + buf_len == 0) { | |
| 738 if (truncate) { | |
| 739 DCHECK(!address.is_initialized()); | |
| 740 } | |
| 741 return 0; | |
| 742 } | |
| 743 | |
| 744 File* file = GetBackingFile(address, index); | |
| 745 if (!file) | |
| 746 return net::ERR_FAILED; | |
| 747 | |
| 748 size_t file_offset = offset; | |
| 749 if (address.is_block_file()) { | |
| 750 DCHECK_LE(offset + buf_len, kMaxBlockSize); | |
| 751 file_offset += address.start_block() * address.BlockSize() + | |
| 752 kBlockHeaderSize; | |
| 753 } else if (truncate || (extending && !buf_len)) { | |
| 754 if (!file->SetLength(offset + buf_len)) | |
| 755 return net::ERR_FAILED; | |
| 756 } | |
| 757 | |
| 758 if (!buf_len) | |
| 759 return 0; | |
| 760 | |
| 761 SyncCallback* io_callback = NULL; | |
| 762 if (callback) { | |
| 763 io_callback = new SyncCallback(this, buf, callback, | |
| 764 net::NetLog::TYPE_DISK_CACHE_WRITE_DATA); | |
| 765 } | |
| 766 | |
| 767 bool completed; | |
| 768 if (!file->Write(buf->data(), buf_len, file_offset, io_callback, | |
| 769 &completed)) { | |
| 770 if (io_callback) | |
| 771 io_callback->Discard(); | |
| 772 return net::ERR_FAILED; | |
| 773 } | |
| 774 | |
| 775 if (io_callback && completed) | |
| 776 io_callback->Discard(); | |
| 777 | |
| 778 ReportIOTime(kWrite, start); | |
| 779 return (completed || !callback) ? buf_len : net::ERR_IO_PENDING; | |
| 780 } | |
| 781 | |
| 782 int EntryImpl::ReadSparseDataImpl(int64 offset, net::IOBuffer* buf, int buf_len, | 426 int EntryImpl::ReadSparseDataImpl(int64 offset, net::IOBuffer* buf, int buf_len, |
| 783 CompletionCallback* callback) { | 427 CompletionCallback* callback) { |
| 784 DCHECK(node_.Data()->dirty || read_only_); | 428 DCHECK(node_.Data()->dirty || read_only_); |
| 785 int result = InitSparseData(); | 429 int result = InitSparseData(); |
| 786 if (net::OK != result) | 430 if (net::OK != result) |
| 787 return result; | 431 return result; |
| 788 | 432 |
| 789 TimeTicks start = TimeTicks::Now(); | 433 TimeTicks start = TimeTicks::Now(); |
| 790 result = sparse_->StartIO(SparseControl::kReadOperation, offset, buf, buf_len, | 434 result = sparse_->StartIO(SparseControl::kReadOperation, offset, buf, buf_len, |
| 791 callback); | 435 callback); |
| (...skipping 28 matching lines...) Expand all Loading... |
| 820 return; | 464 return; |
| 821 | 465 |
| 822 sparse_->CancelIO(); | 466 sparse_->CancelIO(); |
| 823 } | 467 } |
| 824 | 468 |
| 825 int EntryImpl::ReadyForSparseIOImpl(CompletionCallback* callback) { | 469 int EntryImpl::ReadyForSparseIOImpl(CompletionCallback* callback) { |
| 826 DCHECK(sparse_.get()); | 470 DCHECK(sparse_.get()); |
| 827 return sparse_->ReadyToUse(callback); | 471 return sparse_->ReadyToUse(callback); |
| 828 } | 472 } |
| 829 | 473 |
| 830 // ------------------------------------------------------------------------ | |
| 831 | |
| 832 uint32 EntryImpl::GetHash() { | 474 uint32 EntryImpl::GetHash() { |
| 833 return entry_.Data()->hash; | 475 return entry_.Data()->hash; |
| 834 } | 476 } |
| 835 | 477 |
| 836 bool EntryImpl::CreateEntry(Addr node_address, const std::string& key, | 478 bool EntryImpl::CreateEntry(Addr node_address, const std::string& key, |
| 837 uint32 hash) { | 479 uint32 hash) { |
| 838 Trace("Create entry In"); | 480 Trace("Create entry In"); |
| 839 EntryStore* entry_store = entry_.Data(); | 481 EntryStore* entry_store = entry_.Data(); |
| 840 RankingsNode* node = node_.Data(); | 482 RankingsNode* node = node_.Data(); |
| 841 memset(entry_store, 0, sizeof(EntryStore) * entry_.address().num_blocks()); | 483 memset(entry_store, 0, sizeof(EntryStore) * entry_.address().num_blocks()); |
| (...skipping 212 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1054 net_log, net::NetLog::SOURCE_DISK_CACHE_ENTRY); | 696 net_log, net::NetLog::SOURCE_DISK_CACHE_ENTRY); |
| 1055 net_log_.BeginEvent( | 697 net_log_.BeginEvent( |
| 1056 net::NetLog::TYPE_DISK_CACHE_ENTRY, | 698 net::NetLog::TYPE_DISK_CACHE_ENTRY, |
| 1057 make_scoped_refptr(new EntryCreationParameters(GetKey(), created))); | 699 make_scoped_refptr(new EntryCreationParameters(GetKey(), created))); |
| 1058 } | 700 } |
| 1059 | 701 |
| 1060 const net::BoundNetLog& EntryImpl::net_log() const { | 702 const net::BoundNetLog& EntryImpl::net_log() const { |
| 1061 return net_log_; | 703 return net_log_; |
| 1062 } | 704 } |
| 1063 | 705 |
| 706 void EntryImpl::Doom() { |
| 707 backend_->background_queue()->DoomEntryImpl(this); |
| 708 } |
| 709 |
| 710 void EntryImpl::Close() { |
| 711 backend_->background_queue()->CloseEntryImpl(this); |
| 712 } |
| 713 |
| 714 std::string EntryImpl::GetKey() const { |
| 715 CacheEntryBlock* entry = const_cast<CacheEntryBlock*>(&entry_); |
| 716 if (entry->Data()->key_len <= kMaxInternalKeyLength) |
| 717 return std::string(entry->Data()->key); |
| 718 |
| 719 // We keep a copy of the key so that we can always return it, even if the |
| 720 // backend is disabled. |
| 721 if (!key_.empty()) |
| 722 return key_; |
| 723 |
| 724 Addr address(entry->Data()->long_key); |
| 725 DCHECK(address.is_initialized()); |
| 726 size_t offset = 0; |
| 727 if (address.is_block_file()) |
| 728 offset = address.start_block() * address.BlockSize() + kBlockHeaderSize; |
| 729 |
| 730 COMPILE_ASSERT(kNumStreams == kKeyFileIndex, invalid_key_index); |
| 731 File* key_file = const_cast<EntryImpl*>(this)->GetBackingFile(address, |
| 732 kKeyFileIndex); |
| 733 |
| 734 if (!key_file || |
| 735 !key_file->Read(WriteInto(&key_, entry->Data()->key_len + 1), |
| 736 entry->Data()->key_len + 1, offset)) |
| 737 key_.clear(); |
| 738 return key_; |
| 739 } |
| 740 |
| 741 Time EntryImpl::GetLastUsed() const { |
| 742 CacheRankingsBlock* node = const_cast<CacheRankingsBlock*>(&node_); |
| 743 return Time::FromInternalValue(node->Data()->last_used); |
| 744 } |
| 745 |
| 746 Time EntryImpl::GetLastModified() const { |
| 747 CacheRankingsBlock* node = const_cast<CacheRankingsBlock*>(&node_); |
| 748 return Time::FromInternalValue(node->Data()->last_modified); |
| 749 } |
| 750 |
| 751 int32 EntryImpl::GetDataSize(int index) const { |
| 752 if (index < 0 || index >= kNumStreams) |
| 753 return 0; |
| 754 |
| 755 CacheEntryBlock* entry = const_cast<CacheEntryBlock*>(&entry_); |
| 756 return entry->Data()->data_size[index]; |
| 757 } |
| 758 |
| 759 int EntryImpl::ReadData(int index, int offset, net::IOBuffer* buf, int buf_len, |
| 760 net::CompletionCallback* callback) { |
| 761 if (!callback) |
| 762 return ReadDataImpl(index, offset, buf, buf_len, callback); |
| 763 |
| 764 DCHECK(node_.Data()->dirty || read_only_); |
| 765 if (index < 0 || index >= kNumStreams) |
| 766 return net::ERR_INVALID_ARGUMENT; |
| 767 |
| 768 int entry_size = entry_.Data()->data_size[index]; |
| 769 if (offset >= entry_size || offset < 0 || !buf_len) |
| 770 return 0; |
| 771 |
| 772 if (buf_len < 0) |
| 773 return net::ERR_INVALID_ARGUMENT; |
| 774 |
| 775 backend_->background_queue()->ReadData(this, index, offset, buf, buf_len, |
| 776 callback); |
| 777 return net::ERR_IO_PENDING; |
| 778 } |
| 779 |
| 780 int EntryImpl::WriteData(int index, int offset, net::IOBuffer* buf, int buf_len, |
| 781 CompletionCallback* callback, bool truncate) { |
| 782 if (!callback) |
| 783 return WriteDataImpl(index, offset, buf, buf_len, callback, truncate); |
| 784 |
| 785 DCHECK(node_.Data()->dirty || read_only_); |
| 786 if (index < 0 || index >= kNumStreams) |
| 787 return net::ERR_INVALID_ARGUMENT; |
| 788 |
| 789 if (offset < 0 || buf_len < 0) |
| 790 return net::ERR_INVALID_ARGUMENT; |
| 791 |
| 792 backend_->background_queue()->WriteData(this, index, offset, buf, buf_len, |
| 793 truncate, callback); |
| 794 return net::ERR_IO_PENDING; |
| 795 } |
| 796 |
| 797 int EntryImpl::ReadSparseData(int64 offset, net::IOBuffer* buf, int buf_len, |
| 798 net::CompletionCallback* callback) { |
| 799 if (!callback) |
| 800 return ReadSparseDataImpl(offset, buf, buf_len, callback); |
| 801 |
| 802 backend_->background_queue()->ReadSparseData(this, offset, buf, buf_len, |
| 803 callback); |
| 804 return net::ERR_IO_PENDING; |
| 805 } |
| 806 |
| 807 int EntryImpl::WriteSparseData(int64 offset, net::IOBuffer* buf, int buf_len, |
| 808 net::CompletionCallback* callback) { |
| 809 if (!callback) |
| 810 return WriteSparseDataImpl(offset, buf, buf_len, callback); |
| 811 |
| 812 backend_->background_queue()->WriteSparseData(this, offset, buf, buf_len, |
| 813 callback); |
| 814 return net::ERR_IO_PENDING; |
| 815 } |
| 816 |
| 817 int EntryImpl::GetAvailableRange(int64 offset, int len, int64* start, |
| 818 CompletionCallback* callback) { |
| 819 backend_->background_queue()->GetAvailableRange(this, offset, len, start, |
| 820 callback); |
| 821 return net::ERR_IO_PENDING; |
| 822 } |
| 823 |
| 824 bool EntryImpl::CouldBeSparse() const { |
| 825 if (sparse_.get()) |
| 826 return true; |
| 827 |
| 828 scoped_ptr<SparseControl> sparse; |
| 829 sparse.reset(new SparseControl(const_cast<EntryImpl*>(this))); |
| 830 return sparse->CouldBeSparse(); |
| 831 } |
| 832 |
| 833 void EntryImpl::CancelSparseIO() { |
| 834 backend_->background_queue()->CancelSparseIO(this); |
| 835 } |
| 836 |
| 837 int EntryImpl::ReadyForSparseIO(net::CompletionCallback* callback) { |
| 838 if (!sparse_.get()) |
| 839 return net::OK; |
| 840 |
| 841 backend_->background_queue()->ReadyForSparseIO(this, callback); |
| 842 return net::ERR_IO_PENDING; |
| 843 } |
| 844 |
| 845 // When an entry is deleted from the cache, we clean up all the data associated |
| 846 // with it for two reasons: to simplify the reuse of the block (we know that any |
| 847 // unused block is filled with zeros), and to simplify the handling of write / |
| 848 // read partial information from an entry (don't have to worry about returning |
| 849 // data related to a previous cache entry because the range was not fully |
| 850 // written before). |
| 851 EntryImpl::~EntryImpl() { |
| 852 Log("~EntryImpl in"); |
| 853 |
| 854 // Save the sparse info to disk. This will generate IO for this entry and |
| 855 // maybe for a child entry, so it is important to do it before deleting this |
| 856 // entry. |
| 857 sparse_.reset(); |
| 858 |
| 859 // Remove this entry from the list of open entries. |
| 860 backend_->OnEntryDestroyBegin(entry_.address()); |
| 861 |
| 862 if (doomed_) { |
| 863 DeleteEntryData(true); |
| 864 } else { |
| 865 net_log_.AddEvent(net::NetLog::TYPE_DISK_CACHE_CLOSE, NULL); |
| 866 bool ret = true; |
| 867 for (int index = 0; index < kNumStreams; index++) { |
| 868 if (user_buffers_[index].get()) { |
| 869 if (!(ret = Flush(index, 0))) |
| 870 LOG(ERROR) << "Failed to save user data"; |
| 871 } |
| 872 if (unreported_size_[index]) { |
| 873 backend_->ModifyStorageSize( |
| 874 entry_.Data()->data_size[index] - unreported_size_[index], |
| 875 entry_.Data()->data_size[index]); |
| 876 } |
| 877 } |
| 878 |
| 879 if (!ret) { |
| 880 // There was a failure writing the actual data. Mark the entry as dirty. |
| 881 int current_id = backend_->GetCurrentEntryId(); |
| 882 node_.Data()->dirty = current_id == 1 ? -1 : current_id - 1; |
| 883 node_.Store(); |
| 884 } else if (node_.HasData() && node_.Data()->dirty) { |
| 885 node_.Data()->dirty = 0; |
| 886 node_.Store(); |
| 887 } |
| 888 } |
| 889 |
| 890 Trace("~EntryImpl out 0x%p", reinterpret_cast<void*>(this)); |
| 891 net_log_.EndEvent(net::NetLog::TYPE_DISK_CACHE_ENTRY, NULL); |
| 892 backend_->OnEntryDestroyEnd(); |
| 893 } |
| 894 |
| 1064 // ------------------------------------------------------------------------ | 895 // ------------------------------------------------------------------------ |
| 1065 | 896 |
| 897 int EntryImpl::InternalReadData(int index, int offset, net::IOBuffer* buf, |
| 898 int buf_len, CompletionCallback* callback) { |
| 899 DCHECK(node_.Data()->dirty || read_only_); |
| 900 DVLOG(2) << "Read from " << index << " at " << offset << " : " << buf_len; |
| 901 if (index < 0 || index >= kNumStreams) |
| 902 return net::ERR_INVALID_ARGUMENT; |
| 903 |
| 904 int entry_size = entry_.Data()->data_size[index]; |
| 905 if (offset >= entry_size || offset < 0 || !buf_len) |
| 906 return 0; |
| 907 |
| 908 if (buf_len < 0) |
| 909 return net::ERR_INVALID_ARGUMENT; |
| 910 |
| 911 TimeTicks start = TimeTicks::Now(); |
| 912 |
| 913 if (offset + buf_len > entry_size) |
| 914 buf_len = entry_size - offset; |
| 915 |
| 916 UpdateRank(false); |
| 917 |
| 918 backend_->OnEvent(Stats::READ_DATA); |
| 919 backend_->OnRead(buf_len); |
| 920 |
| 921 Addr address(entry_.Data()->data_addr[index]); |
| 922 int eof = address.is_initialized() ? entry_size : 0; |
| 923 if (user_buffers_[index].get() && |
| 924 user_buffers_[index]->PreRead(eof, offset, &buf_len)) { |
| 925 // Complete the operation locally. |
| 926 buf_len = user_buffers_[index]->Read(offset, buf, buf_len); |
| 927 ReportIOTime(kRead, start); |
| 928 return buf_len; |
| 929 } |
| 930 |
| 931 address.set_value(entry_.Data()->data_addr[index]); |
| 932 DCHECK(address.is_initialized()); |
| 933 if (!address.is_initialized()) |
| 934 return net::ERR_FAILED; |
| 935 |
| 936 File* file = GetBackingFile(address, index); |
| 937 if (!file) |
| 938 return net::ERR_FAILED; |
| 939 |
| 940 size_t file_offset = offset; |
| 941 if (address.is_block_file()) { |
| 942 DCHECK_LE(offset + buf_len, kMaxBlockSize); |
| 943 file_offset += address.start_block() * address.BlockSize() + |
| 944 kBlockHeaderSize; |
| 945 } |
| 946 |
| 947 SyncCallback* io_callback = NULL; |
| 948 if (callback) { |
| 949 io_callback = new SyncCallback(this, buf, callback, |
| 950 net::NetLog::TYPE_DISK_CACHE_READ_DATA); |
| 951 } |
| 952 |
| 953 bool completed; |
| 954 if (!file->Read(buf->data(), buf_len, file_offset, io_callback, &completed)) { |
| 955 if (io_callback) |
| 956 io_callback->Discard(); |
| 957 return net::ERR_FAILED; |
| 958 } |
| 959 |
| 960 if (io_callback && completed) |
| 961 io_callback->Discard(); |
| 962 |
| 963 ReportIOTime(kRead, start); |
| 964 return (completed || !callback) ? buf_len : net::ERR_IO_PENDING; |
| 965 } |
| 966 |
| 967 int EntryImpl::InternalWriteData(int index, int offset, net::IOBuffer* buf, |
| 968 int buf_len, CompletionCallback* callback, |
| 969 bool truncate) { |
| 970 DCHECK(node_.Data()->dirty || read_only_); |
| 971 DVLOG(2) << "Write to " << index << " at " << offset << " : " << buf_len; |
| 972 if (index < 0 || index >= kNumStreams) |
| 973 return net::ERR_INVALID_ARGUMENT; |
| 974 |
| 975 if (offset < 0 || buf_len < 0) |
| 976 return net::ERR_INVALID_ARGUMENT; |
| 977 |
| 978 int max_file_size = backend_->MaxFileSize(); |
| 979 |
| 980 // offset or buf_len could be negative numbers. |
| 981 if (offset > max_file_size || buf_len > max_file_size || |
| 982 offset + buf_len > max_file_size) { |
| 983 int size = offset + buf_len; |
| 984 if (size <= max_file_size) |
| 985 size = kint32max; |
| 986 backend_->TooMuchStorageRequested(size); |
| 987 return net::ERR_FAILED; |
| 988 } |
| 989 |
| 990 TimeTicks start = TimeTicks::Now(); |
| 991 |
| 992 // Read the size at this point (it may change inside prepare). |
| 993 int entry_size = entry_.Data()->data_size[index]; |
| 994 bool extending = entry_size < offset + buf_len; |
| 995 truncate = truncate && entry_size > offset + buf_len; |
| 996 Trace("To PrepareTarget 0x%x", entry_.address().value()); |
| 997 if (!PrepareTarget(index, offset, buf_len, truncate)) |
| 998 return net::ERR_FAILED; |
| 999 |
| 1000 Trace("From PrepareTarget 0x%x", entry_.address().value()); |
| 1001 if (extending || truncate) |
| 1002 UpdateSize(index, entry_size, offset + buf_len); |
| 1003 |
| 1004 UpdateRank(true); |
| 1005 |
| 1006 backend_->OnEvent(Stats::WRITE_DATA); |
| 1007 backend_->OnWrite(buf_len); |
| 1008 |
| 1009 if (user_buffers_[index].get()) { |
| 1010 // Complete the operation locally. |
| 1011 user_buffers_[index]->Write(offset, buf, buf_len); |
| 1012 ReportIOTime(kWrite, start); |
| 1013 return buf_len; |
| 1014 } |
| 1015 |
| 1016 Addr address(entry_.Data()->data_addr[index]); |
| 1017 if (offset + buf_len == 0) { |
| 1018 if (truncate) { |
| 1019 DCHECK(!address.is_initialized()); |
| 1020 } |
| 1021 return 0; |
| 1022 } |
| 1023 |
| 1024 File* file = GetBackingFile(address, index); |
| 1025 if (!file) |
| 1026 return net::ERR_FAILED; |
| 1027 |
| 1028 size_t file_offset = offset; |
| 1029 if (address.is_block_file()) { |
| 1030 DCHECK_LE(offset + buf_len, kMaxBlockSize); |
| 1031 file_offset += address.start_block() * address.BlockSize() + |
| 1032 kBlockHeaderSize; |
| 1033 } else if (truncate || (extending && !buf_len)) { |
| 1034 if (!file->SetLength(offset + buf_len)) |
| 1035 return net::ERR_FAILED; |
| 1036 } |
| 1037 |
| 1038 if (!buf_len) |
| 1039 return 0; |
| 1040 |
| 1041 SyncCallback* io_callback = NULL; |
| 1042 if (callback) { |
| 1043 io_callback = new SyncCallback(this, buf, callback, |
| 1044 net::NetLog::TYPE_DISK_CACHE_WRITE_DATA); |
| 1045 } |
| 1046 |
| 1047 bool completed; |
| 1048 if (!file->Write(buf->data(), buf_len, file_offset, io_callback, |
| 1049 &completed)) { |
| 1050 if (io_callback) |
| 1051 io_callback->Discard(); |
| 1052 return net::ERR_FAILED; |
| 1053 } |
| 1054 |
| 1055 if (io_callback && completed) |
| 1056 io_callback->Discard(); |
| 1057 |
| 1058 ReportIOTime(kWrite, start); |
| 1059 return (completed || !callback) ? buf_len : net::ERR_IO_PENDING; |
| 1060 } |
| 1061 |
| 1062 // ------------------------------------------------------------------------ |
| 1063 |
| 1066 bool EntryImpl::CreateDataBlock(int index, int size) { | 1064 bool EntryImpl::CreateDataBlock(int index, int size) { |
| 1067 DCHECK(index >= 0 && index < kNumStreams); | 1065 DCHECK(index >= 0 && index < kNumStreams); |
| 1068 | 1066 |
| 1069 Addr address(entry_.Data()->data_addr[index]); | 1067 Addr address(entry_.Data()->data_addr[index]); |
| 1070 if (!CreateBlock(size, &address)) | 1068 if (!CreateBlock(size, &address)) |
| 1071 return false; | 1069 return false; |
| 1072 | 1070 |
| 1073 entry_.Data()->data_addr[index] = address.value(); | 1071 entry_.Data()->data_addr[index] = address.value(); |
| 1074 entry_.Store(); | 1072 entry_.Store(); |
| 1075 return true; | 1073 return true; |
| (...skipping 361 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1437 Trace("%s 0x%p 0x%x 0x%x", msg, reinterpret_cast<void*>(this), | 1435 Trace("%s 0x%p 0x%x 0x%x", msg, reinterpret_cast<void*>(this), |
| 1438 entry_.address().value(), node_.address().value()); | 1436 entry_.address().value(), node_.address().value()); |
| 1439 | 1437 |
| 1440 Trace(" data: 0x%x 0x%x 0x%x", entry_.Data()->data_addr[0], | 1438 Trace(" data: 0x%x 0x%x 0x%x", entry_.Data()->data_addr[0], |
| 1441 entry_.Data()->data_addr[1], entry_.Data()->long_key); | 1439 entry_.Data()->data_addr[1], entry_.Data()->long_key); |
| 1442 | 1440 |
| 1443 Trace(" doomed: %d 0x%x", doomed_, dirty); | 1441 Trace(" doomed: %d 0x%x", doomed_, dirty); |
| 1444 } | 1442 } |
| 1445 | 1443 |
| 1446 } // namespace disk_cache | 1444 } // namespace disk_cache |
| OLD | NEW |