00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027 #ifndef CEYLAN_SMART_RESOURCE_MANAGER_H_
00028 #define CEYLAN_SMART_RESOURCE_MANAGER_H_
00029
00030
00031
00032 #include "CeylanResourceManager.h"
00033
00034 #include "CeylanSmartResource.h"
00035
00036
00037
00038
00039
00040
00041
00042 #define CEYLAN_DEBUG_SMART_RESOURCE_MANAGER 0
00043
00044
00045 namespace Ceylan
00046 {
00047
00048
00049
00147 template <typename Key>
00148 class SmartResourceManager: public Ceylan::ResourceManager<Key>
00149 {
00150
00151
00152 public:
00153
00154
00191 enum CachePolicy { NeverDrop, DropLessRequestedFirst } ;
00192
00193
00194
00207 explicit SmartResourceManager() ;
00208
00209
00210
00227 explicit SmartResourceManager( System::Size quota,
00228 CachePolicy policy = DropLessRequestedFirst ) ;
00229
00230
00231
00233 virtual ~SmartResourceManager() throw() ;
00234
00235
00236
00237
00238
00239
00240
00280 virtual bool scanForAddition( const Key & key,
00281 const SmartResource & smartResource ) ;
00282
00283
00284
00322 virtual bool takeOwnershipOf( const Key & key,
00323 const SmartResource & resource ) ;
00324
00325
00326
00335 virtual bool isKeyAlreadyAssociated( const Key & key ) const ;
00336
00337
00338
00339
00340
00341
00342
00358 virtual SmartResource * getClone( const Key & key ) ;
00359
00360
00361
00383 virtual const Resource * get( const Key & key ) ;
00384
00385
00386
00387
00388
00389
00397 virtual System::Size getQuota() const ;
00398
00399
00400
00405 virtual CachePolicy getCachePolicy() const ;
00406
00407
00408
00424 virtual System::Size getFootprint() const ;
00425
00426
00427
00428
00429
00430
00431
00439 virtual void update() ;
00440
00441
00442
00447 virtual void updateSizes() ;
00448
00449
00459 virtual void applyPolicy() ;
00460
00461
00462
00469 virtual void flush() ;
00470
00471
00472
00483 virtual const std::string toString(
00484 Ceylan::VerbosityLevels level = Ceylan::high ) const ;
00485
00486
00487
00488
00489 protected:
00490
00491
00492
00493 struct CacheEntry ;
00494
00495
00496
00508 virtual void applyPolicy( const SmartResource * lastCached ) ;
00509
00510
00511
00517 virtual void applyDropLessRequestedFirst(
00518 const SmartResource * lastCached = 0 ) ;
00519
00520
00521
00542 virtual void addEntry( const Key & key,
00543 const SmartResource & newResource,
00544 Ceylan::System::Size size = 0 ) ;
00545
00546
00547
00559 virtual void dropEntryDueToPolicy(
00560 typename std::map<Key,CacheEntry *>::iterator pos ) ;
00561
00562
00563
00570 virtual void dropEntry(
00571 typename std::map<Key, CacheEntry *>::iterator pos ) ;
00572
00573
00574
00580 System::Size _quota ;
00581
00582
00583
00590 System::Size _totalSize ;
00591
00592
00593
00595 CachePolicy _policy ;
00596
00597
00598
00606 Ceylan::Uint32 _droppedByPolicy ;
00607
00608
00609
00611 struct CacheEntry
00612 {
00613
00614
00616 const SmartResource * _resource ;
00617
00623 Uint32 _requestCount ;
00624
00626 Uint32 _cloneCount ;
00627
00629 System::Size _size ;
00630
00631
00632 } ;
00633
00634
00635
00636
00637
00638
00639
00640
00641
00642 #pragma warning( push )
00643 #pragma warning( disable: 4251 )
00644
00645
00646 std::map<Key, CacheEntry *> _entries ;
00647
00648 #pragma warning( pop )
00649
00650
00651
00652 private:
00653
00654
00655
00663 SmartResourceManager( const SmartResourceManager & source ) ;
00664
00665
00674 SmartResourceManager & operator = (
00675 const SmartResourceManager & source ) ;
00676
00677
00678 } ;
00679
00680
00681
00682
00683
00684
00685
00686 template <typename Key>
00687 SmartResourceManager<Key>::SmartResourceManager() :
00688 ResourceManager<Key>(),
00689 _quota( 0 ),
00690 _totalSize( 0 ),
00691 _policy( NeverDrop ),
00692 _droppedByPolicy( 0 ),
00693 _entries()
00694 {
00695
00696 }
00697
00698
00699
00700 template <typename Key>
00701 SmartResourceManager<Key>::SmartResourceManager( System::Size quota,
00702 CachePolicy policy ) :
00703 ResourceManager<Key>(),
00704 _quota( quota ),
00705 _totalSize( 0 ),
00706 _policy( policy ),
00707 _droppedByPolicy( 0 ),
00708 _entries()
00709 {
00710
00711 }
00712
00713
00714
00715 template <typename Key>
00716 SmartResourceManager<Key>::~SmartResourceManager() throw()
00717 {
00718
00725 flush() ;
00726
00727 }
00728
00729
00730
00731
00732
00733
00734
00735 template <typename Key>
00736 System::Size SmartResourceManager<Key>::getQuota() const
00737 {
00738
00739 return _quota ;
00740
00741 }
00742
00743
00744
00745 template <typename Key>
00746 typename Ceylan::SmartResourceManager<Key>::CachePolicy
00747 SmartResourceManager<Key>::getCachePolicy() const
00748 {
00749
00750 return _policy ;
00751
00752 }
00753
00754
00755
00756 template <typename Key>
00757 System::Size SmartResourceManager<Key>::getFootprint() const
00758 {
00759
00760
00761
00762
00763
00764
00765
00766 return _totalSize ;
00767
00768 }
00769
00770
00771
00772 template <typename Key>
00773 bool SmartResourceManager<Key>::scanForAddition( const Key & key,
00774 const SmartResource & smartResource )
00775 {
00776
00777
00778
00779
00780
00781
00782
00783
00784
00785
00786
00787
00788 System::Size resourceSize = smartResource.getSizeInMemory() ;
00789
00790
00791 if ( _policy != NeverDrop && resourceSize > _quota )
00792 return false ;
00793
00794
00795
00796
00797
00798
00799
00800
00801 if ( _policy == NeverDrop && isKeyAlreadyAssociated( key ) )
00802 return false ;
00803
00804
00805
00806
00807
00808 SmartResource & clone = * dynamic_cast<SmartResource *>(
00809 & smartResource.clone() ) ;
00810
00811
00812
00813
00814
00815
00816
00817
00818 addEntry( key, clone, resourceSize ) ;
00819
00820
00821
00822
00823
00824
00825
00826
00827 applyPolicy( & clone ) ;
00828
00829 return true ;
00830
00831 }
00832
00833
00834
00835 template <typename Key>
00836 bool SmartResourceManager<Key>::takeOwnershipOf( const Key & key,
00837 const SmartResource & smartResource )
00838 {
00839
00840
00841
00842
00843
00844
00845
00846
00847
00848
00849
00850 System::Size resourceSize = smartResource.getSizeInMemory() ;
00851
00852
00853 if ( _policy != NeverDrop && resourceSize > _quota )
00854 return false ;
00855
00856
00857
00858
00859
00860
00861 addEntry( key, smartResource, resourceSize ) ;
00862
00863
00864
00865
00866
00867
00868
00869 applyPolicy( & smartResource ) ;
00870
00871 return true ;
00872
00873 }
00874
00875
00876
00877 template <typename Key>
00878 SmartResource * SmartResourceManager<Key>::getClone( const Key & key )
00879 {
00880
00881
00882 typename std::map<Key, CacheEntry *>::const_iterator it =
00883 _entries.find( key ) ;
00884
00885 if ( it == _entries.end() )
00886 return 0 ;
00887
00888
00889 this->_cacheHits++ ;
00890 (*it).second->_requestCount++ ;
00891
00892 #if CEYLAN_DEBUG_SMART_RESOURCE_MANAGER
00893
00894 SmartResource * res = dynamic_cast<SmartResource *>(
00895 & (*it).second->_resource->clone() ) ;
00896
00897 if ( res != 0 )
00898 return res ;
00899 else
00900 {
00901 Ceylan::emergencyShutdown( "SmartResourceManager<Key>::getClone: "
00902 "clone cannot be casted back to Smart resource for "
00903 + (*it).second->_resource->toString() ) ;
00904
00905 return res ;
00906 }
00907
00908 #else // CEYLAN_DEBUG_SMART_RESOURCE_MANAGER
00909
00910 return dynamic_cast<SmartResource *>(
00911 & (*it).second->_resource->clone() ) ;
00912
00913 #endif // CEYLAN_DEBUG_SMART_RESOURCE_MANAGER
00914
00915 }
00916
00917
00918
00919
00920 template <typename Key>
00921 void SmartResourceManager<Key>::update()
00922 {
00923
00924 updateSizes() ;
00925 applyPolicy() ;
00926
00927 }
00928
00929
00930
00931 template <typename Key>
00932 void SmartResourceManager<Key>::updateSizes()
00933 {
00934
00935 System::Size resourceSize ;
00936 _totalSize = 0 ;
00937
00938 for ( typename std::map<Key, CacheEntry *>::const_iterator it =
00939 _entries.begin() ; it != _entries.end(); it++ )
00940 {
00941 resourceSize = (*it).second->_resource->getSizeInMemory() ;
00942 (*it).second->_size = resourceSize ;
00943 _totalSize += resourceSize ;
00944 }
00945
00946 }
00947
00948
00949
00950 template <typename Key>
00951 void SmartResourceManager<Key>::applyPolicy()
00952 {
00953
00954 applyPolicy( 0 ) ;
00955
00956 }
00957
00958
00959
00960
00961
00962
00963
00964 template <typename Key>
00965 bool SmartResourceManager<Key>::isKeyAlreadyAssociated( const Key & key )
00966 const
00967 {
00968
00969
00970 return ( _entries.find( key ) != _entries.end() ) ;
00971
00972 }
00973
00974
00975
00976 template <typename Key>
00977 const Resource * SmartResourceManager<Key>::get( const Key & key )
00978 {
00979
00980 typename std::map<Key, CacheEntry *>::const_iterator it =
00981 _entries.find( key ) ;
00982
00983 if ( it != _entries.end() )
00984 {
00985 this->_cacheHits++ ;
00986 (*it).second->_requestCount++ ;
00987 return (*it).second->_resource ;
00988 }
00989 else
00990 {
00991
00992 this->_cacheMisses++ ;
00993 return 0 ;
00994 }
00995
00996 }
00997
00998
00999
01000 template <typename Key>
01001 void SmartResourceManager<Key>::flush()
01002 {
01003
01004
01005
01006
01007
01008
01009
01010 for ( typename std::map<Key, CacheEntry *>::const_iterator it =
01011 _entries.begin() ; it != _entries.end(); it++ )
01012 {
01013
01014
01015 delete (*it).second->_resource ;
01016
01017
01018 delete (*it).second ;
01019 }
01020
01021 _entries.clear() ;
01022 _totalSize = 0 ;
01023
01024 }
01025
01026
01027
01028 template <typename Key>
01029 const std::string SmartResourceManager<Key>::toString(
01030 VerbosityLevels level ) const
01031 {
01032
01033 std::string res = "Smart resource manager applying " ;
01034
01035 switch( _policy )
01036 {
01037
01038 case NeverDrop:
01039 res += "the 'Never drop'" ;
01040 break ;
01041
01042 case DropLessRequestedFirst:
01043 res += "the 'Drop less requested first'" ;
01044 break ;
01045
01046 default:
01047 res += "an unknown (hence abnormal)" ;
01048 break ;
01049 }
01050
01051 res += " cache policy" ;
01052
01053 if ( _policy != NeverDrop )
01054 res += ", with a memory size quota of "
01055 + Ceylan::toString( static_cast<Ceylan::Uint32>( _quota ) )
01056 + " bytes" ;
01057
01058 if ( level == Ceylan::low )
01059 return res ;
01060
01061 res += ". It is currently managing " ;
01062
01063 System::Size resourceCount = _entries.size() ;
01064
01065 if ( resourceCount == 0 )
01066 res += "no resource" ;
01067 else
01068 res += Ceylan::toString(
01069 static_cast<Ceylan::Uint32>( resourceCount ) )
01070 + " resource(s), for a total estimated size of "
01071 + Ceylan::toString( static_cast<Ceylan::Uint32>( _totalSize ) )
01072 + " bytes" ;
01073
01074 if ( _droppedByPolicy == 0 )
01075 res += ". No resource dropped because of cache policy" ;
01076 else
01077 res += ". " + Ceylan::toString( _droppedByPolicy )
01078 + " resource(s) dropped because of cache policy" ;
01079
01080 Ceylan::Uint32 total = this->_cacheHits + this->_cacheMisses ;
01081
01082 if ( total == 0 )
01083 res += ". No resource request processed for the moment" ;
01084 else
01085 res += ". The average cache success is "
01086 + Ceylan::toNumericalString(
01087 static_cast<Ceylan::Uint8>(
01088 ( 100.0f * this->_cacheHits ) / total ) )
01089 + "% (" + Ceylan::toString( this->_cacheHits )
01090 + " cache hit(s) for "
01091 + Ceylan::toString( this->_cacheMisses ) + " cache misse(s))" ;
01092
01093
01094 if ( level == Ceylan::medium )
01095 return res ;
01096
01097 if ( resourceCount == 0 )
01098 return res ;
01099
01100 res += ". Displaying current cached entrie(s): " ;
01101
01102 Ceylan::Uint32 count = 0 ;
01103 std::list<std::string> entries ;
01104
01105 for ( typename std::map<Key, CacheEntry *>::const_iterator it =
01106 _entries.begin() ; it != _entries.end(); it++ )
01107 {
01108
01109 count++ ;
01110 entries.push_back( "[Entry #" + Ceylan::toString( count )
01111 + "]: size = "
01112 + Ceylan::toString(
01113 static_cast<Ceylan::Uint32>( (*it).second->_size ) )
01114 + ", request count = "
01115 + Ceylan::toString( (*it).second->_requestCount )
01116 + ", resource description = '"
01117 + (*it).second->_resource->toString( Ceylan::low )
01118 + "'" ) ;
01119 }
01120
01121 return res + Ceylan::formatStringList( entries ) ;
01122
01123 }
01124
01125
01126
01127
01128
01129
01130
01131
01132 template <typename Key>
01133 void SmartResourceManager<Key>::applyPolicy(
01134 const SmartResource * lastCached )
01135 {
01136
01137 switch( _policy )
01138 {
01139
01140 case NeverDrop:
01141
01142 break ;
01143
01144 case DropLessRequestedFirst:
01145 applyDropLessRequestedFirst( lastCached ) ;
01146 break ;
01147
01148 default:
01149 Ceylan::emergencyShutdown(
01150 "SmartResourceManager<Key>::applyPolicy : "
01151 "unknown cache policy requested." ) ;
01152 break ;
01153 }
01154
01155 }
01156
01157
01158
01159 template <typename Key>
01160 void SmartResourceManager<Key>::applyDropLessRequestedFirst(
01161 const SmartResource * lastCached )
01162 {
01163
01164
01165 Uint32 minRequestCount = 0 ;
01166 Uint32 minRequestCurrent ;
01167
01168
01169 typename std::map<Key, CacheEntry *>::iterator minIterator ;
01170 bool minAlreadyFound ;
01171
01172
01173
01174 while ( getFootprint() > _quota )
01175 {
01176
01177
01178
01179
01180
01181
01182
01183
01184
01185
01186
01187
01188
01189
01190
01191
01192
01193 minAlreadyFound = false ;
01194
01195 for ( typename std::map<Key, CacheEntry *>::iterator it =
01196 _entries.begin(); it != _entries.end(); it++ )
01197 {
01198
01199
01200
01201
01202
01203
01204 if ( (*it).second->_resource != lastCached )
01205 {
01206
01207 minRequestCurrent = (*it).second->_requestCount ;
01208
01209 if ( minRequestCurrent == 0 )
01210 {
01211
01212 minIterator = it ;
01213 break ;
01214 }
01215
01216
01217 if ( ! minAlreadyFound )
01218 {
01219
01220 minRequestCount = minRequestCurrent ;
01221 minIterator = it ;
01222 minAlreadyFound = true ;
01223 }
01224 else
01225 {
01226
01227 if ( minRequestCurrent < minRequestCount )
01228 {
01229 minRequestCount = minRequestCurrent ;
01230 minIterator = it ;
01231 }
01232 }
01233 }
01234 }
01235
01236
01237
01238
01239
01240
01241 dropEntryDueToPolicy( minIterator ) ;
01242
01243
01244 }
01245
01246 }
01247
01248
01249
01250 template <typename Key>
01251 void SmartResourceManager<Key>::addEntry( const Key & key,
01252 const SmartResource & newResource, Ceylan::System::Size size )
01253 {
01254
01255
01256 typename std::map<Key, CacheEntry *>::iterator it =
01257 _entries.find( key ) ;
01258
01259 if ( it != _entries.end() )
01260 {
01261
01262 if ( _policy == NeverDrop )
01263 throw ResourceManagerException(
01264 "SmartResourceManager<Key>::addEntry: "
01265 "specified key was already associated to a resource, "
01266 "and the current policy, 'NeverDrop', prevents from "
01267 "removing already associated resource." ) ;
01268
01269
01270
01271
01272
01273
01274
01275
01276
01277
01278
01279
01280 dropEntry( it ) ;
01281
01282 }
01283
01284
01285 CacheEntry * newEntry = new CacheEntry() ;
01286
01287
01288 newEntry->_resource = & newResource ;
01289 newEntry->_requestCount = 0 ;
01290
01291 if ( size == 0 )
01292 size = newResource.getSizeInMemory() ;
01293
01294 newEntry->_size = size ;
01295
01296 _entries[ key ] = newEntry ;
01297
01298 _totalSize += size ;
01299
01300
01301 }
01302
01303
01304
01305 template <typename Key>
01306 void SmartResourceManager<Key>::dropEntryDueToPolicy(
01307 typename std::map<Key, CacheEntry *>::iterator pos )
01308 {
01309
01310 dropEntry( pos ) ;
01311 _droppedByPolicy++ ;
01312
01313 }
01314
01315
01316
01317 template <typename Key>
01318 void SmartResourceManager<Key>::dropEntry(
01319 typename std::map<Key, CacheEntry *>::iterator pos )
01320
01321 {
01322
01323
01324 _totalSize -= (*pos).second->_size ;
01325
01326
01327 delete (*pos).second->_resource ;
01328
01329
01330 delete (*pos).second ;
01331 _entries.erase( pos ) ;
01332
01333 }
01334
01335
01336
01337 }
01338
01339
01340
01341 #endif // CEYLAN_SMART_RESOURCE_MANAGER_H_
01342