XRootD
XrdRmcReal.cc
Go to the documentation of this file.
1 /******************************************************************************/
2 /* */
3 /* X r d R m c R e a l . c c */
4 /* */
5 /* (c) 2019 by the Board of Trustees of the Leland Stanford, Jr., University */
6 /* All Rights Reserved */
7 /* Produced by Andrew Hanushevsky for Stanford University under contract */
8 /* DE-AC02-76-SFO0515 with the Department of Energy */
9 /* */
10 /* This file is part of the XRootD software suite. */
11 /* */
12 /* XRootD is free software: you can redistribute it and/or modify it under */
13 /* the terms of the GNU Lesser General Public License as published by the */
14 /* Free Software Foundation, either version 3 of the License, or (at your */
15 /* option) any later version. */
16 /* */
17 /* XRootD is distributed in the hope that it will be useful, but WITHOUT */
18 /* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or */
19 /* FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public */
20 /* License for more details. */
21 /* */
22 /* You should have received a copy of the GNU Lesser General Public License */
23 /* along with XRootD in a file called COPYING.LESSER (LGPL license) and file */
24 /* COPYING (GPL license). If not, see <http://www.gnu.org/licenses/>. */
25 /* */
26 /* The copyright holder's institutional names and contributor's names may not */
27 /* be used to endorse or promote products derived from this software without */
28 /* specific prior written permission of the institution or contributor. */
29 /******************************************************************************/
30 
31 #include <cerrno>
32 #include <cstdio>
33 #include <cstdlib>
34 #include <cstring>
35 #include <unistd.h>
36 #include <sys/mman.h>
37 #include <sys/types.h>
38 
39 #include "XrdRmc/XrdRmcData.hh"
40 #include "XrdSys/XrdSysHeaders.hh"
41 
42 #ifdef __APPLE__
43 #ifndef MAP_ANONYMOUS
44 #define MAP_ANONYMOUS MAP_ANON
45 #endif
46 #endif
47 
48 /******************************************************************************/
49 /* C o n s t r u c t o r */
50 /******************************************************************************/
51 
52 void *XrdRmcRealPRXeq(void *parg)
53 { XrdRmcReal *cP = (XrdRmcReal *)parg;
54  cP->PreRead();
55  return (void *)0;
56 }
57 
60  : XrdOucCache("rmc"),
61  Slots(0), Slash(0), Base((char *)MAP_FAILED), Dbg(0), Lgs(0),
62  AZero(0), Attached(0), prFirst(0), prLast(0),
63  prReady(0), prStop(0), prNum(0)
64 {
65  size_t Bytes;
66  int n, minPag, isServ = ParmV.Options & XrdRmc::isServer;
67 
68 // Copy over options
69 //
70  rc = ENOMEM;
71  Options = ParmV.Options;
72  if (Options & XrdRmc::Debug) Lgs = Dbg = (Options & XrdRmc::Debug);
73  if (Options & XrdRmc::logStats) Lgs = 1;
74  minPag = (ParmV.minPages <= 0 ? 256 : ParmV.minPages);
75 
76 // Establish maximum number of attached files
77 //
78  if (ParmV.MaxFiles <= 0) maxFiles = (isServ ? 16384 : 256);
79  else {maxFiles = (ParmV.MaxFiles > 32764 ? 32764 : ParmV.MaxFiles);
80  maxFiles = maxFiles/sizeof(int)*sizeof(int);
81  if (!maxFiles) maxFiles = 256;
82  }
83 
84 // Adjust segment size to be a power of two and atleast 4k.
85 //
86  if (ParmV.PageSize <= 0) SegSize = 32768;
87  else if (!(SegSize = ParmV.PageSize & ~0xfff)) SegSize = 4096;
88 // else if (SegSize > 16*1024*1024) SegSize = 16*1024*1024;
89  SegShft = 0; n = SegSize-1;
90  while(n) {SegShft++; n = n >> 1;}
91  SegSize = 1<<SegShft;
92 
93 // The max to cache is also adjusted accrodingly based on segment size.
94 //
95  OffMask = SegSize-1;
96  SegCnt = (ParmV.CacheSize > 0 ? ParmV.CacheSize : 104857600)/SegSize;
97  if (SegCnt < minPag) SegCnt = minPag;
98  if (ParmV.Max2Cache < SegSize) maxCache = SegSize;
99  else maxCache = ParmV.Max2Cache/SegSize*SegSize;
100  SegFull = (Options & XrdRmc::isServer ? XrdRmcSlot::lenMask : SegSize);
101 
102 // Allocate the cache plus the cache hash table
103 //
104  Bytes = static_cast<size_t>(SegSize)*SegCnt;
105  Base = (char *)mmap(0, Bytes + SegCnt*sizeof(int), PROT_READ|PROT_WRITE,
106  MAP_PRIVATE|MAP_ANONYMOUS, -1, 0);
107  if (Base == MAP_FAILED) {rc = errno; return;}
108  Slash = (int *)(Base + Bytes); HNum = SegCnt/2*2-1;
109 
110 // Now allocate the actual slots. We add additional slots to map files. These
111 // do not have any memory backing but serve as anchors for memory mappings.
112 //
113  if (!(Slots = new XrdRmcSlot[SegCnt+maxFiles])) return;
114  XrdRmcSlot::Init(Slots, SegCnt);
115 
116 // Set pointers to be able to keep track of CacheIO objects and map them to
117 // CacheData objects. The hash table will be the first page of slot memory.
118 //
119  hTab = (int *)Base;
120  hMax = SegSize/sizeof(int);
121  sBeg = sFree = SegCnt;
122  sEnd = SegCnt + maxFiles;
123 
124 // Now iniialize the slots to be used for the CacheIO objects
125 //
126  for (n = sBeg; n < sEnd; n++)
127  {Slots[n].Own.Next = Slots[n].Own.Prev = n;
128  Slots[n].HLink = n+1;
129  }
130  Slots[sEnd-1].HLink = 0;
131 
132 // Setup the pre-readers if pre-read is enabled
133 //
134  if (Options & XrdRmc::canPreRead)
135  {pthread_t tid;
136  n = (Options & XrdRmc::isServer ? 9 : 3);
137  while(n--)
138  {if (XrdSysThread::Run(&tid, XrdRmcRealPRXeq, (void *)this,
139  0, "Prereader")) break;
140  prNum++;
141  }
142  if (aprP && prNum) XrdRmcData::setAPR(aprDefault, *aprP, SegSize);
143  }
144 
145 // All done
146 //
147  rc = 0;
148 }
149 
150 /******************************************************************************/
151 /* D e s t r u c t o r */
152 /******************************************************************************/
153 
155 {
156 // Wait for all attachers to go away
157 //
158  CMutex.Lock();
159  if (Attached)
160  {XrdSysSemaphore aZero(0);
161  AZero = &aZero;
162  CMutex.UnLock();
163  aZero.Wait();
164  CMutex.Lock();
165  }
166 
167 // If any preread threads exist, then stop them now
168 //
169  prMutex.Lock();
170  if (prNum)
171  {XrdSysSemaphore prDone(0);
172  prStop = &prDone;
173  prReady.Post();
174  prMutex.UnLock();
175  prDone.Wait();
176  prMutex.Lock();
177  }
178 
179 // Delete the slots
180 //
181  delete Slots; Slots = 0;
182 
183 // Unmap cache memory and associated hash table
184 //
185  if (Base != MAP_FAILED)
186  {munmap(Base, static_cast<size_t>(SegSize)*SegCnt);
187  Base = (char *)(MAP_FAILED);
188  }
189 
190 // Release all locks, we are done
191 //
192  prMutex.UnLock();
193  CMutex.UnLock();
194 }
195 
196 /******************************************************************************/
197 /* A t t a c h */
198 /******************************************************************************/
199 
201 {
202  static int Inst = 0;
203  XrdSysMutexHelper Monitor(CMutex);
204  XrdRmcData *dP;
205  int Cnt, Fnum = 0, theOpts = Opts & optRW;
206 
207 // Check if we are being deleted
208 //
209  if (AZero) {errno = ECANCELED; return ioP;}
210 
211 // Setup structured/unstructured option
212 //
213  if ((Opts & optFIS) || (Options & XrdRmc::isStructured)) theOpts |= optFIS;
214 
215 // Get an entry in the filename table.
216 //
217  if (!(Cnt = ioAdd(ioP, Fnum)))
218  {errno = EMFILE;
219  return ioP;
220  }
221 
222 // If this is the first addition then we need to get a new CacheData object.
223 // Otherwise, simply reuse the previous cache data object.
224 //
225  if (Cnt != 1) dP = Slots[Fnum].Status.Data;
226  else {long long vNum = static_cast<long long>(Fnum-SegCnt) << Shift
227  | (static_cast<long long>(Inst) << (Shift - 16));
228  Inst = (Inst+1) & 0xffff;
229  if ((dP = new XrdRmcData(this, ioP, vNum, theOpts)))
230  {Attached++; Slots[Fnum].Status.Data = dP;}
231  }
232 
233 // Some debugging
234 //
235  if (Dbg) std::cerr <<"Cache: Attached " <<Cnt <<'/' <<Attached <<' '
236  <<std::hex << Fnum <<std::dec <<' ' <<ioP->Path() <<std::endl;
237 
238 // All done
239 //
240  if (!dP) {errno = ENOMEM; return ioP;}
241  return (XrdOucCacheIO *)dP;
242 }
243 
244 /******************************************************************************/
245 /* D e t a c h */
246 /******************************************************************************/
247 
248 int XrdRmcReal::Detach(XrdOucCacheIO *ioP)
249 {
250  XrdSysMutexHelper Monitor(CMutex);
251  XrdRmcSlot *sP, *oP;
252  int sNum, Fnum, Free = 0, Faults = 0;
253 
254 // Now we delete this CacheIO from the cache set and see if its still ref'd.
255 //
256  sNum = ioDel(ioP, Fnum);
257  if (!sNum || sNum > 1) return 0;
258 
259 // We will be deleting the CramData object. So, we need to recycle its slots.
260 //
261  oP = &Slots[Fnum];
262  while(oP->Own.Next != Fnum)
263  {sP = &Slots[oP->Own.Next];
264  sP->Owner(Slots);
265  if (sP->Contents < 0 || sP->Status.LRU.Next < 0) Faults++;
266  else {sP->Hide(Slots, Slash, sP->Contents%HNum);
267  sP->Pull(Slots);
268  sP->unRef(Slots);
269  Free++;
270  }
271  }
272 
273 // Reduce attach count and check if the cache is being deleted
274 //
275  Attached--;
276  if (AZero && Attached <= 0) AZero->Post();
277 
278 // Issue debugging message
279 //
280  if (Dbg) std::cerr <<"Cache: " <<Attached <<" att; rel " <<Free <<" slots; "
281  <<Faults <<" Faults; " <<std::hex << Fnum <<std::dec <<' '
282  <<ioP->Path() <<std::endl;
283 
284 // All done, tell the caller to delete itself
285 //
286  return 1;
287 }
288 
289 /******************************************************************************/
290 /* e M s g */
291 /******************************************************************************/
292 
293 void XrdRmcReal::eMsg(const char *Path, const char *What, long long xOff,
294  int xAmt, int eCode)
295 {
296  char Buff[128];
297 
298  if (Dbg)
299  {sprintf(Buff, "Cache: Error %d %s %d bytes at %lld; path=",
300  eCode, What, xAmt, xOff);
301  std::cerr <<Buff <<Path <<std::endl;
302  }
303 }
304 
305 /******************************************************************************/
306 /* G e t */
307 /******************************************************************************/
308 
309 char *XrdRmcReal::Get(XrdOucCacheIO *ioP, long long lAddr, int &rAmt, int &noIO)
310 {
311  XrdSysMutexHelper Monitor(CMutex);
312  XrdRmcSlot::ioQ *Waiter;
313  XrdRmcSlot *sP;
314  int nUse, Fnum, Slot, segHash = lAddr%HNum;
315  char *cBuff;
316 
317 // See if we have this logical address in the cache. Check if the page is in
318 // transit and, if so, wait for it to arrive before proceeding.
319 //
320  noIO = 1;
321  if (Slash[segHash]
322  && (Slot = XrdRmcSlot::Find(Slots, lAddr, Slash[segHash])))
323  {sP = &Slots[Slot];
324  if (sP->Count & XrdRmcSlot::inTrans)
325  {XrdSysSemaphore ioSem(0);
326  XrdRmcSlot::ioQ ioTrans(sP->Status.waitQ, &ioSem);
327  sP->Status.waitQ = &ioTrans;
328  if (Dbg > 1) std::cerr <<"Cache: Wait slot " <<Slot <<std::endl;
329  CMutex.UnLock(); ioSem.Wait(); CMutex.Lock();
330  if (sP->Contents != lAddr) {rAmt = -EIO; return 0;}
331  } else {
332  if (sP->Status.inUse < 0) sP->Status.inUse--;
333  else {sP->Pull(Slots); sP->Status.inUse = -1;}
334  }
335  rAmt = (sP->Count < 0 ? sP->Count & XrdRmcSlot::lenMask : SegSize);
336  if (sP->Count & XrdRmcSlot::isNew)
337  {noIO = -1; sP->Count &= ~XrdRmcSlot::isNew;}
338  if (Dbg > 2) std::cerr <<"Cache: Hit slot " <<Slot <<" sz " <<rAmt <<" nio "
339  <<noIO <<" uc " <<sP->Status.inUse <<std::endl;
340  return Base+(static_cast<long long>(Slot)*SegSize);
341  }
342 
343 // Page is not here. If no allocation wanted or we cannot obtain a free slot
344 // return and indicate there is no associated cache page.
345 //
346  if (!ioP || !(Slot = Slots[Slots->Status.LRU.Next].Pull(Slots)))
347  {rAmt = -ENOMEM; return 0;}
348 
349 // Remove ownership over this slot and remove it from the hash table
350 //
351  sP = &Slots[Slot];
352  if (sP->Contents >= 0)
353  {if (sP->Own.Next != Slot) sP->Owner(Slots);
354  sP->Hide(Slots, Slash, sP->Contents%HNum);
355  }
356 
357 // Read the data into the buffer
358 //
359  sP->Count |= XrdRmcSlot::inTrans;
360  sP->Status.waitQ = 0;
361  CMutex.UnLock();
362  cBuff = Base+(static_cast<long long>(Slot)*SegSize);
363  rAmt = ioP->Read(cBuff, (lAddr & Strip) << SegShft, SegSize);
364  CMutex.Lock();
365 
366 // Post anybody waiting for this slot. We hold the cache lock which will give us
367 // time to complete the slot definition before the waiting thread looks at it.
368 //
369  nUse = -1;
370  while((Waiter = sP->Status.waitQ))
371  {sP->Status.waitQ = sP->Status.waitQ->Next;
372  sP->Status.waitQ->ioEnd->Post();
373  nUse--;
374  }
375 
376 // If I/O succeeded, reinitialize the slot. Otherwise, return free it up
377 //
378  noIO = 0;
379  if (rAmt >= 0)
380  {sP->Contents = lAddr;
381  sP->HLink = Slash[segHash];
382  Slash[segHash] = Slot;
383  Fnum = (lAddr >> Shift) + SegCnt;
384  Slots[Fnum].Owner(Slots, sP);
385  sP->Count = (rAmt == SegSize ? SegFull : rAmt|XrdRmcSlot::isShort);
386  sP->Status.inUse = nUse;
387  if (Dbg > 2) std::cerr <<"Cache: Miss slot " <<Slot <<" sz "
388  <<(sP->Count & XrdRmcSlot::lenMask) <<std::endl;
389  } else {
390  eMsg(ioP->Path(), "reading", (lAddr & Strip) << SegShft, SegSize, rAmt);
391  cBuff = 0;
392  sP->Contents = -1;
393  sP->unRef(Slots);
394  }
395 
396 // Return the associated buffer or zero, as per above
397 //
398  return cBuff;
399 }
400 
401 /******************************************************************************/
402 /* i o A d d */
403 /******************************************************************************/
404 
405 int XrdRmcReal::ioAdd(XrdOucCacheIO *KeyVal, int &iNum)
406 {
407  int hip, phip, hent = ioEnt(KeyVal);
408 
409 // Look up the entry. If found, return it.
410 //
411  if ((hip = hTab[hent]) && (hip = ioLookup(phip, hip, KeyVal)))
412  {iNum = hip; return ++Slots[hip].Count;}
413 
414 // Add the entry
415 //
416  if ((hip = sFree))
417  {sFree = Slots[sFree].HLink;
418  Slots[hip].File(KeyVal, hTab[hent]);
419  hTab[hent] = hip;
420  }
421 
422 // Return information to the caller
423 //
424  iNum = hip;
425  return (hip ? 1 : 0);
426 }
427 
428 /******************************************************************************/
429 /* i o D e l */
430 /******************************************************************************/
431 
432 int XrdRmcReal::ioDel(XrdOucCacheIO *KeyVal, int &iNum)
433 {
434  int cnt, hip, phip, hent = ioEnt(KeyVal);
435 
436 // Look up the entry.
437 //
438  if (!(hip = hTab[hent]) || !(hip = ioLookup(phip, hip, KeyVal))) return 0;
439  iNum = hip;
440 
441 // Delete the item, if need be, and return
442 //
443  cnt = --(Slots[hip].Count);
444  if (cnt <= 0)
445  {if (phip) Slots[phip].HLink = Slots[hip].HLink;
446  else hTab[hent] = Slots[hip].HLink;
447  Slots[hip].HLink = sFree; sFree = hip;
448  }
449  return (cnt < 0 ? 1 : cnt+1);
450 }
451 
452 /******************************************************************************/
453 /* P r e R e a d */
454 /******************************************************************************/
455 
457 {
458  prTask *prP;
459 
460 // Simply wait and dispatch elements
461 //
462  if (Dbg) std::cerr <<"Cache: preread thread started; now " <<prNum <<std::endl;
463  while(1)
464  {prReady.Wait();
465  prMutex.Lock();
466  if (prStop) break;
467  if ((prP = prFirst))
468  {if (!(prFirst = prP->Next)) prLast = 0;
469  prMutex.UnLock();
470  prP->Data->Preread();
471  } else prMutex.UnLock();
472  }
473 
474 // The cache is being deleted, wind down the prereads
475 //
476  prNum--;
477  if (prNum > 0) prReady.Post();
478  else prStop->Post();
479  if (Dbg) std::cerr <<"Cache: preread thread exited; left " <<prNum <<std::endl;
480  prMutex.UnLock();
481 }
482 
483 /******************************************************************************/
484 
485 void XrdRmcReal::PreRead(XrdRmcReal::prTask *prReq)
486 {
487 
488 // Place this element on the queue
489 //
490  prMutex.Lock();
491  if (prLast) {prLast->Next = prReq; prLast = prReq;}
492  else prLast = prFirst = prReq;
493  prReq->Next = 0;
494 
495 // Tell a pre-reader that something is ready
496 //
497  prReady.Post();
498  prMutex.UnLock();
499 }
500 
501 /******************************************************************************/
502 /* R e f */
503 /******************************************************************************/
504 
505 int XrdRmcReal::Ref(char *Addr, int rAmt, int sFlags)
506 {
507  XrdRmcSlot *sP = &Slots[(Addr-Base)>>SegShft];
508  int eof = 0;
509 
510 // Indicate how much data was not yet referenced
511 //
512  CMutex.Lock();
513  if (sP->Contents >= 0)
514  {if (sP->Count < 0) eof = 1;
515  sP->Status.inUse++;
516  if (sP->Status.inUse < 0)
517  {if (sFlags) sP->Count |= sFlags;
518  else if (!eof && (sP->Count -= rAmt) < 0) sP->Count = 0;
519  } else {
520  if (sFlags) {sP->Count |= sFlags; sP->reRef(Slots);}
521  else { if (sP->Count & XrdRmcSlot::isSUSE)
522  sP->unRef(Slots);
523  else if (eof || (sP->Count -= rAmt) > 0) sP->reRef(Slots);
524  else {sP->Count = SegSize/2; sP->unRef(Slots);}
525  }
526  }
527  } else eof = 1;
528 
529 // All done
530 //
531  if (Dbg > 2) std::cerr <<"Cache: Ref " <<std::hex <<sP->Contents <<std::dec
532  << " slot " <<((Addr-Base)>>SegShft)
533  <<" sz " <<(sP->Count & XrdRmcSlot::lenMask)
534  <<" uc " <<sP->Status.inUse <<std::endl;
535  CMutex.UnLock();
536  return !eof;
537 }
538 
539 /******************************************************************************/
540 /* T r u n c */
541 /******************************************************************************/
542 
543 void XrdRmcReal::Trunc(XrdOucCacheIO *ioP, long long lAddr)
544 {
545  XrdSysMutexHelper Monitor(CMutex);
546  XrdRmcSlot *sP, *oP;
547  int sNum, Free = 0, Left = 0, Fnum = (lAddr >> Shift) + SegCnt;
548 
549 // We will be truncating CacheData pages. So, we need to recycle those slots.
550 //
551  oP = &Slots[Fnum]; sP = &Slots[oP->Own.Next];
552  while(oP != sP)
553  {sNum = sP->Own.Next;
554  if (sP->Contents < lAddr) Left++;
555  else {sP->Owner(Slots);
556  sP->Hide(Slots, Slash, sP->Contents%HNum);
557  sP->Pull(Slots);
558  sP->unRef(Slots);
559  Free++;
560  }
561  sP = &Slots[sNum];
562  }
563 
564 // Issue debugging message
565 //
566  if (Dbg) std::cerr <<"Cache: Trunc " <<Free <<" slots; "
567  <<Left <<" Left; " <<std::hex << Fnum <<std::dec <<' '
568  <<ioP->Path() <<std::endl;
569 }
570 
571 /******************************************************************************/
572 /* U p d */
573 /******************************************************************************/
574 
575 void XrdRmcReal::Upd(char *Addr, int wLen, int wOff)
576 {
577  XrdRmcSlot *sP = &Slots[(Addr-Base)>>SegShft];
578 
579 // Check if we extended a short page
580 //
581  CMutex.Lock();
582  if (sP->Count < 0)
583  {int theLen = sP->Count & XrdRmcSlot::lenMask;
584  if (wLen + wOff > theLen)
585  sP->Count = (wLen+wOff) | XrdRmcSlot::isShort;
586  }
587 
588 // Adjust the reference counter and if no references, place on the LRU chain
589 //
590  sP->Status.inUse++;
591  if (sP->Status.inUse >= 0) sP->reRef(Slots);
592 
593 // All done
594 //
595  if (Dbg > 2) std::cerr <<"Cache: Upd " <<std::hex <<sP->Contents <<std::dec
596  << " slot " <<((Addr-Base)>>SegShft)
597  <<" sz " <<(sP->Count & XrdRmcSlot::lenMask)
598  <<" uc " <<sP->Status.inUse <<std::endl;
599  CMutex.UnLock();
600 }
void * XrdRmcRealPRXeq(void *parg)
Definition: XrdRmcReal.cc:52
int Dbg
XrdOucString Path
virtual const char * Path()=0
virtual int Read(char *buff, long long offs, int rlen)=0
static const int optRW
File is read/write (o/w read/only)
Definition: XrdOucCache.hh:517
static const int optFIS
File is structured (e.g. root file)
Definition: XrdOucCache.hh:516
static int setAPR(aprParms &Dest, aprParms &Src, int pSize)
Definition: XrdRmcData.cc:489
XrdOucCacheIO * Attach(XrdOucCacheIO *ioP, int Options=0)
Definition: XrdRmcReal.cc:200
XrdRmcReal(int &rc, XrdRmc::Parms &Parms, XrdOucCacheIO::aprParms *aprP=0)
Definition: XrdRmcReal.cc:58
friend class XrdRmcData
Definition: XrdRmcReal.hh:41
void PreRead()
Definition: XrdRmcReal.cc:456
void File(XrdOucCacheIO *kV, int you)
Definition: XrdRmcSlot.hh:45
void Owner(XrdRmcSlot *Base)
Definition: XrdRmcSlot.hh:90
void unRef(XrdRmcSlot *Base)
Definition: XrdRmcSlot.hh:109
static const int isShort
Definition: XrdRmcSlot.hh:145
struct SlotList LRU
Definition: XrdRmcSlot.hh:132
static const int lenMask
Definition: XrdRmcSlot.hh:144
SlotList Own
Definition: XrdRmcSlot.hh:140
SlotState Status
Definition: XrdRmcSlot.hh:139
static void Init(XrdRmcSlot *Base, int Num)
Definition: XrdRmcSlot.hh:63
int Pull(XrdRmcSlot *Base)
Definition: XrdRmcSlot.hh:74
static const int inTrans
Definition: XrdRmcSlot.hh:146
void reRef(XrdRmcSlot *Base)
Definition: XrdRmcSlot.hh:102
static int Find(XrdRmcSlot *Base, long long What, int n)
Definition: XrdRmcSlot.hh:48
static const int isNew
Definition: XrdRmcSlot.hh:148
struct ioQ * waitQ
Definition: XrdRmcSlot.hh:130
void Hide(XrdRmcSlot *Base, int *hTab, int hI)
Definition: XrdRmcSlot.hh:53
static const int isSUSE
Definition: XrdRmcSlot.hh:147
static const int Debug
Produce some debug messages (levels 0, 1, 2, or 3)
Definition: XrdRmc.hh:136
static const int logStats
Display statistics upon detach.
Definition: XrdRmc.hh:127
static const int isServer
This is server application; not a user application.
Definition: XrdRmc.hh:118
static const int isStructured
Definition: XrdRmc.hh:121
static const int canPreRead
Enable pre-read operations (o/w ignored)
Definition: XrdRmc.hh:124
static int Run(pthread_t *, void *(*proc)(void *), void *arg, int opts=0, const char *desc=0)
int Opts
Definition: XrdMpxStats.cc:58
@ dec
Definition: XrdSysTrace.hh:42
@ hex
Definition: XrdSysTrace.hh:42
XrdSysSemaphore * ioEnd
Definition: XrdRmcSlot.hh:124
Parameters for a newly created memory cache.
Definition: XrdRmc.hh:101
int MaxFiles
Maximum number of files (default 256 or 8K)
Definition: XrdRmc.hh:104
int PageSize
Size of each page in bytes (default 32KB)
Definition: XrdRmc.hh:102
long long CacheSize
Size of cache in bytes (default 100MB)
Definition: XrdRmc.hh:101
int Max2Cache
Largest read to cache (default PageSize)
Definition: XrdRmc.hh:103
short minPages
Minimum number of pages (default 256)
Definition: XrdRmc.hh:106
int Options
Options as defined below (default r/o cache)
Definition: XrdRmc.hh:105