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/read_transaction.h" | |
26 #include "sync/internal_api/public/write_node.h" | 27 #include "sync/internal_api/public/write_node.h" |
27 #include "sync/internal_api/public/write_transaction.h" | 28 #include "sync/internal_api/public/write_transaction.h" |
28 #include "sync/syncable/entry.h" // TODO(tim): Investigating bug 121587. | 29 #include "sync/syncable/entry.h" // TODO(tim): Investigating bug 121587. |
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 |
(...skipping 70 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 old_version; |
tim (not reviewing)
2012/11/01 18:31:36
Should initialize this, if not to zero, to -1 or s
haitaol1
2012/11/02 17:57:11
Done.
| |
118 { | |
119 syncer::WriteTransaction trans(FROM_HERE, share_handle()); | |
120 old_version = trans.GetModelVersion(syncer::BOOKMARKS); | |
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 UpdateVersion(old_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 old_version; |
169 syncer::WriteTransaction trans(FROM_HERE, share_handle()); | 179 int64 sync_id; |
tim (not reviewing)
2012/11/01 18:31:36
initialize these two
haitaol1
2012/11/02 17:57:11
Done.
| |
180 { | |
181 // Acquire a scoped write lock via a transaction. | |
182 syncer::WriteTransaction trans(FROM_HERE, share_handle()); | |
tim (not reviewing)
2012/11/01 18:31:36
Hmm, I see the corner you're in here - you need to
haitaol1
2012/11/02 17:57:11
Done. See changes in write_transaction.cc
| |
183 old_version = trans.GetModelVersion(syncer::BOOKMARKS); | |
184 sync_id = CreateSyncNode(parent, model, index, &trans, | |
185 model_associator_, error_handler()); | |
186 } | |
170 | 187 |
171 CreateSyncNode(parent, model, index, &trans, model_associator_, | 188 if (syncer::kInvalidId != sync_id) { |
172 error_handler()); | 189 // NOTE(haitaol): Siblings of added node in sync DB will also be updated to |
190 // reflect new PREV_ID/NEXT_ID and thus get a new version. | |
191 // But we only update version of added node here. After | |
192 // switching to ordinals for positioning, PREV_ID/NEXT_ID | |
193 // will be deprecated and siblings will not be updated. | |
194 UpdateVersion(old_version, model, | |
195 std::vector<const BookmarkNode*>(1, parent->GetChild(index))); | |
196 } | |
173 } | 197 } |
174 | 198 |
175 // static | 199 // static |
176 int64 BookmarkChangeProcessor::CreateSyncNode(const BookmarkNode* parent, | 200 int64 BookmarkChangeProcessor::CreateSyncNode(const BookmarkNode* parent, |
177 BookmarkModel* model, int index, syncer::WriteTransaction* trans, | 201 BookmarkModel* model, int index, syncer::WriteTransaction* trans, |
178 BookmarkModelAssociator* associator, | 202 BookmarkModelAssociator* associator, |
179 DataTypeErrorHandler* error_handler) { | 203 DataTypeErrorHandler* error_handler) { |
180 const BookmarkNode* child = parent->GetChild(index); | 204 const BookmarkNode* child = parent->GetChild(index); |
181 DCHECK(child); | 205 DCHECK(child); |
182 | 206 |
183 // Create a WriteNode container to hold the new node. | 207 // Create a WriteNode container to hold the new node. |
184 syncer::WriteNode sync_child(trans); | 208 syncer::WriteNode sync_child(trans); |
185 | 209 |
186 // Actually create the node with the appropriate initial position. | 210 // Actually create the node with the appropriate initial position. |
187 if (!PlaceSyncNode(CREATE, parent, index, trans, &sync_child, associator)) { | 211 if (!PlaceSyncNode(CREATE, parent, index, trans, &sync_child, associator)) { |
188 error_handler->OnSingleDatatypeUnrecoverableError(FROM_HERE, | 212 error_handler->OnSingleDatatypeUnrecoverableError(FROM_HERE, |
189 "Sync node creation failed; recovery unlikely"); | 213 "Sync node creation failed; recovery unlikely"); |
190 return syncer::kInvalidId; | 214 return syncer::kInvalidId; |
191 } | 215 } |
192 | 216 |
193 UpdateSyncNodeProperties(child, model, &sync_child); | 217 UpdateSyncNodeProperties(child, model, &sync_child); |
194 | 218 |
195 // Associate the ID from the sync domain with the bookmark node, so that we | 219 // Associate the ID from the sync domain with the bookmark node, so that we |
196 // can refer back to this item later. | 220 // can refer back to this item later. |
197 associator->Associate(child, sync_child.GetId()); | 221 associator->Associate(child, sync_child.GetId()); |
198 | 222 |
199 return sync_child.GetId(); | 223 return sync_child.GetId(); |
200 } | 224 } |
201 | 225 |
202 | |
203 void BookmarkChangeProcessor::BookmarkNodeRemoved(BookmarkModel* model, | 226 void BookmarkChangeProcessor::BookmarkNodeRemoved(BookmarkModel* model, |
204 const BookmarkNode* parent, | 227 const BookmarkNode* parent, |
205 int index, | 228 int index, |
206 const BookmarkNode* node) { | 229 const BookmarkNode* node) { |
207 RemoveSyncNodeHierarchy(node); | 230 RemoveSyncNodeHierarchy(node); |
208 } | 231 } |
209 | 232 |
210 void BookmarkChangeProcessor::BookmarkNodeChanged(BookmarkModel* model, | 233 void BookmarkChangeProcessor::BookmarkNodeChanged(BookmarkModel* model, |
211 const BookmarkNode* node) { | 234 const BookmarkNode* node) { |
212 // We shouldn't see changes to the top-level nodes. | 235 // We shouldn't see changes to the top-level nodes. |
213 if (model->is_permanent_node(node)) { | 236 if (model->is_permanent_node(node)) { |
214 NOTREACHED() << "Saw update to permanent node!"; | 237 NOTREACHED() << "Saw update to permanent node!"; |
215 return; | 238 return; |
216 } | 239 } |
217 | 240 |
218 // Acquire a scoped write lock via a transaction. | 241 int64 old_version; |
219 syncer::WriteTransaction trans(FROM_HERE, share_handle()); | 242 { |
243 // Acquire a scoped write lock via a transaction. | |
244 syncer::WriteTransaction trans(FROM_HERE, share_handle()); | |
245 old_version = trans.GetModelVersion(syncer::BOOKMARKS); | |
220 | 246 |
221 // Lookup the sync node that's associated with |node|. | 247 // Lookup the sync node that's associated with |node|. |
222 syncer::WriteNode sync_node(&trans); | 248 syncer::WriteNode sync_node(&trans); |
223 if (!model_associator_->InitSyncNodeFromChromeId(node->id(), &sync_node)) { | 249 if (!model_associator_->InitSyncNodeFromChromeId(node->id(), &sync_node)) { |
224 // TODO(tim): Investigating bug 121587. | 250 // TODO(tim): Investigating bug 121587. |
225 if (model_associator_->GetSyncIdFromChromeId(node->id()) == | 251 if (model_associator_->GetSyncIdFromChromeId(node->id()) == |
226 syncer::kInvalidId) { | 252 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, | 253 error_handler()->OnSingleDatatypeUnrecoverableError(FROM_HERE, |
248 "Could not InitByIdLookup on BookmarkNodeChanged, " | 254 "Bookmark id not found in model associator on BookmarkNodeChanged"); |
249 " Cryptographer thinks bookmarks not encrypted, and CanDecrypt" | 255 LOG(ERROR) << "Bad id."; |
250 " failed."); | 256 } else if (!sync_node.GetEntry()->good()) { |
251 LOG(ERROR) << "Case 1."; | |
252 } else if (agreement && can_decrypt) { | |
253 error_handler()->OnSingleDatatypeUnrecoverableError(FROM_HERE, | 257 error_handler()->OnSingleDatatypeUnrecoverableError(FROM_HERE, |
254 "Could not InitByIdLookup on BookmarkNodeChanged, " | 258 "Could not InitByIdLookup on BookmarkNodeChanged, good() failed"); |
255 " Cryptographer thinks bookmarks are encrypted, and CanDecrypt" | 259 LOG(ERROR) << "Bad entry."; |
256 " succeeded (?!), but DecryptIfNecessary failed."); | 260 } 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, | 261 error_handler()->OnSingleDatatypeUnrecoverableError(FROM_HERE, |
260 "Could not InitByIdLookup on BookmarkNodeChanged, " | 262 "Could not InitByIdLookup on BookmarkNodeChanged, is_del true"); |
261 " Cryptographer thinks bookmarks are encrypted, but CanDecrypt" | 263 LOG(ERROR) << "Deleted entry."; |
262 " failed."); | |
263 LOG(ERROR) << "Case 3."; | |
264 } else { | 264 } else { |
265 error_handler()->OnSingleDatatypeUnrecoverableError(FROM_HERE, | 265 syncer::Cryptographer* crypto = trans.GetCryptographer(); |
266 "Could not InitByIdLookup on BookmarkNodeChanged, " | 266 syncer::ModelTypeSet encrypted_types(trans.GetEncryptedTypes()); |
267 " Cryptographer thinks bookmarks not encrypted, but CanDecrypt" | 267 const sync_pb::EntitySpecifics& specifics = |
268 " succeeded (super weird, btw)"); | 268 sync_node.GetEntry()->Get(syncer::syncable::SPECIFICS); |
269 LOG(ERROR) << "Case 4."; | 269 CHECK(specifics.has_encrypted()); |
270 const bool can_decrypt = crypto->CanDecrypt(specifics.encrypted()); | |
271 const bool agreement = encrypted_types.Has(syncer::BOOKMARKS); | |
272 if (!agreement && !can_decrypt) { | |
273 error_handler()->OnSingleDatatypeUnrecoverableError(FROM_HERE, | |
274 "Could not InitByIdLookup on BookmarkNodeChanged, " | |
275 " Cryptographer thinks bookmarks not encrypted, and CanDecrypt" | |
276 " failed."); | |
277 LOG(ERROR) << "Case 1."; | |
278 } else if (agreement && can_decrypt) { | |
279 error_handler()->OnSingleDatatypeUnrecoverableError(FROM_HERE, | |
280 "Could not InitByIdLookup on BookmarkNodeChanged, " | |
281 " Cryptographer thinks bookmarks are encrypted, and CanDecrypt" | |
282 " succeeded (?!), but DecryptIfNecessary failed."); | |
283 LOG(ERROR) << "Case 2."; | |
284 } else if (agreement) { | |
285 error_handler()->OnSingleDatatypeUnrecoverableError(FROM_HERE, | |
286 "Could not InitByIdLookup on BookmarkNodeChanged, " | |
287 " Cryptographer thinks bookmarks are encrypted, but CanDecrypt" | |
288 " failed."); | |
289 LOG(ERROR) << "Case 3."; | |
290 } else { | |
291 error_handler()->OnSingleDatatypeUnrecoverableError(FROM_HERE, | |
292 "Could not InitByIdLookup on BookmarkNodeChanged, " | |
293 " Cryptographer thinks bookmarks not encrypted, but CanDecrypt" | |
294 " succeeded (super weird, btw)"); | |
295 LOG(ERROR) << "Case 4."; | |
296 } | |
270 } | 297 } |
298 return; | |
271 } | 299 } |
272 return; | 300 |
301 UpdateSyncNodeProperties(node, model, &sync_node); | |
302 | |
303 DCHECK_EQ(sync_node.GetIsFolder(), node->is_folder()); | |
304 DCHECK_EQ(model_associator_->GetChromeNodeFromSyncId( | |
305 sync_node.GetParentId()), | |
306 node->parent()); | |
307 // This node's index should be one more than the predecessor's index. | |
308 DCHECK_EQ(node->parent()->GetIndexOf(node), | |
309 CalculateBookmarkModelInsertionIndex(node->parent(), | |
310 &sync_node)); | |
273 } | 311 } |
274 | 312 |
275 UpdateSyncNodeProperties(node, model, &sync_node); | 313 UpdateVersion(old_version, model, std::vector<const BookmarkNode*>(1, node)); |
276 | |
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 } | 314 } |
286 | 315 |
287 | |
288 void BookmarkChangeProcessor::BookmarkNodeMoved(BookmarkModel* model, | 316 void BookmarkChangeProcessor::BookmarkNodeMoved(BookmarkModel* model, |
289 const BookmarkNode* old_parent, int old_index, | 317 const BookmarkNode* old_parent, int old_index, |
290 const BookmarkNode* new_parent, int new_index) { | 318 const BookmarkNode* new_parent, int new_index) { |
291 const BookmarkNode* child = new_parent->GetChild(new_index); | 319 const BookmarkNode* child = new_parent->GetChild(new_index); |
292 // We shouldn't see changes to the top-level nodes. | 320 // We shouldn't see changes to the top-level nodes. |
293 if (model->is_permanent_node(child)) { | 321 if (model->is_permanent_node(child)) { |
294 NOTREACHED() << "Saw update to permanent node!"; | 322 NOTREACHED() << "Saw update to permanent node!"; |
295 return; | 323 return; |
296 } | 324 } |
297 | 325 |
298 // Acquire a scoped write lock via a transaction. | 326 int64 old_version; |
299 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()); | |
330 old_version = trans.GetModelVersion(syncer::BOOKMARKS); | |
300 | 331 |
301 // Lookup the sync node that's associated with |child|. | 332 // Lookup the sync node that's associated with |child|. |
302 syncer::WriteNode sync_node(&trans); | 333 syncer::WriteNode sync_node(&trans); |
303 if (!model_associator_->InitSyncNodeFromChromeId(child->id(), &sync_node)) { | 334 if (!model_associator_->InitSyncNodeFromChromeId(child->id(), &sync_node)) { |
304 error_handler()->OnSingleDatatypeUnrecoverableError(FROM_HERE, | 335 error_handler()->OnSingleDatatypeUnrecoverableError(FROM_HERE, |
305 std::string()); | 336 std::string()); |
306 return; | 337 return; |
338 } | |
339 | |
340 if (!PlaceSyncNode(MOVE, new_parent, new_index, &trans, &sync_node, | |
341 model_associator_)) { | |
342 error_handler()->OnSingleDatatypeUnrecoverableError(FROM_HERE, | |
343 std::string()); | |
344 return; | |
345 } | |
307 } | 346 } |
308 | 347 |
309 if (!PlaceSyncNode(MOVE, new_parent, new_index, &trans, &sync_node, | 348 UpdateVersion(old_version, model, std::vector<const BookmarkNode*>(1, child)); |
310 model_associator_)) { | |
311 error_handler()->OnSingleDatatypeUnrecoverableError(FROM_HERE, | |
312 std::string()); | |
313 return; | |
314 } | |
315 } | 349 } |
316 | 350 |
317 void BookmarkChangeProcessor::BookmarkNodeFaviconChanged( | 351 void BookmarkChangeProcessor::BookmarkNodeFaviconChanged( |
318 BookmarkModel* model, | 352 BookmarkModel* model, |
319 const BookmarkNode* node) { | 353 const BookmarkNode* node) { |
320 BookmarkNodeChanged(model, node); | 354 BookmarkNodeChanged(model, node); |
321 } | 355 } |
322 | 356 |
323 void BookmarkChangeProcessor::BookmarkNodeChildrenReordered( | 357 void BookmarkChangeProcessor::BookmarkNodeChildrenReordered( |
324 BookmarkModel* model, const BookmarkNode* node) { | 358 BookmarkModel* model, const BookmarkNode* node) { |
359 int64 old_version; | |
360 std::vector<const BookmarkNode*> children; | |
361 { | |
362 // Acquire a scoped write lock via a transaction. | |
363 syncer::WriteTransaction trans(FROM_HERE, share_handle()); | |
364 old_version = trans.GetModelVersion(syncer::BOOKMARKS); | |
325 | 365 |
326 // Acquire a scoped write lock via a transaction. | 366 // The given node's children got reordered. We need to reorder all the |
327 syncer::WriteTransaction trans(FROM_HERE, share_handle()); | 367 // children of the corresponding sync node. |
368 for (int i = 0; i < node->child_count(); ++i) { | |
369 const BookmarkNode* child = node->GetChild(i); | |
370 children.push_back(child); | |
328 | 371 |
329 // The given node's children got reordered. We need to reorder all the | 372 syncer::WriteNode sync_child(&trans); |
330 // children of the corresponding sync node. | 373 if (!model_associator_->InitSyncNodeFromChromeId(child->id(), |
331 for (int i = 0; i < node->child_count(); ++i) { | 374 &sync_child)) { |
332 syncer::WriteNode sync_child(&trans); | 375 error_handler()->OnSingleDatatypeUnrecoverableError(FROM_HERE, |
333 if (!model_associator_->InitSyncNodeFromChromeId(node->GetChild(i)->id(), | 376 std::string()); |
334 &sync_child)) { | 377 return; |
335 error_handler()->OnSingleDatatypeUnrecoverableError(FROM_HERE, | 378 } |
336 std::string()); | 379 DCHECK_EQ(sync_child.GetParentId(), |
337 return; | 380 model_associator_->GetSyncIdFromChromeId(node->id())); |
338 } | |
339 DCHECK_EQ(sync_child.GetParentId(), | |
340 model_associator_->GetSyncIdFromChromeId(node->id())); | |
341 | 381 |
342 if (!PlaceSyncNode(MOVE, node, i, &trans, &sync_child, | 382 if (!PlaceSyncNode(MOVE, node, i, &trans, &sync_child, |
343 model_associator_)) { | 383 model_associator_)) { |
344 error_handler()->OnSingleDatatypeUnrecoverableError(FROM_HERE, | 384 error_handler()->OnSingleDatatypeUnrecoverableError(FROM_HERE, |
345 std::string()); | 385 std::string()); |
346 return; | 386 return; |
387 } | |
347 } | 388 } |
348 } | 389 } |
390 | |
391 // TODO(haitaol): Filter out children that didn't actually change. | |
392 UpdateVersion(old_version, model, children); | |
349 } | 393 } |
350 | 394 |
351 // static | 395 // static |
352 bool BookmarkChangeProcessor::PlaceSyncNode(MoveOrCreate operation, | 396 bool BookmarkChangeProcessor::PlaceSyncNode(MoveOrCreate operation, |
353 const BookmarkNode* parent, int index, syncer::WriteTransaction* trans, | 397 const BookmarkNode* parent, int index, syncer::WriteTransaction* trans, |
354 syncer::WriteNode* dst, BookmarkModelAssociator* associator) { | 398 syncer::WriteNode* dst, BookmarkModelAssociator* associator) { |
355 syncer::ReadNode sync_parent(trans); | 399 syncer::ReadNode sync_parent(trans); |
356 if (!associator->InitSyncNodeFromChromeId(parent->id(), &sync_parent)) { | 400 if (!associator->InitSyncNodeFromChromeId(parent->id(), &sync_parent)) { |
357 LOG(WARNING) << "Parent lookup failed"; | 401 LOG(WARNING) << "Parent lookup failed"; |
358 return false; | 402 return false; |
(...skipping 136 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
495 << "ACTION_ADD should be seen if and only if the node is unknown."; | 539 << "ACTION_ADD should be seen if and only if the node is unknown."; |
496 passed_deletes = true; | 540 passed_deletes = true; |
497 | 541 |
498 syncer::ReadNode src(trans); | 542 syncer::ReadNode src(trans); |
499 if (src.InitByIdLookup(it->id) != syncer::BaseNode::INIT_OK) { | 543 if (src.InitByIdLookup(it->id) != syncer::BaseNode::INIT_OK) { |
500 error_handler()->OnSingleDatatypeUnrecoverableError(FROM_HERE, | 544 error_handler()->OnSingleDatatypeUnrecoverableError(FROM_HERE, |
501 "ApplyModelChanges was passed a bad ID"); | 545 "ApplyModelChanges was passed a bad ID"); |
502 return; | 546 return; |
503 } | 547 } |
504 | 548 |
505 if (!CreateOrUpdateBookmarkNode(&src, model)) { | 549 const BookmarkNode* node = CreateOrUpdateBookmarkNode(&src, model); |
550 if (node) { | |
551 bookmark_model_->SetNodeMetaInfo(node, kBookmarkTransactionVersionKey, | |
552 base::Int64ToString(model_version)); | |
553 } else { | |
506 // Because the Synced Bookmarks node can be created server side, it's | 554 // Because the Synced Bookmarks node can be created server side, it's |
507 // possible it'll arrive at the client as an update. In that case it | 555 // possible it'll arrive at the client as an update. In that case it |
508 // won't have been associated at startup, the GetChromeNodeFromSyncId | 556 // won't have been associated at startup, the GetChromeNodeFromSyncId |
509 // call above will return NULL, and we won't detect it as a permanent | 557 // call above will return NULL, and we won't detect it as a permanent |
510 // node, resulting in us trying to create it here (which will | 558 // node, resulting in us trying to create it here (which will |
511 // fail). Therefore, we add special logic here just to detect the | 559 // fail). Therefore, we add special logic here just to detect the |
512 // Synced Bookmarks folder. | 560 // Synced Bookmarks folder. |
513 syncer::ReadNode synced_bookmarks(trans); | 561 syncer::ReadNode synced_bookmarks(trans); |
514 if (synced_bookmarks.InitByTagLookup(kMobileBookmarksTag) == | 562 if (synced_bookmarks.InitByTagLookup(kMobileBookmarksTag) == |
515 syncer::BaseNode::INIT_OK && | 563 syncer::BaseNode::INIT_OK && |
(...skipping 63 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
579 if (!src->GetIsFolder()) | 627 if (!src->GetIsFolder()) |
580 model->SetURL(dst, src->GetURL()); | 628 model->SetURL(dst, src->GetURL()); |
581 model->SetTitle(dst, UTF8ToUTF16(src->GetTitle())); | 629 model->SetTitle(dst, UTF8ToUTF16(src->GetTitle())); |
582 | 630 |
583 SetBookmarkFavicon(src, dst, model); | 631 SetBookmarkFavicon(src, dst, model); |
584 } | 632 } |
585 | 633 |
586 return dst; | 634 return dst; |
587 } | 635 } |
588 | 636 |
637 void BookmarkChangeProcessor::UpdateVersion( | |
638 int64 old_version, | |
639 BookmarkModel* model, | |
640 const std::vector<const BookmarkNode*>& nodes) { | |
641 // Open a ReadTransaction to read updated version. | |
642 syncer::ReadTransaction read_trans(FROM_HERE, share_handle()); | |
643 int64 new_version = read_trans.GetModelVersion(syncer::BOOKMARKS); | |
644 DCHECK_GE(new_version, old_version); | |
645 if (new_version > old_version) { | |
646 model->SetNodeMetaInfo(model->root_node(), kBookmarkTransactionVersionKey, | |
647 base::Int64ToString(new_version)); | |
648 for (uint32 i = 0; i < nodes.size(); ++i) { | |
649 model->SetNodeMetaInfo(nodes[i], kBookmarkTransactionVersionKey, | |
650 base::Int64ToString(new_version)); | |
651 } | |
652 } | |
653 } | |
654 | |
589 // static | 655 // static |
590 // Creates a bookmark node under the given parent node from the given sync | 656 // Creates a bookmark node under the given parent node from the given sync |
591 // node. Returns the newly created node. | 657 // node. Returns the newly created node. |
592 const BookmarkNode* BookmarkChangeProcessor::CreateBookmarkNode( | 658 const BookmarkNode* BookmarkChangeProcessor::CreateBookmarkNode( |
593 syncer::BaseNode* sync_node, | 659 syncer::BaseNode* sync_node, |
594 const BookmarkNode* parent, | 660 const BookmarkNode* parent, |
595 BookmarkModel* model, | 661 BookmarkModel* model, |
596 int index) { | 662 int index) { |
597 DCHECK(parent); | 663 DCHECK(parent); |
598 DCHECK(index >= 0 && index <= parent->child_count()); | 664 DCHECK(index >= 0 && index <= parent->child_count()); |
(...skipping 65 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
664 const BookmarkNode* bookmark_node, | 730 const BookmarkNode* bookmark_node, |
665 BookmarkModel* model, | 731 BookmarkModel* model, |
666 syncer::WriteNode* sync_node) { | 732 syncer::WriteNode* sync_node) { |
667 std::vector<unsigned char> favicon_bytes; | 733 std::vector<unsigned char> favicon_bytes; |
668 EncodeFavicon(bookmark_node, model, &favicon_bytes); | 734 EncodeFavicon(bookmark_node, model, &favicon_bytes); |
669 if (!favicon_bytes.empty()) | 735 if (!favicon_bytes.empty()) |
670 sync_node->SetFaviconBytes(favicon_bytes); | 736 sync_node->SetFaviconBytes(favicon_bytes); |
671 } | 737 } |
672 | 738 |
673 } // namespace browser_sync | 739 } // namespace browser_sync |
OLD | NEW |