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

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

Issue 159451: Disk Cache: Delete chained block files when they become empty.... (Closed) Base URL: svn://chrome-svn/chrome/trunk/src/
Patch Set: Created 11 years, 4 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) 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"
11 #include "net/disk_cache/cache_util.h"
11 #include "net/disk_cache/file_lock.h" 12 #include "net/disk_cache/file_lock.h"
12 13
13 using base::Time; 14 using base::Time;
14 15
15 namespace { 16 namespace {
16 17
17 const wchar_t* kBlockName = L"data_"; 18 const wchar_t* kBlockName = L"data_";
18 19
19 // This array is used to perform a fast lookup of the nibble bit pattern to the 20 // This array is used to perform a fast lookup of the nibble bit pattern to the
20 // type of entry that can be stored there (number of consecutive blocks). 21 // type of entry that can be stored there (number of consecutive blocks).
(...skipping 108 matching lines...) Expand 10 before | Expand all | Expand 10 after
129 130
130 for (int j = 0; j < 8; j++, map_block >>= 4) { 131 for (int j = 0; j < 8; j++, map_block >>= 4) {
131 int type = GetMapBlockType(map_block); 132 int type = GetMapBlockType(map_block);
132 if (type) 133 if (type)
133 header->empty[type -1]++; 134 header->empty[type -1]++;
134 } 135 }
135 } 136 }
136 } 137 }
137 138
138 // Returns true if the current block file should not be used as-is to store more 139 // Returns true if the current block file should not be used as-is to store more
139 // records. |block_count| is the number of blocks to allocate, and 140 // records. |block_count| is the number of blocks to allocate.
140 // |use_next_file| is set to true on return if we should use the next file in
141 // the chain, even though we could find empty space on the current file.
142 bool NeedToGrowBlockFile(const disk_cache::BlockFileHeader* header, 141 bool NeedToGrowBlockFile(const disk_cache::BlockFileHeader* header,
143 int block_count, bool* use_next_file) { 142 int block_count) {
144 if ((header->max_entries > disk_cache::kMaxBlocks * 9 / 10) && 143 bool have_space = false;
145 header->next_file) { 144 int empty_blocks = 0;
145 for (int i = 0; i < disk_cache::kMaxNumBlocks; i++) {
146 empty_blocks += header->empty[i] * (i + 1);
147 if (i >= block_count - 1 && header->empty[i])
148 have_space = true;
149 }
150
151 if (header->next_file && (empty_blocks < disk_cache::kMaxBlocks / 10)) {
146 // This file is almost full but we already created another one, don't use 152 // This file is almost full but we already created another one, don't use
147 // this file yet so that it is easier to find empty blocks when we start 153 // this file yet so that it is easier to find empty blocks when we start
148 // using this file again. 154 // using this file again.
149 *use_next_file = true;
150 return true; 155 return true;
151 } 156 }
152 *use_next_file = false; 157 return !have_space;
153 for (int i = block_count; i <= disk_cache::kMaxNumBlocks; i++) {
154 if (header->empty[i - 1])
155 return false;
156 }
157 return true;
158 } 158 }
159 159
160 } // namespace 160 } // namespace
161 161
162 namespace disk_cache { 162 namespace disk_cache {
163 163
164 BlockFiles::~BlockFiles() { 164 BlockFiles::~BlockFiles() {
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(kFirstAdditionlBlockFile);
176 for (int i = 0; i < kFirstAdditionlBlockFile; i++) { 176 for (int i = 0; i < kFirstAdditionlBlockFile; 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
184 // Walk this chain of files removing empty ones.
185 RemoveEmptyFile(static_cast<FileType>(i + 1));
183 } 186 }
184 187
185 init_ = true; 188 init_ = true;
186 return true; 189 return true;
187 } 190 }
188 191
189 void BlockFiles::CloseFiles() { 192 void BlockFiles::CloseFiles() {
190 init_ = false; 193 init_ = false;
191 for (unsigned int i = 0; i < block_files_.size(); i++) { 194 for (unsigned int i = 0; i < block_files_.size(); i++) {
192 if (block_files_[i]) { 195 if (block_files_[i]) {
(...skipping 112 matching lines...) Expand 10 before | Expand all | Expand 10 after
305 308
306 return true; 309 return true;
307 } 310 }
308 311
309 MappedFile* BlockFiles::FileForNewBlock(FileType block_type, int block_count) { 312 MappedFile* BlockFiles::FileForNewBlock(FileType block_type, int block_count) {
310 COMPILE_ASSERT(RANKINGS == 1, invalid_fily_type); 313 COMPILE_ASSERT(RANKINGS == 1, invalid_fily_type);
311 MappedFile* file = block_files_[block_type - 1]; 314 MappedFile* file = block_files_[block_type - 1];
312 BlockFileHeader* header = reinterpret_cast<BlockFileHeader*>(file->buffer()); 315 BlockFileHeader* header = reinterpret_cast<BlockFileHeader*>(file->buffer());
313 316
314 Time start = Time::Now(); 317 Time start = Time::Now();
315 bool use_next_file; 318 while (NeedToGrowBlockFile(header, block_count)) {
316 while (NeedToGrowBlockFile(header, block_count, &use_next_file)) { 319 if (kMaxBlocks == header->max_entries) {
317 if (use_next_file || kMaxBlocks == header->max_entries) {
318 file = NextFile(file); 320 file = NextFile(file);
319 if (!file) 321 if (!file)
320 return NULL; 322 return NULL;
321 header = reinterpret_cast<BlockFileHeader*>(file->buffer()); 323 header = reinterpret_cast<BlockFileHeader*>(file->buffer());
322 continue; 324 continue;
323 } 325 }
324 326
325 if (!GrowBlockFile(file, header)) 327 if (!GrowBlockFile(file, header))
326 return NULL; 328 return NULL;
327 break; 329 break;
(...skipping 26 matching lines...) Expand all
354 } 356 }
355 357
356 int BlockFiles::CreateNextBlockFile(FileType block_type) { 358 int BlockFiles::CreateNextBlockFile(FileType block_type) {
357 for (int i = kFirstAdditionlBlockFile; i <= kMaxBlockFile; i++) { 359 for (int i = kFirstAdditionlBlockFile; i <= kMaxBlockFile; i++) {
358 if (CreateBlockFile(i, block_type, false)) 360 if (CreateBlockFile(i, block_type, false))
359 return i; 361 return i;
360 } 362 }
361 return 0; 363 return 0;
362 } 364 }
363 365
366 // We walk the list of files for this particular block type, deleting the ones
367 // that are empty.
368 void BlockFiles::RemoveEmptyFile(FileType block_type) {
369 MappedFile* file = block_files_[block_type - 1];
370 BlockFileHeader* header = reinterpret_cast<BlockFileHeader*>(file->buffer());
371
372 while (header->next_file) {
373 // Only the block_file argument is relevant for what we want.
374 Addr address(BLOCK_256, 1, header->next_file, 0);
375 MappedFile* next_file = GetFile(address);
376 if (!next_file)
377 return;
378
379 BlockFileHeader* next_header =
380 reinterpret_cast<BlockFileHeader*>(next_file->buffer());
381 if (!next_header->num_entries) {
382 DCHECK_EQ(next_header->entry_size, header->entry_size);
383 // Delete next_file and remove it from the chain.
384 int file_index = header->next_file;
385 header->next_file = next_header->next_file;
386 DCHECK(block_files_.size() >= static_cast<unsigned int>(file_index));
387 block_files_[file_index]->Release();
388 block_files_[file_index] = NULL;
389
390 std::wstring name = Name(file_index);
391 int failure = DeleteCacheFile(name) ? 0 : 1;
392 UMA_HISTOGRAM_COUNTS("DiskCache.DeleteFailed2", failure);
393 if (failure)
394 LOG(ERROR) << "Failed to delete " << name << " from the cache.";
395 continue;
396 }
397
398 header = next_header;
399 file = next_file;
400 }
401 }
402
364 bool BlockFiles::CreateBlock(FileType block_type, int block_count, 403 bool BlockFiles::CreateBlock(FileType block_type, int block_count,
365 Addr* block_address) { 404 Addr* block_address) {
366 if (block_type < RANKINGS || block_type > BLOCK_4K || 405 if (block_type < RANKINGS || block_type > BLOCK_4K ||
367 block_count < 1 || block_count > 4) 406 block_count < 1 || block_count > 4)
368 return false; 407 return false;
369 if (!init_) 408 if (!init_)
370 return false; 409 return false;
371 410
372 MappedFile* file = FileForNewBlock(block_type, block_count); 411 MappedFile* file = FileForNewBlock(block_type, block_count);
373 if (!file) 412 if (!file)
(...skipping 32 matching lines...) Expand 10 before | Expand all | Expand 10 after
406 return; 445 return;
407 446
408 size_t size = address.BlockSize() * address.num_blocks(); 447 size_t size = address.BlockSize() * address.num_blocks();
409 size_t offset = address.start_block() * address.BlockSize() + 448 size_t offset = address.start_block() * address.BlockSize() +
410 kBlockHeaderSize; 449 kBlockHeaderSize;
411 if (deep) 450 if (deep)
412 file->Write(zero_buffer_, size, offset); 451 file->Write(zero_buffer_, size, offset);
413 452
414 BlockFileHeader* header = reinterpret_cast<BlockFileHeader*>(file->buffer()); 453 BlockFileHeader* header = reinterpret_cast<BlockFileHeader*>(file->buffer());
415 DeleteMapBlock(address.start_block(), address.num_blocks(), header); 454 DeleteMapBlock(address.start_block(), address.num_blocks(), header);
455 if (!header->num_entries) {
456 // This file is now empty. Let's try to delete it.
457 FileType type = Addr::RequiredFileType(header->entry_size);
458 if (Addr::BlockSizeForFileType(RANKINGS) == header->entry_size)
459 type = RANKINGS;
460 RemoveEmptyFile(type);
461 }
416 } 462 }
417 463
418 bool BlockFiles::FixBlockFileHeader(MappedFile* file) { 464 bool BlockFiles::FixBlockFileHeader(MappedFile* file) {
419 BlockFileHeader* header = reinterpret_cast<BlockFileHeader*>(file->buffer()); 465 BlockFileHeader* header = reinterpret_cast<BlockFileHeader*>(file->buffer());
420 int file_size = static_cast<int>(file->GetLength()); 466 int file_size = static_cast<int>(file->GetLength());
421 if (file_size < static_cast<int>(sizeof(*header))) 467 if (file_size < static_cast<int>(sizeof(*header)))
422 return false; // file_size > 2GB is also an error. 468 return false; // file_size > 2GB is also an error.
423 469
424 int expected = header->entry_size * header->max_entries + sizeof(*header); 470 int expected = header->entry_size * header->max_entries + sizeof(*header);
425 if (file_size != expected) { 471 if (file_size != expected) {
426 int max_expected = header->entry_size * kMaxBlocks + sizeof(*header); 472 int max_expected = header->entry_size * kMaxBlocks + sizeof(*header);
427 if (file_size < expected || header->empty[3] || file_size > max_expected) { 473 if (file_size < expected || header->empty[3] || file_size > max_expected) {
428 NOTREACHED(); 474 NOTREACHED();
429 LOG(ERROR) << "Unexpected file size"; 475 LOG(ERROR) << "Unexpected file size";
430 return false; 476 return false;
431 } 477 }
432 // We were in the middle of growing the file. 478 // We were in the middle of growing the file.
433 int num_entries = (file_size - sizeof(*header)) / header->entry_size; 479 int num_entries = (file_size - sizeof(*header)) / header->entry_size;
434 header->max_entries = num_entries; 480 header->max_entries = num_entries;
435 } 481 }
436 482
437 FixAllocationCounters(header); 483 FixAllocationCounters(header);
438 header->updating = 0; 484 header->updating = 0;
439 return true; 485 return true;
440 } 486 }
441 487
442 } // namespace disk_cache 488 } // 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