Line data Source code
1 :
2 : /* Copyright (c) 2009-2016, Stefan Eilemann <eile@equalizergraphics.com>
3 : * Daniel Nachbaur <danielnachbaur@gmail.com>
4 : *
5 : * This library is free software; you can redistribute it and/or modify it under
6 : * the terms of the GNU Lesser General Public License version 2.1 as published
7 : * by the Free Software Foundation.
8 : *
9 : * This library is distributed in the hope that it will be useful, but WITHOUT
10 : * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
11 : * FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
12 : * details.
13 : *
14 : * You should have received a copy of the GNU Lesser General Public License
15 : * along with this library; if not, write to the Free Software Foundation, Inc.,
16 : * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
17 : */
18 :
19 : #include "object.h"
20 :
21 : #include "event.h"
22 : #include "task.h"
23 :
24 : #include <co/dataIStream.h>
25 : #include <co/dataOStream.h>
26 : #include <co/iCommand.h>
27 : #include <co/types.h>
28 :
29 : namespace eq
30 : {
31 : namespace fabric
32 : {
33 : namespace detail
34 : {
35 39132 : struct BackupData
36 : {
37 : /** The application-defined name of the object. */
38 : std::string name;
39 :
40 : /** The user data parameters if no _userData object is set. */
41 : co::ObjectVersion userData;
42 : };
43 :
44 9756 : class Object
45 : {
46 : public:
47 8554 : Object()
48 8554 : : userData(0)
49 : , tasks(TASK_NONE)
50 8554 : , serial(CO_INSTANCE_INVALID)
51 : {
52 8554 : }
53 :
54 1224 : Object(const Object& from)
55 1224 : : data(from.data)
56 : , backup()
57 1224 : , userData(from.userData)
58 1224 : , tasks(from.tasks)
59 3672 : , serial(from.serial)
60 : {
61 1224 : }
62 :
63 : // cppcheck-suppress operatorEqVarError
64 0 : Object& operator=(const Object& from)
65 : {
66 0 : if (this == &from)
67 0 : return *this;
68 :
69 0 : data = from.data;
70 0 : userData = from.userData;
71 0 : tasks = from.tasks;
72 0 : serial = from.serial;
73 0 : return *this;
74 : }
75 :
76 : BackupData data; //!< Active data
77 : BackupData backup; //!< Backed up version (from .eqc)
78 :
79 : co::Object* userData; //!< User data object
80 : uint32_t tasks; //!< Worst-case set of tasks
81 : uint32_t serial; //!< Server-unique serial number
82 :
83 : /** The identifiers of removed children since the last slave commit. */
84 : std::vector<uint128_t> removedChildren;
85 : };
86 : }
87 :
88 8554 : Object::Object()
89 8554 : : _impl(new detail::Object)
90 : {
91 8554 : }
92 :
93 1224 : Object::Object(const Object& from)
94 : : co::Serializable(from)
95 1224 : , _impl(new detail::Object(*from._impl))
96 : {
97 1224 : }
98 :
99 19512 : Object::~Object()
100 : {
101 9756 : LBASSERTINFO(!isAttached(), "Object " << getID() << " is still attached");
102 9756 : LBASSERTINFO(!_impl->userData,
103 : "Unset user data before destruction to allow clean release")
104 :
105 19512 : co::LocalNodePtr node = getLocalNode();
106 9756 : if (node.isValid())
107 0 : node->releaseObject(this);
108 9756 : delete _impl;
109 9756 : }
110 :
111 0 : Object& Object::operator=(const Object& from)
112 : {
113 0 : if (this == &from)
114 0 : return *this;
115 :
116 0 : co::Serializable::operator=(from);
117 0 : *_impl = *from._impl;
118 0 : return *this;
119 : }
120 :
121 1708 : bool Object::isDirty() const
122 : {
123 1708 : if (_impl->userData && _impl->userData->isAttached())
124 : {
125 30 : if (_impl->userData->isMaster())
126 28 : _impl->userData->sync(); // apply slave object commits
127 30 : return Serializable::isDirty() || _impl->userData->isDirty();
128 : }
129 :
130 : // else
131 1678 : return Serializable::isDirty();
132 : }
133 :
134 408 : uint128_t Object::commit(const uint32_t incarnation)
135 : {
136 408 : if (!_impl->userData)
137 378 : return Serializable::commit(incarnation);
138 :
139 30 : if (!_impl->userData->isAttached() && hasMasterUserData())
140 : {
141 14 : getLocalNode()->registerObject(_impl->userData);
142 14 : _impl->userData->setAutoObsolete(getUserDataLatency() + 1);
143 14 : _impl->data.userData = _impl->userData;
144 14 : setDirty(DIRTY_USERDATA);
145 : }
146 :
147 30 : if (_impl->userData->isDirty() && _impl->userData->isAttached())
148 : {
149 4 : const uint128_t& version = _impl->userData->commit(incarnation);
150 4 : LBASSERT(version != co::VERSION_NONE);
151 4 : LBASSERT(!_impl->userData->isDirty());
152 4 : LBASSERT(_impl->data.userData.identifier != _impl->userData->getID() ||
153 : _impl->data.userData.version <= version);
154 :
155 14 : if (_impl->userData->isMaster() &&
156 10 : _impl->data.userData != co::ObjectVersion(_impl->userData))
157 : {
158 2 : LBASSERTINFO(_impl->data.userData.identifier !=
159 : _impl->userData->getID() ||
160 : _impl->data.userData.version <
161 : _impl->userData->getVersion(),
162 : _impl->data.userData
163 : << " >= " << co::ObjectVersion(_impl->userData));
164 :
165 2 : _impl->data.userData.identifier = _impl->userData->getID();
166 2 : _impl->data.userData.version = version;
167 2 : setDirty(DIRTY_USERDATA);
168 : }
169 : }
170 :
171 30 : return Serializable::commit(incarnation);
172 : }
173 :
174 116 : void Object::notifyDetach()
175 : {
176 116 : Serializable::notifyDetach();
177 116 : if (!_impl->userData)
178 114 : return;
179 :
180 2 : LBASSERT(!_impl->userData->isAttached() ||
181 : _impl->userData->isMaster() == hasMasterUserData());
182 :
183 2 : if (_impl->userData->isMaster())
184 0 : _impl->data.userData = co::ObjectVersion(0);
185 :
186 2 : getLocalNode()->releaseObject(_impl->userData);
187 : }
188 :
189 64 : void Object::backup()
190 : {
191 64 : LBASSERT(!_impl->userData);
192 64 : _impl->backup = _impl->data;
193 64 : }
194 :
195 0 : void Object::restore()
196 : {
197 0 : LBASSERT(!_impl->userData);
198 0 : _impl->data = _impl->backup;
199 0 : setDirty(DIRTY_NAME | DIRTY_USERDATA);
200 0 : }
201 :
202 314 : void Object::serialize(co::DataOStream& os, const uint64_t dirtyBits)
203 : {
204 314 : if (dirtyBits & DIRTY_NAME)
205 136 : os << _impl->data.name;
206 314 : if (dirtyBits & DIRTY_USERDATA)
207 168 : os << _impl->data.userData;
208 314 : if (dirtyBits & DIRTY_TASKS)
209 136 : os << _impl->tasks;
210 314 : if (dirtyBits & DIRTY_REMOVED)
211 : {
212 136 : LBASSERT(!isMaster() ||
213 : (_impl->removedChildren.empty() && dirtyBits == DIRTY_ALL))
214 136 : os << _impl->removedChildren;
215 136 : _impl->removedChildren.clear();
216 : }
217 314 : if ((dirtyBits & DIRTY_SERIAL) && isMaster())
218 : {
219 136 : _impl->serial = getInstanceID();
220 136 : os << _impl->serial;
221 : }
222 314 : }
223 :
224 222 : void Object::deserialize(co::DataIStream& is, const uint64_t dirtyBits)
225 : {
226 222 : if (dirtyBits & DIRTY_NAME)
227 52 : is >> _impl->data.name;
228 222 : if (dirtyBits & DIRTY_USERDATA)
229 : {
230 86 : is >> _impl->data.userData;
231 : // map&sync below to allow early exits
232 : }
233 222 : if (dirtyBits & DIRTY_TASKS)
234 52 : is >> _impl->tasks;
235 222 : if (dirtyBits & DIRTY_REMOVED)
236 : {
237 104 : std::vector<uint128_t> removed;
238 52 : is >> removed;
239 52 : if (!removed.empty())
240 : {
241 0 : LBASSERT(isMaster());
242 0 : std::vector<uint128_t>::const_iterator i = removed.begin();
243 0 : for (; i != removed.end(); ++i)
244 : {
245 0 : removeChild(*i);
246 : }
247 : }
248 : }
249 222 : if ((dirtyBits & DIRTY_SERIAL) && !isMaster())
250 52 : is >> _impl->serial;
251 :
252 222 : if (isMaster()) // redistribute changes
253 60 : setDirty(dirtyBits & getRedistributableBits());
254 :
255 : // Update user data state
256 222 : if (!(dirtyBits & DIRTY_USERDATA) || !_impl->userData)
257 202 : return;
258 :
259 20 : LBASSERTINFO(_impl->data.userData.identifier != _impl->userData->getID() ||
260 : _impl->data.userData.version >=
261 : _impl->userData->getVersion() ||
262 : _impl->userData->isMaster(),
263 : "Incompatible version, new "
264 : << _impl->data.userData << " old "
265 : << co::ObjectVersion(_impl->userData));
266 :
267 20 : if (_impl->data.userData.identifier == 0)
268 : {
269 2 : if (_impl->userData->isAttached() && !_impl->userData->isMaster())
270 : {
271 0 : LBASSERT(!hasMasterUserData());
272 0 : getLocalNode()->unmapObject(_impl->userData);
273 : }
274 2 : return;
275 : }
276 :
277 18 : if (!_impl->userData->isAttached() && _impl->data.userData.identifier != 0)
278 : {
279 2 : LBASSERT(!hasMasterUserData());
280 2 : if (!getLocalNode()->mapObject(_impl->userData, _impl->data.userData))
281 : {
282 0 : LBWARN << "Mapping of " << lunchbox::className(_impl->userData)
283 0 : << " user data failed" << std::endl;
284 0 : LBUNREACHABLE;
285 0 : return;
286 : }
287 : }
288 :
289 18 : if (!_impl->userData->isMaster() && _impl->userData->isAttached())
290 : {
291 2 : LBASSERTINFO(_impl->userData->getID() ==
292 : _impl->data.userData.identifier,
293 : _impl->userData->getID()
294 : << " != " << _impl->data.userData.identifier);
295 2 : _impl->userData->sync(_impl->data.userData.version);
296 : }
297 : }
298 :
299 3346 : void Object::setName(const std::string& name)
300 : {
301 3346 : if (_impl->data.name == name)
302 0 : return;
303 3346 : _impl->data.name = name;
304 3346 : setDirty(DIRTY_NAME);
305 : }
306 :
307 46 : void Object::setUserData(co::Object* userData)
308 : {
309 46 : LBASSERT(!userData || !userData->isAttached());
310 :
311 46 : if (_impl->userData == userData)
312 14 : return;
313 :
314 32 : if (_impl->userData && _impl->userData->isAttached())
315 : {
316 14 : LBASSERT(_impl->userData->isMaster() == hasMasterUserData());
317 14 : _impl->userData->getLocalNode()->releaseObject(_impl->userData);
318 : }
319 :
320 32 : _impl->userData = userData;
321 :
322 32 : if (hasMasterUserData())
323 28 : setDirty(DIRTY_USERDATA);
324 4 : else if (_impl->data.userData.identifier != 0)
325 : {
326 4 : co::LocalNodePtr node = getLocalNode();
327 2 : if (node.isValid())
328 0 : node->mapObject(_impl->userData, _impl->data.userData);
329 : }
330 : }
331 :
332 32 : co::Object* Object::getUserData()
333 : {
334 32 : return _impl->userData;
335 : }
336 :
337 2 : const co::Object* Object::getUserData() const
338 : {
339 2 : return _impl->userData;
340 : }
341 :
342 512 : uint32_t Object::getTasks() const
343 : {
344 512 : return _impl->tasks;
345 : }
346 :
347 68 : uint32_t Object::getSerial() const
348 : {
349 68 : return _impl->serial;
350 : }
351 :
352 54554 : const std::string& Object::getName() const
353 : {
354 54554 : return _impl->data.name;
355 : }
356 :
357 510 : void Object::setTasks(const uint32_t tasks)
358 : {
359 510 : if (_impl->tasks == tasks)
360 460 : return;
361 50 : _impl->tasks = tasks;
362 50 : setDirty(DIRTY_TASKS);
363 : }
364 :
365 6580 : void Object::postRemove(Object* child)
366 : {
367 6580 : LBASSERT(child);
368 6580 : if (!child->isAttached())
369 6580 : return;
370 :
371 0 : LBASSERT(!child->isMaster());
372 0 : LBASSERT(!isMaster());
373 :
374 0 : _impl->removedChildren.push_back(child->getID());
375 0 : setDirty(DIRTY_REMOVED);
376 :
377 0 : co::LocalNodePtr localNode = child->getLocalNode();
378 0 : localNode->releaseObject(child);
379 : }
380 :
381 6 : bool Object::_cmdSync(co::ICommand&)
382 : {
383 6 : LBASSERT(isMaster());
384 6 : sync(co::VERSION_HEAD);
385 6 : return true;
386 : }
387 :
388 32 : void Object::updateEvent(Event& event, const int64_t time)
389 : {
390 32 : event.serial = getSerial();
391 32 : event.time = time;
392 32 : event.originator = getID();
393 32 : }
394 : }
395 60 : }
|