XRootD
Loading...
Searching...
No Matches
XrdSutPFCache.cc
Go to the documentation of this file.
1/******************************************************************************/
2/* */
3/* X r d S u t C a c h e . c c */
4/* */
5/* (c) 2004 by the Board of Trustees of the Leland Stanford, Jr., University */
6/* Produced by Gerri Ganis for CERN */
7/* */
8/* This file is part of the XRootD software suite. */
9/* */
10/* XRootD is free software: you can redistribute it and/or modify it under */
11/* the terms of the GNU Lesser General Public License as published by the */
12/* Free Software Foundation, either version 3 of the License, or (at your */
13/* option) any later version. */
14/* */
15/* XRootD is distributed in the hope that it will be useful, but WITHOUT */
16/* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or */
17/* FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public */
18/* License for more details. */
19/* */
20/* You should have received a copy of the GNU Lesser General Public License */
21/* along with XRootD in a file called COPYING.LESSER (LGPL license) and file */
22/* COPYING (GPL license). If not, see <http://www.gnu.org/licenses/>. */
23/* */
24/* The copyright holder's institutional names and contributor's names may not */
25/* be used to endorse or promote products derived from this software without */
26/* specific prior written permission of the institution or contributor. */
27/******************************************************************************/
28
29#include <cstdio>
30#include <cstdlib>
31#include <sys/types.h>
32#include <sys/stat.h>
33#include <unistd.h>
34#include <ctime>
35
37#include "XrdSut/XrdSutPFile.hh"
38#include "XrdSut/XrdSutTrace.hh"
39#include "XrdSut/XrdSutAux.hh"
40#include "XrdSys/XrdSysTimer.hh"
41
42/******************************************************************************/
43/* */
44/* For caching temporary information during the authentication handshake */
45/* */
46/******************************************************************************/
47
48//__________________________________________________________________
50{
51 // Destructor
52
53 // We are destroying the cache
54 rwlock.WriteLock();
55
56 // Cleanup content
57 while (cachemx > -1) {
58 if (cachent[cachemx]) {
59 delete cachent[cachemx];
60 cachent[cachemx] = 0;
61 }
62 cachemx--;
63 }
64 // Cleanup table
65 if (cachent)
66 delete[] cachent;
67
68 // Done
69 rwlock.UnLock();
70}
71
72//__________________________________________________________________
73int XrdSutPFCache::Init(int capacity, bool lock)
74{
75 // Initialize the cache to hold up to capacity entries.
76 // Later on, capacity is double each time more space is needed.
77 // Return 0 if ok, -1 otherwise
78 EPNAME("Cache::Init");
79
80 // Lock for writing
81 if (lock) rwlock.WriteLock();
82
83 // Nothing to do if already done
84 if (isinit) {
85 if (lock) rwlock.UnLock();
86 return 0;
87 }
88
89 // Make sure capacity makes sense; use a default, if not
90 capacity = (capacity > 0) ? capacity : 100;
91
92 // Allocate
93 cachent = new XrdSutPFEntry *[capacity];
94 if (cachent) {
95 for (int i = 0; i < capacity; i++) { cachent[i] = 0; }
96 cachesz = capacity;
97 DEBUG("cache allocated for "<<cachesz<<" entries");
98
99 // Update time stamp
100 utime = (kXR_int32)time(0);
101
102 // Init hash table
103 if (Rehash(0, 0) != 0) {
104 DEBUG("problems initialising hash table");
105 }
106 // UnLock
107 if (lock) rwlock.UnLock();
108 return 0;
109
110 } else
111 DEBUG("could not allocate cache - out-of-resources ");
112
113 // Flag has initialized
114 isinit = 1;
115
116 // UnLock
117 if (lock) rwlock.UnLock();
118 return -1;
119}
120
121//__________________________________________________________________
122XrdSutPFEntry *XrdSutPFCache::Get(XrdSutPFCacheRef &urRef, const char *ID, bool *wild)
123{
124 // Retrieve an entry with ID, if any
125 // If wild is defined, search also best matching regular expression
126 // with wildcard '*'; *wild = 0 will indicate exact match,
127 // *wild = 1 wild card compatibility match
128 EPNAME("Cache::Get");
129 XrdSutPFEntry *pfEnt;
130 int i;
131
132 TRACE(Dump,"locating entry for ID: "<<ID);
133
134 //
135 // If ID is undefined, do nothing
136 if (!ID || !strlen(ID)) {
137 DEBUG("empty ID !");
138 return (XrdSutPFEntry *)0 ;
139 }
140 if (wild) *wild = 0;
141
142 if (Rehash() != 0) {
143 DEBUG("problems rehashing");
144 return (XrdSutPFEntry *)0 ;
145 }
146
147 // Lock for reading
148 XrdSysRWLockHelper isg(rwlock, 1);
149
150 // Find the entry and lock it. Repeat if we can get a lock.
151 //
152 for (i = 0; i < maxTries; i++)
153 {if ((pfEnt = Get(ID, wild)))
154 {if (pfEnt->pfeMutex.CondLock())
155 {urRef.Set(&(pfEnt->pfeMutex));
156 return pfEnt;
157 }
158 } else return pfEnt;
159 isg.UnLock();
160 XrdSysTimer::Wait(retryMSW);
161 if (Rehash() != 0)
162 {DEBUG("problems rehashing");
163 return (XrdSutPFEntry *)0 ;
164 }
165 isg.Lock(&rwlock, 1);
166 }
167
168 // Nothing found
169 return (XrdSutPFEntry *)0 ;
170}
171
172//__________________________________________________________________
173XrdSutPFEntry *XrdSutPFCache::Get(const char *ID, bool *wild)
174{
175
176 // Look in the hash first
177 kXR_int32 *ie = hashtable.Find(ID);
178 if (ie && *ie >= 0 && *ie < cachesz) {
179 // Return the associated entry
180 return cachent[*ie];
181 }
182
183 // If wild cards allowed search sequentially
184 if (wild) {
185 XrdOucString sid(ID);
186 int i = 0, match = 0, nmmax = 0, iref = -1;
187 for (; i <= cachemx; i++) {
188 if (cachent[i]) {
189 match = sid.matches(cachent[i]->name);
190 if (match > nmmax) {
191 nmmax = match;
192 iref = i;
193 }
194 }
195 }
196 if (iref > -1) {
197 *wild = 1;
198 return cachent[iref];
199 }
200 }
201
202 // Nothing found
203 return (XrdSutPFEntry *)0 ;
204}
205
206//__________________________________________________________________
207XrdSutPFEntry *XrdSutPFCache::Add(XrdSutPFCacheRef &urRef, const char *ID, bool force)
208{
209 // Add an entry with ID in cache
210 // Cache buffer is re-allocated with double size, if needed
211 // Hash is updated
212 EPNAME("Cache::Add");
213
214 //
215 // IF ID is undefined, do nothing
216 if (!ID || !strlen(ID)) {
217 DEBUG("empty ID !");
218 return (XrdSutPFEntry *)0 ;
219 }
220
221 //
222 // If an entry already exists, return it
223 XrdSutPFEntry *ent = Get(urRef, ID);
224 if (ent)
225 return ent;
226
227 // Lock for writing
228 XrdSysRWLockHelper isg(rwlock, 0);
229
230 //
231 // Make sure there enough space for a new entry
232 if (cachemx == cachesz - 1) {
233 //
234 // Duplicate buffer
235 XrdSutPFEntry **newcache = new XrdSutPFEntry *[2*cachesz];
236 if (!newcache) {
237 DEBUG("could not extend cache to size: "<<(2*cachesz));
238 return (XrdSutPFEntry *)0 ;
239 }
240 // Update info
241 cachesz *= 2;
242 //
243 // Copy existing valid entries, calculating real size
244 int i = 0, nmx = 0;
245 for (; i <= cachemx; i++) {
246 if (cachent[i]) {
247 newcache[nmx] = cachent[i];
248 nmx++;
249 }
250 }
251 // update size
252 cachemx = nmx - 1;
253 //
254 // Reset new entries
255 for (i = cachemx + 1; i <= cachemx; i++) {
256 newcache[i] = 0;
257 }
258 //
259 // Cleanup and reassign
260 delete[] cachent;
261 cachent = newcache;
262 //
263 // Force rehash in this case
264 force = 1;
265 }
266 //
267 // The next free
268 int pos = cachemx + 1;
269
270 //
271 // Add new entry
272 cachent[pos] = new XrdSutPFEntry(ID);
273 if (cachent[pos]) {
274 cachemx = pos;
275 } else {
276 DEBUG("could not allocate space for new cache entry");
277 return (XrdSutPFEntry *)0 ;
278 }
279 // Update time stamp
280 utime = (kXR_int32)time(0);
281
282 // Rebuild hash table
283 if (Rehash(force, 0) != 0) {
284 DEBUG("problems re-hashing");
285 return (XrdSutPFEntry *)0 ;
286 }
287
288 // We are done (we can lock the entry without a wait)
289 urRef.Lock(&(cachent[pos]->pfeMutex));
290 return cachent[pos];
291}
292
293//__________________________________________________________________
294bool XrdSutPFCache::Remove(const char *ID, int opt)
295{
296 // If opt==1 remove entry with name matching exactly ID from cache
297 // If opt==0 all entries with names starting with ID are removed
298 // Return 1 if ok, 0 otherwise
299 EPNAME("Cache::Remove");
300
301 //
302 // IF ID is undefined, do nothing
303 if (!ID || !strlen(ID)) {
304 DEBUG("empty ID !");
305 return 0 ;
306 }
307
308 // Lock for writing
309 XrdSysRWLockHelper isg(rwlock, 0);
310
311 if (Rehash(0, 0) != 0) {
312 DEBUG("problems rehashing");
313 return 0 ;
314 }
315
316 bool found = 0;
317 if (opt == 1) {
318 int pos = -1;
319 // Look in the hash first
320 kXR_int32 *ie = hashtable.Find(ID);
321 if (*ie >= 0 && *ie < cachesz) {
322 // Return the associated entry
323 pos = *ie;
324 }
325
326 //
327 // Check if pos makes sense
328 if (cachent[pos] && !strcmp(cachent[pos]->name,ID)) {
329 if (!Delete(cachent[pos])) DEBUG("Delete deferred for " <<ID);
330 cachent[pos] = 0;
331 // We are done, if not the one at highest index
332 if (pos < cachemx)
333 return 1;
334 // We update the highest index
335 found = 1;
336 }
337 } else {
338 // Loop over entries
339 int i = cachemx;
340 for (; i >= 0; i--) {
341 if (cachent[i]) {
342 if (!strncmp(cachent[i]->name,ID,strlen(ID))) {
343 if (!Delete(cachent[i])) DEBUG("Delete deferred for " <<ID);
344 cachent[i] = 0;
345 found = 1;
346 }
347 }
348 }
349 }
350
351 if (found) {
352 // Update time stamp
353 utime = (kXR_int32)time(0);
354
355 // Rebuild hash table
356 if (Rehash(0, 0) != 0) {
357 DEBUG("problems re-hashing");
358 return 0 ;
359 }
360 }
361
362 // We are done
363 return found;
364}
365
366//__________________________________________________________________
367bool XrdSutPFCache::Delete(XrdSutPFEntry *pfEnt)
368{
369 struct pfQ {pfQ *next;
370 XrdSutPFEntry *pfEnt;
371 pfQ(pfQ *cP, XrdSutPFEntry *tP)
372 : next(cP), pfEnt(tP) {}
373 ~pfQ() {delete pfEnt;}
374 };
375 EPNAME("Cache::Delete");
376 static pfQ pfDefer(0,0);
377
378// Try to remove all deferred entries first
379//
380 if (pfDefer.next)
381 {pfQ *pQ = &pfDefer, *dQ;
382 int nTot = 0, dTot = 0;
383 while((dQ = pQ->next))
384 {nTot++;
385 if (dQ->pfEnt->pfeMutex.CondLock())
386 {pQ->next = dQ->next;
387 dQ->pfEnt->pfeMutex.UnLock();
388 delete dQ;
389 dTot++;
390 } else pQ = dQ;
391 }
392 if (nTot) DEBUG("Deferred delete " <<dTot <<" of " <<nTot);
393 }
394
395// Now try to delete this entry
396//
397 if (pfEnt->pfeMutex.CondLock())
398 {pfEnt->pfeMutex.UnLock();
399 delete pfEnt;
400 return true;
401 }
402
403// Defer the delete as someone still has a reference to the entry
404//
405 pfDefer.next = new pfQ(pfDefer.next, pfEnt);
406 return false;
407}
408
409//__________________________________________________________________
411{
412 // Remove entries older then lifet seconds. If lifet <=0, compare
413 // to lifetime, which can be set with SetValidity().
414 // Return number of entries removed
415
416 // Lock for writing
417 EPNAME("Cache::Trim");
418 XrdSysRWLockHelper isg(rwlock, 0);
419
420 //
421 // Make sure lifet makes sense; if not, use internal default
422 lifet = (lifet > 0) ? lifet : lifetime;
423
424 //
425 // Reference time
426 int reftime = time(0) - lifet;
427
428 // Loop over entries
429 int i = cachemx, nrm = 0;
430 for (; i >= 0; i--) {
431 if (cachent[i] && cachent[i]->mtime < reftime) {
432 if (!Delete(cachent[i]))
433 DEBUG("Delete deferred for " <<cachent[i]->name);
434 cachent[i] = 0;
435 nrm++;
436 }
437 if (i == cachemx) {
438 if (!cachent[i])
439 cachemx--;
440 }
441 }
442
443 // We are done
444 return nrm;
445}
446
447//__________________________________________________________________
448int XrdSutPFCache::Reset(int newsz, bool lock)
449{
450 // Remove all existing entries.
451 // If newsz > -1, set new capacity to newsz, reallocating if needed
452 // Return 0 if ok, -1 if problems reallocating.
453 EPNAME("Cache::Reset");
454
455 // Lock for writing
456 if (lock) rwlock.WriteLock();
457
458 // Loop over entries
459 int i = cachemx;
460 for (; i >= 0; i--) {
461 if (cachent[i]) {
462 if (!Delete(cachent[i]))
463 DEBUG("Delete deferred for " <<cachent[i]->name);
464 cachent[i] = 0;
465 }
466 }
467
468 int rc = 0;
469 // Reallocate, if requested
470 if (newsz > -1 && newsz != cachesz) {
471 delete[] cachent;
472 cachent = 0;
473 cachesz = 0;
474 cachemx = -1;
475 isinit = 0;
476 rc = Init(newsz, 0);
477 }
478
479 // Unlock
480 if (lock) rwlock.UnLock();
481
482 // We are done
483 return rc;
484}
485
486//________________________________________________________________
487void XrdSutPFCache::Dump(const char *msg)
488{
489 // Dump content of the cache
490 EPNAME("Cache::Dump");
491
492 PRINT("//-----------------------------------------------------");
493 PRINT("//");
494 if (msg && strlen(msg) > 0) {
495 PRINT("// "<<msg);
496 PRINT("//");
497 }
498 PRINT("// Capacity: "<<cachesz);
499 PRINT("// Max index filled: "<<cachemx);
500 PRINT("//");
501
502 // Lock for reading
503 XrdSysRWLockHelper isg(rwlock, 1);
504
505 if (cachesz > 0) {
506
507 XrdSutPFEntry *ent = 0;
508 int i = 0, nn = 0;
509 for (; i <= cachemx; i++) {
510
511 // get entry
512 if ((ent = cachent[i])) {
513
514 char smt[20] = {0};
515 XrdSutTimeString(ent->mtime,smt);
516
517 nn++;
518 PRINT("// #:"<<nn<<" st:"<<ent->status<<" cn:"<<ent->cnt
519 <<" buf:"<<ent->buf1.len<<","<<ent->buf2.len<<","
520 <<ent->buf3.len<<","<<ent->buf4.len<<" mod:"<<smt
521 <<" name:"<<ent->name);
522 }
523
524 }
525 PRINT("//");
526 }
527 PRINT("//-----------------------------------------------------");
528}
529
530//__________________________________________________________________
531int XrdSutPFCache::Load(const char *pfn)
532{
533 // Initialize the cache from the content of a file of PF entries
534 // Return 0 if ok, -1 otherwise
535 EPNAME("Cache::Load");
536
537 // Make sure file name is defined
538 if (!pfn) {
539 DEBUG("invalid input file name");
540 return -1;
541 }
542
543 // Check if file exists and if it has been modified since last load
544 struct stat st;
545 if (stat(pfn,&st) == -1) {
546 DEBUG("cannot stat file (errno: "<<errno<<")");
547 return -1;
548 }
549 if (utime > -1 && utime > st.st_mtime) {
550 DEBUG("cached information for file "<<pfn<<" is up-to-date");
551 return 0;
552 }
553
554 // Lock for writing
555 XrdSysRWLockHelper isg(rwlock, 0);
556
557 // Attach to file and open it
558 XrdSutPFile ff(pfn, kPFEopen);
559 if (!ff.IsValid()) {
560 DEBUG("file is not a valid PFEntry file ("<<ff.LastErrStr()<<")");
561 return -1;
562 }
563
564 // Read the header
565 XrdSutPFHeader header;
566 if (ff.ReadHeader(header) < 0) {
567 ff.Close();
568 return -1;
569 }
570
571 // If the file has no entries there is nothing to do
572 if (header.entries <= 0) {
573 DEBUG("PFEntry file is empty - default init and return");
574 // Save file name
575 pfile = pfn;
576 Init(-1, 0);
577 return 0;
578 }
579
580 // Allocate cache, if not done already or if too small
581 if (Reset(header.entries, 0) == -1) {
582 DEBUG("problems allocating / resizing cache ");
583 ff.Close();
584 return -1;
585 }
586
587 // Read entries
588 kXR_int32 ne = 0;
589 XrdSutPFEntInd ind;
590 kXR_int32 nxtofs = header.indofs;
591 while (nxtofs > 0 && ne < header.entries) {
592 //
593 // read index entry
594 if (ff.ReadInd(nxtofs, ind) < 0) {
595 DEBUG("problems reading index entry ");
596 ff.Close();
597 return -1;
598 }
599
600 // If active ...
601 if (ind.entofs > 0) {
602
603 // Read entry out
604 XrdSutPFEntry ent;
605 if (ff.ReadEnt(ind.entofs, ent) < 0) {
606 ff.Close();
607 return -1;
608 }
609
610 // Copy for the cache
611 XrdSutPFEntry *cent = new XrdSutPFEntry(ent);
612
613 if (cent) {
614 // Set the id
615 cent->SetName(ind.name);
616
617 // Fill the array
618 cachent[ne] = cent;
619
620 // Count
621 ne++;
622
623 } else {
624 DEBUG("problems duplicating entry for cache");
625 ff.Close();
626 return -1;
627 }
628 }
629
630 // Go to next
631 nxtofs = ind.nxtofs;
632 }
633 cachemx = ne-1;
634 if (nxtofs > 0)
635 DEBUG("WARNING: inconsistent number of entries: possible file corruption");
636
637 // Update the time stamp
638 utime = (kXR_int32)time(0);
639
640 // Save file name
641 pfile = pfn;
642
643 // Close the file
644 ff.Close();
645
646 DEBUG("PF file "<<pfn<<" loaded in cache (found "<<ne<<" entries)");
647
648 // Force update hash table
649 if (Rehash(1, 0) != 0) {
650 DEBUG("problems creating hash table");
651 return -1;
652 }
653
654 return 0;
655}
656
657
658//__________________________________________________________________
659int XrdSutPFCache::Rehash(bool force, bool lock)
660{
661 // Update or create hahs table corresponding to the present content of the
662 // cache
663 // Return 0 if ok, -1 otherwise
664 EPNAME("Cache::Rehash");
665
666 // Lock for writing
667 if (lock) rwlock.WriteLock();
668
669 if (htmtime >= utime && !force) {
670 TRACE(Dump, "hash table is up-to-date");
671 if (lock) rwlock.UnLock();
672 return 0;
673 }
674
675 // Clean up the hash table
676 hashtable.Purge();
677
678 kXR_int32 i = 0, nht = 0;
679 for (; i <= cachemx; i++) {
680 if (cachent[i]) {
681 // Fill the hash table
682 kXR_int32 *key = new kXR_int32(i);
683 if (key) {
684 TRACE(Dump, "Adding ID: "<<cachent[i]->name<<"; key: "<<*key);
685 hashtable.Add(cachent[i]->name,key);
686 nht++;
687 }
688 }
689 }
690 // Update modification time
691 htmtime = (kXR_int32)time(0);
692
693 // Unlock
694 if (lock) rwlock.UnLock();
695
696 DEBUG("Hash table updated (found "<<nht<<" active entries)");
697 return 0;
698}
699
700//__________________________________________________________________
701int XrdSutPFCache::Flush(const char *pfn)
702{
703 // Flush cache content to file pfn.
704 // If pfn == 0 and the cache was initialized from a file, flush
705 // to initializing file.
706 // If pfn does not exist, create it.
707 // Return 0 if ok, -1 otherwise
708 EPNAME("Cache::Flush");
709
710 // Make sure we have all the info
711 if (!pfn && pfile.length() <= 0) {
712 DEBUG("invalid input");
713 return -1;
714 }
715 if (!pfn)
716 pfn = pfile.c_str();
717
718 // Attach to file and open it; create if not ther
719 XrdSutPFile ff(pfn, (kPFEopen | kPFEcreate));
720 if (!ff.IsValid()) {
721 DEBUG("cannot attach-to or create file "<<pfn<<" ("<<ff.LastErrStr()<<")");
722 return -1;
723 }
724
725 // Lock for writing
726 XrdSysRWLockHelper isg(rwlock, 0);
727
728 //
729 // Loop over cache entries
730 int i = 0, nr = 0, nfs = 0;
731 for (; i <= cachemx; i++ ) {
732 if (cachent[i]) {
733 //
734 // Retrieve related from file, if any
735 // Read entry out
736 XrdSutPFEntry ent;
737 if ((nr = ff.ReadEntry(cachent[i]->name, ent)) < 0) {
738 ff.Close();
739 return -1;
740 }
741 //
742 // Write (update) only if older that cache or not found
743 if (nr == 0 || cachent[i]->mtime > ent.mtime) {
744 if (ff.WriteEntry(*cachent[i]) < 0) {
745 ff.Close();
746 return -1;
747 }
748 nfs++;
749 }
750 }
751 }
752
753 // Close the file
754 ff.Close();
755
756 // Update the time stamp (to avoid fake loads later on)
757 utime = (kXR_int32)time(0);
758
759 // Save file name
760 if (pfile.length() <= 0)
761 pfile = pfn;
762
763 DEBUG("Cache flushed to file "<<pfn<<" ("<<nfs<<" entries updated / written)");
764
765 return 0;
766}
767
768//__________________________________________________________________
770{
771 // Refresh content of a cache created from file.
772 // Return 0 if ok, -1 otherwise
773 EPNAME("Cache::Refresh");
774
775 // Make sure we have all the info
776 if (pfile.length() <= 0) {
777 DEBUG("cache was not initialized from file - do nothing");
778 return -1;
779 }
780
781 // Check if file exists and if it has been modified since last load
782 struct stat st;
783 if (stat(pfile.c_str(),&st) == -1) {
784 DEBUG("cannot stat file (errno: "<<errno<<")");
785 return -1;
786 }
787 if (utime > -1 && utime > st.st_mtime) {
788 DEBUG("cached information for file "<<pfile<<" is up-to-date");
789 return 0;
790 }
791
792 // Lock for writing
793 XrdSysRWLockHelper isg(rwlock, 0);
794
795 if (Load(pfile.c_str()) != 0) {
796 DEBUG("problems loading passwd information from file: "<<pfile);
797 return -1;
798 }
799
800 // Update the time stamp (to avoid fake loads or refreshs later on)
801 utime = (kXR_int32)time(0);
802
803 DEBUG("Cache refreshed from file: "<<pfile);
804
805 return 0;
806}
807
808
int kXR_int32
Definition XPtypes.hh:89
#define DEBUG(x)
#define EPNAME(x)
#define PRINT(y)
#define stat(a, b)
Definition XrdPosix.hh:101
int XrdSutTimeString(int t, char *st, int opt)
Definition XrdSutAux.cc:305
#define kPFEopen
#define kPFEcreate
#define TRACE(act, x)
Definition XrdTrace.hh:63
#define ID
T * Add(const char *KeyVal, T *KeyData, const int LifeTime=0, XrdOucHash_Options opt=Hash_default)
T * Find(const char *KeyVal, time_t *KeyTime=0)
int length() const
const char * c_str() const
kXR_int32 len
void Lock(XrdSysMutex *Mutex)
void Set(XrdSysMutex *Mutex)
virtual ~XrdSutPFCache()
bool Remove(const char *ID, int opt=1)
int Flush(const char *pfname=0)
XrdSutPFEntry * Add(XrdSutPFCacheRef &urRef, const char *ID, bool force=0)
int Reset(int newsz=-1, bool lock=1)
int Init(int capacity=100, bool lock=1)
void Dump(const char *msg=0)
int Load(const char *pfname)
int Rehash(bool force=0, bool lock=1)
int Trim(int lifet=0)
kXR_int32 entofs
kXR_int32 nxtofs
kXR_int32 mtime
XrdSutPFBuf buf3
XrdSutPFBuf buf1
XrdSysMutex pfeMutex
void SetName(const char *n=0)
XrdSutPFBuf buf2
XrdSutPFBuf buf4
kXR_int32 entries
kXR_int32 indofs
kXR_int32 WriteEntry(XrdSutPFEntry ent)
bool IsValid() const
kXR_int32 Close(kXR_int32 d=-1)
kXR_int32 ReadEntry(const char *name, XrdSutPFEntry &ent, int opt=0)
const char * LastErrStr() const
void Lock(XrdSysRWLock *lock, bool rd=1)
static void Wait(int milliseconds)