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

Side by Side Diff: net/disk_cache/v3/block_bitmaps.cc

Issue 15203004: Disk cache: Reference CL for the implementation of file format version 3. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src/
Patch Set: Created 7 years, 6 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/v3/block_bitmaps.h ('k') | net/disk_cache/v3/disk_format_v3.h » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Property Changes:
Added: svn:eol-style
+ LF
OLDNEW
(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 int BlockBitmaps::GetHeader(Addr address) {
35 DCHECK(bitmaps_.size() >= kFirstAdditionalBlockFileV3);
36 DCHECK(address.is_block_file() || !address.is_initialized());
37 if (!address.is_initialized())
38 return NULL;
39
40 int file_index = address.FileNumber();
41 if (static_cast<unsigned int>(file_index) >= bitmaps_.size() ||
42 !bitmaps_[file_index].Get()) {
43 return -1;
44 }
45 DCHECK(bitmaps_.size() >= static_cast<unsigned int>(file_index));
46 return file_index;
47 }
48
49 bool BlockBitmaps::CreateBlock(FileType block_type, int block_count,
50 Addr* block_address) {
51 if (block_type < BLOCK_256 || block_type > BLOCK_EVICTED ||
52 block_count < 1 || block_count > 4)
53 return false;
54
55 int header_num = HeaderForNewBlock(block_type, block_count);
56 if (header_num < 0)
57 return false;
58
59 int target_size = 0;
60 for (int i = block_count; i <= 4; i++) {
61 if (bitmaps_[header_num]->empty[i - 1]) {
62 target_size = i;
63 break;
64 }
65 }
66
67 DCHECK(target_size);
68 int index;
69 if (!bitmaps_[header_num].CreateMapBlock(target_size, block_count, &index))
70 return false;
71
72 if (!index && (block_type == BLOCK_ENTRIES || block_type == BLOCK_EVICTED) &&
73 !bitmaps_[header_num].CreateMapBlock(target_size, block_count, &index)) {
74 // index 0 for entries is a reserved value.
75 return false;
76 }
77
78 // Yes, the count may be off by 1 when we start.
79 empty_counts_[target_size] -= block_count;
80 if (empty_counts_[target_size] < kNumExtraBlocks / 2)
81 backend_->GrowBlockFiles();
82
83 Addr address(block_type, block_count, bitmaps_[header_num]->this_file, index);
84 block_address->set_value(address.value());
85 Trace("CreateBlock 0x%x", address.value());
86 return true;
87 }
88
89 void BlockBitmaps::DeleteBlock(Addr address) {
90 if (!address.is_initialized() || address.is_separate_file())
91 return;
92
93 int header_num = GetHeader(address);
94 if (header_num < 0)
95 return;
96
97 Trace("DeleteBlock 0x%x", address.value());
98 bitmaps_[header_num].DeleteMapBlock(address.start_block(),
99 address.num_blocks());
100
101 if (!bitmaps_[header_num]->num_entries) {
102 // This file is now empty. Let's try to delete it.
103 //FileType type = Addr::RequiredFileType(header->entry_size);
104 //if (Addr::BlockSizeForFileType(RANKINGS) == header->entry_size)
105 // type = RANKINGS;
106 //RemoveEmptyFile(type); // Ignore failures.
107 }
108 }
109
110 void BlockBitmaps::Clear() {
111 bitmaps_.clear();
112 }
113
114 void BlockBitmaps::ReportStats() {
115 int used_blocks[kFirstAdditionalBlockFile];
116 int load[kFirstAdditionalBlockFile];
117 for (int i = 0; i < kFirstAdditionalBlockFile; i++) {
118 GetFileStats(i, &used_blocks[i], &load[i]);
119 }
120 UMA_HISTOGRAM_COUNTS("DiskCache.Blocks_0", used_blocks[0]);
121 UMA_HISTOGRAM_COUNTS("DiskCache.Blocks_1", used_blocks[1]);
122 UMA_HISTOGRAM_COUNTS("DiskCache.Blocks_2", used_blocks[2]);
123 UMA_HISTOGRAM_COUNTS("DiskCache.Blocks_3", used_blocks[3]);
124
125 UMA_HISTOGRAM_ENUMERATION("DiskCache.BlockLoad_0", load[0], 101);
126 UMA_HISTOGRAM_ENUMERATION("DiskCache.BlockLoad_1", load[1], 101);
127 UMA_HISTOGRAM_ENUMERATION("DiskCache.BlockLoad_2", load[2], 101);
128 UMA_HISTOGRAM_ENUMERATION("DiskCache.BlockLoad_3", load[3], 101);
129 }
130
131 bool BlockBitmaps::IsValid(Addr address) {
132 #ifdef NDEBUG
133 return true;
134 #else
135 if (!address.is_initialized() || address.is_separate_file())
136 return false;
137
138 int header_num = GetHeader(address);
139 if (header_num < 0)
140 return false;
141
142 bool rv = bitmaps_[header_num].UsedMapBlock(address.start_block(),
143 address.num_blocks());
144 DCHECK(rv);
145 return rv;
146 #endif
147 }
148
149 int BlockBitmaps::EmptyBlocksForType(int next_file) {
150 int empty_blocks = 0;
151 do {
152 empty_blocks += bitmaps_[next_file].EmptyBlocks();
153 next_file = bitmaps_[next_file]->next_file;
154 } while (next_file);
155 return empty_blocks;
156 }
157
158 int BlockBitmaps::HeaderForNewBlock(FileType block_type, int block_count) {
159 COMPILE_ASSERT(RANKINGS == 1, invalid_file_type);
160 int header_num = block_type - 1;
161 bool found = true;
162
163 TimeTicks start = TimeTicks::Now();
164 while (bitmaps_[header_num].NeedToGrowBlockFile(block_count)) {
165 header_num = bitmaps_[header_num]->next_file;
166 if (!header_num) {
167 found = false;
168 break;
169 }
170 }
171
172 if (!found) {
173 // Restart the search, looking for any file with space.
174 header_num = block_type - 1;
175 do {
176 if (bitmaps_[header_num].CanAllocate(block_count))
177 found = true;
178 else
179 header_num = bitmaps_[header_num]->next_file;
180 } while (header_num && !found);
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 // Note that we expect to be called outside of a FileLock... however, we cannot
192 // DCHECK on header->updating because we may be fixing a crash.
193 bool BlockBitmaps::FixBlockFileHeader(MappedFile* file) {
194 ScopedFlush flush(file);
195 BlockHeader header(file);
196 int file_size = static_cast<int>(file->GetLength());
197 if (file_size < header.Size())
198 return false; // file_size > 2GB is also an error.
199
200 const int kMinBlockSize = 36;
201 const int kMaxBlockSize = 4096;
202 if (header->entry_size < kMinBlockSize ||
203 header->entry_size > kMaxBlockSize || header->num_entries < 0)
204 return false;
205
206 // Make sure that we survive crashes.
207 header->updating = 1;
208 int expected = header->entry_size * header->max_entries + header.Size();
209 if (file_size != expected) {
210 int max_expected = header->entry_size * kMaxBlocks + header.Size();
211 if (file_size < expected || header->empty[3] || file_size > max_expected) {
212 NOTREACHED();
213 LOG(ERROR) << "Unexpected file size";
214 return false;
215 }
216 // We were in the middle of growing the file.
217 int num_entries = (file_size - header.Size()) / header->entry_size;
218 header->max_entries = num_entries;
219 }
220
221 header.FixAllocationCounters();
222 int empty_blocks = header.EmptyBlocks();
223 if (empty_blocks + header->num_entries > header->max_entries)
224 header->num_entries = header->max_entries - empty_blocks;
225
226 if (!header.ValidateCounters())
227 return false;
228
229 header->updating = 0;
230 return true;
231 }
232
233 // We are interested in the total number of blocks used by this file type, and
234 // the max number of blocks that we can store (reported as the percentage of
235 // used blocks). In order to find out the number of used blocks, we have to
236 // substract the empty blocks from the total blocks for each file in the chain.
237 void BlockBitmaps::GetFileStats(int index, int* used_count, int* load) {
238 int max_blocks = 0;
239 *used_count = 0;
240 *load = 0;
241 for (;;) {
242 BlockFileHeader* header = bitmaps_[index].Get();
243
244 max_blocks += header->max_entries;
245 int used = header->max_entries;
246 for (int i = 0; i < 4; i++) {
247 used -= header->empty[i] * (i + 1);
248 DCHECK_GE(used, 0);
249 }
250 *used_count += used;
251
252 if (!header->next_file)
253 break;
254 index = header->next_file;
255 }
256 if (max_blocks)
257 *load = *used_count * 100 / max_blocks;
258 }
259
260 } // namespace disk_cache
OLDNEW
« no previous file with comments | « net/disk_cache/v3/block_bitmaps.h ('k') | net/disk_cache/v3/disk_format_v3.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698