| OLD | NEW |
| (Empty) |
| 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. | |
| 4 | |
| 5 #include "sync/syncable/model_neutral_mutable_entry.h" | |
| 6 | |
| 7 #include <stddef.h> | |
| 8 #include <stdint.h> | |
| 9 | |
| 10 #include <string> | |
| 11 | |
| 12 #include "sync/internal_api/public/base/unique_position.h" | |
| 13 #include "sync/syncable/directory.h" | |
| 14 #include "sync/syncable/scoped_kernel_lock.h" | |
| 15 #include "sync/syncable/syncable_changes_version.h" | |
| 16 #include "sync/syncable/syncable_util.h" | |
| 17 #include "sync/syncable/syncable_write_transaction.h" | |
| 18 | |
| 19 using std::string; | |
| 20 | |
| 21 namespace syncer { | |
| 22 | |
| 23 namespace syncable { | |
| 24 | |
| 25 ModelNeutralMutableEntry::ModelNeutralMutableEntry(BaseWriteTransaction* trans, | |
| 26 CreateNewUpdateItem, | |
| 27 const Id& id) | |
| 28 : Entry(trans), base_write_transaction_(trans) { | |
| 29 Entry same_id(trans, GET_BY_ID, id); | |
| 30 kernel_ = NULL; | |
| 31 if (same_id.good()) { | |
| 32 return; // already have an item with this ID. | |
| 33 } | |
| 34 std::unique_ptr<EntryKernel> kernel(new EntryKernel()); | |
| 35 | |
| 36 kernel->put(ID, id); | |
| 37 kernel->put(META_HANDLE, trans->directory()->NextMetahandle()); | |
| 38 kernel->mark_dirty(&trans->directory()->kernel()->dirty_metahandles); | |
| 39 kernel->put(IS_DEL, true); | |
| 40 // We match the database defaults here | |
| 41 kernel->put(BASE_VERSION, CHANGES_VERSION); | |
| 42 if (!trans->directory()->InsertEntry(trans, kernel.get())) { | |
| 43 return; // Failed inserting. | |
| 44 } | |
| 45 trans->TrackChangesTo(kernel.get()); | |
| 46 | |
| 47 kernel_ = kernel.release(); | |
| 48 } | |
| 49 | |
| 50 ModelNeutralMutableEntry::ModelNeutralMutableEntry(BaseWriteTransaction* trans, | |
| 51 CreateNewTypeRoot, | |
| 52 ModelType type) | |
| 53 : Entry(trans), base_write_transaction_(trans) { | |
| 54 // We allow NIGORI because we allow SyncEncryptionHandler to restore a nigori | |
| 55 // across Directory instances (see SyncEncryptionHandler::RestoreNigori). | |
| 56 if (type != NIGORI) | |
| 57 DCHECK(IsTypeWithClientGeneratedRoot(type)); | |
| 58 Entry same_type_root(trans, GET_TYPE_ROOT, type); | |
| 59 kernel_ = NULL; | |
| 60 if (same_type_root.good()) { | |
| 61 return; // already have a type root for the given type | |
| 62 } | |
| 63 | |
| 64 std::unique_ptr<EntryKernel> kernel(new EntryKernel()); | |
| 65 | |
| 66 sync_pb::EntitySpecifics specifics; | |
| 67 AddDefaultFieldValue(type, &specifics); | |
| 68 kernel->put(SPECIFICS, specifics); | |
| 69 | |
| 70 kernel->put(ID, | |
| 71 syncable::Id::CreateFromClientString(ModelTypeToString(type))); | |
| 72 kernel->put(META_HANDLE, trans->directory()->NextMetahandle()); | |
| 73 kernel->put(PARENT_ID, syncable::Id::GetRoot()); | |
| 74 kernel->put(BASE_VERSION, CHANGES_VERSION); | |
| 75 kernel->put(NON_UNIQUE_NAME, ModelTypeToString(type)); | |
| 76 kernel->put(IS_DIR, true); | |
| 77 | |
| 78 kernel->mark_dirty(&trans->directory()->kernel()->dirty_metahandles); | |
| 79 | |
| 80 if (!trans->directory()->InsertEntry(trans, kernel.get())) { | |
| 81 return; // Failed inserting. | |
| 82 } | |
| 83 | |
| 84 trans->TrackChangesTo(kernel.get()); | |
| 85 | |
| 86 kernel_ = kernel.release(); | |
| 87 } | |
| 88 | |
| 89 ModelNeutralMutableEntry::ModelNeutralMutableEntry( | |
| 90 BaseWriteTransaction* trans, GetById, const Id& id) | |
| 91 : Entry(trans, GET_BY_ID, id), base_write_transaction_(trans) { | |
| 92 } | |
| 93 | |
| 94 ModelNeutralMutableEntry::ModelNeutralMutableEntry(BaseWriteTransaction* trans, | |
| 95 GetByHandle, | |
| 96 int64_t metahandle) | |
| 97 : Entry(trans, GET_BY_HANDLE, metahandle), base_write_transaction_(trans) {} | |
| 98 | |
| 99 ModelNeutralMutableEntry::ModelNeutralMutableEntry( | |
| 100 BaseWriteTransaction* trans, GetByClientTag, const std::string& tag) | |
| 101 : Entry(trans, GET_BY_CLIENT_TAG, tag), base_write_transaction_(trans) { | |
| 102 } | |
| 103 | |
| 104 ModelNeutralMutableEntry::ModelNeutralMutableEntry( | |
| 105 BaseWriteTransaction* trans, GetTypeRoot, ModelType type) | |
| 106 : Entry(trans, GET_TYPE_ROOT, type), base_write_transaction_(trans) { | |
| 107 } | |
| 108 | |
| 109 void ModelNeutralMutableEntry::PutBaseVersion(int64_t value) { | |
| 110 DCHECK(kernel_); | |
| 111 if (kernel_->ref(BASE_VERSION) != value) { | |
| 112 base_write_transaction_->TrackChangesTo(kernel_); | |
| 113 kernel_->put(BASE_VERSION, value); | |
| 114 MarkDirty(); | |
| 115 } | |
| 116 } | |
| 117 | |
| 118 void ModelNeutralMutableEntry::PutServerVersion(int64_t value) { | |
| 119 DCHECK(kernel_); | |
| 120 if (kernel_->ref(SERVER_VERSION) != value) { | |
| 121 base_write_transaction_->TrackChangesTo(kernel_); | |
| 122 ScopedKernelLock lock(dir()); | |
| 123 kernel_->put(SERVER_VERSION, value); | |
| 124 MarkDirty(); | |
| 125 } | |
| 126 } | |
| 127 | |
| 128 void ModelNeutralMutableEntry::PutServerMtime(base::Time value) { | |
| 129 DCHECK(kernel_); | |
| 130 if (kernel_->ref(SERVER_MTIME) != value) { | |
| 131 base_write_transaction_->TrackChangesTo(kernel_); | |
| 132 kernel_->put(SERVER_MTIME, value); | |
| 133 MarkDirty(); | |
| 134 } | |
| 135 } | |
| 136 | |
| 137 void ModelNeutralMutableEntry::PutServerCtime(base::Time value) { | |
| 138 DCHECK(kernel_); | |
| 139 if (kernel_->ref(SERVER_CTIME) != value) { | |
| 140 base_write_transaction_->TrackChangesTo(kernel_); | |
| 141 kernel_->put(SERVER_CTIME, value); | |
| 142 MarkDirty(); | |
| 143 } | |
| 144 } | |
| 145 | |
| 146 bool ModelNeutralMutableEntry::PutId(const Id& value) { | |
| 147 DCHECK(kernel_); | |
| 148 if (kernel_->ref(ID) != value) { | |
| 149 base_write_transaction_->TrackChangesTo(kernel_); | |
| 150 if (!dir()->ReindexId(base_write_transaction(), kernel_, value)) | |
| 151 return false; | |
| 152 MarkDirty(); | |
| 153 } | |
| 154 return true; | |
| 155 } | |
| 156 | |
| 157 void ModelNeutralMutableEntry::PutServerParentId(const Id& value) { | |
| 158 DCHECK(kernel_); | |
| 159 if (kernel_->ref(SERVER_PARENT_ID) != value) { | |
| 160 base_write_transaction_->TrackChangesTo(kernel_); | |
| 161 kernel_->put(SERVER_PARENT_ID, value); | |
| 162 MarkDirty(); | |
| 163 } | |
| 164 } | |
| 165 | |
| 166 bool ModelNeutralMutableEntry::PutIsUnsynced(bool value) { | |
| 167 DCHECK(kernel_); | |
| 168 if (kernel_->ref(IS_UNSYNCED) != value) { | |
| 169 base_write_transaction_->TrackChangesTo(kernel_); | |
| 170 MetahandleSet* index = &dir()->kernel()->unsynced_metahandles; | |
| 171 | |
| 172 ScopedKernelLock lock(dir()); | |
| 173 if (value) { | |
| 174 if (!SyncAssert(index->insert(kernel_->ref(META_HANDLE)).second, | |
| 175 FROM_HERE, | |
| 176 "Could not insert", | |
| 177 base_write_transaction())) { | |
| 178 return false; | |
| 179 } | |
| 180 } else { | |
| 181 if (!SyncAssert(1U == index->erase(kernel_->ref(META_HANDLE)), | |
| 182 FROM_HERE, | |
| 183 "Entry Not succesfully erased", | |
| 184 base_write_transaction())) { | |
| 185 return false; | |
| 186 } | |
| 187 } | |
| 188 kernel_->put(IS_UNSYNCED, value); | |
| 189 MarkDirty(); | |
| 190 } | |
| 191 return true; | |
| 192 } | |
| 193 | |
| 194 bool ModelNeutralMutableEntry::PutIsUnappliedUpdate(bool value) { | |
| 195 DCHECK(kernel_); | |
| 196 if (kernel_->ref(IS_UNAPPLIED_UPDATE) != value) { | |
| 197 base_write_transaction_->TrackChangesTo(kernel_); | |
| 198 // Use kernel_->GetServerModelType() instead of | |
| 199 // GetServerModelType() as we may trigger some DCHECKs in the | |
| 200 // latter. | |
| 201 MetahandleSet* index = &dir()->kernel()->unapplied_update_metahandles[ | |
| 202 kernel_->GetServerModelType()]; | |
| 203 | |
| 204 ScopedKernelLock lock(dir()); | |
| 205 if (value) { | |
| 206 if (!SyncAssert(index->insert(kernel_->ref(META_HANDLE)).second, | |
| 207 FROM_HERE, | |
| 208 "Could not insert", | |
| 209 base_write_transaction())) { | |
| 210 return false; | |
| 211 } | |
| 212 } else { | |
| 213 if (!SyncAssert(1U == index->erase(kernel_->ref(META_HANDLE)), | |
| 214 FROM_HERE, | |
| 215 "Entry Not succesfully erased", | |
| 216 base_write_transaction())) { | |
| 217 return false; | |
| 218 } | |
| 219 } | |
| 220 kernel_->put(IS_UNAPPLIED_UPDATE, value); | |
| 221 MarkDirty(); | |
| 222 } | |
| 223 return true; | |
| 224 } | |
| 225 | |
| 226 void ModelNeutralMutableEntry::PutServerIsDir(bool value) { | |
| 227 DCHECK(kernel_); | |
| 228 if (kernel_->ref(SERVER_IS_DIR) != value) { | |
| 229 base_write_transaction_->TrackChangesTo(kernel_); | |
| 230 kernel_->put(SERVER_IS_DIR, value); | |
| 231 MarkDirty(); | |
| 232 } | |
| 233 } | |
| 234 | |
| 235 void ModelNeutralMutableEntry::PutServerIsDel(bool value) { | |
| 236 DCHECK(kernel_); | |
| 237 bool old_value = kernel_->ref(SERVER_IS_DEL); | |
| 238 if (old_value != value) { | |
| 239 base_write_transaction_->TrackChangesTo(kernel_); | |
| 240 kernel_->put(SERVER_IS_DEL, value); | |
| 241 MarkDirty(); | |
| 242 } | |
| 243 | |
| 244 if (!value || kernel_->ref(IS_UNAPPLIED_UPDATE)) { | |
| 245 // Update delete journal for existence status change on server side here | |
| 246 // instead of in PutIsDel() because IS_DEL may not be updated due to | |
| 247 // early returns when processing updates. And because | |
| 248 // UpdateDeleteJournalForServerDelete() checks for SERVER_IS_DEL, it has | |
| 249 // to be called on sync thread. | |
| 250 | |
| 251 // Please note that the delete journal applies only to the deletions | |
| 252 // originating on the server side (hence the IS_UNAPPLIED_UPDATE check), | |
| 253 // but it still makes sense to remove the entry from the delete journal | |
| 254 // when it gets undeleted locally. | |
| 255 dir()->delete_journal()->UpdateDeleteJournalForServerDelete( | |
| 256 base_write_transaction(), old_value, *kernel_); | |
| 257 } | |
| 258 } | |
| 259 | |
| 260 void ModelNeutralMutableEntry::PutServerNonUniqueName( | |
| 261 const std::string& value) { | |
| 262 DCHECK(kernel_); | |
| 263 if (kernel_->ref(SERVER_NON_UNIQUE_NAME) != value) { | |
| 264 base_write_transaction_->TrackChangesTo(kernel_); | |
| 265 kernel_->put(SERVER_NON_UNIQUE_NAME, value); | |
| 266 MarkDirty(); | |
| 267 } | |
| 268 } | |
| 269 | |
| 270 bool ModelNeutralMutableEntry::PutUniqueServerTag(const string& new_tag) { | |
| 271 if (new_tag == kernel_->ref(UNIQUE_SERVER_TAG)) { | |
| 272 return true; | |
| 273 } | |
| 274 | |
| 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"; | |
| 281 return false; | |
| 282 } | |
| 283 dir()->kernel()->server_tags_map.erase( | |
| 284 kernel_->ref(UNIQUE_SERVER_TAG)); | |
| 285 kernel_->put(UNIQUE_SERVER_TAG, new_tag); | |
| 286 MarkDirty(); | |
| 287 if (!new_tag.empty()) { | |
| 288 dir()->kernel()->server_tags_map[new_tag] = kernel_; | |
| 289 } | |
| 290 | |
| 291 return true; | |
| 292 } | |
| 293 | |
| 294 bool ModelNeutralMutableEntry::PutUniqueClientTag(const string& new_tag) { | |
| 295 if (new_tag == kernel_->ref(UNIQUE_CLIENT_TAG)) { | |
| 296 return true; | |
| 297 } | |
| 298 | |
| 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"; | |
| 305 return false; | |
| 306 } | |
| 307 dir()->kernel()->client_tags_map.erase( | |
| 308 kernel_->ref(UNIQUE_CLIENT_TAG)); | |
| 309 kernel_->put(UNIQUE_CLIENT_TAG, new_tag); | |
| 310 MarkDirty(); | |
| 311 if (!new_tag.empty()) { | |
| 312 dir()->kernel()->client_tags_map[new_tag] = kernel_; | |
| 313 } | |
| 314 | |
| 315 return true; | |
| 316 } | |
| 317 | |
| 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)) { | |
| 322 NOTREACHED(); | |
| 323 return; | |
| 324 } | |
| 325 | |
| 326 // TODO(stanisc): Does this need a call to TrackChangesTo? | |
| 327 | |
| 328 if (!kernel_->ref(UNIQUE_BOOKMARK_TAG).empty() && | |
| 329 tag != kernel_->ref(UNIQUE_BOOKMARK_TAG)) { | |
| 330 // There is only one scenario where our tag is expected to change. That | |
| 331 // scenario occurs when our current tag is a non-correct tag assigned during | |
| 332 // the UniquePosition migration. | |
| 333 std::string migration_generated_tag = | |
| 334 GenerateSyncableBookmarkHash(std::string(), | |
| 335 kernel_->ref(ID).GetServerId()); | |
| 336 DCHECK_EQ(migration_generated_tag, kernel_->ref(UNIQUE_BOOKMARK_TAG)); | |
| 337 } | |
| 338 | |
| 339 kernel_->put(UNIQUE_BOOKMARK_TAG, tag); | |
| 340 MarkDirty(); | |
| 341 } | |
| 342 | |
| 343 void ModelNeutralMutableEntry::PutServerSpecifics( | |
| 344 const sync_pb::EntitySpecifics& value) { | |
| 345 DCHECK(kernel_); | |
| 346 CHECK(!value.password().has_client_only_encrypted_data()); | |
| 347 // TODO(ncarter): This is unfortunately heavyweight. Can we do | |
| 348 // better? | |
| 349 const std::string& serialized_value = value.SerializeAsString(); | |
| 350 if (serialized_value != kernel_->ref(SERVER_SPECIFICS).SerializeAsString()) { | |
| 351 base_write_transaction_->TrackChangesTo(kernel_); | |
| 352 if (kernel_->ref(IS_UNAPPLIED_UPDATE)) { | |
| 353 // Remove ourselves from unapplied_update_metahandles with our | |
| 354 // old server type. | |
| 355 const ModelType old_server_type = kernel_->GetServerModelType(); | |
| 356 const int64_t metahandle = kernel_->ref(META_HANDLE); | |
| 357 size_t erase_count = | |
| 358 dir()->kernel()->unapplied_update_metahandles[old_server_type] | |
| 359 .erase(metahandle); | |
| 360 DCHECK_EQ(erase_count, 1u); | |
| 361 } | |
| 362 | |
| 363 // Check for potential sharing - SERVER_SPECIFICS is often | |
| 364 // copied from SPECIFICS. | |
| 365 if (serialized_value == kernel_->ref(SPECIFICS).SerializeAsString()) { | |
| 366 kernel_->copy(SPECIFICS, SERVER_SPECIFICS); | |
| 367 } else { | |
| 368 kernel_->put(SERVER_SPECIFICS, value); | |
| 369 } | |
| 370 MarkDirty(); | |
| 371 | |
| 372 if (kernel_->ref(IS_UNAPPLIED_UPDATE)) { | |
| 373 // Add ourselves back into unapplied_update_metahandles with our | |
| 374 // new server type. | |
| 375 const ModelType new_server_type = kernel_->GetServerModelType(); | |
| 376 const int64_t metahandle = kernel_->ref(META_HANDLE); | |
| 377 dir()->kernel()->unapplied_update_metahandles[new_server_type] | |
| 378 .insert(metahandle); | |
| 379 } | |
| 380 } | |
| 381 } | |
| 382 | |
| 383 void ModelNeutralMutableEntry::PutBaseServerSpecifics( | |
| 384 const sync_pb::EntitySpecifics& value) { | |
| 385 DCHECK(kernel_); | |
| 386 CHECK(!value.password().has_client_only_encrypted_data()); | |
| 387 // TODO(ncarter): This is unfortunately heavyweight. Can we do | |
| 388 // better? | |
| 389 const std::string& serialized_value = value.SerializeAsString(); | |
| 390 if (serialized_value != | |
| 391 kernel_->ref(BASE_SERVER_SPECIFICS).SerializeAsString()) { | |
| 392 base_write_transaction_->TrackChangesTo(kernel_); | |
| 393 // Check for potential sharing - BASE_SERVER_SPECIFICS is often | |
| 394 // copied from SERVER_SPECIFICS. | |
| 395 if (serialized_value == | |
| 396 kernel_->ref(SERVER_SPECIFICS).SerializeAsString()) { | |
| 397 kernel_->copy(SERVER_SPECIFICS, BASE_SERVER_SPECIFICS); | |
| 398 } else { | |
| 399 kernel_->put(BASE_SERVER_SPECIFICS, value); | |
| 400 } | |
| 401 MarkDirty(); | |
| 402 } | |
| 403 } | |
| 404 | |
| 405 void ModelNeutralMutableEntry::PutServerUniquePosition( | |
| 406 const UniquePosition& value) { | |
| 407 DCHECK(kernel_); | |
| 408 if (!kernel_->ref(SERVER_UNIQUE_POSITION).Equals(value)) { | |
| 409 base_write_transaction_->TrackChangesTo(kernel_); | |
| 410 // We should never overwrite a valid position with an invalid one. | |
| 411 DCHECK(value.IsValid()); | |
| 412 ScopedKernelLock lock(dir()); | |
| 413 kernel_->put(SERVER_UNIQUE_POSITION, value); | |
| 414 MarkDirty(); | |
| 415 } | |
| 416 } | |
| 417 | |
| 418 void ModelNeutralMutableEntry::PutServerAttachmentMetadata( | |
| 419 const sync_pb::AttachmentMetadata& value) { | |
| 420 DCHECK(kernel_); | |
| 421 const std::string& serialized_value = value.SerializeAsString(); | |
| 422 if (serialized_value != | |
| 423 kernel_->ref(SERVER_ATTACHMENT_METADATA).SerializeAsString()) { | |
| 424 base_write_transaction_->TrackChangesTo(kernel_); | |
| 425 // Check for potential sharing - SERVER_ATTACHMENT_METADATA is often | |
| 426 // copied from ATTACHMENT_METADATA. | |
| 427 if (serialized_value == | |
| 428 kernel_->ref(ATTACHMENT_METADATA).SerializeAsString()) { | |
| 429 kernel_->copy(ATTACHMENT_METADATA, SERVER_ATTACHMENT_METADATA); | |
| 430 } else { | |
| 431 kernel_->put(SERVER_ATTACHMENT_METADATA, value); | |
| 432 } | |
| 433 MarkDirty(); | |
| 434 } | |
| 435 } | |
| 436 | |
| 437 void ModelNeutralMutableEntry::PutSyncing(bool value) { | |
| 438 kernel_->put(SYNCING, value); | |
| 439 } | |
| 440 | |
| 441 void ModelNeutralMutableEntry::PutDirtySync(bool value) { | |
| 442 DCHECK(!value || GetSyncing()); | |
| 443 kernel_->put(DIRTY_SYNC, value); | |
| 444 } | |
| 445 | |
| 446 void ModelNeutralMutableEntry::PutParentIdPropertyOnly(const Id& parent_id) { | |
| 447 base_write_transaction_->TrackChangesTo(kernel_); | |
| 448 dir()->ReindexParentId(base_write_transaction(), kernel_, parent_id); | |
| 449 MarkDirty(); | |
| 450 } | |
| 451 | |
| 452 void ModelNeutralMutableEntry::UpdateTransactionVersion(int64_t value) { | |
| 453 kernel_->put(TRANSACTION_VERSION, value); | |
| 454 MarkDirty(); | |
| 455 } | |
| 456 | |
| 457 ModelNeutralMutableEntry::ModelNeutralMutableEntry(BaseWriteTransaction* trans) | |
| 458 : Entry(trans), base_write_transaction_(trans) {} | |
| 459 | |
| 460 void ModelNeutralMutableEntry::MarkDirty() { | |
| 461 kernel_->mark_dirty(&dir()->kernel()->dirty_metahandles); | |
| 462 } | |
| 463 | |
| 464 } // namespace syncable | |
| 465 | |
| 466 } // namespace syncer | |
| OLD | NEW |