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 if (kernel_
->ref(BASE_VERSION
) != value
) {
109 base_write_transaction_
->TrackChangesTo(kernel_
);
110 kernel_
->put(BASE_VERSION
, value
);
115 void ModelNeutralMutableEntry::PutServerVersion(int64 value
) {
117 if (kernel_
->ref(SERVER_VERSION
) != value
) {
118 base_write_transaction_
->TrackChangesTo(kernel_
);
119 ScopedKernelLock
lock(dir());
120 kernel_
->put(SERVER_VERSION
, value
);
125 void ModelNeutralMutableEntry::PutServerMtime(base::Time value
) {
127 if (kernel_
->ref(SERVER_MTIME
) != value
) {
128 base_write_transaction_
->TrackChangesTo(kernel_
);
129 kernel_
->put(SERVER_MTIME
, value
);
134 void ModelNeutralMutableEntry::PutServerCtime(base::Time value
) {
136 if (kernel_
->ref(SERVER_CTIME
) != value
) {
137 base_write_transaction_
->TrackChangesTo(kernel_
);
138 kernel_
->put(SERVER_CTIME
, value
);
143 bool ModelNeutralMutableEntry::PutId(const Id
& value
) {
145 if (kernel_
->ref(ID
) != value
) {
146 base_write_transaction_
->TrackChangesTo(kernel_
);
147 if (!dir()->ReindexId(base_write_transaction(), kernel_
, value
))
154 void ModelNeutralMutableEntry::PutServerParentId(const Id
& value
) {
156 if (kernel_
->ref(SERVER_PARENT_ID
) != value
) {
157 base_write_transaction_
->TrackChangesTo(kernel_
);
158 kernel_
->put(SERVER_PARENT_ID
, value
);
163 bool ModelNeutralMutableEntry::PutIsUnsynced(bool value
) {
165 if (kernel_
->ref(IS_UNSYNCED
) != value
) {
166 base_write_transaction_
->TrackChangesTo(kernel_
);
167 MetahandleSet
* index
= &dir()->kernel()->unsynced_metahandles
;
169 ScopedKernelLock
lock(dir());
171 if (!SyncAssert(index
->insert(kernel_
->ref(META_HANDLE
)).second
,
174 base_write_transaction())) {
178 if (!SyncAssert(1U == index
->erase(kernel_
->ref(META_HANDLE
)),
180 "Entry Not succesfully erased",
181 base_write_transaction())) {
185 kernel_
->put(IS_UNSYNCED
, value
);
191 bool ModelNeutralMutableEntry::PutIsUnappliedUpdate(bool value
) {
193 if (kernel_
->ref(IS_UNAPPLIED_UPDATE
) != value
) {
194 base_write_transaction_
->TrackChangesTo(kernel_
);
195 // Use kernel_->GetServerModelType() instead of
196 // GetServerModelType() as we may trigger some DCHECKs in the
198 MetahandleSet
* index
= &dir()->kernel()->unapplied_update_metahandles
[
199 kernel_
->GetServerModelType()];
201 ScopedKernelLock
lock(dir());
203 if (!SyncAssert(index
->insert(kernel_
->ref(META_HANDLE
)).second
,
206 base_write_transaction())) {
210 if (!SyncAssert(1U == index
->erase(kernel_
->ref(META_HANDLE
)),
212 "Entry Not succesfully erased",
213 base_write_transaction())) {
217 kernel_
->put(IS_UNAPPLIED_UPDATE
, value
);
223 void ModelNeutralMutableEntry::PutServerIsDir(bool value
) {
225 if (kernel_
->ref(SERVER_IS_DIR
) != value
) {
226 base_write_transaction_
->TrackChangesTo(kernel_
);
227 kernel_
->put(SERVER_IS_DIR
, value
);
232 void ModelNeutralMutableEntry::PutServerIsDel(bool value
) {
234 bool old_value
= kernel_
->ref(SERVER_IS_DEL
);
235 if (old_value
!= value
) {
236 base_write_transaction_
->TrackChangesTo(kernel_
);
237 kernel_
->put(SERVER_IS_DEL
, value
);
241 if (!value
|| kernel_
->ref(IS_UNAPPLIED_UPDATE
)) {
242 // Update delete journal for existence status change on server side here
243 // instead of in PutIsDel() because IS_DEL may not be updated due to
244 // early returns when processing updates. And because
245 // UpdateDeleteJournalForServerDelete() checks for SERVER_IS_DEL, it has
246 // to be called on sync thread.
248 // Please note that the delete journal applies only to the deletions
249 // originating on the server side (hence the IS_UNAPPLIED_UPDATE check),
250 // but it still makes sense to remove the entry from the delete journal
251 // when it gets undeleted locally.
252 dir()->delete_journal()->UpdateDeleteJournalForServerDelete(
253 base_write_transaction(), old_value
, *kernel_
);
257 void ModelNeutralMutableEntry::PutServerNonUniqueName(
258 const std::string
& value
) {
260 if (kernel_
->ref(SERVER_NON_UNIQUE_NAME
) != value
) {
261 base_write_transaction_
->TrackChangesTo(kernel_
);
262 kernel_
->put(SERVER_NON_UNIQUE_NAME
, value
);
267 bool ModelNeutralMutableEntry::PutUniqueServerTag(const string
& new_tag
) {
268 if (new_tag
== kernel_
->ref(UNIQUE_SERVER_TAG
)) {
272 base_write_transaction_
->TrackChangesTo(kernel_
);
273 ScopedKernelLock
lock(dir());
274 // Make sure your new value is not in there already.
275 if (dir()->kernel()->server_tags_map
.find(new_tag
) !=
276 dir()->kernel()->server_tags_map
.end()) {
277 DVLOG(1) << "Detected duplicate server tag";
280 dir()->kernel()->server_tags_map
.erase(
281 kernel_
->ref(UNIQUE_SERVER_TAG
));
282 kernel_
->put(UNIQUE_SERVER_TAG
, new_tag
);
284 if (!new_tag
.empty()) {
285 dir()->kernel()->server_tags_map
[new_tag
] = kernel_
;
291 bool ModelNeutralMutableEntry::PutUniqueClientTag(const string
& new_tag
) {
292 if (new_tag
== kernel_
->ref(UNIQUE_CLIENT_TAG
)) {
296 base_write_transaction_
->TrackChangesTo(kernel_
);
297 ScopedKernelLock
lock(dir());
298 // Make sure your new value is not in there already.
299 if (dir()->kernel()->client_tags_map
.find(new_tag
) !=
300 dir()->kernel()->client_tags_map
.end()) {
301 DVLOG(1) << "Detected duplicate client tag";
304 dir()->kernel()->client_tags_map
.erase(
305 kernel_
->ref(UNIQUE_CLIENT_TAG
));
306 kernel_
->put(UNIQUE_CLIENT_TAG
, new_tag
);
308 if (!new_tag
.empty()) {
309 dir()->kernel()->client_tags_map
[new_tag
] = kernel_
;
315 void ModelNeutralMutableEntry::PutUniqueBookmarkTag(const std::string
& tag
) {
316 // This unique tag will eventually be used as the unique suffix when adjusting
317 // this bookmark's position. Let's make sure it's a valid suffix.
318 if (!UniquePosition::IsValidSuffix(tag
)) {
323 // TODO(stanisc): Does this need a call to TrackChangesTo?
325 if (!kernel_
->ref(UNIQUE_BOOKMARK_TAG
).empty() &&
326 tag
!= kernel_
->ref(UNIQUE_BOOKMARK_TAG
)) {
327 // There is only one scenario where our tag is expected to change. That
328 // scenario occurs when our current tag is a non-correct tag assigned during
329 // the UniquePosition migration.
330 std::string migration_generated_tag
=
331 GenerateSyncableBookmarkHash(std::string(),
332 kernel_
->ref(ID
).GetServerId());
333 DCHECK_EQ(migration_generated_tag
, kernel_
->ref(UNIQUE_BOOKMARK_TAG
));
336 kernel_
->put(UNIQUE_BOOKMARK_TAG
, tag
);
340 void ModelNeutralMutableEntry::PutServerSpecifics(
341 const sync_pb::EntitySpecifics
& value
) {
343 CHECK(!value
.password().has_client_only_encrypted_data());
344 // TODO(ncarter): This is unfortunately heavyweight. Can we do
346 const std::string
& serialized_value
= value
.SerializeAsString();
347 if (serialized_value
!= kernel_
->ref(SERVER_SPECIFICS
).SerializeAsString()) {
348 base_write_transaction_
->TrackChangesTo(kernel_
);
349 if (kernel_
->ref(IS_UNAPPLIED_UPDATE
)) {
350 // Remove ourselves from unapplied_update_metahandles with our
352 const ModelType old_server_type
= kernel_
->GetServerModelType();
353 const int64 metahandle
= kernel_
->ref(META_HANDLE
);
355 dir()->kernel()->unapplied_update_metahandles
[old_server_type
]
357 DCHECK_EQ(erase_count
, 1u);
360 // Check for potential sharing - SERVER_SPECIFICS is often
361 // copied from SPECIFICS.
362 if (serialized_value
== kernel_
->ref(SPECIFICS
).SerializeAsString()) {
363 kernel_
->copy(SPECIFICS
, SERVER_SPECIFICS
);
365 kernel_
->put(SERVER_SPECIFICS
, value
);
369 if (kernel_
->ref(IS_UNAPPLIED_UPDATE
)) {
370 // Add ourselves back into unapplied_update_metahandles with our
372 const ModelType new_server_type
= kernel_
->GetServerModelType();
373 const int64 metahandle
= kernel_
->ref(META_HANDLE
);
374 dir()->kernel()->unapplied_update_metahandles
[new_server_type
]
380 void ModelNeutralMutableEntry::PutBaseServerSpecifics(
381 const sync_pb::EntitySpecifics
& value
) {
383 CHECK(!value
.password().has_client_only_encrypted_data());
384 // TODO(ncarter): This is unfortunately heavyweight. Can we do
386 const std::string
& serialized_value
= value
.SerializeAsString();
387 if (serialized_value
!=
388 kernel_
->ref(BASE_SERVER_SPECIFICS
).SerializeAsString()) {
389 base_write_transaction_
->TrackChangesTo(kernel_
);
390 // Check for potential sharing - BASE_SERVER_SPECIFICS is often
391 // copied from SERVER_SPECIFICS.
392 if (serialized_value
==
393 kernel_
->ref(SERVER_SPECIFICS
).SerializeAsString()) {
394 kernel_
->copy(SERVER_SPECIFICS
, BASE_SERVER_SPECIFICS
);
396 kernel_
->put(BASE_SERVER_SPECIFICS
, value
);
402 void ModelNeutralMutableEntry::PutServerUniquePosition(
403 const UniquePosition
& value
) {
405 if(!kernel_
->ref(SERVER_UNIQUE_POSITION
).Equals(value
)) {
406 base_write_transaction_
->TrackChangesTo(kernel_
);
407 // We should never overwrite a valid position with an invalid one.
408 DCHECK(value
.IsValid());
409 ScopedKernelLock
lock(dir());
410 kernel_
->put(SERVER_UNIQUE_POSITION
, value
);
415 void ModelNeutralMutableEntry::PutServerAttachmentMetadata(
416 const sync_pb::AttachmentMetadata
& value
) {
418 const std::string
& serialized_value
= value
.SerializeAsString();
419 if (serialized_value
!=
420 kernel_
->ref(SERVER_ATTACHMENT_METADATA
).SerializeAsString()) {
421 base_write_transaction_
->TrackChangesTo(kernel_
);
422 // Check for potential sharing - SERVER_ATTACHMENT_METADATA is often
423 // copied from ATTACHMENT_METADATA.
424 if (serialized_value
==
425 kernel_
->ref(ATTACHMENT_METADATA
).SerializeAsString()) {
426 kernel_
->copy(ATTACHMENT_METADATA
, SERVER_ATTACHMENT_METADATA
);
428 kernel_
->put(SERVER_ATTACHMENT_METADATA
, value
);
434 void ModelNeutralMutableEntry::PutSyncing(bool value
) {
435 kernel_
->put(SYNCING
, value
);
438 void ModelNeutralMutableEntry::PutDirtySync(bool value
) {
439 DCHECK(!value
|| GetSyncing());
440 kernel_
->put(DIRTY_SYNC
, value
);
443 void ModelNeutralMutableEntry::PutParentIdPropertyOnly(const Id
& parent_id
) {
444 base_write_transaction_
->TrackChangesTo(kernel_
);
445 dir()->ReindexParentId(base_write_transaction(), kernel_
, parent_id
);
449 void ModelNeutralMutableEntry::UpdateTransactionVersion(int64 value
) {
450 kernel_
->put(TRANSACTION_VERSION
, value
);
454 ModelNeutralMutableEntry::ModelNeutralMutableEntry(BaseWriteTransaction
* trans
)
455 : Entry(trans
), base_write_transaction_(trans
) {}
457 void ModelNeutralMutableEntry::MarkDirty() {
458 kernel_
->mark_dirty(&dir()->kernel()->dirty_metahandles
);
461 } // namespace syncable
463 } // namespace syncer