ATLAS Offline Software
Loading...
Searching...
No Matches
AtlCoolCopy.cxx
Go to the documentation of this file.
1/*
2 Copyright (C) 2002-2026 CERN for the benefit of the ATLAS collaboration
3*/
4
5// AtlCoolCopy.cxx
6// COOL copying utility, C++ based on PyCoolCopy from Sven Schmidt
7// Richard Hawkings, started 30/5/06
8// compiles in offline cmt framework to binary executable, needs offline env
9
10#include <algorithm>
11#include <cmath>
12#include <ctime>
13#include <fstream>
14#include <iostream>
15#include <sstream>
16#include <string>
17#include <vector>
18#include <nlohmann/json.hpp>
19#include <curl/curl.h>
20
21#include "CoolKernel/DatabaseId.h"
22#include "CoolKernel/Exception.h"
23#include "CoolKernel/IDatabaseSvc.h"
24#include "CoolKernel/IDatabase.h"
25#include "CoolKernel/IFolder.h"
26#include "CoolKernel/FolderSpecification.h"
27#include "CoolKernel/IFolderSet.h"
28#include "CoolKernel/IObject.h"
29#include "CoolKernel/IObjectIterator.h"
30#include "CoolKernel/IRecordIterator.h"
31#include "CoolApplication/Application.h"
32#include "CoralBase/AttributeListException.h"
33
34#include "GaudiUtils/IFileCatalog.h"
35#include "GaudiUtils/IFileCatalogMgr.h"
36#include "GaudiKernel/ISvcLocator.h"
37#include "GaudiKernel/Bootstrap.h"
38
40#include "RelationalAccess/ConnectionService.h"
41#include "RelationalAccess/IConnectionServiceConfiguration.h"
42#include "RelationalAccess/ISessionProxy.h"
43#include "RelationalAccess/ITransaction.h"
44#include "RelationalAccess/ISchema.h"
45#include "RelationalAccess/ITable.h"
46#include "RelationalAccess/IQuery.h"
47#include "RelationalAccess/ICursor.h"
48
53
55
56#include "PoolMapElement.h"
57#include "ReplicaSorter.h"
58#include "CoolTagInfo.h"
59
60#include "TFile.h"
61#include "TTree.h"
62#include "TH1.h"
63#include "TObjString.h"
64
65size_t WriteCallback(void *contents, size_t size, size_t nmemb, std::string *s) {
66 size_t newLength = size * nmemb;
67
68 try
69 {
70 s->append((char *)contents, newLength);
71 }
72 catch (std::bad_alloc &e)
73 {
74 // handle memory problem
75 return 0;
76 }
77 return newLength;
78}
79
80
82 public:
83 AtlCoolCopy(const std::string& sourcedb, const std::string& destdb,
84 bool allowcreate=false);
85 bool isOpen() const;
86 bool addFolder(const std::string& folder,const bool onlyTags);
87 bool addExclude(const std::string& folder);
88 int copyFolder ATLAS_NOT_THREAD_SAFE
89 (const std::string& folder,const std::vector<std::string>& taglist);
90 int doCopy ATLAS_NOT_THREAD_SAFE ();
91 int setOpts(int argc, const char* argv[]);
92
93 private:
94 // methods
95 bool openConnections(const std::string& sourcedb, const std::string& destdb,
96 bool allowcreate);
97 bool openCoraCool();
98 bool getLockedTags();
99 bool procOptVector(const int argc, const char* argv[],
100 std::vector<std::string>& folders);
101 static std::string transConn(const std::string& inconn);
102 void setChannelRange(const cool::IFolderPtr& sourcefl);
103 static cool::ChannelId channelID(const cool::IFolderPtr& folder,
104 const std::string& chanstring);
106 (const std::string& folder,const std::string& destfolder,
107 const cool::IFolderPtr& sourcefl,const CoraCoolFolderPtr& sourceflc,
108 const cool::IFolderPtr& destfl,const CoraCoolFolderPtr& destflc,
109 const std::string& sourcetag,const std::string& desttag,
110 const cool::ValidityKey since,const cool::ValidityKey until,
111 bool timestamp,bool checkrefs,bool iscora,
112 const cool::PayloadMode::Mode paymode, bool created);
113 void adjustIOVs(const cool::ValidityKey& since,
114 const cool::ValidityKey& until,
115 const cool::ValidityKey& qsince,
116 const cool::ValidityKey& quntil,
117 cool::ValidityKey& newsince,
118 cool::ValidityKey& newuntil,
119 const bool timestamp) const;
120 int nocopyIOVs(const std::string& folder,
121 const cool::IFolderPtr& sourcefl,const std::string& sourcetag,
122 const cool::ValidityKey since,const cool::ValidityKey until,
123 bool checkrefs);
124 int verifyIOVs(const std::string& folder,
125 const cool::IFolderPtr& sourcefl,const CoraCoolFolderPtr& sourceflc,
126 const cool::IFolderPtr& destfl,const CoraCoolFolderPtr& destflc,
127 const std::string& sourcetag,
128 const cool::ValidityKey since,const cool::ValidityKey until,
129 const bool checkrefs,const bool iscora,
130 const cool::PayloadMode::Mode paymode);
131 int rootIOVs(const std::string& folder,
132 const cool::IFolderPtr& sourcefl,const std::string& sourcetag,
133 const cool::ValidityKey since,const cool::ValidityKey until,
134 const bool timestamp);
135 std::string rootDirs(const std::string& folder, const std::string& toproot);
136 bool rootAllocate(const cool::IFieldSpecification& spec,
137 void*& sptr,char& rootID) const;
138 void rootWrite(void* sptr, const cool::IField& field) const;
139 static bool isNumeric(const char* input);
140 static bool equalRecord(const cool::IRecord& lhs,
141 const cool::IRecord& rhs);
142 int analyseIOVs(const std::string& folder,
143 const cool::IFolderPtr& sourcefl,const std::string& sourcetag,
144 const cool::ValidityKey since,const cool::ValidityKey until,
145 const bool timestamp);
146 static TH1F* bookOrFindTH1F(const std::string& hID, const std::string& htitle,
147 const int chan, const float xlow, const float xhigh);
148 static cool::ValidityKey timeVal(const char* input);
149 static std::string timeString(const cool::ValidityKey iovtime);
150 static cool::ValidityKey runLBVal(const char* input1, const char* input2);
151 bool getTimeFromRun();
152 bool getOnlineRun();
153 bool getBulkRun();
154 bool getRunList();
155
156 static int getUpdateMode(std::string_view desc, std::string_view tag);
157
158 bool checkChannels(const std::string& folder,
159 const cool::IFolderPtr& sourcefl,const cool::IFolderPtr& destfl,
160 bool newfolder);
161 void checkRef(const cool::IRecord& payload,
162 const std::string& folder,const std::string& tag);
163 int tagParents();
164 int writeTagInfo();
165 int listPoolRefs();
166 int resolvePoolRefs ATLAS_NOT_THREAD_SAFE ();
167 static std::string getCoolHistGUID(const std::string& file);
168 void filePoolRefs();
169 void setupCatalog(const std::vector<std::string>& catvec);
170 SmartIF<Gaudi::IFileCatalog> m_catalog;
171
172 // input parameters
173 std::string m_sourcedb;
174 std::string m_destdb;
184 bool m_root;
223 cool::ValidityKey m_runemin;
224 cool::ValidityKey m_runemax;
225 cool::ValidityKey m_timemin;
226 cool::ValidityKey m_timemax;
227 cool::ValidityKey m_newrunemin;
228 cool::ValidityKey m_newrunemax;
229 cool::ValidityKey m_newtimemin;
230 cool::ValidityKey m_newtimemax;
231 cool::ValidityKey m_srunemin;
232 cool::ValidityKey m_srunemax;
233 std::vector<std::string> m_channelRange;
234 std::string m_channel1;
235 std::string m_channel2;
238 long long m_anadelt;
239 std::string m_outfolder;
240 std::string m_outtag;
241 std::string m_newdataset;
242 std::string m_checkoutputfile;
243 std::string m_timedb;
244 std::string m_taglabel;
245 std::string m_runinfohost;
246 std::vector<std::string> m_addguid; // additional guids to be processsed
247 std::vector<std::string> m_addlfn; // additional LFNs to be processsed
248 std::vector<std::string> m_parfile; // list of additional files with params
249 std::vector<cool::ChannelId> m_excludechans; // list of channels to exclude
250 std::vector<std::string> m_runfile; // list of filenames with run numbers
251 std::vector<unsigned int> m_runlist; // list of runs open for UPD2 tags
252
253 // internal variables
254 coral::ConnectionService m_coralsvc;
255 cool::Application m_coolapp;
256 cool::IDatabaseSvc* m_dbSvc;
258 cool::IDatabasePtr m_sourceDbPtr;
259 cool::IDatabasePtr m_destDbPtr;
262 std::vector<std::string> m_folderlist; // list of leaf folders to process
263 std::vector<std::string> m_folderexcl; // list of leaf folders to exclude
264 std::vector<std::string> m_tags; // list of tags
265 std::vector<std::string> m_magic; // list magic tags fragments to match
266 std::vector<std::string> m_poolcat; // list of POOL catalogues for input
267 std::vector<std::string> m_mergecat; // list of POOL catalogues for mergechk
268 bool m_open;
269 cool::ChannelSelection m_chansel;
270 typedef std::map<std::string,PoolMapElement> PoolMap;
271 PoolMap::iterator m_poollast; // pointer to last POOL ref updated
272 PoolMap m_poolrefs; // POOL refs and usage counts
273 // hierarchical tags - tag name and folder
274 using HiTagMap = std::map<std::string, std::string>;
276 // tags indirectly used in the hierarchy and have to be treated at end
277 std::vector<std::string> m_hiparent;
278 // map of CoolTagInfo objects - tags which have have their descriptions
279 // and lock status set in the destination DB at the end
280 using CoolTagMap = std::map<std::string, CoolTagInfo>;
282 // output root file for ROOT file export and IOV analysis
284
285 // ROOT ntuple variables.
286 ULong64_t m_nt_since = 0;
287 ULong64_t m_nt_until = 0;
288 UInt_t m_nt_runsince = 0;
289 UInt_t m_nt_rununtil = 0;
290 UInt_t m_nt_lbsince = 0;
291 UInt_t m_nt_lbuntil = 0;
292 UInt_t m_nt_channel = 0;
293 char m_nt_tagid[256] = {0};
294 std::string m_nt_treename;
295 std::vector<void*> m_nt_bufferptr;
296};
297
298inline bool AtlCoolCopy::isOpen() const { return m_open; }
299
300void printHelp();
301
302AtlCoolCopy::AtlCoolCopy(const std::string& sourcedb, const std::string& destdb,
303 bool allowcreate) :
304 m_sourcedb(sourcedb),m_destdb(destdb),m_allowcreate(allowcreate),
305 m_recreate(false),
306 m_includehead(false),m_excludehead(false),
307 m_usertags(true),m_userupdatehead(false),m_debug(false),m_alliov(false),
308 m_verify(false),m_root(false),m_zeronull(false),m_analyse(false),
309 m_checkrefs(false),m_listpfn(false),m_poolopen(false),m_poolall(false),
310 m_nocopy(false),m_nodata(false),m_nochannel(false),m_chdesc(false),
311 m_hitag(false),m_nohitag(false),m_forcesingle(false),m_forcemulti(false),
312 m_forcerune(false),m_forcetime(false),m_forcepay(false),m_forcenopay(false),
313 m_sourceread(true),m_truncate(false),m_skipout(false),m_skiprep(false),
314 m_applock(false),m_applocksv(false),
315 m_readoracle(false),m_gettime(false),m_getonline(false),m_onlinerun(false),
316 m_getbulk(false),
317 m_prunetags(false),m_lockedonly(false),m_copytaginfo(false),
318 m_copytaglock(false),m_coracool(true),m_ignoremode(false),
319 m_ignorespec(false),m_checkdesttag(false),m_noclobroot(false),
320 m_runemin(cool::ValidityKeyMin),m_runemax(cool::ValidityKeyMax),
321 m_timemin(cool::ValidityKeyMin),m_timemax(cool::ValidityKeyMax),
322 m_newrunemin(cool::ValidityKeyMin),m_newrunemax(cool::ValidityKeyMax),
323 m_newtimemin(cool::ValidityKeyMin),m_newtimemax(cool::ValidityKeyMax),
324 m_srunemin(cool::ValidityKeyMin),m_srunemax(cool::ValidityKeyMax),
325 m_channel1(""),m_channel2(""),m_bufsize(1000),m_sealmsg(5),
328 m_runinfohost("http://atlas-run-info-api.web.cern.ch/api"),
330 m_dbSvc(&(m_coolapp.databaseService())),m_repsort(nullptr),
331 m_open(false),m_chansel(cool::ChannelSelection::all()),p_rootfile(nullptr)
332{
333 m_poolrefs.clear();
335 // configure CORAL components
336 coral::IConnectionServiceConfiguration& csconfig=m_coralsvc.configuration();
337 csconfig.disablePoolAutomaticCleanUp();
338 csconfig.setConnectionTimeOut(0);
339}
340
341bool AtlCoolCopy::openConnections(const std::string& sourcedb,
342 const std::string& destdb,bool allowcreate) {
343 // check connections not already open
344 if (m_open) return true;
345 // initialise replica sorter if it was requested
346 if (m_readoracle) {
348 coral::IConnectionServiceConfiguration& csconfig=m_coralsvc.configuration();
349 csconfig.setReplicaSortingAlgorithm(*m_repsort);
350 }
351 // cool::IDatabaseSvc& dbSvc=cool::DatabaseSvcFactory::databaseService();
352 // open source database
353 std::cout << "Open source database: " << sourcedb << std::endl;
354 if (!m_sourceread) std::cout << "... in UPDATE mode" << std::endl;
355 try {
356 m_sourceDbPtr=m_dbSvc->openDatabase(transConn(sourcedb),m_sourceread);
357 }
358 catch (std::exception& e) {
359 std::cout << "Cool exception caught: " << e.what() << std::endl;
360 return false;
361 }
362 // open destination database
363 if (m_nocopy) {
364 m_open=true;
365 return true;
366 } else if (m_root || m_analyse) {
367 std::cout << "Open destination ROOT file: " << destdb << std::endl;
368 p_rootfile=new TFile(destdb.c_str(),"RECREATE");
369 if (p_rootfile==nullptr) std::cout << "ERROR: Could not open ROOT file" <<
370 std::endl;
371 m_open=(p_rootfile!=nullptr);
372 return m_open;
373 }
374 std::string tdestdb=transConn(destdb);
375 std::cout << "Open destination database: " << tdestdb << std::endl;
376 try {
377 m_destDbPtr=m_dbSvc->openDatabase(tdestdb,m_verify);
378 // if the open succeeds and we are using recreate mode, drop/delete
379 // the existing database first
380 if (m_recreate) {
381 std::cout <<
382 "Forcing recreation of destination database - deleting existing data!"
383 << std::endl;
384 m_destDbPtr.reset();
385 m_dbSvc->dropDatabase(tdestdb);
386 // go into catch to recrete database
387 throw cool::DatabaseDoesNotExist("old database deleted");
388 }
389 }
390 catch (std::exception& e) {
391 std::cout << "COOL exception caught: " << e.what() << std::endl;
392 // try to recover by creating new DB if possible and requested
393 if (allowcreate || m_recreate) {
394 std::cout << "Try to create new conditions DB" << std::endl;
395 try {
396 m_destDbPtr=m_dbSvc->createDatabase(tdestdb);
397 std::cout << "Creation succeeded" << std::endl;
398 }
399 catch (cool::Exception& e) {
400 std::cout << "Creation failed" << std::endl;
401 return false;
402 }
403 } else {
404 return false;
405 }
406 }
407 m_open=true;
408 return true;
409}
410
412 if (m_sourceCoraPtr.get()==nullptr) {
413 std::cout << "Attempt to open source CoraCool DB " << m_sourcedb <<
414 std::endl;
417 std::cout << "Opened CoraCool source DB" << std::endl;
418 }
419 // skip destination DB if not copying
420 if (m_nocopy) return true;
421 if (m_destCoraPtr.get()==nullptr) {
422 std::cout << "Attempt to open destination CoraCool DB " << m_destdb <<
423 std::endl;
426 std::cout << "Opened CoraCool dest DB" << std::endl;
427 }
428 return true;
429}
430
432 // set m_tags to list of top level tags which are locked
433 m_tags.clear();
434 cool::IFolderSetPtr topfolder=m_sourceDbPtr->getFolderSet("/");
435 const std::vector<std::string>& toptaglist=topfolder->listTags();
436 for (std::vector<std::string>::const_iterator toptag=toptaglist.begin();
437 toptag!=toptaglist.end();++toptag) {
438 cool::HvsTagLock::Status tstat=topfolder->tagLockStatus(*toptag);
439 if (tstat==cool::HvsTagLock::LOCKED ||
440 tstat==cool::HvsTagLock::PARTIALLYLOCKED) {
441 std::cout << "Top-level tag " << *toptag << " will be copied" <<
442 std::endl;
443 m_tags.push_back(*toptag);
444 }
445 }
446 std::cout << "Total of " << m_tags.size() << " top-level tags to be copied"
447 << std::endl;
448 return (!m_tags.empty());
449}
450
451std::string AtlCoolCopy::transConn(const std::string& inconn) {
452 // translate simple connection string (no slash) to mycool.db with given
453 // instance name, all others are left alone
454 if (inconn.find('/')==std::string::npos) {
455 return "sqlite://X;schema=mycool.db;dbname="+inconn;
456 } else {
457 return inconn;
458 }
459}
460
461
462bool AtlCoolCopy::addFolder(const std::string& folder,const bool onlyTags) {
463 std::cout << "Add folders in path:" << folder << " [ ";
464 const std::vector<std::string> nodelist=m_sourceDbPtr->listAllNodes();
465 // find all matching leaf folders
466 for (std::vector<std::string>::const_iterator nodeitr=nodelist.begin();
467 nodeitr!=nodelist.end();++nodeitr) {
468 // match exact folder name or leading part of path
469 // for leading part matches, next char in folder name must be '/'
470 // so /CALO/SetA matches /CALO/SetA/X but not /CALO/SetAB
471 if (*nodeitr==folder || folder=="/" ||
472 (nodeitr->compare(0,folder.size(),folder)==0 &&
473 nodeitr->size()>folder.size() && nodeitr->compare(folder.size(),1,"/")==0)) {
474 // check if folder on exclude list
475 bool exclude=false;
476 for (std::vector<std::string>::const_iterator iexcl=m_folderexcl.begin();
477 iexcl!=m_folderexcl.end();++iexcl) {
478 if (iexcl->compare(0,1,"/")==0) {
479 // exclude pattern starting / matches folder path (/SCT or /SCT/DCS)
480 exclude=(exclude || nodeitr->compare(0,iexcl->size(),*iexcl)==0);
481 } else {
482 // exclude pattern without leading / matches anywhere in folder
483 exclude=(exclude || (nodeitr->find(*iexcl)!=std::string::npos));
484 }
485 }
486 // check folder exists (is a leaf folder), and not excluded
487 if (m_sourceDbPtr->existsFolder(*nodeitr) && !exclude && !onlyTags) {
488 // only add if folder not already on list
489 if (find(m_folderlist.begin(),m_folderlist.end(),*nodeitr)==
490 m_folderlist.end()) {
491 std::cout << *nodeitr << " ";
492 m_folderlist.push_back(*nodeitr);
493 }
494 }
495 // if its a folderset, check for any hierarchical tags
496 if (!m_nohitag && m_sourceDbPtr->existsFolderSet(*nodeitr) && !exclude) {
497 if (!m_prunetags) {
498 const std::vector<std::string> foldersettags=
499 m_sourceDbPtr->getFolderSet(*nodeitr)->listTags();
500 if (!foldersettags.empty()) {
501 for (std::vector<std::string>::const_iterator
502 itr=foldersettags.begin();itr!=foldersettags.end();++itr) {
503 m_hitagmap[*itr]=*nodeitr;
504 }
505 }
506 } else {
507 // only take tags in this folder which are referenced from one of
508 // the input tags (assumed to be top-level tags)
509 cool::IFolderSetPtr sfolder=m_sourceDbPtr->getFolderSet(*nodeitr);
510 for (std::vector<std::string>::const_iterator toptag=m_tags.begin();
511 toptag!=m_tags.end();++toptag) {
512 try {
513 std::string rtag=sfolder->resolveTag(*toptag);
514 m_hitagmap[rtag]=*nodeitr;
515 }
516 // catch exceptions indicating tag defines nothing here
517 // note std::exception rather than COOL exception to cover case
518 // when trying to resolve a leaf tag in the '/' folder, which
519 // throws a coral AttributeException
520 catch (std::exception& e) {}
521 }
522 }
523 }
524 }
525 }
526 std::cout << "]" << std::endl;
527 return true;
528}
529
530bool AtlCoolCopy::addExclude(const std::string& folder) {
531 std::cout << "Adding folder to exclude list: " << folder << std::endl;
532 m_folderexcl.push_back(folder);
533 return true;
534}
535
536int AtlCoolCopy::copyFolder ATLAS_NOT_THREAD_SAFE
537 (const std::string& folder,const std::vector<std::string>& taglist) {
538 // get source folder
539 cool::IFolderPtr sourcefl,destfl;
540 CoraCoolFolderPtr sourceflc,destflc;
541 try {
542 sourcefl=m_sourceDbPtr->getFolder(folder);
543 }
544 catch (cool::Exception& e) {
545 std::cout << "Could not get source folder: " << folder << std::endl;
546 return 20;
547 }
548 const std::string& sourcedesc=sourcefl->description();
549 // check if folder should be skipped from replication
550 if (m_skiprep && sourcedesc.find("<norep/>")!=std::string::npos) {
551 std::cout << "Folder " << folder <<
552 " skipped due to <norep/> metadata" << std::endl;
553 return 0;
554 }
555 const bool iscora=(m_coracool &&
556 sourcedesc.find("<coracool")!=std::string::npos);
557 if (iscora) {
558 // activate CoraCool and get source folder pointer
559 openCoraCool();
560 sourceflc=m_sourceCoraPtr->getFolder(folder);
561 }
562 // setup the channel-range
563 setChannelRange(sourcefl);
564
565 cool::FolderVersioning::Mode vermode=sourcefl->versioningMode();
566 cool::FolderVersioning::Mode dvermode=vermode;
567 if (m_forcesingle) {
568 dvermode=cool::FolderVersioning::SINGLE_VERSION;
569 std::cout << "Forcing destination folder to singleversion" << std::endl;
570 }
571 if (m_forcemulti) {
572 dvermode=cool::FolderVersioning::MULTI_VERSION;
573 std::cout << "Forcing destination folder to multiversion" << std::endl;
574 }
575 // setup type of folder (payload mode, inline, separate, or vector)
576 const cool::PayloadMode::Mode spaymode=
577 sourcefl->folderSpecification().payloadMode();
578 cool::PayloadMode::Mode dpaymode=spaymode;
579
580 // set name for destination folder
581 std::string destfolder=folder;
582 if (!m_outfolder.empty()) {
583 destfolder=m_outfolder;
584 std::cout << "Destination folder will be renamed to " << destfolder <<
585 std::endl;
586 }
587
588// get destination folder, try to create if not there (and not verifying!)
589 bool created=false;
590 if (!m_nocopy && !m_root && !m_analyse) {
591 if (!m_destDbPtr->existsFolder(destfolder) && !m_verify) {
592 std::cout << "Creating folder " << destfolder << " payload-type " <<
593 dpaymode << " on destination" << std::endl;
594 created=true;
595 std::string metadata=sourcedesc;
596 if (m_forcerune || m_forcetime) {
597 std::string newmeta=m_forcerune ? "run-lumi" : "time";
598 std::string::size_type p1,p2;
599 p1=metadata.find("<timeStamp>");
600 p2=metadata.find("</timeStamp>");
601 if (p1!=std::string::npos && p2!=std::string::npos) {
602 metadata.replace(0,p2,"<timeStamp>"+newmeta);
603 std::cout << "Forced destination folder to " << newmeta << " : "
604 << metadata << std::endl;
605 } else {
606 std::cout <<
607 "ERROR: Could not parse metadata string to force timestamp type"
608 << std::endl;
609 }
610 }
611 // force separate or inline payload, but not if input is vector
612 if (m_forcepay && spaymode!=cool::PayloadMode::VECTORPAYLOAD)
613 dpaymode=cool::PayloadMode::SEPARATEPAYLOAD;
614 if (m_forcenopay && spaymode!=cool::PayloadMode::VECTORPAYLOAD)
615 dpaymode=cool::PayloadMode::INLINEPAYLOAD;
616
617 try {
618 if (iscora) {
619 destflc=m_destCoraPtr->createFolder(destfolder,
620 sourceflc->coralTableName(),
621 sourceflc->fkSpecification(),
622 sourceflc->payloadSpecification(),
623 sourceflc->coralFKey(),
624 sourceflc->coralPKey(),
625 metadata,dvermode,true);
626 std::cout << "Created CoraCool folder" << std::endl;
627 destfl=m_destDbPtr->getFolder(destfolder);
628 } else {
629 destfl=m_destDbPtr->createFolder(destfolder,
630 cool::FolderSpecification(dvermode,
631 sourcefl->payloadSpecification(),dpaymode),
632 metadata,true);
633 }
634 }
635 catch (cool::Exception&e ) {
636 std::cout << "Create folder failed - aborting" << std::endl;
637 return 30;
638 }
639 }
640 // now get the pointer to destination folder if needed
641 // note both COOL and CoraCool pointers are set if needed
642 try {
643 if (iscora) destflc=m_destCoraPtr->getFolder(destfolder);
644 destfl=m_destDbPtr->getFolder(destfolder);
645 }
646 catch (cool::Exception& e) {
647 std::cout << "Could not get destination folder: " << destfolder
648 << std::endl;
649 return 21;
650 }
651 // check payload specifications of folders are the same
652 const cool::IRecordSpecification& sourcespec=
653 sourcefl->payloadSpecification();
654 const cool::IRecordSpecification& destspec=
655 destfl->payloadSpecification();
656 if (!(sourcespec==destspec)) {
657 bool badspec=false;
658 if (m_ignorespec) {
659 // specifications differ - check names are same
660 std::cout <<
661 "WARNING Source and destination folder specifications differ" <<
662 std::endl;
663 for (unsigned int i=0;i<sourcespec.size();++i) {
664 const std::string& sname=sourcespec[i].name();
665 if (!destspec.exists(sname)) {
666 std::cout << "ERROR: Field " << sname << " absent from destination"
667 << std::endl;
668 badspec=true;
669 }
670 }
671 } else {
672 badspec=true;
673 }
674 if (badspec) {
675 std::cout <<
676 "ERROR Source and destination folder specifications differ"
677 << std::endl;
678 return 22;
679 }
680 }
681 // check folder descriptions are the same - just print WARNING if not
682 const std::string& destdesc=destfl->description();
683 if (sourcedesc!=destdesc) {
684 std::cout << "WARNING: Source and destination folder descriptions (meta-data) differ" << std::endl;
685 std::cout << "Source folder: " << sourcedesc << std::endl;
686 std::cout << "Destn folder: " << destdesc << std::endl;
687 }
688 // check payload modes are same - print warning if not
689 const cool::PayloadMode::Mode dpaymode=
690 destfl->folderSpecification().payloadMode();
691 if (spaymode!=dpaymode) {
692 std::cout << "WARNING: Source (" << spaymode << ") and destination (" <<
693 dpaymode << " folder payload modes differ" << std::endl;
694 }
695
696 // check/set channels table if requested
697 if (!m_nochannel) {
698 if (!checkChannels(folder,sourcefl,destfl,created)) return 23;
699 }
700 }
701 // if only copying structures, stop here
702 if (m_nodata) return 0;
703 // extract folder/range information
704 std::cout << "Start to process folder: " << folder;
705 // check for timestamp XML
706 bool timestamp=(sourcefl->description().find("<timeStamp>time")!=
707 std::string::npos);
708 cool::ValidityKey since,until;
709 if (timestamp) {
710 since=m_timemin;
711 until=m_timemax;
712 std::cout << " (timestamp)" << std::endl;
713 } else {
714 since=m_runemin;
715 until=m_runemax;
716 std::cout << " (run/lumi)" << std::endl;
717 }
718 if (m_alliov || m_truncate)
719 std::cout << "Output IOVs will be modified" << std::endl;
720 if (m_skipout)
721 std::cout << "IOVs extending outside selection range will be skipped"
722 << std::endl;
723
724 bool checkrefs=false;
725 const std::string name0=sourcefl->payloadSpecification()[0].name();
726 if (m_checkrefs && (name0=="PoolRef" || name0=="fileGUID")) {
727 checkrefs=true;
728 std::cout << "Check POOL references in folder " << folder << std::endl;
729 }
730 // if nocopy, and checking POOL references, and folder is not a POOL ref one
731 // can skip the data access
732 if (m_checkrefs && m_nocopy && !checkrefs) return 0;
733
734 // check for <fullrep/> metadata indicating copy all tags if -skiprep option
735 bool copyall=
736 (m_skiprep && (sourcedesc.find("<fullrep/>")!=std::string::npos));
737 if (copyall) std::cout <<
738 "All tags in folder will be copied due to <fullrep/> metadata" << std::endl;
739
740 // set up true list of tags to copy
741 std::vector<std::string> tags;
742 if (vermode==cool::FolderVersioning::SINGLE_VERSION) {
743 std::cout << "Single version folder" << std::endl;
744 tags.emplace_back("HEAD");
745 } else {
746 std::cout << "Multi version folder: consider tags [ ";
747 // get list of tags in this node which are requested
748 const std::vector<std::string> foldertags=sourcefl->listTags();
749 for (std::vector<std::string>::const_iterator itag=foldertags.begin();
750 itag!=foldertags.end();++itag) {
751 bool copyit=copyall;
752 // if input taglist is empty, take all tags in folder
753 if (taglist.empty() ||
754 find(taglist.begin(),taglist.end(),*itag)!=taglist.end())
755 copyit=true;
756 for (std::vector<std::string>::const_iterator imtag=m_magic.begin();
757 imtag!=m_magic.end();++imtag) {
758 if (itag->find(*imtag)!=std::string::npos) copyit=true;
759 }
760 if (copyit) {
761 tags.push_back(*itag);
762 std::cout << *itag << " ";
763 }
764 }
765 // if no tags were found, or doing inclusive hierarchical tag copying
766 // try resolving input tags hierarchically
767 if (tags.empty() || m_hitag) {
768 for (std::vector<std::string>::const_iterator itag=taglist.begin();
769 itag!=taglist.end();++itag) {
770 try {
771 std::string htag=sourcefl->resolveTag(*itag);
772 if (find(tags.begin(),tags.end(),htag)==tags.end()) {
773 std::cout << *itag << "=" << htag << " ";
774 tags.push_back(std::move(htag));
775 }
776 }
777 // ignore exceptions indicating tag not defined here
778 // note std::exception rather than COOL exception to cover case
779 // when trying to resolve a leaf tag in the '/' folder, which
780 // throws a coral AttributeException
781 catch (std::exception& e) { }
782 }
783 }
784 std::cout << "]" << std::endl;
785 // if still no tags were found, or forced HEAD tag copying, or no
786 // tags in the folder at all (=MV folder being used as SV), add HEAD
787 if (((tags.empty() || m_includehead) && !m_excludehead) ||
788 foldertags.empty())
789 tags.emplace_back("HEAD");
790 }
791
792 sourcefl->setPrefetchAll(false);
793 for (std::vector<std::string>::const_iterator itag=tags.begin();
794 itag!=tags.end();++itag) {
795 std::string outtag=*itag;
796 if (!m_outtag.empty()) outtag=m_outtag;
797 int retcode;
798 // verify or copy folder
799 if (m_verify) {
800 if (!destfl) {
801 retcode = 1;
802 }
803 else {
804 retcode=verifyIOVs(folder,sourcefl,sourceflc,destfl,destflc,
805 *itag,since,until,checkrefs,iscora,spaymode);
806 }
807 } else if (m_nocopy) {
808 retcode=nocopyIOVs(folder,sourcefl,*itag,since,until,checkrefs);
809 } else if (m_root) {
810 retcode=rootIOVs(folder,sourcefl,*itag,since,until,timestamp);
811 } else if (m_analyse) {
812 retcode=analyseIOVs(folder,sourcefl,*itag,since,until,timestamp);
813 } else {
814 retcode=copyIOVs(folder,destfolder,sourcefl,sourceflc,destfl,destflc,
815 *itag,outtag,since,until,timestamp,checkrefs,iscora,
816 spaymode,created);
817 }
818 if (retcode!=0) {
819 std::cout << "ERROR operation failed for folder " << folder << " tag " <<
820 *itag << std::endl;
821 return retcode;
822 }
823 }
824 return 0;
825}
826
827void AtlCoolCopy::setChannelRange(const cool::IFolderPtr& sourcefl) {
828 // add range specified via -ch1 -ch2 if given
829 if (!m_channel1.empty() && !m_channel2.empty()) {
830 m_channelRange.clear();
831 m_channelRange.push_back(m_channel1+":"+m_channel2);
832 }
833 m_chansel=cool::ChannelSelection::all();
834 const size_t nChanRange=m_channelRange.size();
835 for (size_t i=0;i<nChanRange;i++) {
836 size_t cpos=m_channelRange[i].find(':');
837 if (cpos==std::string::npos || cpos > m_channelRange[i].size()-1) {
838 // single channel
839 std::cout << "Adding channel " << m_channelRange[i] <<
840 " to channel selection" << std::endl;
841 if (m_chansel.allChannels())
842 m_chansel=cool::ChannelSelection(channelID(sourcefl,
843 m_channelRange[i]));
844 else
845 m_chansel.addChannel(channelID(sourcefl,m_channelRange[i]));
846 }
847 else {
848 // Channel Range
849 std::string c1=m_channelRange[i].substr(0,cpos);
850 std::string c2=m_channelRange[i].substr(1+cpos);
851 std::cout << "Adding channel range " << c1 << " to " << c2 <<
852 " to channel selection" << std::endl;
853 if (m_chansel.allChannels())
854 m_chansel=cool::ChannelSelection(channelID(sourcefl,c1),
855 channelID(sourcefl,c2));
856 else
857 m_chansel.addRange(channelID(sourcefl,c1),channelID(sourcefl,c2));
858 }
859 }//end loop over channel ranges
860}
861
862cool::ChannelId AtlCoolCopy::channelID(const cool::IFolderPtr& folder,
863 const std::string& chanstring) {
864 const char* cstr=chanstring.c_str();
865 if (isNumeric(cstr)) {
866 // channel is a number
867 return cool::ChannelId(strtoul(cstr,nullptr,10));
868 } else {
869 cool::ChannelId chan=0;
870 try {
871 chan=folder->channelId(chanstring);
872 std::cout << "Channel name " << chanstring << " maps to channelID "
873 << chan << std::endl;
874 }
875 catch (cool::Exception& e) {
876 std::cout << "ERROR: Channel name " << chanstring <<
877 " not defined in folder " << std::endl;
878 }
879 return chan;
880 }
881}
882
883// Calls non-thread-safe functions of CoraCoolFolder.
884int AtlCoolCopy::copyIOVs ATLAS_NOT_THREAD_SAFE
885 (const std::string& folder,
886 const std::string& destfolder,
887 const cool::IFolderPtr& sourcefl,const CoraCoolFolderPtr& sourceflc,
888 const cool::IFolderPtr& destfl,const CoraCoolFolderPtr& destflc,
889 const std::string& sourcetag,const std::string& desttag,
890 const cool::ValidityKey since,const cool::ValidityKey until,
891 bool timestamp,bool checkrefs,bool iscora,
892 const cool::PayloadMode::Mode paymode ,bool created) {
893
894 std::cout << "Copying tag " << sourcetag << " of folder " << folder <<
895 " to destination tag " << desttag << std::endl;
896 cool::FolderVersioning::Mode vermode=sourcefl->versioningMode();
897 cool::FolderVersioning::Mode dvermode=destfl->versioningMode();
898 // check for online mode
899 int updatemode=getUpdateMode(destfl->description(),desttag);
900 std::vector<std::string> dtaglist=destfl->listTags();
901 // if online mode, must have --getonline and either -truncate or -alliov
902 // only if destination DB is oracle
903 if (updatemode==1 && m_destdb.find("oracle")!=std::string::npos &&
904 (!m_getonline || (!m_truncate && !m_alliov))) {
905 if (m_ignoremode) {
906 std::cout << "Folder is online (UPD1) mode but IGNORING PROTECTION"
907 << std::endl;
908 } else {
909 if(find(dtaglist.begin(),dtaglist.end(),desttag)!=dtaglist.end()) {
910 std::cout << "Folder is online mode (UPD1) and tag already exist - -getonline and -truncate or -alliov options MUST be used" << std::endl;
911 return 35;
912 }
913 else {
914 std::cout << "Folder is online mode (UPD1), new tag will be created" << std::endl;
915 }
916
917 }
918 }
919 // if UPD4 mode, must have -getbulk and either -truncate or -alliov
920 if (updatemode==4 && m_destdb.find("oracle")!=std::string::npos &&
921 (!m_getbulk || (!m_truncate && !m_alliov))) {
922 if (m_ignoremode) {
923 std::cout << "Folder is bulkreco (UPD4) mode but IGNORING PROTECTION"
924 << std::endl;
925 } else {
926 if(find(dtaglist.begin(),dtaglist.end(),desttag)!=dtaglist.end()) {
927 std::cout << "Folder is bulkreco mode (UPD4) - -getbulk and -truncate or -alliov options MUST be used" << std::endl;
928 return 35;
929 } else {
930 std::cout << "Folder is bulkreco mode (UPD4), new tag will be created" << std::endl;
931 }
932
933 }
934 }
935
936 // if destination tags are being checked, check if this tag already
937 // exists in destination folder, if so skip copy
938 // also skip if tag is HEAD, and folder was not newly created
939 if (m_checkdesttag) {
940 if (find(dtaglist.begin(),dtaglist.end(),desttag)!=dtaglist.end()
941 || (desttag=="HEAD" && !created)) {
942 std::cout << "Destination tag " << desttag <<
943 " already exists in folder " << folder << " - skip copy" << std::endl;
944 return 0;
945 }
946 }
947 bool relock=false; // tag must be relocked afterwards
948 bool prot=false; //update is protected, irrespective of if tag must be locked
949 if ((m_applock || (updatemode==1 && m_getonline) || updatemode==2 ||
950 (updatemode==4 && m_getbulk)) &&
951 dvermode==cool::FolderVersioning::MULTI_VERSION) {
952 // check if the destination tag exists and is locked
953 std::vector<std::string> dtaglist=destfl->listTags();
954 for (std::vector<std::string>::const_iterator itr=dtaglist.begin();
955 itr!=dtaglist.end();++itr) {
956 if (desttag==*itr) {
957 // tag exists - must protect it unless ignoremode
958 prot=!m_ignoremode;
959 // check lock status
960 if (destfl->tagLockStatus(desttag)==cool::HvsTagLock::LOCKED) {
961 std::cout << "Unlocking destination tag " << desttag <<
962 " for append or UPDx access" << std::endl;
963 if (m_applocksv) {
964 std::cout << "Appending according to SV folder rules" << std::endl;
965 if (updatemode!=3) {
966 std::cout <<
967 "ERROR: Only allowed for UPD3 mode tags" << std::endl;
968 return 36;
969 }
970 }
971 destfl->setTagLockStatus(desttag,cool::HvsTagLock::UNLOCKED);
972 relock=true;
973 }
974 }
975 }
976 }
977 int nobj=0;
978 int nbuf=0;
979 int nskip=0;
980 int nbad=0;
981 // set up tag to be used at point of insertion
982 std::string localtag="";
983 if (dvermode==cool::FolderVersioning::MULTI_VERSION &&
984 desttag!="HEAD" && m_usertags) localtag=desttag;
985 // now loop over IOVs - separate for CoraCool and COOL
986 try {
987 if (iscora) {
988 // branch for CoraCool
989 sourceflc->setPrefetchAll(false);
990 CoraCoolObjectIterPtr sourceitr;
991 if (vermode==cool::FolderVersioning::SINGLE_VERSION) {
992 sourceitr=sourceflc->browseObjects(since,until,m_chansel);
993 } else {
994 sourceitr=sourceflc->browseObjects(since,until,m_chansel,sourcetag);
995 }
996 // keep track of new FKs of inserted objects
997 std::map<int,int> insertkeymap;
998 unsigned int nref=0;
999 while (sourceitr->hasNext()) {
1000 CoraCoolObjectPtr obj=sourceitr->next();
1001 // check object should not be skipped as spreading outside select-IOV
1002 if (m_skipout &&
1003 (obj->since()<m_srunemin || obj->until()>m_srunemax)) {
1004 ++nskip;
1005 continue;
1006 }
1007 // check object should not be skipped as excluded channel
1008 if (!m_excludechans.empty()) {
1009 if (find(m_excludechans.begin(),m_excludechans.end(),
1010 obj->channelId())!=m_excludechans.end()) {
1011 ++nskip;
1012 continue;
1013 }
1014 }
1015 if (nbuf==0) {
1016 if (m_debug) std::cout <<
1017 "Setup new CoraCool storage buffer at object " << nobj << std::endl;
1018 destflc->setupStorageBuffer();
1019 }
1020 cool::ValidityKey newsince,newuntil;
1021 adjustIOVs(obj->since(),obj->until(),since,until,newsince,newuntil,
1022 timestamp);
1023 // skip negative/zero IOV lengths
1024 if (newsince>=newuntil) {
1025 std::cout << "WARNING: Skipping IOV with since " << newsince <<
1026 ">= until" << newuntil << std::endl;
1027 ++nbad;
1028 continue;
1029 }
1030 // find the old FK, check if we have already inserted this
1031 // in which case a reference can be added
1032 int oldfk=0;
1033 std::map<int,int>::const_iterator ikey=insertkeymap.end();
1034 bool foundkey=false;
1035 // ensure returned data is not of zero size - if so cannot extract
1036 // and remember the FK
1037 if (obj->size()>0) {
1038 oldfk=sourceflc->getAttrKey(
1039 (*obj->begin())[sourceflc->coralFKey()]);
1040 ikey=insertkeymap.find(oldfk);
1041 foundkey=true;
1042 }
1043 if (ikey==insertkeymap.end()) {
1044 int newfk=
1045 destflc->storeObject(newsince,newuntil,obj->begin(),obj->end(),
1046 obj->channelId(),localtag,
1047 (!m_userupdatehead && !localtag.empty()));
1048 if (foundkey) insertkeymap[oldfk]=newfk;
1049 } else {
1050 destflc->referenceObject(newsince,newuntil,ikey->second,
1051 obj->channelId(),localtag,
1052 (!m_userupdatehead && !localtag.empty()));
1053 ++nref;
1054 }
1055 ++nbuf;
1056 // flush buffer every m_bufsize objects
1057 if (nbuf==m_bufsize) {
1058 if (m_debug) std::cout << "Flush buffer after " << nobj << "," <<
1059 nbuf << " objects " << std::endl;
1060 // note CoraCool requires explicit re-setup of buffer after a flush
1061 destflc->flushStorageBuffer();
1062 destflc->setupStorageBuffer();
1063 nbuf=0;
1064 }
1065 ++nobj;
1066 }
1067 sourceitr->close();
1068 if (nref>0) std::cout << "Reference-to-existing used for " << nref
1069 << " payload objects" << std::endl;
1070 if (nbuf>0) {
1071 if (m_debug) std::cout << "Final buffer flush at " << nobj <<
1072 "," << nbuf << std::endl;
1073 destflc->flushStorageBuffer();
1074 }
1075 } else {
1076 // branch for pure COOL objects
1077 cool::IObjectIteratorPtr sourceitr;
1078 if (vermode==cool::FolderVersioning::SINGLE_VERSION) {
1079 sourceitr=sourcefl->browseObjects(since,until,m_chansel);
1080 } else {
1081 sourceitr=sourcefl->browseObjects(since,until,m_chansel,sourcetag);
1082 }
1083 while (sourceitr->goToNext()) {
1084 const cool::IObject& obj=sourceitr->currentRef();
1085 // check object should not be skipped as spreading outside select-IOV
1086 if (m_skipout && (obj.since()<m_srunemin || obj.until()>m_srunemax)) {
1087 ++nskip;
1088 continue;
1089 }
1090 // check object should not be skipped as excluded channel
1091 if (!m_excludechans.empty()) {
1092 if (find(m_excludechans.begin(),m_excludechans.end(),
1093 obj.channelId())!=m_excludechans.end()) {
1094 ++nskip;
1095 continue;
1096 }
1097 }
1098 if (nbuf==0) {
1099 if (m_debug) std::cout << "Setup new storage buffer at object " <<
1100 nobj << std::endl;
1101 destfl->setupStorageBuffer();
1102 }
1103 cool::ValidityKey newsince;
1104 cool::ValidityKey newuntil;
1105 adjustIOVs(obj.since(),obj.until(),since,until,newsince,newuntil,
1106 timestamp);
1107 // skip negative/zero IOV lengths
1108 if (newsince>=newuntil) {
1109 std::cout << "WARNING: Skipping IOV with since " << newsince <<
1110 ">= until" << newuntil << std::endl;
1111 ++nbad;
1112 continue;
1113 }
1114 if (checkrefs) checkRef(obj.payload(),folder,sourcetag);
1115 if (prot) {
1116 // check existing data in destination DB to ensure no clash
1117 if (m_applocksv) {
1118 // appendlockedsv mode - all IOV ends must be infinite
1119 // and new since must be greater than old since
1120 if (newuntil!=cool::ValidityKeyMax) {
1121 std::cout << "New IOVs must have until=cool::ValidityKeyMax" << std::endl;
1122 throw cool::Exception("Illegal insert over locked IOV",
1123 "AtlCoolCopy");
1124 }
1125 cool::IObjectIteratorPtr checkitr=destfl->browseObjects(newsince,
1126 newuntil,obj.channelId(),desttag);
1127 while (checkitr->goToNext()) {
1128 const cool::IObject& checkobj=checkitr->currentRef();
1129 if (checkobj.since()>=newsince) {
1130 std::cout << "ERROR:: Attempt to insert SV overlapping IOV whilst appending to locked tag" << std::endl;
1131 throw cool::Exception("Illegal insert over locked IOV",
1132 "AtlCoolCopy");
1133 }
1134 if (checkobj.until()!=cool::ValidityKeyMax) {
1135 std::cout << "Existing IOVs must have until=cool::ValidityKeyMax" << std::endl;
1136 throw cool::Exception("Illegal insert over locked IOV",
1137 "AtlCoolCopy");
1138 }
1139 }
1140 checkitr->close();
1141 } else if (m_applock) {
1142 // appendlocked mode - just make sure no objects in this IOV
1143 const unsigned int nexist=
1144 destfl->countObjects(newsince,newuntil,obj.channelId(),desttag);
1145 if (nexist>0) {
1146 std::cout << "ERROR: Attempt to insert IOV over " << nexist <<
1147 " objects whilst appending to locked tag" << std::endl;
1148 throw cool::Exception("Illegal insert over locked IOV",
1149 "AtlCoolCopy");
1150 }
1151 } else if (updatemode==2) {
1152 // UPD2 tag - make sure run is on list of runs open for update
1153 // only for run/lumi based folders
1154 if (timestamp)
1155 throw cool::Exception(
1156 "Attempt to insert into locked UPD2 tag with timestamp format",
1157 "AtlCoolCopy");
1158 unsigned int run1=newsince >> 32;
1159 unsigned int run2=(newuntil-1) >> 32;
1160 for (unsigned int irun=run1;irun<=run2;++irun) {
1161 if (!std::binary_search(m_runlist.begin(),m_runlist.end(),irun))
1162 {
1163 std::cout << "Run " << irun << " from range [" << run1 << ","
1164 << run2 << "] not found in runfile list" << std::endl;
1165 throw cool::Exception("Illegal insert over locked IOV",
1166 "AtlCoolCopy");
1167 }
1168 }
1169 }
1170 // updatemode==1 will fall through, but no checks are done here
1171 }
1172 if (paymode==cool::PayloadMode::VECTORPAYLOAD) {
1173 // cool vector payload object copy
1174 cool::IRecordIterator& pitr=obj.payloadIterator();
1175 const cool::IRecordVectorPtr vptr=pitr.fetchAllAsVector();
1176 destfl->storeObject(newsince,newuntil,
1177 *vptr,obj.channelId(),localtag,
1178 (!m_userupdatehead && !localtag.empty()));
1179 nbuf+=vptr->size();
1180 pitr.close();
1181 } else {
1182 // standard COOL object copy
1183 destfl->storeObject(newsince,newuntil,
1184 obj.payload(),obj.channelId(),localtag,
1185 (!m_userupdatehead && !localtag.empty()));
1186 ++nbuf;
1187 }
1188 // flush buffer every m_bufsize objects
1189 if (nbuf>=m_bufsize) {
1190 if (m_debug) std::cout << "Flush buffer after " << nobj << "," <<
1191 nbuf << " objects " << std::endl;
1192 destfl->flushStorageBuffer();
1193 nbuf=0;
1194 }
1195 ++nobj;
1196 }
1197 // finished with the iterator
1198 sourceitr->close();
1199 if (nbuf>0) {
1200 if (m_debug) std::cout << "Final buffer flush at " << nobj <<
1201 "," << nbuf << std::endl;
1202 destfl->flushStorageBuffer();
1203 } // end of COOL-specific part
1204 }
1205 std::cout << "Folder copied with " << nobj << " objects" << std::endl;
1206 if (nskip>0) std::cout << nskip <<
1207 " objects were skipped extending outside IOV selection or excluded channel"
1208 << std::endl;
1209 if (nbad>0) std::cout << nbad <<
1210 " objects were skipped having zero or negative IOV lengths" << std::endl;
1211 }
1212 // exceptions thrown from insert loop (both COOL or CORACOOL)
1213 catch (cool::Exception& e) {
1214 std::cout << "Exception thrown from copy loop: " << e.what() <<
1215 std::endl;
1216 if (relock) {
1217 std::cout << "Relocking destination tag " << desttag << std::endl;
1218 destfl->setTagLockStatus(desttag,cool::HvsTagLock::LOCKED);
1219 }
1220 return 31;
1221 }
1222 // check if tag needs to be relocked
1223 if (relock) {
1224 std::cout << "Relocking destination tag " << desttag << std::endl;
1225 destfl->setTagLockStatus(desttag,cool::HvsTagLock::LOCKED);
1226 }
1227
1228 if (dvermode==cool::FolderVersioning::MULTI_VERSION && desttag!="HEAD") {
1229 if (!m_usertags) {
1230 // apply HEAD style tagging
1231 std::cout << "Tag folder with HEAD-style tagging for tag: " << desttag
1232 << std::endl;
1233 try {
1234 destfl->tagCurrentHead(desttag,sourcefl->tagDescription(sourcetag));
1235 }
1236 catch (cool::Exception& e) {
1237 std::cout << "Exception thrown in HEAD-style folder-tag: " <<
1238 e.what() << std::endl;
1239 return 32;
1240 }
1241 }
1242 // record information about this tag for later
1243 if (m_copytaginfo) m_cooltagmap.insert(
1244 CoolTagMap::value_type(desttag,CoolTagInfo(m_sourceDbPtr,folder,
1245 destfolder,sourcetag,desttag,m_taglabel)));
1246 // check if any hierarchical tags reference the just-copied tag
1247 if (!m_hitagmap.empty()) {
1248 for (HiTagMap::const_iterator imap=m_hitagmap.begin();
1249 imap!=m_hitagmap.end();++imap) {
1250 try {
1251 if (sourcefl->findTagRelation(imap->first)==sourcetag) {
1252 std::cout << "Create hierarchical tag between " << desttag <<
1253 " and " << imap->first << " in folder " << imap->second <<
1254 std::endl;
1255 // first check this relation has not already been created
1256 try {
1257 std::string etag=destfl->resolveTag(imap->first);
1258 if (etag==desttag) {
1259 std::cout << "This relation has already been created" << std::endl;
1260 } else {
1261 std::cout << "ERROR: Tag in parent already related to " <<
1262 desttag << std::endl;
1263 }
1264 }
1265 catch (cool::Exception& e ) {
1266 // only do creation if does not already exist - via exception
1267 try {
1268 destfl->createTagRelation(imap->first,desttag);
1269 // check if this implicates a new parent folder
1270 // to be checked for further tags up the tree
1271 if (find(m_hiparent.begin(),m_hiparent.end(),imap->second)==
1272 m_hiparent.end()) m_hiparent.push_back(imap->second);
1273 // store the original tag information to transfer
1274 // properties later
1275 if (m_copytaginfo &&
1276 m_cooltagmap.find(imap->first)==m_cooltagmap.end())
1277 m_cooltagmap.insert(CoolTagMap::value_type(imap->first,
1278 CoolTagInfo(m_sourceDbPtr,imap->second,imap->second,
1279 imap->first,imap->first)));
1280 }
1281 catch (cool::Exception& e) {
1282 std::cout << "Cool exception " << e.what() <<
1283 "thrown in hierarchical tag creation" << std::endl;
1284 return 34;
1285 }
1286 }
1287 }
1288 }
1289 catch (cool::Exception& e) {
1290 }
1291 }
1292 }
1293 }
1294 return 0;
1295}
1296
1297void AtlCoolCopy::adjustIOVs(const cool::ValidityKey& since,
1298 const cool::ValidityKey& until,
1299 const cool::ValidityKey& qsince,
1300 const cool::ValidityKey& quntil,
1301 cool::ValidityKey& newsince,
1302 cool::ValidityKey& newuntil,
1303 bool timestamp) const {
1304 // set newsince/until to since/until
1305 // but doing any required truncation/adjustment
1306 newsince=since;
1307 newuntil=until;
1308 if (m_alliov) {
1309 // make IOV cover specified range
1310 if (timestamp) {
1311 newsince=m_newtimemin;
1312 newuntil=m_newtimemax;
1313 } else {
1314 newsince=m_newrunemin;
1315 newuntil=m_newrunemax;
1316 }
1317 }
1318 // check for IOV truncation to range of query
1319 if (m_truncate) {
1320 if (newsince<qsince) newsince=qsince;
1321 if (newuntil>quntil) newuntil=quntil;
1322 }
1323 // check not requesting an IOV with negative length
1324 if (newuntil<newsince) throw cool::Exception(
1325 "Attempt to insert IOV with -ve length","AtlCoolCopy::adjustIOVs");
1326}
1327
1328int AtlCoolCopy::nocopyIOVs(const std::string& folder,
1329 const cool::IFolderPtr& sourcefl,const std::string& sourcetag,
1330 const cool::ValidityKey since,const cool::ValidityKey until,
1331 bool checkrefs) {
1332
1333 std::cout << "Reading tag " << sourcetag << " of folder " << folder <<
1334 " (no copy)" << std::endl;
1335 cool::FolderVersioning::Mode vermode=sourcefl->versioningMode();
1336 int nobj=0;
1337 cool::IObjectIteratorPtr sourceitr;
1338 if (vermode==cool::FolderVersioning::SINGLE_VERSION) {
1339 sourceitr=sourcefl->browseObjects(since,until,m_chansel);
1340 } else {
1341 sourceitr=sourcefl->browseObjects(since,until,m_chansel,sourcetag);
1342 }
1343 try {
1344 while (sourceitr->goToNext()) {
1345 const cool::IObject& obj=sourceitr->currentRef();
1346 if (checkrefs) checkRef(obj.payload(),folder,sourcetag);
1347 ++nobj;
1348 }
1349 std::cout << "Folder scanned with " << nobj << " objects" << std::endl;
1350 }
1351 // exceptions thrown from read loop
1352 catch (cool::Exception& e) {
1353 std::cout << "Exception thrown from read loop: " << e.what() <<
1354 std::endl;
1355 return 33;
1356 }
1357 // finished with the iterator
1358 sourceitr->close();
1359 return 0;
1360}
1361
1362int AtlCoolCopy::verifyIOVs(const std::string& folder,
1363 const cool::IFolderPtr& sourcefl,const CoraCoolFolderPtr& sourceflc,
1364 const cool::IFolderPtr& destfl,const CoraCoolFolderPtr& destflc,
1365 const std::string& sourcetag,
1366 const cool::ValidityKey since,const cool::ValidityKey until,
1367 const bool checkrefs,const bool iscora,
1368 const cool::PayloadMode::Mode paymode) {
1369
1370 std::cout << "Verifying tag " << sourcetag << " of folder " << folder <<
1371 std::endl;
1372 destfl->setPrefetchAll(false);
1373 cool::FolderVersioning::Mode vermode=sourcefl->versioningMode();
1374 int nobj=0;
1375 cool::IObjectIteratorPtr sourceitr,destitr;
1376 CoraCoolObjectIterPtr csourceitr,cdestitr;
1377 std::string tag=sourcetag;
1378 if (vermode==cool::FolderVersioning::SINGLE_VERSION || sourcetag=="HEAD")
1379 tag="";
1380 try {
1381 if (iscora) {
1382 sourceflc->setPrefetchAll(false);
1383 csourceitr=sourceflc->browseObjects(since,until,m_chansel,tag);
1384 cdestitr=destflc->browseObjects(since,until,m_chansel,tag);
1385 } else {
1386 sourceitr=sourcefl->browseObjects(since,until,m_chansel,tag);
1387 destitr=destfl->browseObjects(since,until,m_chansel,tag);
1388 }
1389 }
1390 catch (std::exception& e) {
1391 std::cout << "Exception thrown from verify iterator setup: " << e.what() <<
1392 std::endl;
1393 return 105;
1394 }
1395 try {
1396 // the check algorithm assumes the two databases will give back the
1397 // results of the query in the same order, which is currently the
1398 // case in COOL 1.3. If this changes, the verification will be more complex
1399 if (iscora) {
1400 const std::string& cfkey=sourceflc->coralFKey();
1401 const std::string& cpkey=sourceflc->coralPKey();
1402 while (csourceitr->hasNext()) {
1403 CoraCoolObjectPtr sobj=csourceitr->next();
1404 // check object should not be skipped as excluded channel
1405 if (!m_excludechans.empty()) {
1406 if (find(m_excludechans.begin(),m_excludechans.end(),
1407 sobj->channelId())!=m_excludechans.end()) {
1408 continue;
1409 }
1410 }
1411 if (cdestitr->hasNext()) {
1412 CoraCoolObjectPtr dobj=cdestitr->next();
1413 // check objects are the same
1414 int iret=0;
1415 // check IOV equality
1416 if (sobj->since()!=dobj->since() || sobj->until()!=dobj->until())
1417 iret=100;
1418 // check channel equality
1419 if (sobj->channelId()!=dobj->channelId())
1420 iret=101;
1421 // check size of payloads
1422 if (sobj->size()!=dobj->size()) {
1423 std::cout << "ERROR CoraCool object " << nobj <<
1424 " sizes do not match: " << sobj->size() << " " << dobj->size()
1425 << std::endl;
1426 iret=102;
1427 }
1428 // check payload equality (does not check attribute names)
1429 CoraCoolObject::const_iterator ditr=dobj->begin();
1430 for (CoraCoolObject::const_iterator sitr=sobj->begin();
1431 sitr!=sobj->end();++sitr,++ditr) {
1432 // loop over all the attributes, in order to skip PK and FK
1433 for (coral::AttributeList::const_iterator aitr=sitr->begin();
1434 aitr!=sitr->end();++aitr) {
1435 const std::string& aname=aitr->specification().name();
1436 if (aname!=cfkey && aname!=cpkey) {
1437 try {
1438 if (*aitr!=(*ditr)[aname]) {
1439 std::cout << "ERROR Values of attriute " << aname <<
1440 " differ" << std::endl;
1441 iret=102;
1442 }
1443 }
1444 catch (coral::AttributeListException& e) {
1445 std::cout << "ERROR: CoraCool attribute " << aname <<
1446 " not found in destination!" << std::endl;
1447 iret=102;
1448 }
1449 }
1450 }
1451 }
1452 if (iret!=0) {
1453 std::cout << "ERROR database entries do not match: since: " <<
1454 sobj->since() << "," << dobj->since() << " until: " <<
1455 sobj->until() << "," << dobj->until() << " channel: " <<
1456 sobj->channelId() << "," << dobj->channelId() << std::endl;
1457 return iret;
1458 }
1459 } else {
1460 std::cout <<
1461 "ERROR destination folder no matching CoraCool iterator for object "
1462 << nobj << std::endl;
1463 return 103;
1464 }
1465 ++ nobj;
1466 }
1467 } else {
1468 while (sourceitr->goToNext()) {
1469 const cool::IObject& sobj=sourceitr->currentRef();
1470 // check object should not be skipped as excluded channel
1471 if (!m_excludechans.empty()) {
1472 if (find(m_excludechans.begin(),m_excludechans.end(),
1473 sobj.channelId())!=m_excludechans.end()) {
1474 continue;
1475 }
1476 }
1477 if (checkrefs) checkRef(sobj.payload(),folder,sourcetag);
1478 if (destitr->goToNext()) {
1479 const cool::IObject& dobj=destitr->currentRef();
1480 // check objects are the same
1481 int iret=0;
1482 // check IOV equality
1483 if (sobj.since()!=dobj.since() || sobj.until()!=dobj.until())
1484 iret=100;
1485 // check channel equality
1486 if (sobj.channelId()!=dobj.channelId())
1487 iret=101;
1488 // check payload equality (does not check attribute names)
1489 // do not use cool::IRecord equality operator as does not correctly
1490 // handle null values
1491 if (paymode==cool::PayloadMode::VECTORPAYLOAD) {
1492 cool::IRecordIterator& spitr=sobj.payloadIterator();
1493 const cool::IRecordVectorPtr svptr=spitr.fetchAllAsVector();
1494 cool::IRecordIterator& dpitr=dobj.payloadIterator();
1495 const cool::IRecordVectorPtr dvptr=dpitr.fetchAllAsVector();
1496 if (svptr->size()!=dvptr->size()) {
1497 iret=102;
1498 } else {
1499 // loop through the payloads, checking equality - assumes
1500 // order is significant and same in source and destination DBs
1501 cool::IRecordVector::const_iterator svitr=svptr->begin();
1502 cool::IRecordVector::const_iterator svend=svptr->end();
1503 cool::IRecordVector::const_iterator dvitr=dvptr->begin();
1504 for (;svitr!=svend;++svitr,++dvitr) {
1505 if (!equalRecord(**svitr,**dvitr)) iret=102;
1506 }
1507 }
1508 if (iret!=0) {
1509 std::cout << "ERROR vector payloads do not match (size " << svptr->size() << "," << dvptr->size() << ")" << std::endl;
1510 }
1511
1512 } else {
1513 // standard COOL folder - simple check of payloads
1514 if (!equalRecord(sobj.payload(),dobj.payload())) iret=102;
1515 }
1516
1517 if (iret!=0) {
1518 std::cout << "ERROR database entries do not match: since: " <<
1519 sobj.since() << "," << dobj.since() << " until: " <<
1520 sobj.until() << "," << dobj.until() << " channel: " <<
1521 sobj.channelId() << "," << dobj.channelId() << std::endl;
1522 std::cout << "Source payload:" << std::endl;
1523 sobj.payload().attributeList().toOutputStream(std::cout);
1524 std::cout << std::endl << "Destination payload:" << std::endl;
1525 dobj.payload().attributeList().toOutputStream(std::cout);
1526 std::cout << std::endl;
1527 return iret;
1528 }
1529 } else {
1530 std::cout <<
1531 "ERROR destination folder no matching iterator for object "
1532 << nobj << std::endl;
1533 return 103;
1534 }
1535 ++nobj;
1536 }
1537 }
1538 }
1539 catch (cool::Exception& e) {
1540 std::cout << "Exception thrown from verify loop: " << e.what() <<
1541 std::endl;
1542 return 104;
1543 }
1544 // finished with the iterators
1545 if (iscora) {
1546 } else {
1547 sourceitr->close();
1548 destitr->close();
1549 }
1550 std::cout << "Verification of folder " << folder << " tag " <<
1551 sourcetag << " OK (" << nobj << " objects)" << std::endl;
1552 return 0;
1553}
1554
1555
1556
1557int AtlCoolCopy::rootIOVs(const std::string& folder,
1558 const cool::IFolderPtr& sourcefl,const std::string& sourcetag,
1559 const cool::ValidityKey since,const cool::ValidityKey until,
1560 const bool timestamp) {
1561 // copy this selection to ROOT
1562 std::cout << "Write tag " << sourcetag << " of folder " << folder <<
1563 " to ROOT file" << std::endl;
1564 // create the directory structure - top directory COOL
1565 std::string treename=rootDirs(folder,"COOL");
1566 bool timestamp2=timestamp;
1567 if (m_forcetime) timestamp2=true;
1568 if (m_forcerune) timestamp2=false;
1569 cool::FolderVersioning::Mode vermode=sourcefl->versioningMode();
1570 // create TTree with appropriate structure - only if it does not exist
1571 // could have been created from a previous tag in the same folder
1572 TTree* tree=static_cast<TTree*>(gDirectory->FindObject(treename.c_str()));
1573 if (tree==nullptr) {
1574 std::cout << "Book TTree " << treename << std::endl;
1575 tree=new TTree(treename.c_str(),"COOL datadump");
1576 if (timestamp2) {
1577 tree->Branch("IOVSince",&m_nt_since,"IOVSince/l");
1578 tree->Branch("IOVUntil",&m_nt_until,"IOVUntil/l");
1579 } else {
1580 tree->Branch("RunSince",&m_nt_runsince,"RunSince/i");
1581 tree->Branch("RunUntil",&m_nt_rununtil,"RunUntil/i");
1582 tree->Branch("LBSince",&m_nt_lbsince,"LBSince/i");
1583 tree->Branch("LBUntil",&m_nt_lbuntil,"LBUntil/i");
1584 }
1585 tree->Branch("ChannelID",&m_nt_channel,"ChannelID/i");
1586 if (vermode==cool::FolderVersioning::MULTI_VERSION)
1587 tree->Branch("TagID",m_nt_tagid,"TagID/C");
1588 // now loop through specification, creating payload buffer and tree
1589 const cool::IRecordSpecification& spec=
1590 (sourcefl->folderSpecification()).payloadSpecification();
1591 unsigned int ncolumns=spec.size();
1592 // clear the buffer of pointers - note this leaks the memory of the
1593 // previous buffers, but to do this properly would have to remember
1594 // the type of each object and delete appropriately
1595 m_nt_treename=std::move(treename);
1596 m_nt_bufferptr.clear();
1597 for (unsigned int icol=0;icol<ncolumns;++icol) {
1598 const cool::IFieldSpecification& fieldspec=spec[icol];
1599 void* ptr=nullptr;
1600 char rootID;
1601 if (rootAllocate(fieldspec,ptr,rootID)) {
1602 tree->Branch(fieldspec.name().c_str(),ptr,
1603 (fieldspec.name()+"/"+rootID).c_str());
1604 if (m_debug) std::cout << "Defining column for " << spec[icol].name()
1605 << " of type " << spec[icol].storageType().name() << std::endl;
1606 } else {
1607 std::cout << "Attribute " << spec[icol].name() << " of type " <<
1608 spec[icol].storageType().name() << " will be skipped" << std::endl;
1609 }
1610 m_nt_bufferptr.push_back(ptr);
1611 }
1612 } else {
1613 std::cout << "TTree " << treename << " already exists" << std::endl;
1614 // check we have seen and defined this tree
1615 unsigned int size=
1616 (sourcefl->folderSpecification()).payloadSpecification().size();
1617 if (treename!=m_nt_treename || size!=m_nt_bufferptr.size()) {
1618 std::cout << "ERROR in tree buffer definition: expect " << treename <<
1619 " size " << size << " but buffer has " << m_nt_treename << " size "
1620 << m_nt_bufferptr.size() << std::endl;
1621 return 123;
1622 }
1623 }
1624
1625 int nobj=0;
1626 int nex=0;
1627 cool::IObjectIteratorPtr sourceitr;
1628 try {
1629 if (vermode==cool::FolderVersioning::SINGLE_VERSION) {
1630 sourceitr=sourcefl->browseObjects(since,until,m_chansel);
1631 } else {
1632 sourceitr=sourcefl->browseObjects(since,until,m_chansel,sourcetag);
1633 }
1634 }
1635 catch (cool::Exception& e) {
1636 std::cout << "Exception thrown from ROOT copy iterator setup: " <<
1637 e.what() << std::endl;
1638 return 125;
1639 }
1640 // now loop over all IOVs to copy them
1641 try {
1642 while (sourceitr->goToNext()) {
1643 const cool::IObject& sobj=sourceitr->currentRef();
1644 if (timestamp2) {
1645 m_nt_since=sobj.since();
1646 m_nt_until=sobj.until();
1647 } else {
1648 m_nt_runsince=(sobj.since() >> 32);
1649 m_nt_rununtil=(sobj.until() >> 32);
1650 m_nt_lbsince=(sobj.since() & 0xFFFFFFFF);
1651 m_nt_lbuntil=(sobj.until() & 0xFFFFFFFF);
1652 }
1653 m_nt_channel=sobj.channelId();
1654 if (vermode==cool::FolderVersioning::MULTI_VERSION) {
1655 // truncate the string first to avoid coverity complaining about
1656 // potential buffer overruns
1657 std::string sourcetag2=sourcetag.substr(0,255);
1658 strncpy(m_nt_tagid,sourcetag2.c_str(),sizeof(m_nt_tagid)-1);
1659 }
1660 // loop over the payload elements and fill the ones for which buffers
1661 // are defined
1662 try {
1663 const cool::IRecord& record=sobj.payload();
1664 for (unsigned int icol=0;icol<record.size();++icol) {
1665 if (m_nt_bufferptr[icol]!=nullptr) rootWrite(m_nt_bufferptr[icol],record[icol]);
1666 }
1667 tree->Fill();
1668 ++nobj;
1669 }
1670 catch (cool::Exception& e) {
1671 // can get exceptions due to NULL values
1672 // catch them and continue...
1673 ++nex;
1674 }
1675 }
1676 sourceitr->close();
1677 std::cout << "Written " << nobj << " objects to ROOT TTree with " << nex
1678 << " nulls/exceptions" << std::endl;
1679 }
1680 catch (cool::Exception& e) {
1681 std::cout << "Exception thrown from ROOT file writing loop: " <<
1682 e.what() << std::endl;
1683 return 124;
1684 }
1685 return 0;
1686}
1687
1688std::string AtlCoolCopy::rootDirs(const std::string& folder,
1689 const std::string& toproot) {
1690 // create a ROOT directory structure start with toproot (=COOL or COOLANA)
1691 // and cd to the directory where a tree should be created
1692 // return the tree name (=leaf of the COOL foldername)
1693 p_rootfile->cd();
1694 if (p_rootfile->FindObject(toproot.c_str())==nullptr) {
1695 p_rootfile->mkdir(toproot.c_str());
1696 std::cout << "Made top directory " << toproot << std::endl;
1697 }
1698 gDirectory->cd(toproot.c_str());
1699 // now parse the COOL folder name to create intermediate directories
1700 // assume folder names begin with '/', to be skipped
1701 std::string::size_type iofs1=1;
1702 std::string::size_type iofs2=1;
1703 std::string treename;
1704 while (iofs2!=std::string::npos) {
1705 iofs2=folder.find('/',iofs1);
1706 if (iofs2==std::string::npos) {
1707 // no more /, so current part of string is leaf tree name
1708 treename=folder.substr(iofs1);
1709 } else {
1710 std::string dirname=folder.substr(iofs1,iofs2-iofs1);
1711 iofs1=iofs2+1;
1712 if (gDirectory->FindObject(dirname.c_str())==nullptr) {
1713 std::cout << "Make directory " << dirname << std::endl;
1714 gDirectory->mkdir(dirname.c_str());
1715 }
1716 gDirectory->cd(dirname.c_str());
1717 }
1718 }
1719 return treename;
1720}
1721
1722bool AtlCoolCopy::rootAllocate(const cool::IFieldSpecification& spec,
1723 void*& sptr,char& rootID) const {
1724 const cool::StorageType& stype=spec.storageType();
1725 rootID=' ';
1726 sptr=nullptr;
1727 if (stype==cool::StorageType::Bool) {
1728 // map bool to uint32 for now
1729 sptr=static_cast<void*>(new unsigned int(0));
1730 rootID='i';
1731 } else if (stype==cool::StorageType::UChar) {
1732 sptr=static_cast<void*>(new unsigned char(' '));
1733 rootID='C';
1734 } else if (stype==cool::StorageType::Int16) {
1735 sptr=static_cast<void*>(new short(0));
1736 rootID='S';
1737 } else if (stype==cool::StorageType::UInt16) {
1738 sptr=static_cast<void*>(new unsigned short(0));
1739 rootID='s';
1740 } else if (stype==cool::StorageType::Int32) {
1741 sptr=static_cast<void*>(new int(0));
1742 rootID='I';
1743 } else if (stype==cool::StorageType::UInt32) {
1744 sptr=static_cast<void*>(new unsigned int(0));
1745 rootID='i';
1746 } else if (stype==cool::StorageType::Int64) {
1747 sptr=static_cast<void*>(new long long int(0));
1748 rootID='L';
1749 } else if (stype==cool::StorageType::UInt63) {
1750 sptr=static_cast<void*>(new unsigned long long int(0));
1751 rootID='l';
1752 } else if (stype==cool::StorageType::Float) {
1753 sptr=static_cast<void*>(new float(0.));
1754 rootID='F';
1755 } else if (stype==cool::StorageType::Double) {
1756 sptr=static_cast<void*>(new double(0.));
1757 rootID='D';
1758 } else if (stype==cool::StorageType::String4k ||
1759 stype==cool::StorageType::String255) {
1760 sptr=static_cast<void*>(new char[4100]);
1761 rootID='C';
1762 } else if (stype==cool::StorageType::String64k && !m_noclobroot) {
1763 sptr=static_cast<void*>(new char[65536]);
1764 rootID='C';
1765 } else if (stype==cool::StorageType::String16M && !m_noclobroot) {
1766 sptr=static_cast<void*>(new char[67108864]);
1767 rootID='C';
1768 } else if (stype==cool::StorageType::Blob64k && !m_noclobroot) {
1769 sptr=static_cast<void*>(new char[65536]);
1770 rootID='C';
1771 } else {
1772 std::cout << "rootAllocate: Unsupported storage type for attribute: " <<
1773 spec.name() << std::endl;
1774 }
1775 return (sptr!=nullptr);
1776}
1777
1778void AtlCoolCopy::rootWrite(void* sptr,const cool::IField& field) const {
1779 // check for NULL value
1780 bool recnull=(field.isNull() && m_zeronull);
1781 const cool::StorageType& stype=field.storageType();
1782 if (stype==cool::StorageType::Bool) {
1783 if (recnull) {
1784 *(static_cast<int*>(sptr))=0;
1785 } else {
1786 *(static_cast<int*>(sptr))=(field.data<bool>() ? 1 : 0);
1787 }
1788 } else if (stype==cool::StorageType::UChar) {
1789 if (recnull) {
1790 *(static_cast<unsigned char*>(sptr))=0;
1791 } else {
1792 *(static_cast<unsigned char*>(sptr))=field.data<unsigned char>();
1793 }
1794 } else if (stype==cool::StorageType::Int16) {
1795 if (recnull) {
1796 *(static_cast<short*>(sptr))=0;
1797 } else {
1798 *(static_cast<short*>(sptr))=field.data<short>();
1799 }
1800 } else if (stype==cool::StorageType::UInt16) {
1801 if (recnull) {
1802 *(static_cast<unsigned short*>(sptr))=0;
1803 } else {
1804 *(static_cast<unsigned short*>(sptr))=field.data<unsigned short>();
1805 }
1806 } else if (stype==cool::StorageType::Int32) {
1807 if (recnull) {
1808 *(static_cast<int*>(sptr))=0;
1809 } else {
1810 *(static_cast<int*>(sptr))=field.data<int>();
1811 }
1812 } else if (stype==cool::StorageType::UInt32) {
1813 if (recnull) {
1814 *(static_cast<unsigned int*>(sptr))=0;
1815 } else {
1816 *(static_cast<unsigned int*>(sptr))=field.data<unsigned int>();
1817 }
1818 } else if (stype==cool::StorageType::Int64) {
1819 if (recnull) {
1820 *(static_cast<long long*>(sptr))=0;
1821 } else {
1822 *(static_cast<long long*>(sptr))=field.data<long long>();
1823 }
1824 } else if (stype==cool::StorageType::UInt63) {
1825 if (recnull) {
1826 *(static_cast<unsigned long long*>(sptr))=0;
1827 } else {
1828 *(static_cast<unsigned long long*>(sptr))=field.data<unsigned long long>();
1829 }
1830 } else if (stype==cool::StorageType::Float) {
1831 if (recnull) {
1832 *(static_cast<float*>(sptr))=0.;
1833 } else {
1834 *(static_cast<float*>(sptr))=field.data<float>();
1835 }
1836 } else if (stype==cool::StorageType::Double) {
1837 if (recnull) {
1838 *(static_cast<double*>(sptr))=0.;
1839 } else {
1840 *(static_cast<double*>(sptr))=field.data<double>();
1841 }
1842 } else if (stype==cool::StorageType::String255 ||
1843 stype==cool::StorageType::String4k ||
1844 stype==cool::StorageType::String64k ||
1845 stype==cool::StorageType::String16M) {
1846 if (recnull) {
1847 strcpy(static_cast<char*>(sptr),"NULL");
1848 } else {
1849 strcpy(static_cast<char*>(sptr),field.data<std::string>().c_str());
1850 }
1851 } else if (stype==cool::StorageType::Blob64k && !m_noclobroot) {
1852 if (recnull) {
1853 strcpy(static_cast<char*>(sptr),"NULL");
1854 } else {
1855 auto blob = field.data<coral::Blob>();
1856 std::string blobStr((char*)blob.startingAddress(), blob.size());
1857 strcpy(static_cast<char*>(sptr), blobStr.c_str());
1858 }
1859 } else {
1860 std::cout << "ERROR: Unknown storage type in rootWrite!" << std::endl;
1861 }
1862}
1863
1864int AtlCoolCopy::analyseIOVs(const std::string& folder,
1865 const cool::IFolderPtr& sourcefl,const std::string& sourcetag,
1866 const cool::ValidityKey since,const cool::ValidityKey until,
1867 const bool timestamp) {
1868 // analyse the IOV and channel structure of this folder/tag, make ROOT histos
1869 std::cout << "Analyse tag " << sourcetag << " of folder " << folder <<
1870 std::endl;
1871 bool anatime=(m_anadelt>=0);
1872 if (anatime) {
1873 std::cout << "Analyse time structures with tolerance of " <<
1874 m_anadelt/1.E9 << " seconds " << std::endl;
1875 }
1876 // create COOLANA/folder structure and create leaf directory for histograms
1877 std::string dirname=rootDirs(folder,"COOLANA");
1878 if (gDirectory->FindObject(dirname.c_str())==nullptr) {
1879 std::cout << "Make directory " << dirname << std::endl;
1880 gDirectory->mkdir(dirname.c_str());
1881 }
1882 gDirectory->cd(dirname.c_str());
1883 // get channels
1884 std::vector<cool::ChannelId> channels=sourcefl->listChannels();
1885 unsigned int nchan=channels.size();
1886 // end of last IOV seen on this channel
1887 long long* lastiov=new long long[nchan];
1888 long long* iovtotlen=new long long[nchan];
1889 long long* iovtotgap=new long long[nchan];
1890 int* iovn=new int[nchan];
1891 for (unsigned int i=0;i<nchan;++i) {
1892 lastiov[i]=-1; // no IOV seen on this channel yet
1893 iovtotlen[i]=0;
1894 iovtotgap[i]=0;
1895 iovn[i]=0;
1896 }
1897 cool::ValidityKey globsince=cool::ValidityKeyMax;
1898 cool::ValidityKey globuntil=cool::ValidityKeyMin;
1899
1900 // book histograms - only if the objects do not already exist (previous tag)
1901 TH1F* h_iovchan=bookOrFindTH1F("IOVSperChannel","IOVs per channel",
1902 nchan,-0.5,nchan-0.5);
1903 TH1F* h_iovname=bookOrFindTH1F("IOVSperChannelName",
1904 "IOVs per channel-name (copy of IOVSperChannel)",
1905 nchan,-0.5,nchan-0.5);
1906 TH1F* h_iovlength=bookOrFindTH1F("IOVLogLength","IOV log10 length",
1907 100,0.,20.);
1908 TH1F* h_iovgap=bookOrFindTH1F("IOVLogGapLength","IOV log10 gap length",
1909 100,0.,20.);
1910 // histograms for time analysis if needed
1911 TH1F* h_anadelt=nullptr;
1912 TH1F* h_chandelt=nullptr;
1913 if (anatime) {
1914 h_anadelt=bookOrFindTH1F("IOVAlignLogDelT","IOV alignment log deltaT",
1915 100,0.,20.);
1916 // add factor 2 in number of channels, to catch those where a channel
1917 // changes many times within the m_anadelt window (i.e. noise/jitter)
1918 h_chandelt=bookOrFindTH1F("AlignedChanPerIOV","Aligned channels per IOV",
1919 nchan*2,0.5,nchan*2-0.5);
1920 }
1921 std::cout << "Booked histograms for folder with " << nchan << " channels"
1922 << std::endl;
1923 // setup storage for IOV time analysis
1924 using IOVTimeMap = std::map<cool::ValidityKey, int>;
1925 IOVTimeMap iov_time_map;
1926
1927 // setup iterator to loop over objects
1928 int nobj=0;
1929 cool::FolderVersioning::Mode vermode=sourcefl->versioningMode();
1930 cool::IObjectIteratorPtr sourceitr;
1931 try {
1932 if (vermode==cool::FolderVersioning::SINGLE_VERSION) {
1933 sourceitr=sourcefl->browseObjects(since,until,m_chansel);
1934 } else {
1935 sourceitr=sourcefl->browseObjects(since,until,m_chansel,sourcetag);
1936 }
1937 }
1938 catch (cool::Exception& e) {
1939 std::cout << "Exception thrown from analysis copy iterator setup: " <<
1940 e.what() << std::endl;
1941 return 135;
1942 }
1943 // look up names of all the channels in one go
1944 std::map<cool::ChannelId,std::string>
1945 chanmap=sourcefl->listChannelsWithNames();
1946 // now loop over all IOVs and write them
1947 try {
1948 while (sourceitr->goToNext()) {
1949 const cool::IObject& sobj=sourceitr->currentRef();
1950 // get channel and find its index
1951 cool::ChannelId ichanid=sobj.channelId();
1952 const std::string& cname=chanmap[ichanid];
1953 std::pair<std::vector<cool::ChannelId>::iterator,
1954 std::vector<cool::ChannelId>::iterator > chanitr=
1955 std::equal_range(channels.begin(),channels.end(),ichanid);
1956 if (chanitr.first!=chanitr.second) {
1957 cool::ChannelId ichan=std::distance(channels.begin(),chanitr.first);
1958 Int_t bin=h_iovchan->Fill(ichan);
1959 if (ichan && !h_iovname->GetBinContent(bin)) {
1960 h_iovname->GetXaxis()->SetBinLabel(bin,cname.c_str());
1961 }
1962 h_iovname->Fill(ichan);
1963 // analyse IOV start/stop
1964 cool::ValidityKey since2=sobj.since();
1965 cool::ValidityKey until2=sobj.until();
1966 if (since2<globsince) globsince=since2;
1967 // dont count IOV is open-ended, so length statistics will make sense
1968 if (until2!=cool::ValidityKeyMax) {
1969 if (until2>globuntil) globuntil=until2;
1970 long long len=until2-since2;
1971 h_iovlength->Fill(log10(len));
1972 iovn[ichan]+=1;
1973 iovtotlen[ichan]+=len;
1974 }
1975 if (lastiov[ichan]<static_cast<long long>(since2) &&
1976 lastiov[ichan]>=0) {
1977 // have a gap in the IOV structure for this channel
1978 long long gap=since2-lastiov[ichan];
1979 iovtotgap[ichan]+=gap;
1980 h_iovgap->Fill(log10(gap));
1981 std::cout << "Gap of " << gap << std::endl;
1982 }
1983 if (until2!=cool::ValidityKeyMax) {
1984 lastiov[ichan]=until2;
1985 } else {
1986 lastiov[ichan]=since2;
1987 }
1988 // analyse IOV alignment
1989 if (anatime) {
1990 long long del1=-1;
1991 long long del2=-1;
1992 // find the nearest time to this one
1993 // this gives the first value exceeding since2
1994 IOVTimeMap::iterator hiitr=iov_time_map.lower_bound(since2);
1995 IOVTimeMap::iterator lowitr=hiitr;
1996 if (hiitr!=iov_time_map.end()) {
1997 // del1 is +ve time interval to next one
1998 del1=hiitr->first-since2;
1999 }
2000 if (lowitr!=iov_time_map.begin()) {
2001 // del2 is +ve time interval to previous one
2002 --lowitr;
2003 del2=since2-lowitr->first;
2004 }
2005 long long del=-1;
2006 IOVTimeMap::iterator moditr;
2007 bool domod=false;
2008 if (del1<=m_anadelt && del1>-1) {
2009 moditr=hiitr;
2010 del=del1;
2011 domod=true;
2012 }
2013 if (del2<=m_anadelt && del2>-1 && (del2<del || del==-1)) {
2014 moditr=lowitr;
2015 del=del2;
2016 domod=true;
2017 }
2018 if (domod) {
2019 ++(moditr->second);
2020 if (del>0) {
2021 h_anadelt->Fill(log10(del));
2022 } else {
2023 h_anadelt->Fill(0.);
2024 }
2025 } else {
2026 iov_time_map[since2]=0;
2027 }
2028 }
2029 } else {
2030 // channel ID not found
2031 std::cout << "ERROR :Channel " << ichanid <<
2032 " not found in channel list - ignored" << std::endl;
2033 }
2034 ++nobj;
2035 }
2036 std::cout << "Finished analysis with " << nobj << " objects" << std::endl;
2037 if (timestamp) {
2038 std::cout << "IOV timestamp range: " << globsince << " " <<
2039 timeString(globsince) << "to " << globuntil << " " <<
2040 timeString(globuntil) << std::endl;
2041 } else {
2042 std::cout << "IOV run/LB range [" << (globsince >> 32) << "," <<
2043 (globsince & 0xFFFFFFFF) << "] to [" << (globuntil >> 32) << "," <<
2044 (globuntil & 0xFFFFFFFF) << "]" << std::endl;
2045 }
2046 // calculate statistics for each channel
2047 TH1F* h_iovoccchan=bookOrFindTH1F("ChannelOcc","Channel Occupancy",
2048 nchan,-0.5,nchan-0.5);
2049 TH1F* h_iovlenchan=bookOrFindTH1F("IOVLenChan",
2050 "Mean IOV length per channel",nchan,-0.5,nchan-0.5);
2051 for (unsigned int i=0;i<nchan;++i) {
2052 float occ=0.;
2053 float avlen=0.;
2054 if (iovn[i]>0) {
2055 occ=1.-float(iovtotgap[i])/float(iovtotlen[i]+iovtotgap[i]);
2056 avlen=float(iovtotlen[i])/iovn[i];
2057 }
2058 h_iovoccchan->Fill(i,occ);
2059 h_iovlenchan->Fill(i,avlen);
2060 }
2061 if (anatime) {
2062 std::cout << "Alignment analysis: " << iov_time_map.size()
2063 << " seperate IOV starts (tolerance " << m_anadelt/1.E9 <<
2064 " seconds)" << std::endl;
2065 // fill histogram of number of channels incremented per IOV
2066 for (IOVTimeMap::const_iterator itr=iov_time_map.begin();
2067 itr!=iov_time_map.end();++itr) {
2068 h_chandelt->Fill(itr->second);
2069 }
2070 }
2071 }
2072 catch (cool::Exception& e) {
2073 std::cout << "Exception thrown from folder analysis reading loop: " <<
2074 e.what() << std::endl;
2075 return 134;
2076 }
2077 sourceitr->close();
2078 delete [] lastiov;
2079 delete [] iovtotlen;
2080 delete [] iovtotgap;
2081 delete[] iovn; iovn=nullptr;
2082 return 0;
2083}
2084
2085TH1F* AtlCoolCopy::bookOrFindTH1F(const std::string& hID,
2086 const std::string& htitle,
2087 const int nchan, const float xlow, const float xhigh) {
2088 // check histogram does not exist in current directory
2089 // if yes, return pointer to it, else book and return pointer
2090 TObject* obj=gDirectory->FindObject(hID.c_str());
2091 if (obj==nullptr) {
2092 return new TH1F(hID.c_str(),htitle.c_str(),nchan,xlow,xhigh);
2093 } else {
2094 return static_cast<TH1F*>(obj);
2095 }
2096}
2097
2098
2099int AtlCoolCopy::doCopy ATLAS_NOT_THREAD_SAFE () {
2100 if (isOpen()) {
2101 int retcode=0;
2102 // execute copy for all defined folders
2103 for (std::vector<std::string>::const_iterator ifolder=
2104 m_folderlist.begin();ifolder!=m_folderlist.end();++ifolder) {
2105 int code=copyFolder(*ifolder,m_tags);
2106 if (code>retcode) retcode=code;
2107 }
2108 if (!m_hiparent.empty()) {
2109 // fill in any hierarchical tags for parent folders
2110 int code=tagParents();
2111 if (code>retcode) retcode=code;
2112 }
2113 if (m_copytaginfo) {
2114 // write information (tag description, lock status) to dest tags
2115 int code=writeTagInfo();
2116 if (code>retcode) retcode=code;
2117 }
2118 if (m_checkrefs) {
2119 int code=0;
2120 if (m_poolcat.empty()) {
2121 code=listPoolRefs();
2122 if (!m_checkoutputfile.empty()) filePoolRefs();
2123 } else {
2124 code=resolvePoolRefs();
2125 }
2126 if (code>retcode) retcode=code;
2127 }
2128 if (p_rootfile) {
2129 p_rootfile->Write();
2130 delete p_rootfile;
2131 }
2132 return retcode;
2133 } else {
2134 return 10;
2135 }
2136}
2137
2138bool AtlCoolCopy::procOptVector(const int argc, const char* argv[],
2139 std::vector<std::string>& folders) {
2140 // process an array of options, return True if OK, False if not
2141 int ic=0;
2142 bool error=false;
2143 while (ic<argc) {
2144 int ir=argc-ic;
2145 std::string_view par0=argv[ic];
2146 // strip double "--" to achieve compatability with python-style options
2147 if (par0.compare(0,2,"--")==0) par0=par0.substr(1);
2148 if ((par0=="-f" || par0=="-folder") && ir>1) {
2149 folders.emplace_back(argv[ic+1]);
2150 ++ic;
2151 } else if ((par0=="-e" || par0=="-exclude") && ir>1) {
2152 addExclude(argv[ic+1]);
2153 ++ic;
2154 } else if ((par0=="-t" || par0=="-tag") && ir>1) {
2155 m_tags.emplace_back(argv[ic+1]);
2156 ++ic;
2157 } else if ((par0=="-mt" || par0=="-magic") && ir>1) {
2158 m_magic.push_back("_"+std::string(argv[ic+1]));
2159 ++ic;
2160 } else if ((par0=="-of" || par0=="-outfolder") && ir>1) {
2161 m_outfolder=argv[ic+1];
2162 ++ic;
2163 } else if ((par0=="-ot" || par0=="-outtag") && ir>1) {
2164 m_outtag=argv[ic+1];
2165 ++ic;
2166 } else if ((par0=="-bs" || par0=="-buffersize") && ir>1) {
2167 m_bufsize=atoi(argv[ic+1]);
2168 ++ic;
2169 } else if ((par0=="-sl" || par0=="-seal") && ir>1) {
2170 m_sealmsg=atoi(argv[ic+1]);
2171 ++ic;
2172 } else if ((par0=="-rls" || par0=="-runlumisince") && ir>2) {
2173 m_runemin=runLBVal(argv[ic+1],argv[ic+2]);
2174 ic+=2;
2175 } else if ((par0=="-rlu" || par0=="-runlumiuntil") && ir>2) {
2176 m_runemax=runLBVal(argv[ic+1],argv[ic+2]);
2177 ic+=2;
2178 } else if ((par0=="-nrls" || par0=="-newrunlumisince") && ir>2) {
2179 m_newrunemin=runLBVal(argv[ic+1],argv[ic+2]);
2180 ic+=2;
2181 } else if ((par0=="-nrlu" || par0=="-newrunlumiuntil") && ir>2) {
2182 m_newrunemax=runLBVal(argv[ic+1],argv[ic+2]);
2183 ic+=2;
2184 } else if ((par0=="-srls" || par0=="-skiprunlumisince") && ir>2) {
2185 m_srunemin=runLBVal(argv[ic+1],argv[ic+2]);
2186 m_skipout=true;
2187 ic+=2;
2188 } else if ((par0=="-srlu" || par0=="-skiprunlumiuntil") && ir>2) {
2189 m_srunemax=runLBVal(argv[ic+1],argv[ic+2]);
2190 m_skipout=true;
2191 ic+=2;
2192 } else if (par0=="-ro" || par0=="-root") {
2193 m_root=true;
2194 } else if (par0=="-zn" || par0=="-zeronull") {
2195 m_zeronull=true;
2196 } else if (par0=="-ana" || par0=="-analyse") {
2197 m_analyse=true;
2198 float ttime=atof(argv[ic+1])*1.E9;
2199 m_anadelt=static_cast<long long>(ttime);
2200 ++ic;
2201 } else if ((par0=="-rs" || par0=="-runsince") && ir>1) {
2202 m_runemin=(static_cast<long long>(atol(argv[ic+1])) << 32);
2203 ++ic;
2204 } else if ((par0=="-ru" || par0=="-rununtil") && ir>1) {
2205 m_runemax=(static_cast<long long>(1+atol(argv[ic+1])) << 32)-1;
2206 ++ic;
2207 } else if ((par0=="-r" || par0=="-run") && ir>1) {
2208 m_runemin=(static_cast<long long>(atol(argv[ic+1])) << 32);
2209 m_runemax=(static_cast<long long>(1+atol(argv[ic+1])) << 32)-1;
2210 ++ic;
2211 } else if ((par0=="-ts" || par0=="-timesince") && ir>1) {
2212 m_timemin=timeVal(argv[ic+1]);
2213 ++ic;
2214 } else if ((par0=="-tu" || par0=="-timeuntil") && ir>1) {
2215 m_timemax=timeVal(argv[ic+1]);
2216 ++ic;
2217 } else if ((par0=="-nts" || par0=="-newtimesince") && ir>1) {
2218 m_newtimemin=timeVal(argv[ic+1]);
2219 ++ic;
2220 } else if ((par0=="-ntu" || par0=="-newtimeuntil") && ir>1) {
2221 m_newtimemax=timeVal(argv[ic+1]);
2222 ++ic;
2223 } else if (par0=="-c" || par0=="-create") {
2224 m_allowcreate=true;
2225 } else if ((par0=="-ch" || par0=="-channel") && ir>1) {
2226 m_channelRange.emplace_back(argv[ic+1]);
2227 ++ic;
2228 } else if ((par0=="-ch1" || par0=="-channel1") && ir>1) {
2229 m_channel1=argv[ic+1];
2230 ++ic;
2231 } else if ((par0=="-ch2" || par0=="-channel2") && ir>1) {
2232 m_channel2=argv[ic+1];
2233 ++ic;
2234 } else if (par0=="-chd" || par0=="-channeldesc") {
2235 m_chdesc=true;
2236 // no abbreviaton for this one - dangerous option
2237 } else if (par0=="-forcerecreate") {
2238 m_recreate=true;
2239 } else if (par0=="-d" || par0=="-debug") {
2240 m_debug=true;
2241 } else if (par0=="-a" || par0=="-alliov") {
2242 m_alliov=true;
2243 } else if (par0=="-ih" || par0=="-includehead") {
2244 m_includehead=true;
2245 } else if (par0=="-eh" || par0=="-excludehead") {
2246 m_excludehead=true;
2247 } else if (par0=="-ht" || par0=="-headtag") {
2248 m_usertags=false;
2249 } else if (par0=="-uht" || par0=="-userheadtag") {
2250 m_userupdatehead=true;
2251 } else if (par0=="-v" || par0=="-verify") {
2252 m_verify=true;
2253 } else if (par0=="-nc" || par0=="-nocopy") {
2254 m_nocopy=true;
2255 } else if (par0=="-noc" || par0=="-nocoracool") {
2256 m_coracool=false;
2257 } else if (par0=="-nch" || par0=="-nochannel") {
2258 m_nochannel=true;
2259 } else if (par0=="-ncr" || par0=="-noclobroot") {
2260 m_noclobroot=true;
2261 } else if (par0=="-nd" || par0=="-nodata") {
2262 m_nodata=true;
2263 } else if (par0=="-nh" || par0=="-nohitag") {
2264 m_nohitag=true;
2265 } else if (par0=="-hi" || par0=="-hitag") {
2266 m_hitag=true;
2267 } else if ((par0=="-ec" || par0=="-excludechannel") && ir>1) {
2268 m_excludechans.push_back(strtoul(argv[ic+1],nullptr,10));
2269 ++ic;
2270 } else if (par0=="-fs" || par0=="-forcesingle") {
2271 m_forcesingle=true;
2272 } else if (par0=="-fm" || par0=="-forcemulti") {
2273 m_forcemulti=true;
2274 } else if (par0=="-frl" || par0=="-forcerunlumi") {
2275 m_forcerune=true;
2276 } else if (par0=="-ftm" || par0=="-forcetime") {
2277 m_forcetime=true;
2278 } else if (par0=="-fp" || par0=="-forcepayload") {
2279 m_forcepay=true;
2280 } else if (par0=="-fnp" || par0=="-forcenopayload") {
2281 m_forcenopay=true;
2282 } else if (par0=="-cr" || par0=="-checkrefs") {
2283 m_checkrefs=true;
2284 } else if (par0=="-lp" || par0=="-listpfn") {
2285 m_listpfn=true;
2286 m_checkrefs=true;
2287 } else if (par0=="-cf" || par0=="-checkfiles") {
2288 m_poolopen=true;
2289 m_checkrefs=true;
2290 } else if (par0=="-pa" || par0=="-poolall") {
2291 m_poolall=true;
2292 } else if ((par0=="-co" || par0=="-checkoutput") && ir>1) {
2293 m_checkoutputfile=argv[ic+1];
2294 ++ic;
2295 } else if ((par0=="-pc" || par0=="-poolcat") && ir>1) {
2296 m_poolcat.emplace_back(argv[ic+1]);
2297 ++ic;
2298 } else if ((par0=="-mc" || par0=="-mergecat") && ir>1) {
2299 m_mergecat.emplace_back(argv[ic+1]);
2300 ++ic;
2301 } else if ((par0=="-ds" || par0=="-dataset") && ir>1) {
2302 m_newdataset=argv[ic+1];
2303 ++ic;
2304 } else if (par0=="-us" || par0=="-updatesource") {
2305 m_sourceread=false;
2306 } else if (par0=="-cd" || par0=="-checkdest") {
2307 m_checkdesttag=true;
2308 } else if (par0=="-tr" || par0=="-truncate") {
2309 m_truncate=true;
2310 } else if (par0=="-al" || par0=="-appendlocked") {
2311 m_applock=true;
2312 } else if (par0=="-alsv" || par0=="-appendlockedsv") {
2313 m_applock=true;
2314 m_applocksv=true;
2315 } else if (par0=="-rdo" || par0=="-readoracle") {
2316 m_readoracle=true;
2317 } else if (par0=="-skiprep" || par0=="-sr") {
2318 m_skiprep=true;
2319 } else if (par0=="-go" || par0=="-getonline") {
2320 m_getonline=true;
2321 } else if (par0=="-onr" || par0=="-onlinerun") {
2322 m_onlinerun=true;
2323 } else if (par0=="-gb" || par0=="-getbulk") {
2324 m_getbulk=true;
2325 } else if (par0=="-gt" || par0=="-gettime") {
2326 m_gettime=true;
2327 } else if ((par0=="-tdb" || par0=="-timedb") && ir>1) {
2328 m_timedb=argv[ic+1];
2329 ++ic;
2330 } else if (par0=="-ignoremode" && ir>1) {
2331 std::cout << "Ignoremode password is " << argv[ic+1] << ":end" << std::endl;
2332 if (strcmp(argv[ic+1],"BackDoor")==0) {
2333 m_ignoremode=true;
2334 } else {
2335 std::cout << "ERROR: Incorrect password for -ignoremode" << std::endl;
2336 error=true;
2337 }
2338 ++ic;
2339 } else if (par0=="-is" || par0=="-ignorespec") {
2340 m_ignorespec=true;
2341 } else if (par0=="-pt" || par0=="-prunetags") {
2342 m_prunetags=true;
2343 m_excludehead=true;
2344 } else if (par0=="-lo" || par0=="-lockedonly") {
2345 m_lockedonly=true;
2346 m_prunetags=true;
2347 m_excludehead=true;
2348 } else if (par0=="-cti" || par0=="-copytaginfo") {
2349 m_copytaginfo=true;
2350 } else if (par0=="-ctl" || par0=="-copytaglock") {
2351 m_copytaginfo=true;
2352 m_copytaglock=true;
2353 } else if ((par0=="-tl" || par0=="-taglabel") && ir>1) {
2354 m_taglabel=argv[ic+1];
2355 ++ic;
2356 m_copytaginfo=true;
2357 } else if ((par0=="-ag" || par0=="-addguid") && ir>1) {
2358 m_addguid.emplace_back(argv[ic+1]);
2359 ++ic;
2360 } else if ((par0=="-alf" || par0=="-addlfn") && ir>1) {
2361 m_addlfn.emplace_back(argv[ic+1]);
2362 ++ic;
2363 } else if ((par0=="-pf" || par0=="-parfile") && ir>1) {
2364 m_parfile.emplace_back(argv[ic+1]);
2365 ++ic;
2366 } else if ((par0=="-rf" || par0=="-runfile") && ir>1) {
2367 m_runfile.emplace_back(argv[ic+1]);
2368 ++ic;
2369 } else if ((par0=="-ws" || par0=="-runinfohost") && ir>1) {
2370 m_runinfohost=argv[ic+1];
2371 ++ic;
2372 } else if (par0=="-h" || par0=="-help") {
2373 // help printout triggered by -999 return code
2374 return 999;
2375 } else {
2376 std::cout << "Parameter error for argument: " << par0 << std::endl;
2377 error=true;
2378 }
2379 ++ic;
2380 }
2381 return !error;
2382}
2383
2384
2385int AtlCoolCopy::setOpts(int argc, const char* argv[]) {
2386 // accumulate raw folder list
2387 std::vector<std::string> folders;
2388 // process options given on command-line
2389 if (!procOptVector(argc,argv,folders)) return 2;
2390
2391 // parse any parameters in files via parfile option
2392 for (std::vector<std::string>::const_iterator ifile=m_parfile.begin();
2393 ifile!=m_parfile.end();++ifile) {
2394 std::cout << "Reading parameters from file " << *ifile << std::endl;
2395 FILE* p_inp=fopen(ifile->c_str(),"r");
2396 if (p_inp==nullptr) {
2397 std::cout << "File not found" << std::endl;
2398 return 3;
2399 }
2400 std::vector<char> p_buf (999);
2401 while (!feof(p_inp)) {
2402 char* p_line=fgets(p_buf.data(),p_buf.size(),p_inp);
2403 if (p_line!=nullptr) {
2404 int fargc=0;
2405 const char* fargv[99];
2406 // split this line into tokens
2407 char* p_start=nullptr;
2408 while (*p_line!='\0') {
2409 if (*p_line==' ' || *p_line=='\n') {
2410 // pointing at a space/newline, marking the end of a parameter
2411 if (p_start!=nullptr) {
2412 // if we have a parameter, mark the end and store it
2413 *p_line='\0';
2414 fargv[fargc]=p_start;
2415 fargc++;
2416 p_start=nullptr;
2417 }
2418 } else {
2419 // mark the start of a parameter
2420 if (p_start==nullptr) p_start=p_line;
2421 }
2422 ++p_line;
2423 }
2424 if (fargc>0) {
2425 if (!procOptVector(fargc,&fargv[0],folders)) {
2426 fclose(p_inp);
2427 return 3;
2428 }
2429 }
2430 }
2431 }
2432 std::cout << "Close file" << std::endl;
2433 fclose(p_inp);
2434 }
2435
2436 // now open the database so folder lookup will work
2438 std::cout << "Problem opening connections" << std::endl;
2439 return 10;
2440 } else {
2441 // having assembled the raw list of folders and exclude list, construct
2442 // real list of folders (allows exclude to be specified after folders on
2443 // command line), if none given, add '/'
2444 if (m_lockedonly) {
2445 if (getLockedTags()==0) return 11;
2446 }
2447 if (folders.empty()) {
2448 // no folders specified, take all with tags
2449 addFolder("/",false);
2450 } else {
2451 // explicit list of folders
2452 for (std::vector<std::string>::const_iterator ifold=folders.begin();
2453 ifold!=folders.end();++ifold) addFolder(*ifold,false);
2454 // need to process only tags in root folder, if inclusive hiearchicals
2455 if (m_hitag) addFolder("/",true);
2456 }
2457 }
2458 if (m_getonline) {
2459 if (!getOnlineRun()) return 6;
2460 }
2461 if (m_getbulk) {
2462 if (!getBulkRun()) return 6;
2463 }
2464 if (m_gettime) {
2465 if (!getTimeFromRun()) return 5;
2466 }
2467 if (!m_runfile.empty()) {
2468 if (!getRunList()) return 7;
2469 }
2470 // list out parameter changes
2471 if (m_runemin!=cool::ValidityKeyMin || m_runemax!=cool::ValidityKeyMax)
2472 std::cout << "Source run/LB range [" << (m_runemin >> 32) << "," <<
2473 (m_runemin & 0xFFFFFFFF) << "] to [" << (m_runemax >> 32) << "," <<
2474 (m_runemax & 0xFFFFFFFF) << "]" << std::endl;
2475 if (m_timemin!=cool::ValidityKeyMin || m_timemax!=cool::ValidityKeyMax)
2476 std::cout << "Source timestamp range " << m_timemin << " " <<
2477 timeString(m_timemin) << "to " << m_timemax << " " <<
2478 timeString(m_timemax) << std::endl;
2479 if (m_alliov)
2480 std::cout << "Change o/p run/LB range [" << (m_newrunemin >> 32) << "," <<
2481 (m_newrunemin & 0xFFFFFFFF) << "] to [" << (m_newrunemax >> 32) << "," <<
2482 (m_newrunemax & 0xFFFFFFFF) << "]" << std::endl;
2483 if (m_alliov)
2484 std::cout << "Change o/p timestamp range " << m_newtimemin << " " <<
2485 timeString(m_newtimemin) << "to " << m_newtimemax << " " <<
2486 timeString(m_newtimemax) << std::endl;
2487 if (m_skipout) {
2488 std::cout << "Skip IOVs extending outside run/LB range [" <<
2489 (m_srunemin >> 32) << "," << (m_srunemin & 0xFFFFFFFF) << "] to [" <<
2490 (m_srunemax >> 32) << "," << (m_srunemax & 0xFFFFFFFF) << "]" <<
2491 std::endl;
2492 }
2493 if (!m_excludechans.empty()) {
2494 for (std::vector<cool::ChannelId>::const_iterator itr=
2495 m_excludechans.begin();itr!=m_excludechans.end();++itr)
2496 std::cout << "Channel " << *itr << " will be excluded" << std::endl;
2497 }
2498 if (m_hitag) std::cout << "All hierarchical tags connecting to referenced tags will be copied" << std::endl;
2499 if (m_nohitag) std::cout << "Hierarchical tag relations will not be copied"
2500 << std::endl;
2501 return 0;
2502}
2503
2504bool AtlCoolCopy::isNumeric(const char* input) {
2505 // determine if input string is numeric or string
2506 bool isnum=true;
2507 const char* cptr=input;
2508 while (*cptr!='\0') {
2509 if (!isdigit(*cptr)) { isnum=false; break;}
2510 ++cptr;
2511 }
2512 return isnum;
2513}
2514
2515bool AtlCoolCopy::equalRecord(const cool::IRecord& lhs,
2516 const cool::IRecord& rhs) {
2517 // equality test for COOL IRecords, handling NULL string attributes correctly
2518 // tests values and types of Attributes, not names
2519 if (lhs.size()!=rhs.size()) return false;
2520 for (size_t i=0;i<lhs.size();++i) {
2521 // types must match - have to test explicitly first
2522 if (lhs[i].specification().storageType()!=
2523 rhs[i].specification().storageType())
2524 return false;
2525 // now use IField equality to for final test (spec again and data)
2526 if (lhs[i]!=rhs[i]) {
2527 // if not equal, check for special case of strings and compare directly
2528 // types are known to be equal so only test LHS
2529 const cool::StorageType& stype=lhs[i].specification().storageType();
2530 if (stype==cool::StorageType::String255 ||
2531 stype==cool::StorageType::String4k ||
2532 stype==cool::StorageType::String64k ||
2533 stype==cool::StorageType::String16M) {
2534 // check if string data payloads are really equal or not
2535 if (lhs[i].data<std::string>()!=rhs[i].data<std::string>())
2536 return false;
2537 } else {
2538 // if not string, trust the result of IField !=operator
2539 return false;
2540 }
2541 }
2542 }
2543 return true;
2544}
2545
2546
2547cool::ValidityKey AtlCoolCopy::timeVal(const char* input) {
2548 // convert input char* string to 64bit COOL validityKey
2549 // input either represents a string in seconds, or a date in the form
2550 // yyyy/mm/dd:hh:mm:ss
2551 // first determine if input is a number
2552 if (isNumeric(input)) {
2553 return static_cast<long long>(atol(input))*
2554 static_cast<long long>(1.E9);
2555 } else {
2556 struct tm mytm{},mytm2{};
2557 char* result=strptime(input,"%Y-%m-%d:%T",&mytm);
2558 if (result!=nullptr) {
2559 // make the DST field zero, so the time is interpreted without daylight
2560 // savings time
2561 mytm.tm_isdst=0;
2562 // now have to correct for the local time zone - do this by also
2563 // calculating the time since epoch for 2/1/1970 midnight (no DST)
2564 time_t tm = mktime(&mytm);
2565 if (tm == static_cast<time_t>(-1)) {
2566 std::cout <<
2567 "ERROR in mktime" << std::endl;
2568 return 0;
2569 }
2570 cool::ValidityKey itime=static_cast<cool::ValidityKey>(tm);
2571 strptime("1970-01-02:00:00:00","%Y-%m-%d:%T",&mytm2);
2572 time_t tm2 = mktime(&mytm2);
2573 if (tm2 == static_cast<time_t>(-1)) {
2574 std::cout <<
2575 "ERROR in mktime" << std::endl;
2576 return 0;
2577 }
2578 cool::ValidityKey caltime=static_cast<cool::ValidityKey>(tm2);
2579 itime+=24*60*60-caltime;
2580 return itime*static_cast<cool::ValidityKey>(1.E9);
2581 } else {
2582 std::cout <<
2583 "ERROR in format of time value, use e.g. 2007-05-25:14:01:00" <<
2584 std::endl;
2585 return 0;
2586 }
2587 }
2588}
2589
2590std::string AtlCoolCopy::timeString(const cool::ValidityKey iovtime) {
2591 if (iovtime==cool::ValidityKeyMin) {
2592 return "ValidityKeyMin ";
2593 } else if (iovtime==cool::ValidityKeyMax) {
2594 return "ValidityKeyMax ";
2595 } else {
2596 time_t time=static_cast<time_t>(iovtime/1E9);
2597 struct tm result;
2598 char buf[32];
2599 return "UTC "+std::string(asctime_r(gmtime_r(&time, &result), buf));
2600 }
2601}
2602
2603cool::ValidityKey AtlCoolCopy::runLBVal(const char* input1,const char* input2) {
2604 // parse the inputs as run/LB numbers to generate a validitykey
2605 // used in processing -rls-type options
2606 cool::ValidityKey val;
2607 if (input1[0]=='M' || input1[0]=='m') {
2608 val=((1LL << 31)-1) << 32;
2609 } else {
2610 val=static_cast<long long>(atol(input1)) << 32;
2611 }
2612 if (input2[0]=='M' || input2[0]=='m') {
2613 val+=(1LL << 32);
2614 } else {
2615 val+=atoll(input2);
2616 }
2617 if (val>cool::ValidityKeyMax) val=cool::ValidityKeyMax;
2618 return val;
2619}
2620
2621
2623 // extract time limits for a run range using the expected information
2624 // in the /TDAQ/RunCtrl/SOR_Params and EOR_Params on the given DB connection
2625
2626 // choose database instance based on run number switchover if none is given
2627 if (m_timedb.empty()) {
2628 if ((m_runemin >> 32)>=236107) {
2629 m_timedb="COOLONL_TDAQ/CONDBR2";
2630 } else {
2631 m_timedb="COOLONL_TDAQ/COMP200";
2632 }
2633 }
2634 // select foldername based on database instance
2635 std::string sorfolder="/TDAQ/RunCtrl/SOR_Params";
2636 std::string eorfolder="/TDAQ/RunCtrl/EOR_Params";
2637 if (m_timedb.find ("CONDBR2")!=std::string::npos) {
2638 sorfolder="/TDAQ/RunCtrl/SOR";
2639 eorfolder="/TDAQ/RunCtrl/EOR";
2640 }
2641 std::cout << "Extracting times for run range [" << (m_runemin >> 32) <<
2642 "," << (m_runemax >> 32) << "] from database " << m_timedb <<
2643 " folder " << sorfolder << std::endl;
2644 if (m_runemin==cool::ValidityKeyMin || m_runemax==cool::ValidityKeyMax) {
2645 std::cout << "ERROR: Run range not correctly specified" << std::endl;
2646 return false;
2647 }
2648 // open database connection
2649 cool::IDatabasePtr tdaqdb;
2650 try {
2651 tdaqdb=m_dbSvc->openDatabase(transConn(m_timedb),m_sourceread);
2652 std::cout << "Opened database connection" << std::endl;
2653 }
2654 catch (std::exception& e) {
2655 std::cout << "COOL exception caught: " << e.what() << std::endl;
2656 return false;
2657 }
2658 // start of run information
2659 try {
2660 cool::IFolderPtr folder=tdaqdb->getFolder(sorfolder);
2661 // channel number is arbitrary - have to loop
2662 cool::IObjectIteratorPtr itr=folder->browseObjects(m_runemin,m_runemin,
2663 cool::ChannelSelection::all());
2664 int nobj=0;
2665 while (itr->goToNext()) {
2666 const cool::IRecord& payload=itr->currentRef().payload();
2667 m_timemin=payload["SORTime"].data<unsigned long long>();
2668 ++nobj;
2669 }
2670 itr->close();
2671 if (nobj!=1) {
2672 std::cout << "ERROR: Found " << nobj << " SOR records" << std::endl;
2673 return false;
2674 }
2675 }
2676 catch (std::exception& e) {
2677 std::cout << "Exception accessing SOR information: " << e.what() <<
2678 std::endl;
2679 return false;
2680 }
2681 // end of run information
2682 try {
2683 cool::IFolderPtr folder=tdaqdb->getFolder(eorfolder);
2684 // channel number is arbitrary - have to loop
2685 cool::IObjectIteratorPtr itr=folder->browseObjects(((m_runemax >> 32) << 32),((m_runemax >> 32) << 32),
2686 cool::ChannelSelection::all());
2687 int nobj=0;
2688 while (itr->goToNext()) {
2689 const cool::IRecord& payload=itr->currentRef().payload();
2690 m_timemax=payload["EORTime"].data<unsigned long long>();
2691 ++nobj;
2692 }
2693 itr->close();
2694 if (nobj!=1) {
2695 std::cout << "ERROR: Found " << nobj << " EOR records" << std::endl;
2696 return false;
2697 }
2698 }
2699 catch (std::exception& e) {
2700 std::cout << "Exception accessing SOR information: " << e.what() <<
2701 std::endl;
2702 return false;
2703 }
2704 tdaqdb->closeDatabase();
2705 std::cout << "Timestamp range set to " << m_timemin << " " <<
2706 timeString(m_timemin) << "to " << m_timemax << " " <<
2707 timeString(m_timemax) << std::endl;
2708 return true;
2709}
2710
2712 // open using the ATLAS_COOLONL_GLOBAL schema, since we have authentication
2713 // information for this one by default
2714 // get minimum run-number/timestamp for bulk reco update
2715 std::cout << "Extracting current run-number from ATLAS_RUN_NUMBER @ ATONR_ADG ... " <<
2716 // Initialize libcurl
2717 curl_global_init(CURL_GLOBAL_ALL);
2718 using uniqueCurl_t = std::unique_ptr<CURL,decltype(&curl_easy_cleanup)>;
2719 uniqueCurl_t curl(curl_easy_init(), curl_easy_cleanup);
2720 CURLcode res = CURLE_OK;
2721 if (curl) {
2722 std::string url = m_runinfohost + "/runs?sort=runnumber:DESC&size=1";
2723 // Set the URL
2724 res = curl_easy_setopt(curl.get(), CURLOPT_URL, url.c_str());
2725 if (res != CURLE_OK) {
2726 std::cerr << "Failed to perform request: curl_easy_setopt, line "<<__LINE__<<std::endl;
2727 return false;
2728 }
2729 // Follow HTTP redirections
2730 res = curl_easy_setopt(curl.get(), CURLOPT_FOLLOWLOCATION, 1L);
2731 if (res != CURLE_OK) {
2732 std::cerr << "Failed to perform request: curl_easy_setopt, line "<<__LINE__<<std::endl;
2733 return false;
2734 }
2735 // Response data buffer
2736 std::string response;
2737
2738 // Set the callback function to receive response data
2739 res = curl_easy_setopt(curl.get(), CURLOPT_WRITEFUNCTION, WriteCallback);
2740 if (res != CURLE_OK) {
2741 std::cerr << "Failed to perform request: curl_easy_setopt, line "<<__LINE__<<std::endl;
2742 return false;
2743 }
2744 res = curl_easy_setopt(curl.get(), CURLOPT_WRITEDATA, &response);
2745 if (res != CURLE_OK) {
2746 std::cerr << "Failed to perform request: curl_easy_setopt, line "<<__LINE__<<std::endl;
2747 return false;
2748 }
2749
2750 // Perform the request
2751 res = curl_easy_perform(curl.get());
2752 if (res != CURLE_OK) {
2753 std::cerr << "Failed to perform request: " << curl_easy_strerror(res) << ":" << url << std::endl;
2754 return false;
2755 } else {
2756 // Print the received response
2757 std::cout << "Response: " << std::endl;
2758 std::cout << response << std::endl;
2759 // Parse the JSON string
2760 try {
2761 nlohmann::json jsonData = nlohmann::json::parse(response);
2762
2763 // Extract the runnumber field
2764 int runNumber = jsonData["resources"][0]["runnumber"];
2765 int nextrun=runNumber+1;
2766 std::cout << "Next run started will be " << nextrun << std::endl;
2767 const long long rtime=time(nullptr);
2768 std::cout << "Epoch time extracted " << rtime << std::endl;
2769 if (m_alliov) {
2770 // if overwriting IOVs, set the new IOV lower limit
2771 m_newrunemin=(static_cast<long long>(nextrun)) << 32;
2772 m_newtimemin=rtime*static_cast<long long>(1E9);
2773 } else {
2774 // set the query lower limit - for use with truncate option
2775 m_runemin=(static_cast<long long>(nextrun)) << 32;
2776 m_timemin=rtime*static_cast<long long>(1E9);
2777 m_truncate=true;
2778 }
2779 } catch (nlohmann::json::parse_error& e) {
2780 std::cerr << "Failed to parse JSON response: " << e.what() << std::endl;
2781 return false;
2782 } catch (nlohmann::json::type_error& e) {
2783 std::cerr << "Failed to extract data from JSON response: " << e.what() << std::endl;
2784 return false;
2785 } catch (std::exception& e) {
2786 std::cerr << "Failed to extract run and timestamp from JSON response: " << e.what() << std::endl;
2787 return false;
2788 }
2789 }
2790 // Clean up done by unique_ptr d'tor
2791 } else {
2792 std::cerr << "Failed to initialize libcurl." << std::endl;
2793 return false;
2794 }
2795 // Cleanup libcurl
2796 curl_global_cleanup();
2797 return true;
2798}
2800 // get minimum run-number/timestamp for bulk reco update
2801 if (m_getonline) {
2802 std::cout << "ERROR: -getonline and -getbulk cannot be used simultaneously"
2803 << std::endl;
2804 return false;
2805 }
2806 std::cout << "Call getbulk using URL" << std::endl;
2807 // Initialize libcurl
2808 curl_global_init(CURL_GLOBAL_ALL);
2809 using uniqueCurl_t = std::unique_ptr<CURL,decltype(&curl_easy_cleanup)>;
2810 uniqueCurl_t curl(curl_easy_init(), curl_easy_cleanup);
2811 //CURL *curl = curl_easy_init();
2812 CURLcode res = CURLE_OK;
2813
2814 if (curl) {
2815 std::string url = m_runinfohost + "/runs/nemop/sync";
2816 // Set the URL
2817 res = curl_easy_setopt(curl.get(), CURLOPT_URL, url.c_str());
2818 if (res != CURLE_OK) {
2819 std::cerr << "Failed to perform request: curl_easy_setopt, line "<<__LINE__<<std::endl;
2820 return false;
2821 }
2822 // Follow HTTP redirections
2823 res = curl_easy_setopt(curl.get(), CURLOPT_FOLLOWLOCATION, 1L);
2824 if (res != CURLE_OK) {
2825 std::cerr << "Failed to perform request: curl_easy_setopt, line "<<__LINE__<<std::endl;
2826 return false;
2827 }
2828 // Response data buffer
2829 std::string response;
2830
2831 // Set the callback function to receive response data
2832 res = curl_easy_setopt(curl.get(), CURLOPT_WRITEFUNCTION, WriteCallback);
2833 if (res != CURLE_OK) {
2834 std::cerr << "Failed to perform request: curl_easy_setopt, line "<<__LINE__<<std::endl;
2835 return false;
2836 }
2837 res = curl_easy_setopt(curl.get(), CURLOPT_WRITEDATA, &response);
2838 if (res != CURLE_OK) {
2839 std::cerr << "Failed to perform request: curl_easy_setopt, line "<<__LINE__<<std::endl;
2840 return false;
2841 }
2842 // Perform the request
2843 res = curl_easy_perform(curl.get());
2844 if (res != CURLE_OK) {
2845 std::cerr << "Failed to perform request: " << curl_easy_strerror(res) << ":" << url << std::endl;
2846 return false;
2847 } else {
2848 // Print the received response
2849 std::cout << "Response: " << std::endl;
2850 std::cout << response << std::endl;
2851 try {
2852 // Split the response into two fields
2853 nlohmann::json jsonData = nlohmann::json::parse(response);
2854 // Extract the run and timestamp fields
2855 int nextrun = jsonData["run"];
2856 long long rtime = jsonData["timestamp"];
2857 std::cout << "Next run started will be " << nextrun << std::endl;
2858 std::cout << "Epoch time extracted " << rtime << std::endl;
2859 if (m_alliov) {
2860 // if overwriting IOVs, set the new IOV lower limit
2861 m_newrunemin=(static_cast<long long>(nextrun)) << 32;
2862 m_newtimemin=rtime*static_cast<long long>(1E9);
2863 } else {
2864 // set the query lower limit - for use with truncate option
2865 m_runemin=(static_cast<long long>(nextrun)) << 32;
2866 m_timemin=rtime*static_cast<long long>(1E9);
2867 m_truncate=true;
2868 }
2869 } catch (nlohmann::json::parse_error& e) {
2870 std::cerr << "Failed to parse JSON response: " << e.what() << std::endl;
2871 return false;
2872 } catch (nlohmann::json::type_error& e) {
2873 std::cerr << "Failed to extract data from JSON response: " << e.what() << std::endl;
2874 return false;
2875 } catch (std::exception& e) {
2876 std::cerr << "Failed to extract run and timestamp from JSON response: " << e.what() << std::endl;
2877 return false;
2878 }
2879 }
2880 // Clean up done by unique_ptr
2881 } else {
2882 std::cerr << "Failed to initialize libcurl." << std::endl;
2883 return false;
2884 }
2885 // Cleanup libcurl
2886 curl_global_cleanup();
2887
2888 return true;
2889}
2890
2892 // loop over all given filenames
2893 for (std::vector<std::string>::const_iterator itr=m_runfile.begin();
2894 itr!=m_runfile.end();++itr) {
2895 std::cout << "Reading allowed run numbers from file " << *itr << std::endl;
2896 FILE* p_inp=fopen(itr->c_str(),"r");
2897 if (p_inp==nullptr) {
2898 std::cout << "File not found" << std::endl;
2899 return false;
2900 }
2901 std::vector<char> p_buf (999);
2902 while (!feof(p_inp)) {
2903 char* p_line=fgets(p_buf.data(),p_buf.size(),p_inp);
2904 if (p_line!=nullptr) {
2905 unsigned int run=atoi(p_line);
2906 m_runlist.push_back(run);
2907 }
2908 }
2909 fclose(p_inp);
2910 }
2911 std::sort(m_runlist.begin(),m_runlist.end());
2912 std::cout << "Read list of " << m_runlist.size() << " runs from " <<
2913 m_runfile.size() << " input runlist files" << std::endl;
2914 for (std::vector<unsigned int>::const_iterator itr=m_runlist.begin();
2915 itr!=m_runlist.end();++itr) std::cout <<
2916 "Update allowed for run " << *itr << std::endl;
2917 return true;
2918}
2919
2920int AtlCoolCopy::getUpdateMode(std::string_view desc,
2921 std::string_view tag) {
2922 // analyse the folder description and tag name for updateMode flags
2923 // return 1 for online mode, 0 otherwise
2924 std::string_view modestr="";
2925 int mode=0;
2926 std::string::size_type iofs1=desc.find("<updateMode>");
2927 std::string::size_type iofs2=desc.find("</updateMode>");
2928 if (iofs1!=std::string::npos && iofs2!=std::string::npos && iofs2>iofs1)
2929 modestr=desc.substr(iofs1+12,iofs2-iofs1-12);
2930 if (modestr=="UPD1" || tag.find("UPD1")!=std::string::npos) mode=1;
2931 if (modestr=="UPD2" || tag.find("UPD2")!=std::string::npos) mode=2;
2932 if (modestr=="UPD3" || tag.find("UPD3")!=std::string::npos) mode=3;
2933 if (modestr=="UPD4" || tag.find("UPD4")!=std::string::npos) mode=4;
2934 return mode;
2935}
2936
2937
2938bool AtlCoolCopy::checkChannels(const std::string& folder,
2939 const cool::IFolderPtr& sourcefl,const cool::IFolderPtr& destfl,
2940 bool newfolder) {
2941 // Channel manipulation is slow due to lack of bulk API for creating them
2942 // this routine therefore does the minimum work, not checking destination
2943 // if folder is newly created, and not copying description unless requested
2944 // get map of all channels
2945 const std::map<cool::ChannelId,std::string> chanmap=
2946 sourcefl->listChannelsWithNames();
2947 if (m_debug) std::cout << "Checking channels table for folder " << folder
2948 << " with " << chanmap.size() << " channels" << std::endl;
2949 int ncreate=0;
2950 int nmodify=0;
2951 // iterate over all channels
2952 for (std::map<cool::ChannelId,std::string>::const_iterator
2953 itr=chanmap.begin();itr!=chanmap.end();++itr) {
2954 // assume now ALL channels are in channels table (COOL 2.4 and above)
2955 const cool::ChannelId chan=itr->first;
2956 // check if channel should be skipped
2957 if (!m_excludechans.empty()) {
2958 if (find(m_excludechans.begin(),m_excludechans.end(),
2959 chan)!=m_excludechans.end()) continue;
2960 }
2961 if (!m_chansel.inSelection(chan)) continue;
2962
2963 const std::string& sourcename=itr->second;
2964 // only look up channel description if we are copying it
2965 std::string sourcedesc="";
2966 if (m_chdesc) sourcedesc=sourcefl->channelDescription(chan);
2967 // only check destination if folder alreay existed
2968 if (!newfolder && destfl->existsChannel(chan)) {
2969 const std::string & destname=destfl->channelName(chan);
2970 std::string destdesc="";
2971 if (m_chdesc) destdesc=destfl->channelDescription(chan);
2972 // if sourcename is not set, and destination is, dont worry
2973 if (sourcename!=destname && !sourcename.empty()) {
2974 // channel names differ - error if verifying, set if copying
2975 if (m_verify) {
2976 std::cout << "ERROR: Channel " << chan << " names differ: " <<
2977 sourcename << " " << destname << std::endl;
2978 return false;
2979 }
2980 destfl->setChannelName(chan,sourcename);
2981 std::cout << "Modify channel " << chan << " name from "
2982 << destname << " to " << sourcename << std::endl;
2983 ++nmodify;
2984 }
2985 if (sourcedesc!=destdesc && !sourcedesc.empty()) {
2986 // channel descriptions differ - error if verifying, set if copying
2987 if (m_verify) {
2988 std::cout << "ERROR: Channel " << chan << " descriptions differ: "
2989 << sourcedesc << " " << destdesc << std::endl;
2990 return false;
2991 }
2992 std::cout << "Modify channel " << chan << " description from "
2993 << sourcedesc << " to " << destdesc << std::endl;
2994 destfl->setChannelDescription(chan,sourcedesc);
2995 ++nmodify;
2996 }
2997 } else {
2998 // channel does not exist on destination - if verifying, this is error
2999 if (m_verify) return false;
3000 // otherwise create it
3001 if (m_debug) std::cout << "Create new channel " << chan << " name "
3002 << sourcename << " description" << sourcedesc << std::endl;
3003 destfl->createChannel(chan,sourcename,sourcedesc);
3004 ++ncreate;
3005 }
3006 }
3007 if (ncreate>0) std::cout << "Created " << ncreate << " new channels for "
3008 << folder << std::endl;
3009 if (nmodify>0) std::cout << "Modified " << nmodify << " channel info for "
3010 << folder << std::endl;
3011 return true;
3012}
3013
3014
3015void AtlCoolCopy::checkRef(const cool::IRecord& payload,
3016 const std::string& folder, const std::string& tag) {
3017 const std::string name=payload[0].name();
3018 if (name=="PoolRef" || name=="fileGUID") {
3019 std::string poolref;
3020 std::string addr=payload[0].data<std::string>();
3021 if (name=="PoolRef") {
3022 std::string::size_type iofs1=addr.find("[DB=");
3023 std::string::size_type iofs2=addr.find(']',iofs1);
3024 if (iofs1!=std::string::npos && iofs2!=std::string::npos && iofs2>iofs1) {
3025 poolref=addr.substr(iofs1+4,iofs2-iofs1-4);
3026 } else {
3027 std::cout << "ERROR: Badly formed POOL object reference " <<
3028 addr << std::endl;
3029 }
3030 } else {
3031 // for fileGUID, POOL GUID is just the string
3032 poolref=std::move(addr);
3033 }
3034 std::string foldertag=folder+":"+tag;
3035 // insert into list, first check if same as before
3036 if (m_poollast!=m_poolrefs.end() && m_poollast->first==poolref) {
3037 m_poollast->second.inccount();
3038 m_poollast->second.addfoldertag(foldertag);
3039 } else {
3040 m_poollast=m_poolrefs.find(poolref);
3041 if (m_poollast!=m_poolrefs.end()) {
3042 m_poollast->second.inccount();
3043 m_poollast->second.addfoldertag(foldertag);
3044 } else {
3045 m_poolrefs[poolref]=PoolMapElement(1,foldertag);
3046 m_poollast=m_poolrefs.find(poolref);
3047 }
3048 }
3049 }
3050}
3051
3053 std::cout << "Copying additional hierarchical tags of parent folders"
3054 << std::endl;
3055 while (!m_hiparent.empty()) {
3056 // take first element and erase it
3057 std::string folderset=*m_hiparent.begin();
3058 m_hiparent.erase(m_hiparent.begin());
3059 // process any tags defined for this folderset
3060 if (m_sourceDbPtr->existsFolderSet(folderset)) {
3061 cool::IFolderSetPtr sourcefl=m_sourceDbPtr->getFolderSet(folderset);
3062 cool::IFolderSetPtr destfl=m_destDbPtr->getFolderSet(folderset);
3063 std::cout << "Processing folderset " << folderset << std::endl;
3064 for (HiTagMap::const_iterator imap=m_hitagmap.begin();
3065 imap!=m_hitagmap.end();++imap) {
3066 try {
3067 // will throw exception if this tag is not pointing to the folder
3068 std::string sourcetag=sourcefl->findTagRelation(imap->first);
3069 std::cout << "Create hierarchical tag between " << sourcetag <<
3070 " and " << imap->first << " in folder " << imap->second <<
3071 std::endl;
3072 try {
3073 // first check this relation has not already been created
3074 std::string etag=destfl->resolveTag(imap->first);
3075 if (etag==sourcetag) {
3076 std::cout << "This relation has already been created" << std::endl;
3077 } else {
3078 std::cout << "ERROR: Tag in parent already related to " <<
3079 etag << std::endl;
3080 return 34;
3081 }
3082 }
3083 catch (cool::Exception& e ) {
3084 // only do creation if does not already exist - via exception
3085 try {
3086 destfl->createTagRelation(imap->first,sourcetag);
3087 // check if this implicates yet another parent folder to be checked
3088 if (find(m_hiparent.begin(),m_hiparent.end(),imap->second)==
3089 m_hiparent.end()) m_hiparent.push_back(imap->second);
3090 if (m_copytaginfo &&
3091 m_cooltagmap.find(imap->first)==m_cooltagmap.end())
3092 m_cooltagmap.insert(CoolTagMap::value_type(imap->first,
3093 CoolTagInfo(m_sourceDbPtr,imap->second,imap->second,
3094 imap->first,imap->first)));
3095 }
3096 catch (cool::Exception& e) {
3097 std::cout << "Cool exception " << e.what() <<
3098 "thrown in hierarchical tag creation" << std::endl;
3099 return 34;
3100 }
3101 }
3102 }
3103 // exceptions from findTag - do nothing
3104 catch (cool::Exception& e) { }
3105 }
3106 } else {
3107 std::cout << "ERROR Folderset " << folderset << " not found" <<
3108 std::endl;
3109 }
3110 }
3111 return 0;
3112}
3113
3115 std::cout << "Write tag description ";
3116 if (m_copytaglock) std::cout << "and lock info ";
3117 std::cout << "for " << m_cooltagmap.size() << " tags" << std::endl;
3118 for (CoolTagMap::const_iterator itr=m_cooltagmap.begin();
3119 itr!=m_cooltagmap.end();++itr) {
3120 itr->second.write(m_destDbPtr,m_copytaglock);
3121 }
3122 return 0;
3123}
3124
3126 std::cout << "Total of " << m_poolrefs.size() << " POOL files referenced"
3127 << std::endl;
3128 for (PoolMap::const_iterator ipool=m_poolrefs.begin();
3129 ipool!=m_poolrefs.end();++ipool) {
3130 std::cout << "Ref " << ipool->first << " (" << ipool->second.count()
3131 << ")" << std::endl;
3132 }
3133 return 0;
3134}
3135
3136int AtlCoolCopy::resolvePoolRefs ATLAS_NOT_THREAD_SAFE () {
3137 std::cout << "Total of " << m_poolrefs.size() << " POOL Files referenced"
3138 << std::endl;
3139 setupCatalog(m_poolcat);
3140 if( !m_catalog ) return 110;
3141 pool::SimpleUtilityBase pool_utility;
3142 if (m_poolopen) {
3143 // prepare POOL session
3144 pool_utility.startSession();
3145 }
3146 // inject additional GUIDs/LFNs if needed
3147 if (!m_addguid.empty()) {
3148 for (std::vector<std::string>::const_iterator itr=m_addguid.begin();
3149 itr!=m_addguid.end();++itr) {
3150 m_poolrefs[*itr]=PoolMapElement(1,"ADDGUID");
3151 std::cout << "Added POOL file GUID: " << *itr << std::endl;
3152 }
3153 }
3154 if (!m_addlfn.empty()) {
3155 for (std::vector<std::string>::const_iterator itr=m_addlfn.begin();
3156 itr!=m_addlfn.end();++itr) {
3157 std::string guid = m_catalog->lookupLFN(*itr);
3158 std::cout << "Add POOL file GUID: " << guid << " from LFN " << *itr
3159 << std::endl;
3160 m_poolrefs[guid]=PoolMapElement(1,"ADDLFN");
3161 }
3162 }
3163
3164 // set up for making new dataset if needed
3165 using LFNGVec = std::vector<std::pair<std::string, std::string> >;
3166 LFNGVec dsfound;
3167 bool dscopy=!m_newdataset.empty();
3168
3169 // loop through GUIDs and attempt to resolve
3170 int nbad=0;
3171 for (PoolMap::iterator ipool=m_poolrefs.begin();
3172 ipool!=m_poolrefs.end();++ipool) {
3173 std::string guid=ipool->first;
3174 Gaudi::IFileCatalog::Files lfns;
3175 m_catalog->getLFN( guid, lfns );
3176 if( !lfns.empty() ) {
3177 // file found in cataloge - print LFN and usage count
3178 const std::string lfn = lfns[0].first;
3179 ipool->second.setlfn(lfn);
3180 std::cout << "LFN: " << lfn << " (" << ipool->second.count()
3181 << ")" << std::endl;
3182 if(dscopy) dsfound.push_back(std::pair<std::string,std::string>(lfn,guid));
3183 } else {
3184 // error bit 0 - no LFN
3185 if(!m_listpfn) ipool->second.setErrorBit(0);
3186 }
3187 if (m_listpfn || m_poolopen) {
3188 Gaudi::IFileCatalog::Files pfns_techs;
3189 m_catalog->getPFN( guid, pfns_techs );
3190 if( !pfns_techs.empty() ) {
3191 std::string &pfn = pfns_techs[0].first;
3192 ipool->second.setpfn(pfn);
3193 std::cout << "PFN: " << pfn << " (" << ipool->second.count() << ")" << std::endl;
3194 if (m_poolopen) {
3195 // first try the file as a CoolHist file
3196 std::string hguid=getCoolHistGUID(pfn);
3197 if(!hguid.empty()) {
3198 // successful get of CoolHist GUID
3199 if (hguid!=ipool->first) {
3200 std::cout << "ERROR File CoolHist GUID " << hguid << " inconsistent with catalogue " << ipool->first << std::endl;
3201 ipool->second.setErrorBit(3);
3202 }
3203 } else {
3204 // try the file as a genuine POOL file
3205 try {
3206 const std::string fid = pool_utility.readFileGUID( pfn );
3207 if( fid != ipool->first ) {
3208 std::cout << "ERROR File GUID " << fid << " inconsistent with catalogue " << ipool->first << std::endl;
3209 // file GUID inconsistent with catalogue - error bit 3
3210 ipool->second.setErrorBit(3);
3211 }
3212 } catch( std::runtime_error& e ) {
3213 std::cout << "Cannot open file for reading!" << std::endl;
3214 std::cout << e.what() << std::endl;
3215 // File cannot be opened: set error bit 2
3216 ipool->second.setErrorBit(2);
3217 }
3218 }
3219 } // end of actions opening POOL file
3220 } else {
3221 // PFN not found - set bit 1
3222 ipool->second.setErrorBit(1);
3223 }
3224 }
3225 // check file error code
3226 if (ipool->second.errcode()>0) ++nbad;
3227 }
3228 m_catalog->commit();
3229
3230 // produce definition of new dataset if needed
3231 if (dscopy) {
3232 // start up a new catalogue instance with the merge catalogues
3233 // which indicate which files are already available and don't need to
3234 // put in the output dataset definition
3235 setupCatalog(m_mergecat);
3236 if( !m_catalog ) return 110;
3237 const std::string dssname="register.sh";
3238 std::cout << "Write DQ2 registerFileInDataset commands to " << dssname
3239 << " for registration in dataset " << m_newdataset << std::endl;
3240 std::ofstream dsstream(dssname.c_str());
3241 for (LFNGVec::const_iterator itr=dsfound.begin();
3242 itr!=dsfound.end();++itr) {
3243 const std::string& lfn=itr->first;
3244 const std::string& guid=itr->second;
3245 Gaudi::IFileCatalog::Files lfns;
3246 m_catalog->getLFN( guid, lfns );
3247 if( !lfns.empty() ) {
3248 // file is already registered - check logical names are consistent
3249 const std::string lfn2 = lfns[0].first;
3250 if (lfn2!=lfn) std::cout << "WARNING: LFNs for GUID " << guid <<
3251 " differ in input/merge datasets: " << lfn << " vs "
3252 << lfn2 << std::endl;
3253 } else {
3254 // file is not registered - add to output
3255 dsstream << "dq2-register-files " << m_newdataset << " "
3256 << lfn << " " << guid << std::endl;
3257 }
3258 }
3259 m_catalog->commit();
3260 }
3261
3262 int retcode=0;
3263 if (nbad==0) {
3264 std::cout << "All POOL references were resolved by catalogues"
3265 << std::endl;
3266 } else {
3267 std::cout << "ERROR Could not resolve " << nbad << " files" << std::endl;
3268 retcode=111;
3269 }
3270 if (nbad>0 || m_poolall) filePoolRefs();
3271 return retcode;
3272}
3273
3274std::string AtlCoolCopy::getCoolHistGUID(const std::string& file) {
3275 // attempt to extract COOL Hist GUID from file
3276 std::string hguid="";
3277 TFile* myfile=TFile::Open(file.c_str(),"READ");
3278 if (myfile!=nullptr) {
3279 TObjString* oguid;
3280 myfile->GetObject("fileGUID",oguid);
3281 if (oguid!=nullptr) {
3282 hguid=oguid->GetString();
3283 std::cout << "CoolHist GUID found to be " << hguid << std::endl;
3284 }
3285 myfile->Close();
3286 }
3287 return hguid;
3288}
3289
3291 // list POOL refs and error codes, optionally to file
3292 if (!m_checkoutputfile.empty()) {
3293 std::cout << "Write POOL file checkoutput on " << m_checkoutputfile <<
3294 std::endl;
3295 } else {
3296 m_checkoutputfile="/dev/null";
3297 }
3298 std::ofstream chkostream(m_checkoutputfile.c_str());
3299 std::cout << "ErrCode GUID Count LFN PFN Folders ..." << std::endl;
3300 for (PoolMap::const_iterator ipool=m_poolrefs.begin();
3301 ipool!=m_poolrefs.end();++ipool) {
3302 if (m_poolall || ipool->second.errcode()>0) {
3303 std::ostringstream line;
3304 // write error code, GUID, usage count
3305 line << ipool->second.errcode() << " " << ipool->first << " " <<
3306 ipool->second.count() << " ";
3307 if (!ipool->second.lfn().empty()) {
3308 line << ipool->second.lfn() << " ";
3309 } else {
3310 line << "noLFN ";
3311 }
3312 if (!ipool->second.pfn().empty()) {
3313 line << ipool->second.pfn() << " ";
3314 } else {
3315 line << "noPFN ";
3316 }
3317 for (std::vector<std::string>::const_iterator
3318 itr=ipool->second.foldertag().begin();
3319 itr!=ipool->second.foldertag().end();++itr)
3320 line << *itr << " ";
3321 std::cout << line.str() << std::endl;
3322 chkostream << line.str() << std::endl;
3323 }
3324 }
3325}
3326
3327void AtlCoolCopy::setupCatalog(const std::vector<std::string>& catvec)
3328{
3329 try {
3330 SmartIF<Gaudi::IFileCatalogMgr> catMgr( Gaudi::svcLocator()->service<Gaudi::IFileCatalogMgr>( "Gaudi::MultiFileCatalog" ) );
3331 std::string writeCatName("file:PoolFileCatalog.xml");
3332 catMgr->addCatalog( "xmlcatalog_"+writeCatName );
3333 catMgr->setWriteCatalog( catMgr->findCatalog( writeCatName, true ) );
3334
3335 for( const auto& icat : catvec ) {
3336 std::cout << "Add catalogue: " << icat << std::endl;
3337 // if catalogue contains ":", assume it already has the full format specifier
3338 if( icat.contains(':') ) {
3339 catMgr->addCatalog(icat);
3340 } else {
3341 catMgr->addCatalog("xmlcatalog_file:" + icat);
3342 }
3343 }
3344 m_catalog = catMgr;
3345 m_catalog->init();
3346 }
3347 catch (std::exception& e) {
3348 std::cout << "Could not setup POOL catalogues, exception:" << e.what() << std::endl;
3349 }
3350}
3351
3353 std::cout << "usage: AtlCoolCopy.exe <sourceCoolDB> <destinationCoolDB> { <options> }" << std::endl;
3354 std::cout << "Options are (see doc/mainpage.h for more):" << std::endl <<
3355 "-a, -alliov : set IOVs on destination to [ValidityKeyMin, ValidityKeyMax]" << std::endl <<" or following settings of -nrls,-nrlu,-nts,-ntu" <<
3356 std::endl <<
3357 "-ag, -addguid <guid> : Add GUID to list accessed for POOL checks" <<
3358 std::endl <<
3359 "-alf, -addlfn <LFN> : Add LFN to list accessed for POOL checks" <<
3360 std::endl <<
3361 "-al, -appendlocked : Allow locked tags to be updated if no overlap" <<
3362 std::endl <<
3363 "-alsv, -appendlockedsv : Allow locked tag update for openended IOVs" <<
3364 std::endl <<
3365 "-ana, -analyse <delta_t>: produce analysis ROOT file (filename = dest DB argument)" << std::endl <<
3366"-bs, -buffersize <size> : set size of bulkstorage output buf to <size> objs"
3367 << std::endl <<
3368 "-c, -create : create destination DB if not already existing"
3369 << std::endl <<
3370 "-cd, -checkdest : Check destination DB and skip already existing tags"
3371 << std::endl <<
3372 "-ch, -channel : restrict selection to given channel or range specified as c1:c2" << std::endl <<
3373 "-ch1, -channel1 : specify start of a range of channels" << std::endl <<
3374 "-ch2, -channel2 : specify end of a range of channels" << std::endl <<
3375 "-cf, -checkfiles : check POOL files can be opened and have correct GUID"
3376 << std::endl <<
3377 "-co, -checkoutput <file> : write POOL file check output on file"
3378 << std::endl << "-cti, -copytaginfo : Copy tag descriptions"
3379 << std::endl << "-ctl, -copytaglock : Copy tag locked status and descriptions"
3380 << std::endl << "-cr, -checkrefs : check POOL references"
3381 << std::endl << "-d, -debug : produce debug output" << std::endl;
3382 std::cout <<
3383 "-ds, -dataset : output register.sh for creating DQ2 datasets "
3384 << std::endl <<
3385 "-ec, -excludechannel : exclude given channel from copy" << std::endl <<
3386 "-eh, -excludehead : exclude HEAD tag even if no tags found in MV folders"
3387 << std::endl <<
3388 "-ih, -includehead : include HEAD as well as any tags in MV folders" <<
3389 std::endl <<
3390 "-e, -exclude <pattern> : exclude folders" << std::endl <<
3391 "-f, -folder <pattern> : include folders" << std::endl <<
3392 "-fs, -forcesingle : force destination folder to be singleversion"
3393 << std::endl <<
3394 "-fm, -forcemulti : force destination folder to be multiversion"
3395 << std::endl <<
3396 "-frl, -forcerunlumi : force destination folder to be run/LB indexed"
3397 << std::endl <<
3398 "-ftm, -forcetime : force destination folder to be timestamp indexed"
3399 << std::endl <<
3400 "-fp, -forcepayload : Force destn folders to be created with payload tbl" << std::endl <<
3401 "-fnp, -forcenopayload : Force destn folders to be created without payload tbl" << std::endl <<
3402 "-forcerecreate : delete and recreate destination database" << std::endl;
3403 std::cout << "-ht, -headtag : Use HEAD-style tagging"
3404 << std::endl <<
3405 "-go, -getonline : Set minimum run number (-rls setting) to next ONLINE run"
3406 << std::endl <<
3407 "-gb, -getbulk : Set minimum run number (-rls setting) to next bulk reco run"
3408 << std::endl <<
3409 "-gt, -gettime : Extract timestamp information for given run number range"
3410 << std::endl <<
3411 "-h, -help : print help and exit" << std::endl <<
3412 "-hi, -hitag : Copy hierrchical tags inclusively" << std::endl <<
3413 "-ignoremode <pwd> : Ignore UPDx mode protection (experts only)"
3414 << std::endl <<
3415 "-is, -ignorespec : Ignore differences in folder spec if names are all equal" << std::endl <<
3416 "-lo, -lockedonly : Only copy locked/partially-locked top-level tags"
3417 << std::endl <<
3418 "-nc, -nocopy : Do not actually copy, just read source DB" << std::endl <<
3419 "-nch, -nochannel : Do not check or copy channel information" << std::endl
3420<< "-ncr, -noclobroot: Do not copy CLOB data into ROOT files" << std::endl
3421<< "-noc, -nocoracool : Do not copy Coracool structure payloads " << std::endl <<
3422 "-nd, -nodata : Copy only folder structures, not data" << std::endl <<
3423 "-nh, -nohitag : Do not follow hierarchical tag relations" << std::endl <<
3424"-mc, -mergecat <catfile> : specify POOL file catalogue for new dataset making"
3425 << std::endl;
3426 std::cout << "-of, -outfolder <folder> : rename folder on output"
3427 << std::endl <<
3428 "-onr, -onlinerun : Retrieve run number from online server (not replica)" <<std::endl <<
3429 "-ot, -outtag : " << "Rename tag on output" << std::endl;
3430 std::cout <<
3431 "-pa, -poolall : Output all POOL files (incl good) when checking files"
3432 << std::endl <<
3433"-pc, -poolcat <catfile> : specify POOL file catalogue for ref checking"
3434 << std::endl <<
3435 "-pf, -parfile <file> : Read additional options/parameters from file" <<
3436 std::endl <<
3437"-pt, -prunetags : Copy only hierarchical tags descending from specified toptags"
3438 << std::endl <<
3439"-rdo, -readoracle : force data to be read from Oracle, using dbreplica.config"
3440 << std::endl <<
3441 "-sl, -seal <val>: Set SEAL (hence COOL/POOL) output level to <val>"
3442 << std::endl <<
3443 "-sr, -skiprep : Skip folders having <norep/> folder metadata tag" <<
3444 std::endl <<
3445 "-t, -tag <tag> : Copy multiversion data with tag <tag>" << std::endl <<
3446 "-mt, -magic <tag> : Include magic tags involving the given pattern " << std::endl <<
3447"-tr, -truncate : Set destination IOVs outside query interval to query interval"
3448 << std::endl <<
3449"-tl, -taglabel : Specify tag description to enter in destination DB"
3450 << std::endl <<
3451 "-uht, -userheadtag : Also copy user tag data to the HEAD" << std::endl <<
3452 "-v, -verify : Verify data present on destination rather than copying" <<
3453 std::endl <<
3454 "-ro, -root : Produce ROOT output file instead of copying to COOL"
3455 << std::endl <<
3456 "-zn, -zeronull : Zero NULLs in ROOT file instead of skipping them" <<
3457 std::endl <<
3458 "-rls, -runlumisince <run> <LB> : Set minimum IOV interval" << std::endl <<
3459 "-rlu, -runlumiuntil <run> <LB> : Set maximum IOV interval" << std::endl <<
3460 "-rs, -runsince <run> : Set minimum IOV interval" << std::endl <<
3461 "-ru, -rununtil <run> : Set maximum IOV interval" << std::endl <<
3462 "-r, -run <run> : Copy only run <run>" << std::endl <<
3463"-srls, -skiprunlumisince <run> <LB> : Set minimum IOV for skipping IOV in copy"
3464 << std::endl <<
3465"-srlu, -skiprunlumiuntil <run> <LB> : Set maximum IOV for skipping IOV in copy"
3466 << std::endl <<
3467 "-tdb, -timedb <dbconn> : Set database connection for time information" <<
3468 "-ts, -timesince <time> : Set minimum IOV interval (UTC SECONDs or UTC YYYY-MM-DD:hh:mm:ss)" <<
3469 std::endl <<
3470 "-tu, -timeuntil <time> : Set maximum IOV interval (UTC SECONDs or UTC YYYY-MM-DD:hh:mm:ss)" <<
3471 std::endl;
3472 std::cout <<
3473 "-nrls, -newrunlumisince <run> <LB> : Set minimum of output IOV interval (use with -alliov)" << std::endl <<
3474 "-nrlu, -newrunlumiuntil <run> <LB> : Set maximum of output IOV interval (use with --aliov)" << std::endl <<
3475 "-nts, -newtimesince <time> : Set minimum of outputIOV interval (UTC SECONDs or UTC YYYY-MM-DD:hh:mm:ss) (use with --alliov)" <<
3476 std::endl <<
3477 "-ntu, -newtimeuntil <time> : Set maximum of output IOV interval (UTC SECONDs or UTC YYYY-MM-DD:hh:mm:ss) (use with --alliov)" <<
3478 std::endl;
3479 std::cout << "See http://twiki.cern.ch/twiki/bin/view/Atlas/AtlCoolCopy for more details" << std::endl;
3480}
3481
3482int main ATLAS_NOT_THREAD_SAFE (int argc, const char* argv[]) {
3483 int retcode=0;
3484 if (argc<3) {
3485 printHelp();
3486 retcode=1;
3487 } else {
3488 AtlCoolCopy mycopy(argv[1],argv[2]);
3489 retcode=mycopy.setOpts(argc-3,&argv[3]);
3490 if (retcode==999) {
3491 printHelp();
3492 return 0;
3493 }
3494 if (retcode==0) retcode=mycopy.doCopy();
3495 }
3496 if (retcode>0) std::cout << "ERROR AtlCoolCopy.exe fails with exit code " <<
3497 retcode << std::endl;
3498 return retcode;
3499}
int AtlCoolCopy::doCopy ATLAS_NOT_THREAD_SAFE()
Install fatal handler with default options.
void printHelp()
size_t WriteCallback(void *contents, size_t size, size_t nmemb, std::string *s)
boost::shared_ptr< CoraCoolObject > CoraCoolObjectPtr
boost::shared_ptr< CoraCoolObjectIter > CoraCoolObjectIterPtr
boost::shared_ptr< CoraCoolDatabase > CoraCoolDatabasePtr
boost::shared_ptr< CoraCoolFolder > CoraCoolFolderPtr
int main(int, char **)
Main class for all the CppUnit test classes.
std::pair< std::vector< unsigned int >, bool > res
MDT_Response response
size_t size() const
Number of registered mappings.
Define macros for attributes used to control the static checker.
void filePoolRefs()
static bool equalRecord(const cool::IRecord &lhs, const cool::IRecord &rhs)
cool::IDatabasePtr m_destDbPtr
void setChannelRange(const cool::IFolderPtr &sourcefl)
cool::ValidityKey m_newrunemin
AtlCoolCopy(const std::string &sourcedb, const std::string &destdb, bool allowcreate=false)
std::vector< std::string > m_folderexcl
static std::string timeString(const cool::ValidityKey iovtime)
int resolvePoolRefs ATLAS_NOT_THREAD_SAFE()
UInt_t m_nt_runsince
cool::ValidityKey m_timemax
bool openCoraCool()
cool::ValidityKey m_newrunemax
cool::Application m_coolapp
UInt_t m_nt_rununtil
std::string m_timedb
std::vector< std::string > m_channelRange
std::string rootDirs(const std::string &folder, const std::string &toproot)
std::string m_outfolder
std::vector< cool::ChannelId > m_excludechans
HiTagMap m_hitagmap
std::map< std::string, CoolTagInfo > CoolTagMap
std::vector< std::string > m_tags
cool::ValidityKey m_runemax
bool isOpen() const
bool openConnections(const std::string &sourcedb, const std::string &destdb, bool allowcreate)
CoraCoolDatabasePtr m_destCoraPtr
cool::ValidityKey m_srunemax
long long m_anadelt
TFile * p_rootfile
std::string m_newdataset
cool::ValidityKey m_timemin
std::string m_outtag
std::vector< std::string > m_parfile
bool addExclude(const std::string &folder)
void rootWrite(void *sptr, const cool::IField &field) const
PoolMap m_poolrefs
PoolMap::iterator m_poollast
std::string m_sourcedb
std::string m_nt_treename
bool addFolder(const std::string &folder, const bool onlyTags)
bool getTimeFromRun()
std::vector< std::string > m_hiparent
int verifyIOVs(const std::string &folder, const cool::IFolderPtr &sourcefl, const CoraCoolFolderPtr &sourceflc, const cool::IFolderPtr &destfl, const CoraCoolFolderPtr &destflc, const std::string &sourcetag, const cool::ValidityKey since, const cool::ValidityKey until, const bool checkrefs, const bool iscora, const cool::PayloadMode::Mode paymode)
int copyFolder ATLAS_NOT_THREAD_SAFE(const std::string &folder, const std::vector< std::string > &taglist)
std::string m_channel2
UInt_t m_nt_lbuntil
std::vector< void * > m_nt_bufferptr
static std::string getCoolHistGUID(const std::string &file)
static std::string transConn(const std::string &inconn)
int copyIOVs ATLAS_NOT_THREAD_SAFE(const std::string &folder, const std::string &destfolder, const cool::IFolderPtr &sourcefl, const CoraCoolFolderPtr &sourceflc, const cool::IFolderPtr &destfl, const CoraCoolFolderPtr &destflc, const std::string &sourcetag, const std::string &desttag, const cool::ValidityKey since, const cool::ValidityKey until, bool timestamp, bool checkrefs, bool iscora, const cool::PayloadMode::Mode paymode, bool created)
std::vector< std::string > m_poolcat
int doCopy ATLAS_NOT_THREAD_SAFE()
cool::ChannelSelection m_chansel
int rootIOVs(const std::string &folder, const cool::IFolderPtr &sourcefl, const std::string &sourcetag, const cool::ValidityKey since, const cool::ValidityKey until, const bool timestamp)
void adjustIOVs(const cool::ValidityKey &since, const cool::ValidityKey &until, const cool::ValidityKey &qsince, const cool::ValidityKey &quntil, cool::ValidityKey &newsince, cool::ValidityKey &newuntil, const bool timestamp) const
cool::IDatabaseSvc * m_dbSvc
std::vector< std::string > m_mergecat
CoraCoolDatabasePtr m_sourceCoraPtr
UInt_t m_nt_lbsince
bool rootAllocate(const cool::IFieldSpecification &spec, void *&sptr, char &rootID) const
int setOpts(int argc, const char *argv[])
coral::ConnectionService m_coralsvc
cool::ValidityKey m_newtimemax
bool getLockedTags()
bool procOptVector(const int argc, const char *argv[], std::vector< std::string > &folders)
std::vector< std::string > m_addguid
std::map< std::string, std::string > HiTagMap
bool getOnlineRun()
std::string m_channel1
ULong64_t m_nt_since
cool::ValidityKey m_runemin
char m_nt_tagid[256]
std::string m_destdb
std::string m_checkoutputfile
void checkRef(const cool::IRecord &payload, const std::string &folder, const std::string &tag)
std::vector< std::string > m_magic
static cool::ValidityKey runLBVal(const char *input1, const char *input2)
std::string m_taglabel
std::vector< unsigned int > m_runlist
std::vector< std::string > m_folderlist
std::vector< std::string > m_runfile
static TH1F * bookOrFindTH1F(const std::string &hID, const std::string &htitle, const int chan, const float xlow, const float xhigh)
static bool isNumeric(const char *input)
std::string m_runinfohost
bool m_userupdatehead
SmartIF< Gaudi::IFileCatalog > m_catalog
cool::ValidityKey m_srunemin
static int getUpdateMode(std::string_view desc, std::string_view tag)
ULong64_t m_nt_until
void setupCatalog(const std::vector< std::string > &catvec)
cool::IDatabasePtr m_sourceDbPtr
static cool::ChannelId channelID(const cool::IFolderPtr &folder, const std::string &chanstring)
int nocopyIOVs(const std::string &folder, const cool::IFolderPtr &sourcefl, const std::string &sourcetag, const cool::ValidityKey since, const cool::ValidityKey until, bool checkrefs)
static cool::ValidityKey timeVal(const char *input)
std::vector< std::string > m_addlfn
CoolTagMap m_cooltagmap
std::map< std::string, PoolMapElement > PoolMap
ReplicaSorter * m_repsort
UInt_t m_nt_channel
bool checkChannels(const std::string &folder, const cool::IFolderPtr &sourcefl, const cool::IFolderPtr &destfl, bool newfolder)
cool::ValidityKey m_newtimemin
int analyseIOVs(const std::string &folder, const cool::IFolderPtr &sourcefl, const std::string &sourcetag, const cool::ValidityKey since, const cool::ValidityKey until, const bool timestamp)
AttrListVec::const_iterator const_iterator
Common base class for POOL utilities.
virtual std::string readFileGUID(const std::string &pfn)
void contents(std::vector< std::string > &keys, TDirectory *td, const std::string &directory, const std::string &pattern, const std::string &path)
int ir
counter of the current depth
Definition fastadd.cxx:49
std::vector< std::string > tags
Definition hcg.cxx:107
std::string find(const std::string &s)
return a remapped string
Definition hcg.cxx:140
std::set< std::string > exclude
list of directories to be excluded
Definition hcg.cxx:100
static std::string treename
Definition iLumiCalc.h:31
void sort(typename DataModel_detail::iterator< DVL > beg, typename DataModel_detail::iterator< DVL > end)
Specialization of sort for DataVector/List.
TChain * tree
TFile * file
int run(int argc, char *argv[])
std::string dirname(std::string name)
Definition utils.cxx:200