Bug 1305780 - P1. Implement the update fail scheme for v4. r?gcp
MozReview-Commit-ID: LeVpVIUdmjc
--- a/toolkit/components/url-classifier/Classifier.cpp
+++ b/toolkit/components/url-classifier/Classifier.cpp
@@ -14,16 +14,17 @@
#include "nsIFile.h"
#include "nsNetCID.h"
#include "nsPrintfCString.h"
#include "nsThreadUtils.h"
#include "mozilla/Telemetry.h"
#include "mozilla/Logging.h"
#include "mozilla/SyncRunnable.h"
#include "mozilla/Base64.h"
+#include "mozilla/Unused.h"
// MOZ_LOG=UrlClassifierDbService:5
extern mozilla::LazyLogModule gUrlClassifierDbServiceLog;
#define LOG(args) MOZ_LOG(gUrlClassifierDbServiceLog, mozilla::LogLevel::Debug, args)
#define LOG_ENABLED() MOZ_LOG_TEST(gUrlClassifierDbServiceLog, mozilla::LogLevel::Debug)
#define STORE_DIRECTORY NS_LITERAL_CSTRING("safebrowsing")
#define TO_DELETE_DIR_SUFFIX NS_LITERAL_CSTRING("-to_delete")
@@ -344,59 +345,97 @@ Classifier::Reset()
CreateStoreDirectory();
mTableFreshness.Clear();
RegenActiveTables();
}
void
-Classifier::ResetTables(const nsTArray<nsCString>& aTables)
+Classifier::ResetTables(ClearType aType, const nsTArray<nsCString>& aTables)
{
- // Clear lookup cache
- MarkSpoiled(aTables);
+ for (uint32_t i = 0; i < aTables.Length(); i++) {
+ LOG(("Resetting table: %s", aTables[i].get()));
+ // Spoil this table by marking it as no known freshness
+ mTableFreshness.Remove(aTables[i]);
+ LookupCache *cache = GetLookupCache(aTables[i]);
+ if (cache) {
+ // Remove any cached Completes for this table if clear type is Clear_Cache
+ if (aType == Clear_Cache) {
+ cache->ClearCache();
+ } else {
+ cache->ClearAll();
+ }
+ }
+ }
- // Clear on-disk database
- DeleteTables(aTables);
+ // Clear on-disk database if clear type is Clear_All
+ if (aType == Clear_All) {
+ DeleteTables(mRootStoreDirectory, aTables);
- RegenActiveTables();
+ RegenActiveTables();
+ }
}
void
-Classifier::DeleteTables(const nsTArray<nsCString>& aTables)
+Classifier::DeleteTables(nsIFile* aDirectory, const nsTArray<nsCString>& aTables)
{
nsCOMPtr<nsISimpleEnumerator> entries;
- nsresult rv = mRootStoreDirectory->GetDirectoryEntries(getter_AddRefs(entries));
+ nsresult rv = aDirectory->GetDirectoryEntries(getter_AddRefs(entries));
NS_ENSURE_SUCCESS_VOID(rv);
bool hasMore;
while (NS_SUCCEEDED(rv = entries->HasMoreElements(&hasMore)) && hasMore) {
nsCOMPtr<nsISupports> supports;
rv = entries->GetNext(getter_AddRefs(supports));
NS_ENSURE_SUCCESS_VOID(rv);
nsCOMPtr<nsIFile> file = do_QueryInterface(supports);
NS_ENSURE_TRUE_VOID(file);
+ // If |file| is a directory, recurse to find its entries as well.
+ bool isDirectory;
+ if (NS_FAILED(file->IsDirectory(&isDirectory))) {
+ continue;
+ }
+ if (isDirectory) {
+ DeleteTables(file, aTables);
+ continue;
+ }
+
nsCString leafName;
rv = file->GetNativeLeafName(leafName);
NS_ENSURE_SUCCESS_VOID(rv);
leafName.Truncate(leafName.RFind("."));
if (aTables.Contains(leafName)) {
if (NS_FAILED(file->Remove(false))) {
NS_WARNING(nsPrintfCString("Fail to remove file %s from the disk",
leafName.get()).get());
}
}
}
NS_ENSURE_SUCCESS_VOID(rv);
}
void
+Classifier::AbortUpdateAndReset(const nsCString& aTable)
+{
+ LOG(("Abort updating table %s.", aTable.get()));
+
+ // ResetTables will clear both in-memory & on-disk data.
+ ResetTables(Clear_All, nsTArray<nsCString> { aTable });
+
+ // Remove the backup and delete directory since we are aborting
+ // from an update.
+ Unused << RemoveBackupTables();
+ Unused << CleanToDelete();
+}
+
+void
Classifier::TableRequest(nsACString& aResult)
{
// Generating v2 table info.
nsTArray<nsCString> tables;
ActiveTables(tables);
for (uint32_t i = 0; i < tables.Length(); i++) {
HashStore store(tables[i], mRootStoreDirectory);
@@ -545,17 +584,17 @@ Classifier::ApplyUpdates(nsTArray<TableU
if (TableUpdate::Cast<TableUpdateV2>((*aUpdates)[i])) {
rv = UpdateHashStore(aUpdates, updateTable);
} else {
rv = UpdateTableV4(aUpdates, updateTable);
}
if (NS_FAILED(rv)) {
if (rv != NS_ERROR_OUT_OF_MEMORY) {
- Reset();
+ AbortUpdateAndReset(updateTable);
}
return rv;
}
}
}
} // End of scopedUpdatesClearer scope.
@@ -597,32 +636,16 @@ Classifier::ApplyFullHashes(nsTArray<Tab
NS_ENSURE_SUCCESS(rv, rv);
aUpdates->ElementAt(i) = nullptr;
}
return NS_OK;
}
-nsresult
-Classifier::MarkSpoiled(const nsTArray<nsCString>& aTables)
-{
- for (uint32_t i = 0; i < aTables.Length(); i++) {
- LOG(("Spoiling table: %s", aTables[i].get()));
- // Spoil this table by marking it as no known freshness
- mTableFreshness.Remove(aTables[i]);
- // Remove any cached Completes for this table
- LookupCache *cache = GetLookupCache(aTables[i]);
- if (cache) {
- cache->ClearCache();
- }
- }
- return NS_OK;
-}
-
int64_t
Classifier::GetLastUpdateTime(const nsACString& aTableName)
{
int64_t age;
bool found = mTableFreshness.Get(aTableName, &age);
return found ? (age * PR_MSEC_PER_SEC) : 0;
}
--- a/toolkit/components/url-classifier/Classifier.h
+++ b/toolkit/components/url-classifier/Classifier.h
@@ -27,19 +27,25 @@ public:
Classifier();
~Classifier();
nsresult Open(nsIFile& aCacheDirectory);
void Close();
void Reset();
/**
- * Clear In-Memory & On-Disk data for specific tables
+ * Clear data for specific tables.
+ * If ClearType is Clear_Cache, this function will only clear cache in lookup
+ * cache, otherwise, it will clear data in lookup cache and data stored on disk.
*/
- void ResetTables(const nsTArray<nsCString>& aTables);
+ enum ClearType {
+ Clear_Cache,
+ Clear_All,
+ };
+ void ResetTables(ClearType aType, const nsTArray<nsCString>& aTables);
/**
* Get the list of active tables and their chunks in a format
* suitable for an update request.
*/
void TableRequest(nsACString& aResult);
/*
@@ -61,21 +67,16 @@ public:
*/
nsresult ApplyUpdates(nsTArray<TableUpdate*>* aUpdates);
/**
* Apply full hashes retrived from gethash to cache.
*/
nsresult ApplyFullHashes(nsTArray<TableUpdate*>* aUpdates);
- /**
- * Failed update. Spoil the entries so we don't block hosts
- * unnecessarily
- */
- nsresult MarkSpoiled(const nsTArray<nsCString>& aTables);
void SetLastUpdateTime(const nsACString& aTableName, uint64_t updateTime);
int64_t GetLastUpdateTime(const nsACString& aTableName);
nsresult CacheCompletions(const CacheResultArray& aResults);
uint32_t GetHashKey(void) { return mHashKey; }
/*
* Get a bunch of extra prefixes to query for completion
* and mask the real entry being requested
*/
@@ -96,17 +97,18 @@ public:
// Note that if the table name is not owned by any provider, just use
// the root directory.
static nsresult GetPrivateStoreDirectory(nsIFile* aRootStoreDirectory,
const nsACString& aTableName,
nsIFile** aPrivateStoreDirectory);
private:
void DropStores();
- void DeleteTables(const nsTArray<nsCString>& aTables);
+ void DeleteTables(nsIFile* aDirectory, const nsTArray<nsCString>& aTables);
+ void AbortUpdateAndReset(const nsCString& aTable);
nsresult CreateStoreDirectory();
nsresult SetupPathNames();
nsresult RecoverBackups();
nsresult CleanToDelete();
nsresult BackupTables();
nsresult RemoveBackupTables();
nsresult RegenActiveTables();
--- a/toolkit/components/url-classifier/LookupCache.h
+++ b/toolkit/components/url-classifier/LookupCache.h
@@ -121,34 +121,34 @@ public:
#endif
virtual nsresult Open();
virtual nsresult Init() = 0;
virtual nsresult ClearPrefixes() = 0;
virtual nsresult Has(const Completion& aCompletion,
bool* aHas, bool* aComplete) = 0;
+ virtual void ClearAll();
+
template<typename T>
static T* Cast(LookupCache* aThat) {
return ((aThat && T::VER == aThat->Ver()) ? reinterpret_cast<T*>(aThat) : nullptr);
}
private:
nsresult Reset();
nsresult LoadPrefixSet();
virtual nsresult StoreToFile(nsIFile* aFile) = 0;
virtual nsresult LoadFromFile(nsIFile* aFile) = 0;
virtual size_t SizeOfPrefixSet() = 0;
virtual int Ver() const = 0;
protected:
- virtual void ClearAll();
-
bool mPrimed;
nsCString mTableName;
nsCOMPtr<nsIFile> mRootStoreDirectory;
nsCOMPtr<nsIFile> mStoreDirectory;
// Full length hashes obtained in gethash request
CompletionArray mGetHashCache;
--- a/toolkit/components/url-classifier/nsUrlClassifierDBService.cpp
+++ b/toolkit/components/url-classifier/nsUrlClassifierDBService.cpp
@@ -561,17 +561,17 @@ nsUrlClassifierDBServiceWorker::FinishSt
LOG(("nsUrlClassifierDBService::FinishStream Failed to parse the stream "
"using mProtocolParser."));
mUpdateStatus = mProtocolParser->Status();
}
mUpdateObserver->StreamFinished(mProtocolParser->Status(), 0);
if (NS_SUCCEEDED(mUpdateStatus)) {
if (mProtocolParser->ResetRequested()) {
- mClassifier->ResetTables(mUpdateTables);
+ mClassifier->ResetTables(Classifier::Clear_All, mUpdateTables);
}
}
mProtocolParser = nullptr;
return NS_OK;
}
@@ -593,30 +593,30 @@ nsUrlClassifierDBServiceWorker::FinishUp
if (NS_SUCCEEDED(mUpdateStatus)) {
LOG(("Notifying success: %d", mUpdateWaitSec));
mUpdateObserver->UpdateSuccess(mUpdateWaitSec);
} else if (NS_ERROR_NOT_IMPLEMENTED == mUpdateStatus) {
LOG(("Treating NS_ERROR_NOT_IMPLEMENTED a successful update "
"but still mark it spoiled."));
mUpdateObserver->UpdateSuccess(0);
- mClassifier->MarkSpoiled(mUpdateTables);
+ mClassifier->ResetTables(Classifier::Clear_Cache, mUpdateTables);
} else {
if (LOG_ENABLED()) {
nsAutoCString errorName;
mozilla::GetErrorName(mUpdateStatus, errorName);
LOG(("Notifying error: %s (%d)", errorName.get(), mUpdateStatus));
}
mUpdateObserver->UpdateError(mUpdateStatus);
/*
- * mark the tables as spoiled, we don't want to block hosts
- * longer than normal because our update failed
+ * mark the tables as spoiled(clear cache in LookupCache), we don't want to
+ * block hosts longer than normal because our update failed
*/
- mClassifier->MarkSpoiled(mUpdateTables);
+ mClassifier->ResetTables(Classifier::Clear_Cache, mUpdateTables);
}
mUpdateObserver = nullptr;
return NS_OK;
}
nsresult
nsUrlClassifierDBServiceWorker::ApplyUpdate()
@@ -680,20 +680,20 @@ nsUrlClassifierDBServiceWorker::CancelUp
if (mUpdateObserver) {
LOG(("UpdateObserver exists, cancelling"));
mUpdateStatus = NS_BINDING_ABORTED;
mUpdateObserver->UpdateError(mUpdateStatus);
/*
- * mark the tables as spoiled, we don't want to block hosts
- * longer than normal because our update failed
+ * mark the tables as spoiled(clear cache in LookupCache), we don't want to
+ * block hosts longer than normal because our update failed
*/
- mClassifier->MarkSpoiled(mUpdateTables);
+ mClassifier->ResetTables(Classifier::Clear_Cache, mUpdateTables);
ResetStream();
ResetUpdate();
} else {
LOG(("No UpdateObserver, nothing to cancel"));
}
return NS_OK;