Sirikata
libcore/include/sirikata/core/transfer/MemoryCacheLayer.hpp
Go to the documentation of this file.
00001 /*  Sirikata Transfer -- Content Transfer management system
00002  *  MemoryCacheLayer.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 1, 2009 */
00033 
00034 #ifndef SIRIKATA_MemoryCacheLayer_HPP__
00035 #define SIRIKATA_MemoryCacheLayer_HPP__
00036 
00037 #include "CacheLayer.hpp"
00038 #include "CacheMap.hpp"
00039 
00040 namespace Sirikata {
00041 namespace Transfer {
00042 
00044 class MemoryCacheLayer : public CacheLayer {
00045 public:
00046     struct CacheData : public CacheEntry {
00047         SparseData mSparse;
00048     };
00049 
00050 private:
00051     typedef CacheMap MemoryMap;
00052     MemoryMap mData;
00053 
00054 protected:
00055     virtual void populateCache(const Fingerprint &fileId, const DenseDataPtr &respondData) {
00056         {
00057             MemoryMap::write_iterator writer(mData);
00058             if (mData.alloc(respondData->length(), writer)) {
00059                 bool newentry = writer.insert(fileId, respondData->length());
00060                 if (newentry) {
00061                     SILOG(transfer,detailed,fileId << " created " << *respondData);
00062                     CacheData *cdata = new CacheData;
00063                     *writer = cdata;
00064                     cdata->mSparse.addValidData(respondData);
00065                     writer.use();
00066                 } else {
00067                     CacheData *cdata = static_cast<CacheData*>(*writer);
00068                     cdata->mSparse.addValidData(respondData);
00069                     if (SILOGP(transfer,detailed)) {
00070                         std::stringstream rangeListStream;
00071                         Range::printRangeList(rangeListStream,
00072                             static_cast<DenseDataList&>(cdata->mSparse),
00073                             static_cast<Range>(*respondData));
00074                         SILOG(transfer,detailed,fileId << " already exists: " << rangeListStream.str());
00075                     }
00076                     writer.update(cdata->mSparse.getSpaceUsed());
00077                 }
00078 
00079             }
00080         }
00081         CacheLayer::populateParentCaches(fileId, respondData);
00082     }
00083 
00084     virtual void destroyCacheEntry(const Fingerprint &fileId, CacheEntry *cacheLayerData, cache_usize_type releaseSize) {
00085         CacheData *toDelete = static_cast<CacheData*>(cacheLayerData);
00086         delete toDelete;
00087     }
00088 
00089 public:
00090     MemoryCacheLayer(CachePolicy *policy, CacheLayer *tryNext)
00091             : CacheLayer(tryNext),
00092             mData(NULL, policy) {
00093         mData.setOwner(this);//to avoid warning in visual studio
00094     }
00095 
00096     virtual void purgeFromCache(const Fingerprint &fileId) {
00097         CacheMap::write_iterator iter(mData);
00098         if (iter.find(fileId)) {
00099             iter.erase();
00100         }
00101         CacheLayer::purgeFromCache(fileId);
00102     }
00103 
00104     virtual void getData(const Fingerprint &fileId, const Range &requestedRange,
00105             const TransferCallback&callback) {
00106         bool haveData = false;
00107         SparseData foundData;
00108         {
00109             MemoryMap::read_iterator iter(mData);
00110             if (iter.find(fileId)) {
00111                 const SparseData &sparseData = static_cast<const CacheData*>(*iter)->mSparse;
00112                 if (SILOGP(transfer,detailed)) {
00113                         std::stringstream rangeListStream;
00114                         Range::printRangeList(rangeListStream,
00115                             static_cast<const DenseDataList&>(sparseData),
00116                             requestedRange);
00117                         SILOG(transfer,detailed,"Found " << fileId << "; ranges=" << rangeListStream.str());
00118                 }
00119                 if (sparseData.contains(requestedRange)) {
00120                     haveData = true;
00121                     foundData = sparseData;
00122                 }
00123             }
00124         }
00125         if (haveData) {
00126             for (DenseDataList::iterator iter = foundData.DenseDataList::begin();
00127                     iter != foundData.DenseDataList::end();
00128                     ++iter) {
00129                 CacheLayer::populateParentCaches(fileId, iter.getPtr());
00130             }
00131             callback(&foundData);
00132         } else {
00133             CacheLayer::getData(fileId, requestedRange, callback);
00134         }
00135     }
00136 };
00137 
00138 }
00139 }
00140 
00141 #endif /* SIRIKATA_MemoryCache_HPP__ */