LCOV - code coverage report
Current view: top level - co - objectMap.cpp (source / functions) Hit Total Coverage
Test: Collage Lines: 177 214 82.7 %
Date: 2015-11-03 13:48:53 Functions: 22 23 95.7 %

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

Generated by: LCOV version 1.11