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

Side by Side Diff: sync/internal_api/write_node.cc

Issue 11636006: WIP: The Bookmark Position Megapatch (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Various updates, including switch suffix to unique_client_tag style Created 8 years 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
« no previous file with comments | « sync/internal_api/test/test_entry_factory.cc ('k') | sync/protocol/bookmark_specifics.proto » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
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 "sync/internal_api/public/write_node.h" 5 #include "sync/internal_api/public/write_node.h"
6 6
7 #include "base/utf_string_conversions.h" 7 #include "base/utf_string_conversions.h"
8 #include "base/values.h" 8 #include "base/values.h"
9 #include "sync/internal_api/public/base_transaction.h" 9 #include "sync/internal_api/public/base_transaction.h"
10 #include "sync/internal_api/public/write_transaction.h" 10 #include "sync/internal_api/public/write_transaction.h"
11 #include "sync/internal_api/syncapi_internal.h" 11 #include "sync/internal_api/syncapi_internal.h"
12 #include "sync/protocol/app_specifics.pb.h" 12 #include "sync/protocol/app_specifics.pb.h"
13 #include "sync/protocol/autofill_specifics.pb.h" 13 #include "sync/protocol/autofill_specifics.pb.h"
14 #include "sync/protocol/bookmark_specifics.pb.h" 14 #include "sync/protocol/bookmark_specifics.pb.h"
15 #include "sync/protocol/extension_specifics.pb.h" 15 #include "sync/protocol/extension_specifics.pb.h"
16 #include "sync/protocol/password_specifics.pb.h" 16 #include "sync/protocol/password_specifics.pb.h"
17 #include "sync/protocol/session_specifics.pb.h" 17 #include "sync/protocol/session_specifics.pb.h"
18 #include "sync/protocol/theme_specifics.pb.h" 18 #include "sync/protocol/theme_specifics.pb.h"
19 #include "sync/protocol/typed_url_specifics.pb.h" 19 #include "sync/protocol/typed_url_specifics.pb.h"
20 #include "sync/syncable/mutable_entry.h" 20 #include "sync/syncable/mutable_entry.h"
21 #include "sync/syncable/nigori_util.h" 21 #include "sync/syncable/nigori_util.h"
22 #include "sync/syncable/syncable_util.h"
22 #include "sync/util/cryptographer.h" 23 #include "sync/util/cryptographer.h"
23 24
24 using std::string; 25 using std::string;
25 using std::vector; 26 using std::vector;
26 27
27 namespace syncer { 28 namespace syncer {
28 29
29 using syncable::kEncryptedString; 30 using syncable::kEncryptedString;
30 using syncable::SPECIFICS; 31 using syncable::SPECIFICS;
31 32
(...skipping 165 matching lines...) Expand 10 before | Expand all | Expand 10 after
197 SetEntitySpecifics(entity_specifics); 198 SetEntitySpecifics(entity_specifics);
198 } 199 }
199 200
200 void WriteNode::SetEntitySpecifics( 201 void WriteNode::SetEntitySpecifics(
201 const sync_pb::EntitySpecifics& new_value) { 202 const sync_pb::EntitySpecifics& new_value) {
202 ModelType new_specifics_type = 203 ModelType new_specifics_type =
203 GetModelTypeFromSpecifics(new_value); 204 GetModelTypeFromSpecifics(new_value);
204 DCHECK_NE(new_specifics_type, UNSPECIFIED); 205 DCHECK_NE(new_specifics_type, UNSPECIFIED);
205 DVLOG(1) << "Writing entity specifics of type " 206 DVLOG(1) << "Writing entity specifics of type "
206 << ModelTypeToString(new_specifics_type); 207 << ModelTypeToString(new_specifics_type);
207 // GetModelType() can be unspecified if this is the first time this 208 DCHECK_EQ(new_specifics_type, GetModelType());
208 // node is being initialized (see PutModelType()). Otherwise, it
209 // should match |new_specifics_type|.
210 if (GetModelType() != UNSPECIFIED) {
211 DCHECK_EQ(new_specifics_type, GetModelType());
212 }
213 209
214 // Preserve unknown fields. 210 // Preserve unknown fields.
215 const sync_pb::EntitySpecifics& old_specifics = entry_->Get(SPECIFICS); 211 const sync_pb::EntitySpecifics& old_specifics = entry_->Get(SPECIFICS);
216 sync_pb::EntitySpecifics new_specifics; 212 sync_pb::EntitySpecifics new_specifics;
217 new_specifics.CopyFrom(new_value); 213 new_specifics.CopyFrom(new_value);
218 new_specifics.mutable_unknown_fields()->MergeFrom( 214 new_specifics.mutable_unknown_fields()->MergeFrom(
219 old_specifics.unknown_fields()); 215 old_specifics.unknown_fields());
220 216
221 // Will update the entry if encryption was necessary. 217 // Will update the entry if encryption was necessary.
222 if (!UpdateEntryWithEncryption(GetTransaction()->GetWrappedTrans(), 218 if (!UpdateEntryWithEncryption(GetTransaction()->GetWrappedTrans(),
(...skipping 62 matching lines...) Expand 10 before | Expand all | Expand 10 after
285 // Find a node by client tag, and bind this WriteNode to it. 281 // Find a node by client tag, and bind this WriteNode to it.
286 // Return true if the write node was found, and was not deleted. 282 // Return true if the write node was found, and was not deleted.
287 // Undeleting a deleted node is possible by ClientTag. 283 // Undeleting a deleted node is possible by ClientTag.
288 BaseNode::InitByLookupResult WriteNode::InitByClientTagLookup( 284 BaseNode::InitByLookupResult WriteNode::InitByClientTagLookup(
289 ModelType model_type, 285 ModelType model_type,
290 const std::string& tag) { 286 const std::string& tag) {
291 DCHECK(!entry_) << "Init called twice"; 287 DCHECK(!entry_) << "Init called twice";
292 if (tag.empty()) 288 if (tag.empty())
293 return INIT_FAILED_PRECONDITION; 289 return INIT_FAILED_PRECONDITION;
294 290
295 const std::string hash = GenerateSyncableHash(model_type, tag); 291 const std::string hash = syncable::GenerateSyncableHash(model_type, tag);
296 292
297 entry_ = new syncable::MutableEntry(transaction_->GetWrappedWriteTrans(), 293 entry_ = new syncable::MutableEntry(transaction_->GetWrappedWriteTrans(),
298 syncable::GET_BY_CLIENT_TAG, hash); 294 syncable::GET_BY_CLIENT_TAG, hash);
299 if (!entry_->good()) 295 if (!entry_->good())
300 return INIT_FAILED_ENTRY_NOT_GOOD; 296 return INIT_FAILED_ENTRY_NOT_GOOD;
301 if (entry_->Get(syncable::IS_DEL)) 297 if (entry_->Get(syncable::IS_DEL))
302 return INIT_FAILED_ENTRY_IS_DEL; 298 return INIT_FAILED_ENTRY_IS_DEL;
303 return DecryptIfNecessary() ? INIT_OK : INIT_FAILED_DECRYPT_IF_NECESSARY; 299 return DecryptIfNecessary() ? INIT_OK : INIT_FAILED_DECRYPT_IF_NECESSARY;
304 } 300 }
305 301
306 BaseNode::InitByLookupResult WriteNode::InitByTagLookup( 302 BaseNode::InitByLookupResult WriteNode::InitByTagLookup(
307 const std::string& tag) { 303 const std::string& tag) {
308 DCHECK(!entry_) << "Init called twice"; 304 DCHECK(!entry_) << "Init called twice";
309 if (tag.empty()) 305 if (tag.empty())
310 return INIT_FAILED_PRECONDITION; 306 return INIT_FAILED_PRECONDITION;
311 entry_ = new syncable::MutableEntry(transaction_->GetWrappedWriteTrans(), 307 entry_ = new syncable::MutableEntry(transaction_->GetWrappedWriteTrans(),
312 syncable::GET_BY_SERVER_TAG, tag); 308 syncable::GET_BY_SERVER_TAG, tag);
313 if (!entry_->good()) 309 if (!entry_->good())
314 return INIT_FAILED_ENTRY_NOT_GOOD; 310 return INIT_FAILED_ENTRY_NOT_GOOD;
315 if (entry_->Get(syncable::IS_DEL)) 311 if (entry_->Get(syncable::IS_DEL))
316 return INIT_FAILED_ENTRY_IS_DEL; 312 return INIT_FAILED_ENTRY_IS_DEL;
317 ModelType model_type = GetModelType(); 313 ModelType model_type = GetModelType();
318 DCHECK_EQ(model_type, NIGORI); 314 DCHECK_EQ(model_type, NIGORI);
319 return INIT_OK; 315 return INIT_OK;
320 } 316 }
321 317
322 void WriteNode::PutModelType(ModelType model_type) {
323 // Set an empty specifics of the appropriate datatype. The presence
324 // of the specific field will identify the model type.
325 DCHECK(GetModelType() == model_type ||
326 GetModelType() == UNSPECIFIED); // Immutable once set.
327
328 sync_pb::EntitySpecifics specifics;
329 AddDefaultFieldValue(model_type, &specifics);
330 SetEntitySpecifics(specifics);
331 }
332
333 // Create a new node with default properties, and bind this WriteNode to it. 318 // Create a new node with default properties, and bind this WriteNode to it.
334 // Return true on success. 319 // Return true on success.
335 bool WriteNode::InitByCreation(ModelType model_type, 320 bool WriteNode::InitBookmarkByCreation(const BaseNode& parent,
336 const BaseNode& parent, 321 const BaseNode* predecessor) {
337 const BaseNode* predecessor) {
338 DCHECK(!entry_) << "Init called twice"; 322 DCHECK(!entry_) << "Init called twice";
339 // |predecessor| must be a child of |parent| or NULL. 323 // |predecessor| must be a child of |parent| or NULL.
340 if (predecessor && predecessor->GetParentId() != parent.GetId()) { 324 if (predecessor && predecessor->GetParentId() != parent.GetId()) {
341 DCHECK(false); 325 DCHECK(false);
342 return false; 326 return false;
343 } 327 }
344 328
345 syncable::Id parent_id = parent.GetEntry()->Get(syncable::ID); 329 syncable::Id parent_id = parent.GetEntry()->Get(syncable::ID);
346 330
347 // Start out with a dummy name. We expect 331 // Start out with a dummy name. We expect
348 // the caller to set a meaningful name after creation. 332 // the caller to set a meaningful name after creation.
349 string dummy(kDefaultNameForNewNodes); 333 string dummy(kDefaultNameForNewNodes);
350 334
351 entry_ = new syncable::MutableEntry(transaction_->GetWrappedWriteTrans(), 335 entry_ = new syncable::MutableEntry(transaction_->GetWrappedWriteTrans(),
352 syncable::CREATE, parent_id, dummy); 336 syncable::CREATE_BOOKMARK, parent_id,
337 dummy);
353 338
354 if (!entry_->good()) 339 if (!entry_->good())
355 return false; 340 return false;
356 341
357 // Entries are untitled folders by default. 342 // Entries are untitled folders by default.
358 entry_->Put(syncable::IS_DIR, true); 343 entry_->Put(syncable::IS_DIR, true);
359 344
360 PutModelType(model_type);
361
362 // Now set the predecessor, which sets IS_UNSYNCED as necessary. 345 // Now set the predecessor, which sets IS_UNSYNCED as necessary.
363 return PutPredecessor(predecessor); 346 return PutPredecessor(predecessor);
364 } 347 }
365 348
366 // Create a new node with default properties and a client defined unique tag, 349 // Create a new node with default properties and a client defined unique tag,
367 // and bind this WriteNode to it. 350 // and bind this WriteNode to it.
368 // Return true on success. If the tag exists in the database, then 351 // Return true on success. If the tag exists in the database, then
369 // we will attempt to undelete the node. 352 // we will attempt to undelete the node.
370 // TODO(chron): Code datatype into hash tag. 353 // TODO(chron): Code datatype into hash tag.
371 // TODO(chron): Is model type ever lost? 354 // TODO(chron): Is model type ever lost?
372 WriteNode::InitUniqueByCreationResult WriteNode::InitUniqueByCreation( 355 WriteNode::InitUniqueByCreationResult WriteNode::InitUniqueByCreation(
373 ModelType model_type, 356 ModelType model_type,
374 const BaseNode& parent, 357 const BaseNode& parent,
375 const std::string& tag) { 358 const std::string& tag) {
376 // This DCHECK will only fail if init is called twice. 359 // This DCHECK will only fail if init is called twice.
377 DCHECK(!entry_); 360 DCHECK(!entry_);
378 if (tag.empty()) { 361 if (tag.empty()) {
379 LOG(WARNING) << "InitUniqueByCreation failed due to empty tag."; 362 LOG(WARNING) << "InitUniqueByCreation failed due to empty tag.";
380 return INIT_FAILED_EMPTY_TAG; 363 return INIT_FAILED_EMPTY_TAG;
381 } 364 }
382 365
383 const std::string hash = GenerateSyncableHash(model_type, tag); 366 const std::string hash = syncable::GenerateSyncableHash(model_type, tag);
384 367
385 syncable::Id parent_id = parent.GetEntry()->Get(syncable::ID); 368 syncable::Id parent_id = parent.GetEntry()->Get(syncable::ID);
386 369
387 // Start out with a dummy name. We expect 370 // Start out with a dummy name. We expect
388 // the caller to set a meaningful name after creation. 371 // the caller to set a meaningful name after creation.
389 string dummy(kDefaultNameForNewNodes); 372 string dummy(kDefaultNameForNewNodes);
390 373
391 // Check if we have this locally and need to undelete it. 374 // Check if we have this locally and need to undelete it.
392 scoped_ptr<syncable::MutableEntry> existing_entry( 375 scoped_ptr<syncable::MutableEntry> existing_entry(
393 new syncable::MutableEntry(transaction_->GetWrappedWriteTrans(), 376 new syncable::MutableEntry(transaction_->GetWrappedWriteTrans(),
(...skipping 25 matching lines...) Expand all
419 // tags and updates. 402 // tags and updates.
420 403
421 existing_entry->Put(syncable::NON_UNIQUE_NAME, dummy); 404 existing_entry->Put(syncable::NON_UNIQUE_NAME, dummy);
422 existing_entry->Put(syncable::PARENT_ID, parent_id); 405 existing_entry->Put(syncable::PARENT_ID, parent_id);
423 entry_ = existing_entry.release(); 406 entry_ = existing_entry.release();
424 } else { 407 } else {
425 return INIT_FAILED_ENTRY_ALREADY_EXISTS; 408 return INIT_FAILED_ENTRY_ALREADY_EXISTS;
426 } 409 }
427 } else { 410 } else {
428 entry_ = new syncable::MutableEntry(transaction_->GetWrappedWriteTrans(), 411 entry_ = new syncable::MutableEntry(transaction_->GetWrappedWriteTrans(),
429 syncable::CREATE, parent_id, dummy); 412 syncable::CREATE_UNIQUE,
413 model_type, parent_id, dummy);
430 if (!entry_->good()) 414 if (!entry_->good())
431 return INIT_FAILED_COULD_NOT_CREATE_ENTRY; 415 return INIT_FAILED_COULD_NOT_CREATE_ENTRY;
432 416
433 // Only set IS_DIR for new entries. Don't bitflip undeleted ones. 417 // Only set IS_DIR for new entries. Don't bitflip undeleted ones.
434 entry_->Put(syncable::UNIQUE_CLIENT_TAG, hash); 418 entry_->Put(syncable::UNIQUE_CLIENT_TAG, hash);
435 } 419 }
436 420
437 // We don't support directory and tag combinations. 421 // We don't support directory and tag combinations.
438 entry_->Put(syncable::IS_DIR, false); 422 entry_->Put(syncable::IS_DIR, false);
439 423
440 // Will clear specifics data.
441 PutModelType(model_type);
442
443 // Now set the predecessor, which sets IS_UNSYNCED as necessary. 424 // Now set the predecessor, which sets IS_UNSYNCED as necessary.
444 bool success = PutPredecessor(NULL); 425 bool success = PutPredecessor(NULL);
445 if (!success) 426 if (!success)
446 return INIT_FAILED_SET_PREDECESSOR; 427 return INIT_FAILED_SET_PREDECESSOR;
447 428
448 return INIT_SUCCESS; 429 return INIT_SUCCESS;
449 } 430 }
450 431
451 bool WriteNode::SetPosition(const BaseNode& new_parent, 432 bool WriteNode::SetPosition(const BaseNode& new_parent,
452 const BaseNode* predecessor) { 433 const BaseNode* predecessor) {
453 // |predecessor| must be a child of |new_parent| or NULL. 434 // |predecessor| must be a child of |new_parent| or NULL.
454 if (predecessor && predecessor->GetParentId() != new_parent.GetId()) { 435 if (predecessor && predecessor->GetParentId() != new_parent.GetId()) {
455 DCHECK(false); 436 DCHECK(false);
456 return false; 437 return false;
457 } 438 }
458 439
459 syncable::Id new_parent_id = new_parent.GetEntry()->Get(syncable::ID); 440 syncable::Id new_parent_id = new_parent.GetEntry()->Get(syncable::ID);
460 441
461 // Filter out redundant changes if both the parent and the predecessor match. 442 // Filter out redundant changes if both the parent and the predecessor match.
462 if (new_parent_id == entry_->Get(syncable::PARENT_ID)) { 443 if (new_parent_id == entry_->Get(syncable::PARENT_ID)) {
463 const syncable::Id& old = entry_->Get(syncable::PREV_ID); 444 const syncable::Id& old = entry_->GetPredecessorId();
464 if ((!predecessor && old.IsRoot()) || 445 if ((!predecessor && old.IsRoot()) ||
465 (predecessor && (old == predecessor->GetEntry()->Get(syncable::ID)))) { 446 (predecessor && (old == predecessor->GetEntry()->Get(syncable::ID)))) {
466 return true; 447 return true;
467 } 448 }
468 } 449 }
469 450
470 // Atomically change the parent. This will fail if it would 451 // Atomically change the parent. This will fail if it would
471 // introduce a cycle in the hierarchy. 452 // introduce a cycle in the hierarchy.
472 if (!entry_->Put(syncable::PARENT_ID, new_parent_id)) 453 if (!entry_->Put(syncable::PARENT_ID, new_parent_id))
473 return false; 454 return false;
474 455
475 // Now set the predecessor, which sets IS_UNSYNCED as necessary. 456 // Now set the predecessor, which sets IS_UNSYNCED as necessary.
476 return PutPredecessor(predecessor); 457 return PutPredecessor(predecessor);
458 return true;
477 } 459 }
478 460
479 const syncable::Entry* WriteNode::GetEntry() const { 461 const syncable::Entry* WriteNode::GetEntry() const {
480 return entry_; 462 return entry_;
481 } 463 }
482 464
483 const BaseTransaction* WriteNode::GetTransaction() const { 465 const BaseTransaction* WriteNode::GetTransaction() const {
484 return transaction_; 466 return transaction_;
485 } 467 }
486 468
(...skipping 18 matching lines...) Expand all
505 MarkForSyncing(); 487 MarkForSyncing();
506 488
507 return true; 489 return true;
508 } 490 }
509 491
510 void WriteNode::MarkForSyncing() { 492 void WriteNode::MarkForSyncing() {
511 syncable::MarkForSyncing(entry_); 493 syncable::MarkForSyncing(entry_);
512 } 494 }
513 495
514 } // namespace syncer 496 } // namespace syncer
OLDNEW
« no previous file with comments | « sync/internal_api/test/test_entry_factory.cc ('k') | sync/protocol/bookmark_specifics.proto » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698