blob: 09b7cd94c61a8d9a7f81b8fe9f356bf114ed1760 [file] [log] [blame]
Avi Drissman8ba1bad2022-09-13 19:22:361// Copyright 2014 The Chromium Authors
[email protected]bc5223d2013-08-20 01:42:522// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
maxbogue8ef25082015-11-16 19:09:585#include "components/sync_sessions/tab_node_pool.h"
[email protected]bc5223d2013-08-20 01:42:526
zea9b42f4312017-03-01 19:15:447#include <algorithm>
Mikel Astizeca64c982018-09-27 13:50:058#include <limits>
Mikel Astiz07c2f922019-03-29 14:12:569#include <utility>
zea9b42f4312017-03-01 19:15:4410
[email protected]bc5223d2013-08-20 01:42:5211#include "base/logging.h"
Max Boguefef332d2016-07-28 22:09:0912#include "components/sync/base/model_type.h"
13#include "components/sync/protocol/session_specifics.pb.h"
pnoland1901afa52017-03-23 21:24:0014#include "components/sync_sessions/synced_tab_delegate.h"
[email protected]bc5223d2013-08-20 01:42:5215
maxboguea79d99b72016-09-15 15:59:1616namespace sync_sessions {
[email protected]bc5223d2013-08-20 01:42:5217
maxbogue8ef25082015-11-16 19:09:5818TabNodePool::TabNodePool() : max_used_tab_node_id_(kInvalidTabNodeID) {}
[email protected]bc5223d2013-08-20 01:42:5219
20// static
21// We start vending tab node IDs at 0.
[email protected]f4fa3fc2014-04-16 23:16:0422const int TabNodePool::kInvalidTabNodeID = -1;
[email protected]bc5223d2013-08-20 01:42:5223
Victor Hugo Vianna Silva988fe7322021-09-23 18:16:5624TabNodePool::~TabNodePool() = default;
[email protected]bc5223d2013-08-20 01:42:5225
[email protected]f4fa3fc2014-04-16 23:16:0426void TabNodePool::AddTabNode(int tab_node_id) {
[email protected]bc5223d2013-08-20 01:42:5227 DCHECK_GT(tab_node_id, kInvalidTabNodeID);
Mikel Astizeca64c982018-09-27 13:50:0528 DCHECK_LE(tab_node_id, max_used_tab_node_id_);
[email protected]bc5223d2013-08-20 01:42:5229 DCHECK(nodeid_tabid_map_.find(tab_node_id) == nodeid_tabid_map_.end());
zea9b42f4312017-03-01 19:15:4430 DVLOG(1) << "Adding tab node " << tab_node_id << " to pool.";
zea9b42f4312017-03-01 19:15:4431 free_nodes_pool_.insert(tab_node_id);
Mikel Astizeca64c982018-09-27 13:50:0532 missing_nodes_pool_.erase(tab_node_id);
[email protected]bc5223d2013-08-20 01:42:5233}
34
Mikel Astize023c572018-03-28 07:56:5635void TabNodePool::AssociateTabNode(int tab_node_id, SessionID tab_id) {
[email protected]bc5223d2013-08-20 01:42:5236 DCHECK_GT(tab_node_id, kInvalidTabNodeID);
Mikel Astize023c572018-03-28 07:56:5637 DCHECK(tab_id.is_valid());
zea9b42f4312017-03-01 19:15:4438
39 // This is a new node association, the sync node should be free.
40 // Remove node from free node pool and then associate it with the tab.
jdoerrie3feb1852018-10-05 12:16:4441 auto it = free_nodes_pool_.find(tab_node_id);
zea9b42f4312017-03-01 19:15:4442 DCHECK(it != free_nodes_pool_.end());
43 free_nodes_pool_.erase(it);
44
[email protected]bc5223d2013-08-20 01:42:5245 DCHECK(nodeid_tabid_map_.find(tab_node_id) == nodeid_tabid_map_.end());
Mikel Astize023c572018-03-28 07:56:5646 DVLOG(1) << "Associating tab node " << tab_node_id << " with tab "
47 << tab_id.id();
48 nodeid_tabid_map_.emplace(tab_node_id, tab_id);
zea9b42f4312017-03-01 19:15:4449 tabid_nodeid_map_[tab_id] = tab_node_id;
[email protected]bc5223d2013-08-20 01:42:5250}
51
Mikel Astizaadda5912018-04-13 11:14:3752int TabNodePool::GetTabNodeIdFromTabId(SessionID tab_id) const {
jdoerrie3feb1852018-10-05 12:16:4453 auto it = tabid_nodeid_map_.find(tab_id);
Mikel Astizaadda5912018-04-13 11:14:3754 if (it != tabid_nodeid_map_.end()) {
55 return it->second;
zea9b42f4312017-03-01 19:15:4456 }
Mikel Astizaadda5912018-04-13 11:14:3757 return kInvalidTabNodeID;
[email protected]bc5223d2013-08-20 01:42:5258}
59
Mikel Astize023c572018-03-28 07:56:5660void TabNodePool::FreeTab(SessionID tab_id) {
61 DCHECK(tab_id.is_valid());
jdoerrie3feb1852018-10-05 12:16:4462 auto it = tabid_nodeid_map_.find(tab_id);
zea9b42f4312017-03-01 19:15:4463 if (it == tabid_nodeid_map_.end()) {
64 return; // Already freed.
65 }
[email protected]bc5223d2013-08-20 01:42:5266
zea9b42f4312017-03-01 19:15:4467 int tab_node_id = it->second;
Mikel Astize023c572018-03-28 07:56:5668 DVLOG(1) << "Freeing tab " << tab_id.id() << " at node " << tab_node_id;
zea9b42f4312017-03-01 19:15:4469 nodeid_tabid_map_.erase(nodeid_tabid_map_.find(tab_node_id));
70 tabid_nodeid_map_.erase(it);
[email protected]bc5223d2013-08-20 01:42:5271 free_nodes_pool_.insert(tab_node_id);
[email protected]bc5223d2013-08-20 01:42:5272}
73
Mikel Astizcb491c4cb2018-05-24 13:08:2674int TabNodePool::AssociateWithFreeTabNode(SessionID tab_id) {
75 DCHECK_EQ(0U, tabid_nodeid_map_.count(tab_id));
76
Mikel Astizaadda5912018-04-13 11:14:3777 int tab_node_id;
Mikel Astizeca64c982018-09-27 13:50:0578 if (free_nodes_pool_.empty() && missing_nodes_pool_.empty()) {
79 // Tab pool has neither free nodes nor "holes" within the ID range, so
80 // allocate a new one by extending the range.
Mikel Astizaadda5912018-04-13 11:14:3781 tab_node_id = ++max_used_tab_node_id_;
82 AddTabNode(tab_node_id);
83 } else {
Mikel Astizeca64c982018-09-27 13:50:0584 tab_node_id = std::numeric_limits<int>::max();
85 // Take the smallest available, either from the freed pool or from IDs that
86 // were never associated before (but are within 0..max_used_tab_node_id_).
87 if (!free_nodes_pool_.empty()) {
88 tab_node_id = *free_nodes_pool_.begin();
Mikel Astiz5dc588e2018-10-05 13:06:0289 DCHECK_LE(tab_node_id, max_used_tab_node_id_);
Mikel Astizeca64c982018-09-27 13:50:0590 }
91 if (!missing_nodes_pool_.empty() &&
92 *missing_nodes_pool_.begin() < tab_node_id) {
93 tab_node_id = *missing_nodes_pool_.begin();
Mikel Astiz5dc588e2018-10-05 13:06:0294 DCHECK_LE(tab_node_id, max_used_tab_node_id_);
Mikel Astizeca64c982018-09-27 13:50:0595 AddTabNode(tab_node_id);
96 }
Mikel Astizaadda5912018-04-13 11:14:3797 }
98
99 AssociateTabNode(tab_node_id, tab_id);
100 return tab_node_id;
101}
102
Mikel Astize023c572018-03-28 07:56:56103void TabNodePool::ReassociateTabNode(int tab_node_id, SessionID tab_id) {
zea9b42f4312017-03-01 19:15:44104 DCHECK_GT(tab_node_id, kInvalidTabNodeID);
Mikel Astize023c572018-03-28 07:56:56105 DCHECK(tab_id.is_valid());
zea9b42f4312017-03-01 19:15:44106
107 auto tabid_it = tabid_nodeid_map_.find(tab_id);
108 if (tabid_it != tabid_nodeid_map_.end()) {
109 if (tabid_it->second == tab_node_id) {
110 return; // Already associated properly.
111 } else {
112 // Another node is already associated with this tab. Free it.
113 FreeTab(tab_id);
114 }
zea9e833632017-02-10 18:59:11115 }
zea9b42f4312017-03-01 19:15:44116
117 auto nodeid_it = nodeid_tabid_map_.find(tab_node_id);
118 if (nodeid_it != nodeid_tabid_map_.end()) {
119 // This node was already associated with another tab. Free it.
120 FreeTab(nodeid_it->second);
121 } else {
Mikel Astizeca64c982018-09-27 13:50:05122 // This is a new tab node. Add it before association. We also need to
123 // remember the "holes".
124 for (int missing_tab_node_id = max_used_tab_node_id_ + 1;
125 missing_tab_node_id < tab_node_id; ++missing_tab_node_id) {
126 missing_nodes_pool_.insert(missing_tab_node_id);
127 }
128 max_used_tab_node_id_ = std::max(max_used_tab_node_id_, tab_node_id);
zea9b42f4312017-03-01 19:15:44129 AddTabNode(tab_node_id);
130 }
131
132 AssociateTabNode(tab_node_id, tab_id);
[email protected]bc5223d2013-08-20 01:42:52133}
134
Mikel Astize023c572018-03-28 07:56:56135SessionID TabNodePool::GetTabIdFromTabNodeId(int tab_node_id) const {
jdoerrie3feb1852018-10-05 12:16:44136 auto it = nodeid_tabid_map_.find(tab_node_id);
[email protected]bc5223d2013-08-20 01:42:52137 if (it != nodeid_tabid_map_.end()) {
138 return it->second;
139 }
Mikel Astize023c572018-03-28 07:56:56140 return SessionID::InvalidValue();
[email protected]bc5223d2013-08-20 01:42:52141}
142
Mohamed Amir Yosef7d39a722019-06-07 08:51:21143std::set<int> TabNodePool::CleanupFreeTabNodes() {
Mahmoud Rashadfa26bb1d2022-02-11 20:17:41144 // Convert all free nodes into missing nodes, each representing a deletion.
145 missing_nodes_pool_.insert(free_nodes_pool_.begin(), free_nodes_pool_.end());
146 std::set<int> deleted_node_ids = std::move(free_nodes_pool_);
147 free_nodes_pool_.clear();
Mikel Astiz5dc588e2018-10-05 13:06:02148
Mahmoud Rashadfa26bb1d2022-02-11 20:17:41149 // As an optimization to save memory, update |max_used_tab_node_id_| and
150 // shrink |missing_nodes_pool_| appropriately.
151 if (nodeid_tabid_map_.empty()) {
152 max_used_tab_node_id_ = kInvalidTabNodeID;
153 } else {
154 max_used_tab_node_id_ = nodeid_tabid_map_.rbegin()->first;
Mikel Astiz5dc588e2018-10-05 13:06:02155 }
156
Mahmoud Rashadfa26bb1d2022-02-11 20:17:41157 missing_nodes_pool_.erase(
158 missing_nodes_pool_.upper_bound(max_used_tab_node_id_),
159 missing_nodes_pool_.end());
Mikel Astizeca64c982018-09-27 13:50:05160
Mikel Astiz07c2f922019-03-29 14:12:56161 return deleted_node_ids;
[email protected]bc5223d2013-08-20 01:42:52162}
163
Mikel Astizdb744b642018-04-20 10:17:14164void TabNodePool::DeleteTabNode(int tab_node_id) {
jdoerrie3feb1852018-10-05 12:16:44165 auto it = nodeid_tabid_map_.find(tab_node_id);
Mikel Astizdb744b642018-04-20 10:17:14166 if (it == nodeid_tabid_map_.end()) {
167 free_nodes_pool_.erase(tab_node_id);
168 return;
169 }
170
171 DCHECK_EQ(0U, free_nodes_pool_.count(tab_node_id));
172
173 SessionID tab_id = it->second;
174 DVLOG(1) << "Deleting node " << tab_node_id << " with tab ID " << tab_id;
175 tabid_nodeid_map_.erase(tab_id);
176 nodeid_tabid_map_.erase(it);
177}
178
Mikel Astizdb744b642018-04-20 10:17:14179std::set<int> TabNodePool::GetAllTabNodeIds() const {
180 std::set<int> tab_node_ids = free_nodes_pool_;
Victor Hugo Vianna Silva98c8fea2022-02-09 17:45:58181 for (const auto& [tab_node_id, tab_id] : nodeid_tabid_map_) {
182 tab_node_ids.insert(tab_node_id);
Mikel Astizdb744b642018-04-20 10:17:14183 }
184 return tab_node_ids;
185}
186
Mikel Astiz5dc588e2018-10-05 13:06:02187int TabNodePool::GetMaxUsedTabNodeIdForTest() const {
188 return max_used_tab_node_id_;
189}
190
maxboguea79d99b72016-09-15 15:59:16191} // namespace sync_sessions