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 "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 Loading... |
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 Loading... |
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 Loading... |
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 Loading... |
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 |
OLD | NEW |