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 195 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
206 | 206 |
207 void BookmarkModelAssociator::UpdatePermanentNodeVisibility() { | 207 void BookmarkModelAssociator::UpdatePermanentNodeVisibility() { |
208 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | 208 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
209 DCHECK(bookmark_model_->IsLoaded()); | 209 DCHECK(bookmark_model_->IsLoaded()); |
210 | 210 |
211 bookmark_model_->SetPermanentNodeVisible( | 211 bookmark_model_->SetPermanentNodeVisible( |
212 BookmarkNode::MOBILE, | 212 BookmarkNode::MOBILE, |
213 id_map_.find(bookmark_model_->mobile_node()->id()) != id_map_.end()); | 213 id_map_.find(bookmark_model_->mobile_node()->id()) != id_map_.end()); |
214 } | 214 } |
215 | 215 |
216 bool BookmarkModelAssociator::DisassociateModels(SyncError* error) { | 216 SyncError BookmarkModelAssociator::DisassociateModels() { |
217 id_map_.clear(); | 217 id_map_.clear(); |
218 id_map_inverse_.clear(); | 218 id_map_inverse_.clear(); |
219 dirty_associations_sync_ids_.clear(); | 219 dirty_associations_sync_ids_.clear(); |
220 return true; | 220 return SyncError(); |
221 } | 221 } |
222 | 222 |
223 int64 BookmarkModelAssociator::GetSyncIdFromChromeId(const int64& node_id) { | 223 int64 BookmarkModelAssociator::GetSyncIdFromChromeId(const int64& node_id) { |
224 BookmarkIdToSyncIdMap::const_iterator iter = id_map_.find(node_id); | 224 BookmarkIdToSyncIdMap::const_iterator iter = id_map_.find(node_id); |
225 return iter == id_map_.end() ? sync_api::kInvalidId : iter->second; | 225 return iter == id_map_.end() ? sync_api::kInvalidId : iter->second; |
226 } | 226 } |
227 | 227 |
228 const BookmarkNode* BookmarkModelAssociator::GetChromeNodeFromSyncId( | 228 const BookmarkNode* BookmarkModelAssociator::GetChromeNodeFromSyncId( |
229 int64 sync_id) { | 229 int64 sync_id) { |
230 SyncIdToBookmarkNodeMap::const_iterator iter = id_map_inverse_.find(sync_id); | 230 SyncIdToBookmarkNodeMap::const_iterator iter = id_map_inverse_.find(sync_id); |
(...skipping 90 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
321 if (bookmark->is_url()) { | 321 if (bookmark->is_url()) { |
322 if (bookmark->url() != sync_node->GetURL()) | 322 if (bookmark->url() != sync_node->GetURL()) |
323 return false; | 323 return false; |
324 } | 324 } |
325 // Don't compare favicons here, because they are not really | 325 // Don't compare favicons here, because they are not really |
326 // user-updated and we don't have versioning information -- a site changing | 326 // user-updated and we don't have versioning information -- a site changing |
327 // its favicon shouldn't result in a bookmark mismatch. | 327 // its favicon shouldn't result in a bookmark mismatch. |
328 return true; | 328 return true; |
329 } | 329 } |
330 | 330 |
331 bool BookmarkModelAssociator::AssociateTaggedPermanentNode( | 331 SyncError BookmarkModelAssociator::AssociateTaggedPermanentNode( |
332 const BookmarkNode* permanent_node, const std::string&tag) { | 332 const BookmarkNode* permanent_node, const std::string&tag) { |
333 // Do nothing if |permanent_node| is already initialized and associated. | 333 // Do nothing if |permanent_node| is already initialized and associated. |
334 int64 sync_id = GetSyncIdFromChromeId(permanent_node->id()); | 334 int64 sync_id = GetSyncIdFromChromeId(permanent_node->id()); |
335 if (sync_id != sync_api::kInvalidId) | 335 if (sync_id != sync_api::kInvalidId) |
336 return true; | 336 return SyncError(); |
337 if (!GetSyncIdForTaggedNode(tag, &sync_id)) | 337 if (!GetSyncIdForTaggedNode(tag, &sync_id)) |
338 return false; | 338 return unrecoverable_error_handler_->CreateAndUploadError( |
| 339 FROM_HERE, |
| 340 "Permanent node not found", |
| 341 model_type()); |
339 | 342 |
340 Associate(permanent_node, sync_id); | 343 Associate(permanent_node, sync_id); |
341 return true; | 344 return SyncError(); |
342 } | 345 } |
343 | 346 |
344 bool BookmarkModelAssociator::GetSyncIdForTaggedNode(const std::string& tag, | 347 bool BookmarkModelAssociator::GetSyncIdForTaggedNode(const std::string& tag, |
345 int64* sync_id) { | 348 int64* sync_id) { |
346 sync_api::ReadTransaction trans(FROM_HERE, user_share_); | 349 sync_api::ReadTransaction trans(FROM_HERE, user_share_); |
347 sync_api::ReadNode sync_node(&trans); | 350 sync_api::ReadNode sync_node(&trans); |
348 if (!sync_node.InitByTagLookup(tag.c_str())) | 351 if (!sync_node.InitByTagLookup(tag.c_str())) |
349 return false; | 352 return false; |
350 *sync_id = sync_node.GetId(); | 353 *sync_id = sync_node.GetId(); |
351 return true; | 354 return true; |
352 } | 355 } |
353 | 356 |
354 bool BookmarkModelAssociator::AssociateModels(SyncError* error) { | 357 SyncError BookmarkModelAssociator::AssociateModels() { |
355 scoped_ptr<ScopedAssociationUpdater> association_updater( | 358 scoped_ptr<ScopedAssociationUpdater> association_updater( |
356 new ScopedAssociationUpdater(bookmark_model_)); | 359 new ScopedAssociationUpdater(bookmark_model_)); |
357 // Try to load model associations from persisted associations first. If that | 360 // Try to load model associations from persisted associations first. If that |
358 // succeeds, we don't need to run the complex model matching algorithm. | 361 // succeeds, we don't need to run the complex model matching algorithm. |
359 if (LoadAssociations()) | 362 if (LoadAssociations()) |
360 return true; | 363 return SyncError(); |
361 | 364 |
362 DisassociateModels(error); | 365 DisassociateModels(); |
363 | 366 |
364 // We couldn't load model associations from persisted associations. So build | 367 // We couldn't load model associations from persisted associations. So build |
365 // them. | 368 // them. |
366 return BuildAssociations(error); | 369 return BuildAssociations(); |
367 } | 370 } |
368 | 371 |
369 bool BookmarkModelAssociator::BuildAssociations(SyncError* error) { | 372 SyncError BookmarkModelAssociator::BuildAssociations() { |
370 // Algorithm description: | 373 // Algorithm description: |
371 // Match up the roots and recursively do the following: | 374 // Match up the roots and recursively do the following: |
372 // * For each sync node for the current sync parent node, find the best | 375 // * For each sync node for the current sync parent node, find the best |
373 // matching bookmark node under the corresponding bookmark parent node. | 376 // matching bookmark node under the corresponding bookmark parent node. |
374 // If no matching node is found, create a new bookmark node in the same | 377 // If no matching node is found, create a new bookmark node in the same |
375 // position as the corresponding sync node. | 378 // position as the corresponding sync node. |
376 // If a matching node is found, update the properties of it from the | 379 // If a matching node is found, update the properties of it from the |
377 // corresponding sync node. | 380 // corresponding sync node. |
378 // * When all children sync nodes are done, add the extra children bookmark | 381 // * When all children sync nodes are done, add the extra children bookmark |
379 // nodes to the sync parent node. | 382 // nodes to the sync parent node. |
380 // | 383 // |
381 // This algorithm will do a good job of merging when folder names are a good | 384 // This algorithm will do a good job of merging when folder names are a good |
382 // indicator of the two folders being the same. It will handle reordering and | 385 // indicator of the two folders being the same. It will handle reordering and |
383 // new node addition very well (without creating duplicates). | 386 // new node addition very well (without creating duplicates). |
384 // This algorithm will not do well if the folder name has changes but the | 387 // This algorithm will not do well if the folder name has changes but the |
385 // children under them are all the same. | 388 // children under them are all the same. |
386 | 389 |
| 390 SyncError error; |
387 DCHECK(bookmark_model_->IsLoaded()); | 391 DCHECK(bookmark_model_->IsLoaded()); |
388 | 392 |
389 // To prime our association, we associate the top-level nodes, Bookmark Bar | 393 // To prime our association, we associate the top-level nodes, Bookmark Bar |
390 // and Other Bookmarks. | 394 // and Other Bookmarks. |
391 if (!AssociateTaggedPermanentNode(bookmark_model_->other_node(), | 395 error = AssociateTaggedPermanentNode(bookmark_model_->other_node(), |
392 kOtherBookmarksTag)) { | 396 kOtherBookmarksTag); |
393 error->Reset(FROM_HERE, kServerError, model_type()); | 397 if (error.IsSet()) { |
394 return false; | 398 return error; |
395 } | 399 } |
396 if (!AssociateTaggedPermanentNode(bookmark_model_->bookmark_bar_node(), | 400 |
397 kBookmarkBarTag)) { | 401 error = AssociateTaggedPermanentNode(bookmark_model_->bookmark_bar_node(), |
398 error->Reset(FROM_HERE, kServerError, model_type()); | 402 kBookmarkBarTag); |
399 return false; | 403 if (error.IsSet()) { |
| 404 return error; |
400 } | 405 } |
401 if (!AssociateTaggedPermanentNode(bookmark_model_->mobile_node(), | 406 |
402 kMobileBookmarksTag) && | 407 if (expect_mobile_bookmarks_folder_) { |
403 expect_mobile_bookmarks_folder_) { | 408 error = AssociateTaggedPermanentNode(bookmark_model_->mobile_node(), |
404 error->Reset(FROM_HERE, kServerError, model_type()); | 409 kMobileBookmarksTag); |
405 return false; | 410 if (error.IsSet()) { |
| 411 return error; |
| 412 } |
406 } | 413 } |
407 | 414 |
408 int64 bookmark_bar_sync_id = GetSyncIdFromChromeId( | 415 int64 bookmark_bar_sync_id = GetSyncIdFromChromeId( |
409 bookmark_model_->bookmark_bar_node()->id()); | 416 bookmark_model_->bookmark_bar_node()->id()); |
410 DCHECK_NE(bookmark_bar_sync_id, sync_api::kInvalidId); | 417 DCHECK_NE(bookmark_bar_sync_id, sync_api::kInvalidId); |
411 int64 other_bookmarks_sync_id = GetSyncIdFromChromeId( | 418 int64 other_bookmarks_sync_id = GetSyncIdFromChromeId( |
412 bookmark_model_->other_node()->id()); | 419 bookmark_model_->other_node()->id()); |
413 DCHECK_NE(other_bookmarks_sync_id, sync_api::kInvalidId); | 420 DCHECK_NE(other_bookmarks_sync_id, sync_api::kInvalidId); |
414 int64 mobile_bookmarks_sync_id = GetSyncIdFromChromeId( | 421 int64 mobile_bookmarks_sync_id = GetSyncIdFromChromeId( |
415 bookmark_model_->mobile_node()->id()); | 422 bookmark_model_->mobile_node()->id()); |
416 if (expect_mobile_bookmarks_folder_) { | 423 if (expect_mobile_bookmarks_folder_) { |
417 DCHECK_NE(sync_api::kInvalidId, mobile_bookmarks_sync_id); | 424 DCHECK_NE(sync_api::kInvalidId, mobile_bookmarks_sync_id); |
418 } | 425 } |
419 | 426 |
420 std::stack<int64> dfs_stack; | 427 std::stack<int64> dfs_stack; |
421 if (mobile_bookmarks_sync_id != sync_api::kInvalidId) | 428 if (mobile_bookmarks_sync_id != sync_api::kInvalidId) |
422 dfs_stack.push(mobile_bookmarks_sync_id); | 429 dfs_stack.push(mobile_bookmarks_sync_id); |
423 dfs_stack.push(other_bookmarks_sync_id); | 430 dfs_stack.push(other_bookmarks_sync_id); |
424 dfs_stack.push(bookmark_bar_sync_id); | 431 dfs_stack.push(bookmark_bar_sync_id); |
425 | 432 |
426 sync_api::WriteTransaction trans(FROM_HERE, user_share_); | 433 sync_api::WriteTransaction trans(FROM_HERE, user_share_); |
427 | 434 |
428 while (!dfs_stack.empty()) { | 435 while (!dfs_stack.empty()) { |
429 int64 sync_parent_id = dfs_stack.top(); | 436 int64 sync_parent_id = dfs_stack.top(); |
430 dfs_stack.pop(); | 437 dfs_stack.pop(); |
431 | 438 |
432 sync_api::ReadNode sync_parent(&trans); | 439 sync_api::ReadNode sync_parent(&trans); |
433 if (!sync_parent.InitByIdLookup(sync_parent_id)) { | 440 if (!sync_parent.InitByIdLookup(sync_parent_id)) { |
434 error->Reset(FROM_HERE, "Failed to lookup node.", model_type()); | 441 return unrecoverable_error_handler_->CreateAndUploadError( |
435 return false; | 442 FROM_HERE, |
| 443 "Failed to lookup node.", |
| 444 model_type()); |
436 } | 445 } |
437 // Only folder nodes are pushed on to the stack. | 446 // Only folder nodes are pushed on to the stack. |
438 DCHECK(sync_parent.GetIsFolder()); | 447 DCHECK(sync_parent.GetIsFolder()); |
439 | 448 |
440 const BookmarkNode* parent_node = GetChromeNodeFromSyncId(sync_parent_id); | 449 const BookmarkNode* parent_node = GetChromeNodeFromSyncId(sync_parent_id); |
441 DCHECK(parent_node->is_folder()); | 450 DCHECK(parent_node->is_folder()); |
442 | 451 |
443 BookmarkNodeFinder node_finder(parent_node); | 452 BookmarkNodeFinder node_finder(parent_node); |
444 | 453 |
445 int index = 0; | 454 int index = 0; |
446 int64 sync_child_id = sync_parent.GetFirstChildId(); | 455 int64 sync_child_id = sync_parent.GetFirstChildId(); |
447 while (sync_child_id != sync_api::kInvalidId) { | 456 while (sync_child_id != sync_api::kInvalidId) { |
448 sync_api::WriteNode sync_child_node(&trans); | 457 sync_api::WriteNode sync_child_node(&trans); |
449 if (!sync_child_node.InitByIdLookup(sync_child_id)) { | 458 if (!sync_child_node.InitByIdLookup(sync_child_id)) { |
450 error->Reset(FROM_HERE, "Failed to lookup node.", model_type()); | 459 return unrecoverable_error_handler_->CreateAndUploadError( |
451 return false; | 460 FROM_HERE, |
| 461 "Failed to lookup node.", |
| 462 model_type()); |
452 } | 463 } |
453 | 464 |
454 const BookmarkNode* child_node = NULL; | 465 const BookmarkNode* child_node = NULL; |
455 child_node = node_finder.FindBookmarkNode(sync_child_node); | 466 child_node = node_finder.FindBookmarkNode(sync_child_node); |
456 if (child_node) { | 467 if (child_node) { |
457 bookmark_model_->Move(child_node, parent_node, index); | 468 bookmark_model_->Move(child_node, parent_node, index); |
458 // Set the favicon for bookmark node from sync node or vice versa. | 469 // Set the favicon for bookmark node from sync node or vice versa. |
459 if (BookmarkChangeProcessor::SetBookmarkFavicon( | 470 if (BookmarkChangeProcessor::SetBookmarkFavicon( |
460 &sync_child_node, child_node, bookmark_model_)) { | 471 &sync_child_node, child_node, bookmark_model_)) { |
461 BookmarkChangeProcessor::SetSyncNodeFavicon( | 472 BookmarkChangeProcessor::SetSyncNodeFavicon( |
(...skipping 25 matching lines...) Expand all Loading... |
487 // At this point all the children nodes of the parent sync node have | 498 // At this point all the children nodes of the parent sync node have |
488 // corresponding children in the parent bookmark node and they are all in | 499 // corresponding children in the parent bookmark node and they are all in |
489 // the right positions: from 0 to index - 1. | 500 // the right positions: from 0 to index - 1. |
490 // So the children starting from index in the parent bookmark node are the | 501 // So the children starting from index in the parent bookmark node are the |
491 // ones that are not present in the parent sync node. So create them. | 502 // ones that are not present in the parent sync node. So create them. |
492 for (int i = index; i < parent_node->child_count(); ++i) { | 503 for (int i = index; i < parent_node->child_count(); ++i) { |
493 sync_child_id = BookmarkChangeProcessor::CreateSyncNode( | 504 sync_child_id = BookmarkChangeProcessor::CreateSyncNode( |
494 parent_node, bookmark_model_, i, &trans, this, | 505 parent_node, bookmark_model_, i, &trans, this, |
495 unrecoverable_error_handler_); | 506 unrecoverable_error_handler_); |
496 if (sync_api::kInvalidId == sync_child_id) { | 507 if (sync_api::kInvalidId == sync_child_id) { |
497 error->Reset(FROM_HERE, "Failed to create sync node.", model_type()); | 508 return unrecoverable_error_handler_->CreateAndUploadError( |
498 return false; // Creation failed. | 509 FROM_HERE, |
| 510 "Failed to create sync node.", |
| 511 model_type()); |
499 } | 512 } |
500 if (parent_node->GetChild(i)->is_folder()) | 513 if (parent_node->GetChild(i)->is_folder()) |
501 dfs_stack.push(sync_child_id); | 514 dfs_stack.push(sync_child_id); |
502 number_of_new_sync_nodes_created_at_association_++; | 515 number_of_new_sync_nodes_created_at_association_++; |
503 } | 516 } |
504 } | 517 } |
505 | 518 |
506 return true; | 519 return SyncError(); |
507 } | 520 } |
508 | 521 |
509 void BookmarkModelAssociator::PostPersistAssociationsTask() { | 522 void BookmarkModelAssociator::PostPersistAssociationsTask() { |
510 // No need to post a task if a task is already pending. | 523 // No need to post a task if a task is already pending. |
511 if (weak_factory_.HasWeakPtrs()) | 524 if (weak_factory_.HasWeakPtrs()) |
512 return; | 525 return; |
513 MessageLoop::current()->PostTask( | 526 MessageLoop::current()->PostTask( |
514 FROM_HERE, | 527 FROM_HERE, |
515 base::Bind( | 528 base::Bind( |
516 &BookmarkModelAssociator::PersistAssociations, | 529 &BookmarkModelAssociator::PersistAssociations, |
(...skipping 127 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
644 bool BookmarkModelAssociator::CryptoReadyIfNecessary() { | 657 bool BookmarkModelAssociator::CryptoReadyIfNecessary() { |
645 // We only access the cryptographer while holding a transaction. | 658 // We only access the cryptographer while holding a transaction. |
646 sync_api::ReadTransaction trans(FROM_HERE, user_share_); | 659 sync_api::ReadTransaction trans(FROM_HERE, user_share_); |
647 const syncable::ModelTypeSet encrypted_types = | 660 const syncable::ModelTypeSet encrypted_types = |
648 sync_api::GetEncryptedTypes(&trans); | 661 sync_api::GetEncryptedTypes(&trans); |
649 return !encrypted_types.Has(syncable::BOOKMARKS) || | 662 return !encrypted_types.Has(syncable::BOOKMARKS) || |
650 trans.GetCryptographer()->is_ready(); | 663 trans.GetCryptographer()->is_ready(); |
651 } | 664 } |
652 | 665 |
653 } // namespace browser_sync | 666 } // namespace browser_sync |
OLD | NEW |