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

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