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