Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 // Copyright 2014 The Chromium Authors. All rights reserved. | 1 // Copyright 2014 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/sync_sessions/sessions_sync_manager.h" | 5 #include "components/sync_sessions/sessions_sync_manager.h" |
| 6 | 6 |
| 7 #include <algorithm> | 7 #include <algorithm> |
| 8 #include <utility> | 8 #include <utility> |
| 9 | 9 |
| 10 #include "base/format_macros.h" | 10 #include "base/format_macros.h" |
| (...skipping 33 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 44 const int kMaxSyncNavigationCount = 6; | 44 const int kMaxSyncNavigationCount = 6; |
| 45 | 45 |
| 46 // The URL at which the set of synced tabs is displayed. We treat it differently | 46 // The URL at which the set of synced tabs is displayed. We treat it differently |
| 47 // from all other URL's as accessing it triggers a sync refresh of Sessions. | 47 // from all other URL's as accessing it triggers a sync refresh of Sessions. |
| 48 const char kNTPOpenTabSyncURL[] = "chrome://newtab/#open_tabs"; | 48 const char kNTPOpenTabSyncURL[] = "chrome://newtab/#open_tabs"; |
| 49 | 49 |
| 50 // Default number of days without activity after which a session is considered | 50 // Default number of days without activity after which a session is considered |
| 51 // stale and becomes a candidate for garbage collection. | 51 // stale and becomes a candidate for garbage collection. |
| 52 const int kDefaultStaleSessionThresholdDays = 14; // 2 weeks. | 52 const int kDefaultStaleSessionThresholdDays = 14; // 2 weeks. |
| 53 | 53 |
| 54 // Clean up navigation tracking when we have over this many global_ids. | |
| 55 const size_t kNavigationTrackingCleanupThreshold = 100; | |
| 56 | |
| 57 // When we clean up navigation tracking, delete this many global_ids. | |
| 58 const int kNavigationTrackingCleanupAmount = 10; | |
| 59 | |
| 60 // Used to record conflict information into histogram Sync.GlobalIdConflict. | |
| 61 enum SyncGlobalIdConflict { | |
| 62 CONFLICT = 0, | |
| 63 NO_CONFLICT_NEW_ID, | |
| 64 NO_CONFLICT_SAME_IDS, | |
| 65 CONFLICT_MAX, | |
| 66 }; | |
| 67 | |
| 54 // Comparator function for use with std::sort that will sort tabs by | 68 // Comparator function for use with std::sort that will sort tabs by |
| 55 // descending timestamp (i.e., most recent first). | 69 // descending timestamp (i.e., most recent first). |
| 56 bool TabsRecencyComparator(const sessions::SessionTab* t1, | 70 bool TabsRecencyComparator(const sessions::SessionTab* t1, |
| 57 const sessions::SessionTab* t2) { | 71 const sessions::SessionTab* t2) { |
| 58 return t1->timestamp > t2->timestamp; | 72 return t1->timestamp > t2->timestamp; |
| 59 } | 73 } |
| 60 | 74 |
| 61 // Comparator function for use with std::sort that will sort sessions by | 75 // Comparator function for use with std::sort that will sort sessions by |
| 62 // descending modified_time (i.e., most recent first). | 76 // descending modified_time (i.e., most recent first). |
| 63 bool SessionsRecencyComparator(const SyncedSession* s1, | 77 bool SessionsRecencyComparator(const SyncedSession* s1, |
| (...skipping 507 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 571 GURL virtual_url = | 585 GURL virtual_url = |
| 572 modified_tab->GetVirtualURLAtIndex(modified_tab->GetCurrentEntryIndex()); | 586 modified_tab->GetVirtualURLAtIndex(modified_tab->GetCurrentEntryIndex()); |
| 573 if (virtual_url.is_valid() && | 587 if (virtual_url.is_valid() && |
| 574 virtual_url.spec() == kNTPOpenTabSyncURL) { | 588 virtual_url.spec() == kNTPOpenTabSyncURL) { |
| 575 DVLOG(1) << "Triggering sync refresh for sessions datatype."; | 589 DVLOG(1) << "Triggering sync refresh for sessions datatype."; |
| 576 if (!datatype_refresh_callback_.is_null()) | 590 if (!datatype_refresh_callback_.is_null()) |
| 577 datatype_refresh_callback_.Run(); | 591 datatype_refresh_callback_.Run(); |
| 578 } | 592 } |
| 579 } | 593 } |
| 580 | 594 |
| 595 sessions::SerializedNavigationEntry current; | |
| 596 modified_tab->GetSerializedNavigationAtIndex( | |
|
vabr (Chromium)
2017/07/22 08:22:22
This might be on the path of the crash in https://
| |
| 597 modified_tab->GetCurrentEntryIndex(), ¤t); | |
| 598 TrackNavigationIds(current); | |
| 599 | |
| 581 if (local_tab_pool_out_of_sync_) { | 600 if (local_tab_pool_out_of_sync_) { |
| 582 // If our tab pool is corrupt, pay the price of a full re-association to | 601 // If our tab pool is corrupt, pay the price of a full re-association to |
| 583 // fix things up. This takes care of the new tab modification as well. | 602 // fix things up. This takes care of the new tab modification as well. |
| 584 bool rebuild_association_succeeded = RebuildAssociations(); | 603 bool rebuild_association_succeeded = RebuildAssociations(); |
| 585 DCHECK(!rebuild_association_succeeded || !local_tab_pool_out_of_sync_); | 604 DCHECK(!rebuild_association_succeeded || !local_tab_pool_out_of_sync_); |
| 586 return; | 605 return; |
| 587 } | 606 } |
| 588 | 607 |
| 589 syncer::SyncChangeList changes; | 608 syncer::SyncChangeList changes; |
| 590 AssociateTab(modified_tab, &changes); | 609 AssociateTab(modified_tab, &changes); |
| (...skipping 687 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1278 DVLOG(1) << "Found stale session " << session_tag << " with age " | 1297 DVLOG(1) << "Found stale session " << session_tag << " with age " |
| 1279 << session_age_in_days << ", deleting."; | 1298 << session_age_in_days << ", deleting."; |
| 1280 DeleteForeignSessionInternal(session_tag, &changes); | 1299 DeleteForeignSessionInternal(session_tag, &changes); |
| 1281 } | 1300 } |
| 1282 } | 1301 } |
| 1283 | 1302 |
| 1284 if (!changes.empty()) | 1303 if (!changes.empty()) |
| 1285 sync_processor_->ProcessSyncChanges(FROM_HERE, changes); | 1304 sync_processor_->ProcessSyncChanges(FROM_HERE, changes); |
| 1286 } | 1305 } |
| 1287 | 1306 |
| 1307 void SessionsSyncManager::AddGlobalIdChangeObserver( | |
| 1308 syncer::GlobalIdChange callback) { | |
| 1309 global_id_change_observers_.push_back(std::move(callback)); | |
| 1310 } | |
| 1311 | |
| 1312 int64_t SessionsSyncManager::GetLatestGlobalId(int64_t global_id) { | |
| 1313 auto g2u_iter = global_to_unique_.find(global_id); | |
| 1314 if (g2u_iter != global_to_unique_.end()) { | |
| 1315 auto u2g_iter = unique_to_current_global_.find(g2u_iter->second); | |
| 1316 if (u2g_iter != unique_to_current_global_.end()) { | |
| 1317 return u2g_iter->second; | |
| 1318 } | |
| 1319 } | |
| 1320 return global_id; | |
| 1321 } | |
| 1322 | |
| 1288 // static | 1323 // static |
| 1289 std::string SessionsSyncManager::TagHashFromSpecifics( | 1324 std::string SessionsSyncManager::TagHashFromSpecifics( |
| 1290 const sync_pb::SessionSpecifics& specifics) { | 1325 const sync_pb::SessionSpecifics& specifics) { |
| 1291 return syncer::GenerateSyncableHash(syncer::SESSIONS, | 1326 return syncer::GenerateSyncableHash(syncer::SESSIONS, |
| 1292 TagFromSpecifics(specifics)); | 1327 TagFromSpecifics(specifics)); |
| 1293 } | 1328 } |
| 1294 | 1329 |
| 1330 void SessionsSyncManager::TrackNavigationIds( | |
| 1331 const sessions::SerializedNavigationEntry& current) { | |
| 1332 // The expectation is that global_id will update for a given unique_id, which | |
| 1333 // should accurately and uniquely represent a single navigation. It is | |
| 1334 // theoretically possible for two unique_ids to map to the same global_id, but | |
| 1335 // hopefully rare enough that it doesn't cause much harm. Lets record metrics | |
| 1336 // verify this theory. | |
| 1337 int64_t global_id = current.timestamp().ToInternalValue(); | |
| 1338 // It is possible that the global_id has not been set yet for this navigation. | |
| 1339 // In this case there's nothing here for us to track yet. | |
| 1340 if (global_id == 0) { | |
| 1341 return; | |
| 1342 } | |
| 1343 | |
| 1344 int unique_id = current.unique_id(); | |
| 1345 DCHECK_NE(0, unique_id); | |
| 1346 | |
| 1347 auto g2u_iter = global_to_unique_.find(global_id); | |
| 1348 if (g2u_iter == global_to_unique_.end()) { | |
| 1349 global_to_unique_.insert(g2u_iter, std::make_pair(global_id, unique_id)); | |
| 1350 UMA_HISTOGRAM_ENUMERATION("Sync.GlobalIdConflict", NO_CONFLICT_NEW_ID, | |
| 1351 CONFLICT_MAX); | |
| 1352 } else if (g2u_iter->second != unique_id) { | |
| 1353 UMA_HISTOGRAM_ENUMERATION("Sync.GlobalIdConflict", CONFLICT, CONFLICT_MAX); | |
| 1354 } else { | |
| 1355 UMA_HISTOGRAM_ENUMERATION("Sync.GlobalIdConflict", NO_CONFLICT_SAME_IDS, | |
| 1356 CONFLICT_MAX); | |
| 1357 } | |
| 1358 | |
| 1359 auto u2g_iter = unique_to_current_global_.find(unique_id); | |
| 1360 if (u2g_iter == unique_to_current_global_.end()) { | |
| 1361 unique_to_current_global_.insert(u2g_iter, | |
| 1362 std::make_pair(unique_id, global_id)); | |
| 1363 } else if (u2g_iter->second != global_id) { | |
| 1364 // Remember the old_global_id before we insert and invalidate out iter. | |
| 1365 int64_t old_global_id = u2g_iter->second; | |
| 1366 | |
| 1367 // TODO(skym): Use insert_or_assign with hint once on C++17. | |
| 1368 unique_to_current_global_[unique_id] = global_id; | |
| 1369 | |
| 1370 // This should be done after updating unique_to_current_global_ in case one | |
| 1371 // of our observers calls into GetLatestGlobalId(). | |
| 1372 for (auto& observer : global_id_change_observers_) { | |
| 1373 observer.Run(old_global_id, global_id); | |
| 1374 } | |
| 1375 } | |
| 1376 | |
| 1377 CleanupNavigationTracking(); | |
| 1378 } | |
| 1379 | |
| 1380 void SessionsSyncManager::CleanupNavigationTracking() { | |
| 1381 DCHECK(kNavigationTrackingCleanupThreshold > | |
| 1382 kNavigationTrackingCleanupAmount); | |
| 1383 | |
| 1384 // |global_to_unique_| is implicitly ordered by least recently created, which | |
| 1385 // means we can drop from the beginning. | |
| 1386 if (global_to_unique_.size() > kNavigationTrackingCleanupThreshold) { | |
| 1387 auto iter = global_to_unique_.begin(); | |
| 1388 std::advance(iter, kNavigationTrackingCleanupAmount); | |
| 1389 global_to_unique_.erase(global_to_unique_.begin(), iter); | |
| 1390 | |
| 1391 // While |unique_id|s do get bigger for the most part, this isn't a great | |
| 1392 // thing to make assumptions about, and an old tab may get refreshed often | |
| 1393 // and still be very important. So instead just delete anything that's | |
| 1394 // orphaned from |global_to_unique_|. | |
| 1395 base::EraseIf(unique_to_current_global_, | |
| 1396 [this](const std::pair<int, int64_t> kv) { | |
| 1397 return !base::ContainsKey(global_to_unique_, kv.second); | |
| 1398 }); | |
| 1399 } | |
| 1400 } | |
| 1401 | |
| 1295 }; // namespace sync_sessions | 1402 }; // namespace sync_sessions |
| OLD | NEW |