// Ryzom - MMORPG Framework // Copyright (C) 2010 Winch Gate Property Limited // // This program is free software: you can redistribute it and/or modify // it under the terms of the GNU Affero General Public License as // published by the Free Software Foundation, either version 3 of the // License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU Affero General Public License for more details. // // You should have received a copy of the GNU Affero General Public License // along with this program. If not, see . #include "stdpch.h" #include "processing_spreader.h" #include "frontend_service.h" /* * Constructor */ CProcessingSpreader::CProcessingSpreader() : ExecutionPeriod(1), _ClientMapIndex(0), _Invalidated(true) #ifdef TEST_WORSE_EXECUTION_PERIOD , _Count(0) #endif { } /* * Initialization */ void CProcessingSpreader::init() { _ClientMapIterator = CFrontEndService::instance()->receiveSub()->clientMap().end(); } /* * Get the range (beginning iterator, index and outer bound) for the current processing */ void CProcessingSpreader::getProcessingBounds( THostMap::iterator& firstit, sint& firstindex, sint& outerboundindex ) { THostMap& clientmap = CFrontEndService::instance()->receiveSub()->clientMap(); sint nbClients = clientmap.size(); // Test if the index has reached the end of the client map if ( _ClientMapIndex >= nbClients ) { // The range begins at the beginning of the client map firstit = clientmap.begin(); firstindex = 0; } else { // Return the current iterator (if it is valid) if ( _Invalidated ) { _Invalidated = false; // Rescan the client map to get the new iterator // It is necessary when the client referenced by _ClientMapIndex left the FE. THostMap::iterator it = clientmap.begin(); for ( sint i=0; i!=_ClientMapIndex; ++i, ++it ); firstit = it; firstindex = _ClientMapIndex; //nlinfo( "%p: Scanning client map to index %d, iterator %p", this, firstindex, firstit ); } else { // _ClientMapIterator is valid if and only if endProcessing() was called // since the previous getProcessingBounds() firstit = _ClientMapIterator; firstindex = _ClientMapIndex; //nlinfo( "%p: Giving back index %d, iterator %p", this, firstindex, firstit ); } } sint maxNbClientsProcessedPerTick = MaxNbClients / ExecutionPeriod; outerboundindex = firstindex + min( maxNbClientsProcessedPerTick, nbClients - firstindex ); _ClientMapIndex = outerboundindex; } /* * Method to call after a new client is added into the clientmap */ void CProcessingSpreader::notifyClientAddition( THostMap::iterator endBeforeAddition ) { THostMap& clientmap = CFrontEndService::instance()->receiveSub()->clientMap(); //nlinfo( "%p: Addition, iterator=%p", this, _ClientMapIterator ); // NEW: Always (because an addition may be an insertion => mismatch between index and iterator) _ClientMapIterator = clientmap.begin(); _ClientMapIndex = 0; // If _ClientMapIterator was pointed on the end, reset it /*if ( _ClientMapIterator == endBeforeAddition ) { // Necessary for getProcessingBounds() to work when there is no invalidation _ClientMapIterator = clientmap.begin(); //nlinfo( "%p: Resetting to begin", this ); } */ } void CProcessingSpreader::notifyClientRemoval( THostMap::iterator icm ) { //nlinfo( "%p: Removal", this ); if ( (!_Invalidated) && (_ClientMapIterator == icm) ) // without the test of !_Invalidated, stldebug will cry in operator==() if calling notifyClientRemoval() twice (the second time, _ClientMapIterator points to an erased element) { _Invalidated = true; //nlinfo( "%p: Iterator=%p leaving => invalidate!" ); } }