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 DCHECK(IsTypeWithClientGeneratedRoot(type
));
52 Entry
same_type_root(trans
, GET_TYPE_ROOT
, type
);
54 if (same_type_root
.good()) {
55 return; // already have a type root for the given type
58 scoped_ptr
<EntryKernel
> kernel(new EntryKernel());
60 sync_pb::EntitySpecifics specifics
;
61 AddDefaultFieldValue(type
, &specifics
);
62 kernel
->put(SPECIFICS
, specifics
);
65 syncable::Id::CreateFromClientString(ModelTypeToString(type
)));
66 kernel
->put(META_HANDLE
, trans
->directory()->NextMetahandle());
67 kernel
->put(PARENT_ID
, syncable::Id::GetRoot());
68 kernel
->put(BASE_VERSION
, CHANGES_VERSION
);
69 kernel
->put(NON_UNIQUE_NAME
, ModelTypeToString(type
));
70 kernel
->put(IS_DIR
, true);
72 kernel
->mark_dirty(&trans
->directory()->kernel()->dirty_metahandles
);
74 if (!trans
->directory()->InsertEntry(trans
, kernel
.get())) {
75 return; // Failed inserting.
78 trans
->TrackChangesTo(kernel
.get());
80 kernel_
= kernel
.release();
83 ModelNeutralMutableEntry::ModelNeutralMutableEntry(
84 BaseWriteTransaction
* trans
, GetById
, const Id
& id
)
85 : Entry(trans
, GET_BY_ID
, id
), base_write_transaction_(trans
) {
88 ModelNeutralMutableEntry::ModelNeutralMutableEntry(
89 BaseWriteTransaction
* trans
, GetByHandle
, int64 metahandle
)
90 : Entry(trans
, GET_BY_HANDLE
, metahandle
), base_write_transaction_(trans
) {
93 ModelNeutralMutableEntry::ModelNeutralMutableEntry(
94 BaseWriteTransaction
* trans
, GetByClientTag
, const std::string
& tag
)
95 : Entry(trans
, GET_BY_CLIENT_TAG
, tag
), base_write_transaction_(trans
) {
98 ModelNeutralMutableEntry::ModelNeutralMutableEntry(
99 BaseWriteTransaction
* trans
, GetTypeRoot
, ModelType type
)
100 : Entry(trans
, GET_TYPE_ROOT
, type
), base_write_transaction_(trans
) {
103 void ModelNeutralMutableEntry::PutBaseVersion(int64 value
) {
105 base_write_transaction_
->TrackChangesTo(kernel_
);
106 if (kernel_
->ref(BASE_VERSION
) != value
) {
107 kernel_
->put(BASE_VERSION
, value
);
108 kernel_
->mark_dirty(&dir()->kernel()->dirty_metahandles
);
112 void ModelNeutralMutableEntry::PutServerVersion(int64 value
) {
114 base_write_transaction_
->TrackChangesTo(kernel_
);
115 if (kernel_
->ref(SERVER_VERSION
) != value
) {
116 ScopedKernelLock
lock(dir());
117 kernel_
->put(SERVER_VERSION
, value
);
118 kernel_
->mark_dirty(&dir()->kernel()->dirty_metahandles
);
122 void ModelNeutralMutableEntry::PutServerMtime(base::Time value
) {
124 base_write_transaction_
->TrackChangesTo(kernel_
);
125 if (kernel_
->ref(SERVER_MTIME
) != value
) {
126 kernel_
->put(SERVER_MTIME
, value
);
127 kernel_
->mark_dirty(&dir()->kernel()->dirty_metahandles
);
131 void ModelNeutralMutableEntry::PutServerCtime(base::Time value
) {
133 base_write_transaction_
->TrackChangesTo(kernel_
);
134 if (kernel_
->ref(SERVER_CTIME
) != value
) {
135 kernel_
->put(SERVER_CTIME
, value
);
136 kernel_
->mark_dirty(&dir()->kernel()->dirty_metahandles
);
140 bool ModelNeutralMutableEntry::PutId(const Id
& value
) {
142 base_write_transaction_
->TrackChangesTo(kernel_
);
143 if (kernel_
->ref(ID
) != value
) {
144 if (!dir()->ReindexId(base_write_transaction(), kernel_
, value
))
146 kernel_
->mark_dirty(&dir()->kernel()->dirty_metahandles
);
151 void ModelNeutralMutableEntry::PutServerParentId(const Id
& value
) {
153 base_write_transaction_
->TrackChangesTo(kernel_
);
155 if (kernel_
->ref(SERVER_PARENT_ID
) != value
) {
156 kernel_
->put(SERVER_PARENT_ID
, value
);
157 kernel_
->mark_dirty(&dir()->kernel()->dirty_metahandles
);
161 bool ModelNeutralMutableEntry::PutIsUnsynced(bool value
) {
163 base_write_transaction_
->TrackChangesTo(kernel_
);
164 if (kernel_
->ref(IS_UNSYNCED
) != value
) {
165 MetahandleSet
* index
= &dir()->kernel()->unsynced_metahandles
;
167 ScopedKernelLock
lock(dir());
169 if (!SyncAssert(index
->insert(kernel_
->ref(META_HANDLE
)).second
,
172 base_write_transaction())) {
176 if (!SyncAssert(1U == index
->erase(kernel_
->ref(META_HANDLE
)),
178 "Entry Not succesfully erased",
179 base_write_transaction())) {
183 kernel_
->put(IS_UNSYNCED
, value
);
184 kernel_
->mark_dirty(&dir()->kernel()->dirty_metahandles
);
189 bool ModelNeutralMutableEntry::PutIsUnappliedUpdate(bool value
) {
191 base_write_transaction_
->TrackChangesTo(kernel_
);
192 if (kernel_
->ref(IS_UNAPPLIED_UPDATE
) != value
) {
193 // Use kernel_->GetServerModelType() instead of
194 // GetServerModelType() as we may trigger some DCHECKs in the
196 MetahandleSet
* index
= &dir()->kernel()->unapplied_update_metahandles
[
197 kernel_
->GetServerModelType()];
199 ScopedKernelLock
lock(dir());
201 if (!SyncAssert(index
->insert(kernel_
->ref(META_HANDLE
)).second
,
204 base_write_transaction())) {
208 if (!SyncAssert(1U == index
->erase(kernel_
->ref(META_HANDLE
)),
210 "Entry Not succesfully erased",
211 base_write_transaction())) {
215 kernel_
->put(IS_UNAPPLIED_UPDATE
, value
);
216 kernel_
->mark_dirty(&dir()->kernel()->dirty_metahandles
);
221 void ModelNeutralMutableEntry::PutServerIsDir(bool value
) {
223 base_write_transaction_
->TrackChangesTo(kernel_
);
224 bool old_value
= kernel_
->ref(SERVER_IS_DIR
);
225 if (old_value
!= value
) {
226 kernel_
->put(SERVER_IS_DIR
, value
);
227 kernel_
->mark_dirty(GetDirtyIndexHelper());
231 void ModelNeutralMutableEntry::PutServerIsDel(bool value
) {
233 base_write_transaction_
->TrackChangesTo(kernel_
);
234 bool old_value
= kernel_
->ref(SERVER_IS_DEL
);
235 if (old_value
!= value
) {
236 kernel_
->put(SERVER_IS_DEL
, value
);
237 kernel_
->mark_dirty(GetDirtyIndexHelper());
240 // Update delete journal for existence status change on server side here
241 // instead of in PutIsDel() because IS_DEL may not be updated due to
242 // early returns when processing updates. And because
243 // UpdateDeleteJournalForServerDelete() checks for SERVER_IS_DEL, it has
244 // to be called on sync thread.
245 dir()->delete_journal()->UpdateDeleteJournalForServerDelete(
246 base_write_transaction(), old_value
, *kernel_
);
249 void ModelNeutralMutableEntry::PutServerNonUniqueName(
250 const std::string
& value
) {
252 base_write_transaction_
->TrackChangesTo(kernel_
);
254 if (kernel_
->ref(SERVER_NON_UNIQUE_NAME
) != value
) {
255 kernel_
->put(SERVER_NON_UNIQUE_NAME
, value
);
256 kernel_
->mark_dirty(&dir()->kernel()->dirty_metahandles
);
260 bool ModelNeutralMutableEntry::PutUniqueServerTag(const string
& new_tag
) {
261 if (new_tag
== kernel_
->ref(UNIQUE_SERVER_TAG
)) {
265 base_write_transaction_
->TrackChangesTo(kernel_
);
266 ScopedKernelLock
lock(dir());
267 // Make sure your new value is not in there already.
268 if (dir()->kernel()->server_tags_map
.find(new_tag
) !=
269 dir()->kernel()->server_tags_map
.end()) {
270 DVLOG(1) << "Detected duplicate server tag";
273 dir()->kernel()->server_tags_map
.erase(
274 kernel_
->ref(UNIQUE_SERVER_TAG
));
275 kernel_
->put(UNIQUE_SERVER_TAG
, new_tag
);
276 kernel_
->mark_dirty(&dir()->kernel()->dirty_metahandles
);
277 if (!new_tag
.empty()) {
278 dir()->kernel()->server_tags_map
[new_tag
] = kernel_
;
284 bool ModelNeutralMutableEntry::PutUniqueClientTag(const string
& new_tag
) {
285 if (new_tag
== kernel_
->ref(UNIQUE_CLIENT_TAG
)) {
289 base_write_transaction_
->TrackChangesTo(kernel_
);
290 ScopedKernelLock
lock(dir());
291 // Make sure your new value is not in there already.
292 if (dir()->kernel()->client_tags_map
.find(new_tag
) !=
293 dir()->kernel()->client_tags_map
.end()) {
294 DVLOG(1) << "Detected duplicate client tag";
297 dir()->kernel()->client_tags_map
.erase(
298 kernel_
->ref(UNIQUE_CLIENT_TAG
));
299 kernel_
->put(UNIQUE_CLIENT_TAG
, new_tag
);
300 kernel_
->mark_dirty(&dir()->kernel()->dirty_metahandles
);
301 if (!new_tag
.empty()) {
302 dir()->kernel()->client_tags_map
[new_tag
] = kernel_
;
308 void ModelNeutralMutableEntry::PutUniqueBookmarkTag(const std::string
& tag
) {
309 // This unique tag will eventually be used as the unique suffix when adjusting
310 // this bookmark's position. Let's make sure it's a valid suffix.
311 if (!UniquePosition::IsValidSuffix(tag
)) {
316 if (!kernel_
->ref(UNIQUE_BOOKMARK_TAG
).empty() &&
317 tag
!= kernel_
->ref(UNIQUE_BOOKMARK_TAG
)) {
318 // There is only one scenario where our tag is expected to change. That
319 // scenario occurs when our current tag is a non-correct tag assigned during
320 // the UniquePosition migration.
321 std::string migration_generated_tag
=
322 GenerateSyncableBookmarkHash(std::string(),
323 kernel_
->ref(ID
).GetServerId());
324 DCHECK_EQ(migration_generated_tag
, kernel_
->ref(UNIQUE_BOOKMARK_TAG
));
327 kernel_
->put(UNIQUE_BOOKMARK_TAG
, tag
);
328 kernel_
->mark_dirty(&dir()->kernel()->dirty_metahandles
);
331 void ModelNeutralMutableEntry::PutServerSpecifics(
332 const sync_pb::EntitySpecifics
& value
) {
334 CHECK(!value
.password().has_client_only_encrypted_data());
335 base_write_transaction_
->TrackChangesTo(kernel_
);
336 // TODO(ncarter): This is unfortunately heavyweight. Can we do
338 if (kernel_
->ref(SERVER_SPECIFICS
).SerializeAsString() !=
339 value
.SerializeAsString()) {
340 if (kernel_
->ref(IS_UNAPPLIED_UPDATE
)) {
341 // Remove ourselves from unapplied_update_metahandles with our
343 const ModelType old_server_type
= kernel_
->GetServerModelType();
344 const int64 metahandle
= kernel_
->ref(META_HANDLE
);
346 dir()->kernel()->unapplied_update_metahandles
[old_server_type
]
348 DCHECK_EQ(erase_count
, 1u);
351 kernel_
->put(SERVER_SPECIFICS
, value
);
352 kernel_
->mark_dirty(&dir()->kernel()->dirty_metahandles
);
354 if (kernel_
->ref(IS_UNAPPLIED_UPDATE
)) {
355 // Add ourselves back into unapplied_update_metahandles with our
357 const ModelType new_server_type
= kernel_
->GetServerModelType();
358 const int64 metahandle
= kernel_
->ref(META_HANDLE
);
359 dir()->kernel()->unapplied_update_metahandles
[new_server_type
]
365 void ModelNeutralMutableEntry::PutBaseServerSpecifics(
366 const sync_pb::EntitySpecifics
& value
) {
368 CHECK(!value
.password().has_client_only_encrypted_data());
369 base_write_transaction_
->TrackChangesTo(kernel_
);
370 // TODO(ncarter): This is unfortunately heavyweight. Can we do
372 if (kernel_
->ref(BASE_SERVER_SPECIFICS
).SerializeAsString()
373 != value
.SerializeAsString()) {
374 kernel_
->put(BASE_SERVER_SPECIFICS
, value
);
375 kernel_
->mark_dirty(&dir()->kernel()->dirty_metahandles
);
379 void ModelNeutralMutableEntry::PutServerUniquePosition(
380 const UniquePosition
& value
) {
382 base_write_transaction_
->TrackChangesTo(kernel_
);
383 if(!kernel_
->ref(SERVER_UNIQUE_POSITION
).Equals(value
)) {
384 // We should never overwrite a valid position with an invalid one.
385 DCHECK(value
.IsValid());
386 ScopedKernelLock
lock(dir());
387 kernel_
->put(SERVER_UNIQUE_POSITION
, value
);
388 kernel_
->mark_dirty(&dir()->kernel()->dirty_metahandles
);
392 void ModelNeutralMutableEntry::PutServerAttachmentMetadata(
393 const sync_pb::AttachmentMetadata
& value
) {
395 base_write_transaction_
->TrackChangesTo(kernel_
);
397 if (kernel_
->ref(SERVER_ATTACHMENT_METADATA
).SerializeAsString() !=
398 value
.SerializeAsString()) {
399 kernel_
->put(SERVER_ATTACHMENT_METADATA
, value
);
400 kernel_
->mark_dirty(&dir()->kernel()->dirty_metahandles
);
404 void ModelNeutralMutableEntry::PutSyncing(bool value
) {
405 kernel_
->put(SYNCING
, value
);
408 void ModelNeutralMutableEntry::PutDirtySync(bool value
) {
409 DCHECK(!value
|| GetSyncing());
410 kernel_
->put(DIRTY_SYNC
, value
);
413 void ModelNeutralMutableEntry::PutParentIdPropertyOnly(const Id
& parent_id
) {
414 base_write_transaction_
->TrackChangesTo(kernel_
);
415 dir()->ReindexParentId(base_write_transaction(), kernel_
, parent_id
);
416 kernel_
->mark_dirty(&dir()->kernel()->dirty_metahandles
);
419 void ModelNeutralMutableEntry::UpdateTransactionVersion(int64 value
) {
420 ScopedKernelLock
lock(dir());
421 kernel_
->put(TRANSACTION_VERSION
, value
);
422 kernel_
->mark_dirty(&(dir()->kernel()->dirty_metahandles
));
425 ModelNeutralMutableEntry::ModelNeutralMutableEntry(BaseWriteTransaction
* trans
)
426 : Entry(trans
), base_write_transaction_(trans
) {}
428 MetahandleSet
* ModelNeutralMutableEntry::GetDirtyIndexHelper() {
429 return &dir()->kernel()->dirty_metahandles
;
432 } // namespace syncable
434 } // namespace syncer