Sirikata
libcore/include/sirikata/core/transfer/CacheMap.hpp
Go to the documentation of this file.
00001 /*  Sirikata Transfer -- Content Transfer management system
00002  *  CacheMap.hpp
00003  *
00004  *  Copyright (c) 2008, Patrick Reiter Horn
00005  *  All rights reserved.
00006  *
00007  *  Redistribution and use in source and binary forms, with or without
00008  *  modification, are permitted provided that the following conditions are
00009  *  met:
00010  *  * Redistributions of source code must retain the above copyright
00011  *    notice, this list of conditions and the following disclaimer.
00012  *  * Redistributions in binary form must reproduce the above copyright
00013  *    notice, this list of conditions and the following disclaimer in
00014  *    the documentation and/or other materials provided with the
00015  *    distribution.
00016  *  * Neither the name of Sirikata nor the names of its contributors may
00017  *    be used to endorse or promote products derived from this software
00018  *    without specific prior written permission.
00019  *
00020  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
00021  * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
00022  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
00023  * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
00024  * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
00025  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
00026  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
00027  * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
00028  * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
00029  * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
00030  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
00031  */
00032 /*  Created on: Jan 7, 2009 */
00033 
00034 #ifndef SIRIKATA_CacheMap_HPP__
00035 #define SIRIKATA_CacheMap_HPP__
00036 
00037 #include "CachePolicy.hpp"
00038 #include "CacheLayer.hpp"
00039 #include <boost/thread.hpp>
00040 #include <boost/thread/shared_mutex.hpp>
00041 
00042 namespace Sirikata {
00043 namespace Transfer {
00044 
00049 class CacheMap : Noncopyable {
00050 public:
00051     typedef CacheLayer::CacheEntry *CacheData;
00052 
00053     class read_iterator;
00054     class write_iterator;
00055 
00056 private:
00057     typedef CachePolicy::Data *PolicyData;
00058     typedef std::pair<CacheData, std::pair<PolicyData, cache_usize_type> > MapEntry;
00059     typedef std::map<Fingerprint, MapEntry> MapClass;
00060 
00061     MapClass mMap;
00062     boost::shared_mutex mMapLock;
00063 
00064     CacheLayer *mOwner;
00065     CachePolicy *mPolicy;
00066 
00067     inline void destroyCacheLayerEntry(const Fingerprint &id, const CacheData &data, cache_usize_type size) {
00068         mOwner->destroyCacheEntry(id, data, size);
00069     }
00070 
00071 public:
00072     CacheMap(CacheLayer *owner, CachePolicy *policy) :
00073         mOwner(owner), mPolicy(policy) {
00074     }
00075     void setOwner(CacheLayer *owner) {//if you can't afford to initialize in initializer list
00076         mOwner=owner;
00077     }
00078 
00079     ~CacheMap() {
00080         write_iterator clearIterator(*this);
00081         clearIterator.eraseAll();
00082     }
00083 
00093     inline bool alloc(cache_usize_type required, write_iterator &writer) {
00094         bool cachable = mPolicy->cachable(required);
00095         if (!cachable) {
00096             return false;
00097         }
00098         Fingerprint toDelete;
00099         while (mPolicy->nextItem(required, toDelete)) {
00100             writer.find(toDelete);
00101             writer.erase();
00102         }
00103         return true;
00104     }
00105 
00114     class read_iterator {
00115         CacheMap *mCachemap;
00116         boost::shared_lock<boost::shared_mutex> mLock;
00117 
00118         MapClass *mMap;
00119         MapClass::iterator mIter;
00120 
00121     public:
00123         read_iterator(CacheMap &m)
00124             : mCachemap(&m), mLock(m.mMapLock),
00125             mMap(&m.mMap), mIter(m.mMap.end()) {
00126         }
00127 
00129         inline operator bool () const{
00130             return (mIter != mMap->end());
00131         }
00132 
00133         inline bool iterate () {
00134             if (mIter == mMap->end()) {
00135                 mIter = mMap->begin();
00136             } else {
00137                 ++mIter;
00138             }
00139             return (mIter != mMap->end());
00140         }
00141 
00146         inline bool find(const Fingerprint &id) {
00147             mIter = mMap->find(id);
00148             return (bool)*this;
00149         }
00150 
00152         inline CacheData operator* () const {
00153             return (*mIter).second.first;
00154         }
00155 
00157         inline const Fingerprint &getId() const {
00158             return (*mIter).first;
00159         }
00160 
00162         inline cache_usize_type getSize() const {
00163             return (*mIter).second.second.second;
00164         }
00165 
00167         inline PolicyData getPolicyInfo() {
00168             return (*mIter).second.second.first;
00169         }
00170 
00172         inline void use() {
00173             mCachemap->mPolicy->use(getId(), getPolicyInfo(), getSize());
00174         }
00175     };
00176 
00185     class write_iterator : Noncopyable {
00186         CacheMap *mCachemap;
00187         boost::unique_lock<boost::shared_mutex> mLock;
00188 
00189         MapClass *mMap;
00190         MapClass::iterator mIter;
00191 
00192     public:
00194         write_iterator(CacheMap &m)
00195             : mCachemap(&m), mLock(m.mMapLock),
00196             mMap(&m.mMap), mIter(m.mMap.end()) {
00197         }
00198 
00200         inline operator bool () const{
00201             return (mIter != mMap->end());
00202         }
00203 
00208         bool find(const Fingerprint &id) {
00209             mIter = mMap->find(id);
00210             return (bool)*this;
00211         }
00212 
00214         inline CacheData &operator* () {
00215             return (*mIter).second.first;
00216         }
00217 
00219         inline const Fingerprint &getId() const {
00220             return (*mIter).first;
00221         }
00222 
00224         inline cache_usize_type getSize() const {
00225             return (*mIter).second.second.second;
00226         }
00227 
00229         inline PolicyData getPolicyInfo() {
00230             return (*mIter).second.second.first;
00231         }
00232 
00234         inline void use() {
00235             mCachemap->mPolicy->use(getId(), getPolicyInfo(), getSize());
00236         }
00237 
00244         inline void update(cache_usize_type newSize) {
00245             cache_usize_type oldSize = getSize();
00246             (*mIter).second.second.second = newSize;
00247             mCachemap->mPolicy->useAndUpdate(getId(),
00248                     getPolicyInfo(), oldSize, newSize);
00249         }
00250 
00257         void erase() {
00258             mCachemap->mPolicy->destroy(getId(), getPolicyInfo(), getSize());
00259             mCachemap->destroyCacheLayerEntry(getId(), (**this), getSize());
00260             mMap->erase(mIter);
00261             mIter = mMap->end();
00262         }
00263 
00267         void eraseAll() {
00268             for (mIter = mMap->begin(); mIter != mMap->end(); ++mIter) {
00269                 mCachemap->mPolicy->destroy(getId(), getPolicyInfo(), getSize());
00270                 mCachemap->destroyCacheLayerEntry(getId(), (**this), getSize());
00271             }
00272             mMap->clear();
00273             mIter = mMap->end();
00274         }
00275 
00288         bool insert(const Fingerprint &id, cache_usize_type size) {
00289             std::pair<MapClass::iterator, bool> ins=
00290                 mMap->insert(MapClass::value_type(id,
00291                         MapEntry(CacheData(), std::pair<PolicyData, cache_usize_type>(PolicyData(), size))));
00292             mIter = ins.first;
00293 
00294             if (ins.second) {
00295                 (*mIter).second.second.first = mCachemap->mPolicy->create(id, size);
00296             }
00297             return ins.second;
00298         }
00299     };
00300 
00301     friend class read_iterator;
00302     friend class write_iterator;
00303 
00304 };
00305 
00306 }
00307 }
00308 
00309 #endif /* SIRIKATA_CacheMap_HPP__ */