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

Side by Side Diff: chrome/browser/history/in_memory_url_index.cc

Issue 8275004: Revert 105300 - HQP Refactoring (in Preparation for SQLite Cache) (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src/
Patch Set: Created 9 years, 2 months 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 unified diff | Download patch | Annotate | Revision Log
OLDNEW
1 // Copyright (c) 2011 The Chromium Authors. All rights reserved. 1 // Copyright (c) 2011 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 #include "chrome/browser/history/in_memory_url_index.h" 5 #include "chrome/browser/history/in_memory_url_index.h"
6 6
7 #include <algorithm> 7 #include <algorithm>
8 #include <functional> 8 #include <functional>
9 #include <iterator> 9 #include <iterator>
10 #include <limits> 10 #include <limits>
11 #include <numeric> 11 #include <numeric>
12 12
13 #include "base/file_util.h" 13 #include "base/file_util.h"
14 #include "base/i18n/break_iterator.h"
14 #include "base/i18n/case_conversion.h" 15 #include "base/i18n/case_conversion.h"
15 #include "base/metrics/histogram.h" 16 #include "base/metrics/histogram.h"
17 #include "base/string_util.h"
16 #include "base/threading/thread_restrictions.h" 18 #include "base/threading/thread_restrictions.h"
17 #include "base/time.h" 19 #include "base/time.h"
18 #include "base/utf_string_conversions.h" 20 #include "base/utf_string_conversions.h"
19 #include "chrome/browser/autocomplete/autocomplete.h" 21 #include "chrome/browser/autocomplete/autocomplete.h"
20 #include "chrome/browser/autocomplete/history_provider_util.h" 22 #include "chrome/browser/autocomplete/history_provider_util.h"
21 #include "chrome/browser/history/history_notifications.h"
22 #include "chrome/browser/history/url_database.h" 23 #include "chrome/browser/history/url_database.h"
23 #include "chrome/browser/profiles/profile.h" 24 #include "chrome/browser/profiles/profile.h"
24 #include "chrome/common/chrome_notification_types.h"
25 #include "chrome/common/url_constants.h" 25 #include "chrome/common/url_constants.h"
26 #include "content/common/notification_details.h"
27 #include "content/common/notification_source.h"
28 #include "googleurl/src/url_parse.h" 26 #include "googleurl/src/url_parse.h"
29 #include "googleurl/src/url_util.h" 27 #include "googleurl/src/url_util.h"
30 #include "net/base/escape.h" 28 #include "net/base/escape.h"
31 #include "net/base/net_util.h" 29 #include "net/base/net_util.h"
32 #include "third_party/protobuf/src/google/protobuf/repeated_field.h" 30 #include "third_party/protobuf/src/google/protobuf/repeated_field.h"
33 #include "ui/base/l10n/l10n_util.h" 31 #include "ui/base/l10n/l10n_util.h"
34 32
35 using google::protobuf::RepeatedField; 33 using google::protobuf::RepeatedField;
36 using google::protobuf::RepeatedPtrField; 34 using google::protobuf::RepeatedPtrField;
37 using in_memory_url_index::InMemoryURLIndexCacheItem; 35 using in_memory_url_index::InMemoryURLIndexCacheItem;
(...skipping 16 matching lines...) Expand all
54 HistoryInfoMapEntry; 52 HistoryInfoMapEntry;
55 53
56 const size_t InMemoryURLIndex::kNoCachedResultForTerm = -1; 54 const size_t InMemoryURLIndex::kNoCachedResultForTerm = -1;
57 55
58 // Score ranges used to get a 'base' score for each of the scoring factors 56 // Score ranges used to get a 'base' score for each of the scoring factors
59 // (such as recency of last visit, times visited, times the URL was typed, 57 // (such as recency of last visit, times visited, times the URL was typed,
60 // and the quality of the string match). There is a matching value range for 58 // and the quality of the string match). There is a matching value range for
61 // each of these scores for each factor. 59 // each of these scores for each factor.
62 const int kScoreRank[] = { 1425, 1200, 900, 400 }; 60 const int kScoreRank[] = { 1425, 1200, 900, 400 };
63 61
62 ScoredHistoryMatch::ScoredHistoryMatch()
63 : raw_score(0),
64 can_inline(false) {}
65
66 ScoredHistoryMatch::ScoredHistoryMatch(const URLRow& url_info)
67 : HistoryMatch(url_info, 0, false, false),
68 raw_score(0),
69 can_inline(false) {}
70
71 ScoredHistoryMatch::~ScoredHistoryMatch() {}
72
73 // Comparison function for sorting ScoredMatches by their scores.
74 bool ScoredHistoryMatch::MatchScoreGreater(const ScoredHistoryMatch& m1,
75 const ScoredHistoryMatch& m2) {
76 return m1.raw_score >= m2.raw_score;
77 }
78
64 InMemoryURLIndex::SearchTermCacheItem::SearchTermCacheItem( 79 InMemoryURLIndex::SearchTermCacheItem::SearchTermCacheItem(
65 const WordIDSet& word_id_set, 80 const WordIDSet& word_id_set,
66 const HistoryIDSet& history_id_set) 81 const HistoryIDSet& history_id_set)
67 : word_id_set_(word_id_set), 82 : word_id_set_(word_id_set),
68 history_id_set_(history_id_set), 83 history_id_set_(history_id_set),
69 used_(true) {} 84 used_(true) {}
70 85
71 InMemoryURLIndex::SearchTermCacheItem::SearchTermCacheItem() 86 InMemoryURLIndex::SearchTermCacheItem::SearchTermCacheItem()
72 : used_(true) {} 87 : used_(true) {}
73 88
74 InMemoryURLIndex::SearchTermCacheItem::~SearchTermCacheItem() {} 89 InMemoryURLIndex::SearchTermCacheItem::~SearchTermCacheItem() {}
75 90
91 // Comparison function for sorting TermMatches by their offsets.
92 bool MatchOffsetLess(const TermMatch& m1, const TermMatch& m2) {
93 return m1.offset < m2.offset;
94 }
95
76 // Comparison function for sorting search terms by descending length. 96 // Comparison function for sorting search terms by descending length.
77 bool LengthGreater(const string16& string_a, const string16& string_b) { 97 bool LengthGreater(const string16& string_a, const string16& string_b) {
78 return string_a.length() > string_b.length(); 98 return string_a.length() > string_b.length();
79 } 99 }
80 100
81 // std::accumulate helper function to add up TermMatches' lengths. 101 // std::accumulate helper function to add up TermMatches' lengths.
82 int AccumulateMatchLength(int total, const TermMatch& match) { 102 int AccumulateMatchLength(int total, const TermMatch& match) {
83 return total + match.length; 103 return total + match.length;
84 } 104 }
85 105
(...skipping 22 matching lines...) Expand all
108 return 0; 128 return 0;
109 int score = kScoreRank[i]; 129 int score = kScoreRank[i];
110 if (i > 0) { 130 if (i > 0) {
111 score += (value - value_ranks[i]) * 131 score += (value - value_ranks[i]) *
112 (kScoreRank[i - 1] - kScoreRank[i]) / 132 (kScoreRank[i - 1] - kScoreRank[i]) /
113 (value_ranks[i - 1] - value_ranks[i]); 133 (value_ranks[i - 1] - value_ranks[i]);
114 } 134 }
115 return score; 135 return score;
116 } 136 }
117 137
118 InMemoryURLIndex::InMemoryURLIndex(Profile* profile, 138 InMemoryURLIndex::InMemoryURLIndex(const FilePath& history_dir)
119 const FilePath& history_dir)
120 : history_dir_(history_dir), 139 : history_dir_(history_dir),
121 private_data_(new URLIndexPrivateData) { 140 history_item_count_(0) {
122 InMemoryURLIndex::InitializeSchemeWhitelist(&scheme_whitelist_); 141 InMemoryURLIndex::InitializeSchemeWhitelist(&scheme_whitelist_);
123 if (profile) {
124 Source<Profile> source(profile);
125 registrar_.Add(this, chrome::NOTIFICATION_HISTORY_URL_VISITED, source);
126 registrar_.Add(this, chrome::NOTIFICATION_HISTORY_TYPED_URLS_MODIFIED,
127 source);
128 registrar_.Add(this, chrome::NOTIFICATION_HISTORY_URLS_DELETED, source);
129 }
130 } 142 }
131 143
132 // Called only by unit tests. 144 // Called only by unit tests.
133 InMemoryURLIndex::InMemoryURLIndex() 145 InMemoryURLIndex::InMemoryURLIndex()
134 : private_data_(new URLIndexPrivateData) { 146 : history_item_count_(0) {
135 InMemoryURLIndex::InitializeSchemeWhitelist(&scheme_whitelist_); 147 InMemoryURLIndex::InitializeSchemeWhitelist(&scheme_whitelist_);
136 } 148 }
137 149
138 InMemoryURLIndex::~InMemoryURLIndex() {} 150 InMemoryURLIndex::~InMemoryURLIndex() {}
139 151
140 // static 152 // static
141 void InMemoryURLIndex::InitializeSchemeWhitelist( 153 void InMemoryURLIndex::InitializeSchemeWhitelist(
142 std::set<std::string>* whitelist) { 154 std::set<std::string>* whitelist) {
143 DCHECK(whitelist); 155 DCHECK(whitelist);
144 whitelist->insert(std::string(chrome::kAboutScheme)); 156 whitelist->insert(std::string(chrome::kAboutScheme));
145 whitelist->insert(std::string(chrome::kChromeUIScheme)); 157 whitelist->insert(std::string(chrome::kChromeUIScheme));
146 whitelist->insert(std::string(chrome::kFileScheme)); 158 whitelist->insert(std::string(chrome::kFileScheme));
147 whitelist->insert(std::string(chrome::kFtpScheme)); 159 whitelist->insert(std::string(chrome::kFtpScheme));
148 whitelist->insert(std::string(chrome::kHttpScheme)); 160 whitelist->insert(std::string(chrome::kHttpScheme));
149 whitelist->insert(std::string(chrome::kHttpsScheme)); 161 whitelist->insert(std::string(chrome::kHttpsScheme));
150 whitelist->insert(std::string(chrome::kMailToScheme)); 162 whitelist->insert(std::string(chrome::kMailToScheme));
151 } 163 }
152 164
153 // Indexing 165 // Indexing
154 166
155 bool InMemoryURLIndex::Init(URLDatabase* history_db, 167 bool InMemoryURLIndex::Init(history::URLDatabase* history_db,
156 const std::string& languages) { 168 const std::string& languages) {
157 // TODO(mrossetti): Register for profile/language change notifications. 169 // TODO(mrossetti): Register for profile/language change notifications.
158 languages_ = languages; 170 languages_ = languages;
159 return ReloadFromHistory(history_db, false); 171 return ReloadFromHistory(history_db, false);
160 } 172 }
161 173
162 void InMemoryURLIndex::ShutDown() { 174 void InMemoryURLIndex::ShutDown() {
163 registrar_.RemoveAll();
164 // Write our cache. 175 // Write our cache.
165 SaveToCacheFile(); 176 SaveToCacheFile();
166 } 177 }
167 178
168 void InMemoryURLIndex::Observe(int type,
169 const NotificationSource& source,
170 const NotificationDetails& details) {
171 switch (type) {
172 case chrome::NOTIFICATION_HISTORY_URL_VISITED:
173 OnURLVisited(Details<URLVisitedDetails>(details).ptr());
174 break;
175 case chrome::NOTIFICATION_HISTORY_TYPED_URLS_MODIFIED:
176 OnURLsModified(Details<history::URLsModifiedDetails>(details).ptr());
177 break;
178 case chrome::NOTIFICATION_HISTORY_URLS_DELETED:
179 OnURLsDeleted(Details<history::URLsDeletedDetails>(details).ptr());
180 break;
181 default:
182 // For simplicity, the unit tests send us all notifications, even when
183 // we haven't registered for them, so don't assert here.
184 break;
185 }
186 }
187
188 void InMemoryURLIndex::OnURLVisited(const URLVisitedDetails* details) {
189 UpdateURL(details->row);
190 }
191
192 void InMemoryURLIndex::OnURLsModified(const URLsModifiedDetails* details) {
193 for (std::vector<history::URLRow>::const_iterator row =
194 details->changed_urls.begin();
195 row != details->changed_urls.end(); ++row)
196 UpdateURL(*row);
197 }
198
199 void InMemoryURLIndex::OnURLsDeleted(const URLsDeletedDetails* details) {
200 if (details->all_history) {
201 ClearPrivateData();
202 } else {
203 for (std::vector<URLRow>::const_iterator row = details->rows.begin();
204 row != details->rows.end(); ++row)
205 DeleteURL(*row);
206 }
207 }
208
209 bool InMemoryURLIndex::IndexRow(const URLRow& row) { 179 bool InMemoryURLIndex::IndexRow(const URLRow& row) {
210 const GURL& gurl(row.url()); 180 const GURL& gurl(row.url());
211 181
212 // Index only URLs with a whitelisted scheme. 182 // Index only URLs with a whitelisted scheme.
213 if (!InMemoryURLIndex::URLSchemeIsWhitelisted(gurl)) 183 if (!InMemoryURLIndex::URLSchemeIsWhitelisted(gurl))
214 return true; 184 return true;
215 185
216 URLID row_id = row.id();
217 // Strip out username and password before saving and indexing.
218 string16 url(net::FormatUrl(gurl, languages_, 186 string16 url(net::FormatUrl(gurl, languages_,
219 net::kFormatUrlOmitUsernamePassword, 187 net::kFormatUrlOmitUsernamePassword,
220 UnescapeRule::SPACES | UnescapeRule::URL_SPECIAL_CHARS, 188 UnescapeRule::SPACES | UnescapeRule::URL_SPECIAL_CHARS,
221 NULL, NULL, NULL)); 189 NULL, NULL, NULL));
222 HistoryID history_id = static_cast<HistoryID>(row_id); 190
223 DCHECK_LT(history_id, std::numeric_limits<HistoryID>::max()); 191 HistoryID history_id = static_cast<HistoryID>(row.id());
192 DCHECK_LT(row.id(), std::numeric_limits<HistoryID>::max());
224 193
225 // Add the row for quick lookup in the history info store. 194 // Add the row for quick lookup in the history info store.
226 URLRow new_row(GURL(url), row_id); 195 URLRow new_row(GURL(url), row.id());
227 new_row.set_visit_count(row.visit_count()); 196 new_row.set_visit_count(row.visit_count());
228 new_row.set_typed_count(row.typed_count()); 197 new_row.set_typed_count(row.typed_count());
229 new_row.set_last_visit(row.last_visit()); 198 new_row.set_last_visit(row.last_visit());
230 new_row.set_title(row.title()); 199 new_row.set_title(row.title());
231 private_data_->history_info_map_[history_id] = new_row; 200 history_info_map_[history_id] = new_row;
232 201
233 // Index the words contained in the URL and title of the row.
234 AddRowWordsToIndex(new_row);
235 return true;
236 }
237
238 void InMemoryURLIndex::AddRowWordsToIndex(const URLRow& row) {
239 HistoryID history_id = static_cast<HistoryID>(row.id());
240 // Split URL into individual, unique words then add in the title words. 202 // Split URL into individual, unique words then add in the title words.
241 const GURL& gurl(row.url());
242 string16 url(net::FormatUrl(gurl, languages_,
243 net::kFormatUrlOmitUsernamePassword,
244 UnescapeRule::SPACES | UnescapeRule::URL_SPECIAL_CHARS,
245 NULL, NULL, NULL));
246 url = base::i18n::ToLower(url); 203 url = base::i18n::ToLower(url);
247 String16Set url_words = String16SetFromString16(url); 204 String16Set url_words = WordSetFromString16(url);
248 String16Set title_words = String16SetFromString16(row.title()); 205 String16Set title_words = WordSetFromString16(row.title());
249 String16Set words; 206 String16Set words;
250 std::set_union(url_words.begin(), url_words.end(), 207 std::set_union(url_words.begin(), url_words.end(),
251 title_words.begin(), title_words.end(), 208 title_words.begin(), title_words.end(),
252 std::insert_iterator<String16Set>(words, words.begin())); 209 std::insert_iterator<String16Set>(words, words.begin()));
253 for (String16Set::iterator word_iter = words.begin(); 210 for (String16Set::iterator word_iter = words.begin();
254 word_iter != words.end(); ++word_iter) 211 word_iter != words.end(); ++word_iter)
255 AddWordToIndex(*word_iter, history_id); 212 AddWordToIndex(*word_iter, history_id);
256 213
257 search_term_cache_.clear(); // Invalidate the term cache. 214 ++history_item_count_;
258 } 215 return true;
259
260 void InMemoryURLIndex::RemoveRowFromIndex(const URLRow& row) {
261 RemoveRowWordsFromIndex(row);
262 HistoryID history_id = static_cast<HistoryID>(row.id());
263 private_data_->history_info_map_.erase(history_id);
264 }
265
266 void InMemoryURLIndex::RemoveRowWordsFromIndex(const URLRow& row) {
267 // Remove the entries in history_id_word_map_ and word_id_history_map_ for
268 // this row.
269 URLIndexPrivateData& private_data(*(private_data_.get()));
270 HistoryID history_id = static_cast<HistoryID>(row.id());
271 WordIDSet word_id_set = private_data.history_id_word_map_[history_id];
272 private_data.history_id_word_map_.erase(history_id);
273
274 // Reconcile any changes to word usage.
275 for (WordIDSet::iterator word_id_iter = word_id_set.begin();
276 word_id_iter != word_id_set.end(); ++word_id_iter) {
277 WordID word_id = *word_id_iter;
278 private_data.word_id_history_map_[word_id].erase(history_id);
279 if (!private_data.word_id_history_map_[word_id].empty())
280 continue; // The word is still in use.
281
282 // The word is no longer in use. Reconcile any changes to character usage.
283 string16 word = private_data.word_list_[word_id];
284 Char16Set characters = Char16SetFromString16(word);
285 for (Char16Set::iterator uni_char_iter = characters.begin();
286 uni_char_iter != characters.end(); ++uni_char_iter) {
287 char16 uni_char = *uni_char_iter;
288 private_data.char_word_map_[uni_char].erase(word_id);
289 if (private_data.char_word_map_[uni_char].empty())
290 private_data.char_word_map_.erase(uni_char); // No longer in use.
291 }
292
293 // Complete the removal of references to the word.
294 private_data.word_id_history_map_.erase(word_id);
295 private_data.word_map_.erase(word);
296 private_data.word_list_[word_id] = string16();
297 private_data.available_words_.insert(word_id);
298 }
299 } 216 }
300 217
301 bool InMemoryURLIndex::ReloadFromHistory(history::URLDatabase* history_db, 218 bool InMemoryURLIndex::ReloadFromHistory(history::URLDatabase* history_db,
302 bool clear_cache) { 219 bool clear_cache) {
303 ClearPrivateData(); 220 ClearPrivateData();
304 221
305 if (!history_db) 222 if (!history_db)
306 return false; 223 return false;
307 224
308 if (clear_cache || !RestoreFromCacheFile()) { 225 if (clear_cache || !RestoreFromCacheFile()) {
309 base::TimeTicks beginning_time = base::TimeTicks::Now(); 226 base::TimeTicks beginning_time = base::TimeTicks::Now();
310 // The index has to be built from scratch. 227 // The index has to be built from scratch.
311 URLDatabase::URLEnumerator history_enum; 228 URLDatabase::URLEnumerator history_enum;
312 if (!history_db->InitURLEnumeratorForSignificant(&history_enum)) 229 if (!history_db->InitURLEnumeratorForSignificant(&history_enum))
313 return false; 230 return false;
314 URLRow row; 231 URLRow row;
315 while (history_enum.GetNextURL(&row)) { 232 while (history_enum.GetNextURL(&row)) {
316 if (!IndexRow(row)) 233 if (!IndexRow(row))
317 return false; 234 return false;
318 } 235 }
319 UMA_HISTOGRAM_TIMES("History.InMemoryURLIndexingTime", 236 UMA_HISTOGRAM_TIMES("History.InMemoryURLIndexingTime",
320 base::TimeTicks::Now() - beginning_time); 237 base::TimeTicks::Now() - beginning_time);
321 SaveToCacheFile(); 238 SaveToCacheFile();
322 } 239 }
323 return true; 240 return true;
324 } 241 }
325 242
326 void InMemoryURLIndex::ClearPrivateData() { 243 void InMemoryURLIndex::ClearPrivateData() {
327 private_data_->Clear(); 244 history_item_count_ = 0;
245 word_list_.clear();
246 word_map_.clear();
247 char_word_map_.clear();
248 word_id_history_map_.clear();
249 history_info_map_.clear();
328 search_term_cache_.clear(); 250 search_term_cache_.clear();
329 } 251 }
330 252
331 bool InMemoryURLIndex::RestoreFromCacheFile() { 253 bool InMemoryURLIndex::RestoreFromCacheFile() {
332 // TODO(mrossetti): Figure out how to determine if the cache is up-to-date. 254 // TODO(mrossetti): Figure out how to determine if the cache is up-to-date.
333 // That is: ensure that the database has not been modified since the cache 255 // That is: ensure that the database has not been modified since the cache
334 // was last saved. DB file modification date is inadequate. There are no 256 // was last saved. DB file modification date is inadequate. There are no
335 // SQLite table checksums automatically stored. 257 // SQLite table checksums automatically stored.
336 // FIXME(mrossetti): Move File IO to another thread. 258 // FIXME(mrossetti): Move File IO to another thread.
337 base::ThreadRestrictions::ScopedAllowIO allow_io; 259 base::ThreadRestrictions::ScopedAllowIO allow_io;
(...skipping 15 matching lines...) Expand all
353 return false; 275 return false;
354 } 276 }
355 277
356 if (!RestorePrivateData(index_cache)) { 278 if (!RestorePrivateData(index_cache)) {
357 ClearPrivateData(); // Back to square one -- must build from scratch. 279 ClearPrivateData(); // Back to square one -- must build from scratch.
358 return false; 280 return false;
359 } 281 }
360 282
361 UMA_HISTOGRAM_TIMES("History.InMemoryURLIndexRestoreCacheTime", 283 UMA_HISTOGRAM_TIMES("History.InMemoryURLIndexRestoreCacheTime",
362 base::TimeTicks::Now() - beginning_time); 284 base::TimeTicks::Now() - beginning_time);
363 UMA_HISTOGRAM_COUNTS("History.InMemoryURLHistoryItems", 285 UMA_HISTOGRAM_COUNTS("History.InMemoryURLHistoryItems", history_item_count_);
364 private_data_->history_id_word_map_.size());
365 UMA_HISTOGRAM_COUNTS("History.InMemoryURLCacheSize", data.size()); 286 UMA_HISTOGRAM_COUNTS("History.InMemoryURLCacheSize", data.size());
366 UMA_HISTOGRAM_COUNTS_10000("History.InMemoryURLWords", 287 UMA_HISTOGRAM_COUNTS_10000("History.InMemoryURLWords", word_map_.size());
367 private_data_->word_map_.size()); 288 UMA_HISTOGRAM_COUNTS_10000("History.InMemoryURLChars", char_word_map_.size());
368 UMA_HISTOGRAM_COUNTS_10000("History.InMemoryURLChars",
369 private_data_->char_word_map_.size());
370 return true; 289 return true;
371 } 290 }
372 291
373 bool InMemoryURLIndex::SaveToCacheFile() { 292 bool InMemoryURLIndex::SaveToCacheFile() {
374 // TODO(mrossetti): Move File IO to another thread. 293 // TODO(mrossetti): Move File IO to another thread.
375 base::ThreadRestrictions::ScopedAllowIO allow_io; 294 base::ThreadRestrictions::ScopedAllowIO allow_io;
376 base::TimeTicks beginning_time = base::TimeTicks::Now(); 295 base::TimeTicks beginning_time = base::TimeTicks::Now();
377 InMemoryURLIndexCacheItem index_cache; 296 InMemoryURLIndexCacheItem index_cache;
378 SavePrivateData(&index_cache); 297 SavePrivateData(&index_cache);
379 std::string data; 298 std::string data;
(...skipping 11 matching lines...) Expand all
391 int size = data.size(); 310 int size = data.size();
392 if (file_util::WriteFile(file_path, data.c_str(), size) != size) { 311 if (file_util::WriteFile(file_path, data.c_str(), size) != size) {
393 LOG(WARNING) << "Failed to write " << file_path.value(); 312 LOG(WARNING) << "Failed to write " << file_path.value();
394 return false; 313 return false;
395 } 314 }
396 UMA_HISTOGRAM_TIMES("History.InMemoryURLIndexSaveCacheTime", 315 UMA_HISTOGRAM_TIMES("History.InMemoryURLIndexSaveCacheTime",
397 base::TimeTicks::Now() - beginning_time); 316 base::TimeTicks::Now() - beginning_time);
398 return true; 317 return true;
399 } 318 }
400 319
401 void InMemoryURLIndex::UpdateURL(const URLRow& row) { 320 void InMemoryURLIndex::UpdateURL(URLID row_id, const URLRow& row) {
402 // The row may or may not already be in our index. If it is not already 321 // The row may or may not already be in our index. If it is not already
403 // indexed and it qualifies then it gets indexed. If it is already 322 // indexed and it qualifies then it gets indexed. If it is already
404 // indexed and still qualifies then it gets updated, otherwise it 323 // indexed and still qualifies then it gets updated, otherwise it
405 // is deleted from the index. 324 // is deleted from the index.
406 HistoryInfoMap::iterator row_pos = 325 HistoryInfoMap::iterator row_pos = history_info_map_.find(row_id);
407 private_data_->history_info_map_.find(row.id()); 326 if (row_pos == history_info_map_.end()) {
408 if (row_pos == private_data_->history_info_map_.end()) {
409 // This new row should be indexed if it qualifies. 327 // This new row should be indexed if it qualifies.
410 if (RowQualifiesAsSignificant(row, base::Time())) 328 if (RowQualifiesAsSignificant(row, base::Time()))
411 IndexRow(row); 329 IndexRow(row);
412 } else if (RowQualifiesAsSignificant(row, base::Time())) { 330 } else if (RowQualifiesAsSignificant(row, base::Time())) {
413 // This indexed row still qualifies and will be re-indexed. 331 // This indexed row still qualifies and will be re-indexed.
414 // The url won't have changed but the title, visit count, etc. 332 // The url won't have changed but the title, visit count, etc.
415 // might have changed. 333 // might have changed.
416 URLRow& old_row = row_pos->second; 334 URLRow& old_row = row_pos->second;
417 old_row.set_visit_count(row.visit_count()); 335 old_row.set_visit_count(row.visit_count());
418 old_row.set_typed_count(row.typed_count()); 336 old_row.set_typed_count(row.typed_count());
419 old_row.set_last_visit(row.last_visit()); 337 old_row.set_last_visit(row.last_visit());
420 // While the URL is guaranteed to remain stable, the title may have changed. 338 // TODO(mrossetti): When we start indexing the title the next line
421 // If so, then we need to update the index with the changed words. 339 // will need attention.
422 if (old_row.title() != row.title()) { 340 old_row.set_title(row.title());
423 // Clear all words associated with this row and re-index both the
424 // URL and title.
425 RemoveRowWordsFromIndex(row);
426 old_row.set_title(row.title());
427 AddRowWordsToIndex(old_row);
428 }
429 } else { 341 } else {
430 // This indexed row no longer qualifies and will be de-indexed by 342 // This indexed row no longer qualifies and will be de-indexed.
431 // clearing all words associated with this row. 343 history_info_map_.erase(row_id);
432 RemoveRowFromIndex(row);
433 } 344 }
434 // This invalidates the cache. 345 // This invalidates the cache.
435 search_term_cache_.clear(); 346 search_term_cache_.clear();
347 // TODO(mrossetti): Record this transaction in the cache.
436 } 348 }
437 349
438 void InMemoryURLIndex::DeleteURL(const URLRow& row) { 350 void InMemoryURLIndex::DeleteURL(URLID row_id) {
439 RemoveRowFromIndex(row); 351 // Note that this does not remove any reference to this row from the
352 // word_id_history_map_. That map will continue to contain (and return)
353 // hits against this row until that map is rebuilt, but since the
354 // history_info_map_ no longer references the row no erroneous results
355 // will propagate to the user.
356 history_info_map_.erase(row_id);
440 // This invalidates the word cache. 357 // This invalidates the word cache.
441 search_term_cache_.clear(); 358 search_term_cache_.clear();
442 // TODO(mrossetti): Record this transaction in the cache. 359 // TODO(mrossetti): Record this transaction in the cache.
443 } 360 }
444 361
445 // Searching 362 // Searching
446 363
447 ScoredHistoryMatches InMemoryURLIndex::HistoryItemsForTerms( 364 ScoredHistoryMatches InMemoryURLIndex::HistoryItemsForTerms(
448 const String16Vector& terms) { 365 const String16Vector& terms) {
449 ScoredHistoryMatches scored_items; 366 ScoredHistoryMatches scored_items;
450
451 // Do nothing if we have indexed no words (probably because we've not been
452 // initialized yet).
453 if (private_data_->word_list_.empty())
454 return scored_items;
455
456 if (!terms.empty()) { 367 if (!terms.empty()) {
457 // Reset used_ flags for search_term_cache_. We use a basic mark-and-sweep 368 // Reset used_ flags for search_term_cache_. We use a basic mark-and-sweep
458 // approach. 369 // approach.
459 ResetSearchTermCache(); 370 ResetSearchTermCache();
460 371
461 // Lowercase the terms. 372 // Lowercase the terms.
462 // TODO(mrossetti): Another opportunity for a transform algorithm. 373 // TODO(mrossetti): Another opportunity for a transform algorithm.
463 String16Vector lower_terms; 374 String16Vector lower_terms;
464 for (String16Vector::const_iterator term_iter = terms.begin(); 375 for (String16Vector::const_iterator term_iter = terms.begin();
465 term_iter != terms.end(); ++term_iter) 376 term_iter != terms.end(); ++term_iter)
(...skipping 37 matching lines...) Expand 10 before | Expand all | Expand 10 after
503 414
504 return scored_items; 415 return scored_items;
505 } 416 }
506 417
507 void InMemoryURLIndex::ResetSearchTermCache() { 418 void InMemoryURLIndex::ResetSearchTermCache() {
508 for (SearchTermCacheMap::iterator iter = search_term_cache_.begin(); 419 for (SearchTermCacheMap::iterator iter = search_term_cache_.begin();
509 iter != search_term_cache_.end(); ++iter) 420 iter != search_term_cache_.end(); ++iter)
510 iter->second.used_ = false; 421 iter->second.used_ = false;
511 } 422 }
512 423
513 HistoryIDSet InMemoryURLIndex::HistoryIDSetFromWords( 424 InMemoryURLIndex::HistoryIDSet InMemoryURLIndex::HistoryIDSetFromWords(
514 const string16& uni_string) { 425 const string16& uni_string) {
515 // Break the terms down into individual terms (words), get the candidate 426 // Break the terms down into individual terms (words), get the candidate
516 // set for each term, and intersect each to get a final candidate list. 427 // set for each term, and intersect each to get a final candidate list.
517 // Note that a single 'term' from the user's perspective might be 428 // Note that a single 'term' from the user's perspective might be
518 // a string like "http://www.somewebsite.com" which, from our perspective, 429 // a string like "http://www.somewebsite.com" which, from our perspective,
519 // is four words: 'http', 'www', 'somewebsite', and 'com'. 430 // is four words: 'http', 'www', 'somewebsite', and 'com'.
520 HistoryIDSet history_id_set; 431 HistoryIDSet history_id_set;
521 String16Vector terms = String16VectorFromString16(uni_string, true); 432 String16Vector terms = WordVectorFromString16(uni_string, true);
522 // Sort the terms into the longest first as such are likely to narrow down 433 // Sort the terms into the longest first as such are likely to narrow down
523 // the results quicker. Also, single character terms are the most expensive 434 // the results quicker. Also, single character terms are the most expensive
524 // to process so save them for last. 435 // to process so save them for last.
525 std::sort(terms.begin(), terms.end(), LengthGreater); 436 std::sort(terms.begin(), terms.end(), LengthGreater);
526 for (String16Vector::iterator iter = terms.begin(); iter != terms.end(); 437 for (String16Vector::iterator iter = terms.begin(); iter != terms.end();
527 ++iter) { 438 ++iter) {
528 string16 uni_word = *iter; 439 string16 uni_word = *iter;
529 HistoryIDSet term_history_set = HistoryIDsForTerm(uni_word); 440 HistoryIDSet term_history_set = HistoryIDsForTerm(uni_word);
530 if (term_history_set.empty()) { 441 if (term_history_set.empty()) {
531 history_id_set.clear(); 442 history_id_set.clear();
532 break; 443 break;
533 } 444 }
534 if (iter == terms.begin()) { 445 if (iter == terms.begin()) {
535 history_id_set.swap(term_history_set); 446 history_id_set.swap(term_history_set);
536 } else { 447 } else {
537 HistoryIDSet new_history_id_set; 448 HistoryIDSet new_history_id_set;
538 std::set_intersection(history_id_set.begin(), history_id_set.end(), 449 std::set_intersection(history_id_set.begin(), history_id_set.end(),
539 term_history_set.begin(), term_history_set.end(), 450 term_history_set.begin(), term_history_set.end(),
540 std::inserter(new_history_id_set, 451 std::inserter(new_history_id_set,
541 new_history_id_set.begin())); 452 new_history_id_set.begin()));
542 history_id_set.swap(new_history_id_set); 453 history_id_set.swap(new_history_id_set);
543 } 454 }
544 } 455 }
545 return history_id_set; 456 return history_id_set;
546 } 457 }
547 458
548 HistoryIDSet InMemoryURLIndex::HistoryIDsForTerm( 459 InMemoryURLIndex::HistoryIDSet InMemoryURLIndex::HistoryIDsForTerm(
549 const string16& term) { 460 const string16& term) {
550 if (term.empty()) 461 if (term.empty())
551 return HistoryIDSet(); 462 return HistoryIDSet();
552 463
553 // TODO(mrossetti): Consider optimizing for very common terms such as 464 // TODO(mrossetti): Consider optimizing for very common terms such as
554 // 'http[s]', 'www', 'com', etc. Or collect the top 100 more frequently 465 // 'http[s]', 'www', 'com', etc. Or collect the top 100 more frequently
555 // occuring words in the user's searches. 466 // occuring words in the user's searches.
556 467
557 size_t term_length = term.length(); 468 size_t term_length = term.length();
558 WordIDSet word_id_set; 469 InMemoryURLIndex::WordIDSet word_id_set;
559 if (term_length > 1) { 470 if (term_length > 1) {
560 // See if this term or a prefix thereof is present in the cache. 471 // See if this term or a prefix thereof is present in the cache.
561 SearchTermCacheMap::iterator best_prefix(search_term_cache_.end()); 472 SearchTermCacheMap::iterator best_prefix(search_term_cache_.end());
562 for (SearchTermCacheMap::iterator cache_iter = search_term_cache_.begin(); 473 for (SearchTermCacheMap::iterator cache_iter = search_term_cache_.begin();
563 cache_iter != search_term_cache_.end(); ++cache_iter) { 474 cache_iter != search_term_cache_.end(); ++cache_iter) {
564 if (StartsWith(term, cache_iter->first, false) && 475 if (StartsWith(term, cache_iter->first, false) &&
565 (best_prefix == search_term_cache_.end() || 476 (best_prefix == search_term_cache_.end() ||
566 cache_iter->first.length() > best_prefix->first.length())) 477 cache_iter->first.length() > best_prefix->first.length()))
567 best_prefix = cache_iter; 478 best_prefix = cache_iter;
568 } 479 }
(...skipping 25 matching lines...) Expand all
594 505
595 // Filter for each remaining, unique character in the term. 506 // Filter for each remaining, unique character in the term.
596 Char16Set leftover_chars = Char16SetFromString16(leftovers); 507 Char16Set leftover_chars = Char16SetFromString16(leftovers);
597 Char16Set unique_chars; 508 Char16Set unique_chars;
598 std::set_difference(leftover_chars.begin(), leftover_chars.end(), 509 std::set_difference(leftover_chars.begin(), leftover_chars.end(),
599 prefix_chars.begin(), prefix_chars.end(), 510 prefix_chars.begin(), prefix_chars.end(),
600 std::inserter(unique_chars, unique_chars.begin())); 511 std::inserter(unique_chars, unique_chars.begin()));
601 512
602 // Reduce the word set with any leftover, unprocessed characters. 513 // Reduce the word set with any leftover, unprocessed characters.
603 if (!unique_chars.empty()) { 514 if (!unique_chars.empty()) {
604 WordIDSet leftover_set( 515 WordIDSet leftover_set(WordIDSetForTermChars(unique_chars));
605 private_data_->WordIDSetForTermChars(unique_chars));
606 // We might come up empty on the leftovers. 516 // We might come up empty on the leftovers.
607 if (leftover_set.empty()) { 517 if (leftover_set.empty()) {
608 search_term_cache_[term] = SearchTermCacheItem(); 518 search_term_cache_[term] = SearchTermCacheItem();
609 return HistoryIDSet(); 519 return HistoryIDSet();
610 } 520 }
611 // Or there may not have been a prefix from which to start. 521 // Or there may not have been a prefix from which to start.
612 if (prefix_chars.empty()) { 522 if (prefix_chars.empty()) {
613 word_id_set.swap(leftover_set); 523 word_id_set.swap(leftover_set);
614 } else { 524 } else {
615 WordIDSet new_word_id_set; 525 WordIDSet new_word_id_set;
616 std::set_intersection(word_id_set.begin(), word_id_set.end(), 526 std::set_intersection(word_id_set.begin(), word_id_set.end(),
617 leftover_set.begin(), leftover_set.end(), 527 leftover_set.begin(), leftover_set.end(),
618 std::inserter(new_word_id_set, 528 std::inserter(new_word_id_set,
619 new_word_id_set.begin())); 529 new_word_id_set.begin()));
620 word_id_set.swap(new_word_id_set); 530 word_id_set.swap(new_word_id_set);
621 } 531 }
622 } 532 }
623 533
624 // We must filter the word list because the resulting word set surely 534 // We must filter the word list because the resulting word set surely
625 // contains words which do not have the search term as a proper subset. 535 // contains words which do not have the search term as a proper subset.
626 for (WordIDSet::iterator word_set_iter = word_id_set.begin(); 536 for (WordIDSet::iterator word_set_iter = word_id_set.begin();
627 word_set_iter != word_id_set.end(); ) { 537 word_set_iter != word_id_set.end(); ) {
628 if (private_data_->word_list_[*word_set_iter].find(term) == 538 if (word_list_[*word_set_iter].find(term) == string16::npos)
629 string16::npos)
630 word_id_set.erase(word_set_iter++); 539 word_id_set.erase(word_set_iter++);
631 else 540 else
632 ++word_set_iter; 541 ++word_set_iter;
633 } 542 }
634 } else { 543 } else {
635 word_id_set = 544 word_id_set = WordIDSetForTermChars(Char16SetFromString16(term));
636 private_data_->WordIDSetForTermChars(Char16SetFromString16(term));
637 } 545 }
638 546
639 // If any words resulted then we can compose a set of history IDs by unioning 547 // If any words resulted then we can compose a set of history IDs by unioning
640 // the sets from each word. 548 // the sets from each word.
641 HistoryIDSet history_id_set; 549 HistoryIDSet history_id_set;
642 if (!word_id_set.empty()) { 550 if (!word_id_set.empty()) {
643 for (WordIDSet::iterator word_id_iter = word_id_set.begin(); 551 for (WordIDSet::iterator word_id_iter = word_id_set.begin();
644 word_id_iter != word_id_set.end(); ++word_id_iter) { 552 word_id_iter != word_id_set.end(); ++word_id_iter) {
645 WordID word_id = *word_id_iter; 553 WordID word_id = *word_id_iter;
646 WordIDHistoryMap::iterator word_iter = 554 WordIDHistoryMap::iterator word_iter = word_id_history_map_.find(word_id);
647 private_data_->word_id_history_map_.find(word_id); 555 if (word_iter != word_id_history_map_.end()) {
648 if (word_iter != private_data_->word_id_history_map_.end()) {
649 HistoryIDSet& word_history_id_set(word_iter->second); 556 HistoryIDSet& word_history_id_set(word_iter->second);
650 history_id_set.insert(word_history_id_set.begin(), 557 history_id_set.insert(word_history_id_set.begin(),
651 word_history_id_set.end()); 558 word_history_id_set.end());
652 } 559 }
653 } 560 }
654 } 561 }
655 562
656 // Record a new cache entry for this word if the term is longer than 563 // Record a new cache entry for this word if the term is longer than
657 // a single character. 564 // a single character.
658 if (term_length > 1) 565 if (term_length > 1)
659 search_term_cache_[term] = SearchTermCacheItem(word_id_set, history_id_set); 566 search_term_cache_[term] = SearchTermCacheItem(word_id_set, history_id_set);
660 567
661 return history_id_set; 568 return history_id_set;
662 } 569 }
663 570
664 // Utility Functions 571 // Utility Functions
665 572
573 // static
574 InMemoryURLIndex::String16Set InMemoryURLIndex::WordSetFromString16(
575 const string16& uni_string) {
576 const size_t kMaxWordLength = 64;
577 String16Vector words = WordVectorFromString16(uni_string, false);
578 String16Set word_set;
579 for (String16Vector::const_iterator iter = words.begin(); iter != words.end();
580 ++iter)
581 word_set.insert(base::i18n::ToLower(*iter).substr(0, kMaxWordLength));
582 return word_set;
583 }
584
585 // static
586 InMemoryURLIndex::String16Vector InMemoryURLIndex::WordVectorFromString16(
587 const string16& uni_string,
588 bool break_on_space) {
589 base::i18n::BreakIterator iter(
590 uni_string,
591 break_on_space ? base::i18n::BreakIterator::BREAK_SPACE
592 : base::i18n::BreakIterator::BREAK_WORD);
593 String16Vector words;
594 if (!iter.Init())
595 return words;
596 while (iter.Advance()) {
597 if (break_on_space || iter.IsWord()) {
598 string16 word = iter.GetString();
599 if (break_on_space)
600 TrimWhitespace(word, TRIM_ALL, &word);
601 if (!word.empty())
602 words.push_back(word);
603 }
604 }
605 return words;
606 }
607
608 // static
609 InMemoryURLIndex::Char16Set InMemoryURLIndex::Char16SetFromString16(
610 const string16& term) {
611 Char16Set characters;
612 for (string16::const_iterator iter = term.begin(); iter != term.end();
613 ++iter)
614 characters.insert(*iter);
615 return characters;
616 }
617
666 void InMemoryURLIndex::AddWordToIndex(const string16& term, 618 void InMemoryURLIndex::AddWordToIndex(const string16& term,
667 HistoryID history_id) { 619 HistoryID history_id) {
668 WordMap::iterator word_pos = private_data_->word_map_.find(term); 620 WordMap::iterator word_pos = word_map_.find(term);
669 if (word_pos != private_data_->word_map_.end()) 621 if (word_pos != word_map_.end())
670 UpdateWordHistory(word_pos->second, history_id); 622 UpdateWordHistory(word_pos->second, history_id);
671 else 623 else
672 AddWordHistory(term, history_id); 624 AddWordHistory(term, history_id);
673 } 625 }
674 626
675 void InMemoryURLIndex::UpdateWordHistory(WordID word_id, HistoryID history_id) { 627 void InMemoryURLIndex::UpdateWordHistory(WordID word_id, HistoryID history_id) {
676 WordIDHistoryMap::iterator history_pos = 628 WordIDHistoryMap::iterator history_pos = word_id_history_map_.find(word_id);
677 private_data_->word_id_history_map_.find(word_id); 629 DCHECK(history_pos != word_id_history_map_.end());
678 DCHECK(history_pos != private_data_->word_id_history_map_.end()); 630 HistoryIDSet& history_id_set(history_pos->second);
679 HistoryIDSet& history_id_set(history_pos->second); 631 history_id_set.insert(history_id);
680 history_id_set.insert(history_id);
681 private_data_->AddToHistoryIDWordMap(history_id, word_id);
682 } 632 }
683 633
684 // Add a new word to the word list and the word map, and then create a 634 // Add a new word to the word list and the word map, and then create a
685 // new entry in the word/history map. 635 // new entry in the word/history map.
686 void InMemoryURLIndex::AddWordHistory(const string16& term, 636 void InMemoryURLIndex::AddWordHistory(const string16& term,
687 HistoryID history_id) { 637 HistoryID history_id) {
688 URLIndexPrivateData& private_data(*(private_data_.get())); 638 word_list_.push_back(term);
689 WordID word_id = private_data.word_list_.size(); 639 WordID word_id = word_list_.size() - 1;
690 if (private_data.available_words_.empty()) { 640 word_map_[term] = word_id;
691 private_data.word_list_.push_back(term);
692 } else {
693 word_id = *(private_data.available_words_.begin());
694 private_data.word_list_[word_id] = term;
695 private_data.available_words_.erase(word_id);
696 }
697 private_data.word_map_[term] = word_id;
698
699 HistoryIDSet history_id_set; 641 HistoryIDSet history_id_set;
700 history_id_set.insert(history_id); 642 history_id_set.insert(history_id);
701 private_data.word_id_history_map_[word_id] = history_id_set; 643 word_id_history_map_[word_id] = history_id_set;
702 private_data_->AddToHistoryIDWordMap(history_id, word_id);
703
704 // For each character in the newly added word (i.e. a word that is not 644 // For each character in the newly added word (i.e. a word that is not
705 // already in the word index), add the word to the character index. 645 // already in the word index), add the word to the character index.
706 Char16Set characters = Char16SetFromString16(term); 646 Char16Set characters = Char16SetFromString16(term);
707 for (Char16Set::iterator uni_char_iter = characters.begin(); 647 for (Char16Set::iterator uni_char_iter = characters.begin();
708 uni_char_iter != characters.end(); ++uni_char_iter) { 648 uni_char_iter != characters.end(); ++uni_char_iter) {
709 char16 uni_char = *uni_char_iter; 649 char16 uni_char = *uni_char_iter;
710 CharWordIDMap::iterator char_iter = 650 CharWordIDMap::iterator char_iter = char_word_map_.find(uni_char);
711 private_data.char_word_map_.find(uni_char); 651 if (char_iter != char_word_map_.end()) {
712 if (char_iter != private_data.char_word_map_.end()) {
713 // Update existing entry in the char/word index. 652 // Update existing entry in the char/word index.
714 WordIDSet& word_id_set(char_iter->second); 653 WordIDSet& word_id_set(char_iter->second);
715 word_id_set.insert(word_id); 654 word_id_set.insert(word_id);
716 } else { 655 } else {
717 // Create a new entry in the char/word index. 656 // Create a new entry in the char/word index.
718 WordIDSet word_id_set; 657 WordIDSet word_id_set;
719 word_id_set.insert(word_id); 658 word_id_set.insert(word_id);
720 private_data.char_word_map_[uni_char] = word_id_set; 659 char_word_map_[uni_char] = word_id_set;
721 } 660 }
722 } 661 }
723 } 662 }
724 663
664 InMemoryURLIndex::WordIDSet InMemoryURLIndex::WordIDSetForTermChars(
665 const Char16Set& term_chars) {
666 WordIDSet word_id_set;
667 for (Char16Set::const_iterator c_iter = term_chars.begin();
668 c_iter != term_chars.end(); ++c_iter) {
669 CharWordIDMap::iterator char_iter = char_word_map_.find(*c_iter);
670 if (char_iter == char_word_map_.end()) {
671 // A character was not found so there are no matching results: bail.
672 word_id_set.clear();
673 break;
674 }
675 WordIDSet& char_word_id_set(char_iter->second);
676 // It is possible for there to no longer be any words associated with
677 // a particular character. Give up in that case.
678 if (char_word_id_set.empty()) {
679 word_id_set.clear();
680 break;
681 }
682
683 if (c_iter == term_chars.begin()) {
684 // First character results becomes base set of results.
685 word_id_set = char_word_id_set;
686 } else {
687 // Subsequent character results get intersected in.
688 WordIDSet new_word_id_set;
689 std::set_intersection(word_id_set.begin(), word_id_set.end(),
690 char_word_id_set.begin(), char_word_id_set.end(),
691 std::inserter(new_word_id_set,
692 new_word_id_set.begin()));
693 word_id_set.swap(new_word_id_set);
694 }
695 }
696 return word_id_set;
697 }
698
725 // static 699 // static
726 // TODO(mrossetti): This can be made a ctor for ScoredHistoryMatch. 700 TermMatches InMemoryURLIndex::MatchTermInString(const string16& term,
701 const string16& string,
702 int term_num) {
703 const size_t kMaxCompareLength = 2048;
704 const string16& short_string = (string.length() > kMaxCompareLength) ?
705 string.substr(0, kMaxCompareLength) : string;
706 TermMatches matches;
707 for (size_t location = short_string.find(term); location != string16::npos;
708 location = short_string.find(term, location + 1)) {
709 matches.push_back(TermMatch(term_num, location, term.length()));
710 }
711 return matches;
712 }
713
714 // static
715 TermMatches InMemoryURLIndex::SortAndDeoverlap(const TermMatches& matches) {
716 if (matches.empty())
717 return matches;
718 TermMatches sorted_matches = matches;
719 std::sort(sorted_matches.begin(), sorted_matches.end(), MatchOffsetLess);
720 TermMatches clean_matches;
721 TermMatch last_match = sorted_matches[0];
722 clean_matches.push_back(last_match);
723 for (TermMatches::const_iterator iter = sorted_matches.begin() + 1;
724 iter != sorted_matches.end(); ++iter) {
725 if (iter->offset >= last_match.offset + last_match.length) {
726 last_match = *iter;
727 clean_matches.push_back(last_match);
728 }
729 }
730 return clean_matches;
731 }
732
733 // static
734 std::vector<size_t> InMemoryURLIndex::OffsetsFromTermMatches(
735 const TermMatches& matches) {
736 std::vector<size_t> offsets;
737 for (TermMatches::const_iterator i = matches.begin(); i != matches.end(); ++i)
738 offsets.push_back(i->offset);
739 return offsets;
740 }
741
742 // static
743 TermMatches InMemoryURLIndex::ReplaceOffsetsInTermMatches(
744 const TermMatches& matches,
745 const std::vector<size_t>& offsets) {
746 DCHECK_EQ(matches.size(), offsets.size());
747 TermMatches new_matches;
748 std::vector<size_t>::const_iterator offset_iter = offsets.begin();
749 for (TermMatches::const_iterator term_iter = matches.begin();
750 term_iter != matches.end(); ++term_iter, ++offset_iter) {
751 if (*offset_iter != string16::npos) {
752 TermMatch new_match(*term_iter);
753 new_match.offset = *offset_iter;
754 new_matches.push_back(new_match);
755 }
756 }
757 return new_matches;
758 }
759
760 // static
727 ScoredHistoryMatch InMemoryURLIndex::ScoredMatchForURL( 761 ScoredHistoryMatch InMemoryURLIndex::ScoredMatchForURL(
728 const URLRow& row, 762 const URLRow& row,
729 const String16Vector& terms) { 763 const String16Vector& terms) {
730 ScoredHistoryMatch match(row); 764 ScoredHistoryMatch match(row);
731 GURL gurl = row.url(); 765 GURL gurl = row.url();
732 if (!gurl.is_valid()) 766 if (!gurl.is_valid())
733 return match; 767 return match;
734 768
735 // Figure out where each search term appears in the URL and/or page title 769 // Figure out where each search term appears in the URL and/or page title
736 // so that we can score as well as provide autocomplete highlighting. 770 // so that we can score as well as provide autocomplete highlighting.
737 string16 url = base::i18n::ToLower(UTF8ToUTF16(gurl.spec())); 771 string16 url = base::i18n::ToLower(UTF8ToUTF16(gurl.spec()));
738 string16 title = base::i18n::ToLower(row.title()); 772 string16 title = base::i18n::ToLower(row.title());
739 int term_num = 0; 773 int term_num = 0;
740 for (String16Vector::const_iterator iter = terms.begin(); iter != terms.end(); 774 for (String16Vector::const_iterator iter = terms.begin(); iter != terms.end();
741 ++iter, ++term_num) { 775 ++iter, ++term_num) {
742 string16 term = *iter; 776 string16 term = *iter;
743 TermMatches url_term_matches = MatchTermInString(term, url, term_num); 777 TermMatches url_term_matches = MatchTermInString(term, url, term_num);
744 TermMatches title_term_matches = MatchTermInString(term, title, term_num); 778 TermMatches title_term_matches = MatchTermInString(term, title, term_num);
745 if (url_term_matches.empty() && title_term_matches.empty()) 779 if (url_term_matches.empty() && title_term_matches.empty())
746 return match; // A term was not found in either URL or title - reject. 780 return match; // A term was not found in either URL or title - reject.
747 match.url_matches.insert(match.url_matches.end(), url_term_matches.begin(), 781 match.url_matches.insert(match.url_matches.end(), url_term_matches.begin(),
748 url_term_matches.end()); 782 url_term_matches.end());
749 match.title_matches.insert(match.title_matches.end(), 783 match.title_matches.insert(match.title_matches.end(),
750 title_term_matches.begin(), 784 title_term_matches.begin(),
751 title_term_matches.end()); 785 title_term_matches.end());
752 } 786 }
753 787
754 // Sort matches by offset and eliminate any which overlap. 788 // Sort matches by offset and eliminate any which overlap.
755 match.url_matches = SortAndDeoverlapMatches(match.url_matches); 789 match.url_matches = SortAndDeoverlap(match.url_matches);
756 match.title_matches = SortAndDeoverlapMatches(match.title_matches); 790 match.title_matches = SortAndDeoverlap(match.title_matches);
757 791
758 // We should not (currently) inline autocomplete a result unless both of the 792 // We should not (currently) inline autocomplete a result unless both of the
759 // following are true: 793 // following are true:
760 // * There is exactly one substring matches in the URL, and 794 // * There is exactly one substring matches in the URL, and
761 // * The one URL match starts at the beginning of the URL. 795 // * The one URL match starts at the beginning of the URL.
762 match.can_inline = 796 match.can_inline =
763 match.url_matches.size() == 1 && match.url_matches[0].offset == 0; 797 match.url_matches.size() == 1 && match.url_matches[0].offset == 0;
764 798
765 // Get partial scores based on term matching. Note that the score for 799 // Get partial scores based on term matching. Note that the score for
766 // each of the URL and title are adjusted by the fraction of the 800 // each of the URL and title are adjusted by the fraction of the
(...skipping 31 matching lines...) Expand 10 before | Expand all | Expand 10 after
798 int factor[] = {term_score, days_ago_value, visit_count_value, 832 int factor[] = {term_score, days_ago_value, visit_count_value,
799 visit_count_value, typed_count_value, typed_count_value, 833 visit_count_value, typed_count_value, typed_count_value,
800 typed_count_value}; 834 typed_count_value};
801 const int kInsignificantFactors = 2; 835 const int kInsignificantFactors = 2;
802 const int kSignificantFactors = arraysize(factor) - kInsignificantFactors; 836 const int kSignificantFactors = arraysize(factor) - kInsignificantFactors;
803 std::partial_sort(factor, factor + kSignificantFactors, 837 std::partial_sort(factor, factor + kSignificantFactors,
804 factor + arraysize(factor), std::greater<int>()); 838 factor + arraysize(factor), std::greater<int>());
805 for (int i = 0; i < kSignificantFactors; ++i) 839 for (int i = 0; i < kSignificantFactors; ++i)
806 match.raw_score += factor[i]; 840 match.raw_score += factor[i];
807 match.raw_score /= kSignificantFactors; 841 match.raw_score /= kSignificantFactors;
842
808 return match; 843 return match;
809 } 844 }
810 845
811 int InMemoryURLIndex::ScoreComponentForMatches(const TermMatches& matches, 846 int InMemoryURLIndex::ScoreComponentForMatches(const TermMatches& matches,
812 size_t max_length) { 847 size_t max_length) {
813 // TODO(mrossetti): This is good enough for now but must be fine-tuned. 848 // TODO(mrossetti): This is good enough for now but must be fine-tuned.
814 if (matches.empty()) 849 if (matches.empty())
815 return 0; 850 return 0;
816 851
817 // Score component for whether the input terms (if more than one) were found 852 // Score component for whether the input terms (if more than one) were found
(...skipping 41 matching lines...) Expand 10 before | Expand all | Expand 10 after
859 894
860 // Scale the sum of the three components above into a single score component 895 // Scale the sum of the three components above into a single score component
861 // on the same scale as that used in ScoredMatchForURL(). 896 // on the same scale as that used in ScoredMatchForURL().
862 return ScoreForValue(raw_score, kTermScoreLevel); 897 return ScoreForValue(raw_score, kTermScoreLevel);
863 } 898 }
864 899
865 InMemoryURLIndex::AddHistoryMatch::AddHistoryMatch( 900 InMemoryURLIndex::AddHistoryMatch::AddHistoryMatch(
866 const InMemoryURLIndex& index, 901 const InMemoryURLIndex& index,
867 const String16Vector& lower_terms) 902 const String16Vector& lower_terms)
868 : index_(index), 903 : index_(index),
869 lower_terms_(lower_terms) {} 904 lower_terms_(lower_terms) {
905 }
870 906
871 InMemoryURLIndex::AddHistoryMatch::~AddHistoryMatch() {} 907 InMemoryURLIndex::AddHistoryMatch::~AddHistoryMatch() {}
872 908
873 void InMemoryURLIndex::AddHistoryMatch::operator()(const HistoryID history_id) { 909 void InMemoryURLIndex::AddHistoryMatch::operator()(
910 const InMemoryURLIndex::HistoryID history_id) {
874 HistoryInfoMap::const_iterator hist_pos = 911 HistoryInfoMap::const_iterator hist_pos =
875 index_.private_data_->history_info_map_.find(history_id); 912 index_.history_info_map_.find(history_id);
876 // Note that a history_id may be present in the word_id_history_map_ yet not 913 // Note that a history_id may be present in the word_id_history_map_ yet not
877 // be found in the history_info_map_. This occurs when an item has been 914 // be found in the history_info_map_. This occurs when an item has been
878 // deleted by the user or the item no longer qualifies as a quick result. 915 // deleted by the user or the item no longer qualifies as a quick result.
879 if (hist_pos != index_.private_data_->history_info_map_.end()) { 916 if (hist_pos != index_.history_info_map_.end()) {
880 const URLRow& hist_item = hist_pos->second; 917 const URLRow& hist_item = hist_pos->second;
881 ScoredHistoryMatch match(ScoredMatchForURL(hist_item, lower_terms_)); 918 ScoredHistoryMatch match(ScoredMatchForURL(hist_item, lower_terms_));
882 if (match.raw_score > 0) 919 if (match.raw_score > 0)
883 scored_matches_.push_back(match); 920 scored_matches_.push_back(match);
884 } 921 }
885 } 922 }
886 923
887 bool InMemoryURLIndex::GetCacheFilePath(FilePath* file_path) { 924 bool InMemoryURLIndex::GetCacheFilePath(FilePath* file_path) {
888 if (history_dir_.empty()) 925 if (history_dir_.empty())
889 return false; 926 return false;
890 *file_path = history_dir_.Append(FILE_PATH_LITERAL("History Provider Cache")); 927 *file_path = history_dir_.Append(FILE_PATH_LITERAL("History Provider Cache"));
891 return true; 928 return true;
892 } 929 }
893 930
894 bool InMemoryURLIndex::URLSchemeIsWhitelisted(const GURL& gurl) const { 931 bool InMemoryURLIndex::URLSchemeIsWhitelisted(const GURL& gurl) const {
895 return scheme_whitelist_.find(gurl.scheme()) != scheme_whitelist_.end(); 932 return scheme_whitelist_.find(gurl.scheme()) != scheme_whitelist_.end();
896 } 933 }
897 934
898 void InMemoryURLIndex::SavePrivateData(InMemoryURLIndexCacheItem* cache) const { 935 void InMemoryURLIndex::SavePrivateData(InMemoryURLIndexCacheItem* cache) const {
899 DCHECK(cache); 936 DCHECK(cache);
900 cache->set_timestamp(base::Time::Now().ToInternalValue()); 937 cache->set_timestamp(base::Time::Now().ToInternalValue());
901 // history_item_count_ is no longer used but rather than change the protobuf 938 cache->set_history_item_count(history_item_count_);
902 // definition use a placeholder. This will go away with the switch to SQLite.
903 cache->set_history_item_count(0);
904 SaveWordList(cache); 939 SaveWordList(cache);
905 SaveWordMap(cache); 940 SaveWordMap(cache);
906 SaveCharWordMap(cache); 941 SaveCharWordMap(cache);
907 SaveWordIDHistoryMap(cache); 942 SaveWordIDHistoryMap(cache);
908 SaveHistoryInfoMap(cache); 943 SaveHistoryInfoMap(cache);
909 } 944 }
910 945
911 bool InMemoryURLIndex::RestorePrivateData( 946 bool InMemoryURLIndex::RestorePrivateData(
912 const InMemoryURLIndexCacheItem& cache) { 947 const InMemoryURLIndexCacheItem& cache) {
913 last_saved_ = base::Time::FromInternalValue(cache.timestamp()); 948 last_saved_ = base::Time::FromInternalValue(cache.timestamp());
914 return RestoreWordList(cache) && RestoreWordMap(cache) && 949 history_item_count_ = cache.history_item_count();
915 RestoreCharWordMap(cache) && RestoreWordIDHistoryMap(cache) && 950 return (history_item_count_ == 0) || (RestoreWordList(cache) &&
916 RestoreHistoryInfoMap(cache); 951 RestoreWordMap(cache) && RestoreCharWordMap(cache) &&
952 RestoreWordIDHistoryMap(cache) && RestoreHistoryInfoMap(cache));
917 } 953 }
918 954
955
919 void InMemoryURLIndex::SaveWordList(InMemoryURLIndexCacheItem* cache) const { 956 void InMemoryURLIndex::SaveWordList(InMemoryURLIndexCacheItem* cache) const {
920 if (private_data_->word_list_.empty()) 957 if (word_list_.empty())
921 return; 958 return;
922 WordListItem* list_item = cache->mutable_word_list(); 959 WordListItem* list_item = cache->mutable_word_list();
923 list_item->set_word_count(private_data_->word_list_.size()); 960 list_item->set_word_count(word_list_.size());
924 for (String16Vector::const_iterator iter = private_data_->word_list_.begin(); 961 for (String16Vector::const_iterator iter = word_list_.begin();
925 iter != private_data_->word_list_.end(); ++iter) 962 iter != word_list_.end(); ++iter)
926 list_item->add_word(UTF16ToUTF8(*iter)); 963 list_item->add_word(UTF16ToUTF8(*iter));
927 } 964 }
928 965
929 bool InMemoryURLIndex::RestoreWordList(const InMemoryURLIndexCacheItem& cache) { 966 bool InMemoryURLIndex::RestoreWordList(const InMemoryURLIndexCacheItem& cache) {
930 if (!cache.has_word_list()) 967 if (!cache.has_word_list())
931 return false; 968 return false;
932 const WordListItem& list_item(cache.word_list()); 969 const WordListItem& list_item(cache.word_list());
933 uint32 expected_item_count = list_item.word_count(); 970 uint32 expected_item_count = list_item.word_count();
934 uint32 actual_item_count = list_item.word_size(); 971 uint32 actual_item_count = list_item.word_size();
935 if (actual_item_count == 0 || actual_item_count != expected_item_count) 972 if (actual_item_count == 0 || actual_item_count != expected_item_count)
936 return false; 973 return false;
937 const RepeatedPtrField<std::string>& words(list_item.word()); 974 const RepeatedPtrField<std::string>& words(list_item.word());
938 for (RepeatedPtrField<std::string>::const_iterator iter = words.begin(); 975 for (RepeatedPtrField<std::string>::const_iterator iter = words.begin();
939 iter != words.end(); ++iter) 976 iter != words.end(); ++iter)
940 private_data_->word_list_.push_back(UTF8ToUTF16(*iter)); 977 word_list_.push_back(UTF8ToUTF16(*iter));
941 return true; 978 return true;
942 } 979 }
943 980
944 void InMemoryURLIndex::SaveWordMap(InMemoryURLIndexCacheItem* cache) const { 981 void InMemoryURLIndex::SaveWordMap(InMemoryURLIndexCacheItem* cache) const {
945 if (private_data_->word_map_.empty()) 982 if (word_map_.empty())
946 return; 983 return;
947 WordMapItem* map_item = cache->mutable_word_map(); 984 WordMapItem* map_item = cache->mutable_word_map();
948 map_item->set_item_count(private_data_->word_map_.size()); 985 map_item->set_item_count(word_map_.size());
949 for (WordMap::const_iterator iter = private_data_->word_map_.begin(); 986 for (WordMap::const_iterator iter = word_map_.begin();
950 iter != private_data_->word_map_.end(); ++iter) { 987 iter != word_map_.end(); ++iter) {
951 WordMapEntry* map_entry = map_item->add_word_map_entry(); 988 WordMapEntry* map_entry = map_item->add_word_map_entry();
952 map_entry->set_word(UTF16ToUTF8(iter->first)); 989 map_entry->set_word(UTF16ToUTF8(iter->first));
953 map_entry->set_word_id(iter->second); 990 map_entry->set_word_id(iter->second);
954 } 991 }
955 } 992 }
956 993
957 bool InMemoryURLIndex::RestoreWordMap(const InMemoryURLIndexCacheItem& cache) { 994 bool InMemoryURLIndex::RestoreWordMap(const InMemoryURLIndexCacheItem& cache) {
958 if (!cache.has_word_map()) 995 if (!cache.has_word_map())
959 return false; 996 return false;
960 const WordMapItem& list_item(cache.word_map()); 997 const WordMapItem& list_item(cache.word_map());
961 uint32 expected_item_count = list_item.item_count(); 998 uint32 expected_item_count = list_item.item_count();
962 uint32 actual_item_count = list_item.word_map_entry_size(); 999 uint32 actual_item_count = list_item.word_map_entry_size();
963 if (actual_item_count == 0 || actual_item_count != expected_item_count) 1000 if (actual_item_count == 0 || actual_item_count != expected_item_count)
964 return false; 1001 return false;
965 const RepeatedPtrField<WordMapEntry>& entries(list_item.word_map_entry()); 1002 const RepeatedPtrField<WordMapEntry>& entries(list_item.word_map_entry());
966 for (RepeatedPtrField<WordMapEntry>::const_iterator iter = entries.begin(); 1003 for (RepeatedPtrField<WordMapEntry>::const_iterator iter = entries.begin();
967 iter != entries.end(); ++iter) 1004 iter != entries.end(); ++iter)
968 private_data_->word_map_[UTF8ToUTF16(iter->word())] = iter->word_id(); 1005 word_map_[UTF8ToUTF16(iter->word())] = iter->word_id();
969 return true; 1006 return true;
970 } 1007 }
971 1008
972 void InMemoryURLIndex::SaveCharWordMap(InMemoryURLIndexCacheItem* cache) const { 1009 void InMemoryURLIndex::SaveCharWordMap(InMemoryURLIndexCacheItem* cache) const {
973 if (private_data_->char_word_map_.empty()) 1010 if (char_word_map_.empty())
974 return; 1011 return;
975 CharWordMapItem* map_item = cache->mutable_char_word_map(); 1012 CharWordMapItem* map_item = cache->mutable_char_word_map();
976 map_item->set_item_count(private_data_->char_word_map_.size()); 1013 map_item->set_item_count(char_word_map_.size());
977 for (CharWordIDMap::const_iterator iter = 1014 for (CharWordIDMap::const_iterator iter = char_word_map_.begin();
978 private_data_->char_word_map_.begin(); 1015 iter != char_word_map_.end(); ++iter) {
979 iter != private_data_->char_word_map_.end(); ++iter) {
980 CharWordMapEntry* map_entry = map_item->add_char_word_map_entry(); 1016 CharWordMapEntry* map_entry = map_item->add_char_word_map_entry();
981 map_entry->set_char_16(iter->first); 1017 map_entry->set_char_16(iter->first);
982 const WordIDSet& word_id_set(iter->second); 1018 const WordIDSet& word_id_set(iter->second);
983 map_entry->set_item_count(word_id_set.size()); 1019 map_entry->set_item_count(word_id_set.size());
984 for (WordIDSet::const_iterator set_iter = word_id_set.begin(); 1020 for (WordIDSet::const_iterator set_iter = word_id_set.begin();
985 set_iter != word_id_set.end(); ++set_iter) 1021 set_iter != word_id_set.end(); ++set_iter)
986 map_entry->add_word_id(*set_iter); 1022 map_entry->add_word_id(*set_iter);
987 } 1023 }
988 } 1024 }
989 1025
(...skipping 13 matching lines...) Expand all
1003 expected_item_count = iter->item_count(); 1039 expected_item_count = iter->item_count();
1004 actual_item_count = iter->word_id_size(); 1040 actual_item_count = iter->word_id_size();
1005 if (actual_item_count == 0 || actual_item_count != expected_item_count) 1041 if (actual_item_count == 0 || actual_item_count != expected_item_count)
1006 return false; 1042 return false;
1007 char16 uni_char = static_cast<char16>(iter->char_16()); 1043 char16 uni_char = static_cast<char16>(iter->char_16());
1008 WordIDSet word_id_set; 1044 WordIDSet word_id_set;
1009 const RepeatedField<int32>& word_ids(iter->word_id()); 1045 const RepeatedField<int32>& word_ids(iter->word_id());
1010 for (RepeatedField<int32>::const_iterator jiter = word_ids.begin(); 1046 for (RepeatedField<int32>::const_iterator jiter = word_ids.begin();
1011 jiter != word_ids.end(); ++jiter) 1047 jiter != word_ids.end(); ++jiter)
1012 word_id_set.insert(*jiter); 1048 word_id_set.insert(*jiter);
1013 private_data_->char_word_map_[uni_char] = word_id_set; 1049 char_word_map_[uni_char] = word_id_set;
1014 } 1050 }
1015 return true; 1051 return true;
1016 } 1052 }
1017 1053
1018 void InMemoryURLIndex::SaveWordIDHistoryMap(InMemoryURLIndexCacheItem* cache) 1054 void InMemoryURLIndex::SaveWordIDHistoryMap(InMemoryURLIndexCacheItem* cache)
1019 const { 1055 const {
1020 if (private_data_->word_id_history_map_.empty()) 1056 if (word_id_history_map_.empty())
1021 return; 1057 return;
1022 WordIDHistoryMapItem* map_item = cache->mutable_word_id_history_map(); 1058 WordIDHistoryMapItem* map_item = cache->mutable_word_id_history_map();
1023 map_item->set_item_count(private_data_->word_id_history_map_.size()); 1059 map_item->set_item_count(word_id_history_map_.size());
1024 for (WordIDHistoryMap::const_iterator iter = 1060 for (WordIDHistoryMap::const_iterator iter = word_id_history_map_.begin();
1025 private_data_->word_id_history_map_.begin(); 1061 iter != word_id_history_map_.end(); ++iter) {
1026 iter != private_data_->word_id_history_map_.end(); ++iter) {
1027 WordIDHistoryMapEntry* map_entry = 1062 WordIDHistoryMapEntry* map_entry =
1028 map_item->add_word_id_history_map_entry(); 1063 map_item->add_word_id_history_map_entry();
1029 map_entry->set_word_id(iter->first); 1064 map_entry->set_word_id(iter->first);
1030 const HistoryIDSet& history_id_set(iter->second); 1065 const HistoryIDSet& history_id_set(iter->second);
1031 map_entry->set_item_count(history_id_set.size()); 1066 map_entry->set_item_count(history_id_set.size());
1032 for (HistoryIDSet::const_iterator set_iter = history_id_set.begin(); 1067 for (HistoryIDSet::const_iterator set_iter = history_id_set.begin();
1033 set_iter != history_id_set.end(); ++set_iter) 1068 set_iter != history_id_set.end(); ++set_iter)
1034 map_entry->add_history_id(*set_iter); 1069 map_entry->add_history_id(*set_iter);
1035 } 1070 }
1036 } 1071 }
(...skipping 12 matching lines...) Expand all
1049 for (RepeatedPtrField<WordIDHistoryMapEntry>::const_iterator iter = 1084 for (RepeatedPtrField<WordIDHistoryMapEntry>::const_iterator iter =
1050 entries.begin(); iter != entries.end(); ++iter) { 1085 entries.begin(); iter != entries.end(); ++iter) {
1051 expected_item_count = iter->item_count(); 1086 expected_item_count = iter->item_count();
1052 actual_item_count = iter->history_id_size(); 1087 actual_item_count = iter->history_id_size();
1053 if (actual_item_count == 0 || actual_item_count != expected_item_count) 1088 if (actual_item_count == 0 || actual_item_count != expected_item_count)
1054 return false; 1089 return false;
1055 WordID word_id = iter->word_id(); 1090 WordID word_id = iter->word_id();
1056 HistoryIDSet history_id_set; 1091 HistoryIDSet history_id_set;
1057 const RepeatedField<int64>& history_ids(iter->history_id()); 1092 const RepeatedField<int64>& history_ids(iter->history_id());
1058 for (RepeatedField<int64>::const_iterator jiter = history_ids.begin(); 1093 for (RepeatedField<int64>::const_iterator jiter = history_ids.begin();
1059 jiter != history_ids.end(); ++jiter) { 1094 jiter != history_ids.end(); ++jiter)
1060 history_id_set.insert(*jiter); 1095 history_id_set.insert(*jiter);
1061 private_data_->AddToHistoryIDWordMap(*jiter, word_id); 1096 word_id_history_map_[word_id] = history_id_set;
1062 }
1063 private_data_->word_id_history_map_[word_id] = history_id_set;
1064 } 1097 }
1065 return true; 1098 return true;
1066 } 1099 }
1067 1100
1068 void InMemoryURLIndex::SaveHistoryInfoMap( 1101 void InMemoryURLIndex::SaveHistoryInfoMap(
1069 InMemoryURLIndexCacheItem* cache) const { 1102 InMemoryURLIndexCacheItem* cache) const {
1070 if (private_data_->history_info_map_.empty()) 1103 if (history_info_map_.empty())
1071 return; 1104 return;
1072 HistoryInfoMapItem* map_item = cache->mutable_history_info_map(); 1105 HistoryInfoMapItem* map_item = cache->mutable_history_info_map();
1073 map_item->set_item_count(private_data_->history_info_map_.size()); 1106 map_item->set_item_count(history_info_map_.size());
1074 for (HistoryInfoMap::const_iterator iter = 1107 for (HistoryInfoMap::const_iterator iter = history_info_map_.begin();
1075 private_data_->history_info_map_.begin(); 1108 iter != history_info_map_.end(); ++iter) {
1076 iter != private_data_->history_info_map_.end(); ++iter) {
1077 HistoryInfoMapEntry* map_entry = map_item->add_history_info_map_entry(); 1109 HistoryInfoMapEntry* map_entry = map_item->add_history_info_map_entry();
1078 map_entry->set_history_id(iter->first); 1110 map_entry->set_history_id(iter->first);
1079 const URLRow& url_row(iter->second); 1111 const URLRow& url_row(iter->second);
1080 // Note: We only save information that contributes to the index so there 1112 // Note: We only save information that contributes to the index so there
1081 // is no need to save search_term_cache_ (not persistent), 1113 // is no need to save search_term_cache_ (not persistent),
1082 // languages_, etc. 1114 // languages_, etc.
1083 map_entry->set_visit_count(url_row.visit_count()); 1115 map_entry->set_visit_count(url_row.visit_count());
1084 map_entry->set_typed_count(url_row.typed_count()); 1116 map_entry->set_typed_count(url_row.typed_count());
1085 map_entry->set_last_visit(url_row.last_visit().ToInternalValue()); 1117 map_entry->set_last_visit(url_row.last_visit().ToInternalValue());
1086 map_entry->set_url(url_row.url().spec()); 1118 map_entry->set_url(url_row.url().spec());
(...skipping 17 matching lines...) Expand all
1104 HistoryID history_id = iter->history_id(); 1136 HistoryID history_id = iter->history_id();
1105 GURL url(iter->url()); 1137 GURL url(iter->url());
1106 URLRow url_row(url, history_id); 1138 URLRow url_row(url, history_id);
1107 url_row.set_visit_count(iter->visit_count()); 1139 url_row.set_visit_count(iter->visit_count());
1108 url_row.set_typed_count(iter->typed_count()); 1140 url_row.set_typed_count(iter->typed_count());
1109 url_row.set_last_visit(base::Time::FromInternalValue(iter->last_visit())); 1141 url_row.set_last_visit(base::Time::FromInternalValue(iter->last_visit()));
1110 if (iter->has_title()) { 1142 if (iter->has_title()) {
1111 string16 title(UTF8ToUTF16(iter->title())); 1143 string16 title(UTF8ToUTF16(iter->title()));
1112 url_row.set_title(title); 1144 url_row.set_title(title);
1113 } 1145 }
1114 private_data_->history_info_map_[history_id] = url_row; 1146 history_info_map_[history_id] = url_row;
1115 } 1147 }
1116 return true; 1148 return true;
1117 } 1149 }
1118 1150
1119 } // namespace history 1151 } // namespace history
OLDNEW
« no previous file with comments | « chrome/browser/history/in_memory_url_index.h ('k') | chrome/browser/history/in_memory_url_index_types.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698