Cache.h

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 #include <iostream>
00063 #include <list>
00064 #include <string>
00065 #include "RawTile.h"
00066 
00067 
00068 
00070 
00071 class Cache {
00072 
00073 
00074  private:
00075 
00077   unsigned long maxSize;
00078 
00080   int tileSize;
00081 
00083   unsigned long currentSize;
00084 
00086 #ifdef POOL_ALLOCATOR
00087   typedef std::list < std::pair<const std::string,RawTile>,
00088     __gnu_cxx::__pool_alloc< std::pair<const std::string,RawTile> > > TileList;
00089 #else
00090   typedef std::list < std::pair<const std::string,RawTile> > TileList;
00091 #endif
00092 
00094   typedef std::list < std::pair<const std::string,RawTile> >::iterator List_Iter;
00095 
00097 #ifdef USE_HASHMAP
00098 #ifdef POOL_ALLOCATOR
00099   typedef __gnu_cxx::hash_map < const std::string, List_Iter,
00100     __gnu_cxx::hash< const std::string >,
00101     std::equal_to< const std::string >,
00102     __gnu_cxx::__pool_alloc< std::pair<const std::string, List_Iter> >
00103     > TileMap;
00104 #else
00105   typedef __gnu_cxx::hash_map < const std::string,List_Iter > TileMap;
00106 #endif
00107 #else
00108   typedef std::map < const std::string,List_Iter > TileMap;
00109 #endif
00110 
00112   TileList tileList;
00113 
00115   TileMap tileMap;
00116 
00117 
00119 
00123   TileMap::iterator _touch( const std::string &key ) {
00124     TileMap::iterator miter = tileMap.find( key );
00125     if( miter == tileMap.end() ) return miter;
00126     // Move the found node to the head of the list.
00127     tileList.splice( tileList.begin(), tileList, miter->second );
00128     return miter;
00129   }
00130 
00131 
00133 
00137   void _remove( const TileMap::iterator &miter ) {
00138     // Reduce our current size counter
00139     currentSize -= ( (miter->second->second).dataLength +
00140                      ((miter->second->second).filename.capacity()+1)*sizeof(char) +
00141                      tileSize );
00142     tileList.erase( miter->second );
00143     tileMap.erase( miter );
00144   }
00145 
00146 
00148 
00149   void _remove( const std::string &key ) {
00150     TileMap::iterator miter = tileMap.find( key );
00151     this->_remove( miter );
00152   }
00153 
00154 
00155 
00156  public:
00157 
00159 
00160   Cache( float max ) {
00161     maxSize = (unsigned long)(max*1024000) ; currentSize = 0;
00162     // 128 added at the end represents 2*average strings lengths
00163     tileSize = sizeof( RawTile ) + sizeof( std::pair<const std::string,RawTile> ) +
00164       sizeof( std::pair<const std::string, List_Iter> ) + 128;
00165   };
00166 
00167 
00169   ~Cache() {
00170     tileList.clear();
00171     tileMap.clear();
00172   }
00173 
00174 
00176 
00177   void insert( const RawTile& r ) {
00178 
00179     if( maxSize == 0 ) return;
00180 
00181     std::string key = this->getIndex( r.filename, r.resolution, r.tileNum,
00182                                       r.hSequence, r.vSequence, r.compressionType, r.quality );
00183 
00184     // Touch the key, if it exists
00185     TileMap::iterator miter = this->_touch( key );
00186 
00187     // Check whether this tile exists in our cache
00188     if( miter != tileMap.end() ){
00189       // Check the timestamp and delete if necessary
00190       if( miter->second->second.timestamp < r.timestamp ){
00191         this->_remove( miter );
00192       }
00193       // If this index already exists and it is up to date, do nothing
00194       else return;
00195     }
00196 
00197     // Store the key if it doesn't already exist in our cache
00198     // Ok, do the actual insert at the head of the list
00199     tileList.push_front( std::make_pair(key,r) );
00200 
00201     // And store this in our map
00202     List_Iter liter = tileList.begin();
00203     tileMap[ key ] = liter;
00204 
00205     // Update our total current size variable. Use the string::capacity function
00206     // rather than length() as std::string can allocate slightly more than necessary
00207     // The +1 is for the terminating null byte
00208     currentSize += (r.dataLength + (r.filename.capacity()+1)*sizeof(char) + tileSize);
00209 
00210     // Check to see if we need to remove an element due to exceeding max_size
00211     while( currentSize > maxSize ) {
00212       // Remove the last element
00213       liter = tileList.end();
00214       --liter;
00215       this->_remove( liter->first );
00216     }
00217 
00218   }
00219 
00220 
00222   unsigned int getNumElements() { return tileList.size(); }
00223 
00224 
00226   float getMemorySize() { return (float) ( currentSize / 1024000.0 ); }
00227 
00228 
00230 
00240   RawTile* getTile( std::string f, int r, int t, int h, int v, CompressionType c, int q ) {
00241 
00242     if( maxSize == 0 ) return NULL;
00243 
00244     std::string key = this->getIndex( f, r, t, h, v, c, q );
00245 
00246     TileMap::iterator miter = tileMap.find( key );
00247     if( miter == tileMap.end() ) return NULL;
00248     this->_touch( key );
00249 
00250     return &(miter->second->second);
00251   }
00252 
00253 
00255 
00265   std::string getIndex( std::string f, int r, int t, int h, int v, CompressionType c, int q ) {
00266     char tmp[1024];
00267     snprintf( tmp, 1024, "%s:%d:%d:%d:%d:%d:%d", f.c_str(), r, t, h, v, c, q );
00268     return std::string( tmp );
00269   }
00270 
00271 
00272 
00273 };
00274 
00275 
00276 
00277 #endif

Generated on Fri Nov 26 16:55:07 2010 for iipsrv by  doxygen 1.5.8