00001
00002
00003 const char *XrdSutCacheCVSID = "$Id: XrdSutCache.cc 30949 2009-11-02 16:37:58Z ganis $";
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013 #include <stdio.h>
00014 #include <stdlib.h>
00015 #include <sys/types.h>
00016 #include <sys/stat.h>
00017 #include <unistd.h>
00018 #include <time.h>
00019
00020 #include <XrdSut/XrdSutCache.hh>
00021 #include <XrdSut/XrdSutPFile.hh>
00022 #include <XrdSut/XrdSutTrace.hh>
00023 #include <XrdSut/XrdSutAux.hh>
00024
00025
00026
00027
00028
00029
00030
00031
00032
00033 XrdSutCache::~XrdSutCache()
00034 {
00035
00036
00037
00038 while (cachemx > -1) {
00039 if (cachent[cachemx]) {
00040 delete cachent[cachemx];
00041 cachent[cachemx] = 0;
00042 }
00043 cachemx--;
00044 }
00045
00046 if (cachent)
00047 delete[] cachent;
00048 }
00049
00050
00051 int XrdSutCache::Init(int capacity)
00052 {
00053
00054
00055
00056 EPNAME("Cache::Init");
00057
00058
00059 capacity = (capacity > 0) ? capacity : 100;
00060
00061
00062 cachent = new XrdSutPFEntry *[capacity];
00063 if (cachent) {
00064 cachesz = capacity;
00065 DEBUG("cache allocated for "<<cachesz<<" entries");
00066
00067
00068 utime = (kXR_int32)time(0);
00069
00070
00071 if (Rehash() != 0) {
00072 DEBUG("problems initialising hash table");
00073 return 0 ;
00074 }
00075 return 0;
00076
00077 } else
00078 DEBUG("could not allocate cache - out-of-resources ");
00079 return -1;
00080 }
00081
00082
00083 XrdSutPFEntry *XrdSutCache::Get(const char *ID, bool *wild)
00084 {
00085
00086
00087
00088
00089 EPNAME("Cache::Get");
00090
00091 TRACE(Dump,"locating entry for ID: "<<ID);
00092
00093
00094
00095 if (!ID || !strlen(ID)) {
00096 DEBUG("empty ID !");
00097 return (XrdSutPFEntry *)0 ;
00098 }
00099 if (wild) *wild = 0;
00100
00101 if (Rehash() != 0) {
00102 DEBUG("problems rehashing");
00103 return (XrdSutPFEntry *)0 ;
00104 }
00105
00106
00107 kXR_int32 *ie = hashtable.Find(ID);
00108 if (ie && *ie >= 0 && *ie < cachesz) {
00109
00110 return cachent[*ie];
00111 }
00112
00113
00114 if (wild) {
00115 XrdOucString sid(ID);
00116 int i = 0, match = 0, nmmax = 0, iref = -1;
00117 for (; i <= cachemx; i++) {
00118 if (cachent[i]) {
00119 match = sid.matches(cachent[i]->name);
00120 if (match > nmmax) {
00121 nmmax = match;
00122 iref = i;
00123 }
00124 }
00125 }
00126 if (iref > -1) {
00127 *wild = 1;
00128 return cachent[iref];
00129 }
00130 }
00131
00132
00133 return (XrdSutPFEntry *)0 ;
00134 }
00135
00136
00137 XrdSutPFEntry *XrdSutCache::Add(const char *ID, bool force)
00138 {
00139
00140
00141
00142 EPNAME("Cache::Add");
00143
00144
00145
00146 if (!ID || !strlen(ID)) {
00147 DEBUG("empty ID !");
00148 return (XrdSutPFEntry *)0 ;
00149 }
00150
00151
00152
00153 XrdSutPFEntry *ent = Get(ID);
00154 if (ent)
00155 return ent;
00156
00157
00158
00159 if (cachemx == cachesz - 1) {
00160
00161
00162 XrdSutPFEntry **newcache = new XrdSutPFEntry *[2*cachesz];
00163 if (!newcache) {
00164 DEBUG("could not extend cache to size: "<<(2*cachesz));
00165 return (XrdSutPFEntry *)0 ;
00166 }
00167
00168 cachesz *= 2;
00169
00170
00171 int i = 0, nmx = 0;
00172 for (; i <= cachemx; i++) {
00173 if (cachent[i]) {
00174 newcache[nmx] = cachent[i];
00175 nmx++;
00176 }
00177 }
00178
00179 cachemx = nmx - 1;
00180
00181
00182 for (i = cachemx + 1; i <= cachemx; i++) {
00183 newcache[i] = 0;
00184 }
00185
00186
00187 delete[] cachent;
00188 cachent = newcache;
00189
00190
00191 force = 1;
00192 }
00193
00194
00195 int pos = cachemx + 1;
00196
00197
00198
00199 cachent[pos] = new XrdSutPFEntry(ID);
00200 if (cachent[pos]) {
00201 cachemx = pos;
00202 } else {
00203 DEBUG("could not allocate space for new cache entry");
00204 return (XrdSutPFEntry *)0 ;
00205 }
00206
00207 utime = (kXR_int32)time(0);
00208
00209
00210 if (Rehash(force) != 0) {
00211 DEBUG("problems re-hashing");
00212 return (XrdSutPFEntry *)0 ;
00213 }
00214
00215
00216 return cachent[pos];
00217 }
00218
00219
00220 bool XrdSutCache::Remove(const char *ID, int opt)
00221 {
00222
00223
00224
00225 EPNAME("Cache::Remove");
00226
00227
00228
00229 if (!ID || !strlen(ID)) {
00230 DEBUG("empty ID !");
00231 return 0 ;
00232 }
00233
00234 if (Rehash() != 0) {
00235 DEBUG("problems rehashing");
00236 return 0 ;
00237 }
00238
00239 bool found = 0;
00240 if (opt == 1) {
00241 int pos = -1;
00242
00243 kXR_int32 *ie = hashtable.Find(ID);
00244 if (*ie >= 0 && *ie < cachesz) {
00245
00246 pos = *ie;
00247 }
00248
00249
00250
00251 if (cachent[pos] && !strcmp(cachent[pos]->name,ID)) {
00252 delete cachent[pos];
00253 cachent[pos] = 0;
00254
00255 if (pos < cachemx)
00256 return 1;
00257
00258 found = 1;
00259 }
00260 } else {
00261
00262 int i = cachemx;
00263 for (; i >= 0; i--) {
00264 if (cachent[i]) {
00265 if (!strncmp(cachent[i]->name,ID,strlen(ID))) {
00266 delete cachent[i];
00267 cachent[i] = 0;
00268 found = 1;
00269 }
00270 }
00271 }
00272 }
00273
00274 if (found) {
00275
00276 utime = (kXR_int32)time(0);
00277
00278
00279 if (Rehash() != 0) {
00280 DEBUG("problems re-hashing");
00281 return 0 ;
00282 }
00283 }
00284
00285
00286 return found;
00287 }
00288
00289
00290 int XrdSutCache::Trim(int lifet)
00291 {
00292
00293
00294
00295
00296
00297
00298 lifet = (lifet > 0) ? lifet : lifetime;
00299
00300
00301
00302 int reftime = time(0) - lifet;
00303
00304
00305 int i = cachemx, nrm = 0;
00306 for (; i >= 0; i--) {
00307 if (cachent[i] && cachent[i]->mtime < reftime) {
00308 delete cachent[i];
00309 cachent[i] = 0;
00310 nrm++;
00311 }
00312 if (i == cachemx) {
00313 if (!cachent[i])
00314 cachemx--;
00315 }
00316 }
00317
00318
00319 return nrm;
00320 }
00321
00322
00323 int XrdSutCache::Reset(int newsz)
00324 {
00325
00326
00327
00328
00329
00330 int i = cachemx;
00331 for (; i >= 0; i--) {
00332 if (cachent[i]) {
00333 delete cachent[i];
00334 cachent[i] = 0;
00335 }
00336 }
00337
00338
00339 if (newsz > -1 && newsz != cachesz) {
00340 delete[] cachent;
00341 cachent = 0;
00342 cachesz = 0;
00343 cachemx = -1;
00344 return Init(newsz);
00345 }
00346
00347
00348 return 0;
00349 }
00350
00351
00352 void XrdSutCache::Dump(const char *msg)
00353 {
00354
00355 EPNAME("Cache::Dump");
00356
00357 PRINT("//-----------------------------------------------------");
00358 PRINT("//");
00359 if (msg && strlen(msg) > 0) {
00360 PRINT("// "<<msg);
00361 PRINT("//");
00362 }
00363 PRINT("// Capacity: "<<cachesz);
00364 PRINT("// Max index filled: "<<cachemx);
00365 PRINT("//");
00366
00367 if (cachesz > 0) {
00368
00369 XrdSutPFEntry *ent = 0;
00370 int i = 0, nn = 0;
00371 for (; i <= cachemx; i++) {
00372
00373
00374 if ((ent = cachent[i])) {
00375
00376 char smt[20] = {0};
00377 XrdSutTimeString(ent->mtime,smt);
00378
00379 nn++;
00380 PRINT("// #:"<<nn<<" st:"<<ent->status<<" cn:"<<ent->cnt
00381 <<" buf:"<<ent->buf1.len<<","<<ent->buf2.len<<","
00382 <<ent->buf3.len<<","<<ent->buf4.len<<" mod:"<<smt
00383 <<" name:"<<ent->name);
00384 }
00385
00386 }
00387 PRINT("//");
00388 }
00389 PRINT("//-----------------------------------------------------");
00390 }
00391
00392
00393 int XrdSutCache::Load(const char *pfn)
00394 {
00395
00396
00397 EPNAME("Cache::Load");
00398
00399
00400 if (!pfn) {
00401 DEBUG("invalid input file name");
00402 return -1;
00403 }
00404
00405
00406 struct stat st;
00407 if (stat(pfn,&st) == -1) {
00408 DEBUG("cannot stat file (errno: "<<errno<<")");
00409 return -1;
00410 }
00411 if (utime > -1 && utime > st.st_mtime) {
00412 DEBUG("cached information for file "<<pfn<<" is up-to-date");
00413 return 0;
00414 }
00415
00416
00417 XrdSutPFile ff(pfn, kPFEopen);
00418 if (!ff.IsValid()) {
00419 DEBUG("file is not a valid PFEntry file ("<<ff.LastErrStr()<<")");
00420 return -1;
00421 }
00422
00423
00424 XrdSutPFHeader header;
00425 if (ff.ReadHeader(header) < 0) {
00426 ff.Close();
00427 return -1;
00428 }
00429
00430
00431 if (header.entries <= 0) {
00432 DEBUG("PFEntry file is empty - default init and return");
00433
00434 pfile = pfn;
00435 Init();
00436 return 0;
00437 }
00438
00439
00440 if (Reset(header.entries) == -1) {
00441 DEBUG("problems allocating / resizing cache ");
00442 ff.Close();
00443 return -1;
00444 }
00445
00446
00447 kXR_int32 ne = 0;
00448 XrdSutPFEntInd ind;
00449 kXR_int32 nxtofs = header.indofs;
00450 while (nxtofs > 0 && ne < header.entries) {
00451
00452
00453 if (ff.ReadInd(nxtofs, ind) < 0) {
00454 DEBUG("problems reading index entry ");
00455 ff.Close();
00456 return -1;
00457 }
00458
00459
00460 if (ind.entofs > 0) {
00461
00462
00463 XrdSutPFEntry ent;
00464 if (ff.ReadEnt(ind.entofs, ent) < 0) {
00465 ff.Close();
00466 return -1;
00467 }
00468
00469
00470 XrdSutPFEntry *cent = new XrdSutPFEntry(ent);
00471
00472 if (cent) {
00473
00474 cent->SetName(ind.name);
00475
00476
00477 cachent[ne] = cent;
00478
00479
00480 ne++;
00481
00482 } else {
00483 DEBUG("problems duplicating entry for cache");
00484 ff.Close();
00485 return -1;
00486 }
00487 }
00488
00489
00490 nxtofs = ind.nxtofs;
00491 }
00492 cachemx = ne-1;
00493 if (nxtofs > 0)
00494 DEBUG("WARNING: inconsistent number of entries: possible file corruption");
00495
00496
00497 utime = (kXR_int32)time(0);
00498
00499
00500 pfile = pfn;
00501
00502
00503 ff.Close();
00504
00505 DEBUG("PF file "<<pfn<<" loaded in cache (found "<<ne<<" entries)");
00506
00507
00508 if (Rehash(1) != 0) {
00509 DEBUG("problems creating hash table");
00510 return -1;
00511 }
00512
00513 return 0;
00514 }
00515
00516
00517
00518 int XrdSutCache::Rehash(bool force)
00519 {
00520
00521
00522
00523 EPNAME("Cache::Rehash");
00524
00525 if (htmtime >= utime && !force) {
00526 TRACE(Dump, "hash table is up-to-date");
00527 return 0;
00528 }
00529
00530
00531 hashtable.Purge();
00532
00533 kXR_int32 i = 0, nht = 0;
00534 for (; i <= cachemx; i++) {
00535 if (cachent[i]) {
00536
00537 kXR_int32 *key = new kXR_int32(i);
00538 if (key) {
00539 TRACE(Dump, "Adding ID: "<<cachent[i]->name<<"; key: "<<*key);
00540 hashtable.Add(cachent[i]->name,key);
00541 nht++;
00542 }
00543 }
00544 }
00545
00546 htmtime = (kXR_int32)time(0);
00547
00548 DEBUG("Hash table updated (found "<<nht<<" active entries)");
00549 return 0;
00550 }
00551
00552
00553 int XrdSutCache::Flush(const char *pfn)
00554 {
00555
00556
00557
00558
00559
00560 EPNAME("Cache::Flush");
00561
00562
00563 if (!pfn && pfile.length() <= 0) {
00564 DEBUG("invalid input");
00565 return -1;
00566 }
00567 if (!pfn)
00568 pfn = pfile.c_str();
00569
00570
00571 XrdSutPFile ff(pfn, (kPFEopen | kPFEcreate));
00572 if (!ff.IsValid()) {
00573 DEBUG("cannot attach-to or create file "<<pfn<<" ("<<ff.LastErrStr()<<")");
00574 return -1;
00575 }
00576
00577
00578
00579 int i = 0, nr = 0, nfs = 0;
00580 for (; i <= cachemx; i++ ) {
00581 if (cachent[i]) {
00582
00583
00584
00585 XrdSutPFEntry ent;
00586 if ((nr = ff.ReadEntry(cachent[i]->name, ent)) < 0) {
00587 ff.Close();
00588 return -1;
00589 }
00590
00591
00592 if (nr == 0 || cachent[i]->mtime > ent.mtime) {
00593 if (ff.WriteEntry(*cachent[i]) < 0) {
00594 ff.Close();
00595 return -1;
00596 }
00597 nfs++;
00598 }
00599 }
00600 }
00601
00602
00603 ff.Close();
00604
00605
00606 utime = (kXR_int32)time(0);
00607
00608
00609 if (pfile.length() <= 0)
00610 pfile = pfn;
00611
00612 DEBUG("Cache flushed to file "<<pfn<<" ("<<nfs<<" entries updated / written)");
00613
00614 return 0;
00615 }
00616
00617
00618 int XrdSutCache::Refresh()
00619 {
00620
00621
00622 EPNAME("Cache::Refresh");
00623
00624
00625 if (pfile.length() <= 0) {
00626 DEBUG("cache was not initialized from file - do nothing");
00627 return -1;
00628 }
00629
00630
00631 struct stat st;
00632 if (stat(pfile.c_str(),&st) == -1) {
00633 DEBUG("cannot stat file (errno: "<<errno<<")");
00634 return -1;
00635 }
00636 if (utime > -1 && utime > st.st_mtime) {
00637 DEBUG("cached information for file "<<pfile<<" is up-to-date");
00638 return 0;
00639 }
00640
00641 if (Load(pfile.c_str()) != 0) {
00642 DEBUG("problems loading passwd information from file: "<<pfile);
00643 return -1;
00644 }
00645
00646
00647 utime = (kXR_int32)time(0);
00648
00649 DEBUG("Cache refreshed from file: "<<pfile);
00650
00651 return 0;
00652 }
00653