| 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 |