Logo ROOT  
Reference Guide
 
Loading...
Searching...
No Matches
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
51#include "TBranchIMTHelper.h"
52
53#include "ROOT/TIOFeatures.hxx"
54
55#include <atomic>
56#include <cstddef>
57#include <cstring>
58#include <cstdio>
59
60
62
63/** \class TBranch
64\ingroup tree
65
66A TTree is a list of TBranches
67
68A TBranch supports:
69 - The list of TLeaf describing this branch.
70 - The list of TBasket (branch buffers).
71
72See TBranch structure in TTree.
73
74See also specialized branches:
75 - TBranchObject in case the branch is one object
76 - TBranchClones in case the branch is an array of clone objects
77*/
78
79
80
81
82////////////////////////////////////////////////////////////////////////////////
83/// Default constructor. Used for I/O by default.
84
86: TNamed()
87, TAttFill(0, 1001)
88, fCompress(0)
89, fBasketSize(32000)
90, fEntryOffsetLen(1000)
91, fWriteBasket(0)
92, fEntryNumber(0)
93, fExtraBasket(nullptr)
94, fOffset(0)
95, fMaxBaskets(10)
96, fNBaskets(0)
97, fSplitLevel(0)
98, fNleaves(0)
99, fReadBasket(0)
100, fReadEntry(-1)
101, fFirstBasketEntry(-1)
102, fNextBasketEntry(-1)
103, fCurrentBasket(nullptr)
104, fEntries(0)
105, fFirstEntry(0)
106, fTotBytes(0)
107, fZipBytes(0)
108, fBranches()
109, fLeaves()
110, fBaskets(fMaxBaskets)
111, fBasketBytes(nullptr)
112, fBasketEntry(nullptr)
113, fBasketSeek(nullptr)
114, fTree(nullptr)
115, fMother(nullptr)
116, fParent(nullptr)
117, fAddress(nullptr)
118, fDirectory(nullptr)
119, fFileName("")
120, fEntryBuffer(nullptr)
121, fTransientBuffer(nullptr)
122, fBrowsables(nullptr)
123, fBulk(*this)
124, fSkipZip(false)
125, fReadLeaves(&TBranch::ReadLeavesImpl)
126, fFillLeaves(&TBranch::FillLeavesImpl)
127{
129}
130
131////////////////////////////////////////////////////////////////////////////////
132/// Create a Branch as a child of a Tree
133///
134/// * address is the address of the first item of a structure
135/// or the address of a pointer to an object (see example in TTree.cxx).
136/// * leaflist is the concatenation of all the variable names and types
137/// separated by a colon character :
138/// The variable name and the variable type are separated by a
139/// slash (/). The variable type must be 1 character. (Characters
140/// after the first are legal and will be appended to the visible
141/// name of the leaf, but have no effect.) If no type is given, the
142/// type of the variable is assumed to be the same as the previous
143/// variable. If the first variable does not have a type, it is
144/// assumed of type F by default. The list of currently supported
145/// types is given below:
146/// - `C` : a character string terminated by the 0 character
147/// - `B` : an 8 bit signed integer (`Char_t`); Treated as a character when in an array.
148/// - `b` : an 8 bit unsigned integer (`UChar_t`)
149/// - `S` : a 16 bit signed integer (`Short_t`)
150/// - `s` : a 16 bit unsigned integer (`UShort_t`)
151/// - `I` : a 32 bit signed integer (`Int_t`)
152/// - `i` : a 32 bit unsigned integer (`UInt_t`)
153/// - `F` : a 32 bit floating point (`Float_t`)
154/// - `f` : a 24 bit floating point with truncated mantissa (`Float16_t`)
155/// - `D` : a 64 bit floating point (`Double_t`)
156/// - `d` : a 24 bit truncated floating point (`Double32_t`)
157/// - `L` : a 64 bit signed integer (`Long64_t`)
158/// - `l` : a 64 bit unsigned integer (`ULong64_t`)
159/// - `G` : a long signed integer (`Long_t`, which `sizeof` is platform dependent), stored as a 64 bit integer but usually held in memory as a 64 bit integer on 64 bit machines and 32 bit on 32 bit machines. Due to this difference, this data type is **not cross-platform**.
160/// - `g` : a long unsigned integer (`ULong_t`, which `sizeof` is platform dependent), stored as a 64 bit unsigned integer but held in memory usually as a 64 bit integer on 64 bit machines and 32 bit on 32 bit machines. Due to this difference, this data type is **not cross-platform**.
161/// - `O` : [the letter `o`, not a zero] a boolean (`bool`)
162///
163/// Arrays of values are supported with the following syntax:
164/// - If leaf name has the form var[nelem], where nelem is alphanumeric, then
165/// if nelem is a leaf name, it is used as the variable size of the array,
166/// otherwise return 0.
167/// The leaf referred to by nelem **MUST** be an int (/I),
168/// - If leaf name has the form var[nelem], where nelem is a non-negative integers, then
169/// it is used as the fixed size of the array.
170/// - If leaf name has the form of a multi dimension array (e.g. var[nelem][nelem2])
171/// where nelem and nelem2 are non-negative integers) then
172/// it is used as a 2 dimensional array of fixed size.
173/// - In case of the truncated floating point types (Float16_t and Double32_t) you can
174/// furthermore specify the range in the style [xmin,xmax] or [xmin,xmax,nbits] after
175/// the type character. See `TStreamerElement::GetRange()` for further information.
176/// - Any of other form is not supported.
177///
178/// Note that the TTree will assume that all the item are contiguous in memory.
179/// On some platform, this is not always true of the member of a struct or a class,
180/// due to padding and alignment. Sorting your data member in order of decreasing
181/// sizeof usually leads to their being contiguous in memory.
182///
183/// * bufsize is the buffer size in bytes for this branch
184/// The default value is 32000 bytes and should be ok for most cases.
185/// You can specify a larger value (e.g. 256000) if your Tree is not split
186/// and each entry is large (Megabytes)
187/// A small value for bufsize is optimum if you intend to access
188/// the entries in the Tree randomly and your Tree is in split mode.
189///
190/// See an example of a Branch definition in the TTree constructor.
191///
192/// Note that in case the data type is an object, this branch can contain
193/// only this object.
194///
195/// Note that this function is invoked by TTree::Branch
196
197TBranch::TBranch(TTree *tree, const char *name, void *address, const char *leaflist, Int_t basketsize, Int_t compress)
199, TAttFill(0, 1001)
200, fCompress(compress)
201, fBasketSize((basketsize < 100) ? 100 : basketsize)
202, fEntryOffsetLen(0)
203, fWriteBasket(0)
204, fEntryNumber(0)
205, fExtraBasket(nullptr)
206, fIOFeatures(tree ? tree->GetIOFeatures().GetFeatures() : 0)
207, fOffset(0)
208, fMaxBaskets(10)
209, fNBaskets(0)
210, fSplitLevel(0)
211, fNleaves(0)
212, fReadBasket(0)
213, fReadEntry(-1)
214, fFirstBasketEntry(-1)
215, fNextBasketEntry(-1)
216, fCurrentBasket(nullptr)
217, fEntries(0)
218, fFirstEntry(0)
219, fTotBytes(0)
220, fZipBytes(0)
221, fBranches()
222, fLeaves()
223, fBaskets(fMaxBaskets)
224, fBasketBytes(nullptr)
225, fBasketEntry(nullptr)
226, fBasketSeek(nullptr)
227, fTree(tree)
228, fMother(nullptr)
229, fParent(nullptr)
230, fAddress((char *)address)
231, fDirectory(fTree->GetDirectory())
232, fFileName("")
233, fEntryBuffer(nullptr)
234, fTransientBuffer(nullptr)
235, fBrowsables(nullptr)
236, fBulk(*this)
237, fSkipZip(false)
238, fReadLeaves(&TBranch::ReadLeavesImpl)
239, fFillLeaves(&TBranch::FillLeavesImpl)
240{
242}
243
244////////////////////////////////////////////////////////////////////////////////
245/// Create a Branch as a child of another Branch
246///
247/// See documentation for
248/// TBranch::TBranch(TTree *, const char *, void *, const char *, Int_t, Int_t)
249
250TBranch::TBranch(TBranch *parent, const char *name, void *address, const char *leaflist, Int_t basketsize,
253, TAttFill(0, 1001)
254, fCompress(compress)
255, fBasketSize((basketsize < 100) ? 100 : basketsize)
256, fEntryOffsetLen(0)
257, fWriteBasket(0)
258, fEntryNumber(0)
259, fExtraBasket(nullptr)
260, fIOFeatures(parent->fIOFeatures)
261, fOffset(0)
262, fMaxBaskets(10)
263, fNBaskets(0)
264, fSplitLevel(0)
265, fNleaves(0)
266, fReadBasket(0)
267, fReadEntry(-1)
268, fFirstBasketEntry(-1)
269, fNextBasketEntry(-1)
270, fCurrentBasket(nullptr)
271, fEntries(0)
272, fFirstEntry(0)
273, fTotBytes(0)
274, fZipBytes(0)
275, fBranches()
276, fLeaves()
277, fBaskets(fMaxBaskets)
278, fBasketBytes(nullptr)
279, fBasketEntry(nullptr)
280, fBasketSeek(nullptr)
281, fTree(parent ? parent->GetTree() : nullptr)
282, fMother(parent ? parent->GetMother() : nullptr)
283, fParent(parent)
284, fAddress((char *)address)
285, fDirectory(fTree ? fTree->GetDirectory() : nullptr)
286, fFileName("")
287, fEntryBuffer(nullptr)
288, fTransientBuffer(nullptr)
289, fBrowsables(nullptr)
290, fBulk(*this)
291, fSkipZip(false)
292, fReadLeaves(&TBranch::ReadLeavesImpl)
293, fFillLeaves(&TBranch::FillLeavesImpl)
294{
296}
297
298void TBranch::Init(const char* name, const char* leaflist, Int_t compress)
299{
300 // Initialization routine called from the constructor. This should NOT be made virtual.
301
303 if ((compress == -1) && fTree->GetDirectory()) {
305 if (bfile) {
306 fCompress = bfile->GetCompressionSettings();
307 }
308 }
309
313
314 for (Int_t i = 0; i < fMaxBaskets; ++i) {
315 fBasketBytes[i] = 0;
316 fBasketEntry[i] = 0;
317 fBasketSeek[i] = 0;
318 }
319
320 //
321 // Decode the leaflist (search for : as separator).
322 //
323
324 char* nameBegin = const_cast<char*>(leaflist);
325 Int_t offset = 0;
326 auto len = strlen(leaflist);
327 // FIXME: Make these string streams instead.
328 char* leafname = new char[len + 1];
329 char* leaftype = new char[320];
330 // Note: The default leaf type is a float.
331 strlcpy(leaftype, "F",320);
332 char* pos = const_cast<char*>(leaflist);
333 const char* leaflistEnd = leaflist + len;
334 for (; pos <= leaflistEnd; ++pos) {
335 // -- Scan leaf specification and create leaves.
336 if ((*pos == ':') || (*pos == 0)) {
337 // -- Reached end of a leaf spec, create a leaf.
338 Int_t lenName = pos - nameBegin;
339 char* ctype = nullptr;
340 if (lenName) {
342 leafname[lenName] = 0;
343 ctype = strstr(leafname, "/");
344 if (ctype) {
345 *ctype = 0;
346 strlcpy(leaftype, ctype + 1,320);
347 }
348 }
349 if (lenName == 0 || ctype == leafname) {
350 Warning("TBranch","No name was given to the leaf number '%d' in the leaflist of the branch '%s'.",fNleaves,name);
351 snprintf(leafname, len + 1, "__noname%d", fNleaves);
352 }
353 TLeaf* leaf = nullptr;
354 if (leaftype[1] == '[' && !strchr(leaftype, ',')) {
355 Warning("TBranch", "Array size for branch '%s' must be specified after leaf name, not after the type name!", name);
356 // and continue for backward compatibility?
357 } else if (leaftype[1] && !strchr(leaftype, ',')) {
358 Warning("TBranch", "Extra characters after type tag '%s' for branch '%s'; must be one character.", leaftype, name);
359 // and continue for backward compatibility?
360 }
361 if (*leaftype == 'C') {
362 leaf = new TLeafC(this, leafname, leaftype);
363 } else if (*leaftype == 'O') {
364 leaf = new TLeafO(this, leafname, leaftype);
365 } else if (*leaftype == 'B') {
366 leaf = new TLeafB(this, leafname, leaftype);
367 } else if (*leaftype == 'b') {
368 leaf = new TLeafB(this, leafname, leaftype);
369 leaf->SetUnsigned();
370 } else if (*leaftype == 'S') {
371 leaf = new TLeafS(this, leafname, leaftype);
372 } else if (*leaftype == 's') {
373 leaf = new TLeafS(this, leafname, leaftype);
374 leaf->SetUnsigned();
375 } else if (*leaftype == 'I') {
376 leaf = new TLeafI(this, leafname, leaftype);
377 } else if (*leaftype == 'i') {
378 leaf = new TLeafI(this, leafname, leaftype);
379 leaf->SetUnsigned();
380 } else if (*leaftype == 'F') {
381 leaf = new TLeafF(this, leafname, leaftype);
382 } else if (*leaftype == 'f') {
383 leaf = new TLeafF16(this, leafname, leaftype);
384 } else if (*leaftype == 'L') {
385 leaf = new TLeafL(this, leafname, leaftype);
386 } else if (*leaftype == 'l') {
387 leaf = new TLeafL(this, leafname, leaftype);
388 leaf->SetUnsigned();
389 } else if (*leaftype == 'D') {
390 leaf = new TLeafD(this, leafname, leaftype);
391 } else if (*leaftype == 'd') {
392 leaf = new TLeafD32(this, leafname, leaftype);
393 } else if (*leaftype == 'G') {
394 leaf = new TLeafG(this, leafname, leaftype);
395 } else if (*leaftype == 'g') {
396 leaf = new TLeafG(this, leafname, leaftype);
397 leaf->SetUnsigned();
398 }
399 if (!leaf) {
400 Error("TLeaf", "Illegal data type for %s/%s", name, leaflist);
401 delete[] leaftype;
402 delete [] leafname;
403 MakeZombie();
404 return;
405 }
406 if (leaf->IsZombie()) {
407 delete leaf;
408 leaf = nullptr;
409 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.";
410 Error("TBranch", msg, name, leaflist);
411 delete [] leafname;
412 delete[] leaftype;
413 MakeZombie();
414 return;
415 }
416 leaf->SetBranch(this);
417 leaf->SetAddress((char*) (fAddress + offset));
418 leaf->SetOffset(offset);
419 if (leaf->GetLeafCount()) {
420 // -- Leaf is a varying length array, we need an offset array.
421 fEntryOffsetLen = 1000;
422 }
423 if (leaf->InheritsFrom(TLeafC::Class())) {
424 // -- Leaf is a character string, we need an offset array.
425 fEntryOffsetLen = 1000;
426 }
427 ++fNleaves;
429 fTree->GetListOfLeaves()->Add(leaf);
430 if (*pos == 0) {
431 // -- We reached the end of the leaf specification.
432 break;
433 }
434 nameBegin = pos + 1;
435 offset += leaf->GetLenType() * leaf->GetLen();
436 }
437 }
438 delete[] leafname;
439 leafname = nullptr;
440 delete[] leaftype;
441 leaftype = nullptr;
442
443}
444
445////////////////////////////////////////////////////////////////////////////////
446/// Destructor.
447
449{
450 delete fBrowsables;
451 fBrowsables = nullptr;
452
453 // Note: We do *not* have ownership of the buffer.
454 fEntryBuffer = nullptr;
455
456 delete [] fBasketSeek;
457 fBasketSeek = nullptr;
458
459 delete [] fBasketEntry;
460 fBasketEntry = nullptr;
461
462 delete [] fBasketBytes;
463 fBasketBytes = nullptr;
464
466 delete fExtraBasket;
468 fNBaskets = 0;
469 fCurrentBasket = nullptr;
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())) {
499
501 TFile* file = (TFile*)gROOT->GetListOfFiles()->FindObject(bFileName);
502 if (file){
503 file->Close();
504 delete file;
505 file = nullptr;
506 }
507 }
508
509 fTree = nullptr;
510 fDirectory = nullptr;
511
512 if (fTransientBuffer) {
513 delete fTransientBuffer;
514 fTransientBuffer = nullptr;
515 }
516}
517
518////////////////////////////////////////////////////////////////////////////////
519/// Returns the transient buffer currently used by this TBranch for reading/writing baskets.
520
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
544{
545 TBasket *basket = &b;
546
547 basket->SetBranch(this);
548
549 if (fWriteBasket >= fMaxBaskets) {
551 }
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) {
580 }
581 }
582 }
584
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.
600 fTree->IncrementTotalBuffers(basket->GetBufferSize());
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 }
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) {
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.
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 all = false;
758 if (options && options[0]) {
759 TString opt = options;
760 opt.ToLower();
761 if (opt.Contains("all")) all = true;
762 }
763
766
767 if ( (fNBaskets>1) || all ) {
768 //slow case
769 for (Int_t i=0;i<nbaskets;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 = nullptr;
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();
802 if (basket && fBasketBytes[i]!=0) {
803 basket->DropBuffers();
804 if (basket == fCurrentBasket) {
805 fCurrentBasket = nullptr;
807 fNextBasketEntry = -1;
808 }
809 delete basket;
810 fBaskets.AddAt(nullptr,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
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) {
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.
919
922 ((lnew + (2 * nsize) + nbytes) >= fBasketSize))) {
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 }
956 static TBasket toread_fLast;
958 toread_fLast.Streamer(*fEntryBuffer);
960 last = toread_fLast.GetLast();
961 // last now contains the decompressed number of bytes.
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;
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];
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.
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 {
995 }
999 }
1000 fEntries++;
1001 fEntryNumber++;
1002 UInt_t len = 0;
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!
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.
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;
1050
1052 TBranch* branch = nullptr;
1053 for(Int_t i = 0; i < nbranches; ++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 nullptr;
1074}
1075
1076////////////////////////////////////////////////////////////////////////////////
1077/// Find the leaf corresponding to the name 'searchname'.
1078
1080{
1085
1086 // We allow the user to pass only the last dotted component of the name.
1087 TIter next(GetListOfLeaves());
1088 TLeaf* leaf = nullptr;
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 nullptr;
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
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)) {
1148 if (nwrite<0) {
1149 ++nerror;
1150 } else {
1151 nbytes += nwrite;
1152 }
1153 }
1154 }
1156 for (Int_t i = 0; i < len; ++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;
1185
1186 if (basket && !basket->IsZombie()) {
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 }
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 = nullptr;
1205 fFirstBasketEntry = -1;
1206 fNextBasketEntry = -1;
1207 }
1208 delete basket;
1209 --fNBaskets;
1210 fBaskets[ibasket] = nullptr;
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
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 ?
1235 if (basket) return basket;
1236 if (basketnumber == fWriteBasket) return nullptr;
1237
1238 // create/decode basket parameters from buffer
1239 TFile *file = GetFile(0);
1240 if (file == nullptr) {
1241 return nullptr;
1242 }
1243 // if cluster pre-fetching or retaining is on, do not re-use existing baskets
1244 // unless a new cluster is used.
1247 else
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, false);
1261 if (fSkipZip) pf->SetSkipZip();
1262 }
1263 }
1264
1265 //now read basket
1267 if (R__unlikely(badread || basket->GetSeekKey() != fBasketSeek[basketnumber] || basket->IsZombie())) {
1268 nerrors++;
1269 if (nerrors > 10) return nullptr;
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 nullptr;
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 nullptr;
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 nullptr;
1284 }
1285
1286 ++fNBaskets;
1287
1289 auto perfStats = GetTree()->GetPerfStats();
1290 if (perfStats)
1291 perfStats->SetUsed(this, basketnumber);
1292
1294 return basket;
1295}
1296
1297////////////////////////////////////////////////////////////////////////////////
1298/// Return address of basket in the file
1299
1305
1306////////////////////////////////////////////////////////////////////////////////
1307/// Returns (and, if 0, creates) browsable objects for this branch
1308/// See TVirtualBranchBrowsable::FillListOfBrowsables.
1309
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.
1353{
1357 // We have found the basket containing this entry.
1358 // make sure basket buffers are in memory.
1360 first = fFirstBasketEntry;
1361 return fReadBasket;
1362 } else {
1363 if ((entry < fFirstEntry) || (entry >= fEntryNumber)) {
1364 return -1;
1365 }
1366 first = fFirstBasketEntry;
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 }
1383 }
1384 // We have found the basket containing this entry.
1385 // make sure basket buffers are in memory.
1387 if (!basket) {
1389 if (!basket) {
1390 fCurrentBasket = nullptr;
1391 fFirstBasketEntry = -1;
1392 fNextBasketEntry = -1;
1393 return -2;
1394 }
1395 if (fTree->GetClusterPrefetch()) {
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.
1405 fFirstBasketEntry = first;
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 {
1415 }
1416 } else {
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/// \brief Read a basket of events into the given buffer with byte swapping.
1436///
1437/// \return On success, the number of events of the type held by this branch
1438/// that have been read into the buffer. -1 on failure.
1439///
1440/// On success, the caller should be able to access the contents of buf as they
1441/// are with:
1442///
1443/// ~~~{.cpp}
1444/// static_cast<T*>(buf.GetCurrent())
1445/// ~~~
1446///
1447/// where T is the type stored on this branch.
1448///
1449/// When `count_buf` points to a valid TBuffer and the branch has a branch count,
1450/// `count_buf` will be filled (via a call to GetEntriesSerialized) with the data
1451/// from the branchCount. After deserialization those value can be used to calculate
1452/// the number of elements corresponding to each entries.
1453///
1454/// For each entry the number of elements is the multiplication of
1455///
1456/// ~~~{.cpp}
1457/// TLeaf *leaf = static_cast<TLeaf*>(branch->GetListOfLeaves()->At(0));
1458/// auto len = leaf->GetLen();
1459/// ~~~
1460///
1461/// and the value in the BranchCount corresponding to that entry (can be obtained
1462/// from `branch->GetBranchCount()`).
1463///
1464/// \note This interface is not meant to be exposed to end users, but rather it should
1465/// be wrapped by higher-level interfaces.
1466///
1467/// \note See TBranch::GetEntriesSerialized() for an alternative that does not
1468/// perform byte swapping (useful to save one pass over data in some cases).
1469///
1471{
1472 // TODO: eventually support multiple leaves.
1473 if (R__unlikely(fNleaves != 1)) return -1;
1474 TLeaf *leaf = static_cast<TLeaf*>(fLeaves.UncheckedAt(0));
1475 if (R__unlikely(leaf->GetDeserializeType() == TLeaf::DeserializeType::kExternal)) {
1476 return -1;
1477 }
1478
1479 // Remember which entry we are reading.
1480 fReadEntry = entry;
1481
1482 bool enabled = !TestBit(kDoNotProcess);
1483 if (R__unlikely(!enabled)) return -1;
1484 TBasket *basket = nullptr;
1485 Long64_t first;
1487 if (R__unlikely(result < 0)) return -1;
1488 // Only support reading from full clusters.
1489 if (R__unlikely(entry != first)) {
1490 //printf("Failed to read from full cluster; first entry is %ld; requested entry is %ld.\n", first, entry);
1491 return -1;
1492 }
1493
1494 basket->PrepareBasket(entry);
1495 TBuffer* buf = basket->GetBufferRef();
1496
1497 // Test for very old ROOT files.
1498 if (R__unlikely(!buf)) {
1499 Error("GetBulkEntries", "Failed to get a new buffer.\n");
1500 return -1;
1501 }
1502 // Test for displacements, which aren't supported in fast mode.
1503 if (R__unlikely(basket->GetDisplacement())) {
1504 Error("GetBulkEntries", "Basket has displacement.\n");
1505 return -1;
1506 }
1507
1508 if (&user_buf != buf) {
1509 // The basket was already in memory and might (and might not) be backed by persistent
1510 // storage.
1512 if (fBasketSeek[fReadBasket]) {
1513 // It is backed, so we can be destructive
1514 user_buf.SetBuffer(buf->Buffer(), buf->BufferSize());
1515 buf->ResetBit(TBufferIO::kIsOwner);
1516 fCurrentBasket = nullptr;
1517 fBaskets[fReadBasket] = nullptr;
1518 } else {
1519 // This is the only copy, we can't return it as is to the user, just make a copy.
1520 if (user_buf.BufferSize() < buf->BufferSize()) {
1521 user_buf.AutoExpand(buf->BufferSize());
1522 }
1523 memcpy(user_buf.Buffer(), buf->Buffer(), buf->BufferSize());
1524 }
1525 }
1526
1527 Int_t bufbegin = basket->GetKeylen();
1528 user_buf.SetBufferOffset(bufbegin);
1529
1531 //printf("Requesting %d events; fNextBasketEntry=%lld; first=%lld.\n", N, fNextBasketEntry, first);
1532 if (R__unlikely(!leaf->ReadBasketFast(user_buf, N))) {
1533 Error("GetBulkEntries", "Leaf failed to read.\n");
1534 return -1;
1535 }
1536 user_buf.SetBufferOffset(bufbegin);
1537
1538 if (fCurrentBasket == nullptr) {
1539 R__ASSERT(fExtraBasket == nullptr && "fExtraBasket should have been set to nullptr by GetFreshBasket");
1541 basket->DisownBuffer();
1542 }
1543
1544 return N;
1545}
1546
1547////////////////////////////////////////////////////////////////////////////////
1548/// \brief Read a basket of events into the given buffer without byte swapping.
1549///
1550/// \return On success, the number of events of the type held by this branch
1551/// that have been read into the buffer. -1 on failure.
1552///
1553/// On success, the caller still need to deserialize the content. For example for
1554/// a scalar branch and `N` the return value (i.e. number of entries)
1555///
1556/// ~~~{.cpp}
1557/// rawdata = static_cast<char*>(buf.GetCurrent());
1558/// for (std::size_t i = 0u; i < N; ++i, ++target)
1559/// frombuf(rawdata, target); // `frombuf` also advances the `rawdata` pointer
1560/// ~~~
1561///
1562/// where target is a pointer or array to the type stored on this branch.
1563///
1564/// When `count_buf` points to a valid TBuffer and the branch has a branch count,
1565/// `count_buf` will be filled (via a call to GetEntriesSerialized()) with the data
1566/// from the branchCount. After deserialization those value can be used to calculate
1567/// the number of elements corresponding to each entries.
1568///
1569/// For each entry the number of elements is the multiplication of
1570///
1571/// ~~~{.cpp}
1572/// TLeaf *leaf = dynamic_cast<TLeaf*>(branch->GetListOfLeaves()->At(0));
1573/// auto len = leaf->GetLen();
1574/// ~~~
1575///
1576/// and the value in the BranchCount corresponding to that entry (can be obtained
1577/// from `branch->GetBranchCount()`).
1578///
1579/// \note This interface is not meant to be exposed to end users, but rather it should
1580/// be wrapped by higher-level interfaces.
1581///
1582/// \note See TBranch::GetBulkEntries() for an alternative that also performs byte swapping.
1583///
1585{
1586 // TODO: Template this and TBranch::GetBulkEntries; only difference is the TLeaf function (ReadBasketFast vs
1587 // ReadBasketSerialized
1588
1589 // TODO: eventually support multiple leaves.
1590 if (R__unlikely(fNleaves != 1)) { return -1; }
1591 TLeaf *leaf = static_cast<TLeaf*>(fLeaves.UncheckedAt(0));
1592 if (R__unlikely(leaf->GetDeserializeType() == TLeaf::DeserializeType::kDestructive)) {
1593 Error("GetEntriesSerialized", "Encountered a branch with destructive deserialization; failing.");
1594 return -1;
1595 }
1596
1597 // Remember which entry we are reading.
1598 fReadEntry = entry;
1599
1600 bool enabled = !TestBit(kDoNotProcess);
1601 if (R__unlikely(!enabled)) { return -1; }
1602 TBasket *basket = nullptr;
1603 Long64_t first;
1605 if (R__unlikely(result < 0)) { return -1; }
1606 // Only support reading from full clusters.
1607 if (R__unlikely(entry != first)) {
1608 Error("GetEntriesSerialized", "Failed to read from full cluster; first entry is %lld; requested entry is %lld.\n", first, entry);
1609 return -1;
1610 }
1611
1612 basket->PrepareBasket(entry);
1613 TBuffer* buf = basket->GetBufferRef();
1614
1615 // Test for very old ROOT files.
1616 if (R__unlikely(!buf)) {
1617 Error("GetEntriesSerialized", "Failed to get a new buffer.\n");
1618 return -1;
1619 }
1620 // Test for displacements, which aren't supported in fast mode.
1621 if (R__unlikely(basket->GetDisplacement())) {
1622 Error("GetEntriesSerialized", "Basket has displacement.\n");
1623 return -1;
1624 }
1625
1626 if (&user_buf != buf) {
1627 // The basket was already in memory and might (and might not) be backed by persistent
1628 // storage.
1630 if (fBasketSeek[fReadBasket]) {
1631 // It is backed, so we can be destructive
1632 user_buf.SetBuffer(buf->Buffer(), buf->BufferSize());
1633 buf->ResetBit(TBufferIO::kIsOwner);
1634 fCurrentBasket = nullptr;
1635 fBaskets[fReadBasket] = nullptr;
1636 } else {
1637 // This is the only copy, we can't return it as is to the user, just make a copy.
1638 if (user_buf.BufferSize() < buf->BufferSize()) {
1639 user_buf.AutoExpand(buf->BufferSize());
1640 }
1641 memcpy(user_buf.Buffer(), buf->Buffer(), buf->BufferSize());
1642 }
1643 }
1644
1645 Int_t bufbegin = basket->GetKeylen();
1646 user_buf.SetBufferOffset(bufbegin);
1647
1649 //Info("GetEntriesSerialized", "Requesting %d events; fNextBasketEntry=%lld; first=%lld.\n", N, fNextBasketEntry, first);
1650
1651 user_buf.SetBufferOffset(bufbegin);
1652
1653 if (count_buf) {
1654 TLeaf *count_leaf = leaf->GetLeafCount();
1655 if (count_leaf) {
1656 //printf("Getting leaf count entries.\n");
1657 TBranch *count_branch = count_leaf->GetBranch();
1658 if (R__unlikely(count_branch->GetEntriesSerialized(entry, *count_buf) < 0)) {
1659 Error("GetEntriesSerialized", "Failed to read count leaf.\n");
1660 return -1;
1661 }
1662 } else {
1663 // TODO: if you ask for a count on a fixed-size branch, maybe we should
1664 // just fail?
1666 char *tmp_ptr = reinterpret_cast<char*>(&entry_count_serialized);
1667 tobuf(tmp_ptr, leaf->GetLenType() * leaf->GetNdata());
1668 Int_t cur_offset = count_buf->GetCurrent() - count_buf->Buffer();
1669 for (int idx=0; idx<N; idx++) {
1671 }
1672 count_buf->SetBufferOffset(cur_offset);
1673 }
1674 }
1675
1676 if (fCurrentBasket == nullptr) {
1677 R__ASSERT(fExtraBasket == nullptr && "fExtraBasket should have been set to nullptr by GetFreshBasket");
1679 basket->DisownBuffer();
1680 }
1681
1682 return N;
1683}
1684
1685////////////////////////////////////////////////////////////////////////////////
1686/// Read all leaves of entry and return total number of bytes read.
1687///
1688/// The input argument "entry" is the entry number in the current tree.
1689/// In case of a TChain, the entry number in the current Tree must be found
1690/// before calling this function. For example:
1691///
1692///~~~ {.cpp}
1693/// TChain* chain = ...;
1694/// Long64_t localEntry = chain->LoadTree(entry);
1695/// branch->GetEntry(localEntry);
1696///~~~
1697///
1698/// The function returns the number of bytes read from the input buffer.
1699/// If entry does not exist, the function returns 0.
1700/// If an I/O error occurs, the function returns -1.
1701///
1702/// See IMPORTANT REMARKS in TTree::GetEntry.
1703
1705{
1706 // Remember which entry we are reading.
1707 fReadEntry = entry;
1708
1709 if (R__unlikely(TestBit(kDoNotProcess) && !getall)) { return 0; }
1710
1711 TBasket *basket; // will be initialized in the if/then clauses.
1712 Long64_t first;
1713
1714 Int_t result = GetBasketAndFirst(basket, first, nullptr);
1715 if (R__unlikely(result < 0)) { return result + 1; }
1716
1717 basket->PrepareBasket(entry);
1718 TBuffer* buf = basket->GetBufferRef();
1719
1720 // This test necessary to read very old Root files (NvE).
1721 if (R__unlikely(!buf)) {
1722 TFile* file = GetFile(0);
1723 if (!file) return -1;
1724 basket->ReadBasketBuffers(fBasketSeek[fReadBasket], fBasketBytes[fReadBasket], file);
1725 buf = basket->GetBufferRef();
1726 }
1727
1728 // Set entry offset in buffer.
1730 buf->ResetMap();
1731 }
1732 if (R__unlikely(!buf->IsReading())) {
1733 basket->SetReadMode();
1734 }
1735
1736 Int_t* entryOffset = basket->GetEntryOffset();
1737 Int_t bufbegin = 0;
1738 if (entryOffset) {
1739 bufbegin = entryOffset[entry-first];
1740 buf->SetBufferOffset(bufbegin);
1741 Int_t* displacement = basket->GetDisplacement();
1743 buf->SetBufferDisplacement(displacement[entry-first]);
1744 }
1745 } else {
1746 bufbegin = basket->GetKeylen() + ((entry-first) * basket->GetNevBufSize());
1747 buf->SetBufferOffset(bufbegin);
1748 }
1749
1750 // Int_t bufbegin = buf->Length();
1751 (this->*fReadLeaves)(*buf);
1752 return buf->Length() - bufbegin;
1753}
1754
1755////////////////////////////////////////////////////////////////////////////////
1756/// Read all leaves of an entry and export buffers to real objects in a TClonesArray list.
1757///
1758/// Returns total number of bytes read.
1759
1761{
1762 // Remember which entry we are reading.
1763 fReadEntry = entry;
1764
1765 if (TestBit(kDoNotProcess)) {
1766 return 0;
1767 }
1768 if ((entry < 0) || (entry >= fEntryNumber)) {
1769 return 0;
1770 }
1771 Int_t nbytes = 0;
1773 Long64_t last = fNextBasketEntry - 1;
1774 // Are we still in the same ReadBasket?
1775 if ((entry < first) || (entry > last)) {
1777 if (fReadBasket < 0) {
1778 fNextBasketEntry = -1;
1779 Error("In the branch %s, no basket contains the entry %d\n", GetName(), entry);
1780 return -1;
1781 }
1782 if (fReadBasket == fWriteBasket) {
1784 } else {
1786 }
1788 }
1789
1790 // We have found the basket containing this entry.
1791 // Make sure basket buffers are in memory.
1794 if (!basket) {
1795 fFirstBasketEntry = -1;
1796 fNextBasketEntry = -1;
1797 return 0;
1798 }
1799 TBuffer* buf = basket->GetBufferRef();
1800 // Set entry offset in buffer and read data from all leaves.
1802 buf->ResetMap();
1803 }
1804 if (R__unlikely(!buf->IsReading())) {
1805 basket->SetReadMode();
1806 }
1807 Int_t* entryOffset = basket->GetEntryOffset();
1808 Int_t bufbegin = 0;
1809 if (entryOffset) {
1810 bufbegin = entryOffset[entry-first];
1811 buf->SetBufferOffset(bufbegin);
1812 Int_t* displacement = basket->GetDisplacement();
1814 buf->SetBufferDisplacement(displacement[entry-first]);
1815 }
1816 } else {
1817 bufbegin = basket->GetKeylen() + ((entry-first) * basket->GetNevBufSize());
1818 buf->SetBufferOffset(bufbegin);
1819 }
1821 leaf->ReadBasketExport(*buf, li, nentries);
1822 nbytes = buf->Length() - bufbegin;
1823 return nbytes;
1824}
1825
1826////////////////////////////////////////////////////////////////////////////////
1827/// Fill expectedClass and expectedType with information on the data type of the
1828/// object/values contained in this branch (and thus the type of pointers
1829/// expected to be passed to Set[Branch]Address
1830/// return 0 in case of success and > 0 in case of failure.
1831
1833{
1834 expectedClass = nullptr;
1836 TLeaf* l = (TLeaf*) GetListOfLeaves()->At(0);
1837 if (l) {
1838 expectedType = (EDataType) gROOT->GetType(l->GetTypeName())->GetType();
1839 return 0;
1840 } else {
1841 Error("GetExpectedType", "Did not find any leaves in %s",GetName());
1842 return 1;
1843 }
1844}
1845
1846////////////////////////////////////////////////////////////////////////////////
1847/// Return pointer to the file where branch buffers reside, returns 0
1848/// in case branch buffers reside in the same file as tree header.
1849/// If mode is 1 the branch buffer file is recreated.
1850
1852{
1853 if (fDirectory) return fDirectory->GetFile();
1854
1855 // check if a file with this name is in the list of Root files
1856 TFile *file = nullptr;
1857 {
1859 file = (TFile*)gROOT->GetListOfFiles()->FindObject(fFileName.Data());
1860 if (file) {
1861 fDirectory = file;
1862 return file;
1863 }
1864 }
1865
1866 if (fFileName.Length() == 0) return nullptr;
1867
1869
1870 // Open file (new file if mode = 1)
1871 {
1873 if (mode) file = TFile::Open(bFileName, "recreate");
1874 else file = TFile::Open(bFileName);
1875 }
1876 if (!file) return nullptr;
1877 if (file->IsZombie()) {delete file; return nullptr;}
1878 fDirectory = (TDirectory*)file;
1879 return file;
1880}
1881
1882////////////////////////////////////////////////////////////////////////////////
1883/// Return a fresh basket by either reusing an existing basket that needs
1884/// to be drop (according to TTree::MemoryFull) or create a new one.
1885///
1886/// If the user_buffer argument is non-null, then the memory in the
1887/// user-provided buffer will be utilized by the underlying basket.
1888///
1889/// The basket number is used to estimate the required buffer size
1890/// and try to optimize memory usage and number of memory allocation.
1891
1893{
1894 TBasket *basket = nullptr;
1895 if (user_buffer && fExtraBasket) {
1897 fExtraBasket = nullptr;
1898 basket->AdoptBuffer(user_buffer);
1899 } else {
1900 if (GetTree()->MemoryFull(0)) {
1901 if (fNBaskets==1) {
1902 // Steal the existing basket
1905 if (!basket) {
1906 fBaskets.SetLast(-2); // For recalculation of Last.
1908 if (oldindex != fBaskets.LowerBound()-1) {
1910 }
1911 }
1912 if (basket && fBasketBytes[oldindex]!=0) {
1913 if (basket == fCurrentBasket) {
1914 fCurrentBasket = nullptr;
1915 fFirstBasketEntry = -1;
1916 fNextBasketEntry = -1;
1917 }
1918 fBaskets.AddAt(nullptr,oldindex);
1919 fBaskets.SetLast(-1);
1920 fNBaskets = 0;
1921 basket->ReadResetBuffer(basketnumber);
1922#ifdef R__TRACK_BASKET_ALLOC_TIME
1923 fTree->AddAllocationTime(basket->GetResetAllocationTime());
1924#endif
1925 fTree->AddAllocationCount(basket->GetResetAllocationCount());
1926 } else {
1927 basket = fTree->CreateBasket(this);
1928 }
1929 } else if (fNBaskets == 0) {
1930 // There is nothing to drop!
1931 basket = fTree->CreateBasket(this);
1932 } else {
1933 // Memory is full and there is more than one basket,
1934 // Let DropBaskets do it job.
1935 DropBaskets();
1936 basket = fTree->CreateBasket(this);
1937 }
1938 } else {
1939 basket = fTree->CreateBasket(this);
1940 }
1941 if (user_buffer)
1942 basket->AdoptBuffer(user_buffer);
1943 }
1944 return basket;
1945}
1946
1947////////////////////////////////////////////////////////////////////////////////
1948/// Drops the cluster two behind the current cluster and returns a fresh basket
1949/// by either reusing or creating a new one
1950
1952{
1953 TBasket *basket = nullptr;
1954
1955 auto CreateOrReuseBasket = [this, user_buffer]() -> TBasket* {
1956 TBasket *newbasket = nullptr;
1957 if (fExtraBasket) {
1959 fExtraBasket = nullptr;
1960 } else {
1961 newbasket = fTree->CreateBasket(this);
1962 }
1963 if (user_buffer)
1964 newbasket->AdoptBuffer(user_buffer);
1965 return newbasket;
1966 };
1967
1968 // If GetClusterIterator is called with a negative entry then GetStartEntry will be 0
1969 // So we need to check if we reach the zero before we have gone back (1-VirtualSize) clusters
1970 // if this is the case, we want to keep everything in memory so we return a new basket
1972 if (iter.GetStartEntry() == 0) {
1973 return CreateOrReuseBasket();
1974 }
1975
1976 // Iterate backwards (1-VirtualSize) clusters to reach cluster to be unloaded from memory,
1977 // skipped if VirtualSize > 0.
1978 for (Int_t j = 0; j < -fTree->GetMaxVirtualSize(); j++) {
1979 if (iter.Previous() == 0) {
1980 return CreateOrReuseBasket();
1981 }
1982 }
1983
1984 Int_t entryToUnload = iter.Previous();
1985 // Finds the basket to unload from memory. Since the basket should be close to current
1986 // basket, just iterate backwards until the correct basket is reached. This should
1987 // be fast as long as the number of baskets per cluster is small
1991 if (basketToUnload < 0) {
1992 return CreateOrReuseBasket();
1993 }
1994 }
1995
1996 // Retrieves the basket that is going to be unloaded from memory. If the basket did not
1997 // exist, create a new one
1999 if (basket) {
2000 fBaskets.AddAt(nullptr, basketToUnload);
2001 --fNBaskets;
2002 } else {
2004 }
2006
2007 // Clear the rest of the baskets. While it would be ideal to reuse these baskets
2008 // for other baskets in the new cluster. It would require the function to go
2009 // beyond its current scope. In the ideal case when each cluster only has 1 basket
2010 // this will perform well
2011 iter.Next();
2012 while (fBasketEntry[basketToUnload] < iter.GetStartEntry()) {
2014 if (oldbasket) {
2015 oldbasket->DropBuffers();
2016 delete oldbasket;
2017 fBaskets.AddAt(nullptr, basketToUnload);
2018 --fNBaskets;
2019 }
2021 }
2022 fBaskets.SetLast(-1);
2023 return basket;
2024}
2025
2026////////////////////////////////////////////////////////////////////////////////
2027/// Return the 'full' name of the branch. In particular prefix the mother's name
2028/// when it does not end in a trailing dot and thus is not part of the branch name
2030{
2032 if (!mother || mother==this) {
2033 return fName;
2034 }
2035
2036 const auto motherName = mother->GetName();
2037 const auto len = strlen(motherName);
2038 if (len > 0 && (motherName[len-1] == '.')) {
2039 return fName;
2040 }
2041
2042 // Reserve the final size to avoid allocations
2043 TString result{static_cast<Ssiz_t>(len + 1 + fName.Length())};
2045 result += ".";
2046 result += fName;
2047 return result;
2048}
2049
2050////////////////////////////////////////////////////////////////////////////////
2051/// Return pointer to the 1st Leaf named name in thisBranch
2052
2053TLeaf* TBranch::GetLeaf(const char* name) const
2054{
2055 Int_t i;
2056 for (i=0;i<fNleaves;i++) {
2058 if (!strcmp(leaf->GetName(),name)) return leaf;
2059 }
2060 return nullptr;
2061}
2062
2063////////////////////////////////////////////////////////////////////////////////
2064/// Get real file name
2065
2067{
2068 if (fFileName.Length()==0) {
2069 return fFileName;
2070 }
2072
2073 // check if branch file name is absolute or a URL (e.g. root://host/...)
2074 char *bname = gSystem->ExpandPathName(fFileName.Data());
2075 if (!gSystem->IsAbsoluteFileName(bname) && !strstr(bname, ":/") && fTree && fTree->GetCurrentFile()) {
2076
2077 // if not, get filename where tree header is stored
2078 const char *tfn = fTree->GetCurrentFile()->GetName();
2079
2080 // If it is an archive file we need a special treatment
2081 TUrl arc(tfn);
2082 if (strlen(arc.GetAnchor()) > 0) {
2083 arc.SetAnchor(gSystem->BaseName(fFileName));
2084 bFileName = arc.GetUrl();
2085 } else {
2086 // if this is an absolute path or a URL then prepend this path
2087 // to the branch file name
2088 char *tname = gSystem->ExpandPathName(tfn);
2089 if (gSystem->IsAbsoluteFileName(tname) || strstr(tname, ":/")) {
2091 bFileName += "/";
2093 }
2094 delete [] tname;
2095 }
2096 }
2097 delete [] bname;
2098
2099 return bFileName;
2100}
2101
2102////////////////////////////////////////////////////////////////////////////////
2103/// Return all elements of one row unpacked in internal array fValues
2104/// [Actually just returns 1 (?)]
2105
2107{
2108 return 1;
2109}
2110
2111////////////////////////////////////////////////////////////////////////////////
2112/// Return whether this branch is in a mode where the object are decomposed
2113/// or not (Also known as MakeClass mode).
2114
2116{
2117 // Regular TBranch and TBrancObject can not be in makeClass mode
2118
2119 return false;
2120}
2121
2122////////////////////////////////////////////////////////////////////////////////
2123/// Get our top-level parent branch in the tree.
2124
2126{
2127 if (fMother) return fMother;
2128
2129 {
2130 TBranch *parent = fParent;
2131 while(parent) {
2132 if (parent->fMother) {
2133 const_cast<TBranch*>(this)->fMother = parent->fMother; // We can not yet use the 'mutable' keyword
2134 return fMother;
2135 }
2136 if (!parent->fParent) {
2137 // This is the top node
2138 const_cast<TBranch*>(this)->fMother = parent; // We can not yet use the 'mutable' keyword
2139 return fMother;
2140 }
2141 parent = parent->fParent;
2142 }
2143 }
2144
2145 const TObjArray* array = fTree->GetListOfBranches();
2146 Int_t n = array->GetEntriesFast();
2147 for (Int_t i = 0; i < n; ++i) {
2148 TBranch* branch = (TBranch*) array->UncheckedAt(i);
2149 TBranch* parent = branch->GetSubBranch(this);
2150 if (parent) {
2151 const_cast<TBranch*>(this)->fMother = branch; // We can not yet use the 'mutable' keyword
2152 return branch;
2153 }
2154 }
2155 return nullptr;
2156}
2157
2158////////////////////////////////////////////////////////////////////////////////
2159/// Find the parent branch of child.
2160/// Return 0 if child is not in this branch hierarchy.
2161
2163{
2164 // Handle error condition, if the parameter is us, we cannot find the parent.
2165 if (this == child) {
2166 // Note: We cast away any const-ness of "this".
2167 return (TBranch*) this;
2168 }
2169
2170 if (child->fParent) {
2171 return child->fParent;
2172 }
2173
2175 for (Int_t i = 0; i < len; ++i) {
2177 if (!branch) {
2178 continue;
2179 }
2180 if (branch == child) {
2181 // We are the direct parent of child.
2182 // Note: We cast away any const-ness of "this".
2183 const_cast<TBranch*>(child)->fParent = (TBranch*)this; // We can not yet use the 'mutable' keyword
2184 return (TBranch*) this;
2185 }
2186 // FIXME: This is a tail-recursion!
2187 TBranch* parent = branch->GetSubBranch(child);
2188 if (parent) {
2189 return parent;
2190 }
2191 }
2192 // We failed to find the parent.
2193 return nullptr;
2194}
2195
2196////////////////////////////////////////////////////////////////////////////////
2197/// Return total number of bytes in the branch (including current buffer)
2198
2200{
2202 // This intentionally only store the TBranch part and thus slightly
2203 // under-estimate the space used.
2204 // Since the TBranchElement part contains pointers to other branches (branch count),
2205 // doing regular Streaming would end up including those and thus greatly over-estimate
2206 // the size used.
2207 const_cast<TBranch *>(this)->TBranch::Streamer(b);
2208
2209 Long64_t totbytes = 0;
2210 if (fZipBytes > 0) totbytes = fTotBytes;
2211 return totbytes + b.Length();
2212}
2213
2214////////////////////////////////////////////////////////////////////////////////
2215/// Return total number of bytes in the branch (excluding current buffer)
2216/// if option ="*" includes all sub-branches of this branch too
2217
2219{
2221 if (!option) return totbytes;
2222 if (option[0] != '*') return totbytes;
2223 //scan sub-branches
2225 for (Int_t i = 0; i < len; ++i) {
2227 if (branch) totbytes += branch->GetTotBytes(option);
2228 }
2229 return totbytes;
2230}
2231
2232////////////////////////////////////////////////////////////////////////////////
2233/// Return total number of zip bytes in the branch
2234/// if option ="*" includes all sub-branches of this branch too
2235
2237{
2239 if (!option) return zipbytes;
2240 if (option[0] != '*') return zipbytes;
2241 //scan sub-branches
2243 for (Int_t i = 0; i < len; ++i) {
2245 if (branch) zipbytes += branch->GetZipBytes(option);
2246 }
2247 return zipbytes;
2248}
2249
2250////////////////////////////////////////////////////////////////////////////////
2251/// Returns the IO settings currently in use for this branch.
2252
2257
2258////////////////////////////////////////////////////////////////////////////////
2259/// Return true if an existing object in a TBranchObject must be deleted.
2260
2262{
2263 return TestBit(kAutoDelete);
2264}
2265
2266////////////////////////////////////////////////////////////////////////////////
2267/// Return true if more than one leaf or browsables, false otherwise.
2268
2270{
2271 if (fNleaves > 1) {
2272 return true;
2273 }
2274 TList* browsables = const_cast<TBranch*>(this)->GetBrowsables();
2275 return browsables && browsables->GetSize();
2276}
2277
2278////////////////////////////////////////////////////////////////////////////////
2279/// keep a maximum of fMaxEntries in memory
2280
2282{
2285 if (basket) basket->MoveEntries(dentries);
2288 //loop on sub branches
2290 for (Int_t i = 0; i < nb; ++i) {
2292 branch->KeepCircular(maxEntries);
2293 }
2294}
2295
2296////////////////////////////////////////////////////////////////////////////////
2297/// Baskets associated to this branch are forced to be in memory.
2298/// You can call TTree::SetMaxVirtualSize(maxmemory) to instruct
2299/// the system that the total size of the imported baskets does not
2300/// exceed maxmemory bytes.
2301///
2302/// The function returns the number of baskets that have been put in memory.
2303/// This method may be called to force all baskets of one or more branches
2304/// in memory when random access to entries in this branch is required.
2305/// See also TTree::LoadBaskets to load all baskets of all branches in memory.
2306
2308{
2309 Int_t nimported = 0;
2311 TFile *file = GetFile(0);
2312 if (!file) return 0;
2313 TBasket *basket;
2314 for (Int_t i=0;i<nbaskets;i++) {
2316 if (basket) continue;
2317 basket = GetFreshBasket(i, nullptr);
2318 if (fBasketBytes[i] == 0) {
2319 fBasketBytes[i] = basket->ReadBasketBytes(fBasketSeek[i],file);
2320 }
2321 Int_t badread = basket->ReadBasketBuffers(fBasketSeek[i],fBasketBytes[i],file);
2322 if (badread) {
2323 Error("Loadbaskets","Error while reading basket buffer %d of branch %s",i,GetName());
2324 return -1;
2325 }
2326 ++fNBaskets;
2328 nimported++;
2329 }
2330 return nimported;
2331}
2332
2333////////////////////////////////////////////////////////////////////////////////
2334/// Print TBranch parameters
2335///
2336/// If options contains "basketsInfo" print the entry number, location and size
2337/// of each baskets.
2338
2340{
2341 const int kLINEND = 77;
2342 Float_t cx = 1;
2343
2345 if ( titleContent == GetName() ) {
2346 titleContent.Clear();
2347 }
2348
2349 if (fLeaves.GetEntries() == 1) {
2350 if (titleContent.Length()>=2 && titleContent[titleContent.Length()-2]=='/' && isalpha(titleContent[titleContent.Length()-1])) {
2351 // The type is already encoded. Nothing to do.
2352 } else {
2354 if (titleContent.Length()) {
2355 titleContent.Prepend(" ");
2356 }
2357 // titleContent.Append("type: ");
2358 titleContent.Prepend(leaf->GetTypeName());
2359 }
2360 }
2361 Int_t titleLength = titleContent.Length();
2362
2364 aLength += (aLength / 54 + 1) * 80 + 100;
2365 if (aLength < 200) aLength = 200;
2366 char *bline = new char[aLength];
2367
2369 if (fZipBytes) cx = (fTotBytes+0.00001)/fZipBytes;
2370 if (titleLength) snprintf(bline,aLength,"*Br%5d :%-9s : %-54s *",fgCount,GetName(),titleContent.Data());
2371 else snprintf(bline,aLength,"*Br%5d :%-9s : %-54s *",fgCount,GetName()," ");
2372 if (strlen(bline) > UInt_t(kLINEND)) {
2373 char *tmp = new char[strlen(bline)+1];
2375 snprintf(bline,aLength,"*Br%5d :%-9s : ",fgCount,GetName());
2376 int pos = strlen (bline);
2377 int npos = pos;
2378 int beg=0, end;
2379 while (beg < titleLength) {
2380 for (end=beg+1; end < titleLength-1; end ++)
2381 if (tmp[end] == ':') break;
2382 if (npos + end-beg+1 >= 78) {
2383 while (npos < kLINEND) {
2384 bline[pos ++] = ' ';
2385 npos ++;
2386 }
2387 bline[pos ++] = '*';
2388 bline[pos ++] = '\n';
2389 bline[pos ++] = '*';
2390 npos = 1;
2391 for (; npos < 12; npos ++)
2392 bline[pos ++] = ' ';
2393 bline[pos-2] = '|';
2394 }
2395 for (int n = beg; n <= end; n ++)
2396 bline[pos+n-beg] = tmp[n];
2397 pos += end-beg+1;
2398 npos += end-beg+1;
2399 beg = end+1;
2400 }
2401 while (npos < kLINEND) {
2402 bline[pos ++] = ' ';
2403 npos ++;
2404 }
2405 bline[pos ++] = '*';
2406 bline[pos] = '\0';
2407 delete[] tmp;
2408 }
2409 Printf("%s", bline);
2410
2411 if (fTotBytes > 2000000000) {
2412 Printf("*Entries :%lld : Total Size=%11lld bytes File Size = %lld *",fEntries,totBytes,fZipBytes);
2413 } else {
2414 if (fZipBytes > 0) {
2415 Printf("*Entries :%9lld : Total Size=%11lld bytes File Size = %10lld *",fEntries,totBytes,fZipBytes);
2416 } else {
2417 if (fWriteBasket > 0) {
2418 Printf("*Entries :%9lld : Total Size=%11lld bytes All baskets in memory *",fEntries,totBytes);
2419 } else {
2420 Printf("*Entries :%9lld : Total Size=%11lld bytes One basket in memory *",fEntries,totBytes);
2421 }
2422 }
2423 }
2424 Printf("*Baskets :%9d : Basket Size=%11d bytes Compression= %6.2f *",fWriteBasket,fBasketSize,cx);
2425
2426 if (strncmp(option,"basketsInfo",std::char_traits<char>::length("basketsInfo"))==0) {
2428 for (Int_t i=0;i<nbaskets;i++) {
2429 Printf("*Basket #%4d entry=%6lld pos=%6lld size=%5d",
2430 i, fBasketEntry[i], fBasketSeek[i], fBasketBytes[i]);
2431 }
2432 }
2433
2434 Printf("*............................................................................*");
2435 delete [] bline;
2436 fgCount++;
2437}
2438
2439////////////////////////////////////////////////////////////////////////////////
2440/// Print the information we have about which basket is currently cached and
2441/// whether they have been 'used'/'read' from the cache.
2442
2447
2448////////////////////////////////////////////////////////////////////////////////
2449/// Loop on all leaves of this branch to read Basket buffer.
2450
2452{
2453 // fLeaves->ReadBasket(basket);
2454}
2455
2456////////////////////////////////////////////////////////////////////////////////
2457/// Loop on all leaves of this branch to read Basket buffer.
2458
2460{
2461 for (Int_t i = 0; i < fNleaves; ++i) {
2463 leaf->ReadBasket(b);
2464 }
2465}
2466
2467////////////////////////////////////////////////////////////////////////////////
2468/// Read zero leaves without the overhead of a loop.
2469
2473
2474////////////////////////////////////////////////////////////////////////////////
2475/// Read one leaf without the overhead of a loop.
2476
2481
2482////////////////////////////////////////////////////////////////////////////////
2483/// Read two leaves without the overhead of a loop.
2484
2490
2491////////////////////////////////////////////////////////////////////////////////
2492/// Loop on all leaves of this branch to fill Basket buffer.
2493
2495{
2496 for (Int_t i = 0; i < fNleaves; ++i) {
2498 leaf->FillBasket(b);
2499 }
2500}
2501
2502////////////////////////////////////////////////////////////////////////////////
2503/// Refresh this branch using new information in b
2504/// This function is called by TTree::Refresh
2505
2507{
2508 if (b==nullptr) return;
2509
2510 fEntryOffsetLen = b->fEntryOffsetLen;
2511 fWriteBasket = b->fWriteBasket;
2512 fEntryNumber = b->fEntryNumber;
2513 fMaxBaskets = b->fMaxBaskets;
2514 fEntries = b->fEntries;
2515 fTotBytes = b->fTotBytes;
2516 fZipBytes = b->fZipBytes;
2517 fReadBasket = 0;
2518 fReadEntry = -1;
2519 fFirstBasketEntry = -1;
2520 fNextBasketEntry = -1;
2521 fCurrentBasket = nullptr;
2522 delete [] fBasketBytes;
2523 delete [] fBasketEntry;
2524 delete [] fBasketSeek;
2528 Int_t i;
2529 for (i=0;i<fMaxBaskets;i++) {
2530 fBasketBytes[i] = b->fBasketBytes[i];
2531 fBasketEntry[i] = b->fBasketEntry[i];
2532 fBasketSeek[i] = b->fBasketSeek[i];
2533 }
2534 fBaskets.Delete();
2535 Int_t nbaskets = b->fBaskets.GetSize();
2537 // If the current fWritebasket is in memory, take it (just swap)
2538 // from the Tree being read
2539 TBasket *basket = (TBasket*)b->fBaskets.UncheckedAt(fWriteBasket);
2541 if (basket) {
2542 fNBaskets = 1;
2543 --(b->fNBaskets);
2544 b->fBaskets.RemoveAt(fWriteBasket);
2545 basket->SetBranch(this);
2546 }
2547}
2548
2549////////////////////////////////////////////////////////////////////////////////
2550/// Reset a Branch.
2551///
2552/// - Existing buffers are deleted.
2553/// - Entries, max and min are reset.
2554
2556{
2557 fReadBasket = 0;
2558 fReadEntry = -1;
2559 fFirstBasketEntry = -1;
2560 fNextBasketEntry = -1;
2561 fCurrentBasket = nullptr;
2562 fWriteBasket = 0;
2563 fEntries = 0;
2564 fTotBytes = 0;
2565 fZipBytes = 0;
2566 fEntryNumber = 0;
2567
2568 if (fBasketBytes) {
2569 for (Int_t i = 0; i < fMaxBaskets; ++i) {
2570 fBasketBytes[i] = 0;
2571 }
2572 }
2573
2574 if (fBasketEntry) {
2575 for (Int_t i = 0; i < fMaxBaskets; ++i) {
2576 fBasketEntry[i] = 0;
2577 }
2578 }
2579
2580 if (fBasketSeek) {
2581 for (Int_t i = 0; i < fMaxBaskets; ++i) {
2582 fBasketSeek[i] = 0;
2583 }
2584 }
2585
2586 fBaskets.Delete();
2587 fNBaskets = 0;
2588}
2589
2590////////////////////////////////////////////////////////////////////////////////
2591/// Reset a Branch.
2592///
2593/// - Existing buffers are deleted.
2594/// - Entries, max and min are reset.
2595
2597{
2598 fReadBasket = 0;
2599 fReadEntry = -1;
2600 fFirstBasketEntry = -1;
2601 fNextBasketEntry = -1;
2602 fCurrentBasket = nullptr;
2603 fWriteBasket = 0;
2604 fEntries = 0;
2605 fTotBytes = 0;
2606 fZipBytes = 0;
2607 fEntryNumber = 0;
2608
2609 if (fBasketBytes) {
2610 for (Int_t i = 0; i < fMaxBaskets; ++i) {
2611 fBasketBytes[i] = 0;
2612 }
2613 }
2614
2615 if (fBasketEntry) {
2616 for (Int_t i = 0; i < fMaxBaskets; ++i) {
2617 fBasketEntry[i] = 0;
2618 }
2619 }
2620
2621 if (fBasketSeek) {
2622 for (Int_t i = 0; i < fMaxBaskets; ++i) {
2623 fBasketSeek[i] = 0;
2624 }
2625 }
2626
2628 if (reusebasket) {
2629 fBaskets[fWriteBasket] = nullptr;
2630 } else {
2632 if (reusebasket) {
2633 fBaskets[fReadBasket] = nullptr;
2634 }
2635 }
2636 fBaskets.Delete();
2637 if (reusebasket) {
2638 fNBaskets = 1;
2639 reusebasket->WriteReset();
2640 fBaskets[0] = reusebasket;
2641 } else {
2642 fNBaskets = 0;
2643 }
2644}
2645
2646////////////////////////////////////////////////////////////////////////////////
2647/// Reset the address of the branch.
2648
2650{
2651 fAddress = nullptr;
2652
2653 // Reset last read entry number, we have will had new user object now.
2654 fReadEntry = -1;
2655
2656 for (Int_t i = 0; i < fNleaves; ++i) {
2658 leaf->SetAddress(nullptr);
2659 }
2660
2662 for (Int_t i = 0; i < nbranches; ++i) {
2664 // FIXME: This is a tail recursion.
2665 abranch->ResetAddress();
2666 }
2667}
2668
2669////////////////////////////////////////////////////////////////////////////////
2670/// Static function resetting fgCount
2671
2673{
2674 fgCount = 0;
2675}
2676
2677////////////////////////////////////////////////////////////////////////////////
2678/// Set address of this branch.
2679/// @see TBranchElement::SetAddress
2680/// @note TBranch::SetAddress is a lower level interface and has less ability
2681/// to check for incorrect setup than TTree::SetBranchAddress. Without
2682/// TTree::SetMakeClass, if the branch is within an object, the input of
2683/// SetAddress is expected to be the start of the object (and thus the offset
2684/// of the data member is added to the provided address). The explicit purpose
2685/// of TTree::SetMakeClass is to disable this addition of the offset. Note that
2686/// TTree::SetBranchAddress will detect this case and automatically call
2687/// SetMakeClass for a data member within a class.
2688/// For example, the tutorial https://root.cern/doc/master/tree108__tree_8C.html
2689/// generates a ROOT file with a TTree. To read the temperature values,
2690/// you need either `tree->SetBranchAddress("fTemperature", &temp);` or
2691/// `tree->SetMakeClass(1); tree->GetBranch("fTemperature")->SetAddress(&temp);`.
2692
2694{
2695 if (TestBit(kDoNotProcess)) {
2696 return;
2697 }
2698 fReadEntry = -1;
2699 fFirstBasketEntry = -1;
2700 fNextBasketEntry = -1;
2701 fAddress = (char*) addr;
2702 for (Int_t i = 0; i < fNleaves; ++i) {
2704 Int_t offset = leaf->GetOffset();
2705 if (TestBit(kIsClone)) {
2706 offset = 0;
2707 }
2708 if (fAddress) leaf->SetAddress(fAddress + offset);
2709 else leaf->SetAddress(nullptr);
2710 }
2711}
2712
2713////////////////////////////////////////////////////////////////////////////////
2714/// Set the automatic delete bit.
2715///
2716/// This bit is used by TBranchObject::ReadBasket to decide if an object
2717/// referenced by a TBranchObject must be deleted or not before reading
2718/// a new entry.
2719///
2720/// If autodel is true, this existing object will be deleted, a new object
2721/// created by the default constructor, then read from disk by the streamer.
2722///
2723/// If autodel is false, the existing object is not deleted. Root assumes
2724/// that the user is taking care of deleting any internal object or array
2725/// (this can be done in the streamer).
2726
2728{
2729 if (autodel) {
2730 SetBit(kAutoDelete, true);
2731 } else {
2732 SetBit(kAutoDelete, false);
2733 }
2734}
2735
2736////////////////////////////////////////////////////////////////////////////////
2737/// Set the basket size
2738/// The function makes sure that the basket size is greater than fEntryOffsetlen
2739
2750
2751////////////////////////////////////////////////////////////////////////////////
2752/// Set address of this branch directly from a TBuffer to avoid streaming.
2753///
2754/// Note: We do not take ownership of the buffer.
2755
2757{
2758 // Check this is possible
2759 if ( (fNleaves != 1)
2760 || (strcmp("TLeafObject",fLeaves.UncheckedAt(0)->ClassName())!=0) ) {
2761 Error("TBranch::SetAddress","Filling from a TBuffer can only be done with a not split object branch. Request ignored.");
2762 } else {
2763 fReadEntry = -1;
2764 fNextBasketEntry = -1;
2765 fFirstBasketEntry = -1;
2766 // Note: We do not take ownership of the buffer.
2767 fEntryBuffer = buf;
2768 }
2769}
2770
2771////////////////////////////////////////////////////////////////////////////////
2772/// Set compression algorithm.
2773
2775{
2777 if (fCompress < 0) {
2779 } else {
2780 int level = fCompress % 100;
2781 fCompress = 100 * algorithm + level;
2782 }
2783
2785 for (Int_t i=0;i<nb;i++) {
2787 branch->SetCompressionAlgorithm(algorithm);
2788 }
2789}
2790
2791////////////////////////////////////////////////////////////////////////////////
2792/// Set compression level.
2793
2795{
2796 if (level < 0) level = 0;
2797 if (level > 99) level = 99;
2798 if (fCompress < 0) {
2799 fCompress = level;
2800 } else {
2801 int algorithm = fCompress / 100;
2803 fCompress = 100 * algorithm + level;
2804 }
2805
2807 for (Int_t i=0;i<nb;i++) {
2809 branch->SetCompressionLevel(level);
2810 }
2811}
2812
2813////////////////////////////////////////////////////////////////////////////////
2814/// Set compression settings.
2815
2817{
2819
2821 for (Int_t i=0;i<nb;i++) {
2823 branch->SetCompressionSettings(settings);
2824 }
2825}
2826
2827////////////////////////////////////////////////////////////////////////////////
2828/// Update the default value for the branch's fEntryOffsetLen if and only if
2829/// it was already non zero (and the new value is not zero)
2830/// If updateExisting is true, also update all the existing branches.
2831
2833{
2834 if (fEntryOffsetLen && newdefault) {
2836 }
2837 if (updateExisting) {
2838 TIter next( GetListOfBranches() );
2839 TBranch *b;
2840 while ( ( b = (TBranch*)next() ) ) {
2841 b->SetEntryOffsetLen( newdefault, true );
2842 }
2843 }
2844}
2845
2846////////////////////////////////////////////////////////////////////////////////
2847/// Set the number of entries in this branch.
2848
2854
2855////////////////////////////////////////////////////////////////////////////////
2856/// Set file where this branch writes/reads its buffers.
2857/// By default the branch buffers reside in the file where the
2858/// Tree was created.
2859/// If the file name where the tree was created is an absolute
2860/// path name or an URL (e.g. or root://host/...)
2861/// and if the fname is not an absolute path name or an URL then
2862/// the path of the tree file is prepended to fname to make the
2863/// branch file relative to the tree file. In this case one can
2864/// move the tree + all branch files to a different location in
2865/// the file system and still access the branch files.
2866/// The ROOT file will be connected only when necessary.
2867/// If called by TBranch::Fill (via TBasket::WriteFile), the file
2868/// will be created with the option "recreate".
2869/// If called by TBranch::GetEntry (via TBranch::GetBasket), the file
2870/// will be opened in read mode.
2871/// To open a file in "update" mode or with a certain compression
2872/// level, use TBranch::SetFile(TFile *file).
2873
2875{
2876 if (file == nullptr) file = fTree->GetCurrentFile();
2877 fDirectory = (TDirectory*)file;
2878 if (file == fTree->GetCurrentFile()) fFileName = "";
2879 else fFileName = file->GetName();
2880
2881 if (file && fCompress == -1) {
2883 }
2884
2885 // Apply to all existing baskets.
2887 TBasket *basket;
2888 while ((basket = (TBasket*)nextb())) {
2889 basket->SetParent(file);
2890 }
2891
2892 // Apply to sub-branches as well.
2893 TIter next(GetListOfBranches());
2894 TBranch *branch;
2895 while ((branch = (TBranch*)next())) {
2896 branch->SetFile(file);
2897 }
2898}
2899
2900////////////////////////////////////////////////////////////////////////////////
2901/// Set file where this branch writes/reads its buffers.
2902/// By default the branch buffers reside in the file where the
2903/// Tree was created.
2904/// If the file name where the tree was created is an absolute
2905/// path name or an URL (e.g. root://host/...)
2906/// and if the fname is not an absolute path name or an URL then
2907/// the path of the tree file is prepended to fname to make the
2908/// branch file relative to the tree file. In this case one can
2909/// move the tree + all branch files to a different location in
2910/// the file system and still access the branch files.
2911/// The ROOT file will be connected only when necessary.
2912/// If called by TBranch::Fill (via TBasket::WriteFile), the file
2913/// will be created with the option "recreate".
2914/// If called by TBranch::GetEntry (via TBranch::GetBasket), the file
2915/// will be opened in read mode.
2916/// To open a file in "update" mode or with a certain compression
2917/// level, use TBranch::SetFile(TFile *file).
2918
2919void TBranch::SetFile(const char* fname)
2920{
2921 fFileName = fname;
2922 fDirectory = nullptr;
2923
2924 //apply to sub-branches as well
2925 TIter next(GetListOfBranches());
2926 TBranch *branch;
2927 while ((branch = (TBranch*)next())) {
2928 branch->SetFile(fname);
2929 }
2930}
2931
2932////////////////////////////////////////////////////////////////////////////////
2933/// Set the branch in a mode where the object are decomposed
2934/// (Also known as MakeClass mode).
2935/// Return whether the setting was possible (it is not possible for
2936/// TBranch and TBranchObject).
2937
2938bool TBranch::SetMakeClass(bool /* decomposeObj */)
2939{
2940 // Regular TBranch and TBrancObject can not be in makeClass mode
2941 return false;
2942}
2943
2944////////////////////////////////////////////////////////////////////////////////
2945/// Set object this branch is pointing to.
2946
2947void TBranch::SetObject(void * /* obj */)
2948{
2949 if (TestBit(kDoNotProcess)) {
2950 return;
2951 }
2952 Warning("SetObject","is not supported in TBranch objects");
2953}
2954
2955////////////////////////////////////////////////////////////////////////////////
2956/// Set branch status to Process or DoNotProcess.
2957
2958void TBranch::SetStatus(bool status)
2959{
2960 if (status) ResetBit(kDoNotProcess);
2961 else SetBit(kDoNotProcess);
2962}
2963
2964////////////////////////////////////////////////////////////////////////////////
2965/// Stream a class object
2966
2968{
2969 if (b.IsReading()) {
2970 UInt_t R__s, R__c;
2971 fTree = nullptr; // Will be set by TTree::Streamer
2972 fAddress = nullptr;
2973 gROOT->SetReadingObject(true);
2974
2975 // Reset transients.
2977 fCurrentBasket = nullptr;
2978 fFirstBasketEntry = -1;
2979 fNextBasketEntry = -1;
2980
2981 Version_t v = b.ReadVersion(&R__s, &R__c);
2982 if (v > 9) {
2983 b.ReadClassBuffer(TBranch::Class(), this, v, R__s, R__c);
2984
2985 if (fWriteBasket>=fBaskets.GetSize()) {
2987 }
2988 fDirectory = nullptr;
2990 for (Int_t i=0;i<fNleaves;i++) {
2992 leaf->SetBranch(this);
2993 }
2995 for (Int_t i=0;i<nbranches;i++) {
2997 br->fParent = this;
2998 }
2999
3000 fNBaskets = 0;
3001 for (Int_t j = fWriteBasket; j>=0; --j) {
3003 if (bk) {
3004 bk->SetBranch(this);
3005 // GetTree()->IncrementTotalBuffers(bk->GetBufferSize());
3006 ++fNBaskets;
3007 }
3008 }
3009 if (fWriteBasket >= fMaxBaskets) {
3010 //old versions may need this fix
3015
3016 }
3018 gROOT->SetReadingObject(false);
3019 if (IsA() == TBranch::Class()) {
3020 if (fNleaves == 0) {
3022 } else if (fNleaves == 1) {
3024 } else if (fNleaves == 2) {
3026 } else {
3028 }
3029 }
3030 return;
3031 }
3032 //====process old versions before automatic schema evolution
3033 Int_t n,i,j,ijunk;
3034 if (v > 5) {
3035 Stat_t djunk;
3037 if (v > 7) TAttFill::Streamer(b);
3038 b >> fCompress;
3039 b >> fBasketSize;
3040 b >> fEntryOffsetLen;
3041 b >> fWriteBasket;
3043 b >> fOffset;
3044 b >> fMaxBaskets;
3045 if (v > 6) b >> fSplitLevel;
3046 b >> djunk; fEntries = (Long64_t)djunk;
3049
3057 b >> isArray;
3058 b.ReadFastArray(fBasketBytes,fMaxBaskets);
3059 b >> isArray;
3060 for (i=0;i<fMaxBaskets;i++) {b >> ijunk; fBasketEntry[i] = ijunk;}
3061 b >> isArray;
3062 for (i=0;i<fMaxBaskets;i++) {
3063 if (isArray == 2) b >> fBasketSeek[i];
3064 else {Int_t bsize; b >> bsize; fBasketSeek[i] = (Long64_t)bsize;};
3065 }
3067 b.CheckByteCount(R__s, R__c, TBranch::IsA());
3068 fDirectory = nullptr;
3070 for (i=0;i<fNleaves;i++) {
3072 leaf->SetBranch(this);
3073 }
3074 fNBaskets = 0;
3075 for (j = fWriteBasket; j >= 0; --j) {
3077 if (bk) {
3078 bk->SetBranch(this);
3079 //GetTree()->IncrementTotalBuffers(bk->GetBufferSize());
3080 ++fNBaskets;
3081 }
3082 }
3083 if (fWriteBasket >= fMaxBaskets) {
3084 //old versions may need this fix
3089
3090 }
3091 // Check Byte Count is not needed since it was done in ReadBuffer
3093 gROOT->SetReadingObject(false);
3094 b.CheckByteCount(R__s, R__c, TBranch::IsA());
3095 if (IsA() == TBranch::Class()) {
3096 if (fNleaves == 0) {
3098 } else if (fNleaves == 1) {
3100 } else if (fNleaves == 2) {
3102 } else {
3104 }
3105 }
3106 return;
3107 }
3108 //====process very old versions
3109 Stat_t djunk;
3111 b >> fCompress;
3112 b >> fBasketSize;
3113 b >> fEntryOffsetLen;
3114 b >> fMaxBaskets;
3115 b >> fWriteBasket;
3117 b >> djunk; fEntries = (Long64_t)djunk;
3120 b >> fOffset;
3124 for (i=0;i<fNleaves;i++) {
3126 leaf->SetBranch(this);
3127 }
3129 for (j = fWriteBasket; j > 0; --j) {
3131 if (bk) {
3132 bk->SetBranch(this);
3133 //GetTree()->IncrementTotalBuffers(bk->GetBufferSize());
3134 }
3135 }
3137 b >> n;
3138 if (n > fMaxBaskets) {
3139 Error("Streamer",
3140 "Inconsistent number of baskets. This basket cannot be read. Read %d for the actual number of baskets "
3141 "while we read %d as the value of fMaxBaskets.",
3142 n, fMaxBaskets);
3143 MakeZombie();
3144 return;
3145 }
3146 for (i=0;i<n;i++) {b >> ijunk; fBasketEntry[i] = ijunk;}
3148 if (v > 4) {
3149 n = b.ReadArray(fBasketBytes);
3150 } else {
3151 for (n=0;n<fMaxBaskets;n++) fBasketBytes[n] = 0;
3152 }
3153 if (v < 2) {
3155 for (n=0;n<fWriteBasket;n++) {
3156 TBasket *basket = GetBasketImpl(n, nullptr);
3157 fBasketSeek[n] = basket ? basket->GetSeekKey() : 0;
3158 }
3159 } else {
3161 b >> n;
3162 for (n=0;n<fMaxBaskets;n++) {
3163 Int_t aseek;
3164 b >> aseek;
3166 }
3167 }
3168 if (v > 2) {
3170 }
3171 fDirectory = nullptr;
3172 if (v < 4) SetAutoDelete(true);
3174 gROOT->SetReadingObject(false);
3175 b.CheckByteCount(R__s, R__c, TBranch::IsA());
3176 //====end of old versions
3177 if (IsA() == TBranch::Class()) {
3178 if (fNleaves == 0) {
3180 } else if (fNleaves == 1) {
3182 } else if (fNleaves == 2) {
3184 } else {
3186 }
3187 }
3188 } else {
3192 if (fMaxBaskets < 10) fMaxBaskets = 10;
3193
3194 TBasket **stash = new TBasket *[lastBasket];
3195 for (Int_t i = 0; i < lastBasket; ++i) {
3197 if (ba && (fBasketBytes[i] || ba->GetNevBuf()==0)) {
3198 // Already on disk or empty.
3199 stash[i] = ba;
3200 fBaskets[i] = nullptr;
3201 } else {
3202 stash[i] = nullptr;
3203 }
3204 }
3205
3206 b.WriteClassBuffer(TBranch::Class(), this);
3207
3208 for (Int_t i = 0; i < lastBasket; ++i) {
3209 if (stash[i]) fBaskets[i] = stash[i];
3210 }
3211
3212 delete[] stash;
3214 }
3215}
3216
3217////////////////////////////////////////////////////////////////////////////////
3218/// Write the current basket to disk and return the number of bytes
3219/// written to the file.
3220
3222{
3223 Int_t nevbuf = basket->GetNevBuf();
3224 if (fEntryOffsetLen > 10 && (4*nevbuf) < fEntryOffsetLen ) {
3225 // Make sure that the fEntryOffset array does not stay large unnecessarily.
3226 fEntryOffsetLen = nevbuf < 3 ? 10 : 4*nevbuf; // assume some fluctuations.
3227 } else if (fEntryOffsetLen && nevbuf > fEntryOffsetLen) {
3228 // Increase the array ...
3229 fEntryOffsetLen = 2*nevbuf; // assume some fluctuations.
3230 }
3231
3232 // Note: captures `basket`, `where`, and `this` by value; modifies the TBranch and basket,
3233 // as we make a copy of the pointer. We cannot capture `basket` by reference as the pointer
3234 // itself might be modified after `WriteBasketImpl` exits.
3235 auto doUpdates = [this, basket, where]() {
3236 Int_t nout = basket->WriteBuffer(); // Write buffer
3237 if (nout < 0)
3238 Error("WriteBasketImpl", "basket's WriteBuffer failed.");
3239 fBasketBytes[where] = basket->GetNbytes();
3240 fBasketSeek[where] = basket->GetSeekKey();
3241 Int_t addbytes = basket->GetObjlen() + basket->GetKeylen();
3242 TBasket *reusebasket = nullptr;
3243 if (nout>0) {
3244 // The Basket was written so we can now safely reuse it.
3245 fBaskets[where] = nullptr;
3246
3248 reusebasket->WriteReset();
3249
3250 fZipBytes += nout;
3254#ifdef R__TRACK_BASKET_ALLOC_TIME
3255 fTree->AddAllocationTime(reusebasket->GetResetAllocationTime());
3256#endif
3257 fTree->AddAllocationCount(reusebasket->GetResetAllocationCount());
3258 }
3259
3260 if (where==fWriteBasket) {
3261 ++fWriteBasket;
3262 if (fWriteBasket >= fMaxBaskets) {
3264 }
3266 // The 'current' basket has Reset, so if we need it we will need
3267 // to reload it.
3268 fCurrentBasket = nullptr;
3269 fFirstBasketEntry = -1;
3270 fNextBasketEntry = -1;
3271 }
3274 } else {
3275 --fNBaskets;
3276 fBaskets[where] = nullptr;
3277 basket->DropBuffers();
3278 if (basket == fCurrentBasket) {
3279 fCurrentBasket = nullptr;
3280 fFirstBasketEntry = -1;
3281 fNextBasketEntry = -1;
3282 }
3283 delete basket;
3284 }
3285 return nout;
3286 };
3287 if (imtHelper) {
3288 imtHelper->Run(doUpdates);
3289 return 0;
3290 } else {
3291 return doUpdates();
3292 }
3293}
3294
3295////////////////////////////////////////////////////////////////////////////////
3296///set the first entry number (case of TBranchSTL)
3297
3299{
3301 fEntries = 0;
3303 if( fBasketEntry )
3304 fBasketEntry[0] = entry;
3305 for( Int_t i = 0; i < fBranches.GetEntriesFast(); ++i )
3306 ((TBranch*)fBranches[i])->SetFirstEntry( entry );
3307}
3308
3309////////////////////////////////////////////////////////////////////////////////
3310/// If the branch address is not set, we set all addresses starting with
3311/// the top level parent branch.
3312
3314{
3315 SetAddress(nullptr); // in some cases, this triggers setting of the address
3316}
3317
3318////////////////////////////////////////////////////////////////////////////////
3319/// Refresh the value of fDirectory (i.e. where this branch writes/reads its buffers)
3320/// with the current value of fTree->GetCurrentFile unless this branch has been
3321/// redirected to a different file. Also update the sub-branches.
3322
3324{
3325 TFile *file = fTree->GetCurrentFile();
3326 if (fFileName.Length() == 0) {
3327 fDirectory = file;
3328
3329 // Apply to all existing baskets.
3331 TBasket *basket;
3332 while ((basket = (TBasket*)nextb())) {
3333 basket->SetParent(file);
3334 }
3335 }
3336
3337 // Apply to sub-branches as well.
3338 TIter next(GetListOfBranches());
3339 TBranch *branch;
3340 while ((branch = (TBranch*)next())) {
3341 branch->UpdateFile();
3342 }
3343}
void tobuf(char *&buf, Bool_t x)
Definition Bytes.h:55
#define R__likely(expr)
Definition RConfig.hxx:569
#define R__unlikely(expr)
Definition RConfig.hxx:568
#define b(i)
Definition RSha256.hxx:100
size_t size(const MatrixT &matrix)
retrieve the size of a square matrix
int Int_t
Signed integer 4 bytes (int)
Definition RtypesCore.h:60
short Version_t
Class version identifier (short)
Definition RtypesCore.h:80
char Char_t
Character 1 byte (char)
Definition RtypesCore.h:52
unsigned int UInt_t
Unsigned integer 4 bytes (unsigned int)
Definition RtypesCore.h:61
float Float_t
Float 4 bytes (float)
Definition RtypesCore.h:72
constexpr Ssiz_t kNPOS
The equivalent of std::string::npos for the ROOT class TString.
Definition RtypesCore.h:132
long long Long64_t
Portable signed long integer 8 bytes.
Definition RtypesCore.h:84
const char Option_t
Option string (const char)
Definition RtypesCore.h:81
const UInt_t kNewClassTag
const UInt_t kByteCountMask
ROOT::Detail::TRangeCast< T, true > TRangeDynCast
TRangeDynCast is an adapter class that allows the typed iteration through a TCollection.
EDataType
Definition TDataType.h:28
@ kOther_t
Definition TDataType.h:32
#define R__ASSERT(e)
Checks condition e and reports a fatal error if it's false.
Definition TError.h:130
#define N
Option_t Option_t option
Option_t Option_t TPoint TPoint const char GetTextMagnitude GetFillStyle GetLineColor GetLineWidth GetMarkerStyle GetTextAlign GetTextColor GetTextSize void char Point_t Rectangle_t WindowAttributes_t Float_t Float_t Float_t Int_t Int_t UInt_t UInt_t Rectangle_t Int_t Int_t Window_t TString Int_t GCValues_t GetPrimarySelectionOwner GetDisplay GetScreen GetColormap GetNativeEvent const char const char dpyName wid window const char font_name cursor keysym reg const char only_if_exist regb h Point_t winding char text const char depth char const char Int_t count const char ColorStruct_t color const char Pixmap_t Pixmap_t PictureAttributes_t attr const char char ret_data h unsigned char height h offset
Option_t Option_t TPoint TPoint const char GetTextMagnitude GetFillStyle GetLineColor GetLineWidth GetMarkerStyle GetTextAlign GetTextColor GetTextSize void char Point_t Rectangle_t WindowAttributes_t Float_t Float_t Float_t Int_t Int_t UInt_t UInt_t Rectangle_t result
Option_t Option_t TPoint TPoint const char GetTextMagnitude GetFillStyle GetLineColor GetLineWidth GetMarkerStyle GetTextAlign GetTextColor GetTextSize void char Point_t Rectangle_t WindowAttributes_t Float_t Float_t Float_t Int_t Int_t UInt_t UInt_t Rectangle_t Int_t Int_t Window_t child
Option_t Option_t TPoint TPoint const char GetTextMagnitude GetFillStyle GetLineColor GetLineWidth GetMarkerStyle GetTextAlign GetTextColor GetTextSize void char Point_t Rectangle_t WindowAttributes_t Float_t Float_t Float_t Int_t Int_t UInt_t UInt_t Rectangle_t Int_t Int_t Window_t TString Int_t GCValues_t GetPrimarySelectionOwner GetDisplay GetScreen GetColormap GetNativeEvent const char const char dpyName wid window const char font_name cursor keysym reg const char only_if_exist regb h Point_t winding char text const char depth char const char Int_t count const char ColorStruct_t color const char Pixmap_t Pixmap_t PictureAttributes_t attr const char char ret_data h unsigned char height h Atom_t Int_t ULong_t ULong_t unsigned char prop_list Atom_t Atom_t Atom_t Time_t UChar_t len
Option_t Option_t TPoint TPoint const char mode
char name[80]
Definition TGX11.cxx:142
int nentries
R__EXTERN TVirtualMutex * gROOTMutex
Definition TROOT.h:63
#define gROOT
Definition TROOT.h:417
void Printf(const char *fmt,...)
Formats a string in a circular formatting buffer and prints the string.
Definition TString.cxx:2584
R__EXTERN TSystem * gSystem
Definition TSystem.h:582
#define R__LOCKGUARD_IMT(mutex)
#define R__LOCKGUARD(mutex)
#define gPad
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...
Fill Area Attributes class.
Definition TAttFill.h:21
virtual void Streamer(TBuffer &)
Manages buffers for branches of a Tree.
Definition TBasket.h:34
A TTree is a list of TBranches.
Definition TBranch.h:93
virtual TLeaf * GetLeaf(const char *name) const
Return pointer to the 1st Leaf named name in thisBranch.
Definition TBranch.cxx:2053
virtual bool GetMakeClass() const
Return whether this branch is in a mode where the object are decomposed or not (Also known as MakeCla...
Definition TBranch.cxx:2115
virtual void SetupAddresses()
If the branch address is not set, we set all addresses starting with the top level parent branch.
Definition TBranch.cxx:3313
virtual void ResetAddress()
Reset the address of the branch.
Definition TBranch.cxx:2649
TString fFileName
Name of file where buffers are stored ("" if in same file as Tree header)
Definition TBranch.h:158
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
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:1892
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:128
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:85
void SetCompressionSettings(Int_t settings=ROOT::RCompressionSetting::EDefaults::kUseCompiledDefault)
Set compression settings.
Definition TBranch.cxx:2816
const char * GetIconName() const override
Return icon name depending on type of branch.
Definition TBranch.cxx:1330
Int_t BackFill()
Loop on all leaves of this branch to back fill Basket buffer.
Definition TBranch.cxx:678
~TBranch() override
Destructor.
Definition TBranch.cxx:448
Int_t fMaxBaskets
Maximum number of Baskets so far.
Definition TBranch.h:134
Long64_t fTotBytes
Total number of bytes in all leaves before compression.
Definition TBranch.h:145
TBuffer * fTransientBuffer
! Pointer to the current transient buffer.
Definition TBranch.h:160
virtual void ReadBasket(TBuffer &b)
Loop on all leaves of this branch to read Basket buffer.
Definition TBranch.cxx:2451
TTree * GetTree() const
Definition TBranch.h:261
static TClass * Class()
FillLeaves_t fFillLeaves
! Pointer to the FillLeaves implementation to use.
Definition TBranch.h:172
virtual TString GetFullName() const
Return the 'full' name of the branch.
Definition TBranch.cxx:2029
@ kAutoDelete
Definition TBranch.h:119
@ 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:121
@ kIsClone
To indicate a TBranchClones.
Definition TBranch.h:112
@ kDoNotProcess
Active bit for branches.
Definition TBranch.h:111
TObjArray fLeaves
-> List of leaves of this branch
Definition TBranch.h:148
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:156
virtual void DropBaskets(Option_t *option="")
Loop on all branch baskets.
Definition TBranch.cxx:755
TObjArray * GetListOfBranches()
Definition TBranch.h:255
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:161
void ReadLeavesImpl(TBuffer &b)
Loop on all leaves of this branch to read Basket buffer.
Definition TBranch.cxx:2459
Int_t fOffset
Offset of this branch.
Definition TBranch.h:133
Long64_t * fBasketEntry
[fMaxBaskets] Table of first entry in each basket
Definition TBranch.h:151
Int_t GetEntriesSerialized(Long64_t N, TBuffer &user_buf)
Definition TBranch.h:194
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:298
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:1704
TIOFeatures GetIOFeatures() const
Returns the IO settings currently in use for this branch.
Definition TBranch.cxx:2253
TClass * IsA() const override
Definition TBranch.h:304
void FillLeavesImpl(TBuffer &b)
Loop on all leaves of this branch to fill Basket buffer.
Definition TBranch.cxx:2494
Long64_t fReadEntry
! Current entry number when reading
Definition TBranch.h:139
void Print(Option_t *option="") const override
Print TBranch parameters.
Definition TBranch.cxx:2339
static void ResetCount()
Static function resetting fgCount.
Definition TBranch.cxx:2672
TBranch * GetSubBranch(const TBranch *br) const
Find the parent branch of child.
Definition TBranch.cxx:2162
ReadLeaves_t fReadLeaves
! Pointer to the ReadLeaves implementation to use.
Definition TBranch.h:170
virtual void SetObject(void *objadd)
Set object this branch is pointing to.
Definition TBranch.cxx:2947
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:2485
virtual void AddBasket(TBasket &b, bool ondisk, Long64_t startEntry)
Add the basket to this branch.
Definition TBranch.cxx:543
virtual void SetAddress(void *add)
Set address of this branch.
Definition TBranch.cxx:2693
static Int_t fgCount
! branch counter
Definition TBranch.h:125
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:222
Int_t fNBaskets
! Number of baskets in memory
Definition TBranch.h:135
void ReadLeaves1Impl(TBuffer &b)
Read one leaf without the overhead of a loop.
Definition TBranch.cxx:2477
Int_t GetBulkEntries(Long64_t, TBuffer &)
Read a basket of events into the given buffer with byte swapping.
Definition TBranch.cxx:1470
virtual void SetFile(TFile *file=nullptr)
Set file where this branch writes/reads its buffers.
Definition TBranch.cxx:2874
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:1760
virtual void SetAutoDelete(bool autodel=true)
Set the automatic delete bit.
Definition TBranch.cxx:2727
Long64_t fZipBytes
Total number of bytes in all leaves after compression.
Definition TBranch.h:146
TIOFeatures fIOFeatures
IO features for newly-created baskets.
Definition TBranch.h:132
void Browse(TBrowser *b) override
Browser interface.
Definition TBranch.cxx:697
void SetCompressionAlgorithm(Int_t algorithm=ROOT::RCompressionSetting::EAlgorithm::kUseGlobal)
Set compression algorithm.
Definition TBranch.cxx:2774
virtual void SetEntryOffsetLen(Int_t len, bool updateSubBranches=false)
Update the default value for the branch's fEntryOffsetLen if and only if it was already non zero (and...
Definition TBranch.cxx:2832
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:167
TObjArray * GetListOfBaskets()
Definition TBranch.h:254
virtual void SetBufferAddress(TBuffer *entryBuffer)
Set address of this branch directly from a TBuffer to avoid streaming.
Definition TBranch.cxx:2756
Long64_t GetEntries() const
Definition TBranch.h:260
Int_t fNleaves
! Number of leaves
Definition TBranch.h:137
Int_t fSplitLevel
Branch split level.
Definition TBranch.h:136
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:3221
virtual void UpdateFile()
Refresh the value of fDirectory (i.e.
Definition TBranch.cxx:3323
Int_t * fBasketBytes
[fMaxBaskets] Length of baskets on file
Definition TBranch.h:150
Long64_t fNextBasketEntry
! Next entry that will requires us to go to the next basket
Definition TBranch.h:141
bool IsAutoDelete() const
Return true if an existing object in a TBranchObject must be deleted.
Definition TBranch.cxx:2261
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:1851
TObjArray fBranches
-> List of Branches of this branch
Definition TBranch.h:147
virtual void KeepCircular(Long64_t maxEntries)
keep a maximum of fMaxEntries in memory
Definition TBranch.cxx:2281
virtual void SetStatus(bool status=true)
Set branch status to Process or DoNotProcess.
Definition TBranch.cxx:2958
virtual void ResetAfterMerge(TFileMergeInfo *)
Reset a Branch.
Definition TBranch.cxx:2596
void ReadLeaves0Impl(TBuffer &b)
Read zero leaves without the overhead of a loop.
Definition TBranch.cxx:2470
bool SupportsBulkRead() const
Returns true if this branch supports bulk IO, false otherwise.
Definition TBranch.cxx:1429
TString GetRealFileName() const
Get real file name.
Definition TBranch.cxx:2066
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:157
void PrintCacheInfo() const
Print the information we have about which basket is currently cached and whether they have been 'used...
Definition TBranch.cxx:2443
TObjArray fBaskets
-> List of baskets of this branch
Definition TBranch.h:149
virtual Int_t LoadBaskets()
Baskets associated to this branch are forced to be in memory.
Definition TBranch.cxx:2307
TBranch * fMother
! Pointer to top-level parent branch in the tree.
Definition TBranch.h:154
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:2218
TBranch * fParent
! Pointer to parent branch.
Definition TBranch.h:155
Int_t WriteBasket(TBasket *basket, Int_t where)
Definition TBranch.h:184
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
bool fSkipZip
! After being read, the buffer will not be unzipped.
Definition TBranch.h:164
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:1832
bool IsFolder() const override
Return true if more than one leaf or browsables, false otherwise.
Definition TBranch.cxx:2269
virtual void SetFirstEntry(Long64_t entry)
set the first entry number (case of TBranchSTL)
Definition TBranch.cxx:3298
Long64_t GetTotalSize(Option_t *option="") const
Return total number of bytes in the branch (including current buffer)
Definition TBranch.cxx:2199
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:2236
virtual void Refresh(TBranch *b)
Refresh this branch using new information in b This function is called by TTree::Refresh.
Definition TBranch.cxx:2506
virtual bool SetMakeClass(bool decomposeObj=true)
Set the branch in a mode where the object are decomposed (Also known as MakeClass mode).
Definition TBranch.cxx:2938
Int_t fWriteBasket
Last basket number written.
Definition TBranch.h:129
Long64_t * fBasketSeek
[fMaxBaskets] Addresses of baskets on file
Definition TBranch.h:152
TObjArray * GetListOfLeaves()
Definition TBranch.h:256
virtual void SetEntries(Long64_t entries)
Set the number of entries in this branch.
Definition TBranch.cxx:2849
Int_t fReadBasket
! Current basket number when reading
Definition TBranch.h:138
Long64_t fFirstEntry
Number of the first entry in this branch.
Definition TBranch.h:144
TBasket * fExtraBasket
! Allocated basket not currently holding any data.
Definition TBranch.h:131
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:2106
Int_t fBasketSize
Initial Size of Basket Buffer.
Definition TBranch.h:127
Int_t Fill()
Definition TBranch.h:214
virtual void Reset(Option_t *option="")
Reset a Branch.
Definition TBranch.cxx:2555
virtual void SetBasketSize(Int_t bufsize)
Set the basket size The function makes sure that the basket size is greater than fEntryOffsetlen.
Definition TBranch.cxx:2740
Long64_t fEntryNumber
Current entry number (last one filled in this branch)
Definition TBranch.h:130
TBranch * GetMother() const
Get our top-level parent branch in the tree.
Definition TBranch.cxx:2125
Int_t fCompress
Compression level and algorithm.
Definition TBranch.h:126
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:159
TBasket * fCurrentBasket
! Pointer to the current basket.
Definition TBranch.h:142
Long64_t fFirstBasketEntry
! First entry in the current basket.
Definition TBranch.h:140
void SetCompressionLevel(Int_t level=ROOT::RCompressionSetting::ELevel::kUseMin)
Set compression level.
Definition TBranch.cxx:2794
void Streamer(TBuffer &) override
Stream a class object.
Definition TBranch.cxx:2967
Long64_t fEntries
Number of entries.
Definition TBranch.h:143
TBasket * GetFreshCluster(TBuffer *user_buffer)
Drops the cluster two behind the current cluster and returns a fresh basket by either reusing or crea...
Definition TBranch.cxx:1951
TTree * fTree
! Pointer to Tree header
Definition TBranch.h:153
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
void Expand(Int_t newsize, Bool_t copy=kTRUE)
Expand (or shrink) the I/O buffer to newsize bytes.
Definition TBuffer.cxx:222
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 SetBufferOffset(Int_t offset=0)
Definition TBuffer.h:93
void SetReadMode()
Set buffer in read mode.
Definition TBuffer.cxx:301
TClass * IsA() const override
Definition TBuffer.h:340
virtual char * ReadString(char *s, Int_t max)=0
@ kMinimalSize
Definition TBuffer.h:78
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:84
An array of clone (identical) objects.
void Browse(TBrowser *b) override
Browse this collection (called by TBrowser).
virtual Int_t GetSize() const
Return the capacity of the collection, i.e.
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:221
TObject * FindObject(const char *name) const override
Find object by name in the list of memory objects.
virtual Bool_t IsWritable() const
Definition TDirectory.h:238
A cache when reading files over the network.
A class to pass information from the TFileMerger to the objects being merged.
A file, usually with extension .root, that stores data and code in the form of serialized objects in ...
Definition TFile.h:130
Int_t GetCompressionLevel() const
Definition TFile.h:483
virtual void MakeFree(Long64_t first, Long64_t last)
Mark unused bytes on the file.
Definition TFile.cxx:1509
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:3801
void Close(Option_t *option="") override
Close a file.
Definition TFile.cxx:991
A TLeaf for an 8 bit Integer data type.
Definition TLeafB.h:26
A TLeaf for a variable length string.
Definition TLeafC.h:26
static TClass * Class()
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 long integer data type (Long_t, non-portable size).
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
A doubly linked list.
Definition TList.h:38
static TClass * Class()
The TNamed class is the base class for all named ROOT classes.
Definition TNamed.h:29
const char * GetName() const override
Returns name of object.
Definition TNamed.h:49
void Streamer(TBuffer &) override
Stream an object of class TObject.
const char * GetTitle() const override
Returns title of object.
Definition TNamed.h:50
TString fName
Definition TNamed.h:32
An array of TObjects.
Definition TObjArray.h:31
Int_t GetEntriesFast() const
Definition TObjArray.h:58
virtual void Expand(Int_t newSize)
Expand or shrink the array to newSize elements.
void AddAt(TObject *obj, Int_t idx) override
Add object at position ids.
virtual void AddAtAndExpand(TObject *obj, Int_t idx)
Add object at position idx.
void Streamer(TBuffer &) override
Stream all objects in the array to or from the I/O buffer.
Int_t GetEntries() const override
Return the number of objects in array (i.e.
void Delete(Option_t *option="") override
Remove all objects from the array AND delete all heap based objects.
TObject * At(Int_t idx) const override
Definition TObjArray.h:170
TObject * UncheckedAt(Int_t i) const
Definition TObjArray.h:90
TObject * Remove(TObject *obj) override
Remove object from array.
void SetLast(Int_t last)
Set index of last object in array, effectively truncating the array.
TObject * RemoveAt(Int_t idx) override
Remove object at index idx.
Int_t GetLast() const override
Return index of last object in array.
Int_t LowerBound() const
Definition TObjArray.h:97
void Add(TObject *obj) override
Definition TObjArray.h:68
R__ALWAYS_INLINE Bool_t TestBit(UInt_t f) const
Definition TObject.h:204
virtual const char * ClassName() const
Returns name of class to which the object belongs.
Definition TObject.cxx:225
virtual void Warning(const char *method, const char *msgfmt,...) const
Issue warning message.
Definition TObject.cxx:1081
R__ALWAYS_INLINE Bool_t IsZombie() const
Definition TObject.h:161
void SetBit(UInt_t f, Bool_t set)
Set or unset the user status bits as specified in f.
Definition TObject.cxx:885
virtual void Error(const char *method, const char *msgfmt,...) const
Issue error message.
Definition TObject.cxx:1095
virtual void Fatal(const char *method, const char *msgfmt,...) const
Issue fatal error message.
Definition TObject.cxx:1123
void MakeZombie()
Definition TObject.h:55
void ResetBit(UInt_t f)
Definition TObject.h:203
static Int_t * ReAllocInt(Int_t *vp, size_t size, size_t oldsize)
Reallocate (i.e.
Definition TStorage.cxx:257
static void * ReAlloc(void *vp, size_t size, size_t oldsize)
Reallocate (i.e.
Definition TStorage.cxx:182
Basic string class.
Definition TString.h:137
Ssiz_t Length() const
Definition TString.h:426
void ToLower()
Change string to lower-case.
Definition TString.cxx:1189
const char * Data() const
Definition TString.h:385
virtual void Streamer(TBuffer &)
Stream a string object.
Definition TString.cxx:1492
Bool_t Contains(const char *pat, ECaseCompare cmp=kExact) const
Definition TString.h:642
virtual Bool_t ExpandPathName(TString &path)
Expand a pathname getting rid of special shell characters like ~.
Definition TSystem.cxx:1289
virtual const char * BaseName(const char *pathname)
Base name of a file name. Base name of /user/root is root.
Definition TSystem.cxx:948
virtual Bool_t IsAbsoluteFileName(const char *dir)
Return true if dir is an absolute pathname.
Definition TSystem.cxx:965
virtual TString GetDirName(const char *pathname)
Return the directory name in pathname.
Definition TSystem.cxx:1046
Helper class to iterate over cluster of baskets.
Definition TTree.h:322
Long64_t Previous()
Move on to the previous cluster and return the starting entry of this previous cluster.
Definition TTree.cxx:720
Long64_t GetStartEntry()
Definition TTree.h:354
Long64_t Next()
Move on to the next cluster and return the starting entry of this next cluster.
Definition TTree.cxx:676
A TTree represents a columnar dataset.
Definition TTree.h:89
virtual TVirtualPerfStats * GetPerfStats() const
Definition TTree.h:601
virtual TClusterIterator GetClusterIterator(Long64_t firstentry)
Return an iterator over the cluster of baskets starting at firstentry.
Definition TTree.cxx:5570
void AddAllocationCount(UInt_t count)
Definition TTree.h:389
virtual TObjArray * GetListOfLeaves()
Definition TTree.h:584
TFile * GetCurrentFile() const
Return pointer to the current file.
Definition TTree.cxx:5582
void Draw(Option_t *opt) override
Default Draw method for all objects.
Definition TTree.h:486
virtual void IncrementTotalBuffers(Int_t nbytes)
Definition TTree.h:641
TDirectory * GetDirectory() const
Definition TTree.h:517
TTreeCache * GetReadCache(TFile *file) const
Find and return the TTreeCache registered with the file and which may contain branches for us.
Definition TTree.cxx:6572
virtual bool GetClusterPrefetch() const
Definition TTree.h:512
virtual TObjArray * GetListOfBranches()
Definition TTree.h:583
virtual void AddZipBytes(Int_t zip)
Definition TTree.h:384
virtual TBasket * CreateBasket(TBranch *)
Create a basket for this tree and given branch.
Definition TTree.cxx:3770
@ kOnlyFlushAtCluster
If set, the branch's buffers will grow until an event cluster boundary is hit, guaranteeing a basket ...
Definition TTree.h:308
@ kCircular
Definition TTree.h:304
virtual void AddTotBytes(Int_t tot)
Definition TTree.h:383
virtual Long64_t GetAutoFlush() const
Definition TTree.h:502
virtual Long64_t GetMaxVirtualSize() const
Definition TTree.h:595
This class represents a WWW compatible URL.
Definition TUrl.h:33
static Int_t FillListOfBrowsables(TList &list, const TBranch *branch, const TVirtualBranchBrowsable *parent=nullptr)
Askes all registered generators to fill their browsables into the list.
const Int_t n
Definition legend1.C:16
Short_t Max(Short_t a, Short_t b)
Returns the largest of a and b.
Definition TMathBase.h:249
Long64_t BinarySearch(Long64_t n, const T *array, T value)
Binary search in an array of n values to locate value.
Definition TMathBase.h:329
@ kUndefined
Undefined compression algorithm (must be kept the last of the list in case a new algorithm is added).
@ kUseMin
Compression level reserved when we are not sure what to use (1 is for the fastest compression)
Definition Compression.h:72
TLine l
Definition textangle.C:4