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