Index: sync/syncable/mutable_entry.cc |
diff --git a/sync/syncable/mutable_entry.cc b/sync/syncable/mutable_entry.cc |
index 5090ad1a9116739a00d89ae6f6952ec9c765acaa..11fb11af361b9df867bf2959e264251c82b35588 100644 |
--- a/sync/syncable/mutable_entry.cc |
+++ b/sync/syncable/mutable_entry.cc |
@@ -5,10 +5,11 @@ |
#include "sync/syncable/mutable_entry.h" |
#include "base/memory/scoped_ptr.h" |
-#include "sync/internal_api/public/base/node_ordinal.h" |
+#include "sync/internal_api/public/base/unique_position.h" |
#include "sync/syncable/directory.h" |
#include "sync/syncable/scoped_index_updater.h" |
#include "sync/syncable/scoped_kernel_lock.h" |
+#include "sync/syncable/scoped_parent_child_index_updater.h" |
#include "sync/syncable/syncable-inl.h" |
#include "sync/syncable/syncable_changes_version.h" |
#include "sync/syncable/syncable_util.h" |
@@ -19,15 +20,9 @@ using std::string; |
namespace syncer { |
namespace syncable { |
-MutableEntry::MutableEntry(WriteTransaction* trans, Create, |
- const Id& parent_id, const string& name) |
- : Entry(trans), |
- write_transaction_(trans) { |
- Init(trans, parent_id, name); |
-} |
- |
- |
-void MutableEntry::Init(WriteTransaction* trans, const Id& parent_id, |
+void MutableEntry::Init(WriteTransaction* trans, |
+ ModelType model_type, |
+ const Id& parent_id, |
const string& name) { |
scoped_ptr<EntryKernel> kernel(new EntryKernel); |
kernel_ = NULL; |
@@ -42,10 +37,15 @@ void MutableEntry::Init(WriteTransaction* trans, const Id& parent_id, |
kernel->put(MTIME, now); |
// We match the database defaults here |
kernel->put(BASE_VERSION, CHANGES_VERSION); |
- kernel->put(SERVER_ORDINAL_IN_PARENT, NodeOrdinal::CreateInitialOrdinal()); |
- if (!trans->directory()->InsertEntry(trans, kernel.get())) { |
- return; // We failed inserting, nothing more to do. |
- } |
+ |
+ // Normally the SPECIFICS setting code is wrapped in logic to deal with |
+ // unknown fields and encryption. Since all we want to do here is ensure that |
+ // GetModelType() returns a correct value from the very beginning, these |
+ // few lines are sufficient. |
+ sync_pb::EntitySpecifics specifics; |
+ AddDefaultFieldValue(model_type, &specifics); |
+ kernel->put(SPECIFICS, specifics); |
+ |
// Because this entry is new, it was originally deleted. |
kernel->put(IS_DEL, true); |
trans->SaveOriginal(kernel.get()); |
@@ -55,6 +55,33 @@ void MutableEntry::Init(WriteTransaction* trans, const Id& parent_id, |
kernel_ = kernel.release(); |
} |
+MutableEntry::MutableEntry(WriteTransaction* trans, CreateBookmark, |
+ const Id& parent_id, const string& name) |
+ : Entry(trans), |
+ write_transaction_(trans) { |
+ Init(trans, BOOKMARKS, parent_id, name); |
+ |
+ std::string unique_tag = syncable::GenerateSyncableBookmarkHash( |
+ trans->directory()->cache_guid(), Get(ID).value()); |
+ |
+ kernel_->put(UNIQUE_BOOKMARK_TAG, unique_tag); |
+ kernel_->put(UNIQUE_POSITION, |
+ UniquePosition::InitialPosition(unique_tag)); |
+ trans->directory()->InsertEntry(trans, kernel_); |
+} |
+ |
+MutableEntry::MutableEntry(WriteTransaction* trans, |
+ CreateUnique, |
+ ModelType model_type, |
+ const Id& parent_id, |
+ const string& name) |
+ : Entry(trans), |
+ write_transaction_(trans) { |
+ DCHECK_NE(model_type, BOOKMARKS); |
+ Init(trans, model_type, parent_id, name); |
+ trans->directory()->InsertEntry(trans, kernel_); |
+} |
+ |
MutableEntry::MutableEntry(WriteTransaction* trans, CreateNewUpdateItem, |
const Id& id) |
: Entry(trans), write_transaction_(trans) { |
@@ -68,7 +95,6 @@ MutableEntry::MutableEntry(WriteTransaction* trans, CreateNewUpdateItem, |
kernel->put(ID, id); |
kernel->put(META_HANDLE, trans->directory_->NextMetahandle()); |
kernel->mark_dirty(trans->directory_->kernel_->dirty_metahandles); |
- kernel->put(SERVER_ORDINAL_IN_PARENT, NodeOrdinal::CreateInitialOrdinal()); |
kernel->put(IS_DEL, true); |
// We match the database defaults here |
kernel->put(BASE_VERSION, CHANGES_VERSION); |
@@ -106,10 +132,6 @@ bool MutableEntry::PutIsDel(bool is_del) { |
return true; |
} |
if (is_del) { |
- if (!UnlinkFromOrder()) { |
- return false; |
- } |
- |
// If the server never knew about this item and it's deleted then we don't |
// need to keep it around. Unsetting IS_UNSYNCED will: |
// - Ensure that the item is never committed to the server. |
@@ -127,20 +149,13 @@ bool MutableEntry::PutIsDel(bool is_del) { |
ScopedKernelLock lock(dir()); |
// Some indices don't include deleted items and must be updated |
// upon a value change. |
- ScopedIndexUpdater<ParentIdAndHandleIndexer> updater(lock, kernel_, |
- dir()->kernel_->parent_id_child_index); |
+ ScopedParentChildIndexUpdater updater(lock, kernel_, |
+ dir()->kernel_->parent_child_index); |
kernel_->put(IS_DEL, is_del); |
kernel_->mark_dirty(dir()->kernel_->dirty_metahandles); |
} |
- if (!is_del) |
- // Restores position to the 0th index. |
- if (!PutPredecessor(Id())) { |
- // TODO(lipalani) : Propagate the error to caller. crbug.com/100444. |
- NOTREACHED(); |
- } |
- |
return true; |
} |
@@ -173,11 +188,12 @@ bool MutableEntry::Put(IdField field, const Id& value) { |
if (!dir()->ReindexId(write_transaction(), kernel_, value)) |
return false; |
} else if (PARENT_ID == field) { |
- PutParentIdPropertyOnly(value); // Makes sibling order inconsistent. |
- // Fixes up the sibling order inconsistency. |
- if (!PutPredecessor(Id())) { |
- // TODO(lipalani) : Propagate the error to caller. crbug.com/100444. |
- NOTREACHED(); |
+ PutParentIdPropertyOnly(value); |
+ if (!Get(IS_DEL)) { |
+ if (!PutPredecessor(Id())) { |
+ // TODO(lipalani) : Propagate the error to caller. crbug.com/100444. |
+ NOTREACHED(); |
+ } |
} |
} else { |
kernel_->put(field, value); |
@@ -187,15 +203,16 @@ bool MutableEntry::Put(IdField field, const Id& value) { |
return true; |
} |
-bool MutableEntry::Put(OrdinalField field, const NodeOrdinal& value) { |
+bool MutableEntry::Put(UniquePositionField field, const UniquePosition& value) { |
DCHECK(kernel_); |
- DCHECK(value.IsValid()); |
write_transaction_->SaveOriginal(kernel_); |
if(!kernel_->ref(field).Equals(value)) { |
+ // We should never overwrite a valid position with an invalid one. |
+ DCHECK(value.IsValid()); |
ScopedKernelLock lock(dir()); |
- if (SERVER_ORDINAL_IN_PARENT == field) { |
- ScopedIndexUpdater<ParentIdAndHandleIndexer> updater( |
- lock, kernel_, dir()->kernel_->parent_id_child_index); |
+ if (UNIQUE_POSITION == field) { |
+ ScopedParentChildIndexUpdater updater( |
+ lock, kernel_, dir()->kernel_->parent_child_index); |
kernel_->put(field, value); |
} else { |
kernel_->put(field, value); |
@@ -351,67 +368,22 @@ bool MutableEntry::Put(IndexedBitField field, bool value) { |
return true; |
} |
-bool MutableEntry::UnlinkFromOrder() { |
- ScopedKernelLock lock(dir()); |
- return dir()->UnlinkEntryFromOrder(kernel_, |
- write_transaction(), |
- &lock, |
- NODE_MANIPULATION); |
+void MutableEntry::PutUniqueBookmarkTag(const std::string& tag) { |
+ // This unique tag will eventually be used as the unique suffix when adjusting |
+ // this bookmark's position. Let's make sure it's a valid suffix. |
+ if (!UniquePosition::IsValidSuffix(tag)) { |
+ NOTREACHED(); |
+ return; |
+ } |
+ kernel_->put(UNIQUE_BOOKMARK_TAG, tag); |
+ kernel_->mark_dirty(dir()->kernel_->dirty_metahandles); |
} |
bool MutableEntry::PutPredecessor(const Id& predecessor_id) { |
- if (!UnlinkFromOrder()) |
+ MutableEntry predecessor(write_transaction_, GET_BY_ID, predecessor_id); |
+ if (!predecessor.good()) |
return false; |
- |
- if (Get(IS_DEL)) { |
- DCHECK(predecessor_id.IsNull()); |
- return true; |
- } |
- |
- // TODO(ncarter): It should be possible to not maintain position for |
- // non-bookmark items. However, we'd need to robustly handle all possible |
- // permutations of setting IS_DEL and the SPECIFICS to identify the |
- // object type; or else, we'd need to add a ModelType to the |
- // MutableEntry's Create ctor. |
- // if (!ShouldMaintainPosition()) { |
- // return false; |
- // } |
- |
- // This is classic insert-into-doubly-linked-list from CS 101 and your last |
- // job interview. An "IsRoot" Id signifies the head or tail. |
- Id successor_id; |
- if (!predecessor_id.IsRoot()) { |
- MutableEntry predecessor(write_transaction(), GET_BY_ID, predecessor_id); |
- if (!predecessor.good()) { |
- LOG(ERROR) << "Predecessor is not good : " |
- << predecessor_id.GetServerId(); |
- return false; |
- } |
- if (predecessor.Get(PARENT_ID) != Get(PARENT_ID)) |
- return false; |
- successor_id = predecessor.Get(NEXT_ID); |
- predecessor.Put(NEXT_ID, Get(ID)); |
- } else { |
- syncable::Directory* dir = trans()->directory(); |
- if (!dir->GetFirstChildId(trans(), Get(PARENT_ID), &successor_id)) { |
- return false; |
- } |
- } |
- if (!successor_id.IsRoot()) { |
- MutableEntry successor(write_transaction(), GET_BY_ID, successor_id); |
- if (!successor.good()) { |
- LOG(ERROR) << "Successor is not good: " |
- << successor_id.GetServerId(); |
- return false; |
- } |
- if (successor.Get(PARENT_ID) != Get(PARENT_ID)) |
- return false; |
- successor.Put(PREV_ID, Get(ID)); |
- } |
- DCHECK(predecessor_id != Get(ID)); |
- DCHECK(successor_id != Get(ID)); |
- Put(PREV_ID, predecessor_id); |
- Put(NEXT_ID, successor_id); |
+ dir()->PutPredecessor(kernel_, predecessor.kernel_); |
return true; |
} |