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

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

Issue 11533008: Use delete journal to remove bookmarks that are already deleted in sync model (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Created 8 years 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 (c) 2012 The Chromium Authors. All rights reserved. 1 // Copyright (c) 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/bookmark_model_associator.h" 5 #include "chrome/browser/sync/glue/bookmark_model_associator.h"
6 6
7 #include <stack> 7 #include <stack>
8 8
9 #include "base/bind.h" 9 #include "base/bind.h"
10 #include "base/command_line.h" 10 #include "base/command_line.h"
(...skipping 69 matching lines...) Expand 10 before | Expand all | Expand 10 after
80 // Provides the following abstraction: given a parent bookmark node, find best 80 // Provides the following abstraction: given a parent bookmark node, find best
81 // matching child node for many sync nodes. 81 // matching child node for many sync nodes.
82 class BookmarkNodeFinder { 82 class BookmarkNodeFinder {
83 public: 83 public:
84 // Creates an instance with the given parent bookmark node. 84 // Creates an instance with the given parent bookmark node.
85 explicit BookmarkNodeFinder(const BookmarkNode* parent_node); 85 explicit BookmarkNodeFinder(const BookmarkNode* parent_node);
86 86
87 // Finds best matching node for the given sync node. 87 // Finds best matching node for the given sync node.
88 // Returns the matching node if one exists; NULL otherwise. If a matching 88 // Returns the matching node if one exists; NULL otherwise. If a matching
89 // node is found, it's removed for further matches. 89 // node is found, it's removed for further matches.
90 const BookmarkNode* FindBookmarkNode(const syncer::BaseNode& sync_node); 90 const BookmarkNode* FindBookmarkNode(const GURL& url,
91 const std::string& title,
92 bool is_folder);
91 93
92 private: 94 private:
93 typedef std::multiset<const BookmarkNode*, BookmarkComparer> BookmarkNodesSet; 95 typedef std::multiset<const BookmarkNode*, BookmarkComparer> BookmarkNodesSet;
94 96
95 const BookmarkNode* parent_node_; 97 const BookmarkNode* parent_node_;
96 BookmarkNodesSet child_nodes_; 98 BookmarkNodesSet child_nodes_;
97 99
98 DISALLOW_COPY_AND_ASSIGN(BookmarkNodeFinder); 100 DISALLOW_COPY_AND_ASSIGN(BookmarkNodeFinder);
99 }; 101 };
100 102
(...skipping 15 matching lines...) Expand all
116 }; 118 };
117 119
118 BookmarkNodeFinder::BookmarkNodeFinder(const BookmarkNode* parent_node) 120 BookmarkNodeFinder::BookmarkNodeFinder(const BookmarkNode* parent_node)
119 : parent_node_(parent_node) { 121 : parent_node_(parent_node) {
120 for (int i = 0; i < parent_node_->child_count(); ++i) { 122 for (int i = 0; i < parent_node_->child_count(); ++i) {
121 child_nodes_.insert(parent_node_->GetChild(i)); 123 child_nodes_.insert(parent_node_->GetChild(i));
122 } 124 }
123 } 125 }
124 126
125 const BookmarkNode* BookmarkNodeFinder::FindBookmarkNode( 127 const BookmarkNode* BookmarkNodeFinder::FindBookmarkNode(
126 const syncer::BaseNode& sync_node) { 128 const GURL& url, const std::string& title, bool is_folder) {
127 // Create a bookmark node from the given sync node. 129 // Create a bookmark node from the given bookmark attributes.
128 BookmarkNode temp_node(GURL(sync_node.GetBookmarkSpecifics().url())); 130 BookmarkNode temp_node(url);
129 temp_node.SetTitle(UTF8ToUTF16(sync_node.GetTitle())); 131 temp_node.SetTitle(UTF8ToUTF16(title));
130 if (sync_node.GetIsFolder()) 132 if (is_folder)
131 temp_node.set_type(BookmarkNode::FOLDER); 133 temp_node.set_type(BookmarkNode::FOLDER);
132 else 134 else
133 temp_node.set_type(BookmarkNode::URL); 135 temp_node.set_type(BookmarkNode::URL);
134 136
135 const BookmarkNode* result = NULL; 137 const BookmarkNode* result = NULL;
136 BookmarkNodesSet::iterator iter = child_nodes_.find(&temp_node); 138 BookmarkNodesSet::iterator iter = child_nodes_.find(&temp_node);
137 if (iter != child_nodes_.end()) { 139 if (iter != child_nodes_.end()) {
138 result = *iter; 140 result = *iter;
139 // Remove the matched node so we don't match with it again. 141 // Remove the matched node so we don't match with it again.
140 child_nodes_.erase(iter); 142 child_nodes_.erase(iter);
(...skipping 290 matching lines...) Expand 10 before | Expand all | Expand 10 after
431 433
432 // WARNING: The order in which we push these should match their order in the 434 // WARNING: The order in which we push these should match their order in the
433 // bookmark model (see BookmarkModel::DoneLoading(..)). 435 // bookmark model (see BookmarkModel::DoneLoading(..)).
434 std::stack<int64> dfs_stack; 436 std::stack<int64> dfs_stack;
435 dfs_stack.push(bookmark_bar_sync_id); 437 dfs_stack.push(bookmark_bar_sync_id);
436 dfs_stack.push(other_bookmarks_sync_id); 438 dfs_stack.push(other_bookmarks_sync_id);
437 if (mobile_bookmarks_sync_id != syncer::kInvalidId) 439 if (mobile_bookmarks_sync_id != syncer::kInvalidId)
438 dfs_stack.push(mobile_bookmarks_sync_id); 440 dfs_stack.push(mobile_bookmarks_sync_id);
439 441
440 syncer::WriteTransaction trans(FROM_HERE, user_share_); 442 syncer::WriteTransaction trans(FROM_HERE, user_share_);
443
444 ApplyDeletesFromSyncJournal(&trans);
445
441 syncer::ReadNode bm_root(&trans); 446 syncer::ReadNode bm_root(&trans);
442 if (bm_root.InitByTagLookup(syncer::ModelTypeToRootTag(syncer::BOOKMARKS)) == 447 if (bm_root.InitByTagLookup(syncer::ModelTypeToRootTag(syncer::BOOKMARKS)) ==
443 syncer::BaseNode::INIT_OK) { 448 syncer::BaseNode::INIT_OK) {
444 syncer_merge_result->set_num_items_before_association( 449 syncer_merge_result->set_num_items_before_association(
445 bm_root.GetTotalNodeCount()); 450 bm_root.GetTotalNodeCount());
446 } 451 }
447 local_merge_result->set_num_items_before_association( 452 local_merge_result->set_num_items_before_association(
448 bookmark_model_->root_node()->GetTotalNodeCount()); 453 bookmark_model_->root_node()->GetTotalNodeCount());
449 454
450 while (!dfs_stack.empty()) { 455 while (!dfs_stack.empty()) {
(...skipping 22 matching lines...) Expand all
473 syncer::WriteNode sync_child_node(&trans); 478 syncer::WriteNode sync_child_node(&trans);
474 if (sync_child_node.InitByIdLookup(sync_child_id) != 479 if (sync_child_node.InitByIdLookup(sync_child_id) !=
475 syncer::BaseNode::INIT_OK) { 480 syncer::BaseNode::INIT_OK) {
476 return unrecoverable_error_handler_->CreateAndUploadError( 481 return unrecoverable_error_handler_->CreateAndUploadError(
477 FROM_HERE, 482 FROM_HERE,
478 "Failed to lookup node.", 483 "Failed to lookup node.",
479 model_type()); 484 model_type());
480 } 485 }
481 486
482 const BookmarkNode* child_node = NULL; 487 const BookmarkNode* child_node = NULL;
483 child_node = node_finder.FindBookmarkNode(sync_child_node); 488 child_node = node_finder.FindBookmarkNode(
489 GURL(sync_child_node.GetBookmarkSpecifics().url()),
490 sync_child_node.GetTitle(),
491 sync_child_node.GetIsFolder());
484 if (child_node) 492 if (child_node)
485 Associate(child_node, sync_child_id); 493 Associate(child_node, sync_child_id);
486 // All bookmarks are currently modified at association time (even if 494 // All bookmarks are currently modified at association time (even if
487 // it doesn't change anything). 495 // it doesn't change anything).
488 // TODO(sync): introduce logic to only modify the bookmark model if 496 // TODO(sync): introduce logic to only modify the bookmark model if
489 // necessary. 497 // necessary.
490 const BookmarkNode* new_child_node = 498 const BookmarkNode* new_child_node =
491 BookmarkChangeProcessor::CreateOrUpdateBookmarkNode( 499 BookmarkChangeProcessor::CreateOrUpdateBookmarkNode(
492 &sync_child_node, 500 &sync_child_node,
493 bookmark_model_, 501 bookmark_model_,
(...skipping 35 matching lines...) Expand 10 before | Expand all | Expand 10 after
529 } 537 }
530 538
531 local_merge_result->set_num_items_after_association( 539 local_merge_result->set_num_items_after_association(
532 bookmark_model_->root_node()->GetTotalNodeCount()); 540 bookmark_model_->root_node()->GetTotalNodeCount());
533 syncer_merge_result->set_num_items_after_association( 541 syncer_merge_result->set_num_items_after_association(
534 bm_root.GetTotalNodeCount()); 542 bm_root.GetTotalNodeCount());
535 543
536 return syncer::SyncError(); 544 return syncer::SyncError();
537 } 545 }
538 546
547 struct FolderInfo {
548 FolderInfo(const BookmarkNode* f, const BookmarkNode* p, int64 id)
549 : folder(f), parent(p), sync_id(id) {}
550 const BookmarkNode* folder;
551 const BookmarkNode* parent;
552 int64 sync_id;
553 };
554 typedef std::vector<FolderInfo> FolderInfoList;
555
556 int64 BookmarkModelAssociator::ApplyDeletesFromSyncJournal(
557 syncer::BaseTransaction* trans) {
558 int64 num_deleted = 0;
559
560 syncer::SyncDataList deleted_sync_bookmarks;
561 trans->GetDeletedSyncData(syncer::BOOKMARKS, &deleted_sync_bookmarks);
tim (not reviewing) 2012/12/11 19:58:33 How can we make it so that this data is *sent* to
562 if (deleted_sync_bookmarks.empty())
563 return 0;
564
565 std::stack<const BookmarkNode*> dfs_stack;
566 dfs_stack.push(bookmark_model_->bookmark_bar_node());
567 dfs_stack.push(bookmark_model_->other_node());
568 if (expect_mobile_bookmarks_folder_)
569 dfs_stack.push(bookmark_model_->mobile_node());
570
571 FolderInfoList folders_deleted;
572 while (!dfs_stack.empty()) {
573 const BookmarkNode* parent = dfs_stack.top();
574 dfs_stack.pop();
575
576 BookmarkNodeFinder finder(parent);
577 syncer::SyncDataList::iterator it = deleted_sync_bookmarks.begin();
578 while (it != deleted_sync_bookmarks.end()) {
579 const BookmarkNode* child = finder.FindBookmarkNode(
580 GURL(it->GetSpecifics().bookmark().url()), it->GetTitle(),
581 it->IsFolder());
582 if (child) {
583 if (child->is_folder()) {
584 // Save folders first and delete only empty ones later.
585 folders_deleted.push_back(FolderInfo(child, parent,
586 it->GetRemoteId()));
587 } else {
588 bookmark_model_->Remove(parent, child->GetIndexOf(parent));
589 ++num_deleted;
590 }
591 deleted_sync_bookmarks.erase(it++);
592 } else {
593 ++it;
594 }
595 }
596
597 if (deleted_sync_bookmarks.empty())
598 break;
599 }
600
601 // Ids of sync nodes not found in bookmark model, i.e. deletion is persisted.
602 std::set<int64> confirmed_sync_deletes;
603
604 // Remove empty folders from bottom to top.
605 for (FolderInfoList::const_reverse_iterator it = folders_deleted.rbegin();
606 it != folders_deleted.rend(); ++it) {
607 if (it->folder->child_count() == 0) {
608 bookmark_model_->Remove(it->parent, it->folder->GetIndexOf(it->parent));
609 ++num_deleted;
610 } else {
611 // Keep non-empty folder and remove its journal so that it won't match
612 // again in the future.
613 confirmed_sync_deletes.insert(it->sync_id);
614 }
615 }
616
617 // Consider deletion of unmatched sync nodes to be confirmed.
618 for (size_t i = 0; i < deleted_sync_bookmarks.size(); ++i)
619 confirmed_sync_deletes.insert(deleted_sync_bookmarks[i].GetRemoteId());
620 trans->PurgeDeletedSyncData(confirmed_sync_deletes);
621
622 return num_deleted;
623 }
624
539 void BookmarkModelAssociator::PostPersistAssociationsTask() { 625 void BookmarkModelAssociator::PostPersistAssociationsTask() {
540 // No need to post a task if a task is already pending. 626 // No need to post a task if a task is already pending.
541 if (weak_factory_.HasWeakPtrs()) 627 if (weak_factory_.HasWeakPtrs())
542 return; 628 return;
543 MessageLoop::current()->PostTask( 629 MessageLoop::current()->PostTask(
544 FROM_HERE, 630 FROM_HERE,
545 base::Bind( 631 base::Bind(
546 &BookmarkModelAssociator::PersistAssociations, 632 &BookmarkModelAssociator::PersistAssociations,
547 weak_factory_.GetWeakPtr())); 633 weak_factory_.GetWeakPtr()));
548 } 634 }
(...skipping 57 matching lines...) Expand 10 before | Expand all | Expand 10 after
606 UMA_HISTOGRAM_ENUMERATION("Sync.LocalModelOutOfSync", 692 UMA_HISTOGRAM_ENUMERATION("Sync.LocalModelOutOfSync",
607 syncer::BOOKMARKS, syncer::MODEL_TYPE_COUNT); 693 syncer::BOOKMARKS, syncer::MODEL_TYPE_COUNT);
608 // Clear version on bookmark model so that we only report error once. 694 // Clear version on bookmark model so that we only report error once.
609 bookmark_model_->DeleteNodeMetaInfo(bookmark_model_->root_node(), 695 bookmark_model_->DeleteNodeMetaInfo(bookmark_model_->root_node(),
610 kBookmarkTransactionVersionKey); 696 kBookmarkTransactionVersionKey);
611 } 697 }
612 } 698 }
613 } 699 }
614 700
615 } // namespace browser_sync 701 } // namespace browser_sync
OLDNEW
« no previous file with comments | « chrome/browser/sync/glue/bookmark_model_associator.h ('k') | chrome/browser/sync/glue/generic_change_processor.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698