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"
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"
22 ModelNeutralMutableEntry::ModelNeutralMutableEntry(BaseWriteTransaction
* trans
,
25 : Entry(trans
), base_write_transaction_(trans
) {
26 Entry
same_id(trans
, GET_BY_ID
, id
);
29 return; // already have an item with this ID.
31 scoped_ptr
<EntryKernel
> kernel(new EntryKernel());
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
,
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).
54 DCHECK(IsTypeWithClientGeneratedRoot(type
));
55 Entry
same_type_root(trans
, GET_TYPE_ROOT
, type
);
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
);
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
) {
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
) {
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
) {
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
) {
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
) {
145 base_write_transaction_
->TrackChangesTo(kernel_
);
146 if (kernel_
->ref(ID
) != value
) {
147 if (!dir()->ReindexId(base_write_transaction(), kernel_
, value
))
149 kernel_
->mark_dirty(&dir()->kernel()->dirty_metahandles
);
154 void ModelNeutralMutableEntry::PutServerParentId(const Id
& value
) {
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
) {
166 base_write_transaction_
->TrackChangesTo(kernel_
);
167 if (kernel_
->ref(IS_UNSYNCED
) != value
) {
168 MetahandleSet
* index
= &dir()->kernel()->unsynced_metahandles
;
170 ScopedKernelLock
lock(dir());
172 if (!SyncAssert(index
->insert(kernel_
->ref(META_HANDLE
)).second
,
175 base_write_transaction())) {
179 if (!SyncAssert(1U == index
->erase(kernel_
->ref(META_HANDLE
)),
181 "Entry Not succesfully erased",
182 base_write_transaction())) {
186 kernel_
->put(IS_UNSYNCED
, value
);
187 kernel_
->mark_dirty(&dir()->kernel()->dirty_metahandles
);
192 bool ModelNeutralMutableEntry::PutIsUnappliedUpdate(bool value
) {
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
199 MetahandleSet
* index
= &dir()->kernel()->unapplied_update_metahandles
[
200 kernel_
->GetServerModelType()];
202 ScopedKernelLock
lock(dir());
204 if (!SyncAssert(index
->insert(kernel_
->ref(META_HANDLE
)).second
,
207 base_write_transaction())) {
211 if (!SyncAssert(1U == index
->erase(kernel_
->ref(META_HANDLE
)),
213 "Entry Not succesfully erased",
214 base_write_transaction())) {
218 kernel_
->put(IS_UNAPPLIED_UPDATE
, value
);
219 kernel_
->mark_dirty(&dir()->kernel()->dirty_metahandles
);
224 void ModelNeutralMutableEntry::PutServerIsDir(bool value
) {
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
) {
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
) {
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
)) {
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";
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_
;
294 bool ModelNeutralMutableEntry::PutUniqueClientTag(const string
& new_tag
) {
295 if (new_tag
== kernel_
->ref(UNIQUE_CLIENT_TAG
)) {
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";
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_
;
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
)) {
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
) {
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
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
353 const ModelType old_server_type
= kernel_
->GetServerModelType();
354 const int64 metahandle
= kernel_
->ref(META_HANDLE
);
356 dir()->kernel()->unapplied_update_metahandles
[old_server_type
]
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
);
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
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
]
381 void ModelNeutralMutableEntry::PutBaseServerSpecifics(
382 const sync_pb::EntitySpecifics
& value
) {
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
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
);
397 kernel_
->put(BASE_SERVER_SPECIFICS
, value
);
399 kernel_
->mark_dirty(&dir()->kernel()->dirty_metahandles
);
403 void ModelNeutralMutableEntry::PutServerUniquePosition(
404 const UniquePosition
& value
) {
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
) {
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
);
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