Line data Source code
1 :
2 : /* Copyright (c) 2012-2016, Daniel Nachbaur <danielnachbaur@googlemail.com>
3 : * 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 2 : 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 1 : 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 6 : 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 10 : lunchbox::ScopedFastWrite mutex( _impl->lock );
170 7 : if( dirtyBits == DIRTY_ALL )
171 : {
172 9 : for( MapCIter i = _impl->map.begin(); i != _impl->map.end(); ++i )
173 5 : os << i->first << i->second.version << i->second.type;
174 4 : os << ObjectVersion();
175 4 : return;
176 : }
177 :
178 3 : if( dirtyBits & DIRTY_ADDED )
179 : {
180 1 : os << _impl->added;
181 9 : for( IDVectorCIter i = _impl->added.begin();
182 6 : i != _impl->added.end(); ++i )
183 : {
184 2 : const Entry& entry = _impl->map[ *i ];
185 2 : os << entry.version << entry.type;
186 : }
187 : }
188 3 : if( dirtyBits & DIRTY_REMOVED )
189 1 : os << _impl->removed;
190 3 : if( dirtyBits & DIRTY_CHANGED )
191 3 : os << _impl->changed;
192 : }
193 :
194 4 : void ObjectMap::deserialize( DataIStream& is, const uint64_t dirtyBits )
195 : {
196 7 : lunchbox::ScopedFastWrite mutex( _impl->lock );
197 4 : if( dirtyBits == DIRTY_ALL )
198 : {
199 1 : LBASSERT( _impl->map.empty( ));
200 :
201 1 : ObjectVersion ov;
202 1 : is >> ov;
203 1 : while( ov != ObjectVersion( ))
204 : {
205 0 : LBASSERT( _impl->map.find( ov.identifier ) == _impl->map.end( ));
206 0 : Entry& entry = _impl->map[ ov.identifier ];
207 0 : entry.version = ov.version;
208 0 : is >> entry.type >> ov;
209 : }
210 1 : return;
211 : }
212 :
213 3 : if( dirtyBits & DIRTY_ADDED )
214 : {
215 2 : IDVector added;
216 1 : is >> added;
217 :
218 3 : for( IDVectorCIter i = added.begin(); i != added.end(); ++i )
219 : {
220 2 : LBASSERT( _impl->map.find( *i ) == _impl->map.end( ));
221 2 : Entry& entry = _impl->map[ *i ];
222 2 : is >> entry.version >> entry.type;
223 : }
224 : }
225 3 : if( dirtyBits & DIRTY_REMOVED )
226 : {
227 2 : IDVector removed;
228 1 : is >> removed;
229 :
230 2 : for( IDVectorCIter i = removed.begin(); i != removed.end(); ++i )
231 : {
232 1 : MapIter it = _impl->map.find( *i );
233 1 : LBASSERT( it != _impl->map.end( ));
234 1 : _impl->_removeObject( it->second );
235 1 : _impl->map.erase( it );
236 : }
237 : }
238 3 : if( dirtyBits & DIRTY_CHANGED )
239 : {
240 6 : ObjectVersions changed;
241 3 : is >> changed;
242 :
243 8 : for( ObjectVersionsCIter i = changed.begin(); i!=changed.end(); ++i)
244 : {
245 5 : const ObjectVersion& ov = *i;
246 5 : LBASSERT( _impl->map.find( ov.identifier ) != _impl->map.end( ));
247 :
248 5 : Entry& entry = _impl->map[ ov.identifier ];
249 5 : if( !entry.instance || entry.instance->isMaster( ))
250 : {
251 6 : LBERROR << "Empty or master instance for object "
252 6 : << ov.identifier << " in slave object map" << std::endl;
253 2 : continue;
254 : }
255 :
256 3 : if( ov.version < entry.instance->getVersion( ))
257 0 : LBWARN << "Cannot sync " << entry.instance
258 0 : << " to older version " << ov.version << ", got "
259 0 : << entry.instance->getVersion() << std::endl;
260 : else
261 3 : entry.version = entry.instance->sync( ov.version );
262 : }
263 : }
264 : }
265 :
266 2 : void ObjectMap::notifyAttached()
267 : {
268 2 : _impl->added.clear();
269 2 : _impl->removed.clear();
270 2 : _impl->changed.clear();
271 2 : }
272 :
273 3 : bool ObjectMap::register_( Object* object, const uint32_t type )
274 : {
275 3 : LBASSERT( object );
276 3 : if( !object )
277 0 : return false;
278 :
279 6 : lunchbox::ScopedFastWrite mutex( _impl->lock );
280 3 : MapIter it = _impl->map.find( object->getID( ));
281 3 : if( it != _impl->map.end( ))
282 1 : return false;
283 :
284 2 : _impl->handler.registerObject( object );
285 2 : const Entry entry( object->getVersion(), object, type );
286 2 : _impl->map[ object->getID() ] = entry;
287 2 : _impl->masters.push_back( object );
288 2 : _impl->added.push_back( object->getID( ));
289 2 : setDirty( DIRTY_ADDED );
290 2 : return true;
291 : }
292 :
293 3 : bool ObjectMap::deregister( Object* object )
294 : {
295 3 : LBASSERT( object );
296 3 : if( !object )
297 0 : return false;
298 :
299 6 : lunchbox::ScopedFastWrite mutex( _impl->lock );
300 3 : MapIter mapIt = _impl->map.find( object->getID( ));
301 3 : ObjectsIter masterIt = std::find( _impl->masters.begin(),
302 6 : _impl->masters.end(), object );
303 3 : if( mapIt == _impl->map.end() || masterIt == _impl->masters.end( ))
304 1 : return false;
305 :
306 2 : _impl->handler.deregisterObject( object );
307 2 : _impl->map.erase( mapIt );
308 2 : _impl->masters.erase( masterIt );
309 2 : _impl->removed.push_back( object->getID( ));
310 2 : setDirty( DIRTY_REMOVED );
311 2 : return true;
312 : }
313 :
314 2 : Object* ObjectMap::map( const uint128_t& identifier, Object* instance )
315 : {
316 2 : if( identifier == 0 )
317 0 : return 0;
318 :
319 4 : lunchbox::ScopedFastWrite mutex( _impl->lock );
320 2 : MapIter i = _impl->map.find( identifier );
321 2 : LBASSERT( i != _impl->map.end( ));
322 2 : if( i == _impl->map.end( ))
323 : {
324 0 : LBWARN << "Object mapping failed, no master registered" << std::endl;
325 0 : return 0;
326 : }
327 :
328 2 : Entry& entry = i->second;
329 2 : if( entry.instance )
330 : {
331 0 : LBASSERTINFO( !instance || entry.instance == instance,
332 : entry.instance << " != " << instance )
333 0 : if( !instance || entry.instance == instance )
334 0 : return entry.instance;
335 :
336 0 : LBWARN << "Object mapping failed, different instance registered"
337 0 : << std::endl;
338 0 : return 0;
339 : }
340 2 : LBASSERT( entry.type != OBJECTTYPE_NONE );
341 :
342 3 : Object* object = instance ? instance :
343 3 : _impl->factory.createObject( entry.type );
344 2 : LBASSERT( object );
345 2 : if( !object )
346 0 : return 0;
347 :
348 4 : const uint32_t req = _impl->handler.mapObjectNB( object, identifier,
349 : entry.version,
350 4 : getMasterNode( ));
351 2 : if( !_impl->handler.mapObjectSync( req ))
352 : {
353 0 : if( !instance )
354 0 : _impl->factory.destroyObject( object, entry.type );
355 0 : return 0;
356 : }
357 :
358 2 : if( object->getVersion() != entry.version )
359 0 : LBWARN << "Object " << *object << " could not be mapped to desired "
360 0 : << "version, should be " << entry.version << ", but is "
361 0 : << object->getVersion() << std::endl;
362 :
363 2 : entry.instance = object;
364 2 : entry.own = !instance;
365 2 : return object;
366 : }
367 :
368 1 : bool ObjectMap::unmap( Object* object )
369 : {
370 1 : LBASSERT( object );
371 1 : if( !object )
372 0 : return false;
373 :
374 2 : lunchbox::ScopedFastWrite mutex( _impl->lock );
375 1 : MapIter it = _impl->map.find( object->getID( ));
376 1 : if( it == _impl->map.end( ))
377 0 : return false;
378 :
379 1 : _impl->_removeObject( it->second );
380 1 : return true;
381 : }
382 :
383 1 : void ObjectMap::clear()
384 : {
385 1 : _impl->clear();
386 1 : }
387 :
388 66 : }
|