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(
48 BaseWriteTransaction
* trans
, GetById
, const Id
& id
)
49 : Entry(trans
, GET_BY_ID
, id
), base_write_transaction_(trans
) {
52 ModelNeutralMutableEntry::ModelNeutralMutableEntry(
53 BaseWriteTransaction
* trans
, GetByHandle
, int64 metahandle
)
54 : Entry(trans
, GET_BY_HANDLE
, metahandle
), base_write_transaction_(trans
) {
57 ModelNeutralMutableEntry::ModelNeutralMutableEntry(
58 BaseWriteTransaction
* trans
, GetByClientTag
, const std::string
& tag
)
59 : Entry(trans
, GET_BY_CLIENT_TAG
, tag
), base_write_transaction_(trans
) {
62 ModelNeutralMutableEntry::ModelNeutralMutableEntry(
63 BaseWriteTransaction
* trans
, GetTypeRoot
, ModelType type
)
64 : Entry(trans
, GET_TYPE_ROOT
, type
), base_write_transaction_(trans
) {
67 void ModelNeutralMutableEntry::PutBaseVersion(int64 value
) {
69 base_write_transaction_
->TrackChangesTo(kernel_
);
70 if (kernel_
->ref(BASE_VERSION
) != value
) {
71 kernel_
->put(BASE_VERSION
, value
);
72 kernel_
->mark_dirty(&dir()->kernel_
->dirty_metahandles
);
76 void ModelNeutralMutableEntry::PutServerVersion(int64 value
) {
78 base_write_transaction_
->TrackChangesTo(kernel_
);
79 if (kernel_
->ref(SERVER_VERSION
) != value
) {
80 ScopedKernelLock
lock(dir());
81 kernel_
->put(SERVER_VERSION
, value
);
82 kernel_
->mark_dirty(&dir()->kernel_
->dirty_metahandles
);
86 void ModelNeutralMutableEntry::PutServerMtime(base::Time value
) {
88 base_write_transaction_
->TrackChangesTo(kernel_
);
89 if (kernel_
->ref(SERVER_MTIME
) != value
) {
90 kernel_
->put(SERVER_MTIME
, value
);
91 kernel_
->mark_dirty(&dir()->kernel_
->dirty_metahandles
);
95 void ModelNeutralMutableEntry::PutServerCtime(base::Time value
) {
97 base_write_transaction_
->TrackChangesTo(kernel_
);
98 if (kernel_
->ref(SERVER_CTIME
) != value
) {
99 kernel_
->put(SERVER_CTIME
, value
);
100 kernel_
->mark_dirty(&dir()->kernel_
->dirty_metahandles
);
104 bool ModelNeutralMutableEntry::PutId(const Id
& value
) {
106 base_write_transaction_
->TrackChangesTo(kernel_
);
107 if (kernel_
->ref(ID
) != value
) {
108 if (!dir()->ReindexId(base_write_transaction(), kernel_
, value
))
110 kernel_
->mark_dirty(&dir()->kernel_
->dirty_metahandles
);
115 void ModelNeutralMutableEntry::PutServerParentId(const Id
& value
) {
117 base_write_transaction_
->TrackChangesTo(kernel_
);
119 if (kernel_
->ref(SERVER_PARENT_ID
) != value
) {
120 kernel_
->put(SERVER_PARENT_ID
, value
);
121 kernel_
->mark_dirty(&dir()->kernel_
->dirty_metahandles
);
125 bool ModelNeutralMutableEntry::PutIsUnsynced(bool value
) {
127 base_write_transaction_
->TrackChangesTo(kernel_
);
128 if (kernel_
->ref(IS_UNSYNCED
) != value
) {
129 MetahandleSet
* index
= &dir()->kernel_
->unsynced_metahandles
;
131 ScopedKernelLock
lock(dir());
133 if (!SyncAssert(index
->insert(kernel_
->ref(META_HANDLE
)).second
,
136 base_write_transaction())) {
140 if (!SyncAssert(1U == index
->erase(kernel_
->ref(META_HANDLE
)),
142 "Entry Not succesfully erased",
143 base_write_transaction())) {
147 kernel_
->put(IS_UNSYNCED
, value
);
148 kernel_
->mark_dirty(&dir()->kernel_
->dirty_metahandles
);
153 bool ModelNeutralMutableEntry::PutIsUnappliedUpdate(bool value
) {
155 base_write_transaction_
->TrackChangesTo(kernel_
);
156 if (kernel_
->ref(IS_UNAPPLIED_UPDATE
) != value
) {
157 // Use kernel_->GetServerModelType() instead of
158 // GetServerModelType() as we may trigger some DCHECKs in the
160 MetahandleSet
* index
= &dir()->kernel_
->unapplied_update_metahandles
[
161 kernel_
->GetServerModelType()];
163 ScopedKernelLock
lock(dir());
165 if (!SyncAssert(index
->insert(kernel_
->ref(META_HANDLE
)).second
,
168 base_write_transaction())) {
172 if (!SyncAssert(1U == index
->erase(kernel_
->ref(META_HANDLE
)),
174 "Entry Not succesfully erased",
175 base_write_transaction())) {
179 kernel_
->put(IS_UNAPPLIED_UPDATE
, value
);
180 kernel_
->mark_dirty(&dir()->kernel_
->dirty_metahandles
);
185 void ModelNeutralMutableEntry::PutServerIsDir(bool value
) {
187 base_write_transaction_
->TrackChangesTo(kernel_
);
188 bool old_value
= kernel_
->ref(SERVER_IS_DIR
);
189 if (old_value
!= value
) {
190 kernel_
->put(SERVER_IS_DIR
, value
);
191 kernel_
->mark_dirty(GetDirtyIndexHelper());
195 void ModelNeutralMutableEntry::PutServerIsDel(bool value
) {
197 base_write_transaction_
->TrackChangesTo(kernel_
);
198 bool old_value
= kernel_
->ref(SERVER_IS_DEL
);
199 if (old_value
!= value
) {
200 kernel_
->put(SERVER_IS_DEL
, value
);
201 kernel_
->mark_dirty(GetDirtyIndexHelper());
204 // Update delete journal for existence status change on server side here
205 // instead of in PutIsDel() because IS_DEL may not be updated due to
206 // early returns when processing updates. And because
207 // UpdateDeleteJournalForServerDelete() checks for SERVER_IS_DEL, it has
208 // to be called on sync thread.
209 dir()->delete_journal()->UpdateDeleteJournalForServerDelete(
210 base_write_transaction(), old_value
, *kernel_
);
213 void ModelNeutralMutableEntry::PutServerNonUniqueName(
214 const std::string
& value
) {
216 base_write_transaction_
->TrackChangesTo(kernel_
);
218 if (kernel_
->ref(SERVER_NON_UNIQUE_NAME
) != value
) {
219 kernel_
->put(SERVER_NON_UNIQUE_NAME
, value
);
220 kernel_
->mark_dirty(&dir()->kernel_
->dirty_metahandles
);
224 bool ModelNeutralMutableEntry::PutUniqueServerTag(const string
& new_tag
) {
225 if (new_tag
== kernel_
->ref(UNIQUE_SERVER_TAG
)) {
229 base_write_transaction_
->TrackChangesTo(kernel_
);
230 ScopedKernelLock
lock(dir());
231 // Make sure your new value is not in there already.
232 if (dir()->kernel_
->server_tags_map
.find(new_tag
) !=
233 dir()->kernel_
->server_tags_map
.end()) {
234 DVLOG(1) << "Detected duplicate server tag";
237 dir()->kernel_
->server_tags_map
.erase(
238 kernel_
->ref(UNIQUE_SERVER_TAG
));
239 kernel_
->put(UNIQUE_SERVER_TAG
, new_tag
);
240 kernel_
->mark_dirty(&dir()->kernel_
->dirty_metahandles
);
241 if (!new_tag
.empty()) {
242 dir()->kernel_
->server_tags_map
[new_tag
] = kernel_
;
248 bool ModelNeutralMutableEntry::PutUniqueClientTag(const string
& new_tag
) {
249 if (new_tag
== kernel_
->ref(UNIQUE_CLIENT_TAG
)) {
253 base_write_transaction_
->TrackChangesTo(kernel_
);
254 ScopedKernelLock
lock(dir());
255 // Make sure your new value is not in there already.
256 if (dir()->kernel_
->client_tags_map
.find(new_tag
) !=
257 dir()->kernel_
->client_tags_map
.end()) {
258 DVLOG(1) << "Detected duplicate client tag";
261 dir()->kernel_
->client_tags_map
.erase(
262 kernel_
->ref(UNIQUE_CLIENT_TAG
));
263 kernel_
->put(UNIQUE_CLIENT_TAG
, new_tag
);
264 kernel_
->mark_dirty(&dir()->kernel_
->dirty_metahandles
);
265 if (!new_tag
.empty()) {
266 dir()->kernel_
->client_tags_map
[new_tag
] = kernel_
;
272 void ModelNeutralMutableEntry::PutUniqueBookmarkTag(const std::string
& tag
) {
273 // This unique tag will eventually be used as the unique suffix when adjusting
274 // this bookmark's position. Let's make sure it's a valid suffix.
275 if (!UniquePosition::IsValidSuffix(tag
)) {
280 if (!kernel_
->ref(UNIQUE_BOOKMARK_TAG
).empty() &&
281 tag
!= kernel_
->ref(UNIQUE_BOOKMARK_TAG
)) {
282 // There is only one scenario where our tag is expected to change. That
283 // scenario occurs when our current tag is a non-correct tag assigned during
284 // the UniquePosition migration.
285 std::string migration_generated_tag
=
286 GenerateSyncableBookmarkHash(std::string(),
287 kernel_
->ref(ID
).GetServerId());
288 DCHECK_EQ(migration_generated_tag
, kernel_
->ref(UNIQUE_BOOKMARK_TAG
));
291 kernel_
->put(UNIQUE_BOOKMARK_TAG
, tag
);
292 kernel_
->mark_dirty(&dir()->kernel_
->dirty_metahandles
);
295 void ModelNeutralMutableEntry::PutServerSpecifics(
296 const sync_pb::EntitySpecifics
& value
) {
298 CHECK(!value
.password().has_client_only_encrypted_data());
299 base_write_transaction_
->TrackChangesTo(kernel_
);
300 // TODO(ncarter): This is unfortunately heavyweight. Can we do
302 if (kernel_
->ref(SERVER_SPECIFICS
).SerializeAsString() !=
303 value
.SerializeAsString()) {
304 if (kernel_
->ref(IS_UNAPPLIED_UPDATE
)) {
305 // Remove ourselves from unapplied_update_metahandles with our
307 const ModelType old_server_type
= kernel_
->GetServerModelType();
308 const int64 metahandle
= kernel_
->ref(META_HANDLE
);
310 dir()->kernel_
->unapplied_update_metahandles
[old_server_type
]
312 DCHECK_EQ(erase_count
, 1u);
315 kernel_
->put(SERVER_SPECIFICS
, value
);
316 kernel_
->mark_dirty(&dir()->kernel_
->dirty_metahandles
);
318 if (kernel_
->ref(IS_UNAPPLIED_UPDATE
)) {
319 // Add ourselves back into unapplied_update_metahandles with our
321 const ModelType new_server_type
= kernel_
->GetServerModelType();
322 const int64 metahandle
= kernel_
->ref(META_HANDLE
);
323 dir()->kernel_
->unapplied_update_metahandles
[new_server_type
]
329 void ModelNeutralMutableEntry::PutBaseServerSpecifics(
330 const sync_pb::EntitySpecifics
& value
) {
332 CHECK(!value
.password().has_client_only_encrypted_data());
333 base_write_transaction_
->TrackChangesTo(kernel_
);
334 // TODO(ncarter): This is unfortunately heavyweight. Can we do
336 if (kernel_
->ref(BASE_SERVER_SPECIFICS
).SerializeAsString()
337 != value
.SerializeAsString()) {
338 kernel_
->put(BASE_SERVER_SPECIFICS
, value
);
339 kernel_
->mark_dirty(&dir()->kernel_
->dirty_metahandles
);
343 void ModelNeutralMutableEntry::PutServerUniquePosition(
344 const UniquePosition
& value
) {
346 base_write_transaction_
->TrackChangesTo(kernel_
);
347 if(!kernel_
->ref(SERVER_UNIQUE_POSITION
).Equals(value
)) {
348 // We should never overwrite a valid position with an invalid one.
349 DCHECK(value
.IsValid());
350 ScopedKernelLock
lock(dir());
351 kernel_
->put(SERVER_UNIQUE_POSITION
, value
);
352 kernel_
->mark_dirty(&dir()->kernel_
->dirty_metahandles
);
356 void ModelNeutralMutableEntry::PutSyncing(bool value
) {
357 kernel_
->put(SYNCING
, value
);
360 void ModelNeutralMutableEntry::PutParentIdPropertyOnly(const Id
& parent_id
) {
361 base_write_transaction_
->TrackChangesTo(kernel_
);
362 dir()->ReindexParentId(base_write_transaction(), kernel_
, parent_id
);
363 kernel_
->mark_dirty(&dir()->kernel_
->dirty_metahandles
);
366 void ModelNeutralMutableEntry::UpdateTransactionVersion(int64 value
) {
367 ScopedKernelLock
lock(dir());
368 kernel_
->put(TRANSACTION_VERSION
, value
);
369 kernel_
->mark_dirty(&(dir()->kernel_
->dirty_metahandles
));
372 ModelNeutralMutableEntry::ModelNeutralMutableEntry(BaseWriteTransaction
* trans
)
373 : Entry(trans
), base_write_transaction_(trans
) {}
375 MetahandleSet
* ModelNeutralMutableEntry::GetDirtyIndexHelper() {
376 return &dir()->kernel_
->dirty_metahandles
;
379 } // namespace syncable
381 } // namespace syncer