OLD | NEW |
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 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 | 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/v3/block_bitmaps.h" | 5 #include "net/disk_cache/v3/block_bitmaps.h" |
6 | 6 |
7 #include "base/metrics/histogram.h" | 7 #include "base/metrics/histogram.h" |
| 8 #include "base/strings/string_util.h" |
| 9 #include "base/strings/stringprintf.h" |
| 10 #include "base/threading/thread_checker.h" |
8 #include "base/time/time.h" | 11 #include "base/time/time.h" |
| 12 #include "net/disk_cache/cache_util.h" |
9 #include "net/disk_cache/disk_format_base.h" | 13 #include "net/disk_cache/disk_format_base.h" |
| 14 #include "net/disk_cache/file_lock.h" |
10 #include "net/disk_cache/trace.h" | 15 #include "net/disk_cache/trace.h" |
| 16 #include "net/disk_cache/v3/backend_impl_v3.h" |
11 | 17 |
12 using base::TimeTicks; | 18 using base::TimeTicks; |
13 | 19 |
14 namespace disk_cache { | 20 namespace disk_cache { |
15 | 21 |
16 BlockBitmaps::BlockBitmaps() { | 22 BlockBitmaps::BlockBitmaps(BackendImplV3* backend) : backend_(backend) { |
17 } | 23 } |
18 | 24 |
19 BlockBitmaps::~BlockBitmaps() { | 25 BlockBitmaps::~BlockBitmaps() { |
20 } | 26 } |
21 | 27 |
22 void BlockBitmaps::Init(const BlockFilesBitmaps& bitmaps) { | 28 void BlockBitmaps::Init(const BlockFilesBitmaps& bitmaps) { |
23 bitmaps_ = bitmaps; | 29 bitmaps_ = bitmaps; |
| 30 for (int i = 0; i < kFirstAdditionalBlockFileV3; i++) |
| 31 empty_counts_[i] = EmptyBlocksForType(i); |
24 } | 32 } |
25 | 33 |
26 bool BlockBitmaps::CreateBlock(FileType block_type, | 34 bool BlockBitmaps::CreateBlock(FileType block_type, |
27 int block_count, | 35 int block_count, |
28 Addr* block_address) { | 36 Addr* block_address) { |
29 DCHECK_NE(block_type, EXTERNAL); | 37 DCHECK_NE(block_type, EXTERNAL); |
30 DCHECK_NE(block_type, RANKINGS); | 38 DCHECK_NE(block_type, RANKINGS); |
31 if (block_count < 1 || block_count > kMaxNumBlocks) | 39 if (block_count < 1 || block_count > kMaxNumBlocks) |
32 return false; | 40 return false; |
33 | 41 |
34 int header_num = HeaderNumberForNewBlock(block_type, block_count); | 42 int header_num = HeaderNumberForNewBlock(block_type, block_count); |
35 if (header_num < 0) | 43 if (header_num < 0) |
36 return false; | 44 return false; |
37 | 45 |
| 46 int old_num_allocations = bitmaps_[header_num].MinimumAllocations(); |
| 47 |
38 int index; | 48 int index; |
39 if (!bitmaps_[header_num].CreateMapBlock(block_count, &index)) | 49 if (!bitmaps_[header_num].CreateMapBlock(block_count, &index)) |
40 return false; | 50 return false; |
41 | 51 |
42 if (!index && (block_type == BLOCK_ENTRIES || block_type == BLOCK_EVICTED) && | 52 if (!index && (block_type == BLOCK_ENTRIES || block_type == BLOCK_EVICTED) && |
43 !bitmaps_[header_num].CreateMapBlock(block_count, &index)) { | 53 !bitmaps_[header_num].CreateMapBlock(block_count, &index)) { |
44 // index 0 for entries is a reserved value. | 54 // index 0 for entries is a reserved value. |
45 return false; | 55 return false; |
46 } | 56 } |
47 | 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 |
48 Addr address(block_type, block_count, bitmaps_[header_num].FileId(), index); | 65 Addr address(block_type, block_count, bitmaps_[header_num].FileId(), index); |
49 block_address->set_value(address.value()); | 66 block_address->set_value(address.value()); |
50 Trace("CreateBlock 0x%x", address.value()); | 67 Trace("CreateBlock 0x%x", address.value()); |
51 return true; | 68 return true; |
52 } | 69 } |
53 | 70 |
54 void BlockBitmaps::DeleteBlock(Addr address) { | 71 void BlockBitmaps::DeleteBlock(Addr address) { |
55 if (!address.is_initialized() || address.is_separate_file()) | 72 if (!address.is_initialized() || address.is_separate_file()) |
56 return; | 73 return; |
57 | 74 |
58 int header_num = GetHeaderNumber(address); | 75 int header_num = GetHeaderNumber(address); |
59 if (header_num < 0) | 76 if (header_num < 0) |
60 return; | 77 return; |
61 | 78 |
62 Trace("DeleteBlock 0x%x", address.value()); | 79 Trace("DeleteBlock 0x%x", address.value()); |
63 bitmaps_[header_num].DeleteMapBlock(address.start_block(), | 80 bitmaps_[header_num].DeleteMapBlock(address.start_block(), |
64 address.num_blocks()); | 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 //} |
65 } | 90 } |
66 | 91 |
67 void BlockBitmaps::Clear() { | 92 void BlockBitmaps::Clear() { |
68 bitmaps_.clear(); | 93 bitmaps_.clear(); |
69 } | 94 } |
70 | 95 |
71 void BlockBitmaps::ReportStats() { | 96 void BlockBitmaps::ReportStats() { |
72 int used_blocks[kFirstAdditionalBlockFile]; | 97 int used_blocks[kFirstAdditionalBlockFile]; |
73 int load[kFirstAdditionalBlockFile]; | 98 int load[kFirstAdditionalBlockFile]; |
74 for (int i = 0; i < kFirstAdditionalBlockFile; i++) { | 99 for (int i = 0; i < kFirstAdditionalBlockFile; i++) { |
(...skipping 34 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
109 if (!address.is_initialized()) | 134 if (!address.is_initialized()) |
110 return -1; | 135 return -1; |
111 | 136 |
112 int file_index = address.FileNumber(); | 137 int file_index = address.FileNumber(); |
113 if (static_cast<unsigned int>(file_index) >= bitmaps_.size()) | 138 if (static_cast<unsigned int>(file_index) >= bitmaps_.size()) |
114 return -1; | 139 return -1; |
115 | 140 |
116 return file_index; | 141 return file_index; |
117 } | 142 } |
118 | 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 |
119 int BlockBitmaps::HeaderNumberForNewBlock(FileType block_type, | 153 int BlockBitmaps::HeaderNumberForNewBlock(FileType block_type, |
120 int block_count) { | 154 int block_count) { |
121 DCHECK_GT(block_type, 0); | 155 DCHECK_GT(block_type, 0); |
122 int header_num = block_type - 1; | 156 int header_num = block_type - 1; |
123 bool found = true; | 157 bool found = true; |
124 | 158 |
125 TimeTicks start = TimeTicks::Now(); | 159 TimeTicks start = TimeTicks::Now(); |
126 while (bitmaps_[header_num].NeedToGrowBlockFile(block_count)) { | 160 while (bitmaps_[header_num].NeedToGrowBlockFile(block_count)) { |
127 header_num = bitmaps_[header_num].NextFileId(); | 161 header_num = bitmaps_[header_num].NextFileId(); |
128 if (!header_num) { | 162 if (!header_num) { |
129 found = false; | 163 found = false; |
130 break; | 164 break; |
131 } | 165 } |
132 } | 166 } |
133 | 167 |
134 if (!found) { | 168 if (!found) { |
135 // Restart the search, looking for any file with space. We know that all | 169 // Restart the search, looking for any file with space. We know that all |
136 // files of this type are low on free blocks, but we cannot grow any file | 170 // files of this type are low on free blocks, but we cannot grow any file |
137 // at this time. | 171 // at this time. |
138 header_num = block_type - 1; | 172 header_num = block_type - 1; |
139 do { | 173 do { |
140 if (bitmaps_[header_num].CanAllocate(block_count)) { | 174 if (bitmaps_[header_num].CanAllocate(block_count)) { |
141 found = true; // Make sure file 0 is not mistaken with a failure. | 175 found = true; // Make sure file 0 is not mistaken with a failure. |
142 break; | 176 break; |
143 } | 177 } |
144 header_num = bitmaps_[header_num].NextFileId(); | 178 header_num = bitmaps_[header_num].NextFileId(); |
145 } while (header_num); | 179 } while (header_num); |
146 | 180 |
147 if (!found) | 181 if (!found) { |
| 182 NOTREACHED(); |
148 header_num = -1; | 183 header_num = -1; |
| 184 } |
149 } | 185 } |
150 | 186 |
151 HISTOGRAM_TIMES("DiskCache.GetFileForNewBlock", TimeTicks::Now() - start); | 187 HISTOGRAM_TIMES("DiskCache.GetFileForNewBlock", TimeTicks::Now() - start); |
152 return header_num; | 188 return header_num; |
153 } | 189 } |
154 | 190 |
155 // We are interested in the total number of blocks used by this file type, and | 191 // We are interested in the total number of blocks used by this file type, and |
156 // the max number of blocks that we can store (reported as the percentage of | 192 // the max number of blocks that we can store (reported as the percentage of |
157 // used blocks). In order to find out the number of used blocks, we have to | 193 // used blocks). In order to find out the number of used blocks, we have to |
158 // substract the empty blocks from the total blocks for each file in the chain. | 194 // substract the empty blocks from the total blocks for each file in the chain. |
(...skipping 10 matching lines...) Expand all Loading... |
169 *used_count += used; | 205 *used_count += used; |
170 | 206 |
171 index = bitmaps_[index].NextFileId(); | 207 index = bitmaps_[index].NextFileId(); |
172 } while (index); | 208 } while (index); |
173 | 209 |
174 if (max_blocks) | 210 if (max_blocks) |
175 *load = *used_count * 100 / max_blocks; | 211 *load = *used_count * 100 / max_blocks; |
176 } | 212 } |
177 | 213 |
178 } // namespace disk_cache | 214 } // namespace disk_cache |
OLD | NEW |