OLD | NEW |
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 Loading... |
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 Loading... |
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 Loading... |
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 Loading... |
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 Loading... |
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 |
OLD | NEW |