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 |