xrootd
XrdOucCache.hh
Go to the documentation of this file.
1 #ifndef __XRDOUCCACHE_HH__
2 #define __XRDOUCCACHE_HH__
3 /******************************************************************************/
4 /* */
5 /* X r d O u c C a c h e . h h */
6 /* */
7 /* (c) 2011 by the Board of Trustees of the Leland Stanford, Jr., University */
8 /* All Rights Reserved */
9 /* Produced by Andrew Hanushevsky for Stanford University under contract */
10 /* DE-AC02-76-SFO0515 with the Department of Energy */
11 /******************************************************************************/
12 
13 #include "XrdSys/XrdSysPthread.hh"
14 
15 /* The classes defined here can be used to implement a general cache for
16  data from an arbitrary source (e.g. files, sockets, etc); as follows:
17 
18  1. Create an instance of XrdOucCacheIO. This object is used to actually
19  bring in missing data into the cache or write out dirty cache pages.
20  There can be many instances of this class, as needed. However, make sure
21  that there is a 1-to-1 unique correspondence between data and its CacheIO
22  object. Violating this may cause the same data to be cached multiple
23  times and if the cache is writable the data may be inconsistent!
24 
25  2. Create an instance of XrdOucCache. You can specify various cache
26  handling parameters (see the class definition). You can also define
27  additional instances if you want more than one cache. The specific cache
28  you create will be defined by an implementation that derives from these
29  classes. For instance, an implementation of a memory cache is defined
30  in "XrdOucCacheDram.hh".
31 
32  3. Use the Attach() method in XrdOucCache to attach your XrdOucCacheIO
33  object with a cache instance. The method returns a remanufactured
34  XrdOucCacheIO object that interposes the cache in front of the original
35  XrdOucCacheIO. This allows you to transparently use the cache.
36 
37  4. When finished using the remanufactured XrdOucCacheIO object, use its
38  Detach() method to remove the association from the cache. Other actions
39  are defined by the actual implementation. For instance XrdOucCacheDram
40  also releases any assigned cache pages, writes out any dirty pages, and
41  may optionally delete the object when all references have been removed.
42 
43  5. You may delete cache instances as well. Just be sure that no associations
44  still exist using the XrdOucCache::isAttached() method. Otherwise, the
45  cache destructor will wait until all attached objects are detached.
46 
47  Example:
48  class physIO : public XrdOucCacheIO {...}; // Define required methods
49  class xCache : public XrdOucCache {...}; // The cache implementation
50  XrdOucCache::Parms myParms; // Set any desired parameters
51  XrdOucCache *myCache;
52  XrdOucCacheIO *cacheIO;
53  xCache theCache; // Implementation instance
54 
55  myCache = theCache.Create(myParms); // Create a cache instance
56  cacheIO = myCache->Attach(physIO); // Interpose the cache
57 
58  // Use cacheIO (fronted by myCache) instead of physIO. When done...
59 
60  delete cacheIO->Detach(); // Deletes cacheIO and physIO
61 */
62 
63 /******************************************************************************/
64 /* C l a s s X r d O u c C a c h e S t a t s */
65 /******************************************************************************/
66 
67 /* The XrdOucCacheStats object holds statistics on cache usage. It is available
68  in for each XrdOucCacheIO and each XrdOucCache object. The former usually
69  identifies a specific file while the latter provides summary information.
70 */
71 
73 {
74 public:
75 long long BytesPead; // Bytes read via preread (not included in BytesRead)
76 long long BytesRead; // Total number of bytes read into the cache
77 long long BytesGet; // Number of bytes delivered from the cache
78 long long BytesPass; // Number of bytes read but not cached
79 long long BytesWrite; // Total number of bytes written from the cache
80 long long BytesPut; // Number of bytes updated in the cache
81 int Hits; // Number of times wanted data was in the cache
82 int Miss; // Number of times wanted data was *not* in the cache
83 int HitsPR; // Number of pages wanted data was just preread
84 int MissPR; // Number of pages wanted data was just read
85 
86 inline void Get(XrdOucCacheStats &Dst)
87  {sMutex.Lock();
89  Dst.BytesPass = BytesPass;
91  Dst.Hits = Hits; Dst.Miss = Miss;
92  Dst.HitsPR = HitsPR; Dst.MissPR = MissPR;
93  sMutex.UnLock();
94  }
95 
96 inline void Add(XrdOucCacheStats &Src)
97  {sMutex.Lock();
98  BytesRead += Src.BytesPead; BytesGet += Src.BytesRead;
99  BytesPass += Src.BytesPass;
100  BytesWrite += Src.BytesWrite; BytesPut += Src.BytesPut;
101  Hits += Src.Hits; Miss += Src.Miss;
102  HitsPR += Src.HitsPR; MissPR += Src.MissPR;
103  sMutex.UnLock();
104  }
105 
106 inline void Add(long long &Dest, int &Val)
107  {sMutex.Lock(); Dest += Val; sMutex.UnLock();}
108 
109 inline void Lock() {sMutex.Lock();}
110 inline void UnLock() {sMutex.UnLock();}
111 
113  BytesPass(0), BytesWrite(0), BytesPut(0),
114  Hits(0), Miss(0),
115  HitsPR(0), MissPR(0) {}
117 private:
119 };
120 
121 /******************************************************************************/
122 /* C l a s s X r d O u c C a c h e I O */
123 /******************************************************************************/
124 
125 /* The XrdOucCacheIO object is responsible for interacting with the original
126  data source/target. It can be used with or without a front-end cache.
127 
128  Six abstract methods are provided FSize(), Path(), Read(), Sync(), Trunc(),
129  and Write(). You must provide implementations for each as described below.
130 
131  Four additional virtual methods are pre-defined: Base(), Detach(), and
132  Preread() (2x). Normally, there is no need to over-ride these methods.
133 
134  Finally, each object carries with it a XrdOucCacheStats object.
135 */
136 
138 {
139 public:
140 
141 // FSize() returns the current size of the file associated with this object.
142 
143 // Success: size of the file in bytes.
144 // Failure: -errno associated with the error.
145 virtual
146 long long FSize() = 0;
147 
148 // Path() returns the path name associated with this object.
149 //
150 virtual
151 const char *Path() = 0;
152 
153 // Read() places Length bytes in Buffer from a data source at Offset.
154 // When fronted by a cache, the cache is inspected first.
155 
156 // Success: actual number of bytes placed in Buffer.
157 // Failure: -errno associated with the error.
158 virtual
159 int Read (char *Buffer, long long Offset, int Length) = 0;
160 
161 // Sync() copies any outstanding modified bytes to the target.
162 
163 // Success: return 0.
164 // Failure: -errno associated with the error.
165 virtual
166 int Sync() = 0;
167 
168 // Trunc() truncates the file to the specified offset.
169 
170 // Success: return 0.
171 // Failure: -errno associated with the error.
172 virtual
173 int Trunc(long long Offset) = 0;
174 
175 
176 // Write() takes Length bytes in Buffer and writes to a data target at Offset.
177 // When fronted by a cache, the cache is updated as well.
178 
179 // Success: actual number of bytes copied from the Buffer.
180 // Failure: -errno associated with the error.
181 virtual
182 int Write(char *Buffer, long long Offset, int Length) = 0;
183 
184 // Base() returns the underlying XrdOucCacheIO object being used.
185 //
186 virtual XrdOucCacheIO *Base() {return this;}
187 
188 // Detach() detaches the object from the cache. It must be called instead of
189 // using the delete operator since CacheIO objects may have multiple
190 // outstanding references and actual deletion may need to be defered.
191 // Detach() returns the underlying CacheIO object when the last
192 // reference has been removed and 0 otherwise. This allows to say
193 // something like "delete ioP->Detach()" if you want to make sure you
194 // delete the underlying object as well. Alternatively, use the optADB
195 // option when attaching a CacheIO object to a cache. This will delete
196 // underlying object and always return 0 to avoid a double delete.
197 // When not fronted by a cache, Detach() always returns itself. This
198 // makes its use consistent whether or not a cache is employed.
199 //
200 virtual XrdOucCacheIO *Detach() {return this;}
201 
202 // Preread() places Length bytes into the cache from a data source at Offset.
203 // When there is no cache or the associated cache does not support or
204 // allow pre-reads, it's a no-op. Cache placement limits do not apply.
205 // To maximize parallelism, Peread() should called *after* obtaining
206 // the wanted bytes using Read(). If the cache implementation supports
207 // automatic prereads; you can setup parameters on how this should be
208 // done using the next the next structure and method. The following
209 // options can be specified:
210 //
211 static const int SingleUse = 0x0001; // Mark pages for single use
212 
213 virtual
214 void Preread (long long Offset, int Length, int Opts=0) {}
215 
216 // The following structure describes automatic preread parameters. These can be
217 // set at any time for each XrdOucCacheIO object. It can also be specified when
218 // creating a cache to establish the defaults (see XrdOucCache::Create()).
219 // Generally, an implementation that supports prereads should disable small
220 // prereads when minPages or loBound is set to zero; and should disable large
221 // prereads when maxiRead or maxPages is set to zero. Refer to the actual
222 // derived class implementation on how the cache handles prereads.
223 //
224 struct aprParms
225  {int Trigger; // preread if (rdln < Trigger) (0 -> pagesize+1)
226  int prRecalc; // Recalc pr efficiency every prRecalc bytes (0->50M)
227  int Reserve4;
228  short minPages; // If rdln/pgsz < min, preread minPages (0->off)
229  char minPerf; // Minimum auto preread performance required (0->n/a)
230  char Reserve1;
231 
233  minPages(0), minPerf(90), Reserve1(0)
234  {}
235  };
236 
237 virtual
238 void Preread(aprParms &Parms) {}
239 
240 // Here is where the stats about cache and I/O usage reside. There
241 // is a summary object in the associated cache as well.
242 //
244 
245 virtual ~XrdOucCacheIO() {} // Always use Detach() instead of direct delete!
246 };
247 
248 /******************************************************************************/
249 /* C l a s s X r d O u c C a c h e */
250 /******************************************************************************/
251 
252 /* The XrdOucCache class is used to define an instance of a cache. There can
253  be many such instances. Each instance is associated with one or more
254  XrdOucCacheIO objects. Use the Attach() method in this class to create
255  such associations.
256 */
257 
259 {
260 public:
261 
262 /* Attach() must be called to obtain a new XrdOucCacheIO object that fronts an
263  existing XrdOucCacheIO object with this cache.
264  Upon success a pointer to a new XrdOucCacheIO object is returned
265  and must be used to read and write data with the cache interposed.
266  Upon failure, the original XrdOucCacheIO object is returned with
267  errno set. You can continue using the object without any cache.
268  The following Attach() options are available and, when specified,
269  override the default options associated with the cache, except for
270  optRW, optNEW, and optWIN which are valid only for a r/w cache.
271 */
272 static const int optADB = 0x1000; // Automatically delete underlying CacheIO
273 static const int optFIS = 0x0001; // File is Structured (e.g. root file)
274 static const int optFIU = 0x0002; // File is Unstructured (e.g. unix file)
275 static const int optRW = 0x0004; // File is read/write (o/w read/only)
276 static const int optNEW = 0x0014; // File is new -> optRW (o/w read to write)
277 static const int optWIN = 0x0024; // File is new -> optRW use write-in cache
278 
279 virtual
280 XrdOucCacheIO *Attach(XrdOucCacheIO *ioP, int Options=0) = 0;
281 
282 /* isAttached()
283  Returns the number of CacheIO objects attached to this cache.
284  Hence, 0 (false) if none and true otherwise.
285 */
286 virtual
287 int isAttached() {return 0;}
288 
289 /* You must first create an instance of a cache using the Create() method.
290  The Parms structure is used to pass parameters about the cache and should
291  be filled in with values meaningful to the type of cache being created.
292  The fields below, while oriented toward a memory cache, are sufficiently
293  generic to apply to almost any kind of cache. Refer to the actual
294  implementation in the derived class to see how these values are used.
295 */
296 struct Parms
297  {long long CacheSize; // Size of cache in bytes (default 100MB)
298  int PageSize; // Size of each page in bytes (default 32KB)
299  int Max2Cache; // Largest read to cache (default PageSize)
300  int MaxFiles; // Maximum number of files (default 256 or 8K)
301  int Options; // Options as defined below (default r/o cache)
302  int Reserve1; // Reserved for future use
303  int Reserve2; // Reserved for future use
304 
305  Parms() : CacheSize(104857600), PageSize(32768),
306  Max2Cache(0), MaxFiles(0), Options(0),
307  Reserve1(0), Reserve2(0) {}
308  };
309 
310 // Valid option values in Parms::Options
311 //
312 static const int
313 isServer = 0x0010; // This is server application (as opposed to a user app).
314  // Appropriate internal optimizations will be used.
315 static const int
316 isStructured = 0x0020; // Optimize for structured files (e.g. root).
317 
318 static const int
319 canPreRead = 0x0040; // Enable pre-read operations (o/w ignored)
320 
321 static const int
322 logStats = 0x0080; // Display statistics upon detach
323 
324 static const int
325 Serialized = 0x0004; // Caller ensures MRSW semantics
326 
327 static const int
328 ioMTSafe = 0x0008; // CacheIO object is MT-safe
329 
330 static const int
331 Debug = 0x0003; // Produce some debug messages (levels 0, 1, 2, or 3)
332 
333 /* Create() Creates an instance of a cache using the specified parameters.
334  You must pass the cache parms and optionally any automatic
335  pre-read parameters that will be used as future defaults.
336  Upon success, returns a pointer to the cache. Otherwise, a null
337  pointer is returned with errno set to indicate the problem.
338 */
339 virtual
340 XrdOucCache *Create(Parms &Params, XrdOucCacheIO::aprParms *aprP=0) = 0;
341 
342 /* The following holds statistics for the cache itself. It is updated as
343  associated cacheIO objects are deleted and their statistics are added.
344 */
346 
348 virtual ~XrdOucCache() {}
349 };
350 
351 /******************************************************************************/
352 /* C r e a t i n g C a c h e P l u g - I n s */
353 /******************************************************************************/
354 
355 /* You can create a cache plug-in for those parts of the xrootd system that
356  allow a dynamically selectable cache implementation (e.g. the proxy server
357  plug-in supports cache plug-ins via the pss.cachelib directive).
358 
359  Your plug-in must exist in a shared library and have the following extern C
360  function defined:
361 
362  extern "C"
363  {
364  XrdOucCache *XrdOucGetCache(XrdSysLogger *Logger, // Where messages go
365  const char *Config, // Config file used
366  const char *Parms); // Optional parm string
367  }
368 
369  When Logger is null, you should use cerr to output messages. Otherwise,
370  tie an instance XrdSysError to the passed logger.
371  When Config is null, no configuration file is present. Otherwise, you need
372  additional configuration information you should get it
373  from that file in order to support single configuration.
374  When Parms is null, no parameter string was specified.
375 
376  The call should return an instance of an XrdOucCache object upon success and
377  a null pointer otherwise. The instance is used to create actual caches using
378  the object's Create() method.
379 */
380 #endif