1 /**************************************************************************
2 * Copyright(c) 1998-1999, ALICE Experiment at CERN, All rights reserved. *
4 * Author: The ALICE Off-line Project. *
5 * Contributors are mentioned in the code where appropriate. *
7 * Permission to use, copy, modify and distribute this software and its *
8 * documentation strictly for non-commercial purposes is hereby granted *
9 * without fee, provided that the above copyright notice appears in all *
10 * copies and that both the copyright notice and this permission notice *
11 * appear in the supporting documentation. The authors make no claims *
12 * about the suitability of this software for any purpose. It is *
13 * provided "as is" without express or implied warranty. *
14 **************************************************************************/
18 Revision 1.34 2007/04/04 10:33:36 jgrosseo
19 1) Storing of files to the Grid is now done _after_ your preprocessors succeeded. This is transparent, which means that you can still use the same functions (Store, StoreReferenceData) to store files to the Grid. However, the Shuttle first stores them locally and transfers them after the preprocessor finished. The return code of these two functions has changed from UInt_t to Bool_t which gives you the success of the storing.
20 In case of an error with the Grid, the Shuttle will retry the storing later, the preprocessor does not need to be run again.
22 2) The meaning of the return code of the preprocessor has changed. 0 is now success and any other value means failure. This value is stored in the log and you can use it to keep details about the error condition.
24 3) New function StoreReferenceFile to _directly_ store a file (without opening it) to the reference storage.
26 4) The memory usage of the preprocessor is monitored. If it exceeds 2 GB it is terminated.
28 5) New function AliPreprocessor::ProcessDCS(). If you do not need to have DCS data in all cases, you can skip the processing by implemting this function and returning kFALSE under certain conditions. E.g. if there is a certain run type.
29 If you always need DCS data (like before), you do not need to implement it.
31 6) The run type has been added to the monitoring page
33 Revision 1.33 2007/04/03 13:56:01 acolla
34 Grid Storage at the end of preprocessing. Added virtual method to disable DCS query according to the
37 Revision 1.32 2007/02/28 10:41:56 acolla
38 Run type field added in SHUTTLE framework. Run type is read from "run type" logbook and retrieved by
39 AliPreprocessor::GetRunType() function.
40 Added some ldap definition files.
42 Revision 1.30 2007/02/13 11:23:21 acolla
43 Moved getters and setters of Shuttle's main OCDB/Reference, local
44 OCDB/Reference, temp and log folders to AliShuttleInterface
46 Revision 1.27 2007/01/30 17:52:42 jgrosseo
47 adding monalisa monitoring
49 Revision 1.26 2007/01/23 19:20:03 acolla
50 Removed old ldif files, added TOF, MCH ldif files. Added some options in
51 AliShuttleConfig::Print. Added in Ali Shuttle: SetShuttleTempDir and
54 Revision 1.25 2007/01/15 19:13:52 acolla
55 Moved some AliInfo to AliDebug in SendMail function
57 Revision 1.21 2006/12/07 08:51:26 jgrosseo
59 table, db names in ldap configuration
60 added GRP preprocessor
61 DCS data can also be retrieved by data point
63 Revision 1.20 2006/11/16 16:16:48 jgrosseo
64 introducing strict run ordering flag
65 removed giving preprocessor name to preprocessor, they have to know their name themselves ;-)
67 Revision 1.19 2006/11/06 14:23:04 jgrosseo
68 major update (Alberto)
69 o) reading of run parameters from the logbook
70 o) online offline naming conversion
71 o) standalone DCSclient package
73 Revision 1.18 2006/10/20 15:22:59 jgrosseo
74 o) Adding time out to the execution of the preprocessors: The Shuttle forks and the parent process monitors the child
75 o) Merging Collect, CollectAll, CollectNew function
76 o) Removing implementation of empty copy constructors (declaration still there!)
78 Revision 1.17 2006/10/05 16:20:55 jgrosseo
79 adapting to new CDB classes
81 Revision 1.16 2006/10/05 15:46:26 jgrosseo
82 applying to the new interface
84 Revision 1.15 2006/10/02 16:38:39 jgrosseo
87 storing of objects that failed to be stored to the grid before
88 interfacing of shuttle status table in daq system
90 Revision 1.14 2006/08/29 09:16:05 jgrosseo
93 Revision 1.13 2006/08/15 10:50:00 jgrosseo
94 effc++ corrections (alberto)
96 Revision 1.12 2006/08/08 14:19:29 jgrosseo
97 Update to shuttle classes (Alberto)
99 - Possibility to set the full object's path in the Preprocessor's and
100 Shuttle's Store functions
101 - Possibility to extend the object's run validity in the same classes
102 ("startValidity" and "validityInfinite" parameters)
103 - Implementation of the StoreReferenceData function to store reference
104 data in a dedicated CDB storage.
106 Revision 1.11 2006/07/21 07:37:20 jgrosseo
107 last run is stored after each run
109 Revision 1.10 2006/07/20 09:54:40 jgrosseo
110 introducing status management: The processing per subdetector is divided into several steps,
111 after each step the status is stored on disk. If the system crashes in any of the steps the Shuttle
112 can keep track of the number of failures and skips further processing after a certain threshold is
113 exceeded. These thresholds can be configured in LDAP.
115 Revision 1.9 2006/07/19 10:09:55 jgrosseo
116 new configuration, accesst to DAQ FES (Alberto)
118 Revision 1.8 2006/07/11 12:44:36 jgrosseo
119 adding parameters for extended validity range of data produced by preprocessor
121 Revision 1.7 2006/07/10 14:37:09 jgrosseo
122 small fix + todo comment
124 Revision 1.6 2006/07/10 13:01:41 jgrosseo
125 enhanced storing of last sucessfully processed run (alberto)
127 Revision 1.5 2006/07/04 14:59:57 jgrosseo
128 revision of AliDCSValue: Removed wrapper classes, reduced storage size per value by factor 2
130 Revision 1.4 2006/06/12 09:11:16 jgrosseo
131 coding conventions (Alberto)
133 Revision 1.3 2006/06/06 14:26:40 jgrosseo
134 o) removed files that were moved to STEER
135 o) shuttle updated to follow the new interface (Alberto)
137 Revision 1.2 2006/03/07 07:52:34 hristov
138 New version (B.Yordanov)
140 Revision 1.6 2005/11/19 17:19:14 byordano
141 RetrieveDATEEntries and RetrieveConditionsData added
143 Revision 1.5 2005/11/19 11:09:27 byordano
144 AliShuttle declaration added
146 Revision 1.4 2005/11/17 17:47:34 byordano
147 TList changed to TObjArray
149 Revision 1.3 2005/11/17 14:43:23 byordano
152 Revision 1.1.1.1 2005/10/28 07:33:58 hristov
153 Initial import as subdirectory in AliRoot
155 Revision 1.2 2005/09/13 08:41:15 byordano
156 default startTime endTime added
158 Revision 1.4 2005/08/30 09:13:02 byordano
161 Revision 1.3 2005/08/29 21:15:47 byordano
167 // This class is the main manager for AliShuttle.
168 // It organizes the data retrieval from DCS and call the
169 // interface methods of AliPreprocessor.
170 // For every detector in AliShuttleConfgi (see AliShuttleConfig),
171 // data for its set of aliases is retrieved. If there is registered
172 // AliPreprocessor for this detector then it will be used
173 // accroding to the schema (see AliPreprocessor).
174 // If there isn't registered AliPreprocessor than the retrieved
175 // data is stored automatically to the undelying AliCDBStorage.
176 // For detSpec is used the alias name.
179 #include "AliShuttle.h"
181 #include "AliCDBManager.h"
182 #include "AliCDBStorage.h"
183 #include "AliCDBId.h"
184 #include "AliCDBRunRange.h"
185 #include "AliCDBPath.h"
186 #include "AliCDBEntry.h"
187 #include "AliShuttleConfig.h"
188 #include "DCSClient/AliDCSClient.h"
190 #include "AliPreprocessor.h"
191 #include "AliShuttleStatus.h"
192 #include "AliShuttleLogbookEntry.h"
197 #include <TTimeStamp.h>
198 #include <TObjString.h>
199 #include <TSQLServer.h>
200 #include <TSQLResult.h>
203 #include <TSystemDirectory.h>
204 #include <TSystemFile.h>
205 #include <TFileMerger.h>
207 #include <TGridResult.h>
209 #include <TMonaLisaWriter.h>
213 #include <sys/types.h>
214 #include <sys/wait.h>
218 //______________________________________________________________________________________________
219 AliShuttle::AliShuttle(const AliShuttleConfig* config,
220 UInt_t timeout, Int_t retries):
222 fTimeout(timeout), fRetries(retries),
232 fReadTestMode(kFALSE)
235 // config: AliShuttleConfig used
236 // timeout: timeout used for AliDCSClient connection
237 // retries: the number of retries in case of connection error.
240 if (!fConfig->IsValid()) AliFatal("********** !!!!! Invalid configuration !!!!! **********");
241 for(int iSys=0;iSys<4;iSys++) {
244 fFXSlist[iSys].SetOwner(kTRUE);
246 fPreprocessorMap.SetOwner(kTRUE);
248 for (UInt_t iDet=0; iDet<NDetectors(); iDet++)
249 fFirstUnprocessed[iDet] = kFALSE;
251 fMonitoringMutex = new TMutex();
254 //______________________________________________________________________________________________
255 AliShuttle::~AliShuttle()
261 fPreprocessorMap.DeleteAll();
262 for(int iSys=0;iSys<4;iSys++)
264 fServer[iSys]->Close();
265 delete fServer[iSys];
274 if (fMonitoringMutex)
276 delete fMonitoringMutex;
277 fMonitoringMutex = 0;
281 //______________________________________________________________________________________________
282 void AliShuttle::RegisterPreprocessor(AliPreprocessor* preprocessor)
285 // Registers new AliPreprocessor.
286 // It uses GetName() for indentificator of the pre processor.
287 // The pre processor is registered it there isn't any other
288 // with the same identificator (GetName()).
291 const char* detName = preprocessor->GetName();
292 if(GetDetPos(detName) < 0)
293 AliFatal(Form("********** !!!!! Invalid detector name: %s !!!!! **********", detName));
295 if (fPreprocessorMap.GetValue(detName)) {
296 AliWarning(Form("AliPreprocessor %s is already registered!", detName));
300 fPreprocessorMap.Add(new TObjString(detName), preprocessor);
302 //______________________________________________________________________________________________
303 Bool_t AliShuttle::Store(const AliCDBPath& path, TObject* object,
304 AliCDBMetaData* metaData, Int_t validityStart, Bool_t validityInfinite)
306 // Stores a CDB object in the storage for offline reconstruction. Objects that are not needed for
307 // offline reconstruction, but should be stored anyway (e.g. for debugging) should NOT be stored
308 // using this function. Use StoreReferenceData instead!
309 // It calls StoreLocally function which temporarily stores the data locally; when the preprocessor
310 // finishes the data are transferred to the main storage (Grid).
312 return StoreLocally(fgkLocalCDB, path, object, metaData, validityStart, validityInfinite);
315 //______________________________________________________________________________________________
316 Bool_t AliShuttle::StoreReferenceData(const AliCDBPath& path, TObject* object, AliCDBMetaData* metaData)
318 // Stores a CDB object in the storage for reference data. This objects will not be available during
319 // offline reconstrunction. Use this function for reference data only!
320 // It calls StoreLocally function which temporarily stores the data locally; when the preprocessor
321 // finishes the data are transferred to the main storage (Grid).
323 return StoreLocally(fgkLocalRefStorage, path, object, metaData);
326 //______________________________________________________________________________________________
327 Bool_t AliShuttle::StoreLocally(const TString& localUri,
328 const AliCDBPath& path, TObject* object, AliCDBMetaData* metaData,
329 Int_t validityStart, Bool_t validityInfinite)
331 // Store object temporarily in local storage. Parameters are passed by Store and StoreReferenceData functions.
332 // when the preprocessor finishes the data are transferred to the main storage (Grid).
333 // The parameters are:
334 // 1) Uri of the backup storage (Local)
335 // 2) the object's path.
336 // 3) the object to be stored
337 // 4) the metaData to be associated with the object
338 // 5) the validity start run number w.r.t. the current run,
339 // if the data is valid only for this run leave the default 0
340 // 6) specifies if the calibration data is valid for infinity (this means until updated),
341 // typical for calibration runs, the default is kFALSE
343 // returns 0 if fail, 1 otherwise
345 if (fTestMode & kErrorStorage)
347 Log(fCurrentDetector, "StoreLocally - In TESTMODE - Simulating error while storing locally");
351 const char* cdbType = (localUri == fgkLocalCDB) ? "CDB" : "Reference";
353 Int_t firstRun = GetCurrentRun() - validityStart;
355 AliWarning("First valid run happens to be less than 0! Setting it to 0.");
360 if(validityInfinite) {
361 lastRun = AliCDBRunRange::Infinity();
363 lastRun = GetCurrentRun();
366 // Version is set to current run, it will be used later to transfer data to Grid
367 AliCDBId id(path, firstRun, lastRun, GetCurrentRun(), -1);
369 if(! dynamic_cast<TObjString*> (metaData->GetProperty("RunUsed(TObjString)"))){
370 TObjString runUsed = Form("%d", GetCurrentRun());
371 metaData->SetProperty("RunUsed(TObjString)", runUsed.Clone());
374 Bool_t result = kFALSE;
376 if (!(AliCDBManager::Instance()->GetStorage(localUri))) {
377 Log("SHUTTLE", Form("StoreLocally - Cannot activate local %s storage", cdbType));
379 result = AliCDBManager::Instance()->GetStorage(localUri)
380 ->Put(object, id, metaData);
385 Log(fCurrentDetector, Form("StoreLocally - Can't store object <%s>!", id.ToString().Data()));
391 //______________________________________________________________________________________________
392 Bool_t AliShuttle::StoreOCDB()
395 // Called when preprocessor ends successfully or when previous storage attempt failed (kStoreError status)
396 // Calls underlying StoreOCDB(const char*) function twice, for OCDB and Reference storage.
397 // Then calls StoreRefFilesToGrid to store reference files.
400 if (fTestMode & kErrorGrid)
402 Log("SHUTTLE", "StoreOCDB - In TESTMODE - Simulating error while storing in the Grid");
403 Log(fCurrentDetector, "StoreOCDB - In TESTMODE - Simulating error while storing in the Grid");
407 AliInfo("Storing OCDB data ...");
408 Bool_t resultCDB = StoreOCDB(fgkMainCDB);
410 AliInfo("Storing reference data ...");
411 Bool_t resultRef = StoreOCDB(fgkMainRefStorage);
413 AliInfo("Storing reference files ...");
414 Bool_t resultRefFiles = StoreRefFilesToGrid();
416 return resultCDB && resultRef && resultRefFiles;
419 //______________________________________________________________________________________________
420 Bool_t AliShuttle::StoreOCDB(const TString& gridURI)
423 // Called by StoreOCDB(), performs actual storage to the main OCDB and reference storages (Grid)
426 TObjArray* gridIds=0;
428 Bool_t result = kTRUE;
430 const char* type = 0;
432 if(gridURI == fgkMainCDB) {
434 localURI = fgkLocalCDB;
435 } else if(gridURI == fgkMainRefStorage) {
437 localURI = fgkLocalRefStorage;
439 AliError(Form("Invalid storage URI: %s", gridURI.Data()));
443 AliCDBManager* man = AliCDBManager::Instance();
445 AliCDBStorage *gridSto = man->GetStorage(gridURI);
448 Form("StoreOCDB - cannot activate main %s storage", type));
452 gridIds = gridSto->GetQueryCDBList();
454 // get objects previously stored in local CDB
455 AliCDBStorage *localSto = man->GetStorage(localURI);
458 Form("StoreOCDB - cannot activate local %s storage", type));
461 AliCDBPath aPath(GetOfflineDetName(fCurrentDetector.Data()),"*","*");
462 // Local objects were stored with current run as Grid version!
463 TList* localEntries = localSto->GetAll(aPath.GetPath(), GetCurrentRun(), GetCurrentRun());
464 localEntries->SetOwner(1);
466 // loop on local stored objects
467 TIter localIter(localEntries);
468 AliCDBEntry *aLocEntry = 0;
469 while((aLocEntry = dynamic_cast<AliCDBEntry*> (localIter.Next()))){
470 aLocEntry->SetOwner(1);
471 AliCDBId aLocId = aLocEntry->GetId();
472 aLocEntry->SetVersion(-1);
473 aLocEntry->SetSubVersion(-1);
475 // If local object is valid up to infinity we store it only if it is
476 // the first unprocessed run!
477 if (aLocId.GetLastRun() == AliCDBRunRange::Infinity() &&
478 !fFirstUnprocessed[GetDetPos(fCurrentDetector)])
480 Log("SHUTTLE", Form("StoreOCDB - %s: object %s has validity infinite but "
481 "there are previous unprocessed runs!",
482 fCurrentDetector.Data(), aLocId.GetPath().Data()));
486 // loop on Grid valid Id's
487 Bool_t store = kTRUE;
488 TIter gridIter(gridIds);
489 AliCDBId* aGridId = 0;
490 while((aGridId = dynamic_cast<AliCDBId*> (gridIter.Next()))){
491 if(aGridId->GetPath() != aLocId.GetPath()) continue;
492 // skip all objects valid up to infinity
493 if(aGridId->GetLastRun() == AliCDBRunRange::Infinity()) continue;
494 // if we get here, it means there's already some more recent object stored on Grid!
499 // If we get here, the file can be stored!
500 Bool_t storeOk = gridSto->Put(aLocEntry);
501 if(!store || storeOk){
505 Log(fCurrentDetector.Data(),
506 Form("StoreOCDB - A more recent object already exists in %s storage: <%s>",
507 type, aGridId->ToString().Data()));
510 Form("StoreOCDB - Object <%s> successfully put into %s storage",
511 aLocId.ToString().Data(), type));
514 // removing local filename...
516 localSto->IdToFilename(aLocId, filename);
517 AliInfo(Form("Removing local file %s", filename.Data()));
518 RemoveFile(filename.Data());
522 Form("StoreOCDB - Grid %s storage of object <%s> failed",
523 type, aLocId.ToString().Data()));
527 localEntries->Clear();
532 //______________________________________________________________________________________________
533 Bool_t AliShuttle::StoreReferenceFile(const char* detector, const char* localFile, const char* gridFileName)
536 // Stores reference file directly (without opening it). This function stores the file locally
537 // renaming it to #runNumber_gridFileName.
540 if (fTestMode & kErrorStorage)
542 Log(fCurrentDetector, "StoreReferenceFile - In TESTMODE - Simulating error while storing locally");
546 AliCDBManager* man = AliCDBManager::Instance();
547 AliCDBStorage* sto = man->GetStorage(fgkLocalRefStorage);
549 TString localBaseFolder = sto->GetBaseFolder();
552 targetDir.Form("%s/%s", localBaseFolder.Data(), detector);
555 target.Form("%s/%d_%s", targetDir.Data(), GetCurrentRun(), gridFileName);
557 Int_t result = gSystem->GetPathInfo(targetDir, 0, (Long64_t*) 0, 0, 0);
560 result = gSystem->mkdir(targetDir, kTRUE);
563 Log("SHUTTLE", Form("StoreReferenceFile - Error creating base directory %s", targetDir.Data()));
568 result = gSystem->CopyFile(localFile, target);
572 Log("SHUTTLE", Form("StoreReferenceFile - Stored file %s locally to %s", localFile, target.Data()));
577 Log("SHUTTLE", Form("StoreReferenceFile - Storing file %s locally to %s failed", localFile, target.Data()));
582 //______________________________________________________________________________________________
583 Bool_t AliShuttle::StoreRefFilesToGrid()
586 // Transfers the reference file to the Grid.
587 // The final full path of the file is:
588 // gridBaseReferenceFolder/DET/#runNumber_gridFileName
591 AliCDBManager* man = AliCDBManager::Instance();
592 AliCDBStorage* sto = man->GetStorage(fgkLocalRefStorage);
595 TString localBaseFolder = sto->GetBaseFolder();
598 dir.Form("%s/%s", localBaseFolder.Data(), fCurrentDetector.Data());
600 AliCDBStorage* gridSto = man->GetStorage(fgkMainRefStorage);
603 TString gridBaseFolder = gridSto->GetBaseFolder();
605 alienDir.Form("%s%s", gridBaseFolder.Data(), fCurrentDetector.Data());
610 // check that DET folder exists, otherwise create it
611 TGridResult* result = gGrid->Ls(alienDir.Data());
616 if(!result->GetFileName(0)) {
617 if(!gGrid->Mkdir(alienDir.Data(),"",0)){
618 Log("SHUTTLE", Form("StoreRefFilesToGrid - Cannot create directory %s",
626 begin.Form("%d_", GetCurrentRun());
628 TSystemDirectory* baseDir = new TSystemDirectory("/", dir);
629 TList* dirList = baseDir->GetListOfFiles();
633 Int_t nDirs = dirList->GetEntries();
635 Bool_t success = kTRUE;
637 for (Int_t iDir=0; iDir<nDirs; ++iDir)
639 TSystemFile* entry = dynamic_cast<TSystemFile*> (dirList->At(iDir));
643 if (entry->IsDirectory())
646 TString fileName(entry->GetName());
647 if (!fileName.BeginsWith(begin))
650 TString fullLocalPath;
651 fullLocalPath.Form("%s/%s", dir.Data(), fileName.Data());
653 TString fullGridPath;
654 fullGridPath.Form("alien://%s/%s", alienDir.Data(), fileName.Data());
656 Log("SHUTTLE", Form("StoreRefFilesToGrid - Copying local file %s to %s", fullLocalPath.Data(), fullGridPath.Data()));
658 TFileMerger fileMerger;
659 Bool_t result = fileMerger.Cp(fullLocalPath, fullGridPath);
663 Log("SHUTTLE", Form("StoreRefFilesToGrid - Copying local file %s to %s succeeded", fullLocalPath.Data(), fullGridPath.Data()));
664 RemoveFile(fullLocalPath);
668 Log("SHUTTLE", Form("StoreRefFilesToGrid - Copying local file %s to %s failed", fullLocalPath.Data(), fullGridPath.Data()));
678 //______________________________________________________________________________________________
679 void AliShuttle::CleanLocalStorage(const TString& uri)
682 // Called in case the preprocessor is declared failed. Remove remaining objects from the local storages.
685 const char* type = 0;
686 if(uri == fgkLocalCDB) {
688 } else if(uri == fgkLocalRefStorage) {
691 AliError(Form("Invalid storage URI: %s", uri.Data()));
695 AliCDBManager* man = AliCDBManager::Instance();
697 // open local storage
698 AliCDBStorage *localSto = man->GetStorage(uri);
701 Form("CleanLocalStorage - cannot activate local %s storage", type));
705 TString filename(Form("%s/%s/*/Run*_v%d_s*.root",
706 localSto->GetBaseFolder().Data(), fCurrentDetector.Data(), GetCurrentRun()));
708 AliInfo(Form("filename = %s", filename.Data()));
710 AliInfo(Form("Removing remaining local files from run %d and detector %s ...",
711 GetCurrentRun(), fCurrentDetector.Data()));
713 RemoveFile(filename.Data());
717 //______________________________________________________________________________________________
718 void AliShuttle::RemoveFile(const char* filename)
721 // removes local file
724 TString command(Form("rm -f %s", filename));
726 Int_t result = gSystem->Exec(command.Data());
729 Log("SHUTTLE", Form("RemoveFile - %s: Cannot remove file %s!",
730 fCurrentDetector.Data(), filename));
734 //______________________________________________________________________________________________
735 AliShuttleStatus* AliShuttle::ReadShuttleStatus()
738 // Reads the AliShuttleStatus from the CDB
746 fStatusEntry = AliCDBManager::Instance()->GetStorage(GetLocalCDB())
747 ->Get(Form("/SHUTTLE/STATUS/%s", fCurrentDetector.Data()), GetCurrentRun());
749 if (!fStatusEntry) return 0;
750 fStatusEntry->SetOwner(1);
752 AliShuttleStatus* status = dynamic_cast<AliShuttleStatus*> (fStatusEntry->GetObject());
754 AliError("Invalid object stored to CDB!");
761 //______________________________________________________________________________________________
762 Bool_t AliShuttle::WriteShuttleStatus(AliShuttleStatus* status)
765 // writes the status for one subdetector
773 Int_t run = GetCurrentRun();
775 AliCDBId id(AliCDBPath("SHUTTLE", "STATUS", fCurrentDetector), run, run);
777 fStatusEntry = new AliCDBEntry(status, id, new AliCDBMetaData);
778 fStatusEntry->SetOwner(1);
780 UInt_t result = AliCDBManager::Instance()->GetStorage(fgkLocalCDB)->Put(fStatusEntry);
783 Log("SHUTTLE", Form("WriteShuttleStatus - Failed for %s, run %d",
784 fCurrentDetector.Data(), run));
793 //______________________________________________________________________________________________
794 void AliShuttle::UpdateShuttleStatus(AliShuttleStatus::Status newStatus, Bool_t increaseCount)
797 // changes the AliShuttleStatus for the given detector and run to the given status
801 AliError("UNEXPECTED: fStatusEntry empty");
805 AliShuttleStatus* status = dynamic_cast<AliShuttleStatus*> (fStatusEntry->GetObject());
808 Log("SHUTTLE", "UNEXPECTED: status could not be read from current CDB entry");
812 TString actionStr = Form("UpdateShuttleStatus - %s: Changing state from %s to %s",
813 fCurrentDetector.Data(),
814 status->GetStatusName(),
815 status->GetStatusName(newStatus));
816 Log("SHUTTLE", actionStr);
817 SetLastAction(actionStr);
819 status->SetStatus(newStatus);
820 if (increaseCount) status->IncreaseCount();
822 AliCDBManager::Instance()->GetStorage(fgkLocalCDB)->Put(fStatusEntry);
827 //______________________________________________________________________________________________
828 void AliShuttle::SendMLInfo()
831 // sends ML information about the current status of the current detector being processed
834 AliShuttleStatus* status = dynamic_cast<AliShuttleStatus*> (fStatusEntry->GetObject());
837 Log("SHUTTLE", "SendMLInfo - UNEXPECTED: status could not be read from current CDB entry");
841 TMonaLisaText mlStatus(Form("%s_status", fCurrentDetector.Data()), status->GetStatusName());
842 TMonaLisaValue mlRetryCount(Form("%s_count", fCurrentDetector.Data()), status->GetCount());
845 mlList.Add(&mlStatus);
846 mlList.Add(&mlRetryCount);
848 fMonaLisa->SendParameters(&mlList);
851 //______________________________________________________________________________________________
852 Bool_t AliShuttle::ContinueProcessing()
854 // this function reads the AliShuttleStatus information from CDB and
855 // checks if the processing should be continued
856 // if yes it returns kTRUE and updates the AliShuttleStatus with nextStatus
858 if (!fConfig->HostProcessDetector(fCurrentDetector)) return kFALSE;
860 AliPreprocessor* aPreprocessor =
861 dynamic_cast<AliPreprocessor*> (fPreprocessorMap.GetValue(fCurrentDetector));
864 AliInfo(Form("%s: no preprocessor registered", fCurrentDetector.Data()));
868 AliShuttleLogbookEntry::Status entryStatus =
869 fLogbookEntry->GetDetectorStatus(fCurrentDetector);
871 if(entryStatus != AliShuttleLogbookEntry::kUnprocessed) {
872 AliInfo(Form("ContinueProcessing - %s is %s",
873 fCurrentDetector.Data(),
874 fLogbookEntry->GetDetectorStatusName(entryStatus)));
878 // if we get here, according to Shuttle logbook subdetector is in UNPROCESSED state
880 // check if current run is first unprocessed run for current detector
881 if (fConfig->StrictRunOrder(fCurrentDetector) &&
882 !fFirstUnprocessed[GetDetPos(fCurrentDetector)])
884 Log("SHUTTLE", Form("ContinueProcessing - %s requires strict run ordering but this is not the first unprocessed run!"));
888 AliShuttleStatus* status = ReadShuttleStatus();
891 Log("SHUTTLE", Form("ContinueProcessing - %s: Processing first time",
892 fCurrentDetector.Data()));
893 status = new AliShuttleStatus(AliShuttleStatus::kStarted);
894 return WriteShuttleStatus(status);
897 // The following two cases shouldn't happen if Shuttle Logbook was correctly updated.
898 // If it happens it may mean Logbook updating failed... let's do it now!
899 if (status->GetStatus() == AliShuttleStatus::kDone ||
900 status->GetStatus() == AliShuttleStatus::kFailed){
901 Log("SHUTTLE", Form("ContinueProcessing - %s is already %s. Updating Shuttle Logbook",
902 fCurrentDetector.Data(),
903 status->GetStatusName(status->GetStatus())));
904 UpdateShuttleLogbook(fCurrentDetector.Data(),
905 status->GetStatusName(status->GetStatus()));
909 if (status->GetStatus() == AliShuttleStatus::kStoreError) {
911 Form("ContinueProcessing - %s: Grid storage of one or more objects failed. Trying again now",
912 fCurrentDetector.Data()));
913 UpdateShuttleStatus(AliShuttleStatus::kStoreStarted);
915 Log("SHUTTLE", Form("ContinueProcessing - %s: all objects successfully stored into main storage",
916 fCurrentDetector.Data()));
917 UpdateShuttleStatus(AliShuttleStatus::kDone);
918 UpdateShuttleLogbook(fCurrentDetector.Data(), "DONE");
921 Form("ContinueProcessing - %s: Grid storage failed again",
922 fCurrentDetector.Data()));
923 UpdateShuttleStatus(AliShuttleStatus::kStoreError);
928 // if we get here, there is a restart
929 Bool_t cont = kFALSE;
932 if (status->GetCount() >= fConfig->GetMaxRetries()) {
933 Log("SHUTTLE", Form("ContinueProcessing - %s failed %d times in status %s - "
934 "Updating Shuttle Logbook", fCurrentDetector.Data(),
935 status->GetCount(), status->GetStatusName()));
936 UpdateShuttleLogbook(fCurrentDetector.Data(), "FAILED");
937 UpdateShuttleStatus(AliShuttleStatus::kFailed);
939 // there may still be objects in local OCDB and reference storage
940 // and FXS databases may be not updated: do it now!
942 // TODO Currently disabled, we want to keep files in case of failure!
943 // CleanLocalStorage(fgkLocalCDB);
944 // CleanLocalStorage(fgkLocalRefStorage);
945 // UpdateTableFailCase();
947 // Send mail to detector expert!
948 AliInfo(Form("Sending mail to %s expert...", fCurrentDetector.Data()));
950 Log("SHUTTLE", Form("ContinueProcessing - Could not send mail to %s expert",
951 fCurrentDetector.Data()));
954 Log("SHUTTLE", Form("ContinueProcessing - %s: restarting. "
955 "Aborted before with %s. Retry number %d.", fCurrentDetector.Data(),
956 status->GetStatusName(), status->GetCount()));
957 Bool_t increaseCount = kTRUE;
958 if (status->GetStatus() == AliShuttleStatus::kDCSError || status->GetStatus() == AliShuttleStatus::kDCSStarted)
959 increaseCount = kFALSE;
960 UpdateShuttleStatus(AliShuttleStatus::kStarted, increaseCount);
967 //______________________________________________________________________________________________
968 Bool_t AliShuttle::Process(AliShuttleLogbookEntry* entry)
971 // Makes data retrieval for all detectors in the configuration.
972 // entry: Shuttle logbook entry, contains run paramenters and status of detectors
973 // (Unprocessed, Inactive, Failed or Done).
974 // Returns kFALSE in case of error occured and kTRUE otherwise
977 if (!entry) return kFALSE;
979 fLogbookEntry = entry;
981 AliInfo(Form("\n\n \t\t\t^*^*^*^*^*^*^*^*^*^*^*^* run %d: START ^*^*^*^*^*^*^*^*^*^*^*^* \n",
984 // create ML instance that monitors this run
985 fMonaLisa = new TMonaLisaWriter(Form("%d", GetCurrentRun()), "SHUTTLE", "aliendb1.cern.ch");
986 // disable monitoring of other parameters that come e.g. from TFile
987 gMonitoringWriter = 0;
989 // Send the information to ML
990 TMonaLisaText mlStatus("SHUTTLE_status", "Processing");
991 TMonaLisaText mlRunType("SHUTTLE_runtype", Form("%s (%s)", entry->GetRunType(), entry->GetRunParameter("log")));
994 mlList.Add(&mlStatus);
995 mlList.Add(&mlRunType);
997 fMonaLisa->SendParameters(&mlList);
999 if (fLogbookEntry->IsDone())
1001 Log("SHUTTLE","Process - Shuttle is already DONE. Updating logbook");
1002 UpdateShuttleLogbook("shuttle_done");
1007 // read test mode if flag is set
1010 TString logEntry(entry->GetRunParameter("log"));
1011 //printf("log entry = %s\n", logEntry.Data());
1012 TString searchStr("Testmode: ");
1013 Int_t pos = logEntry.Index(searchStr.Data());
1014 //printf("%d\n", pos);
1017 TSubString subStr = logEntry(pos + searchStr.Length(), logEntry.Length());
1018 //printf("%s\n", subStr.String().Data());
1019 TString newStr(subStr.Data());
1020 TObjArray* token = newStr.Tokenize(' ');
1024 TObjString* tmpStr = dynamic_cast<TObjString*> (token->First());
1027 Int_t testMode = tmpStr->String().Atoi();
1030 Log("SHUTTLE", Form("Enabling test mode %d", testMode));
1031 SetTestMode((TestMode) testMode);
1039 fLogbookEntry->Print("all");
1042 Bool_t hasError = kFALSE;
1044 AliCDBStorage *mainCDBSto = AliCDBManager::Instance()->GetStorage(fgkMainCDB);
1045 if(mainCDBSto) mainCDBSto->QueryCDB(GetCurrentRun());
1046 AliCDBStorage *mainRefSto = AliCDBManager::Instance()->GetStorage(fgkMainRefStorage);
1047 if(mainRefSto) mainRefSto->QueryCDB(GetCurrentRun());
1049 // Loop on detectors in the configuration
1050 TIter iter(fConfig->GetDetectors());
1051 TObjString* aDetector = 0;
1053 while ((aDetector = (TObjString*) iter.Next()))
1055 fCurrentDetector = aDetector->String();
1057 if (ContinueProcessing() == kFALSE) continue;
1059 AliInfo(Form("\n\n \t\t\t****** run %d - %s: START ******",
1060 GetCurrentRun(), aDetector->GetName()));
1062 for(Int_t iSys=0;iSys<3;iSys++) fFXSCalled[iSys]=kFALSE;
1064 Log(fCurrentDetector.Data(), "Starting processing");
1070 Log("SHUTTLE", "ERROR: Forking failed");
1075 AliInfo(Form("In parent process of %d - %s: Starting monitoring",
1076 GetCurrentRun(), aDetector->GetName()));
1078 Long_t begin = time(0);
1080 int status; // to be used with waitpid, on purpose an int (not Int_t)!
1081 while (waitpid(pid, &status, WNOHANG) == 0)
1083 Long_t expiredTime = time(0) - begin;
1085 if (expiredTime > fConfig->GetPPTimeOut())
1088 tmp.Form("Process of %s time out. Run time: %d seconds. Killing...",
1089 fCurrentDetector.Data(), expiredTime);
1090 Log("SHUTTLE", tmp);
1091 Log(fCurrentDetector, tmp);
1095 UpdateShuttleStatus(AliShuttleStatus::kPPTimeOut);
1098 gSystem->Sleep(1000);
1102 gSystem->Sleep(1000);
1105 checkStr.Form("ps -o vsize --pid %d | tail -n 1", pid);
1106 FILE* pipe = gSystem->OpenPipe(checkStr, "r");
1109 Log("SHUTTLE", Form("Error: Could not open pipe to %s", checkStr.Data()));
1114 if (!fgets(buffer, 100, pipe))
1116 Log("SHUTTLE", "Error: ps did not return anything");
1117 gSystem->ClosePipe(pipe);
1120 gSystem->ClosePipe(pipe);
1122 //Log("SHUTTLE", Form("ps returned %s", buffer));
1125 if ((sscanf(buffer, "%d\n", &mem) != 1) || !mem)
1127 Log("SHUTTLE", "Error: Could not parse output of ps");
1131 if (expiredTime % 60 == 0)
1132 Log("SHUTTLE", Form("%s: Checking process. Run time: %d seconds - Memory consumption: %d KB",
1133 fCurrentDetector.Data(), expiredTime, mem));
1135 if (mem > fConfig->GetPPMaxMem())
1138 tmp.Form("Process exceeds maximum allowed memory (%d KB > %d KB). Killing...",
1139 mem, fConfig->GetPPMaxMem());
1140 Log("SHUTTLE", tmp);
1141 Log(fCurrentDetector, tmp);
1145 UpdateShuttleStatus(AliShuttleStatus::kPPOutOfMemory);
1148 gSystem->Sleep(1000);
1153 AliInfo(Form("In parent process of %d - %s: Client has terminated.",
1154 GetCurrentRun(), aDetector->GetName()));
1156 if (WIFEXITED(status))
1158 Int_t returnCode = WEXITSTATUS(status);
1160 Log("SHUTTLE", Form("%s: the return code is %d", fCurrentDetector.Data(),
1163 if (returnCode == 0) hasError = kTRUE;
1169 AliInfo(Form("In client process of %d - %s", GetCurrentRun(), aDetector->GetName()));
1171 Bool_t success = ProcessCurrentDetector();
1172 if (success) // Preprocessor finished successfully!
1174 // Update time_processed field in FXS DB
1175 if (UpdateTable() == kFALSE)
1176 Log("SHUTTLE", Form("Process - %s: Could not update FXS databases!"));
1178 // Transfer the data from local storage to main storage (Grid)
1179 UpdateShuttleStatus(AliShuttleStatus::kStoreStarted);
1180 if (StoreOCDB() == kFALSE)
1182 AliInfo(Form("\n \t\t\t****** run %d - %s: STORAGE ERROR ****** \n\n",
1183 GetCurrentRun(), aDetector->GetName()));
1184 UpdateShuttleStatus(AliShuttleStatus::kStoreError);
1187 AliInfo(Form("\n \t\t\t****** run %d - %s: DONE ****** \n\n",
1188 GetCurrentRun(), aDetector->GetName()));
1189 UpdateShuttleStatus(AliShuttleStatus::kDone);
1190 UpdateShuttleLogbook(fCurrentDetector, "DONE");
1194 for (UInt_t iSys=0; iSys<3; iSys++)
1196 if (fFXSCalled[iSys]) fFXSlist[iSys].Clear();
1199 AliInfo(Form("Client process of %d - %s is exiting now with %d.",
1200 GetCurrentRun(), aDetector->GetName(), success));
1202 // the client exits here
1203 gSystem->Exit(success);
1205 AliError("We should never get here!!!");
1209 AliInfo(Form("\n\n \t\t\t^*^*^*^*^*^*^*^*^*^*^*^* run %d: FINISH ^*^*^*^*^*^*^*^*^*^*^*^* \n",
1212 //check if shuttle is done for this run, if so update logbook
1213 TObjArray checkEntryArray;
1214 checkEntryArray.SetOwner(1);
1215 TString whereClause = Form("where run=%d", GetCurrentRun());
1216 if (!QueryShuttleLogbook(whereClause.Data(), checkEntryArray) || checkEntryArray.GetEntries() == 0) {
1217 Log("SHUTTLE", Form("Process - Warning: Cannot check status of run %d on Shuttle logbook!",
1219 return hasError == kFALSE;
1222 AliShuttleLogbookEntry* checkEntry = dynamic_cast<AliShuttleLogbookEntry*>
1223 (checkEntryArray.At(0));
1227 if (checkEntry->IsDone())
1229 Log("SHUTTLE","Process - Shuttle is DONE. Updating logbook");
1230 UpdateShuttleLogbook("shuttle_done");
1234 for (UInt_t iDet=0; iDet<NDetectors(); iDet++)
1236 if (checkEntry->GetDetectorStatus(iDet) == AliShuttleLogbookEntry::kUnprocessed)
1238 AliDebug(2, Form("Run %d: setting %s as \"not first time unprocessed\"",
1239 checkEntry->GetRun(), GetDetName(iDet)));
1240 fFirstUnprocessed[iDet] = kFALSE;
1246 // remove ML instance
1252 return hasError == kFALSE;
1255 //______________________________________________________________________________________________
1256 Bool_t AliShuttle::ProcessCurrentDetector()
1259 // Makes data retrieval just for a specific detector (fCurrentDetector).
1260 // Threre should be a configuration for this detector.
1262 AliInfo(Form("Retrieving values for %s, run %d", fCurrentDetector.Data(), GetCurrentRun()));
1267 Bool_t aDCSError = kFALSE;
1269 // call preprocessor
1270 AliPreprocessor* aPreprocessor =
1271 dynamic_cast<AliPreprocessor*> (fPreprocessorMap.GetValue(fCurrentDetector));
1273 aPreprocessor->Initialize(GetCurrentRun(), GetCurrentStartTime(), GetCurrentEndTime());
1275 Bool_t processDCS = aPreprocessor->ProcessDCS();
1277 if (!processDCS || fTestMode & kSkipDCS)
1279 AliInfo("In TESTMODE - Skipping DCS processing!");
1281 else if (fTestMode & kErrorDCS)
1283 AliInfo("In TESTMODE - Simulating DCS error");
1284 UpdateShuttleStatus(AliShuttleStatus::kDCSError);
1288 UpdateShuttleStatus(AliShuttleStatus::kDCSStarted);
1290 TString host(fConfig->GetDCSHost(fCurrentDetector));
1291 Int_t port = fConfig->GetDCSPort(fCurrentDetector);
1293 // Retrieval of Aliases
1294 TObjString* anAlias = 0;
1296 Int_t nTotAliases= ((TMap*)fConfig->GetDCSAliases(fCurrentDetector))->GetEntries();
1297 TIter iterAliases(fConfig->GetDCSAliases(fCurrentDetector));
1298 while ((anAlias = (TObjString*) iterAliases.Next()))
1300 TObjArray *valueSet = new TObjArray();
1301 valueSet->SetOwner(1);
1303 if (((iAlias-1) % 500) == 0 || iAlias == nTotAliases)
1304 AliInfo(Form("Querying DCS archive: alias %s (%d of %d)",
1305 anAlias->GetName(), iAlias++, nTotAliases));
1306 aDCSError = (GetValueSet(host, port, anAlias->String(), valueSet, kAlias) == 0);
1310 dcsMap.Add(anAlias->Clone(), valueSet);
1312 Log(fCurrentDetector,
1313 Form("ProcessCurrentDetector - Error while retrieving alias %s",
1314 anAlias->GetName()));
1315 UpdateShuttleStatus(AliShuttleStatus::kDCSError);
1321 // Retrieval of Data Points
1322 TObjString* aDP = 0;
1324 Int_t nTotDPs= ((TMap*)fConfig->GetDCSDataPoints(fCurrentDetector))->GetEntries();
1325 TIter iterDP(fConfig->GetDCSDataPoints(fCurrentDetector));
1326 while ((aDP = (TObjString*) iterDP.Next()))
1328 TObjArray *valueSet = new TObjArray();
1329 valueSet->SetOwner(1);
1330 if (((iDP-1) % 500) == 0 || iDP == nTotDPs)
1331 AliInfo(Form("Querying DCS archive: DP %s (%d of %d)",
1332 aDP->GetName(), iDP++, nTotDPs));
1333 aDCSError = (GetValueSet(host, port, aDP->String(), valueSet, kDP) == 0);
1337 dcsMap.Add(aDP->Clone(), valueSet);
1339 Log(fCurrentDetector,
1340 Form("ProcessCurrentDetector - Error while retrieving data point %s",
1342 UpdateShuttleStatus(AliShuttleStatus::kDCSError);
1349 // DCS Archive DB processing successful. Call Preprocessor!
1350 UpdateShuttleStatus(AliShuttleStatus::kPPStarted);
1352 UInt_t returnValue = aPreprocessor->Process(&dcsMap);
1354 if (returnValue > 0) // Preprocessor error!
1356 Log(fCurrentDetector, Form("Preprocessor failed. Process returned %d.", returnValue));
1357 UpdateShuttleStatus(AliShuttleStatus::kPPError);
1363 UpdateShuttleStatus(AliShuttleStatus::kPPDone);
1364 Log(fCurrentDetector, Form("ProcessCurrentDetector - %s preprocessor returned success",
1365 fCurrentDetector.Data()));
1372 //______________________________________________________________________________________________
1373 Bool_t AliShuttle::QueryShuttleLogbook(const char* whereClause,
1376 // Query DAQ's Shuttle logbook and fills detector status object.
1377 // Call QueryRunParameters to query DAQ logbook for run parameters.
1380 entries.SetOwner(1);
1382 // check connection, in case connect
1383 if(!Connect(3)) return kFALSE;
1386 sqlQuery = Form("select * from %s %s order by run", fConfig->GetShuttlelbTable(), whereClause);
1388 TSQLResult* aResult = fServer[3]->Query(sqlQuery);
1390 AliError(Form("Can't execute query <%s>!", sqlQuery.Data()));
1394 AliDebug(2,Form("Query = %s", sqlQuery.Data()));
1396 if(aResult->GetRowCount() == 0) {
1397 AliInfo("No entries in Shuttle Logbook match request");
1402 // TODO Check field count!
1403 const UInt_t nCols = 22;
1404 if (aResult->GetFieldCount() != (Int_t) nCols) {
1405 AliError("Invalid SQL result field number!");
1411 while ((aRow = aResult->Next())) {
1412 TString runString(aRow->GetField(0), aRow->GetFieldLength(0));
1413 Int_t run = runString.Atoi();
1415 AliShuttleLogbookEntry *entry = QueryRunParameters(run);
1419 // loop on detectors
1420 for(UInt_t ii = 0; ii < nCols; ii++)
1421 entry->SetDetectorStatus(aResult->GetFieldName(ii), aRow->GetField(ii));
1423 entries.AddLast(entry);
1431 //______________________________________________________________________________________________
1432 AliShuttleLogbookEntry* AliShuttle::QueryRunParameters(Int_t run)
1435 // Retrieve run parameters written in the DAQ logbook and sets them into AliShuttleLogbookEntry object
1438 // check connection, in case connect
1443 sqlQuery.Form("select * from %s where run=%d", fConfig->GetDAQlbTable(), run);
1445 TSQLResult* aResult = fServer[3]->Query(sqlQuery);
1447 AliError(Form("Can't execute query <%s>!", sqlQuery.Data()));
1451 if (aResult->GetRowCount() == 0) {
1452 Log("SHUTTLE", Form("QueryRunParameters - No entry in DAQ Logbook for run %d. Skipping", run));
1457 if (aResult->GetRowCount() > 1) {
1458 AliError(Form("More than one entry in DAQ Logbook for run %d. Skipping", run));
1463 TSQLRow* aRow = aResult->Next();
1466 AliError(Form("Could not retrieve row for run %d. Skipping", run));
1471 AliShuttleLogbookEntry* entry = new AliShuttleLogbookEntry(run);
1473 for (Int_t ii = 0; ii < aResult->GetFieldCount(); ii++)
1474 entry->SetRunParameter(aResult->GetFieldName(ii), aRow->GetField(ii));
1476 UInt_t startTime = entry->GetStartTime();
1477 UInt_t endTime = entry->GetEndTime();
1479 if (!startTime || !endTime || startTime > endTime) {
1481 Form("QueryRunParameters - Invalid parameters for Run %d: startTime = %d, endTime = %d",
1482 run, startTime, endTime));
1495 //______________________________________________________________________________________________
1496 Bool_t AliShuttle::GetValueSet(const char* host, Int_t port, const char* entry,
1497 TObjArray* valueSet, DCSType type)
1499 // Retrieve all "entry" data points from the DCS server
1500 // host, port: TSocket connection parameters
1501 // entry: name of the alias or data point
1502 // valueSet: array of retrieved AliDCSValue's
1503 // type: kAlias or kDP
1505 AliDCSClient client(host, port, fTimeout, fRetries);
1506 if (!client.IsConnected())
1515 result = client.GetAliasValues(entry,
1516 GetCurrentStartTime(), GetCurrentEndTime(), valueSet);
1520 result = client.GetDPValues(entry,
1521 GetCurrentStartTime(), GetCurrentEndTime(), valueSet);
1526 Log(fCurrentDetector.Data(), Form("GetValueSet - Can't get '%s'! Reason: %s",
1527 entry, AliDCSClient::GetErrorString(result)));
1529 if (result == AliDCSClient::fgkServerError)
1531 Log(fCurrentDetector.Data(), Form("GetValueSet - Server error: %s",
1532 client.GetServerError().Data()));
1541 //______________________________________________________________________________________________
1542 const char* AliShuttle::GetFile(Int_t system, const char* detector,
1543 const char* id, const char* source)
1545 // Get calibration file from file exchange servers
1546 // First queris the FXS database for the file name, using the run, detector, id and source info
1547 // then calls RetrieveFile(filename) for actual copy to local disk
1548 // run: current run being processed (given by Logbook entry fLogbookEntry)
1549 // detector: the Preprocessor name
1550 // id: provided as a parameter by the Preprocessor
1551 // source: provided by the Preprocessor through GetFileSources function
1553 // check if test mode should simulate a FXS error
1554 if (fTestMode & kErrorFXSFiles)
1556 Log(detector, Form("GetFile - In TESTMODE - Simulating error while connecting to %s FXS", GetSystemName(system)));
1560 // check connection, in case connect
1561 if (!Connect(system))
1563 Log(detector, Form("GetFile - Couldn't connect to %s FXS database", GetSystemName(system)));
1567 // Query preparation
1568 TString sourceName(source);
1570 TString sqlQueryStart = Form("select filePath,size,fileChecksum from %s where",
1571 fConfig->GetFXSdbTable(system));
1572 TString whereClause = Form("run=%d and detector=\"%s\" and fileId=\"%s\"",
1573 GetCurrentRun(), detector, id);
1577 whereClause += Form(" and DAQsource=\"%s\"", source);
1579 else if (system == kDCS)
1583 else if (system == kHLT)
1585 whereClause += Form(" and DDLnumbers=\"%s\"", source);
1589 TString sqlQuery = Form("%s %s", sqlQueryStart.Data(), whereClause.Data());
1591 AliDebug(2, Form("SQL query: \n%s",sqlQuery.Data()));
1594 TSQLResult* aResult = 0;
1595 aResult = dynamic_cast<TSQLResult*> (fServer[system]->Query(sqlQuery));
1597 Log(detector, Form("GetFileName - Can't execute SQL query to %s database for: id = %s, source = %s",
1598 GetSystemName(system), id, sourceName.Data()));
1602 if(aResult->GetRowCount() == 0)
1605 Form("GetFileName - No entry in %s FXS db for: id = %s, source = %s",
1606 GetSystemName(system), id, sourceName.Data()));
1611 if (aResult->GetRowCount() > 1) {
1613 Form("GetFileName - More than one entry in %s FXS db for: id = %s, source = %s",
1614 GetSystemName(system), id, sourceName.Data()));
1619 if (aResult->GetFieldCount() != nFields) {
1621 Form("GetFileName - Wrong field count in %s FXS db for: id = %s, source = %s",
1622 GetSystemName(system), id, sourceName.Data()));
1627 TSQLRow* aRow = dynamic_cast<TSQLRow*> (aResult->Next());
1630 Log(detector, Form("GetFileName - Empty set result in %s FXS db from query: id = %s, source = %s",
1631 GetSystemName(system), id, sourceName.Data()));
1636 TString filePath(aRow->GetField(0), aRow->GetFieldLength(0));
1637 TString fileSize(aRow->GetField(1), aRow->GetFieldLength(1));
1638 TString fileChecksum(aRow->GetField(2), aRow->GetFieldLength(2));
1643 AliDebug(2, Form("filePath = %s; size = %s, fileChecksum = %s",
1644 filePath.Data(), fileSize.Data(), fileChecksum.Data()));
1646 // retrieved file is renamed to make it unique
1647 TString localFileName = Form("%s_%s_%d_%s_%s.shuttle",
1648 GetSystemName(system), detector, GetCurrentRun(), id, sourceName.Data());
1651 // file retrieval from FXS
1652 UInt_t nRetries = 0;
1653 UInt_t maxRetries = 3;
1654 Bool_t result = kFALSE;
1656 // copy!! if successful TSystem::Exec returns 0
1657 while(nRetries++ < maxRetries) {
1658 AliDebug(2, Form("Trying to copy file. Retry # %d", nRetries));
1659 result = RetrieveFile(system, filePath.Data(), localFileName.Data());
1662 Log(detector, Form("GetFileName - Copy of file %s from %s FXS failed",
1663 filePath.Data(), GetSystemName(system)));
1666 AliInfo(Form("File %s copied from %s FXS into %s/%s",
1667 filePath.Data(), GetSystemName(system),
1668 GetShuttleTempDir(), localFileName.Data()));
1671 if (fileChecksum.Length()>0)
1673 // compare md5sum of local file with the one stored in the FXS DB
1674 Int_t md5Comp = gSystem->Exec(Form("md5sum %s/%s |grep %s 2>&1 > /dev/null",
1675 GetShuttleTempDir(), localFileName.Data(), fileChecksum.Data()));
1679 Log(detector, Form("GetFileName - md5sum of file %s does not match with local copy!",
1685 Log(fCurrentDetector, Form("GetFile - md5sum of file %s not set in %s database, skipping comparison",
1686 filePath.Data(), GetSystemName(system)));
1691 if(!result) return 0;
1693 fFXSCalled[system]=kTRUE;
1694 TObjString *fileParams = new TObjString(Form("%s#!?!#%s", id, sourceName.Data()));
1695 fFXSlist[system].Add(fileParams);
1697 static TString fullLocalFileName;
1698 fullLocalFileName = TString::Format("%s/%s", GetShuttleTempDir(), localFileName.Data());
1700 AliInfo(Form("fullLocalFileName = %s", fullLocalFileName.Data()));
1702 return fullLocalFileName.Data();
1706 //______________________________________________________________________________________________
1707 Bool_t AliShuttle::RetrieveFile(UInt_t system, const char* fxsFileName, const char* localFileName)
1710 // Copies file from FXS to local Shuttle machine
1713 // check temp directory: trying to cd to temp; if it does not exist, create it
1714 AliDebug(2, Form("Copy file %s from %s FXS into %s/%s",
1715 GetSystemName(system), fxsFileName, GetShuttleTempDir(), localFileName));
1717 void* dir = gSystem->OpenDirectory(GetShuttleTempDir());
1719 if (gSystem->mkdir(GetShuttleTempDir(), kTRUE)) {
1720 AliError(Form("Can't open directory <%s>", GetShuttleTempDir()));
1725 gSystem->FreeDirectory(dir);
1728 TString baseFXSFolder;
1731 baseFXSFolder = "FES/";
1733 else if (system == kDCS)
1737 else if (system == kHLT)
1739 baseFXSFolder = "~/";
1743 TString command = Form("scp -oPort=%d -2 %s@%s:%s%s %s/%s",
1744 fConfig->GetFXSPort(system),
1745 fConfig->GetFXSUser(system),
1746 fConfig->GetFXSHost(system),
1747 baseFXSFolder.Data(),
1749 GetShuttleTempDir(),
1752 AliDebug(2, Form("%s",command.Data()));
1754 Bool_t result = (gSystem->Exec(command.Data()) == 0);
1759 //______________________________________________________________________________________________
1760 TList* AliShuttle::GetFileSources(Int_t system, const char* detector, const char* id)
1763 // Get sources producing the condition file Id from file exchange servers
1766 // check if test mode should simulate a FXS error
1767 if (fTestMode & kErrorFXSSources)
1769 Log(detector, Form("GetFileSources - In TESTMODE - Simulating error while connecting to %s FXS", GetSystemName(system)));
1776 AliError("DCS system has only one source of data!");
1780 // check connection, in case connect
1781 if (!Connect(system))
1783 Log(detector, Form("GetFile - Couldn't connect to %s FXS database", GetSystemName(system)));
1787 TString sourceName = 0;
1790 sourceName = "DAQsource";
1791 } else if (system == kHLT)
1793 sourceName = "DDLnumbers";
1796 TString sqlQueryStart = Form("select %s from %s where", sourceName.Data(), fConfig->GetFXSdbTable(system));
1797 TString whereClause = Form("run=%d and detector=\"%s\" and fileId=\"%s\"",
1798 GetCurrentRun(), detector, id);
1799 TString sqlQuery = Form("%s %s", sqlQueryStart.Data(), whereClause.Data());
1801 AliDebug(2, Form("SQL query: \n%s",sqlQuery.Data()));
1804 TSQLResult* aResult;
1805 aResult = fServer[system]->Query(sqlQuery);
1807 Log(detector, Form("GetFileSources - Can't execute SQL query to %s database for id: %s",
1808 GetSystemName(system), id));
1812 if (aResult->GetRowCount() == 0)
1815 Form("GetFileSources - No entry in %s FXS table for id: %s", GetSystemName(system), id));
1821 TList *list = new TList();
1824 while ((aRow = aResult->Next()))
1827 TString source(aRow->GetField(0), aRow->GetFieldLength(0));
1828 AliDebug(2, Form("%s = %s", sourceName.Data(), source.Data()));
1829 list->Add(new TObjString(source));
1838 //______________________________________________________________________________________________
1839 Bool_t AliShuttle::Connect(Int_t system)
1841 // Connect to MySQL Server of the system's FXS MySQL databases
1842 // DAQ Logbook, Shuttle Logbook and DAQ FXS db are on the same host
1845 // check connection: if already connected return
1846 if(fServer[system] && fServer[system]->IsConnected()) return kTRUE;
1848 TString dbHost, dbUser, dbPass, dbName;
1850 if (system < 3) // FXS db servers
1852 dbHost = Form("mysql://%s:%d", fConfig->GetFXSdbHost(system), fConfig->GetFXSdbPort(system));
1853 dbUser = fConfig->GetFXSdbUser(system);
1854 dbPass = fConfig->GetFXSdbPass(system);
1855 dbName = fConfig->GetFXSdbName(system);
1856 } else { // Run & Shuttle logbook servers
1857 // TODO Will the Shuttle logbook server be the same as the Run logbook server ???
1858 dbHost = Form("mysql://%s:%d", fConfig->GetDAQlbHost(), fConfig->GetDAQlbPort());
1859 dbUser = fConfig->GetDAQlbUser();
1860 dbPass = fConfig->GetDAQlbPass();
1861 dbName = fConfig->GetDAQlbDB();
1864 fServer[system] = TSQLServer::Connect(dbHost.Data(), dbUser.Data(), dbPass.Data());
1865 if (!fServer[system] || !fServer[system]->IsConnected()) {
1868 AliError(Form("Can't establish connection to FXS database for %s",
1869 AliShuttleInterface::GetSystemName(system)));
1871 AliError("Can't establish connection to Run logbook.");
1873 if(fServer[system]) delete fServer[system];
1878 TSQLResult* aResult=0;
1881 aResult = fServer[kDAQ]->GetTables(dbName.Data());
1884 aResult = fServer[kDCS]->GetTables(dbName.Data());
1887 aResult = fServer[kHLT]->GetTables(dbName.Data());
1890 aResult = fServer[3]->GetTables(dbName.Data());
1898 //______________________________________________________________________________________________
1899 Bool_t AliShuttle::UpdateTable()
1902 // Update FXS table filling time_processed field in all rows corresponding to current run and detector
1905 Bool_t result = kTRUE;
1907 for (UInt_t system=0; system<3; system++)
1909 if(!fFXSCalled[system]) continue;
1911 // check connection, in case connect
1912 if (!Connect(system))
1914 Log(fCurrentDetector, Form("UpdateTable - Couldn't connect to %s FXS database", GetSystemName(system)));
1919 TTimeStamp now; // now
1921 // Loop on FXS list entries
1922 TIter iter(&fFXSlist[system]);
1923 TObjString *aFXSentry=0;
1924 while ((aFXSentry = dynamic_cast<TObjString*> (iter.Next())))
1926 TString aFXSentrystr = aFXSentry->String();
1927 TObjArray *aFXSarray = aFXSentrystr.Tokenize("#!?!#");
1928 if (!aFXSarray || aFXSarray->GetEntries() != 2 )
1930 Log(fCurrentDetector, Form("UpdateTable - error updating %s FXS entry. Check string: <%s>",
1931 GetSystemName(system), aFXSentrystr.Data()));
1932 if(aFXSarray) delete aFXSarray;
1936 const char* fileId = ((TObjString*) aFXSarray->At(0))->GetName();
1937 const char* source = ((TObjString*) aFXSarray->At(1))->GetName();
1939 TString whereClause;
1942 whereClause = Form("where run=%d and detector=\"%s\" and fileId=\"%s\" and DAQsource=\"%s\";",
1943 GetCurrentRun(), fCurrentDetector.Data(), fileId, source);
1945 else if (system == kDCS)
1947 whereClause = Form("where run=%d and detector=\"%s\" and fileId=\"%s\";",
1948 GetCurrentRun(), fCurrentDetector.Data(), fileId);
1950 else if (system == kHLT)
1952 whereClause = Form("where run=%d and detector=\"%s\" and fileId=\"%s\" and DDLnumbers=\"%s\";",
1953 GetCurrentRun(), fCurrentDetector.Data(), fileId, source);
1958 TString sqlQuery = Form("update %s set time_processed=%d %s", fConfig->GetFXSdbTable(system),
1959 now.GetSec(), whereClause.Data());
1961 AliDebug(2, Form("SQL query: \n%s",sqlQuery.Data()));
1964 TSQLResult* aResult;
1965 aResult = dynamic_cast<TSQLResult*> (fServer[system]->Query(sqlQuery));
1968 Log(fCurrentDetector, Form("UpdateTable - %s db: can't execute SQL query <%s>",
1969 GetSystemName(system), sqlQuery.Data()));
1980 //______________________________________________________________________________________________
1981 Bool_t AliShuttle::UpdateTableFailCase()
1983 // Update FXS table filling time_processed field in all rows corresponding to current run and detector
1984 // this is called in case the preprocessor is declared failed for the current run, because
1985 // the fields are updated only in case of success
1987 Bool_t result = kTRUE;
1989 for (UInt_t system=0; system<3; system++)
1991 // check connection, in case connect
1992 if (!Connect(system))
1994 Log(fCurrentDetector, Form("UpdateTableFailCase - Couldn't connect to %s FXS database",
1995 GetSystemName(system)));
2000 TTimeStamp now; // now
2002 // Loop on FXS list entries
2004 TString whereClause = Form("where run=%d and detector=\"%s\";",
2005 GetCurrentRun(), fCurrentDetector.Data());
2008 TString sqlQuery = Form("update %s set time_processed=%d %s", fConfig->GetFXSdbTable(system),
2009 now.GetSec(), whereClause.Data());
2011 AliDebug(2, Form("SQL query: \n%s",sqlQuery.Data()));
2014 TSQLResult* aResult;
2015 aResult = dynamic_cast<TSQLResult*> (fServer[system]->Query(sqlQuery));
2018 Log(fCurrentDetector, Form("UpdateTableFailCase - %s db: can't execute SQL query <%s>",
2019 GetSystemName(system), sqlQuery.Data()));
2029 //______________________________________________________________________________________________
2030 Bool_t AliShuttle::UpdateShuttleLogbook(const char* detector, const char* status)
2033 // Update Shuttle logbook filling detector or shuttle_done column
2034 // ex. of usage: UpdateShuttleLogbook("PHOS", "DONE") or UpdateShuttleLogbook("shuttle_done")
2037 // check connection, in case connect
2039 Log("SHUTTLE", "UpdateShuttleLogbook - Couldn't connect to DAQ Logbook.");
2043 TString detName(detector);
2045 if(detName == "shuttle_done")
2047 setClause = "set shuttle_done=1";
2049 // Send the information to ML
2050 TMonaLisaText mlStatus("SHUTTLE_status", "Done");
2053 mlList.Add(&mlStatus);
2055 fMonaLisa->SendParameters(&mlList);
2057 TString statusStr(status);
2058 if(statusStr.Contains("done", TString::kIgnoreCase) ||
2059 statusStr.Contains("failed", TString::kIgnoreCase)){
2060 setClause = Form("set %s=\"%s\"", detector, status);
2063 Form("UpdateShuttleLogbook - Invalid status <%s> for detector %s",
2069 TString whereClause = Form("where run=%d", GetCurrentRun());
2071 TString sqlQuery = Form("update %s %s %s",
2072 fConfig->GetShuttlelbTable(), setClause.Data(), whereClause.Data());
2074 AliDebug(2, Form("SQL query: \n%s",sqlQuery.Data()));
2077 TSQLResult* aResult;
2078 aResult = dynamic_cast<TSQLResult*> (fServer[3]->Query(sqlQuery));
2080 Log("SHUTTLE", Form("UpdateShuttleLogbook - Can't execute query <%s>", sqlQuery.Data()));
2088 //______________________________________________________________________________________________
2089 Int_t AliShuttle::GetCurrentRun() const
2092 // Get current run from logbook entry
2095 return fLogbookEntry ? fLogbookEntry->GetRun() : -1;
2098 //______________________________________________________________________________________________
2099 UInt_t AliShuttle::GetCurrentStartTime() const
2102 // get current start time
2105 return fLogbookEntry ? fLogbookEntry->GetStartTime() : 0;
2108 //______________________________________________________________________________________________
2109 UInt_t AliShuttle::GetCurrentEndTime() const
2112 // get current end time from logbook entry
2115 return fLogbookEntry ? fLogbookEntry->GetEndTime() : 0;
2118 //______________________________________________________________________________________________
2119 void AliShuttle::Log(const char* detector, const char* message)
2122 // Fill log string with a message
2125 void* dir = gSystem->OpenDirectory(GetShuttleLogDir());
2127 if (gSystem->mkdir(GetShuttleLogDir(), kTRUE)) {
2128 AliError(Form("Can't open directory <%s>", GetShuttleLogDir()));
2133 gSystem->FreeDirectory(dir);
2136 TString toLog = Form("%s (%d): %s - ", TTimeStamp(time(0)).AsString("s"), getpid(), detector);
2137 if (GetCurrentRun() >= 0)
2138 toLog += Form("run %d - ", GetCurrentRun());
2139 toLog += Form("%s", message);
2141 AliInfo(toLog.Data());
2144 if (GetCurrentRun() >= 0)
2145 fileName.Form("%s/%s_%d.log", GetShuttleLogDir(), detector, GetCurrentRun());
2147 fileName.Form("%s/%s.log", GetShuttleLogDir(), detector);
2149 gSystem->ExpandPathName(fileName);
2152 logFile.open(fileName, ofstream::out | ofstream::app);
2154 if (!logFile.is_open()) {
2155 AliError(Form("Could not open file %s", fileName.Data()));
2159 logFile << toLog.Data() << "\n";
2164 //______________________________________________________________________________________________
2165 Bool_t AliShuttle::Collect(Int_t run)
2168 // Collects conditions data for all UNPROCESSED run written to DAQ LogBook in case of run = -1 (default)
2169 // If a dedicated run is given this run is processed
2171 // In operational mode, this is the Shuttle function triggered by the EOR signal.
2175 Log("SHUTTLE","Collect - Shuttle called. Collecting conditions data for unprocessed runs");
2177 Log("SHUTTLE", Form("Collect - Shuttle called. Collecting conditions data for run %d", run));
2179 SetLastAction("Starting");
2181 TString whereClause("where shuttle_done=0");
2183 whereClause += Form(" and run=%d", run);
2185 TObjArray shuttleLogbookEntries;
2186 if (!QueryShuttleLogbook(whereClause, shuttleLogbookEntries))
2188 Log("SHUTTLE", "Collect - Can't retrieve entries from Shuttle logbook");
2192 if (shuttleLogbookEntries.GetEntries() == 0)
2195 Log("SHUTTLE","Collect - Found no UNPROCESSED runs in Shuttle logbook");
2197 Log("SHUTTLE", Form("Collect - Run %d is already DONE "
2198 "or it does not exist in Shuttle logbook", run));
2202 for (UInt_t iDet=0; iDet<NDetectors(); iDet++)
2203 fFirstUnprocessed[iDet] = kTRUE;
2207 // query Shuttle logbook for earlier runs, check if some detectors are unprocessed,
2208 // flag them into fFirstUnprocessed array
2209 TString whereClause(Form("where shuttle_done=0 and run < %d", run));
2210 TObjArray tmpLogbookEntries;
2211 if (!QueryShuttleLogbook(whereClause, tmpLogbookEntries))
2213 Log("SHUTTLE", "Collect - Can't retrieve entries from Shuttle logbook");
2217 TIter iter(&tmpLogbookEntries);
2218 AliShuttleLogbookEntry* anEntry = 0;
2219 while ((anEntry = dynamic_cast<AliShuttleLogbookEntry*> (iter.Next())))
2221 for (UInt_t iDet=0; iDet<NDetectors(); iDet++)
2223 if (anEntry->GetDetectorStatus(iDet) == AliShuttleLogbookEntry::kUnprocessed)
2225 AliDebug(2, Form("Run %d: setting %s as \"not first time unprocessed\"",
2226 anEntry->GetRun(), GetDetName(iDet)));
2227 fFirstUnprocessed[iDet] = kFALSE;
2235 if (!RetrieveConditionsData(shuttleLogbookEntries))
2237 Log("SHUTTLE", "Collect - Process of at least one run failed");
2241 Log("SHUTTLE", "Collect - Requested run(s) successfully processed");
2245 //______________________________________________________________________________________________
2246 Bool_t AliShuttle::RetrieveConditionsData(const TObjArray& dateEntries)
2249 // Retrieve conditions data for all runs that aren't processed yet
2252 Bool_t hasError = kFALSE;
2254 TIter iter(&dateEntries);
2255 AliShuttleLogbookEntry* anEntry;
2257 while ((anEntry = (AliShuttleLogbookEntry*) iter.Next())){
2258 if (!Process(anEntry)){
2262 // clean SHUTTLE temp directory
2263 TString filename = Form("%s/*.shuttle", GetShuttleTempDir());
2264 RemoveFile(filename.Data());
2267 return hasError == kFALSE;
2270 //______________________________________________________________________________________________
2271 ULong_t AliShuttle::GetTimeOfLastAction() const
2274 // Gets time of last action
2279 fMonitoringMutex->Lock();
2281 tmp = fLastActionTime;
2283 fMonitoringMutex->UnLock();
2288 //______________________________________________________________________________________________
2289 const TString AliShuttle::GetLastAction() const
2292 // returns a string description of the last action
2297 fMonitoringMutex->Lock();
2301 fMonitoringMutex->UnLock();
2306 //______________________________________________________________________________________________
2307 void AliShuttle::SetLastAction(const char* action)
2310 // updates the monitoring variables
2313 fMonitoringMutex->Lock();
2315 fLastAction = action;
2316 fLastActionTime = time(0);
2318 fMonitoringMutex->UnLock();
2321 //______________________________________________________________________________________________
2322 const char* AliShuttle::GetRunParameter(const char* param)
2325 // returns run parameter read from DAQ logbook
2328 if(!fLogbookEntry) {
2329 AliError("No logbook entry!");
2333 return fLogbookEntry->GetRunParameter(param);
2336 //______________________________________________________________________________________________
2337 AliCDBEntry* AliShuttle::GetFromOCDB(const char* detector, const AliCDBPath& path)
2340 // returns object from OCDB valid for current run
2343 if (fTestMode & kErrorOCDB)
2345 Log(detector, "GetFromOCDB - In TESTMODE - Simulating error with OCDB");
2349 AliCDBStorage *sto = AliCDBManager::Instance()->GetStorage(fgkMainCDB);
2352 Log(detector, "GetFromOCDB - Cannot activate main OCDB for query!");
2356 return dynamic_cast<AliCDBEntry*> (sto->Get(path, GetCurrentRun()));
2359 //______________________________________________________________________________________________
2360 Bool_t AliShuttle::SendMail()
2363 // sends a mail to the subdetector expert in case of preprocessor error
2366 if (fTestMode != kNone)
2369 void* dir = gSystem->OpenDirectory(GetShuttleLogDir());
2372 if (gSystem->mkdir(GetShuttleLogDir(), kTRUE))
2374 AliError(Form("Can't open directory <%s>", GetShuttleLogDir()));
2379 gSystem->FreeDirectory(dir);
2382 TString bodyFileName;
2383 bodyFileName.Form("%s/mail.body", GetShuttleLogDir());
2384 gSystem->ExpandPathName(bodyFileName);
2387 mailBody.open(bodyFileName, ofstream::out);
2389 if (!mailBody.is_open())
2391 AliError(Form("Could not open mail body file %s", bodyFileName.Data()));
2396 TIter iterExperts(fConfig->GetResponsibles(fCurrentDetector));
2397 TObjString *anExpert=0;
2398 while ((anExpert = (TObjString*) iterExperts.Next()))
2400 to += Form("%s,", anExpert->GetName());
2402 to.Remove(to.Length()-1);
2403 AliDebug(2, Form("to: %s",to.Data()));
2405 // TODO this will be removed...
2406 if (to.Contains("not_yet_set")) {
2407 AliInfo("List of detector responsibles not yet set!");
2411 TString cc="alberto.colla@cern.ch";
2413 TString subject = Form("%s Shuttle preprocessor error in run %d !",
2414 fCurrentDetector.Data(), GetCurrentRun());
2415 AliDebug(2, Form("subject: %s", subject.Data()));
2417 TString body = Form("Dear %s expert(s), \n\n", fCurrentDetector.Data());
2418 body += Form("SHUTTLE just detected that your preprocessor "
2419 "exited with ERROR state in run %d!!\n\n", GetCurrentRun());
2420 body += Form("Please check %s status on the web page asap!\n\n", fCurrentDetector.Data());
2421 body += Form("The last 10 lines of %s log file are following:\n\n");
2423 AliDebug(2, Form("Body begin: %s", body.Data()));
2425 mailBody << body.Data();
2427 mailBody.open(bodyFileName, ofstream::out | ofstream::app);
2429 TString logFileName = Form("%s/%s_%d.log", GetShuttleLogDir(), fCurrentDetector.Data(), GetCurrentRun());
2430 TString tailCommand = Form("tail -n 10 %s >> %s", logFileName.Data(), bodyFileName.Data());
2431 if (gSystem->Exec(tailCommand.Data()))
2433 mailBody << Form("%s log file not found ...\n\n", fCurrentDetector.Data());
2436 TString endBody = Form("------------------------------------------------------\n\n");
2437 endBody += Form("In case of problems please contact the SHUTTLE core team.\n\n");
2438 endBody += "Please do not answer this message directly, it is automatically generated.\n\n";
2439 endBody += "Sincerely yours,\n\n \t\t\tthe SHUTTLE\n";
2441 AliDebug(2, Form("Body end: %s", endBody.Data()));
2443 mailBody << endBody.Data();
2448 TString mailCommand = Form("mail -s \"%s\" -c %s %s < %s",
2452 bodyFileName.Data());
2453 AliDebug(2, Form("mail command: %s", mailCommand.Data()));
2455 Bool_t result = gSystem->Exec(mailCommand.Data());
2460 //______________________________________________________________________________________________
2461 const char* AliShuttle::GetRunType()
2464 // returns run type read from "run type" logbook
2467 if(!fLogbookEntry) {
2468 AliError("No logbook entry!");
2472 return fLogbookEntry->GetRunType();
2475 //______________________________________________________________________________________________
2476 void AliShuttle::SetShuttleTempDir(const char* tmpDir)
2479 // sets Shuttle temp directory
2482 fgkShuttleTempDir = gSystem->ExpandPathName(tmpDir);
2485 //______________________________________________________________________________________________
2486 void AliShuttle::SetShuttleLogDir(const char* logDir)
2489 // sets Shuttle log directory
2492 fgkShuttleLogDir = gSystem->ExpandPathName(logDir);