|
xrootd
|
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
1.7.5