00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013 const char *XrdCnsLogClientCVSID = "$Id: XrdCnsLogClient.cc 32231 2010-02-05 18:24:46Z ganis $";
00014
00015 #include <errno.h>
00016 #include <unistd.h>
00017 #include <fcntl.h>
00018 #include <string.h>
00019 #include <stdio.h>
00020 #include <sys/types.h>
00021 #include <sys/stat.h>
00022 #include <sys/uio.h>
00023
00024 #include "Xrd/XrdTrace.hh"
00025
00026 #include "XrdClient/XrdClient.hh"
00027 #include "XrdClient/XrdClientAdmin.hh"
00028
00029 #include "XrdCns/XrdCnsConfig.hh"
00030 #include "XrdCns/XrdCnsInventory.hh"
00031 #include "XrdCns/XrdCnsLog.hh"
00032 #include "XrdCns/XrdCnsLogClient.hh"
00033 #include "XrdCns/XrdCnsLogFile.hh"
00034 #include "XrdCns/XrdCnsLogRec.hh"
00035 #include "XrdCns/XrdCnsXref.hh"
00036
00037 #include "XrdNet/XrdNetDNS.hh"
00038 #include "XrdOuc/XrdOucNSWalk.hh"
00039 #include "XrdOuc/XrdOucTList.hh"
00040 #include "XrdOuc/XrdOucUtils.hh"
00041 #include "XrdSys/XrdSysError.hh"
00042 #include "XrdSys/XrdSysTimer.hh"
00043
00044
00045
00046
00047
00048 namespace XrdCns
00049 {
00050 extern XrdCnsConfig Config;
00051
00052 extern XrdSysError MLog;
00053
00054 extern XrdOucTrace XrdTrace;
00055 }
00056
00057 using namespace XrdCns;
00058
00059
00060
00061
00062
00063 XrdCnsLogClient::XrdCnsLogClient(XrdOucTList *rP,
00064 XrdCnsLogClient *pClient) : lfSem(0)
00065 {
00066 static int cNum = 0;
00067 static int bSfx = static_cast<int>(time(0)) - 1248126834;
00068 static char *myName = XrdNetDNS::getHostName();
00069 char destBuff[512];
00070
00071
00072
00073 pfxNF = cNum++;
00074 Next = pClient;
00075 sfxFN = bSfx;
00076 logFirst = 0;
00077 logLast = 0;
00078 urlHost = strdup(rP->text);
00079
00080
00081
00082 strcpy(logDir, Config.ePath);
00083 logFN = logDir + strlen(Config.ePath);
00084 strcpy(logFN, rP->text);
00085 logFN = logFN + strlen(rP->text);
00086 *logFN++ = '/';
00087
00088
00089
00090 crtFN = crtURL + sprintf(crtURL, "root://%s/", urlHost);
00091
00092
00093
00094 sprintf(destBuff, "root://%s//tmp", urlHost);
00095 admURL = strdup(destBuff);
00096 Admin = 0;
00097
00098
00099
00100 arkOnly = Config.Opts & XrdCnsConfig::optNoCns;
00101 if (rP->val >= 0) {*arkURL = '\0'; arkFN = 0;}
00102 else {strcpy(arkURL, crtURL); arkPath = arkURL + strlen(crtURL);
00103 strcpy(arkPath,Config.bPath); strcat(arkPath, myName);
00104 arkFN = arkPath + strlen(arkPath); *arkFN++ = '/';
00105 if (!arkOnly) arkOnly= (rP == Config.bDest);
00106 MLog.Emsg("LogClient", "Server inventory at", arkURL);
00107 }
00108 }
00109
00110
00111
00112
00113
00114 int XrdCnsLogClient::Activate(XrdCnsLogFile *basefile)
00115 {
00116 XrdCnsLogFile *lfP;
00117
00118
00119
00120 sfxFN++;
00121 sprintf(logFN,"cns.log.%d.%010d", pfxNF, sfxFN);
00122
00123
00124
00125 if ((lfP = basefile->Subscribe(logDir, pfxNF)))
00126 {lfMutex.Lock();
00127 if (logLast) logLast->Next = lfP;
00128 else logFirst = lfP;
00129 logLast = lfP; lfSem.Post();
00130 lfMutex.UnLock();
00131 }
00132
00133
00134
00135 if (Next) return Next->Activate(basefile);
00136 return 1;
00137 }
00138
00139
00140
00141
00142
00143 int XrdCnsLogClient::Init()
00144 {
00145 static const int Mode = S_IRWXU | S_IRWXG | S_IROTH | S_IXOTH;
00146 XrdOucNSWalk::NSEnt *nInv = 0, *nFirst, *nsP;
00147 XrdCnsLogFile *fP;
00148 long long totsz = 0;
00149 int rc;
00150
00151
00152
00153 strcpy(logFN, XrdCnsLog::invFNa);
00154 unlink(logDir);
00155
00156
00157
00158 if ((rc = XrdOucUtils::makePath(logDir, Mode)))
00159 {MLog.Emsg("Init", rc, "create log path", logDir); return 0;}
00160
00161
00162
00163 *logFN = '\0';
00164 nFirst = XrdCnsLog::List(logDir, &nInv);
00165
00166
00167
00168 if (Config.Opts & XrdCnsConfig::optRecr)
00169 while((nsP = nFirst))
00170 {nFirst = nFirst->Next; delete nsP;}
00171
00172
00173
00174 if (nInv) {nInv->Next = nFirst; nFirst = nInv;
00175 nInv->Stat.st_nlink = 0;
00176 }
00177
00178
00179
00180 while((nsP = nFirst))
00181 {nFirst = nFirst->Next;
00182 MLog.Emsg("Init", "Recovered log file", nsP->Path);
00183 fP = new XrdCnsLogFile(nsP->Path, nsP->Stat.st_nlink, 0);
00184 if (logLast) logLast->Next = fP;
00185 else logFirst = fP;
00186 totsz += nsP->Stat.st_size;
00187 logLast = fP;
00188 delete nsP;
00189 }
00190
00191
00192
00193 if (totsz > 10*1024*1024)
00194 MLog.Emsg("Init", "Warning! More than 10MB of logs queued for", urlHost);
00195
00196
00197
00198 if (!(Config.Opts & XrdCnsConfig::optRecr)) return 1;
00199 if (!(rc = Run(0)))
00200 MLog.Emsg("LogClient", urlHost, "namespace recreation failed!");
00201 return rc;
00202 }
00203
00204
00205
00206
00207
00208 int XrdCnsLogClient::Run(int Always)
00209 {
00210 const char *TraceID = "ClientRun";
00211 XrdCnsLogFile *lfP = 0;
00212 XrdCnsLogRec *lrP;
00213 char invDir[MAXPATHLEN+1], *invFN = invDir;
00214 time_t mCheck = time(0) - 10;
00215 int n, Ok = 0;
00216
00217
00218
00219
00220 if (!Always && !arkFN && !Manifest()) return 0;
00221
00222
00223
00224
00225
00226 Admin = admConnect(Admin);
00227
00228 do{if (arkFN && time(0) >= mCheck)
00229 {if (!Manifest())
00230 {if (!Always) return 0;
00231 MLog.Emsg("LogClient","Unable to create inventory at",arkURL);
00232 }
00233 mCheck = time(0) + Config.mInt;
00234 }
00235
00236 do {lfMutex.Lock();
00237 if ((lfP = logFirst))
00238 {if (!(logFirst = lfP->Next)) logLast = 0; lfMutex.UnLock();}
00239 else {lfMutex.UnLock(); lfSem.Wait();}
00240 } while(!lfP);
00241
00242 if (lfP->Open())
00243 {while((lrP = lfP->getRec()))
00244 {if (arkOnly) continue;
00245 TRACE(DEBUG, urlHost <<" log data: '" <<lrP->Data() <<"'");
00246 switch (lrP->Type())
00247 {case XrdCnsLogRec::lrClosew: Ok = do_Trunc (lrP); break;
00248 case XrdCnsLogRec::lrCreate: Ok = do_Create(lrP); break;
00249 case XrdCnsLogRec::lrInvD: strcpy(invDir, lrP->Lfn1(n));
00250 invFN = invDir+n; Ok = 0;
00251 *invFN++ = '/';
00252 break;
00253 case XrdCnsLogRec::lrInvF: strcpy(invFN, lrP->Lfn1());
00254 if ((Ok = do_Create(lrP, invDir)))
00255 Ok = do_Trunc( lrP, invDir);
00256 break;
00257 case XrdCnsLogRec::lrMkdir: Ok = do_Mkdir (lrP); break;
00258 case XrdCnsLogRec::lrMv: Ok = do_Mv (lrP); break;
00259 case XrdCnsLogRec::lrRm: Ok = do_Rm (lrP); break;
00260 case XrdCnsLogRec::lrRmdir: Ok = do_Rmdir (lrP); break;
00261 case XrdCnsLogRec::lrMount:
00262 case XrdCnsLogRec::lrSpace:
00263 if (Config.Space)
00264 Config.Space->Add(lrP->Lfn1(),lrP->Space());
00265 break;
00266 case XrdCnsLogRec::lrTOD: break;
00267 default: MLog.Emsg("Run","Invalid logrec for",lrP->Lfn1());
00268 Ok = 0;
00269 }
00270 if (Ok) lfP->Commit();
00271 }
00272 if (!arkFN || Archive(lfP)) lfP->Unlink();
00273 delete lfP;
00274 }
00275 } while(Always);
00276
00277
00278
00279 return 1;
00280 }
00281
00282
00283
00284
00285
00286 namespace XrdCns
00287 {
00288 void *StartLogClient(void *parg)
00289 {
00290 XrdCnsLogClient *lcP = static_cast<XrdCnsLogClient *>(parg);
00291 lcP->Run();
00292 return (void *)0;
00293 }
00294 }
00295
00296 int XrdCnsLogClient::Start()
00297 {
00298 pthread_t tid;
00299 int rc;
00300
00301
00302
00303 if ((rc = XrdSysThread::Run(&tid, StartLogClient, (void *)this,
00304 XRDSYSTHREAD_BIND, "Log client")))
00305 {MLog.Emsg("Start", rc, "create log client thread");
00306 if (Next) Next->Start();
00307 return 0;
00308 }
00309
00310
00311
00312 if (Next) return Next->Start();
00313 return 1;
00314 }
00315
00316
00317
00318
00319
00320
00321
00322
00323 XrdClientAdmin *XrdCnsLogClient::admConnect(XrdClientAdmin *adminP)
00324 {
00325 const char *TraceID = "admConnect";
00326 static XrdSysMutex xcMutex;
00327
00328
00329
00330 if (adminP) delete adminP;
00331
00332
00333
00334 xcMutex.Lock();
00335 adminP = new XrdClientAdmin(admURL);
00336 xcMutex.UnLock();
00337
00338
00339
00340 do {TRACE(DEBUG, "Connecting to " <<urlHost);
00341 if (adminP->Connect()) break;
00342 xrdEmsg("connect", admURL, adminP);
00343 XrdSysTimer::Snooze(20);
00344 } while (1);
00345
00346
00347
00348 return adminP;
00349 }
00350
00351
00352
00353
00354
00355 int XrdCnsLogClient::Archive(XrdCnsLogFile *lfP)
00356 {
00357 static const int OMode = kXR_open_updt | kXR_delete | kXR_mkpath;
00358 static const int AMode = kXR_ur | kXR_uw | kXR_gr | kXR_gw | kXR_or;
00359 XrdClient *fP;
00360 int Blen, rc = 1;
00361 const char *lFN;
00362 char *oP, oldName[2048], *Buff = lfP->getLog(Blen);
00363
00364
00365
00366 if (!arkFN || !Blen) return 1;
00367
00368
00369
00370 if (!(lFN = rindex(lfP->FName(), '/')))
00371 {MLog.Emsg("LogClient", "Unable to determine archive log file name.");
00372 return 0;
00373 } else lFN++;
00374
00375
00376
00377 strcpy(arkFN, lFN);
00378 MLog.Emsg("Archive", "Creating backup", arkURL);
00379 *arkFN = '.';
00380 fP = new XrdClient(arkURL);
00381
00382
00383
00384 if (!fP->Open(AMode, OMode, 0) || (fP->LastServerResp()->status) != kXR_ok)
00385 xrdEmsg("archive", lfP->FName(), fP);
00386 else if (Buff && Blen && !fP->Write(Buff, 0, Blen))
00387 xrdEmsg("write", lfP->FName(), fP);
00388 else rc = 0;
00389
00390
00391
00392 delete fP;
00393 strcpy(oldName, arkURL); *arkFN = (*lFN == 'i' ? 'I' : *lFN);
00394 oP = oldName + (arkPath - arkURL);
00395 if (!Admin->Mv(oP, arkPath))
00396 {xrdEmsg("rename", oldName, Admin); Admin->Rm(oP); rc = 1;}
00397
00398 return rc == 0;
00399 }
00400
00401
00402
00403
00404
00405 int XrdCnsLogClient::do_Create(XrdCnsLogRec *lrP, const char *lfn)
00406 {
00407 static const int OMode = kXR_open_updt | kXR_delete | kXR_mkpath;
00408 XrdClient *fP;
00409 int AMode = kXR_ur | kXR_uw;
00410 int CMode, Ok = 1;
00411
00412
00413
00414 CMode = lrP->Mode();
00415 if (CMode & S_IRGRP) AMode |= kXR_gr;
00416 if (CMode & S_IWGRP) AMode |= kXR_gw;
00417 if (CMode & S_IROTH) AMode |= kXR_or;
00418
00419
00420
00421 if (!lfn) strcpy(crtFN, lrP->Lfn1());
00422 else {strcpy(crtFN, lfn);
00423 if (Config.Space)
00424 {char *spName = Config.Space->Key(lrP->Space());
00425 if (spName && strcmp(spName, "public"))
00426 {strcat(crtFN, "?oss.cgroup="); strcat(crtFN, spName);}
00427 }
00428 }
00429 fP = new XrdClient(crtURL);
00430
00431
00432
00433 if (!fP->Open(AMode, OMode, 0) || (fP->LastServerResp()->status) != kXR_ok)
00434 Ok = xrdEmsg("create", lrP->Lfn1(), fP);
00435
00436
00437
00438 delete fP;
00439 return Ok;
00440 }
00441
00442
00443
00444
00445
00446 int XrdCnsLogClient::do_Mkdir(XrdCnsLogRec *lrP)
00447 {
00448 if (!Admin->Mkdir(lrP->Lfn1(), 7, 7, 5))
00449 return xrdEmsg("mkdir", lrP->Lfn1());
00450 return 1;
00451 }
00452
00453
00454
00455
00456
00457 int XrdCnsLogClient::do_Mv(XrdCnsLogRec *lrP)
00458 {
00459 if (!Admin->Mv(lrP->Lfn1(), lrP->Lfn2()))
00460 return xrdEmsg("mv", lrP->Lfn1());
00461 return 1;
00462 }
00463
00464
00465
00466
00467
00468 int XrdCnsLogClient::do_Rm(XrdCnsLogRec *lrP)
00469 {
00470 if (!Admin->Rm(lrP->Lfn1())) return xrdEmsg("rm", lrP->Lfn1());
00471 return 1;
00472 }
00473
00474
00475
00476
00477
00478 int XrdCnsLogClient::do_Rmdir(XrdCnsLogRec *lrP)
00479 {
00480 if (!Admin->Rmdir(lrP->Lfn1())) return xrdEmsg("rmdir", lrP->Lfn1());
00481 return 1;
00482 }
00483
00484
00485
00486
00487
00488 int XrdCnsLogClient::do_Trunc(XrdCnsLogRec *lrP, const char *lfn)
00489 {
00490 if (!Admin->Truncate((lfn ? lfn : lrP->Lfn1()), lrP->Size()))
00491 return xrdEmsg("trunc", (lfn ? lfn : lrP->Lfn1()));
00492 return 1;
00493 }
00494
00495
00496
00497
00498
00499 int XrdCnsLogClient::Manifest()
00500 {
00501 const char *TraceID = "Manifest";
00502 XrdCnsInventory Inventory;
00503
00504 XrdCnsLogFile *lfP;
00505 XrdOucTList *xP;
00506 long long vSize;
00507 long V1, V2, V3;
00508 char oldName[MAXPATHLEN+1];
00509
00510
00511
00512 lfMutex.Lock();
00513 if (logFirst)
00514 {const char *fN = rindex(logFirst->FName(), '/');
00515 if (fN && !strcmp(XrdCnsLog::invFNz, fN+1))
00516 {lfMutex.UnLock(); return 1;}
00517 }
00518 lfMutex.UnLock();
00519
00520
00521
00522 if (arkFN)
00523 {strcpy(arkFN, XrdCnsLog::invFNz);
00524 if (Admin->Stat(arkPath, V1, vSize, V2, V3)) return 1;
00525 if (Admin->LastServerError()->errnum != kXR_NotFound)
00526 {xrdEmsg("find inventory", arkPath, Admin); return 0;}
00527 TRACE(DEBUG, "Creating inventory...");
00528 }
00529
00530
00531
00532 strcpy(logFN, XrdCnsLog::invFNa);
00533 lfP = new XrdCnsLogFile(logDir, 0, 0);
00534 if (!(lfP->Open(0))) {delete lfP; return 0;}
00535
00536
00537
00538 Inventory.Init(lfP);
00539
00540
00541
00542 xP = Config.Exports;
00543 while(xP && Inventory.Conduct(xP->text)) xP = xP->next;
00544 lfP->Eol(); delete lfP;
00545
00546
00547
00548 if (xP) {unlink(logDir); return 0;}
00549
00550
00551
00552 strcpy(oldName, logDir); strcpy(logFN, XrdCnsLog::invFNt);
00553 if (rename(oldName, logDir))
00554 {MLog.Emsg("Manifest", errno, "rename", oldName);
00555 unlink(logDir); return 0;
00556 }
00557
00558
00559
00560 lfP = new XrdCnsLogFile(logDir, 0, 0);
00561 lfMutex.Lock();
00562 lfP->Next = logFirst; logFirst = lfP;
00563 if (!logLast) logLast = lfP;
00564 lfMutex.UnLock();
00565
00566
00567
00568 return 1;
00569 }
00570
00571
00572
00573
00574
00575 int XrdCnsLogClient::mapError(int rc)
00576 {
00577 switch(rc)
00578 {case kXR_NotFound: return ENOENT;
00579 case kXR_NotAuthorized: return EACCES;
00580 case kXR_IOError: return EIO;
00581 case kXR_NoMemory: return ENOMEM;
00582 case kXR_NoSpace: return ENOSPC;
00583 case kXR_ArgTooLong: return ENAMETOOLONG;
00584 case kXR_noserver: return EHOSTUNREACH;
00585 case kXR_NotFile: return ENOTBLK;
00586 case kXR_isDirectory: return EISDIR;
00587 case kXR_FSError: return ENOSYS;
00588 default: return ECANCELED;
00589 }
00590 }
00591
00592
00593
00594
00595
00596 int XrdCnsLogClient::xrdEmsg(const char *Opname, const char *theFN,
00597 XrdClientAdmin *aP)
00598 {
00599 char *etext = aP->LastServerError()->errmsg;
00600 int rc=mapError(aP->LastServerError()->errnum);
00601
00602 if (rc == ECANCELED && etext && *etext) MLog.Emsg("LogClient", etext);
00603 else MLog.Emsg("LogClient", rc, Opname, theFN);
00604 return 0;
00605 }
00606
00607
00608
00609 int XrdCnsLogClient::xrdEmsg(const char *Opname, const char *theFN)
00610 {
00611 return xrdEmsg(Opname, theFN, Admin);
00612 }
00613
00614
00615
00616 int XrdCnsLogClient::xrdEmsg(const char *Opn, const char *Fn, XrdClient *fP)
00617 {
00618 char *etext = fP->LastServerError()->errmsg;
00619 int rc=mapError(fP->LastServerError()->errnum);
00620
00621 if (rc == ECANCELED && etext && *etext) MLog.Emsg("LogClient", etext);
00622 else MLog.Emsg("LogClient", rc, Opn, Fn);
00623 return 0;
00624 }