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