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

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

Issue 1226213002: Sync: Support nodes with implicit permanent folders: Node Browser and out-of-order loading from DB (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Fixed memory leak Created 5 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
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 "base/stl_util.h" 7 #include "base/stl_util.h"
8 8
9 #include "sync/syncable/entry_kernel.h" 9 #include "sync/syncable/entry_kernel.h"
10 #include "sync/syncable/syncable_id.h" 10 #include "sync/syncable/syncable_id.h"
(...skipping 25 matching lines...) Expand all
36 DCHECK(!b->ref(UNIQUE_POSITION).IsValid()); 36 DCHECK(!b->ref(UNIQUE_POSITION).IsValid());
37 // Sort by META_HANDLE to ensure consistent order for testing. 37 // Sort by META_HANDLE to ensure consistent order for testing.
38 return a->ref(META_HANDLE) < b->ref(META_HANDLE); 38 return a->ref(META_HANDLE) < b->ref(META_HANDLE);
39 } 39 }
40 } 40 }
41 41
42 ParentChildIndex::ParentChildIndex() { 42 ParentChildIndex::ParentChildIndex() {
43 } 43 }
44 44
45 ParentChildIndex::~ParentChildIndex() { 45 ParentChildIndex::~ParentChildIndex() {
46 STLDeleteContainerPairSecondPointers( 46 for (ParentChildrenMap::iterator it = parent_children_map_.begin();
47 parent_children_map_.begin(), parent_children_map_.end()); 47 it != parent_children_map_.end(); ++it) {
48 if (it->second.owned()) {
49 delete it->second.child_set();
50 }
51 }
48 } 52 }
49 53
50 bool ParentChildIndex::ShouldInclude(const EntryKernel* entry) { 54 bool ParentChildIndex::ShouldInclude(const EntryKernel* entry) {
51 // This index excludes deleted items and the root item. The root 55 // This index excludes deleted items and the root item. The root
52 // item is excluded so that it doesn't show up as a child of itself. 56 // item is excluded so that it doesn't show up as a child of itself.
53 return !entry->ref(IS_DEL) && !entry->ref(ID).IsRoot(); 57 // The index also excludes items without client data e.g. the items
58 // that don't have client SPECIFICS or PARENT_ID. There is no need to
59 // include server-only entries because they shouldn't show up on the client
Nicolas Zea 2015/07/09 20:36:34 nit: "on the client until they're applied."
stanisc 2015/07/09 23:59:27 Done.
60 return !entry->ref(IS_DEL) && !entry->ref(ID).IsRoot() &&
61 (entry->GetModelType() != UNSPECIFIED ||
62 !entry->ref(PARENT_ID).IsNull());
54 } 63 }
55 64
56 bool ParentChildIndex::Insert(EntryKernel* entry) { 65 bool ParentChildIndex::Insert(EntryKernel* entry) {
57 DCHECK(ShouldInclude(entry)); 66 DCHECK(ShouldInclude(entry));
58 67
59 const Id& parent_id = GetParentId(entry); 68 OrderedChildSet* children = nullptr;
Nicolas Zea 2015/07/09 20:36:34 nit: children here implies to me that they're chil
stanisc 2015/07/09 23:59:27 Done.
60 // Store type root ID when inserting a type root entry. 69 const Id& parent_id = entry->ref(PARENT_ID);
61 if (parent_id.IsRoot()) { 70 ModelType model_type = entry->GetModelType();
62 ModelType model_type = GetModelType(entry); 71
63 // TODO(stanisc): there are some unit tests that create entries 72 if (ShouldUseParentId(parent_id, model_type)) {
64 // at the root and don't bother initializing specifics which 73 // Hierarchical type, lookup child set in the map.
65 // produces TOP_LEVEL_FOLDER type here. 74 DCHECK(!parent_id.IsNull());
66 if (syncer::IsRealDataType(model_type)) { 75 ParentChildrenMap::iterator it = parent_children_map_.find(parent_id);
67 model_type_root_ids_[model_type] = entry->ref(ID); 76 if (it != parent_children_map_.end()) {
77 children = it->second.child_set();
68 } 78 }
79 } else {
80 // Non-hierarchical type, return a pre-defined collection by type.
81 children = &type_root_child_sets_[model_type];
69 } 82 }
70 83
71 OrderedChildSet* children = NULL; 84 if (!children) {
72 ParentChildrenMap::iterator i = parent_children_map_.find(parent_id); 85 DCHECK(!parent_id.IsNull());
73 if (i != parent_children_map_.end()) {
74 children = i->second;
75 } else {
76 children = new OrderedChildSet(); 86 children = new OrderedChildSet();
77 parent_children_map_.insert(std::make_pair(parent_id, children)); 87 InsertChildSet(parent_id, ChildSetEntry(children, true));
78 } 88 }
79 89
90 // If this is one of type root folder for a non-hierarchical type, associate
91 // its ID with the model type and the type's pre-defined child set with the
92 // type root ID.
93 if (parent_id.IsRoot() && entry->ref(IS_DIR) &&
94 syncer::IsRealDataType(model_type) &&
95 !TypeSupportsHierarchy(model_type)) {
Nicolas Zea 2015/07/09 20:36:34 Isn't TypeSupportsHierarchy a sufficient condition
stanisc 2015/07/09 21:45:17 Since the condition is "not TypeSupportsHierarchy"
stanisc 2015/07/09 23:59:27 Discussed. Added TODO.
96 const Id& type_root_id = entry->ref(ID);
97 // Disassociate the type root child set with the previous ID if any.
98 const Id& prev_type_root_id = model_type_root_ids_[model_type];
99 if (!prev_type_root_id.IsNull()) {
100 ParentChildrenMap::iterator it =
101 parent_children_map_.find(prev_type_root_id);
102 if (it != parent_children_map_.end()) {
103 // If the entry exists in the map it must already have the same
104 // model type specific child set and now own it. In this case
stanisc 2015/07/09 20:33:48 "now own" -> "not own"
stanisc 2015/07/09 23:59:27 Done.
105 // it should be safe to simply remove the entry.
106 DCHECK(!it->second.owned());
107 DCHECK_EQ(it->second.child_set(), &type_root_child_sets_[model_type]);
108 parent_children_map_.erase(it);
109 }
110 }
111 // Store the new type root ID and associate the child set.
112 // Note that the child set isn't owned by the map in this case.
113 model_type_root_ids_[model_type] = type_root_id;
114 InsertChildSet(type_root_id,
115 ChildSetEntry(&type_root_child_sets_[model_type], false));
116 }
117
118 // Finally, insert the entry in the child set.
80 return children->insert(entry).second; 119 return children->insert(entry).second;
81 } 120 }
82 121
83 // Like the other containers used to help support the syncable::Directory, this 122 // Like the other containers used to help support the syncable::Directory, this
84 // one does not own any EntryKernels. This function removes references to the 123 // one does not own any EntryKernels. This function removes references to the
85 // given EntryKernel but does not delete it. 124 // given EntryKernel but does not delete it.
86 void ParentChildIndex::Remove(EntryKernel* e) { 125 void ParentChildIndex::Remove(EntryKernel* e) {
87 const Id& parent_id = GetParentId(e); 126 OrderedChildSet* children = nullptr;
127 ModelType model_type = e->GetModelType();
128 const Id& parent_id = e->ref(PARENT_ID);
129 bool is_owned = false;
130 ParentChildrenMap::iterator it;
88 131
89 ParentChildrenMap::iterator parent = parent_children_map_.find(parent_id); 132 if (ShouldUseParentId(parent_id, model_type)) {
90 DCHECK(parent != parent_children_map_.end()); 133 // Hierarchical type, lookup child set in the map.
134 DCHECK(!parent_id.IsNull());
135 it = parent_children_map_.find(parent_id);
136 DCHECK(it != parent_children_map_.end());
137 children = it->second.child_set();
138 is_owned = it->second.owned();
139 } else {
140 // Non-hierarchical type, return a pre-defined child set by type.
141 children = &type_root_child_sets_[model_type];
142 }
91 143
92 OrderedChildSet* children = parent->second;
93 OrderedChildSet::iterator j = children->find(e); 144 OrderedChildSet::iterator j = children->find(e);
94 DCHECK(j != children->end()); 145 DCHECK(j != children->end());
95 146
147 // Erase the entry from the child set.
96 children->erase(j); 148 children->erase(j);
97 if (children->empty()) { 149 // If the set is now empty and is owned by the map, erase it from the map.
150 if (children->empty() && is_owned) {
98 delete children; 151 delete children;
99 parent_children_map_.erase(parent); 152 parent_children_map_.erase(it);
100 } 153 }
101 } 154 }
102 155
103 bool ParentChildIndex::Contains(EntryKernel *e) const { 156 bool ParentChildIndex::Contains(EntryKernel *e) const {
104 const Id& parent_id = GetParentId(e); 157 const OrderedChildSet* children = GetChildSet(e);
105 ParentChildrenMap::const_iterator parent = 158 return children && children->count(e) > 0;
106 parent_children_map_.find(parent_id);
107 if (parent == parent_children_map_.end()) {
108 return false;
109 }
110 const OrderedChildSet* children = parent->second;
111 DCHECK(children && !children->empty());
112 return children->count(e) > 0;
113 } 159 }
114 160
115 const OrderedChildSet* ParentChildIndex::GetChildren(const Id& id) const { 161 const OrderedChildSet* ParentChildIndex::GetChildren(const Id& id) const {
116 DCHECK(!id.IsNull()); 162 DCHECK(!id.IsNull());
117 163
118 ParentChildrenMap::const_iterator parent = parent_children_map_.find(id); 164 ParentChildrenMap::const_iterator parent = parent_children_map_.find(id);
119 if (parent == parent_children_map_.end()) { 165 if (parent == parent_children_map_.end()) {
120 return nullptr; 166 return nullptr;
121 } 167 }
122 168
123 // A successful lookup implies at least some children exist. 169 OrderedChildSet* children = parent->second.child_set();
124 DCHECK(!parent->second->empty()); 170 // The expectation is that the function returns nullptr instead of an empty
125 return parent->second; 171 // child set
172 if (children && children->empty())
173 children = nullptr;
174 return children;
126 } 175 }
127 176
128 const OrderedChildSet* ParentChildIndex::GetChildren(EntryKernel* e) const { 177 const OrderedChildSet* ParentChildIndex::GetChildren(EntryKernel* e) const {
129 return GetChildren(e->ref(ID)); 178 return GetChildren(e->ref(ID));
130 } 179 }
131 180
132 const OrderedChildSet* ParentChildIndex::GetSiblings(EntryKernel* e) const { 181 const OrderedChildSet* ParentChildIndex::GetSiblings(EntryKernel* e) const {
182 // This implies the entry is in the index.
133 DCHECK(Contains(e)); 183 DCHECK(Contains(e));
134 const OrderedChildSet* siblings = GetChildren(GetParentId(e)); 184 const OrderedChildSet* siblings = GetChildSet(e);
135 DCHECK(siblings && !siblings->empty()); 185 DCHECK(siblings && !siblings->empty());
136 return siblings; 186 return siblings;
137 } 187 }
138 188
139 const Id& ParentChildIndex::GetParentId(EntryKernel* e) const { 189 /* static */
140 const Id& parent_id = e->ref(PARENT_ID); 190 bool ParentChildIndex::ShouldUseParentId(const Id& parent_id,
141 if (!parent_id.IsNull()) { 191 ModelType model_type) {
142 return parent_id; 192 // Returns true for compatibility with legacy unit tests.
143 } 193 return parent_id.IsRoot() || TypeSupportsHierarchy(model_type) ||
144 return GetModelTypeRootId(GetModelType(e)); 194 !syncer::IsRealDataType(model_type);
145 } 195 }
146 196
147 ModelType ParentChildIndex::GetModelType(EntryKernel* e) { 197 const OrderedChildSet* ParentChildIndex::GetChildSet(EntryKernel* e) const {
148 // TODO(stanisc): is there a more effective way to find out model type?
149 ModelType model_type = e->GetModelType(); 198 ModelType model_type = e->GetModelType();
150 if (!syncer::IsRealDataType(model_type)) { 199
151 model_type = e->GetServerModelType(); 200 const Id& parent_id = e->ref(PARENT_ID);
201 if (ShouldUseParentId(parent_id, model_type)) {
202 // Hierarchical type, lookup child set in the map.
203 ParentChildrenMap::const_iterator it = parent_children_map_.find(parent_id);
204 if (it != parent_children_map_.end()) {
205 return it->second.child_set();
206 }
207 } else {
208 // Non-hierarchical type, return a pre-defined collection by type.
209 return &type_root_child_sets_[model_type];
152 } 210 }
153 return model_type; 211
212 return nullptr;
213 }
214
215 void ParentChildIndex::InsertChildSet(const Id& id,
216 const ChildSetEntry& entry) {
217 parent_children_map_.insert(std::make_pair(id, entry));
154 } 218 }
155 219
156 const Id& ParentChildIndex::GetModelTypeRootId(ModelType model_type) const { 220 const Id& ParentChildIndex::GetModelTypeRootId(ModelType model_type) const {
157 // TODO(stanisc): Review whether this approach is reliable enough.
158 // Should this method simply enumerate children of root node ("r") instead?
159 return model_type_root_ids_[model_type]; 221 return model_type_root_ids_[model_type];
160 } 222 }
161 223
162 } // namespace syncable 224 } // namespace syncable
163 } // namespace syncer 225 } // namespace syncer
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698