| // Copyright 2014 The Chromium Authors. All rights reserved. |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| #include "components/search_engines/keyword_web_data_service.h" |
| |
| #include "base/bind.h" |
| #include "base/location.h" |
| #include "base/single_thread_task_runner.h" |
| #include "build/build_config.h" |
| #include "components/search_engines/keyword_table.h" |
| #include "components/search_engines/template_url_data.h" |
| #include "components/webdata/common/web_data_results.h" |
| #include "components/webdata/common/web_database_service.h" |
| |
| namespace { |
| |
| WebDatabase::State PerformKeywordOperationsImpl( |
| const KeywordTable::Operations& operations, |
| WebDatabase* db) { |
| return KeywordTable::FromWebDatabase(db)->PerformOperations(operations) |
| ? WebDatabase::COMMIT_NEEDED |
| : WebDatabase::COMMIT_NOT_NEEDED; |
| } |
| |
| std::unique_ptr<WDTypedResult> GetKeywordsImpl(WebDatabase* db) { |
| KeywordTable* const keyword_table = KeywordTable::FromWebDatabase(db); |
| WDKeywordsResult result; |
| if (!keyword_table->GetKeywords(&result.keywords)) |
| return nullptr; |
| |
| result.default_search_provider_id = |
| keyword_table->GetDefaultSearchProviderID(); |
| result.builtin_keyword_version = keyword_table->GetBuiltinKeywordVersion(); |
| return std::make_unique<WDResult<WDKeywordsResult>>(KEYWORDS_RESULT, result); |
| } |
| |
| WebDatabase::State SetDefaultSearchProviderIDImpl(TemplateURLID id, |
| WebDatabase* db) { |
| return KeywordTable::FromWebDatabase(db)->SetDefaultSearchProviderID(id) |
| ? WebDatabase::COMMIT_NEEDED |
| : WebDatabase::COMMIT_NOT_NEEDED; |
| } |
| |
| WebDatabase::State SetBuiltinKeywordVersionImpl(int version, WebDatabase* db) { |
| return KeywordTable::FromWebDatabase(db)->SetBuiltinKeywordVersion(version) |
| ? WebDatabase::COMMIT_NEEDED |
| : WebDatabase::COMMIT_NOT_NEEDED; |
| } |
| |
| } // namespace |
| |
| WDKeywordsResult::WDKeywordsResult() = default; |
| |
| WDKeywordsResult::WDKeywordsResult(const WDKeywordsResult&) = default; |
| |
| WDKeywordsResult& WDKeywordsResult::operator=(const WDKeywordsResult&) = |
| default; |
| |
| WDKeywordsResult::~WDKeywordsResult() = default; |
| |
| KeywordWebDataService::BatchModeScoper::BatchModeScoper( |
| KeywordWebDataService* service) |
| : service_(service) { |
| if (service_) |
| service_->AdjustBatchModeLevel(true); |
| } |
| |
| KeywordWebDataService::BatchModeScoper::~BatchModeScoper() { |
| if (service_) |
| service_->AdjustBatchModeLevel(false); |
| } |
| |
| KeywordWebDataService::KeywordWebDataService( |
| scoped_refptr<WebDatabaseService> wdbs, |
| scoped_refptr<base::SingleThreadTaskRunner> ui_task_runner) |
| : WebDataServiceBase(std::move(wdbs), std::move(ui_task_runner)), |
| timer_(FROM_HERE, |
| base::TimeDelta::FromSeconds(5), |
| base::BindRepeating(&KeywordWebDataService::CommitQueuedOperations, |
| base::Unretained(this))) {} |
| |
| void KeywordWebDataService::AddKeyword(const TemplateURLData& data) { |
| if (batch_mode_level_) { |
| queued_keyword_operations_.push_back( |
| KeywordTable::Operation(KeywordTable::ADD, data)); |
| } else { |
| AdjustBatchModeLevel(true); |
| AddKeyword(data); |
| AdjustBatchModeLevel(false); |
| } |
| } |
| |
| void KeywordWebDataService::RemoveKeyword(TemplateURLID id) { |
| if (batch_mode_level_) { |
| TemplateURLData data; |
| data.id = id; |
| queued_keyword_operations_.push_back( |
| KeywordTable::Operation(KeywordTable::REMOVE, data)); |
| } else { |
| AdjustBatchModeLevel(true); |
| RemoveKeyword(id); |
| AdjustBatchModeLevel(false); |
| } |
| } |
| |
| void KeywordWebDataService::UpdateKeyword(const TemplateURLData& data) { |
| if (batch_mode_level_) { |
| queued_keyword_operations_.push_back( |
| KeywordTable::Operation(KeywordTable::UPDATE, data)); |
| } else { |
| AdjustBatchModeLevel(true); |
| UpdateKeyword(data); |
| AdjustBatchModeLevel(false); |
| } |
| } |
| |
| WebDataServiceBase::Handle KeywordWebDataService::GetKeywords( |
| WebDataServiceConsumer* consumer) { |
| // Force pending changes to be visible immediately so the results of this call |
| // won't be out of date. |
| CommitQueuedOperations(); |
| |
| return wdbs_->ScheduleDBTaskWithResult( |
| FROM_HERE, base::Bind(&GetKeywordsImpl), consumer); |
| } |
| |
| void KeywordWebDataService::SetDefaultSearchProviderID(TemplateURLID id) { |
| wdbs_->ScheduleDBTask(FROM_HERE, |
| base::Bind(&SetDefaultSearchProviderIDImpl, id)); |
| } |
| |
| void KeywordWebDataService::SetBuiltinKeywordVersion(int version) { |
| wdbs_->ScheduleDBTask(FROM_HERE, |
| base::Bind(&SetBuiltinKeywordVersionImpl, version)); |
| } |
| |
| void KeywordWebDataService::ShutdownOnUISequence() { |
| CommitQueuedOperations(); |
| WebDataServiceBase::ShutdownOnUISequence(); |
| } |
| |
| KeywordWebDataService::~KeywordWebDataService() { |
| DCHECK(!batch_mode_level_); |
| DCHECK(queued_keyword_operations_.empty()); |
| } |
| |
| void KeywordWebDataService::AdjustBatchModeLevel(bool entering_batch_mode) { |
| if (entering_batch_mode) { |
| ++batch_mode_level_; |
| } else { |
| DCHECK(batch_mode_level_); |
| --batch_mode_level_; |
| if (!batch_mode_level_ && !queued_keyword_operations_.empty() && |
| !timer_.IsRunning()) { |
| // When killing an app on Android/iOS, shutdown isn't guaranteed to be |
| // called. Finishing this task immediately ensures the table is fully |
| // populated even if the app is killed before the timer expires. |
| #if defined(OS_ANDROID) || defined(OS_IOS) |
| CommitQueuedOperations(); |
| #else |
| timer_.Reset(); |
| #endif |
| } |
| } |
| } |
| |
| void KeywordWebDataService::CommitQueuedOperations() { |
| if (!queued_keyword_operations_.empty()) { |
| wdbs_->ScheduleDBTask(FROM_HERE, base::Bind(&PerformKeywordOperationsImpl, |
| queued_keyword_operations_)); |
| queued_keyword_operations_.clear(); |
| } |
| timer_.Stop(); |
| } |