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

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

Issue 11341048: Populate versions on individual nodes in sync model and native bookmark model. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Restore heap unallocatability of write transaction Created 8 years, 1 month ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
OLDNEW
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 #include "chrome/browser/sync/glue/bookmark_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
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
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
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
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
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698