1868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)// Copyright (c) 2012 The Chromium Authors. All rights reserved. 2868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)// Use of this source code is governed by a BSD-style license that can be 3868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)// found in the LICENSE file. 4868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) 5868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)#include "net/disk_cache/block_files.h" 6868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) 7868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)#include "base/atomicops.h" 8868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)#include "base/file_util.h" 9868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)#include "base/metrics/histogram.h" 105e3f23d412006dc4db4e659864679f29341e113fTorne (Richard Coles)#include "base/strings/string_util.h" 115e3f23d412006dc4db4e659864679f29341e113fTorne (Richard Coles)#include "base/strings/stringprintf.h" 12868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)#include "base/threading/thread_checker.h" 13eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch#include "base/time/time.h" 14868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)#include "net/disk_cache/cache_util.h" 15868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)#include "net/disk_cache/file_lock.h" 16868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)#include "net/disk_cache/trace.h" 17868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) 18868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)using base::TimeTicks; 19868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) 20868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)namespace disk_cache { 21868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) 22868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)BlockFiles::BlockFiles(const base::FilePath& path) 23868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) : init_(false), zero_buffer_(NULL), path_(path) { 24868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)} 25868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) 26868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)BlockFiles::~BlockFiles() { 27868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) if (zero_buffer_) 28868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) delete[] zero_buffer_; 29868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) CloseFiles(); 30868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)} 31868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) 32868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)bool BlockFiles::Init(bool create_files) { 33868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) DCHECK(!init_); 34868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) if (init_) 35868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) return false; 36868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) 37868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) thread_checker_.reset(new base::ThreadChecker); 38868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) 39868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) block_files_.resize(kFirstAdditionalBlockFile); 40868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) for (int i = 0; i < kFirstAdditionalBlockFile; i++) { 41868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) if (create_files) 42868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) if (!CreateBlockFile(i, static_cast<FileType>(i + 1), true)) 43868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) return false; 44868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) 45868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) if (!OpenBlockFile(i)) 46868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) return false; 47868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) 48868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) // Walk this chain of files removing empty ones. 49868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) if (!RemoveEmptyFile(static_cast<FileType>(i + 1))) 50868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) return false; 51868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) } 52868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) 53868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) init_ = true; 54868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) return true; 55868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)} 56868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) 57868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)bool BlockFiles::CreateBlock(FileType block_type, int block_count, 58868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) Addr* block_address) { 59868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) DCHECK(thread_checker_->CalledOnValidThread()); 60868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) if (block_type < RANKINGS || block_type > BLOCK_4K || 61868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) block_count < 1 || block_count > 4) 62868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) return false; 63868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) if (!init_) 64868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) return false; 65868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) 66868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) MappedFile* file = FileForNewBlock(block_type, block_count); 67868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) if (!file) 68868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) return false; 69868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) 70868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) ScopedFlush flush(file); 71868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) BlockFileHeader* header = reinterpret_cast<BlockFileHeader*>(file->buffer()); 72868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) 73868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) int target_size = 0; 74868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) for (int i = block_count; i <= 4; i++) { 75868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) if (header->empty[i - 1]) { 76868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) target_size = i; 77868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) break; 78868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) } 79868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) } 80868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) 81868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) DCHECK(target_size); 82868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) int index; 83868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) if (!CreateMapBlock(target_size, block_count, header, &index)) 84868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) return false; 85868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) 86868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) Addr address(block_type, block_count, header->this_file, index); 87868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) block_address->set_value(address.value()); 88868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) Trace("CreateBlock 0x%x", address.value()); 89868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) return true; 90868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)} 91868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) 92868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)void BlockFiles::DeleteBlock(Addr address, bool deep) { 93868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) DCHECK(thread_checker_->CalledOnValidThread()); 94868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) if (!address.is_initialized() || address.is_separate_file()) 95868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) return; 96868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) 97868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) if (!zero_buffer_) { 98868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) zero_buffer_ = new char[Addr::BlockSizeForFileType(BLOCK_4K) * 4]; 99868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) memset(zero_buffer_, 0, Addr::BlockSizeForFileType(BLOCK_4K) * 4); 100868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) } 101868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) MappedFile* file = GetFile(address); 102868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) if (!file) 103868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) return; 104868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) 105868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) Trace("DeleteBlock 0x%x", address.value()); 106868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) 107868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) size_t size = address.BlockSize() * address.num_blocks(); 108868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) size_t offset = address.start_block() * address.BlockSize() + 109868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) kBlockHeaderSize; 110868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) if (deep) 111868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) file->Write(zero_buffer_, size, offset); 112868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) 113868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) BlockFileHeader* header = reinterpret_cast<BlockFileHeader*>(file->buffer()); 114868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) DeleteMapBlock(address.start_block(), address.num_blocks(), header); 115868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) file->Flush(); 116868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) 117868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) if (!header->num_entries) { 118868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) // This file is now empty. Let's try to delete it. 119868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) FileType type = Addr::RequiredFileType(header->entry_size); 120868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) if (Addr::BlockSizeForFileType(RANKINGS) == header->entry_size) 121868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) type = RANKINGS; 122868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) RemoveEmptyFile(type); // Ignore failures. 123868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) } 124868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)} 125868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) 126868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)void BlockFiles::CloseFiles() { 127868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) if (init_) { 128868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) DCHECK(thread_checker_->CalledOnValidThread()); 129868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) } 130868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) init_ = false; 131868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) for (unsigned int i = 0; i < block_files_.size(); i++) { 132868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) if (block_files_[i]) { 133868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) block_files_[i]->Release(); 134868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) block_files_[i] = NULL; 135868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) } 136868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) } 137868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) block_files_.clear(); 138868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)} 139868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) 140868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)void BlockFiles::ReportStats() { 141868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) DCHECK(thread_checker_->CalledOnValidThread()); 142868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) int used_blocks[kFirstAdditionalBlockFile]; 143868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) int load[kFirstAdditionalBlockFile]; 144868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) for (int i = 0; i < kFirstAdditionalBlockFile; i++) { 145868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) GetFileStats(i, &used_blocks[i], &load[i]); 146868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) } 147868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) UMA_HISTOGRAM_COUNTS("DiskCache.Blocks_0", used_blocks[0]); 148868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) UMA_HISTOGRAM_COUNTS("DiskCache.Blocks_1", used_blocks[1]); 149868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) UMA_HISTOGRAM_COUNTS("DiskCache.Blocks_2", used_blocks[2]); 150868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) UMA_HISTOGRAM_COUNTS("DiskCache.Blocks_3", used_blocks[3]); 151868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) 152868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) UMA_HISTOGRAM_ENUMERATION("DiskCache.BlockLoad_0", load[0], 101); 153868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) UMA_HISTOGRAM_ENUMERATION("DiskCache.BlockLoad_1", load[1], 101); 154868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) UMA_HISTOGRAM_ENUMERATION("DiskCache.BlockLoad_2", load[2], 101); 155868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) UMA_HISTOGRAM_ENUMERATION("DiskCache.BlockLoad_3", load[3], 101); 156868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)} 157868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) 158868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)bool BlockFiles::IsValid(Addr address) { 159868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)#ifdef NDEBUG 160868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) return true; 161868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)#else 162868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) if (!address.is_initialized() || address.is_separate_file()) 163868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) return false; 164868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) 165868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) MappedFile* file = GetFile(address); 166868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) if (!file) 167868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) return false; 168868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) 169868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) BlockFileHeader* header = reinterpret_cast<BlockFileHeader*>(file->buffer()); 170868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) bool rv = UsedMapBlock(address.start_block(), address.num_blocks(), header); 171868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) DCHECK(rv); 172868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) 173868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) static bool read_contents = false; 174868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) if (read_contents) { 175868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) scoped_ptr<char[]> buffer; 176868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) buffer.reset(new char[Addr::BlockSizeForFileType(BLOCK_4K) * 4]); 177868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) size_t size = address.BlockSize() * address.num_blocks(); 178868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) size_t offset = address.start_block() * address.BlockSize() + 179868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) kBlockHeaderSize; 180868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) bool ok = file->Read(buffer.get(), size, offset); 181868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) DCHECK(ok); 182868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) } 183868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) 184868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) return rv; 185868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)#endif 186868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)} 187868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) 188eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen MurdochMappedFile* BlockFiles::GetFile(Addr address) { 189eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch DCHECK(thread_checker_->CalledOnValidThread()); 190eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch DCHECK(block_files_.size() >= 4); 191eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch DCHECK(address.is_block_file() || !address.is_initialized()); 192eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch if (!address.is_initialized()) 193eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch return NULL; 194eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch 195eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch int file_index = address.FileNumber(); 196eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch if (static_cast<unsigned int>(file_index) >= block_files_.size() || 197eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch !block_files_[file_index]) { 198eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch // We need to open the file 199eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch if (!OpenBlockFile(file_index)) 200eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch return NULL; 201eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch } 202eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch DCHECK(block_files_.size() >= static_cast<unsigned int>(file_index)); 203eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch return block_files_[file_index]; 204eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch} 205eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch 206868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)bool BlockFiles::GrowBlockFile(MappedFile* file, BlockFileHeader* header) { 207868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) if (kMaxBlocks == header->max_entries) 208868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) return false; 209868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) 210868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) ScopedFlush flush(file); 211868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) DCHECK(!header->empty[3]); 212868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) int new_size = header->max_entries + 1024; 213868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) if (new_size > kMaxBlocks) 214868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) new_size = kMaxBlocks; 215868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) 216868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) int new_size_bytes = new_size * header->entry_size + sizeof(*header); 217868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) 218868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) if (!file->SetLength(new_size_bytes)) { 219868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) // Most likely we are trying to truncate the file, so the header is wrong. 220868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) if (header->updating < 10 && !FixBlockFileHeader(file)) { 221868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) // If we can't fix the file increase the lock guard so we'll pick it on 222868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) // the next start and replace it. 223868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) header->updating = 100; 224868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) return false; 225868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) } 226868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) return (header->max_entries >= new_size); 227868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) } 228868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) 229868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) FileLock lock(header); 230868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) header->empty[3] = (new_size - header->max_entries) / 4; // 4 blocks entries 231868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) header->max_entries = new_size; 232868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) 233868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) return true; 234868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)} 235868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) 236868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)MappedFile* BlockFiles::FileForNewBlock(FileType block_type, int block_count) { 237868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) COMPILE_ASSERT(RANKINGS == 1, invalid_file_type); 238868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) MappedFile* file = block_files_[block_type - 1]; 239868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) BlockFileHeader* header = reinterpret_cast<BlockFileHeader*>(file->buffer()); 240868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) 241868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) TimeTicks start = TimeTicks::Now(); 242868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) while (NeedToGrowBlockFile(header, block_count)) { 243868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) if (kMaxBlocks == header->max_entries) { 244868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) file = NextFile(file); 245868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) if (!file) 246868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) return NULL; 247868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) header = reinterpret_cast<BlockFileHeader*>(file->buffer()); 248868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) continue; 249868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) } 250868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) 251868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) if (!GrowBlockFile(file, header)) 252868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) return NULL; 253868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) break; 254868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) } 255868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) HISTOGRAM_TIMES("DiskCache.GetFileForNewBlock", TimeTicks::Now() - start); 256868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) return file; 257868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)} 258868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) 259868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)// Note that we expect to be called outside of a FileLock... however, we cannot 260868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)// DCHECK on header->updating because we may be fixing a crash. 261868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)bool BlockFiles::FixBlockFileHeader(MappedFile* file) { 262868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) ScopedFlush flush(file); 263868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) BlockFileHeader* header = reinterpret_cast<BlockFileHeader*>(file->buffer()); 264868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) int file_size = static_cast<int>(file->GetLength()); 265868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) if (file_size < static_cast<int>(sizeof(*header))) 266868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) return false; // file_size > 2GB is also an error. 267868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) 268868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) const int kMinBlockSize = 36; 269868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) const int kMaxBlockSize = 4096; 270868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) if (header->entry_size < kMinBlockSize || 271868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) header->entry_size > kMaxBlockSize || header->num_entries < 0) 272868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) return false; 273868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) 274868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) // Make sure that we survive crashes. 275868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) header->updating = 1; 276868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) int expected = header->entry_size * header->max_entries + sizeof(*header); 277868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) if (file_size != expected) { 278868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) int max_expected = header->entry_size * kMaxBlocks + sizeof(*header); 279868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) if (file_size < expected || header->empty[3] || file_size > max_expected) { 280868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) NOTREACHED(); 281868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) LOG(ERROR) << "Unexpected file size"; 282868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) return false; 283868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) } 284868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) // We were in the middle of growing the file. 285868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) int num_entries = (file_size - sizeof(*header)) / header->entry_size; 286868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) header->max_entries = num_entries; 287868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) } 288868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) 289868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) FixAllocationCounters(header); 290868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) int empty_blocks = EmptyBlocks(header); 291868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) if (empty_blocks + header->num_entries > header->max_entries) 292868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) header->num_entries = header->max_entries - empty_blocks; 293868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) 294868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) if (!ValidateCounters(header)) 295868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) return false; 296868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) 297868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) header->updating = 0; 298868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) return true; 299868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)} 300868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) 301868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)// We are interested in the total number of blocks used by this file type, and 302868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)// the max number of blocks that we can store (reported as the percentage of 303868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)// used blocks). In order to find out the number of used blocks, we have to 304868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)// substract the empty blocks from the total blocks for each file in the chain. 305868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)void BlockFiles::GetFileStats(int index, int* used_count, int* load) { 306868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) int max_blocks = 0; 307868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) *used_count = 0; 308868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) *load = 0; 309868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) for (;;) { 310868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) if (!block_files_[index] && !OpenBlockFile(index)) 311868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) return; 312868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) 313868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) BlockFileHeader* header = 314868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) reinterpret_cast<BlockFileHeader*>(block_files_[index]->buffer()); 315868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) 316868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) max_blocks += header->max_entries; 317868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) int used = header->max_entries; 318868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) for (int i = 0; i < 4; i++) { 319868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) used -= header->empty[i] * (i + 1); 320868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) DCHECK_GE(used, 0); 321868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) } 322868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) *used_count += used; 323868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) 324868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) if (!header->next_file) 325868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) break; 326868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) index = header->next_file; 327868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) } 328868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) if (max_blocks) 329868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) *load = *used_count * 100 / max_blocks; 330868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)} 331868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) 332868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)} // namespace disk_cache 333