Line data Source code
1 :
2 : /* Copyright (c) 2009-2014, Stefan Eilemann <eile@equalizergraphics.com>
3 : * 2012, Daniel Nachbaur <danielnachbaur@gmail.com>
4 : *
5 : * This library is free software; you can redistribute it and/or modify it under
6 : * the terms of the GNU Lesser General Public License version 2.1 as published
7 : * by the Free Software Foundation.
8 : *
9 : * This library is distributed in the hope that it will be useful, but WITHOUT
10 : * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
11 : * FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
12 : * details.
13 : *
14 : * You should have received a copy of the GNU Lesser General Public License
15 : * along with this library; if not, write to the Free Software Foundation, Inc.,
16 : * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
17 : */
18 :
19 : #ifndef EQFABRIC_OBJECT_H
20 : #define EQFABRIC_OBJECT_H
21 :
22 : #include <eq/fabric/api.h>
23 : #include <eq/fabric/error.h> // enum
24 : #include <eq/fabric/types.h>
25 : #include <co/objectOCommand.h> // used inline send()
26 : #include <co/objectVersion.h> // member
27 : #include <co/serializable.h> // base class
28 :
29 : namespace eq
30 : {
31 : namespace fabric
32 : {
33 : namespace detail { class Object; }
34 :
35 : /**
36 : * Internal base class for all distributed, inheritable Equalizer objects.
37 : *
38 : * This class provides common data storage used by all Equalizer resource
39 : * entities. Do not subclass directly.
40 : */
41 : class Object : public co::Serializable
42 : {
43 : public:
44 : /** @name Data Access. */
45 : //@{
46 : /** Set the name of the object. @version 1.0 */
47 : EQFABRIC_API virtual void setName( const std::string& name );
48 :
49 : /** @return the name of the object. @version 1.0 */
50 : EQFABRIC_API const std::string& getName() const;
51 :
52 : /**
53 : * Set user-specific data.
54 : *
55 : * Registration, mapping, commit and sync of the user data object are
56 : * automatically executed when committing and syncing this object. Not all
57 : * instances of the object have to set a user data object. All instances
58 : * have to set the same type of object.
59 : * @version 1.0
60 : */
61 : EQFABRIC_API void setUserData( co::Object* userData );
62 :
63 : /** @return the user-specific data. @version 1.0 */
64 : EQFABRIC_API co::Object* getUserData();
65 :
66 : /** @return the user-specific data. @version 1.0 */
67 : EQFABRIC_API const co::Object* getUserData() const;
68 : //@}
69 :
70 : /** @name Data Access */
71 : //@{
72 : /**
73 : * Return the set of tasks this channel might execute in the worst case.
74 : *
75 : * It is not guaranteed that all the tasks will be actually executed during
76 : * rendering.
77 : *
78 : * @return the tasks.
79 : * @warning Experimental - may not be supported in the future
80 : */
81 : EQFABRIC_API uint32_t getTasks() const;
82 :
83 : EQFABRIC_API uint32_t getSerial() const;
84 : //@}
85 :
86 : /** @return true if the object has data to commit. @version 1.0 */
87 : EQFABRIC_API virtual bool isDirty() const;
88 :
89 : /** @internal */
90 : EQFABRIC_API virtual uint128_t commit( const uint32_t incarnation =
91 : CO_COMMIT_NEXT );
92 :
93 : /** @internal Back up app-specific data, excluding child data. */
94 : EQFABRIC_API virtual void backup();
95 :
96 : /** @internal Restore the last backup. */
97 : EQFABRIC_API virtual void restore();
98 :
99 : /**
100 : * The changed parts of the object since the last pack().
101 : *
102 : * Subclasses should define their own bits, starting at DIRTY_CUSTOM.
103 : */
104 : enum DirtyBits
105 : {
106 : DIRTY_NAME = Serializable::DIRTY_CUSTOM << 0, // 1
107 : DIRTY_USERDATA = Serializable::DIRTY_CUSTOM << 1, // 2
108 : DIRTY_TASKS = Serializable::DIRTY_CUSTOM << 2, // 4
109 : DIRTY_REMOVED = Serializable::DIRTY_CUSTOM << 3, // 8
110 : DIRTY_SERIAL = Serializable::DIRTY_CUSTOM << 4, // 16
111 : // Leave room for binary-compatible patches
112 : DIRTY_CUSTOM = Serializable::DIRTY_CUSTOM << 6, // 64
113 : DIRTY_OBJECT_BITS = DIRTY_NAME | DIRTY_USERDATA
114 : };
115 :
116 : protected:
117 : /** Construct a new Object. */
118 : EQFABRIC_API Object();
119 :
120 : /** Construct an unmapped, unregistered copy of an object. */
121 : EQFABRIC_API Object( const Object& );
122 :
123 : /** Destruct the object. */
124 : EQFABRIC_API virtual ~Object();
125 :
126 : /** NOP assignment operator. @version 1.1.1 */
127 : EQFABRIC_API Object& operator = ( const Object& from );
128 :
129 : /**
130 : * @return true if this instance shall hold the master instance of the
131 : * user data object, false otherwise.
132 : */
133 0 : virtual bool hasMasterUserData() { return false; }
134 :
135 : /** @return the latency to be used for keeping user data versions. */
136 0 : virtual uint32_t getUserDataLatency() const { return 0; }
137 :
138 : /** @internal Set the tasks this entity might potentially execute. */
139 : EQFABRIC_API void setTasks( const uint32_t tasks );
140 :
141 : EQFABRIC_API virtual void notifyDetach();
142 :
143 : EQFABRIC_API virtual void serialize( co::DataOStream& os,
144 : const uint64_t dirtyBits );
145 : EQFABRIC_API virtual void deserialize( co::DataIStream& is,
146 : const uint64_t dirtyBits );
147 :
148 : /** @internal @return the bits to be re-committed by the master. */
149 0 : virtual uint64_t getRedistributableBits() const
150 0 : { return DIRTY_OBJECT_BITS; }
151 :
152 : /**
153 : * @internal
154 : * Remove the given child on the master during the next commit.
155 : * @sa removeChild
156 : */
157 : EQFABRIC_API void postRemove( Object* child );
158 :
159 : /** @internal Execute the slave remove request. @sa postRemove */
160 0 : virtual void removeChild( const uint128_t& ) { LBUNIMPLEMENTED; }
161 :
162 : /** @internal commit, register child slave instance with the server. */
163 : template< class C, class S >
164 : void commitChild( C* child, S* sender, uint32_t cmd,
165 : const uint32_t incarnation );
166 :
167 : /** @internal commit slave instance to the server. */
168 : template< class C > inline
169 0 : void commitChild( C* child, const uint32_t incarnation )
170 : {
171 0 : LBASSERT( child->isAttached( ));
172 0 : child->commit( incarnation );
173 0 : }
174 :
175 : /** @internal commit, register child slave instances with the server. */
176 : template< class C, class S >
177 : void commitChildren( const std::vector< C* >& children, S* sender,
178 : uint32_t cmd, const uint32_t incarnation );
179 :
180 : /** @internal commit, register child slave instances with the server. */
181 : template< class C >
182 73586 : void commitChildren( const std::vector< C* >& children, uint32_t cmd,
183 : const uint32_t incarnation )
184 73586 : { commitChildren< C, Object >( children, this, cmd, incarnation ); }
185 :
186 : /** @internal commit all children. */
187 : template< class C >
188 : void commitChildren( const std::vector< C* >& children,
189 : const uint32_t incarnation );
190 :
191 : /** @internal sync all children to head version. */
192 : template< class C >
193 : void syncChildren( const std::vector< C* >& children );
194 :
195 : /** @internal unmap/deregister all children. */
196 : template< class P, class C >
197 : inline void releaseChildren( const std::vector< C* >& children );
198 :
199 : /** @internal sync master object to the given slave commit. */
200 : EQFABRIC_API bool _cmdSync( co::ICommand& command );
201 :
202 : private:
203 : detail::Object* const _impl;
204 : };
205 :
206 : // Template Implementation
207 : template< class C, class S > inline void
208 156437 : Object::commitChild( C* child, S* sender, uint32_t cmd,
209 : const uint32_t incarnation )
210 : {
211 156437 : if( !child->isAttached( ))
212 : {
213 0 : LBASSERT( !isMaster( ));
214 0 : co::LocalNodePtr localNode = child->getConfig()->getLocalNode();
215 : lunchbox::Request< uint128_t > request =
216 0 : localNode->registerRequest< uint128_t >();
217 0 : co::NodePtr node = child->getServer().get();
218 0 : sender->send( node, cmd ) << request;
219 :
220 0 : LBCHECK( localNode->mapObject( child, request.wait(),
221 0 : co::VERSION_NONE ));
222 : }
223 156437 : child->commit( incarnation );
224 156437 : }
225 :
226 : template< class C, class S > inline void
227 92023 : Object::commitChildren( const std::vector< C* >& children, S* sender,
228 : uint32_t cmd, const uint32_t incarnation )
229 : {
230 : // TODO Opt: async register and commit
231 745380 : for( typename std::vector< C* >::const_iterator i = children.begin();
232 496920 : i != children.end(); ++i )
233 : {
234 156437 : C* child = *i;
235 156437 : commitChild< C, S >( child, sender, cmd, incarnation );
236 : }
237 92023 : }
238 :
239 : template< class C >
240 47 : inline void Object::commitChildren( const std::vector< C* >& children,
241 : const uint32_t incarnation )
242 : {
243 : // TODO Opt: async commit
244 360 : for( typename std::vector< C* >::const_iterator i = children.begin();
245 240 : i != children.end(); ++i )
246 : {
247 73 : C* child = *i;
248 73 : LBASSERT( child->isAttached( ));
249 73 : child->commit( incarnation );
250 : }
251 47 : }
252 :
253 : template< class C >
254 99 : inline void Object::syncChildren( const std::vector< C* >& children )
255 : {
256 798 : for( typename std::vector< C* >::const_iterator i = children.begin();
257 532 : i != children.end(); ++i )
258 : {
259 167 : C* child = *i;
260 167 : LBASSERT( child->isMaster( )); // slaves are synced using version
261 167 : child->sync();
262 : }
263 99 : }
264 :
265 : template< class P, class C >
266 146 : inline void Object::releaseChildren( const std::vector< C* >& children )
267 : {
268 292 : for( size_t i = children.size(); i > 0; --i )
269 : {
270 146 : C* child = children[ i - 1 ];
271 :
272 146 : if( child->isAttached( ))
273 : {
274 73 : getLocalNode()->releaseObject( child );
275 73 : if( !isMaster( ))
276 : {
277 73 : static_cast< P* >( this )->_removeChild( child );
278 73 : static_cast< P* >( this )->release( child );
279 : }
280 : }
281 : else
282 : {
283 73 : LBASSERT( isMaster( ));
284 : }
285 : }
286 146 : }
287 : }
288 : }
289 : #endif // EQFABRIC_OBJECT_H
|