Main Page | Class Hierarchy | Alphabetical List | Class List | File List | Class Members | File Members | Related Pages

VirtualCache.d

Go to the documentation of this file.
00001 /*******************************************************************************
00002 
00003         @file VirtualCache.d
00004         
00005         Copyright (c) 2004 Kris Bell
00006         
00007         This software is provided 'as-is', without any express or implied
00008         warranty. In no event will the authors be held liable for damages
00009         of any kind arising from the use of this software.
00010         
00011         Permission is hereby granted to anyone to use this software for any 
00012         purpose, including commercial applications, and to alter it and/or 
00013         redistribute it freely, subject to the following restrictions:
00014         
00015         1. The origin of this software must not be misrepresented; you must 
00016            not claim that you wrote the original software. If you use this 
00017            software in a product, an acknowledgment within documentation of 
00018            said product would be appreciated but is not required.
00019 
00020         2. Altered source versions must be plainly marked as such, and must 
00021            not be misrepresented as being the original software.
00022 
00023         3. This notice may not be removed or altered from any distribution
00024            of the source.
00025 
00026         4. Derivative works are permitted, but they must carry this notice
00027            in full and credit the original source.
00028 
00029 
00030                         ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
00031 
00032         
00033         @version        Initial version, April 2004      
00034         @author         Kris
00035 
00036 
00037 *******************************************************************************/
00038 
00039 module mango.cache.VirtualCache;
00040 
00041 private import  mango.cache.QueuedCache;
00042 
00043 private import  mango.io.Buffer,
00044                 mango.io.Exception,
00045                 mango.io.PickleReader,
00046                 mango.io.PickleWriter,
00047                 mango.io.ArrayAllocator;
00048 
00049 private import  mango.io.model.IPickle,
00050                 mango.io.model.IBitBucket;
00051 
00052 private import  mango.cache.model.IPayload;
00053 
00054 /******************************************************************************
00055 
00056         Uses a combination of QueuedCache and IBitBucket to spill LRU
00057         cache entries from cache memory, and then recover them intact.
00058         Each cache entry placed into a VirtualCache should have support
00059         for the IPicked interface, such that its content will be written
00060         externally, and restored correctly. In practical terms, this means
00061         the IPayload's placed here should override the read(), write(), 
00062         create() and getGuid() default implementations.
00063 
00064         Here's a contrived example:
00065 
00066         @code
00067         // create a FileBucket as a place to spill cache entries
00068         auto FileBucket bucket = new FileBucket (new FilePath("bucket.bin"), FileBucket.HalfK);
00069 
00070         // note that we specify only two entries, to ensure we'll spill 
00071         // entries to the FileBucket
00072         VirtualCache cache = new VirtualCache (bucket, 2);
00073 
00074         // need to tell registry how to resurrect our spilled entries
00075         PickleRegistry.enroll (new Payload);
00076         
00077         // stuff a few entries into the cache. Adding the third entry
00078         // will cause a spillover to the FileBucket
00079         cache.put ("a", new Payload);
00080         cache.put ("b", new Payload);
00081         cache.put ("c", new Payload);
00082 
00083         // retrieve entries such that we cause one more spillage and
00084         // two resurrections
00085         assert (cache.get("a"));
00086         assert (cache.get("c"));
00087         assert (cache.get("b"));
00088         @endcode
00089 
00090 ******************************************************************************/
00091 
00092 class VirtualCache : QueuedCache
00093 {
00094         private Buffer                  buffer;
00095         private IBitBucket              bucket;
00096         private PickleReader            reader;
00097         private PickleWriter            writer;
00098 
00099         /**********************************************************************
00100         
00101                 Create a VirtualCache with the provided IBitBucket and 
00102                 maximum capacity. Said capacity sets the waterline mark
00103                 whereby further additions to the cache will cause least
00104                 recently used entries to be spilled to the IBitBucket.
00105                 The concurrency level indicates approximately how many 
00106                 threads will content for write access at one time.
00107 
00108         **********************************************************************/
00109 
00110         this (IBitBucket bucket, uint capacity, uint concurrency = 16)
00111         {
00112                 super (capacity, concurrency);
00113                 
00114                 this.bucket = bucket;
00115 
00116                 // create an expanding buffer for writing Objects
00117                 this.buffer = new GrowableBuffer (bucket.getBufferSize());
00118 
00119                 // hook up a writer for serializing Objects
00120                 writer = new PickleWriter (buffer);
00121 
00122                 // hook up a reader for Object reconstruction. Note 
00123                 // that buffer content will be set to data returned
00124                 // by the IBitBucket
00125                 reader = new PickleReader (new Buffer);
00126                 reader.setAllocator (new BufferAllocator);
00127         }
00128 
00129         /**********************************************************************
00130 
00131                 Return the IBitBucket used by this VirtualCache
00132 
00133         **********************************************************************/
00134 
00135         IBitBucket getBucket ()
00136         {
00137                 return bucket;
00138         }
00139 
00140         /**********************************************************************
00141 
00142                 Return an entry from this cache. If the given key is not
00143                 found, we attempt to resurrect the entry via data from 
00144                 our IBitBucket.
00145 
00146                 Returns the IPayload upon success, null if the given
00147                 key was never placed into the cache.
00148 
00149         **********************************************************************/
00150 
00151         override IPayload get (char[] key)
00152         {
00153                 IPayload        e;
00154                 void[]          obj;
00155 
00156                 // see if it's already in the cache ...
00157                 if ((e = super.get (key)) is null)
00158                    {
00159                    // else try to get it from the IBitBucket ...
00160                    obj = bucket.get (key);
00161                    if (obj.length)
00162                       {
00163                       // materialize the object, and stuff it into the cache
00164                       reader.getBuffer.setValidContent (obj);
00165                       e = cast(IPayload) reader.thaw ();
00166                       if (e)
00167                           super.put (key, e);
00168                       }
00169                    }
00170                 return e;
00171         }
00172 
00173         /**********************************************************************
00174 
00175                 Remove an entry from this cache, and from the associated
00176                 IBitBucket too.
00177 
00178         **********************************************************************/
00179 
00180         override IPayload extract (char[] key, ulong timeLimit = ulong.max)
00181         {
00182                 // remove from cache?
00183                 IPayload p = super.extract (key, timeLimit);
00184 
00185                 if (p)
00186                     // remove it from the bucket
00187                     bucket.remove (key);
00188                 return p;
00189         }
00190 
00191         /**********************************************************************
00192 
00193                 Place an entry into the cache and associate it with the 
00194                 provided key. Note that there can be only one entry for 
00195                 any particular key. If two keys entries are added with 
00196                 the same key, the second one overwrites the first.
00197 
00198                 Copy entry to Bucket immediately, so we avoid writing 
00199                 it each time it gets bumped from the cache. 
00200 
00201         **********************************************************************/
00202 
00203         override IPayload put (char[] key, IPayload entry)
00204         {
00205                 if (super.put (key, entry))
00206                    {
00207                    buffer.clear ();
00208                    writer.freeze (entry);
00209                    bucket.put (key, buffer.toString);
00210                    return entry;
00211                    }
00212                 throw new IOException ("Failed to add cache entry to queue");
00213         }       
00214 }
00215 

Generated on Tue Jan 25 21:18:25 2005 for Mango by doxygen 1.3.6