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

Generated on Sat Dec 24 17:28:34 2005 for Mango by  doxygen 1.4.0