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

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

Issue 17507006: Disk cache v3 ref2 Base URL: svn://svn.chromium.org/chrome/trunk/src/
Patch Set: Incl IndexTable cl Created 7 years, 1 month 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/files/file_path.h" 8 #include "base/file_util.h"
9 #include "base/metrics/histogram.h" 9 #include "base/metrics/histogram.h"
10 #include "base/strings/string_util.h" 10 #include "base/strings/string_util.h"
11 #include "base/strings/stringprintf.h" 11 #include "base/strings/stringprintf.h"
12 #include "base/threading/thread_checker.h" 12 #include "base/threading/thread_checker.h"
13 #include "base/time/time.h" 13 #include "base/time/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];
(...skipping 112 matching lines...) Expand 10 before | Expand all | Expand 10 after
145 DCHECK_GE(header_->empty[bits_at_end - 1], 0); 146 DCHECK_GE(header_->empty[bits_at_end - 1], 0);
146 } 147 }
147 base::subtle::MemoryBarrier(); 148 base::subtle::MemoryBarrier();
148 header_->num_entries--; 149 header_->num_entries--;
149 DCHECK_GE(header_->num_entries, 0); 150 DCHECK_GE(header_->num_entries, 0);
150 HISTOGRAM_TIMES("DiskCache.DeleteBlock", TimeTicks::Now() - start); 151 HISTOGRAM_TIMES("DiskCache.DeleteBlock", TimeTicks::Now() - start);
151 } 152 }
152 153
153 // Note that this is a simplified version of DeleteMapBlock(). 154 // Note that this is a simplified version of DeleteMapBlock().
154 bool BlockHeader::UsedMapBlock(int index, int size) { 155 bool BlockHeader::UsedMapBlock(int index, int size) {
155 if (size < 0 || size > kMaxNumBlocks) 156 if (size < 0 || size > kMaxNumBlocks) {
157 NOTREACHED();
156 return false; 158 return false;
157 159 }
158 int byte_index = index / 8; 160 int byte_index = index / 8;
159 uint8* byte_map = reinterpret_cast<uint8*>(header_->allocation_map); 161 uint8* byte_map = reinterpret_cast<uint8*>(header_->allocation_map);
160 uint8 map_block = byte_map[byte_index]; 162 uint8 map_block = byte_map[byte_index];
161 163
162 if (index % 8 >= 4) 164 if (index % 8 >= 4)
163 map_block >>= 4; 165 map_block >>= 4;
164 166
165 DCHECK((((1 << size) - 1) << (index % 8)) < 0x100); 167 DCHECK((((1 << size) - 1) << (index % 8)) < 0x100);
166 uint8 to_clear = ((1 << size) - 1) << (index % 8); 168 uint8 to_clear = ((1 << size) - 1) << (index % 8);
167 return ((byte_map[byte_index] & to_clear) == to_clear); 169 return ((byte_map[byte_index] & to_clear) == to_clear);
(...skipping 75 matching lines...) Expand 10 before | Expand all | Expand 10 after
243 } 245 }
244 246
245 int BlockHeader::FileId() const { 247 int BlockHeader::FileId() const {
246 return header_->this_file; 248 return header_->this_file;
247 } 249 }
248 250
249 int BlockHeader::NextFileId() const { 251 int BlockHeader::NextFileId() const {
250 return header_->next_file; 252 return header_->next_file;
251 } 253 }
252 254
253 int BlockHeader::Size() const {
254 return static_cast<int>(sizeof(*header_));
255 }
256
257 BlockFileHeader* BlockHeader::Header() { 255 BlockFileHeader* BlockHeader::Header() {
258 return header_; 256 return header_;
259 } 257 }
260 258
261 // ------------------------------------------------------------------------ 259 // ------------------------------------------------------------------------
262 260
263 BlockFiles::BlockFiles(const base::FilePath& path) 261 BlockFiles::BlockFiles(const base::FilePath& path)
264 : init_(false), zero_buffer_(NULL), path_(path) { 262 : init_(false),
263 small_steps_(false),
264 data_offset_(0),
265 zero_buffer_(NULL),
266 path_(path) {
265 } 267 }
266 268
267 BlockFiles::~BlockFiles() { 269 BlockFiles::~BlockFiles() {
268 if (zero_buffer_) 270 if (zero_buffer_)
269 delete[] zero_buffer_; 271 delete[] zero_buffer_;
270 CloseFiles(); 272 CloseFiles();
271 } 273 }
272 274
273 bool BlockFiles::Init(bool create_files) { 275 bool BlockFiles::Init(bool create_files, int num_files) {
274 DCHECK(!init_); 276 DCHECK(!init_);
275 if (init_) 277 if (init_)
276 return false; 278 return false;
277 279
280 data_offset_ = num_files > kFirstAdditionalBlockFile ? 0 : kBlockHeaderSize;
278 thread_checker_.reset(new base::ThreadChecker); 281 thread_checker_.reset(new base::ThreadChecker);
279 282
280 block_files_.resize(kFirstAdditionalBlockFile); 283 block_headers_.resize(num_files);
281 for (int i = 0; i < kFirstAdditionalBlockFile; i++) { 284 block_data_.resize(num_files);
285 for (int i = 0; i < num_files; i++) {
282 if (create_files) 286 if (create_files)
283 if (!CreateBlockFile(i, static_cast<FileType>(i + 1), true)) 287 if (!CreateBlockFile(i, static_cast<FileType>(i + 1), true))
284 return false; 288 return false;
285 289
286 if (!OpenBlockFile(i)) 290 if (!OpenBlockFile(i))
287 return false; 291 return false;
288 292
289 // Walk this chain of files removing empty ones. 293 // Walk this chain of files removing empty ones.
290 if (!RemoveEmptyFile(static_cast<FileType>(i + 1))) 294 if (!RemoveEmptyFile(static_cast<FileType>(i + 1)))
291 return false; 295 return false;
296
297 if (!data_offset_ && !PreallocateSpace(static_cast<FileType>(i + 1)))
298 return false;
292 } 299 }
293 300
294 init_ = true; 301 init_ = true;
295 return true; 302 return true;
296 } 303 }
297 304
305 void BlockFiles::GetBitmaps(int num_files, BlockFilesBitmaps* bitmaps) {
306 bitmaps->clear();
307 bitmaps->resize(num_files);
308
309 for (int i = 0; i < num_files; i++) {
310 // Only the block_file argument is relevant for what we want.
311 Addr address(BLOCK_256, 1, i, 0);
312 BlockHeader header(GetFileHeader(address));
313 (*bitmaps)[i] = header;
314 }
315 }
316
298 MappedFile* BlockFiles::GetFile(Addr address) { 317 MappedFile* BlockFiles::GetFile(Addr address) {
299 DCHECK(thread_checker_->CalledOnValidThread()); 318 int file_index = GetFileIndex(address);
300 DCHECK_GE(block_files_.size(), 319 if (file_index < 0)
301 static_cast<size_t>(kFirstAdditionalBlockFile));
302 DCHECK(address.is_block_file() || !address.is_initialized());
303 if (!address.is_initialized())
304 return NULL; 320 return NULL;
305 321
306 int file_index = address.FileNumber(); 322 if (data_offset_)
307 if (static_cast<unsigned int>(file_index) >= block_files_.size() || 323 return block_headers_[file_index];
308 !block_files_[file_index]) { 324
309 // We need to open the file 325 DCHECK(block_data_.size() >= static_cast<unsigned int>(file_index));
310 if (!OpenBlockFile(file_index)) 326 return block_data_[file_index];
311 return NULL;
312 }
313 DCHECK_GE(block_files_.size(), static_cast<unsigned int>(file_index));
314 return block_files_[file_index];
315 } 327 }
316 328
317 bool BlockFiles::CreateBlock(FileType block_type, int block_count, 329 bool BlockFiles::CreateBlock(FileType block_type, int block_count,
318 Addr* block_address) { 330 Addr* block_address) {
319 DCHECK(thread_checker_->CalledOnValidThread()); 331 DCHECK(thread_checker_->CalledOnValidThread());
320 DCHECK_NE(block_type, EXTERNAL); 332 DCHECK_NE(block_type, EXTERNAL);
321 DCHECK_NE(block_type, BLOCK_FILES); 333 DCHECK_NE(block_type, BLOCK_FILES);
322 DCHECK_NE(block_type, BLOCK_ENTRIES); 334 DCHECK_NE(block_type, BLOCK_ENTRIES);
323 DCHECK_NE(block_type, BLOCK_EVICTED); 335 DCHECK_NE(block_type, BLOCK_EVICTED);
324 if (block_count < 1 || block_count > kMaxNumBlocks) 336 if (block_count < 1 || block_count > kMaxNumBlocks)
(...skipping 28 matching lines...) Expand all
353 zero_buffer_ = new char[Addr::BlockSizeForFileType(BLOCK_4K) * 4]; 365 zero_buffer_ = new char[Addr::BlockSizeForFileType(BLOCK_4K) * 4];
354 memset(zero_buffer_, 0, Addr::BlockSizeForFileType(BLOCK_4K) * 4); 366 memset(zero_buffer_, 0, Addr::BlockSizeForFileType(BLOCK_4K) * 4);
355 } 367 }
356 MappedFile* file = GetFile(address); 368 MappedFile* file = GetFile(address);
357 if (!file) 369 if (!file)
358 return; 370 return;
359 371
360 Trace("DeleteBlock 0x%x", address.value()); 372 Trace("DeleteBlock 0x%x", address.value());
361 373
362 size_t size = address.BlockSize() * address.num_blocks(); 374 size_t size = address.BlockSize() * address.num_blocks();
363 size_t offset = address.start_block() * address.BlockSize() + 375 size_t offset = address.start_block() * address.BlockSize() + data_offset_;
364 kBlockHeaderSize;
365 if (deep) 376 if (deep)
366 file->Write(zero_buffer_, size, offset); 377 file->Write(zero_buffer_, size, offset);
367 378
368 BlockHeader file_header(file); 379 BlockHeader file_header(GetFileHeader(address));
369 file_header.DeleteMapBlock(address.start_block(), address.num_blocks()); 380 file_header.DeleteMapBlock(address.start_block(), address.num_blocks());
370 file->Flush(); 381 file->Flush();
371 382
372 if (!file_header.Header()->num_entries) { 383 if (!file_header.Header()->num_entries) {
373 // This file is now empty. Let's try to delete it. 384 // This file is now empty. Let's try to delete it.
374 FileType type = Addr::RequiredFileType(file_header.Header()->entry_size); 385 FileType type = Addr::RequiredFileType(file_header.Header()->entry_size);
375 if (Addr::BlockSizeForFileType(RANKINGS) == 386 if (Addr::BlockSizeForFileType(RANKINGS) ==
376 file_header.Header()->entry_size) { 387 file_header.Header()->entry_size) {
377 type = RANKINGS; 388 type = RANKINGS;
378 } 389 }
379 RemoveEmptyFile(type); // Ignore failures. 390 RemoveEmptyFile(type); // Ignore failures.
380 } 391 }
381 } 392 }
382 393
383 void BlockFiles::CloseFiles() { 394 void BlockFiles::CloseFiles() {
384 if (init_) { 395 if (init_) {
385 DCHECK(thread_checker_->CalledOnValidThread()); 396 DCHECK(thread_checker_->CalledOnValidThread());
386 } 397 }
387 init_ = false; 398 init_ = false;
388 for (unsigned int i = 0; i < block_files_.size(); i++) { 399 for (unsigned int i = 0; i < block_headers_.size(); i++) {
389 if (block_files_[i]) { 400 if (block_headers_[i]) {
390 block_files_[i]->Release(); 401 block_headers_[i]->Release();
391 block_files_[i] = NULL; 402 block_headers_[i] = NULL;
392 } 403 }
393 } 404 }
394 block_files_.clear(); 405 for (unsigned int i = 0; i < block_data_.size(); i++) {
406 if (block_data_[i]) {
407 block_data_[i]->Release();
408 block_data_[i] = NULL;
409 }
410 }
411 block_headers_.clear();
412 block_data_.clear();
395 } 413 }
396 414
397 void BlockFiles::ReportStats() { 415 void BlockFiles::ReportStats() {
398 DCHECK(thread_checker_->CalledOnValidThread()); 416 DCHECK(thread_checker_->CalledOnValidThread());
399 int used_blocks[kFirstAdditionalBlockFile]; 417 int used_blocks[kFirstAdditionalBlockFile];
400 int load[kFirstAdditionalBlockFile]; 418 int load[kFirstAdditionalBlockFile];
401 for (int i = 0; i < kFirstAdditionalBlockFile; i++) { 419 for (int i = 0; i < kFirstAdditionalBlockFile; i++) {
402 GetFileStats(i, &used_blocks[i], &load[i]); 420 GetFileStats(i, &used_blocks[i], &load[i]);
403 } 421 }
404 UMA_HISTOGRAM_COUNTS("DiskCache.Blocks_0", used_blocks[0]); 422 UMA_HISTOGRAM_COUNTS("DiskCache.Blocks_0", used_blocks[0]);
405 UMA_HISTOGRAM_COUNTS("DiskCache.Blocks_1", used_blocks[1]); 423 UMA_HISTOGRAM_COUNTS("DiskCache.Blocks_1", used_blocks[1]);
406 UMA_HISTOGRAM_COUNTS("DiskCache.Blocks_2", used_blocks[2]); 424 UMA_HISTOGRAM_COUNTS("DiskCache.Blocks_2", used_blocks[2]);
407 UMA_HISTOGRAM_COUNTS("DiskCache.Blocks_3", used_blocks[3]); 425 UMA_HISTOGRAM_COUNTS("DiskCache.Blocks_3", used_blocks[3]);
408 426
409 UMA_HISTOGRAM_ENUMERATION("DiskCache.BlockLoad_0", load[0], 101); 427 UMA_HISTOGRAM_ENUMERATION("DiskCache.BlockLoad_0", load[0], 101);
410 UMA_HISTOGRAM_ENUMERATION("DiskCache.BlockLoad_1", load[1], 101); 428 UMA_HISTOGRAM_ENUMERATION("DiskCache.BlockLoad_1", load[1], 101);
411 UMA_HISTOGRAM_ENUMERATION("DiskCache.BlockLoad_2", load[2], 101); 429 UMA_HISTOGRAM_ENUMERATION("DiskCache.BlockLoad_2", load[2], 101);
412 UMA_HISTOGRAM_ENUMERATION("DiskCache.BlockLoad_3", load[3], 101); 430 UMA_HISTOGRAM_ENUMERATION("DiskCache.BlockLoad_3", load[3], 101);
413 } 431 }
414 432
415 bool BlockFiles::IsValid(Addr address) { 433 bool BlockFiles::IsValid(Addr address) {
416 #ifdef NDEBUG 434 #ifdef NDEBUG
417 return true; 435 return true;
418 #else 436 #else
419 if (!address.is_initialized() || address.is_separate_file()) 437 if (!address.is_initialized() || address.is_separate_file())
420 return false; 438 return false;
421 439
422 MappedFile* file = GetFile(address); 440 MappedFile* file = GetFileHeader(address);
423 if (!file) 441 if (!file)
424 return false; 442 return false;
425 443
426 BlockHeader header(file); 444 BlockHeader header(file);
427 bool rv = header.UsedMapBlock(address.start_block(), address.num_blocks()); 445 bool rv = header.UsedMapBlock(address.start_block(), address.num_blocks());
428 DCHECK(rv); 446 DCHECK(rv);
429
430 static bool read_contents = false;
431 if (read_contents) {
432 scoped_ptr<char[]> buffer;
433 buffer.reset(new char[Addr::BlockSizeForFileType(BLOCK_4K) * 4]);
434 size_t size = address.BlockSize() * address.num_blocks();
435 size_t offset = address.start_block() * address.BlockSize() +
436 kBlockHeaderSize;
437 bool ok = file->Read(buffer.get(), size, offset);
438 DCHECK(ok);
439 }
440
441 return rv; 447 return rv;
442 #endif 448 #endif
443 } 449 }
444 450
445 bool BlockFiles::CreateBlockFile(int index, FileType file_type, bool force) { 451 bool BlockFiles::CreateBlockFile(int index, FileType file_type, bool force) {
446 base::FilePath name = Name(index); 452 base::FilePath name = HeaderName(index);
447 int flags = 453 int flags =
448 force ? base::PLATFORM_FILE_CREATE_ALWAYS : base::PLATFORM_FILE_CREATE; 454 force ? base::PLATFORM_FILE_CREATE_ALWAYS : base::PLATFORM_FILE_CREATE;
449 flags |= base::PLATFORM_FILE_WRITE | base::PLATFORM_FILE_EXCLUSIVE_WRITE; 455 flags |= base::PLATFORM_FILE_WRITE | base::PLATFORM_FILE_EXCLUSIVE_WRITE;
450 456
451 scoped_refptr<File> file(new File( 457 scoped_refptr<File> file(new File(
452 base::CreatePlatformFile(name, flags, NULL, NULL))); 458 base::CreatePlatformFile(name, flags, NULL, NULL)));
453 if (!file->IsValid()) 459 if (!file->IsValid())
454 return false; 460 return false;
455 461
456 BlockFileHeader header; 462 BlockFileHeader header;
457 memset(&header, 0, sizeof(header)); 463 memset(&header, 0, sizeof(header));
458 header.magic = kBlockMagic; 464 header.magic = kBlockMagic;
459 header.version = kBlockVersion2; 465 header.version = data_offset_ ? kBlockVersion2 : kBlockCurrentVersion;
460 header.entry_size = Addr::BlockSizeForFileType(file_type); 466 header.entry_size = Addr::BlockSizeForFileType(file_type);
461 header.this_file = static_cast<int16>(index); 467 header.this_file = static_cast<int16>(index);
462 DCHECK(index <= kint16max && index >= 0); 468 DCHECK(index <= kint16max && index >= 0);
463 469
464 return file->Write(&header, sizeof(header), 0); 470 if (!file->Write(&header, sizeof(header), 0))
471 return false;
472
473 if (header.version == kBlockVersion2)
474 return true;
475
476 // Now create another file for the data itself.
477 name = DataName(index);
478 file = new File(base::CreatePlatformFile(name, flags, NULL, NULL));
479 return file->IsValid();
465 } 480 }
466 481
467 bool BlockFiles::OpenBlockFile(int index) { 482 bool BlockFiles::OpenBlockFile(int index) {
468 if (block_files_.size() - 1 < static_cast<unsigned int>(index)) { 483 if (block_headers_.size() - 1 < static_cast<unsigned int>(index)) {
469 DCHECK(index > 0); 484 DCHECK(index > 0);
470 int to_add = index - static_cast<int>(block_files_.size()) + 1; 485 int to_add = index - static_cast<int>(block_headers_.size()) + 1;
471 block_files_.resize(block_files_.size() + to_add); 486 block_headers_.resize(block_headers_.size() + to_add);
487 block_data_.resize(block_data_.size() + to_add);
472 } 488 }
489 DCHECK_EQ(block_headers_.size(), block_data_.size());
490 DCHECK(!block_headers_[index]);
473 491
474 base::FilePath name = Name(index); 492 base::FilePath name = HeaderName(index);
475 scoped_refptr<MappedFile> file(new MappedFile()); 493 scoped_refptr<MappedFile> file(new MappedFile());
476 494
477 if (!file->Init(name, kBlockHeaderSize)) { 495 if (!file->Init(name, kBlockHeaderSize)) {
478 LOG(ERROR) << "Failed to open " << name.value(); 496 LOG(ERROR) << "Failed to open " << name.value();
479 return false; 497 return false;
480 } 498 }
481 499
482 size_t file_len = file->GetLength(); 500 size_t file_len = file->GetLength();
483 if (file_len < static_cast<size_t>(kBlockHeaderSize)) { 501 if (file_len < static_cast<size_t>(kBlockHeaderSize)) {
484 LOG(ERROR) << "File too small " << name.value(); 502 LOG(ERROR) << "File too small " << name.value();
485 return false; 503 return false;
486 } 504 }
487 505
488 BlockHeader file_header(file.get()); 506 BlockHeader file_header(file);
489 BlockFileHeader* header = file_header.Header(); 507 if (kBlockMagic != file_header.Header()->magic ||
490 if (kBlockMagic != header->magic || kBlockVersion2 != header->version) { 508 (kBlockVersion2 != file_header.Header()->version &&
509 kBlockCurrentVersion != file_header.Header()->version)) {
491 LOG(ERROR) << "Invalid file version or magic " << name.value(); 510 LOG(ERROR) << "Invalid file version or magic " << name.value();
492 return false; 511 return false;
493 } 512 }
494 513
495 if (header->updating || !file_header.ValidateCounters()) { 514 if ((kBlockCurrentVersion == file_header.Header()->version && data_offset_) ||
515 (kBlockVersion2 == file_header.Header()->version && !data_offset_)) {
516 LOG(ERROR) << "Unexpected file version" << name.value();
517 return false;
518 }
519
520 if (kBlockVersion2 == file_header.Header()->version) {
521 if (static_cast<int>(file_len) <
522 file_header.Header()->max_entries * file_header.Header()->entry_size +
523 kBlockHeaderSize) {
524 LOG(ERROR) << "File too small " << name.value();
525 return false;
526 }
527
528 if (index == 0) {
529 // Load the links file into memory with a single read.
530 scoped_ptr<char[]> buf(new char[file_len]);
531 if (!file->Read(buf.get(), file_len, 0))
532 return false;
533 }
534
535 ScopedFlush flush(file);
536 file.swap(&block_headers_[index]);
537
538 if (file_header.Header()->updating || !file_header.ValidateCounters()) {
539 // Last instance was not properly shutdown, or counters are out of sync.
540 if (!FixBlockFileHeader(index)) {
541 LOG(ERROR) << "Unable to fix block file " << name.value();
542 file.swap(&block_headers_[index]);
543 return false;
544 }
545 }
546 return true;
547 }
548
549 DCHECK(!block_data_[index]);
550
551 // Open the data file.
552 name = DataName(index);
553 scoped_refptr<MappedFile> data_file(new MappedFile());
554 if (!data_file->InitNoMap(name)) {
555 LOG(ERROR) << "Failed to open " << name.value();
556 return false;
557 }
558
559 if (static_cast<int>(data_file->GetLength()) <
560 file_header.Header()->max_entries * file_header.Header()->entry_size) {
561 LOG(ERROR) << "File too small " << name.value();
562 return false;
563 }
564
565 file.swap(&block_headers_[index]);
566 data_file.swap(&block_data_[index]);
567
568 if (file_header.Header()->updating || !file_header.ValidateCounters()) {
496 // Last instance was not properly shutdown, or counters are out of sync. 569 // Last instance was not properly shutdown, or counters are out of sync.
497 if (!FixBlockFileHeader(file.get())) { 570 if (!FixBlockFileHeader(index)) {
498 LOG(ERROR) << "Unable to fix block file " << name.value(); 571 LOG(ERROR) << "Unable to fix block file " << name.value();
572 file.swap(&block_headers_[index]);
573 data_file.swap(&block_data_[index]);
499 return false; 574 return false;
500 } 575 }
501 } 576 }
502 577
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.get());
517 DCHECK(!block_files_[index]);
518 file.swap(&block_files_[index]);
519 return true; 578 return true;
520 } 579 }
521 580
522 bool BlockFiles::GrowBlockFile(MappedFile* file, BlockFileHeader* header) { 581 bool BlockFiles::GrowBlockFile(BlockFileHeader* header) {
523 if (kMaxBlocks == header->max_entries) 582 if (kMaxBlocks == header->max_entries)
524 return false; 583 return false;
525 584
585 int file_index = header->this_file;
586 MappedFile* file = data_offset_ ? block_headers_[file_index] :
587 block_data_[file_index];
526 ScopedFlush flush(file); 588 ScopedFlush flush(file);
527 DCHECK(!header->empty[3]); 589 if (data_offset_)
528 int new_size = header->max_entries + 1024; 590 DCHECK(!header->empty[3]);
591
592 int step_size = small_steps_ ? 32 : kNumExtraBlocks;
593 int new_size = header->max_entries + step_size;
529 if (new_size > kMaxBlocks) 594 if (new_size > kMaxBlocks)
530 new_size = kMaxBlocks; 595 new_size = kMaxBlocks;
531 596
532 int new_size_bytes = new_size * header->entry_size + sizeof(*header); 597 int new_size_bytes = new_size * header->entry_size + data_offset_;
533 598
534 if (!file->SetLength(new_size_bytes)) { 599 if (!file->SetLength(new_size_bytes)) {
535 // Most likely we are trying to truncate the file, so the header is wrong. 600 // Most likely we are trying to truncate the file, so the header is wrong.
536 if (header->updating < 10 && !FixBlockFileHeader(file)) { 601 if (header->updating < 10 && !FixBlockFileHeader(file_index)) {
537 // If we can't fix the file increase the lock guard so we'll pick it on 602 // If we can't fix the file increase the lock guard so we'll pick it on
538 // the next start and replace it. 603 // the next start and replace it.
539 header->updating = 100; 604 header->updating = 100;
540 return false; 605 return false;
541 } 606 }
542 return (header->max_entries >= new_size); 607 return (header->max_entries >= new_size);
543 } 608 }
544 609
545 FileLock lock(header); 610 FileLock lock(header);
546 header->empty[3] = (new_size - header->max_entries) / 4; // 4 blocks entries 611 header->empty[3] += (new_size - header->max_entries) / 4; // 4 blocks entries
547 header->max_entries = new_size; 612 header->max_entries = new_size;
548 613
549 return true; 614 return true;
550 } 615 }
551 616
552 MappedFile* BlockFiles::FileForNewBlock(FileType block_type, int block_count) { 617 MappedFile* BlockFiles::FileForNewBlock(FileType block_type, int block_count) {
553 COMPILE_ASSERT(RANKINGS == 1, invalid_file_type); 618 COMPILE_ASSERT(RANKINGS == 1, invalid_file_type);
554 MappedFile* file = block_files_[block_type - 1]; 619 MappedFile* file = block_headers_[block_type - 1];
555 BlockHeader file_header(file); 620 BlockHeader file_header(file);
556 621
557 TimeTicks start = TimeTicks::Now(); 622 TimeTicks start = TimeTicks::Now();
558 while (file_header.NeedToGrowBlockFile(block_count)) { 623 while (file_header.NeedToGrowBlockFile(block_count)) {
559 if (kMaxBlocks == file_header.Header()->max_entries) { 624 if (kMaxBlocks == file_header.Header()->max_entries) {
560 file = NextFile(file); 625 file = NextFile(file);
561 if (!file) 626 if (!file)
562 return NULL; 627 return NULL;
563 file_header = BlockHeader(file); 628 file_header = BlockHeader(file);
564 continue; 629 continue;
565 } 630 }
566 631
567 if (!GrowBlockFile(file, file_header.Header())) 632 if (!GrowBlockFile(file_header.Header()))
568 return NULL; 633 return NULL;
569 break; 634 break;
570 } 635 }
571 HISTOGRAM_TIMES("DiskCache.GetFileForNewBlock", TimeTicks::Now() - start); 636 HISTOGRAM_TIMES("DiskCache.GetFileForNewBlock", TimeTicks::Now() - start);
572 return file; 637 return file;
573 } 638 }
574 639
575 MappedFile* BlockFiles::NextFile(MappedFile* file) { 640 MappedFile* BlockFiles::NextFile(MappedFile* file) {
576 ScopedFlush flush(file); 641 ScopedFlush flush(file);
577 BlockFileHeader* header = reinterpret_cast<BlockFileHeader*>(file->buffer()); 642 BlockFileHeader* header = reinterpret_cast<BlockFileHeader*>(file->buffer());
578 int new_file = header->next_file; 643 int new_file = header->next_file;
579 if (!new_file) { 644 if (!new_file) {
580 // RANKINGS is not reported as a type for small entries, but we may be 645 // RANKINGS is not reported as a type for small entries, but we may be
581 // extending the rankings block file. 646 // extending the rankings block file.
582 FileType type = Addr::RequiredFileType(header->entry_size); 647 FileType type = Addr::RequiredFileType(header->entry_size);
583 if (header->entry_size == Addr::BlockSizeForFileType(RANKINGS)) 648 if (header->entry_size == Addr::BlockSizeForFileType(RANKINGS))
584 type = RANKINGS; 649 type = RANKINGS;
585 650
586 new_file = CreateNextBlockFile(type); 651 new_file = CreateNextBlockFile(type);
587 if (!new_file) 652 if (!new_file)
588 return NULL; 653 return NULL;
589 654
590 FileLock lock(header); 655 FileLock lock(header);
591 header->next_file = new_file; 656 header->next_file = new_file;
592 } 657 }
593 658
594 // Only the block_file argument is relevant for what we want. 659 // Only the block_file argument is relevant for what we want.
595 Addr address(BLOCK_256, 1, new_file, 0); 660 Addr address(BLOCK_256, 1, new_file, 0);
596 return GetFile(address); 661 return GetFileHeader(address);
662 }
663
664 int BlockFiles::GetFileIndex(Addr address) {
665 DCHECK(thread_checker_->CalledOnValidThread());
666 DCHECK(block_headers_.size() >= 4);
667 DCHECK(address.is_block_file() || !address.is_initialized());
668 if (!address.is_initialized())
669 return -1;
670
671 int file_index = address.FileNumber();
672 if (static_cast<unsigned int>(file_index) >= block_headers_.size() ||
673 !block_headers_[file_index]) {
674 // We need to open the file
675 if (!OpenBlockFile(file_index))
676 return -1;
677 }
678 DCHECK(block_headers_.size() >= static_cast<unsigned int>(file_index));
679 return file_index;
680 }
681
682 MappedFile* BlockFiles::GetFileHeader(Addr address) {
683 int file_index = GetFileIndex(address);
684 if (file_index < 0)
685 return NULL;
686
687 return block_headers_[file_index];
597 } 688 }
598 689
599 int BlockFiles::CreateNextBlockFile(FileType block_type) { 690 int BlockFiles::CreateNextBlockFile(FileType block_type) {
600 for (int i = kFirstAdditionalBlockFile; i <= kMaxBlockFile; i++) { 691 for (int i = kFirstAdditionalBlockFile; i <= kMaxBlockFile; i++) {
601 if (CreateBlockFile(i, block_type, false)) 692 if (CreateBlockFile(i, block_type, false))
602 return i; 693 return i;
603 } 694 }
604 return 0; 695 return 0;
605 } 696 }
606 697
607 // We walk the list of files for this particular block type, deleting the ones 698 // We walk the list of files for this particular block type, deleting the ones
608 // that are empty. 699 // that are empty.
609 bool BlockFiles::RemoveEmptyFile(FileType block_type) { 700 bool BlockFiles::RemoveEmptyFile(FileType block_type) {
610 MappedFile* file = block_files_[block_type - 1]; 701 MappedFile* file = block_headers_[block_type - 1];
611 BlockFileHeader* header = reinterpret_cast<BlockFileHeader*>(file->buffer()); 702 BlockFileHeader* header = reinterpret_cast<BlockFileHeader*>(file->buffer());
612 703
613 while (header->next_file) { 704 while (header->next_file) {
614 // Only the block_file argument is relevant for what we want. 705 // Only the block_file argument is relevant for what we want.
615 Addr address(BLOCK_256, 1, header->next_file, 0); 706 Addr address(BLOCK_256, 1, header->next_file, 0);
616 MappedFile* next_file = GetFile(address); 707 MappedFile* next_file = GetFileHeader(address);
617 if (!next_file) 708 if (!next_file)
618 return false; 709 return false;
619 710
620 BlockFileHeader* next_header = 711 BlockFileHeader* next_header =
621 reinterpret_cast<BlockFileHeader*>(next_file->buffer()); 712 reinterpret_cast<BlockFileHeader*>(next_file->buffer());
622 if (!next_header->num_entries) { 713 if (!next_header->num_entries) {
623 DCHECK_EQ(next_header->entry_size, header->entry_size); 714 DCHECK_EQ(next_header->entry_size, header->entry_size);
624 // Delete next_file and remove it from the chain. 715 // Delete next_file and remove it from the chain.
625 int file_index = header->next_file; 716 int file_index = header->next_file;
626 header->next_file = next_header->next_file; 717 header->next_file = next_header->next_file;
627 DCHECK(block_files_.size() >= static_cast<unsigned int>(file_index)); 718 DCHECK(block_headers_.size() >= static_cast<unsigned int>(file_index));
628 file->Flush(); 719 file->Flush();
629 720
630 // We get a new handle to the file and release the old one so that the 721 // We get a new handle to the file and release the old one so that the
631 // file gets unmmaped... so we can delete it. 722 // file gets unmmaped... so we can delete it.
632 base::FilePath name = Name(file_index); 723 base::FilePath name = HeaderName(file_index);
633 scoped_refptr<File> this_file(new File(false)); 724 scoped_refptr<File> this_file(new File(false));
634 this_file->Init(name); 725 this_file->Init(name);
635 block_files_[file_index]->Release(); 726 block_headers_[file_index]->Release();
636 block_files_[file_index] = NULL; 727 block_headers_[file_index] = NULL;
637 728
638 int failure = DeleteCacheFile(name) ? 0 : 1; 729 int failure = DeleteCacheFile(name) ? 0 : 1;
639 UMA_HISTOGRAM_COUNTS("DiskCache.DeleteFailed2", failure);
640 if (failure) 730 if (failure)
641 LOG(ERROR) << "Failed to delete " << name.value() << " from the cache."; 731 LOG(ERROR) << "Failed to delete " << name.value() << " from the cache.";
732
733 if (!data_offset_) {
734 name = DataName(file_index);
735 if (!DeleteCacheFile(name)) {
736 failure = 1;
737 LOG(ERROR) << "Failed to delete " << name.value() <<
738 " from the cache.";
739 }
740 block_data_[file_index]->Release();
741 block_data_[file_index] = NULL;
742 }
743 UMA_HISTOGRAM_COUNTS("DiskCache.DeleteFailed2", failure);
642 continue; 744 continue;
643 } 745 }
644 746
645 header = next_header; 747 header = next_header;
646 file = next_file; 748 file = next_file;
647 } 749 }
648 return true; 750 return true;
649 } 751 }
650 752
753 bool BlockFiles::PreallocateSpace(FileType block_type) {
754 MappedFile* file = block_headers_[block_type - 1];
755 BlockHeader file_header(file);
756
757 int empty_blocks = file_header.EmptyBlocks();
758 while (file_header.Header()->next_file) {
759 // Only the block_file argument is relevant for what we want.
760 Addr address(BLOCK_256, 1, file_header.Header()->next_file, 0);
761 MappedFile* next_file = GetFileHeader(address);
762 if (!next_file)
763 return false;
764
765 BlockHeader next_header(next_file);
766 empty_blocks += next_header.EmptyBlocks();
767
768 file_header = next_header;
769 file = next_file;
770 }
771 if (empty_blocks > kNumExtraBlocks * 2 / 3)
772 return true;
773
774 // Restart the search.
775 file = block_headers_[block_type - 1];
776 file_header = BlockHeader(file);
777 while (kMaxBlocks == file_header.Header()->max_entries) {
778 file = NextFile(file);
779 if (!file)
780 return false;
781 file_header = BlockHeader(file);
782 }
783 return GrowBlockFile(file_header.Header());
784 }
785
651 // Note that we expect to be called outside of a FileLock... however, we cannot 786 // Note that we expect to be called outside of a FileLock... however, we cannot
652 // DCHECK on header->updating because we may be fixing a crash. 787 // DCHECK on header->updating because we may be fixing a crash.
653 bool BlockFiles::FixBlockFileHeader(MappedFile* file) { 788 bool BlockFiles::FixBlockFileHeader(int index) {
654 ScopedFlush flush(file); 789 DCHECK_GE(block_headers_.size(), static_cast<unsigned int>(index));
655 BlockHeader file_header(file); 790 MappedFile* header_file = block_headers_[index];
656 int file_size = static_cast<int>(file->GetLength()); 791 ScopedFlush flush(header_file);
657 if (file_size < file_header.Size()) 792 BlockHeader file_header(header_file);
793
794 MappedFile* data_file = data_offset_ ? header_file : block_data_[index];
795 int file_size = static_cast<int>(data_file->GetLength());
796 if (file_size < data_offset_)
658 return false; // file_size > 2GB is also an error. 797 return false; // file_size > 2GB is also an error.
659 798
660 const int kMinBlockSize = 36; 799 const int kMinBlockSize = 36;
661 const int kMaxBlockSize = 4096; 800 const int kMaxBlockSize = 4096;
662 BlockFileHeader* header = file_header.Header(); 801 if (file_header.Header()->entry_size < kMinBlockSize ||
663 if (header->entry_size < kMinBlockSize || 802 file_header.Header()->entry_size > kMaxBlockSize ||
664 header->entry_size > kMaxBlockSize || header->num_entries < 0) 803 file_header.Header()->num_entries < 0)
665 return false; 804 return false;
666 805
667 // Make sure that we survive crashes. 806 // Make sure that we survive crashes.
668 header->updating = 1; 807 file_header.Header()->updating = 1;
669 int expected = header->entry_size * header->max_entries + file_header.Size(); 808 int expected =
809 file_header.Header()->entry_size * file_header.Header()->max_entries +
810 data_offset_;
670 if (file_size != expected) { 811 if (file_size != expected) {
671 int max_expected = header->entry_size * kMaxBlocks + file_header.Size(); 812 int max_expected = file_header.Header()->entry_size * kMaxBlocks +
672 if (file_size < expected || header->empty[3] || file_size > max_expected) { 813 data_offset_;
814 if (file_size < expected || file_header.Header()->empty[3] ||
815 file_size > max_expected) {
673 NOTREACHED(); 816 NOTREACHED();
674 LOG(ERROR) << "Unexpected file size"; 817 LOG(ERROR) << "Unexpected file size";
675 return false; 818 return false;
676 } 819 }
677 // We were in the middle of growing the file. 820 // We were in the middle of growing the file.
678 int num_entries = (file_size - file_header.Size()) / header->entry_size; 821 int num_entries = (file_size - data_offset_) /
679 header->max_entries = num_entries; 822 file_header.Header()->entry_size;
823 file_header.Header()->max_entries = num_entries;
680 } 824 }
681 825
682 file_header.FixAllocationCounters(); 826 file_header.FixAllocationCounters();
683 int empty_blocks = file_header.EmptyBlocks(); 827 int empty_blocks = file_header.EmptyBlocks();
684 if (empty_blocks + header->num_entries > header->max_entries) 828 if (empty_blocks + file_header.Header()->num_entries >
685 header->num_entries = header->max_entries - empty_blocks; 829 file_header.Header()->max_entries) {
830 file_header.Header()->num_entries = file_header.Header()->max_entries -
831 empty_blocks;
832 }
686 833
687 if (!file_header.ValidateCounters()) 834 if (!file_header.ValidateCounters())
688 return false; 835 return false;
689 836
690 header->updating = 0; 837 file_header.Header()->updating = 0;
691 return true; 838 return true;
692 } 839 }
693 840
694 // We are interested in the total number of blocks used by this file type, and 841 // We are interested in the total number of blocks used by this file type, and
695 // the max number of blocks that we can store (reported as the percentage of 842 // the max number of blocks that we can store (reported as the percentage of
696 // used blocks). In order to find out the number of used blocks, we have to 843 // used blocks). In order to find out the number of used blocks, we have to
697 // substract the empty blocks from the total blocks for each file in the chain. 844 // substract the empty blocks from the total blocks for each file in the chain.
698 void BlockFiles::GetFileStats(int index, int* used_count, int* load) { 845 void BlockFiles::GetFileStats(int index, int* used_count, int* load) {
699 int max_blocks = 0; 846 int max_blocks = 0;
700 *used_count = 0; 847 *used_count = 0;
701 *load = 0; 848 *load = 0;
702 for (;;) { 849 for (;;) {
703 if (!block_files_[index] && !OpenBlockFile(index)) 850 if (!block_headers_[index] && !OpenBlockFile(index))
704 return; 851 return;
705 852
706 BlockFileHeader* header = 853 BlockFileHeader* header =
707 reinterpret_cast<BlockFileHeader*>(block_files_[index]->buffer()); 854 reinterpret_cast<BlockFileHeader*>(block_headers_[index]->buffer());
708 855
709 max_blocks += header->max_entries; 856 max_blocks += header->max_entries;
710 int used = header->max_entries; 857 int used = header->max_entries;
711 for (int i = 0; i < kMaxNumBlocks; i++) { 858 for (int i = 0; i < 4; i++) {
712 used -= header->empty[i] * (i + 1); 859 used -= header->empty[i] * (i + 1);
713 DCHECK_GE(used, 0); 860 DCHECK_GE(used, 0);
714 } 861 }
715 *used_count += used; 862 *used_count += used;
716 863
717 if (!header->next_file) 864 if (!header->next_file)
718 break; 865 break;
719 index = header->next_file; 866 index = header->next_file;
720 } 867 }
721 if (max_blocks) 868 if (max_blocks)
722 *load = *used_count * 100 / max_blocks; 869 *load = *used_count * 100 / max_blocks;
723 } 870 }
724 871
725 base::FilePath BlockFiles::Name(int index) { 872 base::FilePath BlockFiles::HeaderName(int index) {
726 // The file format allows for 256 files. 873 // The file format allows for 256 files.
727 DCHECK(index < 256 && index >= 0); 874 DCHECK(index < 256 && index >= 0);
728 std::string tmp = base::StringPrintf("%s%d", kBlockName, index); 875 std::string tmp = base::StringPrintf("%s%d", kBlockName, index);
729 return path_.AppendASCII(tmp); 876 return path_.AppendASCII(tmp);
730 } 877 }
731 878
879 base::FilePath BlockFiles::DataName(int index) {
880 // The file format allows for 256 files.
881 DCHECK(index < 256 || index >= 0);
882 std::string tmp = base::StringPrintf("%s%d_d", kBlockName, index);
883 return path_.AppendASCII(tmp);
884 }
885
732 } // namespace disk_cache 886 } // namespace disk_cache
OLDNEW
« no previous file with comments | « net/disk_cache/block_files.h ('k') | net/disk_cache/block_files_unittest.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698