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

Side by Side Diff: net/disk_cache/backend_impl.cc

Issue 155951: Disk cache: Fix handling of invalid entries that are detected... (Closed) Base URL: svn://chrome-svn/chrome/trunk/src/
Patch Set: Created 11 years, 5 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/backend_impl.h ('k') | net/disk_cache/backend_unittest.cc » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 // Copyright (c) 2006-2008 The Chromium Authors. All rights reserved. 1 // Copyright (c) 2006-2008 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/backend_impl.h" 5 #include "net/disk_cache/backend_impl.h"
6 6
7 #include "base/field_trial.h" 7 #include "base/field_trial.h"
8 #include "base/file_path.h" 8 #include "base/file_path.h"
9 #include "base/file_util.h" 9 #include "base/file_util.h"
10 #include "base/histogram.h" 10 #include "base/histogram.h"
(...skipping 129 matching lines...) Expand 10 before | Expand all | Expand 10 after
140 140
141 // Sets |current_group| for the current experiment. Returns false if the files 141 // Sets |current_group| for the current experiment. Returns false if the files
142 // should be discarded. 142 // should be discarded.
143 bool InitExperiment(int* current_group) { 143 bool InitExperiment(int* current_group) {
144 if (*current_group == 3 || *current_group == 4) { 144 if (*current_group == 3 || *current_group == 4) {
145 // Discard current cache for groups 3 and 4. 145 // Discard current cache for groups 3 and 4.
146 return false; 146 return false;
147 } 147 }
148 148
149 if (*current_group <= 5) { 149 if (*current_group <= 5) {
150 #if defined(UNIT_TEST)
151 // The unit test controls directly what to test.
152 *current_group = 0;
153 return true;
154 #endif
155
150 // Re-load the two groups. 156 // Re-load the two groups.
151 int option = base::RandInt(0, 9); 157 int option = base::RandInt(0, 9);
152 158
153 if (option > 1) { 159 if (option > 1) {
154 // 80% will be out of the experiment. 160 // 80% will be out of the experiment.
155 *current_group = 9; 161 *current_group = 9;
156 } else { 162 } else {
157 *current_group = option + 6; 163 *current_group = option + 6;
158 } 164 }
159 } 165 }
(...skipping 1010 matching lines...) Expand 10 before | Expand all | Expand 10 after
1170 if (parent_entry) { 1176 if (parent_entry) {
1171 parent_entry->SetNextAddress(child); 1177 parent_entry->SetNextAddress(child);
1172 parent_entry = NULL; 1178 parent_entry = NULL;
1173 } else { 1179 } else {
1174 data_->table[hash & mask_] = child.value(); 1180 data_->table[hash & mask_] = child.value();
1175 } 1181 }
1176 1182
1177 if (!error) { 1183 if (!error) {
1178 // It is important to call DestroyInvalidEntry after removing this 1184 // It is important to call DestroyInvalidEntry after removing this
1179 // entry from the table. 1185 // entry from the table.
1180 DestroyInvalidEntry(address, cache_entry); 1186 DestroyInvalidEntry(cache_entry);
1181 cache_entry = NULL; 1187 cache_entry = NULL;
1182 } else { 1188 } else {
1183 Trace("NewEntry failed on MatchEntry 0x%x", address.value()); 1189 Trace("NewEntry failed on MatchEntry 0x%x", address.value());
1184 } 1190 }
1185 1191
1186 // Restart the search. 1192 // Restart the search.
1187 address.set_value(data_->table[hash & mask_]); 1193 address.set_value(data_->table[hash & mask_]);
1188 continue; 1194 continue;
1189 } 1195 }
1190 1196
(...skipping 54 matching lines...) Expand 10 before | Expand all | Expand 10 after
1245 return false; 1251 return false;
1246 } else { 1252 } else {
1247 // Get the next entry from the last list, and the actual entries for the 1253 // Get the next entry from the last list, and the actual entries for the
1248 // elements on the other lists. 1254 // elements on the other lists.
1249 for (int i = 0; i < kListsToSearch; i++) { 1255 for (int i = 0; i < kListsToSearch; i++) {
1250 EntryImpl* temp = NULL; 1256 EntryImpl* temp = NULL;
1251 if (iterator->list == i) { 1257 if (iterator->list == i) {
1252 OpenFollowingEntryFromList(forward, iterator->list, 1258 OpenFollowingEntryFromList(forward, iterator->list,
1253 &iterator->nodes[i], &temp); 1259 &iterator->nodes[i], &temp);
1254 } else { 1260 } else {
1255 temp = GetEnumeratedEntry(iterator->nodes[i]); 1261 temp = GetEnumeratedEntry(iterator->nodes[i], false);
1256 } 1262 }
1257 1263
1258 entries[i].swap(&temp); // The entry was already addref'd. 1264 entries[i].swap(&temp); // The entry was already addref'd.
1259 } 1265 }
1260 } 1266 }
1261 1267
1262 int newest = -1; 1268 int newest = -1;
1263 int oldest = -1; 1269 int oldest = -1;
1264 Time access_times[kListsToSearch]; 1270 Time access_times[kListsToSearch];
1265 for (int i = 0; i < kListsToSearch; i++) { 1271 for (int i = 0; i < kListsToSearch; i++) {
(...skipping 35 matching lines...) Expand 10 before | Expand all | Expand 10 after
1301 if (!new_eviction_ && Rankings::NO_USE != list) 1307 if (!new_eviction_ && Rankings::NO_USE != list)
1302 return false; 1308 return false;
1303 1309
1304 Rankings::ScopedRankingsBlock rankings(&rankings_, *from_entry); 1310 Rankings::ScopedRankingsBlock rankings(&rankings_, *from_entry);
1305 CacheRankingsBlock* next_block = forward ? 1311 CacheRankingsBlock* next_block = forward ?
1306 rankings_.GetNext(rankings.get(), list) : 1312 rankings_.GetNext(rankings.get(), list) :
1307 rankings_.GetPrev(rankings.get(), list); 1313 rankings_.GetPrev(rankings.get(), list);
1308 Rankings::ScopedRankingsBlock next(&rankings_, next_block); 1314 Rankings::ScopedRankingsBlock next(&rankings_, next_block);
1309 *from_entry = NULL; 1315 *from_entry = NULL;
1310 1316
1311 *next_entry = GetEnumeratedEntry(next.get()); 1317 *next_entry = GetEnumeratedEntry(next.get(), false);
1312 if (!*next_entry) 1318 if (!*next_entry)
1313 return false; 1319 return false;
1314 1320
1315 *from_entry = next.release(); 1321 *from_entry = next.release();
1316 return true; 1322 return true;
1317 } 1323 }
1318 1324
1319 EntryImpl* BackendImpl::GetEnumeratedEntry(CacheRankingsBlock* next) { 1325 EntryImpl* BackendImpl::GetEnumeratedEntry(CacheRankingsBlock* next,
1326 bool to_evict) {
1320 if (!next) 1327 if (!next)
1321 return NULL; 1328 return NULL;
1322 1329
1323 scoped_refptr<EntryImpl> entry; 1330 EntryImpl* entry;
1324 EntryImpl* temp = NULL; 1331 bool dirty;
1332 if (NewEntry(Addr(next->Data()->contents), &entry, &dirty))
1333 return NULL;
1325 1334
1326 if (next->Data()->pointer) { 1335 if (dirty) {
1327 entry = reinterpret_cast<EntryImpl*>(next->Data()->pointer); 1336 // We cannot trust this entry. This code also releases the reference.
1328 entry.swap(&temp); 1337 DestroyInvalidEntryFromEnumeration(entry);
1329 return temp; 1338 return NULL;
1330 } 1339 }
1331 1340
1332 bool dirty; 1341 // There is no need to store the entry to disk if we want to delete it.
1333 if (NewEntry(Addr(next->Data()->contents), &temp, &dirty)) 1342 if (!to_evict && !entry->Update()) {
1334 return NULL; 1343 entry->Release();
1335 entry.swap(&temp);
1336
1337 if (dirty) {
1338 // We cannot trust this entry. Call MatchEntry to go through the regular
1339 // path and take the appropriate action.
1340 std::string key = entry->GetKey();
1341 uint32 hash = entry->GetHash();
1342 entry = NULL; // Release the entry.
1343 temp = MatchEntry(key, hash, false);
1344 if (temp)
1345 temp->Release();
1346
1347 return NULL; 1344 return NULL;
1348 } 1345 }
1349 if (!entry->Update())
1350 return NULL;
1351 1346
1352 entry.swap(&temp); 1347 return entry;
1353 return temp;
1354 } 1348 }
1355 1349
1356 bool BackendImpl::ResurrectEntry(EntryImpl* deleted_entry, Entry** entry) { 1350 bool BackendImpl::ResurrectEntry(EntryImpl* deleted_entry, Entry** entry) {
1357 if (ENTRY_NORMAL == deleted_entry->entry()->Data()->state) { 1351 if (ENTRY_NORMAL == deleted_entry->entry()->Data()->state) {
1358 deleted_entry->Release(); 1352 deleted_entry->Release();
1359 stats_.OnEvent(Stats::CREATE_MISS); 1353 stats_.OnEvent(Stats::CREATE_MISS);
1360 Trace("create entry miss "); 1354 Trace("create entry miss ");
1361 return false; 1355 return false;
1362 } 1356 }
1363 1357
1364 // We are attempting to create an entry and found out that the entry was 1358 // We are attempting to create an entry and found out that the entry was
1365 // previously deleted. 1359 // previously deleted.
1366 1360
1367 eviction_.OnCreateEntry(deleted_entry); 1361 eviction_.OnCreateEntry(deleted_entry);
1368 *entry = deleted_entry; 1362 *entry = deleted_entry;
1369 1363
1370 stats_.OnEvent(Stats::CREATE_HIT); 1364 stats_.OnEvent(Stats::CREATE_HIT);
1371 Trace("Resurrect entry hit "); 1365 Trace("Resurrect entry hit ");
1372 return true; 1366 return true;
1373 } 1367 }
1374 1368
1375 void BackendImpl::DestroyInvalidEntry(Addr address, EntryImpl* entry) { 1369 void BackendImpl::DestroyInvalidEntry(EntryImpl* entry) {
1376 LOG(WARNING) << "Destroying invalid entry."; 1370 LOG(WARNING) << "Destroying invalid entry.";
1377 Trace("Destroying invalid entry 0x%p", entry); 1371 Trace("Destroying invalid entry 0x%p", entry);
1378 1372
1379 entry->SetPointerForInvalidEntry(GetCurrentEntryId()); 1373 entry->SetPointerForInvalidEntry(GetCurrentEntryId());
1380 1374
1381 eviction_.OnDoomEntry(entry); 1375 eviction_.OnDoomEntry(entry);
1382 entry->InternalDoom(); 1376 entry->InternalDoom();
1383 1377
1384 if (!new_eviction_) 1378 if (!new_eviction_)
1385 DecreaseNumEntries(); 1379 DecreaseNumEntries();
1386 stats_.OnEvent(Stats::INVALID_ENTRY); 1380 stats_.OnEvent(Stats::INVALID_ENTRY);
1387 } 1381 }
1388 1382
1383 // This is kind of ugly. The entry may or may not be part of the cache index
1384 // table, and it may even have corrupt fields. If we just doom it, we may end up
1385 // deleting it twice (if all fields are right, and when looking up the parent of
1386 // chained entries wee see this one... and we delete it because it is dirty). If
1387 // we ignore it, we may leave it here forever. So we're going to attempt to
1388 // delete it through the provided object, without touching the index table
1389 // (because we cannot jus call MatchEntry()), and also attempt to delete it from
1390 // the table through the key: this may find a new entry (too bad), or an entry
1391 // that was just deleted and consider it a very corrupt entry.
1392 void BackendImpl::DestroyInvalidEntryFromEnumeration(EntryImpl* entry) {
1393 std::string key = entry->GetKey();
1394 entry->SetPointerForInvalidEntry(GetCurrentEntryId());
1395 CacheAddr next_entry = entry->entry()->Data()->next;
1396 if (!next_entry) {
1397 DestroyInvalidEntry(entry);
1398 entry->Release();
1399 }
1400 DoomEntry(key);
1401
1402 if (!next_entry)
1403 return;
1404
1405 // We have a chained entry so instead of destroying first this entry and then
1406 // anything with this key, we just called DoomEntry() first. If that call
1407 // deleted everything, |entry| has invalid data. Let's see if there is
1408 // something else to do. We started with just a rankings node (we come from
1409 // an enumeration), so that one may still be there.
1410 CacheRankingsBlock* rankings = entry->rankings();
1411 rankings->Load();
1412 if (rankings->Data()->contents) {
1413 // We still have something. Clean this up.
1414 DestroyInvalidEntry(entry);
1415 }
1416 entry->Release();
1417 }
1418
1389 void BackendImpl::AddStorageSize(int32 bytes) { 1419 void BackendImpl::AddStorageSize(int32 bytes) {
1390 data_->header.num_bytes += bytes; 1420 data_->header.num_bytes += bytes;
1391 DCHECK(data_->header.num_bytes >= 0); 1421 DCHECK(data_->header.num_bytes >= 0);
1392 1422
1393 if (data_->header.num_bytes > max_size_) 1423 if (data_->header.num_bytes > max_size_)
1394 eviction_.TrimCache(false); 1424 eviction_.TrimCache(false);
1395 } 1425 }
1396 1426
1397 void BackendImpl::SubstractStorageSize(int32 bytes) { 1427 void BackendImpl::SubstractStorageSize(int32 bytes) {
1398 data_->header.num_bytes -= bytes; 1428 data_->header.num_bytes -= bytes;
(...skipping 203 matching lines...) Expand 10 before | Expand all | Expand 10 after
1602 1632
1603 return num_dirty; 1633 return num_dirty;
1604 } 1634 }
1605 1635
1606 bool BackendImpl::CheckEntry(EntryImpl* cache_entry) { 1636 bool BackendImpl::CheckEntry(EntryImpl* cache_entry) {
1607 RankingsNode* rankings = cache_entry->rankings()->Data(); 1637 RankingsNode* rankings = cache_entry->rankings()->Data();
1608 return !rankings->pointer; 1638 return !rankings->pointer;
1609 } 1639 }
1610 1640
1611 } // namespace disk_cache 1641 } // namespace disk_cache
OLDNEW
« no previous file with comments | « net/disk_cache/backend_impl.h ('k') | net/disk_cache/backend_unittest.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698