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

Side by Side Diff: sync/syncable/mutable_entry.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/syncable/mutable_entry.h ('k') | sync/syncable/nigori_util.cc » ('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/syncable/mutable_entry.h" 5 #include "sync/syncable/mutable_entry.h"
6 6
7 #include "base/memory/scoped_ptr.h" 7 #include "base/memory/scoped_ptr.h"
8 #include "sync/internal_api/public/base/node_ordinal.h" 8 #include "sync/internal_api/public/base/unique_position.h"
9 #include "sync/syncable/directory.h" 9 #include "sync/syncable/directory.h"
10 #include "sync/syncable/scoped_index_updater.h" 10 #include "sync/syncable/scoped_index_updater.h"
11 #include "sync/syncable/scoped_kernel_lock.h" 11 #include "sync/syncable/scoped_kernel_lock.h"
12 #include "sync/syncable/scoped_parent_child_index_updater.h"
12 #include "sync/syncable/syncable-inl.h" 13 #include "sync/syncable/syncable-inl.h"
13 #include "sync/syncable/syncable_changes_version.h" 14 #include "sync/syncable/syncable_changes_version.h"
14 #include "sync/syncable/syncable_util.h" 15 #include "sync/syncable/syncable_util.h"
15 #include "sync/syncable/write_transaction.h" 16 #include "sync/syncable/write_transaction.h"
16 17
17 using std::string; 18 using std::string;
18 19
19 namespace syncer { 20 namespace syncer {
20 namespace syncable { 21 namespace syncable {
21 22
22 MutableEntry::MutableEntry(WriteTransaction* trans, Create, 23 void MutableEntry::Init(WriteTransaction* trans,
23 const Id& parent_id, const string& name) 24 ModelType model_type,
24 : Entry(trans), 25 const Id& parent_id,
25 write_transaction_(trans) {
26 Init(trans, parent_id, name);
27 }
28
29
30 void MutableEntry::Init(WriteTransaction* trans, const Id& parent_id,
31 const string& name) { 26 const string& name) {
32 scoped_ptr<EntryKernel> kernel(new EntryKernel); 27 scoped_ptr<EntryKernel> kernel(new EntryKernel);
33 kernel_ = NULL; 28 kernel_ = NULL;
34 29
35 kernel->put(ID, trans->directory_->NextId()); 30 kernel->put(ID, trans->directory_->NextId());
36 kernel->put(META_HANDLE, trans->directory_->NextMetahandle()); 31 kernel->put(META_HANDLE, trans->directory_->NextMetahandle());
37 kernel->mark_dirty(trans->directory_->kernel_->dirty_metahandles); 32 kernel->mark_dirty(trans->directory_->kernel_->dirty_metahandles);
38 kernel->put(PARENT_ID, parent_id); 33 kernel->put(PARENT_ID, parent_id);
39 kernel->put(NON_UNIQUE_NAME, name); 34 kernel->put(NON_UNIQUE_NAME, name);
40 const base::Time& now = base::Time::Now(); 35 const base::Time& now = base::Time::Now();
41 kernel->put(CTIME, now); 36 kernel->put(CTIME, now);
42 kernel->put(MTIME, now); 37 kernel->put(MTIME, now);
43 // We match the database defaults here 38 // We match the database defaults here
44 kernel->put(BASE_VERSION, CHANGES_VERSION); 39 kernel->put(BASE_VERSION, CHANGES_VERSION);
45 kernel->put(SERVER_ORDINAL_IN_PARENT, NodeOrdinal::CreateInitialOrdinal()); 40
46 if (!trans->directory()->InsertEntry(trans, kernel.get())) { 41 // Normally the SPECIFICS setting code is wrapped in logic to deal with
47 return; // We failed inserting, nothing more to do. 42 // unknown fields and encryption. Since all we want to do here is ensure that
48 } 43 // GetModelType() returns a correct value from the very beginning, these
44 // few lines are sufficient.
45 sync_pb::EntitySpecifics specifics;
46 AddDefaultFieldValue(model_type, &specifics);
47 kernel->put(SPECIFICS, specifics);
48
49 // Because this entry is new, it was originally deleted. 49 // Because this entry is new, it was originally deleted.
50 kernel->put(IS_DEL, true); 50 kernel->put(IS_DEL, true);
51 trans->SaveOriginal(kernel.get()); 51 trans->SaveOriginal(kernel.get());
52 kernel->put(IS_DEL, false); 52 kernel->put(IS_DEL, false);
53 53
54 // Now swap the pointers. 54 // Now swap the pointers.
55 kernel_ = kernel.release(); 55 kernel_ = kernel.release();
56 } 56 }
57 57
58 MutableEntry::MutableEntry(WriteTransaction* trans, CreateBookmark,
59 const Id& parent_id, const string& name)
60 : Entry(trans),
61 write_transaction_(trans) {
62 Init(trans, BOOKMARKS, parent_id, name);
63
64 std::string unique_tag = syncable::GenerateSyncableBookmarkHash(
65 trans->directory()->cache_guid(), Get(ID).value());
66
67 kernel_->put(UNIQUE_BOOKMARK_TAG, unique_tag);
68 kernel_->put(UNIQUE_POSITION,
69 UniquePosition::InitialPosition(unique_tag));
70 trans->directory()->InsertEntry(trans, kernel_);
71 }
72
73 MutableEntry::MutableEntry(WriteTransaction* trans,
74 CreateUnique,
75 ModelType model_type,
76 const Id& parent_id,
77 const string& name)
78 : Entry(trans),
79 write_transaction_(trans) {
80 DCHECK_NE(model_type, BOOKMARKS);
81 Init(trans, model_type, parent_id, name);
82 trans->directory()->InsertEntry(trans, kernel_);
83 }
84
58 MutableEntry::MutableEntry(WriteTransaction* trans, CreateNewUpdateItem, 85 MutableEntry::MutableEntry(WriteTransaction* trans, CreateNewUpdateItem,
59 const Id& id) 86 const Id& id)
60 : Entry(trans), write_transaction_(trans) { 87 : Entry(trans), write_transaction_(trans) {
61 Entry same_id(trans, GET_BY_ID, id); 88 Entry same_id(trans, GET_BY_ID, id);
62 kernel_ = NULL; 89 kernel_ = NULL;
63 if (same_id.good()) { 90 if (same_id.good()) {
64 return; // already have an item with this ID. 91 return; // already have an item with this ID.
65 } 92 }
66 scoped_ptr<EntryKernel> kernel(new EntryKernel()); 93 scoped_ptr<EntryKernel> kernel(new EntryKernel());
67 94
68 kernel->put(ID, id); 95 kernel->put(ID, id);
69 kernel->put(META_HANDLE, trans->directory_->NextMetahandle()); 96 kernel->put(META_HANDLE, trans->directory_->NextMetahandle());
70 kernel->mark_dirty(trans->directory_->kernel_->dirty_metahandles); 97 kernel->mark_dirty(trans->directory_->kernel_->dirty_metahandles);
71 kernel->put(SERVER_ORDINAL_IN_PARENT, NodeOrdinal::CreateInitialOrdinal());
72 kernel->put(IS_DEL, true); 98 kernel->put(IS_DEL, true);
73 // We match the database defaults here 99 // We match the database defaults here
74 kernel->put(BASE_VERSION, CHANGES_VERSION); 100 kernel->put(BASE_VERSION, CHANGES_VERSION);
75 if (!trans->directory()->InsertEntry(trans, kernel.get())) { 101 if (!trans->directory()->InsertEntry(trans, kernel.get())) {
76 return; // Failed inserting. 102 return; // Failed inserting.
77 } 103 }
78 trans->SaveOriginal(kernel.get()); 104 trans->SaveOriginal(kernel.get());
79 105
80 kernel_ = kernel.release(); 106 kernel_ = kernel.release();
81 } 107 }
(...skipping 17 matching lines...) Expand all
99 : Entry(trans, GET_BY_SERVER_TAG, tag), write_transaction_(trans) { 125 : Entry(trans, GET_BY_SERVER_TAG, tag), write_transaction_(trans) {
100 } 126 }
101 127
102 bool MutableEntry::PutIsDel(bool is_del) { 128 bool MutableEntry::PutIsDel(bool is_del) {
103 DCHECK(kernel_); 129 DCHECK(kernel_);
104 write_transaction_->SaveOriginal(kernel_); 130 write_transaction_->SaveOriginal(kernel_);
105 if (is_del == kernel_->ref(IS_DEL)) { 131 if (is_del == kernel_->ref(IS_DEL)) {
106 return true; 132 return true;
107 } 133 }
108 if (is_del) { 134 if (is_del) {
109 if (!UnlinkFromOrder()) {
110 return false;
111 }
112
113 // If the server never knew about this item and it's deleted then we don't 135 // If the server never knew about this item and it's deleted then we don't
114 // need to keep it around. Unsetting IS_UNSYNCED will: 136 // need to keep it around. Unsetting IS_UNSYNCED will:
115 // - Ensure that the item is never committed to the server. 137 // - Ensure that the item is never committed to the server.
116 // - Allow any items with the same UNIQUE_CLIENT_TAG created on other 138 // - Allow any items with the same UNIQUE_CLIENT_TAG created on other
117 // clients to override this entry. 139 // clients to override this entry.
118 // - Let us delete this entry permanently through 140 // - Let us delete this entry permanently through
119 // DirectoryBackingStore::DropDeletedEntries() when we next restart sync. 141 // DirectoryBackingStore::DropDeletedEntries() when we next restart sync.
120 // This will save memory and avoid crbug.com/125381. 142 // This will save memory and avoid crbug.com/125381.
121 if (!Get(ID).ServerKnows()) { 143 if (!Get(ID).ServerKnows()) {
122 Put(IS_UNSYNCED, false); 144 Put(IS_UNSYNCED, false);
123 } 145 }
124 } 146 }
125 147
126 { 148 {
127 ScopedKernelLock lock(dir()); 149 ScopedKernelLock lock(dir());
128 // Some indices don't include deleted items and must be updated 150 // Some indices don't include deleted items and must be updated
129 // upon a value change. 151 // upon a value change.
130 ScopedIndexUpdater<ParentIdAndHandleIndexer> updater(lock, kernel_, 152 ScopedParentChildIndexUpdater updater(lock, kernel_,
131 dir()->kernel_->parent_id_child_index); 153 dir()->kernel_->parent_child_index);
132 154
133 kernel_->put(IS_DEL, is_del); 155 kernel_->put(IS_DEL, is_del);
134 kernel_->mark_dirty(dir()->kernel_->dirty_metahandles); 156 kernel_->mark_dirty(dir()->kernel_->dirty_metahandles);
135 } 157 }
136 158
137 if (!is_del)
138 // Restores position to the 0th index.
139 if (!PutPredecessor(Id())) {
140 // TODO(lipalani) : Propagate the error to caller. crbug.com/100444.
141 NOTREACHED();
142 }
143
144 return true; 159 return true;
145 } 160 }
146 161
147 bool MutableEntry::Put(Int64Field field, const int64& value) { 162 bool MutableEntry::Put(Int64Field field, const int64& value) {
148 DCHECK(kernel_); 163 DCHECK(kernel_);
149 write_transaction_->SaveOriginal(kernel_); 164 write_transaction_->SaveOriginal(kernel_);
150 if (kernel_->ref(field) != value) { 165 if (kernel_->ref(field) != value) {
151 ScopedKernelLock lock(dir()); 166 ScopedKernelLock lock(dir());
152 kernel_->put(field, value); 167 kernel_->put(field, value);
153 kernel_->mark_dirty(dir()->kernel_->dirty_metahandles); 168 kernel_->mark_dirty(dir()->kernel_->dirty_metahandles);
(...skipping 12 matching lines...) Expand all
166 } 181 }
167 182
168 bool MutableEntry::Put(IdField field, const Id& value) { 183 bool MutableEntry::Put(IdField field, const Id& value) {
169 DCHECK(kernel_); 184 DCHECK(kernel_);
170 write_transaction_->SaveOriginal(kernel_); 185 write_transaction_->SaveOriginal(kernel_);
171 if (kernel_->ref(field) != value) { 186 if (kernel_->ref(field) != value) {
172 if (ID == field) { 187 if (ID == field) {
173 if (!dir()->ReindexId(write_transaction(), kernel_, value)) 188 if (!dir()->ReindexId(write_transaction(), kernel_, value))
174 return false; 189 return false;
175 } else if (PARENT_ID == field) { 190 } else if (PARENT_ID == field) {
176 PutParentIdPropertyOnly(value); // Makes sibling order inconsistent. 191 PutParentIdPropertyOnly(value);
177 // Fixes up the sibling order inconsistency. 192 if (!Get(IS_DEL)) {
178 if (!PutPredecessor(Id())) { 193 if (!PutPredecessor(Id())) {
179 // TODO(lipalani) : Propagate the error to caller. crbug.com/100444. 194 // TODO(lipalani) : Propagate the error to caller. crbug.com/100444.
180 NOTREACHED(); 195 NOTREACHED();
196 }
181 } 197 }
182 } else { 198 } else {
183 kernel_->put(field, value); 199 kernel_->put(field, value);
184 } 200 }
185 kernel_->mark_dirty(dir()->kernel_->dirty_metahandles); 201 kernel_->mark_dirty(dir()->kernel_->dirty_metahandles);
186 } 202 }
187 return true; 203 return true;
188 } 204 }
189 205
190 bool MutableEntry::Put(OrdinalField field, const NodeOrdinal& value) { 206 bool MutableEntry::Put(UniquePositionField field, const UniquePosition& value) {
191 DCHECK(kernel_); 207 DCHECK(kernel_);
192 DCHECK(value.IsValid());
193 write_transaction_->SaveOriginal(kernel_); 208 write_transaction_->SaveOriginal(kernel_);
194 if(!kernel_->ref(field).Equals(value)) { 209 if(!kernel_->ref(field).Equals(value)) {
210 // We should never overwrite a valid position with an invalid one.
211 DCHECK(value.IsValid());
195 ScopedKernelLock lock(dir()); 212 ScopedKernelLock lock(dir());
196 if (SERVER_ORDINAL_IN_PARENT == field) { 213 if (UNIQUE_POSITION == field) {
197 ScopedIndexUpdater<ParentIdAndHandleIndexer> updater( 214 ScopedParentChildIndexUpdater updater(
198 lock, kernel_, dir()->kernel_->parent_id_child_index); 215 lock, kernel_, dir()->kernel_->parent_child_index);
199 kernel_->put(field, value); 216 kernel_->put(field, value);
200 } else { 217 } else {
201 kernel_->put(field, value); 218 kernel_->put(field, value);
202 } 219 }
203 kernel_->mark_dirty(dir()->kernel_->dirty_metahandles); 220 kernel_->mark_dirty(dir()->kernel_->dirty_metahandles);
204 } 221 }
205 return true; 222 return true;
206 } 223 }
207 224
208 void MutableEntry::PutParentIdPropertyOnly(const Id& parent_id) { 225 void MutableEntry::PutParentIdPropertyOnly(const Id& parent_id) {
(...skipping 135 matching lines...) Expand 10 before | Expand all | Expand 10 after
344 write_transaction())) { 361 write_transaction())) {
345 return false; 362 return false;
346 } 363 }
347 } 364 }
348 kernel_->put(field, value); 365 kernel_->put(field, value);
349 kernel_->mark_dirty(dir()->kernel_->dirty_metahandles); 366 kernel_->mark_dirty(dir()->kernel_->dirty_metahandles);
350 } 367 }
351 return true; 368 return true;
352 } 369 }
353 370
354 bool MutableEntry::UnlinkFromOrder() { 371 void MutableEntry::PutUniqueBookmarkTag(const std::string& tag) {
355 ScopedKernelLock lock(dir()); 372 // This unique tag will eventually be used as the unique suffix when adjusting
356 return dir()->UnlinkEntryFromOrder(kernel_, 373 // this bookmark's position. Let's make sure it's a valid suffix.
357 write_transaction(), 374 if (!UniquePosition::IsValidSuffix(tag)) {
358 &lock, 375 NOTREACHED();
359 NODE_MANIPULATION); 376 return;
377 }
378 kernel_->put(UNIQUE_BOOKMARK_TAG, tag);
379 kernel_->mark_dirty(dir()->kernel_->dirty_metahandles);
360 } 380 }
361 381
362 bool MutableEntry::PutPredecessor(const Id& predecessor_id) { 382 bool MutableEntry::PutPredecessor(const Id& predecessor_id) {
363 if (!UnlinkFromOrder()) 383 MutableEntry predecessor(write_transaction_, GET_BY_ID, predecessor_id);
384 if (!predecessor.good())
364 return false; 385 return false;
365 386 dir()->PutPredecessor(kernel_, predecessor.kernel_);
366 if (Get(IS_DEL)) {
367 DCHECK(predecessor_id.IsNull());
368 return true;
369 }
370
371 // TODO(ncarter): It should be possible to not maintain position for
372 // non-bookmark items. However, we'd need to robustly handle all possible
373 // permutations of setting IS_DEL and the SPECIFICS to identify the
374 // object type; or else, we'd need to add a ModelType to the
375 // MutableEntry's Create ctor.
376 // if (!ShouldMaintainPosition()) {
377 // return false;
378 // }
379
380 // This is classic insert-into-doubly-linked-list from CS 101 and your last
381 // job interview. An "IsRoot" Id signifies the head or tail.
382 Id successor_id;
383 if (!predecessor_id.IsRoot()) {
384 MutableEntry predecessor(write_transaction(), GET_BY_ID, predecessor_id);
385 if (!predecessor.good()) {
386 LOG(ERROR) << "Predecessor is not good : "
387 << predecessor_id.GetServerId();
388 return false;
389 }
390 if (predecessor.Get(PARENT_ID) != Get(PARENT_ID))
391 return false;
392 successor_id = predecessor.Get(NEXT_ID);
393 predecessor.Put(NEXT_ID, Get(ID));
394 } else {
395 syncable::Directory* dir = trans()->directory();
396 if (!dir->GetFirstChildId(trans(), Get(PARENT_ID), &successor_id)) {
397 return false;
398 }
399 }
400 if (!successor_id.IsRoot()) {
401 MutableEntry successor(write_transaction(), GET_BY_ID, successor_id);
402 if (!successor.good()) {
403 LOG(ERROR) << "Successor is not good: "
404 << successor_id.GetServerId();
405 return false;
406 }
407 if (successor.Get(PARENT_ID) != Get(PARENT_ID))
408 return false;
409 successor.Put(PREV_ID, Get(ID));
410 }
411 DCHECK(predecessor_id != Get(ID));
412 DCHECK(successor_id != Get(ID));
413 Put(PREV_ID, predecessor_id);
414 Put(NEXT_ID, successor_id);
415 return true; 387 return true;
416 } 388 }
417 389
418 bool MutableEntry::Put(BitTemp field, bool value) { 390 bool MutableEntry::Put(BitTemp field, bool value) {
419 DCHECK(kernel_); 391 DCHECK(kernel_);
420 kernel_->put(field, value); 392 kernel_->put(field, value);
421 return true; 393 return true;
422 } 394 }
423 395
424 // This function sets only the flags needed to get this entry to sync. 396 // This function sets only the flags needed to get this entry to sync.
425 bool MarkForSyncing(MutableEntry* e) { 397 bool MarkForSyncing(MutableEntry* e) {
426 DCHECK_NE(static_cast<MutableEntry*>(NULL), e); 398 DCHECK_NE(static_cast<MutableEntry*>(NULL), e);
427 DCHECK(!e->IsRoot()) << "We shouldn't mark a permanent object for syncing."; 399 DCHECK(!e->IsRoot()) << "We shouldn't mark a permanent object for syncing.";
428 if (!(e->Put(IS_UNSYNCED, true))) 400 if (!(e->Put(IS_UNSYNCED, true)))
429 return false; 401 return false;
430 e->Put(SYNCING, false); 402 e->Put(SYNCING, false);
431 return true; 403 return true;
432 } 404 }
433 405
434 } // namespace syncable 406 } // namespace syncable
435 } // namespace syncer 407 } // namespace syncer
OLDNEW
« no previous file with comments | « sync/syncable/mutable_entry.h ('k') | sync/syncable/nigori_util.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698