/******************************************************************************/ /* */ /* X r d C n s L o g S e r v e r . c c */ /* */ /* (c) 2009 by the Board of Trustees of the Leland Stanford, Jr., University */ /* All Rights Reserved */ /* Produced by Andrew Hanushevsky for Stanford University under contract */ /* DE-AC02-76-SFO0515 with the Department of Energy */ /* */ /* This file is part of the XRootD software suite. */ /* */ /* XRootD is free software: you can redistribute it and/or modify it under */ /* the terms of the GNU Lesser General Public License as published by the */ /* Free Software Foundation, either version 3 of the License, or (at your */ /* option) any later version. */ /* */ /* XRootD is distributed in the hope that it will be useful, but WITHOUT */ /* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or */ /* FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public */ /* License for more details. */ /* */ /* You should have received a copy of the GNU Lesser General Public License */ /* along with XRootD in a file called COPYING.LESSER (LGPL license) and file */ /* COPYING (GPL license). If not, see . */ /* */ /* The copyright holder's institutional names and contributor's names may not */ /* be used to endorse or promote products derived from this software without */ /* specific prior written permission of the institution or contributor. */ /******************************************************************************/ #include #include #include #include #include "Xrd/XrdTrace.hh" #include "XrdOss/XrdOssPath.hh" #include "XrdOuc/XrdOucTList.hh" #include "XrdCns/XrdCnsConfig.hh" #include "XrdCns/XrdCnsLogClient.hh" #include "XrdCns/XrdCnsLogFile.hh" #include "XrdCns/XrdCnsLogRec.hh" #include "XrdCns/XrdCnsLogServer.hh" #include "XrdSys/XrdSysError.hh" #include "XrdSys/XrdSysPthread.hh" /******************************************************************************/ /* G l o b a l O b j e c t s */ /******************************************************************************/ namespace XrdCns { extern XrdCnsConfig Config; extern XrdSysError MLog; extern XrdOucTrace XrdTrace; } using namespace XrdCns; /******************************************************************************/ /* T h r e a d I n t e r f a c e s */ /******************************************************************************/ namespace XrdCns { void *StartLogServer(void *parg) { XrdCnsLogServer *lsP = static_cast(parg); lsP->Run(); MLog.Emsg("Run", "Fatal log server error; terminating!"); _exit(8); return (void *)0; } } /******************************************************************************/ /* C o n s t r u c t o r */ /******************************************************************************/ XrdCnsLogServer::XrdCnsLogServer() { // Construct our logfile path // strcpy(logDir, Config.ePath); logFN = logDir + strlen(Config.ePath); } /******************************************************************************/ /* I n i t */ /******************************************************************************/ int XrdCnsLogServer::Init(XrdOucTList *rList) { struct stat Stat; pthread_t tid; int rc, aOK = 1; // First, inform the log file the maximum true records we will add // XrdCnsLogFile::maxRecs(Config.qLim); // If this is a command line recreate then just serially do the recreates // if (Config.Opts & XrdCnsConfig::optRecr) {while(rList) {Client = new XrdCnsLogClient(rList, 0); if (!Client->Init()) aOK = 0; delete Client; rList = rList->next; } return aOK; } // First see if we have a pending log file // strcpy(logFN, "cns.log"); if (stat(logDir, &Stat)) {if (errno != ENOENT) {MLog.Emsg("Init", errno, "stat file", logDir); return 0;} Stat.st_size = 0; } // If this is an empty log file, then remove it, otherwise end file it // if (Stat.st_size != 0) {XrdCnsLogFile myLogFile(logDir); if (!myLogFile.Open(0, Stat.st_size) || !myLogFile.Eol()) return 0; } unlink(logDir); // We now can create required log clients and initialize them // *logFN = '\0'; while(rList) {Client = new XrdCnsLogClient(rList, Client); if (!Client->Init()) {MLog.Emsg("Init", "Initialization for",rList->text,"failed."); aOK = 0; } rList = rList->next; } // Now activate a new log and start the clients // if (aOK) {strcpy(logFN, "cns.log"); logFile = new XrdCnsLogFile(logDir); if (!logFile->Open(0)) aOK = 0; else {if (!Client->Activate(logFile)) aOK = 0; else Client->Start(); } } // Now start the server // if ((rc = XrdSysThread::Run(&tid, StartLogServer, (void *)this, XRDSYSTHREAD_BIND, "Log server"))) {MLog.Emsg("Start", rc, "create log server thread"); aOK = 0;} // All done // return aOK; } /******************************************************************************/ /* Private M a s s a g e */ /******************************************************************************/ void XrdCnsLogServer::Massage(XrdCnsLogRec *lrP) { const char *cP; char lfnBuff[MAXPATHLEN+1], pfnBuff[MAXPATHLEN+1], lnkBuff[MAXPATHLEN+1]; char *cgiP, *mP; int lnkbsz = sizeof(lnkBuff); // Get the pfn for the lfn // strcpy(lfnBuff, lrP->Lfn1()); if ((cgiP = index(lfnBuff, '?'))) *cgiP = '\0'; if (!Config.LocalPath(lfnBuff, pfnBuff, sizeof(pfnBuff))) return; // Now get space information // cP = XrdOssPath::Extract(pfnBuff, lnkBuff, lnkbsz); // Check if we actually have a true mount point // if (lnkBuff[1]) mP = lnkBuff; else {Config.MountPath(lfnBuff, pfnBuff, sizeof(pfnBuff)); mP = pfnBuff; } // Set information in the create record // lrP->setData(cP, mP); } /******************************************************************************/ /* R u n */ /******************************************************************************/ void XrdCnsLogServer::Run() { static const char *TraceID = "ServerRun"; XrdCnsLogFile *lfP; XrdCnsLogRec *lrP; char lrT; int nRecs; // All we need to do is transfer log records from the queue to the log file // and periodically close out the log and start over. Timing marks are // periodically placed in the queue that cause a nil-pointer to be returned. // We honor them if we actually have something in the log file. In any case, // We must activate the new file before we close out the old file to make sure // log clients have a logfile that they can actually process. // do{nRecs = Config.qLim; lfP = logFile; while(nRecs && (lrP = XrdCnsLogRec::Get(lrT))) {if (lrP->Type() == XrdCnsLogRec::lrCreate) Massage(lrP); lfP->Add(lrP); lrP->Recycle(); nRecs--; } if (nRecs != Config.qLim) {TRACE(DEBUG, "Closing out " <<(Config.qLim-nRecs) <<" log records."); lfP->Eol(); if (!lfP->Unlink()) break; logFile = new XrdCnsLogFile(logDir); if (!logFile->Open() || !Client->Activate(logFile)) break; delete lfP; } } while(1); // At the moment we don't really have a recovery strategy // MLog.Emsg("Run", "Fatal error occurred; terminating. . ."); }