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

Side by Side Diff: components/sync_sessions/sessions_sync_manager.cc

Issue 1877083002: [Sync] Moved tab_node_id tracking to session object and improved foreign session garbage collection. (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Created 4 years, 8 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
OLDNEW
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/metrics/field_trial.h" 10 #include "base/metrics/field_trial.h"
(...skipping 25 matching lines...) Expand all
36 36
37 // The maximum number of navigations in each direction we care to sync. 37 // The maximum number of navigations in each direction we care to sync.
38 const int kMaxSyncNavigationCount = 6; 38 const int kMaxSyncNavigationCount = 6;
39 39
40 // The URL at which the set of synced tabs is displayed. We treat it differently 40 // The URL at which the set of synced tabs is displayed. We treat it differently
41 // from all other URL's as accessing it triggers a sync refresh of Sessions. 41 // from all other URL's as accessing it triggers a sync refresh of Sessions.
42 const char kNTPOpenTabSyncURL[] = "chrome://newtab/#open_tabs"; 42 const char kNTPOpenTabSyncURL[] = "chrome://newtab/#open_tabs";
43 43
44 // Default number of days without activity after which a session is considered 44 // Default number of days without activity after which a session is considered
45 // stale and becomes a candidate for garbage collection. 45 // stale and becomes a candidate for garbage collection.
46 const size_t kDefaultStaleSessionThresholdDays = 14; // 2 weeks. 46 const int kDefaultStaleSessionThresholdDays = 14; // 2 weeks.
47 47
48 // Comparator function for use with std::sort that will sort tabs by 48 // Comparator function for use with std::sort that will sort tabs by
49 // descending timestamp (i.e., most recent first). 49 // descending timestamp (i.e., most recent first).
50 bool TabsRecencyComparator(const sessions::SessionTab* t1, 50 bool TabsRecencyComparator(const sessions::SessionTab* t1,
51 const sessions::SessionTab* t2) { 51 const sessions::SessionTab* t2) {
52 return t1->timestamp > t2->timestamp; 52 return t1->timestamp > t2->timestamp;
53 } 53 }
54 54
55 // Comparator function for use with std::sort that will sort sessions by 55 // Comparator function for use with std::sort that will sort sessions by
56 // descending modified_time (i.e., most recent first). 56 // descending modified_time (i.e., most recent first).
(...skipping 451 matching lines...) Expand 10 before | Expand all | Expand 10 after
508 // to avoid any possible ping-pong delete/reassociate sequence, but 508 // to avoid any possible ping-pong delete/reassociate sequence, but
509 // remember that this happened as our TabNodePool is inconsistent. 509 // remember that this happened as our TabNodePool is inconsistent.
510 local_tab_pool_out_of_sync_ = true; 510 local_tab_pool_out_of_sync_ = true;
511 LOG(WARNING) << "Local session data deleted. Ignoring until next " 511 LOG(WARNING) << "Local session data deleted. Ignoring until next "
512 << "local navigation event."; 512 << "local navigation event.";
513 } else if (session.has_header()) { 513 } else if (session.has_header()) {
514 // Disassociate only when header node is deleted. For tab node 514 // Disassociate only when header node is deleted. For tab node
515 // deletions, the header node will be updated and foreign tab will 515 // deletions, the header node will be updated and foreign tab will
516 // get deleted. 516 // get deleted.
517 DisassociateForeignSession(session.session_tag()); 517 DisassociateForeignSession(session.session_tag());
518 } else if (session.has_tab() &&
519 current_machine_tag() != session.session_tag()) {
Nicolas Zea 2016/04/12 20:38:03 the current_machine_tag condition isn't necessary
skym 2016/04/12 22:12:14 Done.
520 // The challenge here is that we don't know if this tab deletion is
521 // being processes before or after the parent was updated to no longer
Nicolas Zea 2016/04/12 20:38:03 being processes -> being processed
skym 2016/04/12 22:12:14 Done.
522 // reference us, or even more extreme, the parent has been deleted as
Nicolas Zea 2016/04/12 20:38:03 "reference us, or even" -> "reference the tab. Or,
skym 2016/04/12 22:12:13 Done.
523 // well. Tell the tracker to do what it can. The header's update will
524 // mostly get us into the correct state, the only thing this deletion
525 // needs to accomplish is make sure we never tell sync to delete this
526 // tab later during garbage collection.
527 session_tracker_.TryDeleteTab(session.session_tag(),
528 session.tab().tab_id(),
529 session.tab_node_id());
518 } 530 }
519 break; 531 break;
520 case syncer::SyncChange::ACTION_ADD: 532 case syncer::SyncChange::ACTION_ADD:
521 case syncer::SyncChange::ACTION_UPDATE: 533 case syncer::SyncChange::ACTION_UPDATE:
522 if (current_machine_tag() == session.session_tag()) { 534 if (current_machine_tag() == session.session_tag()) {
523 // We should only ever receive a change to our own machine's session 535 // We should only ever receive a change to our own machine's session
524 // info if encryption was turned on. In that case, the data is still 536 // info if encryption was turned on. In that case, the data is still
525 // the same, so we can ignore. 537 // the same, so we can ignore.
526 // TODO(skym): Is it really safe to return here? Why not continue?
527 // Couldn't there be multiple SessionSpecifics in the SyncChangeList
528 // that contain different session tags?
529 LOG(WARNING) << "Dropping modification to local session."; 538 LOG(WARNING) << "Dropping modification to local session.";
530 return syncer::SyncError(); 539 return syncer::SyncError();
531 } 540 }
532 UpdateTrackerWithForeignSession( 541 UpdateTrackerWithForeignSession(
533 session, syncer::SyncDataRemote(it->sync_data()).GetModifiedTime()); 542 session, syncer::SyncDataRemote(it->sync_data()).GetModifiedTime());
534 break; 543 break;
535 default: 544 default:
536 NOTREACHED() << "Processing sync changes failed, unknown change type."; 545 NOTREACHED() << "Processing sync changes failed, unknown change type.";
537 } 546 }
538 } 547 }
(...skipping 12 matching lines...) Expand all
551 return syncer::SyncChange( 560 return syncer::SyncChange(
552 FROM_HERE, SyncChange::ACTION_DELETE, 561 FROM_HERE, SyncChange::ACTION_DELETE,
553 SyncData::CreateLocalDelete( 562 SyncData::CreateLocalDelete(
554 TabNodePool::TabIdToTag(current_machine_tag(), tab.tab_node_id()), 563 TabNodePool::TabIdToTag(current_machine_tag(), tab.tab_node_id()),
555 syncer::SESSIONS)); 564 syncer::SESSIONS));
556 } 565 }
557 } 566 }
558 567
559 bool SessionsSyncManager::GetAllForeignSessions( 568 bool SessionsSyncManager::GetAllForeignSessions(
560 std::vector<const sync_driver::SyncedSession*>* sessions) { 569 std::vector<const sync_driver::SyncedSession*>* sessions) {
561 if (!session_tracker_.LookupAllForeignSessions(sessions)) 570 if (!session_tracker_.LookupAllForeignSessions(sessions, true))
562 return false; 571 return false;
563 std::sort(sessions->begin(), sessions->end(), SessionsRecencyComparator); 572 std::sort(sessions->begin(), sessions->end(), SessionsRecencyComparator);
564 return true; 573 return true;
565 } 574 }
566 575
567 bool SessionsSyncManager::InitFromSyncModel( 576 bool SessionsSyncManager::InitFromSyncModel(
568 const syncer::SyncDataList& sync_data, 577 const syncer::SyncDataList& sync_data,
569 syncer::SyncDataList* restored_tabs, 578 syncer::SyncDataList* restored_tabs,
570 syncer::SyncChangeList* new_changes) { 579 syncer::SyncChangeList* new_changes) {
571 bool found_current_header = false; 580 bool found_current_header = false;
572 for (syncer::SyncDataList::const_iterator it = sync_data.begin(); 581 for (syncer::SyncDataList::const_iterator it = sync_data.begin();
573 it != sync_data.end(); ++it) { 582 it != sync_data.end(); ++it) {
574 // TODO(skym): Why don't we ever look at data.change_type()? Why is this
575 // code path so much different from ProcessSyncChanges?
576 const syncer::SyncData& data = *it; 583 const syncer::SyncData& data = *it;
577 DCHECK(data.GetSpecifics().has_session()); 584 DCHECK(data.GetSpecifics().has_session());
578 const sync_pb::SessionSpecifics& specifics = data.GetSpecifics().session(); 585 const sync_pb::SessionSpecifics& specifics = data.GetSpecifics().session();
579 if (specifics.session_tag().empty() || 586 if (specifics.session_tag().empty() ||
580 (specifics.has_tab() && 587 (specifics.has_tab() &&
581 (!specifics.has_tab_node_id() || !specifics.tab().has_tab_id()))) { 588 (!specifics.has_tab_node_id() || !specifics.tab().has_tab_id()))) {
582 syncer::SyncChange tombstone(TombstoneTab(specifics)); 589 syncer::SyncChange tombstone(TombstoneTab(specifics));
583 if (tombstone.IsValid()) 590 if (tombstone.IsValid())
584 new_changes->push_back(tombstone); 591 new_changes->push_back(tombstone);
585 } else if (specifics.session_tag() != current_machine_tag()) { 592 } else if (specifics.session_tag() != current_machine_tag()) {
(...skipping 26 matching lines...) Expand all
612 } 619 }
613 620
614 void SessionsSyncManager::UpdateTrackerWithForeignSession( 621 void SessionsSyncManager::UpdateTrackerWithForeignSession(
615 const sync_pb::SessionSpecifics& specifics, 622 const sync_pb::SessionSpecifics& specifics,
616 const base::Time& modification_time) { 623 const base::Time& modification_time) {
617 std::string foreign_session_tag = specifics.session_tag(); 624 std::string foreign_session_tag = specifics.session_tag();
618 DCHECK_NE(foreign_session_tag, current_machine_tag()); 625 DCHECK_NE(foreign_session_tag, current_machine_tag());
619 626
620 sync_driver::SyncedSession* foreign_session = 627 sync_driver::SyncedSession* foreign_session =
621 session_tracker_.GetSession(foreign_session_tag); 628 session_tracker_.GetSession(foreign_session_tag);
629
622 if (specifics.has_header()) { 630 if (specifics.has_header()) {
623 // Read in the header data for this foreign session. Header data is 631 // Read in the header data for this foreign session. Header data is
624 // essentially a collection of windows, each of which has an ordered id list 632 // essentially a collection of windows, each of which has an ordered id list
625 // for their tabs. 633 // for their tabs.
626 634
627 if (!IsValidSessionHeader(specifics.header())) { 635 if (!IsValidSessionHeader(specifics.header())) {
628 LOG(WARNING) << "Ignoring foreign session node with invalid header " 636 LOG(WARNING) << "Ignoring foreign session node with invalid header "
629 << "and tag " << foreign_session_tag << "."; 637 << "and tag " << foreign_session_tag << ".";
630 return; 638 return;
631 } 639 }
632 640
633 // Load (or create) the SyncedSession object for this client. 641 // Load (or create) the SyncedSession object for this client.
634 const sync_pb::SessionHeader& header = specifics.header(); 642 const sync_pb::SessionHeader& header = specifics.header();
635 PopulateSessionHeaderFromSpecifics(header, modification_time, 643 PopulateSessionHeaderFromSpecifics(header, modification_time,
636 foreign_session); 644 foreign_session);
637 645
638 // Reset the tab/window tracking for this session (must do this before 646 // Reset the tab/window tracking for this session before adding them all
639 // we start calling PutWindowInSession and PutTabInWindow so that all 647 // back. This allows us to avoid a two way diff.
640 // unused tabs/windows get cleared by the CleanupSession(...) call).
641 session_tracker_.ResetSessionTracking(foreign_session_tag); 648 session_tracker_.ResetSessionTracking(foreign_session_tag);
642 649
643 // Process all the windows and their tab information. 650 // Process all the windows and their tab information.
644 int num_windows = header.window_size(); 651 int num_windows = header.window_size();
645 DVLOG(1) << "Associating " << foreign_session_tag << " with " << num_windows 652 DVLOG(1) << "Associating " << foreign_session_tag << " with " << num_windows
646 << " windows."; 653 << " windows.";
647 654
648 for (int i = 0; i < num_windows; ++i) { 655 for (int i = 0; i < num_windows; ++i) {
649 const sync_pb::SessionWindow& window_s = header.window(i); 656 const sync_pb::SessionWindow& window_s = header.window(i);
650 SessionID::id_type window_id = window_s.window_id(); 657 SessionID::id_type window_id = window_s.window_id();
651 session_tracker_.PutWindowInSession(foreign_session_tag, window_id); 658 session_tracker_.PutWindowInSession(foreign_session_tag, window_id);
652 BuildSyncedSessionFromSpecifics(foreign_session_tag, window_s, 659 BuildSyncedSessionFromSpecifics(foreign_session_tag, window_s,
653 modification_time, 660 modification_time,
654 foreign_session->windows[window_id]); 661 foreign_session->windows[window_id]);
655 } 662 }
656 // Delete any closed windows and unused tabs as necessary.
657 session_tracker_.CleanupSession(foreign_session_tag);
658 } else if (specifics.has_tab()) { 663 } else if (specifics.has_tab()) {
659 const sync_pb::SessionTab& tab_s = specifics.tab(); 664 const sync_pb::SessionTab& tab_s = specifics.tab();
660 SessionID::id_type tab_id = tab_s.tab_id(); 665 SessionID::id_type tab_id = tab_s.tab_id();
661 666
662 const sessions::SessionTab* existing_tab; 667 const sessions::SessionTab* existing_tab;
663 if (session_tracker_.LookupSessionTab(foreign_session_tag, tab_id, 668 if (session_tracker_.LookupSessionTab(foreign_session_tag, tab_id,
664 &existing_tab) && 669 &existing_tab) &&
665 existing_tab->timestamp > modification_time) { 670 existing_tab->timestamp > modification_time) {
671 // Remember that there is more sync data behind this tab_id if we decide
672 // to garbage collection this session. We never do granular garbage
Nicolas Zea 2016/04/12 20:38:03 to garbage collection -> to garbage collect (or to
skym 2016/04/12 22:12:14 Comment is different now.
673 // collection because we don't want to fight with the owning device.
674 session_tracker_.GetTab(foreign_session_tag, tab_id,
675 specifics.tab_node_id());
666 DVLOG(1) << "Ignoring " << foreign_session_tag << "'s session tab " 676 DVLOG(1) << "Ignoring " << foreign_session_tag << "'s session tab "
667 << tab_id << " with earlier modification time"; 677 << tab_id << " with earlier modification time";
668 return; 678 return;
669 } 679 }
670 680
671 sessions::SessionTab* tab = session_tracker_.GetTab( 681 sessions::SessionTab* tab = session_tracker_.GetTab(
672 foreign_session_tag, tab_id, specifics.tab_node_id()); 682 foreign_session_tag, tab_id, specifics.tab_node_id());
673 683
674 // Update SessionTab based on protobuf. 684 // Update SessionTab based on protobuf.
675 tab->SetFromSyncData(tab_s, modification_time); 685 tab->SetFromSyncData(tab_s, modification_time);
(...skipping 57 matching lines...) Expand 10 before | Expand all | Expand 10 after
733 case sync_pb::SyncEnums_DeviceType_TYPE_TABLET: 743 case sync_pb::SyncEnums_DeviceType_TYPE_TABLET:
734 session_header->device_type = sync_driver::SyncedSession::TYPE_TABLET; 744 session_header->device_type = sync_driver::SyncedSession::TYPE_TABLET;
735 break; 745 break;
736 case sync_pb::SyncEnums_DeviceType_TYPE_OTHER: 746 case sync_pb::SyncEnums_DeviceType_TYPE_OTHER:
737 // Intentionally fall-through 747 // Intentionally fall-through
738 default: 748 default:
739 session_header->device_type = sync_driver::SyncedSession::TYPE_OTHER; 749 session_header->device_type = sync_driver::SyncedSession::TYPE_OTHER;
740 break; 750 break;
741 } 751 }
742 } 752 }
743 session_header->modified_time = mtime; 753 session_header->modified_time =
754 std::max(mtime, session_header->modified_time);
744 } 755 }
745 756
746 // static 757 // static
747 void SessionsSyncManager::BuildSyncedSessionFromSpecifics( 758 void SessionsSyncManager::BuildSyncedSessionFromSpecifics(
748 const std::string& session_tag, 759 const std::string& session_tag,
749 const sync_pb::SessionWindow& specifics, 760 const sync_pb::SessionWindow& specifics,
750 base::Time mtime, 761 base::Time mtime,
751 sessions::SessionWindow* session_window) { 762 sessions::SessionWindow* session_window) {
752 if (specifics.has_window_id()) 763 if (specifics.has_window_id())
753 session_window->window_id.set_id(specifics.window_id()); 764 session_window->window_id.set_id(specifics.window_id());
(...skipping 50 matching lines...) Expand 10 before | Expand all | Expand 10 after
804 const std::string& tag, 815 const std::string& tag,
805 syncer::SyncChangeList* change_output) { 816 syncer::SyncChangeList* change_output) {
806 if (tag == current_machine_tag()) { 817 if (tag == current_machine_tag()) {
807 LOG(ERROR) << "Attempting to delete local session. This is not currently " 818 LOG(ERROR) << "Attempting to delete local session. This is not currently "
808 << "supported."; 819 << "supported.";
809 return; 820 return;
810 } 821 }
811 822
812 std::set<int> tab_node_ids_to_delete; 823 std::set<int> tab_node_ids_to_delete;
813 session_tracker_.LookupTabNodeIds(tag, &tab_node_ids_to_delete); 824 session_tracker_.LookupTabNodeIds(tag, &tab_node_ids_to_delete);
814 if (!DisassociateForeignSession(tag)) { 825 if (DisassociateForeignSession(tag)) {
815 // We don't have any data for this session, our work here is done! 826 // Only tell sync to delete the header if there was one.
816 return; 827 change_output->push_back(
828 syncer::SyncChange(FROM_HERE, SyncChange::ACTION_DELETE,
829 SyncData::CreateLocalDelete(tag, syncer::SESSIONS)));
817 } 830 }
818 831
819 // Prepare deletes for the meta-node as well as individual tab nodes.
820 change_output->push_back(
821 syncer::SyncChange(FROM_HERE, SyncChange::ACTION_DELETE,
822 SyncData::CreateLocalDelete(tag, syncer::SESSIONS)));
823
824 for (std::set<int>::const_iterator it = tab_node_ids_to_delete.begin(); 832 for (std::set<int>::const_iterator it = tab_node_ids_to_delete.begin();
825 it != tab_node_ids_to_delete.end(); ++it) { 833 it != tab_node_ids_to_delete.end(); ++it) {
826 change_output->push_back(syncer::SyncChange( 834 change_output->push_back(syncer::SyncChange(
827 FROM_HERE, SyncChange::ACTION_DELETE, 835 FROM_HERE, SyncChange::ACTION_DELETE,
828 SyncData::CreateLocalDelete(TabNodePool::TabIdToTag(tag, *it), 836 SyncData::CreateLocalDelete(TabNodePool::TabIdToTag(tag, *it),
829 syncer::SESSIONS))); 837 syncer::SESSIONS)));
830 } 838 }
831 if (!sessions_updated_callback_.is_null()) 839 if (!sessions_updated_callback_.is_null())
832 sessions_updated_callback_.Run(); 840 sessions_updated_callback_.Run();
833 } 841 }
834 842
835 bool SessionsSyncManager::DisassociateForeignSession( 843 bool SessionsSyncManager::DisassociateForeignSession(
836 const std::string& foreign_session_tag) { 844 const std::string& foreign_session_tag) {
837 if (foreign_session_tag == current_machine_tag()) { 845 DCHECK_NE(foreign_session_tag, current_machine_tag());
838 DVLOG(1) << "Local session deleted! Doing nothing until a navigation is "
839 << "triggered.";
840 return false;
841 }
842 DVLOG(1) << "Disassociating session " << foreign_session_tag; 846 DVLOG(1) << "Disassociating session " << foreign_session_tag;
843 return session_tracker_.DeleteSession(foreign_session_tag); 847 return session_tracker_.DeleteSession(foreign_session_tag);
844 } 848 }
845 849
846 bool SessionsSyncManager::GetForeignSession( 850 bool SessionsSyncManager::GetForeignSession(
847 const std::string& tag, 851 const std::string& tag,
848 std::vector<const sessions::SessionWindow*>* windows) { 852 std::vector<const sessions::SessionWindow*>* windows) {
849 return session_tracker_.LookupSessionWindows(tag, windows); 853 return session_tracker_.LookupSessionWindows(tag, windows);
850 } 854 }
851 855
(...skipping 171 matching lines...) Expand 10 before | Expand all | Expand 10 after
1023 return &favicon_cache_; 1027 return &favicon_cache_;
1024 } 1028 }
1025 1029
1026 SyncedWindowDelegatesGetter* 1030 SyncedWindowDelegatesGetter*
1027 SessionsSyncManager::synced_window_delegates_getter() const { 1031 SessionsSyncManager::synced_window_delegates_getter() const {
1028 return sessions_client_->GetSyncedWindowDelegatesGetter(); 1032 return sessions_client_->GetSyncedWindowDelegatesGetter();
1029 } 1033 }
1030 1034
1031 void SessionsSyncManager::DoGarbageCollection() { 1035 void SessionsSyncManager::DoGarbageCollection() {
1032 std::vector<const sync_driver::SyncedSession*> sessions; 1036 std::vector<const sync_driver::SyncedSession*> sessions;
1033 if (!GetAllForeignSessions(&sessions)) 1037 session_tracker_.LookupAllForeignSessions(&sessions, false);
1034 return; // No foreign sessions.
1035
1036 // Iterate through all the sessions and delete any with age older than
1037 // |stale_session_threshold_days_|.
1038 syncer::SyncChangeList changes; 1038 syncer::SyncChangeList changes;
1039 for (std::vector<const sync_driver::SyncedSession*>::const_iterator iter = 1039 for (const auto* session : sessions) {
1040 sessions.begin();
1041 iter != sessions.end(); ++iter) {
1042 const sync_driver::SyncedSession* session = *iter;
1043 int session_age_in_days = 1040 int session_age_in_days =
1044 (base::Time::Now() - session->modified_time).InDays(); 1041 (base::Time::Now() - session->modified_time).InDays();
1045 std::string session_tag = session->session_tag; 1042 if (session_age_in_days > stale_session_threshold_days_) {
1046 if (session_age_in_days > 0 && // If false, local clock is not trustworty. 1043 std::string session_tag = session->session_tag;
1047 static_cast<size_t>(session_age_in_days) >
1048 stale_session_threshold_days_) {
1049 DVLOG(1) << "Found stale session " << session_tag << " with age " 1044 DVLOG(1) << "Found stale session " << session_tag << " with age "
1050 << session_age_in_days << ", deleting."; 1045 << session_age_in_days << ", deleting.";
1051 DeleteForeignSessionInternal(session_tag, &changes); 1046 DeleteForeignSessionInternal(session_tag, &changes);
1052 } 1047 }
1053 } 1048 }
1054 1049
1055 if (!changes.empty()) 1050 if (!changes.empty()) {
Nicolas Zea 2016/04/12 20:38:03 nit: rest of file has (I think) been leaving curly
skym 2016/04/12 22:12:14 Done.
1056 sync_processor_->ProcessSyncChanges(FROM_HERE, changes); 1051 sync_processor_->ProcessSyncChanges(FROM_HERE, changes);
1052 }
1057 } 1053 }
1058 1054
1059 }; // namespace browser_sync 1055 }; // namespace browser_sync
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698