Line data Source code
1 :
2 : /* Copyright (c) 2009-2014, Stefan Eilemann <eile@equalizergraphics.com>
3 : * 2012, 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 "task.h"
22 :
23 : #include <co/iCommand.h>
24 : #include <co/dataIStream.h>
25 : #include <co/dataOStream.h>
26 : #include <co/types.h>
27 :
28 : namespace eq
29 : {
30 : namespace fabric
31 : {
32 : namespace detail
33 : {
34 23917 : struct BackupData
35 : {
36 : /** The application-defined name of the object. */
37 : std::string name;
38 :
39 : /** The user data parameters if no _userData object is set. */
40 : co::ObjectVersion userData;
41 : };
42 :
43 5285 : class Object
44 : {
45 : public:
46 5870 : Object()
47 : : userData( 0 )
48 : , tasks( TASK_NONE )
49 5870 : , serial( CO_INSTANCE_INVALID )
50 5870 : {}
51 :
52 636 : Object( const Object& from )
53 : : data( from.data )
54 : , backup()
55 : , userData( from.userData )
56 : , tasks( from.tasks )
57 636 : , serial( from.serial )
58 636 : {}
59 :
60 : // cppcheck-suppress operatorEqVarError
61 0 : Object& operator = ( const Object& from )
62 : {
63 0 : if( this == &from )
64 0 : return *this;
65 :
66 0 : data = from.data;
67 0 : userData = from.userData;
68 0 : tasks = from.tasks;
69 0 : serial = from.serial;
70 0 : return *this;
71 : }
72 :
73 : BackupData data; //!< Active data
74 : BackupData backup; //!< Backed up version (from .eqc)
75 :
76 : co::Object* userData; //!< User data object
77 : uint32_t tasks; //!< Worst-case set of tasks
78 : uint32_t serial; //!< Server-unique serial number
79 :
80 : /** The identifiers of removed children since the last slave commit. */
81 : std::vector< uint128_t > removedChildren;
82 : };
83 : }
84 :
85 5870 : Object::Object()
86 5870 : : _impl( new detail::Object )
87 5870 : {}
88 :
89 636 : Object::Object( const Object& from )
90 : : co::Serializable( from )
91 636 : , _impl( new detail::Object( *from._impl ))
92 636 : {}
93 :
94 10570 : Object::~Object()
95 : {
96 5285 : LBASSERTINFO( !isAttached(), "Object " << getID() << " is still attached" );
97 5285 : LBASSERTINFO( !_impl->userData,
98 : "Unset user data before destruction to allow clean release" )
99 :
100 5285 : co::LocalNodePtr node = getLocalNode();
101 5285 : if( node.isValid() )
102 0 : node->releaseObject( this );
103 5285 : delete _impl;
104 5285 : }
105 :
106 0 : Object& Object::operator = ( const Object& from )
107 : {
108 0 : if( this == &from )
109 0 : return *this;
110 :
111 0 : co::Serializable::operator = ( from );
112 0 : *_impl = *from._impl;
113 0 : return *this;
114 : }
115 :
116 166594 : bool Object::isDirty() const
117 : {
118 166594 : if( _impl->userData && _impl->userData->isAttached( ))
119 : {
120 15 : if( _impl->userData->isMaster( ))
121 14 : _impl->userData->sync(); // apply slave object commits
122 15 : return Serializable::isDirty() || _impl->userData->isDirty();
123 : }
124 :
125 : // else
126 166579 : return Serializable::isDirty();
127 : }
128 :
129 165782 : uint128_t Object::commit( const uint32_t incarnation )
130 : {
131 165782 : if( !_impl->userData )
132 165767 : return Serializable::commit( incarnation );
133 :
134 15 : if( !_impl->userData->isAttached() && hasMasterUserData( ))
135 : {
136 7 : getLocalNode()->registerObject( _impl->userData );
137 7 : _impl->userData->setAutoObsolete( getUserDataLatency() + 1 );
138 7 : _impl->data.userData = _impl->userData;
139 7 : setDirty( DIRTY_USERDATA );
140 : }
141 :
142 15 : if( _impl->userData->isDirty() && _impl->userData->isAttached( ))
143 : {
144 2 : const uint128_t& version = _impl->userData->commit( incarnation );
145 2 : LBASSERT( version != co::VERSION_NONE );
146 2 : LBASSERT( !_impl->userData->isDirty( ));
147 2 : LBASSERT( _impl->data.userData.identifier != _impl->userData->getID() ||
148 : _impl->data.userData.version <= version );
149 :
150 7 : if( _impl->userData->isMaster() &&
151 5 : _impl->data.userData != _impl->userData )
152 : {
153 1 : LBASSERTINFO( _impl->data.userData.identifier !=
154 : _impl->userData->getID() ||
155 : _impl->data.userData.version <
156 : _impl->userData->getVersion(),
157 : _impl->data.userData << " >= " <<
158 : co::ObjectVersion( _impl->userData ));
159 :
160 1 : _impl->data.userData.identifier = _impl->userData->getID();
161 1 : _impl->data.userData.version = version;
162 1 : setDirty( DIRTY_USERDATA );
163 : }
164 : }
165 :
166 15 : return Serializable::commit( incarnation );
167 : }
168 :
169 533 : void Object::notifyDetach()
170 : {
171 533 : Serializable::notifyDetach();
172 533 : if( !_impl->userData )
173 1058 : return;
174 :
175 8 : LBASSERT( !_impl->userData->isAttached() ||
176 : _impl->userData->isMaster() == hasMasterUserData( ));
177 :
178 8 : if( _impl->userData->isMaster( ))
179 7 : _impl->data.userData = co::ObjectVersion( 0 );
180 :
181 8 : getLocalNode()->releaseObject( _impl->userData );
182 : }
183 :
184 313 : void Object::backup()
185 : {
186 313 : LBASSERT( !_impl->userData );
187 313 : _impl->backup = _impl->data;
188 313 : }
189 :
190 22 : void Object::restore()
191 : {
192 22 : LBASSERT( !_impl->userData );
193 22 : _impl->data = _impl->backup;
194 22 : setDirty( DIRTY_NAME | DIRTY_USERDATA );
195 22 : }
196 :
197 869 : void Object::serialize( co::DataOStream& os, const uint64_t dirtyBits )
198 : {
199 869 : if( dirtyBits & DIRTY_NAME )
200 432 : os << _impl->data.name;
201 869 : if( dirtyBits & DIRTY_USERDATA )
202 448 : os << _impl->data.userData;
203 869 : if( dirtyBits & DIRTY_TASKS )
204 485 : os << _impl->tasks;
205 869 : if( dirtyBits & DIRTY_REMOVED )
206 : {
207 432 : LBASSERT( !isMaster() ||
208 : ( _impl->removedChildren.empty() && dirtyBits == DIRTY_ALL ))
209 432 : os << _impl->removedChildren;
210 432 : _impl->removedChildren.clear();
211 : }
212 869 : if( (dirtyBits & DIRTY_SERIAL) && isMaster( ))
213 : {
214 432 : _impl->serial = getInstanceID();
215 432 : os << _impl->serial;
216 : }
217 869 : }
218 :
219 591 : void Object::deserialize( co::DataIStream& is, const uint64_t dirtyBits )
220 : {
221 591 : if( dirtyBits & DIRTY_NAME )
222 220 : is >> _impl->data.name;
223 591 : if( dirtyBits & DIRTY_USERDATA )
224 : {
225 236 : is >> _impl->data.userData;
226 : // map&sync below to allow early exits
227 : }
228 591 : if( dirtyBits & DIRTY_TASKS )
229 238 : is >> _impl->tasks;
230 591 : if( dirtyBits & DIRTY_REMOVED )
231 : {
232 220 : std::vector< uint128_t > removed;
233 220 : is >> removed;
234 220 : if( !removed.empty( ))
235 : {
236 0 : LBASSERT( isMaster( ));
237 0 : std::vector< uint128_t >::const_iterator i = removed.begin();
238 0 : for( ; i != removed.end(); ++i )
239 : {
240 0 : removeChild( *i );
241 : }
242 220 : }
243 : }
244 591 : if( (dirtyBits & DIRTY_SERIAL) && !isMaster( ))
245 220 : is >> _impl->serial;
246 :
247 591 : if( isMaster( )) // redistribute changes
248 147 : setDirty( dirtyBits & getRedistributableBits( ));
249 :
250 : // Update user data state
251 591 : if( !(dirtyBits & DIRTY_USERDATA) || !_impl->userData )
252 575 : return;
253 :
254 16 : LBASSERTINFO( _impl->data.userData.identifier != _impl->userData->getID() ||
255 : _impl->data.userData.version>=_impl->userData->getVersion() ||
256 : _impl->userData->isMaster(),
257 : "Incompatible version, new " << _impl->data.userData
258 : << " old " << co::ObjectVersion( _impl->userData ));
259 :
260 16 : if( _impl->data.userData.identifier == 0 )
261 : {
262 7 : if( _impl->userData->isAttached() && !_impl->userData->isMaster( ))
263 : {
264 0 : LBASSERT( !hasMasterUserData( ));
265 0 : getLocalNode()->unmapObject( _impl->userData );
266 : }
267 7 : return;
268 : }
269 :
270 9 : if( !_impl->userData->isAttached() && _impl->data.userData.identifier != 0 )
271 : {
272 1 : LBASSERT( !hasMasterUserData( ));
273 1 : if( !getLocalNode()->mapObject( _impl->userData, _impl->data.userData ))
274 : {
275 0 : LBWARN << "Mapping of " << lunchbox::className( _impl->userData )
276 0 : << " user data failed" << std::endl;
277 0 : LBUNREACHABLE;
278 0 : return;
279 : }
280 : }
281 :
282 9 : if( !_impl->userData->isMaster() && _impl->userData->isAttached( ))
283 : {
284 1 : LBASSERTINFO( _impl->userData->getID() ==
285 : _impl->data.userData.identifier,
286 : _impl->userData->getID() << " != "
287 : << _impl->data.userData.identifier );
288 1 : _impl->userData->sync( _impl->data.userData.version );
289 : }
290 : }
291 :
292 1789 : void Object::setName( const std::string& name )
293 : {
294 1789 : if( _impl->data.name == name )
295 1802 : return;
296 1776 : _impl->data.name = name;
297 1776 : setDirty( DIRTY_NAME );
298 : }
299 :
300 16 : void Object::setUserData( co::Object* userData )
301 : {
302 16 : LBASSERT( !userData || !userData->isAttached() );
303 :
304 16 : if( _impl->userData == userData )
305 16 : return;
306 :
307 16 : if( _impl->userData && _impl->userData->isAttached( ))
308 : {
309 0 : LBASSERT( _impl->userData->isMaster() == hasMasterUserData( ));
310 0 : _impl->userData->getLocalNode()->releaseObject( _impl->userData );
311 : }
312 :
313 16 : _impl->userData = userData;
314 :
315 16 : if( hasMasterUserData( ))
316 14 : setDirty( DIRTY_USERDATA );
317 2 : else if( _impl->data.userData.identifier != 0 )
318 : {
319 1 : co::LocalNodePtr node = getLocalNode();
320 1 : if( node.isValid() )
321 0 : node->mapObject( _impl->userData, _impl->data.userData );
322 : }
323 : }
324 :
325 9 : co::Object* Object::getUserData()
326 : {
327 9 : return _impl->userData;
328 : }
329 :
330 1 : const co::Object* Object::getUserData() const
331 : {
332 1 : return _impl->userData;
333 : }
334 :
335 1408 : uint32_t Object::getTasks() const
336 : {
337 1408 : return _impl->tasks;
338 : }
339 :
340 157 : uint32_t Object::getSerial() const
341 : {
342 157 : return _impl->serial;
343 : }
344 :
345 30512 : const std::string& Object::getName() const
346 : {
347 30512 : return _impl->data.name;
348 : }
349 :
350 1415 : void Object::setTasks( const uint32_t tasks )
351 : {
352 1415 : if( _impl->tasks == tasks )
353 2599 : return;
354 231 : _impl->tasks = tasks;
355 231 : setDirty( DIRTY_TASKS );
356 : }
357 :
358 3639 : void Object::postRemove( Object* child )
359 : {
360 3639 : LBASSERT( child );
361 3639 : if( !child->isAttached( ))
362 7278 : return;
363 :
364 0 : LBASSERT( !child->isMaster( ));
365 0 : LBASSERT( !isMaster( ));
366 :
367 0 : _impl->removedChildren.push_back( child->getID( ));
368 0 : setDirty( DIRTY_REMOVED );
369 :
370 0 : co::LocalNodePtr localNode = child->getLocalNode();
371 0 : localNode->releaseObject( child );
372 : }
373 :
374 10 : bool Object::_cmdSync( co::ICommand& )
375 : {
376 10 : LBASSERT( isMaster( ));
377 10 : sync( co::VERSION_HEAD );
378 10 : return true;
379 : }
380 :
381 : }
382 45 : }
|