Chromium Code Reviews| 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 |