xrootd
XrdOucCache.hh
Go to the documentation of this file.
00001 #ifndef __XRDOUCCACHE_HH__
00002 #define __XRDOUCCACHE_HH__
00003 /******************************************************************************/
00004 /*                                                                            */
00005 /*                        X r d O u c C a c h e . h h                         */
00006 /*                                                                            */
00007 /* (c) 2011 by the Board of Trustees of the Leland Stanford, Jr., University  */
00008 /*                            All Rights Reserved                             */
00009 /*   Produced by Andrew Hanushevsky for Stanford University under contract    */
00010 /*              DE-AC02-76-SFO0515 with the Department of Energy              */
00011 /******************************************************************************/
00012 
00013 #include "XrdSys/XrdSysPthread.hh"
00014   
00015 /* The classes defined here can be used to implement a general memory cache for
00016    data from an arbitrary source (e.g. files, sockets, etc); as follows:
00017 
00018    1. Create an instance of XrdOucCacheIO. This object is used to actually
00019       bring in missing data into the cache or write out dirty cache pages.
00020       There can be many instances of this class, as needed. However, make sure
00021       that there is a 1-to-1 unique correspondence between data and its CacheIO
00022       object. Violating this may cause the same data to be cached multiple
00023       times and if the cache is writable the data may be inconsistent!
00024 
00025    2. Create an instance of XrdOucCache. You can specify various cache
00026       handling parameters (see the class definition). You can also define
00027       additional instances if you want more than one memory cache.
00028 
00029    3. Use the Attach() method in XrdOucCache to attach your XrdOucCacheIO
00030       object with a cache instance. The method returns a remanufactured
00031       XrdOucCacheIO object that interposes the cache in front of the original
00032       XrdOucCacheIO. This allows you to transparently use the cache.
00033 
00034    4. When finished using the remanufactured XrdOucCacheIO object, use its
00035       Detach() method to remove the association from the cache, release any
00036       assigned cache pages, write out any dirty pages, and delete the object
00037       when all references have been removed.
00038 
00039    5. You may delete cache instances as well. Just be sure that no associations
00040       still exist using the XrdOucCache::isAttached() method. Otherwise, the
00041       cache destructor will wait until all attached objects are detached.
00042 
00043    Example:
00044       class physIO : public XrdOucCacheIO {...}; // Define required methods
00045       XrdOucCache::Parms myParms;                // Set any desired parameters
00046       XrdOucCache   *myCache;
00047       XrdOucCacheIO *cacheIO;
00048 
00049       myCache = XrdOucCache::Create(myParms);    // Create a cache instance
00050       cacheIO = myCache->Attach(physIO);         // Interpose the cache
00051 
00052       // Use cacheIO (fronted by myCache) instead of physIO. When done...
00053 
00054       delete cacheIO->Detach();                  // Deletes cacheIO and physIO
00055 */
00056   
00057 /******************************************************************************/
00058 /*                C l a s s   X r d O u c C a c h e S t a t s                 */
00059 /******************************************************************************/
00060   
00061 /* The XrdOucCacheStats object holds statistics on cache usage. It is available
00062    in for each XrdOucCacheIO and each XrdOucCache object. The former usually
00063    identifies a specific file while the latter provides summary information.
00064 */
00065 
00066 class XrdOucCacheStats
00067 {
00068 public:
00069 long long    BytesPead;  // Bytes read via preread (not included in BytesRead)
00070 long long    BytesRead;  // Total number of bytes read into the cache
00071 long long    BytesGet;   // Number of bytes delivered from the cache
00072 long long    BytesPass;  // Number of bytes read but not cached
00073 long long    BytesWrite; // Total number of bytes written from the cache
00074 long long    BytesPut;   // Number of bytes updated in the cache
00075 int          Hits;       // Number of times wanted data was in the cache
00076 int          Miss;       // Number of times wanted data was *not* in the cache
00077 int          HitsPR;     // Number of pages wanted data was just preread
00078 int          MissPR;     // Number of pages wanted data was just    read
00079 
00080 inline void Get(XrdOucCacheStats &Dst)
00081                {sMutex.Lock();
00082                 Dst.BytesRead   = BytesPead;  Dst.BytesGet    = BytesRead;
00083                 Dst.BytesPass   = BytesPass;
00084                 Dst.BytesWrite  = BytesWrite; Dst.BytesPut    = BytesPut;
00085                 Dst.Hits        = Hits;       Dst.Miss        = Miss;
00086                 Dst.HitsPR      = HitsPR;     Dst.MissPR      = MissPR;
00087                 sMutex.UnLock();
00088                }
00089 
00090 inline void Add(XrdOucCacheStats &Src)
00091                {sMutex.Lock();
00092                 BytesRead  += Src.BytesPead;  BytesGet   += Src.BytesRead;
00093                 BytesPass  += Src.BytesPass;
00094                 BytesWrite += Src.BytesWrite; BytesPut   += Src.BytesPut;
00095                 Hits       += Src.Hits;       Miss       += Src.Miss;
00096                 HitsPR     += Src.HitsPR;     MissPR     += Src.MissPR;
00097                 sMutex.UnLock();
00098                }
00099 
00100 inline void  Add(long long &Dest, int &Val)
00101                 {sMutex.Lock(); Dest += Val; sMutex.UnLock();}
00102 
00103 inline void  Lock()   {sMutex.Lock();}
00104 inline void  UnLock() {sMutex.UnLock();}
00105 
00106              XrdOucCacheStats() : BytesPead(0), BytesRead(0),  BytesGet(0),
00107                                   BytesPass(0), BytesWrite(0), BytesPut(0),
00108                                   Hits(0),      Miss(0),
00109                                   HitsPR(0),    MissPR(0) {}
00110             ~XrdOucCacheStats() {}
00111 private:
00112 XrdSysMutex sMutex;
00113 };
00114 
00115 /******************************************************************************/
00116 /*                   C l a s s   X r d O u c C a c h e I O                    */
00117 /******************************************************************************/
00118 
00119 /* The XrdOucCacheIO object is responsible for interacting with the original
00120    data source/target. It can be used with or without a front-end cache.
00121 
00122    Five abstract methods are provided Path(), Read(), Sync(), Trunc(), and
00123    Write(). You must provide implementations for each as described below.
00124 
00125    Four additional virtual methods are pre-defined: Base(), Detach(), and
00126    Preread() (2x). Normally, there is no need to over-ride these methods.
00127 
00128    Finally, each object carries with it a XrdOucCacheStats object.
00129 */
00130 
00131 class XrdOucCacheIO
00132 {
00133 public:
00134 
00135 // Path()   returns the path name associated with this object.
00136 //
00137 virtual
00138 const char *Path() = 0;
00139 
00140 // Read()   places Length bytes in Buffer from a data source at Offset.
00141 //          When fronted by a memory cache, the cache is inspected first.
00142 
00143 //          Success: actual number of bytes placed in Buffer.
00144 //          Failure: -errno associated with the error.
00145 virtual
00146 int         Read (char *Buffer, long long Offset, int Length) = 0;
00147 
00148 // Sync()   copies any outstanding modified bytes to the target.
00149 
00150 //          Success: return 0.
00151 //          Failure: -errno associated with the error.
00152 virtual
00153 int         Sync() = 0;
00154 
00155 // Trunc()  truncates the file to the specified offset.
00156 
00157 //          Success: return 0.
00158 //          Failure: -errno associated with the error.
00159 virtual
00160 int         Trunc(long long Offset) = 0;
00161 
00162 
00163 // Write()  takes Length bytes in Buffer and writes to a data target at Offset.
00164 //          When fronted by a memory cache, the cache is updated as well.
00165 
00166 //          Success: actual number of bytes copied from the Buffer.
00167 //          Failure: -errno associated with the error.
00168 virtual
00169 int         Write(char *Buffer, long long Offset, int Length) = 0;
00170 
00171 // Base()   returns the underlying XrdOucCacheIO object being used.
00172 //
00173 virtual XrdOucCacheIO *Base()   {return this;}
00174 
00175 // Detach() detaches the object from the cache. It must be called instead of
00176 //          using the delete operator since CacheIO objects may have multiple
00177 //          outstanding references and actual deletion may need to be defered.
00178 //          Detach() returns the underlying CacheIO object when the last
00179 //          reference has been removed and 0 otherwise. This allows to say
00180 //          something like "delete ioP->Detach()" if you want to make sure you
00181 //          delete the underlying object as well. Alternatively, use the optADB
00182 //          option when attaching a CacheIO object to a cache. This will delete
00183 //          underlying object and always return 0 to avoid a double delete.
00184 //          When not fronted by a cache, Detach() always returns itself. This
00185 //          makes its use consistent whether or not a memory cache is employed.
00186 //
00187 virtual XrdOucCacheIO *Detach() {return this;}
00188 
00189 // Preread() places Length bytes into the cache from a data source at Offset.
00190 //          When there is no memory cache or the associated cache does not
00191 //          allow pre-reads, it's a no-op. Cache placement limits do not apply.
00192 //          To maximize parallelism, Peread() should called *after* obtaining
00193 //          the wanted bytes using Read(). You can also do automatic prereads;
00194 //          see the next the next structure and method. The following options
00195 //          can be specified:
00196 //
00197 static const int SingleUse = 0x0001; // Mark pages for single use
00198 
00199 virtual
00200 void        Preread (long long Offset, int Length, int Opts=0) {}
00201 
00202 // The following structure describes automatic preread parameters. These can be
00203 // set at any time for each XrdOucCacheIO object. It can also be specified when
00204 // creating a cache to establish the default parameters. Note that setting
00205 // minPages or loBound to zero turns off small prereads while setting maxiRead
00206 // or maxPages to zero turns off large prereads. See the cache notes.
00207 //
00208 struct aprParms
00209       {int   Trigger;   // preread if (rdln < Trigger)        (0 -> pagesize+1)
00210        int   prRecalc;  // Recalc pr efficiency every prRecalc bytes   (0->50M)
00211        int   Reserve4;
00212        short minPages;  // If rdln/pgsz < min,  preread minPages       (0->off)
00213        char  minPerf;   // Minimum auto preread performance required   (0->n/a)
00214        char  Reserve1;
00215 
00216              aprParms() : Trigger(0),  prRecalc(0), Reserve4(0),
00217                           minPages(0), minPerf(90), Reserve1(0)
00218                           {}
00219       };
00220 
00221 virtual
00222 void        Preread(aprParms &Parms) {}
00223 
00224 //          Here is where the stats about cache and I/O usage reside. There
00225 //          is a summary object in the associated cache as well.
00226 //
00227 XrdOucCacheStats Statistics;
00228 
00229 virtual    ~XrdOucCacheIO() {}  // Use Detach() instead of direct delete!
00230 };
00231 
00232 /******************************************************************************/
00233 /*                     C l a s s   X r d O u c C a c h e                      */
00234 /******************************************************************************/
00235   
00236 /* The XrdOucCache class is used to define an instance of a memory cache. There
00237    can be many such instances. Each instance is associated with one or more
00238    XrdOucCacheIO objects. Use the Attach() method in this class to create 
00239    such associations.
00240 
00241    Notes: 1. The minimum PageSize is 4096 (4k) and must be a power of 2.
00242              The maximum PageSize is 16MB.
00243           2. The size of the cache is forced to be a multiple PageSize and
00244              have a minimum size of PageSize * 256.
00245           3. The minimum external read size is equal to PageSize.
00246           4. Currently, only write-through caches are supported.
00247           5. The Max2Cache value avoids placing data in the cache when a read
00248              exceeds the specified value. The minimum allowed is PageSize, which
00249              is also the default.
00250           6. Structured file optimization allows pages whose bytes have been
00251              fully referenced to be discarded; effectively increasing the cache.
00252           7. A structured cache treats all files as structured. By default, the
00253              cache treats files as unstructured. You can over-ride the settings
00254              on an individual file basis when the file's I/O object is attached
00255              by passing the XrdOucCache::optFIS or XrdOucCache::optFIU option.
00256           8. Write-in caches are only supported for files attached with the
00257              XrdOucCache::optWIN setting. Otherwise, updates are handled
00258              with write-through operations.
00259           9. A cache object may be deleted. However, the deletion is delayed
00260              until all CacheIO objects attached to the cache are detached.
00261              Use isAttached() to find out if any CacheIO objects are attached.
00262          10. The default maximum attached files is set to 8192 when isServer
00263              has been specified. Otherwise, it is set at 256.
00264          11. When canPreRead is specified, the cache asynchronously handles
00265              preread requests (see XrdOucCacheIO::Preread()) using 9 threads
00266              when isServer is in effect. Otherwise, 3 threads are used.
00267          12. The max queue depth for prereads is 8. When the max is exceeded
00268              the oldest preread is discarded to make room for the newest one.
00269          13. If you specify the canPreRead option when creating the cache you
00270              can also enable automatic prereads if the algorithm is workable.
00271              Otherwise, you will need to implement your own algorithm and
00272              issue prereads manually usingthe XrdOucCacheIO::Preread() method.
00273          14. The automatic preread algorithm is (ref XrdOucCacheIO::aprParms):
00274              a) A preread operation occurs when all of the following conditions
00275                 are satisfied:
00276                 o The cache CanPreRead option is in effect.
00277                 o The read length < 'miniRead'
00278                    ||(read length < 'maxiRead' && Offset == next maxi offset)
00279              b) The preread page count is set to be readlen/pagesize and the
00280                 preread occurs at the page after read_offset+readlen. The page
00281                 is adjusted, as follows:
00282                 o If the count is < minPages, it is set to minPages.
00283                 o The count must be > 0 at this point.
00284              c) Normally, pre-read pages participate in the LRU scheme. However,
00285                 if the preread was triggered using 'maxiRead' then the pages are
00286                 marked for single use only. This means that the moment data is
00287                 delivered from the page, the page is recycled.
00288          15. Invalid options silently force the use of the default.
00289 */
00290 
00291 class XrdOucCache
00292 {
00293 public:
00294 
00295 /* Attach()   must be called to obtain a new XrdOucCacheIO object that fronts an
00296               existing XrdOucCacheIO object with this memory cache.
00297               Upon success a pointer to a new XrdOucCacheIO object is returned
00298               and must be used to read and write data with the cache interposed.
00299               Upon failure, the original XrdOucCacheIO object is returned with
00300               errno set. You can continue using the object without any cache.
00301               The following Attach() options are available and, when specified,
00302               override the default options associated with the cache, except for
00303               optRW, optNEW, and optWIN which are valid only for a r/w cache.
00304 */
00305 static const int optADB = 0x1000; // Automatically delete underlying CacheIO
00306 static const int optFIS = 0x0001; // File is   Structured (e.g. root file)
00307 static const int optFIU = 0x0002; // File is Unstructured (e.g. unix file)
00308 static const int optRW  = 0x0004; // File is read/write   (o/w read/only)
00309 static const int optNEW = 0x0014; // File is new -> optRW (o/w read to write)
00310 static const int optWIN = 0x0024; // File is new -> optRW use write-in cache
00311 
00312 virtual
00313 XrdOucCacheIO *Attach(XrdOucCacheIO *ioP, int Options=0) = 0;
00314 
00315 /* isAttached()
00316                Returns the number of CacheIO objects attached to this cache.
00317                Hence, 0 (false) if none and true otherwise.
00318 */
00319 virtual
00320 int            isAttached() {return 0;}
00321 
00322 /* You must first create an instance of a cache. The Parms structure is used
00323    to pass parameters about the cache and should be filled in:
00324 */
00325 struct Parms
00326       {long long CacheSize; // Size of cache in bytes     (default 100MB)
00327        int       PageSize;  // Size of each page in bytes (default 32KB)
00328        int       Max2Cache; // Largest read to cache      (default PageSize)
00329        int       MaxFiles;  // Maximum number of files    (default 256 or 8K)
00330        int       Options;   // Options as defined below   (default r/o cache)
00331        int       Reserve1;  // Reserved for future use
00332        int       Reserve2;  // Reserved for future use
00333 
00334                  Parms() : CacheSize(104857600), PageSize(32768),
00335                            Max2Cache(0), MaxFiles(0), Options(0),
00336                            Reserve1(0),  Reserve2(0) {}
00337       };
00338 
00339 // Valid option values in Parms::Options
00340 //
00341 static const int
00342 isServer     = 0x0010; // This is server application (as opposed to a user app).
00343                        // Appropriate internal optimizations will be used.
00344 static const int
00345 isStructured = 0x0020; // Optimize for structured files (e.g. root).
00346 
00347 static const int
00348 canPreRead   = 0x0040; // Enable pre-read operations (o/w ignored)
00349 
00350 static const int
00351 logStats     = 0x0080; // Display statistics upon detach
00352 
00353 static const int
00354 Serialized   = 0x0004; // Caller ensures MRSW semantics
00355 
00356 static const int
00357 ioMTSafe     = 0x0008; // CacheIO object is MT-safe
00358 
00359 static const int
00360 Debug        = 0x0003; // Produce some debug messages (levels 0, 1, 2, or 3)
00361 
00362 /* Create()    Creates an instance of a cache using the specified parameters.
00363                You must pass the cache parms and optionally any automatic
00364                pre-read parameters that will be used as future defaults.
00365                Upon success, returns a pointer to the cache. Otherwise, a null
00366                pointer is returned with errno set to indicate the problem.
00367 */
00368 static
00369 XrdOucCache   *Create(Parms &Params, XrdOucCacheIO::aprParms *aprP=0);
00370 
00371 /* The following holds statistics for the cache itself. It is updated as
00372    associated cacheIO objects are deleted and their statistics are added.
00373 */
00374 XrdOucCacheStats Stats;
00375 
00376                XrdOucCache() {}
00377 virtual       ~XrdOucCache() {}
00378 };
00379 #endif