LCOV - code coverage report
Current view: top level - co - objectMap.cpp (source / functions) Hit Total Coverage
Test: Collage Lines: 174 211 82.5 %
Date: 2016-12-14 01:26:48 Functions: 22 23 95.7 %

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

Generated by: LCOV version 1.11