Changeset 731
- Timestamp:
- 10/13/15 15:14:23 (9 years ago)
- Location:
- XIOS/trunk/src
- Files:
-
- 16 edited
Legend:
- Unmodified
- Added
- Removed
-
XIOS/trunk/src/array_new.hpp
r680 r731 518 518 virtual void reset(void) { this->free(); initialized = false; } 519 519 virtual bool isEmpty(void) const { return !initialized; } 520 virtual size_t size(void) const { return (this->dimensions() + 1) * sizeof(int) + sizeof(size_t) + this->numElements() * sizeof(T_numtype); } 520 virtual size_t size(void) const { return size(this->numElements()); } 521 static size_t size(sizeType numElements) { return (N_rank + 1) * sizeof(int) + sizeof(size_t) + numElements * sizeof(T_numtype); } 521 522 522 523 virtual CBaseType* clone(void) const { return new CArray(*this); } -
XIOS/trunk/src/context_client.cpp
r726 r731 73 73 } 74 74 75 76 75 /*! 77 76 In case of attached mode, the current context must be reset to context for client … … 80 79 void CContextClient::sendEvent(CEventClient& event) 81 80 { 82 list<int>::iterator itServer; 83 list<int> ranks; 84 list<int> sizes; 85 list<int>::iterator itSize; 86 87 ranks = event.getRanks(); 81 list<int> ranks = event.getRanks(); 88 82 if (!event.isEmpty()) 89 83 { 90 sizes = event.getSizes(); 91 CMessage msg; 92 93 msg << *(sizes.begin()) << timeLine; 94 for (list<int>::iterator it = sizes.begin(); it != sizes.end(); it++) *it += msg.size(); 84 list<int> sizes = event.getSizes(); 85 95 86 list<CBufferOut*> buffList = getBuffers(ranks, sizes); 96 87 97 list<CBufferOut*>::iterator it; 98 for (it = buffList.begin(), itSize = sizes.begin(); it != buffList.end(); ++it, ++itSize) 99 { 100 **it << *itSize << timeLine; 101 } 102 event.send(buffList); 88 event.send(timeLine, sizes, buffList); 89 103 90 checkBuffers(ranks); 104 91 } … … 271 258 Finalize context client and do some reports 272 259 */ 273 274 260 void CContextClient::finalize(void) 275 261 { 276 262 map<int,CClientBuffer*>::iterator itBuff; 277 263 bool stop = true; 278 264 279 265 CEventClient event(CContext::GetType(), CContext::EVENT_ID_CONTEXT_FINALIZE); 280 266 if (isServerLeader()) … … 309 295 310 296 releaseBuffers(); 311 312 297 } 313 298 } -
XIOS/trunk/src/event_client.cpp
r591 r731 8 8 namespace xios 9 9 { 10 CEventClient::CEventClient(int classId_,int typeId_) 10 const size_t CEventClient::headerSize = sizeof(int) + sizeof(size_t) + sizeof(int) + sizeof(classId) + sizeof(typeId); 11 12 CEventClient::CEventClient(int classId_, int typeId_) 11 13 { 12 classId =classId_;13 typeId =typeId_;14 classId = classId_; 15 typeId = typeId_; 14 16 } 15 16 void CEventClient::push(int rank, int nbSender,CMessage& msg)17 18 void CEventClient::push(int rank, int nbSender, CMessage& msg) 17 19 { 18 nbSenders.push_back(nbSender) 19 ranks.push_back(rank) 20 messages.push_back(&msg) 20 nbSenders.push_back(nbSender); 21 ranks.push_back(rank); 22 messages.push_back(&msg); 21 23 } 22 24 23 25 bool CEventClient::isEmpty(void) 24 26 { 25 return ranks.empty() 27 return ranks.empty(); 26 28 } 27 29 28 list<int> CEventClient::getRanks(void)30 std::list<int> CEventClient::getRanks(void) 29 31 { 30 return ranks ; 31 } 32 33 list<int> CEventClient::getSizes(void) 34 { 35 list<CMessage*>::iterator it ; 36 list<int> sizes ; 37 size_t headerSize=sizeof(int)+sizeof(classId)+sizeof(typeId) ; 38 39 for(it=messages.begin();it!=messages.end();++it) sizes.push_back((*it)->size()+headerSize) ; 40 return sizes ; 41 } 42 43 void CEventClient::send(list<CBufferOut*>& buffers) 44 { 45 list<CBufferOut*>::iterator itBuff ; 46 list<CMessage*>::iterator itMsg ; 47 list<int>::iterator itSenders ; 48 49 for(itBuff=buffers.begin(),itMsg=messages.begin(),itSenders=nbSenders.begin();itBuff!=buffers.end();++itBuff,++itMsg,++itSenders) 50 { 51 **itBuff<<*itSenders<<classId<<typeId<<**itMsg ; 52 } 53 } 54 /* 55 CEventClient::CEventClient(CContextClient& client_,int nbSender_,list<int>& serverList_) 56 { 57 client=&client_ ; 58 nbSender=nbSender_ ; 59 serverList=serverList_ ; 60 61 client->registerEvent(*this) ; 32 return ranks; 62 33 } 63 34 64 list<CBufferOut*> CEventClient::newEvent(int classId, int type, list<int> sizes)35 std::list<int> CEventClient::getSizes(void) 65 36 { 66 list<int>::iterator it ; 67 list<CBufferOut*>::iterator itBuff; 68 69 70 CMessage msg; 71 72 msg<<nbSender<<classId<<type ; 73 74 for(it=sizes.begin();it!=sizes.end();it++) *it+=msg.size() ; 75 list<CBufferOut*> buffers=client->newEvent(*this,sizes) ; 37 std::list<CMessage*>::iterator it; 38 std::list<int> sizes; 76 39 77 for(itBuff=buffers.begin();itBuff!=buffers.end();itBuff++) *(*itBuff)<<msg ; 78 79 return buffers ; 80 81 } 82 83 void CEventClient::send(void) 84 { 85 client->sendEvent(*this) ; 40 for (it = messages.begin(); it != messages.end(); ++it) sizes.push_back((*it)->size() + headerSize); 41 return sizes; 86 42 } 87 43 88 */ 89 44 void CEventClient::send(size_t timeLine, const std::list<int>& sizes, std::list<CBufferOut*>& buffers) 45 { 46 std::list<CBufferOut*>::iterator itBuff = buffers.begin(); 47 std::list<int>::const_iterator itSizes = sizes.begin(), itSenders = nbSenders.begin(); 48 std::list<CMessage*>::iterator itMsg = messages.begin(); 49 50 for (; itBuff != buffers.end(); ++itBuff, ++itSizes, ++itSenders, ++itMsg) 51 { 52 **itBuff << *itSizes << timeLine << *itSenders << classId << typeId << **itMsg; 53 } 54 } 90 55 } -
XIOS/trunk/src/event_client.hpp
r591 r731 8 8 namespace xios 9 9 { 10 11 10 class CEventClient 12 11 { 13 12 public: 14 15 // CEventClient(CContextClient& client,int nbSender,list<int>& serverList); 16 CEventClient(int classId, int typeId); 17 void push(int rank,int nbSender, CMessage& msg) ; 13 static const size_t headerSize; 18 14 19 // list<CBufferOut*> newEvent(int classId, int type, list<int> sizes) ; 20 list<int> getRanks(void) ; 21 list<int> getSizes(void) ; 22 void send(list<CBufferOut*>&) ; 23 bool isEmpty(void) ; 24 list<int> ranks ; 25 list<int> nbSenders ; 26 list<CMessage*> messages ; 27 // CContextClient* client ; 28 int classId ; 29 int typeId ; 30 } ; 15 CEventClient(int classId, int typeId); 31 16 17 void push(int rank, int nbSender, CMessage& msg); 18 void send(size_t timeLine, const std::list<int>& sizes, std::list<CBufferOut*>&); 19 20 bool isEmpty(void); 21 std::list<int> getRanks(void); 22 std::list<int> getSizes(void); 23 24 private: 25 int classId; 26 int typeId; 27 std::list<int> ranks; 28 std::list<int> nbSenders; 29 std::list<CMessage*> messages; 30 }; 32 31 } 33 32 -
XIOS/trunk/src/node/axis.cpp
r713 r731 116 116 { 117 117 return offsetWrittenIndexes_; 118 } 119 120 //---------------------------------------------------------------- 121 122 /*! 123 * Compute the minimum buffer size required to send the attributes to the server(s). 124 * 125 * \return A map associating the server rank with its minimum buffer size. 126 */ 127 std::map<int, StdSize> CAxis::getAttributesBufferSize() 128 { 129 CContextClient* client = CContext::getCurrent()->client; 130 131 std::map<int, StdSize> attributesSizes = getMinimumBufferSizeForAttributes(); 132 133 bool isNonDistributed = (n == n_glo); 134 135 if (client->isServerLeader()) 136 { 137 // size estimation for sendServerAttribut 138 size_t size = 6 * sizeof(size_t); 139 // size estimation for sendNonDistributedValue 140 if (isNonDistributed) 141 size = std::max(size, CArray<double,1>::size(n_glo) + (isCompressible_ ? CArray<int,1>::size(n_glo) : 0)); 142 size += CEventClient::headerSize + getId().size() + sizeof(size_t); 143 144 const std::list<int>& ranks = client->getRanksServerLeader(); 145 for (std::list<int>::const_iterator itRank = ranks.begin(), itRankEnd = ranks.end(); itRank != itRankEnd; ++itRank) 146 { 147 if (size > attributesSizes[*itRank]) 148 attributesSizes[*itRank] = size; 149 } 150 } 151 152 if (!isNonDistributed) 153 { 154 // size estimation for sendDistributedValue 155 std::map<int, std::vector<size_t> >::const_iterator it, ite = indSrv_.end(); 156 for (it = indSrv_.begin(); it != ite; ++it) 157 { 158 size_t sizeIndexEvent = CArray<int,1>::size(it->second.size()); 159 if (isCompressible_) 160 sizeIndexEvent += CArray<int,1>::size(indWrittenSrv_[it->first].size()); 161 162 size_t sizeValEvent = CArray<double,1>::size(it->second.size()); 163 if (hasBounds_) 164 sizeValEvent += CArray<double,2>::size(it->second.size()); 165 166 size_t size = CEventClient::headerSize + getId().size() + sizeof(size_t) + std::max(sizeIndexEvent, sizeValEvent); 167 if (size > attributesSizes[it->first]) 168 attributesSizes[it->first] = size; 169 } 170 } 171 172 return attributesSizes; 118 173 } 119 174 -
XIOS/trunk/src/node/axis.hpp
r676 r731 71 71 int getTotalNumberWrittenIndexes() const; 72 72 int getOffsetWrittenIndexes() const; 73 74 std::map<int, StdSize> getAttributesBufferSize(); 73 75 74 76 /// Test /// -
XIOS/trunk/src/node/context.cpp
r730 r731 266 266 void CContext::setClientServerBuffer() 267 267 { 268 size_t bufferSizeMin= CXios::minBufferSize;268 size_t minBufferSize = CXios::minBufferSize; 269 269 #define DECLARE_NODE(Name_, name_) \ 270 if ( bufferSizeMin < sizeof(C##Name_##Definition)) bufferSizeMin= sizeof(C##Name_##Definition);270 if (minBufferSize < sizeof(C##Name_##Definition)) minBufferSize = sizeof(C##Name_##Definition); 271 271 #define DECLARE_NODE_PAR(Name_, name_) 272 272 #include "node_type.conf" … … 274 274 #undef DECLARE_NODE_PAR 275 275 276 std::map<int, StdSize> bufferSize = getDataSize(); 277 std::map<int, StdSize>::iterator it = bufferSize.begin(), 278 ite = bufferSize.end(); 279 for (; it != ite; ++it) 280 if (it->second < bufferSizeMin) it->second = bufferSizeMin; 276 std::map<int, StdSize> bufferSize = getAttributesBufferSize(); 277 std::map<int, StdSize>::iterator it, ite = bufferSize.end(); 278 for (it = bufferSize.begin(); it != ite; ++it) 279 if (it->second < minBufferSize) it->second = minBufferSize; 280 281 std::map<int, StdSize> dataBufferSize = getDataBufferSize(); 282 ite = dataBufferSize.end(); 283 for (it = dataBufferSize.begin(); it != ite; ++it) 284 if (it->second > bufferSize[it->first]) bufferSize[it->first] = it->second; 281 285 282 286 if (client->isServerLeader()) … … 284 288 const std::list<int>& ranks = client->getRanksServerLeader(); 285 289 for (std::list<int>::const_iterator itRank = ranks.begin(), itRankEnd = ranks.end(); itRank != itRankEnd; ++itRank) 286 if (!bufferSize.count(*itRank)) bufferSize[*itRank] = bufferSizeMin;290 if (!bufferSize.count(*itRank)) bufferSize[*itRank] = minBufferSize; 287 291 } 288 292 … … 791 795 } 792 796 793 std::map<int, StdSize>& CContext::getDataSize() 797 std::map<int, StdSize>& CContext::getAttributesBufferSize() 798 { 799 std::map<int, StdSize> attributesSize; 800 801 size_t numEnabledFiles = this->enabledFiles.size(); 802 for (size_t i = 0; i < numEnabledFiles; ++i) 803 { 804 CFile* file = this->enabledFiles[i]; 805 806 std::vector<CField*> enabledFields = file->getEnabledFields(); 807 size_t numEnabledFields = enabledFields.size(); 808 for (size_t j = 0; j < numEnabledFields; ++j) 809 { 810 const std::map<int, StdSize> mapSize = enabledFields[j]->getGridAttributesBufferSize(); 811 std::map<int, StdSize>::const_iterator it = mapSize.begin(), itE = mapSize.end(); 812 for (; it != itE; ++it) 813 { 814 // If attributesSize[it->first] does not exist, it will be zero-initialized 815 // so we can use it safely without checking for its existance 816 if (attributesSize[it->first] < it->second) 817 attributesSize[it->first] = it->second; 818 } 819 } 820 } 821 822 return attributesSize; 823 } 824 825 std::map<int, StdSize>& CContext::getDataBufferSize() 794 826 { 795 827 CFile::mode_attr::t_enum mode = hasClient ? CFile::mode_attr::write : CFile::mode_attr::read; … … 810 842 for (size_t j = 0; j < numEnabledFields; ++j) 811 843 { 812 const std::map<int, StdSize> mapSize = enabledFields[j]->getGridData Size();844 const std::map<int, StdSize> mapSize = enabledFields[j]->getGridDataBufferSize(); 813 845 std::map<int, StdSize>::const_iterator it = mapSize.begin(), itE = mapSize.end(); 814 846 for (; it != itE; ++it) -
XIOS/trunk/src/node/context.hpp
r730 r731 120 120 void postProcessing(); 121 121 122 std::map<int, StdSize>& getDataSize(); 122 std::map<int, StdSize>& getAttributesBufferSize(); 123 std::map<int, StdSize>& getDataBufferSize(); 123 124 void setClientServerBuffer(); 124 125 -
XIOS/trunk/src/node/domain.cpp
r727 r731 102 102 { 103 103 return offsetWrittenIndexes_; 104 } 105 106 //---------------------------------------------------------------- 107 108 /*! 109 * Compute the minimum buffer size required to send the attributes to the server(s). 110 * 111 * \return A map associating the server rank with its minimum buffer size. 112 */ 113 std::map<int, StdSize> CDomain::getAttributesBufferSize() 114 { 115 CContextClient* client = CContext::getCurrent()->client; 116 117 std::map<int, StdSize> attributesSizes = getMinimumBufferSizeForAttributes(); 118 119 if (client->isServerLeader()) 120 { 121 // size estimation for sendServerAttribut 122 size_t size = 11 * sizeof(size_t); 123 124 const std::list<int>& ranks = client->getRanksServerLeader(); 125 for (std::list<int>::const_iterator itRank = ranks.begin(), itRankEnd = ranks.end(); itRank != itRankEnd; ++itRank) 126 { 127 if (size > attributesSizes[*itRank]) 128 attributesSizes[*itRank] = size; 129 } 130 } 131 132 std::map<int, std::vector<size_t> >::const_iterator it, ite = indSrv_.end(); 133 for (it = indSrv_.begin(); it != ite; ++it) 134 { 135 // size estimation for sendIndex (and sendArea which is always smaller or equal) 136 size_t sizeIndexEvent = 2 * sizeof(size_t) + 2 * CArray<int,1>::size(it->second.size()); 137 if (isCompressible_) 138 sizeIndexEvent += CArray<int,1>::size(indWrittenSrv_[it->first].size()); 139 140 // size estimation for sendLonLat 141 size_t sizeLonLatEvent = CArray<double,1>::size(it->second.size()); 142 if (hasBounds) 143 sizeLonLatEvent += CArray<double,2>::size(it->second.size()); 144 145 size_t size = CEventClient::headerSize + getId().size() + sizeof(size_t) + std::max(sizeIndexEvent, sizeLonLatEvent); 146 if (size > attributesSizes[it->first]) 147 attributesSizes[it->first] = size; 148 } 149 150 return attributesSizes; 104 151 } 105 152 -
XIOS/trunk/src/node/domain.hpp
r727 r731 90 90 int getTotalNumberWrittenIndexes() const; 91 91 int getOffsetWrittenIndexes() const; 92 93 std::map<int, StdSize> getAttributesBufferSize(); 92 94 93 95 bool isEmpty(void) const; -
XIOS/trunk/src/node/field.cpp
r708 r731 527 527 } 528 528 529 std::map<int, StdSize> CField::getGridDataSize() 530 { 531 return grid->getConnectedServerDataSize(); 529 std::map<int, StdSize> CField::getGridAttributesBufferSize() 530 { 531 return grid->getAttributesBufferSize(); 532 } 533 534 std::map<int, StdSize> CField::getGridDataBufferSize() 535 { 536 return grid->getDataBufferSize(getId()); 532 537 } 533 538 -
XIOS/trunk/src/node/field.hpp
r707 r731 93 93 void resetNStepMax(); 94 94 95 std::map<int, StdSize> getGridDataSize(); 95 std::map<int, StdSize> getGridAttributesBufferSize(); 96 std::map<int, StdSize> getGridDataBufferSize(); 96 97 97 98 public: -
XIOS/trunk/src/node/grid.cpp
r721 r731 84 84 } 85 85 86 std::map<int, StdSize> CGrid::getConnectedServerDataSize() 87 { 88 double secureFactor = 2.5 * sizeof(double) * CXios::bufferSizeFactor; 89 StdSize retVal = 1; 90 std::map<int, StdSize> ret; 91 std::map<int, size_t >::const_iterator itb = connectedDataSize_.begin(), it, itE = connectedDataSize_.end(); 92 93 if (isScalarGrid()) 86 /*! 87 * Compute the minimum buffer size required to send the attributes to the server(s). 88 * 89 * \return A map associating the server rank with its minimum buffer size. 90 */ 91 std::map<int, StdSize> CGrid::getAttributesBufferSize() 92 { 93 std::map<int, StdSize> attributesSizes = getMinimumBufferSizeForAttributes(); 94 95 // The grid indexes require a similar size as the actual data 96 std::map<int, StdSize> dataSizes = getDataBufferSize(); 97 std::map<int, StdSize>::iterator it, itE = dataSizes.end(); 98 for (it = dataSizes.begin(); it != itE; ++it) 94 99 { 95 for (it = itb; it != itE; ++it) 100 it->second += 2 * sizeof(bool); 101 if (it->second > attributesSizes[it->first]) 102 attributesSizes[it->first] = it->second; 103 } 104 105 // Account for the axis attributes 106 std::vector<CAxis*> axisList = getAxis(); 107 for (size_t i = 0; i < axisList.size(); ++i) 108 { 109 std::map<int, StdSize> axisAttBuffSize = axisList[i]->getAttributesBufferSize(); 110 for (it = axisAttBuffSize.begin(), itE = axisAttBuffSize.end(); it != itE; ++it) 96 111 { 97 retVal *= secureFactor; 98 ret.insert(std::make_pair(it->first, retVal)); 99 } 100 return ret; 101 } 102 103 for (it = itb; it != itE; ++it) 104 { 105 retVal = it->second; 106 retVal *= secureFactor; 107 ret.insert(std::make_pair<int,StdSize>(it->first, retVal)); 108 } 109 110 if (connectedDataSize_.empty()) 111 { 112 for (int i = 0; i < connectedServerRank_.size(); ++i) 113 { 114 retVal = 1; 115 retVal *= secureFactor; 116 ret.insert(std::make_pair<int,StdSize>(connectedServerRank_[i], retVal)); 112 if (it->second > attributesSizes[it->first]) 113 attributesSizes[it->first] = it->second; 117 114 } 118 115 } 119 116 120 // In some cases in which domain is masked, we need to count for connected server for longitude and latitude121 std::vector<CDomain*> domList P = this->getDomains();122 if (!domListP.empty())117 // Account for the domain attributes 118 std::vector<CDomain*> domList = getDomains(); 119 for (size_t i = 0; i < domList.size(); ++i) 123 120 { 124 for (int i = 0; i < domListP.size(); ++i) 121 std::map<int, StdSize> domAttBuffSize = domList[i]->getAttributesBufferSize(); 122 for (it = domAttBuffSize.begin(), itE = domAttBuffSize.end(); it != itE; ++it) 125 123 { 126 const std::map<int, vector<size_t> >& indexDomainServer = domListP[i]->getIndexServer(); 127 std::map<int, vector<size_t> >::const_iterator itDom = indexDomainServer.begin(), iteDom = indexDomainServer.end(); 128 for (; itDom != iteDom; ++itDom) 129 { 130 if (ret.end() == ret.find(itDom->first)) 131 { 132 retVal = (itDom->second).size(); 133 retVal *= secureFactor; 134 ret.insert(std::make_pair<int,StdSize>(itDom->first, retVal)); 135 } 136 } 124 if (it->second > attributesSizes[it->first]) 125 attributesSizes[it->first] = it->second; 137 126 } 138 127 } 139 140 return ret; 128 129 return attributesSizes; 130 } 131 132 /*! 133 * Compute the minimum buffer size required to send the data to the server(s). 134 * 135 * \param id the id used to tag the data 136 * \return A map associating the server rank with its minimum buffer size. 137 */ 138 std::map<int, StdSize> CGrid::getDataBufferSize(const std::string& id /*= ""*/) 139 { 140 std::map<int, StdSize> dataSizes; 141 const size_t extraSize = CEventClient::headerSize + (id.empty() ? getId() : id).size() + sizeof(size_t); 142 143 std::map<int, size_t>::const_iterator itb = connectedDataSize_.begin(), it, itE = connectedDataSize_.end(); 144 for (it = itb; it != itE; ++it) 145 dataSizes.insert(std::make_pair(it->first, extraSize + CArray<double,1>::size(it->second))); 146 147 return dataSizes; 141 148 } 142 149 -
XIOS/trunk/src/node/grid.hpp
r687 r731 158 158 void computeDomConServer(); 159 159 std::map<int, int> getDomConServerSide(); 160 std::map<int, StdSize> getConnectedServerDataSize(); 160 std::map<int, StdSize> getAttributesBufferSize(); 161 std::map<int, StdSize> getDataBufferSize(const std::string& id = ""); 161 162 std::vector<StdString> getDomainList(); 162 163 std::vector<StdString> getAxisList(); -
XIOS/trunk/src/object_template.hpp
r591 r731 54 54 /// Traitement statique /// 55 55 static void ClearAllAttributes(void); 56 std::map<int, size_t> getMinimumBufferSizeForAttributes(); 56 57 void sendAttributToServer(const string& id); 57 58 void sendAttributToServer(CAttribute& attr) ; -
XIOS/trunk/src/object_template_impl.hpp
r595 r731 162 162 163 163 template<typename T> 164 std::map<int, size_t> CObjectTemplate<T>::getMinimumBufferSizeForAttributes() 165 { 166 CContextClient* client = CContext::getCurrent()->client; 167 std::map<int, size_t> minimumSizes; 168 169 if (client->isServerLeader()) 170 { 171 size_t minimumSize = 0; 172 CAttributeMap& attrMap = *this; 173 CAttributeMap::const_iterator it = attrMap.begin(), itE = attrMap.end(); 174 for (; it != itE; ++it) 175 { 176 if (!it->second->isEmpty()) 177 { 178 size_t size = it->second->getName().size() + it->second->size(); 179 if (size > minimumSize) 180 minimumSize = size; 181 } 182 } 183 184 if (minimumSize) 185 { 186 // Account for extra header info 187 minimumSize += CEventClient::headerSize + getIdServer().size(); 188 189 const std::list<int>& ranks = client->getRanksServerLeader(); 190 for (std::list<int>::const_iterator itRank = ranks.begin(), itRankEnd = ranks.end(); itRank != itRankEnd; ++itRank) 191 minimumSizes.insert(std::make_pair(*itRank, minimumSize)); 192 } 193 } 194 195 return minimumSizes; 196 } 197 198 template<typename T> 164 199 void CObjectTemplate<T>::sendAllAttributesToServer() 165 200 { … … 170 205 if (!(it->second)->isEmpty()) sendAttributToServer(*(it->second)); 171 206 } 172 173 207 } 174 208
Note: See TracChangeset
for help on using the changeset viewer.