ROOT  6.06/09
Reference Guide
TTreeCloner.cxx
Go to the documentation of this file.
1 // @(#)root/tree:$Id$
2 // Author: Philippe Canal 07/11/2005
3 
4 /*************************************************************************
5  * Copyright (C) 1995-2000, Rene Brun and Fons Rademakers. *
6  * All rights reserved. *
7  * *
8  * For the licensing terms see $ROOTSYS/LICENSE. *
9  * For the list of contributors see $ROOTSYS/README/CREDITS. *
10  *************************************************************************/
11 
12 /** \class TTreeCloner
13 Class implementing or helping the various TTree cloning method
14 */
15 
16 #include "TBasket.h"
17 #include "TBranch.h"
18 #include "TBranchClones.h"
19 #include "TBranchElement.h"
20 #include "TStreamerInfo.h"
21 #include "TBranchRef.h"
22 #include "TError.h"
23 #include "TProcessID.h"
24 #include "TMath.h"
25 #include "TTree.h"
26 #include "TTreeCloner.h"
27 #include "TFile.h"
28 #include "TLeafB.h"
29 #include "TLeafI.h"
30 #include "TLeafL.h"
31 #include "TLeafS.h"
32 #include "TLeafO.h"
33 #include "TLeafC.h"
34 #include "TFileCacheRead.h"
35 
36 #include <algorithm>
37 
38 ////////////////////////////////////////////////////////////////////////////////
39 
41 {
42  if (fObject->fBasketSeek[i1] == fObject->fBasketSeek[i2]) {
43  if (fObject->fBasketEntry[i1] == fObject->fBasketEntry[i2]) {
44  return i1 < i2;
45  }
46  return fObject->fBasketEntry[i1] < fObject->fBasketEntry[i2];
47  }
48  return fObject->fBasketSeek[i1] < fObject->fBasketSeek[i2];
49 }
50 
51 ////////////////////////////////////////////////////////////////////////////////
52 
54 {
55  if (fObject->fBasketEntry[i1] == fObject->fBasketEntry[i2]) {
56  return i1 < i2;
57  }
58  return fObject->fBasketEntry[i1] < fObject->fBasketEntry[i2];
59 }
60 
61 ////////////////////////////////////////////////////////////////////////////////
62 /// Constructor. This object would transfer the data from
63 /// 'from' to 'to' using the method indicated in method.
64 ///
65 /// The value of the parameter 'method' determines in which
66 /// order the branches' baskets are written to the output file.
67 ///
68 /// When a TTree is filled the data is stored in the individual
69 /// branches' basket. Each basket is written individually to
70 /// the disk as soon as it is full. In consequence the baskets
71 /// of branches that contain 'large' data chunk are written to
72 /// the disk more often.
73 ///
74 /// There is currently 3 supported sorting order:
75 ///
76 /// SortBasketsByOffset (the default)
77 /// SortBasketsByBranch
78 /// SortBasketsByEntry
79 ///
80 /// When using SortBasketsByOffset the baskets are written in
81 /// the output file in the same order as in the original file
82 /// (i.e. the basket are sorted on their offset in the original
83 /// file; Usually this also means that the baskets are sorted
84 /// on the index/number of the _last_ entry they contain)
85 ///
86 /// When using SortBasketsByBranch all the baskets of each
87 /// individual branches are stored contiguously. This tends to
88 /// optimize reading speed when reading a small number (1->5) of
89 /// branches, since all their baskets will be clustered together
90 /// instead of being spread across the file. However it might
91 /// decrease the performance when reading more branches (or the full
92 /// entry).
93 ///
94 /// When using SortBasketsByEntry the baskets with the lowest
95 /// starting entry are written first. (i.e. the baskets are
96 /// sorted on the index/number of the first entry they contain).
97 /// This means that on the file the baskets will be in the order
98 /// in which they will be needed when reading the whole tree
99 /// sequentially.
100 
101 TTreeCloner::TTreeCloner(TTree *from, TTree *to, Option_t *method, UInt_t options) :
102  fWarningMsg(),
103  fIsValid(kTRUE),
105  fOptions(options),
106  fFromTree(from),
107  fToTree(to),
108  fMethod(method),
109  fFromBranches( from ? from->GetListOfLeaves()->GetEntries()+1 : 0),
110  fToBranches( to ? to->GetListOfLeaves()->GetEntries()+1 : 0),
117  fPidOffset(0),
119  fToStartEntries(0),
120  fCacheSize(0LL),
123 {
124  TString opt(method);
125  opt.ToLower();
126  if (opt.Contains("sortbasketsbybranch")) {
127  //::Info("TTreeCloner::TTreeCloner","use: kSortBasketsByBranch");
129  } else if (opt.Contains("sortbasketsbyentry")) {
130  //::Info("TTreeCloner::TTreeCloner","use: kSortBasketsByEntry");
132  } else {
133  //::Info("TTreeCloner::TTreeCloner","use: kSortBasketsByOffset");
135  }
137 
138  if (fFromTree == nullptr) {
139  if (to)
140  fWarningMsg.Form("An input TTree is required (cloning to %s).",
141  to->GetName());
142  else
143  fWarningMsg.Form("An input and output TTree are required.");
144  if (!(fOptions & kNoWarnings)) {
145  Warning("TTreeCloner::TTreeCloner", "%s", fWarningMsg.Data());
146  }
147  fIsValid = kFALSE;
148  }
149  if (fToTree == nullptr) {
150  fWarningMsg.Form("An output TTree is required (cloning %s).",
151  from ? from->GetName() : "no tree");
152  if (!(fOptions & kNoWarnings)) {
153  Warning("TTreeCloner::TTreeCloner", "%s", fWarningMsg.Data());
154  }
155  fIsValid = kFALSE;
156  } else if (fToTree->GetDirectory() == nullptr) {
157  fWarningMsg.Form("The output TTree (%s) must be associated with a directory.",
158  fToTree->GetName());
159  if (!(fOptions & kNoWarnings)) {
160  Warning("TTreeCloner::TTreeCloner", "%s", fWarningMsg.Data());
161  }
162  fIsValid = kFALSE;
163  } else if (fToTree->GetCurrentFile() == nullptr) {
164  fWarningMsg.Form("The output TTree (%s) must be associated with a directory (%s) that is in a file.",
166  if (!(fOptions & kNoWarnings)) {
167  Warning("TTreeCloner::TTreeCloner", "%s", fWarningMsg.Data());
168  }
169  fIsValid = kFALSE;
170  } else if (! fToTree->GetDirectory()->IsWritable()) {
172  fWarningMsg.Form("The output TTree (%s) must be associated with a writable file (%s).",
174  } else {
175  fWarningMsg.Form("The output TTree (%s) must be associated with a writable directory (%s in %s).",
177  }
178  if (!(fOptions & kNoWarnings)) {
179  Warning("TTreeCloner::TTreeCloner", "%s", fWarningMsg.Data());
180  }
181  fIsValid = kFALSE;
182  }
183 
184  if (fIsValid && (!(fOptions & kNoFileCache))) {
186  }
187 }
188 
189 ////////////////////////////////////////////////////////////////////////////////
190 /// Execute the cloning.
191 
193 {
194  if (!IsValid()) {
195  return kFALSE;
196  }
197  CreateCache();
200  CopyProcessIds();
202  CollectBaskets();
203  SortBaskets();
204  WriteBaskets();
206  RestoreCache();
207 
208  return kTRUE;
209 }
210 
211 ////////////////////////////////////////////////////////////////////////////////
212 /// TTreeCloner destructor
213 
215 {
216  // The file cache was restored to its previous value at the end of Exec,
217  // we can safely delete our cache.
218  delete fFileCache;
219  delete [] fBasketBranchNum;
220  delete [] fBasketNum;
221  delete [] fBasketSeek;
222  delete [] fBasketEntry;
223  delete [] fBasketIndex;
224 }
225 
226 ////////////////////////////////////////////////////////////////////////////////
227 /// Before we can start adding new basket, we need to flush to
228 /// disk the partially filled baskets (the WriteBasket)
229 
231 {
232  for(Int_t i=0; i<fToBranches.GetEntries(); ++i) {
234  to->FlushOneBasket(to->GetWriteBasket());
235  }
236 }
237 
238 ////////////////////////////////////////////////////////////////////////////////
239 /// Fill the array of branches, adding the branch 'from' and 'to',
240 /// and matching the sub-branches of the 'from' and 'to' branches.
241 /// Returns the total number of baskets in all the from branch and
242 /// it sub-branches.
243 
245  // Since this is called from the constructor, this can not be a virtual function
246 
247  UInt_t numBaskets = 0;
248  if (from->InheritsFrom(TBranchClones::Class())) {
249  TBranchClones *fromclones = (TBranchClones*) from;
250  TBranchClones *toclones = (TBranchClones*) to;
251  numBaskets += CollectBranches(fromclones->fBranchCount, toclones->fBranchCount);
252 
253  } else if (from->InheritsFrom(TBranchElement::Class())) {
254  Int_t nb = from->GetListOfLeaves()->GetEntries();
255  Int_t fnb = to->GetListOfLeaves()->GetEntries();
256  if (nb != fnb && (nb == 0 || fnb == 0)) {
257  // We might be in the case where one branch is split
258  // while the other is not split. We must reject this match.
259  fWarningMsg.Form("The export branch and the import branch do not have the same split level. (The branch name is %s.)",
260  from->GetName());
261  if (!(fOptions & kNoWarnings)) {
262  Warning("TTreeCloner::CollectBranches", "%s", fWarningMsg.Data());
263  }
265  fIsValid = kFALSE;
266  return 0;
267  }
268  if (((TBranchElement*) from)->GetStreamerType() != ((TBranchElement*) to)->GetStreamerType()) {
269  fWarningMsg.Form("The export branch and the import branch do not have the same streamer type. (The branch name is %s.)",
270  from->GetName());
271  if (!(fOptions & kNoWarnings)) {
272  Warning("TTreeCloner::CollectBranches", "%s", fWarningMsg.Data());
273  }
274  fIsValid = kFALSE;
275  return 0;
276  }
277  TBranchElement *fromelem = (TBranchElement*) from;
278  TBranchElement *toelem = (TBranchElement*) to;
279  if (fromelem->fMaximum > toelem->fMaximum) toelem->fMaximum = fromelem->fMaximum;
280  } else {
281 
282  Int_t nb = from->GetListOfLeaves()->GetEntries();
283  Int_t fnb = to->GetListOfLeaves()->GetEntries();
284  if (nb != fnb) {
285  fWarningMsg.Form("The export branch and the import branch (%s) do not have the same number of leaves (%d vs %d)",
286  from->GetName(), fnb, nb);
287  if (!(fOptions & kNoWarnings)) {
288  Error("TTreeCloner::CollectBranches", "%s", fWarningMsg.Data());
289  }
290  fIsValid = kFALSE;
291  return 0;
292  }
293  for (Int_t i=0;i<nb;i++) {
294 
295  TLeaf *fromleaf_gen = (TLeaf*)from->GetListOfLeaves()->At(i);
296  TLeaf *toleaf_gen = (TLeaf*)to->GetListOfLeaves()->At(i);
297  if (toleaf_gen->IsA() != fromleaf_gen->IsA() ) {
298  // The data type do not match, we can not do a fast merge.
299  fWarningMsg.Form("The export leaf and the import leaf (%s.%s) do not have the data type (%s vs %s)",
300  from->GetName(),fromleaf_gen->GetName(),fromleaf_gen->GetTypeName(),toleaf_gen->GetTypeName());
301  if (! (fOptions & kNoWarnings) ) {
302  Warning("TTreeCloner::CollectBranches", "%s", fWarningMsg.Data());
303  }
304  fIsValid = kFALSE;
306  return 0;
307  }
308  if (fromleaf_gen->IsA()==TLeafI::Class()) {
309  TLeafI *fromleaf = (TLeafI*)fromleaf_gen;
310  TLeafI *toleaf = (TLeafI*)toleaf_gen;
311  if (fromleaf->GetMaximum() > toleaf->GetMaximum())
312  toleaf->SetMaximum( fromleaf->GetMaximum() );
313  if (fromleaf->GetMinimum() < toleaf->GetMinimum())
314  toleaf->SetMinimum( fromleaf->GetMinimum() );
315  } else if (fromleaf_gen->IsA()==TLeafL::Class()) {
316  TLeafL *fromleaf = (TLeafL*)fromleaf_gen;
317  TLeafL *toleaf = (TLeafL*)toleaf_gen;
318  if (fromleaf->GetMaximum() > toleaf->GetMaximum())
319  toleaf->SetMaximum( fromleaf->GetMaximum() );
320  if (fromleaf->GetMinimum() < toleaf->GetMinimum())
321  toleaf->SetMinimum( fromleaf->GetMinimum() );
322  } else if (fromleaf_gen->IsA()==TLeafB::Class()) {
323  TLeafB *fromleaf = (TLeafB*)fromleaf_gen;
324  TLeafB *toleaf = (TLeafB*)toleaf_gen;
325  if (fromleaf->GetMaximum() > toleaf->GetMaximum())
326  toleaf->SetMaximum( fromleaf->GetMaximum() );
327  if (fromleaf->GetMinimum() < toleaf->GetMinimum())
328  toleaf->SetMinimum( fromleaf->GetMinimum() );
329  } else if (fromleaf_gen->IsA()==TLeafS::Class()) {
330  TLeafS *fromleaf = (TLeafS*)fromleaf_gen;
331  TLeafS *toleaf = (TLeafS*)toleaf_gen;
332  if (fromleaf->GetMaximum() > toleaf->GetMaximum())
333  toleaf->SetMaximum( fromleaf->GetMaximum() );
334  if (fromleaf->GetMinimum() < toleaf->GetMinimum())
335  toleaf->SetMinimum( fromleaf->GetMinimum() );
336  } else if (fromleaf_gen->IsA()==TLeafO::Class()) {
337  TLeafO *fromleaf = (TLeafO*)fromleaf_gen;
338  TLeafO *toleaf = (TLeafO*)toleaf_gen;
339  if (fromleaf->GetMaximum() > toleaf->GetMaximum())
340  toleaf->SetMaximum( fromleaf->GetMaximum() );
341  if (fromleaf->GetMinimum() < toleaf->GetMinimum())
342  toleaf->SetMinimum( fromleaf->GetMinimum() );
343  } else if (fromleaf_gen->IsA()==TLeafC::Class()) {
344  TLeafC *fromleaf = (TLeafC*)fromleaf_gen;
345  TLeafC *toleaf = (TLeafC*)toleaf_gen;
346  if (fromleaf->GetMaximum() > toleaf->GetMaximum())
347  toleaf->SetMaximum( fromleaf->GetMaximum() );
348  if (fromleaf->GetMinimum() < toleaf->GetMinimum())
349  toleaf->SetMinimum( fromleaf->GetMinimum() );
350  if (fromleaf->GetLenStatic() > toleaf->GetLenStatic())
351  toleaf->SetLen(fromleaf->GetLenStatic());
352  }
353  }
354 
355  }
356 
357  fFromBranches.AddLast(from);
358  if (!from->TestBit(TBranch::kDoNotUseBufferMap)) {
359  // Make sure that we reset the Buffer's map if needed.
361  }
362  fToBranches.AddLast(to);
363 
364  numBaskets += from->GetWriteBasket();
365  numBaskets += CollectBranches(from->GetListOfBranches(),to->GetListOfBranches());
366 
367  return numBaskets;
368 }
369 
370 ////////////////////////////////////////////////////////////////////////////////
371 /// Fill the array of branches, matching the branches of the 'from' and 'to' arrays.
372 /// Returns the total number of baskets in all the branches.
373 
375 {
376  // Since this is called from the constructor, this can not be a virtual function
377 
378  Int_t fnb = from->GetEntries();
379  Int_t tnb = to->GetEntries();
380  if (!fnb || !tnb) {
381  return 0;
382  }
383 
384  UInt_t numBasket = 0;
385  Int_t fi = 0;
386  Int_t ti = 0;
387  while (ti < tnb) {
388  TBranch* fb = (TBranch*) from->UncheckedAt(fi);
389  TBranch* tb = (TBranch*) to->UncheckedAt(ti);
390  Int_t firstfi = fi;
391  while (strcmp(fb->GetName(), tb->GetName())) {
392  ++fi;
393  if (fi >= fnb) {
394  // continue at the beginning
395  fi = 0;
396  }
397  if (fi==firstfi) {
398  // We tried all the branches and there is not match.
399  fb = 0;
400  break;
401  }
402  fb = (TBranch*) from->UncheckedAt(fi);
403  }
404  if (fb) {
405  numBasket += CollectBranches(fb, tb);
406  ++fi;
407  if (fi >= fnb) {
408  fi = 0;
409  }
410  } else {
411  if (tb->GetMother()==tb) {
412  // Top level branch.
413  if (!(fOptions & kIgnoreMissingTopLevel)) {
414  fWarningMsg.Form("One of the export top level branches (%s) is not present in the import TTree.",
415  tb->GetName());
416  if (!(fOptions & kNoWarnings)) {
417  Error("TTreeCloner::CollectBranches", "%s", fWarningMsg.Data());
418  }
419  fIsValid = kFALSE;
420  }
421  } else {
422  fWarningMsg.Form("One of the export sub-branches (%s) is not present in the import TTree.",
423  tb->GetName());
424  if (!(fOptions & kNoWarnings)) {
425  Error("TTreeCloner::CollectBranches", "%s", fWarningMsg.Data());
426  }
427  fIsValid = kFALSE;
428  }
429  }
430  ++ti;
431  }
432  return numBasket;
433 }
434 
435 ////////////////////////////////////////////////////////////////////////////////
436 /// Fill the array of branches, matching the branches of the 'from' and 'to' TTrees
437 /// Returns the total number of baskets in all the branches.
438 
440 {
441  // Since this is called from the constructor, this can not be a virtual function
442 
443  if (!fFromTree || !fToTree) {
444  return 0;
445  }
448 
449  if (fFromTree->GetBranchRef()) {
450  fToTree->BranchRef();
452  }
453  return numBasket;
454 }
455 
456 ////////////////////////////////////////////////////////////////////////////////
457 /// Collect the information about the on-file basket that need
458 /// to be copied.
459 
461 {
463 
464  for(UInt_t i=0,bi=0; i<len; ++i) {
466  for(Int_t b=0; b<from->GetWriteBasket(); ++b,++bi) {
467  fBasketBranchNum[bi] = i;
468  fBasketNum[bi] = b;
469  fBasketSeek[bi] = from->GetBasketSeek(b);
470  //fprintf(stderr,"For %s %d %lld\n",from->GetName(),bi,fBasketSeek[bi]);
471  fBasketEntry[bi] = from->GetBasketEntry()[b];
472  fBasketIndex[bi] = bi;
473  }
474  }
475 }
476 
477 ////////////////////////////////////////////////////////////////////////////////
478 /// Make sure that all the needed TStreamerInfo are
479 /// present in the output file
480 
482 {
483  TFile *fromFile = fFromTree->GetDirectory()->GetFile();
484  TFile *toFile = fToTree->GetDirectory()->GetFile();
485  TList *l = fromFile->GetStreamerInfoList();
486  TIter next(l);
487  TStreamerInfo *oldInfo;
488  while ( (oldInfo = (TStreamerInfo*)next()) ) {
489  if (oldInfo->IsA() != TStreamerInfo::Class()) {
490  continue;
491  }
492  TStreamerInfo *curInfo = 0;
493  TClass *cl = TClass::GetClass(oldInfo->GetName());
494 
495  if (!cl->IsLoaded() || cl->GetNew()) {
496  // Insure that the TStreamerInfo is loaded
497  curInfo = (TStreamerInfo*)cl->GetStreamerInfo(oldInfo->GetClassVersion());
498  if (oldInfo->GetClassVersion()==1) {
499  // We may have a Foreign class let's look using the
500  // checksum:
501  TStreamerInfo *matchInfo = (TStreamerInfo*)cl->FindStreamerInfo(oldInfo->GetCheckSum());
502  if (matchInfo) {
503  curInfo = matchInfo;
504  }
505  }
506  curInfo->ForceWriteInfo(toFile);
507  } else {
508  // If there is no default constructor the GetStreamerInfo
509  // will not work. It also means (hopefully) that an
510  // inheriting class has a streamerInfo in the list (which
511  // will induces the setting of this streamerInfo)
512 
513  oldInfo->ForceWriteInfo(toFile);
514  }
515  }
516  delete l;
517 }
518 
519 ////////////////////////////////////////////////////////////////////////////////
520 /// Transfer the basket from the input file to the output file
521 
523 {
524  TBasket *basket = 0;
525  for(Int_t i=0; i<fToBranches.GetEntries(); ++i) {
526  TBranch *from = (TBranch*)fFromBranches.UncheckedAt( i );
527  TBranch *to = (TBranch*)fToBranches.UncheckedAt( i );
528 
529  basket = from->GetListOfBaskets()->GetEntries() ? from->GetBasket(from->GetWriteBasket()) : 0;
530  if (basket) {
531  basket = (TBasket*)basket->Clone();
532  basket->SetBranch(to);
533  to->AddBasket(*basket, kFALSE, fToStartEntries+from->GetBasketEntry()[from->GetWriteBasket()]);
534  } else {
536  }
537  // In older files, if the branch is a TBranchElement non-terminal 'object' branch, it's basket will contain 0
538  // events, in newer file in the same case, the write basket will be missing.
539  if (from->GetEntries()!=0 && from->GetWriteBasket()==0 && (basket==0 || basket->GetNevBuf()==0)) {
540  to->SetEntries(to->GetEntries()+from->GetEntries());
541  }
542  }
543 }
544 
545 ////////////////////////////////////////////////////////////////////////////////
546 /// Make sure that all the needed TStreamerInfo are
547 /// present in the output file
548 
550 {
551  // NOTE: We actually need to merge the ProcessId somehow :(
552 
553  TFile *fromfile = fFromTree->GetDirectory()->GetFile();
554  TFile *tofile = fToTree->GetDirectory()->GetFile();
555 
556  fPidOffset = tofile->GetNProcessIDs();
557 
558  TIter next(fromfile->GetListOfKeys());
559  TKey *key;
560  TDirectory::TContext cur(fromfile);
561  while ((key = (TKey*)next())) {
562  if (!strcmp(key->GetClassName(),"TProcessID")) {
563  TProcessID *pid = (TProcessID*)key->ReadObjectAny(0);
564  if (!pid) continue;
565 
566  //UShort_t out = TProcessID::WriteProcessID(id,tofile);
567  UShort_t out = 0;
568  TObjArray *pids = tofile->GetListOfProcessIDs();
569  Int_t npids = tofile->GetNProcessIDs();
570  Bool_t wasIn = kFALSE;
571  for (Int_t i=0;i<npids;i++) {
572  if (pids->At(i) == pid) {out = (UShort_t)i; wasIn = kTRUE; break;}
573  }
574 
575  if (!wasIn) {
576  TDirectory *dirsav = gDirectory;
577  tofile->cd();
578  tofile->SetBit(TFile::kHasReferences);
579  pids->AddAtAndExpand(pid,npids);
580  pid->IncrementCount();
581  char name[32];
582  snprintf(name,32,"ProcessID%d",npids);
583  pid->Write(name);
584  tofile->IncrementProcessIDs();
585  if (gDebug > 0) {
586  Info("WriteProcessID", "name=%s, file=%s", name, tofile->GetName());
587  }
588  if (dirsav) dirsav->cd();
589  out = (UShort_t)npids;
590  }
591  if (out<fPidOffset) {
592  Error("CopyProcessIDs","Copied %s from %s might already exist!\n",
593  pid->GetName(),fromfile->GetName());
594  }
595  }
596  }
597 }
598 
599 ////////////////////////////////////////////////////////////////////////////////
600 /// Create a TFileCacheRead if it was requested.
601 
603 {
604  if (fCacheSize && fFromTree->GetCurrentFile()) {
606  auto prev = f->GetCacheRead(fFromTree);
607  if (fFileCache && prev == fFileCache) {
608  return;
609  }
610  fPrevCache = prev;
611  // Remove the previous cache if any.
612  if (prev) f->SetCacheRead(nullptr, fFromTree);
613  // The constructor attach the new cache.
615  }
616 }
617 
618 ////////////////////////////////////////////////////////////////////////////////
619 /// Restore the TFileCacheRead to its previous value.
620 
622  if (IsValid() && fFileCache && fFromTree->GetCurrentFile()) {
624  f->SetCacheRead(nullptr,fFromTree); // Remove our file cache.
626  }
627 }
628 
629 ////////////////////////////////////////////////////////////////////////////////
630 /// Set the entries and import the cluster range of the
631 
633 {
634  // First undo, the external call to SetEntries
635  // We could improve the interface to optional tell the TTreeCloner that the
636  // SetEntries was not done.
638 
640 
642 }
643 
644 ////////////////////////////////////////////////////////////////////////////////
645 /// Set the TFile cache size to be used.
646 /// Note that the default is to use the same size as the default TTreeCache for
647 /// the input tree.
648 /// \param size Size of the cache. Zero disable the use of the cache.
649 
651 {
652  fCacheSize = size;
653  if (IsValid() && fFileCache) {
654  if (fCacheSize == 0 || fCacheSize != fFileCache->GetBufferSize()) {
656  f->SetCacheRead(nullptr,fFromTree);
657  delete fFileCache;
658  fFileCache = nullptr;
659  }
660  }
661  // Note if the TFile cache is needed, it will be created at the
662  // beginning of Exec.
663 }
664 
665 ////////////////////////////////////////////////////////////////////////////////
666 /// Sort the basket according to the user request.
667 
669 {
670  // Currently this sort __has to__ preserve the order
671  // of basket for each individual branch.
672 
673  switch (fCloneMethod) {
675  // nothing to do, it is already sorted.
676  break;
677  case kSortBasketsByEntry: {
678  for(UInt_t i = 0; i < fMaxBaskets; ++i) { fBasketIndex[i] = i; }
679  std::sort(fBasketIndex, fBasketIndex+fMaxBaskets, CompareEntry( this) );
680  break;
681  }
683  default: {
684  for(UInt_t i = 0; i < fMaxBaskets; ++i) { fBasketIndex[i] = i; }
685  std::sort(fBasketIndex, fBasketIndex+fMaxBaskets, CompareSeek( this) );
686  break;
687  }
688  }
689 }
690 
691 ////////////////////////////////////////////////////////////////////////////////
692 /// Fill the file cache with the next set of basket.
693 ///
694 /// \param from index of the first lement of fFromBranches to start caching
695 /// \return The index of first element of fFromBranches that is not in the cache
697 {
698  if (!fFileCache) return 0;
699  // Reset the cache
700  fFileCache->Prefetch(0, 0);
701  Long64_t size = 0;
702  for (UInt_t j = from; j < fMaxBaskets; ++j) {
704 
705 
706  Int_t index = fBasketNum[ fBasketIndex[j] ];
707  Long64_t pos = frombr->GetBasketSeek(index);
708  Int_t len = frombr->GetBasketBytes()[index];
709  if (pos && len) {
710  size += len;
711  if (size > fFileCache->GetBufferSize()) {
712  return j;
713  }
714  fFileCache->Prefetch(pos,len);
715  }
716  }
717  return fMaxBaskets;
718 }
719 
720 ////////////////////////////////////////////////////////////////////////////////
721 /// Transfer the basket from the input file to the output file
722 
724 {
725  TBasket *basket = new TBasket();
726  for(UInt_t j = 0, notCached = 0; j<fMaxBaskets; ++j) {
729 
730  TFile *tofile = to->GetFile(0);
731  TFile *fromfile = from->GetFile(0);
732 
733  Int_t index = fBasketNum[ fBasketIndex[j] ];
734 
735  Long64_t pos = from->GetBasketSeek(index);
736  if (pos!=0) {
737  if (fFileCache && j >= notCached) {
738  notCached = FillCache(notCached);
739  }
740  if (from->GetBasketBytes()[index] == 0) {
741  from->GetBasketBytes()[index] = basket->ReadBasketBytes(pos, fromfile);
742  }
743  Int_t len = from->GetBasketBytes()[index];
744 
745  basket->LoadBasketBuffers(pos,len,fromfile,fFromTree);
747  basket->CopyTo(tofile);
748  to->AddBasket(*basket,kTRUE,fToStartEntries + from->GetBasketEntry()[index]);
749  } else {
750  TBasket *frombasket = from->GetBasket( index );
751  if (frombasket && frombasket->GetNevBuf()>0) {
752  TBasket *tobasket = (TBasket*)frombasket->Clone();
753  tobasket->SetBranch(to);
754  to->AddBasket(*tobasket, kFALSE, fToStartEntries+from->GetBasketEntry()[index]);
755  to->FlushOneBasket(to->GetWriteBasket());
756  }
757  }
758  }
759  delete basket;
760 }
Describe Streamer information for one class version.
Definition: TStreamerInfo.h:47
virtual Int_t GetNProcessIDs() const
Definition: TFile.h:199
virtual Bool_t cd(const char *path=0)
Change current directory to "this" directory.
TTreeCloner(const TTreeCloner &)=delete
virtual Int_t GetMinimum() const
Definition: TLeafL.h:46
Int_t ReadBasketBytes(Long64_t pos, TFile *file)
Read basket buffers in memory and cleanup.
Definition: TBasket.cxx:645
virtual void SetMaximum(Char_t max)
Definition: TLeafB.h:54
virtual Int_t Write(const char *name=0, Int_t option=0, Int_t bufsize=0)
Write this object to the current directory.
Definition: TObject.cxx:823
A TLeaf describes individual elements of a TBranch See TBranch structure in TTree.
Definition: TLeaf.h:37
A TLeaf for an 8 bit Integer data type.
Definition: TLeafB.h:28
virtual Int_t GetMaximum() const
Definition: TLeafS.h:43
virtual Int_t GetMaximum() const
Definition: TLeafL.h:45
UInt_t * fBasketIndex
Definition: TTreeCloner.h:58
An array of TObjects.
Definition: TObjArray.h:39
void ImportClusterRanges()
Set the entries and import the cluster range of the.
void RestoreCache()
Restore the TFileCacheRead to its previous value.
Long64_t * fBasketEntry
Definition: TTreeCloner.h:57
long long Long64_t
Definition: RtypesCore.h:69
friend class CompareEntry
Definition: TTreeCloner.h:91
virtual Bool_t InheritsFrom(const char *classname) const
Returns kTRUE if object inherits from class "classname".
Definition: TObject.cxx:487
ClassImp(TSeqCollection) Int_t TSeqCollection TIter next(this)
Return index of object in collection.
TObjArray * GetListOfBaskets()
Definition: TBranch.h:176
Int_t FlushOneBasket(UInt_t which)
If we have a write basket in memory and it contains some entries and has not yet been written to disk...
Definition: TBranch.cxx:1040
A cache when reading files over the network.
const char Option_t
Definition: RtypesCore.h:62
void WriteBaskets()
Transfer the basket from the input file to the output file.
virtual void SetMinimum(Int_t min)
Definition: TLeafC.h:56
virtual void SetCacheRead(TFileCacheRead *cache, TObject *tree=0, ECacheAction action=kDisconnect)
Set a pointer to the read cache.
Definition: TFile.cxx:2177
unsigned short UShort_t
Definition: RtypesCore.h:36
#define gDirectory
Definition: TDirectory.h:218
virtual TList * GetListOfKeys() const
virtual void SetMaximum(Bool_t max)
Definition: TLeafO.h:54
virtual void SetMinimum(Long64_t min)
Definition: TLeafL.h:58
Long64_t GetCacheAutoSize(Bool_t withDefault=kFALSE) const
Used for automatic sizing of the cache.
Definition: TTree.cxx:4945
Long64_t fToStartEntries
Definition: TTreeCloner.h:63
A ROOT file is a suite of consecutive data records (TKey instances) with a well defined format...
Definition: TFile.h:45
void ForceWriteInfo(TFile *file, Bool_t force=kFALSE)
Recursively mark streamer infos for writing to a file.
virtual Int_t GetMinimum() const
Definition: TLeafI.h:46
Basic string class.
Definition: TString.h:137
TBranch * fBranchCount
Definition: TBranchClones.h:39
void ToLower()
Change string to lower-case.
Definition: TString.cxx:1088
virtual void Prefetch(Long64_t pos, Int_t len)
Add block of length len at position pos in the list of blocks to be prefetched.
int Int_t
Definition: RtypesCore.h:41
ROOT::NewFunc_t GetNew() const
Return the wrapper around new ThisClass().
Definition: TClass.cxx:6885
bool Bool_t
Definition: RtypesCore.h:59
A TLeaf for a bool data type.
Definition: TLeafO.h:28
const Bool_t kFALSE
Definition: Rtypes.h:92
virtual Long64_t GetBasketSeek(Int_t basket) const
Return address of basket in the file.
Definition: TBranch.cxx:1143
virtual void SetMinimum(Bool_t min)
Definition: TLeafO.h:55
TFile * GetCurrentFile() const
Return pointer to the current file.
Definition: TTree.cxx:5006
A TLeaf for a variable length string.
Definition: TLeafC.h:28
Long64_t * GetBasketEntry() const
Definition: TBranch.h:149
void SetBit(UInt_t f, Bool_t set)
Set or unset the user status bits as specified in f.
Definition: TObject.cxx:732
void SetBranch(TBranch *branch)
Definition: TBasket.h:91
virtual void SetMaximum(Short_t max)
Definition: TLeafS.h:54
const char * Data() const
Definition: TString.h:349
TFileCacheRead * GetCacheRead(TObject *tree=0) const
Return a pointer to the current read cache.
Definition: TFile.cxx:1196
virtual TObjArray * GetListOfBranches()
Definition: TTree.h:405
UInt_t fMaxBaskets
Definition: TTreeCloner.h:52
virtual void SetMinimum(Char_t min)
Definition: TLeafB.h:55
void ImportClusterRanges(TTree *fromtree)
Appends the cluster range information stored in 'fromtree' to this tree, including the value of fAuto...
Definition: TTree.cxx:5708
void Class()
Definition: Class.C:29
virtual Int_t GetMinimum() const
Definition: TLeafS.h:44
virtual void SetLen(Int_t len=1)
Definition: TLeaf.h:102
Int_t * GetBasketBytes() const
Definition: TBranch.h:148
void CloseOutWriteBaskets()
Before we can start adding new basket, we need to flush to disk the partially filled baskets (the Wri...
virtual Int_t GetBufferSize() const
void Info(const char *location, const char *msgfmt,...)
virtual Int_t GetMinimum() const
Definition: TLeafC.h:44
Long64_t GetEntries() const
Definition: TBranch.h:182
TObjArray * GetListOfBranches()
Definition: TBranch.h:177
TBasket * GetBasket(Int_t basket)
Return pointer to basket basketnumber in this Branch.
Definition: TBranch.cxx:1081
virtual TObject * Clone(const char *newname="") const
Make a clone of an object using the Streamer facility.
Definition: TNamed.cxx:63
void SortBaskets()
Sort the basket according to the user request.
Book space in a file, create I/O buffers, to fill them, (un)compress them.
Definition: TKey.h:30
A TProcessID identifies a ROOT job in a unique way in time and space.
Definition: TProcessID.h:34
Int_t GetNevBuf() const
Definition: TBasket.h:79
TFileCacheRead * fPrevCache
Definition: TTreeCloner.h:67
void Error(const char *location, const char *msgfmt,...)
Int_t GetClassVersion() const
virtual Int_t GetMaximum() const
Definition: TLeafB.h:43
TVirtualStreamerInfo * FindStreamerInfo(TObjArray *arr, UInt_t checksum) const
Find the TVirtualStreamerInfo in the StreamerInfos corresponding to checksum.
Definition: TClass.cxx:6594
char * out
Definition: TBase64.cxx:29
Bool_t IsValid()
Definition: TTreeCloner.h:123
virtual void IncrementProcessIDs()
Definition: TFile.h:217
A doubly linked list.
Definition: TList.h:47
TTree * fFromTree
Definition: TTreeCloner.h:46
virtual TFile * GetFile() const
Definition: TDirectory.h:152
TObject * UncheckedAt(Int_t i) const
Definition: TObjArray.h:91
virtual void AddLastBasket(Long64_t startEntry)
Add the start entry of the write basket (not yet created)
Definition: TBranch.cxx:549
virtual void IncrementPidOffset(UShort_t offset)
Increment fPidOffset by 'offset'.
Definition: TKey.cxx:639
virtual const char * GetTypeName() const
Definition: TLeaf.h:81
virtual void AddAtAndExpand(TObject *obj, Int_t idx)
Add object at position idx.
Definition: TObjArray.cxx:221
TVirtualStreamerInfo * GetStreamerInfo(Int_t version=0) const
returns a pointer to the TVirtualStreamerInfo object for version If the object does not exist...
Definition: TClass.cxx:4337
virtual void SetEntries(Long64_t entries)
Set the number of entries in this branch.
Definition: TBranch.cxx:2204
void CopyProcessIds()
Make sure that all the needed TStreamerInfo are present in the output file.
void CopyStreamerInfos()
Make sure that all the needed TStreamerInfo are present in the output file.
TDirectory * GetDirectory() const
Definition: TTree.h:381
virtual void SetMinimum(Short_t min)
Definition: TLeafS.h:55
virtual Int_t GetMinimum() const
Definition: TLeafB.h:44
TBranch * GetMother() const
Get our top-level parent branch in the tree.
Definition: TBranch.cxx:1532
UInt_t GetCheckSum() const
void Form(const char *fmt,...)
Formats a string using a printf style format descriptor.
Definition: TString.cxx:2321
Int_t IncrementCount()
Increase the reference count to this object.
Definition: TProcessID.cxx:268
unsigned int UInt_t
Definition: RtypesCore.h:42
Bool_t TestBit(UInt_t f) const
Definition: TObject.h:173
Manages buffers for branches of a Tree.
Definition: TBasket.h:38
virtual Int_t GetMinimum() const
Definition: TLeafO.h:44
TObjArray fToBranches
Definition: TTreeCloner.h:50
virtual TBranchRef * GetBranchRef() const
Definition: TTree.h:370
TLine * l
Definition: textangle.C:4
virtual const char * GetName() const
Returns name of object.
Definition: TNamed.h:51
The ROOT global object gROOT contains a list of all defined classes.
Definition: TClass.h:81
virtual TList * GetStreamerInfoList()
Read the list of TStreamerInfo objects written to this file.
Definition: TFile.cxx:1319
TTreeCloner * fObject
Definition: TTreeCloner.h:77
friend class CompareSeek
Definition: TTreeCloner.h:90
void Warning(const char *location, const char *msgfmt,...)
Bool_t operator()(UInt_t i1, UInt_t i2)
Definition: TTreeCloner.cxx:53
A Branch for the case of an object.
void CreateCache()
Create a TFileCacheRead if it was requested.
virtual void SetMaximum(Long64_t max)
Definition: TLeafL.h:57
Bool_t IsLoaded() const
Return true if the shared library of this class is currently in the a process's memory.
Definition: TClass.cxx:5526
UInt_t CollectBranches()
Fill the array of branches, matching the branches of the 'from' and 'to' TTrees Returns the total num...
Bool_t Exec()
Execute the cloning.
virtual Int_t GetMaximum() const
Definition: TLeafC.h:43
double f(double x)
UInt_t * fBasketNum
Definition: TTreeCloner.h:54
Bool_t operator()(UInt_t i1, UInt_t i2)
Definition: TTreeCloner.cxx:40
Describe directory structure in memory.
Definition: TDirectory.h:41
UInt_t fOptions
Definition: TTreeCloner.h:45
UInt_t FillCache(UInt_t from)
Fill the file cache with the next set of basket.
UShort_t fPidOffset
Definition: TTreeCloner.h:60
virtual TTree * GetTree() const
Definition: TTree.h:432
TObjArray * GetListOfLeaves()
Definition: TBranch.h:178
Int_t GetEntries() const
Return the number of objects in array (i.e.
Definition: TObjArray.cxx:493
TFileCacheRead * fFileCache
Definition: TTreeCloner.h:66
static TClass * GetClass(const char *name, Bool_t load=kTRUE, Bool_t silent=kFALSE)
Static method returning pointer to TClass of the specified class name.
Definition: TClass.cxx:2881
virtual Int_t GetMaximum() const
Definition: TLeafI.h:45
UInt_t fCloneMethod
Definition: TTreeCloner.h:62
void SetCacheSize(Int_t size)
Set the TFile cache size to be used.
#define name(a, b)
Definition: linkTestLib0.cpp:5
virtual TBranch * BranchRef()
Build the optional branch supporting the TRefTable.
Definition: TTree.cxx:2111
UInt_t * fBasketBranchNum
Definition: TTreeCloner.h:53
A TLeaf for a 16 bit Integer data type.
Definition: TLeafS.h:28
virtual void SetMaximum(Int_t max)
Definition: TLeafI.h:55
virtual void SetMinimum(Int_t min)
Definition: TLeafI.h:56
Class implementing or helping the various TTree cloning method.
Definition: TTreeCloner.h:40
virtual Bool_t cd(const char *path=0)
Change current directory to "this" directory.
Definition: TDirectory.cxx:433
#define nullptr
Definition: Rtypes.h:87
A Branch for the case of an array of clone objects.
Definition: TBranchClones.h:31
virtual Int_t GetLenStatic() const
Definition: TLeaf.h:74
Bool_t Contains(const char *pat, ECaseCompare cmp=kExact) const
Definition: TString.h:567
virtual Bool_t IsWritable() const
Definition: TDirectory.h:168
virtual Int_t GetMaximum() const
Definition: TLeafO.h:43
virtual void AddBasket(TBasket &b, Bool_t ondisk, Long64_t startEntry)
Add the basket to this branch.
Definition: TBranch.cxx:476
A TLeaf for a 64 bit Integer data type.
Definition: TLeafL.h:29
R__EXTERN Int_t gDebug
Definition: Rtypes.h:128
Bool_t fNeedConversion
Definition: TTreeCloner.h:44
virtual void AddLast(TObject *obj)
Add object in the next empty slot in the array.
Definition: TObjArray.cxx:168
virtual Long64_t GetEntries() const
Definition: TTree.h:382
A TTree object has a header with a name and a title.
Definition: TTree.h:94
TString fWarningMsg
Definition: TTreeCloner.h:41
Long64_t CopyTo(TFile *to)
Copy the basket of this branch onto the file to.
Definition: TBasket.cxx:163
void ResetBit(UInt_t f)
Definition: TObject.h:172
TObject * At(Int_t idx) const
Definition: TObjArray.h:167
TTree * fToTree
Definition: TTreeCloner.h:47
virtual TFile * GetFile(Int_t mode=0)
Return pointer to the file where branch buffers reside, returns 0 in case branch buffers reside in th...
Definition: TBranch.cxx:1381
virtual Long64_t SetEntries(Long64_t n=-1)
Change number of entries in the tree.
Definition: TTree.cxx:8140
A TTree is a list of TBranches.
Definition: TBranch.h:58
virtual void SetMaximum(Int_t max)
Definition: TLeafC.h:55
const Bool_t kTRUE
Definition: Rtypes.h:91
Long64_t * fBasketSeek
Definition: TTreeCloner.h:56
TObjArray * GetListOfProcessIDs() const
Definition: TFile.h:196
Option_t * fMethod
Definition: TTreeCloner.h:48
virtual ~TTreeCloner()
TTreeCloner destructor.
void CopyMemoryBaskets()
Transfer the basket from the input file to the output file.
Int_t GetWriteBasket() const
Definition: TBranch.h:170
void CollectBaskets()
Collect the information about the on-file basket that need to be copied.
A TLeaf for an Integer data type.
Definition: TLeafI.h:29
Int_t fCacheSize
Definition: TTreeCloner.h:65
TObjArray fFromBranches
Definition: TTreeCloner.h:49
Int_t LoadBasketBuffers(Long64_t pos, Int_t len, TFile *file, TTree *tree=0)
Load basket buffers in memory without unziping.
Definition: TBasket.cxx:225
Bool_t fIsValid
Definition: TTreeCloner.h:43