OLD | NEW |
(Empty) | |
| 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. |
| 4 |
| 5 #include "net/disk_cache/v3/block_bitmaps.h" |
| 6 |
| 7 #include "base/metrics/histogram.h" |
| 8 #include "base/string_util.h" |
| 9 #include "base/stringprintf.h" |
| 10 #include "base/threading/thread_checker.h" |
| 11 #include "base/time.h" |
| 12 #include "net/disk_cache/cache_util.h" |
| 13 #include "net/disk_cache/disk_format_base.h" |
| 14 #include "net/disk_cache/file_lock.h" |
| 15 #include "net/disk_cache/trace.h" |
| 16 #include "net/disk_cache/v3/backend_impl_v3.h" |
| 17 |
| 18 using base::TimeTicks; |
| 19 |
| 20 namespace disk_cache { |
| 21 |
| 22 BlockBitmaps::BlockBitmaps(BackendImplV3* backend) : backend_(backend) { |
| 23 } |
| 24 |
| 25 BlockBitmaps::~BlockBitmaps() { |
| 26 } |
| 27 |
| 28 void BlockBitmaps::Init(const BlockFilesBitmaps& bitmaps) { |
| 29 bitmaps_ = bitmaps; |
| 30 for (int i = 0; i < kFirstAdditionalBlockFileV3; i++) |
| 31 empty_counts_[i] = EmptyBlocksForType(i); |
| 32 } |
| 33 |
| 34 bool BlockBitmaps::CreateBlock(FileType block_type, |
| 35 int block_count, |
| 36 Addr* block_address) { |
| 37 DCHECK_NE(block_type, EXTERNAL); |
| 38 DCHECK_NE(block_type, RANKINGS); |
| 39 if (block_count < 1 || block_count > kMaxNumBlocks) |
| 40 return false; |
| 41 |
| 42 int header_num = HeaderNumberForNewBlock(block_type, block_count); |
| 43 if (header_num < 0) |
| 44 return false; |
| 45 |
| 46 int old_num_allocations = bitmaps_[header_num].MinimumAllocations(); |
| 47 |
| 48 int index; |
| 49 if (!bitmaps_[header_num].CreateMapBlock(block_count, &index)) |
| 50 return false; |
| 51 |
| 52 if (!index && (block_type == BLOCK_ENTRIES || block_type == BLOCK_EVICTED) && |
| 53 !bitmaps_[header_num].CreateMapBlock(block_count, &index)) { |
| 54 // index 0 for entries is a reserved value. |
| 55 return false; |
| 56 } |
| 57 |
| 58 // Yes, the count may be off by 1 when we start. |
| 59 if (old_num_allocations != bitmaps_[header_num].MinimumAllocations()) |
| 60 empty_counts_[block_type]--; |
| 61 |
| 62 if (empty_counts_[block_type] < (kNumExtraBlocks / kMaxNumBlocks) / 2) |
| 63 backend_->GrowBlockFiles(); |
| 64 |
| 65 Addr address(block_type, block_count, bitmaps_[header_num].FileId(), index); |
| 66 block_address->set_value(address.value()); |
| 67 Trace("CreateBlock 0x%x", address.value()); |
| 68 return true; |
| 69 } |
| 70 |
| 71 void BlockBitmaps::DeleteBlock(Addr address) { |
| 72 if (!address.is_initialized() || address.is_separate_file()) |
| 73 return; |
| 74 |
| 75 int header_num = GetHeaderNumber(address); |
| 76 if (header_num < 0) |
| 77 return; |
| 78 |
| 79 Trace("DeleteBlock 0x%x", address.value()); |
| 80 bitmaps_[header_num].DeleteMapBlock(address.start_block(), |
| 81 address.num_blocks()); |
| 82 |
| 83 //if (!bitmaps_[header_num].Header()->num_entries) { |
| 84 // This file is now empty. Let's try to delete it. |
| 85 //FileType type = Addr::RequiredFileType(header->entry_size); |
| 86 //if (Addr::BlockSizeForFileType(RANKINGS) == header->entry_size) |
| 87 // type = RANKINGS; |
| 88 //RemoveEmptyFile(type); // Ignore failures. |
| 89 //} |
| 90 } |
| 91 |
| 92 void BlockBitmaps::Clear() { |
| 93 bitmaps_.clear(); |
| 94 } |
| 95 |
| 96 void BlockBitmaps::ReportStats() { |
| 97 int used_blocks[kFirstAdditionalBlockFile]; |
| 98 int load[kFirstAdditionalBlockFile]; |
| 99 for (int i = 0; i < kFirstAdditionalBlockFile; i++) { |
| 100 GetFileStats(i, &used_blocks[i], &load[i]); |
| 101 } |
| 102 UMA_HISTOGRAM_COUNTS("DiskCache.Blocks_0", used_blocks[0]); |
| 103 UMA_HISTOGRAM_COUNTS("DiskCache.Blocks_1", used_blocks[1]); |
| 104 UMA_HISTOGRAM_COUNTS("DiskCache.Blocks_2", used_blocks[2]); |
| 105 UMA_HISTOGRAM_COUNTS("DiskCache.Blocks_3", used_blocks[3]); |
| 106 |
| 107 UMA_HISTOGRAM_ENUMERATION("DiskCache.BlockLoad_0", load[0], 101); |
| 108 UMA_HISTOGRAM_ENUMERATION("DiskCache.BlockLoad_1", load[1], 101); |
| 109 UMA_HISTOGRAM_ENUMERATION("DiskCache.BlockLoad_2", load[2], 101); |
| 110 UMA_HISTOGRAM_ENUMERATION("DiskCache.BlockLoad_3", load[3], 101); |
| 111 } |
| 112 |
| 113 bool BlockBitmaps::IsValid(Addr address) { |
| 114 #ifdef NDEBUG |
| 115 return true; |
| 116 #else |
| 117 if (!address.is_initialized() || address.is_separate_file()) |
| 118 return false; |
| 119 |
| 120 int header_num = GetHeaderNumber(address); |
| 121 if (header_num < 0) |
| 122 return false; |
| 123 |
| 124 bool rv = bitmaps_[header_num].UsedMapBlock(address.start_block(), |
| 125 address.num_blocks()); |
| 126 DCHECK(rv); |
| 127 return rv; |
| 128 #endif |
| 129 } |
| 130 |
| 131 int BlockBitmaps::GetHeaderNumber(Addr address) { |
| 132 DCHECK_GE(bitmaps_.size(), static_cast<size_t>(kFirstAdditionalBlockFileV3)); |
| 133 DCHECK(address.is_block_file() || !address.is_initialized()); |
| 134 if (!address.is_initialized()) |
| 135 return -1; |
| 136 |
| 137 int file_index = address.FileNumber(); |
| 138 if (static_cast<unsigned int>(file_index) >= bitmaps_.size()) |
| 139 return -1; |
| 140 |
| 141 return file_index; |
| 142 } |
| 143 |
| 144 int BlockBitmaps::EmptyBlocksForType(int next_file) { |
| 145 int empty_blocks = 0; |
| 146 do { |
| 147 empty_blocks += bitmaps_[next_file].MinimumAllocations(); |
| 148 next_file = bitmaps_[next_file].NextFileId(); |
| 149 } while (next_file); |
| 150 return empty_blocks; |
| 151 } |
| 152 |
| 153 int BlockBitmaps::HeaderNumberForNewBlock(FileType block_type, |
| 154 int block_count) { |
| 155 DCHECK_GT(block_type, 0); |
| 156 int header_num = block_type - 1; |
| 157 bool found = true; |
| 158 |
| 159 TimeTicks start = TimeTicks::Now(); |
| 160 while (bitmaps_[header_num].NeedToGrowBlockFile(block_count)) { |
| 161 header_num = bitmaps_[header_num].NextFileId(); |
| 162 if (!header_num) { |
| 163 found = false; |
| 164 break; |
| 165 } |
| 166 } |
| 167 |
| 168 if (!found) { |
| 169 // Restart the search, looking for any file with space. We know that all |
| 170 // files of this type are low on free blocks, but we cannot grow any file |
| 171 // at this time. |
| 172 header_num = block_type - 1; |
| 173 do { |
| 174 if (bitmaps_[header_num].CanAllocate(block_count)) { |
| 175 found = true; // Make sure file 0 is not mistaken with a failure. |
| 176 break; |
| 177 } |
| 178 header_num = bitmaps_[header_num].NextFileId(); |
| 179 } while (header_num); |
| 180 |
| 181 if (!found) { |
| 182 NOTREACHED(); |
| 183 header_num = -1; |
| 184 } |
| 185 } |
| 186 |
| 187 HISTOGRAM_TIMES("DiskCache.GetFileForNewBlock", TimeTicks::Now() - start); |
| 188 return header_num; |
| 189 } |
| 190 |
| 191 // We are interested in the total number of blocks used by this file type, and |
| 192 // the max number of blocks that we can store (reported as the percentage of |
| 193 // used blocks). In order to find out the number of used blocks, we have to |
| 194 // substract the empty blocks from the total blocks for each file in the chain. |
| 195 void BlockBitmaps::GetFileStats(int index, int* used_count, int* load) { |
| 196 int max_blocks = 0; |
| 197 *used_count = 0; |
| 198 *load = 0; |
| 199 do { |
| 200 int capacity = bitmaps_[index].Capacity(); |
| 201 int used = capacity - bitmaps_[index].EmptyBlocks(); |
| 202 DCHECK_GE(used, 0); |
| 203 |
| 204 max_blocks += capacity; |
| 205 *used_count += used; |
| 206 |
| 207 index = bitmaps_[index].NextFileId(); |
| 208 } while (index); |
| 209 |
| 210 if (max_blocks) |
| 211 *load = *used_count * 100 / max_blocks; |
| 212 } |
| 213 |
| 214 } // namespace disk_cache |
OLD | NEW |