Home | History | Annotate | Download | only in disk_cache
      1 // Copyright (c) 2006-2009 The Chromium Authors. All rights reserved.
      2 // Use of this source code is governed by a BSD-style license that can be
      3 // found in the LICENSE file.
      4 
      5 #include "net/disk_cache/entry_impl.h"
      6 
      7 #include "base/histogram.h"
      8 #include "base/message_loop.h"
      9 #include "base/string_util.h"
     10 #include "net/base/io_buffer.h"
     11 #include "net/base/net_errors.h"
     12 #include "net/disk_cache/backend_impl.h"
     13 #include "net/disk_cache/bitmap.h"
     14 #include "net/disk_cache/cache_util.h"
     15 #include "net/disk_cache/histogram_macros.h"
     16 #include "net/disk_cache/sparse_control.h"
     17 
     18 using base::Time;
     19 using base::TimeDelta;
     20 
     21 namespace {
     22 
     23 // Index for the file used to store the key, if any (files_[kKeyFileIndex]).
     24 const int kKeyFileIndex = 3;
     25 
     26 // This class implements FileIOCallback to buffer the callback from a file IO
     27 // operation from the actual net class.
     28 class SyncCallback: public disk_cache::FileIOCallback {
     29  public:
     30   SyncCallback(disk_cache::EntryImpl* entry, net::IOBuffer* buffer,
     31                net::CompletionCallback* callback )
     32       : entry_(entry), callback_(callback), buf_(buffer), start_(Time::Now()) {
     33     entry->AddRef();
     34     entry->IncrementIoCount();
     35   }
     36   ~SyncCallback() {}
     37 
     38   virtual void OnFileIOComplete(int bytes_copied);
     39   void Discard();
     40  private:
     41   disk_cache::EntryImpl* entry_;
     42   net::CompletionCallback* callback_;
     43   scoped_refptr<net::IOBuffer> buf_;
     44   Time start_;
     45 
     46   DISALLOW_EVIL_CONSTRUCTORS(SyncCallback);
     47 };
     48 
     49 void SyncCallback::OnFileIOComplete(int bytes_copied) {
     50   entry_->DecrementIoCount();
     51   if (callback_) {
     52     entry_->ReportIOTime(disk_cache::EntryImpl::kAsyncIO, start_);
     53     callback_->Run(bytes_copied);
     54   }
     55   entry_->Release();
     56   delete this;
     57 }
     58 
     59 void SyncCallback::Discard() {
     60   callback_ = NULL;
     61   buf_ = NULL;
     62   OnFileIOComplete(0);
     63 }
     64 
     65 // Clears buffer before offset and after valid_len, knowing that the size of
     66 // buffer is kMaxBlockSize.
     67 void ClearInvalidData(char* buffer, int offset, int valid_len) {
     68   DCHECK(offset >= 0);
     69   DCHECK(valid_len >= 0);
     70   DCHECK(disk_cache::kMaxBlockSize >= offset + valid_len);
     71   if (offset)
     72     memset(buffer, 0, offset);
     73   int end = disk_cache::kMaxBlockSize - offset - valid_len;
     74   if (end)
     75     memset(buffer + offset + valid_len, 0, end);
     76 }
     77 
     78 }  // namespace
     79 
     80 namespace disk_cache {
     81 
     82 EntryImpl::EntryImpl(BackendImpl* backend, Addr address)
     83     : entry_(NULL, Addr(0)), node_(NULL, Addr(0)) {
     84   entry_.LazyInit(backend->File(address), address);
     85   doomed_ = false;
     86   backend_ = backend;
     87   for (int i = 0; i < kNumStreams; i++) {
     88     unreported_size_[i] = 0;
     89   }
     90   key_file_ = NULL;
     91 }
     92 
     93 // When an entry is deleted from the cache, we clean up all the data associated
     94 // with it for two reasons: to simplify the reuse of the block (we know that any
     95 // unused block is filled with zeros), and to simplify the handling of write /
     96 // read partial information from an entry (don't have to worry about returning
     97 // data related to a previous cache entry because the range was not fully
     98 // written before).
     99 EntryImpl::~EntryImpl() {
    100   // Save the sparse info to disk before deleting this entry.
    101   sparse_.reset();
    102 
    103   if (doomed_) {
    104     DeleteEntryData(true);
    105   } else {
    106     bool ret = true;
    107     for (int index = 0; index < kNumStreams; index++) {
    108       if (user_buffers_[index].get()) {
    109         if (!(ret = Flush(index, entry_.Data()->data_size[index], false)))
    110           LOG(ERROR) << "Failed to save user data";
    111       } else if (unreported_size_[index]) {
    112         backend_->ModifyStorageSize(
    113             entry_.Data()->data_size[index] - unreported_size_[index],
    114             entry_.Data()->data_size[index]);
    115       }
    116     }
    117 
    118     if (!ret) {
    119       // There was a failure writing the actual data. Mark the entry as dirty.
    120       int current_id = backend_->GetCurrentEntryId();
    121       node_.Data()->dirty = current_id == 1 ? -1 : current_id - 1;
    122       node_.Store();
    123     } else if (node_.HasData() && node_.Data()->dirty) {
    124       node_.Data()->dirty = 0;
    125       node_.Store();
    126     }
    127   }
    128 
    129   backend_->CacheEntryDestroyed(entry_.address());
    130 }
    131 
    132 void EntryImpl::Doom() {
    133   if (doomed_)
    134     return;
    135 
    136   SetPointerForInvalidEntry(backend_->GetCurrentEntryId());
    137   backend_->InternalDoomEntry(this);
    138 }
    139 
    140 void EntryImpl::Close() {
    141   Release();
    142 }
    143 
    144 std::string EntryImpl::GetKey() const {
    145   CacheEntryBlock* entry = const_cast<CacheEntryBlock*>(&entry_);
    146   if (entry->Data()->key_len <= kMaxInternalKeyLength)
    147     return std::string(entry->Data()->key);
    148 
    149   Addr address(entry->Data()->long_key);
    150   DCHECK(address.is_initialized());
    151   size_t offset = 0;
    152   if (address.is_block_file())
    153     offset = address.start_block() * address.BlockSize() + kBlockHeaderSize;
    154 
    155   if (!key_file_) {
    156     // We keep a copy of the file needed to access the key so that we can
    157     // always return this object's key, even if the backend is disabled.
    158     COMPILE_ASSERT(kNumStreams == kKeyFileIndex, invalid_key_index);
    159     key_file_ = const_cast<EntryImpl*>(this)->GetBackingFile(address,
    160                                                              kKeyFileIndex);
    161   }
    162 
    163   std::string key;
    164   if (!key_file_ ||
    165       !key_file_->Read(WriteInto(&key, entry->Data()->key_len + 1),
    166                        entry->Data()->key_len + 1, offset))
    167     key.clear();
    168   return key;
    169 }
    170 
    171 Time EntryImpl::GetLastUsed() const {
    172   CacheRankingsBlock* node = const_cast<CacheRankingsBlock*>(&node_);
    173   return Time::FromInternalValue(node->Data()->last_used);
    174 }
    175 
    176 Time EntryImpl::GetLastModified() const {
    177   CacheRankingsBlock* node = const_cast<CacheRankingsBlock*>(&node_);
    178   return Time::FromInternalValue(node->Data()->last_modified);
    179 }
    180 
    181 int32 EntryImpl::GetDataSize(int index) const {
    182   if (index < 0 || index >= kNumStreams)
    183     return 0;
    184 
    185   CacheEntryBlock* entry = const_cast<CacheEntryBlock*>(&entry_);
    186   return entry->Data()->data_size[index];
    187 }
    188 
    189 int EntryImpl::ReadData(int index, int offset, net::IOBuffer* buf, int buf_len,
    190                         net::CompletionCallback* completion_callback) {
    191   DCHECK(node_.Data()->dirty);
    192   if (index < 0 || index >= kNumStreams)
    193     return net::ERR_INVALID_ARGUMENT;
    194 
    195   int entry_size = entry_.Data()->data_size[index];
    196   if (offset >= entry_size || offset < 0 || !buf_len)
    197     return 0;
    198 
    199   if (buf_len < 0)
    200     return net::ERR_INVALID_ARGUMENT;
    201 
    202   Time start = Time::Now();
    203 
    204   if (offset + buf_len > entry_size)
    205     buf_len = entry_size - offset;
    206 
    207   UpdateRank(false);
    208 
    209   backend_->OnEvent(Stats::READ_DATA);
    210 
    211   if (user_buffers_[index].get()) {
    212     // Complete the operation locally.
    213     DCHECK(kMaxBlockSize >= offset + buf_len);
    214     memcpy(buf->data() , user_buffers_[index].get() + offset, buf_len);
    215     ReportIOTime(kRead, start);
    216     return buf_len;
    217   }
    218 
    219   Addr address(entry_.Data()->data_addr[index]);
    220   DCHECK(address.is_initialized());
    221   if (!address.is_initialized())
    222     return net::ERR_FAILED;
    223 
    224   File* file = GetBackingFile(address, index);
    225   if (!file)
    226     return net::ERR_FAILED;
    227 
    228   size_t file_offset = offset;
    229   if (address.is_block_file())
    230     file_offset += address.start_block() * address.BlockSize() +
    231                    kBlockHeaderSize;
    232 
    233   SyncCallback* io_callback = NULL;
    234   if (completion_callback)
    235     io_callback = new SyncCallback(this, buf, completion_callback);
    236 
    237   bool completed;
    238   if (!file->Read(buf->data(), buf_len, file_offset, io_callback, &completed)) {
    239     if (io_callback)
    240       io_callback->Discard();
    241     return net::ERR_FAILED;
    242   }
    243 
    244   if (io_callback && completed)
    245     io_callback->Discard();
    246 
    247   ReportIOTime(kRead, start);
    248   return (completed || !completion_callback) ? buf_len : net::ERR_IO_PENDING;
    249 }
    250 
    251 int EntryImpl::WriteData(int index, int offset, net::IOBuffer* buf, int buf_len,
    252                          net::CompletionCallback* completion_callback,
    253                          bool truncate) {
    254   DCHECK(node_.Data()->dirty);
    255   if (index < 0 || index >= kNumStreams)
    256     return net::ERR_INVALID_ARGUMENT;
    257 
    258   if (offset < 0 || buf_len < 0)
    259     return net::ERR_INVALID_ARGUMENT;
    260 
    261   int max_file_size = backend_->MaxFileSize();
    262 
    263   // offset of buf_len could be negative numbers.
    264   if (offset > max_file_size || buf_len > max_file_size ||
    265       offset + buf_len > max_file_size) {
    266     int size = offset + buf_len;
    267     if (size <= max_file_size)
    268       size = kint32max;
    269     backend_->TooMuchStorageRequested(size);
    270     return net::ERR_FAILED;
    271   }
    272 
    273   Time start = Time::Now();
    274 
    275   // Read the size at this point (it may change inside prepare).
    276   int entry_size = entry_.Data()->data_size[index];
    277   if (!PrepareTarget(index, offset, buf_len, truncate))
    278     return net::ERR_FAILED;
    279 
    280   if (entry_size < offset + buf_len) {
    281     unreported_size_[index] += offset + buf_len - entry_size;
    282     entry_.Data()->data_size[index] = offset + buf_len;
    283     entry_.set_modified();
    284     if (!buf_len)
    285       truncate = true;  // Force file extension.
    286   } else if (truncate) {
    287       // If the size was modified inside PrepareTarget, we should not do
    288       // anything here.
    289       if ((entry_size > offset + buf_len) &&
    290           (entry_size == entry_.Data()->data_size[index])) {
    291         unreported_size_[index] += offset + buf_len - entry_size;
    292         entry_.Data()->data_size[index] = offset + buf_len;
    293         entry_.set_modified();
    294       } else {
    295         // Nothing to truncate.
    296         truncate = false;
    297       }
    298   }
    299 
    300   UpdateRank(true);
    301 
    302   backend_->OnEvent(Stats::WRITE_DATA);
    303 
    304   if (user_buffers_[index].get()) {
    305     // Complete the operation locally.
    306     if (!buf_len)
    307       return 0;
    308 
    309     DCHECK(kMaxBlockSize >= offset + buf_len);
    310     memcpy(user_buffers_[index].get() + offset, buf->data(), buf_len);
    311     ReportIOTime(kWrite, start);
    312     return buf_len;
    313   }
    314 
    315   Addr address(entry_.Data()->data_addr[index]);
    316   File* file = GetBackingFile(address, index);
    317   if (!file)
    318     return net::ERR_FAILED;
    319 
    320   size_t file_offset = offset;
    321   if (address.is_block_file()) {
    322     file_offset += address.start_block() * address.BlockSize() +
    323                    kBlockHeaderSize;
    324   } else if (truncate) {
    325     if (!file->SetLength(offset + buf_len))
    326       return net::ERR_FAILED;
    327   }
    328 
    329   if (!buf_len)
    330     return 0;
    331 
    332   SyncCallback* io_callback = NULL;
    333   if (completion_callback)
    334     io_callback = new SyncCallback(this, buf, completion_callback);
    335 
    336   bool completed;
    337   if (!file->Write(buf->data(), buf_len, file_offset, io_callback,
    338                    &completed)) {
    339     if (io_callback)
    340       io_callback->Discard();
    341     return net::ERR_FAILED;
    342   }
    343 
    344   if (io_callback && completed)
    345     io_callback->Discard();
    346 
    347   ReportIOTime(kWrite, start);
    348   return (completed || !completion_callback) ? buf_len : net::ERR_IO_PENDING;
    349 }
    350 
    351 int EntryImpl::ReadSparseData(int64 offset, net::IOBuffer* buf, int buf_len,
    352                               net::CompletionCallback* completion_callback) {
    353   DCHECK(node_.Data()->dirty);
    354   int result = InitSparseData();
    355   if (net::OK != result)
    356     return result;
    357 
    358   Time start = Time::Now();
    359   result = sparse_->StartIO(SparseControl::kReadOperation, offset, buf, buf_len,
    360                             completion_callback);
    361   ReportIOTime(kSparseRead, start);
    362   return result;
    363 }
    364 
    365 int EntryImpl::WriteSparseData(int64 offset, net::IOBuffer* buf, int buf_len,
    366                                net::CompletionCallback* completion_callback) {
    367   DCHECK(node_.Data()->dirty);
    368   int result = InitSparseData();
    369   if (net::OK != result)
    370     return result;
    371 
    372   Time start = Time::Now();
    373   result = sparse_->StartIO(SparseControl::kWriteOperation, offset, buf,
    374                             buf_len, completion_callback);
    375   ReportIOTime(kSparseWrite, start);
    376   return result;
    377 }
    378 
    379 int EntryImpl::GetAvailableRange(int64 offset, int len, int64* start) {
    380   int result = InitSparseData();
    381   if (net::OK != result)
    382     return result;
    383 
    384   return sparse_->GetAvailableRange(offset, len, start);
    385 }
    386 
    387 int EntryImpl::GetAvailableRange(int64 offset, int len, int64* start,
    388                                  CompletionCallback* callback) {
    389   return GetAvailableRange(offset, len, start);
    390 }
    391 
    392 void EntryImpl::CancelSparseIO() {
    393   if (!sparse_.get())
    394     return;
    395 
    396   sparse_->CancelIO();
    397 }
    398 
    399 int EntryImpl::ReadyForSparseIO(net::CompletionCallback* completion_callback) {
    400   if (!sparse_.get())
    401     return net::OK;
    402 
    403   return sparse_->ReadyToUse(completion_callback);
    404 }
    405 
    406 // ------------------------------------------------------------------------
    407 
    408 uint32 EntryImpl::GetHash() {
    409   return entry_.Data()->hash;
    410 }
    411 
    412 bool EntryImpl::CreateEntry(Addr node_address, const std::string& key,
    413                             uint32 hash) {
    414   Trace("Create entry In");
    415   EntryStore* entry_store = entry_.Data();
    416   RankingsNode* node = node_.Data();
    417   memset(entry_store, 0, sizeof(EntryStore) * entry_.address().num_blocks());
    418   memset(node, 0, sizeof(RankingsNode));
    419   if (!node_.LazyInit(backend_->File(node_address), node_address))
    420     return false;
    421 
    422   entry_store->rankings_node = node_address.value();
    423   node->contents = entry_.address().value();
    424 
    425   entry_store->hash = hash;
    426   entry_store->creation_time = Time::Now().ToInternalValue();
    427   entry_store->key_len = static_cast<int32>(key.size());
    428   if (entry_store->key_len > kMaxInternalKeyLength) {
    429     Addr address(0);
    430     if (!CreateBlock(entry_store->key_len + 1, &address))
    431       return false;
    432 
    433     entry_store->long_key = address.value();
    434     key_file_ = GetBackingFile(address, kKeyFileIndex);
    435 
    436     size_t offset = 0;
    437     if (address.is_block_file())
    438       offset = address.start_block() * address.BlockSize() + kBlockHeaderSize;
    439 
    440     if (!key_file_ || !key_file_->Write(key.data(), key.size(), offset)) {
    441       DeleteData(address, kKeyFileIndex);
    442       return false;
    443     }
    444 
    445     if (address.is_separate_file())
    446       key_file_->SetLength(key.size() + 1);
    447   } else {
    448     memcpy(entry_store->key, key.data(), key.size());
    449     entry_store->key[key.size()] = '\0';
    450   }
    451   backend_->ModifyStorageSize(0, static_cast<int32>(key.size()));
    452   node->dirty = backend_->GetCurrentEntryId();
    453   Log("Create Entry ");
    454   return true;
    455 }
    456 
    457 bool EntryImpl::IsSameEntry(const std::string& key, uint32 hash) {
    458   if (entry_.Data()->hash != hash ||
    459       static_cast<size_t>(entry_.Data()->key_len) != key.size())
    460     return false;
    461 
    462   std::string my_key = GetKey();
    463   return key.compare(my_key) ? false : true;
    464 }
    465 
    466 void EntryImpl::InternalDoom() {
    467   DCHECK(node_.HasData());
    468   if (!node_.Data()->dirty) {
    469     node_.Data()->dirty = backend_->GetCurrentEntryId();
    470     node_.Store();
    471   }
    472   doomed_ = true;
    473 }
    474 
    475 void EntryImpl::DeleteEntryData(bool everything) {
    476   DCHECK(doomed_ || !everything);
    477 
    478   if (GetEntryFlags() & PARENT_ENTRY) {
    479     // We have some child entries that must go away.
    480     SparseControl::DeleteChildren(this);
    481   }
    482 
    483   if (GetDataSize(0))
    484     CACHE_UMA(COUNTS, "DeleteHeader", 0, GetDataSize(0));
    485   if (GetDataSize(1))
    486     CACHE_UMA(COUNTS, "DeleteData", 0, GetDataSize(1));
    487   for (int index = 0; index < kNumStreams; index++) {
    488     Addr address(entry_.Data()->data_addr[index]);
    489     if (address.is_initialized()) {
    490       DeleteData(address, index);
    491       backend_->ModifyStorageSize(entry_.Data()->data_size[index] -
    492                                       unreported_size_[index], 0);
    493       entry_.Data()->data_addr[index] = 0;
    494       entry_.Data()->data_size[index] = 0;
    495     }
    496   }
    497 
    498   if (!everything) {
    499     entry_.Store();
    500     return;
    501   }
    502 
    503   // Remove all traces of this entry.
    504   backend_->RemoveEntry(this);
    505 
    506   Addr address(entry_.Data()->long_key);
    507   DeleteData(address, kKeyFileIndex);
    508   backend_->ModifyStorageSize(entry_.Data()->key_len, 0);
    509 
    510   memset(node_.buffer(), 0, node_.size());
    511   memset(entry_.buffer(), 0, entry_.size());
    512   node_.Store();
    513   entry_.Store();
    514 
    515   backend_->DeleteBlock(node_.address(), false);
    516   backend_->DeleteBlock(entry_.address(), false);
    517 }
    518 
    519 CacheAddr EntryImpl::GetNextAddress() {
    520   return entry_.Data()->next;
    521 }
    522 
    523 void EntryImpl::SetNextAddress(Addr address) {
    524   entry_.Data()->next = address.value();
    525   bool success = entry_.Store();
    526   DCHECK(success);
    527 }
    528 
    529 bool EntryImpl::LoadNodeAddress() {
    530   Addr address(entry_.Data()->rankings_node);
    531   if (!node_.LazyInit(backend_->File(address), address))
    532     return false;
    533   return node_.Load();
    534 }
    535 
    536 bool EntryImpl::Update() {
    537   DCHECK(node_.HasData());
    538 
    539   RankingsNode* rankings = node_.Data();
    540   if (!rankings->dirty) {
    541     rankings->dirty = backend_->GetCurrentEntryId();
    542     if (!node_.Store())
    543       return false;
    544   }
    545   return true;
    546 }
    547 
    548 bool EntryImpl::IsDirty(int32 current_id) {
    549   DCHECK(node_.HasData());
    550   // We are checking if the entry is valid or not. If there is a pointer here,
    551   // we should not be checking the entry.
    552   if (node_.Data()->dummy)
    553     return true;
    554 
    555   return node_.Data()->dirty && current_id != node_.Data()->dirty;
    556 }
    557 
    558 void EntryImpl::ClearDirtyFlag() {
    559   node_.Data()->dirty = 0;
    560 }
    561 
    562 void EntryImpl::SetPointerForInvalidEntry(int32 new_id) {
    563   node_.Data()->dirty = new_id;
    564   node_.Data()->dummy = 0;
    565   node_.Store();
    566 }
    567 
    568 bool EntryImpl::SanityCheck() {
    569   if (!entry_.Data()->rankings_node || !entry_.Data()->key_len)
    570     return false;
    571 
    572   Addr rankings_addr(entry_.Data()->rankings_node);
    573   if (!rankings_addr.is_initialized() || rankings_addr.is_separate_file() ||
    574       rankings_addr.file_type() != RANKINGS)
    575     return false;
    576 
    577   Addr next_addr(entry_.Data()->next);
    578   if (next_addr.is_initialized() &&
    579       (next_addr.is_separate_file() || next_addr.file_type() != BLOCK_256))
    580     return false;
    581 
    582   return true;
    583 }
    584 
    585 void EntryImpl::IncrementIoCount() {
    586   backend_->IncrementIoCount();
    587 }
    588 
    589 void EntryImpl::DecrementIoCount() {
    590   backend_->DecrementIoCount();
    591 }
    592 
    593 void EntryImpl::SetTimes(base::Time last_used, base::Time last_modified) {
    594   node_.Data()->last_used = last_used.ToInternalValue();
    595   node_.Data()->last_modified = last_modified.ToInternalValue();
    596   node_.set_modified();
    597 }
    598 
    599 void EntryImpl::ReportIOTime(Operation op, const base::Time& start) {
    600   int group = backend_->GetSizeGroup();
    601   switch (op) {
    602     case kRead:
    603       CACHE_UMA(AGE_MS, "ReadTime", group, start);
    604       break;
    605     case kWrite:
    606       CACHE_UMA(AGE_MS, "WriteTime", group, start);
    607       break;
    608     case kSparseRead:
    609       CACHE_UMA(AGE_MS, "SparseReadTime", 0, start);
    610       break;
    611     case kSparseWrite:
    612       CACHE_UMA(AGE_MS, "SparseWriteTime", 0, start);
    613       break;
    614     case kAsyncIO:
    615       CACHE_UMA(AGE_MS, "AsyncIOTime", group, start);
    616       break;
    617     default:
    618       NOTREACHED();
    619   }
    620 }
    621 
    622 // ------------------------------------------------------------------------
    623 
    624 bool EntryImpl::CreateDataBlock(int index, int size) {
    625   DCHECK(index >= 0 && index < kNumStreams);
    626 
    627   Addr address(entry_.Data()->data_addr[index]);
    628   if (!CreateBlock(size, &address))
    629     return false;
    630 
    631   entry_.Data()->data_addr[index] = address.value();
    632   entry_.Store();
    633   return true;
    634 }
    635 
    636 bool EntryImpl::CreateBlock(int size, Addr* address) {
    637   DCHECK(!address->is_initialized());
    638 
    639   FileType file_type = Addr::RequiredFileType(size);
    640   if (EXTERNAL == file_type) {
    641     if (size > backend_->MaxFileSize())
    642       return false;
    643     if (!backend_->CreateExternalFile(address))
    644       return false;
    645   } else {
    646     int num_blocks = (size + Addr::BlockSizeForFileType(file_type) - 1) /
    647                      Addr::BlockSizeForFileType(file_type);
    648 
    649     if (!backend_->CreateBlock(file_type, num_blocks, address))
    650       return false;
    651   }
    652   return true;
    653 }
    654 
    655 void EntryImpl::DeleteData(Addr address, int index) {
    656   if (!address.is_initialized())
    657     return;
    658   if (address.is_separate_file()) {
    659     if (files_[index])
    660       files_[index] = NULL;  // Releases the object.
    661 
    662     int failure = DeleteCacheFile(backend_->GetFileName(address)) ? 0 : 1;
    663     CACHE_UMA(COUNTS, "DeleteFailed", 0, failure);
    664     if (failure)
    665       LOG(ERROR) << "Failed to delete " <<
    666           backend_->GetFileName(address).value() << " from the cache.";
    667   } else {
    668     backend_->DeleteBlock(address, true);
    669   }
    670 }
    671 
    672 void EntryImpl::UpdateRank(bool modified) {
    673   if (!doomed_) {
    674     // Everything is handled by the backend.
    675     backend_->UpdateRank(this, true);
    676     return;
    677   }
    678 
    679   Time current = Time::Now();
    680   node_.Data()->last_used = current.ToInternalValue();
    681 
    682   if (modified)
    683     node_.Data()->last_modified = current.ToInternalValue();
    684 }
    685 
    686 File* EntryImpl::GetBackingFile(Addr address, int index) {
    687   File* file;
    688   if (address.is_separate_file())
    689     file = GetExternalFile(address, index);
    690   else
    691     file = backend_->File(address);
    692   return file;
    693 }
    694 
    695 File* EntryImpl::GetExternalFile(Addr address, int index) {
    696   DCHECK(index >= 0 && index <= kKeyFileIndex);
    697   if (!files_[index].get()) {
    698     // For a key file, use mixed mode IO.
    699     scoped_refptr<File> file(new File(kKeyFileIndex == index));
    700     if (file->Init(backend_->GetFileName(address)))
    701       files_[index].swap(file);
    702   }
    703   return files_[index].get();
    704 }
    705 
    706 bool EntryImpl::PrepareTarget(int index, int offset, int buf_len,
    707                               bool truncate) {
    708   Addr address(entry_.Data()->data_addr[index]);
    709 
    710   if (address.is_initialized() || user_buffers_[index].get())
    711     return GrowUserBuffer(index, offset, buf_len, truncate);
    712 
    713   if (offset + buf_len > kMaxBlockSize)
    714     return CreateDataBlock(index, offset + buf_len);
    715 
    716   user_buffers_[index].reset(new char[kMaxBlockSize]);
    717 
    718   // Overwrite the parts of the buffer that are not going to be written
    719   // by the current operation (and yes, let's assume that nothing is going
    720   // to fail, and we'll actually write over the part that we are not cleaning
    721   // here). The point is to avoid writing random stuff to disk later on.
    722   ClearInvalidData(user_buffers_[index].get(), offset, buf_len);
    723 
    724   return true;
    725 }
    726 
    727 // We get to this function with some data already stored. If there is a
    728 // truncation that results on data stored internally, we'll explicitly
    729 // handle the case here.
    730 bool EntryImpl::GrowUserBuffer(int index, int offset, int buf_len,
    731                                bool truncate) {
    732   Addr address(entry_.Data()->data_addr[index]);
    733 
    734   if (offset + buf_len > kMaxBlockSize) {
    735     // The data has to be stored externally.
    736     if (address.is_initialized()) {
    737       if (address.is_separate_file())
    738         return true;
    739       if (!MoveToLocalBuffer(index))
    740         return false;
    741     }
    742     return Flush(index, offset + buf_len, true);
    743   }
    744 
    745   if (!address.is_initialized()) {
    746     DCHECK(user_buffers_[index].get());
    747     if (truncate)
    748       ClearInvalidData(user_buffers_[index].get(), 0, offset + buf_len);
    749     return true;
    750   }
    751   if (address.is_separate_file()) {
    752     if (!truncate)
    753       return true;
    754     return ImportSeparateFile(index, offset, buf_len);
    755   }
    756 
    757   // At this point we are dealing with data stored on disk, inside a block file.
    758   if (offset + buf_len <= address.BlockSize() * address.num_blocks())
    759     return true;
    760 
    761   // ... and the allocated block has to change.
    762   if (!MoveToLocalBuffer(index))
    763     return false;
    764 
    765   int clear_start = entry_.Data()->data_size[index];
    766   if (truncate)
    767     clear_start = std::min(clear_start, offset + buf_len);
    768   else if (offset < clear_start)
    769     clear_start = std::max(offset + buf_len, clear_start);
    770 
    771   // Clear the end of the buffer.
    772   ClearInvalidData(user_buffers_[index].get(), 0, clear_start);
    773   return true;
    774 }
    775 
    776 bool EntryImpl::MoveToLocalBuffer(int index) {
    777   Addr address(entry_.Data()->data_addr[index]);
    778   DCHECK(!user_buffers_[index].get());
    779   DCHECK(address.is_initialized());
    780   scoped_array<char> buffer(new char[kMaxBlockSize]);
    781 
    782   File* file = GetBackingFile(address, index);
    783   size_t len = entry_.Data()->data_size[index];
    784   size_t offset = 0;
    785 
    786   if (address.is_block_file())
    787     offset = address.start_block() * address.BlockSize() + kBlockHeaderSize;
    788 
    789   if (!file || !file->Read(buffer.get(), len, offset, NULL, NULL))
    790     return false;
    791 
    792   DeleteData(address, index);
    793   entry_.Data()->data_addr[index] = 0;
    794   entry_.Store();
    795 
    796   // If we lose this entry we'll see it as zero sized.
    797   backend_->ModifyStorageSize(static_cast<int>(len) - unreported_size_[index],
    798                               0);
    799   unreported_size_[index] = static_cast<int>(len);
    800 
    801   user_buffers_[index].swap(buffer);
    802   return true;
    803 }
    804 
    805 bool EntryImpl::ImportSeparateFile(int index, int offset, int buf_len) {
    806   if (entry_.Data()->data_size[index] > offset + buf_len) {
    807     unreported_size_[index] += offset + buf_len -
    808                                entry_.Data()->data_size[index];
    809     entry_.Data()->data_size[index] = offset + buf_len;
    810   }
    811 
    812   if (!MoveToLocalBuffer(index))
    813     return false;
    814 
    815   // Clear the end of the buffer.
    816   ClearInvalidData(user_buffers_[index].get(), 0, offset + buf_len);
    817   return true;
    818 }
    819 
    820 // The common scenario is that this is called from the destructor of the entry,
    821 // to write to disk what we have buffered. We don't want to hold the destructor
    822 // until the actual IO finishes, so we'll send an asynchronous write that will
    823 // free up the memory containing the data. To be consistent, this method always
    824 // returns with the buffer freed up (on success).
    825 bool EntryImpl::Flush(int index, int size, bool async) {
    826   Addr address(entry_.Data()->data_addr[index]);
    827   DCHECK(user_buffers_[index].get());
    828   DCHECK(!address.is_initialized());
    829 
    830   if (!size)
    831     return true;
    832 
    833   if (!CreateDataBlock(index, size))
    834     return false;
    835 
    836   address.set_value(entry_.Data()->data_addr[index]);
    837 
    838   File* file = GetBackingFile(address, index);
    839   size_t len = entry_.Data()->data_size[index];
    840   size_t offset = 0;
    841   if (address.is_block_file())
    842     offset = address.start_block() * address.BlockSize() + kBlockHeaderSize;
    843 
    844   // We just told the backend to store len bytes for real.
    845   DCHECK(len == static_cast<size_t>(unreported_size_[index]));
    846   backend_->ModifyStorageSize(0, static_cast<int>(len));
    847   unreported_size_[index] = 0;
    848 
    849   if (!file)
    850     return false;
    851 
    852   // TODO(rvargas): figure out if it's worth to re-enable posting operations.
    853   // Right now it is only used from GrowUserBuffer, not the destructor, and
    854   // it is not accounted for from the point of view of the total number of
    855   // pending operations of the cache. It is also racing with the actual write
    856   // on the GrowUserBuffer path because there is no code to exclude the range
    857   // that is going to be written.
    858   async = false;
    859   if (async) {
    860     if (!file->PostWrite(user_buffers_[index].get(), len, offset))
    861       return false;
    862   } else {
    863     if (!file->Write(user_buffers_[index].get(), len, offset, NULL, NULL))
    864       return false;
    865     user_buffers_[index].reset(NULL);
    866   }
    867 
    868   // The buffer is deleted from the PostWrite operation.
    869   user_buffers_[index].release();
    870 
    871   return true;
    872 }
    873 
    874 int EntryImpl::InitSparseData() {
    875   if (sparse_.get())
    876     return net::OK;
    877 
    878   sparse_.reset(new SparseControl(this));
    879   int result = sparse_->Init();
    880   if (net::OK != result)
    881     sparse_.reset();
    882   return result;
    883 }
    884 
    885 void EntryImpl::SetEntryFlags(uint32 flags) {
    886   entry_.Data()->flags |= flags;
    887   entry_.set_modified();
    888 }
    889 
    890 uint32 EntryImpl::GetEntryFlags() {
    891   return entry_.Data()->flags;
    892 }
    893 
    894 void EntryImpl::GetData(int index, char** buffer, Addr* address) {
    895   if (user_buffers_[index].get()) {
    896     // The data is already in memory, just copy it an we're done.
    897     int data_len = entry_.Data()->data_size[index];
    898     DCHECK(data_len <= kMaxBlockSize);
    899     *buffer = new char[data_len];
    900     memcpy(*buffer, user_buffers_[index].get(), data_len);
    901     return;
    902   }
    903 
    904   // Bad news: we'd have to read the info from disk so instead we'll just tell
    905   // the caller where to read from.
    906   *buffer = NULL;
    907   address->set_value(entry_.Data()->data_addr[index]);
    908   if (address->is_initialized()) {
    909     // Prevent us from deleting the block from the backing store.
    910     backend_->ModifyStorageSize(entry_.Data()->data_size[index] -
    911                                     unreported_size_[index], 0);
    912     entry_.Data()->data_addr[index] = 0;
    913     entry_.Data()->data_size[index] = 0;
    914   }
    915 }
    916 
    917 void EntryImpl::Log(const char* msg) {
    918   int dirty = 0;
    919   if (node_.HasData()) {
    920     dirty = node_.Data()->dirty;
    921   }
    922 
    923   Trace("%s 0x%p 0x%x 0x%x", msg, reinterpret_cast<void*>(this),
    924         entry_.address().value(), node_.address().value());
    925 
    926   Trace("  data: 0x%x 0x%x 0x%x", entry_.Data()->data_addr[0],
    927         entry_.Data()->data_addr[1], entry_.Data()->long_key);
    928 
    929   Trace("  doomed: %d 0x%x", doomed_, dirty);
    930 }
    931 
    932 }  // namespace disk_cache
    933