Line data Source code
1 :
2 : /* Copyright (c) 2012-2013, Daniel Nachbaur <danielnachbaur@googlemail.com>
3 : * 2012-2014, Stefan Eilemann <eile@eyescale.ch>
4 : *
5 : * This file is part of Collage <https://github.com/Eyescale/Collage>
6 : *
7 : * This library is free software; you can redistribute it and/or modify it under
8 : * the terms of the GNU Lesser General Public License version 2.1 as published
9 : * by the Free Software Foundation.
10 : *
11 : * This library is distributed in the hope that it will be useful, but WITHOUT
12 : * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
13 : * FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
14 : * details.
15 : *
16 : * You should have received a copy of the GNU Lesser General Public License
17 : * along with this library; if not, write to the Free Software Foundation, Inc.,
18 : * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
19 : */
20 :
21 : #include "objectMap.h"
22 :
23 : #include "dataIStream.h"
24 : #include "dataOStream.h"
25 : #include "objectFactory.h"
26 :
27 : #include <lunchbox/scopedMutex.h>
28 : #include <lunchbox/spinLock.h>
29 :
30 : namespace co
31 : {
32 : namespace
33 : {
34 2 : struct Entry //!< One object map item
35 : {
36 4 : Entry() : instance( 0 ), type( OBJECTTYPE_NONE ), own( false ) {}
37 2 : Entry( const uint128_t& v, Object* i, const uint32_t t )
38 2 : : version( v ), instance( i ), type( t ), own( false ) {}
39 :
40 : uint128_t version; //!< The current version of the object
41 : Object* instance; //!< The object instance, if attached
42 : uint32_t type; //!< The object class id
43 : bool own; //!< The object is created by us, delete it
44 : };
45 :
46 : typedef stde::hash_map< uint128_t, Entry > Map;
47 : typedef Map::iterator MapIter;
48 : typedef Map::const_iterator MapCIter;
49 : typedef std::vector< uint128_t > IDVector;
50 : typedef IDVector::iterator IDVectorIter;
51 : typedef IDVector::const_iterator IDVectorCIter;
52 : }
53 :
54 : namespace detail
55 : {
56 : class ObjectMap
57 : {
58 : public:
59 2 : ObjectMap( ObjectHandler& h, ObjectFactory& f )
60 2 : : handler( h ) , factory( f ) {}
61 :
62 2 : ~ObjectMap()
63 2 : {
64 2 : LBASSERTINFO( masters.empty(), "Object map not cleared" );
65 2 : LBASSERTINFO( map.empty(), "Object map not cleared" );
66 2 : }
67 :
68 1 : void clear()
69 : {
70 1 : lunchbox::ScopedFastWrite mutex( lock );
71 1 : for( ObjectsCIter i = masters.begin(); i != masters.end(); ++i )
72 : {
73 0 : co::Object* object = *i;
74 0 : map.erase( object->getID( ));
75 0 : handler.deregisterObject( object );
76 : }
77 1 : masters.clear();
78 :
79 2 : for( MapIter i = map.begin(); i != map.end(); ++i )
80 1 : _removeObject( i->second );
81 1 : map.clear();
82 1 : }
83 :
84 3 : void _removeObject( Entry& entry )
85 : {
86 3 : if( !entry.instance )
87 4 : return;
88 :
89 2 : handler.unmapObject( entry.instance );
90 2 : if( entry.own )
91 1 : factory.destroyObject( entry.instance, entry.type );
92 2 : entry.instance = 0;
93 : }
94 :
95 : ObjectHandler& handler;
96 : ObjectFactory& factory; //!< The 'parent' user
97 :
98 : mutable lunchbox::SpinLock lock;
99 :
100 : Map map; //!< the actual map
101 : Objects masters; //!< Master objects registered with this instance
102 :
103 : /** Added master objects since the last commit. */
104 : IDVector added;
105 :
106 : /** Removed master objects since the last commit. */
107 : IDVector removed;
108 :
109 : /** Changed master objects since the last commit. */
110 : ObjectVersions changed;
111 : };
112 : }
113 :
114 2 : ObjectMap::ObjectMap( ObjectHandler& handler, ObjectFactory& factory )
115 2 : : _impl( new detail::ObjectMap( handler, factory ))
116 2 : {}
117 :
118 4 : ObjectMap::~ObjectMap()
119 : {
120 2 : delete _impl;
121 2 : }
122 :
123 3 : uint128_t ObjectMap::commit( const uint32_t incarnation )
124 : {
125 3 : _commitMasters( incarnation );
126 3 : const uint128_t& version = Serializable::commit( incarnation );
127 3 : _impl->added.clear();
128 3 : _impl->removed.clear();
129 3 : _impl->changed.clear();
130 3 : return version;
131 : }
132 :
133 3 : bool ObjectMap::isDirty() const
134 : {
135 3 : if( Serializable::isDirty( ))
136 3 : return true;
137 :
138 0 : lunchbox::ScopedFastRead mutex( _impl->lock );
139 0 : for( ObjectsCIter i =_impl->masters.begin(); i !=_impl->masters.end(); ++i )
140 0 : if( (*i)->isDirty( ))
141 0 : return true;
142 0 : return false;
143 : }
144 :
145 3 : void ObjectMap::_commitMasters( const uint32_t incarnation )
146 : {
147 3 : lunchbox::ScopedFastWrite mutex( _impl->lock );
148 :
149 8 : for( ObjectsCIter i =_impl->masters.begin(); i !=_impl->masters.end(); ++i )
150 : {
151 5 : Object* object = *i;
152 5 : if( !object->isDirty() || object->getChangeType() == Object::STATIC )
153 0 : continue;
154 :
155 5 : const ObjectVersion ov( object->getID(), object->commit( incarnation ));
156 5 : Entry& entry = _impl->map[ ov.identifier ];
157 5 : if( entry.version == ov.version )
158 0 : continue;
159 :
160 5 : entry.version = ov.version;
161 5 : _impl->changed.push_back( ov );
162 : }
163 3 : if( !_impl->changed.empty( ))
164 3 : setDirty( DIRTY_CHANGED );
165 3 : }
166 :
167 7 : void ObjectMap::serialize( DataOStream& os, const uint64_t dirtyBits )
168 : {
169 7 : Serializable::serialize( os, dirtyBits );
170 7 : lunchbox::ScopedFastWrite mutex( _impl->lock );
171 7 : if( dirtyBits == DIRTY_ALL )
172 : {
173 9 : for( MapCIter i = _impl->map.begin(); i != _impl->map.end(); ++i )
174 5 : os << i->first << i->second.version << i->second.type;
175 4 : os << ObjectVersion();
176 11 : return;
177 : }
178 :
179 3 : if( dirtyBits & DIRTY_ADDED )
180 : {
181 1 : os << _impl->added;
182 9 : for( IDVectorCIter i = _impl->added.begin();
183 6 : i != _impl->added.end(); ++i )
184 : {
185 2 : const Entry& entry = _impl->map[ *i ];
186 2 : os << entry.version << entry.type;
187 : }
188 : }
189 3 : if( dirtyBits & DIRTY_REMOVED )
190 1 : os << _impl->removed;
191 3 : if( dirtyBits & DIRTY_CHANGED )
192 3 : os << _impl->changed;
193 : }
194 :
195 4 : void ObjectMap::deserialize( DataIStream& is, const uint64_t dirtyBits )
196 : {
197 4 : Serializable::deserialize( is, dirtyBits );
198 4 : lunchbox::ScopedFastWrite mutex( _impl->lock );
199 4 : if( dirtyBits == DIRTY_ALL )
200 : {
201 1 : LBASSERT( _impl->map.empty( ));
202 :
203 1 : ObjectVersion ov;
204 1 : is >> ov;
205 2 : while( ov != ObjectVersion( ))
206 : {
207 0 : LBASSERT( _impl->map.find( ov.identifier ) == _impl->map.end( ));
208 0 : Entry& entry = _impl->map[ ov.identifier ];
209 0 : entry.version = ov.version;
210 0 : is >> entry.type >> ov;
211 : }
212 5 : return;
213 : }
214 :
215 3 : if( dirtyBits & DIRTY_ADDED )
216 : {
217 1 : IDVector added;
218 1 : is >> added;
219 :
220 3 : for( IDVectorCIter i = added.begin(); i != added.end(); ++i )
221 : {
222 2 : LBASSERT( _impl->map.find( *i ) == _impl->map.end( ));
223 2 : Entry& entry = _impl->map[ *i ];
224 2 : is >> entry.version >> entry.type;
225 1 : }
226 : }
227 3 : if( dirtyBits & DIRTY_REMOVED )
228 : {
229 1 : IDVector removed;
230 1 : is >> removed;
231 :
232 2 : for( IDVectorCIter i = removed.begin(); i != removed.end(); ++i )
233 : {
234 1 : MapIter it = _impl->map.find( *i );
235 1 : LBASSERT( it != _impl->map.end( ));
236 1 : _impl->_removeObject( it->second );
237 1 : _impl->map.erase( it );
238 1 : }
239 : }
240 3 : if( dirtyBits & DIRTY_CHANGED )
241 : {
242 3 : ObjectVersions changed;
243 3 : is >> changed;
244 :
245 8 : for( ObjectVersionsCIter i = changed.begin(); i!=changed.end(); ++i)
246 : {
247 5 : const ObjectVersion& ov = *i;
248 5 : LBASSERT( _impl->map.find( ov.identifier ) != _impl->map.end( ));
249 :
250 5 : Entry& entry = _impl->map[ ov.identifier ];
251 5 : if( !entry.instance || entry.instance->isMaster( ))
252 : {
253 6 : LBERROR << "Empty or master instance for object "
254 6 : << ov.identifier << " in slave object map" << std::endl;
255 2 : continue;
256 : }
257 :
258 3 : if( ov.version < entry.instance->getVersion( ))
259 0 : LBWARN << "Cannot sync " << entry.instance
260 0 : << " to older version " << ov.version << ", got "
261 0 : << entry.instance->getVersion() << std::endl;
262 : else
263 3 : entry.version = entry.instance->sync( ov.version );
264 3 : }
265 3 : }
266 : }
267 :
268 2 : void ObjectMap::notifyAttached()
269 : {
270 2 : _impl->added.clear();
271 2 : _impl->removed.clear();
272 2 : _impl->changed.clear();
273 2 : }
274 :
275 3 : bool ObjectMap::register_( Object* object, const uint32_t type )
276 : {
277 3 : LBASSERT( object );
278 3 : if( !object )
279 0 : return false;
280 :
281 3 : lunchbox::ScopedFastWrite mutex( _impl->lock );
282 3 : MapIter it = _impl->map.find( object->getID( ));
283 3 : if( it != _impl->map.end( ))
284 1 : return false;
285 :
286 2 : _impl->handler.registerObject( object );
287 2 : const Entry entry( object->getVersion(), object, type );
288 2 : _impl->map[ object->getID() ] = entry;
289 2 : _impl->masters.push_back( object );
290 2 : _impl->added.push_back( object->getID( ));
291 2 : setDirty( DIRTY_ADDED );
292 2 : return true;
293 : }
294 :
295 3 : bool ObjectMap::deregister( Object* object )
296 : {
297 3 : LBASSERT( object );
298 3 : if( !object )
299 0 : return false;
300 :
301 3 : lunchbox::ScopedFastWrite mutex( _impl->lock );
302 3 : MapIter mapIt = _impl->map.find( object->getID( ));
303 : ObjectsIter masterIt = std::find( _impl->masters.begin(),
304 3 : _impl->masters.end(), object );
305 3 : if( mapIt == _impl->map.end() || masterIt == _impl->masters.end( ))
306 1 : return false;
307 :
308 2 : _impl->handler.deregisterObject( object );
309 2 : _impl->map.erase( mapIt );
310 2 : _impl->masters.erase( masterIt );
311 2 : _impl->removed.push_back( object->getID( ));
312 2 : setDirty( DIRTY_REMOVED );
313 2 : return true;
314 : }
315 :
316 2 : Object* ObjectMap::map( const uint128_t& identifier, Object* instance )
317 : {
318 2 : if( identifier == 0 )
319 0 : return 0;
320 :
321 2 : lunchbox::ScopedFastWrite mutex( _impl->lock );
322 2 : MapIter i = _impl->map.find( identifier );
323 2 : LBASSERT( i != _impl->map.end( ));
324 2 : if( i == _impl->map.end( ))
325 : {
326 0 : LBWARN << "Object mapping failed, no master registered" << std::endl;
327 0 : return 0;
328 : }
329 :
330 2 : Entry& entry = i->second;
331 2 : if( entry.instance )
332 : {
333 0 : LBASSERTINFO( !instance || entry.instance == instance,
334 : entry.instance << " != " << instance )
335 0 : if( !instance || entry.instance == instance )
336 0 : return entry.instance;
337 :
338 0 : LBWARN << "Object mapping failed, different instance registered"
339 0 : << std::endl;
340 0 : return 0;
341 : }
342 2 : LBASSERT( entry.type != OBJECTTYPE_NONE );
343 :
344 : Object* object = instance ? instance :
345 2 : _impl->factory.createObject( entry.type );
346 2 : LBASSERT( object );
347 2 : if( !object )
348 0 : return 0;
349 :
350 : const uint32_t req = _impl->handler.mapObjectNB( object, identifier,
351 : entry.version,
352 2 : getMasterNode( ));
353 2 : if( !_impl->handler.mapObjectSync( req ))
354 : {
355 0 : if( !instance )
356 0 : _impl->factory.destroyObject( object, entry.type );
357 0 : return 0;
358 : }
359 :
360 2 : if( object->getVersion() != entry.version )
361 0 : LBWARN << "Object " << *object << " could not be mapped to desired "
362 0 : << "version, should be " << entry.version << ", but is "
363 0 : << object->getVersion() << std::endl;
364 :
365 2 : entry.instance = object;
366 2 : entry.own = !instance;
367 2 : return object;
368 : }
369 :
370 1 : bool ObjectMap::unmap( Object* object )
371 : {
372 1 : LBASSERT( object );
373 1 : if( !object )
374 0 : return false;
375 :
376 1 : lunchbox::ScopedFastWrite mutex( _impl->lock );
377 1 : MapIter it = _impl->map.find( object->getID( ));
378 1 : if( it == _impl->map.end( ))
379 0 : return false;
380 :
381 1 : _impl->_removeObject( it->second );
382 1 : return true;
383 : }
384 :
385 1 : void ObjectMap::clear()
386 : {
387 1 : _impl->clear();
388 1 : }
389 :
390 60 : }
|