LCOV - code coverage report
Current view: top level - eq/fabric - object.cpp (source / functions) Hit Total Coverage
Test: Equalizer Lines: 150 189 79.4 %
Date: 2017-12-16 05:07:20 Functions: 29 33 87.9 %

          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             : #include "object.h"
      20             : 
      21             : #include "event.h"
      22             : #include "task.h"
      23             : 
      24             : #include <co/dataIStream.h>
      25             : #include <co/dataOStream.h>
      26             : #include <co/iCommand.h>
      27             : #include <co/types.h>
      28             : 
      29             : namespace eq
      30             : {
      31             : namespace fabric
      32             : {
      33             : namespace detail
      34             : {
      35       39132 : struct BackupData
      36             : {
      37             :     /** The application-defined name of the object. */
      38             :     std::string name;
      39             : 
      40             :     /** The user data parameters if no _userData object is set. */
      41             :     co::ObjectVersion userData;
      42             : };
      43             : 
      44        9756 : class Object
      45             : {
      46             : public:
      47        8554 :     Object()
      48        8554 :         : userData(0)
      49             :         , tasks(TASK_NONE)
      50        8554 :         , serial(CO_INSTANCE_INVALID)
      51             :     {
      52        8554 :     }
      53             : 
      54        1224 :     Object(const Object& from)
      55        1224 :         : data(from.data)
      56             :         , backup()
      57        1224 :         , userData(from.userData)
      58        1224 :         , tasks(from.tasks)
      59        3672 :         , serial(from.serial)
      60             :     {
      61        1224 :     }
      62             : 
      63             :     // cppcheck-suppress operatorEqVarError
      64           0 :     Object& operator=(const Object& from)
      65             :     {
      66           0 :         if (this == &from)
      67           0 :             return *this;
      68             : 
      69           0 :         data = from.data;
      70           0 :         userData = from.userData;
      71           0 :         tasks = from.tasks;
      72           0 :         serial = from.serial;
      73           0 :         return *this;
      74             :     }
      75             : 
      76             :     BackupData data;   //!< Active data
      77             :     BackupData backup; //!< Backed up version (from .eqc)
      78             : 
      79             :     co::Object* userData; //!< User data object
      80             :     uint32_t tasks;       //!< Worst-case set of tasks
      81             :     uint32_t serial;      //!< Server-unique serial number
      82             : 
      83             :     /** The identifiers of removed children since the last slave commit. */
      84             :     std::vector<uint128_t> removedChildren;
      85             : };
      86             : }
      87             : 
      88        8554 : Object::Object()
      89        8554 :     : _impl(new detail::Object)
      90             : {
      91        8554 : }
      92             : 
      93        1224 : Object::Object(const Object& from)
      94             :     : co::Serializable(from)
      95        1224 :     , _impl(new detail::Object(*from._impl))
      96             : {
      97        1224 : }
      98             : 
      99       19512 : Object::~Object()
     100             : {
     101        9756 :     LBASSERTINFO(!isAttached(), "Object " << getID() << " is still attached");
     102        9756 :     LBASSERTINFO(!_impl->userData,
     103             :                  "Unset user data before destruction to allow clean release")
     104             : 
     105       19512 :     co::LocalNodePtr node = getLocalNode();
     106        9756 :     if (node.isValid())
     107           0 :         node->releaseObject(this);
     108        9756 :     delete _impl;
     109        9756 : }
     110             : 
     111           0 : Object& Object::operator=(const Object& from)
     112             : {
     113           0 :     if (this == &from)
     114           0 :         return *this;
     115             : 
     116           0 :     co::Serializable::operator=(from);
     117           0 :     *_impl = *from._impl;
     118           0 :     return *this;
     119             : }
     120             : 
     121        1708 : bool Object::isDirty() const
     122             : {
     123        1708 :     if (_impl->userData && _impl->userData->isAttached())
     124             :     {
     125          30 :         if (_impl->userData->isMaster())
     126          28 :             _impl->userData->sync(); // apply slave object commits
     127          30 :         return Serializable::isDirty() || _impl->userData->isDirty();
     128             :     }
     129             : 
     130             :     // else
     131        1678 :     return Serializable::isDirty();
     132             : }
     133             : 
     134         408 : uint128_t Object::commit(const uint32_t incarnation)
     135             : {
     136         408 :     if (!_impl->userData)
     137         378 :         return Serializable::commit(incarnation);
     138             : 
     139          30 :     if (!_impl->userData->isAttached() && hasMasterUserData())
     140             :     {
     141          14 :         getLocalNode()->registerObject(_impl->userData);
     142          14 :         _impl->userData->setAutoObsolete(getUserDataLatency() + 1);
     143          14 :         _impl->data.userData = _impl->userData;
     144          14 :         setDirty(DIRTY_USERDATA);
     145             :     }
     146             : 
     147          30 :     if (_impl->userData->isDirty() && _impl->userData->isAttached())
     148             :     {
     149           4 :         const uint128_t& version = _impl->userData->commit(incarnation);
     150           4 :         LBASSERT(version != co::VERSION_NONE);
     151           4 :         LBASSERT(!_impl->userData->isDirty());
     152           4 :         LBASSERT(_impl->data.userData.identifier != _impl->userData->getID() ||
     153             :                  _impl->data.userData.version <= version);
     154             : 
     155          14 :         if (_impl->userData->isMaster() &&
     156          10 :             _impl->data.userData != co::ObjectVersion(_impl->userData))
     157             :         {
     158           2 :             LBASSERTINFO(_impl->data.userData.identifier !=
     159             :                                  _impl->userData->getID() ||
     160             :                              _impl->data.userData.version <
     161             :                                  _impl->userData->getVersion(),
     162             :                          _impl->data.userData
     163             :                              << " >= " << co::ObjectVersion(_impl->userData));
     164             : 
     165           2 :             _impl->data.userData.identifier = _impl->userData->getID();
     166           2 :             _impl->data.userData.version = version;
     167           2 :             setDirty(DIRTY_USERDATA);
     168             :         }
     169             :     }
     170             : 
     171          30 :     return Serializable::commit(incarnation);
     172             : }
     173             : 
     174         116 : void Object::notifyDetach()
     175             : {
     176         116 :     Serializable::notifyDetach();
     177         116 :     if (!_impl->userData)
     178         114 :         return;
     179             : 
     180           2 :     LBASSERT(!_impl->userData->isAttached() ||
     181             :              _impl->userData->isMaster() == hasMasterUserData());
     182             : 
     183           2 :     if (_impl->userData->isMaster())
     184           0 :         _impl->data.userData = co::ObjectVersion(0);
     185             : 
     186           2 :     getLocalNode()->releaseObject(_impl->userData);
     187             : }
     188             : 
     189          64 : void Object::backup()
     190             : {
     191          64 :     LBASSERT(!_impl->userData);
     192          64 :     _impl->backup = _impl->data;
     193          64 : }
     194             : 
     195           0 : void Object::restore()
     196             : {
     197           0 :     LBASSERT(!_impl->userData);
     198           0 :     _impl->data = _impl->backup;
     199           0 :     setDirty(DIRTY_NAME | DIRTY_USERDATA);
     200           0 : }
     201             : 
     202         314 : void Object::serialize(co::DataOStream& os, const uint64_t dirtyBits)
     203             : {
     204         314 :     if (dirtyBits & DIRTY_NAME)
     205         136 :         os << _impl->data.name;
     206         314 :     if (dirtyBits & DIRTY_USERDATA)
     207         168 :         os << _impl->data.userData;
     208         314 :     if (dirtyBits & DIRTY_TASKS)
     209         136 :         os << _impl->tasks;
     210         314 :     if (dirtyBits & DIRTY_REMOVED)
     211             :     {
     212         136 :         LBASSERT(!isMaster() ||
     213             :                  (_impl->removedChildren.empty() && dirtyBits == DIRTY_ALL))
     214         136 :         os << _impl->removedChildren;
     215         136 :         _impl->removedChildren.clear();
     216             :     }
     217         314 :     if ((dirtyBits & DIRTY_SERIAL) && isMaster())
     218             :     {
     219         136 :         _impl->serial = getInstanceID();
     220         136 :         os << _impl->serial;
     221             :     }
     222         314 : }
     223             : 
     224         222 : void Object::deserialize(co::DataIStream& is, const uint64_t dirtyBits)
     225             : {
     226         222 :     if (dirtyBits & DIRTY_NAME)
     227          52 :         is >> _impl->data.name;
     228         222 :     if (dirtyBits & DIRTY_USERDATA)
     229             :     {
     230          86 :         is >> _impl->data.userData;
     231             :         // map&sync below to allow early exits
     232             :     }
     233         222 :     if (dirtyBits & DIRTY_TASKS)
     234          52 :         is >> _impl->tasks;
     235         222 :     if (dirtyBits & DIRTY_REMOVED)
     236             :     {
     237         104 :         std::vector<uint128_t> removed;
     238          52 :         is >> removed;
     239          52 :         if (!removed.empty())
     240             :         {
     241           0 :             LBASSERT(isMaster());
     242           0 :             std::vector<uint128_t>::const_iterator i = removed.begin();
     243           0 :             for (; i != removed.end(); ++i)
     244             :             {
     245           0 :                 removeChild(*i);
     246             :             }
     247             :         }
     248             :     }
     249         222 :     if ((dirtyBits & DIRTY_SERIAL) && !isMaster())
     250          52 :         is >> _impl->serial;
     251             : 
     252         222 :     if (isMaster()) // redistribute changes
     253          60 :         setDirty(dirtyBits & getRedistributableBits());
     254             : 
     255             :     // Update user data state
     256         222 :     if (!(dirtyBits & DIRTY_USERDATA) || !_impl->userData)
     257         202 :         return;
     258             : 
     259          20 :     LBASSERTINFO(_impl->data.userData.identifier != _impl->userData->getID() ||
     260             :                      _impl->data.userData.version >=
     261             :                          _impl->userData->getVersion() ||
     262             :                      _impl->userData->isMaster(),
     263             :                  "Incompatible version, new "
     264             :                      << _impl->data.userData << " old "
     265             :                      << co::ObjectVersion(_impl->userData));
     266             : 
     267          20 :     if (_impl->data.userData.identifier == 0)
     268             :     {
     269           2 :         if (_impl->userData->isAttached() && !_impl->userData->isMaster())
     270             :         {
     271           0 :             LBASSERT(!hasMasterUserData());
     272           0 :             getLocalNode()->unmapObject(_impl->userData);
     273             :         }
     274           2 :         return;
     275             :     }
     276             : 
     277          18 :     if (!_impl->userData->isAttached() && _impl->data.userData.identifier != 0)
     278             :     {
     279           2 :         LBASSERT(!hasMasterUserData());
     280           2 :         if (!getLocalNode()->mapObject(_impl->userData, _impl->data.userData))
     281             :         {
     282           0 :             LBWARN << "Mapping of " << lunchbox::className(_impl->userData)
     283           0 :                    << " user data failed" << std::endl;
     284           0 :             LBUNREACHABLE;
     285           0 :             return;
     286             :         }
     287             :     }
     288             : 
     289          18 :     if (!_impl->userData->isMaster() && _impl->userData->isAttached())
     290             :     {
     291           2 :         LBASSERTINFO(_impl->userData->getID() ==
     292             :                          _impl->data.userData.identifier,
     293             :                      _impl->userData->getID()
     294             :                          << " != " << _impl->data.userData.identifier);
     295           2 :         _impl->userData->sync(_impl->data.userData.version);
     296             :     }
     297             : }
     298             : 
     299        3346 : void Object::setName(const std::string& name)
     300             : {
     301        3346 :     if (_impl->data.name == name)
     302           0 :         return;
     303        3346 :     _impl->data.name = name;
     304        3346 :     setDirty(DIRTY_NAME);
     305             : }
     306             : 
     307          46 : void Object::setUserData(co::Object* userData)
     308             : {
     309          46 :     LBASSERT(!userData || !userData->isAttached());
     310             : 
     311          46 :     if (_impl->userData == userData)
     312          14 :         return;
     313             : 
     314          32 :     if (_impl->userData && _impl->userData->isAttached())
     315             :     {
     316          14 :         LBASSERT(_impl->userData->isMaster() == hasMasterUserData());
     317          14 :         _impl->userData->getLocalNode()->releaseObject(_impl->userData);
     318             :     }
     319             : 
     320          32 :     _impl->userData = userData;
     321             : 
     322          32 :     if (hasMasterUserData())
     323          28 :         setDirty(DIRTY_USERDATA);
     324           4 :     else if (_impl->data.userData.identifier != 0)
     325             :     {
     326           4 :         co::LocalNodePtr node = getLocalNode();
     327           2 :         if (node.isValid())
     328           0 :             node->mapObject(_impl->userData, _impl->data.userData);
     329             :     }
     330             : }
     331             : 
     332          32 : co::Object* Object::getUserData()
     333             : {
     334          32 :     return _impl->userData;
     335             : }
     336             : 
     337           2 : const co::Object* Object::getUserData() const
     338             : {
     339           2 :     return _impl->userData;
     340             : }
     341             : 
     342         512 : uint32_t Object::getTasks() const
     343             : {
     344         512 :     return _impl->tasks;
     345             : }
     346             : 
     347          68 : uint32_t Object::getSerial() const
     348             : {
     349          68 :     return _impl->serial;
     350             : }
     351             : 
     352       54554 : const std::string& Object::getName() const
     353             : {
     354       54554 :     return _impl->data.name;
     355             : }
     356             : 
     357         510 : void Object::setTasks(const uint32_t tasks)
     358             : {
     359         510 :     if (_impl->tasks == tasks)
     360         460 :         return;
     361          50 :     _impl->tasks = tasks;
     362          50 :     setDirty(DIRTY_TASKS);
     363             : }
     364             : 
     365        6580 : void Object::postRemove(Object* child)
     366             : {
     367        6580 :     LBASSERT(child);
     368        6580 :     if (!child->isAttached())
     369        6580 :         return;
     370             : 
     371           0 :     LBASSERT(!child->isMaster());
     372           0 :     LBASSERT(!isMaster());
     373             : 
     374           0 :     _impl->removedChildren.push_back(child->getID());
     375           0 :     setDirty(DIRTY_REMOVED);
     376             : 
     377           0 :     co::LocalNodePtr localNode = child->getLocalNode();
     378           0 :     localNode->releaseObject(child);
     379             : }
     380             : 
     381           6 : bool Object::_cmdSync(co::ICommand&)
     382             : {
     383           6 :     LBASSERT(isMaster());
     384           6 :     sync(co::VERSION_HEAD);
     385           6 :     return true;
     386             : }
     387             : 
     388          32 : void Object::updateEvent(Event& event, const int64_t time)
     389             : {
     390          32 :     event.serial = getSerial();
     391          32 :     event.time = time;
     392          32 :     event.originator = getID();
     393          32 : }
     394             : }
     395          60 : }

Generated by: LCOV version 1.11