Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(267)

Side by Side Diff: net/disk_cache/block_files.cc

Issue 15203004: Disk cache: Reference CL for the implementation of file format version 3. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src/
Patch Set: IndexTable review Created 7 years ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
« no previous file with comments | « net/disk_cache/block_files.h ('k') | net/disk_cache/block_files_unittest.cc » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. 1 // Copyright (c) 2012 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/block_files.h" 5 #include "net/disk_cache/block_files.h"
6 6
7 #include "base/atomicops.h" 7 #include "base/atomicops.h"
8 #include "base/file_util.h" 8 #include "base/file_util.h"
9 #include "base/metrics/histogram.h" 9 #include "base/metrics/histogram.h"
10 #include "base/string_util.h" 10 #include "base/string_util.h"
11 #include "base/stringprintf.h" 11 #include "base/stringprintf.h"
12 #include "base/threading/thread_checker.h" 12 #include "base/threading/thread_checker.h"
13 #include "base/time.h" 13 #include "base/time.h"
14 #include "net/disk_cache/cache_util.h" 14 #include "net/disk_cache/cache_util.h"
15 #include "net/disk_cache/file_lock.h" 15 #include "net/disk_cache/file_lock.h"
16 #include "net/disk_cache/trace.h" 16 #include "net/disk_cache/trace.h"
17 17
18 using base::TimeTicks; 18 using base::TimeTicks;
19 19
20 namespace { 20 namespace {
21 21
22 const char* kBlockName = "data_"; 22 const char kBlockName[] = "data_";
23 const char kBlockDataPostfix[] = "_d";
23 24
24 // This array is used to perform a fast lookup of the nibble bit pattern to the 25 // This array is used to perform a fast lookup of the nibble bit pattern to the
25 // type of entry that can be stored there (number of consecutive blocks). 26 // type of entry that can be stored there (number of consecutive blocks).
26 const char s_types[16] = {4, 3, 2, 2, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0}; 27 const char s_types[16] = {4, 3, 2, 2, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0};
27 28
28 // Returns the type of block (number of consecutive blocks that can be stored) 29 // Returns the type of block (number of consecutive blocks that can be stored)
29 // for a given nibble of the bitmap. 30 // for a given nibble of the bitmap.
30 inline int GetMapBlockType(uint8 value) { 31 inline int GetMapBlockType(uint8 value) {
31 value &= 0xf; 32 value &= 0xf;
32 return s_types[value]; 33 return s_types[value];
33 } 34 }
34 35
35 void FixAllocationCounters(disk_cache::BlockFileHeader* header); 36 } // namespace
36 37
37 // Creates a new entry on the allocation map, updating the apropriate counters. 38 namespace disk_cache {
38 // target is the type of block to use (number of empty blocks), and size is the 39
39 // actual number of blocks to use. 40 BlockHeader::BlockHeader() : header_(NULL) {
40 bool CreateMapBlock(int target, int size, disk_cache::BlockFileHeader* header, 41 }
41 int* index) { 42
42 if (target <= 0 || target > disk_cache::kMaxNumBlocks || 43 BlockHeader::BlockHeader(BlockFileHeader* header) : header_(header) {
43 size <= 0 || size > disk_cache::kMaxNumBlocks) { 44 }
45
46 BlockHeader::BlockHeader(MappedFile* file)
47 : header_(reinterpret_cast<BlockFileHeader*>(file->buffer())) {
48 }
49
50 BlockHeader::BlockHeader(const BlockHeader& other) : header_(other.header_) {
51 }
52
53 BlockHeader::~BlockHeader() {
54 }
55
56 bool BlockHeader::CreateMapBlock(int size, int* index) {
57 DCHECK(size > 0 && size <= kMaxNumBlocks);
58 int target = 0;
59 for (int i = size; i <= kMaxNumBlocks; i++) {
60 if (header_->empty[i - 1]) {
61 target = i;
62 break;
63 }
64 }
65
66 if (!target) {
44 NOTREACHED(); 67 NOTREACHED();
45 return false; 68 return false;
46 } 69 }
47 70
48 TimeTicks start = TimeTicks::Now(); 71 TimeTicks start = TimeTicks::Now();
49 // We are going to process the map on 32-block chunks (32 bits), and on every 72 // We are going to process the map on 32-block chunks (32 bits), and on every
50 // chunk, iterate through the 8 nibbles where the new block can be located. 73 // chunk, iterate through the 8 nibbles where the new block can be located.
51 int current = header->hints[target - 1]; 74 int current = header_->hints[target - 1];
52 for (int i = 0; i < header->max_entries / 32; i++, current++) { 75 for (int i = 0; i < header_->max_entries / 32; i++, current++) {
53 if (current == header->max_entries / 32) 76 if (current == header_->max_entries / 32)
54 current = 0; 77 current = 0;
55 uint32 map_block = header->allocation_map[current]; 78 uint32 map_block = header_->allocation_map[current];
56 79
57 for (int j = 0; j < 8; j++, map_block >>= 4) { 80 for (int j = 0; j < 8; j++, map_block >>= 4) {
58 if (GetMapBlockType(map_block) != target) 81 if (GetMapBlockType(map_block) != target)
59 continue; 82 continue;
60 83
61 disk_cache::FileLock lock(header); 84 disk_cache::FileLock lock(header_);
62 int index_offset = j * 4 + 4 - target; 85 int index_offset = j * 4 + 4 - target;
63 *index = current * 32 + index_offset; 86 *index = current * 32 + index_offset;
64 DCHECK_EQ(*index / 4, (*index + size - 1) / 4); 87 DCHECK_EQ(*index / 4, (*index + size - 1) / 4);
65 uint32 to_add = ((1 << size) - 1) << index_offset; 88 uint32 to_add = ((1 << size) - 1) << index_offset;
66 header->num_entries++; 89 header_->num_entries++;
67 90
68 // Note that there is no race in the normal sense here, but if we enforce 91 // Note that there is no race in the normal sense here, but if we enforce
69 // the order of memory accesses between num_entries and allocation_map, we 92 // the order of memory accesses between num_entries and allocation_map, we
70 // can assert that even if we crash here, num_entries will never be less 93 // can assert that even if we crash here, num_entries will never be less
71 // than the actual number of used blocks. 94 // than the actual number of used blocks.
72 base::subtle::MemoryBarrier(); 95 base::subtle::MemoryBarrier();
73 header->allocation_map[current] |= to_add; 96 header_->allocation_map[current] |= to_add;
74 97
75 header->hints[target - 1] = current; 98 header_->hints[target - 1] = current;
76 header->empty[target - 1]--; 99 header_->empty[target - 1]--;
77 DCHECK_GE(header->empty[target - 1], 0); 100 DCHECK_GE(header_->empty[target - 1], 0);
78 if (target != size) { 101 if (target != size) {
79 header->empty[target - size - 1]++; 102 header_->empty[target - size - 1]++;
80 } 103 }
81 HISTOGRAM_TIMES("DiskCache.CreateBlock", TimeTicks::Now() - start); 104 HISTOGRAM_TIMES("DiskCache.CreateBlock", TimeTicks::Now() - start);
82 return true; 105 return true;
83 } 106 }
84 } 107 }
85 108
86 // It is possible to have an undetected corruption (for example when the OS 109 // It is possible to have an undetected corruption (for example when the OS
87 // crashes), fix it here. 110 // crashes), fix it here.
88 LOG(ERROR) << "Failing CreateMapBlock"; 111 LOG(ERROR) << "Failing CreateMapBlock";
89 FixAllocationCounters(header); 112 FixAllocationCounters();
90 return false; 113 return false;
91 } 114 }
92 115
93 // Deletes the block pointed by index from allocation_map, and updates the 116 void BlockHeader::DeleteMapBlock(int index, int size) {
94 // relevant counters on the header. 117 if (size < 0 || size > kMaxNumBlocks) {
95 void DeleteMapBlock(int index, int size, disk_cache::BlockFileHeader* header) {
96 if (size < 0 || size > disk_cache::kMaxNumBlocks) {
97 NOTREACHED(); 118 NOTREACHED();
98 return; 119 return;
99 } 120 }
100 TimeTicks start = TimeTicks::Now(); 121 TimeTicks start = TimeTicks::Now();
101 int byte_index = index / 8; 122 int byte_index = index / 8;
102 uint8* byte_map = reinterpret_cast<uint8*>(header->allocation_map); 123 uint8* byte_map = reinterpret_cast<uint8*>(header_->allocation_map);
103 uint8 map_block = byte_map[byte_index]; 124 uint8 map_block = byte_map[byte_index];
104 125
105 if (index % 8 >= 4) 126 if (index % 8 >= 4)
106 map_block >>= 4; 127 map_block >>= 4;
107 128
108 // See what type of block will be availabe after we delete this one. 129 // See what type of block will be available after we delete this one.
109 int bits_at_end = 4 - size - index % 4; 130 int bits_at_end = 4 - size - index % 4;
110 uint8 end_mask = (0xf << (4 - bits_at_end)) & 0xf; 131 uint8 end_mask = (0xf << (4 - bits_at_end)) & 0xf;
111 bool update_counters = (map_block & end_mask) == 0; 132 bool update_counters = (map_block & end_mask) == 0;
112 uint8 new_value = map_block & ~(((1 << size) - 1) << (index % 4)); 133 uint8 new_value = map_block & ~(((1 << size) - 1) << (index % 4));
113 int new_type = GetMapBlockType(new_value); 134 int new_type = GetMapBlockType(new_value);
114 135
115 disk_cache::FileLock lock(header); 136 disk_cache::FileLock lock(header_);
116 DCHECK((((1 << size) - 1) << (index % 8)) < 0x100); 137 DCHECK((((1 << size) - 1) << (index % 8)) < 0x100);
117 uint8 to_clear = ((1 << size) - 1) << (index % 8); 138 uint8 to_clear = ((1 << size) - 1) << (index % 8);
118 DCHECK((byte_map[byte_index] & to_clear) == to_clear); 139 DCHECK((byte_map[byte_index] & to_clear) == to_clear);
119 byte_map[byte_index] &= ~to_clear; 140 byte_map[byte_index] &= ~to_clear;
120 141
121 if (update_counters) { 142 if (update_counters) {
122 if (bits_at_end) 143 if (bits_at_end)
123 header->empty[bits_at_end - 1]--; 144 header_->empty[bits_at_end - 1]--;
124 header->empty[new_type - 1]++; 145 header_->empty[new_type - 1]++;
125 DCHECK_GE(header->empty[bits_at_end - 1], 0); 146 DCHECK_GE(header_->empty[bits_at_end - 1], 0);
126 } 147 }
127 base::subtle::MemoryBarrier(); 148 base::subtle::MemoryBarrier();
128 header->num_entries--; 149 header_->num_entries--;
129 DCHECK_GE(header->num_entries, 0); 150 DCHECK_GE(header_->num_entries, 0);
130 HISTOGRAM_TIMES("DiskCache.DeleteBlock", TimeTicks::Now() - start); 151 HISTOGRAM_TIMES("DiskCache.DeleteBlock", TimeTicks::Now() - start);
131 } 152 }
132 153
133 #ifndef NDEBUG 154 // Note that this is a simplified version of DeleteMapBlock().
134 // Returns true if the specified block is used. Note that this is a simplified 155 bool BlockHeader::UsedMapBlock(int index, int size) {
135 // version of DeleteMapBlock(). 156 if (size < 0 || size > kMaxNumBlocks) {
136 bool UsedMapBlock(int index, int size, disk_cache::BlockFileHeader* header) {
137 if (size < 0 || size > disk_cache::kMaxNumBlocks) {
138 NOTREACHED(); 157 NOTREACHED();
139 return false; 158 return false;
140 } 159 }
141 int byte_index = index / 8; 160 int byte_index = index / 8;
142 uint8* byte_map = reinterpret_cast<uint8*>(header->allocation_map); 161 uint8* byte_map = reinterpret_cast<uint8*>(header_->allocation_map);
143 uint8 map_block = byte_map[byte_index]; 162 uint8 map_block = byte_map[byte_index];
144 163
145 if (index % 8 >= 4) 164 if (index % 8 >= 4)
146 map_block >>= 4; 165 map_block >>= 4;
147 166
148 DCHECK((((1 << size) - 1) << (index % 8)) < 0x100); 167 DCHECK((((1 << size) - 1) << (index % 8)) < 0x100);
149 uint8 to_clear = ((1 << size) - 1) << (index % 8); 168 uint8 to_clear = ((1 << size) - 1) << (index % 8);
150 return ((byte_map[byte_index] & to_clear) == to_clear); 169 return ((byte_map[byte_index] & to_clear) == to_clear);
151 } 170 }
152 #endif // NDEBUG
153 171
154 // Restores the "empty counters" and allocation hints. 172 void BlockHeader::FixAllocationCounters() {
155 void FixAllocationCounters(disk_cache::BlockFileHeader* header) { 173 for (int i = 0; i < kMaxNumBlocks; i++) {
156 for (int i = 0; i < disk_cache::kMaxNumBlocks; i++) { 174 header_->hints[i] = 0;
157 header->hints[i] = 0; 175 header_->empty[i] = 0;
158 header->empty[i] = 0;
159 } 176 }
160 177
161 for (int i = 0; i < header->max_entries / 32; i++) { 178 for (int i = 0; i < header_->max_entries / 32; i++) {
162 uint32 map_block = header->allocation_map[i]; 179 uint32 map_block = header_->allocation_map[i];
163 180
164 for (int j = 0; j < 8; j++, map_block >>= 4) { 181 for (int j = 0; j < 8; j++, map_block >>= 4) {
165 int type = GetMapBlockType(map_block); 182 int type = GetMapBlockType(map_block);
166 if (type) 183 if (type)
167 header->empty[type -1]++; 184 header_->empty[type -1]++;
168 } 185 }
169 } 186 }
170 } 187 }
171 188
172 // Returns true if the current block file should not be used as-is to store more 189 bool BlockHeader::NeedToGrowBlockFile(int block_count) const {
173 // records. |block_count| is the number of blocks to allocate.
174 bool NeedToGrowBlockFile(const disk_cache::BlockFileHeader* header,
175 int block_count) {
176 bool have_space = false; 190 bool have_space = false;
177 int empty_blocks = 0; 191 int empty_blocks = 0;
178 for (int i = 0; i < disk_cache::kMaxNumBlocks; i++) { 192 for (int i = 0; i < kMaxNumBlocks; i++) {
179 empty_blocks += header->empty[i] * (i + 1); 193 empty_blocks += header_->empty[i] * (i + 1);
180 if (i >= block_count - 1 && header->empty[i]) 194 if (i >= block_count - 1 && header_->empty[i])
181 have_space = true; 195 have_space = true;
182 } 196 }
183 197
184 if (header->next_file && (empty_blocks < disk_cache::kMaxBlocks / 10)) { 198 if (header_->next_file && (empty_blocks < kMaxBlocks / 10)) {
185 // This file is almost full but we already created another one, don't use 199 // This file is almost full but we already created another one, don't use
186 // this file yet so that it is easier to find empty blocks when we start 200 // this file yet so that it is easier to find empty blocks when we start
187 // using this file again. 201 // using this file again.
188 return true; 202 return true;
189 } 203 }
190 return !have_space; 204 return !have_space;
191 } 205 }
192 206
193 // Returns the number of empty blocks for this file. 207 bool BlockHeader::CanAllocate(int block_count) const {
194 int EmptyBlocks(const disk_cache::BlockFileHeader* header) { 208 DCHECK_GT(block_count, 0);
209 for (int i = block_count - 1; i < kMaxNumBlocks; i++) {
210 if (header_->empty[i])
211 return true;
212 }
213
214 return false;
215 }
216
217 int BlockHeader::EmptyBlocks() const {
195 int empty_blocks = 0; 218 int empty_blocks = 0;
196 for (int i = 0; i < disk_cache::kMaxNumBlocks; i++) { 219 for (int i = 0; i < kMaxNumBlocks; i++) {
197 empty_blocks += header->empty[i] * (i + 1); 220 empty_blocks += header_->empty[i] * (i + 1);
198 if (header->empty[i] < 0) 221 if (header_->empty[i] < 0)
199 return false; 222 return 0;
200 } 223 }
201 return empty_blocks; 224 return empty_blocks;
202 } 225 }
203 226
204 // Returns true if the counters look OK. 227 int BlockHeader::MinimumAllocations() const {
205 bool ValidateCounters(const disk_cache::BlockFileHeader* header) { 228 return header_->empty[kMaxNumBlocks - 1];
206 if (header->max_entries < 0 || header->max_entries > disk_cache::kMaxBlocks || 229 }
207 header->num_entries < 0) 230
231 int BlockHeader::Capacity() const {
232 return header_->max_entries;
233 }
234
235 bool BlockHeader::ValidateCounters() const {
236 if (header_->max_entries < 0 || header_->max_entries > kMaxBlocks ||
237 header_->num_entries < 0)
208 return false; 238 return false;
209 239
210 int empty_blocks = EmptyBlocks(header); 240 int empty_blocks = EmptyBlocks();
211 if (empty_blocks + header->num_entries > header->max_entries) 241 if (empty_blocks + header_->num_entries > header_->max_entries)
212 return false; 242 return false;
213 243
214 return true; 244 return true;
215 } 245 }
216 246
217 } // namespace 247 int BlockHeader::FileId() const {
248 return header_->this_file;
249 }
218 250
219 namespace disk_cache { 251 int BlockHeader::NextFileId() const {
252 return header_->next_file;
253 }
254
255 BlockFileHeader* BlockHeader::Header() {
256 return header_;
257 }
258
259 // ------------------------------------------------------------------------
220 260
221 BlockFiles::BlockFiles(const base::FilePath& path) 261 BlockFiles::BlockFiles(const base::FilePath& path)
222 : init_(false), zero_buffer_(NULL), path_(path) { 262 : init_(false),
263 small_steps_(false),
264 data_offset_(0),
265 zero_buffer_(NULL),
266 path_(path) {
223 } 267 }
224 268
225 BlockFiles::~BlockFiles() { 269 BlockFiles::~BlockFiles() {
226 if (zero_buffer_) 270 if (zero_buffer_)
227 delete[] zero_buffer_; 271 delete[] zero_buffer_;
228 CloseFiles(); 272 CloseFiles();
229 } 273 }
230 274
231 bool BlockFiles::Init(bool create_files) { 275 bool BlockFiles::Init(bool create_files, int num_files) {
232 DCHECK(!init_); 276 DCHECK(!init_);
233 if (init_) 277 if (init_)
234 return false; 278 return false;
235 279
280 data_offset_ = num_files > kFirstAdditionalBlockFile ? 0 : kBlockHeaderSize;
236 thread_checker_.reset(new base::ThreadChecker); 281 thread_checker_.reset(new base::ThreadChecker);
237 282
238 block_files_.resize(kFirstAdditionalBlockFile); 283 block_headers_.resize(num_files);
239 for (int i = 0; i < kFirstAdditionalBlockFile; i++) { 284 block_data_.resize(num_files);
285 for (int i = 0; i < num_files; i++) {
240 if (create_files) 286 if (create_files)
241 if (!CreateBlockFile(i, static_cast<FileType>(i + 1), true)) 287 if (!CreateBlockFile(i, static_cast<FileType>(i + 1), true))
242 return false; 288 return false;
243 289
244 if (!OpenBlockFile(i)) 290 if (!OpenBlockFile(i))
245 return false; 291 return false;
246 292
247 // Walk this chain of files removing empty ones. 293 // Walk this chain of files removing empty ones.
248 if (!RemoveEmptyFile(static_cast<FileType>(i + 1))) 294 if (!RemoveEmptyFile(static_cast<FileType>(i + 1)))
249 return false; 295 return false;
296
297 if (!data_offset_ && !PreallocateSpace(static_cast<FileType>(i + 1)))
298 return false;
250 } 299 }
251 300
252 init_ = true; 301 init_ = true;
253 return true; 302 return true;
254 } 303 }
255 304
305 void BlockFiles::GetBitmaps(int num_files, BlockFilesBitmaps* bitmaps) {
306 bitmaps->clear();
307 bitmaps->resize(num_files);
308
309 for (int i = 0; i < num_files; i++) {
310 // Only the block_file argument is relevant for what we want.
311 Addr address(BLOCK_256, 1, i, 0);
312 BlockHeader header(GetFileHeader(address));
313 (*bitmaps)[i] = header;
314 }
315 }
316
256 MappedFile* BlockFiles::GetFile(Addr address) { 317 MappedFile* BlockFiles::GetFile(Addr address) {
257 DCHECK(thread_checker_->CalledOnValidThread()); 318 int file_index = GetFileIndex(address);
258 DCHECK(block_files_.size() >= 4); 319 if (file_index < 0)
259 DCHECK(address.is_block_file() || !address.is_initialized());
260 if (!address.is_initialized())
261 return NULL; 320 return NULL;
262 321
263 int file_index = address.FileNumber(); 322 if (data_offset_)
264 if (static_cast<unsigned int>(file_index) >= block_files_.size() || 323 return block_headers_[file_index];
265 !block_files_[file_index]) { 324
266 // We need to open the file 325 DCHECK(block_data_.size() >= static_cast<unsigned int>(file_index));
267 if (!OpenBlockFile(file_index)) 326 return block_data_[file_index];
268 return NULL;
269 }
270 DCHECK(block_files_.size() >= static_cast<unsigned int>(file_index));
271 return block_files_[file_index];
272 } 327 }
273 328
274 bool BlockFiles::CreateBlock(FileType block_type, int block_count, 329 bool BlockFiles::CreateBlock(FileType block_type, int block_count,
275 Addr* block_address) { 330 Addr* block_address) {
276 DCHECK(thread_checker_->CalledOnValidThread()); 331 DCHECK(thread_checker_->CalledOnValidThread());
277 if (block_type < RANKINGS || block_type > BLOCK_4K || 332 DCHECK_NE(block_type, EXTERNAL);
278 block_count < 1 || block_count > 4) 333 DCHECK_NE(block_type, BLOCK_FILES);
334 DCHECK_NE(block_type, BLOCK_ENTRIES);
335 DCHECK_NE(block_type, BLOCK_EVICTED);
336 if (block_count < 1 || block_count > kMaxNumBlocks)
279 return false; 337 return false;
338
280 if (!init_) 339 if (!init_)
281 return false; 340 return false;
282 341
283 MappedFile* file = FileForNewBlock(block_type, block_count); 342 MappedFile* file = FileForNewBlock(block_type, block_count);
284 if (!file) 343 if (!file)
285 return false; 344 return false;
286 345
287 ScopedFlush flush(file); 346 ScopedFlush flush(file);
288 BlockFileHeader* header = reinterpret_cast<BlockFileHeader*>(file->buffer()); 347 BlockHeader file_header(file);
289 348
290 int target_size = 0;
291 for (int i = block_count; i <= 4; i++) {
292 if (header->empty[i - 1]) {
293 target_size = i;
294 break;
295 }
296 }
297
298 DCHECK(target_size);
299 int index; 349 int index;
300 if (!CreateMapBlock(target_size, block_count, header, &index)) 350 if (!file_header.CreateMapBlock(block_count, &index))
301 return false; 351 return false;
302 352
303 Addr address(block_type, block_count, header->this_file, index); 353 Addr address(block_type, block_count, file_header.FileId(), index);
304 block_address->set_value(address.value()); 354 block_address->set_value(address.value());
305 Trace("CreateBlock 0x%x", address.value()); 355 Trace("CreateBlock 0x%x", address.value());
306 return true; 356 return true;
307 } 357 }
308 358
309 void BlockFiles::DeleteBlock(Addr address, bool deep) { 359 void BlockFiles::DeleteBlock(Addr address, bool deep) {
310 DCHECK(thread_checker_->CalledOnValidThread()); 360 DCHECK(thread_checker_->CalledOnValidThread());
311 if (!address.is_initialized() || address.is_separate_file()) 361 if (!address.is_initialized() || address.is_separate_file())
312 return; 362 return;
313 363
314 if (!zero_buffer_) { 364 if (!zero_buffer_) {
315 zero_buffer_ = new char[Addr::BlockSizeForFileType(BLOCK_4K) * 4]; 365 zero_buffer_ = new char[Addr::BlockSizeForFileType(BLOCK_4K) * 4];
316 memset(zero_buffer_, 0, Addr::BlockSizeForFileType(BLOCK_4K) * 4); 366 memset(zero_buffer_, 0, Addr::BlockSizeForFileType(BLOCK_4K) * 4);
317 } 367 }
318 MappedFile* file = GetFile(address); 368 MappedFile* file = GetFile(address);
319 if (!file) 369 if (!file)
320 return; 370 return;
321 371
322 Trace("DeleteBlock 0x%x", address.value()); 372 Trace("DeleteBlock 0x%x", address.value());
323 373
324 size_t size = address.BlockSize() * address.num_blocks(); 374 size_t size = address.BlockSize() * address.num_blocks();
325 size_t offset = address.start_block() * address.BlockSize() + 375 size_t offset = address.start_block() * address.BlockSize() + data_offset_;
326 kBlockHeaderSize;
327 if (deep) 376 if (deep)
328 file->Write(zero_buffer_, size, offset); 377 file->Write(zero_buffer_, size, offset);
329 378
330 BlockFileHeader* header = reinterpret_cast<BlockFileHeader*>(file->buffer()); 379 BlockHeader file_header(GetFileHeader(address));
331 DeleteMapBlock(address.start_block(), address.num_blocks(), header); 380 file_header.DeleteMapBlock(address.start_block(), address.num_blocks());
332 file->Flush(); 381 file->Flush();
333 382
334 if (!header->num_entries) { 383 if (!file_header.Header()->num_entries) {
335 // This file is now empty. Let's try to delete it. 384 // This file is now empty. Let's try to delete it.
336 FileType type = Addr::RequiredFileType(header->entry_size); 385 FileType type = Addr::RequiredFileType(file_header.Header()->entry_size);
337 if (Addr::BlockSizeForFileType(RANKINGS) == header->entry_size) 386 if (Addr::BlockSizeForFileType(RANKINGS) ==
387 file_header.Header()->entry_size) {
338 type = RANKINGS; 388 type = RANKINGS;
389 }
339 RemoveEmptyFile(type); // Ignore failures. 390 RemoveEmptyFile(type); // Ignore failures.
340 } 391 }
341 } 392 }
342 393
343 void BlockFiles::CloseFiles() { 394 void BlockFiles::CloseFiles() {
344 if (init_) { 395 if (init_) {
345 DCHECK(thread_checker_->CalledOnValidThread()); 396 DCHECK(thread_checker_->CalledOnValidThread());
346 } 397 }
347 init_ = false; 398 init_ = false;
348 for (unsigned int i = 0; i < block_files_.size(); i++) { 399 for (unsigned int i = 0; i < block_headers_.size(); i++) {
349 if (block_files_[i]) { 400 if (block_headers_[i]) {
350 block_files_[i]->Release(); 401 block_headers_[i]->Release();
351 block_files_[i] = NULL; 402 block_headers_[i] = NULL;
352 } 403 }
353 } 404 }
354 block_files_.clear(); 405 for (unsigned int i = 0; i < block_data_.size(); i++) {
406 if (block_data_[i]) {
407 block_data_[i]->Release();
408 block_data_[i] = NULL;
409 }
410 }
411 block_headers_.clear();
412 block_data_.clear();
355 } 413 }
356 414
357 void BlockFiles::ReportStats() { 415 void BlockFiles::ReportStats() {
358 DCHECK(thread_checker_->CalledOnValidThread()); 416 DCHECK(thread_checker_->CalledOnValidThread());
359 int used_blocks[kFirstAdditionalBlockFile]; 417 int used_blocks[kFirstAdditionalBlockFile];
360 int load[kFirstAdditionalBlockFile]; 418 int load[kFirstAdditionalBlockFile];
361 for (int i = 0; i < kFirstAdditionalBlockFile; i++) { 419 for (int i = 0; i < kFirstAdditionalBlockFile; i++) {
362 GetFileStats(i, &used_blocks[i], &load[i]); 420 GetFileStats(i, &used_blocks[i], &load[i]);
363 } 421 }
364 UMA_HISTOGRAM_COUNTS("DiskCache.Blocks_0", used_blocks[0]); 422 UMA_HISTOGRAM_COUNTS("DiskCache.Blocks_0", used_blocks[0]);
365 UMA_HISTOGRAM_COUNTS("DiskCache.Blocks_1", used_blocks[1]); 423 UMA_HISTOGRAM_COUNTS("DiskCache.Blocks_1", used_blocks[1]);
366 UMA_HISTOGRAM_COUNTS("DiskCache.Blocks_2", used_blocks[2]); 424 UMA_HISTOGRAM_COUNTS("DiskCache.Blocks_2", used_blocks[2]);
367 UMA_HISTOGRAM_COUNTS("DiskCache.Blocks_3", used_blocks[3]); 425 UMA_HISTOGRAM_COUNTS("DiskCache.Blocks_3", used_blocks[3]);
368 426
369 UMA_HISTOGRAM_ENUMERATION("DiskCache.BlockLoad_0", load[0], 101); 427 UMA_HISTOGRAM_ENUMERATION("DiskCache.BlockLoad_0", load[0], 101);
370 UMA_HISTOGRAM_ENUMERATION("DiskCache.BlockLoad_1", load[1], 101); 428 UMA_HISTOGRAM_ENUMERATION("DiskCache.BlockLoad_1", load[1], 101);
371 UMA_HISTOGRAM_ENUMERATION("DiskCache.BlockLoad_2", load[2], 101); 429 UMA_HISTOGRAM_ENUMERATION("DiskCache.BlockLoad_2", load[2], 101);
372 UMA_HISTOGRAM_ENUMERATION("DiskCache.BlockLoad_3", load[3], 101); 430 UMA_HISTOGRAM_ENUMERATION("DiskCache.BlockLoad_3", load[3], 101);
373 } 431 }
374 432
375 bool BlockFiles::IsValid(Addr address) { 433 bool BlockFiles::IsValid(Addr address) {
376 #ifdef NDEBUG 434 #ifdef NDEBUG
377 return true; 435 return true;
378 #else 436 #else
379 if (!address.is_initialized() || address.is_separate_file()) 437 if (!address.is_initialized() || address.is_separate_file())
380 return false; 438 return false;
381 439
382 MappedFile* file = GetFile(address); 440 MappedFile* file = GetFileHeader(address);
383 if (!file) 441 if (!file)
384 return false; 442 return false;
385 443
386 BlockFileHeader* header = reinterpret_cast<BlockFileHeader*>(file->buffer()); 444 BlockHeader header(file);
387 bool rv = UsedMapBlock(address.start_block(), address.num_blocks(), header); 445 bool rv = header.UsedMapBlock(address.start_block(), address.num_blocks());
388 DCHECK(rv); 446 DCHECK(rv);
389
390 static bool read_contents = false;
391 if (read_contents) {
392 scoped_ptr<char[]> buffer;
393 buffer.reset(new char[Addr::BlockSizeForFileType(BLOCK_4K) * 4]);
394 size_t size = address.BlockSize() * address.num_blocks();
395 size_t offset = address.start_block() * address.BlockSize() +
396 kBlockHeaderSize;
397 bool ok = file->Read(buffer.get(), size, offset);
398 DCHECK(ok);
399 }
400
401 return rv; 447 return rv;
402 #endif 448 #endif
403 } 449 }
404 450
405 bool BlockFiles::CreateBlockFile(int index, FileType file_type, bool force) { 451 bool BlockFiles::CreateBlockFile(int index, FileType file_type, bool force) {
406 base::FilePath name = Name(index); 452 base::FilePath name = HeaderName(index);
407 int flags = 453 int flags =
408 force ? base::PLATFORM_FILE_CREATE_ALWAYS : base::PLATFORM_FILE_CREATE; 454 force ? base::PLATFORM_FILE_CREATE_ALWAYS : base::PLATFORM_FILE_CREATE;
409 flags |= base::PLATFORM_FILE_WRITE | base::PLATFORM_FILE_EXCLUSIVE_WRITE; 455 flags |= base::PLATFORM_FILE_WRITE | base::PLATFORM_FILE_EXCLUSIVE_WRITE;
410 456
411 scoped_refptr<File> file(new File( 457 scoped_refptr<File> file(new File(
412 base::CreatePlatformFile(name, flags, NULL, NULL))); 458 base::CreatePlatformFile(name, flags, NULL, NULL)));
413 if (!file->IsValid()) 459 if (!file->IsValid())
414 return false; 460 return false;
415 461
416 BlockFileHeader header; 462 BlockFileHeader header;
463 memset(&header, 0, sizeof(header));
464 header.magic = kBlockMagic;
465 header.version = data_offset_ ? kBlockVersion2 : kBlockCurrentVersion;
417 header.entry_size = Addr::BlockSizeForFileType(file_type); 466 header.entry_size = Addr::BlockSizeForFileType(file_type);
418 header.this_file = static_cast<int16>(index); 467 header.this_file = static_cast<int16>(index);
419 DCHECK(index <= kint16max && index >= 0); 468 DCHECK(index <= kint16max && index >= 0);
420 469
421 return file->Write(&header, sizeof(header), 0); 470 if (!file->Write(&header, sizeof(header), 0))
471 return false;
472
473 if (header.version == kBlockVersion2)
474 return true;
475
476 // Now create another file for the data itself.
477 name = DataName(index);
478 file = new File(base::CreatePlatformFile(name, flags, NULL, NULL));
479 return file->IsValid();
422 } 480 }
423 481
424 bool BlockFiles::OpenBlockFile(int index) { 482 bool BlockFiles::OpenBlockFile(int index) {
425 if (block_files_.size() - 1 < static_cast<unsigned int>(index)) { 483 if (block_headers_.size() - 1 < static_cast<unsigned int>(index)) {
426 DCHECK(index > 0); 484 DCHECK(index > 0);
427 int to_add = index - static_cast<int>(block_files_.size()) + 1; 485 int to_add = index - static_cast<int>(block_headers_.size()) + 1;
428 block_files_.resize(block_files_.size() + to_add); 486 block_headers_.resize(block_headers_.size() + to_add);
487 block_data_.resize(block_data_.size() + to_add);
429 } 488 }
489 DCHECK_EQ(block_headers_.size(), block_data_.size());
490 DCHECK(!block_headers_[index]);
430 491
431 base::FilePath name = Name(index); 492 base::FilePath name = HeaderName(index);
432 scoped_refptr<MappedFile> file(new MappedFile()); 493 scoped_refptr<MappedFile> file(new MappedFile());
433 494
434 if (!file->Init(name, kBlockHeaderSize)) { 495 if (!file->Init(name, kBlockHeaderSize)) {
435 LOG(ERROR) << "Failed to open " << name.value(); 496 LOG(ERROR) << "Failed to open " << name.value();
436 return false; 497 return false;
437 } 498 }
438 499
439 size_t file_len = file->GetLength(); 500 size_t file_len = file->GetLength();
440 if (file_len < static_cast<size_t>(kBlockHeaderSize)) { 501 if (file_len < static_cast<size_t>(kBlockHeaderSize)) {
441 LOG(ERROR) << "File too small " << name.value(); 502 LOG(ERROR) << "File too small " << name.value();
442 return false; 503 return false;
443 } 504 }
444 505
445 BlockFileHeader* header = reinterpret_cast<BlockFileHeader*>(file->buffer()); 506 BlockHeader file_header(file);
446 if (kBlockMagic != header->magic || kCurrentVersion != header->version) { 507 if (kBlockMagic != file_header.Header()->magic ||
508 (kBlockVersion2 != file_header.Header()->version &&
509 kBlockCurrentVersion != file_header.Header()->version)) {
447 LOG(ERROR) << "Invalid file version or magic " << name.value(); 510 LOG(ERROR) << "Invalid file version or magic " << name.value();
448 return false; 511 return false;
449 } 512 }
450 513
451 if (header->updating || !ValidateCounters(header)) { 514 if ((kBlockCurrentVersion == file_header.Header()->version && data_offset_) ||
515 (kBlockVersion2 == file_header.Header()->version && !data_offset_)) {
516 LOG(ERROR) << "Unexpected file version" << name.value();
517 return false;
518 }
519
520 if (kBlockVersion2 == file_header.Header()->version) {
521 if (static_cast<int>(file_len) <
522 file_header.Header()->max_entries * file_header.Header()->entry_size +
523 kBlockHeaderSize) {
524 LOG(ERROR) << "File too small " << name.value();
525 return false;
526 }
527
528 if (index == 0) {
529 // Load the links file into memory with a single read.
530 scoped_ptr<char[]> buf(new char[file_len]);
531 if (!file->Read(buf.get(), file_len, 0))
532 return false;
533 }
534
535 ScopedFlush flush(file);
536 file.swap(&block_headers_[index]);
537
538 if (file_header.Header()->updating || !file_header.ValidateCounters()) {
539 // Last instance was not properly shutdown, or counters are out of sync.
540 if (!FixBlockFileHeader(index)) {
541 LOG(ERROR) << "Unable to fix block file " << name.value();
542 file.swap(&block_headers_[index]);
543 return false;
544 }
545 }
546 return true;
547 }
548
549 DCHECK(!block_data_[index]);
550
551 // Open the data file.
552 name = DataName(index);
553 scoped_refptr<MappedFile> data_file(new MappedFile());
554 if (!data_file->InitNoMap(name)) {
555 LOG(ERROR) << "Failed to open " << name.value();
556 return false;
557 }
558
559 if (static_cast<int>(data_file->GetLength()) <
560 file_header.Header()->max_entries * file_header.Header()->entry_size) {
561 LOG(ERROR) << "File too small " << name.value();
562 return false;
563 }
564
565 file.swap(&block_headers_[index]);
566 data_file.swap(&block_data_[index]);
567
568 if (file_header.Header()->updating || !file_header.ValidateCounters()) {
452 // Last instance was not properly shutdown, or counters are out of sync. 569 // Last instance was not properly shutdown, or counters are out of sync.
453 if (!FixBlockFileHeader(file)) { 570 if (!FixBlockFileHeader(index)) {
454 LOG(ERROR) << "Unable to fix block file " << name.value(); 571 LOG(ERROR) << "Unable to fix block file " << name.value();
572 file.swap(&block_headers_[index]);
573 data_file.swap(&block_data_[index]);
455 return false; 574 return false;
456 } 575 }
457 } 576 }
458 577
459 if (static_cast<int>(file_len) <
460 header->max_entries * header->entry_size + kBlockHeaderSize) {
461 LOG(ERROR) << "File too small " << name.value();
462 return false;
463 }
464
465 if (index == 0) {
466 // Load the links file into memory with a single read.
467 scoped_ptr<char[]> buf(new char[file_len]);
468 if (!file->Read(buf.get(), file_len, 0))
469 return false;
470 }
471
472 ScopedFlush flush(file);
473 DCHECK(!block_files_[index]);
474 file.swap(&block_files_[index]);
475 return true; 578 return true;
476 } 579 }
477 580
478 bool BlockFiles::GrowBlockFile(MappedFile* file, BlockFileHeader* header) { 581 bool BlockFiles::GrowBlockFile(BlockFileHeader* header) {
479 if (kMaxBlocks == header->max_entries) 582 if (kMaxBlocks == header->max_entries)
480 return false; 583 return false;
481 584
585 int file_index = header->this_file;
586 MappedFile* file = data_offset_ ? block_headers_[file_index] :
587 block_data_[file_index];
482 ScopedFlush flush(file); 588 ScopedFlush flush(file);
483 DCHECK(!header->empty[3]); 589 if (data_offset_)
484 int new_size = header->max_entries + 1024; 590 DCHECK(!header->empty[3]);
591
592 int step_size = small_steps_ ? 32 : kNumExtraBlocks;
593 int new_size = header->max_entries + step_size;
485 if (new_size > kMaxBlocks) 594 if (new_size > kMaxBlocks)
486 new_size = kMaxBlocks; 595 new_size = kMaxBlocks;
487 596
488 int new_size_bytes = new_size * header->entry_size + sizeof(*header); 597 int new_size_bytes = new_size * header->entry_size + data_offset_;
489 598
490 if (!file->SetLength(new_size_bytes)) { 599 if (!file->SetLength(new_size_bytes)) {
491 // Most likely we are trying to truncate the file, so the header is wrong. 600 // Most likely we are trying to truncate the file, so the header is wrong.
492 if (header->updating < 10 && !FixBlockFileHeader(file)) { 601 if (header->updating < 10 && !FixBlockFileHeader(file_index)) {
493 // If we can't fix the file increase the lock guard so we'll pick it on 602 // If we can't fix the file increase the lock guard so we'll pick it on
494 // the next start and replace it. 603 // the next start and replace it.
495 header->updating = 100; 604 header->updating = 100;
496 return false; 605 return false;
497 } 606 }
498 return (header->max_entries >= new_size); 607 return (header->max_entries >= new_size);
499 } 608 }
500 609
501 FileLock lock(header); 610 FileLock lock(header);
502 header->empty[3] = (new_size - header->max_entries) / 4; // 4 blocks entries 611 header->empty[3] += (new_size - header->max_entries) / 4; // 4 blocks entries
503 header->max_entries = new_size; 612 header->max_entries = new_size;
504 613
505 return true; 614 return true;
506 } 615 }
507 616
508 MappedFile* BlockFiles::FileForNewBlock(FileType block_type, int block_count) { 617 MappedFile* BlockFiles::FileForNewBlock(FileType block_type, int block_count) {
509 COMPILE_ASSERT(RANKINGS == 1, invalid_file_type); 618 COMPILE_ASSERT(RANKINGS == 1, invalid_file_type);
510 MappedFile* file = block_files_[block_type - 1]; 619 MappedFile* file = block_headers_[block_type - 1];
511 BlockFileHeader* header = reinterpret_cast<BlockFileHeader*>(file->buffer()); 620 BlockHeader file_header(file);
512 621
513 TimeTicks start = TimeTicks::Now(); 622 TimeTicks start = TimeTicks::Now();
514 while (NeedToGrowBlockFile(header, block_count)) { 623 while (file_header.NeedToGrowBlockFile(block_count)) {
515 if (kMaxBlocks == header->max_entries) { 624 if (kMaxBlocks == file_header.Header()->max_entries) {
516 file = NextFile(file); 625 file = NextFile(file);
517 if (!file) 626 if (!file)
518 return NULL; 627 return NULL;
519 header = reinterpret_cast<BlockFileHeader*>(file->buffer()); 628 file_header = BlockHeader(file);
520 continue; 629 continue;
521 } 630 }
522 631
523 if (!GrowBlockFile(file, header)) 632 if (!GrowBlockFile(file_header.Header()))
524 return NULL; 633 return NULL;
525 break; 634 break;
526 } 635 }
527 HISTOGRAM_TIMES("DiskCache.GetFileForNewBlock", TimeTicks::Now() - start); 636 HISTOGRAM_TIMES("DiskCache.GetFileForNewBlock", TimeTicks::Now() - start);
528 return file; 637 return file;
529 } 638 }
530 639
531 MappedFile* BlockFiles::NextFile(MappedFile* file) { 640 MappedFile* BlockFiles::NextFile(MappedFile* file) {
532 ScopedFlush flush(file); 641 ScopedFlush flush(file);
533 BlockFileHeader* header = reinterpret_cast<BlockFileHeader*>(file->buffer()); 642 BlockFileHeader* header = reinterpret_cast<BlockFileHeader*>(file->buffer());
534 int new_file = header->next_file; 643 int new_file = header->next_file;
535 if (!new_file) { 644 if (!new_file) {
536 // RANKINGS is not reported as a type for small entries, but we may be 645 // RANKINGS is not reported as a type for small entries, but we may be
537 // extending the rankings block file. 646 // extending the rankings block file.
538 FileType type = Addr::RequiredFileType(header->entry_size); 647 FileType type = Addr::RequiredFileType(header->entry_size);
539 if (header->entry_size == Addr::BlockSizeForFileType(RANKINGS)) 648 if (header->entry_size == Addr::BlockSizeForFileType(RANKINGS))
540 type = RANKINGS; 649 type = RANKINGS;
541 650
542 new_file = CreateNextBlockFile(type); 651 new_file = CreateNextBlockFile(type);
543 if (!new_file) 652 if (!new_file)
544 return NULL; 653 return NULL;
545 654
546 FileLock lock(header); 655 FileLock lock(header);
547 header->next_file = new_file; 656 header->next_file = new_file;
548 } 657 }
549 658
550 // Only the block_file argument is relevant for what we want. 659 // Only the block_file argument is relevant for what we want.
551 Addr address(BLOCK_256, 1, new_file, 0); 660 Addr address(BLOCK_256, 1, new_file, 0);
552 return GetFile(address); 661 return GetFileHeader(address);
662 }
663
664 int BlockFiles::GetFileIndex(Addr address) {
665 DCHECK(thread_checker_->CalledOnValidThread());
666 DCHECK(block_headers_.size() >= 4);
667 DCHECK(address.is_block_file() || !address.is_initialized());
668 if (!address.is_initialized())
669 return -1;
670
671 int file_index = address.FileNumber();
672 if (static_cast<unsigned int>(file_index) >= block_headers_.size() ||
673 !block_headers_[file_index]) {
674 // We need to open the file
675 if (!OpenBlockFile(file_index))
676 return -1;
677 }
678 DCHECK(block_headers_.size() >= static_cast<unsigned int>(file_index));
679 return file_index;
680 }
681
682 MappedFile* BlockFiles::GetFileHeader(Addr address) {
683 int file_index = GetFileIndex(address);
684 if (file_index < 0)
685 return NULL;
686
687 return block_headers_[file_index];
553 } 688 }
554 689
555 int BlockFiles::CreateNextBlockFile(FileType block_type) { 690 int BlockFiles::CreateNextBlockFile(FileType block_type) {
556 for (int i = kFirstAdditionalBlockFile; i <= kMaxBlockFile; i++) { 691 for (int i = kFirstAdditionalBlockFile; i <= kMaxBlockFile; i++) {
557 if (CreateBlockFile(i, block_type, false)) 692 if (CreateBlockFile(i, block_type, false))
558 return i; 693 return i;
559 } 694 }
560 return 0; 695 return 0;
561 } 696 }
562 697
563 // We walk the list of files for this particular block type, deleting the ones 698 // We walk the list of files for this particular block type, deleting the ones
564 // that are empty. 699 // that are empty.
565 bool BlockFiles::RemoveEmptyFile(FileType block_type) { 700 bool BlockFiles::RemoveEmptyFile(FileType block_type) {
566 MappedFile* file = block_files_[block_type - 1]; 701 MappedFile* file = block_headers_[block_type - 1];
567 BlockFileHeader* header = reinterpret_cast<BlockFileHeader*>(file->buffer()); 702 BlockFileHeader* header = reinterpret_cast<BlockFileHeader*>(file->buffer());
568 703
569 while (header->next_file) { 704 while (header->next_file) {
570 // Only the block_file argument is relevant for what we want. 705 // Only the block_file argument is relevant for what we want.
571 Addr address(BLOCK_256, 1, header->next_file, 0); 706 Addr address(BLOCK_256, 1, header->next_file, 0);
572 MappedFile* next_file = GetFile(address); 707 MappedFile* next_file = GetFileHeader(address);
573 if (!next_file) 708 if (!next_file)
574 return false; 709 return false;
575 710
576 BlockFileHeader* next_header = 711 BlockFileHeader* next_header =
577 reinterpret_cast<BlockFileHeader*>(next_file->buffer()); 712 reinterpret_cast<BlockFileHeader*>(next_file->buffer());
578 if (!next_header->num_entries) { 713 if (!next_header->num_entries) {
579 DCHECK_EQ(next_header->entry_size, header->entry_size); 714 DCHECK_EQ(next_header->entry_size, header->entry_size);
580 // Delete next_file and remove it from the chain. 715 // Delete next_file and remove it from the chain.
581 int file_index = header->next_file; 716 int file_index = header->next_file;
582 header->next_file = next_header->next_file; 717 header->next_file = next_header->next_file;
583 DCHECK(block_files_.size() >= static_cast<unsigned int>(file_index)); 718 DCHECK(block_headers_.size() >= static_cast<unsigned int>(file_index));
584 file->Flush(); 719 file->Flush();
585 720
586 // We get a new handle to the file and release the old one so that the 721 // We get a new handle to the file and release the old one so that the
587 // file gets unmmaped... so we can delete it. 722 // file gets unmmaped... so we can delete it.
588 base::FilePath name = Name(file_index); 723 base::FilePath name = HeaderName(file_index);
589 scoped_refptr<File> this_file(new File(false)); 724 scoped_refptr<File> this_file(new File(false));
590 this_file->Init(name); 725 this_file->Init(name);
591 block_files_[file_index]->Release(); 726 block_headers_[file_index]->Release();
592 block_files_[file_index] = NULL; 727 block_headers_[file_index] = NULL;
593 728
594 int failure = DeleteCacheFile(name) ? 0 : 1; 729 int failure = DeleteCacheFile(name) ? 0 : 1;
595 UMA_HISTOGRAM_COUNTS("DiskCache.DeleteFailed2", failure);
596 if (failure) 730 if (failure)
597 LOG(ERROR) << "Failed to delete " << name.value() << " from the cache."; 731 LOG(ERROR) << "Failed to delete " << name.value() << " from the cache.";
732
733 if (!data_offset_) {
734 name = DataName(file_index);
735 if (!DeleteCacheFile(name)) {
736 failure = 1;
737 LOG(ERROR) << "Failed to delete " << name.value() <<
738 " from the cache.";
739 }
740 block_data_[file_index]->Release();
741 block_data_[file_index] = NULL;
742 }
743 UMA_HISTOGRAM_COUNTS("DiskCache.DeleteFailed2", failure);
598 continue; 744 continue;
599 } 745 }
600 746
601 header = next_header; 747 header = next_header;
602 file = next_file; 748 file = next_file;
603 } 749 }
604 return true; 750 return true;
605 } 751 }
606 752
753 bool BlockFiles::PreallocateSpace(FileType block_type) {
754 MappedFile* file = block_headers_[block_type - 1];
755 BlockHeader file_header(file);
756
757 int empty_blocks = file_header.EmptyBlocks();
758 while (file_header.Header()->next_file) {
759 // Only the block_file argument is relevant for what we want.
760 Addr address(BLOCK_256, 1, file_header.Header()->next_file, 0);
761 MappedFile* next_file = GetFileHeader(address);
762 if (!next_file)
763 return false;
764
765 BlockHeader next_header(next_file);
766 empty_blocks += next_header.EmptyBlocks();
767
768 file_header = next_header;
769 file = next_file;
770 }
771 if (empty_blocks > kNumExtraBlocks * 2 / 3)
772 return true;
773
774 // Restart the search.
775 file = block_headers_[block_type - 1];
776 file_header = BlockHeader(file);
777 while (kMaxBlocks == file_header.Header()->max_entries) {
778 file = NextFile(file);
779 if (!file)
780 return false;
781 file_header = BlockHeader(file);
782 }
783 return GrowBlockFile(file_header.Header());
784 }
785
607 // Note that we expect to be called outside of a FileLock... however, we cannot 786 // Note that we expect to be called outside of a FileLock... however, we cannot
608 // DCHECK on header->updating because we may be fixing a crash. 787 // DCHECK on header->updating because we may be fixing a crash.
609 bool BlockFiles::FixBlockFileHeader(MappedFile* file) { 788 bool BlockFiles::FixBlockFileHeader(int index) {
610 ScopedFlush flush(file); 789 DCHECK_GE(block_headers_.size(), static_cast<unsigned int>(index));
611 BlockFileHeader* header = reinterpret_cast<BlockFileHeader*>(file->buffer()); 790 MappedFile* header_file = block_headers_[index];
612 int file_size = static_cast<int>(file->GetLength()); 791 ScopedFlush flush(header_file);
613 if (file_size < static_cast<int>(sizeof(*header))) 792 BlockHeader file_header(header_file);
793
794 MappedFile* data_file = data_offset_ ? header_file : block_data_[index];
795 int file_size = static_cast<int>(data_file->GetLength());
796 if (file_size < data_offset_)
614 return false; // file_size > 2GB is also an error. 797 return false; // file_size > 2GB is also an error.
615 798
616 const int kMinBlockSize = 36; 799 const int kMinBlockSize = 36;
617 const int kMaxBlockSize = 4096; 800 const int kMaxBlockSize = 4096;
618 if (header->entry_size < kMinBlockSize || 801 if (file_header.Header()->entry_size < kMinBlockSize ||
619 header->entry_size > kMaxBlockSize || header->num_entries < 0) 802 file_header.Header()->entry_size > kMaxBlockSize ||
803 file_header.Header()->num_entries < 0)
620 return false; 804 return false;
621 805
622 // Make sure that we survive crashes. 806 // Make sure that we survive crashes.
623 header->updating = 1; 807 file_header.Header()->updating = 1;
624 int expected = header->entry_size * header->max_entries + sizeof(*header); 808 int expected =
809 file_header.Header()->entry_size * file_header.Header()->max_entries +
810 data_offset_;
625 if (file_size != expected) { 811 if (file_size != expected) {
626 int max_expected = header->entry_size * kMaxBlocks + sizeof(*header); 812 int max_expected = file_header.Header()->entry_size * kMaxBlocks +
627 if (file_size < expected || header->empty[3] || file_size > max_expected) { 813 data_offset_;
814 if (file_size < expected || file_header.Header()->empty[3] ||
815 file_size > max_expected) {
628 NOTREACHED(); 816 NOTREACHED();
629 LOG(ERROR) << "Unexpected file size"; 817 LOG(ERROR) << "Unexpected file size";
630 return false; 818 return false;
631 } 819 }
632 // We were in the middle of growing the file. 820 // We were in the middle of growing the file.
633 int num_entries = (file_size - sizeof(*header)) / header->entry_size; 821 int num_entries = (file_size - data_offset_) /
634 header->max_entries = num_entries; 822 file_header.Header()->entry_size;
823 file_header.Header()->max_entries = num_entries;
635 } 824 }
636 825
637 FixAllocationCounters(header); 826 file_header.FixAllocationCounters();
638 int empty_blocks = EmptyBlocks(header); 827 int empty_blocks = file_header.EmptyBlocks();
639 if (empty_blocks + header->num_entries > header->max_entries) 828 if (empty_blocks + file_header.Header()->num_entries >
640 header->num_entries = header->max_entries - empty_blocks; 829 file_header.Header()->max_entries) {
830 file_header.Header()->num_entries = file_header.Header()->max_entries -
831 empty_blocks;
832 }
641 833
642 if (!ValidateCounters(header)) 834 if (!file_header.ValidateCounters())
643 return false; 835 return false;
644 836
645 header->updating = 0; 837 file_header.Header()->updating = 0;
646 return true; 838 return true;
647 } 839 }
648 840
649 // We are interested in the total number of blocks used by this file type, and 841 // We are interested in the total number of blocks used by this file type, and
650 // the max number of blocks that we can store (reported as the percentage of 842 // the max number of blocks that we can store (reported as the percentage of
651 // used blocks). In order to find out the number of used blocks, we have to 843 // used blocks). In order to find out the number of used blocks, we have to
652 // substract the empty blocks from the total blocks for each file in the chain. 844 // substract the empty blocks from the total blocks for each file in the chain.
653 void BlockFiles::GetFileStats(int index, int* used_count, int* load) { 845 void BlockFiles::GetFileStats(int index, int* used_count, int* load) {
654 int max_blocks = 0; 846 int max_blocks = 0;
655 *used_count = 0; 847 *used_count = 0;
656 *load = 0; 848 *load = 0;
657 for (;;) { 849 for (;;) {
658 if (!block_files_[index] && !OpenBlockFile(index)) 850 if (!block_headers_[index] && !OpenBlockFile(index))
659 return; 851 return;
660 852
661 BlockFileHeader* header = 853 BlockFileHeader* header =
662 reinterpret_cast<BlockFileHeader*>(block_files_[index]->buffer()); 854 reinterpret_cast<BlockFileHeader*>(block_headers_[index]->buffer());
663 855
664 max_blocks += header->max_entries; 856 max_blocks += header->max_entries;
665 int used = header->max_entries; 857 int used = header->max_entries;
666 for (int i = 0; i < 4; i++) { 858 for (int i = 0; i < 4; i++) {
667 used -= header->empty[i] * (i + 1); 859 used -= header->empty[i] * (i + 1);
668 DCHECK_GE(used, 0); 860 DCHECK_GE(used, 0);
669 } 861 }
670 *used_count += used; 862 *used_count += used;
671 863
672 if (!header->next_file) 864 if (!header->next_file)
673 break; 865 break;
674 index = header->next_file; 866 index = header->next_file;
675 } 867 }
676 if (max_blocks) 868 if (max_blocks)
677 *load = *used_count * 100 / max_blocks; 869 *load = *used_count * 100 / max_blocks;
678 } 870 }
679 871
680 base::FilePath BlockFiles::Name(int index) { 872 base::FilePath BlockFiles::HeaderName(int index) {
681 // The file format allows for 256 files. 873 // The file format allows for 256 files.
682 DCHECK(index < 256 || index >= 0); 874 DCHECK(index < 256 && index >= 0);
683 std::string tmp = base::StringPrintf("%s%d", kBlockName, index); 875 std::string tmp = base::StringPrintf("%s%d", kBlockName, index);
684 return path_.AppendASCII(tmp); 876 return path_.AppendASCII(tmp);
685 } 877 }
686 878
879 base::FilePath BlockFiles::DataName(int index) {
880 // The file format allows for 256 files.
881 DCHECK(index < 256 || index >= 0);
882 std::string tmp = base::StringPrintf("%s%d_d", kBlockName, index);
883 return path_.AppendASCII(tmp);
884 }
885
687 } // namespace disk_cache 886 } // namespace disk_cache
OLDNEW
« no previous file with comments | « net/disk_cache/block_files.h ('k') | net/disk_cache/block_files_unittest.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698