OLD | NEW |
---|---|
1 // Copyright 2017 The Chromium Authors. All rights reserved. | 1 // Copyright 2017 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 "components/history/core/browser/typed_url_sync_bridge.h" | 5 #include "components/history/core/browser/typed_url_sync_bridge.h" |
6 | 6 |
7 #include "base/big_endian.h" | 7 #include "base/big_endian.h" |
8 #include "base/memory/ptr_util.h" | 8 #include "base/memory/ptr_util.h" |
9 #include "base/metrics/histogram_macros.h" | 9 #include "base/metrics/histogram_macros.h" |
10 #include "base/strings/utf_string_conversions.h" | 10 #include "base/strings/utf_string_conversions.h" |
(...skipping 18 matching lines...) Expand all Loading... | |
29 // the size under control we limit the visit array. | 29 // the size under control we limit the visit array. |
30 static const int kMaxTypedUrlVisits = 100; | 30 static const int kMaxTypedUrlVisits = 100; |
31 | 31 |
32 // There's no limit on how many visits the history DB could have for a given | 32 // There's no limit on how many visits the history DB could have for a given |
33 // typed URL, so we limit how many we fetch from the DB to avoid crashes due to | 33 // typed URL, so we limit how many we fetch from the DB to avoid crashes due to |
34 // running out of memory (http://crbug.com/89793). This value is different | 34 // running out of memory (http://crbug.com/89793). This value is different |
35 // from kMaxTypedUrlVisits, as some of the visits fetched from the DB may be | 35 // from kMaxTypedUrlVisits, as some of the visits fetched from the DB may be |
36 // RELOAD visits, which will be stripped. | 36 // RELOAD visits, which will be stripped. |
37 static const int kMaxVisitsToFetch = 1000; | 37 static const int kMaxVisitsToFetch = 1000; |
38 | 38 |
39 // This is the threshold at which we start throttling sync updates for typed | |
40 // URLs - any URLs with a typed_count >= this threshold will be throttled. | |
41 static const int kTypedUrlVisitThrottleThreshold = 10; | |
42 | |
43 // This is the multiple we use when throttling sync updates. If the multiple is | |
44 // N, we sync up every Nth update (i.e. when typed_count % N == 0). | |
45 static const int kTypedUrlVisitThrottleMultiple = 10; | |
46 | |
39 // Enforce oldest to newest visit order. | 47 // Enforce oldest to newest visit order. |
40 static bool CheckVisitOrdering(const VisitVector& visits) { | 48 static bool CheckVisitOrdering(const VisitVector& visits) { |
41 int64_t previous_visit_time = 0; | 49 int64_t previous_visit_time = 0; |
42 for (VisitVector::const_iterator visit = visits.begin(); | 50 for (VisitVector::const_iterator visit = visits.begin(); |
43 visit != visits.end(); ++visit) { | 51 visit != visits.end(); ++visit) { |
44 if (visit != visits.begin() && | 52 if (visit != visits.begin() && |
45 previous_visit_time > visit->visit_time.ToInternalValue()) | 53 previous_visit_time > visit->visit_time.ToInternalValue()) |
46 return false; | 54 return false; |
47 | 55 |
48 previous_visit_time = visit->visit_time.ToInternalValue(); | 56 previous_visit_time = visit->visit_time.ToInternalValue(); |
49 } | 57 } |
50 return true; | 58 return true; |
51 } | 59 } |
52 | 60 |
53 std::string GetStorageKeyFromURLRow(const URLRow& row) { | 61 std::string GetStorageKeyFromURLRow(const URLRow& row) { |
62 DCHECK_NE(row.id(), 0); | |
54 std::string storage_key(sizeof(row.id()), 0); | 63 std::string storage_key(sizeof(row.id()), 0); |
55 base::WriteBigEndian<URLID>(&storage_key[0], row.id()); | 64 base::WriteBigEndian<URLID>(&storage_key[0], row.id()); |
56 return storage_key; | 65 return storage_key; |
57 } | 66 } |
58 | 67 |
59 bool HasTypedUrl(const VisitVector& visits) { | 68 bool HasTypedUrl(const VisitVector& visits) { |
60 auto typed_url_visit = std::find_if( | 69 auto typed_url_visit = std::find_if( |
61 visits.begin(), visits.end(), [](const history::VisitRow& visit) { | 70 visits.begin(), visits.end(), [](const history::VisitRow& visit) { |
62 return ui::PageTransitionCoreTypeIs(visit.transition, | 71 return ui::PageTransitionCoreTypeIs(visit.transition, |
63 ui::PAGE_TRANSITION_TYPED); | 72 ui::PAGE_TRANSITION_TYPED); |
(...skipping 27 matching lines...) Expand all Loading... | |
91 return base::MakeUnique<syncer::SyncMetadataStoreChangeList>( | 100 return base::MakeUnique<syncer::SyncMetadataStoreChangeList>( |
92 sync_metadata_database_, syncer::TYPED_URLS); | 101 sync_metadata_database_, syncer::TYPED_URLS); |
93 } | 102 } |
94 | 103 |
95 base::Optional<ModelError> TypedURLSyncBridge::MergeSyncData( | 104 base::Optional<ModelError> TypedURLSyncBridge::MergeSyncData( |
96 std::unique_ptr<MetadataChangeList> metadata_change_list, | 105 std::unique_ptr<MetadataChangeList> metadata_change_list, |
97 EntityChangeList entity_data) { | 106 EntityChangeList entity_data) { |
98 DCHECK(sequence_checker_.CalledOnValidSequence()); | 107 DCHECK(sequence_checker_.CalledOnValidSequence()); |
99 | 108 |
100 // Create a mapping of all local data by URLID. These will be narrowed down | 109 // Create a mapping of all local data by URLID. These will be narrowed down |
101 // by CreateOrUpdateUrl() to include only the entries different from sync | 110 // by MergeURLWithSync() to include only the entries different from sync |
102 // server data. | 111 // server data. |
103 TypedURLMap new_db_urls; | 112 TypedURLMap new_db_urls; |
104 | 113 |
105 // Get all the visits and map the URLRows by URL. | 114 // Get all the visits and map the URLRows by URL. |
106 URLVisitVectorMap local_visit_vectors; | 115 URLVisitVectorMap local_visit_vectors; |
107 | 116 |
108 if (!GetValidURLsAndVisits(&local_visit_vectors, &new_db_urls)) { | 117 if (!GetValidURLsAndVisits(&local_visit_vectors, &new_db_urls)) { |
109 return ModelError( | 118 return ModelError( |
110 FROM_HERE, "Could not get the typed_url entries from HistoryBackend."); | 119 FROM_HERE, "Could not get the typed_url entries from HistoryBackend."); |
111 } | 120 } |
112 | 121 |
113 // New sync data organized for different write operations to history backend. | 122 // New sync data organized for different write operations to history backend. |
114 history::URLRows new_synced_urls; | 123 history::URLRows new_synced_urls; |
115 history::URLRows updated_synced_urls; | 124 history::URLRows updated_synced_urls; |
116 TypedURLVisitVector new_synced_visits; | 125 TypedURLVisitVector new_synced_visits; |
117 | 126 |
118 // Iterate through entity_data and check for all the urls that | 127 // Iterate through entity_data and check for all the urls that |
119 // sync already knows about. CreateOrUpdateUrl() will remove urls that | 128 // sync already knows about. MergeURLWithSync() will remove urls that |
120 // are the same as the synced ones from |new_db_urls|. | 129 // are the same as the synced ones from |new_db_urls|. |
121 for (const EntityChange& entity_change : entity_data) { | 130 for (const EntityChange& entity_change : entity_data) { |
122 DCHECK(entity_change.data().specifics.has_typed_url()); | 131 DCHECK(entity_change.data().specifics.has_typed_url()); |
123 const TypedUrlSpecifics& specifics = | 132 const TypedUrlSpecifics& specifics = |
124 entity_change.data().specifics.typed_url(); | 133 entity_change.data().specifics.typed_url(); |
125 if (ShouldIgnoreUrl(GURL(specifics.url()))) | 134 if (ShouldIgnoreUrl(GURL(specifics.url()))) |
126 continue; | 135 continue; |
127 | 136 |
128 // Ignore old sync urls that don't have any transition data stored with | 137 // Ignore old sync urls that don't have any transition data stored with |
129 // them, or transition data that does not match the visit data (will be | 138 // them, or transition data that does not match the visit data (will be |
130 // deleted below). | 139 // deleted below). |
131 if (specifics.visit_transitions_size() == 0 || | 140 if (specifics.visit_transitions_size() == 0 || |
132 specifics.visit_transitions_size() != specifics.visits_size()) { | 141 specifics.visit_transitions_size() != specifics.visits_size()) { |
133 // Generate a debug assertion to help track down http://crbug.com/91473, | 142 // Generate a debug assertion to help track down http://crbug.com/91473, |
134 // even though we gracefully handle this case by overwriting this node. | 143 // even though we gracefully handle this case by overwriting this node. |
135 DCHECK_EQ(specifics.visits_size(), specifics.visit_transitions_size()); | 144 DCHECK_EQ(specifics.visits_size(), specifics.visit_transitions_size()); |
136 DVLOG(1) << "Ignoring obsolete sync url with no visit transition info."; | 145 DVLOG(1) << "Ignoring obsolete sync url with no visit transition info."; |
137 | 146 |
138 continue; | 147 continue; |
139 } | 148 } |
140 UpdateUrlFromServer(specifics, &new_db_urls, &local_visit_vectors, | 149 MergeURLWithSync(specifics, &new_db_urls, &local_visit_vectors, |
141 &new_synced_urls, &new_synced_visits, | 150 &new_synced_urls, &new_synced_visits, |
142 &updated_synced_urls); | 151 &updated_synced_urls); |
143 } | 152 } |
144 | 153 |
145 for (const auto& kv : new_db_urls) { | 154 for (const auto& kv : new_db_urls) { |
146 if (!HasTypedUrl(local_visit_vectors[kv.first])) { | 155 if (!HasTypedUrl(local_visit_vectors[kv.first])) { |
147 // This URL has no TYPED visits, don't sync it | 156 // This URL has no TYPED visits, don't sync it |
148 continue; | 157 continue; |
149 } | 158 } |
150 std::string storage_key = GetStorageKeyFromURLRow(kv.second); | 159 std::string storage_key = GetStorageKeyFromURLRow(kv.second); |
151 change_processor()->Put( | 160 change_processor()->Put( |
152 storage_key, CreateEntityData(kv.second, local_visit_vectors[kv.first]), | 161 storage_key, CreateEntityData(kv.second, local_visit_vectors[kv.first]), |
(...skipping 24 matching lines...) Expand all Loading... | |
177 | 186 |
178 return static_cast<syncer::SyncMetadataStoreChangeList*>( | 187 return static_cast<syncer::SyncMetadataStoreChangeList*>( |
179 metadata_change_list.get()) | 188 metadata_change_list.get()) |
180 ->TakeError(); | 189 ->TakeError(); |
181 } | 190 } |
182 | 191 |
183 base::Optional<ModelError> TypedURLSyncBridge::ApplySyncChanges( | 192 base::Optional<ModelError> TypedURLSyncBridge::ApplySyncChanges( |
184 std::unique_ptr<MetadataChangeList> metadata_change_list, | 193 std::unique_ptr<MetadataChangeList> metadata_change_list, |
185 EntityChangeList entity_changes) { | 194 EntityChangeList entity_changes) { |
186 DCHECK(sequence_checker_.CalledOnValidSequence()); | 195 DCHECK(sequence_checker_.CalledOnValidSequence()); |
187 NOTIMPLEMENTED(); | 196 DCHECK(sync_metadata_database_); |
197 | |
198 std::vector<GURL> pending_deleted_urls; | |
199 TypedURLVisitVector new_synced_visits; | |
200 history::VisitVector deleted_visits; | |
201 history::URLRows updated_synced_urls; | |
202 history::URLRows new_synced_urls; | |
203 | |
204 for (const EntityChange& entity_change : entity_changes) { | |
pavely
2017/07/06 19:28:29
You need to call UpdateStorageKey for ACTION_ADD s
Gang Wu
2017/07/10 19:53:25
Done.
| |
205 if (entity_change.type() == EntityChange::ACTION_DELETE) { | |
206 URLRow url_row; | |
207 int64_t url_id = sync_metadata_database_->StorageKeyToURLID( | |
208 entity_change.storage_key()); | |
209 if (!history_backend_->GetURLByID(url_id, &url_row)) { | |
210 // Ignoring the case which no matching URLRow with URLID |url_id|. | |
211 continue; | |
212 } | |
213 if (url_row.url().is_empty()) { | |
214 // Ignoring empty URL in sync DB; | |
pavely
2017/07/06 19:28:29
url_row comes from history, not sync db.
Dot at th
Gang Wu
2017/07/10 19:53:25
Done.
| |
215 continue; | |
216 } | |
217 | |
218 pending_deleted_urls.push_back(url_row.url()); | |
219 continue; | |
220 } | |
221 | |
222 DCHECK(entity_change.data().specifics.has_typed_url()); | |
223 const TypedUrlSpecifics& specifics = | |
224 entity_change.data().specifics.typed_url(); | |
225 | |
226 GURL url(specifics.url()); | |
227 | |
228 if (ShouldIgnoreUrl(url)) | |
229 continue; | |
230 | |
231 DCHECK(specifics.visits_size()); | |
232 sync_pb::TypedUrlSpecifics filtered_url = FilterExpiredVisits(specifics); | |
233 if (filtered_url.visits_size() == 0) | |
234 continue; | |
235 | |
236 UpdateFromSync(filtered_url, &new_synced_visits, &deleted_visits, | |
237 &updated_synced_urls, &new_synced_urls); | |
238 } | |
239 | |
240 WriteToHistoryBackend(&new_synced_urls, &updated_synced_urls, | |
241 &pending_deleted_urls, &new_synced_visits, | |
242 &deleted_visits); | |
188 return {}; | 243 return {}; |
189 } | 244 } |
190 | 245 |
191 void TypedURLSyncBridge::GetData(StorageKeyList storage_keys, | 246 void TypedURLSyncBridge::GetData(StorageKeyList storage_keys, |
192 DataCallback callback) { | 247 DataCallback callback) { |
193 DCHECK(sequence_checker_.CalledOnValidSequence()); | 248 DCHECK(sequence_checker_.CalledOnValidSequence()); |
194 NOTIMPLEMENTED(); | 249 DCHECK(sync_metadata_database_); |
250 | |
251 auto batch = base::MakeUnique<MutableDataBatch>(); | |
252 for (const std::string& key : storage_keys) { | |
253 URLRow url_row; | |
254 URLID url_id = sync_metadata_database_->StorageKeyToURLID(key); | |
255 | |
256 ++num_db_accesses_; | |
257 if (!history_backend_->GetURLByID(url_id, &url_row)) { | |
258 // Ignoring the case which no matching URLRow with URLID |url_id|. | |
pavely
2017/07/06 19:28:29
which => with?
Gang Wu
2017/07/10 19:53:24
Done.
| |
259 continue; | |
pavely
2017/07/06 19:28:29
Now that sync metadata lives in history db not fin
Gang Wu
2017/07/10 19:53:24
Done.
| |
260 } | |
261 if (url_row.url().is_empty()) { | |
262 // Ignoring empty URL in sync DB; | |
pavely
2017/07/06 19:28:29
Why do we expect and ignore rows with empty urls f
Gang Wu
2017/07/10 19:53:24
Done.
| |
263 continue; | |
264 } | |
265 | |
266 VisitVector visits_vector; | |
267 FixupURLAndGetVisits(&url_row, &visits_vector); | |
268 batch->Put(key, CreateEntityData(url_row, visits_vector)); | |
269 } | |
270 | |
271 callback.Run(std::move(batch)); | |
195 } | 272 } |
196 | 273 |
197 void TypedURLSyncBridge::GetAllData(DataCallback callback) { | 274 void TypedURLSyncBridge::GetAllData(DataCallback callback) { |
198 DCHECK(sequence_checker_.CalledOnValidSequence()); | 275 DCHECK(sequence_checker_.CalledOnValidSequence()); |
199 | 276 |
200 history::URLRows typed_urls; | 277 history::URLRows typed_urls; |
201 ++num_db_accesses_; | 278 ++num_db_accesses_; |
202 if (!history_backend_->GetAllTypedURLs(&typed_urls)) { | 279 if (!history_backend_->GetAllTypedURLs(&typed_urls)) { |
203 ++num_db_errors_; | 280 ++num_db_errors_; |
204 change_processor()->ReportError(FROM_HERE, | 281 change_processor()->ReportError(FROM_HERE, |
(...skipping 33 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
238 bool TypedURLSyncBridge::SupportsGetStorageKey() const { | 315 bool TypedURLSyncBridge::SupportsGetStorageKey() const { |
239 return false; | 316 return false; |
240 } | 317 } |
241 | 318 |
242 void TypedURLSyncBridge::OnURLVisited(history::HistoryBackend* history_backend, | 319 void TypedURLSyncBridge::OnURLVisited(history::HistoryBackend* history_backend, |
243 ui::PageTransition transition, | 320 ui::PageTransition transition, |
244 const history::URLRow& row, | 321 const history::URLRow& row, |
245 const history::RedirectList& redirects, | 322 const history::RedirectList& redirects, |
246 base::Time visit_time) { | 323 base::Time visit_time) { |
247 DCHECK(sequence_checker_.CalledOnValidSequence()); | 324 DCHECK(sequence_checker_.CalledOnValidSequence()); |
248 NOTIMPLEMENTED(); | 325 |
326 if (!change_processor()) | |
327 return; // Sync processor not yet initialized, don't sync. | |
pavely
2017/07/06 19:28:29
change_processor() always returns valid pointer. Y
Gang Wu
2017/07/10 19:53:25
Done.
| |
328 if (!ShouldSyncVisit(row.typed_count(), transition)) | |
329 return; | |
330 | |
331 std::unique_ptr<MetadataChangeList> metadata_change_list = | |
332 CreateMetadataChangeList(); | |
333 | |
334 UpdateSyncFromLocal(row, metadata_change_list.get()); | |
249 } | 335 } |
250 | 336 |
251 void TypedURLSyncBridge::OnURLsModified( | 337 void TypedURLSyncBridge::OnURLsModified( |
252 history::HistoryBackend* history_backend, | 338 history::HistoryBackend* history_backend, |
253 const history::URLRows& changed_urls) { | 339 const history::URLRows& changed_urls) { |
254 DCHECK(sequence_checker_.CalledOnValidSequence()); | 340 DCHECK(sequence_checker_.CalledOnValidSequence()); |
255 NOTIMPLEMENTED(); | 341 |
342 if (!change_processor()) | |
343 return; // Sync processor not yet initialized, don't sync. | |
344 | |
345 std::unique_ptr<MetadataChangeList> metadata_change_list = | |
346 CreateMetadataChangeList(); | |
347 | |
348 for (const auto& row : changed_urls) { | |
349 // Only care if the modified URL is typed. | |
350 if (row.typed_count() >= 0) { | |
351 // If there were any errors updating the sync node, just ignore them and | |
352 // continue on to process the next URL. | |
353 UpdateSyncFromLocal(row, metadata_change_list.get()); | |
354 } | |
355 } | |
256 } | 356 } |
257 | 357 |
258 void TypedURLSyncBridge::OnURLsDeleted(history::HistoryBackend* history_backend, | 358 void TypedURLSyncBridge::OnURLsDeleted(history::HistoryBackend* history_backend, |
259 bool all_history, | 359 bool all_history, |
260 bool expired, | 360 bool expired, |
261 const history::URLRows& deleted_rows, | 361 const history::URLRows& deleted_rows, |
262 const std::set<GURL>& favicon_urls) { | 362 const std::set<GURL>& favicon_urls) { |
263 DCHECK(sequence_checker_.CalledOnValidSequence()); | 363 DCHECK(sequence_checker_.CalledOnValidSequence()); |
264 NOTIMPLEMENTED(); | 364 if (!change_processor()) |
365 return; // Sync processor not yet initialized, don't sync. | |
366 | |
367 // Ignore URLs expired due to old age (we don't want to sync them as deletions | |
368 // to avoid extra traffic up to the server, and also to make sure that a | |
369 // client with a bad clock setting won't go on an expiration rampage and | |
370 // delete all history from every client). The server will gracefully age out | |
371 // the sync DB entries when they've been idle for long enough. | |
372 if (expired) | |
373 return; | |
374 | |
375 std::unique_ptr<MetadataChangeList> metadata_change_list = | |
376 CreateMetadataChangeList(); | |
377 | |
378 if (all_history) { | |
379 auto batch = base::MakeUnique<syncer::MetadataBatch>(); | |
380 if (!sync_metadata_database_->GetAllSyncMetadata(batch.get())) { | |
381 change_processor()->ReportError(FROM_HERE, | |
382 "Failed reading typed url metadata from " | |
383 "TypedURLSyncMetadataDatabase."); | |
384 return; | |
385 } | |
386 | |
387 syncer::EntityMetadataMap metadata_map(batch->TakeAllMetadata()); | |
388 for (const auto& kv : metadata_map) { | |
389 change_processor()->Delete(kv.first, metadata_change_list.get()); | |
390 } | |
391 } else { | |
392 // Delete rows. | |
393 for (const auto& row : deleted_rows) { | |
394 std::string storage_key = GetStorageKeyFromURLRow(row); | |
395 change_processor()->Delete(storage_key, metadata_change_list.get()); | |
396 } | |
397 } | |
265 } | 398 } |
266 | 399 |
267 void TypedURLSyncBridge::Init() { | 400 void TypedURLSyncBridge::Init() { |
268 DCHECK(sequence_checker_.CalledOnValidSequence()); | 401 DCHECK(sequence_checker_.CalledOnValidSequence()); |
269 | 402 |
270 history_backend_observer_.Add(history_backend_); | 403 history_backend_observer_.Add(history_backend_); |
271 LoadMetadata(); | 404 LoadMetadata(); |
272 } | 405 } |
273 | 406 |
274 int TypedURLSyncBridge::GetErrorPercentage() const { | 407 int TypedURLSyncBridge::GetErrorPercentage() const { |
(...skipping 203 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
478 ++visit_ix; | 611 ++visit_ix; |
479 } | 612 } |
480 } | 613 } |
481 DCHECK(CheckVisitOrdering(*visits)); | 614 DCHECK(CheckVisitOrdering(*visits)); |
482 | 615 |
483 new_url->set_last_visit(visits->back().visit_time); | 616 new_url->set_last_visit(visits->back().visit_time); |
484 return different; | 617 return different; |
485 } | 618 } |
486 | 619 |
487 // static | 620 // static |
621 void TypedURLSyncBridge::DiffVisits( | |
622 const history::VisitVector& history_visits, | |
623 const sync_pb::TypedUrlSpecifics& sync_specifics, | |
624 std::vector<history::VisitInfo>* new_visits, | |
625 history::VisitVector* removed_visits) { | |
626 DCHECK(new_visits); | |
627 size_t old_visit_count = history_visits.size(); | |
628 size_t new_visit_count = sync_specifics.visits_size(); | |
629 size_t old_index = 0; | |
630 size_t new_index = 0; | |
631 while (old_index < old_visit_count && new_index < new_visit_count) { | |
632 base::Time new_visit_time = | |
633 base::Time::FromInternalValue(sync_specifics.visits(new_index)); | |
634 if (history_visits[old_index].visit_time < new_visit_time) { | |
635 if (new_index > 0 && removed_visits) { | |
636 // If there are visits missing from the start of the node, that | |
637 // means that they were probably clipped off due to our code that | |
638 // limits the size of the sync nodes - don't delete them from our | |
639 // local history. | |
640 removed_visits->push_back(history_visits[old_index]); | |
641 } | |
642 ++old_index; | |
643 } else if (history_visits[old_index].visit_time > new_visit_time) { | |
644 new_visits->push_back(history::VisitInfo( | |
645 new_visit_time, ui::PageTransitionFromInt( | |
646 sync_specifics.visit_transitions(new_index)))); | |
647 ++new_index; | |
648 } else { | |
649 ++old_index; | |
650 ++new_index; | |
651 } | |
652 } | |
653 | |
654 if (removed_visits) { | |
655 for (; old_index < old_visit_count; ++old_index) { | |
656 removed_visits->push_back(history_visits[old_index]); | |
657 } | |
658 } | |
659 | |
660 for (; new_index < new_visit_count; ++new_index) { | |
661 new_visits->push_back(history::VisitInfo( | |
662 base::Time::FromInternalValue(sync_specifics.visits(new_index)), | |
663 ui::PageTransitionFromInt( | |
664 sync_specifics.visit_transitions(new_index)))); | |
665 } | |
666 } | |
667 | |
668 // static | |
488 void TypedURLSyncBridge::UpdateURLRowFromTypedUrlSpecifics( | 669 void TypedURLSyncBridge::UpdateURLRowFromTypedUrlSpecifics( |
489 const TypedUrlSpecifics& typed_url, | 670 const TypedUrlSpecifics& typed_url, |
490 history::URLRow* new_url) { | 671 history::URLRow* new_url) { |
491 DCHECK_GT(typed_url.visits_size(), 0); | 672 DCHECK_GT(typed_url.visits_size(), 0); |
492 CHECK_EQ(typed_url.visit_transitions_size(), typed_url.visits_size()); | 673 CHECK_EQ(typed_url.visit_transitions_size(), typed_url.visits_size()); |
493 if (!new_url->url().is_valid()) { | 674 if (!new_url->url().is_valid()) { |
494 new_url->set_url(GURL(typed_url.url())); | 675 new_url->set_url(GURL(typed_url.url())); |
495 } | 676 } |
496 new_url->set_title(base::UTF8ToUTF16(typed_url.title())); | 677 new_url->set_title(base::UTF8ToUTF16(typed_url.title())); |
497 new_url->set_hidden(typed_url.hidden()); | 678 new_url->set_hidden(typed_url.hidden()); |
(...skipping 20 matching lines...) Expand all Loading... | |
518 return; | 699 return; |
519 } | 700 } |
520 change_processor()->ModelReadyToSync(std::move(batch)); | 701 change_processor()->ModelReadyToSync(std::move(batch)); |
521 } | 702 } |
522 | 703 |
523 void TypedURLSyncBridge::ClearErrorStats() { | 704 void TypedURLSyncBridge::ClearErrorStats() { |
524 num_db_accesses_ = 0; | 705 num_db_accesses_ = 0; |
525 num_db_errors_ = 0; | 706 num_db_errors_ = 0; |
526 } | 707 } |
527 | 708 |
528 void TypedURLSyncBridge::UpdateUrlFromServer( | 709 void TypedURLSyncBridge::MergeURLWithSync( |
529 const sync_pb::TypedUrlSpecifics& server_typed_url, | 710 const sync_pb::TypedUrlSpecifics& server_typed_url, |
530 TypedURLMap* local_typed_urls, | 711 TypedURLMap* local_typed_urls, |
531 URLVisitVectorMap* local_visit_vectors, | 712 URLVisitVectorMap* local_visit_vectors, |
532 history::URLRows* new_synced_urls, | 713 history::URLRows* new_synced_urls, |
533 TypedURLVisitVector* new_synced_visits, | 714 TypedURLVisitVector* new_synced_visits, |
534 history::URLRows* updated_synced_urls) { | 715 history::URLRows* updated_synced_urls) { |
535 DCHECK(server_typed_url.visits_size() != 0); | 716 DCHECK(server_typed_url.visits_size() != 0); |
536 DCHECK_EQ(server_typed_url.visits_size(), | 717 DCHECK_EQ(server_typed_url.visits_size(), |
537 server_typed_url.visit_transitions_size()); | 718 server_typed_url.visit_transitions_size()); |
538 | 719 |
(...skipping 115 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
654 new_synced_visits->push_back( | 835 new_synced_visits->push_back( |
655 std::pair<GURL, std::vector<history::VisitInfo>>(it->first, | 836 std::pair<GURL, std::vector<history::VisitInfo>>(it->first, |
656 added_visits)); | 837 added_visits)); |
657 } | 838 } |
658 } else { | 839 } else { |
659 // No difference in urls, erase from map | 840 // No difference in urls, erase from map |
660 local_typed_urls->erase(it); | 841 local_typed_urls->erase(it); |
661 } | 842 } |
662 } | 843 } |
663 | 844 |
845 void TypedURLSyncBridge::UpdateFromSync( | |
846 const sync_pb::TypedUrlSpecifics& typed_url, | |
847 TypedURLVisitVector* visits_to_add, | |
848 history::VisitVector* visits_to_remove, | |
849 history::URLRows* updated_urls, | |
850 history::URLRows* new_urls) { | |
851 history::URLRow new_url(GURL(typed_url.url())); | |
852 history::VisitVector existing_visits; | |
853 bool existing_url = history_backend_->GetURL(new_url.url(), &new_url); | |
854 if (existing_url) { | |
855 // This URL already exists locally - fetch the visits so we can | |
856 // merge them below. | |
857 if (!FixupURLAndGetVisits(&new_url, &existing_visits)) { | |
858 return; | |
859 } | |
860 } | |
861 visits_to_add->push_back(std::pair<GURL, std::vector<history::VisitInfo>>( | |
862 new_url.url(), std::vector<history::VisitInfo>())); | |
863 | |
864 // Update the URL with information from the typed URL. | |
865 UpdateURLRowFromTypedUrlSpecifics(typed_url, &new_url); | |
866 | |
867 // Figure out which visits we need to add. | |
868 DiffVisits(existing_visits, typed_url, &visits_to_add->back().second, | |
869 visits_to_remove); | |
870 | |
871 if (existing_url) { | |
872 updated_urls->push_back(new_url); | |
873 } else { | |
874 new_urls->push_back(new_url); | |
875 } | |
876 } | |
877 | |
878 bool TypedURLSyncBridge::UpdateSyncFromLocal( | |
879 URLRow row, | |
880 MetadataChangeList* metadata_change_list) { | |
881 DCHECK_GE(row.typed_count(), 0); | |
882 | |
883 if (ShouldIgnoreUrl(row.url())) | |
884 return false; | |
885 | |
886 // Get the visits for this node. | |
887 VisitVector visit_vector; | |
888 if (!FixupURLAndGetVisits(&row, &visit_vector)) { | |
889 return false; | |
890 } | |
891 | |
892 DCHECK(!visit_vector.empty()); | |
893 | |
894 std::unique_ptr<syncer::EntityData> entity_data = | |
895 CreateEntityData(row, visit_vector); | |
896 if (!entity_data->specifics.has_typed_url()) { | |
897 // Cannot create EntityData, ex. no TYPED visits. | |
898 return false; | |
899 } | |
900 | |
901 std::string storage_key = GetStorageKeyFromURLRow(row); | |
902 change_processor()->Put(storage_key, std::move(entity_data), | |
903 metadata_change_list); | |
904 | |
905 return true; | |
906 } | |
907 | |
664 base::Optional<ModelError> TypedURLSyncBridge::WriteToHistoryBackend( | 908 base::Optional<ModelError> TypedURLSyncBridge::WriteToHistoryBackend( |
665 const history::URLRows* new_urls, | 909 const history::URLRows* new_urls, |
666 const history::URLRows* updated_urls, | 910 const history::URLRows* updated_urls, |
667 const std::vector<GURL>* deleted_urls, | 911 const std::vector<GURL>* deleted_urls, |
668 const TypedURLVisitVector* new_visits, | 912 const TypedURLVisitVector* new_visits, |
669 const history::VisitVector* deleted_visits) { | 913 const history::VisitVector* deleted_visits) { |
670 if (deleted_urls && !deleted_urls->empty()) | 914 if (deleted_urls && !deleted_urls->empty()) |
671 history_backend_->DeleteURLs(*deleted_urls); | 915 history_backend_->DeleteURLs(*deleted_urls); |
672 | 916 |
673 if (new_urls) { | 917 if (new_urls) { |
(...skipping 67 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
741 return true; | 985 return true; |
742 | 986 |
743 // Ignore local file URLs. | 987 // Ignore local file URLs. |
744 if (url.SchemeIsFile()) | 988 if (url.SchemeIsFile()) |
745 return true; | 989 return true; |
746 | 990 |
747 // Ignore localhost URLs. | 991 // Ignore localhost URLs. |
748 if (net::IsLocalhost(url.host_piece())) | 992 if (net::IsLocalhost(url.host_piece())) |
749 return true; | 993 return true; |
750 | 994 |
751 // Ignore username and password, sonce history backend will remove user name | 995 // Ignore username and password, sonce history backend will remove user name |
pavely
2017/07/06 19:28:29
sonce => since
Gang Wu
2017/07/10 19:53:24
Done.
| |
752 // and password in URLDatabase::GURLToDatabaseURL and send username/password | 996 // and password in URLDatabase::GURLToDatabaseURL and send username/password |
753 // removed url to sync later. | 997 // removed url to sync later. |
754 if (url.has_username() || url.has_password()) | 998 if (url.has_username() || url.has_password()) |
755 return true; | 999 return true; |
756 | 1000 |
757 return false; | 1001 return false; |
758 } | 1002 } |
759 | 1003 |
760 bool TypedURLSyncBridge::ShouldIgnoreVisits( | 1004 bool TypedURLSyncBridge::ShouldIgnoreVisits( |
761 const history::VisitVector& visits) { | 1005 const history::VisitVector& visits) { |
762 // We ignore URLs that were imported, but have never been visited by | 1006 // We ignore URLs that were imported, but have never been visited by |
763 // chromium. | 1007 // chromium. |
764 static const int kFirstImportedSource = history::SOURCE_FIREFOX_IMPORTED; | 1008 static const int kFirstImportedSource = history::SOURCE_FIREFOX_IMPORTED; |
765 history::VisitSourceMap map; | 1009 history::VisitSourceMap map; |
766 if (!history_backend_->GetVisitsSource(visits, &map)) | 1010 if (!history_backend_->GetVisitsSource(visits, &map)) |
767 return false; // If we can't read the visit, assume it's not imported. | 1011 return false; // If we can't read the visit, assume it's not imported. |
768 | 1012 |
769 // Walk the list of visits and look for a non-imported item. | 1013 // Walk the list of visits and look for a non-imported item. |
770 for (const auto& visit : visits) { | 1014 for (const auto& visit : visits) { |
771 if (map.count(visit.visit_id) == 0 || | 1015 if (map.count(visit.visit_id) == 0 || |
772 map[visit.visit_id] < kFirstImportedSource) { | 1016 map[visit.visit_id] < kFirstImportedSource) { |
773 return false; | 1017 return false; |
774 } | 1018 } |
775 } | 1019 } |
776 // We only saw imported visits, so tell the caller to ignore them. | 1020 // We only saw imported visits, so tell the caller to ignore them. |
777 return true; | 1021 return true; |
778 } | 1022 } |
779 | 1023 |
1024 bool TypedURLSyncBridge::ShouldSyncVisit(int typed_count, | |
1025 ui::PageTransition transition) { | |
1026 // Just use an ad-hoc criteria to determine whether to ignore this | |
1027 // notification. For most users, the distribution of visits is roughly a bell | |
1028 // curve with a long tail - there are lots of URLs with < 5 visits so we want | |
1029 // to make sure we sync up every visit to ensure the proper ordering of | |
1030 // suggestions. But there are relatively few URLs with > 10 visits, and those | |
1031 // tend to be more broadly distributed such that there's no need to sync up | |
1032 // every visit to preserve their relative ordering. | |
1033 return (ui::PageTransitionCoreTypeIs(transition, ui::PAGE_TRANSITION_TYPED) && | |
1034 typed_count >= 0 && | |
1035 (typed_count < kTypedUrlVisitThrottleThreshold || | |
1036 (typed_count % kTypedUrlVisitThrottleMultiple) == 0)); | |
1037 } | |
1038 | |
780 bool TypedURLSyncBridge::FixupURLAndGetVisits(URLRow* url, | 1039 bool TypedURLSyncBridge::FixupURLAndGetVisits(URLRow* url, |
781 VisitVector* visits) { | 1040 VisitVector* visits) { |
782 ++num_db_accesses_; | 1041 ++num_db_accesses_; |
783 if (!history_backend_->GetMostRecentVisitsForURL(url->id(), kMaxVisitsToFetch, | 1042 if (!history_backend_->GetMostRecentVisitsForURL(url->id(), kMaxVisitsToFetch, |
784 visits)) { | 1043 visits)) { |
785 ++num_db_errors_; | 1044 ++num_db_errors_; |
786 // Couldn't load the visits for this URL due to some kind of DB error. | 1045 // Couldn't load the visits for this URL due to some kind of DB error. |
787 // Don't bother writing this URL to the history DB (if we ignore the | 1046 // Don't bother writing this URL to the history DB (if we ignore the |
788 // error and continue, we might end up duplicating existing visits). | 1047 // error and continue, we might end up duplicating existing visits). |
789 DLOG(ERROR) << "Could not load visits for url: " << url->url(); | 1048 DLOG(ERROR) << "Could not load visits for url: " << url->url(); |
(...skipping 55 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
845 } | 1104 } |
846 | 1105 |
847 std::unique_ptr<EntityData> TypedURLSyncBridge::CreateEntityData( | 1106 std::unique_ptr<EntityData> TypedURLSyncBridge::CreateEntityData( |
848 const URLRow& row, | 1107 const URLRow& row, |
849 const VisitVector& visits) { | 1108 const VisitVector& visits) { |
850 auto entity_data = base::MakeUnique<EntityData>(); | 1109 auto entity_data = base::MakeUnique<EntityData>(); |
851 TypedUrlSpecifics* specifics = entity_data->specifics.mutable_typed_url(); | 1110 TypedUrlSpecifics* specifics = entity_data->specifics.mutable_typed_url(); |
852 | 1111 |
853 if (!WriteToTypedUrlSpecifics(row, visits, specifics)) { | 1112 if (!WriteToTypedUrlSpecifics(row, visits, specifics)) { |
854 // Cannot write to specifics, ex. no TYPED visits. | 1113 // Cannot write to specifics, ex. no TYPED visits. |
855 return base::MakeUnique<EntityData>(); | 1114 return base::MakeUnique<EntityData>(); |
pavely
2017/07/06 19:28:29
CreateEntityData came from TypedUrlSyncableService
Gang Wu
2017/07/10 19:53:24
Done.
| |
856 } | 1115 } |
857 entity_data->non_unique_name = row.url().spec(); | 1116 entity_data->non_unique_name = row.url().spec(); |
858 | |
859 return entity_data; | 1117 return entity_data; |
860 } | 1118 } |
861 | 1119 |
862 bool TypedURLSyncBridge::GetValidURLsAndVisits(URLVisitVectorMap* url_to_visit, | 1120 bool TypedURLSyncBridge::GetValidURLsAndVisits(URLVisitVectorMap* url_to_visit, |
863 TypedURLMap* url_to_urlrow) { | 1121 TypedURLMap* url_to_urlrow) { |
864 DCHECK(url_to_visit); | 1122 DCHECK(url_to_visit); |
865 DCHECK(url_to_urlrow); | 1123 DCHECK(url_to_urlrow); |
866 | 1124 |
867 history::URLRows local_typed_urls; | 1125 history::URLRows local_typed_urls; |
868 ++num_db_accesses_; | 1126 ++num_db_accesses_; |
(...skipping 26 matching lines...) Expand all Loading... | |
895 if (!is_existing_url) { | 1153 if (!is_existing_url) { |
896 // The typed url did not save to local history database, so return empty | 1154 // The typed url did not save to local history database, so return empty |
897 // string. | 1155 // string. |
898 return std::string(); | 1156 return std::string(); |
899 } | 1157 } |
900 | 1158 |
901 return GetStorageKeyFromURLRow(existing_url); | 1159 return GetStorageKeyFromURLRow(existing_url); |
902 } | 1160 } |
903 | 1161 |
904 } // namespace history | 1162 } // namespace history |
OLD | NEW |