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 /* This file is part of the XRootD software suite. */ 00013 /* */ 00014 /* XRootD is free software: you can redistribute it and/or modify it under */ 00015 /* the terms of the GNU Lesser General Public License as published by the */ 00016 /* Free Software Foundation, either version 3 of the License, or (at your */ 00017 /* option) any later version. */ 00018 /* */ 00019 /* XRootD is distributed in the hope that it will be useful, but WITHOUT */ 00020 /* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or */ 00021 /* FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public */ 00022 /* License for more details. */ 00023 /* */ 00024 /* You should have received a copy of the GNU Lesser General Public License */ 00025 /* along with XRootD in a file called COPYING.LESSER (LGPL license) and file */ 00026 /* COPYING (GPL license). If not, see <http://www.gnu.org/licenses/>. */ 00027 /* */ 00028 /* The copyright holder's institutional names and contributor's names may not */ 00029 /* be used to endorse or promote products derived from this software without */ 00030 /* specific prior written permission of the institution or contributor. */ 00031 /******************************************************************************/ 00032 00033 #include "XrdSys/XrdSysPthread.hh" 00034 00035 /* The classes defined here can be used to implement a general cache for 00036 data from an arbitrary source (e.g. files, sockets, etc); as follows: 00037 00038 1. Create an instance of XrdOucCacheIO. This object is used to actually 00039 bring in missing data into the cache or write out dirty cache pages. 00040 There can be many instances of this class, as needed. However, make sure 00041 that there is a 1-to-1 unique correspondence between data and its CacheIO 00042 object. Violating this may cause the same data to be cached multiple 00043 times and if the cache is writable the data may be inconsistent! 00044 00045 2. Create an instance of XrdOucCache. You can specify various cache 00046 handling parameters (see the class definition). You can also define 00047 additional instances if you want more than one cache. The specific cache 00048 you create will be defined by an implementation that derives from these 00049 classes. For instance, an implementation of a memory cache is defined 00050 in "XrdOucCacheDram.hh". 00051 00052 3. Use the Attach() method in XrdOucCache to attach your XrdOucCacheIO 00053 object with a cache instance. The method returns a remanufactured 00054 XrdOucCacheIO object that interposes the cache in front of the original 00055 XrdOucCacheIO. This allows you to transparently use the cache. 00056 00057 4. When finished using the remanufactured XrdOucCacheIO object, use its 00058 Detach() method to remove the association from the cache. Other actions 00059 are defined by the actual implementation. For instance XrdOucCacheDram 00060 also releases any assigned cache pages, writes out any dirty pages, and 00061 may optionally delete the object when all references have been removed. 00062 00063 5. You may delete cache instances as well. Just be sure that no associations 00064 still exist using the XrdOucCache::isAttached() method. Otherwise, the 00065 cache destructor will wait until all attached objects are detached. 00066 00067 Example: 00068 class physIO : public XrdOucCacheIO {...}; // Define required methods 00069 class xCache : public XrdOucCache {...}; // The cache implementation 00070 XrdOucCache::Parms myParms; // Set any desired parameters 00071 XrdOucCache *myCache; 00072 XrdOucCacheIO *cacheIO; 00073 xCache theCache; // Implementation instance 00074 00075 myCache = theCache.Create(myParms); // Create a cache instance 00076 cacheIO = myCache->Attach(physIO); // Interpose the cache 00077 00078 // Use cacheIO (fronted by myCache) instead of physIO. When done... 00079 00080 delete cacheIO->Detach(); // Deletes cacheIO and physIO 00081 */ 00082 00083 /******************************************************************************/ 00084 /* C l a s s X r d O u c C a c h e S t a t s */ 00085 /******************************************************************************/ 00086 00087 /* The XrdOucCacheStats object holds statistics on cache usage. It is available 00088 in for each XrdOucCacheIO and each XrdOucCache object. The former usually 00089 identifies a specific file while the latter provides summary information. 00090 */ 00091 00092 class XrdOucCacheStats 00093 { 00094 public: 00095 long long BytesPead; // Bytes read via preread (not included in BytesRead) 00096 long long BytesRead; // Total number of bytes read into the cache 00097 long long BytesGet; // Number of bytes delivered from the cache 00098 long long BytesPass; // Number of bytes read but not cached 00099 long long BytesWrite; // Total number of bytes written from the cache 00100 long long BytesPut; // Number of bytes updated in the cache 00101 int Hits; // Number of times wanted data was in the cache 00102 int Miss; // Number of times wanted data was *not* in the cache 00103 int HitsPR; // Number of pages wanted data was just preread 00104 int MissPR; // Number of pages wanted data was just read 00105 00106 inline void Get(XrdOucCacheStats &Dst) 00107 {sMutex.Lock(); 00108 Dst.BytesRead = BytesPead; Dst.BytesGet = BytesRead; 00109 Dst.BytesPass = BytesPass; 00110 Dst.BytesWrite = BytesWrite; Dst.BytesPut = BytesPut; 00111 Dst.Hits = Hits; Dst.Miss = Miss; 00112 Dst.HitsPR = HitsPR; Dst.MissPR = MissPR; 00113 sMutex.UnLock(); 00114 } 00115 00116 inline void Add(XrdOucCacheStats &Src) 00117 {sMutex.Lock(); 00118 BytesRead += Src.BytesPead; BytesGet += Src.BytesRead; 00119 BytesPass += Src.BytesPass; 00120 BytesWrite += Src.BytesWrite; BytesPut += Src.BytesPut; 00121 Hits += Src.Hits; Miss += Src.Miss; 00122 HitsPR += Src.HitsPR; MissPR += Src.MissPR; 00123 sMutex.UnLock(); 00124 } 00125 00126 inline void Add(long long &Dest, int &Val) 00127 {sMutex.Lock(); Dest += Val; sMutex.UnLock();} 00128 00129 inline void Lock() {sMutex.Lock();} 00130 inline void UnLock() {sMutex.UnLock();} 00131 00132 XrdOucCacheStats() : BytesPead(0), BytesRead(0), BytesGet(0), 00133 BytesPass(0), BytesWrite(0), BytesPut(0), 00134 Hits(0), Miss(0), 00135 HitsPR(0), MissPR(0) {} 00136 ~XrdOucCacheStats() {} 00137 private: 00138 XrdSysMutex sMutex; 00139 }; 00140 00141 /******************************************************************************/ 00142 /* C l a s s X r d O u c C a c h e I O */ 00143 /******************************************************************************/ 00144 00145 /* The XrdOucCacheIO object is responsible for interacting with the original 00146 data source/target. It can be used with or without a front-end cache. 00147 00148 Six abstract methods are provided FSize(), Path(), Read(), Sync(), Trunc(), 00149 and Write(). You must provide implementations for each as described below. 00150 00151 Four additional virtual methods are pre-defined: Base(), Detach(), and 00152 Preread() (2x). Normally, there is no need to over-ride these methods. 00153 00154 Finally, each object carries with it a XrdOucCacheStats object. 00155 */ 00156 00157 class XrdOucCacheIO 00158 { 00159 public: 00160 00161 // FSize() returns the current size of the file associated with this object. 00162 00163 // Success: size of the file in bytes. 00164 // Failure: -errno associated with the error. 00165 virtual 00166 long long FSize() = 0; 00167 00168 // Path() returns the path name associated with this object. 00169 // 00170 virtual 00171 const char *Path() = 0; 00172 00173 // Read() places Length bytes in Buffer from a data source at Offset. 00174 // When fronted by a cache, the cache is inspected first. 00175 00176 // Success: actual number of bytes placed in Buffer. 00177 // Failure: -errno associated with the error. 00178 virtual 00179 int Read (char *Buffer, long long Offset, int Length) = 0; 00180 00181 // Sync() copies any outstanding modified bytes to the target. 00182 00183 // Success: return 0. 00184 // Failure: -errno associated with the error. 00185 virtual 00186 int Sync() = 0; 00187 00188 // Trunc() truncates the file to the specified offset. 00189 00190 // Success: return 0. 00191 // Failure: -errno associated with the error. 00192 virtual 00193 int Trunc(long long Offset) = 0; 00194 00195 00196 // Write() takes Length bytes in Buffer and writes to a data target at Offset. 00197 // When fronted by a cache, the cache is updated as well. 00198 00199 // Success: actual number of bytes copied from the Buffer. 00200 // Failure: -errno associated with the error. 00201 virtual 00202 int Write(char *Buffer, long long Offset, int Length) = 0; 00203 00204 // Base() returns the underlying XrdOucCacheIO object being used. 00205 // 00206 virtual XrdOucCacheIO *Base() {return this;} 00207 00208 // Detach() detaches the object from the cache. It must be called instead of 00209 // using the delete operator since CacheIO objects may have multiple 00210 // outstanding references and actual deletion may need to be defered. 00211 // Detach() returns the underlying CacheIO object when the last 00212 // reference has been removed and 0 otherwise. This allows to say 00213 // something like "delete ioP->Detach()" if you want to make sure you 00214 // delete the underlying object as well. Alternatively, use the optADB 00215 // option when attaching a CacheIO object to a cache. This will delete 00216 // underlying object and always return 0 to avoid a double delete. 00217 // When not fronted by a cache, Detach() always returns itself. This 00218 // makes its use consistent whether or not a cache is employed. 00219 // 00220 virtual XrdOucCacheIO *Detach() {return this;} 00221 00222 // Preread() places Length bytes into the cache from a data source at Offset. 00223 // When there is no cache or the associated cache does not support or 00224 // allow pre-reads, it's a no-op. Cache placement limits do not apply. 00225 // To maximize parallelism, Peread() should called *after* obtaining 00226 // the wanted bytes using Read(). If the cache implementation supports 00227 // automatic prereads; you can setup parameters on how this should be 00228 // done using the next the next structure and method. The following 00229 // options can be specified: 00230 // 00231 static const int SingleUse = 0x0001; // Mark pages for single use 00232 00233 virtual 00234 void Preread (long long Offset, int Length, int Opts=0) {} 00235 00236 // The following structure describes automatic preread parameters. These can be 00237 // set at any time for each XrdOucCacheIO object. It can also be specified when 00238 // creating a cache to establish the defaults (see XrdOucCache::Create()). 00239 // Generally, an implementation that supports prereads should disable small 00240 // prereads when minPages or loBound is set to zero; and should disable large 00241 // prereads when maxiRead or maxPages is set to zero. Refer to the actual 00242 // derived class implementation on how the cache handles prereads. 00243 // 00244 struct aprParms 00245 {int Trigger; // preread if (rdln < Trigger) (0 -> pagesize+1) 00246 int prRecalc; // Recalc pr efficiency every prRecalc bytes (0->50M) 00247 int Reserve4; 00248 short minPages; // If rdln/pgsz < min, preread minPages (0->off) 00249 char minPerf; // Minimum auto preread performance required (0->n/a) 00250 char Reserve1; 00251 00252 aprParms() : Trigger(0), prRecalc(0), Reserve4(0), 00253 minPages(0), minPerf(90), Reserve1(0) 00254 {} 00255 }; 00256 00257 virtual 00258 void Preread(aprParms &Parms) {} 00259 00260 // Here is where the stats about cache and I/O usage reside. There 00261 // is a summary object in the associated cache as well. 00262 // 00263 XrdOucCacheStats Statistics; 00264 00265 virtual ~XrdOucCacheIO() {} // Always use Detach() instead of direct delete! 00266 }; 00267 00268 /******************************************************************************/ 00269 /* C l a s s X r d O u c C a c h e */ 00270 /******************************************************************************/ 00271 00272 /* The XrdOucCache class is used to define an instance of a cache. There can 00273 be many such instances. Each instance is associated with one or more 00274 XrdOucCacheIO objects. Use the Attach() method in this class to create 00275 such associations. 00276 */ 00277 00278 class XrdOucCache 00279 { 00280 public: 00281 00282 /* Attach() must be called to obtain a new XrdOucCacheIO object that fronts an 00283 existing XrdOucCacheIO object with this cache. 00284 Upon success a pointer to a new XrdOucCacheIO object is returned 00285 and must be used to read and write data with the cache interposed. 00286 Upon failure, the original XrdOucCacheIO object is returned with 00287 errno set. You can continue using the object without any cache. 00288 The following Attach() options are available and, when specified, 00289 override the default options associated with the cache, except for 00290 optRW, optNEW, and optWIN which are valid only for a r/w cache. 00291 */ 00292 static const int optADB = 0x1000; // Automatically delete underlying CacheIO 00293 static const int optFIS = 0x0001; // File is Structured (e.g. root file) 00294 static const int optFIU = 0x0002; // File is Unstructured (e.g. unix file) 00295 static const int optRW = 0x0004; // File is read/write (o/w read/only) 00296 static const int optNEW = 0x0014; // File is new -> optRW (o/w read to write) 00297 static const int optWIN = 0x0024; // File is new -> optRW use write-in cache 00298 00299 virtual 00300 XrdOucCacheIO *Attach(XrdOucCacheIO *ioP, int Options=0) = 0; 00301 00302 /* isAttached() 00303 Returns the number of CacheIO objects attached to this cache. 00304 Hence, 0 (false) if none and true otherwise. 00305 */ 00306 virtual 00307 int isAttached() {return 0;} 00308 00309 /* You must first create an instance of a cache using the Create() method. 00310 The Parms structure is used to pass parameters about the cache and should 00311 be filled in with values meaningful to the type of cache being created. 00312 The fields below, while oriented toward a memory cache, are sufficiently 00313 generic to apply to almost any kind of cache. Refer to the actual 00314 implementation in the derived class to see how these values are used. 00315 */ 00316 struct Parms 00317 {long long CacheSize; // Size of cache in bytes (default 100MB) 00318 int PageSize; // Size of each page in bytes (default 32KB) 00319 int Max2Cache; // Largest read to cache (default PageSize) 00320 int MaxFiles; // Maximum number of files (default 256 or 8K) 00321 int Options; // Options as defined below (default r/o cache) 00322 int Reserve1; // Reserved for future use 00323 int Reserve2; // Reserved for future use 00324 00325 Parms() : CacheSize(104857600), PageSize(32768), 00326 Max2Cache(0), MaxFiles(0), Options(0), 00327 Reserve1(0), Reserve2(0) {} 00328 }; 00329 00330 // Valid option values in Parms::Options 00331 // 00332 static const int 00333 isServer = 0x0010; // This is server application (as opposed to a user app). 00334 // Appropriate internal optimizations will be used. 00335 static const int 00336 isStructured = 0x0020; // Optimize for structured files (e.g. root). 00337 00338 static const int 00339 canPreRead = 0x0040; // Enable pre-read operations (o/w ignored) 00340 00341 static const int 00342 logStats = 0x0080; // Display statistics upon detach 00343 00344 static const int 00345 Serialized = 0x0004; // Caller ensures MRSW semantics 00346 00347 static const int 00348 ioMTSafe = 0x0008; // CacheIO object is MT-safe 00349 00350 static const int 00351 Debug = 0x0003; // Produce some debug messages (levels 0, 1, 2, or 3) 00352 00353 /* Create() Creates an instance of a cache using the specified parameters. 00354 You must pass the cache parms and optionally any automatic 00355 pre-read parameters that will be used as future defaults. 00356 Upon success, returns a pointer to the cache. Otherwise, a null 00357 pointer is returned with errno set to indicate the problem. 00358 */ 00359 virtual 00360 XrdOucCache *Create(Parms &Params, XrdOucCacheIO::aprParms *aprP=0) = 0; 00361 00362 /* The following holds statistics for the cache itself. It is updated as 00363 associated cacheIO objects are deleted and their statistics are added. 00364 */ 00365 XrdOucCacheStats Stats; 00366 00367 XrdOucCache() {} 00368 virtual ~XrdOucCache() {} 00369 }; 00370 00371 /******************************************************************************/ 00372 /* C r e a t i n g C a c h e P l u g - I n s */ 00373 /******************************************************************************/ 00374 00375 /* You can create a cache plug-in for those parts of the xrootd system that 00376 allow a dynamically selectable cache implementation (e.g. the proxy server 00377 plug-in supports cache plug-ins via the pss.cachelib directive). 00378 00379 Your plug-in must exist in a shared library and have the following extern C 00380 function defined: 00381 00382 extern "C" 00383 { 00384 XrdOucCache *XrdOucGetCache(XrdSysLogger *Logger, // Where messages go 00385 const char *Config, // Config file used 00386 const char *Parms); // Optional parm string 00387 } 00388 00389 When Logger is null, you should use cerr to output messages. Otherwise, 00390 tie an instance XrdSysError to the passed logger. 00391 When Config is null, no configuration file is present. Otherwise, you need 00392 additional configuration information you should get it 00393 from that file in order to support single configuration. 00394 When Parms is null, no parameter string was specified. 00395 00396 The call should return an instance of an XrdOucCache object upon success and 00397 a null pointer otherwise. The instance is used to create actual caches using 00398 the object's Create() method. 00399 */ 00400 #endif