[Cronet] Delay StartNetLog and StopNetLog until native request context is initialized
[chromium-blink-merge.git] / chrome / browser / autocomplete / in_memory_url_index.cc
blob653301400baa35c1c3d14c0314904dd54ec8d12b
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
5 #include "chrome/browser/autocomplete/in_memory_url_index.h"
7 #include "base/files/file_util.h"
8 #include "base/strings/utf_string_conversions.h"
9 #include "base/trace_event/trace_event.h"
10 #include "chrome/browser/autocomplete/url_index_private_data.h"
11 #include "chrome/common/url_constants.h"
12 #include "components/history/core/browser/history_service.h"
13 #include "components/history/core/browser/url_database.h"
14 #include "content/public/browser/browser_thread.h"
16 using in_memory_url_index::InMemoryURLIndexCacheItem;
18 // Called by DoSaveToCacheFile to delete any old cache file at |path| when
19 // there is no private data to save. Runs on the FILE thread.
20 void DeleteCacheFile(const base::FilePath& path) {
21 DCHECK(!content::BrowserThread::CurrentlyOn(content::BrowserThread::UI));
22 base::DeleteFile(path, false);
25 // Initializes a whitelist of URL schemes.
26 void InitializeSchemeWhitelist(std::set<std::string>* whitelist) {
27 DCHECK(whitelist);
28 if (!whitelist->empty())
29 return; // Nothing to do, already initialized.
30 whitelist->insert(std::string(url::kAboutScheme));
31 whitelist->insert(std::string(content::kChromeUIScheme));
32 whitelist->insert(std::string(url::kFileScheme));
33 whitelist->insert(std::string(url::kFtpScheme));
34 whitelist->insert(std::string(url::kHttpScheme));
35 whitelist->insert(std::string(url::kHttpsScheme));
36 whitelist->insert(std::string(url::kMailToScheme));
39 // Restore/SaveCacheObserver ---------------------------------------------------
41 InMemoryURLIndex::RestoreCacheObserver::~RestoreCacheObserver() {
44 InMemoryURLIndex::SaveCacheObserver::~SaveCacheObserver() {
47 // RebuildPrivateDataFromHistoryDBTask -----------------------------------------
49 InMemoryURLIndex::RebuildPrivateDataFromHistoryDBTask::
50 RebuildPrivateDataFromHistoryDBTask(
51 InMemoryURLIndex* index,
52 const std::string& languages,
53 const std::set<std::string>& scheme_whitelist)
54 : index_(index),
55 languages_(languages),
56 scheme_whitelist_(scheme_whitelist),
57 succeeded_(false) {
60 bool InMemoryURLIndex::RebuildPrivateDataFromHistoryDBTask::RunOnDBThread(
61 history::HistoryBackend* backend,
62 history::HistoryDatabase* db) {
63 data_ = URLIndexPrivateData::RebuildFromHistory(db, languages_,
64 scheme_whitelist_);
65 succeeded_ = data_.get() && !data_->Empty();
66 if (!succeeded_ && data_.get())
67 data_->Clear();
68 return true;
71 void InMemoryURLIndex::RebuildPrivateDataFromHistoryDBTask::
72 DoneRunOnMainThread() {
73 index_->DoneRebuidingPrivateDataFromHistoryDB(succeeded_, data_);
76 InMemoryURLIndex::RebuildPrivateDataFromHistoryDBTask::
77 ~RebuildPrivateDataFromHistoryDBTask() {
80 // InMemoryURLIndex ------------------------------------------------------------
82 InMemoryURLIndex::InMemoryURLIndex(bookmarks::BookmarkModel* bookmark_model,
83 history::HistoryService* history_service,
84 const base::FilePath& history_dir,
85 const std::string& languages)
86 : bookmark_model_(bookmark_model),
87 history_service_(history_service),
88 history_dir_(history_dir),
89 languages_(languages),
90 private_data_(new URLIndexPrivateData),
91 restore_cache_observer_(NULL),
92 save_cache_observer_(NULL),
93 shutdown_(false),
94 restored_(false),
95 needs_to_be_cached_(false),
96 listen_to_history_service_loaded_(false) {
97 InitializeSchemeWhitelist(&scheme_whitelist_);
98 // TODO(mrossetti): Register for language change notifications.
99 if (history_service_)
100 history_service_->AddObserver(this);
103 InMemoryURLIndex::~InMemoryURLIndex() {
104 // If there was a history directory (which there won't be for some unit tests)
105 // then insure that the cache has already been saved.
106 DCHECK(history_dir_.empty() || !needs_to_be_cached_);
107 DCHECK(!history_service_);
108 DCHECK(shutdown_);
111 void InMemoryURLIndex::Init() {
112 PostRestoreFromCacheFileTask();
115 void InMemoryURLIndex::ClearPrivateData() {
116 private_data_->Clear();
119 bool InMemoryURLIndex::GetCacheFilePath(base::FilePath* file_path) {
120 if (history_dir_.empty())
121 return false;
122 *file_path = history_dir_.Append(FILE_PATH_LITERAL("History Provider Cache"));
123 return true;
126 // Querying --------------------------------------------------------------------
128 ScoredHistoryMatches InMemoryURLIndex::HistoryItemsForTerms(
129 const base::string16& term_string,
130 size_t cursor_position,
131 size_t max_matches) {
132 return private_data_->HistoryItemsForTerms(
133 term_string, cursor_position, max_matches, languages_, bookmark_model_);
136 // Updating --------------------------------------------------------------------
138 void InMemoryURLIndex::DeleteURL(const GURL& url) {
139 private_data_->DeleteURL(url);
142 void InMemoryURLIndex::OnURLVisited(history::HistoryService* history_service,
143 ui::PageTransition transition,
144 const history::URLRow& row,
145 const history::RedirectList& redirects,
146 base::Time visit_time) {
147 DCHECK_EQ(history_service_, history_service);
148 needs_to_be_cached_ |= private_data_->UpdateURL(history_service_,
149 row,
150 languages_,
151 scheme_whitelist_,
152 &private_data_tracker_);
155 void InMemoryURLIndex::OnURLsModified(history::HistoryService* history_service,
156 const history::URLRows& changed_urls) {
157 DCHECK_EQ(history_service_, history_service);
158 for (const auto& row : changed_urls) {
159 needs_to_be_cached_ |= private_data_->UpdateURL(history_service_,
160 row,
161 languages_,
162 scheme_whitelist_,
163 &private_data_tracker_);
167 void InMemoryURLIndex::OnURLsDeleted(history::HistoryService* history_service,
168 bool all_history,
169 bool expired,
170 const history::URLRows& deleted_rows,
171 const std::set<GURL>& favicon_urls) {
172 if (all_history) {
173 ClearPrivateData();
174 needs_to_be_cached_ = true;
175 } else {
176 for (const auto& row : deleted_rows)
177 needs_to_be_cached_ |= private_data_->DeleteURL(row.url());
179 // If we made changes, destroy the previous cache. Otherwise, if we go
180 // through an unclean shutdown (and therefore fail to write a new cache file),
181 // when Chrome restarts and we restore from the previous cache, we'll end up
182 // searching over URLs that may be deleted. This would be wrong, and
183 // surprising to the user who bothered to delete some URLs from his/her
184 // history. In this situation, deleting the cache is a better solution than
185 // writing a new cache (after deleting the URLs from the in-memory structure)
186 // because deleting the cache forces it to be rebuilt from history upon
187 // startup. If we instead write a new, updated cache then at the time of next
188 // startup (after an unclean shutdown) we will not rebuild the in-memory data
189 // structures from history but rather use the cache. This solution is
190 // mediocre because this cache may not have the most-recently-visited URLs
191 // in it (URLs visited after user deleted some URLs from history), which
192 // would be odd and confusing. It's better to force a rebuild.
193 base::FilePath path;
194 if (needs_to_be_cached_ && GetCacheFilePath(&path)) {
195 content::BrowserThread::PostBlockingPoolTask(
196 FROM_HERE, base::Bind(DeleteCacheFile, path));
200 void InMemoryURLIndex::OnHistoryServiceLoaded(
201 history::HistoryService* history_service) {
202 if (listen_to_history_service_loaded_)
203 ScheduleRebuildFromHistory();
204 listen_to_history_service_loaded_ = false;
207 // Restoring from Cache --------------------------------------------------------
209 void InMemoryURLIndex::PostRestoreFromCacheFileTask() {
210 DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI));
211 TRACE_EVENT0("browser", "InMemoryURLIndex::PostRestoreFromCacheFileTask");
213 base::FilePath path;
214 if (!GetCacheFilePath(&path) || shutdown_) {
215 restored_ = true;
216 if (restore_cache_observer_)
217 restore_cache_observer_->OnCacheRestoreFinished(false);
218 return;
221 content::BrowserThread::PostTaskAndReplyWithResult
222 <scoped_refptr<URLIndexPrivateData> >(
223 content::BrowserThread::FILE, FROM_HERE,
224 base::Bind(&URLIndexPrivateData::RestoreFromFile, path, languages_),
225 base::Bind(&InMemoryURLIndex::OnCacheLoadDone, AsWeakPtr()));
228 void InMemoryURLIndex::OnCacheLoadDone(
229 scoped_refptr<URLIndexPrivateData> private_data) {
230 if (private_data.get() && !private_data->Empty()) {
231 private_data_tracker_.TryCancelAll();
232 private_data_ = private_data;
233 restored_ = true;
234 if (restore_cache_observer_)
235 restore_cache_observer_->OnCacheRestoreFinished(true);
236 } else if (history_service_) {
237 // When unable to restore from the cache file delete the cache file, if
238 // it exists, and then rebuild from the history database if it's available,
239 // otherwise wait until the history database loaded and then rebuild.
240 base::FilePath path;
241 if (!GetCacheFilePath(&path) || shutdown_)
242 return;
243 content::BrowserThread::PostBlockingPoolTask(
244 FROM_HERE, base::Bind(DeleteCacheFile, path));
245 if (history_service_->backend_loaded()) {
246 ScheduleRebuildFromHistory();
247 } else {
248 listen_to_history_service_loaded_ = true;
253 // Cleanup ---------------------------------------------------------------------
255 void InMemoryURLIndex::Shutdown() {
256 if (history_service_) {
257 history_service_->RemoveObserver(this);
258 history_service_ = nullptr;
260 cache_reader_tracker_.TryCancelAll();
261 shutdown_ = true;
262 base::FilePath path;
263 if (!GetCacheFilePath(&path))
264 return;
265 private_data_tracker_.TryCancelAll();
266 URLIndexPrivateData::WritePrivateDataToCacheFileTask(private_data_, path);
267 needs_to_be_cached_ = false;
270 // Restoring from the History DB -----------------------------------------------
272 void InMemoryURLIndex::ScheduleRebuildFromHistory() {
273 DCHECK(history_service_);
274 history_service_->ScheduleDBTask(
275 scoped_ptr<history::HistoryDBTask>(
276 new InMemoryURLIndex::RebuildPrivateDataFromHistoryDBTask(
277 this, languages_, scheme_whitelist_)),
278 &cache_reader_tracker_);
281 void InMemoryURLIndex::DoneRebuidingPrivateDataFromHistoryDB(
282 bool succeeded,
283 scoped_refptr<URLIndexPrivateData> private_data) {
284 DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI));
285 if (succeeded) {
286 private_data_tracker_.TryCancelAll();
287 private_data_ = private_data;
288 PostSaveToCacheFileTask(); // Cache the newly rebuilt index.
289 } else {
290 private_data_->Clear(); // Dump the old private data.
291 // There is no need to do anything with the cache file as it was deleted
292 // when the rebuild from the history operation was kicked off.
294 restored_ = true;
295 if (restore_cache_observer_)
296 restore_cache_observer_->OnCacheRestoreFinished(succeeded);
299 void InMemoryURLIndex::RebuildFromHistory(
300 history::HistoryDatabase* history_db) {
301 private_data_tracker_.TryCancelAll();
302 private_data_ = URLIndexPrivateData::RebuildFromHistory(history_db,
303 languages_,
304 scheme_whitelist_);
307 // Saving to Cache -------------------------------------------------------------
309 void InMemoryURLIndex::PostSaveToCacheFileTask() {
310 base::FilePath path;
311 if (!GetCacheFilePath(&path))
312 return;
313 // If there is anything in our private data then make a copy of it and tell
314 // it to save itself to a file.
315 if (private_data_.get() && !private_data_->Empty()) {
316 // Note that ownership of the copy of our private data is passed to the
317 // completion closure below.
318 scoped_refptr<URLIndexPrivateData> private_data_copy =
319 private_data_->Duplicate();
320 content::BrowserThread::PostTaskAndReplyWithResult<bool>(
321 content::BrowserThread::FILE, FROM_HERE,
322 base::Bind(&URLIndexPrivateData::WritePrivateDataToCacheFileTask,
323 private_data_copy, path),
324 base::Bind(&InMemoryURLIndex::OnCacheSaveDone, AsWeakPtr()));
325 } else {
326 // If there is no data in our index then delete any existing cache file.
327 content::BrowserThread::PostBlockingPoolTask(
328 FROM_HERE,
329 base::Bind(DeleteCacheFile, path));
333 void InMemoryURLIndex::OnCacheSaveDone(bool succeeded) {
334 if (save_cache_observer_)
335 save_cache_observer_->OnCacheSaveFinished(succeeded);