iipsrv 0.9.9
|
00001 // Tile Cache Class 00002 00003 /* IIP Image Server 00004 00005 Copyright (C) 2005-2010 Ruven Pillay. 00006 Based on an LRU cache by Patrick Audley <http://blackcat.ca/lifeline/query.php/tag=LRU_CACHE> 00007 Copyright (C) 2004 by Patrick Audley 00008 00009 This program is free software; you can redistribute it and/or modify 00010 it under the terms of the GNU General Public License as published by 00011 the Free Software Foundation; either version 2 of the License, or 00012 (at your option) any later version. 00013 00014 This program is distributed in the hope that it will be useful, 00015 but WITHOUT ANY WARRANTY; without even the implied warranty of 00016 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 00017 GNU General Public License for more details. 00018 00019 You should have received a copy of the GNU General Public License 00020 along with this program; if not, write to the Free Software 00021 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 00022 */ 00023 00024 00025 00026 #ifndef _CACHE_H 00027 #define _CACHE_H 00028 00029 // Remove our deprecated warnings for now. We should upgrade our hash_maps to 00030 // unordered_maps, however 00031 #undef __DEPRECATED 00032 00033 // Use the hashmap extensions if we are using >= gcc 3.1 00034 #ifdef __GNUC__ 00035 00036 #if (__GNUC__ == 3 && __GNUC_MINOR__ >= 1) || (__GNUC__ >= 4) 00037 #define USE_HASHMAP 1 00038 #include <ext/hash_map> 00039 namespace __gnu_cxx 00040 { 00041 template<> struct hash< const std::string > { 00042 size_t operator()( const std::string& x ) const { 00043 return hash< const char* >()( x.c_str() ); 00044 } 00045 }; 00046 } 00047 #endif 00048 00049 // And the high performance memory pool allocator if >= gcc 3.4 00050 #if (__GNUC__ == 3 && __GNUC_MINOR__ >= 4) || (__GNUC__ >= 4) 00051 #define POOL_ALLOCATOR 1 00052 #include <ext/pool_allocator.h> 00053 #endif 00054 00055 #endif 00056 00057 00058 #ifndef USE_HASHMAP 00059 #include <map> 00060 #endif 00061 00062 00063 // Fix missing snprintf in Windows 00064 #if _MSC_VER 00065 #define snprintf _snprintf 00066 #endif 00067 00068 00069 #include <iostream> 00070 #include <list> 00071 #include <string> 00072 #include "RawTile.h" 00073 00074 00075 00077 00078 class Cache { 00079 00080 00081 private: 00082 00084 int tileSize; 00085 00087 unsigned long maxSize; 00088 00090 unsigned long currentSize; 00091 00093 #ifdef POOL_ALLOCATOR 00094 typedef std::list < std::pair<const std::string,RawTile>, 00095 __gnu_cxx::__pool_alloc< std::pair<const std::string,RawTile> > > TileList; 00096 #else 00097 typedef std::list < std::pair<const std::string,RawTile> > TileList; 00098 #endif 00099 00101 typedef std::list < std::pair<const std::string,RawTile> >::iterator List_Iter; 00102 00104 #ifdef USE_HASHMAP 00105 #ifdef POOL_ALLOCATOR 00106 typedef __gnu_cxx::hash_map < const std::string, List_Iter, 00107 __gnu_cxx::hash< const std::string >, 00108 std::equal_to< const std::string >, 00109 __gnu_cxx::__pool_alloc< std::pair<const std::string, List_Iter> > 00110 > TileMap; 00111 #else 00112 typedef __gnu_cxx::hash_map < const std::string,List_Iter > TileMap; 00113 #endif 00114 #else 00115 typedef std::map < const std::string,List_Iter > TileMap; 00116 #endif 00117 00119 TileList tileList; 00120 00122 TileMap tileMap; 00123 00124 00126 00130 TileMap::iterator _touch( const std::string &key ) { 00131 TileMap::iterator miter = tileMap.find( key ); 00132 if( miter == tileMap.end() ) return miter; 00133 // Move the found node to the head of the list. 00134 tileList.splice( tileList.begin(), tileList, miter->second ); 00135 return miter; 00136 } 00137 00138 00140 00144 void _remove( const TileMap::iterator &miter ) { 00145 // Reduce our current size counter 00146 currentSize -= ( (miter->second->second).dataLength + 00147 ( (miter->second->second).filename.capacity() + (miter->second->first).capacity() )*sizeof(char) + 00148 tileSize ); 00149 tileList.erase( miter->second ); 00150 tileMap.erase( miter ); 00151 } 00152 00153 00155 00156 void _remove( const std::string &key ) { 00157 TileMap::iterator miter = tileMap.find( key ); 00158 this->_remove( miter ); 00159 } 00160 00161 00162 00163 public: 00164 00166 00167 Cache( float max ) { 00168 maxSize = (unsigned long)(max*1024000) ; currentSize = 0; 00169 // 64 chars added at the end represents an average string length 00170 tileSize = sizeof( RawTile ) + sizeof( std::pair<const std::string,RawTile> ) + 00171 sizeof( std::pair<const std::string, List_Iter> ) + sizeof(char)*64 + sizeof(List_Iter); 00172 }; 00173 00174 00176 ~Cache() { 00177 tileList.clear(); 00178 tileMap.clear(); 00179 } 00180 00181 00183 00184 void insert( const RawTile& r ) { 00185 00186 if( maxSize == 0 ) return; 00187 00188 std::string key = this->getIndex( r.filename, r.resolution, r.tileNum, 00189 r.hSequence, r.vSequence, r.compressionType, r.quality ); 00190 00191 // Touch the key, if it exists 00192 TileMap::iterator miter = this->_touch( key ); 00193 00194 // Check whether this tile exists in our cache 00195 if( miter != tileMap.end() ){ 00196 // Check the timestamp and delete if necessary 00197 if( miter->second->second.timestamp < r.timestamp ){ 00198 this->_remove( miter ); 00199 } 00200 // If this index already exists and it is up to date, do nothing 00201 else return; 00202 } 00203 00204 // Store the key if it doesn't already exist in our cache 00205 // Ok, do the actual insert at the head of the list 00206 tileList.push_front( std::make_pair(key,r) ); 00207 00208 // And store this in our map 00209 List_Iter liter = tileList.begin(); 00210 tileMap[ key ] = liter; 00211 00212 // Update our total current size variable. Use the string::capacity function 00213 // rather than length() as std::string can allocate slightly more than necessary 00214 // The +1 is for the terminating null byte 00215 currentSize += (r.dataLength + (r.filename.capacity()+key.capacity())*sizeof(char) + tileSize); 00216 00217 // Check to see if we need to remove an element due to exceeding max_size 00218 while( currentSize > maxSize ) { 00219 // Remove the last element 00220 liter = tileList.end(); 00221 --liter; 00222 this->_remove( liter->first ); 00223 } 00224 00225 } 00226 00227 00229 unsigned int getNumElements() { return tileList.size(); } 00230 00231 00233 float getMemorySize() { return (float) ( currentSize / 1024000.0 ); } 00234 00235 00237 00247 RawTile* getTile( std::string f, int r, int t, int h, int v, CompressionType c, int q ) { 00248 00249 if( maxSize == 0 ) return NULL; 00250 00251 std::string key = this->getIndex( f, r, t, h, v, c, q ); 00252 00253 TileMap::iterator miter = tileMap.find( key ); 00254 if( miter == tileMap.end() ) return NULL; 00255 this->_touch( key ); 00256 00257 return &(miter->second->second); 00258 } 00259 00260 00262 00272 std::string getIndex( std::string f, int r, int t, int h, int v, CompressionType c, int q ) { 00273 char tmp[1024]; 00274 snprintf( tmp, 1024, "%s:%d:%d:%d:%d:%d:%d", f.c_str(), r, t, h, v, c, q ); 00275 return std::string( tmp ); 00276 } 00277 00278 00279 00280 }; 00281 00282 00283 00284 #endif