[SyncFS] Build indexes from FileTracker entries on disk.
[chromium-blink-merge.git] / sync / syncable / model_neutral_mutable_entry.cc
blob2ae54507fe0a2960056c895314c8d4f4930482d4
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(
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) {
68 DCHECK(kernel_);
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) {
77 DCHECK(kernel_);
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) {
87 DCHECK(kernel_);
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) {
96 DCHECK(kernel_);
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) {
105 DCHECK(kernel_);
106 base_write_transaction_->TrackChangesTo(kernel_);
107 if (kernel_->ref(ID) != value) {
108 if (!dir()->ReindexId(base_write_transaction(), kernel_, value))
109 return false;
110 kernel_->mark_dirty(&dir()->kernel_->dirty_metahandles);
112 return true;
115 void ModelNeutralMutableEntry::PutServerParentId(const Id& value) {
116 DCHECK(kernel_);
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) {
126 DCHECK(kernel_);
127 base_write_transaction_->TrackChangesTo(kernel_);
128 if (kernel_->ref(IS_UNSYNCED) != value) {
129 MetahandleSet* index = &dir()->kernel_->unsynced_metahandles;
131 ScopedKernelLock lock(dir());
132 if (value) {
133 if (!SyncAssert(index->insert(kernel_->ref(META_HANDLE)).second,
134 FROM_HERE,
135 "Could not insert",
136 base_write_transaction())) {
137 return false;
139 } else {
140 if (!SyncAssert(1U == index->erase(kernel_->ref(META_HANDLE)),
141 FROM_HERE,
142 "Entry Not succesfully erased",
143 base_write_transaction())) {
144 return false;
147 kernel_->put(IS_UNSYNCED, value);
148 kernel_->mark_dirty(&dir()->kernel_->dirty_metahandles);
150 return true;
153 bool ModelNeutralMutableEntry::PutIsUnappliedUpdate(bool value) {
154 DCHECK(kernel_);
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
159 // latter.
160 MetahandleSet* index = &dir()->kernel_->unapplied_update_metahandles[
161 kernel_->GetServerModelType()];
163 ScopedKernelLock lock(dir());
164 if (value) {
165 if (!SyncAssert(index->insert(kernel_->ref(META_HANDLE)).second,
166 FROM_HERE,
167 "Could not insert",
168 base_write_transaction())) {
169 return false;
171 } else {
172 if (!SyncAssert(1U == index->erase(kernel_->ref(META_HANDLE)),
173 FROM_HERE,
174 "Entry Not succesfully erased",
175 base_write_transaction())) {
176 return false;
179 kernel_->put(IS_UNAPPLIED_UPDATE, value);
180 kernel_->mark_dirty(&dir()->kernel_->dirty_metahandles);
182 return true;
185 void ModelNeutralMutableEntry::PutServerIsDir(bool value) {
186 DCHECK(kernel_);
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) {
196 DCHECK(kernel_);
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) {
215 DCHECK(kernel_);
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)) {
226 return true;
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";
235 return false;
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_;
245 return true;
248 bool ModelNeutralMutableEntry::PutUniqueClientTag(const string& new_tag) {
249 if (new_tag == kernel_->ref(UNIQUE_CLIENT_TAG)) {
250 return true;
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";
259 return false;
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_;
269 return true;
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)) {
276 NOTREACHED();
277 return;
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) {
297 DCHECK(kernel_);
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
301 // better?
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
306 // old server type.
307 const ModelType old_server_type = kernel_->GetServerModelType();
308 const int64 metahandle = kernel_->ref(META_HANDLE);
309 size_t erase_count =
310 dir()->kernel_->unapplied_update_metahandles[old_server_type]
311 .erase(metahandle);
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
320 // new server type.
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]
324 .insert(metahandle);
329 void ModelNeutralMutableEntry::PutBaseServerSpecifics(
330 const sync_pb::EntitySpecifics& value) {
331 DCHECK(kernel_);
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
335 // better?
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) {
345 DCHECK(kernel_);
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