Bug 1359299 - V4 caches in LookupCache need to be copied around in copy constructor. r=hchang

MozReview-Commit-ID: AjzUUmQKiPW

--HG--
extra : rebase_source : 1c30ee5aa3548dce9b861a70660b1e60410f3654
This commit is contained in:
DimiL 2017-06-06 14:16:57 +08:00
Родитель 45d7f2628e
Коммит e4d42d14a2
7 изменённых файлов: 76 добавлений и 67 удалений

Просмотреть файл

@ -627,6 +627,34 @@ Classifier::RemoveUpdateIntermediaries()
}
}
void
Classifier::CopyAndInvalidateFullHashCache()
{
MOZ_ASSERT(NS_GetCurrentThread() != mUpdateThread,
"CopyAndInvalidateFullHashCache cannot be called on update thread "
"since it mutates mLookupCaches which is only safe on "
"worker thread.");
// New lookup caches are built from disk, data likes cache which is
// generated online won't exist. We have to manually copy cache from
// old LookupCache to new LookupCache.
for (auto& newCache: mNewLookupCaches) {
for (auto& oldCache: mLookupCaches) {
if (oldCache->TableName() == newCache->TableName()) {
newCache->CopyFullHashCache(oldCache);
break;
}
}
}
// Clear cache when update.
// Invalidate cache entries in CopyAndInvalidateFullHashCache because only
// at this point we will have cache data in LookupCache.
for (auto& newCache: mNewLookupCaches) {
newCache->InvalidateExpiredCacheEntries();
}
}
void
Classifier::MergeNewLookupCaches()
{
@ -860,6 +888,10 @@ Classifier::ApplyUpdatesForeground(nsresult aBackgroundRv,
return NS_OK;
}
if (NS_SUCCEEDED(aBackgroundRv)) {
// Copy and Invalidate fullhash cache here because this call requires
// mLookupCaches which is only available on work-thread
CopyAndInvalidateFullHashCache();
return SwapInNewTablesAndCleanup();
}
if (NS_ERROR_OUT_OF_MEMORY != aBackgroundRv) {
@ -1223,9 +1255,6 @@ Classifier::UpdateHashStore(nsTArray<TableUpdate*>* aUpdates,
return NS_ERROR_UC_UPDATE_TABLE_NOT_FOUND;
}
// Clear cache when update
lookupCache->InvalidateExpiredCacheEntries();
FallibleTArray<uint32_t> AddPrefixHashes;
rv = lookupCache->GetPrefixes(AddPrefixHashes);
NS_ENSURE_SUCCESS(rv, rv);
@ -1315,11 +1344,6 @@ Classifier::UpdateTableV4(nsTArray<TableUpdate*>* aUpdates,
return NS_ERROR_UC_UPDATE_TABLE_NOT_FOUND;
}
// Remove cache entries whose negative cache time is expired when update.
// We don't check if positive cache time is expired here because we want to
// keep the eviction rule simple when doing an update.
lookupCache->InvalidateExpiredCacheEntries();
nsresult rv = NS_OK;
// If there are multiple updates for the same table, prefixes1 & prefixes2

Просмотреть файл

@ -140,6 +140,8 @@ private:
void MergeNewLookupCaches(); // Merge mNewLookupCaches into mLookupCaches.
void CopyAndInvalidateFullHashCache();
// Remove any intermediary for update, including in-memory
// and on-disk data.
void RemoveUpdateIntermediaries();

Просмотреть файл

@ -356,6 +356,16 @@ struct CachedFullHashResponse {
typedef nsClassHashtable<nsUint32HashKey, CachedFullHashResponse> FullHashResponseMap;
template<class T>
void
CopyClassHashTable(const T& aSource, T& aDestination)
{
for (auto iter = aSource.ConstIter(); !iter.Done(); iter.Next()) {
auto value = aDestination.LookupOrAdd(iter.Key());
*value = *(iter.Data());
}
}
} // namespace safebrowsing
} // namespace mozilla

Просмотреть файл

@ -148,7 +148,7 @@ LookupCache::CheckCache(const Completion& aCompletion,
uint32_t prefix = aCompletion.ToUint32();
CachedFullHashResponse* fullHashResponse = mCache.Get(prefix);
CachedFullHashResponse* fullHashResponse = mFullHashCache.Get(prefix);
if (!fullHashResponse) {
return NS_OK;
}
@ -178,7 +178,7 @@ LookupCache::CheckCache(const Completion& aCompletion,
fullHashes.Remove(completion);
if (fullHashes.Count() == 0 &&
fullHashResponse->negativeCacheExpirySec < nowSec) {
mCache.Remove(prefix);
mFullHashCache.Remove(prefix);
}
}
}
@ -193,7 +193,7 @@ LookupCache::CheckCache(const Completion& aCompletion,
} else {
LOG(("Found an expired prefix in the negative cache"));
if (fullHashes.Count() == 0) {
mCache.Remove(prefix);
mFullHashCache.Remove(prefix);
}
}
@ -209,7 +209,7 @@ LookupCache::InvalidateExpiredCacheEntries()
{
int64_t nowSec = PR_Now() / PR_USEC_PER_SEC;
for (auto iter = mCache.Iter(); !iter.Done(); iter.Next()) {
for (auto iter = mFullHashCache.Iter(); !iter.Done(); iter.Next()) {
CachedFullHashResponse* response = iter.Data();
if (response->negativeCacheExpirySec < nowSec) {
iter.Remove();
@ -217,10 +217,21 @@ LookupCache::InvalidateExpiredCacheEntries()
}
}
void
LookupCache::CopyFullHashCache(const LookupCache* aSource)
{
if (!aSource) {
return;
}
CopyClassHashTable<FullHashResponseMap>(aSource->mFullHashCache,
mFullHashCache);
}
void
LookupCache::ClearCache()
{
mCache.Clear();
mFullHashCache.Clear();
}
void
@ -239,7 +250,7 @@ LookupCache::GetCacheInfo(nsIUrlClassifierCacheInfo** aCache)
RefPtr<nsUrlClassifierCacheInfo> info = new nsUrlClassifierCacheInfo;
info->table = mTableName;
for (auto iter = mCache.ConstIter(); !iter.Done(); iter.Next()) {
for (auto iter = mFullHashCache.ConstIter(); !iter.Done(); iter.Next()) {
RefPtr<nsUrlClassifierCacheEntry> entry = new nsUrlClassifierCacheEntry;
// Set prefix of the cache entry.
@ -505,7 +516,7 @@ LookupCache::DumpCache()
return;
}
for (auto iter = mCache.ConstIter(); !iter.Done(); iter.Next()) {
for (auto iter = mFullHashCache.ConstIter(); !iter.Done(); iter.Next()) {
CachedFullHashResponse* response = iter.Data();
nsAutoCString prefix;
@ -640,7 +651,7 @@ LookupCacheV2::AddGethashResultToCache(AddCompleteArray& aAddCompletes,
MissPrefixArray& aMissPrefixes,
int64_t aExpirySec)
{
int64_t defaultExpirySec = PR_Now() / PR_USEC_PER_SEC + V2_CACHE_DURATION_SEC;
int64_t defaultExpirySec = PR_Now() / PR_USEC_PER_SEC + V2_CACHE_DURATION_SEC;
if (aExpirySec != 0) {
defaultExpirySec = aExpirySec;
}
@ -649,7 +660,8 @@ LookupCacheV2::AddGethashResultToCache(AddCompleteArray& aAddCompletes,
nsDependentCSubstring fullhash(
reinterpret_cast<const char*>(add.CompleteHash().buf), COMPLETE_SIZE);
CachedFullHashResponse* response = mCache.LookupOrAdd(add.ToUint32());
CachedFullHashResponse* response =
mFullHashCache.LookupOrAdd(add.ToUint32());
response->negativeCacheExpirySec = defaultExpirySec;
FullHashExpiryCache& fullHashes = response->fullHashes;
@ -657,7 +669,9 @@ LookupCacheV2::AddGethashResultToCache(AddCompleteArray& aAddCompletes,
}
for (const Prefix& prefix : aMissPrefixes) {
CachedFullHashResponse* response = mCache.LookupOrAdd(prefix.ToUint32());
CachedFullHashResponse* response =
mFullHashCache.LookupOrAdd(prefix.ToUint32());
response->negativeCacheExpirySec = defaultExpirySec;
}
}

Просмотреть файл

@ -199,12 +199,15 @@ public:
// Called when update to clear expired entries.
void InvalidateExpiredCacheEntries();
// Clear completions retrieved from gethash request.
// Copy fullhash cache from another LookupCache.
void CopyFullHashCache(const LookupCache* aSource);
// Clear fullhash cache from fullhash/gethash response.
void ClearCache();
// Check if completions can be found in cache.
// Currently this is only used by testcase.
bool IsInCache(uint32_t key) { return mCache.Get(key); };
bool IsInCache(uint32_t key) { return mFullHashCache.Get(key); };
#if DEBUG
void DumpCache();
@ -254,8 +257,8 @@ protected:
// For gtest to inspect private members.
friend class PerProviderDirectoryTestUtils;
// Cache gethash result.
FullHashResponseMap mCache;
// Cache stores fullhash response(V4)/gethash response(V2)
FullHashResponseMap mFullHashCache;
};
class LookupCacheV2 final : public LookupCache

Просмотреть файл

@ -330,10 +330,7 @@ LookupCacheV4::ApplyUpdate(TableUpdateV4* aTableUpdate,
nsresult
LookupCacheV4::AddFullHashResponseToCache(const FullHashResponseMap& aResponseMap)
{
for (auto iter = aResponseMap.ConstIter(); !iter.Done(); iter.Next()) {
CachedFullHashResponse* response = mCache.LookupOrAdd(iter.Key());
*response = *(iter.Data());
}
CopyClassHashTable<FullHashResponseMap>(aResponseMap, mFullHashCache);
return NS_OK;
}

Просмотреть файл

@ -558,46 +558,6 @@ function testCachedResultsWithExpire() {
});
}
function testCachedResultsUpdate()
{
var existUrls = ["foo.com/a"];
setupCachedResults(existUrls, function() {
// This is called after setupCachedResults(). Verify that
// checking the url again does not cause a completer request.
// install a new completer, this one should never be queried.
var newCompleter = installCompleter('test-phish-simple', [[1, []]], []);
var assertions = {
"urlsExist" : existUrls,
"completerQueried" : [newCompleter, []]
};
var addUrls = ["foobar.org/a"];
var update2 = buildPhishingUpdate(
[
{ "chunkNum" : 2,
"urls" : addUrls
}],
4);
checkAssertions(assertions, function () {
// Apply the update. The cached completes should be gone.
doStreamUpdate(update2, function() {
// Now the completer gets queried again.
var newCompleter2 = installCompleter('test-phish-simple', [[1, existUrls]], []);
var assertions2 = {
"tableData" : "test-phish-simple;a:1-2",
"urlsExist" : existUrls,
"completerQueried" : [newCompleter2, existUrls]
};
checkAssertions(assertions2, runNextTest);
}, updateError);
});
});
}
function testCachedResultsFailure()
{
var existUrls = ["foo.com/a"];
@ -735,7 +695,6 @@ function run_test()
testCachedResults,
testCachedResultsWithSub,
testCachedResultsWithExpire,
testCachedResultsUpdate,
testCachedResultsFailure,
testErrorList,
testErrorListIndependent