Logo ROOT  
Reference Guide
TBranch.cxx
Go to the documentation of this file.
1// @(#)root/tree:$Id$
2// Author: Rene Brun 12/01/96
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#include "TBranchCacheInfo.h"
13
14#include "TBranch.h"
15
16#include "Bytes.h"
17#include "Compression.h"
18#include "TBasket.h"
19#include "TBranchBrowsable.h"
20#include "TBrowser.h"
21#include "TBuffer.h"
22#include "TClass.h"
23#include "TBufferFile.h"
24#include "TClonesArray.h"
25#include "TFile.h"
26#include "TLeaf.h"
27#include "TLeafB.h"
28#include "TLeafC.h"
29#include "TLeafD.h"
30#include "TLeafD32.h"
31#include "TLeafF.h"
32#include "TLeafF16.h"
33#include "TLeafI.h"
34#include "TLeafL.h"
35#include "TLeafG.h"
36#include "TLeafO.h"
37#include "TLeafObject.h"
38#include "TLeafS.h"
39#include "TMessage.h"
40#include "TROOT.h"
41#include "TSystem.h"
42#include "TMath.h"
43#include "TTree.h"
44#include "TTreeCache.h"
45#include "TTreeCacheUnzip.h"
46#include "TVirtualMutex.h"
47#include "TVirtualPad.h"
48#include "TVirtualPerfStats.h"
49#include "strlcpy.h"
50#include "snprintf.h"
51
52#include "TBranchIMTHelper.h"
53
54#include "ROOT/TIOFeatures.hxx"
55
56#include <atomic>
57#include <cstddef>
58#include <cstring>
59#include <cstdio>
60
61
63
64/** \class TBranch
65\ingroup tree
66
67A TTree is a list of TBranches
68
69A TBranch supports:
70 - The list of TLeaf describing this branch.
71 - The list of TBasket (branch buffers).
72
73See TBranch structure in TTree.
74
75See also specialized branches:
76 - TBranchObject in case the branch is one object
77 - TBranchClones in case the branch is an array of clone objects
78*/
79
81
82
83
84////////////////////////////////////////////////////////////////////////////////
85/// Default constructor. Used for I/O by default.
86
88: TNamed()
89, TAttFill(0, 1001)
90, fCompress(0)
91, fBasketSize(32000)
92, fEntryOffsetLen(1000)
93, fWriteBasket(0)
94, fEntryNumber(0)
95, fExtraBasket(nullptr)
96, fOffset(0)
97, fMaxBaskets(10)
98, fNBaskets(0)
99, fSplitLevel(0)
100, fNleaves(0)
101, fReadBasket(0)
102, fReadEntry(-1)
103, fFirstBasketEntry(-1)
104, fNextBasketEntry(-1)
105, fCurrentBasket(0)
106, fEntries(0)
107, fFirstEntry(0)
108, fTotBytes(0)
109, fZipBytes(0)
110, fBranches()
111, fLeaves()
112, fBaskets(fMaxBaskets)
113, fBasketBytes(0)
114, fBasketEntry(0)
115, fBasketSeek(0)
116, fTree(0)
117, fMother(0)
118, fParent(0)
119, fAddress(0)
120, fDirectory(0)
121, fFileName("")
122, fEntryBuffer(0)
123, fTransientBuffer(0)
124, fBrowsables(0)
125, fBulk(*this)
126, fSkipZip(kFALSE)
127, fReadLeaves(&TBranch::ReadLeavesImpl)
128, fFillLeaves(&TBranch::FillLeavesImpl)
129{
131}
132
133////////////////////////////////////////////////////////////////////////////////
134/// Create a Branch as a child of a Tree
135///
136/// * address is the address of the first item of a structure
137/// or the address of a pointer to an object (see example in TTree.cxx).
138/// * leaflist is the concatenation of all the variable names and types
139/// separated by a colon character :
140/// The variable name and the variable type are separated by a
141/// slash (/). The variable type must be 1 character. (Characters
142/// after the first are legal and will be appended to the visible
143/// name of the leaf, but have no effect.) If no type is given, the
144/// type of the variable is assumed to be the same as the previous
145/// variable. If the first variable does not have a type, it is
146/// assumed of type F by default. The list of currently supported
147/// types is given below:
148/// - `C` : a character string terminated by the 0 character
149/// - `B` : an 8 bit signed integer (`Char_t`)
150/// - `b` : an 8 bit unsigned integer (`UChar_t`)
151/// - `S` : a 16 bit signed integer (`Short_t`)
152/// - `s` : a 16 bit unsigned integer (`UShort_t`)
153/// - `I` : a 32 bit signed integer (`Int_t`)
154/// - `i` : a 32 bit unsigned integer (`UInt_t`)
155/// - `F` : a 32 bit floating point (`Float_t`)
156/// - `f` : a 24 bit floating point with truncated mantissa (`Float16_t`)
157/// - `D` : a 64 bit floating point (`Double_t`)
158/// - `d` : a 24 bit truncated floating point (`Double32_t`)
159/// - `L` : a 64 bit signed integer (`Long64_t`)
160/// - `l` : a 64 bit unsigned integer (`ULong64_t`)
161/// - `G` : a long signed integer, stored as 64 bit (`Long_t`)
162/// - `g` : a long unsigned integer, stored as 64 bit (`ULong_t`)
163/// - `O` : [the letter `o`, not a zero] a boolean (`Bool_t`)
164///
165/// Arrays of values are supported with the following syntax:
166/// - If leaf name has the form var[nelem], where nelem is alphanumeric, then
167/// if nelem is a leaf name, it is used as the variable size of the array,
168/// otherwise return 0.
169/// The leaf referred to by nelem **MUST** be an int (/I),
170/// - If leaf name has the form var[nelem], where nelem is a non-negative integers, then
171/// it is used as the fixed size of the array.
172/// - If leaf name has the form of a multi dimension array (e.g. var[nelem][nelem2])
173/// where nelem and nelem2 are non-negative integers) then
174/// it is used as a 2 dimensional array of fixed size.
175/// - In case of the truncated floating point types (Float16_t and Double32_t) you can
176/// furthermore specify the range in the style [xmin,xmax] or [xmin,xmax,nbits] after
177/// the type character. See `TStreamerElement::GetRange()` for further information.
178/// - Any of other form is not supported.
179///
180/// Note that the TTree will assume that all the item are contiguous in memory.
181/// On some platform, this is not always true of the member of a struct or a class,
182/// due to padding and alignment. Sorting your data member in order of decreasing
183/// sizeof usually leads to their being contiguous in memory.
184///
185/// * bufsize is the buffer size in bytes for this branch
186/// The default value is 32000 bytes and should be ok for most cases.
187/// You can specify a larger value (e.g. 256000) if your Tree is not split
188/// and each entry is large (Megabytes)
189/// A small value for bufsize is optimum if you intend to access
190/// the entries in the Tree randomly and your Tree is in split mode.
191///
192/// See an example of a Branch definition in the TTree constructor.
193///
194/// Note that in case the data type is an object, this branch can contain
195/// only this object.
196///
197/// Note that this function is invoked by TTree::Branch
198
199TBranch::TBranch(TTree *tree, const char *name, void *address, const char *leaflist, Int_t basketsize, Int_t compress)
200 : TNamed(name, leaflist)
201, TAttFill(0, 1001)
202, fCompress(compress)
203, fBasketSize((basketsize < 100) ? 100 : basketsize)
204, fEntryOffsetLen(0)
205, fWriteBasket(0)
206, fEntryNumber(0)
207, fExtraBasket(nullptr)
208, fIOFeatures(tree ? tree->GetIOFeatures().GetFeatures() : 0)
209, fOffset(0)
210, fMaxBaskets(10)
211, fNBaskets(0)
212, fSplitLevel(0)
213, fNleaves(0)
214, fReadBasket(0)
215, fReadEntry(-1)
216, fFirstBasketEntry(-1)
217, fNextBasketEntry(-1)
218, fCurrentBasket(0)
219, fEntries(0)
220, fFirstEntry(0)
221, fTotBytes(0)
222, fZipBytes(0)
223, fBranches()
224, fLeaves()
225, fBaskets(fMaxBaskets)
226, fBasketBytes(0)
227, fBasketEntry(0)
228, fBasketSeek(0)
229, fTree(tree)
230, fMother(0)
231, fParent(0)
232, fAddress((char *)address)
233, fDirectory(fTree->GetDirectory())
234, fFileName("")
235, fEntryBuffer(0)
236, fTransientBuffer(0)
237, fBrowsables(0)
238, fBulk(*this)
239, fSkipZip(kFALSE)
240, fReadLeaves(&TBranch::ReadLeavesImpl)
241, fFillLeaves(&TBranch::FillLeavesImpl)
242{
243 Init(name,leaflist,compress);
244}
245
246////////////////////////////////////////////////////////////////////////////////
247/// Create a Branch as a child of another Branch
248///
249/// See documentation for
250/// TBranch::TBranch(TTree *, const char *, void *, const char *, Int_t, Int_t)
251
252TBranch::TBranch(TBranch *parent, const char *name, void *address, const char *leaflist, Int_t basketsize,
253 Int_t compress)
254: TNamed(name, leaflist)
255, TAttFill(0, 1001)
256, fCompress(compress)
257, fBasketSize((basketsize < 100) ? 100 : basketsize)
258, fEntryOffsetLen(0)
259, fWriteBasket(0)
260, fEntryNumber(0)
261, fExtraBasket(nullptr)
262, fIOFeatures(parent->fIOFeatures)
263, fOffset(0)
264, fMaxBaskets(10)
265, fNBaskets(0)
266, fSplitLevel(0)
267, fNleaves(0)
268, fReadBasket(0)
269, fReadEntry(-1)
270, fFirstBasketEntry(-1)
271, fNextBasketEntry(-1)
272, fCurrentBasket(0)
273, fEntries(0)
274, fFirstEntry(0)
275, fTotBytes(0)
276, fZipBytes(0)
277, fBranches()
278, fLeaves()
279, fBaskets(fMaxBaskets)
280, fBasketBytes(0)
281, fBasketEntry(0)
282, fBasketSeek(0)
283, fTree(parent ? parent->GetTree() : 0)
284, fMother(parent ? parent->GetMother() : 0)
285, fParent(parent)
286, fAddress((char *)address)
287, fDirectory(fTree ? fTree->GetDirectory() : 0)
288, fFileName("")
289, fEntryBuffer(0)
290, fTransientBuffer(0)
291, fBrowsables(0)
292, fBulk(*this)
293, fSkipZip(kFALSE)
294, fReadLeaves(&TBranch::ReadLeavesImpl)
295, fFillLeaves(&TBranch::FillLeavesImpl)
296{
297 Init(name,leaflist,compress);
298}
299
300void TBranch::Init(const char* name, const char* leaflist, Int_t compress)
301{
302 // Initialization routine called from the constructor. This should NOT be made virtual.
303
305 if ((compress == -1) && fTree->GetDirectory()) {
306 TFile* bfile = fTree->GetDirectory()->GetFile();
307 if (bfile) {
309 }
310 }
311
315
316 for (Int_t i = 0; i < fMaxBaskets; ++i) {
317 fBasketBytes[i] = 0;
318 fBasketEntry[i] = 0;
319 fBasketSeek[i] = 0;
320 }
321
322 //
323 // Decode the leaflist (search for : as separator).
324 //
325
326 char* nameBegin = const_cast<char*>(leaflist);
327 Int_t offset = 0;
328 auto len = strlen(leaflist);
329 // FIXME: Make these string streams instead.
330 char* leafname = new char[len + 1];
331 char* leaftype = new char[320];
332 // Note: The default leaf type is a float.
333 strlcpy(leaftype, "F",320);
334 char* pos = const_cast<char*>(leaflist);
335 const char* leaflistEnd = leaflist + len;
336 for (; pos <= leaflistEnd; ++pos) {
337 // -- Scan leaf specification and create leaves.
338 if ((*pos == ':') || (*pos == 0)) {
339 // -- Reached end of a leaf spec, create a leaf.
340 Int_t lenName = pos - nameBegin;
341 char* ctype = 0;
342 if (lenName) {
343 strncpy(leafname, nameBegin, lenName);
344 leafname[lenName] = 0;
345 ctype = strstr(leafname, "/");
346 if (ctype) {
347 *ctype = 0;
348 strlcpy(leaftype, ctype + 1,320);
349 }
350 }
351 if (lenName == 0 || ctype == leafname) {
352 Warning("TBranch","No name was given to the leaf number '%d' in the leaflist of the branch '%s'.",fNleaves,name);
353 snprintf(leafname,640,"__noname%d",fNleaves);
354 }
355 TLeaf* leaf = 0;
356 if (leaftype[1] == '[' && !strchr(leaftype, ',')) {
357 Warning("TBranch", "Array size for branch '%s' must be specified after leaf name, not after the type name!", name);
358 // and continue for backward compatibility?
359 } else if (leaftype[1] && !strchr(leaftype, ',')) {
360 Warning("TBranch", "Extra characters after type tag '%s' for branch '%s'; must be one character.", leaftype, name);
361 // and continue for backward compatibility?
362 }
363 if (*leaftype == 'C') {
364 leaf = new TLeafC(this, leafname, leaftype);
365 } else if (*leaftype == 'O') {
366 leaf = new TLeafO(this, leafname, leaftype);
367 } else if (*leaftype == 'B') {
368 leaf = new TLeafB(this, leafname, leaftype);
369 } else if (*leaftype == 'b') {
370 leaf = new TLeafB(this, leafname, leaftype);
371 leaf->SetUnsigned();
372 } else if (*leaftype == 'S') {
373 leaf = new TLeafS(this, leafname, leaftype);
374 } else if (*leaftype == 's') {
375 leaf = new TLeafS(this, leafname, leaftype);
376 leaf->SetUnsigned();
377 } else if (*leaftype == 'I') {
378 leaf = new TLeafI(this, leafname, leaftype);
379 } else if (*leaftype == 'i') {
380 leaf = new TLeafI(this, leafname, leaftype);
381 leaf->SetUnsigned();
382 } else if (*leaftype == 'F') {
383 leaf = new TLeafF(this, leafname, leaftype);
384 } else if (*leaftype == 'f') {
385 leaf = new TLeafF16(this, leafname, leaftype);
386 } else if (*leaftype == 'L') {
387 leaf = new TLeafL(this, leafname, leaftype);
388 } else if (*leaftype == 'l') {
389 leaf = new TLeafL(this, leafname, leaftype);
390 leaf->SetUnsigned();
391 } else if (*leaftype == 'D') {
392 leaf = new TLeafD(this, leafname, leaftype);
393 } else if (*leaftype == 'd') {
394 leaf = new TLeafD32(this, leafname, leaftype);
395 } else if (*leaftype == 'G') {
396 leaf = new TLeafG(this, leafname, leaftype);
397 } else if (*leaftype == 'g') {
398 leaf = new TLeafG(this, leafname, leaftype);
399 leaf->SetUnsigned();
400 }
401 if (!leaf) {
402 Error("TLeaf", "Illegal data type for %s/%s", name, leaflist);
403 delete[] leaftype;
404 delete [] leafname;
405 MakeZombie();
406 return;
407 }
408 if (leaf->IsZombie()) {
409 delete leaf;
410 leaf = 0;
411 auto msg = "Illegal leaf: %s/%s. If this is a variable size C array it's possible that the branch holding the size is not available.";
412 Error("TBranch", msg, name, leaflist);
413 delete [] leafname;
414 delete[] leaftype;
415 MakeZombie();
416 return;
417 }
418 leaf->SetBranch(this);
419 leaf->SetAddress((char*) (fAddress + offset));
420 leaf->SetOffset(offset);
421 if (leaf->GetLeafCount()) {
422 // -- Leaf is a varying length array, we need an offset array.
423 fEntryOffsetLen = 1000;
424 }
425 if (leaf->InheritsFrom(TLeafC::Class())) {
426 // -- Leaf is a character string, we need an offset array.
427 fEntryOffsetLen = 1000;
428 }
429 ++fNleaves;
430 fLeaves.Add(leaf);
431 fTree->GetListOfLeaves()->Add(leaf);
432 if (*pos == 0) {
433 // -- We reached the end of the leaf specification.
434 break;
435 }
436 nameBegin = pos + 1;
437 offset += leaf->GetLenType() * leaf->GetLen();
438 }
439 }
440 delete[] leafname;
441 leafname = 0;
442 delete[] leaftype;
443 leaftype = 0;
444
445}
446
447////////////////////////////////////////////////////////////////////////////////
448/// Destructor.
449
451{
452 delete fBrowsables;
453 fBrowsables = 0;
454
455 // Note: We do *not* have ownership of the buffer.
456 fEntryBuffer = 0;
457
458 delete [] fBasketSeek;
459 fBasketSeek = 0;
460
461 delete [] fBasketEntry;
462 fBasketEntry = 0;
463
464 delete [] fBasketBytes;
465 fBasketBytes = 0;
466
468 fNBaskets = 0;
469 fCurrentBasket = 0;
471 fNextBasketEntry = -1;
472
473 // Remove our leaves from our tree's list of leaves.
474 if (fTree) {
476 if (lst && lst->GetLast()!=-1) {
477 lst->RemoveAll(&fLeaves);
478 }
479 }
480 // And delete our leaves.
481 fLeaves.Delete();
482
484
485 // If we are in a directory and that directory is not the same
486 // directory that our tree is in, then try to find an open file
487 // with the name fFileName. If we find one, delete that file.
488 // We are attempting to close any alternate file which we have
489 // been directed to write our baskets to.
490 // FIXME: We make no attempt to check if someone else might be
491 // using this file. This is very user hostile. A violation
492 // of the principle of least surprises.
493 //
494 // Warning. Must use FindObject by name instead of fDirectory->GetFile()
495 // because two branches may point to the same file and the file
496 // may have already been deleted in the previous branch.
497 if (fDirectory && (!fTree || fDirectory != fTree->GetDirectory())) {
498 TString bFileName( GetRealFileName() );
499
501 TFile* file = (TFile*)gROOT->GetListOfFiles()->FindObject(bFileName);
502 if (file){
503 file->Close();
504 delete file;
505 file = 0;
506 }
507 }
508
509 fTree = 0;
510 fDirectory = 0;
511
512 if (fTransientBuffer) {
513 delete fTransientBuffer;
515 }
516}
517
518////////////////////////////////////////////////////////////////////////////////
519/// Returns the transient buffer currently used by this TBranch for reading/writing baskets.
520
522{
523 if (fTransientBuffer) {
526 }
527 return fTransientBuffer;
528 }
530 return fTransientBuffer;
531}
532
533////////////////////////////////////////////////////////////////////////////////
534/// Add the basket to this branch.
535///
536/// Warning: if the basket are not 'flushed/copied' in the same
537/// order as they were created, this will induce a slow down in
538/// the insert (since we'll need to move all the record that are
539/// entere 'too early').
540/// Warning we also assume that the __current__ write basket is
541/// not present (aka has been removed) or is empty (no entries).
542
543void TBranch::AddBasket(TBasket& b, Bool_t ondisk, Long64_t startEntry)
544{
545 TBasket *basket = &b;
546
547 basket->SetBranch(this);
548
549 if (fWriteBasket >= fMaxBaskets) {
551 }
552 Int_t where = fWriteBasket;
553
554 if (where && startEntry < fBasketEntry[where-1]) {
555 // Need to find the right location and move the possible baskets
556
557 if (!ondisk) {
558 Warning("AddBasket","The assumption that out-of-order basket only comes from disk based ntuple is false.");
559 }
560
561 if (startEntry < fBasketEntry[0]) {
562 where = 0;
563 } else {
564 for(Int_t i=fWriteBasket-1; i>=0; --i) {
565 if (fBasketEntry[i] < startEntry) {
566 where = i+1;
567 break;
568 } else if (fBasketEntry[i] == startEntry) {
569 Error("AddBasket","An out-of-order basket matches the entry number of an existing basket.");
570 }
571 }
572 }
573
574 if (where < fWriteBasket) {
575 // We shall move the content of the array
576 for (Int_t j=fWriteBasket; j > where; --j) {
577 fBasketEntry[j] = fBasketEntry[j-1];
578 fBasketBytes[j] = fBasketBytes[j-1];
579 fBasketSeek[j] = fBasketSeek[j-1];
580 }
581 }
582 }
583 fBasketEntry[where] = startEntry;
584
585 TBasket *existing = (TBasket*)fBaskets.At(fWriteBasket);
586 if (existing && existing->GetNevBuf()) {
587 Fatal("AddBasket", "Dropping non-empty 'write' basket in %s %s",
588 GetTree()->GetName(), GetName());
589 }
590 delete existing;
591 if (ondisk) {
592 fBasketBytes[where] = basket->GetNbytes(); // not for in mem
593 fBasketSeek[where] = basket->GetSeekKey(); // not for in mem
595 ++fWriteBasket;
596 } else {
597 ++fNBaskets;
598 // The basket we are adding becomes the new 'write' basket.
601 }
602
603 fEntries += basket->GetNevBuf();
604 fEntryNumber += basket->GetNevBuf();
605 if (ondisk) {
606 fTotBytes += basket->GetObjlen() + basket->GetKeylen() ;
607 fZipBytes += basket->GetNbytes();
608 fTree->AddTotBytes(basket->GetObjlen() + basket->GetKeylen());
609 fTree->AddZipBytes(basket->GetNbytes());
610 }
611}
612
613////////////////////////////////////////////////////////////////////////////////
614/// Add the start entry of the write basket (not yet created)
615
617{
618 if (fWriteBasket >= fMaxBaskets) {
620 }
621 Int_t where = fWriteBasket;
622
623 if (where && startEntry < fBasketEntry[where-1]) {
624 // Need to find the right location and move the possible baskets
625
626 Fatal("AddBasket","The last basket must have the highest entry number (%s/%lld/%d).",GetName(),startEntry,fWriteBasket);
627
628 }
629 // The first basket (should) always start at zero. If we are asked to update
630 // it, this likely to be from merging 'empty' branches (base class node and the likes)
631 if (where) {
632 fBasketEntry[where] = startEntry;
634 }
635}
636
637////////////////////////////////////////////////////////////////////////////////
638/// Loop on all leaves of this branch to back fill Basket buffer.
639///
640/// Use this routine instead of TBranch::Fill when filling a branch individually
641/// to catch up with the number of entries already in the TTree.
642///
643/// First it calls TBranch::Fill and then if the number of entries of the branch
644/// reach one of TTree cluster's boundary, the basket is flushed.
645///
646/// The function returns the number of bytes committed to the memory basket.
647/// If a write error occurs, the number of bytes returned is -1.
648/// If no data are written, because e.g. the branch is disabled,
649/// the number of bytes returned is 0.
650///
651/// To insure that the baskets of each cluster are located close by in the
652/// file, when back-filling multiple branches make sure to call BackFill
653/// for the same entry for all the branches consecutively
654/// ~~~ {.cpp}
655/// for( auto e = 0; e < tree->GetEntries(); ++e ) { // loop over entries.
656/// for( auto branch : branchCollection) {
657/// ... Make change to the data associated with the branch ...
658/// branch->BackFill();
659/// }
660/// }
661/// // Since we loop over all the branches for each new entry
662/// // all the baskets for a cluster are consecutive in the file.
663/// ~~~
664/// rather than doing all the entries of one branch at a time.
665/// ~~~ {.cpp}
666/// // Do NOT do things in the following order, it will lead to
667/// // poorly clustered files.
668/// for(auto branch : branchCollection) {
669/// for( auto e = 0; e < tree->GetEntries(); ++e ) { // loop over entries.
670/// ... Make change to the data associated with the branch ...
671/// branch->BackFill();
672/// }
673/// }
674/// // Since we loop over all the entries for one branch
675/// // all the baskets for that branch are consecutive.
676/// ~~~
677
679
680 // Get the end of the next cluster.
681 auto cluster = GetTree()->GetClusterIterator( GetEntries() );
682 cluster.Next();
683 auto endCluster = cluster.GetNextEntry();
684
685 auto result = FillImpl(nullptr);
686
687 if ( result && GetEntries() >= endCluster ) {
688 FlushBaskets();
689 }
690
691 return result;
692}
693
694////////////////////////////////////////////////////////////////////////////////
695/// Browser interface.
696
698{
699 if (fNleaves > 1) {
701 } else {
702 // Get the name and strip any extra brackets
703 // in order to get the full arrays.
704 TString name = GetName();
705 Int_t pos = name.First('[');
706 if (pos!=kNPOS) name.Remove(pos);
707
708 GetTree()->Draw(name, "", b ? b->GetDrawOption() : "");
709 if (gPad) gPad->Update();
710 }
711}
712
713 ///////////////////////////////////////////////////////////////////////////////
714 /// Loop on all branch baskets. If the file where branch buffers reside is
715 /// writable, free the disk space associated to the baskets of the branch,
716 /// then call Reset(). If the option contains "all", delete also the baskets
717 /// for the subbranches.
718 /// The branch is reset.
719 ///
720 /// NOTE that this function must be used with extreme care. Deleting branch baskets
721 /// fragments the file and may introduce inefficiencies when adding new entries
722 /// in the Tree or later on when reading the Tree.
723
725{
726 TString opt = option;
727 opt.ToLower();
728 TFile *file = GetFile(0);
729
731 for(Int_t i=0; i<fWriteBasket; i++) {
732 if (fBasketSeek[i]) file->MakeFree(fBasketSeek[i],fBasketSeek[i]+fBasketBytes[i]-1);
733 }
734 }
735
736 // process subbranches
737 if (opt.Contains("all")) {
739 Int_t nb = lb->GetEntriesFast();
740 for (Int_t j = 0; j < nb; j++) {
741 TBranch* branch = (TBranch*) lb->UncheckedAt(j);
742 if (branch) branch->DeleteBaskets("all");
743 }
744 }
745 DropBaskets("all");
746 Reset();
747}
748
749////////////////////////////////////////////////////////////////////////////////
750/// Loop on all branch baskets. Drop all baskets from memory except readbasket.
751/// If the option contains "all", drop all baskets including
752/// read- and write-baskets (unless they are not stored individually on disk).
753/// The option "all" also lead to DropBaskets being called on the sub-branches.
754
756{
757 Bool_t all = kFALSE;
758 if (options && options[0]) {
759 TString opt = options;
760 opt.ToLower();
761 if (opt.Contains("all")) all = kTRUE;
762 }
763
764 TBasket *basket;
765 Int_t nbaskets = fBaskets.GetEntriesFast();
766
767 if ( (fNBaskets>1) || all ) {
768 //slow case
769 for (Int_t i=0;i<nbaskets;i++) {
770 basket = (TBasket*)fBaskets.UncheckedAt(i);
771 if (!basket) continue;
772 if ((i == fReadBasket || i == fWriteBasket) && !all) continue;
773 // if the basket is not yet on file but already has event in it
774 // we must continue to avoid dropping the basket (and thus losing data)
775 if (fBasketBytes[i]==0 && basket->GetNevBuf() > 0) continue;
776 basket->DropBuffers();
777 --fNBaskets;
779 if (basket == fCurrentBasket) {
780 fCurrentBasket = 0;
782 fNextBasketEntry = -1;
783 }
784 delete basket;
785 }
786
787 // process subbranches
788 if (all) {
790 Int_t nb = lb->GetEntriesFast();
791 for (Int_t j = 0; j < nb; j++) {
792 TBranch* branch = (TBranch*) lb->UncheckedAt(j);
793 if (!branch) continue;
794 branch->DropBaskets("all");
795 }
796 }
797 } else {
798 //fast case
799 if (nbaskets > 0) {
800 Int_t i = fBaskets.GetLast();
801 basket = (TBasket*)fBaskets.UncheckedAt(i);
802 if (basket && fBasketBytes[i]!=0) {
803 basket->DropBuffers();
804 if (basket == fCurrentBasket) {
805 fCurrentBasket = 0;
807 fNextBasketEntry = -1;
808 }
809 delete basket;
810 fBaskets.AddAt(0,i);
811 fBaskets.SetLast(-1);
812 fNBaskets = 0;
813 }
814 }
815 }
816
817}
818
819////////////////////////////////////////////////////////////////////////////////
820/// Increase BasketEntry buffer of a minimum of 10 locations
821/// and a maximum of 50 per cent of current size.
822
824{
825 Int_t newsize = TMath::Max(10,Int_t(1.5*fMaxBaskets));
828 newsize*sizeof(Long64_t),fMaxBaskets*sizeof(Long64_t));
830 newsize*sizeof(Long64_t),fMaxBaskets*sizeof(Long64_t));
831
832 fMaxBaskets = newsize;
833
834 fBaskets.Expand(newsize);
835
836 for (Int_t i=fWriteBasket;i<fMaxBaskets;i++) {
837 fBasketBytes[i] = 0;
838 fBasketEntry[i] = 0;
839 fBasketSeek[i] = 0;
840 }
841}
842
843////////////////////////////////////////////////////////////////////////////////
844/// Loop on all leaves of this branch to fill Basket buffer.
845///
846/// If TBranchIMTHelper is non-null and it is time to WriteBasket, then we will
847/// use TBB to compress in parallel.
848///
849/// The function returns the number of bytes committed to the memory basket.
850/// If a write error occurs, the number of bytes returned is -1.
851/// If no data are written, because e.g. the branch is disabled,
852/// the number of bytes returned is 0.
853
855{
856 if (TestBit(kDoNotProcess)) {
857 return 0;
858 }
859
861 if (!basket) {
862 basket = fTree->CreateBasket(this); // create a new basket
863 if (!basket) return 0;
864 ++fNBaskets;
866 }
867 TBuffer* buf = basket->GetBufferRef();
868
869 // Fill basket buffer.
870
871 Int_t nsize = 0;
872
873 if (buf->IsReading()) {
874 basket->SetWriteMode();
875 }
876
878 buf->ResetMap();
879 }
880
881 Int_t lnew = 0;
882 Int_t nbytes = 0;
883
884 if (fEntryBuffer) {
885 nbytes = FillEntryBuffer(basket,buf,lnew);
886 } else {
887 Int_t lold = buf->Length();
888 basket->Update(lold);
889 ++fEntries;
890 ++fEntryNumber;
891 (this->*fFillLeaves)(*buf);
892 if (buf->GetMapCount()) {
893 // The map is used.
895 }
896 lnew = buf->Length();
897 nbytes = lnew - lold;
898 }
899
900 if (fEntryOffsetLen) {
901 Int_t nevbuf = basket->GetNevBuf();
902 // Total size in bytes of EntryOffset table.
903 nsize = nevbuf * sizeof(Int_t);
904 } else {
905 if (!basket->GetNevBufSize()) {
906 basket->SetNevBufSize(nbytes);
907 }
908 }
909
910 // Should we create a new basket?
911 // fSkipZip force one entry per buffer (old stuff still maintained for CDF)
912 // Transfer full compressed buffer only
913
914 // If GetAutoFlush() is less than zero, then we are determining the end of the autocluster
915 // based upon the number of bytes already flushed. This is incompatible with one-basket-per-cluster
916 // (since we will grow the basket indefinitely and never flush!). Hence, we wait until the
917 // first event cluster is written out and *then* enable one-basket-per-cluster mode.
918 bool noFlushAtCluster = !fTree->TestBit(TTree::kOnlyFlushAtCluster) || (fTree->GetAutoFlush() < 0);
919
920 if (noFlushAtCluster && !fTree->TestBit(TTree::kCircular) &&
922 ((lnew + (2 * nsize) + nbytes) >= fBasketSize))) {
923 Int_t nout = WriteBasketImpl(basket, fWriteBasket, imtHelper);
924 if (nout < 0) Error("TBranch::Fill", "Failed to write out basket.\n");
925 return (nout >= 0) ? nbytes : -1;
926 }
927 return nbytes;
928}
929
930////////////////////////////////////////////////////////////////////////////////
931/// Copy the data from fEntryBuffer into the current basket.
932
934{
935 Int_t nbytes = 0;
936 Int_t objectStart = 0;
937 Int_t last = 0;
938 Int_t lold = buf->Length();
939
940 // Handle the special case of fEntryBuffer != 0
941 if (fEntryBuffer->IsA() == TMessage::Class()) {
942 objectStart = 8;
943 }
945 // The buffer given as input has not been decompressed.
946 if (basket->GetNevBuf()) {
947 // If the basket already contains entry we need to close it
948 // out. (This is because we can only transfer full compressed
949 // buffer)
951 // And restart from scratch
952 return Fill();
953 }
954 Int_t startpos = fEntryBuffer->Length();
956 static TBasket toread_fLast;
958 toread_fLast.Streamer(*fEntryBuffer);
960 last = toread_fLast.GetLast();
961 // last now contains the decompressed number of bytes.
962 fEntryBuffer->SetBufferOffset(startpos);
963 buf->SetBufferOffset(0);
965 basket->Update(lold);
966 } else {
967 // We are required to copy starting at the version number (so not
968 // including the class name.
969 // See if byte count is here, if not it class still be a newClass
970 const UInt_t kNewClassTag = 0xFFFFFFFF;
971 const UInt_t kByteCountMask = 0x40000000; // OR the byte count with this
972 UInt_t tag = 0;
973 UInt_t startpos = fEntryBuffer->Length();
974 fEntryBuffer->SetBufferOffset(objectStart);
975 *fEntryBuffer >> tag;
976 if (tag & kByteCountMask) {
977 *fEntryBuffer >> tag;
978 }
979 if (tag == kNewClassTag) {
980 UInt_t maxsize = 256;
981 char* s = new char[maxsize];
982 Int_t name_start = fEntryBuffer->Length();
983 fEntryBuffer->ReadString(s, maxsize); // Reads at most maxsize - 1 characters, plus null at end.
984 while (strlen(s) == (maxsize - 1)) {
985 // The classname is too large, try again with a large buffer.
986 fEntryBuffer->SetBufferOffset(name_start);
987 maxsize *= 2;
988 delete[] s;
989 s = new char[maxsize];
990 fEntryBuffer->ReadString(s, maxsize); // Reads at most maxsize - 1 characters, plus null at end
991 }
992 delete[] s;
993 } else {
994 fEntryBuffer->SetBufferOffset(objectStart);
995 }
996 objectStart = fEntryBuffer->Length();
997 fEntryBuffer->SetBufferOffset(startpos);
998 basket->Update(lold, objectStart - fEntryBuffer->GetBufferDisplacement());
999 }
1000 fEntries++;
1001 fEntryNumber++;
1002 UInt_t len = 0;
1003 UInt_t startpos = fEntryBuffer->Length();
1004 if (startpos > UInt_t(objectStart)) {
1005 // We assume this buffer have just been directly filled
1006 // the current position in the buffer indicates the end of the object!
1007 len = fEntryBuffer->Length() - objectStart;
1008 } else {
1009 // The buffer have been acquired either via TSocket or via
1010 // TBuffer::SetBuffer(newloc,newsize)
1011 // Only the actual size of the memory buffer gives us an hint about where
1012 // the object ends.
1013 len = fEntryBuffer->BufferSize() - objectStart;
1014 }
1015 buf->WriteBuf(fEntryBuffer->Buffer() + objectStart, len);
1017 // The original buffer came pre-compressed and thus the buffer Length
1018 // does not really show the really object size
1019 // lnew = nbytes = basket->GetLast();
1020 nbytes = last;
1021 lnew = last;
1022 } else {
1023 lnew = buf->Length();
1024 nbytes = lnew - lold;
1025 }
1026
1027 return nbytes;
1028}
1029
1030////////////////////////////////////////////////////////////////////////////////
1031/// Find the immediate sub-branch with passed name.
1032
1034{
1035 // We allow the user to pass only the last dotted component of the name.
1036 std::string longnm;
1037 longnm.reserve(fName.Length()+strlen(name)+3);
1038 longnm = fName.Data();
1039 if (longnm[longnm.length()-1]==']') {
1040 std::size_t dim = longnm.find_first_of("[");
1041 if (dim != std::string::npos) {
1042 longnm.erase(dim);
1043 }
1044 }
1045 if (longnm[longnm.length()-1] != '.') {
1046 longnm += '.';
1047 }
1048 longnm += name;
1049 UInt_t namelen = strlen(name);
1050
1051 Int_t nbranches = fBranches.GetEntries();
1052 TBranch* branch = 0;
1053 for(Int_t i = 0; i < nbranches; ++i) {
1054 branch = (TBranch*) fBranches.UncheckedAt(i);
1055
1056 const char *brname = branch->fName.Data();
1057 UInt_t brlen = branch->fName.Length();
1058 if (brname[brlen-1]==']') {
1059 const char *dim = strchr(brname,'[');
1060 if (dim) {
1061 brlen = dim - brname;
1062 }
1063 }
1064 if (namelen == brlen /* same effective size */
1065 && strncmp(name,brname,brlen) == 0) {
1066 return branch;
1067 }
1068 if (brlen == (size_t)longnm.length()
1069 && strncmp(longnm.c_str(),brname,brlen) == 0) {
1070 return branch;
1071 }
1072 }
1073 return 0;
1074}
1075
1076////////////////////////////////////////////////////////////////////////////////
1077/// Find the leaf corresponding to the name 'searchname'.
1078
1079TLeaf* TBranch::FindLeaf(const char* searchname)
1080{
1081 TString leafname;
1082 TString leaftitle;
1083 TString longname;
1084 TString longtitle;
1085
1086 // We allow the user to pass only the last dotted component of the name.
1087 TIter next(GetListOfLeaves());
1088 TLeaf* leaf = 0;
1089 while ((leaf = (TLeaf*) next())) {
1090 leafname = leaf->GetName();
1091 Ssiz_t dim = leafname.First('[');
1092 if (dim >= 0) leafname.Remove(dim);
1093
1094 if (leafname == searchname) return leaf;
1095
1096 // The leaf element contains the branch name in its name, let's use the title.
1097 leaftitle = leaf->GetTitle();
1098 dim = leaftitle.First('[');
1099 if (dim >= 0) leaftitle.Remove(dim);
1100
1101 if (leaftitle == searchname) return leaf;
1102
1103 TBranch* branch = leaf->GetBranch();
1104 if (branch) {
1105 longname.Form("%s.%s",branch->GetName(),leafname.Data());
1106 dim = longname.First('[');
1107 if (dim>=0) longname.Remove(dim);
1108 if (longname == searchname) return leaf;
1109
1110 // The leaf element contains the branch name in its name.
1111 longname.Form("%s.%s",branch->GetName(),searchname);
1112 if (longname==leafname) return leaf;
1113
1114 longtitle.Form("%s.%s",branch->GetName(),leaftitle.Data());
1115 dim = longtitle.First('[');
1116 if (dim>=0) longtitle.Remove(dim);
1117 if (longtitle == searchname) return leaf;
1118
1119 // The following is for the case where the branch is only
1120 // a sub-branch. Since we do not see it through
1121 // TTree::GetListOfBranches, we need to see it indirectly.
1122 // This is the less sturdy part of this search ... it may
1123 // need refining ...
1124 if (strstr(searchname, ".") && !strcmp(searchname, branch->GetName())) return leaf;
1125 }
1126 }
1127 return 0;
1128}
1129
1130////////////////////////////////////////////////////////////////////////////////
1131/// Flush to disk all the baskets of this branch and any of subbranches.
1132/// Return the number of bytes written or -1 in case of write error.
1133
1135{
1136 UInt_t nerror = 0;
1137 Int_t nbytes = 0;
1138
1139 Int_t maxbasket = fWriteBasket + 1;
1140 // The following protection is not necessary since we should always
1141 // have fWriteBasket < fBasket.GetSize()
1142 //if (fBaskets.GetSize() < maxbasket) {
1143 // maxbasket = fBaskets.GetSize();
1144 //}
1145 for(Int_t i=0; i != maxbasket; ++i) {
1146 if (fBaskets.UncheckedAt(i)) {
1147 Int_t nwrite = FlushOneBasket(i);
1148 if (nwrite<0) {
1149 ++nerror;
1150 } else {
1151 nbytes += nwrite;
1152 }
1153 }
1154 }
1156 for (Int_t i = 0; i < len; ++i) {
1157 TBranch* branch = (TBranch*) fBranches.UncheckedAt(i);
1158 if (!branch) {
1159 continue;
1160 }
1161 Int_t nwrite = branch->FlushBaskets();
1162 if (nwrite<0) {
1163 ++nerror;
1164 } else {
1165 nbytes += nwrite;
1166 }
1167 }
1168 if (nerror) {
1169 return -1;
1170 } else {
1171 return nbytes;
1172 }
1173}
1174
1175////////////////////////////////////////////////////////////////////////////////
1176/// If we have a write basket in memory and it contains some entries and
1177/// has not yet been written to disk, we write it and delete it from memory.
1178/// Return the number of bytes written;
1179
1181{
1182 Int_t nbytes = 0;
1184 TBasket *basket = (TBasket*)fBaskets.UncheckedAt(ibasket);
1185
1186 if (basket) {
1187 if (basket->GetNevBuf()
1188 && fBasketSeek[ibasket]==0) {
1189 // If the basket already contains entry we need to close it out.
1190 // (This is because we can only transfer full compressed buffer)
1191
1192 if (basket->GetBufferRef()->IsReading()) {
1193 basket->SetWriteMode();
1194 }
1195 nbytes = WriteBasket(basket,ibasket);
1196
1197 } else {
1198 // If the basket is empty or has already been written.
1199 if ((Int_t)ibasket==fWriteBasket) {
1200 // Nothing to do.
1201 } else {
1202 basket->DropBuffers();
1203 if (basket == fCurrentBasket) {
1204 fCurrentBasket = 0;
1205 fFirstBasketEntry = -1;
1206 fNextBasketEntry = -1;
1207 }
1208 delete basket;
1209 --fNBaskets;
1210 fBaskets[ibasket] = 0;
1211 }
1212 }
1213 }
1214 }
1215 return nbytes;
1216}
1217
1218////////////////////////////////////////////////////////////////////////////////
1219/// Return pointer to basket basketnumber in this Branch
1220///
1221/// If a new buffer must be created and the user_buffer argument is non-null,
1222/// then the memory in the user_buffer will be shared with the returned TBasket.
1223
1224TBasket* TBranch::GetBasketImpl(Int_t basketnumber, TBuffer *user_buffer)
1225{
1226 // This counter in the sequential case collects errors coming also from
1227 // different files (suppose to have a program reading f1.root, f2.root ...)
1228 // In the mt case, it is made atomic: it safely collects errors from
1229 // different files processed simultaneously.
1230 static std::atomic<Int_t> nerrors(0);
1231
1232 // reference to an existing basket in memory ?
1233 if (basketnumber <0 || basketnumber > fWriteBasket) return 0;
1234 TBasket *basket = (TBasket*)fBaskets.UncheckedAt(basketnumber);
1235 if (basket) return basket;
1236 if (basketnumber == fWriteBasket) return 0;
1237
1238 // create/decode basket parameters from buffer
1239 TFile *file = GetFile(0);
1240 if (file == 0) {
1241 return 0;
1242 }
1243 // if cluster pre-fetching or retaining is on, do not re-use existing baskets
1244 // unless a new cluster is used.
1246 basket = GetFreshCluster();
1247 else
1248 basket = GetFreshBasket(basketnumber, user_buffer);
1249
1250 // fSkipZip is old stuff still maintained for CDF
1252 if (fBasketBytes[basketnumber] == 0) {
1253 fBasketBytes[basketnumber] = basket->ReadBasketBytes(fBasketSeek[basketnumber],file);
1254 }
1255 //add branch to cache (if any)
1256 {
1257 R__LOCKGUARD_IMT(gROOTMutex); // Lock for parallel TTree I/O
1259 if (pf){
1260 if (pf->IsLearning()) pf->LearnBranch(this, kFALSE);
1261 if (fSkipZip) pf->SetSkipZip();
1262 }
1263 }
1264
1265 //now read basket
1266 Int_t badread = basket->ReadBasketBuffers(fBasketSeek[basketnumber],fBasketBytes[basketnumber],file);
1267 if (R__unlikely(badread || basket->GetSeekKey() != fBasketSeek[basketnumber] || basket->IsZombie())) {
1268 nerrors++;
1269 if (nerrors > 10) return 0;
1270 if (nerrors == 10) {
1271 printf(" file probably overwritten: stopping reporting error messages\n");
1272 if (fBasketSeek[basketnumber] > 2000000000) {
1273 printf("===>File is more than 2 Gigabytes\n");
1274 return 0;
1275 }
1276 if (fBasketSeek[basketnumber] > 1000000000) {
1277 printf("===>Your file is may be bigger than the maximum file size allowed on your system\n");
1278 printf(" Check your AFS maximum file size limit for example\n");
1279 return 0;
1280 }
1281 }
1282 Error("GetBasket","File: %s at byte:%lld, branch:%s, entry:%lld, badread=%d, nerrors=%d, basketnumber=%d",file->GetName(),basket->GetSeekKey(),GetName(),fReadEntry,badread,nerrors.load(),basketnumber);
1283 return 0;
1284 }
1285
1286 ++fNBaskets;
1287
1288 fCacheInfo.SetUsed(basketnumber);
1289 auto perfStats = GetTree()->GetPerfStats();
1290 if (perfStats)
1291 perfStats->SetUsed(this, basketnumber);
1292
1293 fBaskets.AddAt(basket,basketnumber);
1294 return basket;
1295}
1296
1297////////////////////////////////////////////////////////////////////////////////
1298/// Return address of basket in the file
1299
1301{
1302 if (basketnumber <0 || basketnumber > fWriteBasket) return 0;
1303 return fBasketSeek[basketnumber];
1304}
1305
1306////////////////////////////////////////////////////////////////////////////////
1307/// Returns (and, if 0, creates) browsable objects for this branch
1308/// See TVirtualBranchBrowsable::FillListOfBrowsables.
1309
1311 if (fBrowsables) return fBrowsables;
1312 fBrowsables=new TList();
1314 return fBrowsables;
1315}
1316
1317////////////////////////////////////////////////////////////////////////////////
1318/// Return the name of the user class whose content is stored in this branch,
1319/// if any. If this branch was created using the 'leaflist' technique, this
1320/// function returns an empty string.
1321
1322const char * TBranch::GetClassName() const
1323{
1324 return "";
1325}
1326
1327////////////////////////////////////////////////////////////////////////////////
1328/// Return icon name depending on type of branch.
1329
1330const char* TBranch::GetIconName() const
1331{
1332 if (IsFolder())
1333 return "TBranchElement-folder";
1334 else
1335 return "TBranchElement-leaf";
1336}
1337
1338////////////////////////////////////////////////////////////////////////////////
1339/// A helper function to locate the correct basket - and its first entry.
1340/// Extracted to a common private function because it is needed by both GetEntry
1341/// and GetBulkEntries. It should not be called directly.
1342///
1343/// If a new basket must be constructed and the user_buffer is provided, then
1344/// the user_buffer will back the memory of the newly-constructed basket.
1345///
1346/// Assumes that this branch is enabled.
1347///
1348/// Returns -1 if the entry does not exist
1349/// Returns -2 in case of error
1350/// Returns the index of the basket in case of success.
1352 TBuffer *user_buffer)
1353{
1354 Long64_t updatedNext = fNextBasketEntry;
1355 Long64_t entry = fReadEntry;
1356 if (R__likely(fCurrentBasket && fFirstBasketEntry <= entry && entry < fNextBasketEntry)) {
1357 // We have found the basket containing this entry.
1358 // make sure basket buffers are in memory.
1359 basket = fCurrentBasket;
1361 return fReadBasket;
1362 } else {
1363 if ((entry < fFirstEntry) || (entry >= fEntryNumber)) {
1364 return -1;
1365 }
1367 Long64_t last = fNextBasketEntry - 1;
1368 // Are we still in the same ReadBasket?
1369 if ((entry < first) || (entry > last)) {
1371 if (fReadBasket < 0) {
1372 fNextBasketEntry = -1;
1373 Error("GetBasketAndFirst", "In the branch %s, no basket contains the entry %lld\n", GetName(), entry);
1374 return -2;
1375 }
1376 if (fReadBasket == fWriteBasket) {
1378 } else {
1380 }
1381 updatedNext = fNextBasketEntry;
1383 }
1384 // We have found the basket containing this entry.
1385 // make sure basket buffers are in memory.
1387 if (!basket) {
1388 basket = GetBasketImpl(fReadBasket, user_buffer);
1389 if (!basket) {
1390 fCurrentBasket = 0;
1391 fFirstBasketEntry = -1;
1392 fNextBasketEntry = -1;
1393 return -2;
1394 }
1395 if (fTree->GetClusterPrefetch()) {
1396 TTree::TClusterIterator clusterIterator = fTree->GetClusterIterator(entry);
1397 clusterIterator.Next();
1398 Int_t nextClusterEntry = clusterIterator.GetNextEntry();
1399 for (Int_t i = fReadBasket + 1; i < fMaxBaskets && fBasketEntry[i] < nextClusterEntry; i++) {
1400 GetBasket(i);
1401 }
1402 }
1403 // Getting the next basket might reset the current one and
1404 // cause a reset of the first / next basket entries back to -1.
1406 fNextBasketEntry = updatedNext;
1407 if (user_buffer) {
1408 // Disassociate basket from memory buffer for bulk IO
1409 // When the user provides a memory buffer (i.e., for bulk IO), we should
1410 // make sure to drop all references to that buffer in the TTree afterward.
1411 fCurrentBasket = nullptr;
1412 fBaskets[fReadBasket] = nullptr;
1413 } else {
1414 fCurrentBasket = basket;
1415 }
1416 } else {
1417 fCurrentBasket = basket;
1418 }
1419 return fReadBasket;
1420 }
1421}
1422
1423////////////////////////////////////////////////////////////////////////////////
1424/// Returns true if this branch supports bulk IO, false otherwise.
1425///
1426/// This will return true if all the various preconditions necessary hold true
1427/// to perform bulk IO (reasonable type, single TLeaf, etc); the bulk IO may
1428/// still fail, depending on the contents of the individual TBaskets loaded.
1430 return (fNleaves == 1) &&
1431 (static_cast<TLeaf*>(fLeaves.UncheckedAt(0))->GetDeserializeType() != TLeaf::DeserializeType::kExternal);
1432}
1433
1434////////////////////////////////////////////////////////////////////////////////
1435/// Read as many events as possible into the given buffer, using zero-copy
1436/// mechanisms.
1437///
1438/// Returns -1 in case of a failure. On success, returns a (non-zero) number of
1439/// events of the type held by this branch currently in the buffer.
1440///
1441/// On success, the caller should be able to access the contents of buf as
1442///
1443/// static_cast<T*>(buf.GetCurrent())
1444///
1445/// where T is the type stored on this branch. The array's length is the return
1446/// value of this function.
1447///
1448/// NOTES:
1449/// - This interface is meant to be used by higher-level, type-safe wrappers, not
1450/// by end-users.
1451/// - This only returns events
1452///
1453
1455{
1456 // TODO: eventually support multiple leaves.
1457 if (R__unlikely(fNleaves != 1)) return -1;
1458 TLeaf *leaf = static_cast<TLeaf*>(fLeaves.UncheckedAt(0));
1460 return -1;
1461 }
1462
1463 // Remember which entry we are reading.
1464 fReadEntry = entry;
1465
1466 Bool_t enabled = !TestBit(kDoNotProcess);
1467 if (R__unlikely(!enabled)) return -1;
1468 TBasket *basket = nullptr;
1470 Int_t result = GetBasketAndFirst(basket, first, &user_buf);
1471 if (R__unlikely(result < 0)) return -1;
1472 // Only support reading from full clusters.
1473 if (R__unlikely(entry != first)) {
1474 //printf("Failed to read from full cluster; first entry is %ld; requested entry is %ld.\n", first, entry);
1475 return -1;
1476 }
1477
1478 basket->PrepareBasket(entry);
1479 TBuffer* buf = basket->GetBufferRef();
1480
1481 // Test for very old ROOT files.
1482 if (R__unlikely(!buf)) {
1483 Error("GetBulkEntries", "Failed to get a new buffer.\n");
1484 return -1;
1485 }
1486 // Test for displacements, which aren't supported in fast mode.
1487 if (R__unlikely(basket->GetDisplacement())) {
1488 Error("GetBulkEntries", "Basket has displacement.\n");
1489 return -1;
1490 }
1491
1492 if (&user_buf != buf) {
1493 // The basket was already in memory and might (and might not) be backed by persistent
1494 // storage.
1495 R__ASSERT(result == fReadBasket);
1496 if (fBasketSeek[fReadBasket]) {
1497 // It is backed, so we can be destructive
1498 user_buf.SetBuffer(buf->Buffer(), buf->BufferSize());
1500 fCurrentBasket = nullptr;
1501 fBaskets[fReadBasket] = nullptr;
1502 } else {
1503 // This is the only copy, we can't return it as is to the user, just make a copy.
1504 if (user_buf.BufferSize() < buf->BufferSize()) {
1505 user_buf.AutoExpand(buf->BufferSize());
1506 }
1507 memcpy(user_buf.Buffer(), buf->Buffer(), buf->BufferSize());
1508 }
1509 }
1510
1511 Int_t bufbegin = basket->GetKeylen();
1512 user_buf.SetBufferOffset(bufbegin);
1513
1515 //printf("Requesting %d events; fNextBasketEntry=%lld; first=%lld.\n", N, fNextBasketEntry, first);
1516 if (R__unlikely(!leaf->ReadBasketFast(user_buf, N))) {
1517 Error("GetBulkEntries", "Leaf failed to read.\n");
1518 return -1;
1519 }
1520 user_buf.SetBufferOffset(bufbegin);
1521
1522 if (fCurrentBasket == nullptr) {
1523 R__ASSERT(fExtraBasket == nullptr && "fExtraBasket should have been set to nullptr by GetFreshBasket");
1524 fExtraBasket = basket;
1525 basket->DisownBuffer();
1526 }
1527
1528 return N;
1529}
1530
1531// TODO: Template this and the call above; only difference is the TLeaf function (ReadBasketFast vs
1532// ReadBasketSerialized
1534{
1535 // TODO: eventually support multiple leaves.
1536 if (R__unlikely(fNleaves != 1)) { return -1; }
1537 TLeaf *leaf = static_cast<TLeaf*>(fLeaves.UncheckedAt(0));
1539 Error("GetEntriesSerialized", "Encountered a branch with destructive deserialization; failing.");
1540 return -1;
1541 }
1542
1543 // Remember which entry we are reading.
1544 fReadEntry = entry;
1545
1546 Bool_t enabled = !TestBit(kDoNotProcess);
1547 if (R__unlikely(!enabled)) { return -1; }
1548 TBasket *basket = nullptr;
1550 Int_t result = GetBasketAndFirst(basket, first, &user_buf);
1551 if (R__unlikely(result < 0)) { return -1; }
1552 // Only support reading from full clusters.
1553 if (R__unlikely(entry != first)) {
1554 Error("GetEntriesSerialized", "Failed to read from full cluster; first entry is %lld; requested entry is %lld.\n", first, entry);
1555 return -1;
1556 }
1557
1558 basket->PrepareBasket(entry);
1559 TBuffer* buf = basket->GetBufferRef();
1560
1561 // Test for very old ROOT files.
1562 if (R__unlikely(!buf)) {
1563 Error("GetEntriesSerialized", "Failed to get a new buffer.\n");
1564 return -1;
1565 }
1566 // Test for displacements, which aren't supported in fast mode.
1567 if (R__unlikely(basket->GetDisplacement())) {
1568 Error("GetEntriesSerialized", "Basket has displacement.\n");
1569 return -1;
1570 }
1571
1572 if (&user_buf != buf) {
1573 // The basket was already in memory and might (and might not) be backed by persistent
1574 // storage.
1575 R__ASSERT(result == fReadBasket);
1576 if (fBasketSeek[fReadBasket]) {
1577 // It is backed, so we can be destructive
1578 user_buf.SetBuffer(buf->Buffer(), buf->BufferSize());
1580 fCurrentBasket = nullptr;
1581 fBaskets[fReadBasket] = nullptr;
1582 } else {
1583 // This is the only copy, we can't return it as is to the user, just make a copy.
1584 if (user_buf.BufferSize() < buf->BufferSize()) {
1585 user_buf.AutoExpand(buf->BufferSize());
1586 }
1587 memcpy(user_buf.Buffer(), buf->Buffer(), buf->BufferSize());
1588 }
1589 }
1590
1591 Int_t bufbegin = basket->GetKeylen();
1592 user_buf.SetBufferOffset(bufbegin);
1593
1595 //Info("GetEntriesSerialized", "Requesting %d events; fNextBasketEntry=%lld; first=%lld.\n", N, fNextBasketEntry, first);
1596
1597 user_buf.SetBufferOffset(bufbegin);
1598
1599 if (count_buf) {
1600 TLeaf *count_leaf = leaf->GetLeafCount();
1601 if (count_leaf) {
1602 //printf("Getting leaf count entries.\n");
1603 TBranch *count_branch = count_leaf->GetBranch();
1604 if (R__unlikely(count_branch->GetEntriesSerialized(entry, *count_buf) < 0)) {
1605 Error("GetEntriesSerialized", "Failed to read count leaf.\n");
1606 return -1;
1607 }
1608 } else {
1609 // TODO: if you ask for a count on a fixed-size branch, maybe we should
1610 // just fail?
1611 Int_t entry_count_serialized;
1612 char *tmp_ptr = reinterpret_cast<char*>(&entry_count_serialized);
1613 tobuf(tmp_ptr, leaf->GetLenType() * leaf->GetNdata());
1614 Int_t cur_offset = count_buf->GetCurrent() - count_buf->Buffer();
1615 for (int idx=0; idx<N; idx++) {
1616 *count_buf << entry_count_serialized;
1617 }
1618 count_buf->SetBufferOffset(cur_offset);
1619 }
1620 }
1621
1622 return N;
1623}
1624
1625////////////////////////////////////////////////////////////////////////////////
1626/// Read all leaves of entry and return total number of bytes read.
1627///
1628/// The input argument "entry" is the entry number in the current tree.
1629/// In case of a TChain, the entry number in the current Tree must be found
1630/// before calling this function. For example:
1631///
1632///~~~ {.cpp}
1633/// TChain* chain = ...;
1634/// Long64_t localEntry = chain->LoadTree(entry);
1635/// branch->GetEntry(localEntry);
1636///~~~
1637///
1638/// The function returns the number of bytes read from the input buffer.
1639/// If entry does not exist, the function returns 0.
1640/// If an I/O error occurs, the function returns -1.
1641///
1642/// See IMPORTANT REMARKS in TTree::GetEntry.
1643
1645{
1646 // Remember which entry we are reading.
1647 fReadEntry = entry;
1648
1649 if (R__unlikely(TestBit(kDoNotProcess) && !getall)) { return 0; }
1650
1651 TBasket *basket; // will be initialized in the if/then clauses.
1653
1654 Int_t result = GetBasketAndFirst(basket, first, nullptr);
1655 if (R__unlikely(result < 0)) { return result + 1; }
1656
1657 basket->PrepareBasket(entry);
1658 TBuffer* buf = basket->GetBufferRef();
1659
1660 // This test necessary to read very old Root files (NvE).
1661 if (R__unlikely(!buf)) {
1662 TFile* file = GetFile(0);
1663 if (!file) return -1;
1665 buf = basket->GetBufferRef();
1666 }
1667
1668 // Set entry offset in buffer.
1670 buf->ResetMap();
1671 }
1672 if (R__unlikely(!buf->IsReading())) {
1673 basket->SetReadMode();
1674 }
1675
1676 Int_t* entryOffset = basket->GetEntryOffset();
1677 Int_t bufbegin = 0;
1678 if (entryOffset) {
1679 bufbegin = entryOffset[entry-first];
1680 buf->SetBufferOffset(bufbegin);
1681 Int_t* displacement = basket->GetDisplacement();
1682 if (R__unlikely(displacement)) {
1683 buf->SetBufferDisplacement(displacement[entry-first]);
1684 }
1685 } else {
1686 bufbegin = basket->GetKeylen() + ((entry-first) * basket->GetNevBufSize());
1687 buf->SetBufferOffset(bufbegin);
1688 }
1689
1690 // Int_t bufbegin = buf->Length();
1691 (this->*fReadLeaves)(*buf);
1692 return buf->Length() - bufbegin;
1693}
1694
1695////////////////////////////////////////////////////////////////////////////////
1696/// Read all leaves of an entry and export buffers to real objects in a TClonesArray list.
1697///
1698/// Returns total number of bytes read.
1699
1701{
1702 // Remember which entry we are reading.
1703 fReadEntry = entry;
1704
1705 if (TestBit(kDoNotProcess)) {
1706 return 0;
1707 }
1708 if ((entry < 0) || (entry >= fEntryNumber)) {
1709 return 0;
1710 }
1711 Int_t nbytes = 0;
1713 Long64_t last = fNextBasketEntry - 1;
1714 // Are we still in the same ReadBasket?
1715 if ((entry < first) || (entry > last)) {
1717 if (fReadBasket < 0) {
1718 fNextBasketEntry = -1;
1719 Error("In the branch %s, no basket contains the entry %d\n", GetName(), entry);
1720 return -1;
1721 }
1722 if (fReadBasket == fWriteBasket) {
1724 } else {
1726 }
1728 }
1729
1730 // We have found the basket containing this entry.
1731 // Make sure basket buffers are in memory.
1732 TBasket* basket = GetBasketImpl(fReadBasket, nullptr);
1733 fCurrentBasket = basket;
1734 if (!basket) {
1735 fFirstBasketEntry = -1;
1736 fNextBasketEntry = -1;
1737 return 0;
1738 }
1739 TBuffer* buf = basket->GetBufferRef();
1740 // Set entry offset in buffer and read data from all leaves.
1742 buf->ResetMap();
1743 }
1744 if (R__unlikely(!buf->IsReading())) {
1745 basket->SetReadMode();
1746 }
1747 Int_t* entryOffset = basket->GetEntryOffset();
1748 Int_t bufbegin = 0;
1749 if (entryOffset) {
1750 bufbegin = entryOffset[entry-first];
1751 buf->SetBufferOffset(bufbegin);
1752 Int_t* displacement = basket->GetDisplacement();
1753 if (R__unlikely(displacement)) {
1754 buf->SetBufferDisplacement(displacement[entry-first]);
1755 }
1756 } else {
1757 bufbegin = basket->GetKeylen() + ((entry-first) * basket->GetNevBufSize());
1758 buf->SetBufferOffset(bufbegin);
1759 }
1760 TLeaf* leaf = (TLeaf*) fLeaves.UncheckedAt(0);
1761 leaf->ReadBasketExport(*buf, li, nentries);
1762 nbytes = buf->Length() - bufbegin;
1763 return nbytes;
1764}
1765
1766////////////////////////////////////////////////////////////////////////////////
1767/// Fill expectedClass and expectedType with information on the data type of the
1768/// object/values contained in this branch (and thus the type of pointers
1769/// expected to be passed to Set[Branch]Address
1770/// return 0 in case of success and > 0 in case of failure.
1771
1772Int_t TBranch::GetExpectedType(TClass *&expectedClass,EDataType &expectedType)
1773{
1774 expectedClass = 0;
1775 expectedType = kOther_t;
1776 TLeaf* l = (TLeaf*) GetListOfLeaves()->At(0);
1777 if (l) {
1778 expectedType = (EDataType) gROOT->GetType(l->GetTypeName())->GetType();
1779 return 0;
1780 } else {
1781 Error("GetExpectedType", "Did not find any leaves in %s",GetName());
1782 return 1;
1783 }
1784}
1785
1786////////////////////////////////////////////////////////////////////////////////
1787/// Return pointer to the file where branch buffers reside, returns 0
1788/// in case branch buffers reside in the same file as tree header.
1789/// If mode is 1 the branch buffer file is recreated.
1790
1792{
1793 if (fDirectory) return fDirectory->GetFile();
1794
1795 // check if a file with this name is in the list of Root files
1796 TFile *file = 0;
1797 {
1799 file = (TFile*)gROOT->GetListOfFiles()->FindObject(fFileName.Data());
1800 if (file) {
1801 fDirectory = file;
1802 return file;
1803 }
1804 }
1805
1806 if (fFileName.Length() == 0) return 0;
1807
1808 TString bFileName( GetRealFileName() );
1809
1810 // Open file (new file if mode = 1)
1811 {
1813 if (mode) file = TFile::Open(bFileName, "recreate");
1814 else file = TFile::Open(bFileName);
1815 }
1816 if (!file) return 0;
1817 if (file->IsZombie()) {delete file; return 0;}
1819 return file;
1820}
1821
1822////////////////////////////////////////////////////////////////////////////////
1823/// Return a fresh basket by either reusing an existing basket that needs
1824/// to be drop (according to TTree::MemoryFull) or create a new one.
1825///
1826/// If the user_buffer argument is non-null, then the memory in the
1827/// user-provided buffer will be utilized by the underlying basket.
1828///
1829/// The basket number is used to estimate the required buffer size
1830/// and try to optimize memory usage and number of memory allocation.
1831
1832TBasket* TBranch::GetFreshBasket(Int_t basketnumber, TBuffer* user_buffer)
1833{
1834 TBasket *basket = 0;
1835 if (user_buffer && fExtraBasket) {
1836 basket = fExtraBasket;
1837 fExtraBasket = nullptr;
1838 basket->AdoptBuffer(user_buffer);
1839 } else {
1840 if (GetTree()->MemoryFull(0)) {
1841 if (fNBaskets==1) {
1842 // Steal the existing basket
1843 Int_t oldindex = fBaskets.GetLast();
1844 basket = (TBasket*)fBaskets.UncheckedAt(oldindex);
1845 if (!basket) {
1846 fBaskets.SetLast(-2); // For recalculation of Last.
1847 oldindex = fBaskets.GetLast();
1848 if (oldindex != fBaskets.LowerBound()-1) {
1849 basket = (TBasket*)fBaskets.UncheckedAt(oldindex);
1850 }
1851 }
1852 if (basket && fBasketBytes[oldindex]!=0) {
1853 if (basket == fCurrentBasket) {
1854 fCurrentBasket = 0;
1855 fFirstBasketEntry = -1;
1856 fNextBasketEntry = -1;
1857 }
1858 fBaskets.AddAt(0,oldindex);
1859 fBaskets.SetLast(-1);
1860 fNBaskets = 0;
1861 basket->ReadResetBuffer(basketnumber);
1862#ifdef R__TRACK_BASKET_ALLOC_TIME
1863 fTree->AddAllocationTime(basket->GetResetAllocationTime());
1864#endif
1866 } else {
1867 basket = fTree->CreateBasket(this);
1868 }
1869 } else if (fNBaskets == 0) {
1870 // There is nothing to drop!
1871 basket = fTree->CreateBasket(this);
1872 } else {
1873 // Memory is full and there is more than one basket,
1874 // Let DropBaskets do it job.
1875 DropBaskets();
1876 basket = fTree->CreateBasket(this);
1877 }
1878 } else {
1879 basket = fTree->CreateBasket(this);
1880 }
1881 if (user_buffer)
1882 basket->AdoptBuffer(user_buffer);
1883 }
1884 return basket;
1885}
1886
1887////////////////////////////////////////////////////////////////////////////////
1888/// Drops the cluster two behind the current cluster and returns a fresh basket
1889/// by either reusing or creating a new one
1890
1892{
1893 TBasket *basket = 0;
1894
1895 // If GetClusterIterator is called with a negative entry then GetStartEntry will be 0
1896 // So we need to check if we reach the zero before we have gone back (1-VirtualSize) clusters
1897 // if this is the case, we want to keep everything in memory so we return a new basket
1899 if (iter.GetStartEntry() == 0) {
1900 return fTree->CreateBasket(this);
1901 }
1902
1903 // Iterate backwards (1-VirtualSize) clusters to reach cluster to be unloaded from memory,
1904 // skipped if VirtualSize > 0.
1905 for (Int_t j = 0; j < -fTree->GetMaxVirtualSize(); j++) {
1906 if (iter.Previous() == 0) {
1907 return fTree->CreateBasket(this);
1908 }
1909 }
1910
1911 Int_t entryToUnload = iter.Previous();
1912 // Finds the basket to unload from memory. Since the basket should be close to current
1913 // basket, just iterate backwards until the correct basket is reached. This should
1914 // be fast as long as the number of baskets per cluster is small
1915 Int_t basketToUnload = fReadBasket;
1916 while (fBasketEntry[basketToUnload] != entryToUnload) {
1917 basketToUnload--;
1918 if (basketToUnload < 0) {
1919 return fTree->CreateBasket(this);
1920 }
1921 }
1922
1923 // Retrieves the basket that is going to be unloaded from memory. If the basket did not
1924 // exist, create a new one
1925 basket = (TBasket *)fBaskets.UncheckedAt(basketToUnload);
1926 if (basket) {
1927 fBaskets.AddAt(0, basketToUnload);
1928 --fNBaskets;
1929 } else {
1930 basket = fTree->CreateBasket(this);
1931 }
1932 ++basketToUnload;
1933
1934 // Clear the rest of the baskets. While it would be ideal to reuse these baskets
1935 // for other baskets in the new cluster. It would require the function to go
1936 // beyond its current scope. In the ideal case when each cluster only has 1 basket
1937 // this will perform well
1938 iter.Next();
1939 while (fBasketEntry[basketToUnload] < iter.GetStartEntry()) {
1940 TBasket *oldbasket = (TBasket *)fBaskets.UncheckedAt(basketToUnload);
1941 if (oldbasket) {
1942 oldbasket->DropBuffers();
1943 delete oldbasket;
1944 fBaskets.AddAt(0, basketToUnload);
1945 --fNBaskets;
1946 }
1947 ++basketToUnload;
1948 }
1949 fBaskets.SetLast(-1);
1950 return basket;
1951}
1952
1953////////////////////////////////////////////////////////////////////////////////
1954/// Return the 'full' name of the branch. In particular prefix the mother's name
1955/// when it does not end in a trailing dot and thus is not part of the branch name
1957{
1958 TBranch* mother = GetMother();
1959 if (!mother || mother==this) {
1960 return fName;
1961 }
1962 TString motherName(mother->GetName());
1963 if (motherName.Length() && (motherName[motherName.Length()-1] == '.')) {
1964 return fName;
1965 }
1966 return motherName + "." + fName;
1967}
1968
1969////////////////////////////////////////////////////////////////////////////////
1970/// Return pointer to the 1st Leaf named name in thisBranch
1971
1972TLeaf* TBranch::GetLeaf(const char* name) const
1973{
1974 Int_t i;
1975 for (i=0;i<fNleaves;i++) {
1976 TLeaf *leaf = (TLeaf*)fLeaves.UncheckedAt(i);
1977 if (!strcmp(leaf->GetName(),name)) return leaf;
1978 }
1979 return 0;
1980}
1981
1982////////////////////////////////////////////////////////////////////////////////
1983/// Get real file name
1984
1986{
1987 if (fFileName.Length()==0) {
1988 return fFileName;
1989 }
1990 TString bFileName = fFileName;
1991
1992 // check if branch file name is absolute or a URL (e.g. root://host/...)
1993 char *bname = gSystem->ExpandPathName(fFileName.Data());
1994 if (!gSystem->IsAbsoluteFileName(bname) && !strstr(bname, ":/") && fTree && fTree->GetCurrentFile()) {
1995
1996 // if not, get filename where tree header is stored
1997 const char *tfn = fTree->GetCurrentFile()->GetName();
1998
1999 // If it is an archive file we need a special treatment
2000 TUrl arc(tfn);
2001 if (strlen(arc.GetAnchor()) > 0) {
2003 bFileName = arc.GetUrl();
2004 } else {
2005 // if this is an absolute path or a URL then prepend this path
2006 // to the branch file name
2007 char *tname = gSystem->ExpandPathName(tfn);
2008 if (gSystem->IsAbsoluteFileName(tname) || strstr(tname, ":/")) {
2009 bFileName = gSystem->GetDirName(tname);
2010 bFileName += "/";
2011 bFileName += fFileName;
2012 }
2013 delete [] tname;
2014 }
2015 }
2016 delete [] bname;
2017
2018 return bFileName;
2019}
2020
2021////////////////////////////////////////////////////////////////////////////////
2022/// Return all elements of one row unpacked in internal array fValues
2023/// [Actually just returns 1 (?)]
2024
2026{
2027 return 1;
2028}
2029
2030////////////////////////////////////////////////////////////////////////////////
2031/// Return whether this branch is in a mode where the object are decomposed
2032/// or not (Also known as MakeClass mode).
2033
2035{
2036 // Regular TBranch and TBrancObject can not be in makeClass mode
2037
2038 return kFALSE;
2039}
2040
2041////////////////////////////////////////////////////////////////////////////////
2042/// Get our top-level parent branch in the tree.
2043
2045{
2046 if (fMother) return fMother;
2047
2048 {
2049 TBranch *parent = fParent;
2050 while(parent) {
2051 if (parent->fMother) {
2052 const_cast<TBranch*>(this)->fMother = parent->fMother; // We can not yet use the 'mutable' keyword
2053 return fMother;
2054 }
2055 if (!parent->fParent) {
2056 // This is the top node
2057 const_cast<TBranch*>(this)->fMother = parent; // We can not yet use the 'mutable' keyword
2058 return fMother;
2059 }
2060 parent = parent->fParent;
2061 }
2062 }
2063
2064 const TObjArray* array = fTree->GetListOfBranches();
2065 Int_t n = array->GetEntriesFast();
2066 for (Int_t i = 0; i < n; ++i) {
2067 TBranch* branch = (TBranch*) array->UncheckedAt(i);
2068 TBranch* parent = branch->GetSubBranch(this);
2069 if (parent) {
2070 const_cast<TBranch*>(this)->fMother = branch; // We can not yet use the 'mutable' keyword
2071 return branch;
2072 }
2073 }
2074 return 0;
2075}
2076
2077////////////////////////////////////////////////////////////////////////////////
2078/// Find the parent branch of child.
2079/// Return 0 if child is not in this branch hierarchy.
2080
2082{
2083 // Handle error condition, if the parameter is us, we cannot find the parent.
2084 if (this == child) {
2085 // Note: We cast away any const-ness of "this".
2086 return (TBranch*) this;
2087 }
2088
2089 if (child->fParent) {
2090 return child->fParent;
2091 }
2092
2094 for (Int_t i = 0; i < len; ++i) {
2095 TBranch* branch = (TBranch*) fBranches.UncheckedAt(i);
2096 if (!branch) {
2097 continue;
2098 }
2099 if (branch == child) {
2100 // We are the direct parent of child.
2101 // Note: We cast away any const-ness of "this".
2102 const_cast<TBranch*>(child)->fParent = (TBranch*)this; // We can not yet use the 'mutable' keyword
2103 return (TBranch*) this;
2104 }
2105 // FIXME: This is a tail-recursion!
2106 TBranch* parent = branch->GetSubBranch(child);
2107 if (parent) {
2108 return parent;
2109 }
2110 }
2111 // We failed to find the parent.
2112 return 0;
2113}
2114
2115////////////////////////////////////////////////////////////////////////////////
2116/// Return total number of bytes in the branch (including current buffer)
2117
2119{
2121 // This intentionally only store the TBranch part and thus slightly
2122 // under-estimate the space used.
2123 // Since the TBranchElement part contains pointers to other branches (branch count),
2124 // doing regular Streaming would end up including those and thus greatly over-estimate
2125 // the size used.
2126 const_cast<TBranch *>(this)->TBranch::Streamer(b);
2127
2128 Long64_t totbytes = 0;
2129 if (fZipBytes > 0) totbytes = fTotBytes;
2130 return totbytes + b.Length();
2131}
2132
2133////////////////////////////////////////////////////////////////////////////////
2134/// Return total number of bytes in the branch (excluding current buffer)
2135/// if option ="*" includes all sub-branches of this branch too
2136
2138{
2139 Long64_t totbytes = fTotBytes;
2140 if (!option) return totbytes;
2141 if (option[0] != '*') return totbytes;
2142 //scan sub-branches
2144 for (Int_t i = 0; i < len; ++i) {
2145 TBranch* branch = (TBranch*) fBranches.UncheckedAt(i);
2146 if (branch) totbytes += branch->GetTotBytes(option);
2147 }
2148 return totbytes;
2149}
2150
2151////////////////////////////////////////////////////////////////////////////////
2152/// Return total number of zip bytes in the branch
2153/// if option ="*" includes all sub-branches of this branch too
2154
2156{
2157 Long64_t zipbytes = fZipBytes;
2158 if (!option) return zipbytes;
2159 if (option[0] != '*') return zipbytes;
2160 //scan sub-branches
2162 for (Int_t i = 0; i < len; ++i) {
2163 TBranch* branch = (TBranch*) fBranches.UncheckedAt(i);
2164 if (branch) zipbytes += branch->GetZipBytes(option);
2165 }
2166 return zipbytes;
2167}
2168
2169////////////////////////////////////////////////////////////////////////////////
2170/// Returns the IO settings currently in use for this branch.
2171
2173{
2174 return fIOFeatures;
2175}
2176
2177////////////////////////////////////////////////////////////////////////////////
2178/// Return kTRUE if an existing object in a TBranchObject must be deleted.
2179
2181{
2182 return TestBit(kAutoDelete);
2183}
2184
2185////////////////////////////////////////////////////////////////////////////////
2186/// Return kTRUE if more than one leaf or browsables, kFALSE otherwise.
2187
2189{
2190 if (fNleaves > 1) {
2191 return kTRUE;
2192 }
2193 TList* browsables = const_cast<TBranch*>(this)->GetBrowsables();
2194 return browsables && browsables->GetSize();
2195}
2196
2197////////////////////////////////////////////////////////////////////////////////
2198/// keep a maximum of fMaxEntries in memory
2199
2201{
2202 Int_t dentries = (Int_t) (fEntries - maxEntries);
2203 TBasket* basket = (TBasket*) fBaskets.UncheckedAt(0);
2204 if (basket) basket->MoveEntries(dentries);
2205 fEntries = maxEntries;
2206 fEntryNumber = maxEntries;
2207 //loop on sub branches
2209 for (Int_t i = 0; i < nb; ++i) {
2210 TBranch* branch = (TBranch*) fBranches.UncheckedAt(i);
2211 branch->KeepCircular(maxEntries);
2212 }
2213}
2214
2215////////////////////////////////////////////////////////////////////////////////
2216/// Baskets associated to this branch are forced to be in memory.
2217/// You can call TTree::SetMaxVirtualSize(maxmemory) to instruct
2218/// the system that the total size of the imported baskets does not
2219/// exceed maxmemory bytes.
2220///
2221/// The function returns the number of baskets that have been put in memory.
2222/// This method may be called to force all baskets of one or more branches
2223/// in memory when random access to entries in this branch is required.
2224/// See also TTree::LoadBaskets to load all baskets of all branches in memory.
2225
2227{
2228 Int_t nimported = 0;
2229 Int_t nbaskets = fWriteBasket;
2230 TFile *file = GetFile(0);
2231 if (!file) return 0;
2232 TBasket *basket;
2233 for (Int_t i=0;i<nbaskets;i++) {
2234 basket = (TBasket*)fBaskets.UncheckedAt(i);
2235 if (basket) continue;
2236 basket = GetFreshBasket(i, nullptr);
2237 if (fBasketBytes[i] == 0) {
2239 }
2240 Int_t badread = basket->ReadBasketBuffers(fBasketSeek[i],fBasketBytes[i],file);
2241 if (badread) {
2242 Error("Loadbaskets","Error while reading basket buffer %d of branch %s",i,GetName());
2243 return -1;
2244 }
2245 ++fNBaskets;
2246 fBaskets.AddAt(basket,i);
2247 nimported++;
2248 }
2249 return nimported;
2250}
2251
2252////////////////////////////////////////////////////////////////////////////////
2253/// Print TBranch parameters
2254///
2255/// If options contains "basketsInfo" print the entry number, location and size
2256/// of each baskets.
2257
2258void TBranch::Print(Option_t *option) const
2259{
2260 const int kLINEND = 77;
2261 Float_t cx = 1;
2262
2263 TString titleContent(GetTitle());
2264 if ( titleContent == GetName() ) {
2265 titleContent.Clear();
2266 }
2267
2268 if (fLeaves.GetEntries() == 1) {
2269 if (titleContent.Length()>=2 && titleContent[titleContent.Length()-2]=='/' && isalpha(titleContent[titleContent.Length()-1])) {
2270 // The type is already encoded. Nothing to do.
2271 } else {
2272 TLeaf *leaf = (TLeaf*)fLeaves.UncheckedAt(0);
2273 if (titleContent.Length()) {
2274 titleContent.Prepend(" ");
2275 }
2276 // titleContent.Append("type: ");
2277 titleContent.Prepend(leaf->GetTypeName());
2278 }
2279 }
2280 Int_t titleLength = titleContent.Length();
2281
2282 Int_t aLength = titleLength + strlen(GetName());
2283 aLength += (aLength / 54 + 1) * 80 + 100;
2284 if (aLength < 200) aLength = 200;
2285 char *bline = new char[aLength];
2286
2287 Long64_t totBytes = GetTotalSize();
2288 if (fZipBytes) cx = (fTotBytes+0.00001)/fZipBytes;
2289 if (titleLength) snprintf(bline,aLength,"*Br%5d :%-9s : %-54s *",fgCount,GetName(),titleContent.Data());
2290 else snprintf(bline,aLength,"*Br%5d :%-9s : %-54s *",fgCount,GetName()," ");
2291 if (strlen(bline) > UInt_t(kLINEND)) {
2292 char *tmp = new char[strlen(bline)+1];
2293 if (titleLength) strlcpy(tmp, titleContent.Data(),strlen(bline)+1);
2294 snprintf(bline,aLength,"*Br%5d :%-9s : ",fgCount,GetName());
2295 int pos = strlen (bline);
2296 int npos = pos;
2297 int beg=0, end;
2298 while (beg < titleLength) {
2299 for (end=beg+1; end < titleLength-1; end ++)
2300 if (tmp[end] == ':') break;
2301 if (npos + end-beg+1 >= 78) {
2302 while (npos < kLINEND) {
2303 bline[pos ++] = ' ';
2304 npos ++;
2305 }
2306 bline[pos ++] = '*';
2307 bline[pos ++] = '\n';
2308 bline[pos ++] = '*';
2309 npos = 1;
2310 for (; npos < 12; npos ++)
2311 bline[pos ++] = ' ';
2312 bline[pos-2] = '|';
2313 }
2314 for (int n = beg; n <= end; n ++)
2315 bline[pos+n-beg] = tmp[n];
2316 pos += end-beg+1;
2317 npos += end-beg+1;
2318 beg = end+1;
2319 }
2320 while (npos < kLINEND) {
2321 bline[pos ++] = ' ';
2322 npos ++;
2323 }
2324 bline[pos ++] = '*';
2325 bline[pos] = '\0';
2326 delete[] tmp;
2327 }
2328 Printf("%s", bline);
2329
2330 if (fTotBytes > 2000000000) {
2331 Printf("*Entries :%lld : Total Size=%11lld bytes File Size = %lld *",fEntries,totBytes,fZipBytes);
2332 } else {
2333 if (fZipBytes > 0) {
2334 Printf("*Entries :%9lld : Total Size=%11lld bytes File Size = %10lld *",fEntries,totBytes,fZipBytes);
2335 } else {
2336 if (fWriteBasket > 0) {
2337 Printf("*Entries :%9lld : Total Size=%11lld bytes All baskets in memory *",fEntries,totBytes);
2338 } else {
2339 Printf("*Entries :%9lld : Total Size=%11lld bytes One basket in memory *",fEntries,totBytes);
2340 }
2341 }
2342 }
2343 Printf("*Baskets :%9d : Basket Size=%11d bytes Compression= %6.2f *",fWriteBasket,fBasketSize,cx);
2344
2345 if (strncmp(option,"basketsInfo",strlen("basketsInfo"))==0) {
2346 Int_t nbaskets = fWriteBasket;
2347 for (Int_t i=0;i<nbaskets;i++) {
2348 Printf("*Basket #%4d entry=%6lld pos=%6lld size=%5d",
2349 i, fBasketEntry[i], fBasketSeek[i], fBasketBytes[i]);
2350 }
2351 }
2352
2353 Printf("*............................................................................*");
2354 delete [] bline;
2355 fgCount++;
2356}
2357
2358////////////////////////////////////////////////////////////////////////////////
2359/// Print the information we have about which basket is currently cached and
2360/// whether they have been 'used'/'read' from the cache.
2361
2363{
2365}
2366
2367////////////////////////////////////////////////////////////////////////////////
2368/// Loop on all leaves of this branch to read Basket buffer.
2369
2371{
2372 // fLeaves->ReadBasket(basket);
2373}
2374
2375////////////////////////////////////////////////////////////////////////////////
2376/// Loop on all leaves of this branch to read Basket buffer.
2377
2379{
2380 for (Int_t i = 0; i < fNleaves; ++i) {
2381 TLeaf* leaf = (TLeaf*) fLeaves.UncheckedAt(i);
2382 leaf->ReadBasket(b);
2383 }
2384}
2385
2386////////////////////////////////////////////////////////////////////////////////
2387/// Read zero leaves without the overhead of a loop.
2388
2390{
2391}
2392
2393////////////////////////////////////////////////////////////////////////////////
2394/// Read one leaf without the overhead of a loop.
2395
2397{
2399}
2400
2401////////////////////////////////////////////////////////////////////////////////
2402/// Read two leaves without the overhead of a loop.
2403
2405{
2408}
2409
2410////////////////////////////////////////////////////////////////////////////////
2411/// Loop on all leaves of this branch to fill Basket buffer.
2412
2414{
2415 for (Int_t i = 0; i < fNleaves; ++i) {
2416 TLeaf* leaf = (TLeaf*) fLeaves.UncheckedAt(i);
2417 leaf->FillBasket(b);
2418 }
2419}
2420
2421////////////////////////////////////////////////////////////////////////////////
2422/// Refresh this branch using new information in b
2423/// This function is called by TTree::Refresh
2424
2426{
2427 if (b==0) return;
2428
2429 fEntryOffsetLen = b->fEntryOffsetLen;
2430 fWriteBasket = b->fWriteBasket;
2431 fEntryNumber = b->fEntryNumber;
2432 fMaxBaskets = b->fMaxBaskets;
2433 fEntries = b->fEntries;
2434 fTotBytes = b->fTotBytes;
2435 fZipBytes = b->fZipBytes;
2436 fReadBasket = 0;
2437 fReadEntry = -1;
2438 fFirstBasketEntry = -1;
2439 fNextBasketEntry = -1;
2440 fCurrentBasket = 0;
2441 delete [] fBasketBytes;
2442 delete [] fBasketEntry;
2443 delete [] fBasketSeek;
2447 Int_t i;
2448 for (i=0;i<fMaxBaskets;i++) {
2449 fBasketBytes[i] = b->fBasketBytes[i];
2450 fBasketEntry[i] = b->fBasketEntry[i];
2451 fBasketSeek[i] = b->fBasketSeek[i];
2452 }
2453 fBaskets.Delete();
2454 Int_t nbaskets = b->fBaskets.GetSize();
2455 fBaskets.Expand(nbaskets);
2456 // If the current fWritebasket is in memory, take it (just swap)
2457 // from the Tree being read
2458 TBasket *basket = (TBasket*)b->fBaskets.UncheckedAt(fWriteBasket);
2459 fBaskets.AddAt(basket,fWriteBasket);
2460 if (basket) {
2461 fNBaskets = 1;
2462 --(b->fNBaskets);
2463 b->fBaskets.RemoveAt(fWriteBasket);
2464 basket->SetBranch(this);
2465 }
2466}
2467
2468////////////////////////////////////////////////////////////////////////////////
2469/// Reset a Branch.
2470///
2471/// - Existing buffers are deleted.
2472/// - Entries, max and min are reset.
2473
2475{
2476 fReadBasket = 0;
2477 fReadEntry = -1;
2478 fFirstBasketEntry = -1;
2479 fNextBasketEntry = -1;
2480 fCurrentBasket = 0;
2481 fWriteBasket = 0;
2482 fEntries = 0;
2483 fTotBytes = 0;
2484 fZipBytes = 0;
2485 fEntryNumber = 0;
2486
2487 if (fBasketBytes) {
2488 for (Int_t i = 0; i < fMaxBaskets; ++i) {
2489 fBasketBytes[i] = 0;
2490 }
2491 }
2492
2493 if (fBasketEntry) {
2494 for (Int_t i = 0; i < fMaxBaskets; ++i) {
2495 fBasketEntry[i] = 0;
2496 }
2497 }
2498
2499 if (fBasketSeek) {
2500 for (Int_t i = 0; i < fMaxBaskets; ++i) {
2501 fBasketSeek[i] = 0;
2502 }
2503 }
2504
2505 fBaskets.Delete();
2506 fNBaskets = 0;
2507}
2508
2509////////////////////////////////////////////////////////////////////////////////
2510/// Reset a Branch.
2511///
2512/// - Existing buffers are deleted.
2513/// - Entries, max and min are reset.
2514
2516{
2517 fReadBasket = 0;
2518 fReadEntry = -1;
2519 fFirstBasketEntry = -1;
2520 fNextBasketEntry = -1;
2521 fCurrentBasket = 0;
2522 fWriteBasket = 0;
2523 fEntries = 0;
2524 fTotBytes = 0;
2525 fZipBytes = 0;
2526 fEntryNumber = 0;
2527
2528 if (fBasketBytes) {
2529 for (Int_t i = 0; i < fMaxBaskets; ++i) {
2530 fBasketBytes[i] = 0;
2531 }
2532 }
2533
2534 if (fBasketEntry) {
2535 for (Int_t i = 0; i < fMaxBaskets; ++i) {
2536 fBasketEntry[i] = 0;
2537 }
2538 }
2539
2540 if (fBasketSeek) {
2541 for (Int_t i = 0; i < fMaxBaskets; ++i) {
2542 fBasketSeek[i] = 0;
2543 }
2544 }
2545
2546 TBasket *reusebasket = (TBasket*)fBaskets[fWriteBasket];
2547 if (reusebasket) {
2549 } else {
2550 reusebasket = (TBasket*)fBaskets[fReadBasket];
2551 if (reusebasket) {
2552 fBaskets[fReadBasket] = 0;
2553 }
2554 }
2555 fBaskets.Delete();
2556 if (reusebasket) {
2557 fNBaskets = 1;
2558 reusebasket->WriteReset();
2559 fBaskets[0] = reusebasket;
2560 } else {
2561 fNBaskets = 0;
2562 }
2563}
2564
2565////////////////////////////////////////////////////////////////////////////////
2566/// Reset the address of the branch.
2567
2569{
2570 fAddress = 0;
2571
2572 // Reset last read entry number, we have will had new user object now.
2573 fReadEntry = -1;
2574
2575 for (Int_t i = 0; i < fNleaves; ++i) {
2576 TLeaf* leaf = (TLeaf*) fLeaves.UncheckedAt(i);
2577 leaf->SetAddress(0);
2578 }
2579
2580 Int_t nbranches = fBranches.GetEntriesFast();
2581 for (Int_t i = 0; i < nbranches; ++i) {
2582 TBranch* abranch = (TBranch*) fBranches[i];
2583 // FIXME: This is a tail recursion.
2584 abranch->ResetAddress();
2585 }
2586}
2587
2588////////////////////////////////////////////////////////////////////////////////
2589/// Static function resetting fgCount
2590
2592{
2593 fgCount = 0;
2594}
2595
2596////////////////////////////////////////////////////////////////////////////////
2597/// Set address of this branch.
2598
2599void TBranch::SetAddress(void* addr)
2600{
2601 if (TestBit(kDoNotProcess)) {
2602 return;
2603 }
2604 fReadEntry = -1;
2605 fFirstBasketEntry = -1;
2606 fNextBasketEntry = -1;
2607 fAddress = (char*) addr;
2608 for (Int_t i = 0; i < fNleaves; ++i) {
2609 TLeaf* leaf = (TLeaf*) fLeaves.UncheckedAt(i);
2610 Int_t offset = leaf->GetOffset();
2611 if (TestBit(kIsClone)) {
2612 offset = 0;
2613 }
2614 if (fAddress) leaf->SetAddress(fAddress + offset);
2615 else leaf->SetAddress(0);
2616 }
2617}
2618
2619////////////////////////////////////////////////////////////////////////////////
2620/// Set the automatic delete bit.
2621///
2622/// This bit is used by TBranchObject::ReadBasket to decide if an object
2623/// referenced by a TBranchObject must be deleted or not before reading
2624/// a new entry.
2625///
2626/// If autodel is kTRUE, this existing object will be deleted, a new object
2627/// created by the default constructor, then read from disk by the streamer.
2628///
2629/// If autodel is kFALSE, the existing object is not deleted. Root assumes
2630/// that the user is taking care of deleting any internal object or array
2631/// (this can be done in the streamer).
2632
2634{
2635 if (autodel) {
2636 SetBit(kAutoDelete, 1);
2637 } else {
2638 SetBit(kAutoDelete, 0);
2639 }
2640}
2641
2642////////////////////////////////////////////////////////////////////////////////
2643/// Set the basket size
2644/// The function makes sure that the basket size is greater than fEntryOffsetlen
2645
2647{
2648 Int_t minsize = 100 + fName.Length();
2649 if (buffsize < minsize+fEntryOffsetLen) buffsize = minsize+fEntryOffsetLen;
2650 fBasketSize = buffsize;
2651 TBasket *basket = (TBasket*)fBaskets[fWriteBasket];
2652 if (basket) {
2653 basket->AdjustSize(fBasketSize);
2654 }
2655}
2656
2657////////////////////////////////////////////////////////////////////////////////
2658/// Set address of this branch directly from a TBuffer to avoid streaming.
2659///
2660/// Note: We do not take ownership of the buffer.
2661
2663{
2664 // Check this is possible
2665 if ( (fNleaves != 1)
2666 || (strcmp("TLeafObject",fLeaves.UncheckedAt(0)->ClassName())!=0) ) {
2667 Error("TBranch::SetAddress","Filling from a TBuffer can only be done with a not split object branch. Request ignored.");
2668 } else {
2669 fReadEntry = -1;
2670 fNextBasketEntry = -1;
2671 fFirstBasketEntry = -1;
2672 // Note: We do not take ownership of the buffer.
2673 fEntryBuffer = buf;
2674 }
2675}
2676
2677////////////////////////////////////////////////////////////////////////////////
2678/// Set compression algorithm.
2679
2681{
2682 if (algorithm < 0 || algorithm >= ROOT::RCompressionSetting::EAlgorithm::kUndefined) algorithm = 0;
2683 if (fCompress < 0) {
2685 } else {
2686 int level = fCompress % 100;
2687 fCompress = 100 * algorithm + level;
2688 }
2689
2691 for (Int_t i=0;i<nb;i++) {
2692 TBranch *branch = (TBranch*)fBranches.UncheckedAt(i);
2693 branch->SetCompressionAlgorithm(algorithm);
2694 }
2695}
2696
2697////////////////////////////////////////////////////////////////////////////////
2698/// Set compression level.
2699
2701{
2702 if (level < 0) level = 0;
2703 if (level > 99) level = 99;
2704 if (fCompress < 0) {
2705 fCompress = level;
2706 } else {
2707 int algorithm = fCompress / 100;
2708 if (algorithm >= ROOT::RCompressionSetting::EAlgorithm::kUndefined) algorithm = 0;
2709 fCompress = 100 * algorithm + level;
2710 }
2711
2713 for (Int_t i=0;i<nb;i++) {
2714 TBranch *branch = (TBranch*)fBranches.UncheckedAt(i);
2715 branch->SetCompressionLevel(level);
2716 }
2717}
2718
2719////////////////////////////////////////////////////////////////////////////////
2720/// Set compression settings.
2721
2723{
2724 fCompress = settings;
2725
2727 for (Int_t i=0;i<nb;i++) {
2728 TBranch *branch = (TBranch*)fBranches.UncheckedAt(i);
2729 branch->SetCompressionSettings(settings);
2730 }
2731}
2732
2733////////////////////////////////////////////////////////////////////////////////
2734/// Update the default value for the branch's fEntryOffsetLen if and only if
2735/// it was already non zero (and the new value is not zero)
2736/// If updateExisting is true, also update all the existing branches.
2737
2738void TBranch::SetEntryOffsetLen(Int_t newdefault, Bool_t updateExisting)
2739{
2740 if (fEntryOffsetLen && newdefault) {
2741 fEntryOffsetLen = newdefault;
2742 }
2743 if (updateExisting) {
2744 TIter next( GetListOfBranches() );
2745 TBranch *b;
2746 while ( ( b = (TBranch*)next() ) ) {
2747 b->SetEntryOffsetLen( newdefault, kTRUE );
2748 }
2749 }
2750}
2751
2752////////////////////////////////////////////////////////////////////////////////
2753/// Set the number of entries in this branch.
2754
2756{
2757 fEntries = entries;
2758 fEntryNumber = entries;
2759}
2760
2761////////////////////////////////////////////////////////////////////////////////
2762/// Set file where this branch writes/reads its buffers.
2763/// By default the branch buffers reside in the file where the
2764/// Tree was created.
2765/// If the file name where the tree was created is an absolute
2766/// path name or an URL (e.g. or root://host/...)
2767/// and if the fname is not an absolute path name or an URL then
2768/// the path of the tree file is prepended to fname to make the
2769/// branch file relative to the tree file. In this case one can
2770/// move the tree + all branch files to a different location in
2771/// the file system and still access the branch files.
2772/// The ROOT file will be connected only when necessary.
2773/// If called by TBranch::Fill (via TBasket::WriteFile), the file
2774/// will be created with the option "recreate".
2775/// If called by TBranch::GetEntry (via TBranch::GetBasket), the file
2776/// will be opened in read mode.
2777/// To open a file in "update" mode or with a certain compression
2778/// level, use TBranch::SetFile(TFile *file).
2779
2781{
2782 if (file == 0) file = fTree->GetCurrentFile();
2784 if (file == fTree->GetCurrentFile()) fFileName = "";
2785 else fFileName = file->GetName();
2786
2787 if (file && fCompress == -1) {
2788 fCompress = file->GetCompressionLevel();
2789 }
2790
2791 // Apply to all existing baskets.
2792 TIter nextb(GetListOfBaskets());
2793 TBasket *basket;
2794 while ((basket = (TBasket*)nextb())) {
2795 basket->SetParent(file);
2796 }
2797
2798 // Apply to sub-branches as well.
2799 TIter next(GetListOfBranches());
2800 TBranch *branch;
2801 while ((branch = (TBranch*)next())) {
2802 branch->SetFile(file);
2803 }
2804}
2805
2806////////////////////////////////////////////////////////////////////////////////
2807/// Set file where this branch writes/reads its buffers.
2808/// By default the branch buffers reside in the file where the
2809/// Tree was created.
2810/// If the file name where the tree was created is an absolute
2811/// path name or an URL (e.g. root://host/...)
2812/// and if the fname is not an absolute path name or an URL then
2813/// the path of the tree file is prepended to fname to make the
2814/// branch file relative to the tree file. In this case one can
2815/// move the tree + all branch files to a different location in
2816/// the file system and still access the branch files.
2817/// The ROOT file will be connected only when necessary.
2818/// If called by TBranch::Fill (via TBasket::WriteFile), the file
2819/// will be created with the option "recreate".
2820/// If called by TBranch::GetEntry (via TBranch::GetBasket), the file
2821/// will be opened in read mode.
2822/// To open a file in "update" mode or with a certain compression
2823/// level, use TBranch::SetFile(TFile *file).
2824
2825void TBranch::SetFile(const char* fname)
2826{
2827 fFileName = fname;
2828 fDirectory = 0;
2829
2830 //apply to sub-branches as well
2831 TIter next(GetListOfBranches());
2832 TBranch *branch;
2833 while ((branch = (TBranch*)next())) {
2834 branch->SetFile(fname);
2835 }
2836}
2837
2838////////////////////////////////////////////////////////////////////////////////
2839/// Set the branch in a mode where the object are decomposed
2840/// (Also known as MakeClass mode).
2841/// Return whether the setting was possible (it is not possible for
2842/// TBranch and TBranchObject).
2843
2845{
2846 // Regular TBranch and TBrancObject can not be in makeClass mode
2847 return kFALSE;
2848}
2849
2850////////////////////////////////////////////////////////////////////////////////
2851/// Set object this branch is pointing to.
2852
2853void TBranch::SetObject(void * /* obj */)
2854{
2855 if (TestBit(kDoNotProcess)) {
2856 return;
2857 }
2858 Warning("SetObject","is not supported in TBranch objects");
2859}
2860
2861////////////////////////////////////////////////////////////////////////////////
2862/// Set branch status to Process or DoNotProcess.
2863
2865{
2866 if (status) ResetBit(kDoNotProcess);
2867 else SetBit(kDoNotProcess);
2868}
2869
2870////////////////////////////////////////////////////////////////////////////////
2871/// Stream a class object
2872
2873void TBranch::Streamer(TBuffer& b)
2874{
2875 if (b.IsReading()) {
2876 UInt_t R__s, R__c;
2877 fTree = 0; // Will be set by TTree::Streamer
2878 fAddress = 0;
2879 gROOT->SetReadingObject(kTRUE);
2880
2881 // Reset transients.
2883 fCurrentBasket = 0;
2884 fFirstBasketEntry = -1;
2885 fNextBasketEntry = -1;
2886
2887 Version_t v = b.ReadVersion(&R__s, &R__c);
2888 if (v > 9) {
2889 b.ReadClassBuffer(TBranch::Class(), this, v, R__s, R__c);
2890
2891 if (fWriteBasket>=fBaskets.GetSize()) {
2893 }
2894 fDirectory = 0;
2896 for (Int_t i=0;i<fNleaves;i++) {
2897 TLeaf *leaf = (TLeaf*)fLeaves.UncheckedAt(i);
2898 leaf->SetBranch(this);
2899 }
2900 auto nbranches = fBranches.GetEntriesFast();
2901 for (Int_t i=0;i<nbranches;i++) {
2903 br->fParent = this;
2904 }
2905
2906 fNBaskets = 0;
2907 for (Int_t j = fWriteBasket; j>=0; --j) {
2909 if (bk) {
2910 bk->SetBranch(this);
2911 // GetTree()->IncrementTotalBuffers(bk->GetBufferSize());
2912 ++fNBaskets;
2913 }
2914 }
2915 if (fWriteBasket >= fMaxBaskets) {
2916 //old versions may need this fix
2921
2922 }
2924 gROOT->SetReadingObject(kFALSE);
2925 if (IsA() == TBranch::Class()) {
2926 if (fNleaves == 0) {
2928 } else if (fNleaves == 1) {
2930 } else if (fNleaves == 2) {
2932 } else {
2934 }
2935 }
2936 return;
2937 }
2938 //====process old versions before automatic schema evolution
2939 Int_t n,i,j,ijunk;
2940 if (v > 5) {
2941 Stat_t djunk;
2942 TNamed::Streamer(b);
2943 if (v > 7) TAttFill::Streamer(b);
2944 b >> fCompress;
2945 b >> fBasketSize;
2946 b >> fEntryOffsetLen;
2947 b >> fWriteBasket;
2948 b >> ijunk; fEntryNumber = (Long64_t)ijunk;
2949 b >> fOffset;
2950 b >> fMaxBaskets;
2951 if (v > 6) b >> fSplitLevel;
2952 b >> djunk; fEntries = (Long64_t)djunk;
2953 b >> djunk; fTotBytes = (Long64_t)djunk;
2954 b >> djunk; fZipBytes = (Long64_t)djunk;
2955
2956 fBranches.Streamer(b);
2957 fLeaves.Streamer(b);
2958 fBaskets.Streamer(b);
2962 Char_t isArray;
2963 b >> isArray;
2964 b.ReadFastArray(fBasketBytes,fMaxBaskets);
2965 b >> isArray;
2966 for (i=0;i<fMaxBaskets;i++) {b >> ijunk; fBasketEntry[i] = ijunk;}
2967 b >> isArray;
2968 for (i=0;i<fMaxBaskets;i++) {
2969 if (isArray == 2) b >> fBasketSeek[i];
2970 else {Int_t bsize; b >> bsize; fBasketSeek[i] = (Long64_t)bsize;};
2971 }
2972 fFileName.Streamer(b);
2973 b.CheckByteCount(R__s, R__c, TBranch::IsA());
2974 fDirectory = 0;
2976 for (i=0;i<fNleaves;i++) {
2977 TLeaf *leaf = (TLeaf*)fLeaves.UncheckedAt(i);
2978 leaf->SetBranch(this);
2979 }
2980 fNBaskets = 0;
2981 for (j = fWriteBasket; j >= 0; --j) {
2983 if (bk) {
2984 bk->SetBranch(this);
2985 //GetTree()->IncrementTotalBuffers(bk->GetBufferSize());
2986 ++fNBaskets;
2987 }
2988 }
2989 if (fWriteBasket >= fMaxBaskets) {
2990 //old versions may need this fix
2995
2996 }
2997 // Check Byte Count is not needed since it was done in ReadBuffer
2999 gROOT->SetReadingObject(kFALSE);
3000 b.CheckByteCount(R__s, R__c, TBranch::IsA());
3001 if (IsA() == TBranch::Class()) {
3002 if (fNleaves == 0) {
3004 } else if (fNleaves == 1) {
3006 } else if (fNleaves == 2) {
3008 } else {
3010 }
3011 }
3012 return;
3013 }
3014 //====process very old versions
3015 Stat_t djunk;
3016 TNamed::Streamer(b);
3017 b >> fCompress;
3018 b >> fBasketSize;
3019 b >> fEntryOffsetLen;
3020 b >> fMaxBaskets;
3021 b >> fWriteBasket;
3022 b >> ijunk; fEntryNumber = (Long64_t)ijunk;
3023 b >> djunk; fEntries = (Long64_t)djunk;
3024 b >> djunk; fTotBytes = (Long64_t)djunk;
3025 b >> djunk; fZipBytes = (Long64_t)djunk;
3026 b >> fOffset;
3027 fBranches.Streamer(b);
3028 fLeaves.Streamer(b);
3030 for (i=0;i<fNleaves;i++) {
3031 TLeaf *leaf = (TLeaf*)fLeaves.UncheckedAt(i);
3032 leaf->SetBranch(this);
3033 }
3034 fBaskets.Streamer(b);
3035 for (j = fWriteBasket; j > 0; --j) {
3037 if (bk) {
3038 bk->SetBranch(this);
3039 //GetTree()->IncrementTotalBuffers(bk->GetBufferSize());
3040 }
3041 }
3043 b >> n;
3044 for (i=0;i<n;i++) {b >> ijunk; fBasketEntry[i] = ijunk;}
3046 if (v > 4) {
3047 n = b.ReadArray(fBasketBytes);
3048 } else {
3049 for (n=0;n<fMaxBaskets;n++) fBasketBytes[n] = 0;
3050 }
3051 if (v < 2) {
3053 for (n=0;n<fWriteBasket;n++) {
3054 TBasket *basket = GetBasketImpl(n, nullptr);
3055 fBasketSeek[n] = basket ? basket->GetSeekKey() : 0;
3056 }
3057 } else {
3059 b >> n;
3060 for (n=0;n<fMaxBaskets;n++) {
3061 Int_t aseek;
3062 b >> aseek;
3063 fBasketSeek[n] = Long64_t(aseek);
3064 }
3065 }
3066 if (v > 2) {
3067 fFileName.Streamer(b);
3068 }
3069 fDirectory = 0;
3070 if (v < 4) SetAutoDelete(kTRUE);
3072 gROOT->SetReadingObject(kFALSE);
3073 b.CheckByteCount(R__s, R__c, TBranch::IsA());
3074 //====end of old versions
3075 if (IsA() == TBranch::Class()) {
3076 if (fNleaves == 0) {
3078 } else if (fNleaves == 1) {
3080 } else if (fNleaves == 2) {
3082 } else {
3084 }
3085 }
3086 } else {
3087 Int_t maxBaskets = fMaxBaskets;
3089 Int_t lastBasket = fMaxBaskets;
3090 if (fMaxBaskets < 10) fMaxBaskets = 10;
3091
3092 TBasket **stash = new TBasket *[lastBasket];
3093 for (Int_t i = 0; i < lastBasket; ++i) {
3094 TBasket *ba = (TBasket *)fBaskets.UncheckedAt(i);
3095 if (ba && (fBasketBytes[i] || ba->GetNevBuf()==0)) {
3096 // Already on disk or empty.
3097 stash[i] = ba;
3098 fBaskets[i] = nullptr;
3099 } else {
3100 stash[i] = nullptr;
3101 }
3102 }
3103
3104 b.WriteClassBuffer(TBranch::Class(), this);
3105
3106 for (Int_t i = 0; i < lastBasket; ++i) {
3107 if (stash[i]) fBaskets[i] = stash[i];
3108 }
3109
3110 delete[] stash;
3111 fMaxBaskets = maxBaskets;
3112 }
3113}
3114
3115////////////////////////////////////////////////////////////////////////////////
3116/// Write the current basket to disk and return the number of bytes
3117/// written to the file.
3118
3120{
3121 Int_t nevbuf = basket->GetNevBuf();
3122 if (fEntryOffsetLen > 10 && (4*nevbuf) < fEntryOffsetLen ) {
3123 // Make sure that the fEntryOffset array does not stay large unnecessarily.
3124 fEntryOffsetLen = nevbuf < 3 ? 10 : 4*nevbuf; // assume some fluctuations.
3125 } else if (fEntryOffsetLen && nevbuf > fEntryOffsetLen) {
3126 // Increase the array ...
3127 fEntryOffsetLen = 2*nevbuf; // assume some fluctuations.
3128 }
3129
3130 // Note: captures `basket`, `where`, and `this` by value; modifies the TBranch and basket,
3131 // as we make a copy of the pointer. We cannot capture `basket` by reference as the pointer
3132 // itself might be modified after `WriteBasketImpl` exits.
3133 auto doUpdates = [=]() {
3134 Int_t nout = basket->WriteBuffer(); // Write buffer
3135 if (nout < 0)
3136 Error("WriteBasketImpl", "basket's WriteBuffer failed.");
3137 fBasketBytes[where] = basket->GetNbytes();
3138 fBasketSeek[where] = basket->GetSeekKey();
3139 Int_t addbytes = basket->GetObjlen() + basket->GetKeylen();
3140 TBasket *reusebasket = 0;
3141 if (nout>0) {
3142 // The Basket was written so we can now safely reuse it.
3143 fBaskets[where] = 0;
3144
3145 reusebasket = basket;
3146 reusebasket->WriteReset();
3147
3148 fZipBytes += nout;
3149 fTotBytes += addbytes;
3150 fTree->AddTotBytes(addbytes);
3151 fTree->AddZipBytes(nout);
3152#ifdef R__TRACK_BASKET_ALLOC_TIME
3153 fTree->AddAllocationTime(reusebasket->GetResetAllocationTime());
3154#endif
3156 }
3157
3158 if (where==fWriteBasket) {
3159 ++fWriteBasket;
3160 if (fWriteBasket >= fMaxBaskets) {
3162 }
3163 if (reusebasket && reusebasket == fCurrentBasket) {
3164 // The 'current' basket has Reset, so if we need it we will need
3165 // to reload it.
3166 fCurrentBasket = 0;
3167 fFirstBasketEntry = -1;
3168 fNextBasketEntry = -1;
3169 }
3172 } else {
3173 --fNBaskets;
3174 fBaskets[where] = 0;
3175 basket->DropBuffers();
3176 if (basket == fCurrentBasket) {
3177 fCurrentBasket = 0;
3178 fFirstBasketEntry = -1;
3179 fNextBasketEntry = -1;
3180 }
3181 delete basket;
3182 }
3183 return nout;
3184 };
3185 if (imtHelper) {
3186 imtHelper->Run(doUpdates);
3187 return 0;
3188 } else {
3189 return doUpdates();
3190 }
3191}
3192
3193////////////////////////////////////////////////////////////////////////////////
3194///set the first entry number (case of TBranchSTL)
3195
3197{
3198 fFirstEntry = entry;
3199 fEntries = 0;
3200 fEntryNumber = entry;
3201 if( fBasketEntry )
3202 fBasketEntry[0] = entry;
3203 for( Int_t i = 0; i < fBranches.GetEntriesFast(); ++i )
3204 ((TBranch*)fBranches[i])->SetFirstEntry( entry );
3205}
3206
3207////////////////////////////////////////////////////////////////////////////////
3208/// If the branch address is not set, we set all addresses starting with
3209/// the top level parent branch.
3210
3212{
3213 SetAddress(nullptr); // in some cases, this triggers setting of the address
3214}
3215
3216////////////////////////////////////////////////////////////////////////////////
3217/// Refresh the value of fDirectory (i.e. where this branch writes/reads its buffers)
3218/// with the current value of fTree->GetCurrentFile unless this branch has been
3219/// redirected to a different file. Also update the sub-branches.
3220
3222{
3224 if (fFileName.Length() == 0) {
3225 fDirectory = file;
3226
3227 // Apply to all existing baskets.
3228 TIter nextb(GetListOfBaskets());
3229 TBasket *basket;
3230 while ((basket = (TBasket*)nextb())) {
3231 basket->SetParent(file);
3232 }
3233 }
3234
3235 // Apply to sub-branches as well.
3236 TIter next(GetListOfBranches());
3237 TBranch *branch;
3238 while ((branch = (TBranch*)next())) {
3239 branch->UpdateFile();
3240 }
3241}
void tobuf(char *&buf, Bool_t x)
Definition: Bytes.h:55
void Class()
Definition: Class.C:29
#define R__likely(expr)
Definition: RConfig.hxx:598
#define R__unlikely(expr)
Definition: RConfig.hxx:597
#define b(i)
Definition: RSha256.hxx:100
size_t size(const MatrixT &matrix)
retrieve the size of a square matrix
const Ssiz_t kNPOS
Definition: RtypesCore.h:124
int Int_t
Definition: RtypesCore.h:45
short Version_t
Definition: RtypesCore.h:65
int Ssiz_t
Definition: RtypesCore.h:67
char Char_t
Definition: RtypesCore.h:33
unsigned int UInt_t
Definition: RtypesCore.h:46
const Bool_t kFALSE
Definition: RtypesCore.h:101
bool Bool_t
Definition: RtypesCore.h:63
double Stat_t
Definition: RtypesCore.h:86
long long Long64_t
Definition: RtypesCore.h:80
float Float_t
Definition: RtypesCore.h:57
const Bool_t kTRUE
Definition: RtypesCore.h:100
const char Option_t
Definition: RtypesCore.h:66
#define ClassImp(name)
Definition: Rtypes.h:364
const UInt_t kNewClassTag
Definition: TBufferFile.cxx:48
const UInt_t kByteCountMask
Definition: TBufferFile.cxx:50
EDataType
Definition: TDataType.h:28
@ kOther_t
Definition: TDataType.h:32
#define R__ASSERT(e)
Definition: TError.h:118
#define N
char name[80]
Definition: TGX11.cxx:110
int nentries
Definition: THbookFile.cxx:91
R__EXTERN TVirtualMutex * gROOTMutex
Definition: TROOT.h:61
#define gROOT
Definition: TROOT.h:404
void Printf(const char *fmt,...)
R__EXTERN TSystem * gSystem
Definition: TSystem.h:559
#define R__LOCKGUARD_IMT(mutex)
#define R__LOCKGUARD(mutex)
#define gPad
Definition: TVirtualPad.h:287
#define snprintf
Definition: civetweb.c:1540
void SetUsed(Int_t basketNumber)
Mark if the basket has been marked as 'used'.
void Print(const char *owner, Long64_t *entries) const
Print the info we have for the baskets.
A helper class for managing IMT work during TTree:Fill operations.
TIOFeatures provides the end-user with the ability to change the IO behavior of data written via a TT...
Definition: TIOFeatures.hxx:69
Fill Area Attributes class.
Definition: TAttFill.h:19
Manages buffers for branches of a Tree.
Definition: TBasket.h:34
void AdoptBuffer(TBuffer *user_buffer)
Adopt a buffer from an external entity.
Definition: TBasket.cxx:721
Int_t GetNevBufSize() const
Definition: TBasket.h:130
Int_t * GetEntryOffset()
Definition: TBasket.h:124
Int_t * GetDisplacement() const
Definition: TBasket.h:123
Int_t GetNevBuf() const
Definition: TBasket.h:129
void DisownBuffer()
Disown all references to the internal buffer - some other object likely now owns it.
Definition: TBasket.cxx:713
void SetBranch(TBranch *branch)
Definition: TBasket.h:148
Int_t ReadBasketBuffers(Long64_t pos, Int_t len, TFile *file)
Read basket buffers in memory and cleanup.
Definition: TBasket.cxx:464
virtual Int_t DropBuffers()
Drop buffers of this basket if it is not the current basket.
Definition: TBasket.cxx:173
virtual void PrepareBasket(Long64_t)
Definition: TBasket.h:133
virtual void MoveEntries(Int_t dentries)
Remove the first dentries of this basket, moving entries at dentries to the start of the buffer.
Definition: TBasket.cxx:310
void SetNevBufSize(Int_t n)
Definition: TBasket.h:149
Int_t GetBufferSize() const
Definition: TBasket.h:122
virtual void AdjustSize(Int_t newsize)
Increase the size of the current fBuffer up to newsize.
Definition: TBasket.cxx:127
virtual void SetReadMode()
Set read mode of basket.
Definition: TBasket.cxx:925
virtual void SetWriteMode()
Set write mode of basket.
Definition: TBasket.cxx:934
Bool_t GetResetAllocationCount() const
Definition: TBasket.h:143
Int_t ReadBasketBytes(Long64_t pos, TFile *file)
Read basket buffers in memory and cleanup.
Definition: TBasket.cxx:698
virtual void ReadResetBuffer(Int_t basketnumber)
Reset the read basket TBuffer memory allocation if needed.
Definition: TBasket.cxx:733
virtual Int_t WriteBuffer()
Write buffer of this basket on the current file.
Definition: TBasket.cxx:1131
Int_t GetLast() const
Definition: TBasket.h:131
void Update(Int_t newlast)
Definition: TBasket.h:152
virtual void WriteReset()
Reset the write basket to the starting state.
Definition: TBasket.cxx:806
A TTree is a list of TBranches.
Definition: TBranch.h:89
virtual TLeaf * GetLeaf(const char *name) const
Return pointer to the 1st Leaf named name in thisBranch.
Definition: TBranch.cxx:1972
virtual void SetupAddresses()
If the branch address is not set, we set all addresses starting with the top level parent branch.
Definition: TBranch.cxx:3211
virtual void ResetAddress()
Reset the address of the branch.
Definition: TBranch.cxx:2568
virtual void SetAutoDelete(Bool_t autodel=kTRUE)
Set the automatic delete bit.
Definition: TBranch.cxx:2633
TString fFileName
Name of file where buffers are stored ("" if in same file as Tree header)
Definition: TBranch.h:145
virtual const char * GetClassName() const
Return the name of the user class whose content is stored in this branch, if any.
Definition: TBranch.cxx:1322
const char * GetIconName() const
Return icon name depending on type of branch.
Definition: TBranch.cxx:1330
TBasket * GetFreshBasket(Int_t basketnumber, TBuffer *user_buffer)
Return a fresh basket by either reusing an existing basket that needs to be drop (according to TTree:...
Definition: TBranch.cxx:1832
TBasket * GetBasketImpl(Int_t basket, TBuffer *user_buffer)
Return pointer to basket basketnumber in this Branch.
Definition: TBranch.cxx:1224
Int_t fEntryOffsetLen
Initial Length of fEntryOffset table in the basket buffers.
Definition: TBranch.h:115
virtual void DeleteBaskets(Option_t *option="")
Loop on all branch baskets.
Definition: TBranch.cxx:724
virtual Long64_t GetBasketSeek(Int_t basket) const
Return address of basket in the file.
Definition: TBranch.cxx:1300
TBranch()
Default constructor. Used for I/O by default.
Definition: TBranch.cxx:87
void SetCompressionSettings(Int_t settings=ROOT::RCompressionSetting::EDefaults::kUseCompiledDefault)
Set compression settings.
Definition: TBranch.cxx:2722
Int_t BackFill()
Loop on all leaves of this branch to back fill Basket buffer.
Definition: TBranch.cxx:678
Int_t fMaxBaskets
Maximum number of Baskets so far.
Definition: TBranch.h:121
Long64_t fTotBytes
Total number of bytes in all leaves before compression.
Definition: TBranch.h:132
TBuffer * fTransientBuffer
! Pointer to the current transient buffer.
Definition: TBranch.h:147
virtual void ReadBasket(TBuffer &b)
Loop on all leaves of this branch to read Basket buffer.
Definition: TBranch.cxx:2370
TTree * GetTree() const
Definition: TBranch.h:248
FillLeaves_t fFillLeaves
! Pointer to the FillLeaves implementation to use.
Definition: TBranch.h:159
virtual TString GetFullName() const
Return the 'full' name of the branch.
Definition: TBranch.cxx:1956
@ kAutoDelete
Definition: TBranch.h:106
@ kDoNotUseBufferMap
If set, at least one of the entry in the branch will use the buffer's map of classname and objects.
Definition: TBranch.h:108
@ kIsClone
To indicate a TBranchClones.
Definition: TBranch.h:102
@ kDoNotProcess
Active bit for branches.
Definition: TBranch.h:101
TObjArray fLeaves
-> List of leaves of this branch
Definition: TBranch.h:135
Int_t GetBasketAndFirst(TBasket *&basket, Long64_t &first, TBuffer *user_buffer)
A helper function to locate the correct basket - and its first entry.
Definition: TBranch.cxx:1351
char * fAddress
! Address of 1st leaf (variable or object)
Definition: TBranch.h:143
virtual void DropBaskets(Option_t *option="")
Loop on all branch baskets.
Definition: TBranch.cxx:755
TObjArray * GetListOfBranches()
Definition: TBranch.h:242
virtual TList * GetBrowsables()
Returns (and, if 0, creates) browsable objects for this branch See TVirtualBranchBrowsable::FillListO...
Definition: TBranch.cxx:1310
TList * fBrowsables
! List of TVirtualBranchBrowsables used for Browse()
Definition: TBranch.h:148
void ReadLeavesImpl(TBuffer &b)
Loop on all leaves of this branch to read Basket buffer.
Definition: TBranch.cxx:2378
Int_t fOffset
Offset of this branch.
Definition: TBranch.h:120
Long64_t * fBasketEntry
[fMaxBaskets] Table of first entry in each basket
Definition: TBranch.h:138
Int_t GetEntriesSerialized(Long64_t N, TBuffer &user_buf)
Definition: TBranch.h:181
virtual void SetEntryOffsetLen(Int_t len, Bool_t updateSubBranches=kFALSE)
Update the default value for the branch's fEntryOffsetLen if and only if it was already non zero (and...
Definition: TBranch.cxx:2738
void ExpandBasketArrays()
Increase BasketEntry buffer of a minimum of 10 locations and a maximum of 50 per cent of current size...
Definition: TBranch.cxx:823
void Init(const char *name, const char *leaflist, Int_t compress)
Definition: TBranch.cxx:300
virtual Int_t GetEntry(Long64_t entry=0, Int_t getall=0)
Read all leaves of entry and return total number of bytes read.
Definition: TBranch.cxx:1644
TIOFeatures GetIOFeatures() const
Returns the IO settings currently in use for this branch.
Definition: TBranch.cxx:2172
void FillLeavesImpl(TBuffer &b)
Loop on all leaves of this branch to fill Basket buffer.
Definition: TBranch.cxx:2413
Long64_t fReadEntry
! Current entry number when reading
Definition: TBranch.h:126
virtual void AddBasket(TBasket &b, Bool_t ondisk, Long64_t startEntry)
Add the basket to this branch.
Definition: TBranch.cxx:543
static void ResetCount()
Static function resetting fgCount.
Definition: TBranch.cxx:2591
TBranch * GetSubBranch(const TBranch *br) const
Find the parent branch of child.
Definition: TBranch.cxx:2081
ReadLeaves_t fReadLeaves
! Pointer to the ReadLeaves implementation to use.
Definition: TBranch.h:157
virtual void SetObject(void *objadd)
Set object this branch is pointing to.
Definition: TBranch.cxx:2853
Int_t FlushBaskets()
Flush to disk all the baskets of this branch and any of subbranches.
Definition: TBranch.cxx:1134
void ReadLeaves2Impl(TBuffer &b)
Read two leaves without the overhead of a loop.
Definition: TBranch.cxx:2404
TBasket * GetFreshCluster()
Drops the cluster two behind the current cluster and returns a fresh basket by either reusing or crea...
Definition: TBranch.cxx:1891
virtual void SetAddress(void *add)
Set address of this branch.
Definition: TBranch.cxx:2599
static Int_t fgCount
! branch counter
Definition: TBranch.h:112
virtual void AddLastBasket(Long64_t startEntry)
Add the start entry of the write basket (not yet created)
Definition: TBranch.cxx:616
TBasket * GetBasket(Int_t basket)
Definition: TBranch.h:209
Int_t fNBaskets
! Number of baskets in memory
Definition: TBranch.h:122
void ReadLeaves1Impl(TBuffer &b)
Read one leaf without the overhead of a loop.
Definition: TBranch.cxx:2396
Int_t GetBulkEntries(Long64_t, TBuffer &)
Read as many events as possible into the given buffer, using zero-copy mechanisms.
Definition: TBranch.cxx:1454
Bool_t IsFolder() const
Return kTRUE if more than one leaf or browsables, kFALSE otherwise.
Definition: TBranch.cxx:2188
virtual Int_t GetEntryExport(Long64_t entry, Int_t getall, TClonesArray *list, Int_t n)
Read all leaves of an entry and export buffers to real objects in a TClonesArray list.
Definition: TBranch.cxx:1700
Long64_t fZipBytes
Total number of bytes in all leaves after compression.
Definition: TBranch.h:133
TIOFeatures fIOFeatures
IO features for newly-created baskets.
Definition: TBranch.h:119
void SetCompressionAlgorithm(Int_t algorithm=ROOT::RCompressionSetting::EAlgorithm::kUseGlobal)
Set compression algorithm.
Definition: TBranch.cxx:2680
Bool_t IsAutoDelete() const
Return kTRUE if an existing object in a TBranchObject must be deleted.
Definition: TBranch.cxx:2180
virtual TLeaf * FindLeaf(const char *name)
Find the leaf corresponding to the name 'searchname'.
Definition: TBranch.cxx:1079
CacheInfo_t fCacheInfo
! Hold info about which basket are in the cache and if they have been retrieved from the cache.
Definition: TBranch.h:154
TObjArray * GetListOfBaskets()
Definition: TBranch.h:241
virtual void SetBufferAddress(TBuffer *entryBuffer)
Set address of this branch directly from a TBuffer to avoid streaming.
Definition: TBranch.cxx:2662
Long64_t GetEntries() const
Definition: TBranch.h:247
Int_t fNleaves
! Number of leaves
Definition: TBranch.h:124
Int_t fSplitLevel
Branch split level.
Definition: TBranch.h:123
Int_t WriteBasketImpl(TBasket *basket, Int_t where, ROOT::Internal::TBranchIMTHelper *)
Write the current basket to disk and return the number of bytes written to the file.
Definition: TBranch.cxx:3119
virtual void UpdateFile()
Refresh the value of fDirectory (i.e.
Definition: TBranch.cxx:3221
Int_t * fBasketBytes
[fMaxBaskets] Length of baskets on file
Definition: TBranch.h:137
virtual void Print(Option_t *option="") const
Print TBranch parameters.
Definition: TBranch.cxx:2258
Long64_t fNextBasketEntry
! Next entry that will requires us to go to the next basket
Definition: TBranch.h:128
virtual ~TBranch()
Destructor.
Definition: TBranch.cxx:450
Int_t FillEntryBuffer(TBasket *basket, TBuffer *buf, Int_t &lnew)
Copy the data from fEntryBuffer into the current basket.
Definition: TBranch.cxx:933
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:1791
virtual void Browse(TBrowser *b)
Browser interface.
Definition: TBranch.cxx:697
TObjArray fBranches
-> List of Branches of this branch
Definition: TBranch.h:134
virtual void KeepCircular(Long64_t maxEntries)
keep a maximum of fMaxEntries in memory
Definition: TBranch.cxx:2200
virtual void ResetAfterMerge(TFileMergeInfo *)
Reset a Branch.
Definition: TBranch.cxx:2515
void ReadLeaves0Impl(TBuffer &b)
Read zero leaves without the overhead of a loop.
Definition: TBranch.cxx:2389
virtual Bool_t GetMakeClass() const
Return whether this branch is in a mode where the object are decomposed or not (Also known as MakeCla...
Definition: TBranch.cxx:2034
TString GetRealFileName() const
Get real file name.
Definition: TBranch.cxx:1985
virtual TBranch * FindBranch(const char *name)
Find the immediate sub-branch with passed name.
Definition: TBranch.cxx:1033
TDirectory * fDirectory
! Pointer to directory where this branch buffers are stored
Definition: TBranch.h:144
void PrintCacheInfo() const
Print the information we have about which basket is currently cached and whether they have been 'used...
Definition: TBranch.cxx:2362
TObjArray fBaskets
-> List of baskets of this branch
Definition: TBranch.h:136
virtual Int_t LoadBaskets()
Baskets associated to this branch are forced to be in memory.
Definition: TBranch.cxx:2226
Bool_t fSkipZip
! After being read, the buffer will not be unzipped.
Definition: TBranch.h:151
TBranch * fMother
! Pointer to top-level parent branch in the tree.
Definition: TBranch.h:141
Long64_t GetTotBytes(Option_t *option="") const
Return total number of bytes in the branch (excluding current buffer) if option ="*" includes all sub...
Definition: TBranch.cxx:2137
virtual Bool_t SetMakeClass(Bool_t decomposeObj=kTRUE)
Set the branch in a mode where the object are decomposed (Also known as MakeClass mode).
Definition: TBranch.cxx:2844
virtual void SetFile(TFile *file=0)
Set file where this branch writes/reads its buffers.
Definition: TBranch.cxx:2780
TBranch * fParent
! Pointer to parent branch.
Definition: TBranch.h:142
Int_t WriteBasket(TBasket *basket, Int_t where)
Definition: TBranch.h:171
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:1180
virtual Int_t GetExpectedType(TClass *&clptr, EDataType &type)
Fill expectedClass and expectedType with information on the data type of the object/values contained ...
Definition: TBranch.cxx:1772
virtual void SetFirstEntry(Long64_t entry)
set the first entry number (case of TBranchSTL)
Definition: TBranch.cxx:3196
Long64_t GetTotalSize(Option_t *option="") const
Return total number of bytes in the branch (including current buffer)
Definition: TBranch.cxx:2118
Long64_t GetZipBytes(Option_t *option="") const
Return total number of zip bytes in the branch if option ="*" includes all sub-branches of this branc...
Definition: TBranch.cxx:2155
virtual void SetBasketSize(Int_t buffsize)
Set the basket size The function makes sure that the basket size is greater than fEntryOffsetlen.
Definition: TBranch.cxx:2646
virtual void Refresh(TBranch *b)
Refresh this branch using new information in b This function is called by TTree::Refresh.
Definition: TBranch.cxx:2425
Int_t fWriteBasket
Last basket number written.
Definition: TBranch.h:116
Long64_t * fBasketSeek
[fMaxBaskets] Addresses of baskets on file
Definition: TBranch.h:139
virtual void SetStatus(Bool_t status=1)
Set branch status to Process or DoNotProcess.
Definition: TBranch.cxx:2864
TObjArray * GetListOfLeaves()
Definition: TBranch.h:243
virtual void SetEntries(Long64_t entries)
Set the number of entries in this branch.
Definition: TBranch.cxx:2755
Int_t fReadBasket
! Current basket number when reading
Definition: TBranch.h:125
Long64_t fFirstEntry
Number of the first entry in this branch.
Definition: TBranch.h:131
TBasket * fExtraBasket
! Allocated basket not currently holding any data.
Definition: TBranch.h:118
virtual Int_t GetRow(Int_t row)
Return all elements of one row unpacked in internal array fValues [Actually just returns 1 (?...
Definition: TBranch.cxx:2025
Int_t fBasketSize
Initial Size of Basket Buffer.
Definition: TBranch.h:114
Int_t Fill()
Definition: TBranch.h:201
virtual void Reset(Option_t *option="")
Reset a Branch.
Definition: TBranch.cxx:2474
Long64_t fEntryNumber
Current entry number (last one filled in this branch)
Definition: TBranch.h:117
TBranch * GetMother() const
Get our top-level parent branch in the tree.
Definition: TBranch.cxx:2044
Int_t fCompress
Compression level and algorithm.
Definition: TBranch.h:113
TBuffer * GetTransientBuffer(Int_t size)
Returns the transient buffer currently used by this TBranch for reading/writing baskets.
Definition: TBranch.cxx:521
virtual Int_t FillImpl(ROOT::Internal::TBranchIMTHelper *)
Loop on all leaves of this branch to fill Basket buffer.
Definition: TBranch.cxx:854
TBuffer * fEntryBuffer
! Buffer used to directly pass the content without streaming
Definition: TBranch.h:146
TBasket * fCurrentBasket
! Pointer to the current basket.
Definition: TBranch.h:129
Long64_t fFirstBasketEntry
! First entry in the current basket.
Definition: TBranch.h:127
void SetCompressionLevel(Int_t level=ROOT::RCompressionSetting::ELevel::kUseMin)
Set compression level.
Definition: TBranch.cxx:2700
Long64_t fEntries
Number of entries.
Definition: TBranch.h:130
Bool_t SupportsBulkRead() const
Returns true if this branch supports bulk IO, false otherwise.
Definition: TBranch.cxx:1429
TTree * fTree
! Pointer to Tree header
Definition: TBranch.h:140
Using a TBrowser one can browse all ROOT objects.
Definition: TBrowser.h:37
The concrete implementation of TBuffer for writing/reading to/from a ROOT file or socket.
Definition: TBufferFile.h:47
@ kNotDecompressed
Definition: TBufferIO.h:66
Buffer base class used for serializing objects.
Definition: TBuffer.h:43
void SetWriteMode()
Set buffer in write mode.
Definition: TBuffer.cxx:315
char * GetCurrent() const
Definition: TBuffer.h:97
void Expand(Int_t newsize, Bool_t copy=kTRUE)
Expand (or shrink) the I/O buffer to newsize bytes.
Definition: TBuffer.cxx:223
virtual Int_t GetBufferDisplacement() const =0
Int_t BufferSize() const
Definition: TBuffer.h:98
@ kIsOwner
Definition: TBuffer.h:75
@ kWrite
Definition: TBuffer.h:73
@ kRead
Definition: TBuffer.h:73
void AutoExpand(Int_t size_needed)
Automatically calculate a new size and expand the buffer to fit at least size_needed.
Definition: TBuffer.cxx:158
void SetBuffer(void *buf, UInt_t bufsiz=0, Bool_t adopt=kTRUE, ReAllocCharFun_t reallocfunc=0)
Sets a new buffer in an existing TBuffer object.
Definition: TBuffer.cxx:187
@ kMinimalSize
Definition: TBuffer.h:78
Bool_t IsReading() const
Definition: TBuffer.h:86
virtual void ResetMap()=0
void SetBufferOffset(Int_t offset=0)
Definition: TBuffer.h:93
virtual Int_t GetMapCount() const =0
void SetReadMode()
Set buffer in read mode.
Definition: TBuffer.cxx:302
virtual void WriteBuf(const void *buf, Int_t max)=0
virtual void SetBufferDisplacement()=0
virtual char * ReadString(char *s, Int_t max)=0
Int_t Length() const
Definition: TBuffer.h:100
char * Buffer() const
Definition: TBuffer.h:96
TClass instances represent classes, structs and namespaces in the ROOT type system.
Definition: TClass.h:80
An array of clone (identical) objects.
Definition: TClonesArray.h:29
void Browse(TBrowser *b)
Browse this collection (called by TBrowser).
virtual void RemoveAll(TCollection *col)
Remove all objects in collection col from this collection.
virtual Int_t GetSize() const
Return the capacity of the collection, i.e.
Definition: TCollection.h:184
TDirectory::TContext keeps track and restore the current directory.
Definition: TDirectory.h:89
Describe directory structure in memory.
Definition: TDirectory.h:45
virtual TFile * GetFile() const
Definition: TDirectory.h:211
virtual Bool_t IsWritable() const
Definition: TDirectory.h:227
A cache when reading files over the network.
virtual void SetSkipZip(Bool_t=kTRUE)
virtual Bool_t IsLearning() const
virtual Int_t LearnBranch(TBranch *, Bool_t=kFALSE)
A ROOT file is a suite of consecutive data records (TKey instances) with a well defined format.
Definition: TFile.h:54
Int_t GetCompressionSettings() const
Definition: TFile.h:399
static TFile * Open(const char *name, Option_t *option="", const char *ftitle="", Int_t compress=ROOT::RCompressionSetting::EDefaults::kUseCompiledDefault, Int_t netopt=0)
Create / open a file.
Definition: TFile.cxx:4011
virtual Long64_t GetSeekKey() const
Definition: TKey.h:90
Int_t GetKeylen() const
Definition: TKey.h:85
Int_t GetObjlen() const
Definition: TKey.h:88
Int_t GetNbytes() const
Definition: TKey.h:87
virtual void SetParent(const TObject *parent)
Set parent in key buffer.
Definition: TKey.cxx:1294
TBuffer * GetBufferRef() const
Definition: TKey.h:80
A TLeaf for an 8 bit Integer data type.
Definition: TLeafB.h:26
A TLeaf for a variable length string.
Definition: TLeafC.h:26
A TLeaf for a 24 bit truncated floating point data type.
Definition: TLeafD32.h:28
A TLeaf for a 64 bit floating point data type.
Definition: TLeafD.h:26
A TLeaf for a 24 bit truncated floating point data type.
Definition: TLeafF16.h:27
A TLeaf for a 32 bit floating point data type.
Definition: TLeafF.h:26
A TLeaf for a 64 bit Integer data type.
Definition: TLeafG.h:27
A TLeaf for an Integer data type.
Definition: TLeafI.h:27
A TLeaf for a 64 bit Integer data type.
Definition: TLeafL.h:27
A TLeaf for a bool data type.
Definition: TLeafO.h:26
A TLeaf for a 16 bit Integer data type.
Definition: TLeafS.h:26
A TLeaf describes individual elements of a TBranch See TBranch structure in TTree.
Definition: TLeaf.h:57
virtual Int_t GetLenType() const
Definition: TLeaf.h:133
virtual const char * GetTypeName() const
Definition: TLeaf.h:139
virtual Int_t GetLen() const
Return the number of effective elements of this leaf, for the current entry.
Definition: TLeaf.cxx:404
virtual TLeaf * GetLeafCount() const
If this leaf stores a variable-sized array or a multi-dimensional array whose last dimension has vari...
Definition: TLeaf.h:121
virtual DeserializeType GetDeserializeType() const
Definition: TLeaf.h:117
virtual void ReadBasketExport(TBuffer &, TClonesArray *, Int_t)
Definition: TLeaf.h:153
virtual void SetAddress(void *add=0)
Definition: TLeaf.h:185
virtual Int_t GetNdata() const
Definition: TLeaf.h:136
virtual void FillBasket(TBuffer &b)
Pack leaf elements in Basket output buffer.
Definition: TLeaf.cxx:180
TBranch * GetBranch() const
Definition: TLeaf.h:116
virtual void SetOffset(Int_t offset=0)
Definition: TLeaf.h:164
virtual bool ReadBasketFast(TBuffer &, Long64_t)
Definition: TLeaf.h:154
virtual void SetBranch(TBranch *branch)
Definition: TLeaf.h:161
virtual void SetUnsigned()
Definition: TLeaf.h:166
virtual Int_t GetOffset() const
Definition: TLeaf.h:137
virtual void ReadBasket(TBuffer &)
Definition: TLeaf.h:152
A doubly linked list.
Definition: TList.h:44
The TNamed class is the base class for all named ROOT classes.
Definition: TNamed.h:29
TString fName
Definition: TNamed.h:32
virtual const char * GetTitle() const
Returns title of object.
Definition: TNamed.h:48
virtual const char * GetName() const
Returns name of object.
Definition: TNamed.h:47
An array of TObjects.
Definition: TObjArray.h:37
Int_t GetEntriesFast() const
Definition: TObjArray.h:64
virtual void Expand(Int_t newSize)
Expand or shrink the array to newSize elements.
Definition: TObjArray.cxx:387
virtual void AddAtAndExpand(TObject *obj, Int_t idx)
Add object at position idx.
Definition: TObjArray.cxx:235
void Add(TObject *obj)
Definition: TObjArray.h:74
Int_t GetEntries() const
Return the number of objects in array (i.e.
Definition: TObjArray.cxx:523
TObject * UncheckedAt(Int_t i) const
Definition: TObjArray.h:90
virtual void Delete(Option_t *option="")
Remove all objects from the array AND delete all heap based objects.
Definition: TObjArray.cxx:356
void SetLast(Int_t last)
Set index of last object in array, effectively truncating the array.
Definition: TObjArray.cxx:775
Int_t GetLast() const
Return index of last object in array.
Definition: TObjArray.cxx:577
Int_t LowerBound() const
Definition: TObjArray.h:97
virtual void AddAt(TObject *obj, Int_t idx)
Add object at position ids.
Definition: TObjArray.cxx:254
virtual TObject * RemoveAt(Int_t idx)
Remove object at index idx.
Definition: TObjArray.cxx:694
TObject * At(Int_t idx) const
Definition: TObjArray.h:166
R__ALWAYS_INLINE Bool_t TestBit(UInt_t f) const
Definition: TObject.h:187
virtual const char * ClassName() const
Returns name of class to which the object belongs.
Definition: TObject.cxx:130
virtual void Warning(const char *method, const char *msgfmt,...) const
Issue warning message.
Definition: TObject.cxx:879
R__ALWAYS_INLINE Bool_t IsZombie() const
Definition: TObject.h:149
void SetBit(UInt_t f, Bool_t set)
Set or unset the user status bits as specified in f.
Definition: TObject.cxx:696
virtual Bool_t InheritsFrom(const char *classname) const
Returns kTRUE if object inherits from class "classname".
Definition: TObject.cxx:445
virtual void Error(const char *method, const char *msgfmt,...) const
Issue error message.
Definition: TObject.cxx:893
virtual void Fatal(const char *method, const char *msgfmt,...) const
Issue fatal error message.
Definition: TObject.cxx:921
void MakeZombie()
Definition: TObject.h:49
void ResetBit(UInt_t f)
Definition: TObject.h:186
static void * ReAlloc(void *vp, size_t size)
Reallocate (i.e.
Definition: TStorage.cxx:183
static Int_t * ReAllocInt(Int_t *vp, size_t size, size_t oldsize)
Reallocate (i.e.
Definition: TStorage.cxx:295
Basic string class.
Definition: TString.h:136
Ssiz_t Length() const
Definition: TString.h:410
void ToLower()
Change string to lower-case.
Definition: TString.cxx:1150
void Clear()
Clear string without changing its capacity.
Definition: TString.cxx:1201
Ssiz_t First(char c) const
Find first occurrence of a character c.
Definition: TString.cxx:523
const char * Data() const
Definition: TString.h:369
TString & Prepend(const char *cs)
Definition: TString.h:661
TString & Remove(Ssiz_t pos)
Definition: TString.h:673
void Form(const char *fmt,...)
Formats a string using a printf style format descriptor.
Definition: TString.cxx:2314
Bool_t Contains(const char *pat, ECaseCompare cmp=kExact) const
Definition: TString.h:624
virtual Bool_t ExpandPathName(TString &path)
Expand a pathname getting rid of special shell characters like ~.
Definition: TSystem.cxx:1274
virtual const char * BaseName(const char *pathname)
Base name of a file name. Base name of /user/root is root.
Definition: TSystem.cxx:935
virtual Bool_t IsAbsoluteFileName(const char *dir)
Return true if dir is an absolute pathname.
Definition: TSystem.cxx:952
virtual TString GetDirName(const char *pathname)
Return the directory name in pathname.
Definition: TSystem.cxx:1032
Helper class to iterate over cluster of baskets.
Definition: TTree.h:267
Long64_t Previous()
Move on to the previous cluster and return the starting entry of this previous cluster.
Definition: TTree.cxx:692
Long64_t GetStartEntry()
Definition: TTree.h:299
Long64_t Next()
Move on to the next cluster and return the starting entry of this next cluster.
Definition: TTree.cxx:648
Long64_t GetNextEntry()
Definition: TTree.h:304
A TTree represents a columnar dataset.
Definition: TTree.h:79
virtual TVirtualPerfStats * GetPerfStats() const
Definition: TTree.h:502
virtual TClusterIterator GetClusterIterator(Long64_t firstentry)
Return an iterator over the cluster of baskets starting at firstentry.
Definition: TTree.cxx:5426
void AddAllocationCount(UInt_t count)
Definition: TTree.h:334
virtual TObjArray * GetListOfLeaves()
Definition: TTree.h:485
TFile * GetCurrentFile() const
Return pointer to the current file.
Definition: TTree.cxx:5438
virtual void IncrementTotalBuffers(Int_t nbytes)
Definition: TTree.h:542
TDirectory * GetDirectory() const
Definition: TTree.h:458
TTreeCache * GetReadCache(TFile *file) const
Find and return the TTreeCache registered with the file and which may contain branches for us.
Definition: TTree.cxx:6277
virtual TObjArray * GetListOfBranches()
Definition: TTree.h:484
virtual void AddZipBytes(Int_t zip)
Definition: TTree.h:329
virtual TBasket * CreateBasket(TBranch *)
Create a basket for this tree and given branch.
Definition: TTree.cxx:3693
@ kOnlyFlushAtCluster
If set, the branch's buffers will grow until an event cluster boundary is hit, guaranteeing a basket ...
Definition: TTree.h:253
@ kCircular
Definition: TTree.h:249
virtual void Draw(Option_t *opt)
Default Draw method for all objects.
Definition: TTree.h:428
virtual Bool_t GetClusterPrefetch() const
Definition: TTree.h:453
virtual void AddTotBytes(Int_t tot)
Definition: TTree.h:328
virtual Long64_t GetAutoFlush() const
Definition: TTree.h:443
virtual Long64_t GetMaxVirtualSize() const
Definition: TTree.h:496
This class represents a WWW compatible URL.
Definition: TUrl.h:33
const char * GetAnchor() const
Definition: TUrl.h:70
const char * GetUrl(Bool_t withDeflt=kFALSE) const
Return full URL.
Definition: TUrl.cxx:389
void SetAnchor(const char *anchor)
Definition: TUrl.h:86
static Int_t FillListOfBrowsables(TList &list, const TBranch *branch, const TVirtualBranchBrowsable *parent=nullptr)
Askes all registered generators to fill their browsables into the list.
virtual void SetUsed(TBranch *b, size_t basketNumber)=0
const Int_t n
Definition: legend1.C:16
Type GetType(const std::string &Name)
Definition: Systematics.cxx:34
static constexpr double s
Short_t Max(Short_t a, Short_t b)
Definition: TMathBase.h:212
Long64_t BinarySearch(Long64_t n, const T *array, T value)
Definition: TMathBase.h:278
Definition: file.py:1
Definition: first.py:1
Definition: tree.py:1
@ kUndefined
Undefined compression algorithm (must be kept the last of the list in case a new algorithm is added).
Definition: Compression.h:100
@ kUseMin
Compression level reserved when we are not sure what to use (1 is for the fastest compression)
Definition: Compression.h:68
auto * l
Definition: textangle.C:4