sessions_global_id_mapper.cc 3.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104
  1. // Copyright 2018 The Chromium Authors. All rights reserved.
  2. // Use of this source code is governed by a BSD-style license that can be
  3. // found in the LICENSE file.
  4. #include "components/sync_sessions/sessions_global_id_mapper.h"
  5. #include <utility>
  6. #include "base/containers/contains.h"
  7. #include "base/containers/cxx20_erase.h"
  8. namespace sync_sessions {
  9. namespace {
  10. // Clean up navigation tracking when we have over this many global_ids.
  11. const size_t kNavigationTrackingCleanupThreshold = 100;
  12. // When we clean up navigation tracking, delete this many global_ids.
  13. const int kNavigationTrackingCleanupAmount = 10;
  14. } // namespace
  15. SessionsGlobalIdMapper::SessionsGlobalIdMapper() = default;
  16. SessionsGlobalIdMapper::~SessionsGlobalIdMapper() = default;
  17. void SessionsGlobalIdMapper::AddGlobalIdChangeObserver(
  18. syncer::GlobalIdChange callback) {
  19. global_id_change_observers_.push_back(std::move(callback));
  20. }
  21. int64_t SessionsGlobalIdMapper::GetLatestGlobalId(int64_t global_id) {
  22. auto g2u_iter = global_to_unique_.find(global_id);
  23. if (g2u_iter != global_to_unique_.end()) {
  24. auto u2g_iter = unique_to_current_global_.find(g2u_iter->second);
  25. if (u2g_iter != unique_to_current_global_.end()) {
  26. return u2g_iter->second;
  27. }
  28. }
  29. return global_id;
  30. }
  31. void SessionsGlobalIdMapper::TrackNavigationId(const base::Time& timestamp,
  32. int unique_id) {
  33. // The expectation is that global_id will update for a given unique_id, which
  34. // should accurately and uniquely represent a single navigation. It is
  35. // theoretically possible for two unique_ids to map to the same global_id, but
  36. // hopefully rare enough that it doesn't cause much harm. Lets record metrics
  37. // verify this theory.
  38. int64_t global_id = timestamp.ToInternalValue();
  39. // It is possible that the global_id has not been set yet for this navigation.
  40. // In this case there's nothing here for us to track yet.
  41. if (global_id == 0) {
  42. return;
  43. }
  44. DCHECK_NE(0, unique_id);
  45. global_to_unique_.emplace(global_id, unique_id);
  46. auto u2g_iter = unique_to_current_global_.find(unique_id);
  47. if (u2g_iter == unique_to_current_global_.end()) {
  48. unique_to_current_global_.insert(u2g_iter,
  49. std::make_pair(unique_id, global_id));
  50. } else if (u2g_iter->second != global_id) {
  51. // Remember the old_global_id before we insert and invalidate out iter.
  52. int64_t old_global_id = u2g_iter->second;
  53. // TODO(skym): Use insert_or_assign with hint once on C++17.
  54. unique_to_current_global_[unique_id] = global_id;
  55. // This should be done after updating unique_to_current_global_ in case one
  56. // of our observers calls into GetLatestGlobalId().
  57. for (auto& observer : global_id_change_observers_) {
  58. observer.Run(old_global_id, global_id);
  59. }
  60. }
  61. CleanupNavigationTracking();
  62. }
  63. void SessionsGlobalIdMapper::CleanupNavigationTracking() {
  64. DCHECK(kNavigationTrackingCleanupThreshold >
  65. kNavigationTrackingCleanupAmount);
  66. // |global_to_unique_| is implicitly ordered by least recently created, which
  67. // means we can drop from the beginning.
  68. if (global_to_unique_.size() > kNavigationTrackingCleanupThreshold) {
  69. auto iter = global_to_unique_.begin();
  70. std::advance(iter, kNavigationTrackingCleanupAmount);
  71. global_to_unique_.erase(global_to_unique_.begin(), iter);
  72. // While |unique_id|s do get bigger for the most part, this isn't a great
  73. // thing to make assumptions about, and an old tab may get refreshed often
  74. // and still be very important. So instead just delete anything that's
  75. // orphaned from |global_to_unique_|.
  76. base::EraseIf(unique_to_current_global_,
  77. [this](const std::pair<int, int64_t> kv) {
  78. return !base::Contains(global_to_unique_, kv.second);
  79. });
  80. }
  81. }
  82. } // namespace sync_sessions