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

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