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