summaryrefslogtreecommitdiffstats
path: root/net/disk_cache/block_files.cc
diff options
context:
space:
mode:
authorrvargas@google.com <rvargas@google.com@0039d316-1c4b-4281-b951-d872f2087c98>2009-07-28 00:35:25 +0000
committerrvargas@google.com <rvargas@google.com@0039d316-1c4b-4281-b951-d872f2087c98>2009-07-28 00:35:25 +0000
commit5c0767d1facaf222cd17956fdf40618173f46a0e (patch)
tree0a2d3c5895d40e65a12f71545cc640959a6c91fb /net/disk_cache/block_files.cc
parentad3d2542c02e8a3dba898d5bcf434d301b0862cf (diff)
downloadchromium_src-5c0767d1facaf222cd17956fdf40618173f46a0e.zip
chromium_src-5c0767d1facaf222cd17956fdf40618173f46a0e.tar.gz
chromium_src-5c0767d1facaf222cd17956fdf40618173f46a0e.tar.bz2
Disk Cache: Delete chained block files when they become empty.
We were leaving empty block files in the chain, and worst of all, not reusing them because we were thinking that these files were "almost full". Now we also check for empty files when the cache starts. BUG=16740 TEST=unittest. Review URL: http://codereview.chromium.org/159451 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@21762 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'net/disk_cache/block_files.cc')
-rw-r--r--net/disk_cache/block_files.cc78
1 files changed, 62 insertions, 16 deletions
diff --git a/net/disk_cache/block_files.cc b/net/disk_cache/block_files.cc
index 8c8d2e2..cd7e5cf 100644
--- a/net/disk_cache/block_files.cc
+++ b/net/disk_cache/block_files.cc
@@ -8,6 +8,7 @@
#include "base/histogram.h"
#include "base/string_util.h"
#include "base/time.h"
+#include "net/disk_cache/cache_util.h"
#include "net/disk_cache/file_lock.h"
using base::Time;
@@ -136,25 +137,24 @@ void FixAllocationCounters(disk_cache::BlockFileHeader* header) {
}
// Returns true if the current block file should not be used as-is to store more
-// records. |block_count| is the number of blocks to allocate, and
-// |use_next_file| is set to true on return if we should use the next file in
-// the chain, even though we could find empty space on the current file.
+// records. |block_count| is the number of blocks to allocate.
bool NeedToGrowBlockFile(const disk_cache::BlockFileHeader* header,
- int block_count, bool* use_next_file) {
- if ((header->max_entries > disk_cache::kMaxBlocks * 9 / 10) &&
- header->next_file) {
+ int block_count) {
+ bool have_space = false;
+ int empty_blocks = 0;
+ for (int i = 0; i < disk_cache::kMaxNumBlocks; i++) {
+ empty_blocks += header->empty[i] * (i + 1);
+ if (i >= block_count - 1 && header->empty[i])
+ have_space = true;
+ }
+
+ if (header->next_file && (empty_blocks < disk_cache::kMaxBlocks / 10)) {
// This file is almost full but we already created another one, don't use
// this file yet so that it is easier to find empty blocks when we start
// using this file again.
- *use_next_file = true;
return true;
}
- *use_next_file = false;
- for (int i = block_count; i <= disk_cache::kMaxNumBlocks; i++) {
- if (header->empty[i - 1])
- return false;
- }
- return true;
+ return !have_space;
}
} // namespace
@@ -180,6 +180,9 @@ bool BlockFiles::Init(bool create_files) {
if (!OpenBlockFile(i))
return false;
+
+ // Walk this chain of files removing empty ones.
+ RemoveEmptyFile(static_cast<FileType>(i + 1));
}
init_ = true;
@@ -312,9 +315,8 @@ MappedFile* BlockFiles::FileForNewBlock(FileType block_type, int block_count) {
BlockFileHeader* header = reinterpret_cast<BlockFileHeader*>(file->buffer());
Time start = Time::Now();
- bool use_next_file;
- while (NeedToGrowBlockFile(header, block_count, &use_next_file)) {
- if (use_next_file || kMaxBlocks == header->max_entries) {
+ while (NeedToGrowBlockFile(header, block_count)) {
+ if (kMaxBlocks == header->max_entries) {
file = NextFile(file);
if (!file)
return NULL;
@@ -361,6 +363,43 @@ int BlockFiles::CreateNextBlockFile(FileType block_type) {
return 0;
}
+// We walk the list of files for this particular block type, deleting the ones
+// that are empty.
+void BlockFiles::RemoveEmptyFile(FileType block_type) {
+ MappedFile* file = block_files_[block_type - 1];
+ BlockFileHeader* header = reinterpret_cast<BlockFileHeader*>(file->buffer());
+
+ while (header->next_file) {
+ // Only the block_file argument is relevant for what we want.
+ Addr address(BLOCK_256, 1, header->next_file, 0);
+ MappedFile* next_file = GetFile(address);
+ if (!next_file)
+ return;
+
+ BlockFileHeader* next_header =
+ reinterpret_cast<BlockFileHeader*>(next_file->buffer());
+ if (!next_header->num_entries) {
+ DCHECK_EQ(next_header->entry_size, header->entry_size);
+ // Delete next_file and remove it from the chain.
+ int file_index = header->next_file;
+ header->next_file = next_header->next_file;
+ DCHECK(block_files_.size() >= static_cast<unsigned int>(file_index));
+ block_files_[file_index]->Release();
+ block_files_[file_index] = NULL;
+
+ std::wstring name = Name(file_index);
+ int failure = DeleteCacheFile(name) ? 0 : 1;
+ UMA_HISTOGRAM_COUNTS("DiskCache.DeleteFailed2", failure);
+ if (failure)
+ LOG(ERROR) << "Failed to delete " << name << " from the cache.";
+ continue;
+ }
+
+ header = next_header;
+ file = next_file;
+ }
+}
+
bool BlockFiles::CreateBlock(FileType block_type, int block_count,
Addr* block_address) {
if (block_type < RANKINGS || block_type > BLOCK_4K ||
@@ -413,6 +452,13 @@ void BlockFiles::DeleteBlock(Addr address, bool deep) {
BlockFileHeader* header = reinterpret_cast<BlockFileHeader*>(file->buffer());
DeleteMapBlock(address.start_block(), address.num_blocks(), header);
+ if (!header->num_entries) {
+ // This file is now empty. Let's try to delete it.
+ FileType type = Addr::RequiredFileType(header->entry_size);
+ if (Addr::BlockSizeForFileType(RANKINGS) == header->entry_size)
+ type = RANKINGS;
+ RemoveEmptyFile(type);
+ }
}
bool BlockFiles::FixBlockFileHeader(MappedFile* file) {