Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 // Copyright (c) 2006-2008 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2006-2008 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/histogram.h" | 8 #include "base/histogram.h" |
| 9 #include "base/string_util.h" | 9 #include "base/string_util.h" |
| 10 #include "base/time.h" | 10 #include "base/time.h" |
| (...skipping 154 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 165 if (zero_buffer_) | 165 if (zero_buffer_) |
| 166 delete[] zero_buffer_; | 166 delete[] zero_buffer_; |
| 167 CloseFiles(); | 167 CloseFiles(); |
| 168 } | 168 } |
| 169 | 169 |
| 170 bool BlockFiles::Init(bool create_files) { | 170 bool BlockFiles::Init(bool create_files) { |
| 171 DCHECK(!init_); | 171 DCHECK(!init_); |
| 172 if (init_) | 172 if (init_) |
| 173 return false; | 173 return false; |
| 174 | 174 |
| 175 block_files_.resize(kFirstAdditionlBlockFile); | 175 block_files_.resize(kFirstAdditionalBlockFile); |
| 176 for (int i = 0; i < kFirstAdditionlBlockFile; i++) { | 176 for (int i = 0; i < kFirstAdditionalBlockFile; i++) { |
| 177 if (create_files) | 177 if (create_files) |
| 178 if (!CreateBlockFile(i, static_cast<FileType>(i + 1), true)) | 178 if (!CreateBlockFile(i, static_cast<FileType>(i + 1), true)) |
| 179 return false; | 179 return false; |
| 180 | 180 |
| 181 if (!OpenBlockFile(i)) | 181 if (!OpenBlockFile(i)) |
| 182 return false; | 182 return false; |
| 183 | 183 |
| 184 // Walk this chain of files removing empty ones. | 184 // Walk this chain of files removing empty ones. |
| 185 RemoveEmptyFile(static_cast<FileType>(i + 1)); | 185 RemoveEmptyFile(static_cast<FileType>(i + 1)); |
| 186 } | 186 } |
| 187 | 187 |
| 188 init_ = true; | 188 init_ = true; |
| 189 return true; | 189 return true; |
| 190 } | 190 } |
| 191 | 191 |
| 192 void BlockFiles::CloseFiles() { | 192 void BlockFiles::CloseFiles() { |
| 193 init_ = false; | 193 init_ = false; |
| 194 for (unsigned int i = 0; i < block_files_.size(); i++) { | 194 for (unsigned int i = 0; i < block_files_.size(); i++) { |
| 195 if (block_files_[i]) { | 195 if (block_files_[i]) { |
| 196 block_files_[i]->Release(); | 196 block_files_[i]->Release(); |
| 197 block_files_[i] = NULL; | 197 block_files_[i] = NULL; |
| 198 } | 198 } |
| 199 } | 199 } |
| 200 block_files_.clear(); | 200 block_files_.clear(); |
| 201 } | 201 } |
| 202 | 202 |
| 203 FilePath BlockFiles::Name(int index) { | 203 void BlockFiles::ReportStats() { |
| 204 // The file format allows for 256 files. | 204 int used_blocks[kFirstAdditionalBlockFile]; |
| 205 DCHECK(index < 256 || index >= 0); | 205 int load[kFirstAdditionalBlockFile]; |
| 206 std::string tmp = StringPrintf("%s%d", kBlockName, index); | 206 for (int i = 0; i < kFirstAdditionalBlockFile; i++) { |
| 207 return path_.AppendASCII(tmp); | 207 GetFileStats(i, &used_blocks[i], &load[i]); |
| 208 } | |
| 209 UMA_HISTOGRAM_COUNTS("Blocks_0", used_blocks[0]); | |
| 210 UMA_HISTOGRAM_COUNTS("Blocks_1", used_blocks[1]); | |
| 211 UMA_HISTOGRAM_COUNTS("Blocks_2", used_blocks[2]); | |
| 212 UMA_HISTOGRAM_COUNTS("Blocks_3", used_blocks[3]); | |
| 213 | |
| 214 UMA_HISTOGRAM_ENUMERATION("BlockLoad_0", load[0], 101); | |
| 215 UMA_HISTOGRAM_ENUMERATION("BlockLoad_1", load[1], 101); | |
| 216 UMA_HISTOGRAM_ENUMERATION("BlockLoad_2", load[2], 101); | |
| 217 UMA_HISTOGRAM_ENUMERATION("BlockLoad_3", load[3], 101); | |
| 208 } | 218 } |
| 209 | 219 |
| 210 bool BlockFiles::CreateBlockFile(int index, FileType file_type, bool force) { | 220 bool BlockFiles::CreateBlockFile(int index, FileType file_type, bool force) { |
| 211 FilePath name = Name(index); | 221 FilePath name = Name(index); |
| 212 int flags = | 222 int flags = |
| 213 force ? base::PLATFORM_FILE_CREATE_ALWAYS : base::PLATFORM_FILE_CREATE; | 223 force ? base::PLATFORM_FILE_CREATE_ALWAYS : base::PLATFORM_FILE_CREATE; |
| 214 flags |= base::PLATFORM_FILE_WRITE | base::PLATFORM_FILE_EXCLUSIVE_WRITE; | 224 flags |= base::PLATFORM_FILE_WRITE | base::PLATFORM_FILE_EXCLUSIVE_WRITE; |
| 215 | 225 |
| 216 scoped_refptr<File> file(new File( | 226 scoped_refptr<File> file(new File( |
| 217 base::CreatePlatformFile(name, flags, NULL))); | 227 base::CreatePlatformFile(name, flags, NULL))); |
| (...skipping 16 matching lines...) Expand all Loading... | |
| 234 } | 244 } |
| 235 | 245 |
| 236 FilePath name = Name(index); | 246 FilePath name = Name(index); |
| 237 scoped_refptr<MappedFile> file(new MappedFile()); | 247 scoped_refptr<MappedFile> file(new MappedFile()); |
| 238 | 248 |
| 239 if (!file->Init(name, kBlockHeaderSize)) { | 249 if (!file->Init(name, kBlockHeaderSize)) { |
| 240 LOG(ERROR) << "Failed to open " << name.value(); | 250 LOG(ERROR) << "Failed to open " << name.value(); |
| 241 return false; | 251 return false; |
| 242 } | 252 } |
| 243 | 253 |
| 244 if (file->GetLength() < static_cast<size_t>(kBlockHeaderSize)) { | 254 size_t file_len = file->GetLength(); |
|
gavinp
2010/07/15 15:03:48
nit: const
rvargas (doing something else)
2010/07/15 18:31:50
What do you mean?
if you mean const size_t file_l
| |
| 255 if (file_len < static_cast<size_t>(kBlockHeaderSize)) { | |
| 245 LOG(ERROR) << "File too small " << name.value(); | 256 LOG(ERROR) << "File too small " << name.value(); |
| 246 return false; | 257 return false; |
| 247 } | 258 } |
| 248 | 259 |
| 249 BlockFileHeader* header = reinterpret_cast<BlockFileHeader*>(file->buffer()); | 260 BlockFileHeader* header = reinterpret_cast<BlockFileHeader*>(file->buffer()); |
| 250 if (kBlockMagic != header->magic || kCurrentVersion != header->version) { | 261 if (kBlockMagic != header->magic || kCurrentVersion != header->version) { |
| 251 LOG(ERROR) << "Invalid file version or magic"; | 262 LOG(ERROR) << "Invalid file version or magic"; |
| 252 return false; | 263 return false; |
| 253 } | 264 } |
| 254 | 265 |
| 255 if (header->updating) { | 266 if (header->updating) { |
| 256 // Last instance was not properly shutdown. | 267 // Last instance was not properly shutdown. |
| 257 if (!FixBlockFileHeader(file)) | 268 if (!FixBlockFileHeader(file)) |
| 258 return false; | 269 return false; |
| 259 } | 270 } |
| 260 | 271 |
| 272 if (index == 0) { | |
| 273 // Load the links file into memory with a single read. | |
| 274 scoped_array<char> buf(new char[file_len]); | |
| 275 if (!file->Read(buf.get(), file_len, 0)) | |
| 276 return false; | |
| 277 } | |
| 278 | |
| 261 DCHECK(!block_files_[index]); | 279 DCHECK(!block_files_[index]); |
| 262 file.swap(&block_files_[index]); | 280 file.swap(&block_files_[index]); |
| 263 return true; | 281 return true; |
| 264 } | 282 } |
| 265 | 283 |
| 266 MappedFile* BlockFiles::GetFile(Addr address) { | 284 MappedFile* BlockFiles::GetFile(Addr address) { |
| 267 DCHECK(block_files_.size() >= 4); | 285 DCHECK(block_files_.size() >= 4); |
| 268 DCHECK(address.is_block_file() || !address.is_initialized()); | 286 DCHECK(address.is_block_file() || !address.is_initialized()); |
| 269 if (!address.is_initialized()) | 287 if (!address.is_initialized()) |
| 270 return NULL; | 288 return NULL; |
| (...skipping 78 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 349 FileLock lock(header); | 367 FileLock lock(header); |
| 350 header->next_file = new_file; | 368 header->next_file = new_file; |
| 351 } | 369 } |
| 352 | 370 |
| 353 // Only the block_file argument is relevant for what we want. | 371 // Only the block_file argument is relevant for what we want. |
| 354 Addr address(BLOCK_256, 1, new_file, 0); | 372 Addr address(BLOCK_256, 1, new_file, 0); |
| 355 return GetFile(address); | 373 return GetFile(address); |
| 356 } | 374 } |
| 357 | 375 |
| 358 int BlockFiles::CreateNextBlockFile(FileType block_type) { | 376 int BlockFiles::CreateNextBlockFile(FileType block_type) { |
| 359 for (int i = kFirstAdditionlBlockFile; i <= kMaxBlockFile; i++) { | 377 for (int i = kFirstAdditionalBlockFile; i <= kMaxBlockFile; i++) { |
| 360 if (CreateBlockFile(i, block_type, false)) | 378 if (CreateBlockFile(i, block_type, false)) |
| 361 return i; | 379 return i; |
| 362 } | 380 } |
| 363 return 0; | 381 return 0; |
| 364 } | 382 } |
| 365 | 383 |
| 366 // We walk the list of files for this particular block type, deleting the ones | 384 // We walk the list of files for this particular block type, deleting the ones |
| 367 // that are empty. | 385 // that are empty. |
| 368 void BlockFiles::RemoveEmptyFile(FileType block_type) { | 386 void BlockFiles::RemoveEmptyFile(FileType block_type) { |
| 369 MappedFile* file = block_files_[block_type - 1]; | 387 MappedFile* file = block_files_[block_type - 1]; |
| (...skipping 108 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 478 // We were in the middle of growing the file. | 496 // We were in the middle of growing the file. |
| 479 int num_entries = (file_size - sizeof(*header)) / header->entry_size; | 497 int num_entries = (file_size - sizeof(*header)) / header->entry_size; |
| 480 header->max_entries = num_entries; | 498 header->max_entries = num_entries; |
| 481 } | 499 } |
| 482 | 500 |
| 483 FixAllocationCounters(header); | 501 FixAllocationCounters(header); |
| 484 header->updating = 0; | 502 header->updating = 0; |
| 485 return true; | 503 return true; |
| 486 } | 504 } |
| 487 | 505 |
| 506 // We are interested in the total number of block used by this file type, and | |
| 507 // the max number of blocks that we can store (reported as the percentage of | |
| 508 // used blocks). In order to find out the number of used blocks, we have to | |
| 509 // substract the empty blocks from the total blocks for each file in the chain. | |
| 510 void BlockFiles::GetFileStats(int index, int* used_count, int* load) { | |
| 511 int max_blocks = 0; | |
| 512 *used_count = 0; | |
| 513 *load = 0; | |
| 514 for (;;) { | |
| 515 if (!block_files_[index] && !OpenBlockFile(index)) | |
| 516 return; | |
| 517 | |
| 518 BlockFileHeader* header = | |
| 519 reinterpret_cast<BlockFileHeader*>(block_files_[index]->buffer()); | |
| 520 | |
| 521 max_blocks += header->max_entries; | |
| 522 int used = header->max_entries; | |
| 523 for (int i = 0; i < 4; i++) { | |
| 524 used -= header->empty[i] * (i + 1); | |
|
nsylvain
2010/07/15 05:47:04
What does header->empty[i] contain? This looks a l
rvargas (doing something else)
2010/07/15 18:31:50
empty is an array of 4 slots that keeps the number
| |
| 525 DCHECK_GE(used, 0); | |
| 526 } | |
| 527 *used_count += used; | |
| 528 | |
| 529 if (!header->next_file) | |
| 530 break; | |
| 531 index = header->next_file; | |
| 532 } | |
| 533 if (max_blocks) | |
| 534 *load = *used_count * 100 / max_blocks; | |
| 535 } | |
| 536 | |
| 537 FilePath BlockFiles::Name(int index) { | |
| 538 // The file format allows for 256 files. | |
| 539 DCHECK(index < 256 || index >= 0); | |
| 540 std::string tmp = StringPrintf("%s%d", kBlockName, index); | |
| 541 return path_.AppendASCII(tmp); | |
| 542 } | |
| 543 | |
| 488 } // namespace disk_cache | 544 } // namespace disk_cache |
| OLD | NEW |