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

Generated on Sun Nov 7 19:06:54 2004 for Mango by doxygen 1.3.6