Update V8 to version 4.5.107.
[chromium-blink-merge.git] / sync / syncable / model_neutral_mutable_entry.cc
blobbdf5299defa60eb025ea066a73d053c0f93d7ef0
1 // Copyright 2013 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
5 #include "sync/syncable/model_neutral_mutable_entry.h"
7 #include <string>
9 #include "sync/internal_api/public/base/unique_position.h"
10 #include "sync/syncable/directory.h"
11 #include "sync/syncable/scoped_kernel_lock.h"
12 #include "sync/syncable/syncable_changes_version.h"
13 #include "sync/syncable/syncable_util.h"
14 #include "sync/syncable/syncable_write_transaction.h"
16 using std::string;
18 namespace syncer {
20 namespace syncable {
22 ModelNeutralMutableEntry::ModelNeutralMutableEntry(BaseWriteTransaction* trans,
23 CreateNewUpdateItem,
24 const Id& id)
25 : Entry(trans), base_write_transaction_(trans) {
26 Entry same_id(trans, GET_BY_ID, id);
27 kernel_ = NULL;
28 if (same_id.good()) {
29 return; // already have an item with this ID.
31 scoped_ptr<EntryKernel> kernel(new EntryKernel());
33 kernel->put(ID, id);
34 kernel->put(META_HANDLE, trans->directory()->NextMetahandle());
35 kernel->mark_dirty(&trans->directory()->kernel()->dirty_metahandles);
36 kernel->put(IS_DEL, true);
37 // We match the database defaults here
38 kernel->put(BASE_VERSION, CHANGES_VERSION);
39 if (!trans->directory()->InsertEntry(trans, kernel.get())) {
40 return; // Failed inserting.
42 trans->TrackChangesTo(kernel.get());
44 kernel_ = kernel.release();
47 ModelNeutralMutableEntry::ModelNeutralMutableEntry(BaseWriteTransaction* trans,
48 CreateNewTypeRoot,
49 ModelType type)
50 : Entry(trans), base_write_transaction_(trans) {
51 // We allow NIGORI because we allow SyncEncryptionHandler to restore a nigori
52 // across Directory instances (see SyncEncryptionHandler::RestoreNigori).
53 if (type != NIGORI)
54 DCHECK(IsTypeWithClientGeneratedRoot(type));
55 Entry same_type_root(trans, GET_TYPE_ROOT, type);
56 kernel_ = NULL;
57 if (same_type_root.good()) {
58 return; // already have a type root for the given type
61 scoped_ptr<EntryKernel> kernel(new EntryKernel());
63 sync_pb::EntitySpecifics specifics;
64 AddDefaultFieldValue(type, &specifics);
65 kernel->put(SPECIFICS, specifics);
67 kernel->put(ID,
68 syncable::Id::CreateFromClientString(ModelTypeToString(type)));
69 kernel->put(META_HANDLE, trans->directory()->NextMetahandle());
70 kernel->put(PARENT_ID, syncable::Id::GetRoot());
71 kernel->put(BASE_VERSION, CHANGES_VERSION);
72 kernel->put(NON_UNIQUE_NAME, ModelTypeToString(type));
73 kernel->put(IS_DIR, true);
75 kernel->mark_dirty(&trans->directory()->kernel()->dirty_metahandles);
77 if (!trans->directory()->InsertEntry(trans, kernel.get())) {
78 return; // Failed inserting.
81 trans->TrackChangesTo(kernel.get());
83 kernel_ = kernel.release();
86 ModelNeutralMutableEntry::ModelNeutralMutableEntry(
87 BaseWriteTransaction* trans, GetById, const Id& id)
88 : Entry(trans, GET_BY_ID, id), base_write_transaction_(trans) {
91 ModelNeutralMutableEntry::ModelNeutralMutableEntry(
92 BaseWriteTransaction* trans, GetByHandle, int64 metahandle)
93 : Entry(trans, GET_BY_HANDLE, metahandle), base_write_transaction_(trans) {
96 ModelNeutralMutableEntry::ModelNeutralMutableEntry(
97 BaseWriteTransaction* trans, GetByClientTag, const std::string& tag)
98 : Entry(trans, GET_BY_CLIENT_TAG, tag), base_write_transaction_(trans) {
101 ModelNeutralMutableEntry::ModelNeutralMutableEntry(
102 BaseWriteTransaction* trans, GetTypeRoot, ModelType type)
103 : Entry(trans, GET_TYPE_ROOT, type), base_write_transaction_(trans) {
106 void ModelNeutralMutableEntry::PutBaseVersion(int64 value) {
107 DCHECK(kernel_);
108 base_write_transaction_->TrackChangesTo(kernel_);
109 if (kernel_->ref(BASE_VERSION) != value) {
110 kernel_->put(BASE_VERSION, value);
111 kernel_->mark_dirty(&dir()->kernel()->dirty_metahandles);
115 void ModelNeutralMutableEntry::PutServerVersion(int64 value) {
116 DCHECK(kernel_);
117 base_write_transaction_->TrackChangesTo(kernel_);
118 if (kernel_->ref(SERVER_VERSION) != value) {
119 ScopedKernelLock lock(dir());
120 kernel_->put(SERVER_VERSION, value);
121 kernel_->mark_dirty(&dir()->kernel()->dirty_metahandles);
125 void ModelNeutralMutableEntry::PutServerMtime(base::Time value) {
126 DCHECK(kernel_);
127 base_write_transaction_->TrackChangesTo(kernel_);
128 if (kernel_->ref(SERVER_MTIME) != value) {
129 kernel_->put(SERVER_MTIME, value);
130 kernel_->mark_dirty(&dir()->kernel()->dirty_metahandles);
134 void ModelNeutralMutableEntry::PutServerCtime(base::Time value) {
135 DCHECK(kernel_);
136 base_write_transaction_->TrackChangesTo(kernel_);
137 if (kernel_->ref(SERVER_CTIME) != value) {
138 kernel_->put(SERVER_CTIME, value);
139 kernel_->mark_dirty(&dir()->kernel()->dirty_metahandles);
143 bool ModelNeutralMutableEntry::PutId(const Id& value) {
144 DCHECK(kernel_);
145 base_write_transaction_->TrackChangesTo(kernel_);
146 if (kernel_->ref(ID) != value) {
147 if (!dir()->ReindexId(base_write_transaction(), kernel_, value))
148 return false;
149 kernel_->mark_dirty(&dir()->kernel()->dirty_metahandles);
151 return true;
154 void ModelNeutralMutableEntry::PutServerParentId(const Id& value) {
155 DCHECK(kernel_);
156 base_write_transaction_->TrackChangesTo(kernel_);
158 if (kernel_->ref(SERVER_PARENT_ID) != value) {
159 kernel_->put(SERVER_PARENT_ID, value);
160 kernel_->mark_dirty(&dir()->kernel()->dirty_metahandles);
164 bool ModelNeutralMutableEntry::PutIsUnsynced(bool value) {
165 DCHECK(kernel_);
166 base_write_transaction_->TrackChangesTo(kernel_);
167 if (kernel_->ref(IS_UNSYNCED) != value) {
168 MetahandleSet* index = &dir()->kernel()->unsynced_metahandles;
170 ScopedKernelLock lock(dir());
171 if (value) {
172 if (!SyncAssert(index->insert(kernel_->ref(META_HANDLE)).second,
173 FROM_HERE,
174 "Could not insert",
175 base_write_transaction())) {
176 return false;
178 } else {
179 if (!SyncAssert(1U == index->erase(kernel_->ref(META_HANDLE)),
180 FROM_HERE,
181 "Entry Not succesfully erased",
182 base_write_transaction())) {
183 return false;
186 kernel_->put(IS_UNSYNCED, value);
187 kernel_->mark_dirty(&dir()->kernel()->dirty_metahandles);
189 return true;
192 bool ModelNeutralMutableEntry::PutIsUnappliedUpdate(bool value) {
193 DCHECK(kernel_);
194 base_write_transaction_->TrackChangesTo(kernel_);
195 if (kernel_->ref(IS_UNAPPLIED_UPDATE) != value) {
196 // Use kernel_->GetServerModelType() instead of
197 // GetServerModelType() as we may trigger some DCHECKs in the
198 // latter.
199 MetahandleSet* index = &dir()->kernel()->unapplied_update_metahandles[
200 kernel_->GetServerModelType()];
202 ScopedKernelLock lock(dir());
203 if (value) {
204 if (!SyncAssert(index->insert(kernel_->ref(META_HANDLE)).second,
205 FROM_HERE,
206 "Could not insert",
207 base_write_transaction())) {
208 return false;
210 } else {
211 if (!SyncAssert(1U == index->erase(kernel_->ref(META_HANDLE)),
212 FROM_HERE,
213 "Entry Not succesfully erased",
214 base_write_transaction())) {
215 return false;
218 kernel_->put(IS_UNAPPLIED_UPDATE, value);
219 kernel_->mark_dirty(&dir()->kernel()->dirty_metahandles);
221 return true;
224 void ModelNeutralMutableEntry::PutServerIsDir(bool value) {
225 DCHECK(kernel_);
226 base_write_transaction_->TrackChangesTo(kernel_);
227 bool old_value = kernel_->ref(SERVER_IS_DIR);
228 if (old_value != value) {
229 kernel_->put(SERVER_IS_DIR, value);
230 kernel_->mark_dirty(GetDirtyIndexHelper());
234 void ModelNeutralMutableEntry::PutServerIsDel(bool value) {
235 DCHECK(kernel_);
236 base_write_transaction_->TrackChangesTo(kernel_);
237 bool old_value = kernel_->ref(SERVER_IS_DEL);
238 if (old_value != value) {
239 kernel_->put(SERVER_IS_DEL, value);
240 kernel_->mark_dirty(GetDirtyIndexHelper());
243 if (!value || kernel_->ref(IS_UNAPPLIED_UPDATE)) {
244 // Update delete journal for existence status change on server side here
245 // instead of in PutIsDel() because IS_DEL may not be updated due to
246 // early returns when processing updates. And because
247 // UpdateDeleteJournalForServerDelete() checks for SERVER_IS_DEL, it has
248 // to be called on sync thread.
250 // Please note that the delete journal applies only to the deletions
251 // originating on the server side (hence the IS_UNAPPLIED_UPDATE check),
252 // but it still makes sense to remove the entry from the delete journal
253 // when it gets undeleted locally.
254 dir()->delete_journal()->UpdateDeleteJournalForServerDelete(
255 base_write_transaction(), old_value, *kernel_);
259 void ModelNeutralMutableEntry::PutServerNonUniqueName(
260 const std::string& value) {
261 DCHECK(kernel_);
262 base_write_transaction_->TrackChangesTo(kernel_);
264 if (kernel_->ref(SERVER_NON_UNIQUE_NAME) != value) {
265 kernel_->put(SERVER_NON_UNIQUE_NAME, value);
266 kernel_->mark_dirty(&dir()->kernel()->dirty_metahandles);
270 bool ModelNeutralMutableEntry::PutUniqueServerTag(const string& new_tag) {
271 if (new_tag == kernel_->ref(UNIQUE_SERVER_TAG)) {
272 return true;
275 base_write_transaction_->TrackChangesTo(kernel_);
276 ScopedKernelLock lock(dir());
277 // Make sure your new value is not in there already.
278 if (dir()->kernel()->server_tags_map.find(new_tag) !=
279 dir()->kernel()->server_tags_map.end()) {
280 DVLOG(1) << "Detected duplicate server tag";
281 return false;
283 dir()->kernel()->server_tags_map.erase(
284 kernel_->ref(UNIQUE_SERVER_TAG));
285 kernel_->put(UNIQUE_SERVER_TAG, new_tag);
286 kernel_->mark_dirty(&dir()->kernel()->dirty_metahandles);
287 if (!new_tag.empty()) {
288 dir()->kernel()->server_tags_map[new_tag] = kernel_;
291 return true;
294 bool ModelNeutralMutableEntry::PutUniqueClientTag(const string& new_tag) {
295 if (new_tag == kernel_->ref(UNIQUE_CLIENT_TAG)) {
296 return true;
299 base_write_transaction_->TrackChangesTo(kernel_);
300 ScopedKernelLock lock(dir());
301 // Make sure your new value is not in there already.
302 if (dir()->kernel()->client_tags_map.find(new_tag) !=
303 dir()->kernel()->client_tags_map.end()) {
304 DVLOG(1) << "Detected duplicate client tag";
305 return false;
307 dir()->kernel()->client_tags_map.erase(
308 kernel_->ref(UNIQUE_CLIENT_TAG));
309 kernel_->put(UNIQUE_CLIENT_TAG, new_tag);
310 kernel_->mark_dirty(&dir()->kernel()->dirty_metahandles);
311 if (!new_tag.empty()) {
312 dir()->kernel()->client_tags_map[new_tag] = kernel_;
315 return true;
318 void ModelNeutralMutableEntry::PutUniqueBookmarkTag(const std::string& tag) {
319 // This unique tag will eventually be used as the unique suffix when adjusting
320 // this bookmark's position. Let's make sure it's a valid suffix.
321 if (!UniquePosition::IsValidSuffix(tag)) {
322 NOTREACHED();
323 return;
326 if (!kernel_->ref(UNIQUE_BOOKMARK_TAG).empty() &&
327 tag != kernel_->ref(UNIQUE_BOOKMARK_TAG)) {
328 // There is only one scenario where our tag is expected to change. That
329 // scenario occurs when our current tag is a non-correct tag assigned during
330 // the UniquePosition migration.
331 std::string migration_generated_tag =
332 GenerateSyncableBookmarkHash(std::string(),
333 kernel_->ref(ID).GetServerId());
334 DCHECK_EQ(migration_generated_tag, kernel_->ref(UNIQUE_BOOKMARK_TAG));
337 kernel_->put(UNIQUE_BOOKMARK_TAG, tag);
338 kernel_->mark_dirty(&dir()->kernel()->dirty_metahandles);
341 void ModelNeutralMutableEntry::PutServerSpecifics(
342 const sync_pb::EntitySpecifics& value) {
343 DCHECK(kernel_);
344 CHECK(!value.password().has_client_only_encrypted_data());
345 base_write_transaction_->TrackChangesTo(kernel_);
346 // TODO(ncarter): This is unfortunately heavyweight. Can we do
347 // better?
348 const std::string& serialized_value = value.SerializeAsString();
349 if (serialized_value != kernel_->ref(SERVER_SPECIFICS).SerializeAsString()) {
350 if (kernel_->ref(IS_UNAPPLIED_UPDATE)) {
351 // Remove ourselves from unapplied_update_metahandles with our
352 // old server type.
353 const ModelType old_server_type = kernel_->GetServerModelType();
354 const int64 metahandle = kernel_->ref(META_HANDLE);
355 size_t erase_count =
356 dir()->kernel()->unapplied_update_metahandles[old_server_type]
357 .erase(metahandle);
358 DCHECK_EQ(erase_count, 1u);
361 // Check for potential sharing - SERVER_SPECIFICS is often
362 // copied from SPECIFICS.
363 if (serialized_value == kernel_->ref(SPECIFICS).SerializeAsString()) {
364 kernel_->copy(SPECIFICS, SERVER_SPECIFICS);
365 } else {
366 kernel_->put(SERVER_SPECIFICS, value);
368 kernel_->mark_dirty(&dir()->kernel()->dirty_metahandles);
370 if (kernel_->ref(IS_UNAPPLIED_UPDATE)) {
371 // Add ourselves back into unapplied_update_metahandles with our
372 // new server type.
373 const ModelType new_server_type = kernel_->GetServerModelType();
374 const int64 metahandle = kernel_->ref(META_HANDLE);
375 dir()->kernel()->unapplied_update_metahandles[new_server_type]
376 .insert(metahandle);
381 void ModelNeutralMutableEntry::PutBaseServerSpecifics(
382 const sync_pb::EntitySpecifics& value) {
383 DCHECK(kernel_);
384 CHECK(!value.password().has_client_only_encrypted_data());
385 base_write_transaction_->TrackChangesTo(kernel_);
386 // TODO(ncarter): This is unfortunately heavyweight. Can we do
387 // better?
388 const std::string& serialized_value = value.SerializeAsString();
389 if (serialized_value !=
390 kernel_->ref(BASE_SERVER_SPECIFICS).SerializeAsString()) {
391 // Check for potential sharing - BASE_SERVER_SPECIFICS is often
392 // copied from SERVER_SPECIFICS.
393 if (serialized_value ==
394 kernel_->ref(SERVER_SPECIFICS).SerializeAsString()) {
395 kernel_->copy(SERVER_SPECIFICS, BASE_SERVER_SPECIFICS);
396 } else {
397 kernel_->put(BASE_SERVER_SPECIFICS, value);
399 kernel_->mark_dirty(&dir()->kernel()->dirty_metahandles);
403 void ModelNeutralMutableEntry::PutServerUniquePosition(
404 const UniquePosition& value) {
405 DCHECK(kernel_);
406 base_write_transaction_->TrackChangesTo(kernel_);
407 if(!kernel_->ref(SERVER_UNIQUE_POSITION).Equals(value)) {
408 // We should never overwrite a valid position with an invalid one.
409 DCHECK(value.IsValid());
410 ScopedKernelLock lock(dir());
411 kernel_->put(SERVER_UNIQUE_POSITION, value);
412 kernel_->mark_dirty(&dir()->kernel()->dirty_metahandles);
416 void ModelNeutralMutableEntry::PutServerAttachmentMetadata(
417 const sync_pb::AttachmentMetadata& value) {
418 DCHECK(kernel_);
419 base_write_transaction_->TrackChangesTo(kernel_);
420 const std::string& serialized_value = value.SerializeAsString();
421 if (serialized_value !=
422 kernel_->ref(SERVER_ATTACHMENT_METADATA).SerializeAsString()) {
423 // Check for potential sharing - SERVER_ATTACHMENT_METADATA is often
424 // copied from ATTACHMENT_METADATA.
425 if (serialized_value ==
426 kernel_->ref(ATTACHMENT_METADATA).SerializeAsString()) {
427 kernel_->copy(ATTACHMENT_METADATA, SERVER_ATTACHMENT_METADATA);
428 } else {
429 kernel_->put(SERVER_ATTACHMENT_METADATA, value);
431 kernel_->mark_dirty(&dir()->kernel()->dirty_metahandles);
435 void ModelNeutralMutableEntry::PutSyncing(bool value) {
436 kernel_->put(SYNCING, value);
439 void ModelNeutralMutableEntry::PutDirtySync(bool value) {
440 DCHECK(!value || GetSyncing());
441 kernel_->put(DIRTY_SYNC, value);
444 void ModelNeutralMutableEntry::PutParentIdPropertyOnly(const Id& parent_id) {
445 base_write_transaction_->TrackChangesTo(kernel_);
446 dir()->ReindexParentId(base_write_transaction(), kernel_, parent_id);
447 kernel_->mark_dirty(&dir()->kernel()->dirty_metahandles);
450 void ModelNeutralMutableEntry::UpdateTransactionVersion(int64 value) {
451 ScopedKernelLock lock(dir());
452 kernel_->put(TRANSACTION_VERSION, value);
453 kernel_->mark_dirty(&(dir()->kernel()->dirty_metahandles));
456 ModelNeutralMutableEntry::ModelNeutralMutableEntry(BaseWriteTransaction* trans)
457 : Entry(trans), base_write_transaction_(trans) {}
459 MetahandleSet* ModelNeutralMutableEntry::GetDirtyIndexHelper() {
460 return &dir()->kernel()->dirty_metahandles;
463 } // namespace syncable
465 } // namespace syncer