LCOV - code coverage report
Current view: top level - co - objectMap.cpp (source / functions) Hit Total Coverage
Test: Collage Lines: 178 215 82.8 %
Date: 2018-01-09 16:37:03 Functions: 22 23 95.7 %

          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 : }

Generated by: LCOV version 1.11