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

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

Issue 2168273002: [Sync] Fix behavior when there are two type roots for a type (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Self review Created 4 years, 5 months 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
« no previous file with comments | « sync/syncable/parent_child_index.h ('k') | sync/syncable/parent_child_index_unittest.cc » ('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/parent_child_index.h" 5 #include "sync/syncable/parent_child_index.h"
6 6
7 #include <memory>
8
7 #include "base/stl_util.h" 9 #include "base/stl_util.h"
8
9 #include "sync/syncable/entry_kernel.h" 10 #include "sync/syncable/entry_kernel.h"
10 #include "sync/syncable/syncable_id.h" 11 #include "sync/syncable/syncable_id.h"
11 12
12 namespace syncer { 13 namespace syncer {
13 namespace syncable { 14 namespace syncable {
14 15
15 bool ChildComparator::operator()(const EntryKernel* a, 16 bool ChildComparator::operator()(const EntryKernel* a,
16 const EntryKernel* b) const { 17 const EntryKernel* b) const {
17 const UniquePosition& a_pos = a->ref(UNIQUE_POSITION); 18 const UniquePosition& a_pos = a->ref(UNIQUE_POSITION);
18 const UniquePosition& b_pos = b->ref(UNIQUE_POSITION); 19 const UniquePosition& b_pos = b->ref(UNIQUE_POSITION);
(...skipping 19 matching lines...) Expand all
38 return a->ref(META_HANDLE) < b->ref(META_HANDLE); 39 return a->ref(META_HANDLE) < b->ref(META_HANDLE);
39 } 40 }
40 } 41 }
41 42
42 ParentChildIndex::ParentChildIndex() { 43 ParentChildIndex::ParentChildIndex() {
43 // Pre-allocate these two vectors to the number of model types. 44 // Pre-allocate these two vectors to the number of model types.
44 model_type_root_ids_.resize(MODEL_TYPE_COUNT); 45 model_type_root_ids_.resize(MODEL_TYPE_COUNT);
45 type_root_child_sets_.resize(MODEL_TYPE_COUNT); 46 type_root_child_sets_.resize(MODEL_TYPE_COUNT);
46 } 47 }
47 48
48 ParentChildIndex::~ParentChildIndex() { 49 ParentChildIndex::~ParentChildIndex() {}
49 for (int i = 0; i < MODEL_TYPE_COUNT; i++) {
50 // Normally all OrderedChildSet instances in |type_root_child_sets_|
51 // are shared with |parent_children_map_|. Null out shared instances and
52 // ScopedVector will take care of the ones that are not shared (if any).
53 if (!model_type_root_ids_[i].IsNull()) {
54 DCHECK_EQ(type_root_child_sets_[i],
55 parent_children_map_.find(model_type_root_ids_[i])->second);
56 type_root_child_sets_[i] = nullptr;
57 }
58 }
59
60 STLDeleteContainerPairSecondPointers(parent_children_map_.begin(),
61 parent_children_map_.end());
62 }
63 50
64 bool ParentChildIndex::ShouldInclude(const EntryKernel* entry) { 51 bool ParentChildIndex::ShouldInclude(const EntryKernel* entry) {
65 // This index excludes deleted items and the root item. The root 52 // 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. 53 // item is excluded so that it doesn't show up as a child of itself.
67 return !entry->ref(IS_DEL) && !entry->ref(ID).IsRoot(); 54 return !entry->ref(IS_DEL) && !entry->ref(ID).IsRoot();
68 } 55 }
69 56
70 bool ParentChildIndex::Insert(EntryKernel* entry) { 57 bool ParentChildIndex::Insert(EntryKernel* entry) {
71 DCHECK(ShouldInclude(entry)); 58 DCHECK(ShouldInclude(entry));
72 59
73 OrderedChildSet* siblings = nullptr; 60 OrderedChildSetRef siblings = nullptr;
74 const Id& parent_id = entry->ref(PARENT_ID); 61 const Id& parent_id = entry->ref(PARENT_ID);
75 ModelType model_type = entry->GetModelType(); 62 ModelType model_type = entry->GetModelType();
76 63
77 if (ShouldUseParentId(parent_id, model_type)) { 64 if (ShouldUseParentId(parent_id, model_type)) {
78 // Hierarchical type, lookup child set in the map. 65 // Hierarchical type, lookup child set in the map.
79 DCHECK(!parent_id.IsNull()); 66 DCHECK(!parent_id.IsNull());
80 ParentChildrenMap::iterator it = parent_children_map_.find(parent_id); 67 ParentChildrenMap::iterator it = parent_children_map_.find(parent_id);
81 if (it != parent_children_map_.end()) { 68 if (it != parent_children_map_.end()) {
82 siblings = it->second; 69 siblings = it->second;
83 } else { 70 } else {
84 siblings = new OrderedChildSet(); 71 siblings = OrderedChildSetRef(new OrderedChildSet());
85 parent_children_map_.insert(std::make_pair(parent_id, siblings)); 72 parent_children_map_.insert(std::make_pair(parent_id, siblings));
86 } 73 }
87 } else { 74 } else {
88 // Non-hierarchical type, return a pre-defined collection by type. 75 // Non-hierarchical type, return a pre-defined collection by type.
89 siblings = GetOrCreateModelTypeChildSet(model_type); 76 siblings = GetOrCreateModelTypeChildSet(model_type);
90 } 77 }
91 78
92 // If this is one of type root folder for a non-hierarchical type, associate 79 // If this is one of type root folder for a non-hierarchical type, associate
93 // its ID with the model type and the type's pre-defined child set with the 80 // its ID with the model type and the type's pre-defined child set with the
94 // type root ID. 81 // type root ID.
95 // TODO(stanisc): crbug/438313: Just TypeSupportsHierarchy condition should 82 // TODO(stanisc): crbug/438313: Just TypeSupportsHierarchy condition should
96 // theoretically be sufficient but in practice many tests don't properly 83 // theoretically be sufficient but in practice many tests don't properly
97 // initialize entries so TypeSupportsHierarchy ends up failing. Consider 84 // initialize entries so TypeSupportsHierarchy ends up failing. Consider
98 // tweaking TypeSupportsHierarchy and fixing all related test code. 85 // tweaking TypeSupportsHierarchy and fixing all related test code.
99 if (parent_id.IsRoot() && entry->ref(IS_DIR) && 86 if (parent_id.IsRoot() && entry->ref(IS_DIR) &&
100 syncer::IsRealDataType(model_type) && 87 syncer::IsRealDataType(model_type) &&
101 !TypeSupportsHierarchy(model_type)) { 88 !TypeSupportsHierarchy(model_type)) {
102 const Id& type_root_id = entry->ref(ID); 89 const Id& type_root_id = entry->ref(ID);
103 // Disassociate the type root child set with the previous ID if any. 90
104 const Id& prev_type_root_id = model_type_root_ids_[model_type]; 91 // If the entry exists in the map it must already have the same
105 if (!prev_type_root_id.IsNull()) { 92 // model type specific child set. We don't know if the old id is still
106 ParentChildrenMap::iterator it = 93 // in use, so we keep it in the parent_children_map_.
Patrick Noland 2016/07/22 22:08:02 This comment is kind of confusing without the cont
stanisc 2016/07/22 22:17:29 Just to make sure if I understand this correctly.
Nicolas Zea 2016/07/22 23:10:50 That's correct. Also updated the comment based on
107 parent_children_map_.find(prev_type_root_id);
108 if (it != parent_children_map_.end()) {
109 // If the entry exists in the map it must already have the same
110 // model type specific child set. This child set will be re-inserted
111 // in the map under the new ID below so it is safe to simply erase
112 // the entry here.
113 DCHECK_EQ(it->second, GetModelTypeChildSet(model_type));
114 parent_children_map_.erase(it);
115 }
116 }
117 // Store the new type root ID and associate the child set. 94 // Store the new type root ID and associate the child set.
118 // Note that the child set isn't owned by the map in this case.
119 model_type_root_ids_[model_type] = type_root_id; 95 model_type_root_ids_[model_type] = type_root_id;
120 parent_children_map_.insert( 96 parent_children_map_.insert(std::make_pair(
121 std::make_pair(type_root_id, GetOrCreateModelTypeChildSet(model_type))); 97 type_root_id, GetOrCreateModelTypeChildSet(model_type)));
122 } 98 }
123 99
124 // Finally, insert the entry in the child set. 100 // Finally, insert the entry in the child set.
125 return siblings->insert(entry).second; 101 return siblings->insert(entry).second;
126 } 102 }
127 103
128 // Like the other containers used to help support the syncable::Directory, this 104 // Like the other containers used to help support the syncable::Directory, this
129 // one does not own any EntryKernels. This function removes references to the 105 // one does not own any EntryKernels. This function removes references to the
130 // given EntryKernel but does not delete it. 106 // given EntryKernel but does not delete it.
131 void ParentChildIndex::Remove(EntryKernel* e) { 107 void ParentChildIndex::Remove(EntryKernel* e) {
132 OrderedChildSet* siblings = nullptr; 108 OrderedChildSetRef siblings = nullptr;
133 ModelType model_type = e->GetModelType(); 109 ModelType model_type = e->GetModelType();
134 const Id& parent_id = e->ref(PARENT_ID); 110 const Id& parent_id = e->ref(PARENT_ID);
135 bool should_erase = false; 111 bool should_erase = false;
136 ParentChildrenMap::iterator it; 112 ParentChildrenMap::iterator sibling_iterator;
137 113
138 if (ShouldUseParentId(parent_id, model_type)) { 114 if (ShouldUseParentId(parent_id, model_type)) {
139 // Hierarchical type, lookup child set in the map. 115 // Hierarchical type, lookup child set in the map.
140 DCHECK(!parent_id.IsNull()); 116 DCHECK(!parent_id.IsNull());
141 it = parent_children_map_.find(parent_id); 117 sibling_iterator = parent_children_map_.find(parent_id);
142 DCHECK(it != parent_children_map_.end()); 118 DCHECK(sibling_iterator != parent_children_map_.end());
143 siblings = it->second; 119 siblings = sibling_iterator->second;
144 should_erase = true; 120 should_erase = true;
145 } else { 121 } else {
146 // Non-hierarchical type, return a pre-defined child set by type. 122 // Non-hierarchical type, return a pre-defined child set by type.
147 siblings = type_root_child_sets_[model_type]; 123 siblings = type_root_child_sets_[model_type];
148 } 124 }
149 125
150 OrderedChildSet::iterator j = siblings->find(e); 126 OrderedChildSet::iterator j = siblings->find(e);
151 DCHECK(j != siblings->end()); 127 DCHECK(j != siblings->end());
152 128
153 // Erase the entry from the child set. 129 // Erase the entry from the child set.
154 siblings->erase(j); 130 siblings->erase(j);
155 // If the set is now empty and isn't shareable with |type_root_child_sets_|, 131 // If the set is now empty and isn't shareable with |type_root_child_sets_|,
156 // erase it from the map. 132 // erase it from the map.
157 if (siblings->empty() && should_erase) { 133 if (siblings->empty() && should_erase) {
158 delete siblings; 134 parent_children_map_.erase(sibling_iterator);
159 parent_children_map_.erase(it);
160 } 135 }
161 } 136 }
162 137
163 bool ParentChildIndex::Contains(EntryKernel *e) const { 138 bool ParentChildIndex::Contains(EntryKernel *e) const {
164 const OrderedChildSet* siblings = GetChildSet(e); 139 const OrderedChildSetRef siblings = GetChildSet(e);
165 return siblings && siblings->count(e) > 0; 140 return siblings && siblings->count(e) > 0;
166 } 141 }
167 142
168 const OrderedChildSet* ParentChildIndex::GetChildren(const Id& id) const { 143 const OrderedChildSet* ParentChildIndex::GetChildren(const Id& id) const {
169 DCHECK(!id.IsNull()); 144 DCHECK(!id.IsNull());
170 145
171 ParentChildrenMap::const_iterator parent = parent_children_map_.find(id); 146 ParentChildrenMap::const_iterator parent = parent_children_map_.find(id);
172 if (parent == parent_children_map_.end()) { 147 if (parent == parent_children_map_.end()) {
173 return nullptr; 148 return nullptr;
174 } 149 }
175 150
176 OrderedChildSet* children = parent->second; 151 OrderedChildSetRef children = parent->second;
177 // The expectation is that the function returns nullptr instead of an empty 152 // The expectation is that the function returns nullptr instead of an empty
178 // child set 153 // child set
179 if (children && children->empty()) 154 if (children && children->empty())
180 children = nullptr; 155 children = nullptr;
181 return children; 156 return children.get();
182 } 157 }
183 158
184 const OrderedChildSet* ParentChildIndex::GetChildren(EntryKernel* e) const { 159 const OrderedChildSet* ParentChildIndex::GetChildren(EntryKernel* e) const {
185 return GetChildren(e->ref(ID)); 160 return GetChildren(e->ref(ID));
186 } 161 }
187 162
188 const OrderedChildSet* ParentChildIndex::GetSiblings(EntryKernel* e) const { 163 const OrderedChildSet* ParentChildIndex::GetSiblings(EntryKernel* e) const {
189 // This implies the entry is in the index. 164 // This implies the entry is in the index.
190 DCHECK(Contains(e)); 165 DCHECK(Contains(e));
191 const OrderedChildSet* siblings = GetChildSet(e); 166 const OrderedChildSetRef siblings = GetChildSet(e);
192 DCHECK(siblings && !siblings->empty()); 167 DCHECK(siblings && !siblings->empty());
193 return siblings; 168 return siblings.get();
194 } 169 }
195 170
196 /* static */ 171 /* static */
197 bool ParentChildIndex::ShouldUseParentId(const Id& parent_id, 172 bool ParentChildIndex::ShouldUseParentId(const Id& parent_id,
198 ModelType model_type) { 173 ModelType model_type) {
199 // For compatibility with legacy unit tests, in addition to hierarchical 174 // For compatibility with legacy unit tests, in addition to hierarchical
200 // entries, this returns true any entries directly under root and for entries 175 // entries, this returns true any entries directly under root and for entries
201 // of UNSPECIFIED model type. 176 // of UNSPECIFIED model type.
202 return parent_id.IsRoot() || TypeSupportsHierarchy(model_type) || 177 return parent_id.IsRoot() || TypeSupportsHierarchy(model_type) ||
203 !syncer::IsRealDataType(model_type); 178 !syncer::IsRealDataType(model_type);
204 } 179 }
205 180
206 const OrderedChildSet* ParentChildIndex::GetChildSet(EntryKernel* e) const { 181 const OrderedChildSetRef ParentChildIndex::GetChildSet(EntryKernel* e) const {
207 ModelType model_type = e->GetModelType(); 182 ModelType model_type = e->GetModelType();
208 183
209 const Id& parent_id = e->ref(PARENT_ID); 184 const Id& parent_id = e->ref(PARENT_ID);
210 if (ShouldUseParentId(parent_id, model_type)) { 185 if (ShouldUseParentId(parent_id, model_type)) {
211 // Hierarchical type, lookup child set in the map. 186 // Hierarchical type, lookup child set in the map.
212 ParentChildrenMap::const_iterator it = parent_children_map_.find(parent_id); 187 ParentChildrenMap::const_iterator it = parent_children_map_.find(parent_id);
213 if (it == parent_children_map_.end()) 188 if (it == parent_children_map_.end())
214 return nullptr; 189 return nullptr;
215 return it->second; 190 return it->second;
216 } 191 }
217 192
218 // Non-hierarchical type, return a collection indexed by type. 193 // Non-hierarchical type, return a collection indexed by type.
219 return GetModelTypeChildSet(model_type); 194 return GetModelTypeChildSet(model_type);
220 } 195 }
221 196
222 const OrderedChildSet* ParentChildIndex::GetModelTypeChildSet( 197 const OrderedChildSetRef ParentChildIndex::GetModelTypeChildSet(
223 ModelType model_type) const { 198 ModelType model_type) const {
224 return type_root_child_sets_[model_type]; 199 return type_root_child_sets_[model_type];
225 } 200 }
226 201
227 OrderedChildSet* ParentChildIndex::GetOrCreateModelTypeChildSet( 202 OrderedChildSetRef ParentChildIndex::GetOrCreateModelTypeChildSet(
228 ModelType model_type) { 203 ModelType model_type) {
229 if (!type_root_child_sets_[model_type]) 204 if (!type_root_child_sets_[model_type])
230 type_root_child_sets_[model_type] = new OrderedChildSet(); 205 type_root_child_sets_[model_type] =
206 OrderedChildSetRef(new OrderedChildSet());
231 return type_root_child_sets_[model_type]; 207 return type_root_child_sets_[model_type];
232 } 208 }
233 209
234 const Id& ParentChildIndex::GetModelTypeRootId(ModelType model_type) const { 210 const Id& ParentChildIndex::GetModelTypeRootId(ModelType model_type) const {
235 return model_type_root_ids_[model_type]; 211 return model_type_root_ids_[model_type];
236 } 212 }
237 213
238 } // namespace syncable 214 } // namespace syncable
239 } // namespace syncer 215 } // namespace syncer
OLDNEW
« no previous file with comments | « sync/syncable/parent_child_index.h ('k') | sync/syncable/parent_child_index_unittest.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698