Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(369)

Side by Side Diff: chrome/browser/sync/glue/session_model_associator.cc

Issue 16421003: [Sync] Add logic to reassociate tab nodes after restart. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Fix win compile, rename uint -> size_t. Created 7 years, 6 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
OLDNEW
1 // Copyright 2012 The Chromium Authors. All rights reserved. 1 // Copyright 2012 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 "chrome/browser/sync/glue/session_model_associator.h" 5 #include "chrome/browser/sync/glue/session_model_associator.h"
6 6
7 #include <algorithm> 7 #include <algorithm>
8 #include <set> 8 #include <set>
9 #include <utility> 9 #include <utility>
10 10
(...skipping 162 matching lines...) Expand 10 before | Expand all | Expand 10 after
173 sync_pb::SessionHeader* header_s = specifics.mutable_header(); 173 sync_pb::SessionHeader* header_s = specifics.mutable_header();
174 SyncedSession* current_session = 174 SyncedSession* current_session =
175 synced_session_tracker_.GetSession(local_tag); 175 synced_session_tracker_.GetSession(local_tag);
176 current_session->modified_time = base::Time::Now(); 176 current_session->modified_time = base::Time::Now();
177 header_s->set_client_name(current_session_name_); 177 header_s->set_client_name(current_session_name_);
178 header_s->set_device_type(DeviceInfo::GetLocalDeviceType()); 178 header_s->set_device_type(DeviceInfo::GetLocalDeviceType());
179 179
180 synced_session_tracker_.ResetSessionTracking(local_tag); 180 synced_session_tracker_.ResetSessionTracking(local_tag);
181 std::set<SyncedWindowDelegate*> windows = 181 std::set<SyncedWindowDelegate*> windows =
182 SyncedWindowDelegate::GetSyncedWindowDelegates(); 182 SyncedWindowDelegate::GetSyncedWindowDelegates();
183 std::set<int64> used_sync_ids;
183 for (std::set<SyncedWindowDelegate*>::const_iterator i = 184 for (std::set<SyncedWindowDelegate*>::const_iterator i =
184 windows.begin(); i != windows.end(); ++i) { 185 windows.begin(); i != windows.end(); ++i) {
185 // Make sure the window has tabs and a viewable window. The viewable window 186 // Make sure the window has tabs and a viewable window. The viewable window
186 // check is necessary because, for example, when a browser is closed the 187 // check is necessary because, for example, when a browser is closed the
187 // destructor is not necessarily run immediately. This means its possible 188 // destructor is not necessarily run immediately. This means its possible
188 // for us to get a handle to a browser that is about to be removed. If 189 // for us to get a handle to a browser that is about to be removed. If
189 // the tab count is 0 or the window is NULL, the browser is about to be 190 // the tab count is 0 or the window is NULL, the browser is about to be
190 // deleted, so we ignore it. 191 // deleted, so we ignore it.
191 if (ShouldSyncWindow(*i) && (*i)->GetTabCount() && (*i)->HasWindow()) { 192 if (ShouldSyncWindow(*i) && (*i)->GetTabCount() && (*i)->HasWindow()) {
192 sync_pb::SessionWindow window_s; 193 sync_pb::SessionWindow window_s;
(...skipping 10 matching lines...) Expand all
203 sync_pb::SessionWindow_BrowserType_TYPE_TABBED); 204 sync_pb::SessionWindow_BrowserType_TYPE_TABBED);
204 } else { 205 } else {
205 window_s.set_browser_type( 206 window_s.set_browser_type(
206 sync_pb::SessionWindow_BrowserType_TYPE_POPUP); 207 sync_pb::SessionWindow_BrowserType_TYPE_POPUP);
207 } 208 }
208 209
209 // Store the order of tabs. 210 // Store the order of tabs.
210 bool found_tabs = false; 211 bool found_tabs = false;
211 for (int j = 0; j < (*i)->GetTabCount(); ++j) { 212 for (int j = 0; j < (*i)->GetTabCount(); ++j) {
212 SessionID::id_type tab_id = (*i)->GetTabIdAt(j); 213 SessionID::id_type tab_id = (*i)->GetTabIdAt(j);
214 SyncedTabDelegate* synced_tab = (*i)->GetTabAt(j);
215
216 // GetTabAt can return a null tab, in case tab is null just skip it.
Nicolas Zea 2013/06/19 21:35:33 "tab; in that case just skip it."
shashi 2013/06/20 00:49:32 Done.
217 if (!synced_tab)
218 continue;
219
220 if (!synced_tab->HasWebContents()) {
221 // For tabs without webcontents update the tab_id, tab_id could have
Nicolas Zea 2013/06/19 21:35:33 "For tabs without WebContents, update the |tab_id|
shashi 2013/06/20 00:49:32 Done.
222 // changed after a session restore.
223 if (synced_tab->GetSyncId() > 0 &&
Nicolas Zea 2013/06/19 21:35:33 != syncer::kInvalidId Maybe worth checking whether
shashi 2013/06/20 00:49:32 I cannot check != syncer::kInvalidId, since TabCon
224 UpdateTabIdIfNecessary(synced_tab->GetSyncId(), tab_id)) {
Nicolas Zea 2013/06/19 21:35:33 why is this part of the condition? Whether the tab
shashi 2013/06/20 00:49:32 Done, removed the condition. I was guarding agains
225 found_tabs = true;
226 used_sync_ids.insert(synced_tab->GetSyncId());
227 window_s.add_tab(tab_id);
228 }
229 continue;
230 }
213 231
214 if (reload_tabs) { 232 if (reload_tabs) {
215 SyncedTabDelegate* tab = (*i)->GetTabAt(j);
216 // It's possible for GetTabAt to return a tab which has no web 233 // It's possible for GetTabAt to return a tab which has no web
217 // contents. We can assume this means the tab already existed but 234 // contents. We can assume this means the tab already existed but
218 // hasn't changed, so no need to reassociate. 235 // hasn't changed, so no need to reassociate.
219 if (tab && tab->HasWebContents() && !AssociateTab(*tab, error)) { 236 if (synced_tab->HasWebContents() &&
237 !AssociateTab(synced_tab, error)) {
220 // Association failed. Either we need to re-associate, or this is an 238 // Association failed. Either we need to re-associate, or this is an
221 // unrecoverable error. 239 // unrecoverable error.
222 return false; 240 return false;
223 } 241 }
224 } 242 }
225 243
226 // If the tab is valid, it would have been added to the tracker either 244 // If the tab is valid, it would have been added to the tracker either
227 // by the above AssociateTab call (at association time), or by the 245 // by the above AssociateTab call (at association time), or by the
228 // change processor calling AssociateTab for all modified tabs. 246 // change processor calling AssociateTab for all modified tabs.
229 // Therefore, we can key whether this window has valid tabs based on 247 // Therefore, we can key whether this window has valid tabs based on
230 // the tab's presence in the tracker. 248 // the tab's presence in the tracker.
231 const SessionTab* tab = NULL; 249 const SessionTab* tab = NULL;
232 if (synced_session_tracker_.LookupSessionTab(local_tag, tab_id, &tab)) { 250 if (synced_session_tracker_.LookupSessionTab(local_tag, tab_id, &tab)) {
233 found_tabs = true; 251 found_tabs = true;
252 used_sync_ids.insert(synced_tab->GetSyncId());
234 window_s.add_tab(tab_id); 253 window_s.add_tab(tab_id);
235 } 254 }
236 } 255 }
237 // Only add a window if it contains valid tabs. 256 // Only add a window if it contains valid tabs.
238 if (found_tabs) { 257 if (found_tabs) {
239 sync_pb::SessionWindow* header_window = header_s->add_window(); 258 sync_pb::SessionWindow* header_window = header_s->add_window();
240 *header_window = window_s; 259 *header_window = window_s;
241 260
242 // Update this window's representation in the synced session tracker. 261 // Update this window's representation in the synced session tracker.
243 synced_session_tracker_.PutWindowInSession(local_tag, window_id); 262 synced_session_tracker_.PutWindowInSession(local_tag, window_id);
244 PopulateSessionWindowFromSpecifics( 263 PopulateSessionWindowFromSpecifics(
245 local_tag, 264 local_tag,
246 window_s, 265 window_s,
247 base::Time::Now(), 266 base::Time::Now(),
248 current_session->windows[window_id], 267 current_session->windows[window_id],
249 &synced_session_tracker_); 268 &synced_session_tracker_);
250 } 269 }
251 } 270 }
252 } 271 }
272
273 // Free old sync nodes.
274 tab_pool_.FreeUnusedTabNodes(used_sync_ids);
253 // Free memory for closed windows and tabs. 275 // Free memory for closed windows and tabs.
254 synced_session_tracker_.CleanupSession(local_tag); 276 synced_session_tracker_.CleanupSession(local_tag);
255 277
256 syncer::WriteTransaction trans(FROM_HERE, sync_service_->GetUserShare()); 278 syncer::WriteTransaction trans(FROM_HERE, sync_service_->GetUserShare());
257 syncer::WriteNode header_node(&trans); 279 syncer::WriteNode header_node(&trans);
258 if (header_node.InitByIdLookup(local_session_syncid_) != 280 if (header_node.InitByIdLookup(local_session_syncid_) !=
259 syncer::BaseNode::INIT_OK) { 281 syncer::BaseNode::INIT_OK) {
260 if (error) { 282 if (error) {
261 *error = error_handler_->CreateAndUploadError( 283 *error = error_handler_->CreateAndUploadError(
262 FROM_HERE, 284 FROM_HERE,
(...skipping 15 matching lines...) Expand all
278 return window->IsTypeTabbed() || window->IsTypePopup(); 300 return window->IsTypeTabbed() || window->IsTypePopup();
279 } 301 }
280 302
281 bool SessionModelAssociator::AssociateTabs( 303 bool SessionModelAssociator::AssociateTabs(
282 const std::vector<SyncedTabDelegate*>& tabs, 304 const std::vector<SyncedTabDelegate*>& tabs,
283 syncer::SyncError* error) { 305 syncer::SyncError* error) {
284 DCHECK(CalledOnValidThread()); 306 DCHECK(CalledOnValidThread());
285 for (std::vector<SyncedTabDelegate*>::const_iterator i = tabs.begin(); 307 for (std::vector<SyncedTabDelegate*>::const_iterator i = tabs.begin();
286 i != tabs.end(); 308 i != tabs.end();
287 ++i) { 309 ++i) {
288 if (!AssociateTab(**i, error)) 310 if (!AssociateTab(*i, error))
289 return false; 311 return false;
290 } 312 }
291 if (waiting_for_change_) QuitLoopForSubtleTesting(); 313 if (waiting_for_change_) QuitLoopForSubtleTesting();
292 return true; 314 return true;
293 } 315 }
294 316
295 bool SessionModelAssociator::AssociateTab(const SyncedTabDelegate& tab, 317 bool SessionModelAssociator::AssociateTab(SyncedTabDelegate* tab,
296 syncer::SyncError* error) { 318 syncer::SyncError* error) {
297 DCHECK(CalledOnValidThread()); 319 DCHECK(CalledOnValidThread());
320 CHECK(tab);
Nicolas Zea 2013/06/19 21:35:33 nit: I don't think this Check is necessary. We'd s
shashi 2013/06/20 00:49:32 Done. Sometimes though, the stack trace of a crash
321 DCHECK(tab->HasWebContents());
298 int64 sync_id; 322 int64 sync_id;
299 SessionID::id_type tab_id = tab.GetSessionId(); 323 SessionID::id_type tab_id = tab->GetSessionId();
300 if (tab.IsBeingDestroyed()) { 324 if (tab->IsBeingDestroyed()) {
301 // This tab is closing. 325 // This tab is closing.
302 TabLinksMap::iterator tab_iter = tab_map_.find(tab_id); 326 TabLinksMap::iterator tab_iter = tab_map_.find(tab_id);
303 if (tab_iter == tab_map_.end()) { 327 if (tab_iter == tab_map_.end()) {
304 // We aren't tracking this tab (for example, sync setting page). 328 // We aren't tracking this tab (for example, sync setting page).
305 return true; 329 return true;
306 } 330 }
307 tab_pool_.FreeTabNode(tab_iter->second->sync_id()); 331 tab_pool_.FreeTabNode(tab_iter->second->sync_id());
308 tab_map_.erase(tab_iter); 332 tab_map_.erase(tab_iter);
309 return true; 333 return true;
310 } 334 }
311 335
312 if (!ShouldSyncTab(tab)) 336 if (!ShouldSyncTab(*tab))
313 return true; 337 return true;
314 338
315 TabLinksMap::iterator tab_map_iter = tab_map_.find(tab_id); 339 TabLinksMap::iterator tab_map_iter = tab_map_.find(tab_id);
316 TabLink* tab_link = NULL; 340 TabLink* tab_link = NULL;
317 if (tab_map_iter == tab_map_.end()) { 341 if (tab_map_iter == tab_map_.end()) {
318 // This is a new tab, get a sync node for it. 342 sync_id = tab->GetSyncId();
319 sync_id = tab_pool_.GetFreeTabNode(); 343 // if there is an old sync node for the tab, reuse it.
320 if (sync_id == syncer::kInvalidId) { 344 if (!tab_pool_.ReassociateTabNode(sync_id, tab_id)) {
321 if (error) { 345 // This is a new tab, get a sync node for it.
322 *error = error_handler_->CreateAndUploadError( 346 sync_id = tab_pool_.GetFreeTabNode();
323 FROM_HERE, 347 if (sync_id == syncer::kInvalidId) {
324 "Received invalid tab node from tab pool.", 348 if (error) {
325 model_type()); 349 *error = error_handler_->CreateAndUploadError(
350 FROM_HERE,
351 "Received invalid tab node from tab pool.",
352 model_type());
353 }
354 return false;
326 } 355 }
327 return false; 356 tab_pool_.AssociateTabNode(sync_id, tab_id);
328 } 357 }
329 tab_link = new TabLink(sync_id, &tab); 358 tab_link = new TabLink(sync_id, tab);
330 tab_map_[tab_id] = make_linked_ptr<TabLink>(tab_link); 359 tab_map_[tab_id] = make_linked_ptr<TabLink>(tab_link);
360 tab->SetSyncId(sync_id);
Nicolas Zea 2013/06/19 21:35:33 move this into the if block? It's redundant for su
shashi 2013/06/20 00:49:32 Done. You are right, it is redundant for successfu
331 } else { 361 } else {
332 // This tab is already associated with a sync node, reuse it. 362 // This tab is already associated with a sync node, reuse it.
333 // Note: on some platforms the tab object may have changed, so we ensure 363 // Note: on some platforms the tab object may have changed, so we ensure
334 // the tab link is up to date. 364 // the tab link is up to date.
335 tab_link = tab_map_iter->second.get(); 365 tab_link = tab_map_iter->second.get();
336 tab_map_iter->second->set_tab(&tab); 366 tab_map_iter->second->set_tab(tab);
337 } 367 }
338 DCHECK(tab_link); 368 DCHECK(tab_link);
339 DCHECK_NE(tab_link->sync_id(), syncer::kInvalidId); 369 DCHECK_NE(tab_link->sync_id(), syncer::kInvalidId);
340 370
341 DVLOG(1) << "Reloading tab " << tab_id << " from window " 371 DVLOG(1) << "Reloading tab " << tab_id << " from window "
342 << tab.GetWindowId(); 372 << tab->GetWindowId();
343 return WriteTabContentsToSyncModel(tab_link, error); 373 return WriteTabContentsToSyncModel(tab_link, error);
344 } 374 }
345 375
346 // static 376 // static
347 GURL SessionModelAssociator::GetCurrentVirtualURL( 377 GURL SessionModelAssociator::GetCurrentVirtualURL(
348 const SyncedTabDelegate& tab_delegate) { 378 const SyncedTabDelegate& tab_delegate) {
349 const int current_index = tab_delegate.GetCurrentEntryIndex(); 379 const int current_index = tab_delegate.GetCurrentEntryIndex();
350 const int pending_index = tab_delegate.GetPendingEntryIndex(); 380 const int pending_index = tab_delegate.GetPendingEntryIndex();
351 const NavigationEntry* current_entry = 381 const NavigationEntry* current_entry =
352 (current_index == pending_index) ? 382 (current_index == pending_index) ?
(...skipping 371 matching lines...) Expand 10 before | Expand all | Expand 10 after
724 } else { 754 } else {
725 // This is previously stored local session information. 755 // This is previously stored local session information.
726 if (specifics.has_header() && 756 if (specifics.has_header() &&
727 local_session_syncid_ == syncer::kInvalidId) { 757 local_session_syncid_ == syncer::kInvalidId) {
728 // This is our previous header node, reuse it. 758 // This is our previous header node, reuse it.
729 local_session_syncid_ = id; 759 local_session_syncid_ = id;
730 if (specifics.header().has_client_name()) { 760 if (specifics.header().has_client_name()) {
731 current_session_name_ = specifics.header().client_name(); 761 current_session_name_ = specifics.header().client_name();
732 } 762 }
733 } else { 763 } else {
734 if (specifics.has_header()) { 764 if (specifics.has_header() || !specifics.has_tab() ||
735 LOG(WARNING) << "Found more than one session header node with local " 765 !specifics.has_tab_node_id() || !specifics.tab().has_tab_id()) {
736 << " tag."; 766 LOG(WARNING) << "Found invalid session node, deleting.";
737 } else if (!specifics.has_tab()) { 767 sync_node.Tombstone();
738 LOG(WARNING) << "Found local node with no header or tag field."; 768 } else {
769 // This is a valid old tab node, add it to the pool so it can be
770 // reused for reassociation.
771 SessionID tab_id;
772 tab_id.set_id(specifics.tab().tab_id());
773 tab_pool_.AddTabNode(id, tab_id, specifics.tab_node_id());
739 } 774 }
740
741 // TODO(zea): fix this once we add support for reassociating
742 // pre-existing tabs with pre-existing tab nodes. We'll need to load
743 // the tab_node_id and ensure the tab_pool_ keeps track of them.
744 sync_node.Tombstone();
745 } 775 }
746 } 776 }
747 id = next_id; 777 id = next_id;
748 } 778 }
749 779
750 // After updating from sync model all tabid's should be free.
751 DCHECK(tab_pool_.full());
752 return true; 780 return true;
753 } 781 }
754 782
755 void SessionModelAssociator::AssociateForeignSpecifics( 783 void SessionModelAssociator::AssociateForeignSpecifics(
756 const sync_pb::SessionSpecifics& specifics, 784 const sync_pb::SessionSpecifics& specifics,
757 const base::Time& modification_time) { 785 const base::Time& modification_time) {
758 DCHECK(CalledOnValidThread()); 786 DCHECK(CalledOnValidThread());
759 std::string foreign_session_tag = specifics.session_tag(); 787 std::string foreign_session_tag = specifics.session_tag();
760 if (foreign_session_tag == GetCurrentMachineTag() && !setup_for_test_) 788 if (foreign_session_tag == GetCurrentMachineTag() && !setup_for_test_)
761 return; 789 return;
(...skipping 382 matching lines...) Expand 10 before | Expand all | Expand 10 after
1144 } 1172 }
1145 1173
1146 bool SessionModelAssociator::CryptoReadyIfNecessary() { 1174 bool SessionModelAssociator::CryptoReadyIfNecessary() {
1147 // We only access the cryptographer while holding a transaction. 1175 // We only access the cryptographer while holding a transaction.
1148 syncer::ReadTransaction trans(FROM_HERE, sync_service_->GetUserShare()); 1176 syncer::ReadTransaction trans(FROM_HERE, sync_service_->GetUserShare());
1149 const syncer::ModelTypeSet encrypted_types = trans.GetEncryptedTypes(); 1177 const syncer::ModelTypeSet encrypted_types = trans.GetEncryptedTypes();
1150 return !encrypted_types.Has(SESSIONS) || 1178 return !encrypted_types.Has(SESSIONS) ||
1151 sync_service_->IsCryptographerReady(&trans); 1179 sync_service_->IsCryptographerReady(&trans);
1152 } 1180 }
1153 1181
1182 bool SessionModelAssociator::UpdateTabIdIfNecessary(
1183 int64 sync_id,
1184 SessionID::id_type new_tab_id) {
1185 DCHECK_GT(sync_id, 0);
1186 SessionID::id_type old_tab_id = tab_pool_.TabIDForSyncID(sync_id);
1187 if (old_tab_id != TabNodePool::kInvalidTabID && old_tab_id == new_tab_id) {
Nicolas Zea 2013/06/19 21:35:33 Why does it matter whether the tab id changed? Sho
shashi 2013/06/20 00:49:32 Done, in fact removed the return value. On 2013/06
1188 return true;
1189 }
1190
1191 // Rewrite tab id if required.
1192 syncer::WriteTransaction trans(FROM_HERE, sync_service_->GetUserShare());
1193 syncer::WriteNode tab_node(&trans);
1194 if (tab_node.InitByIdLookup(sync_id) == syncer::BaseNode::INIT_OK) {
1195 sync_pb::SessionSpecifics session_specifics =
1196 tab_node.GetSessionSpecifics();
1197 DCHECK(session_specifics.has_tab());
1198 if (session_specifics.has_tab()) {
1199 sync_pb::SessionTab* tab_s = session_specifics.mutable_tab();
1200 tab_s->set_tab_id(new_tab_id);
1201 tab_node.SetSessionSpecifics(session_specifics);
1202 // Update tab node pool with the new association.
1203 tab_pool_.ReassociateTabNode(sync_id, new_tab_id);
1204 return true;
1205 }
1206 }
1207 return false;
1208 }
1209
1154 } // namespace browser_sync 1210 } // namespace browser_sync
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698