| 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_change_processor.h" | 5 #include "chrome/browser/sync/glue/bookmark_change_processor.h" |
| 6 | 6 |
| 7 #include <stack> | 7 #include <stack> |
| 8 #include <vector> | 8 #include <vector> |
| 9 | 9 |
| 10 #include "base/location.h" | 10 #include "base/location.h" |
| 11 #include "base/string16.h" | 11 #include "base/string16.h" |
| 12 #include "base/string_number_conversions.h" | 12 #include "base/string_number_conversions.h" |
| 13 #include "base/string_util.h" | 13 #include "base/string_util.h" |
| 14 #include "base/utf_string_conversions.h" | 14 #include "base/utf_string_conversions.h" |
| 15 #include "chrome/browser/bookmarks/bookmark_model.h" | 15 #include "chrome/browser/bookmarks/bookmark_model.h" |
| 16 #include "chrome/browser/bookmarks/bookmark_model_factory.h" | 16 #include "chrome/browser/bookmarks/bookmark_model_factory.h" |
| 17 #include "chrome/browser/bookmarks/bookmark_utils.h" | 17 #include "chrome/browser/bookmarks/bookmark_utils.h" |
| 18 #include "chrome/browser/favicon/favicon_service.h" | 18 #include "chrome/browser/favicon/favicon_service.h" |
| 19 #include "chrome/browser/favicon/favicon_service_factory.h" | 19 #include "chrome/browser/favicon/favicon_service_factory.h" |
| 20 #include "chrome/browser/history/history_service_factory.h" | 20 #include "chrome/browser/history/history_service_factory.h" |
| 21 #include "chrome/browser/profiles/profile.h" | 21 #include "chrome/browser/profiles/profile.h" |
| 22 #include "chrome/browser/sync/profile_sync_service.h" | 22 #include "chrome/browser/sync/profile_sync_service.h" |
| 23 #include "content/public/browser/browser_thread.h" | 23 #include "content/public/browser/browser_thread.h" |
| 24 #include "sync/internal_api/public/change_record.h" | 24 #include "sync/internal_api/public/change_record.h" |
| 25 #include "sync/internal_api/public/read_node.h" | 25 #include "sync/internal_api/public/read_node.h" |
| 26 #include "sync/internal_api/public/write_node.h" | 26 #include "sync/internal_api/public/write_node.h" |
| 27 #include "sync/internal_api/public/write_transaction.h" | 27 #include "sync/internal_api/public/write_transaction.h" |
| 28 #include "sync/syncable/entry.h" // TODO(tim): Investigating bug 121587. | 28 #include "sync/syncable/entry.h" // TODO(tim): Investigating bug 121587. |
| 29 #include "sync/syncable/write_transaction.h" |
| 29 #include "ui/gfx/favicon_size.h" | 30 #include "ui/gfx/favicon_size.h" |
| 30 #include "ui/gfx/image/image_util.h" | 31 #include "ui/gfx/image/image_util.h" |
| 31 | 32 |
| 32 using content::BrowserThread; | 33 using content::BrowserThread; |
| 33 | 34 |
| 34 namespace browser_sync { | 35 namespace browser_sync { |
| 35 | 36 |
| 36 static const char kMobileBookmarksTag[] = "synced_bookmarks"; | 37 static const char kMobileBookmarksTag[] = "synced_bookmarks"; |
| 37 | 38 |
| 38 // Key for sync transaction version in bookmark node meta info. | 39 // Key for sync transaction version in bookmark node meta info. |
| (...skipping 67 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 106 } | 107 } |
| 107 // This node should have no children. | 108 // This node should have no children. |
| 108 DCHECK(!sync_node.HasChildren()); | 109 DCHECK(!sync_node.HasChildren()); |
| 109 // Remove association and delete the sync node. | 110 // Remove association and delete the sync node. |
| 110 model_associator_->Disassociate(sync_node.GetId()); | 111 model_associator_->Disassociate(sync_node.GetId()); |
| 111 sync_node.Remove(); | 112 sync_node.Remove(); |
| 112 } | 113 } |
| 113 | 114 |
| 114 void BookmarkChangeProcessor::RemoveSyncNodeHierarchy( | 115 void BookmarkChangeProcessor::RemoveSyncNodeHierarchy( |
| 115 const BookmarkNode* topmost) { | 116 const BookmarkNode* topmost) { |
| 116 syncer::WriteTransaction trans(FROM_HERE, share_handle()); | 117 int64 new_version = |
| 118 syncer::syncable::kInvalidTransactionVersion; |
| 119 { |
| 120 syncer::WriteTransaction trans(FROM_HERE, share_handle(), &new_version); |
| 117 | 121 |
| 118 // Later logic assumes that |topmost| has been unlinked. | 122 // Later logic assumes that |topmost| has been unlinked. |
| 119 DCHECK(topmost->is_root()); | 123 DCHECK(topmost->is_root()); |
| 120 | 124 |
| 121 // A BookmarkModel deletion event means that |node| and all its children were | 125 // A BookmarkModel deletion event means that |node| and all its children |
| 122 // deleted. Sync backend expects children to be deleted individually, so we do | 126 // were deleted. Sync backend expects children to be deleted individually, |
| 123 // a depth-first-search here. At each step, we consider the |index|-th child | 127 // so we do a depth-first-search here. At each step, we consider the |
| 124 // of |node|. |index_stack| stores index values for the parent levels. | 128 // |index|-th child of |node|. |index_stack| stores index values for the |
| 125 std::stack<int> index_stack; | 129 // parent levels. |
| 126 index_stack.push(0); // For the final pop. It's never used. | 130 std::stack<int> index_stack; |
| 127 const BookmarkNode* node = topmost; | 131 index_stack.push(0); // For the final pop. It's never used. |
| 128 int index = 0; | 132 const BookmarkNode* node = topmost; |
| 129 while (node) { | 133 int index = 0; |
| 130 // The top of |index_stack| should always be |node|'s index. | 134 while (node) { |
| 131 DCHECK(node->is_root() || (node->parent()->GetIndexOf(node) == | 135 // The top of |index_stack| should always be |node|'s index. |
| 132 index_stack.top())); | 136 DCHECK(node->is_root() || (node->parent()->GetIndexOf(node) == |
| 133 if (index == node->child_count()) { | 137 index_stack.top())); |
| 134 // If we've processed all of |node|'s children, delete |node| and move | 138 if (index == node->child_count()) { |
| 135 // on to its successor. | 139 // If we've processed all of |node|'s children, delete |node| and move |
| 136 RemoveOneSyncNode(&trans, node); | 140 // on to its successor. |
| 137 node = node->parent(); | 141 RemoveOneSyncNode(&trans, node); |
| 138 index = index_stack.top() + 1; // (top() + 0) was what we removed. | 142 node = node->parent(); |
| 139 index_stack.pop(); | 143 index = index_stack.top() + 1; // (top() + 0) was what we removed. |
| 140 } else { | 144 index_stack.pop(); |
| 141 // If |node| has an unprocessed child, process it next after pushing the | 145 } else { |
| 142 // current state onto the stack. | 146 // If |node| has an unprocessed child, process it next after pushing the |
| 143 DCHECK_LT(index, node->child_count()); | 147 // current state onto the stack. |
| 144 index_stack.push(index); | 148 DCHECK_LT(index, node->child_count()); |
| 145 node = node->GetChild(index); | 149 index_stack.push(index); |
| 146 index = 0; | 150 node = node->GetChild(index); |
| 151 index = 0; |
| 152 } |
| 147 } | 153 } |
| 154 DCHECK(index_stack.empty()); // Nothing should be left on the stack. |
| 148 } | 155 } |
| 149 DCHECK(index_stack.empty()); // Nothing should be left on the stack. | 156 |
| 157 // Don't need to update versions of deleted nodes. |
| 158 UpdateTransactionVersion(new_version, bookmark_model_, |
| 159 std::vector<const BookmarkNode*>()); |
| 150 } | 160 } |
| 151 | 161 |
| 152 void BookmarkChangeProcessor::Loaded(BookmarkModel* model, | 162 void BookmarkChangeProcessor::Loaded(BookmarkModel* model, |
| 153 bool ids_reassigned) { | 163 bool ids_reassigned) { |
| 154 NOTREACHED(); | 164 NOTREACHED(); |
| 155 } | 165 } |
| 156 | 166 |
| 157 void BookmarkChangeProcessor::BookmarkModelBeingDeleted( | 167 void BookmarkChangeProcessor::BookmarkModelBeingDeleted( |
| 158 BookmarkModel* model) { | 168 BookmarkModel* model) { |
| 159 NOTREACHED(); | 169 NOTREACHED(); |
| 160 bookmark_model_ = NULL; | 170 bookmark_model_ = NULL; |
| 161 } | 171 } |
| 162 | 172 |
| 163 void BookmarkChangeProcessor::BookmarkNodeAdded(BookmarkModel* model, | 173 void BookmarkChangeProcessor::BookmarkNodeAdded(BookmarkModel* model, |
| 164 const BookmarkNode* parent, | 174 const BookmarkNode* parent, |
| 165 int index) { | 175 int index) { |
| 166 DCHECK(share_handle()); | 176 DCHECK(share_handle()); |
| 167 | 177 |
| 168 // Acquire a scoped write lock via a transaction. | 178 int64 new_version = syncer::syncable::kInvalidTransactionVersion; |
| 169 syncer::WriteTransaction trans(FROM_HERE, share_handle()); | 179 int64 sync_id = syncer::kInvalidId; |
| 180 { |
| 181 // Acquire a scoped write lock via a transaction. |
| 182 syncer::WriteTransaction trans(FROM_HERE, share_handle(), &new_version); |
| 183 sync_id = CreateSyncNode(parent, model, index, &trans, |
| 184 model_associator_, error_handler()); |
| 185 } |
| 170 | 186 |
| 171 CreateSyncNode(parent, model, index, &trans, model_associator_, | 187 if (syncer::kInvalidId != sync_id) { |
| 172 error_handler()); | 188 // Siblings of added node in sync DB will also be updated to reflect new |
| 189 // PREV_ID/NEXT_ID and thus get a new version. But we only update version |
| 190 // of added node here. After switching to ordinals for positioning, |
| 191 // PREV_ID/NEXT_ID will be deprecated and siblings will not be updated. |
| 192 UpdateTransactionVersion( |
| 193 new_version, model, |
| 194 std::vector<const BookmarkNode*>(1, parent->GetChild(index))); |
| 195 } |
| 173 } | 196 } |
| 174 | 197 |
| 175 // static | 198 // static |
| 176 int64 BookmarkChangeProcessor::CreateSyncNode(const BookmarkNode* parent, | 199 int64 BookmarkChangeProcessor::CreateSyncNode(const BookmarkNode* parent, |
| 177 BookmarkModel* model, int index, syncer::WriteTransaction* trans, | 200 BookmarkModel* model, int index, syncer::WriteTransaction* trans, |
| 178 BookmarkModelAssociator* associator, | 201 BookmarkModelAssociator* associator, |
| 179 DataTypeErrorHandler* error_handler) { | 202 DataTypeErrorHandler* error_handler) { |
| 180 const BookmarkNode* child = parent->GetChild(index); | 203 const BookmarkNode* child = parent->GetChild(index); |
| 181 DCHECK(child); | 204 DCHECK(child); |
| 182 | 205 |
| 183 // Create a WriteNode container to hold the new node. | 206 // Create a WriteNode container to hold the new node. |
| 184 syncer::WriteNode sync_child(trans); | 207 syncer::WriteNode sync_child(trans); |
| 185 | 208 |
| 186 // Actually create the node with the appropriate initial position. | 209 // Actually create the node with the appropriate initial position. |
| 187 if (!PlaceSyncNode(CREATE, parent, index, trans, &sync_child, associator)) { | 210 if (!PlaceSyncNode(CREATE, parent, index, trans, &sync_child, associator)) { |
| 188 error_handler->OnSingleDatatypeUnrecoverableError(FROM_HERE, | 211 error_handler->OnSingleDatatypeUnrecoverableError(FROM_HERE, |
| 189 "Sync node creation failed; recovery unlikely"); | 212 "Sync node creation failed; recovery unlikely"); |
| 190 return syncer::kInvalidId; | 213 return syncer::kInvalidId; |
| 191 } | 214 } |
| 192 | 215 |
| 193 UpdateSyncNodeProperties(child, model, &sync_child); | 216 UpdateSyncNodeProperties(child, model, &sync_child); |
| 194 | 217 |
| 195 // Associate the ID from the sync domain with the bookmark node, so that we | 218 // Associate the ID from the sync domain with the bookmark node, so that we |
| 196 // can refer back to this item later. | 219 // can refer back to this item later. |
| 197 associator->Associate(child, sync_child.GetId()); | 220 associator->Associate(child, sync_child.GetId()); |
| 198 | 221 |
| 199 return sync_child.GetId(); | 222 return sync_child.GetId(); |
| 200 } | 223 } |
| 201 | 224 |
| 202 | |
| 203 void BookmarkChangeProcessor::BookmarkNodeRemoved(BookmarkModel* model, | 225 void BookmarkChangeProcessor::BookmarkNodeRemoved(BookmarkModel* model, |
| 204 const BookmarkNode* parent, | 226 const BookmarkNode* parent, |
| 205 int index, | 227 int index, |
| 206 const BookmarkNode* node) { | 228 const BookmarkNode* node) { |
| 207 RemoveSyncNodeHierarchy(node); | 229 RemoveSyncNodeHierarchy(node); |
| 208 } | 230 } |
| 209 | 231 |
| 210 void BookmarkChangeProcessor::BookmarkNodeChanged(BookmarkModel* model, | 232 void BookmarkChangeProcessor::BookmarkNodeChanged(BookmarkModel* model, |
| 211 const BookmarkNode* node) { | 233 const BookmarkNode* node) { |
| 212 // We shouldn't see changes to the top-level nodes. | 234 // We shouldn't see changes to the top-level nodes. |
| 213 if (model->is_permanent_node(node)) { | 235 if (model->is_permanent_node(node)) { |
| 214 NOTREACHED() << "Saw update to permanent node!"; | 236 NOTREACHED() << "Saw update to permanent node!"; |
| 215 return; | 237 return; |
| 216 } | 238 } |
| 217 | 239 |
| 218 // Acquire a scoped write lock via a transaction. | 240 int64 new_version = syncer::syncable::kInvalidTransactionVersion; |
| 219 syncer::WriteTransaction trans(FROM_HERE, share_handle()); | 241 { |
| 242 // Acquire a scoped write lock via a transaction. |
| 243 syncer::WriteTransaction trans(FROM_HERE, share_handle(), &new_version); |
| 220 | 244 |
| 221 // Lookup the sync node that's associated with |node|. | 245 // Lookup the sync node that's associated with |node|. |
| 222 syncer::WriteNode sync_node(&trans); | 246 syncer::WriteNode sync_node(&trans); |
| 223 if (!model_associator_->InitSyncNodeFromChromeId(node->id(), &sync_node)) { | 247 if (!model_associator_->InitSyncNodeFromChromeId(node->id(), &sync_node)) { |
| 224 // TODO(tim): Investigating bug 121587. | 248 // TODO(tim): Investigating bug 121587. |
| 225 if (model_associator_->GetSyncIdFromChromeId(node->id()) == | 249 if (model_associator_->GetSyncIdFromChromeId(node->id()) == |
| 226 syncer::kInvalidId) { | 250 syncer::kInvalidId) { |
| 227 error_handler()->OnSingleDatatypeUnrecoverableError(FROM_HERE, | |
| 228 "Bookmark id not found in model associator on BookmarkNodeChanged"); | |
| 229 LOG(ERROR) << "Bad id."; | |
| 230 } else if (!sync_node.GetEntry()->good()) { | |
| 231 error_handler()->OnSingleDatatypeUnrecoverableError(FROM_HERE, | |
| 232 "Could not InitByIdLookup on BookmarkNodeChanged, good() failed"); | |
| 233 LOG(ERROR) << "Bad entry."; | |
| 234 } else if (sync_node.GetEntry()->Get(syncer::syncable::IS_DEL)) { | |
| 235 error_handler()->OnSingleDatatypeUnrecoverableError(FROM_HERE, | |
| 236 "Could not InitByIdLookup on BookmarkNodeChanged, is_del true"); | |
| 237 LOG(ERROR) << "Deleted entry."; | |
| 238 } else { | |
| 239 syncer::Cryptographer* crypto = trans.GetCryptographer(); | |
| 240 syncer::ModelTypeSet encrypted_types(trans.GetEncryptedTypes()); | |
| 241 const sync_pb::EntitySpecifics& specifics = | |
| 242 sync_node.GetEntry()->Get(syncer::syncable::SPECIFICS); | |
| 243 CHECK(specifics.has_encrypted()); | |
| 244 const bool can_decrypt = crypto->CanDecrypt(specifics.encrypted()); | |
| 245 const bool agreement = encrypted_types.Has(syncer::BOOKMARKS); | |
| 246 if (!agreement && !can_decrypt) { | |
| 247 error_handler()->OnSingleDatatypeUnrecoverableError(FROM_HERE, | 251 error_handler()->OnSingleDatatypeUnrecoverableError(FROM_HERE, |
| 248 "Could not InitByIdLookup on BookmarkNodeChanged, " | 252 "Bookmark id not found in model associator on BookmarkNodeChanged"); |
| 249 " Cryptographer thinks bookmarks not encrypted, and CanDecrypt" | 253 LOG(ERROR) << "Bad id."; |
| 250 " failed."); | 254 } else if (!sync_node.GetEntry()->good()) { |
| 251 LOG(ERROR) << "Case 1."; | |
| 252 } else if (agreement && can_decrypt) { | |
| 253 error_handler()->OnSingleDatatypeUnrecoverableError(FROM_HERE, | 255 error_handler()->OnSingleDatatypeUnrecoverableError(FROM_HERE, |
| 254 "Could not InitByIdLookup on BookmarkNodeChanged, " | 256 "Could not InitByIdLookup on BookmarkNodeChanged, good() failed"); |
| 255 " Cryptographer thinks bookmarks are encrypted, and CanDecrypt" | 257 LOG(ERROR) << "Bad entry."; |
| 256 " succeeded (?!), but DecryptIfNecessary failed."); | 258 } else if (sync_node.GetEntry()->Get(syncer::syncable::IS_DEL)) { |
| 257 LOG(ERROR) << "Case 2."; | |
| 258 } else if (agreement) { | |
| 259 error_handler()->OnSingleDatatypeUnrecoverableError(FROM_HERE, | 259 error_handler()->OnSingleDatatypeUnrecoverableError(FROM_HERE, |
| 260 "Could not InitByIdLookup on BookmarkNodeChanged, " | 260 "Could not InitByIdLookup on BookmarkNodeChanged, is_del true"); |
| 261 " Cryptographer thinks bookmarks are encrypted, but CanDecrypt" | 261 LOG(ERROR) << "Deleted entry."; |
| 262 " failed."); | |
| 263 LOG(ERROR) << "Case 3."; | |
| 264 } else { | 262 } else { |
| 265 error_handler()->OnSingleDatatypeUnrecoverableError(FROM_HERE, | 263 syncer::Cryptographer* crypto = trans.GetCryptographer(); |
| 266 "Could not InitByIdLookup on BookmarkNodeChanged, " | 264 syncer::ModelTypeSet encrypted_types(trans.GetEncryptedTypes()); |
| 267 " Cryptographer thinks bookmarks not encrypted, but CanDecrypt" | 265 const sync_pb::EntitySpecifics& specifics = |
| 268 " succeeded (super weird, btw)"); | 266 sync_node.GetEntry()->Get(syncer::syncable::SPECIFICS); |
| 269 LOG(ERROR) << "Case 4."; | 267 CHECK(specifics.has_encrypted()); |
| 268 const bool can_decrypt = crypto->CanDecrypt(specifics.encrypted()); |
| 269 const bool agreement = encrypted_types.Has(syncer::BOOKMARKS); |
| 270 if (!agreement && !can_decrypt) { |
| 271 error_handler()->OnSingleDatatypeUnrecoverableError(FROM_HERE, |
| 272 "Could not InitByIdLookup on BookmarkNodeChanged, " |
| 273 " Cryptographer thinks bookmarks not encrypted, and CanDecrypt" |
| 274 " failed."); |
| 275 LOG(ERROR) << "Case 1."; |
| 276 } else if (agreement && can_decrypt) { |
| 277 error_handler()->OnSingleDatatypeUnrecoverableError(FROM_HERE, |
| 278 "Could not InitByIdLookup on BookmarkNodeChanged, " |
| 279 " Cryptographer thinks bookmarks are encrypted, and CanDecrypt" |
| 280 " succeeded (?!), but DecryptIfNecessary failed."); |
| 281 LOG(ERROR) << "Case 2."; |
| 282 } else if (agreement) { |
| 283 error_handler()->OnSingleDatatypeUnrecoverableError(FROM_HERE, |
| 284 "Could not InitByIdLookup on BookmarkNodeChanged, " |
| 285 " Cryptographer thinks bookmarks are encrypted, but CanDecrypt" |
| 286 " failed."); |
| 287 LOG(ERROR) << "Case 3."; |
| 288 } else { |
| 289 error_handler()->OnSingleDatatypeUnrecoverableError(FROM_HERE, |
| 290 "Could not InitByIdLookup on BookmarkNodeChanged, " |
| 291 " Cryptographer thinks bookmarks not encrypted, but CanDecrypt" |
| 292 " succeeded (super weird, btw)"); |
| 293 LOG(ERROR) << "Case 4."; |
| 294 } |
| 270 } | 295 } |
| 296 return; |
| 271 } | 297 } |
| 272 return; | 298 |
| 299 UpdateSyncNodeProperties(node, model, &sync_node); |
| 300 |
| 301 DCHECK_EQ(sync_node.GetIsFolder(), node->is_folder()); |
| 302 DCHECK_EQ(model_associator_->GetChromeNodeFromSyncId( |
| 303 sync_node.GetParentId()), |
| 304 node->parent()); |
| 305 // This node's index should be one more than the predecessor's index. |
| 306 DCHECK_EQ(node->parent()->GetIndexOf(node), |
| 307 CalculateBookmarkModelInsertionIndex(node->parent(), |
| 308 &sync_node, |
| 309 model_associator_)); |
| 273 } | 310 } |
| 274 | 311 |
| 275 UpdateSyncNodeProperties(node, model, &sync_node); | 312 UpdateTransactionVersion(new_version, model, |
| 276 | 313 std::vector<const BookmarkNode*>(1, node)); |
| 277 DCHECK_EQ(sync_node.GetIsFolder(), node->is_folder()); | |
| 278 DCHECK_EQ(model_associator_->GetChromeNodeFromSyncId( | |
| 279 sync_node.GetParentId()), | |
| 280 node->parent()); | |
| 281 // This node's index should be one more than the predecessor's index. | |
| 282 DCHECK_EQ(node->parent()->GetIndexOf(node), | |
| 283 CalculateBookmarkModelInsertionIndex(node->parent(), | |
| 284 &sync_node, | |
| 285 model_associator_)); | |
| 286 } | 314 } |
| 287 | 315 |
| 288 | |
| 289 void BookmarkChangeProcessor::BookmarkNodeMoved(BookmarkModel* model, | 316 void BookmarkChangeProcessor::BookmarkNodeMoved(BookmarkModel* model, |
| 290 const BookmarkNode* old_parent, int old_index, | 317 const BookmarkNode* old_parent, int old_index, |
| 291 const BookmarkNode* new_parent, int new_index) { | 318 const BookmarkNode* new_parent, int new_index) { |
| 292 const BookmarkNode* child = new_parent->GetChild(new_index); | 319 const BookmarkNode* child = new_parent->GetChild(new_index); |
| 293 // We shouldn't see changes to the top-level nodes. | 320 // We shouldn't see changes to the top-level nodes. |
| 294 if (model->is_permanent_node(child)) { | 321 if (model->is_permanent_node(child)) { |
| 295 NOTREACHED() << "Saw update to permanent node!"; | 322 NOTREACHED() << "Saw update to permanent node!"; |
| 296 return; | 323 return; |
| 297 } | 324 } |
| 298 | 325 |
| 299 // Acquire a scoped write lock via a transaction. | 326 int64 new_version = syncer::syncable::kInvalidTransactionVersion; |
| 300 syncer::WriteTransaction trans(FROM_HERE, share_handle()); | 327 { |
| 328 // Acquire a scoped write lock via a transaction. |
| 329 syncer::WriteTransaction trans(FROM_HERE, share_handle(), &new_version); |
| 301 | 330 |
| 302 // Lookup the sync node that's associated with |child|. | 331 // Lookup the sync node that's associated with |child|. |
| 303 syncer::WriteNode sync_node(&trans); | 332 syncer::WriteNode sync_node(&trans); |
| 304 if (!model_associator_->InitSyncNodeFromChromeId(child->id(), &sync_node)) { | 333 if (!model_associator_->InitSyncNodeFromChromeId(child->id(), &sync_node)) { |
| 305 error_handler()->OnSingleDatatypeUnrecoverableError(FROM_HERE, | 334 error_handler()->OnSingleDatatypeUnrecoverableError(FROM_HERE, |
| 306 std::string()); | 335 std::string()); |
| 307 return; | 336 return; |
| 337 } |
| 338 |
| 339 if (!PlaceSyncNode(MOVE, new_parent, new_index, &trans, &sync_node, |
| 340 model_associator_)) { |
| 341 error_handler()->OnSingleDatatypeUnrecoverableError(FROM_HERE, |
| 342 std::string()); |
| 343 return; |
| 344 } |
| 308 } | 345 } |
| 309 | 346 |
| 310 if (!PlaceSyncNode(MOVE, new_parent, new_index, &trans, &sync_node, | 347 UpdateTransactionVersion(new_version, model, |
| 311 model_associator_)) { | 348 std::vector<const BookmarkNode*>(1, child)); |
| 312 error_handler()->OnSingleDatatypeUnrecoverableError(FROM_HERE, | |
| 313 std::string()); | |
| 314 return; | |
| 315 } | |
| 316 } | 349 } |
| 317 | 350 |
| 318 void BookmarkChangeProcessor::BookmarkNodeFaviconChanged( | 351 void BookmarkChangeProcessor::BookmarkNodeFaviconChanged( |
| 319 BookmarkModel* model, | 352 BookmarkModel* model, |
| 320 const BookmarkNode* node) { | 353 const BookmarkNode* node) { |
| 321 BookmarkNodeChanged(model, node); | 354 BookmarkNodeChanged(model, node); |
| 322 } | 355 } |
| 323 | 356 |
| 324 void BookmarkChangeProcessor::BookmarkNodeChildrenReordered( | 357 void BookmarkChangeProcessor::BookmarkNodeChildrenReordered( |
| 325 BookmarkModel* model, const BookmarkNode* node) { | 358 BookmarkModel* model, const BookmarkNode* node) { |
| 359 int64 new_version = syncer::syncable::kInvalidTransactionVersion; |
| 360 std::vector<const BookmarkNode*> children; |
| 361 { |
| 362 // Acquire a scoped write lock via a transaction. |
| 363 syncer::WriteTransaction trans(FROM_HERE, share_handle(), &new_version); |
| 326 | 364 |
| 327 // Acquire a scoped write lock via a transaction. | 365 // The given node's children got reordered. We need to reorder all the |
| 328 syncer::WriteTransaction trans(FROM_HERE, share_handle()); | 366 // children of the corresponding sync node. |
| 367 for (int i = 0; i < node->child_count(); ++i) { |
| 368 const BookmarkNode* child = node->GetChild(i); |
| 369 children.push_back(child); |
| 329 | 370 |
| 330 // The given node's children got reordered. We need to reorder all the | 371 syncer::WriteNode sync_child(&trans); |
| 331 // children of the corresponding sync node. | 372 if (!model_associator_->InitSyncNodeFromChromeId(child->id(), |
| 332 for (int i = 0; i < node->child_count(); ++i) { | 373 &sync_child)) { |
| 333 syncer::WriteNode sync_child(&trans); | 374 error_handler()->OnSingleDatatypeUnrecoverableError(FROM_HERE, |
| 334 if (!model_associator_->InitSyncNodeFromChromeId(node->GetChild(i)->id(), | 375 std::string()); |
| 335 &sync_child)) { | 376 return; |
| 336 error_handler()->OnSingleDatatypeUnrecoverableError(FROM_HERE, | 377 } |
| 337 std::string()); | 378 DCHECK_EQ(sync_child.GetParentId(), |
| 338 return; | 379 model_associator_->GetSyncIdFromChromeId(node->id())); |
| 339 } | |
| 340 DCHECK_EQ(sync_child.GetParentId(), | |
| 341 model_associator_->GetSyncIdFromChromeId(node->id())); | |
| 342 | 380 |
| 343 if (!PlaceSyncNode(MOVE, node, i, &trans, &sync_child, | 381 if (!PlaceSyncNode(MOVE, node, i, &trans, &sync_child, |
| 344 model_associator_)) { | 382 model_associator_)) { |
| 345 error_handler()->OnSingleDatatypeUnrecoverableError(FROM_HERE, | 383 error_handler()->OnSingleDatatypeUnrecoverableError(FROM_HERE, |
| 346 std::string()); | 384 std::string()); |
| 347 return; | 385 return; |
| 386 } |
| 348 } | 387 } |
| 349 } | 388 } |
| 389 |
| 390 // TODO(haitaol): Filter out children that didn't actually change. |
| 391 UpdateTransactionVersion(new_version, model, children); |
| 350 } | 392 } |
| 351 | 393 |
| 352 // static | 394 // static |
| 353 bool BookmarkChangeProcessor::PlaceSyncNode(MoveOrCreate operation, | 395 bool BookmarkChangeProcessor::PlaceSyncNode(MoveOrCreate operation, |
| 354 const BookmarkNode* parent, int index, syncer::WriteTransaction* trans, | 396 const BookmarkNode* parent, int index, syncer::WriteTransaction* trans, |
| 355 syncer::WriteNode* dst, BookmarkModelAssociator* associator) { | 397 syncer::WriteNode* dst, BookmarkModelAssociator* associator) { |
| 356 syncer::ReadNode sync_parent(trans); | 398 syncer::ReadNode sync_parent(trans); |
| 357 if (!associator->InitSyncNodeFromChromeId(parent->id(), &sync_parent)) { | 399 if (!associator->InitSyncNodeFromChromeId(parent->id(), &sync_parent)) { |
| 358 LOG(WARNING) << "Parent lookup failed"; | 400 LOG(WARNING) << "Parent lookup failed"; |
| 359 return false; | 401 return false; |
| (...skipping 138 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 498 << "ACTION_ADD should be seen if and only if the node is unknown."; | 540 << "ACTION_ADD should be seen if and only if the node is unknown."; |
| 499 passed_deletes = true; | 541 passed_deletes = true; |
| 500 | 542 |
| 501 syncer::ReadNode src(trans); | 543 syncer::ReadNode src(trans); |
| 502 if (src.InitByIdLookup(it->id) != syncer::BaseNode::INIT_OK) { | 544 if (src.InitByIdLookup(it->id) != syncer::BaseNode::INIT_OK) { |
| 503 error_handler()->OnSingleDatatypeUnrecoverableError(FROM_HERE, | 545 error_handler()->OnSingleDatatypeUnrecoverableError(FROM_HERE, |
| 504 "ApplyModelChanges was passed a bad ID"); | 546 "ApplyModelChanges was passed a bad ID"); |
| 505 return; | 547 return; |
| 506 } | 548 } |
| 507 | 549 |
| 508 if (!CreateOrUpdateBookmarkNode(&src, model, model_associator_)) { | 550 const BookmarkNode* node = CreateOrUpdateBookmarkNode(&src, model, |
| 551 model_associator_); |
| 552 if (node) { |
| 553 bookmark_model_->SetNodeMetaInfo(node, kBookmarkTransactionVersionKey, |
| 554 base::Int64ToString(model_version)); |
| 555 } else { |
| 509 // Because the Synced Bookmarks node can be created server side, it's | 556 // Because the Synced Bookmarks node can be created server side, it's |
| 510 // possible it'll arrive at the client as an update. In that case it | 557 // possible it'll arrive at the client as an update. In that case it |
| 511 // won't have been associated at startup, the GetChromeNodeFromSyncId | 558 // won't have been associated at startup, the GetChromeNodeFromSyncId |
| 512 // call above will return NULL, and we won't detect it as a permanent | 559 // call above will return NULL, and we won't detect it as a permanent |
| 513 // node, resulting in us trying to create it here (which will | 560 // node, resulting in us trying to create it here (which will |
| 514 // fail). Therefore, we add special logic here just to detect the | 561 // fail). Therefore, we add special logic here just to detect the |
| 515 // Synced Bookmarks folder. | 562 // Synced Bookmarks folder. |
| 516 syncer::ReadNode synced_bookmarks(trans); | 563 syncer::ReadNode synced_bookmarks(trans); |
| 517 if (synced_bookmarks.InitByTagLookup(kMobileBookmarksTag) == | 564 if (synced_bookmarks.InitByTagLookup(kMobileBookmarksTag) == |
| 518 syncer::BaseNode::INIT_OK && | 565 syncer::BaseNode::INIT_OK && |
| (...skipping 73 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 592 src->GetBookmarkSpecifics().creation_time_us())); | 639 src->GetBookmarkSpecifics().creation_time_us())); |
| 593 } | 640 } |
| 594 | 641 |
| 595 SetBookmarkFavicon(src, dst, model); | 642 SetBookmarkFavicon(src, dst, model); |
| 596 } | 643 } |
| 597 | 644 |
| 598 return dst; | 645 return dst; |
| 599 } | 646 } |
| 600 | 647 |
| 601 // static | 648 // static |
| 649 void BookmarkChangeProcessor::UpdateTransactionVersion( |
| 650 int64 new_version, |
| 651 BookmarkModel* model, |
| 652 const std::vector<const BookmarkNode*>& nodes) { |
| 653 if (new_version != syncer::syncable::kInvalidTransactionVersion) { |
| 654 model->SetNodeMetaInfo(model->root_node(), kBookmarkTransactionVersionKey, |
| 655 base::Int64ToString(new_version)); |
| 656 for (size_t i = 0; i < nodes.size(); ++i) { |
| 657 model->SetNodeMetaInfo(nodes[i], kBookmarkTransactionVersionKey, |
| 658 base::Int64ToString(new_version)); |
| 659 } |
| 660 } |
| 661 } |
| 662 |
| 663 // static |
| 602 // Creates a bookmark node under the given parent node from the given sync | 664 // Creates a bookmark node under the given parent node from the given sync |
| 603 // node. Returns the newly created node. | 665 // node. Returns the newly created node. |
| 604 const BookmarkNode* BookmarkChangeProcessor::CreateBookmarkNode( | 666 const BookmarkNode* BookmarkChangeProcessor::CreateBookmarkNode( |
| 605 syncer::BaseNode* sync_node, | 667 syncer::BaseNode* sync_node, |
| 606 const BookmarkNode* parent, | 668 const BookmarkNode* parent, |
| 607 BookmarkModel* model, | 669 BookmarkModel* model, |
| 608 int index) { | 670 int index) { |
| 609 DCHECK(parent); | 671 DCHECK(parent); |
| 610 DCHECK(index >= 0 && index <= parent->child_count()); | 672 DCHECK(index >= 0 && index <= parent->child_count()); |
| 611 | 673 |
| (...skipping 64 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 676 const BookmarkNode* bookmark_node, | 738 const BookmarkNode* bookmark_node, |
| 677 BookmarkModel* model, | 739 BookmarkModel* model, |
| 678 syncer::WriteNode* sync_node) { | 740 syncer::WriteNode* sync_node) { |
| 679 std::vector<unsigned char> favicon_bytes; | 741 std::vector<unsigned char> favicon_bytes; |
| 680 EncodeFavicon(bookmark_node, model, &favicon_bytes); | 742 EncodeFavicon(bookmark_node, model, &favicon_bytes); |
| 681 if (!favicon_bytes.empty()) | 743 if (!favicon_bytes.empty()) |
| 682 sync_node->SetFaviconBytes(favicon_bytes); | 744 sync_node->SetFaviconBytes(favicon_bytes); |
| 683 } | 745 } |
| 684 | 746 |
| 685 } // namespace browser_sync | 747 } // namespace browser_sync |
| OLD | NEW |