00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013 const char *XrdOfsHandleCVSID = "$Id: XrdOfsHandle.cc 29874 2009-08-21 16:56:04Z ganis $";
00014
00015 #include <stdio.h>
00016 #include <time.h>
00017 #include <sys/errno.h>
00018 #include <sys/types.h>
00019
00020 #include "XrdOfs/XrdOfsHandle.hh"
00021 #include "XrdOfs/XrdOfsStats.hh"
00022 #include "XrdOss/XrdOss.hh"
00023 #include "XrdSys/XrdSysError.hh"
00024 #include "XrdSys/XrdSysPlatform.hh"
00025 #include "XrdSys/XrdSysTimer.hh"
00026
00027
00028
00029
00030
00031
00032
00033
00034 class XrdOfsHanOss : public XrdOssDF
00035 {
00036 public:
00037
00038 int Opendir(const char *) {return -EBADF;}
00039 int Readdir(char *buff, int blen) {return -EBADF;}
00040
00041
00042 int Fstat(struct stat *) {return -EBADF;}
00043 int Fsync() {return -EBADF;}
00044 int Fsync(XrdSfsAio *aiop) {return -EBADF;}
00045 int Ftruncate(unsigned long long) {return -EBADF;}
00046 off_t getMmap(void **addr) {return 0;}
00047 int isCompressed(char *cxidp=0) {return 0;}
00048 int Open(const char *, int, mode_t, XrdOucEnv &) {return -EBADF;}
00049 ssize_t Read(off_t, size_t) {return (ssize_t)-EBADF;}
00050 ssize_t Read(void *, off_t, size_t) {return (ssize_t)-EBADF;}
00051 int Read(XrdSfsAio *aoip) {return (ssize_t)-EBADF;}
00052 ssize_t ReadRaw( void *, off_t, size_t) {return (ssize_t)-EBADF;}
00053 ssize_t Write(const void *, off_t, size_t) {return (ssize_t)-EBADF;}
00054 int Write(XrdSfsAio *aiop) {return (ssize_t)-EBADF;}
00055
00056
00057 int Close(long long *retsz=0) {return -EBADF;}
00058 inline int Handle() {return -1;}
00059
00060 XrdOfsHanOss() {}
00061 ~XrdOfsHanOss() {}
00062
00063 };
00064
00065
00066
00067
00068
00069 class XrdOfsHanXpr
00070 {
00071 friend class XrdOfsHandle;
00072 public:
00073
00074 void add2Q(int doLK=1);
00075
00076 void Deref()
00077 {xqCV.Lock(); Handle=0; Call=0; xTNew=0; xqCV.UnLock();}
00078
00079 static XrdOfsHanXpr *Get();
00080
00081 void Set(XrdOfsHanCB *cbP, time_t xtm)
00082 {xqCV.Lock(); Call = cbP; xTNew = xtm; xqCV.UnLock();}
00083
00084 XrdOfsHanXpr(XrdOfsHandle *hP, XrdOfsHanCB *cbP, time_t xtm)
00085 : Next(0), Handle(hP), Call(cbP), xTime(xtm), xTNew(0) {}
00086 ~XrdOfsHanXpr() {}
00087
00088 private:
00089 XrdOfsHanXpr *Next;
00090 XrdOfsHandle *Handle;
00091 XrdOfsHanCB *Call;
00092 time_t xTime;
00093 time_t xTNew;
00094
00095 static XrdSysCondVar xqCV;
00096 static XrdOfsHanXpr *xprQ;
00097 };
00098
00099 XrdSysCondVar XrdOfsHanXpr::xqCV(0, "HanXpr cv");
00100 XrdOfsHanXpr *XrdOfsHanXpr::xprQ = 0;
00101
00102
00103
00104
00105
00106 class XrdOfsHanPsc
00107 {
00108 public:
00109
00110 union {
00111 XrdOfsHanPsc *Next;
00112 char *User;
00113 };
00114 XrdOfsHanXpr *xprP;
00115 int Unum;
00116 short Ulen;
00117 short Uhst;
00118 short Mode;
00119
00120 static
00121 XrdOfsHanPsc *Alloc();
00122
00123 void Recycle();
00124
00125 XrdOfsHanPsc() : User(0), xprP(0), Unum(0), Ulen(0),
00126 Uhst(0), Mode(0) {}
00127 ~XrdOfsHanPsc() {}
00128 private:
00129
00130 static XrdSysMutex pscMutex;
00131 static XrdOfsHanPsc *Free;
00132 };
00133
00134 XrdSysMutex XrdOfsHanPsc::pscMutex;
00135 XrdOfsHanPsc *XrdOfsHanPsc::Free = 0;
00136
00137
00138
00139
00140
00141 void *XrdOfsHanXpire(void *pp)
00142 {
00143 XrdOfsHandle::StartXpr();
00144 return (void *)0;
00145 }
00146
00147 extern XrdSysError OfsEroute;
00148
00149 extern XrdOfsStats OfsStats;
00150
00151
00152
00153
00154
00155 XrdSysMutex XrdOfsHandle::myMutex;
00156 XrdOfsHanTab XrdOfsHandle::roTable;
00157 XrdOfsHanTab XrdOfsHandle::rwTable;
00158 XrdOssDF *XrdOfsHandle::ossDF = (XrdOssDF *)new XrdOfsHanOss;
00159 XrdOfsHandle *XrdOfsHandle::Free = 0;
00160
00161
00162
00163
00164
00165
00166
00167
00168 int XrdOfsHandle::Alloc(const char *thePath, int Opts, XrdOfsHandle **Handle)
00169 {
00170 XrdOfsHandle *hP;
00171 XrdOfsHanTab *theTable = (Opts & opRW ? &rwTable : &roTable);
00172 XrdOfsHanKey theKey(thePath, (int)strlen(thePath));
00173 int retc;
00174
00175
00176
00177
00178
00179
00180
00181
00182 myMutex.Lock();
00183 if ((hP = theTable->Find(theKey)) && hP->Path.Links != 0xffff)
00184 {hP->Path.Links++; myMutex.UnLock();
00185 if (hP->WaitLock()) {*Handle = hP; return 0;}
00186 myMutex.Lock(); hP->Path.Links--; myMutex.UnLock();
00187 return nolokDelay;
00188 }
00189
00190
00191
00192 if (!(retc = Alloc(theKey, Opts, Handle))) theTable->Add(*Handle);
00193 OfsStats.Add(OfsStats.Data.numHandles);
00194
00195
00196
00197 myMutex.UnLock();
00198 return retc;
00199 }
00200
00201
00202
00203
00204
00205 int XrdOfsHandle::Alloc(XrdOfsHandle **Handle)
00206 {
00207 XrdOfsHanKey myKey("dummy", 5);
00208 int retc;
00209
00210 myMutex.Lock();
00211 if (!(retc = Alloc(myKey, 0, Handle)))
00212 {(*Handle)->Path.Links = 0; (*Handle)->UnLock();}
00213 myMutex.UnLock();
00214 return retc;
00215 }
00216
00217
00218
00219
00220
00221 int XrdOfsHandle::Alloc(XrdOfsHanKey theKey, int Opts, XrdOfsHandle **Handle)
00222 {
00223 static const int minAlloc = 4096/sizeof(XrdOfsHandle);
00224 XrdOfsHandle *hP;
00225
00226
00227
00228 if (!Free && (hP = new XrdOfsHandle[minAlloc]))
00229 {int i = minAlloc; while(i--) {hP->Next = Free; Free = hP; hP++;}}
00230 if ((hP = Free)) Free = hP->Next;
00231
00232
00233
00234 if (hP)
00235 {hP->Path = theKey;
00236 hP->Path.Links = 1;
00237 hP->isChanged = 0;
00238 hP->isCompressed = 0;
00239 hP->isPending = 0;
00240 hP->isRW = (Opts & opPC);
00241 hP->ssi = ossDF;
00242 hP->Posc = 0;
00243 hP->Lock();
00244 *Handle = hP;
00245 return 0;
00246 }
00247 return nomemDelay;
00248 }
00249
00250
00251
00252
00253
00254 void XrdOfsHandle::Hide(const char *thePath)
00255 {
00256 XrdOfsHandle *hP;
00257 XrdOfsHanKey theKey(thePath, (int)strlen(thePath));
00258
00259
00260
00261
00262 myMutex.Lock();
00263 if ((hP = roTable.Find(theKey))) hP->Path.Len = 0;
00264 if ((hP = rwTable.Find(theKey))) hP->Path.Len = 0;
00265 myMutex.UnLock();
00266 }
00267
00268
00269
00270
00271
00272
00273
00274 int XrdOfsHandle::PoscGet(short &Mode, int Done)
00275 {
00276 XrdOfsHanPsc *pP;
00277 int pnum;
00278
00279 if (Posc)
00280 {pnum = Posc->Unum;
00281 Mode = Posc->Mode;
00282 if (Done)
00283 {pP = Posc; Posc = 0;
00284 if (pP->xprP) {myMutex.Lock(); Path.Links--; myMutex.UnLock();}
00285 pP->Recycle();
00286 }
00287 return pnum;
00288 }
00289
00290 Mode = 0;
00291 return 0;
00292 }
00293
00294
00295
00296
00297
00298
00299
00300 int XrdOfsHandle::PoscSet(const char *User, int Unum, short Umod)
00301 {
00302 static const char *Who = "?:0.0@?", *Whc = Who+1, *Whh = Who+5;
00303 const char *Col, *At;
00304 int retval = 0;
00305
00306
00307
00308 if (!Posc)
00309 {if (Unum > 0) Posc = XrdOfsHanPsc::Alloc();
00310 else return 0;
00311 }
00312
00313
00314
00315 if (!(Col = index(User, ':')) || !(At = index(User, '@')))
00316 {User = Who; Col = Whc; At = Whh;}
00317
00318
00319
00320 if (Posc->User)
00321 {if (!Unum)
00322 {if (!strncmp(User, Posc->User, Posc->Ulen)
00323 && !strcmp(Posc->User + Posc->Uhst, At+1)) return 0;
00324 return -ETXTBSY;
00325 } else {
00326 char buff[1024];
00327 sprintf(buff, "%s to %s for", Posc->User, User);
00328 OfsEroute.Emsg("Posc", "Creator changed from", buff, Path.Val);
00329 if (Unum < 0) Unum = Posc->Unum;
00330 else if (Unum != Posc->Unum) retval = Posc->Unum;
00331 }
00332 free(Posc->User);
00333 }
00334
00335
00336
00337 Posc->User = strdup(User);
00338 Posc->Ulen = Col - User + 1;
00339 Posc->Uhst = At - User + 1;
00340 Posc->Unum = Unum;
00341 Posc->Mode = Umod;
00342 return retval;
00343 }
00344
00345
00346
00347
00348
00349
00350
00351 const char *XrdOfsHandle::PoscUsr()
00352 {
00353 if (Posc) return Posc->User;
00354 return "?@?";
00355 }
00356
00357
00358
00359
00360
00361
00362
00363 int XrdOfsHandle::Retire(long long *retsz, char *buff, int blen)
00364 {
00365 int numLeft;
00366
00367
00368
00369
00370
00371 myMutex.Lock();
00372 if (Path.Links == 1)
00373 {if (buff) strlcpy(buff, Path.Val, blen);
00374 numLeft = 0; OfsStats.Dec(OfsStats.Data.numHandles);
00375 if ( (isRW ? rwTable.Remove(this) : roTable.Remove(this)) )
00376 {Next = Free; Free = this;
00377 if (Posc) {Posc->Recycle(); Posc = 0;}
00378 if (Path.Val) {free((void *)Path.Val); Path.Val = (char *)"";}
00379 Path.Len = 0;
00380 if (ssi && ssi != ossDF)
00381 {ssi->Close(retsz); delete ssi; ssi = ossDF;}
00382 } else OfsEroute.Emsg("Retire", "Lost handle to", Path.Val);
00383 } else numLeft = --Path.Links;
00384 UnLock();
00385 myMutex.UnLock();
00386 return numLeft;
00387 }
00388
00389
00390
00391 int XrdOfsHandle::Retire(XrdOfsHanCB *cbP, int hTime)
00392 {
00393 static int allOK = StartXpr(1);
00394 XrdOfsHanXpr *xP;
00395
00396
00397
00398
00399 myMutex.Lock();
00400 if (!Posc || !allOK)
00401 {OfsEroute.Emsg("Retire", "ignoring deferred retire of", Path.Val);
00402 if (Path.Links != 1 || !Posc || !cbP) myMutex.UnLock();
00403 else {myMutex.UnLock(); cbP->Retired(this);}
00404 return Retire();
00405 }
00406 myMutex.UnLock();
00407
00408
00409
00410
00411 if (Posc->xprP) Posc->xprP->Set(cbP, hTime+time(0));
00412 else {xP = Posc->xprP = new XrdOfsHanXpr(this, cbP, hTime+time(0));
00413 xP->add2Q();
00414 }
00415 UnLock();
00416 return 0;
00417 }
00418
00419
00420
00421
00422
00423 int XrdOfsHandle::StartXpr(int Init)
00424 {
00425 static int InitDone = 0;
00426 XrdOfsHanXpr *xP;
00427 XrdOfsHandle *hP;
00428
00429
00430
00431 if (Init)
00432 {pthread_t tid;
00433 int rc;
00434 if (InitDone) return InitDone == 1;
00435 if ((rc = XrdSysThread::Run(&tid, XrdOfsHanXpire, (void *)0,
00436 0, "Handle Timeout")))
00437 {OfsEroute.Emsg("StartXpr", rc, "create handle timeout thread");
00438 InitDone = -1; return 0;
00439 }
00440 InitDone = 1; return 1;
00441 }
00442
00443
00444
00445
00446 do{xP = XrdOfsHanXpr::Get(); hP = xP->Handle;
00447
00448
00449
00450
00451
00452 if (hP->Posc && xP == hP->Posc->xprP) hP->Posc->xprP = 0;
00453 else {OfsEroute.Emsg("StarXtpr", "Invalid xpr ref to", hP->Path.Val);
00454 hP->UnLock(); delete xP; continue;
00455 }
00456
00457
00458
00459
00460
00461
00462 myMutex.Lock();
00463 if (hP->Path.Links != 1 || !xP->Call) myMutex.UnLock();
00464 else {myMutex.UnLock();
00465 xP->Call->Retired(hP);
00466 }
00467
00468
00469
00470 hP->Retire();
00471 delete xP;
00472 } while(1);
00473
00474
00475
00476 return 0;
00477 }
00478
00479
00480
00481
00482
00483 int XrdOfsHandle::WaitLock(void)
00484 {
00485 int ntry = LockTries;
00486
00487
00488
00489 while(ntry--)
00490 {if (hMutex.CondLock()) return 1;
00491 if (ntry) XrdSysTimer::Wait(LockWait);
00492 }
00493
00494
00495
00496 return 0;
00497 }
00498
00499
00500
00501
00502
00503
00504
00505
00506 XrdOfsHanPsc *XrdOfsHanPsc::Alloc()
00507 {
00508 XrdOfsHanPsc *pP;
00509
00510
00511
00512 pscMutex.Lock();
00513 if ((pP = Free)) {Free = pP->Next; pP->Next = 0;}
00514 else pP = new XrdOfsHanPsc;
00515 pscMutex.UnLock();
00516
00517 return pP;
00518 }
00519
00520
00521
00522
00523
00524 void XrdOfsHanPsc::Recycle()
00525 {
00526
00527
00528
00529 if (xprP) {xprP->Deref(); xprP = 0;}
00530 if (User) free(User);
00531 Unum = 0;
00532 Ulen = 0;
00533 Uhst = 0;
00534 Mode = 0;
00535
00536
00537
00538 pscMutex.Lock();
00539 Next = Free; Free = this;
00540 pscMutex.UnLock();
00541 }
00542
00543
00544
00545
00546
00547
00548
00549
00550 XrdOfsHanTab::XrdOfsHanTab(int psize, int csize)
00551 {
00552 prevtablesize = psize;
00553 nashtablesize = csize;
00554 Threshold = (csize * LoadMax) / 100;
00555 nashnum = 0;
00556 nashtable = (XrdOfsHandle **)
00557 malloc( (size_t)(csize*sizeof(XrdOfsHandle *)) );
00558 memset((void *)nashtable, 0, (size_t)(csize*sizeof(XrdOfsHandle *)));
00559 }
00560
00561
00562
00563
00564
00565 void XrdOfsHanTab::Add(XrdOfsHandle *hip)
00566 {
00567 unsigned int kent;
00568
00569
00570
00571 if (++nashnum > Threshold) Expand();
00572
00573
00574
00575 kent = hip->Path.Hash % nashtablesize;
00576 hip->Next = nashtable[kent];
00577 nashtable[kent] = hip;
00578 }
00579
00580
00581
00582
00583
00584 void XrdOfsHanTab::Expand()
00585 {
00586 int newsize, newent, i;
00587 size_t memlen;
00588 XrdOfsHandle **newtab, *nip, *nextnip;
00589
00590
00591
00592 newsize = prevtablesize + nashtablesize;
00593
00594
00595
00596 memlen = (size_t)(newsize*sizeof(XrdOfsHandle *));
00597 if (!(newtab = (XrdOfsHandle **) malloc(memlen))) return;
00598 memset((void *)newtab, 0, memlen);
00599
00600
00601
00602 for (i = 0; i < nashtablesize; i++)
00603 {nip = nashtable[i];
00604 while(nip)
00605 {nextnip = nip->Next;
00606 newent = nip->Path.Hash % newsize;
00607 nip->Next = newtab[newent];
00608 newtab[newent] = nip;
00609 nip = nextnip;
00610 }
00611 }
00612
00613
00614
00615 free((void *)nashtable);
00616 nashtable = newtab;
00617 prevtablesize = nashtablesize;
00618 nashtablesize = newsize;
00619
00620
00621
00622 Threshold = static_cast<int>((static_cast<long long>(newsize)*LoadMax)/100);
00623 }
00624
00625
00626
00627
00628
00629 XrdOfsHandle *XrdOfsHanTab::Find(XrdOfsHanKey &Key)
00630 {
00631 XrdOfsHandle *nip;
00632 unsigned int kent;
00633
00634
00635
00636 kent = Key.Hash%nashtablesize;
00637
00638
00639
00640 nip = nashtable[kent];
00641 while(nip && nip->Path != Key) nip = nip->Next;
00642 return nip;
00643 }
00644
00645
00646
00647
00648
00649 int XrdOfsHanTab::Remove(XrdOfsHandle *rip)
00650 {
00651 XrdOfsHandle *nip, *pip = 0;
00652 unsigned int kent;
00653
00654
00655
00656 kent = rip->Path.Hash%nashtablesize;
00657
00658
00659
00660 nip = nashtable[kent];
00661 while(nip && nip != rip) {pip = nip; nip = nip->Next;}
00662
00663
00664
00665 if (nip)
00666 {if (pip) pip->Next = nip->Next;
00667 else nashtable[kent] = nip->Next;
00668 nashnum--;
00669 }
00670 return nip != 0;
00671 }
00672
00673
00674
00675
00676
00677
00678
00679
00680 void XrdOfsHanXpr::add2Q(int doLK)
00681 {
00682 XrdOfsHanXpr *xPP, *xP;
00683
00684
00685
00686 if (doLK) xqCV.Lock();
00687 xPP = 0; xP = xprQ;
00688
00689 while(xP && xP->xTime < xTime) {xPP = xP; xP = xP->Next;}
00690
00691 Next = xP;
00692 if (xPP) {xPP->Next = this; if (doLK) xqCV.UnLock();}
00693 else { xprQ = this; if (doLK) {xqCV.Signal(); xqCV.UnLock();}}
00694 };
00695
00696
00697
00698
00699
00700 XrdOfsHanXpr *XrdOfsHanXpr::Get()
00701 {
00702 XrdOfsHanXpr *xP;
00703 XrdOfsHandle *hP;
00704 int waitTime = 2592000;
00705
00706
00707
00708
00709 xqCV.Lock();
00710
00711
00712
00713
00714
00715 do{do{if (!(xP = xprQ)) waitTime = 2592000;
00716 else waitTime = xP->xTime - time(0);
00717 if (waitTime > 0) break;
00718 xprQ = xP->Next;
00719
00720
00721
00722 if (!(hP = xP->Handle)) {delete xP; continue;}
00723
00724
00725
00726 if (xP->xTNew)
00727 {xP->xTime = xP->xTNew; xP->xTNew = 0;
00728 xP->add2Q(0);
00729 continue;
00730 }
00731
00732
00733
00734
00735 if (!(hP->WaitLock()))
00736 {OfsEroute.Emsg("Retire", "defering retire of", hP->Path.Val);
00737 xP->xTime = time(0)+30;
00738 xP->add2Q(0);
00739 continue;
00740 }
00741
00742
00743
00744
00745 xqCV.UnLock();
00746 return xP;
00747
00748 } while(1);
00749
00750
00751
00752 xqCV.Wait(waitTime);
00753 } while(1);
00754 }