TuttleOFX
1
|
00001 #include "MemoryCache.hpp" 00002 #include <tuttle/host/attribute/Image.hpp> // to know the function getReference() 00003 #include <tuttle/common/utils/global.hpp> 00004 #include <boost/foreach.hpp> 00005 00006 #include <functional> 00007 00008 namespace tuttle { 00009 namespace host { 00010 namespace memory { 00011 00012 namespace { 00013 00014 /// Check if the cache element is kept in the cache, but is not required by someone else. 00015 bool isUnused( const CACHE_ELEMENT& cacheElement ) 00016 { 00017 return cacheElement->getReferenceCount( ofx::imageEffect::OfxhImage::eReferenceOwnerHost ) < 1; 00018 } 00019 00020 /// Functor to get the smallest unused element in cache 00021 struct UnusedDataFitSize : public std::unary_function<CACHE_ELEMENT*, void> 00022 { 00023 UnusedDataFitSize( std::size_t size ) 00024 : _sizeNeeded( size ) 00025 , _bestMatchDiff( ULONG_MAX ) 00026 , _pBestMatch() 00027 {} 00028 00029 void operator()( const std::pair<Key, CACHE_ELEMENT>& pData ) 00030 { 00031 // used data 00032 if( ! isUnused( pData.second ) ) 00033 return; 00034 00035 const std::size_t bufferSize = pData.second->getPoolData()->reservedSize(); 00036 00037 // Check minimum amount of memory 00038 if( _sizeNeeded > bufferSize ) 00039 return; 00040 00041 const std::size_t diff = bufferSize - _sizeNeeded; 00042 if( diff >= _bestMatchDiff ) 00043 return; 00044 _bestMatchDiff = diff; 00045 _pBestMatch = pData.second; 00046 } 00047 00048 CACHE_ELEMENT bestMatch() 00049 { 00050 return _pBestMatch; 00051 } 00052 00053 private: 00054 const std::size_t _sizeNeeded; 00055 std::size_t _bestMatchDiff; 00056 CACHE_ELEMENT _pBestMatch; 00057 }; 00058 00059 } 00060 00061 MemoryCache& MemoryCache::operator=( const MemoryCache& cache ) 00062 { 00063 if( &cache == this ) 00064 return *this; 00065 boost::mutex::scoped_lock lockerMap1( cache._mutexMap ); 00066 boost::mutex::scoped_lock lockerMap2( _mutexMap ); 00067 _map = cache._map; 00068 return *this; 00069 } 00070 00071 void MemoryCache::put( const std::string& identifier, const double time, CACHE_ELEMENT pData ) 00072 { 00073 boost::mutex::scoped_lock lockerMap( _mutexMap ); 00074 _map[Key( identifier, time )] = pData; 00075 } 00076 00077 CACHE_ELEMENT MemoryCache::get( const std::string& identifier, const double time ) const 00078 { 00079 boost::mutex::scoped_lock lockerMap( _mutexMap ); 00080 MAP::const_iterator itr = _map.find( Key( identifier, time ) ); 00081 00082 if( itr == _map.end() ) 00083 return CACHE_ELEMENT(); 00084 return itr->second; 00085 } 00086 00087 CACHE_ELEMENT MemoryCache::get( const std::size_t& i ) const 00088 { 00089 boost::mutex::scoped_lock lockerMap( _mutexMap ); 00090 MAP::const_iterator itr = _map.begin(); 00091 for( unsigned int j = 0; j < i && itr != _map.end(); ++j ) 00092 ++itr; 00093 00094 if( itr == _map.end() ) 00095 return CACHE_ELEMENT(); 00096 return itr->second; 00097 } 00098 00099 CACHE_ELEMENT MemoryCache::getUnusedWithSize( const std::size_t requestedSize ) const 00100 { 00101 boost::mutex::scoped_lock lockerMap( _mutexMap ); 00102 return std::for_each( _map.begin(), _map.end(), UnusedDataFitSize( requestedSize ) ).bestMatch(); 00103 } 00104 00105 std::size_t MemoryCache::size() const 00106 { 00107 boost::mutex::scoped_lock lockerMap( _mutexMap ); 00108 return _map.size(); 00109 } 00110 00111 bool MemoryCache::empty() const 00112 { 00113 boost::mutex::scoped_lock lockerMap( _mutexMap ); 00114 return _map.empty(); 00115 } 00116 00117 bool MemoryCache::inCache( const CACHE_ELEMENT& pData ) const 00118 { 00119 boost::mutex::scoped_lock lockerMap( _mutexMap ); 00120 return getIteratorForValue( pData ) != _map.end(); 00121 } 00122 00123 namespace { 00124 00125 const std::string EMPTY_STRING = ""; 00126 00127 template<typename T> 00128 struct FindValuePredicate : public std::unary_function<typename T::value_type, bool> 00129 { 00130 const typename T::mapped_type & _value; 00131 FindValuePredicate( const typename T::mapped_type& value ) : _value( value ) {} 00132 00133 bool operator()( const typename T::value_type& pair ) 00134 { 00135 return pair.second == _value; 00136 } 00137 00138 }; 00139 00140 } 00141 00142 MemoryCache::MAP::const_iterator MemoryCache::getIteratorForValue( const CACHE_ELEMENT& pData ) const 00143 { 00144 return std::find_if( _map.begin(), _map.end(), FindValuePredicate<MAP>( pData ) ); 00145 } 00146 00147 MemoryCache::MAP::iterator MemoryCache::getIteratorForValue( const CACHE_ELEMENT& pData ) 00148 { 00149 return std::find_if( _map.begin(), _map.end(), FindValuePredicate<MAP>( pData ) ); 00150 } 00151 00152 double MemoryCache::getTime( const CACHE_ELEMENT& pData ) const 00153 { 00154 boost::mutex::scoped_lock lockerMap( _mutexMap ); 00155 MAP::const_iterator itr = getIteratorForValue( pData ); 00156 00157 if( itr == _map.end() ) 00158 return 0; 00159 return itr->first._time; 00160 } 00161 00162 const std::string& MemoryCache::getPluginName( const CACHE_ELEMENT& pData ) const 00163 { 00164 boost::mutex::scoped_lock lockerMap( _mutexMap ); 00165 MAP::const_iterator itr = getIteratorForValue( pData ); 00166 00167 if( itr == _map.end() ) 00168 return EMPTY_STRING; 00169 return itr->first._identifier; 00170 } 00171 00172 bool MemoryCache::remove( const CACHE_ELEMENT& pData ) 00173 { 00174 boost::mutex::scoped_lock lockerMap( _mutexMap ); 00175 const MAP::iterator itr = getIteratorForValue( pData ); 00176 00177 if( itr == _map.end() ) 00178 return false; 00179 _map.erase( itr ); 00180 return true; 00181 } 00182 00183 void MemoryCache::clearUnused() 00184 { 00185 boost::mutex::scoped_lock lockerMap( _mutexMap ); 00186 for( MAP::iterator it = _map.begin(); it != _map.end(); ) 00187 { 00188 if( isUnused( it->second ) ) 00189 { 00190 _map.erase( it++ ); // post-increment here, increments 'it' and returns a copy of the original 'it' to be used by erase() 00191 } 00192 else 00193 { 00194 ++it; 00195 } 00196 } 00197 } 00198 00199 void MemoryCache::clearAll() 00200 { 00201 TUTTLE_LOG_DEBUG( TUTTLE_TRACE, " - MEMORYCACHE::CLEARALL - " ); 00202 boost::mutex::scoped_lock lockerMap( _mutexMap ); 00203 _map.clear(); 00204 } 00205 00206 std::ostream& operator<<( std::ostream& os, const MemoryCache& v ) 00207 { 00208 os << "[MemoryCache] size:" << v.size() << std::endl; 00209 BOOST_FOREACH( const MemoryCache::MAP::value_type& i, v._map ) 00210 { 00211 os << "[MemoryCache] " << i.first 00212 << " id:" << i.second->getId() 00213 << " ref host:" << i.second->getReferenceCount( ofx::imageEffect::OfxhImage::eReferenceOwnerHost ) 00214 << " ref plugins:" << i.second->getReferenceCount( ofx::imageEffect::OfxhImage::eReferenceOwnerPlugin ) << std::endl; 00215 } 00216 return os; 00217 } 00218 00219 } 00220 } 00221 }