Chromium Code Reviews| Index: components/sync_sessions/sessions_sync_manager.cc |
| diff --git a/components/sync_sessions/sessions_sync_manager.cc b/components/sync_sessions/sessions_sync_manager.cc |
| index 5810f8fc937e2677a29fbc6320a2f727e861c95f..f7bdf27b1a4c4d16f5e220003d5c9974b9f45c3e 100644 |
| --- a/components/sync_sessions/sessions_sync_manager.cc |
| +++ b/components/sync_sessions/sessions_sync_manager.cc |
| @@ -51,6 +51,12 @@ const char kNTPOpenTabSyncURL[] = "chrome://newtab/#open_tabs"; |
| // stale and becomes a candidate for garbage collection. |
| const int kDefaultStaleSessionThresholdDays = 14; // 2 weeks. |
| +// Clean up navigation tracking when we have over this many global_ids. |
| +const size_t kNavigationTrackingCleanupThreshold = 100; |
| + |
| +// When we clean up navigation tracking, delete this many global_ids. |
| +const int kNavigationTrackingCleanupAmount = 10; |
| + |
| // Comparator function for use with std::sort that will sort tabs by |
| // descending timestamp (i.e., most recent first). |
| bool TabsRecencyComparator(const sessions::SessionTab* t1, |
| @@ -578,6 +584,11 @@ void SessionsSyncManager::OnLocalTabModified(SyncedTabDelegate* modified_tab) { |
| } |
| } |
| + sessions::SerializedNavigationEntry current; |
| + modified_tab->GetSerializedNavigationAtIndex( |
| + modified_tab->GetCurrentEntryIndex(), ¤t); |
| + TrackNavigationIds(current); |
| + |
| if (local_tab_pool_out_of_sync_) { |
| // If our tab pool is corrupt, pay the price of a full re-association to |
| // fix things up. This takes care of the new tab modification as well. |
| @@ -1285,6 +1296,22 @@ void SessionsSyncManager::DoGarbageCollection() { |
| sync_processor_->ProcessSyncChanges(FROM_HERE, changes); |
| } |
| +void SessionsSyncManager::AddGlobalIdChangeObserver( |
| + syncer::GlobalIdChange callback) { |
| + global_id_change_observers_.push_back(std::move(callback)); |
| +} |
| + |
| +int64_t SessionsSyncManager::GetLatestGlobalId(int64_t global_id) { |
| + auto g2u_iter = global_to_unique_.find(global_id); |
| + if (g2u_iter != global_to_unique_.end()) { |
|
Patrick Noland
2017/06/28 22:44:37
This might look better as if (auto g2u_iter = ...
skym
2017/07/05 19:14:28
Acknowledged.
|
| + auto u2g_iter = unique_to_current_global_.find(g2u_iter->second); |
| + if (u2g_iter != unique_to_current_global_.end()) { |
| + return u2g_iter->second; |
| + } |
| + } |
| + return global_id; |
| +} |
| + |
| // static |
| std::string SessionsSyncManager::TagHashFromSpecifics( |
| const sync_pb::SessionSpecifics& specifics) { |
| @@ -1292,4 +1319,75 @@ std::string SessionsSyncManager::TagHashFromSpecifics( |
| TagFromSpecifics(specifics)); |
| } |
| +void SessionsSyncManager::TrackNavigationIds( |
| + const sessions::SerializedNavigationEntry& current) { |
| + // The expectation is that global_id will update for a given unique_id, which |
| + // should accurately and uniquely represent a single navigation. It is |
| + // theoretically possible for two unique_ids to map to the same global_id, but |
| + // hopefully rare enough that it doesn't cause much harm. Lets record metrics |
| + // verify this theory. |
| + int64_t global_id = current.timestamp().ToInternalValue(); |
| + // It is possible that the global_id has not been set yet for this navigation. |
| + // In this case there's nothing here for us to track yet. |
| + if (global_id == 0) { |
| + return; |
| + } |
| + |
| + int unique_id = current.unique_id(); |
| + DCHECK_NE(0, unique_id); |
| + |
| + auto g2u_iter = global_to_unique_.find(global_id); |
| + if (g2u_iter == global_to_unique_.end()) { |
| + global_to_unique_.insert(g2u_iter, std::make_pair(global_id, unique_id)); |
| + } else if (g2u_iter->second != unique_id) { |
| + UMA_HISTOGRAM_COUNTS("Sync.GlobalIdConflict", 1); |
|
Steven Holte
2017/06/28 18:59:45
UMA_HISTOGRAM_COUNTS is an alias for UMA_HISTOGRAM
skym
2017/07/05 19:14:28
Done, switched to UMA_HISTOGRAM_ENUMERATION. Wasn'
|
| + } |
| + |
| + auto u2g_iter = unique_to_current_global_.find(unique_id); |
| + if (u2g_iter == unique_to_current_global_.end()) { |
| + unique_to_current_global_.insert(u2g_iter, |
|
Patrick Noland
2017/06/28 22:44:37
if you use base::flat_map (see https://cs.chromium
skym
2017/07/05 19:14:28
I think it'd be a bit confusing to have these two
|
| + std::make_pair(unique_id, global_id)); |
| + } else if (u2g_iter->second != global_id) { |
| + // Remember the old_global_id before we insert and invalidate out iter. |
| + int64_t old_global_id = u2g_iter->second; |
| + |
| + // TODO(skym): Use insert_or_assign with hint once on C++17. |
| + unique_to_current_global_[unique_id] = global_id; |
| + |
| + // This should be done after updating unique_to_current_global_ in case one |
| + // of our observers calls into GetLatestGlobalId(). |
| + for (auto& observer : global_id_change_observers_) { |
| + observer.Run(old_global_id, global_id); |
| + } |
| + } |
| + |
| + CleanupNavigationTracking(); |
| +} |
| + |
| +void SessionsSyncManager::CleanupNavigationTracking() { |
| + DCHECK(kNavigationTrackingCleanupThreshold > |
| + kNavigationTrackingCleanupAmount); |
| + |
| + // |global_to_unique_| is implicitly ordered by least recently created, which |
| + // means we can drop from the beginning. |
| + if (global_to_unique_.size() > kNavigationTrackingCleanupThreshold) { |
|
Patrick Noland
2017/06/28 22:44:37
Can you use the range-based erase here?
skym
2017/07/05 19:14:28
Done.
|
| + for (int i = 0; i < kNavigationTrackingCleanupAmount; ++i) { |
| + global_to_unique_.erase(global_to_unique_.begin()); |
| + } |
| + |
| + // While |unique_id|s do get bigger for the most part, this isn't a great |
| + // thing to make assumptions about, and an old tab may get refreshed often |
| + // and still be very important. So instead just delete anything that's |
| + // orphaned from |global_to_unique_|. |
| + auto u2g_iter = unique_to_current_global_.begin(); |
| + while (u2g_iter != unique_to_current_global_.end()) { |
|
Patrick Noland
2017/06/28 22:44:37
I think you can use base::EraseIf here
skym
2017/07/05 19:14:28
Done.
|
| + if (global_to_unique_.find(u2g_iter->second) == global_to_unique_.end()) { |
| + u2g_iter = unique_to_current_global_.erase(u2g_iter); |
| + } else { |
| + ++u2g_iter; |
| + } |
| + } |
| + } |
| +} |
| + |
| }; // namespace sync_sessions |