OLD | NEW |
---|---|
(Empty) | |
1 // Copyright 2014 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 "mojo/services/public/cpp/view_manager/lib/view_manager_synchronizer.h" | |
6 | |
7 #include "base/bind.h" | |
8 #include "base/message_loop/message_loop.h" | |
9 #include "mojo/public/cpp/bindings/allocation_scope.h" | |
10 #include "mojo/public/cpp/shell/application.h" | |
11 #include "mojo/public/interfaces/shell/shell.mojom.h" | |
12 #include "mojo/services/public/cpp/view_manager/lib/view_manager_private.h" | |
13 | |
14 namespace mojo { | |
15 namespace services { | |
16 namespace view_manager { | |
17 | |
18 class ViewManagerTransaction { | |
19 public: | |
20 virtual ~ViewManagerTransaction() {} | |
21 | |
22 virtual bool Equals(ViewManagerTransaction* other) { | |
sky
2014/04/28 23:04:19
const ViewManagerTransaction* or const ViewManager
| |
23 return other->type_ == type_; | |
24 } | |
25 | |
26 virtual void Commit() = 0; | |
27 | |
28 bool committed() const { return committed_; } | |
29 int change_id() const { return change_id_; } | |
sky
2014/04/28 23:04:19
uint32_t
| |
30 | |
31 protected: | |
32 enum TransactionType { | |
33 TYPE_CREATE_VIEW_TREE_NODE, | |
34 TYPE_HIERARCHY | |
sky
2014/04/28 23:04:19
Add description for TYPE_HIERARCH as it isn't obvi
| |
35 }; | |
36 | |
37 ViewManagerTransaction(TransactionType type, | |
38 ViewManagerSynchronizer* synchronizer) | |
39 : type_(type), | |
40 change_id_(synchronizer->GetNextChangeId()), | |
41 committed_(false), | |
42 synchronizer_(synchronizer) { | |
43 } | |
44 | |
45 IViewManager* service() { return synchronizer_->service_.get(); } | |
46 | |
47 uint32_t MakeTransportId(uint16_t id) { | |
48 return (synchronizer_->connection_id_ << 16) | id; | |
49 } | |
50 | |
51 int type_; | |
sky
2014/04/28 23:04:19
TransactionType?
sky
2014/04/28 23:04:19
Style guide says no protected members.
| |
52 int change_id_; | |
sky
2014/04/28 23:04:19
Can this be const? And uint32_t.
| |
53 bool committed_; | |
54 ViewManagerSynchronizer* synchronizer_; | |
55 | |
56 private: | |
57 DISALLOW_COPY_AND_ASSIGN(ViewManagerTransaction); | |
58 }; | |
59 | |
60 class CreateViewTreeNodeTransaction | |
61 : public ViewManagerTransaction { | |
62 public: | |
63 CreateViewTreeNodeTransaction(int node_id, | |
64 ViewManagerSynchronizer* synchronizer) | |
65 : ViewManagerTransaction(TYPE_CREATE_VIEW_TREE_NODE, synchronizer), | |
66 node_id_(node_id) {} | |
67 virtual ~CreateViewTreeNodeTransaction() {} | |
68 | |
69 private: | |
70 // Overridden from ViewManagerTransaction: | |
71 virtual bool Equals(ViewManagerTransaction* other) OVERRIDE { | |
72 return ViewManagerTransaction::Equals(other) && | |
73 static_cast<CreateViewTreeNodeTransaction*>(other)->node_id_ == | |
74 node_id_; | |
75 } | |
76 virtual void Commit() OVERRIDE { | |
77 DCHECK(!committed()); | |
sky
2014/04/28 23:04:19
Maybe the DCHECK and boolean should be part of the
| |
78 committed_ = true; | |
79 service()->CreateNode( | |
80 node_id_, | |
81 base::Bind(&CreateViewTreeNodeTransaction::OnActionCompleted, | |
82 base::Unretained(this))); | |
83 } | |
84 | |
85 void OnActionCompleted(bool success) { | |
86 DCHECK(success); | |
87 // TODO(beng): Failure means we tried to create with an extant id for this | |
88 // connection. Figure out what to do. | |
89 } | |
90 | |
91 int node_id_; | |
sky
2014/04/28 23:04:19
uint16_t I believe.
| |
92 | |
93 DISALLOW_COPY_AND_ASSIGN(CreateViewTreeNodeTransaction); | |
94 }; | |
95 | |
96 class HierarchyTransaction : public ViewManagerTransaction { | |
97 public: | |
98 enum HierarchyChangeType { | |
99 TYPE_ADD, | |
100 TYPE_REMOVE | |
101 }; | |
102 HierarchyTransaction(HierarchyChangeType hierarchy_change_type, | |
103 int child_id, | |
104 int parent_id, | |
105 ViewManagerSynchronizer* synchronizer) | |
106 : ViewManagerTransaction(TYPE_HIERARCHY, synchronizer), | |
107 hierarchy_change_type_(hierarchy_change_type), | |
108 child_id_(child_id), | |
109 parent_id_(parent_id) {} | |
110 virtual ~HierarchyTransaction() {} | |
111 | |
112 private: | |
113 // Overridden from ViewManagerTransaction: | |
114 virtual bool Equals(ViewManagerTransaction* other) OVERRIDE { | |
115 if (!ViewManagerTransaction::Equals(other)) | |
116 return false; | |
117 | |
118 HierarchyTransaction* hier_txn = static_cast<HierarchyTransaction*>(other); | |
119 return hier_txn->hierarchy_change_type_ == hierarchy_change_type_ && | |
120 hier_txn->child_id_ == child_id_ && | |
121 hier_txn->parent_id_ == parent_id_; | |
122 } | |
123 virtual void Commit() OVERRIDE { | |
124 DCHECK(!committed()); | |
125 committed_ = true; | |
126 switch (hierarchy_change_type_) { | |
127 case TYPE_ADD: | |
sky
2014/04/28 23:04:19
nit: indentation is off for the switch statement.
| |
128 service()->AddNode(MakeTransportId(parent_id_), | |
129 MakeTransportId(child_id_), | |
130 change_id_, | |
131 base::Bind(&HierarchyTransaction::OnActionCompleted, | |
132 base::Unretained(this))); | |
133 break; | |
134 case TYPE_REMOVE: | |
135 service()->RemoveNodeFromParent( | |
136 MakeTransportId(child_id_), | |
137 change_id_, | |
138 base::Bind(&HierarchyTransaction::OnActionCompleted, | |
139 base::Unretained(this))); | |
140 break; | |
141 default: | |
sky
2014/04/28 23:04:19
You should be able to remove this so that you get
| |
142 NOTREACHED(); | |
143 } | |
144 } | |
145 | |
146 void OnActionCompleted(bool success) { | |
147 DCHECK(success); | |
148 // TODO(beng): Failure means either one of the nodes specified didn't exist, | |
149 // or we passed the same node id for both params. Roll back? | |
150 } | |
151 | |
152 HierarchyChangeType hierarchy_change_type_; | |
sky
2014/04/28 23:04:19
const
| |
153 int child_id_; | |
sky
2014/04/28 23:04:19
uint16_t for both of these.
| |
154 int parent_id_; | |
155 | |
156 DISALLOW_COPY_AND_ASSIGN(HierarchyTransaction); | |
157 }; | |
158 | |
159 ViewManagerSynchronizer::ViewManagerSynchronizer(ViewManager* view_manager) | |
160 : view_manager_(view_manager), | |
161 connected_(false), | |
162 connection_id_(0), | |
163 next_change_id_(0), | |
sky
2014/04/28 23:04:19
order doesn't match header.
| |
164 next_id_(0) { | |
165 InterfacePipe<services::view_manager::IViewManager, AnyInterface> | |
166 view_manager_pipe; | |
167 AllocationScope scope; | |
168 ViewManagerPrivate(view_manager_).application()->shell()->Connect( | |
169 "mojo:mojo_view_manager", view_manager_pipe.handle_to_peer.Pass()); | |
170 service_.reset(view_manager_pipe.handle_to_self.Pass(), this); | |
171 } | |
172 | |
173 ViewManagerSynchronizer::~ViewManagerSynchronizer() { | |
174 } | |
175 | |
176 int ViewManagerSynchronizer::CreateViewTreeNode() { | |
177 int id = next_id_++; | |
178 pending_transactions_.push_back(new CreateViewTreeNodeTransaction(id, this)); | |
179 ScheduleSync(); | |
180 return id; | |
181 } | |
182 | |
183 void ViewManagerSynchronizer::AddChild(int child_id, int parent_id) { | |
184 pending_transactions_.push_back( | |
185 new HierarchyTransaction(HierarchyTransaction::TYPE_ADD, | |
186 child_id, | |
187 parent_id, | |
188 this)); | |
189 ScheduleSync(); | |
190 } | |
191 | |
192 void ViewManagerSynchronizer::RemoveChild(int child_id, int parent_id) { | |
193 pending_transactions_.push_back( | |
194 new HierarchyTransaction(HierarchyTransaction::TYPE_REMOVE, | |
195 child_id, | |
196 parent_id, | |
197 this)); | |
198 ScheduleSync(); | |
199 } | |
200 | |
201 //////////////////////////////////////////////////////////////////////////////// | |
202 // ViewManagerSynchronizer, IViewManagerClient implementation: | |
203 | |
204 void ViewManagerSynchronizer::OnConnectionEstablished(uint16 connection_id) { | |
205 connected_ = true; | |
206 connection_id_ = connection_id; | |
207 ScheduleSync(); | |
208 } | |
209 | |
210 void ViewManagerSynchronizer::OnNodeHierarchyChanged(uint32 node, | |
211 uint32 new_parent, | |
212 uint32 old_parent, | |
213 int32 change_id) { | |
214 // The service will still notify us about changes made from this connection, | |
215 // but we use our transaction queue as a record of what those changes were. | |
216 // We use this ack as an opportunity to remove these entries from our queue. | |
217 // Non-zero change_id is the service's way of telling us the change originated | |
218 // from this connection. | |
219 if (RemovedFromPendingQueue(change_id)) | |
sky
2014/04/28 23:04:19
One problematic area is if a transaction generates
Ben Goodger (Google)
2014/04/29 00:00:54
Hrm and probably for nested hiers.
| |
220 return; | |
221 | |
222 if (change_id == 0) { | |
223 // TODO(beng): Apply changes from another client. | |
224 } | |
225 | |
226 // TODO(beng): possible that changes from this client are never ack'ed? e.g. | |
227 // node creates are treated as txns & there is no ack. | |
228 } | |
229 | |
230 void ViewManagerSynchronizer::OnNodeViewReplaced(uint32_t node, | |
231 uint32_t new_view_id, | |
232 uint32_t old_view_id, | |
233 int32_t change_id) { | |
234 // .. | |
235 } | |
236 | |
237 //////////////////////////////////////////////////////////////////////////////// | |
238 // ViewManagerSynchronizer, private: | |
239 | |
240 void ViewManagerSynchronizer::ScheduleSync() { | |
241 base::MessageLoop::current()->PostTask( | |
242 FROM_HERE, | |
243 base::Bind(&ViewManagerSynchronizer::DoSync, base::Unretained(this))); | |
244 } | |
245 | |
246 void ViewManagerSynchronizer::DoSync() { | |
247 // The service connection may not be set up yet. OnConnectionEstablished() | |
248 // will schedule another sync when it is. | |
249 if (!connected_) | |
250 return; | |
251 | |
252 Transactions::const_iterator it = pending_transactions_.begin(); | |
253 for (; it != pending_transactions_.end(); ++it) { | |
254 if (!(*it)->committed()) | |
255 (*it)->Commit(); | |
256 } | |
257 } | |
258 | |
259 int ViewManagerSynchronizer::GetNextChangeId() { | |
260 // TODO(beng): update once change id becomes uint. | |
261 // TODO(beng): deal with change id collisions? Important in the "never ack'ed | |
262 // change" case mentioned in OnNodeHierarchyChanged(). | |
263 // "0" is a special value passed to other connected clients, so we can't use | |
264 // it. | |
265 next_change_id_ = std::max(1, ++next_change_id_); | |
266 return next_change_id_; | |
267 } | |
268 | |
269 bool ViewManagerSynchronizer::RemovedFromPendingQueue(int change_id) { | |
270 if (change_id != 0) { | |
271 Transactions::iterator it = pending_transactions_.begin(); | |
sky
2014/04/28 23:04:19
I think you should only have to check the first tr
Ben Goodger (Google)
2014/04/29 00:00:54
Not quite. I currently have transactions for node
| |
272 for (; it != pending_transactions_.end(); ++it) { | |
273 if ((*it)->change_id() == change_id) { | |
274 pending_transactions_.erase(it); | |
275 return true; | |
276 } | |
277 } | |
278 } | |
279 return false; | |
280 } | |
281 | |
282 } // namespace view_manager | |
283 } // namespace services | |
284 } // namespace mojo | |
OLD | NEW |