Index: net/disk_cache/v3/block_bitmaps.cc |
=================================================================== |
--- net/disk_cache/v3/block_bitmaps.cc (revision 0) |
+++ net/disk_cache/v3/block_bitmaps.cc (revision 0) |
@@ -0,0 +1,214 @@ |
+// Copyright (c) 2012 The Chromium Authors. All rights reserved. |
+// Use of this source code is governed by a BSD-style license that can be |
+// found in the LICENSE file. |
+ |
+#include "net/disk_cache/v3/block_bitmaps.h" |
+ |
+#include "base/metrics/histogram.h" |
+#include "base/string_util.h" |
+#include "base/stringprintf.h" |
+#include "base/threading/thread_checker.h" |
+#include "base/time.h" |
+#include "net/disk_cache/cache_util.h" |
+#include "net/disk_cache/disk_format_base.h" |
+#include "net/disk_cache/file_lock.h" |
+#include "net/disk_cache/trace.h" |
+#include "net/disk_cache/v3/backend_impl_v3.h" |
+ |
+using base::TimeTicks; |
+ |
+namespace disk_cache { |
+ |
+BlockBitmaps::BlockBitmaps(BackendImplV3* backend) : backend_(backend) { |
+} |
+ |
+BlockBitmaps::~BlockBitmaps() { |
+} |
+ |
+void BlockBitmaps::Init(const BlockFilesBitmaps& bitmaps) { |
+ bitmaps_ = bitmaps; |
+ for (int i = 0; i < kFirstAdditionalBlockFileV3; i++) |
+ empty_counts_[i] = EmptyBlocksForType(i); |
+} |
+ |
+bool BlockBitmaps::CreateBlock(FileType block_type, |
+ int block_count, |
+ Addr* block_address) { |
+ DCHECK_NE(block_type, EXTERNAL); |
+ DCHECK_NE(block_type, RANKINGS); |
+ if (block_count < 1 || block_count > kMaxNumBlocks) |
+ return false; |
+ |
+ int header_num = HeaderNumberForNewBlock(block_type, block_count); |
+ if (header_num < 0) |
+ return false; |
+ |
+ int old_num_allocations = bitmaps_[header_num].MinimumAllocations(); |
+ |
+ int index; |
+ if (!bitmaps_[header_num].CreateMapBlock(block_count, &index)) |
+ return false; |
+ |
+ if (!index && (block_type == BLOCK_ENTRIES || block_type == BLOCK_EVICTED) && |
+ !bitmaps_[header_num].CreateMapBlock(block_count, &index)) { |
+ // index 0 for entries is a reserved value. |
+ return false; |
+ } |
+ |
+ // Yes, the count may be off by 1 when we start. |
+ if (old_num_allocations != bitmaps_[header_num].MinimumAllocations()) |
+ empty_counts_[block_type]--; |
+ |
+ if (empty_counts_[block_type] < (kNumExtraBlocks / kMaxNumBlocks) / 2) |
+ backend_->GrowBlockFiles(); |
+ |
+ Addr address(block_type, block_count, bitmaps_[header_num].FileId(), index); |
+ block_address->set_value(address.value()); |
+ Trace("CreateBlock 0x%x", address.value()); |
+ return true; |
+} |
+ |
+void BlockBitmaps::DeleteBlock(Addr address) { |
+ if (!address.is_initialized() || address.is_separate_file()) |
+ return; |
+ |
+ int header_num = GetHeaderNumber(address); |
+ if (header_num < 0) |
+ return; |
+ |
+ Trace("DeleteBlock 0x%x", address.value()); |
+ bitmaps_[header_num].DeleteMapBlock(address.start_block(), |
+ address.num_blocks()); |
+ |
+ //if (!bitmaps_[header_num].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); // Ignore failures. |
+ //} |
+} |
+ |
+void BlockBitmaps::Clear() { |
+ bitmaps_.clear(); |
+} |
+ |
+void BlockBitmaps::ReportStats() { |
+ int used_blocks[kFirstAdditionalBlockFile]; |
+ int load[kFirstAdditionalBlockFile]; |
+ for (int i = 0; i < kFirstAdditionalBlockFile; i++) { |
+ GetFileStats(i, &used_blocks[i], &load[i]); |
+ } |
+ UMA_HISTOGRAM_COUNTS("DiskCache.Blocks_0", used_blocks[0]); |
+ UMA_HISTOGRAM_COUNTS("DiskCache.Blocks_1", used_blocks[1]); |
+ UMA_HISTOGRAM_COUNTS("DiskCache.Blocks_2", used_blocks[2]); |
+ UMA_HISTOGRAM_COUNTS("DiskCache.Blocks_3", used_blocks[3]); |
+ |
+ UMA_HISTOGRAM_ENUMERATION("DiskCache.BlockLoad_0", load[0], 101); |
+ UMA_HISTOGRAM_ENUMERATION("DiskCache.BlockLoad_1", load[1], 101); |
+ UMA_HISTOGRAM_ENUMERATION("DiskCache.BlockLoad_2", load[2], 101); |
+ UMA_HISTOGRAM_ENUMERATION("DiskCache.BlockLoad_3", load[3], 101); |
+} |
+ |
+bool BlockBitmaps::IsValid(Addr address) { |
+#ifdef NDEBUG |
+ return true; |
+#else |
+ if (!address.is_initialized() || address.is_separate_file()) |
+ return false; |
+ |
+ int header_num = GetHeaderNumber(address); |
+ if (header_num < 0) |
+ return false; |
+ |
+ bool rv = bitmaps_[header_num].UsedMapBlock(address.start_block(), |
+ address.num_blocks()); |
+ DCHECK(rv); |
+ return rv; |
+#endif |
+} |
+ |
+int BlockBitmaps::GetHeaderNumber(Addr address) { |
+ DCHECK_GE(bitmaps_.size(), static_cast<size_t>(kFirstAdditionalBlockFileV3)); |
+ DCHECK(address.is_block_file() || !address.is_initialized()); |
+ if (!address.is_initialized()) |
+ return -1; |
+ |
+ int file_index = address.FileNumber(); |
+ if (static_cast<unsigned int>(file_index) >= bitmaps_.size()) |
+ return -1; |
+ |
+ return file_index; |
+} |
+ |
+int BlockBitmaps::EmptyBlocksForType(int next_file) { |
+ int empty_blocks = 0; |
+ do { |
+ empty_blocks += bitmaps_[next_file].MinimumAllocations(); |
+ next_file = bitmaps_[next_file].NextFileId(); |
+ } while (next_file); |
+ return empty_blocks; |
+} |
+ |
+int BlockBitmaps::HeaderNumberForNewBlock(FileType block_type, |
+ int block_count) { |
+ DCHECK_GT(block_type, 0); |
+ int header_num = block_type - 1; |
+ bool found = true; |
+ |
+ TimeTicks start = TimeTicks::Now(); |
+ while (bitmaps_[header_num].NeedToGrowBlockFile(block_count)) { |
+ header_num = bitmaps_[header_num].NextFileId(); |
+ if (!header_num) { |
+ found = false; |
+ break; |
+ } |
+ } |
+ |
+ if (!found) { |
+ // Restart the search, looking for any file with space. We know that all |
+ // files of this type are low on free blocks, but we cannot grow any file |
+ // at this time. |
+ header_num = block_type - 1; |
+ do { |
+ if (bitmaps_[header_num].CanAllocate(block_count)) { |
+ found = true; // Make sure file 0 is not mistaken with a failure. |
+ break; |
+ } |
+ header_num = bitmaps_[header_num].NextFileId(); |
+ } while (header_num); |
+ |
+ if (!found) { |
+ NOTREACHED(); |
+ header_num = -1; |
+ } |
+ } |
+ |
+ HISTOGRAM_TIMES("DiskCache.GetFileForNewBlock", TimeTicks::Now() - start); |
+ return header_num; |
+} |
+ |
+// We are interested in the total number of blocks used by this file type, and |
+// the max number of blocks that we can store (reported as the percentage of |
+// used blocks). In order to find out the number of used blocks, we have to |
+// substract the empty blocks from the total blocks for each file in the chain. |
+void BlockBitmaps::GetFileStats(int index, int* used_count, int* load) { |
+ int max_blocks = 0; |
+ *used_count = 0; |
+ *load = 0; |
+ do { |
+ int capacity = bitmaps_[index].Capacity(); |
+ int used = capacity - bitmaps_[index].EmptyBlocks(); |
+ DCHECK_GE(used, 0); |
+ |
+ max_blocks += capacity; |
+ *used_count += used; |
+ |
+ index = bitmaps_[index].NextFileId(); |
+ } while (index); |
+ |
+ if (max_blocks) |
+ *load = *used_count * 100 / max_blocks; |
+} |
+ |
+} // namespace disk_cache |
Property changes on: net\disk_cache\v3\block_bitmaps.cc |
___________________________________________________________________ |
Added: svn:eol-style |
+ LF |