Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(42)

Side by Side Diff: sync/syncable/directory.cc

Issue 11636006: WIP: The Bookmark Position Megapatch (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Various updates, including switch suffix to unique_client_tag style Created 8 years ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
« no previous file with comments | « sync/syncable/directory.h ('k') | sync/syncable/directory_backing_store.h » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 #include "sync/syncable/directory.h" 5 #include "sync/syncable/directory.h"
6 6
7 #include "base/base64.h"
7 #include "base/debug/trace_event.h" 8 #include "base/debug/trace_event.h"
8 #include "base/perftimer.h"
9 #include "base/stl_util.h" 9 #include "base/stl_util.h"
10 #include "base/string_number_conversions.h" 10 #include "base/string_number_conversions.h"
11 #include "sync/internal_api/public/base/node_ordinal.h" 11 #include "sync/internal_api/public/base/unique_position.h"
12 #include "sync/internal_api/public/util/unrecoverable_error_handler.h" 12 #include "sync/internal_api/public/util/unrecoverable_error_handler.h"
13 #include "sync/syncable/base_transaction.h" 13 #include "sync/syncable/base_transaction.h"
14 #include "sync/syncable/entry.h" 14 #include "sync/syncable/entry.h"
15 #include "sync/syncable/entry_kernel.h" 15 #include "sync/syncable/entry_kernel.h"
16 #include "sync/syncable/in_memory_directory_backing_store.h" 16 #include "sync/syncable/in_memory_directory_backing_store.h"
17 #include "sync/syncable/on_disk_directory_backing_store.h" 17 #include "sync/syncable/on_disk_directory_backing_store.h"
18 #include "sync/syncable/read_transaction.h" 18 #include "sync/syncable/read_transaction.h"
19 #include "sync/syncable/scoped_index_updater.h" 19 #include "sync/syncable/scoped_index_updater.h"
20 #include "sync/syncable/scoped_parent_child_index_updater.h"
20 #include "sync/syncable/syncable-inl.h" 21 #include "sync/syncable/syncable-inl.h"
21 #include "sync/syncable/syncable_changes_version.h" 22 #include "sync/syncable/syncable_changes_version.h"
22 #include "sync/syncable/syncable_util.h" 23 #include "sync/syncable/syncable_util.h"
23 #include "sync/syncable/write_transaction.h" 24 #include "sync/syncable/write_transaction.h"
24 25
25 using std::string; 26 using std::string;
26 27
27 namespace syncer { 28 namespace syncer {
28 namespace syncable { 29 namespace syncable {
29 30
30 namespace { 31 namespace {
31 // Helper function to add an item to the index, if it ought to be added. 32 // Helper function to add an item to the index, if it ought to be added.
32 template<typename Indexer> 33 template<typename Indexer>
33 void InitializeIndexEntry(EntryKernel* entry, 34 void InitializeIndexEntry(EntryKernel* entry,
34 typename Index<Indexer>::Set* index) { 35 typename Index<Indexer>::Set* index) {
35 if (Indexer::ShouldInclude(entry)) { 36 if (Indexer::ShouldInclude(entry)) {
36 index->insert(entry); 37 index->insert(entry);
37 } 38 }
38 } 39 }
39
40 } 40 }
41 41
42 // static 42 // static
43 bool ClientTagIndexer::ShouldInclude(const EntryKernel* a) { 43 bool ClientTagIndexer::ShouldInclude(const EntryKernel* a) {
44 return !a->ref(UNIQUE_CLIENT_TAG).empty(); 44 return !a->ref(UNIQUE_CLIENT_TAG).empty();
45 } 45 }
46 46
47 bool ParentIdAndHandleIndexer::Comparator::operator() (
48 const syncable::EntryKernel* a,
49 const syncable::EntryKernel* b) const {
50 int cmp = a->ref(PARENT_ID).compare(b->ref(PARENT_ID));
51 if (cmp != 0)
52 return cmp < 0;
53
54 const NodeOrdinal& a_position = a->ref(SERVER_ORDINAL_IN_PARENT);
55 const NodeOrdinal& b_position = b->ref(SERVER_ORDINAL_IN_PARENT);
56 if (!a_position.Equals(b_position))
57 return a_position.LessThan(b_position);
58
59 cmp = a->ref(ID).compare(b->ref(ID));
60 return cmp < 0;
61 }
62
63 // static
64 bool ParentIdAndHandleIndexer::ShouldInclude(const EntryKernel* a) {
65 // This index excludes deleted items and the root item. The root
66 // item is excluded so that it doesn't show up as a child of itself.
67 return !a->ref(IS_DEL) && !a->ref(ID).IsRoot();
68 }
69
70 // static 47 // static
71 const FilePath::CharType Directory::kSyncDatabaseFilename[] = 48 const FilePath::CharType Directory::kSyncDatabaseFilename[] =
72 FILE_PATH_LITERAL("SyncData.sqlite3"); 49 FILE_PATH_LITERAL("SyncData.sqlite3");
73 50
74 void Directory::InitKernelForTest( 51 void Directory::InitKernelForTest(
75 const std::string& name, 52 const std::string& name,
76 DirectoryChangeDelegate* delegate, 53 DirectoryChangeDelegate* delegate,
77 const WeakHandle<TransactionObserver>& transaction_observer) { 54 const WeakHandle<TransactionObserver>& transaction_observer) {
78 DCHECK(!kernel_); 55 DCHECK(!kernel_);
79 kernel_ = new Kernel(name, KernelLoadInfo(), delegate, transaction_observer); 56 kernel_ = new Kernel(name, KernelLoadInfo(), delegate, transaction_observer);
(...skipping 24 matching lines...) Expand all
104 Directory::SaveChangesSnapshot::~SaveChangesSnapshot() {} 81 Directory::SaveChangesSnapshot::~SaveChangesSnapshot() {}
105 82
106 Directory::Kernel::Kernel( 83 Directory::Kernel::Kernel(
107 const std::string& name, 84 const std::string& name,
108 const KernelLoadInfo& info, DirectoryChangeDelegate* delegate, 85 const KernelLoadInfo& info, DirectoryChangeDelegate* delegate,
109 const WeakHandle<TransactionObserver>& transaction_observer) 86 const WeakHandle<TransactionObserver>& transaction_observer)
110 : next_write_transaction_id(0), 87 : next_write_transaction_id(0),
111 name(name), 88 name(name),
112 metahandles_index(new Directory::MetahandlesIndex), 89 metahandles_index(new Directory::MetahandlesIndex),
113 ids_index(new Directory::IdsIndex), 90 ids_index(new Directory::IdsIndex),
114 parent_id_child_index(new Directory::ParentIdChildIndex), 91 parent_child_index(new ParentChildIndex),
115 client_tag_index(new Directory::ClientTagIndex), 92 client_tag_index(new Directory::ClientTagIndex),
116 unsynced_metahandles(new MetahandleSet), 93 unsynced_metahandles(new MetahandleSet),
117 dirty_metahandles(new MetahandleSet), 94 dirty_metahandles(new MetahandleSet),
118 metahandles_to_purge(new MetahandleSet), 95 metahandles_to_purge(new MetahandleSet),
119 info_status(Directory::KERNEL_SHARE_INFO_VALID), 96 info_status(Directory::KERNEL_SHARE_INFO_VALID),
120 persisted_info(info.kernel_info), 97 persisted_info(info.kernel_info),
121 cache_guid(info.cache_guid), 98 cache_guid(info.cache_guid),
122 next_metahandle(info.max_metahandle + 1), 99 next_metahandle(info.max_metahandle + 1),
123 delegate(delegate), 100 delegate(delegate),
124 transaction_observer(transaction_observer) { 101 transaction_observer(transaction_observer) {
125 DCHECK(delegate); 102 DCHECK(delegate);
126 DCHECK(transaction_observer.IsInitialized()); 103 DCHECK(transaction_observer.IsInitialized());
127 } 104 }
128 105
106
129 Directory::Kernel::~Kernel() { 107 Directory::Kernel::~Kernel() {
130 delete unsynced_metahandles; 108 delete unsynced_metahandles;
131 delete dirty_metahandles; 109 delete dirty_metahandles;
132 delete metahandles_to_purge; 110 delete metahandles_to_purge;
133 delete parent_id_child_index; 111 delete parent_child_index;
134 delete client_tag_index; 112 delete client_tag_index;
135 delete ids_index; 113 delete ids_index;
136 STLDeleteElements(metahandles_index); 114 STLDeleteElements(metahandles_index);
137 delete metahandles_index; 115 delete metahandles_index;
138 } 116 }
139 117
140 Directory::Directory( 118 Directory::Directory(
141 DirectoryBackingStore* store, 119 DirectoryBackingStore* store,
142 UnrecoverableErrorHandler* unrecoverable_error_handler, 120 UnrecoverableErrorHandler* unrecoverable_error_handler,
143 ReportUnrecoverableErrorFunction report_unrecoverable_error_function, 121 ReportUnrecoverableErrorFunction report_unrecoverable_error_function,
(...skipping 25 matching lines...) Expand all
169 147
170 if (OPENED != result) 148 if (OPENED != result)
171 Close(); 149 Close();
172 return result; 150 return result;
173 } 151 }
174 152
175 void Directory::InitializeIndices() { 153 void Directory::InitializeIndices() {
176 MetahandlesIndex::iterator it = kernel_->metahandles_index->begin(); 154 MetahandlesIndex::iterator it = kernel_->metahandles_index->begin();
177 for (; it != kernel_->metahandles_index->end(); ++it) { 155 for (; it != kernel_->metahandles_index->end(); ++it) {
178 EntryKernel* entry = *it; 156 EntryKernel* entry = *it;
179 InitializeIndexEntry<ParentIdAndHandleIndexer>(entry, 157 if (ParentChildIndex::ShouldInclude(entry))
180 kernel_->parent_id_child_index); 158 kernel_->parent_child_index->Insert(entry);
181 InitializeIndexEntry<IdIndexer>(entry, kernel_->ids_index); 159 InitializeIndexEntry<IdIndexer>(entry, kernel_->ids_index);
182 InitializeIndexEntry<ClientTagIndexer>(entry, kernel_->client_tag_index); 160 InitializeIndexEntry<ClientTagIndexer>(entry, kernel_->client_tag_index);
183 const int64 metahandle = entry->ref(META_HANDLE); 161 const int64 metahandle = entry->ref(META_HANDLE);
184 if (entry->ref(IS_UNSYNCED)) 162 if (entry->ref(IS_UNSYNCED))
185 kernel_->unsynced_metahandles->insert(metahandle); 163 kernel_->unsynced_metahandles->insert(metahandle);
186 if (entry->ref(IS_UNAPPLIED_UPDATE)) { 164 if (entry->ref(IS_UNAPPLIED_UPDATE)) {
187 const ModelType type = entry->GetServerModelType(); 165 const ModelType type = entry->GetServerModelType();
188 kernel_->unapplied_update_metahandles[type].insert(metahandle); 166 kernel_->unapplied_update_metahandles[type].insert(metahandle);
189 } 167 }
190 DCHECK(!entry->is_dirty()); 168 DCHECK(!entry->is_dirty());
(...skipping 158 matching lines...) Expand 10 before | Expand all | Expand 10 after
349 if (!SyncAssert(NULL != entry, FROM_HERE, "Entry is null", trans)) 327 if (!SyncAssert(NULL != entry, FROM_HERE, "Entry is null", trans))
350 return false; 328 return false;
351 329
352 static const char error[] = "Entry already in memory index."; 330 static const char error[] = "Entry already in memory index.";
353 if (!SyncAssert(kernel_->metahandles_index->insert(entry).second, 331 if (!SyncAssert(kernel_->metahandles_index->insert(entry).second,
354 FROM_HERE, 332 FROM_HERE,
355 error, 333 error,
356 trans)) 334 trans))
357 return false; 335 return false;
358 336
359 if (!entry->ref(IS_DEL)) { 337 if (ParentChildIndex::ShouldInclude(entry)) {
360 if (!SyncAssert(kernel_->parent_id_child_index->insert(entry).second, 338 if (!SyncAssert(kernel_->parent_child_index->Insert(entry),
361 FROM_HERE, 339 FROM_HERE,
362 error, 340 error,
363 trans)) { 341 trans)) {
364 return false; 342 return false;
365 } 343 }
366 } 344 }
367 if (!SyncAssert(kernel_->ids_index->insert(entry).second, 345 if (!SyncAssert(kernel_->ids_index->insert(entry).second,
368 FROM_HERE, 346 FROM_HERE,
369 error, 347 error,
370 trans)) 348 trans))
(...skipping 10 matching lines...) Expand all
381 bool Directory::ReindexId(WriteTransaction* trans, 359 bool Directory::ReindexId(WriteTransaction* trans,
382 EntryKernel* const entry, 360 EntryKernel* const entry,
383 const Id& new_id) { 361 const Id& new_id) {
384 ScopedKernelLock lock(this); 362 ScopedKernelLock lock(this);
385 if (NULL != GetEntryById(new_id, &lock)) 363 if (NULL != GetEntryById(new_id, &lock))
386 return false; 364 return false;
387 365
388 { 366 {
389 // Update the indices that depend on the ID field. 367 // Update the indices that depend on the ID field.
390 ScopedIndexUpdater<IdIndexer> updater_a(lock, entry, kernel_->ids_index); 368 ScopedIndexUpdater<IdIndexer> updater_a(lock, entry, kernel_->ids_index);
391 ScopedIndexUpdater<ParentIdAndHandleIndexer> updater_b(lock, entry, 369 ScopedParentChildIndexUpdater updater_b(lock, entry,
392 kernel_->parent_id_child_index); 370 kernel_->parent_child_index);
393 entry->put(ID, new_id); 371 entry->put(ID, new_id);
394 } 372 }
395 return true; 373 return true;
396 } 374 }
397 375
398 bool Directory::ReindexParentId(WriteTransaction* trans, 376 bool Directory::ReindexParentId(WriteTransaction* trans,
399 EntryKernel* const entry, 377 EntryKernel* const entry,
400 const Id& new_parent_id) { 378 const Id& new_parent_id) {
401 ScopedKernelLock lock(this); 379 ScopedKernelLock lock(this);
402 380
403 { 381 {
404 // Update the indices that depend on the PARENT_ID field. 382 // Update the indices that depend on the PARENT_ID field.
405 ScopedIndexUpdater<ParentIdAndHandleIndexer> index_updater(lock, entry, 383 ScopedParentChildIndexUpdater index_updater(lock, entry,
406 kernel_->parent_id_child_index); 384 kernel_->parent_child_index);
407 entry->put(PARENT_ID, new_parent_id); 385 entry->put(PARENT_ID, new_parent_id);
408 } 386 }
409 return true; 387 return true;
410 } 388 }
411 389
412 bool Directory::unrecoverable_error_set(const BaseTransaction* trans) const { 390 bool Directory::unrecoverable_error_set(const BaseTransaction* trans) const {
413 DCHECK(trans != NULL); 391 DCHECK(trans != NULL);
414 return unrecoverable_error_set_; 392 return unrecoverable_error_set_;
415 } 393 }
416 394
(...skipping 111 matching lines...) Expand 10 before | Expand all | Expand 10 after
528 // and the server. 506 // and the server.
529 size_t num_erased = 0; 507 size_t num_erased = 0;
530 num_erased = kernel_->ids_index->erase(entry); 508 num_erased = kernel_->ids_index->erase(entry);
531 DCHECK_EQ(1u, num_erased); 509 DCHECK_EQ(1u, num_erased);
532 num_erased = kernel_->metahandles_index->erase(entry); 510 num_erased = kernel_->metahandles_index->erase(entry);
533 DCHECK_EQ(1u, num_erased); 511 DCHECK_EQ(1u, num_erased);
534 512
535 // Might not be in it 513 // Might not be in it
536 num_erased = kernel_->client_tag_index->erase(entry); 514 num_erased = kernel_->client_tag_index->erase(entry);
537 DCHECK_EQ(entry->ref(UNIQUE_CLIENT_TAG).empty(), !num_erased); 515 DCHECK_EQ(entry->ref(UNIQUE_CLIENT_TAG).empty(), !num_erased);
538 if (!SyncAssert(!kernel_->parent_id_child_index->count(entry), 516 if (!SyncAssert(!kernel_->parent_child_index->Contains(entry),
539 FROM_HERE, 517 FROM_HERE,
540 "Deleted entry still present", 518 "Deleted entry still present",
541 (&trans))) 519 (&trans)))
542 return false; 520 return false;
543 delete entry; 521 delete entry;
544 } 522 }
545 if (trans.unrecoverable_error_set()) 523 if (trans.unrecoverable_error_set())
546 return false; 524 return false;
547 } 525 }
548 return true; 526 return true;
(...skipping 11 matching lines...) Expand all
560 while (it != kernel_->metahandles_index->end()) { 538 while (it != kernel_->metahandles_index->end()) {
561 const sync_pb::EntitySpecifics& local_specifics = (*it)->ref(SPECIFICS); 539 const sync_pb::EntitySpecifics& local_specifics = (*it)->ref(SPECIFICS);
562 const sync_pb::EntitySpecifics& server_specifics = 540 const sync_pb::EntitySpecifics& server_specifics =
563 (*it)->ref(SERVER_SPECIFICS); 541 (*it)->ref(SERVER_SPECIFICS);
564 ModelType local_type = GetModelTypeFromSpecifics(local_specifics); 542 ModelType local_type = GetModelTypeFromSpecifics(local_specifics);
565 ModelType server_type = GetModelTypeFromSpecifics(server_specifics); 543 ModelType server_type = GetModelTypeFromSpecifics(server_specifics);
566 544
567 // Note the dance around incrementing |it|, since we sometimes erase(). 545 // Note the dance around incrementing |it|, since we sometimes erase().
568 if ((IsRealDataType(local_type) && types.Has(local_type)) || 546 if ((IsRealDataType(local_type) && types.Has(local_type)) ||
569 (IsRealDataType(server_type) && types.Has(server_type))) { 547 (IsRealDataType(server_type) && types.Has(server_type))) {
570 if (!UnlinkEntryFromOrder(*it, &trans, &lock, DATA_TYPE_PURGE))
571 return false;
572 548
573 int64 handle = (*it)->ref(META_HANDLE); 549 int64 handle = (*it)->ref(META_HANDLE);
574 kernel_->metahandles_to_purge->insert(handle); 550 kernel_->metahandles_to_purge->insert(handle);
575 551
576 size_t num_erased = 0; 552 size_t num_erased = 0;
577 EntryKernel* entry = *it; 553 EntryKernel* entry = *it;
578 num_erased = kernel_->ids_index->erase(entry); 554 num_erased = kernel_->ids_index->erase(entry);
579 DCHECK_EQ(1u, num_erased); 555 DCHECK_EQ(1u, num_erased);
580 num_erased = kernel_->client_tag_index->erase(entry); 556 num_erased = kernel_->client_tag_index->erase(entry);
581 DCHECK_EQ(entry->ref(UNIQUE_CLIENT_TAG).empty(), !num_erased); 557 DCHECK_EQ(entry->ref(UNIQUE_CLIENT_TAG).empty(), !num_erased);
582 num_erased = kernel_->unsynced_metahandles->erase(handle); 558 num_erased = kernel_->unsynced_metahandles->erase(handle);
583 DCHECK_EQ(entry->ref(IS_UNSYNCED), num_erased > 0); 559 DCHECK_EQ(entry->ref(IS_UNSYNCED), num_erased > 0);
584 num_erased = 560 num_erased =
585 kernel_->unapplied_update_metahandles[server_type].erase(handle); 561 kernel_->unapplied_update_metahandles[server_type].erase(handle);
586 DCHECK_EQ(entry->ref(IS_UNAPPLIED_UPDATE), num_erased > 0); 562 DCHECK_EQ(entry->ref(IS_UNAPPLIED_UPDATE), num_erased > 0);
587 num_erased = kernel_->parent_id_child_index->erase(entry); 563 if (ParentChildIndex::ShouldInclude(entry))
588 DCHECK_EQ(entry->ref(IS_DEL), !num_erased); 564 kernel_->parent_child_index->Remove(entry);
589 kernel_->metahandles_index->erase(it++); 565 kernel_->metahandles_index->erase(it++);
590 delete entry; 566 delete entry;
591 } else { 567 } else {
592 ++it; 568 ++it;
593 } 569 }
594 } 570 }
595 571
596 // Ensure meta tracking for these data types reflects the deleted state. 572 // Ensure meta tracking for these data types reflects the deleted state.
597 for (ModelTypeSet::Iterator it = types.First(); 573 for (ModelTypeSet::Iterator it = types.First();
598 it.Good(); it.Inc()) { 574 it.Good(); it.Inc()) {
(...skipping 404 matching lines...) Expand 10 before | Expand all | Expand 10 after
1003 return false; 979 return false;
1004 } 980 }
1005 } 981 }
1006 return true; 982 return true;
1007 } 983 }
1008 984
1009 void Directory::SetInvariantCheckLevel(InvariantCheckLevel check_level) { 985 void Directory::SetInvariantCheckLevel(InvariantCheckLevel check_level) {
1010 invariant_check_level_ = check_level; 986 invariant_check_level_ = check_level;
1011 } 987 }
1012 988
1013 bool Directory::UnlinkEntryFromOrder(EntryKernel* entry,
1014 WriteTransaction* trans,
1015 ScopedKernelLock* lock,
1016 UnlinkReason unlink_reason) {
1017 if (!SyncAssert(!trans || this == trans->directory(),
1018 FROM_HERE,
1019 "Transaction not pointing to the right directory",
1020 trans))
1021 return false;
1022 Id old_previous = entry->ref(PREV_ID);
1023 Id old_next = entry->ref(NEXT_ID);
1024
1025 entry->put(NEXT_ID, entry->ref(ID));
1026 entry->put(PREV_ID, entry->ref(ID));
1027 entry->mark_dirty(kernel_->dirty_metahandles);
1028
1029 if (!old_previous.IsRoot()) {
1030 if (old_previous == old_next) {
1031 // Note previous == next doesn't imply previous == next == Get(ID). We
1032 // could have prev==next=="c-XX" and Get(ID)=="sX..." if an item was added
1033 // and deleted before receiving the server ID in the commit response.
1034 if (!SyncAssert(
1035 (old_next == entry->ref(ID)) || !old_next.ServerKnows(),
1036 FROM_HERE,
1037 "Encounteered inconsistent entry while deleting",
1038 trans)) {
1039 return false;
1040 }
1041 return true; // Done if we were already self-looped (hence unlinked).
1042 }
1043 EntryKernel* previous_entry = GetEntryById(old_previous, lock);
1044 ModelType type = GetModelTypeFromSpecifics(entry->ref(SPECIFICS));
1045 // TODO(tim): Multiple asserts here for bug 101039 investigation.
1046 if (type == AUTOFILL) {
1047 if (!SyncAssert(previous_entry != NULL,
1048 FROM_HERE,
1049 "Could not find previous autofill entry",
1050 trans)) {
1051 return false;
1052 }
1053 } else {
1054 if (!SyncAssert(previous_entry != NULL,
1055 FROM_HERE,
1056 "Could not find previous entry",
1057 trans)) {
1058 return false;
1059 }
1060 }
1061 if (unlink_reason == NODE_MANIPULATION)
1062 trans->SaveOriginal(previous_entry);
1063 previous_entry->put(NEXT_ID, old_next);
1064 previous_entry->mark_dirty(kernel_->dirty_metahandles);
1065 }
1066
1067 if (!old_next.IsRoot()) {
1068 EntryKernel* next_entry = GetEntryById(old_next, lock);
1069 if (!SyncAssert(next_entry != NULL,
1070 FROM_HERE,
1071 "Could not find next entry",
1072 trans)) {
1073 return false;
1074 }
1075 if (unlink_reason == NODE_MANIPULATION)
1076 trans->SaveOriginal(next_entry);
1077 next_entry->put(PREV_ID, old_previous);
1078 next_entry->mark_dirty(kernel_->dirty_metahandles);
1079 }
1080 return true;
1081 }
1082
1083 int64 Directory::NextMetahandle() { 989 int64 Directory::NextMetahandle() {
1084 ScopedKernelLock lock(this); 990 ScopedKernelLock lock(this);
1085 int64 metahandle = (kernel_->next_metahandle)++; 991 int64 metahandle = (kernel_->next_metahandle)++;
1086 return metahandle; 992 return metahandle;
1087 } 993 }
1088 994
1089 // Always returns a client ID that is the string representation of a negative 995 // Always returns a client ID that is a string representation of a negative
1090 // number. 996 // number.
1091 Id Directory::NextId() { 997 Id Directory::NextId() {
1092 int64 result; 998 int64 result;
1093 { 999 {
1094 ScopedKernelLock lock(this); 1000 ScopedKernelLock lock(this);
1095 result = (kernel_->persisted_info.next_id)--; 1001 result = (kernel_->persisted_info.next_id)--;
1096 kernel_->info_status = KERNEL_SHARE_INFO_DIRTY; 1002 kernel_->info_status = KERNEL_SHARE_INFO_DIRTY;
1097 } 1003 }
1098 DCHECK_LT(result, 0); 1004 DCHECK_LT(result, 0);
1099 return Id::CreateFromClientString(base::Int64ToString(result)); 1005 return Id::CreateFromClientString(base::Int64ToString(result));
1100 } 1006 }
1101 1007
1102 bool Directory::HasChildren(BaseTransaction* trans, const Id& id) { 1008 bool Directory::HasChildren(BaseTransaction* trans, const Id& id) {
1103 ScopedKernelLock lock(this); 1009 ScopedKernelLock lock(this);
1104 return (GetPossibleFirstChild(lock, id) != NULL); 1010 return kernel_->parent_child_index->GetChildren(id) != NULL;
1105 } 1011 }
1106 1012
1107 bool Directory::GetFirstChildId(BaseTransaction* trans, 1013 Id Directory::GetFirstChildId(BaseTransaction* trans,
1108 const Id& parent_id, 1014 const EntryKernel* parent) {
1109 Id* first_child_id) { 1015 DCHECK(parent);
1016 DCHECK(parent->ref(IS_DIR));
1017
1110 ScopedKernelLock lock(this); 1018 ScopedKernelLock lock(this);
1111 EntryKernel* entry = GetPossibleFirstChild(lock, parent_id); 1019 const ChildSet* children =
1112 if (!entry) { 1020 kernel_->parent_child_index->GetChildren(parent->ref(ID));
1113 *first_child_id = Id(); 1021
1114 return true; 1022 // We're expected to return root if there are no children.
1023 if (!children)
1024 return Id();
1025
1026 return (*children->begin())->ref(ID);
1027 }
1028
1029 syncable::Id Directory::GetPredecessorId(EntryKernel* e) {
1030 ScopedKernelLock lock(this);
1031
1032 DCHECK(ParentChildIndex::ShouldInclude(e));
1033 const ChildSet* children =
1034 kernel_->parent_child_index->GetChildren(e->ref(PARENT_ID));
1035 DCHECK(children && !children->empty());
1036 ChildSet::const_iterator i = children->find(e);
1037 DCHECK(i != children->end());
1038
1039 if (i == children->begin()) {
1040 return Id();
1041 } else {
1042 i--;
1043 return (*i)->ref(ID);
1044 }
1045 }
1046
1047 syncable::Id Directory::GetSuccessorId(EntryKernel* e) {
1048 ScopedKernelLock lock(this);
1049
1050 DCHECK(ParentChildIndex::ShouldInclude(e));
1051 const ChildSet* children =
1052 kernel_->parent_child_index->GetChildren(e->ref(PARENT_ID));
1053 DCHECK(children && !children->empty());
1054 ChildSet::const_iterator i = children->find(e);
1055 DCHECK(i != children->end());
1056
1057 i++;
1058 if (i == children->end()) {
1059 return Id();
1060 } else {
1061 return (*i)->ref(ID);
1062 }
1063 }
1064
1065 // TODO(rlarocque): Remove all support for placing ShouldMaintainPosition()
1066 // items as siblings of items that do not maintain postions. It is required
1067 // only for tests.
1068 void Directory::PutPredecessor(EntryKernel* e, EntryKernel* predecessor) {
1069 DCHECK(!e->ref(IS_DEL));
1070 if (!ShouldMaintainPosition(GetModelTypeFromSpecifics(e->ref(SPECIFICS)))) {
1071 DCHECK(!e->ref(UNIQUE_POSITION).IsValid());
1072 return;
1073 }
1074 std::string suffix = e->ref(UNIQUE_BOOKMARK_TAG);
1075 DCHECK(!suffix.empty());
1076
1077 // Remove our item from the list and remember to re-add it later.
1078 ScopedKernelLock lock(this);
1079 ScopedParentChildIndexUpdater updater(lock, e, kernel_->parent_child_index);
1080
1081 // Note: The ScopedParentChildIndexUpdater will update this set for us as we
1082 // leave this function.
1083 const ChildSet* children =
1084 kernel_->parent_child_index->GetChildren(e->ref(PARENT_ID));
1085
1086 if (!children) {
1087 // This parent currently has no other children.
1088 DCHECK(predecessor->ref(ID).IsRoot());
1089 UniquePosition pos = UniquePosition::InitialPosition(suffix);
1090 e->put(UNIQUE_POSITION, pos);
1091 return;
1115 } 1092 }
1116 1093
1117 // Walk to the front of the list; the server position ordering 1094 if (predecessor->ref(ID).IsRoot()) {
1118 // is commonly identical to the linked-list ordering, but pending 1095 // We have at least one sibling, and we're inserting to the left of them.
1119 // unsynced or unapplied items may diverge. 1096 UniquePosition successor_pos = (*children->begin())->ref(UNIQUE_POSITION);
1120 while (!entry->ref(PREV_ID).IsRoot()) { 1097
1121 entry = GetEntryById(entry->ref(PREV_ID), &lock); 1098 if (!successor_pos.IsValid()) {
1122 if (!entry) { 1099 // If all our successors are of non-positionable types, just create an
1123 *first_child_id = Id(); 1100 // initial position. We arbitrarily choose to sort invalid positions to
1124 return false; 1101 // the right of the valid positions.
1102 //
1103 // We really shoulndn't need to support this. See TODO above.
1104 UniquePosition pos = UniquePosition::InitialPosition(suffix);
1105 e->put(UNIQUE_POSITION, pos);
1106 return;
1125 } 1107 }
1108
1109 DCHECK(!children->empty());
1110 UniquePosition pos = UniquePosition::Before(successor_pos, suffix);
1111 e->put(UNIQUE_POSITION, pos);
1112 return;
1126 } 1113 }
1127 *first_child_id = entry->ref(ID); 1114
1128 return true; 1115 // We can't support placing an item after an invalid position. Fortunately,
1116 // the tests don't exercise this particular case. We should not support
1117 // siblings with invalid positions at all. See TODO above.
1118 DCHECK(predecessor->ref(UNIQUE_POSITION).IsValid());
1119
1120 ChildSet::iterator i = children->find(predecessor);
1121 DCHECK(i != children->end());
1122
1123 ++i;
1124 if (i == children->end()) {
1125 // Inserting at the end of the list.
1126 UniquePosition pos = UniquePosition::After(
1127 predecessor->ref(UNIQUE_POSITION),
1128 suffix);
1129 e->put(UNIQUE_POSITION, pos);
1130 return;
1131 }
1132
1133 EntryKernel* successor = *i;
1134
1135 // Another mixed valid and invalid position case. This one could be supported
1136 // in theory, but we're trying to deprecate support for siblings with and
1137 // without valid positions. See TODO above.
1138 DCHECK(successor->ref(UNIQUE_POSITION).IsValid());
1139
1140 // Finally, the normal case: inserting between two elements.
1141 UniquePosition pos = UniquePosition::Between(
1142 predecessor->ref(UNIQUE_POSITION),
1143 successor->ref(UNIQUE_POSITION),
1144 suffix);
1145 e->put(UNIQUE_POSITION, pos);
1146 return;
1129 } 1147 }
1130 1148
1131 bool Directory::GetLastChildIdForTest( 1149 // TODO(rlarocque): Avoid this indirection. Just return the set.
1132 BaseTransaction* trans, const Id& parent_id, Id* last_child_id) {
1133 ScopedKernelLock lock(this);
1134 EntryKernel* entry = GetPossibleFirstChild(lock, parent_id);
1135 if (!entry) {
1136 *last_child_id = Id();
1137 return true;
1138 }
1139
1140 // Walk to the back of the list; the server position ordering
1141 // is commonly identical to the linked-list ordering, but pending
1142 // unsynced or unapplied items may diverge.
1143 while (!entry->ref(NEXT_ID).IsRoot()) {
1144 entry = GetEntryById(entry->ref(NEXT_ID), &lock);
1145 if (!entry) {
1146 *last_child_id = Id();
1147 return false;
1148 }
1149 }
1150
1151 *last_child_id = entry->ref(ID);
1152 return true;
1153 }
1154
1155 Id Directory::ComputePrevIdFromServerPosition(
1156 const EntryKernel* entry,
1157 const syncable::Id& parent_id) {
1158 ScopedKernelLock lock(this);
1159
1160 // Find the natural insertion point in the parent_id_child_index, and
1161 // work back from there, filtering out ineligible candidates.
1162 ParentIdChildIndex::iterator sibling = LocateInParentChildIndex(
1163 lock,
1164 parent_id,
1165 NodeOrdinalToInt64(entry->ref(SERVER_ORDINAL_IN_PARENT)),
1166 entry->ref(ID));
1167 ParentIdChildIndex::iterator first_sibling =
1168 GetParentChildIndexLowerBound(lock, parent_id);
1169
1170 while (sibling != first_sibling) {
1171 --sibling;
1172 EntryKernel* candidate = *sibling;
1173
1174 // The item itself should never be in the range under consideration.
1175 DCHECK_NE(candidate->ref(META_HANDLE), entry->ref(META_HANDLE));
1176
1177 // Ignore unapplied updates -- they might not even be server-siblings.
1178 if (candidate->ref(IS_UNAPPLIED_UPDATE))
1179 continue;
1180
1181 // We can't trust the SERVER_ fields of unsynced items, but they are
1182 // potentially legitimate local predecessors. In the case where
1183 // |update_item| and an unsynced item wind up in the same insertion
1184 // position, we need to choose how to order them. The following check puts
1185 // the unapplied update first; removing it would put the unsynced item(s)
1186 // first.
1187 if (candidate->ref(IS_UNSYNCED))
1188 continue;
1189
1190 // Skip over self-looped items, which are not valid predecessors. This
1191 // shouldn't happen in practice, but is worth defending against.
1192 if (candidate->ref(PREV_ID) == candidate->ref(NEXT_ID) &&
1193 !candidate->ref(PREV_ID).IsRoot()) {
1194 NOTREACHED();
1195 continue;
1196 }
1197 return candidate->ref(ID);
1198 }
1199 // This item will be the first in the sibling order.
1200 return Id();
1201 }
1202
1203 Directory::ParentIdChildIndex::iterator Directory::LocateInParentChildIndex(
1204 const ScopedKernelLock& lock,
1205 const Id& parent_id,
1206 int64 position_in_parent,
1207 const Id& item_id_for_tiebreaking) {
1208 kernel_->needle.put(PARENT_ID, parent_id);
1209 kernel_->needle.put(SERVER_ORDINAL_IN_PARENT,
1210 Int64ToNodeOrdinal(position_in_parent));
1211 kernel_->needle.put(ID, item_id_for_tiebreaking);
1212 return kernel_->parent_id_child_index->lower_bound(&kernel_->needle);
1213 }
1214
1215 Directory::ParentIdChildIndex::iterator
1216 Directory::GetParentChildIndexLowerBound(const ScopedKernelLock& lock,
1217 const Id& parent_id) {
1218 // Peg the parent ID, and use the least values for the remaining
1219 // index variables.
1220 return LocateInParentChildIndex(lock, parent_id,
1221 std::numeric_limits<int64>::min(),
1222 Id::GetLeastIdForLexicographicComparison());
1223 }
1224
1225 Directory::ParentIdChildIndex::iterator
1226 Directory::GetParentChildIndexUpperBound(const ScopedKernelLock& lock,
1227 const Id& parent_id) {
1228 // The upper bound of |parent_id|'s range is the lower
1229 // bound of |++parent_id|'s range.
1230 return GetParentChildIndexLowerBound(lock,
1231 parent_id.GetLexicographicSuccessor());
1232 }
1233
1234 void Directory::AppendChildHandles(const ScopedKernelLock& lock, 1150 void Directory::AppendChildHandles(const ScopedKernelLock& lock,
1235 const Id& parent_id, 1151 const Id& parent_id,
1236 Directory::ChildHandles* result) { 1152 Directory::ChildHandles* result) {
1237 typedef ParentIdChildIndex::iterator iterator; 1153 const ChildSet* children =
1238 CHECK(result); 1154 kernel_->parent_child_index->GetChildren(parent_id);
1239 for (iterator i = GetParentChildIndexLowerBound(lock, parent_id), 1155 if (!children)
1240 end = GetParentChildIndexUpperBound(lock, parent_id); 1156 return;
1241 i != end; ++i) { 1157
1158 for (ChildSet::iterator i = children->begin(); i != children->end(); ++i) {
1242 DCHECK_EQ(parent_id, (*i)->ref(PARENT_ID)); 1159 DCHECK_EQ(parent_id, (*i)->ref(PARENT_ID));
1243 result->push_back((*i)->ref(META_HANDLE)); 1160 result->push_back((*i)->ref(META_HANDLE));
1244 } 1161 }
1245 } 1162 }
1246 1163
1247 EntryKernel* Directory::GetPossibleFirstChild(
1248 const ScopedKernelLock& lock, const Id& parent_id) {
1249 // We can use the server positional ordering as a hint because it's generally
1250 // in sync with the local (linked-list) positional ordering, and we have an
1251 // index on it.
1252 ParentIdChildIndex::iterator candidate =
1253 GetParentChildIndexLowerBound(lock, parent_id);
1254 ParentIdChildIndex::iterator end_range =
1255 GetParentChildIndexUpperBound(lock, parent_id);
1256 for (; candidate != end_range; ++candidate) {
1257 EntryKernel* entry = *candidate;
1258 // Filter out self-looped items, which are temporarily not in the child
1259 // ordering.
1260 if (entry->ref(PREV_ID).IsRoot() ||
1261 entry->ref(PREV_ID) != entry->ref(NEXT_ID)) {
1262 return entry;
1263 }
1264 }
1265 // There were no children in the linked list.
1266 return NULL;
1267 }
1268
1269 ScopedKernelLock::ScopedKernelLock(const Directory* dir) 1164 ScopedKernelLock::ScopedKernelLock(const Directory* dir)
1270 : scoped_lock_(dir->kernel_->mutex), dir_(const_cast<Directory*>(dir)) { 1165 : scoped_lock_(dir->kernel_->mutex), dir_(const_cast<Directory*>(dir)) {
1271 } 1166 }
1272 1167
1273 } // namespace syncable 1168 } // namespace syncable
1274 } // namespace syncer 1169 } // namespace syncer
OLDNEW
« no previous file with comments | « sync/syncable/directory.h ('k') | sync/syncable/directory_backing_store.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698