OLD | NEW |
1 // Copyright (c) 2006-2010 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2006-2010 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/file_util.h" | 7 #include "base/file_util.h" |
8 #include "base/metrics/histogram.h" | 8 #include "base/metrics/histogram.h" |
9 #include "base/string_util.h" | 9 #include "base/string_util.h" |
10 #include "base/stringprintf.h" | 10 #include "base/stringprintf.h" |
(...skipping 202 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
213 return false; | 213 return false; |
214 | 214 |
215 // Walk this chain of files removing empty ones. | 215 // Walk this chain of files removing empty ones. |
216 RemoveEmptyFile(static_cast<FileType>(i + 1)); | 216 RemoveEmptyFile(static_cast<FileType>(i + 1)); |
217 } | 217 } |
218 | 218 |
219 init_ = true; | 219 init_ = true; |
220 return true; | 220 return true; |
221 } | 221 } |
222 | 222 |
| 223 MappedFile* BlockFiles::GetFile(Addr address) { |
| 224 DCHECK(thread_checker_->CalledOnValidThread()); |
| 225 DCHECK(block_files_.size() >= 4); |
| 226 DCHECK(address.is_block_file() || !address.is_initialized()); |
| 227 if (!address.is_initialized()) |
| 228 return NULL; |
| 229 |
| 230 int file_index = address.FileNumber(); |
| 231 if (static_cast<unsigned int>(file_index) >= block_files_.size() || |
| 232 !block_files_[file_index]) { |
| 233 // We need to open the file |
| 234 if (!OpenBlockFile(file_index)) |
| 235 return NULL; |
| 236 } |
| 237 DCHECK(block_files_.size() >= static_cast<unsigned int>(file_index)); |
| 238 return block_files_[file_index]; |
| 239 } |
| 240 |
| 241 bool BlockFiles::CreateBlock(FileType block_type, int block_count, |
| 242 Addr* block_address) { |
| 243 DCHECK(thread_checker_->CalledOnValidThread()); |
| 244 if (block_type < RANKINGS || block_type > BLOCK_4K || |
| 245 block_count < 1 || block_count > 4) |
| 246 return false; |
| 247 if (!init_) |
| 248 return false; |
| 249 |
| 250 MappedFile* file = FileForNewBlock(block_type, block_count); |
| 251 if (!file) |
| 252 return false; |
| 253 |
| 254 BlockFileHeader* header = reinterpret_cast<BlockFileHeader*>(file->buffer()); |
| 255 |
| 256 int target_size = 0; |
| 257 for (int i = block_count; i <= 4; i++) { |
| 258 if (header->empty[i - 1]) { |
| 259 target_size = i; |
| 260 break; |
| 261 } |
| 262 } |
| 263 |
| 264 DCHECK(target_size); |
| 265 int index; |
| 266 if (!CreateMapBlock(target_size, block_count, header, &index)) |
| 267 return false; |
| 268 |
| 269 Addr address(block_type, block_count, header->this_file, index); |
| 270 block_address->set_value(address.value()); |
| 271 Trace("CreateBlock 0x%x", address.value()); |
| 272 return true; |
| 273 } |
| 274 |
| 275 void BlockFiles::DeleteBlock(Addr address, bool deep) { |
| 276 DCHECK(thread_checker_->CalledOnValidThread()); |
| 277 if (!address.is_initialized() || address.is_separate_file()) |
| 278 return; |
| 279 |
| 280 if (!zero_buffer_) { |
| 281 zero_buffer_ = new char[Addr::BlockSizeForFileType(BLOCK_4K) * 4]; |
| 282 memset(zero_buffer_, 0, Addr::BlockSizeForFileType(BLOCK_4K) * 4); |
| 283 } |
| 284 MappedFile* file = GetFile(address); |
| 285 if (!file) |
| 286 return; |
| 287 |
| 288 Trace("DeleteBlock 0x%x", address.value()); |
| 289 |
| 290 BlockFileHeader* header = reinterpret_cast<BlockFileHeader*>(file->buffer()); |
| 291 DeleteMapBlock(address.start_block(), address.num_blocks(), header); |
| 292 |
| 293 size_t size = address.BlockSize() * address.num_blocks(); |
| 294 size_t offset = address.start_block() * address.BlockSize() + |
| 295 kBlockHeaderSize; |
| 296 if (deep) |
| 297 file->Write(zero_buffer_, size, offset); |
| 298 |
| 299 if (!header->num_entries) { |
| 300 // This file is now empty. Let's try to delete it. |
| 301 FileType type = Addr::RequiredFileType(header->entry_size); |
| 302 if (Addr::BlockSizeForFileType(RANKINGS) == header->entry_size) |
| 303 type = RANKINGS; |
| 304 RemoveEmptyFile(type); |
| 305 } |
| 306 } |
| 307 |
223 void BlockFiles::CloseFiles() { | 308 void BlockFiles::CloseFiles() { |
224 if (init_) { | 309 if (init_) { |
225 DCHECK(thread_checker_->CalledOnValidThread()); | 310 DCHECK(thread_checker_->CalledOnValidThread()); |
226 } | 311 } |
227 init_ = false; | 312 init_ = false; |
228 for (unsigned int i = 0; i < block_files_.size(); i++) { | 313 for (unsigned int i = 0; i < block_files_.size(); i++) { |
229 if (block_files_[i]) { | 314 if (block_files_[i]) { |
230 block_files_[i]->Release(); | 315 block_files_[i]->Release(); |
231 block_files_[i] = NULL; | 316 block_files_[i] = NULL; |
232 } | 317 } |
(...skipping 106 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
339 scoped_array<char> buf(new char[file_len]); | 424 scoped_array<char> buf(new char[file_len]); |
340 if (!file->Read(buf.get(), file_len, 0)) | 425 if (!file->Read(buf.get(), file_len, 0)) |
341 return false; | 426 return false; |
342 } | 427 } |
343 | 428 |
344 DCHECK(!block_files_[index]); | 429 DCHECK(!block_files_[index]); |
345 file.swap(&block_files_[index]); | 430 file.swap(&block_files_[index]); |
346 return true; | 431 return true; |
347 } | 432 } |
348 | 433 |
349 MappedFile* BlockFiles::GetFile(Addr address) { | |
350 DCHECK(thread_checker_->CalledOnValidThread()); | |
351 DCHECK(block_files_.size() >= 4); | |
352 DCHECK(address.is_block_file() || !address.is_initialized()); | |
353 if (!address.is_initialized()) | |
354 return NULL; | |
355 | |
356 int file_index = address.FileNumber(); | |
357 if (static_cast<unsigned int>(file_index) >= block_files_.size() || | |
358 !block_files_[file_index]) { | |
359 // We need to open the file | |
360 if (!OpenBlockFile(file_index)) | |
361 return NULL; | |
362 } | |
363 DCHECK(block_files_.size() >= static_cast<unsigned int>(file_index)); | |
364 return block_files_[file_index]; | |
365 } | |
366 | |
367 bool BlockFiles::GrowBlockFile(MappedFile* file, BlockFileHeader* header) { | 434 bool BlockFiles::GrowBlockFile(MappedFile* file, BlockFileHeader* header) { |
368 if (kMaxBlocks == header->max_entries) | 435 if (kMaxBlocks == header->max_entries) |
369 return false; | 436 return false; |
370 | 437 |
371 DCHECK(!header->empty[3]); | 438 DCHECK(!header->empty[3]); |
372 int new_size = header->max_entries + 1024; | 439 int new_size = header->max_entries + 1024; |
373 if (new_size > kMaxBlocks) | 440 if (new_size > kMaxBlocks) |
374 new_size = kMaxBlocks; | 441 new_size = kMaxBlocks; |
375 | 442 |
376 int new_size_bytes = new_size * header->entry_size + sizeof(*header); | 443 int new_size_bytes = new_size * header->entry_size + sizeof(*header); |
(...skipping 105 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
482 if (failure) | 549 if (failure) |
483 LOG(ERROR) << "Failed to delete " << name.value() << " from the cache."; | 550 LOG(ERROR) << "Failed to delete " << name.value() << " from the cache."; |
484 continue; | 551 continue; |
485 } | 552 } |
486 | 553 |
487 header = next_header; | 554 header = next_header; |
488 file = next_file; | 555 file = next_file; |
489 } | 556 } |
490 } | 557 } |
491 | 558 |
492 bool BlockFiles::CreateBlock(FileType block_type, int block_count, | |
493 Addr* block_address) { | |
494 DCHECK(thread_checker_->CalledOnValidThread()); | |
495 if (block_type < RANKINGS || block_type > BLOCK_4K || | |
496 block_count < 1 || block_count > 4) | |
497 return false; | |
498 if (!init_) | |
499 return false; | |
500 | |
501 MappedFile* file = FileForNewBlock(block_type, block_count); | |
502 if (!file) | |
503 return false; | |
504 | |
505 BlockFileHeader* header = reinterpret_cast<BlockFileHeader*>(file->buffer()); | |
506 | |
507 int target_size = 0; | |
508 for (int i = block_count; i <= 4; i++) { | |
509 if (header->empty[i - 1]) { | |
510 target_size = i; | |
511 break; | |
512 } | |
513 } | |
514 | |
515 DCHECK(target_size); | |
516 int index; | |
517 if (!CreateMapBlock(target_size, block_count, header, &index)) | |
518 return false; | |
519 | |
520 Addr address(block_type, block_count, header->this_file, index); | |
521 block_address->set_value(address.value()); | |
522 Trace("CreateBlock 0x%x", address.value()); | |
523 return true; | |
524 } | |
525 | |
526 void BlockFiles::DeleteBlock(Addr address, bool deep) { | |
527 DCHECK(thread_checker_->CalledOnValidThread()); | |
528 if (!address.is_initialized() || address.is_separate_file()) | |
529 return; | |
530 | |
531 if (!zero_buffer_) { | |
532 zero_buffer_ = new char[Addr::BlockSizeForFileType(BLOCK_4K) * 4]; | |
533 memset(zero_buffer_, 0, Addr::BlockSizeForFileType(BLOCK_4K) * 4); | |
534 } | |
535 MappedFile* file = GetFile(address); | |
536 if (!file) | |
537 return; | |
538 | |
539 Trace("DeleteBlock 0x%x", address.value()); | |
540 | |
541 BlockFileHeader* header = reinterpret_cast<BlockFileHeader*>(file->buffer()); | |
542 DeleteMapBlock(address.start_block(), address.num_blocks(), header); | |
543 | |
544 size_t size = address.BlockSize() * address.num_blocks(); | |
545 size_t offset = address.start_block() * address.BlockSize() + | |
546 kBlockHeaderSize; | |
547 if (deep) | |
548 file->Write(zero_buffer_, size, offset); | |
549 | |
550 if (!header->num_entries) { | |
551 // This file is now empty. Let's try to delete it. | |
552 FileType type = Addr::RequiredFileType(header->entry_size); | |
553 if (Addr::BlockSizeForFileType(RANKINGS) == header->entry_size) | |
554 type = RANKINGS; | |
555 RemoveEmptyFile(type); | |
556 } | |
557 } | |
558 | |
559 bool BlockFiles::FixBlockFileHeader(MappedFile* file) { | 559 bool BlockFiles::FixBlockFileHeader(MappedFile* file) { |
560 BlockFileHeader* header = reinterpret_cast<BlockFileHeader*>(file->buffer()); | 560 BlockFileHeader* header = reinterpret_cast<BlockFileHeader*>(file->buffer()); |
561 int file_size = static_cast<int>(file->GetLength()); | 561 int file_size = static_cast<int>(file->GetLength()); |
562 if (file_size < static_cast<int>(sizeof(*header))) | 562 if (file_size < static_cast<int>(sizeof(*header))) |
563 return false; // file_size > 2GB is also an error. | 563 return false; // file_size > 2GB is also an error. |
564 | 564 |
565 int expected = header->entry_size * header->max_entries + sizeof(*header); | 565 int expected = header->entry_size * header->max_entries + sizeof(*header); |
566 if (file_size != expected) { | 566 if (file_size != expected) { |
567 int max_expected = header->entry_size * kMaxBlocks + sizeof(*header); | 567 int max_expected = header->entry_size * kMaxBlocks + sizeof(*header); |
568 if (file_size < expected || header->empty[3] || file_size > max_expected) { | 568 if (file_size < expected || header->empty[3] || file_size > max_expected) { |
(...skipping 43 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
612 } | 612 } |
613 | 613 |
614 FilePath BlockFiles::Name(int index) { | 614 FilePath BlockFiles::Name(int index) { |
615 // The file format allows for 256 files. | 615 // The file format allows for 256 files. |
616 DCHECK(index < 256 || index >= 0); | 616 DCHECK(index < 256 || index >= 0); |
617 std::string tmp = base::StringPrintf("%s%d", kBlockName, index); | 617 std::string tmp = base::StringPrintf("%s%d", kBlockName, index); |
618 return path_.AppendASCII(tmp); | 618 return path_.AppendASCII(tmp); |
619 } | 619 } |
620 | 620 |
621 } // namespace disk_cache | 621 } // namespace disk_cache |
OLD | NEW |