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 /* X r d O u c C a c h e I O C B */ 00144 /******************************************************************************/ 00145 00146 //----------------------------------------------------------------------------- 00149 //----------------------------------------------------------------------------- 00150 00151 class XrdOucCacheIOCB 00152 { 00153 public: 00154 00155 //------------------------------------------------------------------------------ 00161 //------------------------------------------------------------------------------ 00162 virtual 00163 void Done(int result) = 0; 00164 00165 XrdOucCacheIOCB() {} 00166 virtual ~XrdOucCacheIOCB() {} 00167 }; 00168 00169 /******************************************************************************/ 00170 /* C l a s s X r d O u c C a c h e I O */ 00171 /******************************************************************************/ 00172 00173 /* The XrdOucCacheIO object is responsible for interacting with the original 00174 data source/target. It can be used with or without a front-end cache. 00175 00176 Six abstract methods are provided FSize(), Path(), Read(), Sync(), Trunc(), 00177 and Write(). You must provide implementations for each as described below. 00178 00179 Four additional virtual methods are pre-defined: Base(), Detach(), and 00180 Preread() (2x). Normally, there is no need to over-ride these methods. 00181 00182 Finally, each object carries with it a XrdOucCacheStats object. 00183 */ 00184 00185 class XrdOucCacheIO 00186 { 00187 public: 00188 00189 // FSize() returns the current size of the file associated with this object. 00190 00191 // Success: size of the file in bytes. 00192 // Failure: -errno associated with the error. 00193 virtual 00194 long long FSize() = 0; 00195 00196 // Path() returns the path name associated with this object. 00197 // 00198 virtual 00199 const char *Path() = 0; 00200 00201 // Read() places Length bytes in Buffer from a data source at Offset. 00202 // When fronted by a cache, the cache is inspected first. 00203 00204 // Success: actual number of bytes placed in Buffer. 00205 // Failure: -errno associated with the error. 00206 virtual 00207 int Read (char *Buffer, long long Offset, int Length) = 0; 00208 00209 // ReadV() Performs a vector of read requests. When fronted by a cache, 00210 // the cache is inspected first. By batching requests, it provides 00211 // us the ability to skip expensive network round trips. 00212 // If any reads fail or return short, the entire operation should 00213 // fail. 00214 00215 // Success: actual number of bytes read. 00216 // Failure: -errno associated with the read error. 00217 virtual 00218 int ReadV(const XrdOucIOVec *readV, int n) 00219 {int nbytes = 0, curCount = 0; 00220 for (int i=0; i<n; i++) 00221 {curCount = Read(readV[i].data, 00222 readV[i].offset, 00223 readV[i].size); 00224 if (curCount != readV[i].size) 00225 {if (curCount < 0) return curCount; 00226 return -ESPIPE; 00227 } 00228 nbytes += curCount; 00229 } 00230 return nbytes; 00231 } 00232 00233 // Sync() copies any outstanding modified bytes to the target. 00234 00235 // Success: return 0. 00236 // Failure: -errno associated with the error. 00237 virtual 00238 int Sync() = 0; 00239 00240 // Trunc() truncates the file to the specified offset. 00241 00242 // Success: return 0. 00243 // Failure: -errno associated with the error. 00244 virtual 00245 int Trunc(long long Offset) = 0; 00246 00247 00248 // Write() takes Length bytes in Buffer and writes to a data target at Offset. 00249 // When fronted by a cache, the cache is updated as well. 00250 00251 // Success: actual number of bytes copied from the Buffer. 00252 // Failure: -errno associated with the error. 00253 virtual 00254 int Write(char *Buffer, long long Offset, int Length) = 0; 00255 00256 // Base() returns the underlying XrdOucCacheIO object being used. 00257 // 00258 virtual XrdOucCacheIO *Base() {return this;} 00259 00260 // Detach() detaches the object from the cache. It must be called instead of 00261 // using the delete operator since CacheIO objects may have multiple 00262 // outstanding references and actual deletion may need to be defered. 00263 // Detach() returns the underlying CacheIO object when the last 00264 // reference has been removed and 0 otherwise. This allows to say 00265 // something like "delete ioP->Detach()" if you want to make sure you 00266 // delete the underlying object as well. Alternatively, use the optADB 00267 // option when attaching a CacheIO object to a cache. This will delete 00268 // underlying object and always return 0 to avoid a double delete. 00269 // When not fronted by a cache, Detach() always returns itself. This 00270 // makes its use consistent whether or not a cache is employed. 00271 // 00272 virtual XrdOucCacheIO *Detach() {return this;} 00273 00274 00275 // ioActive() returns true if there is any ongoing IO operation. The function is 00276 // used in XrdPosixXrootd::Close() to check if destruction od PosixFile 00277 // has to be done in a separate task. 00278 virtual bool ioActive() { return false; } 00279 00280 // Preread() places Length bytes into the cache from a data source at Offset. 00281 // When there is no cache or the associated cache does not support or 00282 // allow pre-reads, it's a no-op. Cache placement limits do not apply. 00283 // To maximize parallelism, Peread() should called *after* obtaining 00284 // the wanted bytes using Read(). If the cache implementation supports 00285 // automatic prereads; you can setup parameters on how this should be 00286 // done using the next the next structure and method. The following 00287 // options can be specified: 00288 // 00289 static const int SingleUse = 0x0001; // Mark pages for single use 00290 00291 virtual 00292 void Preread (long long Offset, int Length, int Opts=0) 00293 { 00294 (void)Offset; (void)Length; (void)Opts; 00295 } 00296 00297 // The following structure describes automatic preread parameters. These can be 00298 // set at any time for each XrdOucCacheIO object. It can also be specified when 00299 // creating a cache to establish the defaults (see XrdOucCache::Create()). 00300 // Generally, an implementation that supports prereads should disable small 00301 // prereads when minPages or loBound is set to zero; and should disable large 00302 // prereads when maxiRead or maxPages is set to zero. Refer to the actual 00303 // derived class implementation on how the cache handles prereads. 00304 // 00305 struct aprParms 00306 {int Trigger; // preread if (rdln < Trigger) (0 -> pagesize+1) 00307 int prRecalc; // Recalc pr efficiency every prRecalc bytes (0->50M) 00308 int Reserve4; 00309 short minPages; // If rdln/pgsz < min, preread minPages (0->off) 00310 signed 00311 char minPerf; // Minimum auto preread performance required (0->n/a) 00312 char Reserve1; 00313 00314 aprParms() : Trigger(0), prRecalc(0), Reserve4(0), 00315 minPages(0), minPerf(90), Reserve1(0) 00316 {} 00317 }; 00318 00319 virtual 00320 void Preread(aprParms &Parms) { (void)Parms; } 00321 00322 // Here is where the stats about cache and I/O usage reside. There 00323 // is a summary object in the associated cache as well. 00324 // 00325 XrdOucCacheStats Statistics; 00326 00327 virtual ~XrdOucCacheIO() {} // Always use Detach() instead of direct delete! 00328 }; 00329 00330 /******************************************************************************/ 00331 /* C l a s s X r d O u c C a c h e */ 00332 /******************************************************************************/ 00333 00334 /* The XrdOucCache class is used to define an instance of a cache. There can 00335 be many such instances. Each instance is associated with one or more 00336 XrdOucCacheIO objects. Use the Attach() method in this class to create 00337 such associations. 00338 */ 00339 00340 class XrdOucCache 00341 { 00342 public: 00343 00344 /* Attach() must be called to obtain a new XrdOucCacheIO object that fronts an 00345 existing XrdOucCacheIO object with this cache. 00346 Upon success a pointer to a new XrdOucCacheIO object is returned 00347 and must be used to read and write data with the cache interposed. 00348 Upon failure, the original XrdOucCacheIO object is returned with 00349 errno set. You can continue using the object without any cache. 00350 The following Attach() options are available and, when specified, 00351 override the default options associated with the cache, except for 00352 optRW, optNEW, and optWIN which are valid only for a r/w cache. 00353 */ 00354 static const int optADB = 0x1000; // Automatically delete underlying CacheIO 00355 static const int optFIS = 0x0001; // File is Structured (e.g. root file) 00356 static const int optFIU = 0x0002; // File is Unstructured (e.g. unix file) 00357 static const int optRW = 0x0004; // File is read/write (o/w read/only) 00358 static const int optNEW = 0x0014; // File is new -> optRW (o/w read to write) 00359 static const int optWIN = 0x0024; // File is new -> optRW use write-in cache 00360 00361 virtual 00362 XrdOucCacheIO *Attach(XrdOucCacheIO *ioP, int Options=0) = 0; 00363 00364 /* isAttached() 00365 Returns the number of CacheIO objects attached to this cache. 00366 Hence, 0 (false) if none and true otherwise. 00367 */ 00368 virtual 00369 int isAttached() {return 0;} 00370 00371 /* You must first create an instance of a cache using the Create() method. 00372 The Parms structure is used to pass parameters about the cache and should 00373 be filled in with values meaningful to the type of cache being created. 00374 The fields below, while oriented toward a memory cache, are sufficiently 00375 generic to apply to almost any kind of cache. Refer to the actual 00376 implementation in the derived class to see how these values are used. 00377 */ 00378 struct Parms 00379 {long long CacheSize; // Size of cache in bytes (default 100MB) 00380 int PageSize; // Size of each page in bytes (default 32KB) 00381 int Max2Cache; // Largest read to cache (default PageSize) 00382 int MaxFiles; // Maximum number of files (default 256 or 8K) 00383 int Options; // Options as defined below (default r/o cache) 00384 int Reserve1; // Reserved for future use 00385 int Reserve2; // Reserved for future use 00386 00387 Parms() : CacheSize(104857600), PageSize(32768), 00388 Max2Cache(0), MaxFiles(0), Options(0), 00389 Reserve1(0), Reserve2(0) {} 00390 }; 00391 00392 // Valid option values in Parms::Options 00393 // 00394 static const int 00395 isServer = 0x0010; // This is server application (as opposed to a user app). 00396 // Appropriate internal optimizations will be used. 00397 static const int 00398 isStructured = 0x0020; // Optimize for structured files (e.g. root). 00399 00400 static const int 00401 canPreRead = 0x0040; // Enable pre-read operations (o/w ignored) 00402 00403 static const int 00404 logStats = 0x0080; // Display statistics upon detach 00405 00406 static const int 00407 Serialized = 0x0004; // Caller ensures MRSW semantics 00408 00409 static const int 00410 ioMTSafe = 0x0008; // CacheIO object is MT-safe 00411 00412 static const int 00413 Debug = 0x0003; // Produce some debug messages (levels 0, 1, 2, or 3) 00414 00415 /* Create() Creates an instance of a cache using the specified parameters. 00416 You must pass the cache parms and optionally any automatic 00417 pre-read parameters that will be used as future defaults. 00418 Upon success, returns a pointer to the cache. Otherwise, a null 00419 pointer is returned with errno set to indicate the problem. 00420 */ 00421 virtual 00422 XrdOucCache *Create(Parms &Params, XrdOucCacheIO::aprParms *aprP=0) = 0; 00423 00424 00425 // Propagate Unlink client request from posix layer to cache. 00426 virtual 00427 int Unlink(const char* /*path*/) { return 0; } 00428 00429 // Propagate Rmdir client request from posix layer to cache. 00430 virtual 00431 int Rmdir(const char* /*path*/) { return 0; } 00432 00433 // Propagate Rename client request from posix layer to cache. 00434 virtual 00435 int Rename(const char* /*path*/, const char* /*newPath*/) { return 0; } 00436 00437 // Propagate Truncate client request from posix layer to cache. 00438 virtual 00439 int Truncate(const char* /*path*/, off_t /*size*/) { return 0; } 00440 00441 /* The following holds statistics for the cache itself. It is updated as 00442 associated cacheIO objects are deleted and their statistics are added. 00443 */ 00444 XrdOucCacheStats Stats; 00445 00446 XrdOucCache() {} 00447 virtual ~XrdOucCache() {} 00448 }; 00449 00450 /******************************************************************************/ 00451 /* C r e a t i n g C a c h e P l u g - I n s */ 00452 /******************************************************************************/ 00453 00454 /* You can create a cache plug-in for those parts of the xrootd system that 00455 allow a dynamically selectable cache implementation (e.g. the proxy server 00456 plug-in supports cache plug-ins via the pss.cachelib directive). 00457 00458 Your plug-in must exist in a shared library and have the following extern C 00459 function defined: 00460 00461 extern "C" 00462 { 00463 XrdOucCache *XrdOucGetCache(XrdSysLogger *Logger, // Where messages go 00464 const char *Config, // Config file used 00465 const char *Parms); // Optional parm string 00466 } 00467 00468 When Logger is null, you should use cerr to output messages. Otherwise, 00469 tie an instance XrdSysError to the passed logger. 00470 When Config is null, no configuration file is present. Otherwise, you need 00471 additional configuration information you should get it 00472 from that file in order to support single configuration. 00473 When Parms is null, no parameter string was specified. 00474 00475 The call should return an instance of an XrdOucCache object upon success and 00476 a null pointer otherwise. The instance is used to create actual caches using 00477 the object's Create() method. 00478 */ 00479 #endif