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

Unified Diff: chrome/browser/safe_browsing/safe_browsing_database.cc

Issue 794273002: Introduce SafeBrowsingDatabase::ThreadSafeStateManager. (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@a6_dedup_sideeffectfreeWLcode
Patch Set: Created 6 years 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 side-by-side diff with in-line comments
Download patch
Index: chrome/browser/safe_browsing/safe_browsing_database.cc
diff --git a/chrome/browser/safe_browsing/safe_browsing_database.cc b/chrome/browser/safe_browsing/safe_browsing_database.cc
index 2db37e202634ca6b36486947f81c46872ab102c7..f81d6f24eb0c4e11ca1c0dbed54304b8f1a606ee 100644
--- a/chrome/browser/safe_browsing/safe_browsing_database.cc
+++ b/chrome/browser/safe_browsing/safe_browsing_database.cc
@@ -30,6 +30,8 @@
#endif
using content::BrowserThread;
+using safe_browsing::PrefixSet;
+using safe_browsing::PrefixSetBuilder;
namespace {
@@ -432,9 +434,6 @@ base::FilePath SafeBrowsingDatabase::UnwantedSoftwareDBFilename(
}
SafeBrowsingStore* SafeBrowsingDatabaseNew::GetStore(const int list_id) {
- // Stores are not thread safe.
- DCHECK(thread_checker_.CalledOnValidThread());
-
if (list_id == safe_browsing_util::PHISH ||
list_id == safe_browsing_util::MALWARE) {
return browse_store_.get();
@@ -462,6 +461,133 @@ void SafeBrowsingDatabase::RecordFailure(FailureType failure_type) {
FAILURE_DATABASE_MAX);
}
+class SafeBrowsingDatabaseNew::ThreadSafeStateManager::ReadTransaction {
+ public:
+ enum class AutoLockRequirement {
+ LOCK,
+ // SBWhitelist's, IPBlacklist's, and PrefixSet's (not caches) are only
+ // ever written to on the main thread (as enforced by
+ // ThreadSafeStateManager) and can therefore be read on the main thread
+ // without first acquiring |lock_|.
+ DONT_LOCK_ON_MAIN_THREAD
+ };
+
+ ReadTransaction(ThreadSafeStateManager* outer,
mattm 2014/12/12 23:20:30 Maybe ReadTransaction can take a const pointer to
gab 2014/12/15 23:02:30 It could but |prefix_gethash_cache_| would also ha
mattm 2014/12/23 02:09:45 Hm, good point. It kinda seems like prefix_gethash
gab 2014/12/23 21:39:54 Agree that it's kind-of weird to write to the cach
mattm 2014/12/24 00:29:53 Not coming up with anything.. I guess this is okay
+ AutoLockRequirement auto_lock_requirement)
+ : outer_(outer) {
+ if (auto_lock_requirement == AutoLockRequirement::LOCK)
+ transaction_lock_.reset(new base::AutoLock(outer_->lock_));
+ else
+ DCHECK(outer_->thread_checker_.CalledOnValidThread());
+ }
+
+ const SBWhitelist* GetSBWhitelist(SBWhitelistId id) {
+ switch (id) {
+ case SBWhitelistId::CSD:
+ return &outer_->csd_whitelist_;
+ case SBWhitelistId::DOWNLOAD:
+ return &outer_->download_whitelist_;
+ }
+ NOTREACHED();
+ return nullptr;
+ }
+
+ const IPBlacklist* ip_blacklist() { return &outer_->ip_blacklist_; }
+
+ const PrefixSet* GetPrefixSet(PrefixSetId id) {
+ switch (id) {
+ case PrefixSetId::BROWSE:
+ return outer_->browse_prefix_set_.get();
+ case PrefixSetId::SIDE_EFFECT_FREE_WHITELIST:
+ return outer_->side_effect_free_whitelist_prefix_set_.get();
+ case PrefixSetId::UNWANTED_SOFTWARE:
+ return outer_->unwanted_software_prefix_set_.get();
+ }
+ NOTREACHED();
+ return nullptr;
+ }
+
+ PrefixGetHashCache* prefix_gethash_cache() {
+ // The cache is special: it is read/write on all threads. Access to it
+ // therefore requires a LOCK'ed transaction (i.e. it can't benefit from
+ // DONT_LOCK_ON_MAIN_THREAD).
+ DCHECK(transaction_lock_);
+ return &outer_->prefix_gethash_cache_;
+ }
+
+ private:
+ ThreadSafeStateManager* outer_;
+ scoped_ptr<base::AutoLock> transaction_lock_;
+
+ DISALLOW_COPY_AND_ASSIGN(ReadTransaction);
+};
+
+class SafeBrowsingDatabaseNew::ThreadSafeStateManager::WriteTransaction {
+ public:
+ explicit WriteTransaction(ThreadSafeStateManager* outer)
+ : outer_(outer), transaction_lock_(outer_->lock_) {
+ DCHECK(outer_->thread_checker_.CalledOnValidThread());
+ }
+
+ SBWhitelist* GetWritableSBWhitelist(SBWhitelistId id) {
+ switch (id) {
+ case SBWhitelistId::CSD:
+ return &outer_->csd_whitelist_;
+ case SBWhitelistId::DOWNLOAD:
+ return &outer_->download_whitelist_;
+ }
+ NOTREACHED();
+ return nullptr;
+ }
+
+ IPBlacklist* writable_ip_blacklist() { return &outer_->ip_blacklist_; }
+
+ void SwapPrefixSet(PrefixSetId id,
+ scoped_ptr<const PrefixSet> new_prefix_set) {
+ switch (id) {
+ case PrefixSetId::BROWSE:
+ outer_->browse_prefix_set_.swap(new_prefix_set);
+ break;
+ case PrefixSetId::SIDE_EFFECT_FREE_WHITELIST:
+ outer_->side_effect_free_whitelist_prefix_set_.swap(new_prefix_set);
+ break;
+ case PrefixSetId::UNWANTED_SOFTWARE:
+ outer_->unwanted_software_prefix_set_.swap(new_prefix_set);
+ break;
+ }
+ }
+
+ void clear_prefix_gethash_cache() { outer_->prefix_gethash_cache_.clear(); }
+
+ private:
+ ThreadSafeStateManager* outer_;
+ base::AutoLock transaction_lock_;
+
+ DISALLOW_COPY_AND_ASSIGN(WriteTransaction);
+};
+
+SafeBrowsingDatabaseNew::ThreadSafeStateManager::ThreadSafeStateManager() {
+}
+SafeBrowsingDatabaseNew::ThreadSafeStateManager::~ThreadSafeStateManager() {
+}
+
+scoped_ptr<SafeBrowsingDatabaseNew::ReadTransaction>
+SafeBrowsingDatabaseNew::ThreadSafeStateManager::BeginReadTransaction() {
+ return make_scoped_ptr(
+ new ReadTransaction(this, ReadTransaction::AutoLockRequirement::LOCK));
+}
+
+scoped_ptr<SafeBrowsingDatabaseNew::ReadTransaction> SafeBrowsingDatabaseNew::
+ ThreadSafeStateManager::BeginReadTransactionNoLockOnMainThread() {
+ return make_scoped_ptr(new ReadTransaction(
+ this, ReadTransaction::AutoLockRequirement::DONT_LOCK_ON_MAIN_THREAD));
+}
+
+scoped_ptr<SafeBrowsingDatabaseNew::WriteTransaction>
+SafeBrowsingDatabaseNew::ThreadSafeStateManager::BeginWriteTransaction() {
+ return make_scoped_ptr(new WriteTransaction(this));
+}
+
SafeBrowsingDatabaseNew::SafeBrowsingDatabaseNew()
: SafeBrowsingDatabaseNew(new SafeBrowsingStoreFile,
NULL,
@@ -505,13 +631,9 @@ SafeBrowsingDatabaseNew::SafeBrowsingDatabaseNew(
}
SafeBrowsingDatabaseNew::~SafeBrowsingDatabaseNew() {
- // The DCHECK is disabled due to crbug.com/338486 .
- // DCHECK(thread_checker_.CalledOnValidThread());
gab 2014/12/11 19:39:20 This DCHECK is still covered by making SafeBrowsin
}
void SafeBrowsingDatabaseNew::Init(const base::FilePath& filename_base) {
- DCHECK(thread_checker_.CalledOnValidThread());
-
// This should not be run multiple times.
DCHECK(filename_base_.empty());
@@ -525,34 +647,57 @@ void SafeBrowsingDatabaseNew::Init(const base::FilePath& filename_base) {
// live in memory while being actively used. The sense of enabled probably
// belongs in protocol_manager or database_manager.
- browse_store_->Init(
- BrowseDBFilename(filename_base_),
- base::Bind(&SafeBrowsingDatabaseNew::HandleCorruptDatabase,
- base::Unretained(this)));
+ {
+ // NOTE: A transaction here is overkill as there are no pointers to this
+ // class on other threads until this function returns, but it's also
+ // harmless as that also means there is no possibility of contention on the
+ // lock.
+ scoped_ptr<WriteTransaction> txn = state_manager_.BeginWriteTransaction();
+
+ txn->clear_prefix_gethash_cache();
- if (unwanted_software_store_.get()) {
- unwanted_software_store_->Init(
- UnwantedSoftwareDBFilename(filename_base_),
+ browse_store_->Init(
+ BrowseDBFilename(filename_base_),
base::Bind(&SafeBrowsingDatabaseNew::HandleCorruptDatabase,
base::Unretained(this)));
- }
- {
- // NOTE: There is no need to grab the lock in this function, since
- // until it returns, there are no pointers to this class on other
- // threads. Then again, that means there is no possibility of
- // contention on the lock...
- base::AutoLock locked(lookup_lock_);
- prefix_gethash_cache_.clear();
- LoadPrefixSet(BrowseDBFilename(filename_base_),
- &browse_prefix_set_,
- FAILURE_BROWSE_PREFIX_SET_READ);
if (unwanted_software_store_.get()) {
- LoadPrefixSet(UnwantedSoftwareDBFilename(filename_base_),
- &unwanted_software_prefix_set_,
+ unwanted_software_store_->Init(
+ UnwantedSoftwareDBFilename(filename_base_),
+ base::Bind(&SafeBrowsingDatabaseNew::HandleCorruptDatabase,
+ base::Unretained(this)));
+ }
+ LoadPrefixSet(BrowseDBFilename(filename_base_), txn.get(),
+ PrefixSetId::BROWSE, FAILURE_BROWSE_PREFIX_SET_READ);
+ if (unwanted_software_store_.get()) {
+ LoadPrefixSet(UnwantedSoftwareDBFilename(filename_base_), txn.get(),
+ PrefixSetId::UNWANTED_SOFTWARE,
FAILURE_UNWANTED_SOFTWARE_PREFIX_SET_READ);
}
+
+ if (side_effect_free_whitelist_store_.get()) {
+ const base::FilePath side_effect_free_whitelist_filename =
+ SideEffectFreeWhitelistDBFilename(filename_base_);
+ side_effect_free_whitelist_store_->Init(
+ side_effect_free_whitelist_filename,
+ base::Bind(&SafeBrowsingDatabaseNew::HandleCorruptDatabase,
+ base::Unretained(this)));
+
+ LoadPrefixSet(side_effect_free_whitelist_filename, txn.get(),
+ PrefixSetId::SIDE_EFFECT_FREE_WHITELIST,
+ FAILURE_SIDE_EFFECT_FREE_WHITELIST_PREFIX_SET_READ);
+ } else {
+ // Delete any files of the side-effect free sidelist that may be around
+ // from when it was previously enabled.
+ SafeBrowsingStoreFile::DeleteStore(
+ SideEffectFreeWhitelistDBFilename(filename_base_));
+ base::DeleteFile(PrefixSetForFilename(
+ SideEffectFreeWhitelistDBFilename(filename_base_)),
+ false);
+ }
}
+ // Note: End the transaction early because LoadWhiteList() and
+ // WhitelistEverything() manage their own transactions.
if (download_store_.get()) {
download_store_->Init(
@@ -569,12 +714,12 @@ void SafeBrowsingDatabaseNew::Init(const base::FilePath& filename_base) {
std::vector<SBAddFullHash> full_hashes;
if (csd_whitelist_store_->GetAddFullHashes(&full_hashes)) {
- LoadWhitelist(full_hashes, &csd_whitelist_);
+ LoadWhitelist(full_hashes, SBWhitelistId::CSD);
} else {
- WhitelistEverything(&csd_whitelist_);
+ WhitelistEverything(SBWhitelistId::CSD);
}
} else {
- WhitelistEverything(&csd_whitelist_); // Just to be safe.
+ WhitelistEverything(SBWhitelistId::CSD); // Just to be safe.
}
if (download_whitelist_store_.get()) {
@@ -585,12 +730,12 @@ void SafeBrowsingDatabaseNew::Init(const base::FilePath& filename_base) {
std::vector<SBAddFullHash> full_hashes;
if (download_whitelist_store_->GetAddFullHashes(&full_hashes)) {
- LoadWhitelist(full_hashes, &download_whitelist_);
+ LoadWhitelist(full_hashes, SBWhitelistId::DOWNLOAD);
} else {
- WhitelistEverything(&download_whitelist_);
+ WhitelistEverything(SBWhitelistId::DOWNLOAD);
}
} else {
- WhitelistEverything(&download_whitelist_); // Just to be safe.
+ WhitelistEverything(SBWhitelistId::DOWNLOAD); // Just to be safe.
}
if (extension_blacklist_store_.get()) {
@@ -600,27 +745,6 @@ void SafeBrowsingDatabaseNew::Init(const base::FilePath& filename_base) {
base::Unretained(this)));
}
- if (side_effect_free_whitelist_store_.get()) {
- const base::FilePath side_effect_free_whitelist_filename =
- SideEffectFreeWhitelistDBFilename(filename_base_);
- side_effect_free_whitelist_store_->Init(
- side_effect_free_whitelist_filename,
- base::Bind(&SafeBrowsingDatabaseNew::HandleCorruptDatabase,
- base::Unretained(this)));
-
- LoadPrefixSet(side_effect_free_whitelist_filename,
- &side_effect_free_whitelist_prefix_set_,
- FAILURE_SIDE_EFFECT_FREE_WHITELIST_PREFIX_SET_READ);
- } else {
- // Delete any files of the side-effect free sidelist that may be around
- // from when it was previously enabled.
- SafeBrowsingStoreFile::DeleteStore(
- SideEffectFreeWhitelistDBFilename(filename_base_));
- base::DeleteFile(
- PrefixSetForFilename(SideEffectFreeWhitelistDBFilename(filename_base_)),
- false);
- }
-
if (ip_blacklist_store_.get()) {
ip_blacklist_store_->Init(
IpBlacklistDBFilename(filename_base_),
@@ -637,8 +761,6 @@ void SafeBrowsingDatabaseNew::Init(const base::FilePath& filename_base) {
}
bool SafeBrowsingDatabaseNew::ResetDatabase() {
- DCHECK(thread_checker_.CalledOnValidThread());
-
// Delete files on disk.
// TODO(shess): Hard to see where one might want to delete without a
// reset. Perhaps inline |Delete()|?
@@ -647,16 +769,16 @@ bool SafeBrowsingDatabaseNew::ResetDatabase() {
// Reset objects in memory.
{
- base::AutoLock locked(lookup_lock_);
- prefix_gethash_cache_.clear();
- browse_prefix_set_.reset();
- side_effect_free_whitelist_prefix_set_.reset();
- ip_blacklist_.clear();
- unwanted_software_prefix_set_.reset();
+ scoped_ptr<WriteTransaction> txn = state_manager_.BeginWriteTransaction();
+ txn->clear_prefix_gethash_cache();
+ txn->SwapPrefixSet(PrefixSetId::BROWSE, nullptr);
+ txn->SwapPrefixSet(PrefixSetId::SIDE_EFFECT_FREE_WHITELIST, nullptr);
+ txn->SwapPrefixSet(PrefixSetId::UNWANTED_SOFTWARE, nullptr);
+ txn->writable_ip_blacklist()->clear();
}
// Wants to acquire the lock itself.
mattm 2014/12/12 23:20:31 Why not make WhitelistEverything a method on Write
gab 2014/12/15 23:02:30 I debated that in lengths while writing this and h
mattm 2014/12/23 02:09:45 Well, you could one-line it like state_manager_.Be
gab 2014/12/23 21:39:54 Actually, I kind of like that and used it for a fe
- WhitelistEverything(&csd_whitelist_);
- WhitelistEverything(&download_whitelist_);
+ WhitelistEverything(SBWhitelistId::CSD);
+ WhitelistEverything(SBWhitelistId::DOWNLOAD);
return true;
}
@@ -664,35 +786,23 @@ bool SafeBrowsingDatabaseNew::ContainsBrowseUrl(
const GURL& url,
std::vector<SBPrefix>* prefix_hits,
std::vector<SBFullHashResult>* cache_hits) {
- // This method is theoretically thread-safe but document that it is currently
- // only expected to be called on the IO thread.
- DCHECK_CURRENTLY_ON(BrowserThread::IO);
-
- return PrefixSetContainsUrl(
- url, &browse_prefix_set_, prefix_hits, cache_hits);
+ return PrefixSetContainsUrl(url, PrefixSetId::BROWSE, prefix_hits,
+ cache_hits);
}
bool SafeBrowsingDatabaseNew::ContainsUnwantedSoftwareUrl(
const GURL& url,
std::vector<SBPrefix>* prefix_hits,
std::vector<SBFullHashResult>* cache_hits) {
- // This method is theoretically thread-safe but document that it is currently
- // only expected to be called on the IO thread.
- DCHECK_CURRENTLY_ON(BrowserThread::IO);
-
- return PrefixSetContainsUrl(
- url, &unwanted_software_prefix_set_, prefix_hits, cache_hits);
+ return PrefixSetContainsUrl(url, PrefixSetId::UNWANTED_SOFTWARE, prefix_hits,
+ cache_hits);
}
bool SafeBrowsingDatabaseNew::PrefixSetContainsUrl(
const GURL& url,
- scoped_ptr<const safe_browsing::PrefixSet>* prefix_set_getter,
+ PrefixSetId prefix_set_id,
std::vector<SBPrefix>* prefix_hits,
std::vector<SBFullHashResult>* cache_hits) {
- // This method is theoretically thread-safe but document that it is currently
- // only expected to be called on the IO thread.
- DCHECK_CURRENTLY_ON(BrowserThread::IO);
-
// Clear the results first.
prefix_hits->clear();
cache_hits->clear();
@@ -702,47 +812,42 @@ bool SafeBrowsingDatabaseNew::PrefixSetContainsUrl(
if (full_hashes.empty())
return false;
- return PrefixSetContainsUrlHashes(
- full_hashes, prefix_set_getter, prefix_hits, cache_hits);
+ return PrefixSetContainsUrlHashes(full_hashes, prefix_set_id, prefix_hits,
+ cache_hits);
}
bool SafeBrowsingDatabaseNew::ContainsBrowseUrlHashesForTesting(
const std::vector<SBFullHash>& full_hashes,
std::vector<SBPrefix>* prefix_hits,
std::vector<SBFullHashResult>* cache_hits) {
- return PrefixSetContainsUrlHashes(
- full_hashes, &browse_prefix_set_, prefix_hits, cache_hits);
+ return PrefixSetContainsUrlHashes(full_hashes, PrefixSetId::BROWSE,
+ prefix_hits, cache_hits);
}
bool SafeBrowsingDatabaseNew::PrefixSetContainsUrlHashes(
const std::vector<SBFullHash>& full_hashes,
- scoped_ptr<const safe_browsing::PrefixSet>* prefix_set_getter,
+ PrefixSetId prefix_set_id,
std::vector<SBPrefix>* prefix_hits,
std::vector<SBFullHashResult>* cache_hits) {
- // This method is theoretically thread-safe but document that it is currently
- // only expected to be called on the IO thread.
- DCHECK_CURRENTLY_ON(BrowserThread::IO);
-
// Used to determine cache expiration.
const base::Time now = base::Time::Now();
- base::AutoLock locked(lookup_lock_);
-
- // |prefix_set| is empty until it is either read from disk, or the first
- // update populates it. Bail out without a hit if not yet available.
- // |prefix_set_getter| can only be accessed while holding |lookup_lock_| hence
- // why it is passed as a parameter rather than passing the |prefix_set|
- // directly.
- const safe_browsing::PrefixSet* prefix_set = prefix_set_getter->get();
- if (!prefix_set)
- return false;
-
- for (size_t i = 0; i < full_hashes.size(); ++i) {
- if (!GetCachedFullHash(
- &prefix_gethash_cache_, full_hashes[i], now, cache_hits)) {
- // No valid cached result, check the database.
- if (prefix_set->Exists(full_hashes[i]))
- prefix_hits->push_back(full_hashes[i].prefix);
+ {
+ scoped_ptr<ReadTransaction> txn = state_manager_.BeginReadTransaction();
+
+ // |prefix_set| is empty until it is either read from disk, or the first
+ // update populates it. Bail out without a hit if not yet available.
+ const PrefixSet* prefix_set = txn->GetPrefixSet(prefix_set_id);
+ if (!prefix_set)
+ return false;
+
+ for (size_t i = 0; i < full_hashes.size(); ++i) {
+ if (!GetCachedFullHash(txn->prefix_gethash_cache(), full_hashes[i], now,
+ cache_hits)) {
+ // No valid cached result, check the database.
+ if (prefix_set->Exists(full_hashes[i]))
+ prefix_hits->push_back(full_hashes[i].prefix);
+ }
}
}
@@ -757,8 +862,6 @@ bool SafeBrowsingDatabaseNew::PrefixSetContainsUrlHashes(
bool SafeBrowsingDatabaseNew::ContainsDownloadUrl(
const std::vector<GURL>& urls,
std::vector<SBPrefix>* prefix_hits) {
- DCHECK(thread_checker_.CalledOnValidThread());
mattm 2014/12/12 23:20:31 Why are all these removed?
gab 2014/12/15 23:02:30 Because |thread_checker_| moved to ThreadSafeState
-
// Ignore this check when download checking is not enabled.
if (!download_store_.get())
return false;
@@ -772,26 +875,20 @@ bool SafeBrowsingDatabaseNew::ContainsDownloadUrl(
}
bool SafeBrowsingDatabaseNew::ContainsCsdWhitelistedUrl(const GURL& url) {
- // This method is theoretically thread-safe but document that it is currently
- // only expected to be called on the IO thread.
- DCHECK_CURRENTLY_ON(BrowserThread::IO);
-
std::vector<SBFullHash> full_hashes;
UrlToFullHashes(url, true, &full_hashes);
- return ContainsWhitelistedHashes(csd_whitelist_, full_hashes);
+ return ContainsWhitelistedHashes(SBWhitelistId::CSD, full_hashes);
}
bool SafeBrowsingDatabaseNew::ContainsDownloadWhitelistedUrl(const GURL& url) {
std::vector<SBFullHash> full_hashes;
UrlToFullHashes(url, true, &full_hashes);
- return ContainsWhitelistedHashes(download_whitelist_, full_hashes);
+ return ContainsWhitelistedHashes(SBWhitelistId::DOWNLOAD, full_hashes);
}
bool SafeBrowsingDatabaseNew::ContainsExtensionPrefixes(
const std::vector<SBPrefix>& prefixes,
std::vector<SBPrefix>* prefix_hits) {
- DCHECK(thread_checker_.CalledOnValidThread());
-
if (!extension_blacklist_store_)
return false;
@@ -803,10 +900,6 @@ bool SafeBrowsingDatabaseNew::ContainsExtensionPrefixes(
bool SafeBrowsingDatabaseNew::ContainsSideEffectFreeWhitelistUrl(
const GURL& url) {
- // This method is theoretically thread-safe but document that it is currently
- // only expected to be called on the UI thread.
- DCHECK_CURRENTLY_ON(BrowserThread::UI);
-
std::string host;
std::string path;
std::string query;
@@ -816,22 +909,21 @@ bool SafeBrowsingDatabaseNew::ContainsSideEffectFreeWhitelistUrl(
url_to_check += "?" + query;
SBFullHash full_hash = SBFullHashForString(url_to_check);
- base::AutoLock locked(lookup_lock_);
+ scoped_ptr<ReadTransaction> txn = state_manager_.BeginReadTransaction();
+
+ const PrefixSet* side_effect_free_whitelist_prefix_set =
+ txn->GetPrefixSet(PrefixSetId::SIDE_EFFECT_FREE_WHITELIST);
// |side_effect_free_whitelist_prefix_set_| is empty until it is either read
// from disk, or the first update populates it. Bail out without a hit if
// not yet available.
- if (!side_effect_free_whitelist_prefix_set_.get())
+ if (!side_effect_free_whitelist_prefix_set)
return false;
- return side_effect_free_whitelist_prefix_set_->Exists(full_hash);
+ return side_effect_free_whitelist_prefix_set->Exists(full_hash);
}
bool SafeBrowsingDatabaseNew::ContainsMalwareIP(const std::string& ip_address) {
- // This method is theoretically thread-safe but document that it is currently
- // only expected to be called on the IO thread.
- DCHECK_CURRENTLY_ON(BrowserThread::IO);
-
net::IPAddressNumber ip_number;
if (!net::ParseIPLiteralToNumber(ip_address, &ip_number))
return false;
@@ -840,10 +932,10 @@ bool SafeBrowsingDatabaseNew::ContainsMalwareIP(const std::string& ip_address) {
if (ip_number.size() != net::kIPv6AddressSize)
return false; // better safe than sorry.
- base::AutoLock locked(lookup_lock_);
- for (IPBlacklist::const_iterator it = ip_blacklist_.begin();
- it != ip_blacklist_.end();
- ++it) {
+ scoped_ptr<ReadTransaction> txn = state_manager_.BeginReadTransaction();
+ const IPBlacklist* ip_blacklist = txn->ip_blacklist();
+ for (IPBlacklist::const_iterator it = ip_blacklist->begin();
+ it != ip_blacklist->end(); ++it) {
const std::string& mask = it->first;
DCHECK_EQ(mask.size(), ip_number.size());
std::string subnet(net::kIPv6AddressSize, '\0');
@@ -865,28 +957,21 @@ bool SafeBrowsingDatabaseNew::ContainsMalwareIP(const std::string& ip_address) {
bool SafeBrowsingDatabaseNew::ContainsDownloadWhitelistedString(
const std::string& str) {
- // This method is theoretically thread-safe but document that it is currently
- // only expected to be called on the IO thread.
- DCHECK_CURRENTLY_ON(BrowserThread::IO);
-
std::vector<SBFullHash> hashes;
hashes.push_back(SBFullHashForString(str));
- return ContainsWhitelistedHashes(download_whitelist_, hashes);
+ return ContainsWhitelistedHashes(SBWhitelistId::DOWNLOAD, hashes);
}
bool SafeBrowsingDatabaseNew::ContainsWhitelistedHashes(
- const SBWhitelist& whitelist,
+ SBWhitelistId whitelist_id,
const std::vector<SBFullHash>& hashes) {
- // This method is theoretically thread-safe but document that it is currently
- // only expected to be called on the IO thread.
- DCHECK_CURRENTLY_ON(BrowserThread::IO);
-
- base::AutoLock l(lookup_lock_);
- if (whitelist.second)
+ scoped_ptr<ReadTransaction> txn = state_manager_.BeginReadTransaction();
+ const SBWhitelist* whitelist = txn->GetSBWhitelist(whitelist_id);
+ if (whitelist->second)
return true;
for (std::vector<SBFullHash>::const_iterator it = hashes.begin();
it != hashes.end(); ++it) {
- if (std::binary_search(whitelist.first.begin(), whitelist.first.end(),
+ if (std::binary_search(whitelist->first.begin(), whitelist->first.end(),
*it, SBFullHashLess)) {
return true;
}
@@ -899,7 +984,6 @@ void SafeBrowsingDatabaseNew::InsertAddChunk(
SafeBrowsingStore* store,
const safe_browsing_util::ListType list_id,
const SBChunkData& chunk_data) {
- DCHECK(thread_checker_.CalledOnValidThread());
DCHECK(store);
// The server can give us a chunk that we already have because
@@ -930,7 +1014,6 @@ void SafeBrowsingDatabaseNew::InsertSubChunk(
SafeBrowsingStore* store,
const safe_browsing_util::ListType list_id,
const SBChunkData& chunk_data) {
- DCHECK(thread_checker_.CalledOnValidThread());
DCHECK(store);
// The server can give us a chunk that we already have because
@@ -965,8 +1048,6 @@ void SafeBrowsingDatabaseNew::InsertSubChunk(
void SafeBrowsingDatabaseNew::InsertChunks(
const std::string& list_name,
const std::vector<SBChunkData*>& chunks) {
- DCHECK(thread_checker_.CalledOnValidThread());
-
if (corruption_detected_ || chunks.empty())
return;
@@ -1000,8 +1081,6 @@ void SafeBrowsingDatabaseNew::InsertChunks(
void SafeBrowsingDatabaseNew::DeleteChunks(
const std::vector<SBChunkDelete>& chunk_deletes) {
- DCHECK(thread_checker_.CalledOnValidThread());
-
if (corruption_detected_ || chunk_deletes.empty())
return;
@@ -1031,30 +1110,26 @@ void SafeBrowsingDatabaseNew::CacheHashResults(
const std::vector<SBPrefix>& prefixes,
const std::vector<SBFullHashResult>& full_hits,
const base::TimeDelta& cache_lifetime) {
- // This method is theoretically thread-safe but document that it is currently
- // only expected to be called on the IO thread.
- DCHECK_CURRENTLY_ON(BrowserThread::IO);
-
const base::Time expire_after = base::Time::Now() + cache_lifetime;
- base::AutoLock locked(lookup_lock_);
+ scoped_ptr<ReadTransaction> txn = state_manager_.BeginReadTransaction();
+ PrefixGetHashCache* prefix_gethash_cache = txn->prefix_gethash_cache();
// Create or reset all cached results for these prefixes.
for (size_t i = 0; i < prefixes.size(); ++i) {
- prefix_gethash_cache_[prefixes[i]] = SBCachedFullHashResult(expire_after);
+ (*prefix_gethash_cache)[prefixes[i]] = SBCachedFullHashResult(expire_after);
}
// Insert any fullhash hits. Note that there may be one, multiple, or no
// fullhashes for any given entry in |prefixes|.
for (size_t i = 0; i < full_hits.size(); ++i) {
const SBPrefix prefix = full_hits[i].hash.prefix;
- prefix_gethash_cache_[prefix].full_hashes.push_back(full_hits[i]);
+ (*prefix_gethash_cache)[prefix].full_hashes.push_back(full_hits[i]);
}
}
bool SafeBrowsingDatabaseNew::UpdateStarted(
std::vector<SBListChunkRanges>* lists) {
- DCHECK(thread_checker_.CalledOnValidThread());
DCHECK(lists);
// If |BeginUpdate()| fails, reset the database.
@@ -1110,10 +1185,10 @@ bool SafeBrowsingDatabaseNew::UpdateStarted(
}
{
- base::AutoLock locked(lookup_lock_);
+ scoped_ptr<WriteTransaction> txn = state_manager_.BeginWriteTransaction();
// Cached fullhash results must be cleared on every database update (whether
- // successful or not.)
- prefix_gethash_cache_.clear();
+ // successful or not).
+ txn->clear_prefix_gethash_cache();
}
UpdateChunkRangesForLists(browse_store_.get(),
@@ -1153,8 +1228,6 @@ bool SafeBrowsingDatabaseNew::UpdateStarted(
}
void SafeBrowsingDatabaseNew::UpdateFinished(bool update_succeeded) {
- DCHECK(thread_checker_.CalledOnValidThread());
-
// The update may have failed due to corrupt storage (for instance,
// an excessive number of invalid add_chunks and sub_chunks).
// Double-check that the databases are valid.
@@ -1236,17 +1309,17 @@ void SafeBrowsingDatabaseNew::UpdateFinished(bool update_succeeded) {
UpdatePrefixSetUrlStore(BrowseDBFilename(filename_base_),
browse_store_.get(),
- &browse_prefix_set_,
+ PrefixSetId::BROWSE,
FAILURE_BROWSE_DATABASE_UPDATE_FINISH,
FAILURE_BROWSE_PREFIX_SET_WRITE,
true);
UpdateWhitelistStore(CsdWhitelistDBFilename(filename_base_),
csd_whitelist_store_.get(),
- &csd_whitelist_);
+ SBWhitelistId::CSD);
UpdateWhitelistStore(DownloadWhitelistDBFilename(filename_base_),
download_whitelist_store_.get(),
- &download_whitelist_);
+ SBWhitelistId::DOWNLOAD);
if (extension_blacklist_store_) {
int64 size_bytes = UpdateHashPrefixStore(
@@ -1260,7 +1333,7 @@ void SafeBrowsingDatabaseNew::UpdateFinished(bool update_succeeded) {
if (side_effect_free_whitelist_store_) {
UpdatePrefixSetUrlStore(SideEffectFreeWhitelistDBFilename(filename_base_),
side_effect_free_whitelist_store_.get(),
- &side_effect_free_whitelist_prefix_set_,
+ PrefixSetId::SIDE_EFFECT_FREE_WHITELIST,
FAILURE_SIDE_EFFECT_FREE_WHITELIST_UPDATE_FINISH,
FAILURE_SIDE_EFFECT_FREE_WHITELIST_PREFIX_SET_WRITE,
false);
@@ -1272,7 +1345,7 @@ void SafeBrowsingDatabaseNew::UpdateFinished(bool update_succeeded) {
if (unwanted_software_store_) {
UpdatePrefixSetUrlStore(UnwantedSoftwareDBFilename(filename_base_),
unwanted_software_store_.get(),
- &unwanted_software_prefix_set_,
+ PrefixSetId::UNWANTED_SOFTWARE,
FAILURE_UNWANTED_SOFTWARE_DATABASE_UPDATE_FINISH,
FAILURE_UNWANTED_SOFTWARE_PREFIX_SET_WRITE,
true);
@@ -1282,19 +1355,17 @@ void SafeBrowsingDatabaseNew::UpdateFinished(bool update_succeeded) {
void SafeBrowsingDatabaseNew::UpdateWhitelistStore(
const base::FilePath& store_filename,
SafeBrowsingStore* store,
- SBWhitelist* whitelist) {
- DCHECK(thread_checker_.CalledOnValidThread());
-
+ SBWhitelistId whitelist_id) {
if (!store)
return;
// Note: |builder| will not be empty. The current data store implementation
// stores all full-length hashes as both full and prefix hashes.
- safe_browsing::PrefixSetBuilder builder;
+ PrefixSetBuilder builder;
std::vector<SBAddFullHash> full_hashes;
if (!store->FinishUpdate(&builder, &full_hashes)) {
RecordFailure(FAILURE_WHITELIST_DATABASE_UPDATE_FINISH);
- WhitelistEverything(whitelist);
+ WhitelistEverything(whitelist_id);
return;
}
@@ -1302,18 +1373,16 @@ void SafeBrowsingDatabaseNew::UpdateWhitelistStore(
base::mac::SetFileBackupExclusion(store_filename);
#endif
- LoadWhitelist(full_hashes, whitelist);
+ LoadWhitelist(full_hashes, whitelist_id);
}
int64 SafeBrowsingDatabaseNew::UpdateHashPrefixStore(
const base::FilePath& store_filename,
SafeBrowsingStore* store,
FailureType failure_type) {
- DCHECK(thread_checker_.CalledOnValidThread());
-
// These results are not used after this call. Simply ignore the
// returned value after FinishUpdate(...).
- safe_browsing::PrefixSetBuilder builder;
+ PrefixSetBuilder builder;
std::vector<SBAddFullHash> add_full_hashes_result;
if (!store->FinishUpdate(&builder, &add_full_hashes_result))
@@ -1329,13 +1398,11 @@ int64 SafeBrowsingDatabaseNew::UpdateHashPrefixStore(
void SafeBrowsingDatabaseNew::UpdatePrefixSetUrlStore(
const base::FilePath& db_filename,
SafeBrowsingStore* url_store,
- scoped_ptr<const safe_browsing::PrefixSet>* prefix_set,
+ PrefixSetId prefix_set_id,
FailureType finish_failure_type,
FailureType write_failure_type,
bool store_full_hashes_in_prefix_set) {
- DCHECK(thread_checker_.CalledOnValidThread());
DCHECK(url_store);
- DCHECK(prefix_set);
// Measure the amount of IO during the filter build.
base::IoCounters io_before, io_after;
@@ -1359,14 +1426,14 @@ void SafeBrowsingDatabaseNew::UpdatePrefixSetUrlStore(
// TODO(shess): Perhaps refactor to let builder accumulate full hashes on the
// fly? Other clients use the SBAddFullHash vector, but AFAICT they only use
// the SBFullHash portion. It would need an accessor on PrefixSet.
- safe_browsing::PrefixSetBuilder builder;
+ PrefixSetBuilder builder;
std::vector<SBAddFullHash> add_full_hashes;
if (!url_store->FinishUpdate(&builder, &add_full_hashes)) {
RecordFailure(finish_failure_type);
return;
}
- scoped_ptr<const safe_browsing::PrefixSet> new_prefix_set;
+ scoped_ptr<const PrefixSet> new_prefix_set;
if (store_full_hashes_in_prefix_set) {
std::vector<SBFullHash> full_hash_results;
for (size_t i = 0; i < add_full_hashes.size(); ++i) {
@@ -1380,15 +1447,21 @@ void SafeBrowsingDatabaseNew::UpdatePrefixSetUrlStore(
// Swap in the newly built filter.
{
- base::AutoLock locked(lookup_lock_);
- prefix_set->swap(new_prefix_set);
+ scoped_ptr<WriteTransaction> txn = state_manager_.BeginWriteTransaction();
+ txn->SwapPrefixSet(prefix_set_id, new_prefix_set.Pass());
}
UMA_HISTOGRAM_LONG_TIMES("SB2.BuildFilter", base::TimeTicks::Now() - before);
- // Persist the prefix set to disk. Note: there is no need to lock since the
- // only write to |*prefix_set| is on this thread (in the swap() above).
- WritePrefixSet(db_filename, prefix_set->get(), write_failure_type);
+ {
+ // Persist the prefix set to disk. Do not grab the lock to avoid contention
+ // while writing to disk. This is safe as only this thread can ever modify
+ // |state_manager_|'s prefix sets anyways.
+ scoped_ptr<ReadTransaction> txn =
+ state_manager_.BeginReadTransactionNoLockOnMainThread();
+ WritePrefixSet(db_filename, txn->GetPrefixSet(prefix_set_id),
+ write_failure_type);
+ }
// Gather statistics.
if (got_counters && metric->GetIOCounters(&io_after)) {
@@ -1416,11 +1489,9 @@ void SafeBrowsingDatabaseNew::UpdatePrefixSetUrlStore(
}
void SafeBrowsingDatabaseNew::UpdateIpBlacklistStore() {
- DCHECK(thread_checker_.CalledOnValidThread());
-
// Note: prefixes will not be empty. The current data store implementation
// stores all full-length hashes as both full and prefix hashes.
- safe_browsing::PrefixSetBuilder builder;
+ PrefixSetBuilder builder;
std::vector<SBAddFullHash> full_hashes;
if (!ip_blacklist_store_->FinishUpdate(&builder, &full_hashes)) {
RecordFailure(FAILURE_IP_BLACKLIST_UPDATE_FINISH);
@@ -1436,8 +1507,6 @@ void SafeBrowsingDatabaseNew::UpdateIpBlacklistStore() {
}
void SafeBrowsingDatabaseNew::HandleCorruptDatabase() {
- DCHECK(thread_checker_.CalledOnValidThread());
-
// Reset the database after the current task has unwound (but only
// reset once within the scope of a given task).
if (!reset_factory_.HasWeakPtrs()) {
@@ -1449,8 +1518,6 @@ void SafeBrowsingDatabaseNew::HandleCorruptDatabase() {
}
void SafeBrowsingDatabaseNew::OnHandleCorruptDatabase() {
- DCHECK(thread_checker_.CalledOnValidThread());
-
RecordFailure(FAILURE_DATABASE_CORRUPT_HANDLER);
corruption_detected_ = true; // Stop updating the database.
ResetDatabase();
@@ -1464,19 +1531,13 @@ void SafeBrowsingDatabaseNew::OnHandleCorruptDatabase() {
// TODO(shess): I'm not clear why this code doesn't have any
// real error-handling.
-void SafeBrowsingDatabaseNew::LoadPrefixSet(
- const base::FilePath& db_filename,
- scoped_ptr<const safe_browsing::PrefixSet>* prefix_set,
- FailureType read_failure_type) {
- DCHECK(thread_checker_.CalledOnValidThread());
-
- if (!prefix_set)
- return;
-
+void SafeBrowsingDatabaseNew::LoadPrefixSet(const base::FilePath& db_filename,
+ WriteTransaction* txn,
+ PrefixSetId prefix_set_id,
+ FailureType read_failure_type) {
+ DCHECK(txn);
DCHECK(!filename_base_.empty());
- const base::FilePath prefix_set_filename = PrefixSetForFilename(db_filename);
-
// Only use the prefix set if database is present and non-empty.
if (!GetFileSizeOrZero(db_filename))
return;
@@ -1488,15 +1549,15 @@ void SafeBrowsingDatabaseNew::LoadPrefixSet(
base::DeleteFile(bloom_filter_filename, false);
const base::TimeTicks before = base::TimeTicks::Now();
- *prefix_set = safe_browsing::PrefixSet::LoadFile(prefix_set_filename);
- UMA_HISTOGRAM_TIMES("SB2.PrefixSetLoad", base::TimeTicks::Now() - before);
-
- if (!prefix_set->get())
+ scoped_ptr<const PrefixSet> new_prefix_set =
+ PrefixSet::LoadFile(PrefixSetForFilename(db_filename));
+ if (!new_prefix_set.get())
RecordFailure(read_failure_type);
+ txn->SwapPrefixSet(prefix_set_id, new_prefix_set.Pass());
+ UMA_HISTOGRAM_TIMES("SB2.PrefixSetLoad", base::TimeTicks::Now() - before);
}
bool SafeBrowsingDatabaseNew::Delete() {
- DCHECK(thread_checker_.CalledOnValidThread());
DCHECK(!filename_base_.empty());
// TODO(shess): This is a mess. SafeBrowsingFileStore::Delete() closes the
@@ -1575,12 +1636,9 @@ bool SafeBrowsingDatabaseNew::Delete() {
return r1 && r2 && r3 && r4 && r5 && r6 && r7 && r8 && r9 && r10 && r11;
}
-void SafeBrowsingDatabaseNew::WritePrefixSet(
- const base::FilePath& db_filename,
- const safe_browsing::PrefixSet* prefix_set,
- FailureType write_failure_type) {
- DCHECK(thread_checker_.CalledOnValidThread());
-
+void SafeBrowsingDatabaseNew::WritePrefixSet(const base::FilePath& db_filename,
+ const PrefixSet* prefix_set,
+ FailureType write_failure_type) {
if (!prefix_set)
return;
@@ -1602,20 +1660,18 @@ void SafeBrowsingDatabaseNew::WritePrefixSet(
#endif
}
-void SafeBrowsingDatabaseNew::WhitelistEverything(SBWhitelist* whitelist) {
- DCHECK(thread_checker_.CalledOnValidThread());
- base::AutoLock locked(lookup_lock_);
+void SafeBrowsingDatabaseNew::WhitelistEverything(SBWhitelistId whitelist_id) {
+ scoped_ptr<WriteTransaction> txn = state_manager_.BeginWriteTransaction();
+ SBWhitelist* whitelist = txn->GetWritableSBWhitelist(whitelist_id);
whitelist->second = true;
whitelist->first.clear();
}
void SafeBrowsingDatabaseNew::LoadWhitelist(
const std::vector<SBAddFullHash>& full_hashes,
- SBWhitelist* whitelist) {
- DCHECK(thread_checker_.CalledOnValidThread());
-
+ SBWhitelistId whitelist_id) {
if (full_hashes.size() > kMaxWhitelistSize) {
- WhitelistEverything(whitelist);
+ WhitelistEverything(whitelist_id);
return;
}
@@ -1631,9 +1687,10 @@ void SafeBrowsingDatabaseNew::LoadWhitelist(
if (std::binary_search(new_whitelist.begin(), new_whitelist.end(),
kill_switch, SBFullHashLess)) {
// The kill switch is whitelisted hence we whitelist all URLs.
- WhitelistEverything(whitelist);
+ WhitelistEverything(whitelist_id);
} else {
- base::AutoLock locked(lookup_lock_);
+ scoped_ptr<WriteTransaction> txn = state_manager_.BeginWriteTransaction();
+ SBWhitelist* whitelist = txn->GetWritableSBWhitelist(whitelist_id);
whitelist->second = false;
whitelist->first.swap(new_whitelist);
}
@@ -1641,8 +1698,6 @@ void SafeBrowsingDatabaseNew::LoadWhitelist(
void SafeBrowsingDatabaseNew::LoadIpBlacklist(
const std::vector<SBAddFullHash>& full_hashes) {
- DCHECK(thread_checker_.CalledOnValidThread());
-
IPBlacklist new_blacklist;
for (std::vector<SBAddFullHash>::const_iterator it = full_hashes.begin();
it != full_hashes.end();
@@ -1676,26 +1731,24 @@ void SafeBrowsingDatabaseNew::LoadIpBlacklist(
new_blacklist[mask].insert(hashed_ip_prefix);
}
- base::AutoLock locked(lookup_lock_);
- ip_blacklist_.swap(new_blacklist);
+ scoped_ptr<WriteTransaction> txn = state_manager_.BeginWriteTransaction();
+ txn->writable_ip_blacklist()->swap(new_blacklist);
}
bool SafeBrowsingDatabaseNew::IsMalwareIPMatchKillSwitchOn() {
- // This method is theoretically thread-safe but document that it is currently
- // only expected to be called on the IO thread.
- DCHECK_CURRENTLY_ON(BrowserThread::IO);
-
SBFullHash malware_kill_switch = SBFullHashForString(kMalwareIPKillSwitchUrl);
std::vector<SBFullHash> full_hashes;
full_hashes.push_back(malware_kill_switch);
- return ContainsWhitelistedHashes(csd_whitelist_, full_hashes);
+ return ContainsWhitelistedHashes(SBWhitelistId::CSD, full_hashes);
}
bool SafeBrowsingDatabaseNew::IsCsdWhitelistKillSwitchOn() {
- // This method is theoretically thread-safe but document that it is currently
- // only expected to be called on the IO thread.
- DCHECK_CURRENTLY_ON(BrowserThread::IO);
+ scoped_ptr<ReadTransaction> txn = state_manager_.BeginReadTransaction();
+ return txn->GetSBWhitelist(SBWhitelistId::CSD)->second;
+}
- base::AutoLock locked(lookup_lock_);
- return csd_whitelist_.second;
+SafeBrowsingDatabaseNew::PrefixGetHashCache*
+SafeBrowsingDatabaseNew::GetUnsynchronizedPrefixGetHashCacheForTesting() {
+ scoped_ptr<ReadTransaction> txn = state_manager_.BeginReadTransaction();
+ return txn->prefix_gethash_cache();
}

Powered by Google App Engine
This is Rietveld 408576698