LCOV - code coverage report
Current view: top level - co - object.h (source / functions) Hit Total Coverage
Test: Collage Lines: 12 15 80.0 %
Date: 2016-12-14 01:26:48 Functions: 12 14 85.7 %

          Line data    Source code
       1             : 
       2             : /* Copyright (c) 2005-2016, Stefan Eilemann <eile@equalizergraphics.com>
       3             :  *                          Daniel Nachbaur <danielnachbaur@gmail.com>
       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             : #ifndef CO_OBJECT_H
      22             : #define CO_OBJECT_H
      23             : 
      24             : #include <co/dispatcher.h>    // base class
      25             : #include <co/localNode.h>     // used in RefPtr
      26             : #include <co/types.h>         // for Nodes
      27             : #include <co/version.h>       // used as default parameter
      28             : #include <lunchbox/bitOperation.h> // byteswap inline impl
      29             : 
      30             : namespace co
      31             : {
      32             : namespace detail { class Object; }
      33             : class ObjectCM;
      34             : typedef lunchbox::RefPtr< ObjectCM > ObjectCMPtr;
      35             : 
      36             : #  define CO_COMMIT_NEXT LB_UNDEFINED_UINT32 //!< the next commit incarnation
      37             : 
      38             : /**
      39             :  * A distributed object.
      40             :  *
      41             :  * Please refer to the Equalizer Programming Guide and examples on how to
      42             :  * develop and use distributed objects. The Serializable implements a typical
      43             :  * common use case based on the basic Object.
      44             :  */
      45             : class Object : public Dispatcher
      46             : {
      47             : public:
      48             :     /** Object change handling characteristics, see Programming Guide */
      49             :     enum ChangeType
      50             :     {
      51             :         NONE,              //!< @internal
      52             :         STATIC,            //!< non-versioned, unbuffered, static object.
      53             :         INSTANCE,          //!< use only instance data
      54             :         DELTA,             //!< use pack/unpack delta
      55             :         UNBUFFERED         //!< versioned, but don't retain versions
      56             :     };
      57             : 
      58             :     /** Destruct the distributed object. @version 1.0 */
      59             :     CO_API virtual ~Object();
      60             : 
      61             :     /** @name Data Access */
      62             :     //@{
      63             :     /**
      64             :      * @return true if the object is attached (mapped or registered).
      65             :      * @version 1.0
      66             :      */
      67             :     CO_API bool isAttached() const;
      68             : 
      69             :     /** @return the local node to which this object is attached. @version 1.0 */
      70             :     CO_API LocalNodePtr getLocalNode();
      71             : 
      72             :     /**
      73             :      * Set the object's unique identifier.
      74             :      *
      75             :      * Only to be called on unattached objects. The application has to
      76             :      * ensure the uniqueness of the identifier in the peer-to-peer node
      77             :      * network. By default, each object has an identifier guaranteed to be
      78             :      * unique. During mapping, the identifier of the object will be
      79             :      * overwritten with the identifier of the master object.
      80             :      * @version 1.0
      81             :      */
      82             :     CO_API void setID( const uint128_t& identifier );
      83             : 
      84             :     /** @return the object's unique identifier. @version 1.0 */
      85             :     CO_API const uint128_t& getID() const;
      86             : 
      87             :     /** @return the node-wide unique object instance identifier. @version 1.0 */
      88             :     CO_API uint32_t getInstanceID() const;
      89             : 
      90             :     /** @internal @return if this object keeps instance data buffers. */
      91             :     CO_API bool isBuffered() const;
      92             : 
      93             :     /**
      94             :      * @return true if this instance is a registered master version.
      95             :      * @version 1.0
      96             :      */
      97             :     CO_API bool isMaster() const;
      98             :     //@}
      99             : 
     100             :     /** @name Versioning */
     101             :     //@{
     102             :     /** @return how the changes are to be handled. @version 1.0 */
     103          12 :     virtual ChangeType getChangeType() const { return STATIC; }
     104             : 
     105             :     /**
     106             :      * Limit the number of queued versions on slave instances.
     107             :      *
     108             :      * Changing the return value of this method causes the master instance
     109             :      * to block during commit() if any slave instance has reached the
     110             :      * maximum number of queued versions. The method is called on the slave
     111             :      * instance. Multiple slave instances may use different values.
     112             :      *
     113             :      * Changing the return value at runtime, that is, after the slave
     114             :      * instance has been mapped is unsupported and causes undefined
     115             :      * behavior.
     116             :      *
     117             :      * Not supported on master instances for slave object commits. Open an
     118             :      * issue if you need this.
     119             :      *
     120             :      * @return the number of queued versions a slave instance may have.
     121             :      * @version 1.0
     122             :      */
     123         149 :     virtual uint64_t getMaxVersions() const
     124         149 :         { return std::numeric_limits< uint64_t >::max(); }
     125             : 
     126             :     /**
     127             :      * Return the compressor to be used for data transmission.
     128             :      *
     129             :      * This default implementation uses a heuristic to choose the best lossless
     130             :      * compressor in terms of speed and compression ratio. The application may
     131             :      * override this method to deactivate compression by returning the default
     132             :      * pression::Data::CompressorInfo or to select object-specific compressors.
     133             :      * @version 1.6
     134             :      */
     135             :     CO_API virtual CompressorInfo chooseCompressor() const;
     136             : 
     137             :     /**
     138             :      * Return if this object needs a commit.
     139             :      *
     140             :      * This function is used for optimization, to detect early that no
     141             :      * commit is needed. If it returns true, pack() or getInstanceData()
     142             :      * will be executed. The serialization methods can still decide to not
     143             :      * write any data, upon which no new version will be created. If it
     144             :      * returns false, commit() will exit early.
     145             :      *
     146             :      * @return true if a commit is needed.
     147             :      * @version 1.0
     148             :      */
     149         114 :     virtual bool isDirty() const { return true; }
     150             : 
     151             :     /**
     152             :      * Push the instance data of the object to the given nodes.
     153             :      *
     154             :      * Used to push object data from a Node, instead of pulling it during
     155             :      * mapping. Does not establish any mapping, that is, the receiving side
     156             :      * will typically use LocalNode::mapObject with VERSION_NONE to
     157             :      * establish a slave mapping. LocalNode::objectPush() is called once for
     158             :      * each node in the nodes list.
     159             :      *
     160             :      * Buffered objects do not reserialize their instance data. Multicast
     161             :      * connections are preferred, that is, for a set of nodes sharing one
     162             :      * multicast connection the data is only send once.
     163             :      *
     164             :      * @param groupID An identifier to group a set of push operations.
     165             :      * @param objectType A per-push identifier.
     166             :      * @param nodes The vector of nodes to push to.
     167             :      * @version 1.0
     168             :      */
     169             :     CO_API void push( const uint128_t& groupID, const uint128_t& objectType,
     170             :                       const Nodes& nodes );
     171             : 
     172             :     /**
     173             :      * Commit a new version of this object.
     174             :      *
     175             :      * Objects using the change type STATIC can not be committed.
     176             :      *
     177             :      * Master instances will increment new versions continuously, starting at
     178             :      * VERSION_FIRST. If the object has not changed, no new version will
     179             :      * be generated, that is, the current version is returned. The high
     180             :      * value of the returned version will always be 0.
     181             :      *
     182             :      * Slave objects can be committed, but have certain caveats for
     183             :      * serialization. Please refer to the Equalizer Programming Guide for
     184             :      * details. Slave object commits will return a random version on a
     185             :      * successful commit, or VERSION_NONE if the object has not changed since
     186             :      * the last commit. The high value of a successful slave commit will never
     187             :      * be 0.
     188             :      *
     189             :      * The incarnation count is meaningful for buffered master objects. The
     190             :      * commit implementation will keep all instance data committed with an
     191             :      * incarnation count newer than <code>current_incarnation -
     192             :      * getAutoObsolete()</code>. By default, each call to commit creates a new
     193             :      * incarnation, retaining the data from last getAutoObsolete() commit
     194             :      * calls. When the application wishes to auto obsolete by another metric
     195             :      * than commit calls, it has to consistently provide a corresponding
     196             :      * incarnation counter. Buffers with a higher incarnation count than the
     197             :      * current are discarded. A typical use case is to tie the auto obsoletion
     198             :      * to an application-specific frame loop. Decreasing the incarnation counter
     199             :      * will lead to undefined results.
     200             :      *
     201             :      * @param incarnation the commit incarnation for auto obsoletion.
     202             :      * @return the new head version (master) or commit id (slave).
     203             :      * @version 1.0
     204             :      */
     205             :     CO_API virtual uint128_t commit( const uint32_t incarnation =
     206             :                                      CO_COMMIT_NEXT );
     207             : 
     208             :     /**
     209             :      * Automatically obsolete old versions.
     210             :      *
     211             :      * The versions for the last count incarnations are retained for the
     212             :      * buffered object types INSTANCE and DELTA.
     213             :      *
     214             :      * @param count the number of incarnations to retain.
     215             :      * @version 1.0
     216             :      */
     217             :     CO_API void setAutoObsolete( const uint32_t count );
     218             : 
     219             :     /** @return get the number of retained incarnations. @version 1.0 */
     220             :     CO_API uint32_t getAutoObsolete() const;
     221             : 
     222             :     /**
     223             :      * Sync to a given version.
     224             :      *
     225             :      * Objects using the change type STATIC can not be synced.
     226             :      *
     227             :      * Syncing to VERSION_HEAD syncs all received versions, does not block and
     228             :      * always returns true. Syncing to VERSION_NEXT applies one new version,
     229             :      * potentially blocking. Syncing to VERSION_NONE does nothing.
     230             :      *
     231             :      * Slave objects can be synced to VERSION_HEAD, VERSION_NEXT or to any past
     232             :      * or future version generated by a commit on the master instance. Syncing
     233             :      * to a concrete version applies all pending versions up to this version and
     234             :      * potentially blocks if given a future version.
     235             :      *
     236             :      * Master objects can only be synced to VERSION_HEAD, VERSION_NEXT or to
     237             :      * any version generated by a commit on a slave instance. Syncing to a
     238             :      * concrete version applies only this version and potentially blocks.
     239             :      *
     240             :      * The different sync semantics for concrete versions originate from the
     241             :      * fact that master versions are continous and ordered, while slave
     242             :      * versions are random and unordered.
     243             :      *
     244             :      * This function is not thread safe, that is, calling sync()
     245             :      * simultaneously on the same object from multiple threads has to be
     246             :      * protected by the caller using a mutex.
     247             :      *
     248             :      * @param version the version to synchronize (see above).
     249             :      * @return the last version applied.
     250             :      * @version 1.0
     251             :      */
     252             :     CO_API virtual uint128_t sync( const uint128_t& version = VERSION_HEAD );
     253             : 
     254             :     /** @return the latest available (head) version. @version 1.0 */
     255             :     CO_API uint128_t getHeadVersion() const;
     256             : 
     257             :     /** @return the currently synchronized version. @version 1.0 */
     258             :     CO_API uint128_t getVersion() const;
     259             : 
     260             :     /**
     261             :      * Notification that a new head version was received by a slave object.
     262             :      *
     263             :      * The notification is called from the receiver thread, which is different
     264             :      * from the node main thread. The object cannot be sync()'ed from this
     265             :      * notification, as this might lead to deadlocks and synchronization issues
     266             :      * with the application thread changing the object. It should signal the
     267             :      * application, which then takes the appropriate action. Do not perform any
     268             :      * potentially blocking operations from this method.
     269             :      *
     270             :      * @param version The new head version.
     271             :      * @version 1.0
     272             :      */
     273             :     CO_API virtual void notifyNewHeadVersion( const uint128_t& version );
     274             : 
     275             :     /**
     276             :      * Notification that a new version was received by a master object.
     277             :      * The same constraints as for notifyNewHeadVersion() apply.
     278             :      * @version 1.0
     279             :      */
     280           0 :     virtual void notifyNewVersion() {}
     281             :     //@}
     282             : 
     283             :     /** @name Serialization methods for instantiation and versioning. */
     284             :     //@{
     285             :     /**
     286             :      * Serialize all instance information of this distributed object.
     287             :      *
     288             :      * @param os The output stream.
     289             :      * @version 1.0
     290             :      */
     291           2 :     virtual void getInstanceData( DataOStream& os LB_UNUSED ) {}
     292             : 
     293             :     /**
     294             :      * Deserialize the instance data.
     295             :      *
     296             :      * This method is called during object mapping to populate slave
     297             :      * instances with the master object's data.
     298             :      *
     299             :      * @param is the input stream.
     300             :      * @version 1.0
     301             :      */
     302           3 :     virtual void applyInstanceData( DataIStream& is LB_UNUSED ) {}
     303             : 
     304             :     /**
     305             :      * Serialize the modifications since the last call to commit().
     306             :      *
     307             :      * No new version will be created if no data is written to the output
     308             :      * stream.
     309             :      *
     310             :      * @param os the output stream.
     311             :      * @version 1.0
     312             :      */
     313           2 :     virtual void pack( DataOStream& os ) { getInstanceData( os ); }
     314             : 
     315             :     /**
     316             :      * Deserialize a change.
     317             :      *
     318             :      * @param is the input data stream.
     319             :      * @version 1.0
     320             :      */
     321           2 :     virtual void unpack( DataIStream& is ) { applyInstanceData( is ); }
     322             :     //@}
     323             : 
     324             :     /** @name Messaging API */
     325             :     //@{
     326             :     /**
     327             :      * Send a command with optional data to object instance(s) on another
     328             :      * node.
     329             :      *
     330             :      * The returned command can be used to pass additional data. The data
     331             :      * will be send after the command object is destroyed, aka when it is
     332             :      * running out of scope.
     333             :      *
     334             :      * @param node the node where to send the command to.
     335             :      * @param cmd the object command to execute.
     336             :      * @param instanceID the object instance(s) which should handle the command.
     337             :      * @return the command object to pass additional data to.
     338             :      * @version 1.0
     339             :      */
     340             :     CO_API ObjectOCommand send( NodePtr node, const uint32_t cmd,
     341             :                                 const uint32_t instanceID = CO_INSTANCE_ALL );
     342             :     //@}
     343             : 
     344             :     /** @name Notifications */
     345             :     /**
     346             :      * Notify that this object will be registered or mapped.
     347             :      *
     348             :      * The method is called from the thread initiating the registration or
     349             :      * mapping, before the operation is executed.
     350             :      * @version 1.0
     351             :      */
     352          63 :     virtual void notifyAttach() {}
     353             : 
     354             :     /**
     355             :      * Notify that this object has been registered or mapped.
     356             :      *
     357             :      * The method is called from the thread initiating the registration or
     358             :      * mapping, after the operation has been completed successfully.
     359             :      * @sa isMaster()
     360             :      * @version 1.0
     361             :      */
     362          61 :     virtual void notifyAttached() {}
     363             : 
     364             :     /**
     365             :      * Notify that this object will be deregistered or unmapped.
     366             :      *
     367             :      * The method is called from the thread initiating the deregistration or
     368             :      * unmapping, before the operation is executed.
     369             :      * @sa isMaster()
     370             :      * @version 1.0
     371             :      */
     372             :     CO_API virtual void notifyDetach();
     373             : 
     374             :     /**
     375             :      * Notify that this object has been deregistered or unmapped.
     376             :      *
     377             :      * The method is called from the thread initiating the deregistration or
     378             :      * unmapping, after the operation has been executed.
     379             :      * @version 1.0
     380             :      */
     381          62 :     virtual void notifyDetached() {}
     382             :     //@}
     383             : 
     384             :     /** @internal */
     385             :     //@{
     386             :     /** @internal @return the master object instance identifier. */
     387             :     uint32_t getMasterInstanceID() const;
     388             : 
     389             :     /** @internal @return the master object instance identifier. */
     390             :     CO_API NodePtr getMasterNode();
     391             : 
     392             :     /** @internal */
     393             :     CO_API void removeSlave( NodePtr node, const uint32_t instanceID );
     394             :     CO_API void removeSlaves( NodePtr node ); //!< @internal
     395             :     void setMasterNode( NodePtr node ); //!< @internal
     396             :     /** @internal */
     397             :     void addInstanceDatas( const ObjectDataIStreamDeque&, const uint128_t&);
     398             : 
     399             :     /**
     400             :      * @internal
     401             :      * Setup the change manager.
     402             :      *
     403             :      * @param type the type of the change manager.
     404             :      * @param master true if this object is the master.
     405             :      * @param localNode the node the object will be attached to.
     406             :      * @param masterInstanceID the instance identifier of the master object,
     407             :      *                         used when master == false.
     408             :      */
     409             :     void setupChangeManager( const Object::ChangeType type,
     410             :                              const bool master, LocalNodePtr localNode,
     411             :                              const uint32_t masterInstanceID );
     412             : 
     413             :     /** @internal Called when object is attached from the receiver thread. */
     414             :     CO_API virtual void attach( const uint128_t& id,
     415             :                                 const uint32_t instanceID );
     416             :     /**
     417             :      * @internal Called when the object is detached from the local node from the
     418             :      * receiver thread.
     419             :      */
     420             :     CO_API virtual void detach();
     421             : 
     422             :     /** @internal Transfer the attachment from the given object. */
     423             :     void transfer( Object* from );
     424             : 
     425             :     void applyMapData( const uint128_t& version ); //!< @internal
     426             :     void sendInstanceData( const Nodes& nodes ); //!< @internal
     427             :     //@}
     428             : 
     429             : protected:
     430             :     /** Construct a new distributed object. @version 1.0 */
     431             :     CO_API Object();
     432             : 
     433             :     /** NOP assignment operator. @version 1.0 */
     434             :     Object& operator = ( const Object& ) { return *this; }
     435             : 
     436             :     /** Copy construct a new, unattached object. @version 1.0 */
     437             :     CO_API explicit Object( const Object& );
     438             : 
     439             : private:
     440             :     detail::Object* const impl_;
     441             :     void _setChangeManager( ObjectCMPtr cm );
     442             : 
     443             :     ObjectCMPtr _getChangeManager();
     444             :     friend class ObjectStore;
     445             : 
     446         126 :     LB_TS_VAR( _thread );
     447             : };
     448             : 
     449             : /** Output information about the object to the given stream. @version 1.0 */
     450             : CO_API std::ostream& operator << ( std::ostream&, const Object& );
     451             : 
     452             : /** Output object change type in human-readably form. @version 1.0 */
     453             : CO_API std::ostream& operator << ( std::ostream&, const Object::ChangeType& );
     454             : }
     455             : 
     456             : namespace lunchbox
     457             : {
     458           0 : template<> inline void byteswap( co::Object::ChangeType& value )
     459           0 : { byteswap( reinterpret_cast< uint32_t& >( value )); }
     460             : }
     461             : #endif // CO_OBJECT_H

Generated by: LCOV version 1.11