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