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

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