OLD | NEW |
---|---|
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 Loading... | |
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 Loading... | |
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 Loading... | |
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 Loading... | |
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 Loading... | |
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 Loading... | |
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 |
OLD | NEW |