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

Side by Side Diff: net/disk_cache/v3/index_table.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/index_table.h ('k') | net/disk_cache/v3/sparse_control_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) 2013 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/index_table.h"
6
7 #include <set>
8
9 #include "net/base/net_errors.h"
10 #include "net/disk_cache/disk_cache.h"
11 #include "net/disk_cache/v3/backend_impl_v3.h"
12 #include "net/disk_cache/v3/backend_work_item.h"
13
14 using base::Time;
15 using base::TimeDelta;
16 using disk_cache::CellId;
17 using disk_cache::CellList;
18 using disk_cache::IndexCell;
19 using disk_cache::IndexIterator;
20
21 namespace {
22
23 const uint32 kMaxAddress = 1 << 22;
24 const uint32 kBasicMask = 0xFFFF;
25
26 int GetSum(const IndexCell& cell) {
27 return cell.timestamp_and_sum >> 6;
28 }
29
30 // This is a quite peculiar way to calculate the sum, so it will not match if
31 // compared a gainst a pure 2 bit, modulo 2 sum.
32 int CalculateSum(const IndexCell& cell) {
33 uint32* word = bit_cast<uint32*>(&cell);
34 uint32 result = word[0] + word[1];
35 result += result >> 16;
36 result += (result >> 8) + (cell.timestamp_and_hash & 0x3f);
37 result += result >> 4;
38 result += result >> 2;
39 return result & 3;
40 }
41
42 bool SanityCheck(const IndexCell& cell) {
43 if (GetSum(cell) != CalculateSum(cell))
44 return false;
45
46 if (cell.state > disk_cache::ENTRY_USED ||
47 cell.group == disk_cache::ENTRY_RESERVED ||
48 cell.group > disk_cache::ENTRY_EVICTED) {
49 return false;
50 }
51
52 return true;
53 }
54
55 inline bool HashMatches(uint32 stored, uint32 value, int extra_bits) {
56 return (stored >> extra_bits) == (value >> (14 + extra_bits));
57 }
58
59 inline bool MisplacedHash(uint32 stored, uint32 value, int extra_bits) {
60 if (!extra_bits)
61 return false;
62 uint32 mask = (1 << extra_bits) - 1;
63 return (stored & mask) != ((value >> 14) & mask);
64 }
65
66 inline int GetNextBucket(int min_bucket_id, int max_bucket_id,
67 disk_cache::IndexBucket* table,
68 disk_cache::IndexBucket** bucket) {
69 if (!(*bucket)->next)
70 return 0;
71
72 int bucket_id = (*bucket)->next / 4;
73 if (bucket_id < min_bucket_id || bucket_id > max_bucket_id) {
74 (*bucket)->next = 0;
75 return 0;
76 }
77 *bucket = &table[bucket_id - min_bucket_id];
78 return bucket_id;
79 }
80
81 void UpdateListWithCell(int bucket_hash, const IndexCell& cell, CellList* list,
82 int* list_time) {
83 if (!list)
84 return;
85
86 int time = disk_cache::EntryCell::GetTimestamp(cell);
87 if (time < *list_time) {
88 *list_time = time;
89 list->clear();
90 }
91 if (time == *list_time) {
92 CellId cell_id = {
93 (disk_cache::EntryCell::GetHash(cell) << 14) + bucket_hash,
94 disk_cache::Addr::FromEntryAddress(cell.address)
95 };
96 list->push_back(cell_id);
97 }
98 }
99
100 void GetNewestFromBucket(disk_cache::IndexBucket* bucket, int bucket_hash,
101 int limit_time, IndexIterator* iterator) {
102 for (int i = 0; i < 4; i++) {
103 IndexCell& current_cell = bucket->cells[i];
104 if (!current_cell.address)
105 continue;
106 DCHECK(SanityCheck(current_cell));
107 if (!disk_cache::EntryCell::IsNormalState(current_cell))
108 continue;
109
110 int time = disk_cache::EntryCell::GetTimestamp(current_cell);
111 switch (current_cell.group) {
112 case disk_cache::ENTRY_NO_USE:
113 case disk_cache::ENTRY_LOW_USE:
114 case disk_cache::ENTRY_HIGH_USE:
115 if (iterator->forward && time >= limit_time)
116 continue;
117 if (!iterator->forward && time <= limit_time)
118 continue;
119
120 if ((iterator->forward && time > iterator->timestamp) ||
121 (!iterator->forward && time < iterator->timestamp)) {
122 iterator->timestamp = time;
123 iterator->cells.clear();
124 }
125 if (time == iterator->timestamp) {
126 CellId cell_id = {
127 (disk_cache::EntryCell::GetHash(current_cell) << 14) + bucket_hash,
128 disk_cache::Addr::FromEntryAddress(current_cell.address)
129 };
130 iterator->cells.push_back(cell_id);
131 }
132 }
133 }
134 }
135
136 } // namespace
137
138 namespace disk_cache {
139
140 EntryCell::EntryCell() : cell_id_(0), hash_(0) {
141 cell_.Clear();
142 }
143
144 EntryCell::EntryCell(int32 cell_id, uint32 hash, Addr address)
145 : cell_id_(cell_id),
146 hash_(hash) {
147 DCHECK(ValidAddress(address) || !address.value());
148
149 cell_.Clear();
150 cell_.address = address.value() & 0xFFFFFF;
151 cell_.state = ENTRY_NEW;
152 cell_.group = ENTRY_NO_USE;
153 cell_.hash = (hash >> 16) & kBasicMask;
154 cell_.timestamp_and_hash = (hash >> 14) & 3;
155 }
156
157 EntryCell::EntryCell(int32 cell_id, uint32 hash, const IndexCell& cell)
158 : cell_id_(cell_id),
159 hash_(hash),
160 cell_(cell) {
161 }
162
163 EntryCell::~EntryCell() {
164 }
165
166 Addr EntryCell::GetAddress() const {
167 if (group() == ENTRY_EVICTED)
168 return Addr::FromEvictedAddress(cell_.address);
169 else
170 return Addr::FromEntryAddress(cell_.address);
171 }
172
173 int EntryCell::GetTimestamp() const {
174 return GetTimestamp(cell_);
175 }
176
177 void EntryCell::set_reuse(int count) {
178 DCHECK_LT(count, 16);
179 DCHECK_GE(count, 0);
180 cell_.reuse = count;
181 }
182
183 // This operation destroys (ignores) the sum.
184 void EntryCell::set_timestamp(int timestamp) {
185 DCHECK_LT(timestamp, 1 << 20);
186 DCHECK_GE(timestamp, 0);
187 cell_.timestamp_and_hash = ((timestamp & 0x3fff) << 2) +
188 (cell_.timestamp_and_hash & 3);
189 cell_.timestamp_and_sum = (timestamp >> 14) & 0x3f;
190 }
191
192 // Static.
193 bool EntryCell::ValidAddress(Addr address) {
194 if (!address.is_initialized() ||
195 (address.file_type() != BLOCK_EVICTED &&
196 address.file_type() != BLOCK_ENTRIES)) {
197 return false;
198 }
199
200 return (address.value() & 0xF00000) < kMaxAddress;
201 }
202
203 // Static.
204 uint32 EntryCell::GetHash(const IndexCell& cell) {
205 return (cell.hash << 2) + (cell.timestamp_and_hash & 3);
206 }
207
208 // Static.
209 int EntryCell::GetTimestamp(const IndexCell& cell) {
210 return (cell.timestamp_and_hash >> 2) +
211 ((cell.timestamp_and_sum & 0x3f) << 14);
212 }
213
214 // Static.
215 bool EntryCell::IsNormalState(const IndexCell& cell) {
216 EntryState state = static_cast<EntryState>(cell.state);
217 DCHECK_NE(state, ENTRY_FREE);
218 return state != ENTRY_DELETED && state != ENTRY_FIXING;
219 }
220
221 void EntryCell::FixSum() {
222 cell_.timestamp_and_sum = (cell_.timestamp_and_sum & 0x3f) |
223 (CalculateSum(cell_) << 6);
224 }
225
226 EntrySet::EntrySet() : evicted_count(0), current(0) {
227 }
228
229 // -----------------------------------------------------------------------
230
231 IndexTable::IndexTable(BackendImplV3* backend)
232 : backend_(backend),
233 header_(NULL),
234 main_table_(NULL),
235 extra_table_(NULL) {
236 }
237
238 void IndexTable::Init(InitResult* params) {
239 bool growing = header_ != NULL;
240 IndexBucket* old_extra_table = NULL;
241 header_ = &params->index_bitmap->header;
242
243 if (params->main_table) {
244 if (main_table_) {
245 DCHECK_EQ(header_->table_len / kIndexTablesize,
246 backup_header_->table_len / kIndexTablesize + 1);
247 old_extra_table = extra_table_;
248 }
249 main_table_ = params->main_table;
250 }
251 DCHECK(main_table_);
252 extra_table_ = params->extra_table;
253
254 extra_bits_ = header_->table_len / kIndexTablesize - 1;
255 DCHECK_GE(extra_bits_, 0);
256 DCHECK_LE(extra_bits_, 6);
257 mask_ = ((kIndexTablesize / 4) << extra_bits_) - 1;
258
259 int num_words = (header_->table_len + 31) / 32 ;
260 bitmap_.reset(new Bitmap(params->index_bitmap->bitmap, header_->table_len,
261 num_words));
262
263 if (growing) {
264 int old_num_words = (backup_header_->table_len + 31) / 32;
265 DCHECK_GE(num_words, old_num_words);
266 scoped_ptr<uint32[]> storage(new uint32[num_words]);
267 memcpy(storage.get(), backup_bitmap_storage_.get(), old_num_words * 4);
268 memset(storage.get() + old_num_words, 0, (num_words - old_num_words) * 4);
269
270 backup_bitmap_storage_.swap(storage);
271 backup_header_->table_len = header_->table_len;
272 } else {
273 backup_bitmap_storage_.reset(params->backup_bitmap.release());
274 backup_header_.reset(params->backup_header.release());
275 }
276
277 num_words = (backup_header_->table_len + 31) / 32;
278 backup_bitmap_.reset(new Bitmap(backup_bitmap_storage_.get(),
279 backup_header_->table_len, num_words));
280 if (old_extra_table)
281 MoveCells(old_extra_table);
282 }
283
284 void IndexTable::Reset() {
285 header_ = NULL;
286 main_table_ = NULL;
287 extra_table_ = NULL;
288 bitmap_.reset();
289 backup_bitmap_.reset();
290 backup_header_.reset();
291 backup_bitmap_storage_.reset();
292 }
293
294 EntrySet IndexTable::LookupEntry(uint32 hash) {
295 EntrySet entries;
296 int bucket_id = static_cast<int>(hash & mask_);
297 IndexBucket* bucket = &main_table_[bucket_id];
298 for (;;) {
299 for (int i = 0; i < 4; i++) {
300 IndexCell* current_cell = &bucket->cells[i];
301 if (!current_cell->address)
302 continue;
303 if (!SanityCheck(*current_cell)) {
304 NOTREACHED();
305 current_cell->Clear();
306 continue;
307 }
308 int cell_id = bucket_id * 4 + i;
309 if (MisplacedHash(EntryCell::GetHash(*current_cell), hash, extra_bits_)) {
310 HandleMisplacedCell(current_cell, cell_id, hash & mask_);
311 } else if (HashMatches(EntryCell::GetHash(*current_cell), hash,
312 extra_bits_)) {
313 CheckState(current_cell, cell_id);
314 if (current_cell->state != ENTRY_DELETED) {
315 EntryCell entry_cell(cell_id, hash, *current_cell);
316 entries.cells.push_back(entry_cell);
317 if (current_cell->group == ENTRY_EVICTED)
318 entries.evicted_count++;
319 }
320 }
321 }
322 bucket_id = GetNextBucket(mask_ + 1, header()->max_bucket, extra_table_,
323 &bucket);
324 if (!bucket_id)
325 break;
326 }
327 return entries;
328 }
329
330 EntryCell IndexTable::CreateEntryCell(uint32 hash, Addr address) {
331 DCHECK(EntryCell::ValidAddress(address));
332
333 int bucket_id = static_cast<int>(hash & mask_);
334 int cell_id = 0;
335 IndexBucket* bucket = &main_table_[bucket_id];
336 IndexCell* current_cell = NULL;
337 bool found = false;
338 for (; !found;) {
339 for (int i = 0; i < 4 && !found; i++) {
340 current_cell = &bucket->cells[i];
341 if (!current_cell->address) {
342 cell_id = bucket_id * 4 + i;
343 found = true;
344 }
345 }
346 if (found)
347 break;
348 bucket_id = GetNextBucket(mask_ + 1, header()->max_bucket, extra_table_,
349 &bucket);
350 if (!bucket_id)
351 break;
352 }
353
354 if (!found) {
355 bucket_id = NewExtraBucket();
356 if (bucket_id) {
357 cell_id = bucket_id * 4;
358 bucket->next = cell_id;
359 found = true;
360 } else {
361 // address 0 is a reserved value, and the caller interprets it as invalid.
362 address.set_value(0);
363 }
364 }
365
366 EntryCell entry_cell(cell_id, hash, address);
367 if (address.file_type() == BLOCK_EVICTED)
368 entry_cell.set_group(ENTRY_EVICTED);
369 else
370 entry_cell.set_group(ENTRY_NO_USE);
371 Save(&entry_cell);
372
373 if (found) {
374 bitmap_->Set(cell_id, true);
375 backup_bitmap_->Set(cell_id, true);
376 header()->used_cells++;
377 }
378
379 return entry_cell;
380 }
381
382 bool IndexTable::SetSate(uint32 hash, Addr address, EntryState state) {
383 EntryCell cell = FindEntryCellImpl(hash, address, state == ENTRY_FREE);
384 if (!cell.IsValid())
385 return false;
386
387 if (state == ENTRY_DELETED) {
388 bitmap_->Set(cell.cell_id(), false);
389 backup_bitmap_->Set(cell.cell_id(), false);
390 } else if (state == ENTRY_FREE) {
391 DCHECK_EQ(ENTRY_DELETED, cell.state());
392 cell.Clear();
393 Write(cell);
394 header()->used_cells--;
395 return true;
396 }
397 cell.set_state(state);
398
399 Save(&cell);
400 return true;
401 }
402
403 int IndexTable::GetTimestamp(Time time) {
404 TimeDelta delta = time - Time::FromInternalValue(header_->base_time);
405 return std::max(delta.InMinutes(), 0);
406 }
407
408 void IndexTable::UpdateTime(uint32 hash, Addr address) {
409 EntryCell cell = FindEntryCell(hash, address);
410 if (!cell.IsValid())
411 return;
412
413 int minutes = GetTimestamp(backend_->GetCurrentTime());
414
415 // Keep about 3 months of headroom.
416 const int kMaxTimestamp = (1 << 20) - 60 * 24 * 90;
417 if (minutes > kMaxTimestamp) {
418 // TODO(rvargas):
419 // Update header->old_time and trigger a timer
420 // Rebaseline timestamps and don't update sums
421 // Start a timer (about 2 backups)
422 // fix all ckecksums and trigger another timer
423 // update header->old_time because rebaseline is done.
424 minutes = std::min(minutes, (1 << 20) - 1);
425 }
426
427 cell.set_timestamp(minutes);
428 Save(&cell);
429 }
430
431 EntryCell IndexTable::FindEntryCell(uint32 hash, Addr address) {
432 return FindEntryCellImpl(hash, address, false);
433 }
434
435 void IndexTable::Save(EntryCell* cell) {
436 cell->FixSum();
437 Write(*cell);
438 }
439
440 void IndexTable::GetOldest(CellList* no_use, CellList* low_use,
441 CellList* high_use) {
442 header_->num_no_use_entries = 0;
443 header_->num_low_use_entries = 0;
444 header_->num_high_use_entries = 0;
445 header_->num_evicted_entries = 0;
446
447 int no_use_time = kint32max;
448 int low_use_time = kint32max;
449 int high_use_time = kint32max;
450 for (int i = 0; i < static_cast<int32>(mask_ + 1); i++) {
451 int bucket_id = i;
452 IndexBucket* bucket = &main_table_[i];
453 for (;;) {
454 GetOldestFromBucket(bucket, i, no_use, &no_use_time, low_use,
455 &low_use_time, high_use, &high_use_time);
456
457 bucket_id = GetNextBucket(mask_ + 1, header()->max_bucket, extra_table_,
458 &bucket);
459 if (!bucket_id)
460 break;
461 }
462 }
463 header_->num_entries = header_->num_no_use_entries +
464 header_->num_low_use_entries +
465 header_->num_high_use_entries +
466 header_->num_evicted_entries;
467 }
468
469 bool IndexTable::GetNextCells(IndexIterator* iterator) {
470 int current_time = iterator->timestamp;
471 size_t initial_size = iterator->cells.size();
472 iterator->timestamp = iterator->forward ? 0 : kint32max;
473
474 for (int i = 0; i < static_cast<int32>(mask_ + 1); i++) {
475 int bucket_id = i;
476 IndexBucket* bucket = &main_table_[i];
477 for (;;) {
478 GetNewestFromBucket(bucket, i, current_time, iterator);
479
480 bucket_id = GetNextBucket(mask_ + 1, header()->max_bucket, extra_table_,
481 &bucket);
482 if (!bucket_id)
483 break;
484 }
485 }
486 return initial_size != iterator->cells.size();
487 }
488
489 // -----------------------------------------------------------------------
490
491 EntryCell IndexTable::FindEntryCellImpl(uint32 hash, Addr address,
492 bool allow_deleted) {
493 int bucket_id = static_cast<int>(hash & mask_);
494 IndexBucket* bucket = &main_table_[bucket_id];
495 for (;;) {
496 for (int i = 0; i < 4; i++) {
497 IndexCell* current_cell = &bucket->cells[i];
498 if (!current_cell->address)
499 continue;
500 DCHECK(SanityCheck(*current_cell));
501 if (EntryCell::GetHash(*current_cell) == (hash >> 14)) {
502 // We have a match.
503 int cell_id = bucket_id * 4 + i;
504 EntryCell entry_cell(cell_id, hash, *current_cell);
505 if (entry_cell.GetAddress() != address)
506 continue;
507
508 if (!allow_deleted && entry_cell.state() == ENTRY_DELETED)
509 continue;
510
511 return entry_cell;
512 }
513 }
514 bucket_id = GetNextBucket(mask_ + 1, header()->max_bucket, extra_table_,
515 &bucket);
516 if (!bucket_id)
517 break;
518 }
519 return EntryCell();
520 }
521
522 void IndexTable::CheckState(IndexCell* cell, int32 cell_id) {
523 if (cell->state != ENTRY_FIXING) {
524 bool present = ((cell->state & 3) != 0); // Look at the last two bits.
525 if (present != bitmap_->Get(cell_id) ||
526 present != backup_bitmap_->Get(cell_id)) {
527 // There's a mismatch.
528 if (cell->state == ENTRY_DELETED) {
529 // We were in the process of deleting this entry. Finish now.
530 backend_->DeleteCell(cell, cell_id);
531 } else {
532 cell->state = ENTRY_FIXING;
533 }
534 }
535 }
536
537 if (cell->state == ENTRY_FIXING)
538 backend_->FixCell(cell, cell_id);
539 }
540
541 void IndexTable::Write(const EntryCell& cell) {
542 if (!cell.IsValid())
543 return;
544
545 IndexBucket* bucket = NULL;
546 int bucket_id = cell.cell_id() / 4;
547 if (bucket_id < static_cast<int32>(mask_ + 1)) {
548 bucket = &main_table_[bucket_id];
549 } else {
550 DCHECK_LE(bucket_id, header()->max_bucket);
551 bucket = &extra_table_[bucket_id - (mask_ + 1)];
552 }
553 memcpy(&bucket->cells[cell.cell_id() % 4], &cell.cell(), sizeof(IndexCell));
554 }
555
556 int IndexTable::NewExtraBucket() {
557 if (header()->table_len - header()->max_bucket * 4 < kNumExtraBlocks)
558 backend_->GrowIndex();
559
560 if (header()->max_bucket * 4 == header()->table_len - 4)
561 return 0;
562
563 header()->max_bucket++;
564 return header()->max_bucket;
565 }
566
567 void IndexTable::GetOldestFromBucket(IndexBucket* bucket, int bucket_hash,
568 CellList* no_use, int* no_use_time,
569 CellList* low_use, int* low_use_time,
570 CellList* high_use, int* high_use_time) {
571 for (int i = 0; i < 4; i++) {
572 IndexCell& current_cell = bucket->cells[i];
573 if (!current_cell.address)
574 continue;
575 DCHECK(SanityCheck(current_cell));
576 if (!EntryCell::IsNormalState(current_cell))
577 continue;
578
579 int time = EntryCell::GetTimestamp(current_cell);
580 switch (current_cell.group) {
581 case ENTRY_NO_USE:
582 UpdateListWithCell(bucket_hash, current_cell, no_use, no_use_time);
583 header_->num_no_use_entries++;
584 break;
585 case ENTRY_LOW_USE:
586 UpdateListWithCell(bucket_hash, current_cell, low_use, low_use_time);
587 header_->num_low_use_entries++;
588 break;
589 case ENTRY_HIGH_USE:
590 UpdateListWithCell(bucket_hash, current_cell, high_use, high_use_time);
591 header_->num_high_use_entries++;
592 break;
593 case ENTRY_EVICTED:
594 header_->num_evicted_entries++;
595 break;
596 default:
597 NOTREACHED();
598 }
599 }
600 }
601
602 void IndexTable::MoveCells(IndexBucket* old_extra_table) {
603 int max_hash = (mask_ + 1) / 2;
604 int max_bucket = header()->max_bucket;
605 header()->max_bucket = mask_;
606
607 // A cell stores the upper 18 bits of the hash (h >> 14). If the table is say
608 // 8 times the original size (growing from 4x), the bit that we are interested
609 // in would be the 3rd bit of the stored value, in other words multiplir >> 1.
610 uint32 new_bit = ((mask_ + 1) * 4 / kIndexTablesize) >> 1;
611
612 for (int i = 0; i < max_hash; i++) {
613 int bucket_id = i;
614 IndexBucket* bucket = &main_table_[i];
615 for (;;) {
616 for (int j = 0; j < 4; j++) {
617 IndexCell& current_cell = bucket->cells[j];
618 if (!current_cell.address)
619 continue;
620 DCHECK(SanityCheck(current_cell));
621 if (bucket_id == i) {
622 if (EntryCell::GetHash(current_cell) & new_bit) {
623 // Move this cell to the upper half of the table.
624 MoveSingleCell(&current_cell, bucket_id * 4 + j, i, true);
625 }
626 } else {
627 // All cells on extra buckets have to move.
628 MoveSingleCell(&current_cell, bucket_id * 4 + j, i, true);
629 }
630 }
631
632 bucket_id = GetNextBucket(max_hash, max_bucket, old_extra_table, &bucket);
633 if (!bucket_id)
634 break;
635 }
636 }
637 }
638
639 void IndexTable::MoveSingleCell(IndexCell* current_cell, int cell_id,
640 int main_table_index, bool growing) {
641 uint32 hash = (EntryCell::GetHash(*current_cell) << 14) | main_table_index;
642 EntryCell old_cell(cell_id, hash, *current_cell);
643
644 EntryCell new_cell = CreateEntryCell(hash, old_cell.GetAddress());
645 if (!new_cell.IsValid())
646 return; // We'll deal with this entry later.
647
648 new_cell.set_state(old_cell.state());
649 new_cell.set_group(old_cell.group());
650 new_cell.set_reuse(old_cell.reuse());
651 new_cell.set_timestamp(old_cell.GetTimestamp());
652 Save(&new_cell);
653
654 if (old_cell.state() == ENTRY_DELETED) {
655 bitmap_->Set(new_cell.cell_id(), false);
656 backup_bitmap_->Set(new_cell.cell_id(), false);
657 }
658
659 if (!growing || cell_id / 4 == main_table_index) {
660 // Only delete entries that live on the main table.
661 old_cell.Clear();
662 Write(old_cell);
663 }
664 }
665
666 void IndexTable::HandleMisplacedCell(IndexCell* current_cell, int cell_id,
667 int main_table_index) {
668 // The cell may be misplaced, or a duplicate cell exists with this data.
669 uint32 hash = (EntryCell::GetHash(*current_cell) << 14) | main_table_index;
670 MoveSingleCell(current_cell, cell_id, main_table_index, false);
671
672 // Now look for a duplicate cell.
673 CheckBucketList(hash & mask_);
674 }
675
676 void IndexTable::CheckBucketList(int bucket_id) {
677 typedef std::pair<int, EntryGroup> AddressAndGroup;
678 std::set<AddressAndGroup> entries;
679 IndexBucket* bucket = &main_table_[bucket_id];
680 for (;;) {
681 for (int i = 0; i < 4; i++) {
682 IndexCell* current_cell = &bucket->cells[i];
683 if (!current_cell->address)
684 continue;
685 if (!SanityCheck(*current_cell)) {
686 NOTREACHED();
687 current_cell->Clear();
688 continue;
689 }
690 int cell_id = bucket_id * 4 + i;
691 EntryCell cell(cell_id, 0, *current_cell);
692 if (!entries.insert(std::make_pair(cell.GetAddress().value(),
693 cell.group())).second) {
694 current_cell->Clear();
695 continue;
696 }
697 CheckState(current_cell, cell_id);
698 }
699
700 bucket_id = GetNextBucket(mask_ + 1, header()->max_bucket, extra_table_,
701 &bucket);
702 if (!bucket_id)
703 break;
704 }
705 }
706
707 // Things we can be doing:
708 //
709 // - Updating timestamps
710 // Fast, but we go through a few backup cycles to make sure it sticks
711 // - Growing the extra table -> increase bitmap size, remap
712 // Just a matter of tripping to the cache thread. Everything keeps moving
713 // - Growing the whole table -> relocating all entries, may take a while
714 // - Evictions... only when we are NOT doing something else? just find the
715 // entries again so that there's no invalidation of lists
716
717 } // namespace disk_cache
OLDNEW
« no previous file with comments | « net/disk_cache/v3/index_table.h ('k') | net/disk_cache/v3/sparse_control_v3.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698