43 Bool_t TTreeCloner::CompareSeek::operator()(UInt_t i1, UInt_t i2)
45 if (fObject->fBasketSeek[i1] == fObject->fBasketSeek[i2]) {
46 if (fObject->fBasketEntry[i1] == fObject->fBasketEntry[i2]) {
49 return fObject->fBasketEntry[i1] < fObject->fBasketEntry[i2];
51 return fObject->fBasketSeek[i1] < fObject->fBasketSeek[i2];
56 Bool_t TTreeCloner::CompareEntry::operator()(UInt_t i1, UInt_t i2)
58 if (fObject->fBasketEntry[i1] == fObject->fBasketEntry[i2]) {
61 return fObject->fBasketEntry[i1] < fObject->fBasketEntry[i2];
104 TTreeCloner::TTreeCloner(TTree *from, TTree *to, Option_t *method, UInt_t options) :
107 fNeedConversion(kFALSE),
112 fFromBranches( from ? from->GetListOfLeaves()->GetEntries()+1 : 0),
113 fToBranches( to ? to->GetListOfLeaves()->GetEntries()+1 : 0),
114 fMaxBaskets(CollectBranches()),
115 fBasketBranchNum(new UInt_t[fMaxBaskets]),
116 fBasketNum(new UInt_t[fMaxBaskets]),
117 fBasketSeek(new Long64_t[fMaxBaskets]),
118 fBasketEntry(new Long64_t[fMaxBaskets]),
119 fBasketIndex(new UInt_t[fMaxBaskets]),
121 fCloneMethod(TTreeCloner::kDefault),
129 if (opt.Contains(
"sortbasketsbybranch")) {
131 fCloneMethod = TTreeCloner::kSortBasketsByBranch;
132 }
else if (opt.Contains(
"sortbasketsbyentry")) {
134 fCloneMethod = TTreeCloner::kSortBasketsByEntry;
137 fCloneMethod = TTreeCloner::kSortBasketsByOffset;
139 if (fToTree) fToStartEntries = fToTree->GetEntries();
141 if (fFromTree ==
nullptr) {
143 fWarningMsg.Form(
"An input TTree is required (cloning to %s).",
146 fWarningMsg.Form(
"An input and output TTree are required.");
147 if (!(fOptions & kNoWarnings)) {
148 Warning(
"TTreeCloner::TTreeCloner",
"%s", fWarningMsg.Data());
152 if (fToTree ==
nullptr) {
153 fWarningMsg.Form(
"An output TTree is required (cloning %s).",
154 from ? from->GetName() :
"no tree");
155 if (!(fOptions & kNoWarnings)) {
156 Warning(
"TTreeCloner::TTreeCloner",
"%s", fWarningMsg.Data());
159 }
else if (fToTree->GetDirectory() ==
nullptr) {
160 fWarningMsg.Form(
"The output TTree (%s) must be associated with a directory.",
162 if (!(fOptions & kNoWarnings)) {
163 Warning(
"TTreeCloner::TTreeCloner",
"%s", fWarningMsg.Data());
166 }
else if (fToTree->GetCurrentFile() ==
nullptr) {
167 fWarningMsg.Form(
"The output TTree (%s) must be associated with a directory (%s) that is in a file.",
168 fToTree->GetName(),fToTree->GetDirectory()->GetName());
169 if (!(fOptions & kNoWarnings)) {
170 Warning(
"TTreeCloner::TTreeCloner",
"%s", fWarningMsg.Data());
173 }
else if (! fToTree->GetDirectory()->IsWritable()) {
174 if (fToTree->GetDirectory()==fToTree->GetCurrentFile()) {
175 fWarningMsg.Form(
"The output TTree (%s) must be associated with a writable file (%s).",
176 fToTree->GetName(),fToTree->GetCurrentFile()->GetName());
178 fWarningMsg.Form(
"The output TTree (%s) must be associated with a writable directory (%s in %s).",
179 fToTree->GetName(),fToTree->GetDirectory()->GetName(),fToTree->GetCurrentFile()->GetName());
181 if (!(fOptions & kNoWarnings)) {
182 Warning(
"TTreeCloner::TTreeCloner",
"%s", fWarningMsg.Data());
187 if (fIsValid && (!(fOptions & kNoFileCache))) {
188 fCacheSize = fFromTree->GetCacheAutoSize();
195 Bool_t TTreeCloner::Exec()
201 ImportClusterRanges();
204 CloseOutWriteBaskets();
217 TTreeCloner::~TTreeCloner()
222 delete [] fBasketBranchNum;
223 delete [] fBasketNum;
224 delete [] fBasketSeek;
225 delete [] fBasketEntry;
226 delete [] fBasketIndex;
233 void TTreeCloner::CloseOutWriteBaskets()
235 for(Int_t i=0; i<fToBranches.GetEntries(); ++i) {
236 TBranch *to = (TBranch*)fToBranches.UncheckedAt(i);
237 to->FlushOneBasket(to->GetWriteBasket());
247 UInt_t TTreeCloner::CollectBranches(TBranch *from, TBranch *to) {
250 UInt_t numBaskets = 0;
251 if (from->InheritsFrom(TBranchClones::Class())) {
252 TBranchClones *fromclones = (TBranchClones*) from;
253 TBranchClones *toclones = (TBranchClones*) to;
254 numBaskets += CollectBranches(fromclones->fBranchCount, toclones->fBranchCount);
256 }
else if (from->InheritsFrom(TBranchElement::Class())) {
257 Int_t nb = from->GetListOfLeaves()->GetEntries();
258 Int_t fnb = to->GetListOfLeaves()->GetEntries();
259 if (nb != fnb && (nb == 0 || fnb == 0)) {
262 fWarningMsg.Form(
"The export branch and the import branch do not have the same split level. (The branch name is %s.)",
264 if (!(fOptions & kNoWarnings)) {
265 Warning(
"TTreeCloner::CollectBranches",
"%s", fWarningMsg.Data());
267 fNeedConversion = kTRUE;
271 if (((TBranchElement*) from)->GetStreamerType() != ((TBranchElement*) to)->GetStreamerType()) {
272 fWarningMsg.Form(
"The export branch and the import branch do not have the same streamer type. (The branch name is %s.)",
274 if (!(fOptions & kNoWarnings)) {
275 Warning(
"TTreeCloner::CollectBranches",
"%s", fWarningMsg.Data());
280 TBranchElement *fromelem = (TBranchElement*) from;
281 TBranchElement *toelem = (TBranchElement*) to;
282 if (fromelem->fMaximum > toelem->fMaximum) toelem->fMaximum = fromelem->fMaximum;
285 Int_t nb = from->GetListOfLeaves()->GetEntries();
286 Int_t fnb = to->GetListOfLeaves()->GetEntries();
288 fWarningMsg.Form(
"The export branch and the import branch (%s) do not have the same number of leaves (%d vs %d)",
289 from->GetName(), fnb, nb);
290 if (!(fOptions & kNoWarnings)) {
291 Error(
"TTreeCloner::CollectBranches",
"%s", fWarningMsg.Data());
296 for (Int_t i=0;i<nb;i++) {
298 TLeaf *fromleaf = (TLeaf*)from->GetListOfLeaves()->At(i);
299 TLeaf *toleaf = (TLeaf*)to->GetListOfLeaves()->At(i);
300 if (toleaf->IsA() != fromleaf->IsA() ) {
302 fWarningMsg.Form(
"The export leaf and the import leaf (%s.%s) do not have the data type (%s vs %s)",
303 from->GetName(),fromleaf->GetName(),fromleaf->GetTypeName(),toleaf->GetTypeName());
304 if (! (fOptions & kNoWarnings) ) {
305 Warning(
"TTreeCloner::CollectBranches",
"%s", fWarningMsg.Data());
308 fNeedConversion = kTRUE;
311 toleaf->IncludeRange( fromleaf );
316 fFromBranches.AddLast(from);
317 if (!from->TestBit(TBranch::kDoNotUseBufferMap)) {
319 to->ResetBit(TBranch::kDoNotUseBufferMap);
321 fToBranches.AddLast(to);
323 numBaskets += from->GetWriteBasket();
324 numBaskets += CollectBranches(from->GetListOfBranches(),to->GetListOfBranches());
333 UInt_t TTreeCloner::CollectBranches(TObjArray *from, TObjArray *to)
337 Int_t fnb = from->GetEntries();
338 Int_t tnb = to->GetEntries();
343 UInt_t numBasket = 0;
347 TBranch* fb = (TBranch*) from->UncheckedAt(fi);
348 TBranch* tb = (TBranch*) to->UncheckedAt(ti);
350 while (strcmp(fb->GetName(), tb->GetName())) {
361 fb = (TBranch*) from->UncheckedAt(fi);
364 numBasket += CollectBranches(fb, tb);
370 if (tb->GetMother()==tb) {
372 if (!(fOptions & kIgnoreMissingTopLevel)) {
373 fWarningMsg.Form(
"One of the export top level branches (%s) is not present in the import TTree.",
375 if (!(fOptions & kNoWarnings)) {
376 Error(
"TTreeCloner::CollectBranches",
"%s", fWarningMsg.Data());
381 fWarningMsg.Form(
"One of the export sub-branches (%s) is not present in the import TTree.",
383 if (!(fOptions & kNoWarnings)) {
384 Error(
"TTreeCloner::CollectBranches",
"%s", fWarningMsg.Data());
398 UInt_t TTreeCloner::CollectBranches()
402 if (!fFromTree || !fToTree) {
405 UInt_t numBasket = CollectBranches(fFromTree->GetListOfBranches(),
406 fToTree->GetListOfBranches());
408 if (fFromTree->GetBranchRef()) {
409 fToTree->BranchRef();
410 numBasket += CollectBranches(fFromTree->GetBranchRef(),fToTree->GetBranchRef());
419 void TTreeCloner::CollectBaskets()
421 UInt_t len = fFromBranches.GetEntries();
423 for(UInt_t i=0,bi=0; i<len; ++i) {
424 TBranch *from = (TBranch*)fFromBranches.UncheckedAt(i);
425 for(Int_t b=0; b<from->GetWriteBasket(); ++b,++bi) {
426 fBasketBranchNum[bi] = i;
428 fBasketSeek[bi] = from->GetBasketSeek(b);
430 fBasketEntry[bi] = from->GetBasketEntry()[b];
431 fBasketIndex[bi] = bi;
440 void TTreeCloner::CopyStreamerInfos()
442 TFile *fromFile = fFromTree->GetDirectory()->GetFile();
443 TFile *toFile = fToTree->GetDirectory()->GetFile();
444 TList *l = fromFile->GetStreamerInfoList();
446 TStreamerInfo *oldInfo;
447 while ( (oldInfo = (TStreamerInfo*)next()) ) {
448 if (oldInfo->IsA() != TStreamerInfo::Class()) {
451 TStreamerInfo *curInfo = 0;
452 TClass *cl = TClass::GetClass(oldInfo->GetName());
454 if (!cl->IsLoaded() || cl->GetNew()) {
456 curInfo = (TStreamerInfo*)cl->GetStreamerInfo(oldInfo->GetClassVersion());
457 if (oldInfo->GetClassVersion()==1) {
460 TStreamerInfo *matchInfo = (TStreamerInfo*)cl->FindStreamerInfo(oldInfo->GetCheckSum());
465 curInfo->ForceWriteInfo(toFile);
472 oldInfo->ForceWriteInfo(toFile);
481 void TTreeCloner::CopyMemoryBaskets()
484 for(Int_t i=0; i<fToBranches.GetEntries(); ++i) {
485 TBranch *from = (TBranch*)fFromBranches.UncheckedAt( i );
486 TBranch *to = (TBranch*)fToBranches.UncheckedAt( i );
488 basket = from->GetListOfBaskets()->GetEntries() ? from->GetBasket(from->GetWriteBasket()) : 0;
490 basket = (TBasket*)basket->Clone();
491 basket->SetBranch(to);
492 to->AddBasket(*basket, kFALSE, fToStartEntries+from->GetBasketEntry()[from->GetWriteBasket()]);
494 to->AddLastBasket( fToStartEntries+from->GetBasketEntry()[from->GetWriteBasket()] );
498 if (from->GetEntries()!=0 && from->GetWriteBasket()==0 && (basket==0 || basket->GetNevBuf()==0)) {
499 to->SetEntries(to->GetEntries()+from->GetEntries());
508 void TTreeCloner::CopyProcessIds()
512 TFile *fromfile = fFromTree->GetDirectory()->GetFile();
513 TFile *tofile = fToTree->GetDirectory()->GetFile();
515 fPidOffset = tofile->GetNProcessIDs();
517 TIter next(fromfile->GetListOfKeys());
519 TDirectory::TContext cur(fromfile);
520 while ((key = (TKey*)next())) {
521 if (!strcmp(key->GetClassName(),
"TProcessID")) {
522 TProcessID *pid = (TProcessID*)key->ReadObjectAny(0);
527 TObjArray *pids = tofile->GetListOfProcessIDs();
528 Int_t npids = tofile->GetNProcessIDs();
529 Bool_t wasIn = kFALSE;
530 for (Int_t i=0;i<npids;i++) {
531 if (pids->At(i) == pid) {out = (UShort_t)i; wasIn = kTRUE;
break;}
535 TDirectory *dirsav = gDirectory;
537 tofile->SetBit(TFile::kHasReferences);
538 pids->AddAtAndExpand(pid,npids);
539 pid->IncrementCount();
541 snprintf(name,32,
"ProcessID%d",npids);
543 tofile->IncrementProcessIDs();
545 Info(
"WriteProcessID",
"name=%s, file=%s", name, tofile->GetName());
547 if (dirsav) dirsav->cd();
548 out = (UShort_t)npids;
550 if (out<fPidOffset) {
551 Error(
"CopyProcessIDs",
"Copied %s from %s might already exist!\n",
552 pid->GetName(),fromfile->GetName());
561 void TTreeCloner::CreateCache()
563 if (fCacheSize && fFromTree->GetCurrentFile()) {
564 TFile *f = fFromTree->GetCurrentFile();
565 auto prev = fFromTree->GetReadCache(f);
566 if (fFileCache && prev == fFileCache) {
571 if (prev) f->SetCacheRead(
nullptr, fFromTree);
573 fFileCache =
new TFileCacheRead(f, fCacheSize, fFromTree);
580 void TTreeCloner::RestoreCache() {
581 if (IsValid() && fFileCache && fFromTree->GetCurrentFile()) {
582 TFile *f = fFromTree->GetCurrentFile();
583 f->SetCacheRead(
nullptr,fFromTree);
584 f->SetCacheRead(fPrevCache, fFromTree);
591 void TTreeCloner::ImportClusterRanges()
596 fToTree->SetEntries(fToTree->GetEntries() - fFromTree->GetTree()->GetEntries());
598 fToTree->ImportClusterRanges( fFromTree->GetTree() );
603 fToTree->fFlushedBytes += fFromTree->fFlushedBytes;
605 fToTree->SetEntries(fToTree->GetEntries() + fFromTree->GetTree()->GetEntries());
614 void TTreeCloner::SetCacheSize(Int_t size)
617 if (IsValid() && fFileCache) {
618 if (fCacheSize == 0 || fCacheSize != fFileCache->GetBufferSize()) {
619 TFile *f = fFromTree->GetCurrentFile();
620 f->SetCacheRead(
nullptr,fFromTree);
622 fFileCache =
nullptr;
632 void TTreeCloner::SortBaskets()
637 switch (fCloneMethod) {
638 case kSortBasketsByBranch:
641 case kSortBasketsByEntry: {
642 for(UInt_t i = 0; i < fMaxBaskets; ++i) { fBasketIndex[i] = i; }
643 std::sort(fBasketIndex, fBasketIndex+fMaxBaskets, CompareEntry(
this) );
646 case kSortBasketsByOffset:
648 for(UInt_t i = 0; i < fMaxBaskets; ++i) { fBasketIndex[i] = i; }
649 std::sort(fBasketIndex, fBasketIndex+fMaxBaskets, CompareSeek(
this) );
660 UInt_t TTreeCloner::FillCache(UInt_t from)
662 if (!fFileCache)
return 0;
664 fFileCache->Prefetch(0, 0);
666 for (UInt_t j = from; j < fMaxBaskets; ++j) {
667 TBranch *frombr = (TBranch *) fFromBranches.UncheckedAt(fBasketBranchNum[fBasketIndex[j]]);
670 Int_t index = fBasketNum[ fBasketIndex[j] ];
671 Long64_t pos = frombr->GetBasketSeek(index);
672 Int_t len = frombr->GetBasketBytes()[index];
675 if (size > fFileCache->GetBufferSize()) {
678 fFileCache->Prefetch(pos,len);
687 void TTreeCloner::WriteBaskets()
689 TBasket *basket =
new TBasket();
690 for(UInt_t j = 0, notCached = 0; j<fMaxBaskets; ++j) {
691 TBranch *from = (TBranch*)fFromBranches.UncheckedAt( fBasketBranchNum[ fBasketIndex[j] ] );
692 TBranch *to = (TBranch*)fToBranches.UncheckedAt( fBasketBranchNum[ fBasketIndex[j] ] );
694 TFile *tofile = to->GetFile(0);
695 TFile *fromfile = from->GetFile(0);
697 Int_t index = fBasketNum[ fBasketIndex[j] ];
699 Long64_t pos = from->GetBasketSeek(index);
701 if (fFileCache && j >= notCached) {
702 notCached = FillCache(notCached);
704 if (from->GetBasketBytes()[index] == 0) {
705 from->GetBasketBytes()[index] = basket->ReadBasketBytes(pos, fromfile);
707 Int_t len = from->GetBasketBytes()[index];
709 basket->LoadBasketBuffers(pos,len,fromfile,fFromTree);
710 basket->IncrementPidOffset(fPidOffset);
711 basket->CopyTo(tofile);
712 to->AddBasket(*basket,kTRUE,fToStartEntries + from->GetBasketEntry()[index]);
714 TBasket *frombasket = from->GetBasket( index );
715 if (frombasket && frombasket->GetNevBuf()>0) {
716 TBasket *tobasket = (TBasket*)frombasket->Clone();
717 tobasket->SetBranch(to);
718 to->AddBasket(*tobasket, kFALSE, fToStartEntries+from->GetBasketEntry()[index]);
719 to->FlushOneBasket(to->GetWriteBasket());