Logo ROOT  
Reference Guide
 
Loading...
Searching...
No Matches
TBasket.cxx
Go to the documentation of this file.
1// @(#)root/tree:$Id: 4e77188fbf1e7fd026a984989de66663c49b12fc $
2// Author: Rene Brun 19/01/96
3/*************************************************************************
4 * Copyright (C) 1995-2000, Rene Brun and Fons Rademakers. *
5 * All rights reserved. *
6 * *
7 * For the licensing terms see $ROOTSYS/LICENSE. *
8 * For the list of contributors see $ROOTSYS/README/CREDITS. *
9 *************************************************************************/
10
11#include <chrono>
12#include <limits>
13
14#include "TBasket.h"
15#include "TBuffer.h"
16#include "TBufferFile.h"
17#include "TTree.h"
18#include "TBranch.h"
19#include "TFile.h"
20#include "TLeaf.h"
21#include "TMath.h"
22#include "TROOT.h"
23#include "TTreeCache.h"
24#include "TVirtualMutex.h"
25#include "TVirtualPerfStats.h"
26#include "TTimeStamp.h"
27#include "ROOT/TIOFeatures.hxx"
28#include "RZip.h"
29
30#include <bitset>
31
32const UInt_t kDisplacementMask = 0xFF000000; // In the streamer the two highest bytes of
33 // the fEntryOffset are used to stored displacement.
34
35constexpr auto gMaxInt_t = std::numeric_limits<Int_t>::max();
36
37/** \class TBasket
38\ingroup tree
39
40Manages buffers for branches of a Tree.
41
42See picture in TTree.
43*/
44
45////////////////////////////////////////////////////////////////////////////////
46/// Default constructor.
47
51
52////////////////////////////////////////////////////////////////////////////////
53/// Constructor used during reading.
54
58
59////////////////////////////////////////////////////////////////////////////////
60/// Basket normal constructor, used during writing.
61
62TBasket::TBasket(const char *name, const char *title, TBranch *branch)
63 : TKey(branch->GetDirectory()), fBufferSize(branch->GetBasketSize()), fNevBufSize(branch->GetEntryOffsetLen()),
64 fHeaderOnly(true), fIOBits(branch->GetIOFeatures().GetFeatures())
65{
67 SetTitle(title);
68 fClassName = "TBasket";
69 fBuffer = nullptr;
71 fVersion += 1000;
72 if (branch->GetDirectory()) {
73 TFile *file = branch->GetFile();
74 fBufferRef->SetParent(file);
75 }
76 if (branch->GetTree()) {
77#ifdef R__USE_IMT
78 fCompressedBufferRef = branch->GetTransientBuffer(fBufferSize);
79#else
80 fCompressedBufferRef = branch->GetTree()->GetTransientBuffer(fBufferSize);
81#endif
86 }
87 }
92 fLast = fKeylen;
93 fBuffer = nullptr;
94 fHeaderOnly = false;
95 if (fNevBufSize) {
97 for (Int_t i=0;i<fNevBufSize;i++) fEntryOffset[i] = 0;
98 }
99 branch->GetTree()->IncrementTotalBuffers(fBufferSize);
100}
101
102////////////////////////////////////////////////////////////////////////////////
103/// Basket destructor.
104
106{
107 if (fDisplacement) delete [] fDisplacement;
109 if (fBufferRef) delete fBufferRef;
110 fBufferRef = nullptr;
111 fBuffer = nullptr;
112 fDisplacement= nullptr;
113 // Note we only delete the compressed buffer if we own it
116 fCompressedBufferRef = nullptr;
117 }
118 // TKey::~TKey will use fMotherDir to attempt to remove they key
119 // from the directory's list of key. A basket is never in that list
120 // and in some cases (eg. f = new TFile(); TTree t; delete f;) the
121 // directory is gone before the TTree.
122 fMotherDir = nullptr;
123}
124
125////////////////////////////////////////////////////////////////////////////////
126/// Increase the size of the current fBuffer up to newsize.
127
143
144////////////////////////////////////////////////////////////////////////////////
145/// Copy the basket of this branch onto the file to.
146
148{
152 Create(nout, to);
154 fHeaderOnly = true;
156 fHeaderOnly = false;
158
159 return nBytes>0 ? nBytes : -1;
160}
161
162////////////////////////////////////////////////////////////////////////////////
163/// Delete fEntryOffset array.
164
170
171////////////////////////////////////////////////////////////////////////////////
172/// Drop buffers of this basket if it is not the current basket.
173
175{
176 if (!fBuffer && !fBufferRef) return 0;
177
178 if (fDisplacement) delete [] fDisplacement;
180 if (fBufferRef) delete fBufferRef;
182 fBufferRef = nullptr;
183 fCompressedBufferRef = nullptr;
184 fBuffer = nullptr;
185 fDisplacement= nullptr;
186 fEntryOffset = nullptr;
188 return fBufferSize;
189}
190
191////////////////////////////////////////////////////////////////////////////////
192/// Calculates the entry offset array, if possible.
193///
194/// Result is cached, meaning that this should only be invoked once per basket.
195
197{
198 if (fEntryOffset != reinterpret_cast<Int_t *>(-1)) {
199 return fEntryOffset;
200 }
201
202 if (R__unlikely(!fBranch)) {
203 Error("GetCalculatedEntryOffset", "Basket entry offset calculation requested, but no associated TBranch!");
204 return nullptr;
205 }
206 if (R__unlikely(fBranch->GetNleaves() != 1)) {
207 Error("GetCalculatedEntryOffset", "Branch contains multiple leaves - unable to calculated entry offsets!");
208 return nullptr;
209 }
210 TLeaf *leaf = static_cast<TLeaf *>((*fBranch->GetListOfLeaves())[0]);
211 fEntryOffset = leaf->GenerateOffsetArray(fKeylen, fNevBuf);
212 return fEntryOffset;
213}
214
215////////////////////////////////////////////////////////////////////////////////
216/// Determine whether we can generate the offset array when this branch is read.
217///
218
220{
221 if (fBranch->GetNleaves() != 1) {
222 return false;
223 }
224 TLeaf *leaf = static_cast<TLeaf *>((*fBranch->GetListOfLeaves())[0]);
225 return leaf->CanGenerateOffsetArray();
226}
227
228////////////////////////////////////////////////////////////////////////////////
229/// Get pointer to buffer for internal entry.
230
240
241////////////////////////////////////////////////////////////////////////////////
242/// Load basket buffers in memory without unziping.
243/// This function is called by TTreeCloner.
244/// The function returns 0 in case of success, 1 in case of error.
245
247{
248 if (fBufferRef) {
249 // Reuse the buffer if it exist.
250 fBufferRef->Reset();
251
252 // We use this buffer both for reading and writing, we need to
253 // make sure it is properly sized for writing.
255 if (fBufferRef->BufferSize() < len) {
257 }
259 } else {
261 }
262 fBufferRef->SetParent(file);
263 char *buffer = fBufferRef->Buffer();
264 file->Seek(pos);
265 TFileCacheRead *pf = tree->GetReadCache(file);
266 if (pf) {
268 if (tree->GetPerfStats()) gPerfStats = tree->GetPerfStats();
269 Int_t st = pf->ReadBuffer(buffer,pos,len);
270 if (st < 0) {
271 return 1;
272 } else if (st == 0) {
273 // fOffset might have been changed via TFileCacheRead::ReadBuffer(), reset it
274 file->Seek(pos);
275 // If we are using a TTreeCache, disable reading from the default cache
276 // temporarily, to force reading directly from file
277 TTreeCache *fc = dynamic_cast<TTreeCache*>(file->GetCacheRead());
278 if (fc) fc->Disable();
279 Int_t ret = file->ReadBuffer(buffer,len);
280 if (fc) fc->Enable();
281 pf->AddNoCacheBytesRead(len);
282 pf->AddNoCacheReadCalls(1);
283 if (ret) {
284 return 1;
285 }
286 }
287 gPerfStats = temp;
288 // fOffset might have been changed via TFileCacheRead::ReadBuffer(), reset it
289 file->SetOffset(pos + len);
290 } else {
292 if (tree->GetPerfStats() != nullptr) gPerfStats = tree->GetPerfStats();
293 if (file->ReadBuffer(buffer,len)) {
294 gPerfStats = temp;
295 return 1; //error while reading
296 }
297 else gPerfStats = temp;
298 }
299
303
304 return 0;
305}
306
307////////////////////////////////////////////////////////////////////////////////
308/// Remove the first dentries of this basket, moving entries at
309/// dentries to the start of the buffer.
310
312{
313 Int_t i;
314
315 if (dentries >= fNevBuf) return;
317 Int_t moved;
318
320 if (entryOffset) {
323
324 // First store the original location in the fDisplacement array
325 // and record the new start offset
326
327 if (!fDisplacement) {
329 }
330 for (i = 0; i<(fNevBufSize-dentries); ++i) {
333 }
334 for (i = fNevBufSize-dentries; i<fNevBufSize; ++i) {
335 fDisplacement[i] = 0;
336 entryOffset[i] = 0;
337 }
338
339 } else {
340 // If there is no EntryOffset array, this means
341 // that each entry has the same size and that
342 // it does not point to other objects (hence there
343 // is no need for a displacement array).
346 }
347 TBuffer *buf = GetBufferRef();
348 char *buffer = buf->Buffer();
349 memmove(buffer+GetKeylen(),buffer+bufbegin,buf->Length()-bufbegin);
350 buf->SetBufferOffset(buf->Length()-moved);
351 fNevBuf -= dentries;
352}
353
354#define OLD_CASE_EXPRESSION fObjlen==fNbytes-fKeylen && GetBranch()->GetCompressionLevel()!=0 && file->GetVersion()<=30401
355////////////////////////////////////////////////////////////////////////////////
356/// By-passing buffer unzipping has been requested and is
357/// possible (only 1 entry in this basket).
358
360{
362
363 // Make sure that the buffer is set at the END of the data
365
366 // Indicate that this buffer is weird.
368
369 // Usage of this mode assume the existence of only ONE
370 // entry in this basket.
372 delete [] fDisplacement; fDisplacement = nullptr;
373
375 return 0;
376}
377
378////////////////////////////////////////////////////////////////////////////////
379/// We always create the TBuffer for the basket but it hold the buffer from the cache.
380
382{
383 if (fBufferRef) {
386 fBufferRef->Reset();
387 } else {
389 }
390 fBufferRef->SetParent(file);
391
393
394 if (IsZombie()) {
395 return -1;
396 }
397
399
402 }
403
405 return fObjlen+fKeylen;
406}
407
408////////////////////////////////////////////////////////////////////////////////
409/// Initialize a buffer for reading if it is not already initialized
410
412{
414 if (R__likely(bufferRef)) {
415 bufferRef->SetReadMode();
416 Int_t curBufferSize = bufferRef->BufferSize();
417 if (curBufferSize < len) {
418 // Experience shows that giving 5% "wiggle-room" decreases churn.
419 bufferRef->Expand(Int_t(len*1.05));
420 }
421 bufferRef->Reset();
423 } else {
425 }
426 result->SetParent(file);
427 return result;
428}
429
430////////////////////////////////////////////////////////////////////////////////
431/// Initialize the compressed buffer; either from the TTree or create a local one.
432
441
443{
444 if (fEntryOffset != reinterpret_cast<Int_t *>(-1)) {
445 delete[] fEntryOffset;
446 }
447 fEntryOffset = nullptr;
448}
449
450////////////////////////////////////////////////////////////////////////////////
451/// Read basket buffers in memory and cleanup.
452///
453/// Read a basket buffer. Check if buffers of previous ReadBasket
454/// should not be dropped. Remember, we keep buffers in memory up to
455/// fMaxVirtualSize.
456/// The function returns 0 in case of success, 1 in case of error
457/// This function was modified with the addition of the parallel
458/// unzipping, it will try to get the unzipped file from the cache
459/// receiving only a pointer to that buffer (so we shall not
460/// delete that pointer), although we get a new buffer in case
461/// it's not found in the cache.
462/// There is a lot of code duplication but it was necessary to assure
463/// the expected behavior when there is no cache.
464
466{
467 if(!fBranch->GetDirectory()) {
468 return -1;
469 }
470
471 bool oldCase;
474
475 // See if the cache has already unzipped the buffer for us.
476 TFileCacheRead *pf = nullptr;
477 {
478 R__LOCKGUARD_IMT(gROOTMutex); // Lock for parallel TTree I/O
479 pf = fBranch->GetTree()->GetReadCache(file);
480 }
481 if (pf) {
482 Int_t res = -1;
483 bool free = true;
484 char *buffer = nullptr;
485 res = pf->GetUnzipBuffer(&buffer, pos, len, &free);
486 if (R__unlikely(res >= 0)) {
487 len = ReadBasketBuffersUnzip(buffer, res, free, file);
488 // Note that in the kNotDecompressed case, the above function will return 0;
489 // In such a case, we should stop processing
490 if (len <= 0) return -len;
491 goto AfterBuffer;
492 }
493 }
494
495 // Determine which buffer to use, so that we can avoid a memcpy in case of
496 // the basket was not compressed.
499 // Initialize the buffer to hold the uncompressed data.
502 } else {
503 // Initialize the buffer to hold the compressed data.
506 }
507
508 // fBufferSize is likely to be change in the Streamer call (below)
509 // and we will re-add the new size later on.
511
512 if (!readBufferRef) {
513 Error("ReadBasketBuffers", "Unable to allocate buffer.");
514 return 1;
515 }
516
517 if (pf) {
519 if (fBranch->GetTree()->GetPerfStats() != nullptr) gPerfStats = fBranch->GetTree()->GetPerfStats();
520 Int_t st = 0;
521 {
522 R__LOCKGUARD_IMT(gROOTMutex); // Lock for parallel TTree I/O
523 st = pf->ReadBuffer(readBufferRef->Buffer(),pos,len);
524 }
525 if (st < 0) {
526 return 1;
527 } else if (st == 0) {
528 // Read directly from file, not from the cache
529 // If we are using a TTreeCache, disable reading from the default cache
530 // temporarily, to force reading directly from file
531 R__LOCKGUARD_IMT(gROOTMutex); // Lock for parallel TTree I/O
532 TTreeCache *fc = dynamic_cast<TTreeCache*>(file->GetCacheRead());
533 if (fc) fc->Disable();
534 Int_t ret = file->ReadBuffer(readBufferRef->Buffer(),pos,len);
535 if (fc) fc->Enable();
536 pf->AddNoCacheBytesRead(len);
537 pf->AddNoCacheReadCalls(1);
538 if (ret) {
539 return 1;
540 }
541 }
542 gPerfStats = temp;
543 } else {
544 // Read from the file and unstream the header information.
546 if (fBranch->GetTree()->GetPerfStats() != nullptr) gPerfStats = fBranch->GetTree()->GetPerfStats();
547 R__LOCKGUARD_IMT(gROOTMutex); // Lock for parallel TTree I/O
548 if (file->ReadBuffer(readBufferRef->Buffer(),pos,len)) {
549 gPerfStats = temp;
550 return 1;
551 }
552 else gPerfStats = temp;
553 }
555 if (IsZombie()) {
556 return 1;
557 }
558
560
561 // Are we done?
562 if (R__unlikely(readBufferRef == fBufferRef)) // We expect most basket to be compressed.
563 {
565 // The basket was really not compressed as expected.
566 goto AfterBuffer;
567 } else {
568 // Well, somehow the buffer was compressed anyway, we have the compressed data in the uncompressed buffer
569 // Make sure the compressed buffer is initialized, and memcpy.
572 Error("ReadBasketBuffers", "Unable to allocate buffer.");
573 return 1;
574 }
575 fBufferRef->Reset();
578 }
579 }
580 // Sanitize nbytes and lengths
581 if (fKeylen < 0) {
582 Error("ReadBasketBuffers", "The value of fKeylen is incorrect (%d) ; trying to recover by setting it to zero", fKeylen);
583 MakeZombie();
584 fKeylen = 0;
585 return 1;
586 }
587 if (fObjlen < 0) {
588 Error("ReadBasketBuffers", "The value of fObjlen is incorrect (%d) ; trying to recover by setting it to zero", fObjlen);
589 MakeZombie();
590 fObjlen = 0;
591 return 1;
592 }
593 if (fNbytes < 0) {
594 Error("ReadBasketBuffers", "The value of fNbytes is incorrect (%d) ; trying to recover by setting it to zero", fNbytes);
595 MakeZombie();
596 fNbytes = 0;
597 return 1;
598 }
599 if (fKeylen > (gMaxInt_t - fObjlen)) {
600 Error("ReadBasketBuffers", "fObjlen (%d) + fKeylen (%d) > max int (%d): cannot continue to read the key buffer.",
602 MakeZombie();
603 return 1;
604 }
605
606 // Initialize buffer to hold the uncompressed data
607 // Note that in previous versions we didn't allocate buffers until we verified
608 // the zip headers; this is no longer beforehand as the buffer lifetime is scoped
609 // to the TBranch.
614
616 // Case where ROOT thinks the buffer is compressed. Copy over the key and uncompress the object
617 if (fObjlen > fNbytes-fKeylen || oldCase) {
620 }
621
622 // Optional monitor for zip time profiling.
623 Double_t start = 0;
624 if (R__unlikely(gPerfStats)) {
625 start = TTimeStamp();
626 }
627
631 Int_t nin, nbuf;
632 Int_t nout = 0, noutot = 0, nintot = 0;
633
634 // Unzip all the compressed objects in the compressed object buffer.
635 while (true) {
636 // Check the header for errors.
638 Error("ReadBasketBuffers", "Inconsistency found in header (nin=%d, nbuf=%d)", nin, nbuf);
639 break;
640 }
641 if (R__unlikely(oldCase && (nin > fObjlen || nbuf > fObjlen))) {
642 //buffer was very likely not compressed in an old version
644 goto AfterBuffer;
645 }
646
648 if (!nout) break;
649 noutot += nout;
650 nintot += nin;
651 if (noutot >= fObjlen) break;
654 }
655
656 // Make sure the uncompressed numbers are consistent with header.
657 if (R__unlikely(noutot != fObjlen)) {
658 Error("ReadBasketBuffers", "fNbytes = %d, fKeylen = %d, fObjlen = %d, noutot = %d, nout=%d, nin=%d, nbuf=%d", fNbytes,fKeylen,fObjlen, noutot,nout,nin,nbuf);
660 return 1;
661 }
664 if (fBranch->GetTree()->GetPerfStats() != nullptr) gPerfStats = fBranch->GetTree()->GetPerfStats();
665 if (R__unlikely(gPerfStats)) {
666 gPerfStats->UnzipEvent(fBranch->GetTree(),pos,start,nintot,fObjlen);
667 }
668 gPerfStats = temp;
669 } else {
670 // Nothing is compressed - copy over wholesale.
672 }
673
675
677
678 // Read offsets table if needed.
679 // If there's no EntryOffsetLen in the branch -- or the fEntryOffset is marked to be calculated-on-demand --
680 // then we skip reading out.
681 if (!fBranch->GetEntryOffsetLen() || (fEntryOffset == reinterpret_cast<Int_t *>(-1))) {
682 return 0;
683 }
684 // At this point, we're required to read out an offset array.
685 ResetEntryOffset(); // TODO: every basket, we reset the offset array. Is this necessary?
686 // Could we instead switch to std::vector?
690 fEntryOffset = new Int_t[fNevBuf+1];
692 Warning("ReadBasketBuffers","basket:%s has fNevBuf=%d but fEntryOffset=0, pos=%lld, len=%d, fNbytes=%d, fObjlen=%d, trying to repair",GetName(),fNevBuf,pos,len,fNbytes,fObjlen);
693 return 0;
694 }
696 // In this case, we cannot regenerate the offset array at runtime -- but we wrote out an array of
697 // sizes instead of offsets (as sizes compress much better).
699 for (Int_t idx = 1; idx < fNevBuf + 1; idx++) {
700 fEntryOffset[idx] += fEntryOffset[idx - 1];
701 }
702 }
703 fReadEntryOffset = true;
704 // Read the array of displacement if any.
705 delete [] fDisplacement;
706 fDisplacement = nullptr;
707 if (fBufferRef->Length() != len) {
708 // There is more data in the buffer! It is the displacement
709 // array. If len is less than TBuffer::kMinimalSize the actual
710 // size of the buffer is too large, so we can not use the
711 // fBufferRef->BufferSize()
713 }
714
715 return 0;
716}
717
718////////////////////////////////////////////////////////////////////////////////
719/// Read basket buffers in memory and cleanup
720///
721/// Read first bytes of a logical record starting at position pos
722/// return record length (first 4 bytes of record).
723
725{
726 const Int_t len = 128;
727 char buffer[len];
729 file->GetRecordHeader(buffer, pos,len, fNbytes, fObjlen, keylen);
730 fKeylen = keylen;
731 return fNbytes;
732}
733
734////////////////////////////////////////////////////////////////////////////////
735/// Disown all references to the internal buffer - some other object likely now
736/// owns it.
737///
738/// This TBasket is now useless and invalid until it is told to adopt a buffer.
740{
741 fBufferRef = nullptr;
742}
743
744
745////////////////////////////////////////////////////////////////////////////////
746/// Adopt a buffer from an external entity
752
753////////////////////////////////////////////////////////////////////////////////
754/// Reset the read basket TBuffer memory allocation if needed.
755///
756/// This allows to reduce the number of memory allocation while avoiding to
757/// always use the maximum size.
758
760{
761 // By default, we don't reallocate.
762 fResetAllocation = false;
763#ifdef R__TRACK_BASKET_ALLOC_TIME
765#endif
766
767 // Downsize the buffer if needed.
768
769 const auto maxbaskets = fBranch->GetMaxBaskets();
771 return;
772
774
776 const auto basketbytes = fBranch->GetBasketBytes();
777
778 Int_t max_size = basketbytes[basketnumber];
779 for(Int_t b = basketnumber + 1; (b < maxbaskets) && (b < (basketnumber+10)); ++b) {
780 max_size = std::max(max_size, basketbytes[b]);
781 }
782
783 Float_t cx = 1;
784 if (fBranch->GetZipBytes())
786
787 Int_t target_size = static_cast<Int_t>(cx * target_mem_ratio * Float_t(max_size));
788
789 if (target_size && (curSize > target_size)) {
790 /// Only reduce the size if significant enough?
791 Int_t newSize = max_size + 512 - max_size % 512; // Wiggle room and alignment, as above.
792 // We only bother with a resize if it saves 8KB (two normal memory pages).
793 if ((newSize <= curSize - 8 * 1024) &&
794 (static_cast<Float_t>(curSize) / static_cast<Float_t>(newSize) > target_mem_ratio))
795 {
796 if (gDebug > 0) {
797 Info("ReadResetBuffer",
798 "Resizing %d to %d bytes (was %d); next 10 sizes are [%d, %d, %d, %d, %d, %d, %d, %d, %d, %d]. cx=%f ratio=%f max_size = %d ",
810 cx, target_mem_ratio, max_size);
811 }
812 fResetAllocation = true;
813#ifdef R__TRACK_BASKET_ALLOC_TIME
814 std::chrono::time_point<std::chrono::system_clock> start, end;
815 start = std::chrono::high_resolution_clock::now();
816#endif
817 fBufferRef->Expand(newSize, false); // Expand without copying the existing data.
818#ifdef R__TRACK_BASKET_ALLOC_TIME
819 end = std::chrono::high_resolution_clock::now();
820 auto us = std::chrono::duration_cast<std::chrono::microseconds>(end - start);
821 fResetAllocationTime = us.count();
822#endif
823 }
824 }
825}
826
827////////////////////////////////////////////////////////////////////////////////
828/// Reset the write basket to the starting state. i.e. as it was after calling
829/// the constructor (and potentially attaching a TBuffer.)
830/// Reduce memory used by fEntryOffset and the TBuffer if needed ..
831
833{
834 // By default, we don't reallocate.
835 fResetAllocation = false;
836#ifdef R__TRACK_BASKET_ALLOC_TIME
838#endif
839
840 // Name, Title, fClassName, fBranch
841 // stay the same.
842
843 // Downsize the buffer if needed.
844 // See if our current buffer size is significantly larger (>2x) than the historical average.
845 // If so, try decreasing it at this flush boundary to closer to the size from OptimizeBaskets
846 // (or this historical average).
848 // fBufferLen at this point is already reset, so use indirect measurements
850 Longptr_t newSize = -1;
851 if (curSize > 2*curLen)
852 {
854 if (curSize > 2*curBsize ) {
855 Longptr_t avgSize = (Longptr_t)(fBranch->GetTotBytes() / (1+fBranch->GetWriteBasket())); // Average number of bytes per basket so far
856 if (curSize > 2*avgSize) {
858 if (curLen > newSize) {
859 newSize = curLen;
860 }
861 if (avgSize > newSize) {
863 }
864 newSize = newSize + 512 - newSize%512; // Wiggle room and alignment (512 is same as in OptimizeBaskets)
865 }
866 }
867 }
868 // If fBufferRef grew since we last saw it, shrink it to "target memory ratio" of the occupied size
869 // This discourages us from having poorly-occupied buffers on branches with little variability.
870 //
871 // Does not help protect against a burst in event sizes, but does help in the cases where the basket
872 // size jumps from 4MB to 8MB while filling the basket, but we only end up utilizing 4.1MB.
873 //
874 // The above code block is meant to protect against extremely large events.
875
878 Int_t target_size = static_cast<Int_t>(target_mem_ratio * Float_t(max_size));
879 if (max_size && (curSize > target_size) && (newSize == -1)) {
881 newSize = newSize + 512 - newSize % 512; // Wiggle room and alignment, as above.
882 // We only bother with a resize if it saves 8KB (two normal memory pages).
883 if ((newSize > curSize - 8 * 1024) ||
884 (static_cast<Float_t>(curSize) / static_cast<Float_t>(newSize) < target_mem_ratio)) {
885 newSize = -1;
886 } else if (gDebug > 0) {
887 Info("Reset", "Resizing to %ld bytes (was %d); last three sizes were [%d, %d, %d].", newSize, curSize,
889 }
890 }
891
892 if (newSize != -1) {
893 fResetAllocation = true;
894#ifdef R__TRACK_BASKET_ALLOC_TIME
895 std::chrono::time_point<std::chrono::system_clock> start, end;
896 start = std::chrono::high_resolution_clock::now();
897#endif
898 fBufferRef->Expand(newSize,false); // Expand without copying the existing data.
899#ifdef R__TRACK_BASKET_ALLOC_TIME
900 end = std::chrono::high_resolution_clock::now();
901 auto us = std::chrono::duration_cast<std::chrono::microseconds>(end - start);
902 fResetAllocationTime = us.count();
903#endif
904 }
905
906 // Record the actual occupied size of the buffer.
909
910 TKey::Reset();
911
913 if (newNevBufSize==0) {
915 } else if ((newNevBufSize != fNevBufSize) || (fEntryOffset <= reinterpret_cast<Int_t *>(-1))) {
918 }
920
921 fNevBuf = 0;
923 fEntryOffset = nullptr;
925 fDisplacement= nullptr;
926 fBuffer = nullptr;
927
928 fBufferRef->Reset();
930
931 fHeaderOnly = true;
932 fLast = 0; //Must initialize before calling Streamer()
933
935
938 fLast = fKeylen;
939 fBuffer = nullptr;
940 fHeaderOnly = false;
943 if (fNevBufSize) {
944 for (Int_t i=0;i<fNevBufSize;i++) fEntryOffset[i] = 0;
945 }
946}
947
948////////////////////////////////////////////////////////////////////////////////
949/// Set read mode of basket.
950
956
957////////////////////////////////////////////////////////////////////////////////
958/// Set write mode of basket.
959
965
966////////////////////////////////////////////////////////////////////////////////
967/// Stream a class object.
968
970{
971 // As in TBranch::GetBasket, this is used as a half-hearted measure to suppress
972 // the error reporting when many failures occur.
973 static std::atomic<Int_t> nerrors(0);
974
975 char flag;
976 if (b.IsReading()) {
977 TKey::Streamer(b); //this must be first
978 Version_t v = b.ReadVersion();
979 b >> fBufferSize;
980 // NOTE: we now use the upper-bit of the fNevBufSize to see if we have serialized any of the
981 // optional IOBits. If that bit is set, we immediately read out the IOBits; to replace this
982 // (minimal) safeguard against corruption, we will set aside the upper-bit of fIOBits to do
983 // the same thing (the fact this bit is reserved is tested in the unit tests). If there is
984 // someday a need for more than 7 IOBits, we'll widen the field using the same trick.
985 //
986 // We like to keep this safeguard because we immediately will allocate a buffer based on
987 // the value of fNevBufSize -- and would like to avoid wildly inappropriate allocations.
988 b >> fNevBufSize;
989 if (fNevBufSize < 0) {
991 b >> fIOBits;
992 if (!fIOBits || (fIOBits & (1 << 7))) {
993 Error("TBasket::Streamer",
994 "The value of fNevBufSize (%d) or fIOBits (%d) is incorrect ; setting the buffer to a zombie.",
996 MakeZombie();
997 fNevBufSize = 0;
998 } else if (fIOBits && (fIOBits & ~static_cast<Int_t>(EIOBits::kSupported))) {
999 nerrors++;
1000 if (nerrors < 10) {
1001 Error("Streamer", "The value of fIOBits (%s) contains unknown flags (supported flags "
1002 "are %s), indicating this was written with a newer version of ROOT "
1003 "utilizing critical IO features this version of ROOT does not support."
1004 " Refusing to deserialize.",
1005 std::bitset<32>(static_cast<Int_t>(fIOBits)).to_string().c_str(),
1006 std::bitset<32>(static_cast<Int_t>(EIOBits::kSupported)).to_string().c_str());
1007 } else if (nerrors == 10) {
1008 Error("Streamer", "Maximum number of errors has been reported; disabling further messages"
1009 "from this location until the process exits.");
1010 }
1011 fNevBufSize = 0;
1012 MakeZombie();
1013 }
1014 }
1015 b >> fNevBuf;
1016 b >> fLast;
1017 b >> flag;
1019 bool mustGenerateOffsets = false;
1020 if (flag >= 80) {
1021 mustGenerateOffsets = true;
1022 flag -= 80;
1023 }
1024 if (!mustGenerateOffsets && flag && (flag % 10 != 2)) {
1027 if (fNevBuf) b.ReadArray(fEntryOffset);
1028 if (20<flag && flag<40) {
1029 for(int i=0; i<fNevBuf; i++){
1031 }
1032 }
1033 if (flag>40) {
1035 b.ReadArray(fDisplacement);
1036 }
1037 } else if (mustGenerateOffsets) {
1038 // We currently believe that in all cases when offsets can be generated, then the
1039 // displacement array must be zero.
1040 assert(flag <= 40);
1041 fEntryOffset = reinterpret_cast<Int_t *>(-1);
1042 }
1043 if (flag == 1 || flag > 10) {
1045 fBufferRef->SetParent(b.GetParent());
1046 char *buf = fBufferRef->Buffer();
1047 if (v > 1) b.ReadFastArray(buf,fLast);
1048 else b.ReadArray(buf);
1050 // This is now done in the TBranch streamer since fBranch might not
1051 // yet be set correctly.
1052 // fBranch->GetTree()->IncrementTotalBuffers(fBufferSize);
1053 }
1054 } else {
1055
1056 TKey::Streamer(b); //this must be first
1057 b.WriteVersion(TBasket::IsA());
1058 if (fBufferRef) {
1060 if (!fHeaderOnly && !fSeekKey && curLast > fLast) fLast = curLast;
1061 }
1063
1064 b << fBufferSize;
1065 if (fIOBits) {
1066 b << -fNevBufSize;
1067 b << fIOBits;
1068 } else {
1069 b << fNevBufSize;
1070 }
1071 b << fNevBuf;
1072 b << fLast;
1076 // We currently believe that in all cases when offsets can be generated, then the
1077 // displacement array must be zero.
1079 if (fHeaderOnly) {
1080 flag = mustGenerateOffsets ? 80 : 0;
1081 b << flag;
1082 } else {
1083 // On return from this function, we are guaranteed that fEntryOffset
1084 // is either a valid pointer or nullptr.
1085 if (fNevBuf) {
1087 }
1088 flag = 1;
1089 if (!fNevBuf || !fEntryOffset)
1090 flag = 2;
1091 if (fBufferRef) flag += 10;
1092 if (fDisplacement) flag += 40;
1093 // Test if we can skip writing out the offset map.
1094 if (mustGenerateOffsets) {
1095 flag += 80;
1096 }
1097 b << flag;
1098
1100 b.WriteArray(fEntryOffset, fNevBuf);
1101 if (fDisplacement) b.WriteArray(fDisplacement, fNevBuf);
1102 }
1103 if (fBufferRef) {
1104 char *buf = fBufferRef->Buffer();
1105 b.WriteFastArray(buf, fLast);
1106 }
1107 }
1108 }
1109}
1110
1111////////////////////////////////////////////////////////////////////////////////
1112/// Update basket header and EntryOffset table.
1113
1115{
1117 if (entryOffset) {
1118 if (fNevBuf+1 >= fNevBufSize) {
1121 fNevBufSize);
1122 if (fDisplacement) {
1124 fNevBufSize);
1126 }
1129
1130 //Update branch only for the first 10 baskets
1131 if (fBranch->GetWriteBasket() < 10) {
1133 }
1134 }
1136
1137 if (skipped!=offset && !fDisplacement){
1139 for (Int_t i = 0; i<fNevBufSize; i++) fDisplacement[i] = fEntryOffset[i];
1140 }
1141 if (fDisplacement) {
1144 }
1145 }
1146
1147 fNevBuf++;
1148}
1149
1150////////////////////////////////////////////////////////////////////////////////
1151/// Write buffer of this basket on the current file.
1152///
1153/// The function returns the number of bytes committed to the memory.
1154/// If a write error occurs, the number of bytes returned is -1.
1155/// If no data are written, the number of bytes returned is 0.
1156
1158{
1159 constexpr Int_t kWrite = 1;
1160
1161 TFile *file = fBranch->GetFile(kWrite);
1162 if (!file) return 0;
1163 if (!file->IsWritable()) {
1164 return -1;
1165 }
1166 fMotherDir = file; // fBranch->GetDirectory();
1167
1168 // This mutex prevents multiple TBasket::WriteBuffer invocations from interacting
1169 // with the underlying TFile at once - TFile is assumed to *not* be thread-safe.
1170 //
1171 // The only parallelism we'd like to exploit (right now!) is the compression
1172 // step - everything else should be serialized at the TFile level.
1173#ifdef R__USE_IMT
1174 std::unique_lock<std::mutex> sentry(file->fWriteMutex);
1175#endif // R__USE_IMT
1176
1178 // Read the basket information that was saved inside the buffer.
1179 bool writing = fBufferRef->IsWriting();
1182
1186
1188
1189 Create(nout,file);
1191 fHeaderOnly = true;
1192
1193 Streamer(*fBufferRef); //write key itself again
1195 fHeaderOnly = false;
1196 return nBytes>0 ? fKeylen+nout : -1;
1197 }
1198
1199 // Transfer fEntryOffset table at the end of fBuffer.
1200 fLast = fBufferRef->Length();
1202 if (entryOffset) {
1204 if (!CanGenerateOffsetArray()) {
1205 // If we have set the offset map flag, but cannot dynamically generate the map, then
1206 // we should at least convert the offset array to a size array. Note that we always
1207 // write out (fNevBuf+1) entries to match the original case.
1208 if (hasOffsetBit) {
1209 for (Int_t idx = fNevBuf; idx > 0; idx--) {
1210 entryOffset[idx] -= entryOffset[idx - 1];
1211 }
1212 entryOffset[0] = 0;
1213 }
1215 // Convert back to offset format: keeping both sizes and offsets in-memory were considered,
1216 // but it seems better to use CPU than memory.
1217 if (hasOffsetBit) {
1218 entryOffset[0] = fKeylen;
1219 for (Int_t idx = 1; idx < fNevBuf + 1; idx++) {
1220 entryOffset[idx] += entryOffset[idx - 1];
1221 }
1222 }
1223 } else if (!hasOffsetBit) { // In this case, write out as normal
1225 }
1226 if (fDisplacement) {
1228 delete[] fDisplacement;
1229 fDisplacement = nullptr;
1230 }
1231 }
1232
1233 Int_t nout, noutot, bufmax, nzip;
1234
1236
1237 fHeaderOnly = true;
1241 cxlevel = file->GetCompressionLevel();
1245 if (cxlevel > 0) {
1246 Int_t nbuffers = 1 + (fObjlen - 1) / kMAXZIPBUF;
1247 Int_t buflen = fKeylen + fObjlen + 9 * nbuffers + 28; //add 28 bytes in case object is placed in a deleted gap
1248 InitializeCompressedBuffer(buflen, file);
1249 if (!fCompressedBufferRef) {
1250 Warning("WriteBuffer", "Unable to allocate the compressed buffer");
1251 return -1;
1252 }
1255 char *objbuf = fBufferRef->Buffer() + fKeylen;
1256 char *bufcur = &fBuffer[fKeylen];
1257 noutot = 0;
1258 nzip = 0;
1259 for (Int_t i = 0; i < nbuffers; ++i) {
1260 if (i == nbuffers - 1) bufmax = fObjlen - nzip;
1261 else bufmax = kMAXZIPBUF;
1262 // Compress the buffer. Note that we allow multiple TBasket compressions to occur at once
1263 // for a given TFile: that's because the compression buffer when we use IMT is no longer
1264 // shared amongst several threads.
1265#ifdef R__USE_IMT
1266 sentry.unlock();
1267#endif // R__USE_IMT
1268 // NOTE this is declared with C linkage, so it shouldn't except. Also, when
1269 // USE_IMT is defined, we are guaranteed that the compression buffer is unique per-branch.
1270 // (see fCompressedBufferRef in constructor).
1272#ifdef R__USE_IMT
1273 sentry.lock();
1274#endif // R__USE_IMT
1275
1276 // test if buffer has really been compressed. In case of small buffers
1277 // when the buffer contains random data, it may happen that the compressed
1278 // buffer is larger than the input. In this case, we write the original uncompressed buffer
1279 if (nout == 0 || nout >= fObjlen) {
1280 nout = fObjlen;
1281 // We used to delete fBuffer here, we no longer want to since
1282 // the buffer (held by fCompressedBufferRef) might be re-used later.
1284 Create(fObjlen,file);
1286
1287 Streamer(*fBufferRef); //write key itself again
1288 if ((nout+fKeylen)>buflen) {
1289 Warning("WriteBuffer","Possible memory corruption due to compression algorithm, wrote %d bytes past the end of a block of %d bytes. fNbytes=%d, fObjLen=%d, fKeylen=%d",
1290 (nout+fKeylen-buflen),buflen,fNbytes,fObjlen,fKeylen);
1291 }
1292 goto WriteFile;
1293 }
1294 bufcur += nout;
1295 noutot += nout;
1296 objbuf += kMAXZIPBUF;
1297 nzip += kMAXZIPBUF;
1298 }
1299 nout = noutot;
1300 Create(noutot,file);
1302
1303 Streamer(*fBufferRef); //write key itself again
1305 } else {
1307 Create(fObjlen,file);
1309
1310 Streamer(*fBufferRef); //write key itself again
1311 nout = fObjlen;
1312 }
1313
1314WriteFile:
1316 fHeaderOnly = false;
1317 return nBytes>0 ? fKeylen+nout : -1;
1318}
#define R__likely(expr)
Definition RConfig.hxx:595
#define R__unlikely(expr)
Definition RConfig.hxx:594
#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:59
long Longptr_t
Integer large enough to hold a pointer (platform-dependent)
Definition RtypesCore.h:89
short Version_t
Class version identifier (short)
Definition RtypesCore.h:79
unsigned int UInt_t
Unsigned integer 4 bytes (unsigned int)
Definition RtypesCore.h:60
float Float_t
Float 4 bytes (float)
Definition RtypesCore.h:71
long long Long64_t
Portable signed long integer 8 bytes.
Definition RtypesCore.h:83
constexpr auto gMaxInt_t
Definition TBasket.cxx:35
static TBuffer * R__InitializeReadBasketBuffer(TBuffer *bufferRef, Int_t len, TFile *file)
Initialize a buffer for reading if it is not already initialized.
Definition TBasket.cxx:411
#define OLD_CASE_EXPRESSION
Definition TBasket.cxx:354
const UInt_t kDisplacementMask
Definition TBasket.cxx:32
ROOT::Detail::TRangeCast< T, true > TRangeDynCast
TRangeDynCast is an adapter class that allows the typed iteration through a TCollection.
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 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
char name[80]
Definition TGX11.cxx:110
Int_t gDebug
Global variable setting the debug level. Set to 0 to disable, increase it in steps of 1 to increase t...
Definition TROOT.cxx:627
R__EXTERN TVirtualMutex * gROOTMutex
Definition TROOT.h:63
void R__unzip(Int_t *nin, UChar_t *bufin, Int_t *lout, char *bufout, Int_t *nout)
int R__unzip_header(Int_t *nin, UChar_t *bufin, Int_t *lout)
#define R__LOCKGUARD_IMT(mutex)
#define gPerfStats
Int_t * fEntryOffset
[fNevBuf] Offset of entries in fBuffer(TKey); generated at runtime.
Definition TBasket.h:71
Int_t GetEntryPointer(Int_t Entry)
Get pointer to buffer for internal entry.
Definition TBasket.cxx:231
void AdoptBuffer(TBuffer *user_buffer)
Adopt a buffer from an external entity.
Definition TBasket.cxx:747
bool fHeaderOnly
True when only the basket header must be read/written.
Definition TBasket.h:66
TBranch * fBranch
Pointer to the basket support branch.
Definition TBasket.h:73
Long64_t CopyTo(TFile *to)
Copy the basket of this branch onto the file to.
Definition TBasket.cxx:147
Int_t * GetEntryOffset()
Definition TBasket.h:124
void InitializeCompressedBuffer(Int_t len, TFile *file)
Initialize the compressed buffer; either from the TTree or create a local one.
Definition TBasket.cxx:433
UChar_t fNextBufferSizeRecord
! Index into fLastWriteBufferSize of the last buffer written to disk
Definition TBasket.h:77
Int_t ReadBasketBuffersUnzip(char *, Int_t, bool, TFile *)
We always create the TBuffer for the basket but it hold the buffer from the cache.
Definition TBasket.cxx:381
void DisownBuffer()
Disown all references to the internal buffer - some other object likely now owns it.
Definition TBasket.cxx:739
Int_t fLastWriteBufferSize[3]
! Size of the buffer last three buffers we wrote it to disk
Definition TBasket.h:75
Int_t ReadBasketBuffers(Long64_t pos, Int_t len, TFile *file)
Read basket buffers in memory and cleanup.
Definition TBasket.cxx:465
UChar_t fIOBits
!IO feature flags. Serialized in custom portion of streamer to avoid forward compat issues unless nee...
Definition TBasket.h:67
virtual Int_t DropBuffers()
Drop buffers of this basket if it is not the current basket.
Definition TBasket.cxx:174
virtual void MoveEntries(Int_t dentries)
Remove the first dentries of this basket, moving entries at dentries to the start of the buffer.
Definition TBasket.cxx:311
bool fOwnsCompressedBuffer
! Whether or not we own the compressed buffer.
Definition TBasket.h:68
void ResetEntryOffset()
Definition TBasket.cxx:442
TBasket()
Default constructor.
Definition TBasket.cxx:48
virtual void AdjustSize(Int_t newsize)
Increase the size of the current fBuffer up to newsize.
Definition TBasket.cxx:128
virtual void SetReadMode()
Set read mode of basket.
Definition TBasket.cxx:951
virtual void SetWriteMode()
Set write mode of basket.
Definition TBasket.cxx:960
Int_t ReadBasketBuffersUncompressedCase()
By-passing buffer unzipping has been requested and is possible (only 1 entry in this basket).
Definition TBasket.cxx:359
Int_t fBufferSize
fBuffer length in bytes
Definition TBasket.h:62
bool fReadEntryOffset
!Set to true if offset array was read from a file.
Definition TBasket.h:69
Int_t ReadBasketBytes(Long64_t pos, TFile *file)
Read basket buffers in memory and cleanup.
Definition TBasket.cxx:724
virtual void ReadResetBuffer(Int_t basketnumber)
Reset the read basket TBuffer memory allocation if needed.
Definition TBasket.cxx:759
bool fResetAllocation
! True if last reset re-allocated the memory
Definition TBasket.h:76
virtual Int_t WriteBuffer()
Write buffer of this basket on the current file.
Definition TBasket.cxx:1157
void Streamer(TBuffer &) override
Stream a class object.
Definition TBasket.cxx:969
Int_t LoadBasketBuffers(Long64_t pos, Int_t len, TFile *file, TTree *tree=nullptr)
Load basket buffers in memory without unziping.
Definition TBasket.cxx:246
~TBasket() override
Basket destructor.
Definition TBasket.cxx:105
void Update(Int_t newlast)
Definition TBasket.h:152
Int_t fNevBufSize
Length in Int_t of fEntryOffset OR fixed length of each entry if fEntryOffset is null!
Definition TBasket.h:63
Int_t fNevBuf
Number of entries in basket.
Definition TBasket.h:64
Int_t * GetCalculatedEntryOffset()
Calculates the entry offset array, if possible.
Definition TBasket.cxx:196
TClass * IsA() const override
Definition TBasket.h:156
virtual void DeleteEntryOffset()
Delete fEntryOffset array.
Definition TBasket.cxx:165
TBuffer * fCompressedBufferRef
! Compressed buffer.
Definition TBasket.h:74
Int_t fLast
Pointer to last used byte in basket.
Definition TBasket.h:65
Int_t * fDisplacement
![fNevBuf] Displacement of entries in fBuffer(TKey)
Definition TBasket.h:70
bool CanGenerateOffsetArray()
Determine whether we can generate the offset array when this branch is read.
Definition TBasket.cxx:219
virtual void WriteReset()
Reset the write basket to the starting state.
Definition TBasket.cxx:832
A TTree is a list of TBranches.
Definition TBranch.h:93
Int_t GetCompressionLevel() const
Definition TBranch.h:305
Int_t GetCompressionAlgorithm() const
Definition TBranch.h:299
TTree * GetTree() const
Definition TBranch.h:252
Int_t GetWriteBasket() const
Definition TBranch.h:238
Int_t GetNleaves() const
Definition TBranch.h:249
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:2833
Int_t GetMaxBaskets() const
Definition TBranch.h:248
Int_t * GetBasketBytes() const
Definition TBranch.h:214
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:1852
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:2219
virtual Int_t GetBasketSize() const
Definition TBranch.h:217
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:2237
TObjArray * GetListOfLeaves()
Definition TBranch.h:247
TDirectory * GetDirectory() const
Definition TBranch.h:224
Int_t GetEntryOffsetLen() const
Definition TBranch.h:227
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
virtual void Reset()=0
void SetParent(TObject *parent)
Set parent owning this buffer.
Definition TBuffer.cxx:269
void Expand(Int_t newsize, Bool_t copy=kTRUE)
Expand (or shrink) the I/O buffer to newsize bytes.
Definition TBuffer.cxx:222
Int_t BufferSize() const
Definition TBuffer.h:98
virtual void WriteArray(const Bool_t *b, Int_t n)=0
virtual Int_t ReadArray(Bool_t *&b)=0
@ kWrite
Definition TBuffer.h:73
@ kRead
Definition TBuffer.h:73
Bool_t IsWriting() const
Definition TBuffer.h:87
void SetBuffer(void *buf, UInt_t bufsize=0, Bool_t adopt=kTRUE, ReAllocCharFun_t reallocfunc=nullptr)
Sets a new buffer in an existing TBuffer object.
Definition TBuffer.cxx:186
void SetBufferOffset(Int_t offset=0)
Definition TBuffer.h:93
void SetReadMode()
Set buffer in read mode.
Definition TBuffer.cxx:301
virtual void SetBufferDisplacement()=0
Int_t Length() const
Definition TBuffer.h:100
char * Buffer() const
Definition TBuffer.h:96
Bool_t IsWritable() const override
Describe directory structure in memory.
Definition TDirectory.h:45
A cache when reading files over the network.
A file, usually with extension .root, that stores data and code in the form of serialized objects in ...
Definition TFile.h:130
virtual void Seek(Long64_t offset, ERelativeTo pos=kBeg)
Seek to a specific position in the file. Pos it either kBeg, kCur or kEnd.
Definition TFile.cxx:2326
Int_t GetCompressionLevel() const
Definition TFile.h:473
std::mutex fWriteMutex
!Lock for writing baskets / keys into the file.
Definition TFile.h:196
virtual void SetOffset(Long64_t offset, ERelativeTo pos=kBeg)
Set position from where to start reading.
Definition TFile.cxx:2305
Int_t GetCompressionAlgorithm() const
Definition TFile.h:467
Int_t GetRecordHeader(char *buf, Long64_t first, Int_t maxbytes, Int_t &nbytes, Int_t &objlen, Int_t &keylen)
Read the logical record header starting at a certain postion.
Definition TFile.cxx:1312
virtual Bool_t ReadBuffer(char *buf, Int_t len)
Read a buffer from the file.
Definition TFile.cxx:1822
TFileCacheRead * GetCacheRead(const TObject *tree=nullptr) const
Return a pointer to the current read cache.
Definition TFile.cxx:1273
Book space in a file, create I/O buffers, to fill them, (un)compress them.
Definition TKey.h:28
Int_t GetKeylen() const
Definition TKey.h:84
Int_t GetObjlen() const
Definition TKey.h:87
TBuffer * fBufferRef
Pointer to the TBuffer object.
Definition TKey.h:50
Int_t fVersion
Key version identifier.
Definition TKey.h:39
Short_t fKeylen
Number of bytes for the key itself.
Definition TKey.h:43
virtual Int_t WriteFileKeepBuffer(TFile *f=nullptr)
Write the encoded object supported by this key.
Definition TKey.cxx:1540
Long64_t fSeekKey
Location of object on file.
Definition TKey.h:45
char * fBuffer
Object buffer.
Definition TKey.h:49
Int_t fNbytes
Number of bytes for the whole key on file (key header and data)
Definition TKey.h:40
Int_t fObjlen
Length of uncompressed object in bytes.
Definition TKey.h:41
void Reset()
Reset the key as it had not been 'filled' yet.
Definition TKey.cxx:1351
Short_t fCycle
Cycle number.
Definition TKey.h:44
virtual void Create(Int_t nbytes, TFile *f=nullptr)
Create a TKey object of specified size.
Definition TKey.cxx:474
virtual Int_t WriteFile(Int_t cycle=1, TFile *f=nullptr)
Write the encoded object supported by this key.
Definition TKey.cxx:1508
TDirectory * fMotherDir
!pointer to mother directory
Definition TKey.h:52
TString fClassName
Object Class name.
Definition TKey.h:47
void Streamer(TBuffer &) override
Stream a class object.
Definition TKey.cxx:1407
TBuffer * GetBufferRef() const
Definition TKey.h:79
A TLeaf describes individual elements of a TBranch See TBranch structure in TTree.
Definition TLeaf.h:57
virtual void SetTitle(const char *title="")
Set the title of the TNamed.
Definition TNamed.cxx:173
const char * GetName() const override
Returns name of object.
Definition TNamed.h:49
virtual void SetName(const char *name)
Set the name of the TNamed.
Definition TNamed.cxx:149
R__ALWAYS_INLINE Bool_t TestBit(UInt_t f) const
Definition TObject.h:202
virtual void Warning(const char *method, const char *msgfmt,...) const
Issue warning message.
Definition TObject.cxx:1057
R__ALWAYS_INLINE Bool_t IsZombie() const
Definition TObject.h:159
void SetBit(UInt_t f, Bool_t set)
Set or unset the user status bits as specified in f.
Definition TObject.cxx:864
virtual void Error(const char *method, const char *msgfmt,...) const
Issue error message.
Definition TObject.cxx:1071
void MakeZombie()
Definition TObject.h:53
virtual void Info(const char *method, const char *msgfmt,...) const
Issue info message.
Definition TObject.cxx:1045
static Int_t * ReAllocInt(Int_t *vp, size_t size, size_t oldsize)
Reallocate (i.e.
Definition TStorage.cxx:257
The TTimeStamp encapsulates seconds and ns since EPOCH.
Definition TTimeStamp.h:45
A cache to speed-up the reading of ROOT datasets.
Definition TTreeCache.h:32
A TTree represents a columnar dataset.
Definition TTree.h:89
virtual TVirtualPerfStats * GetPerfStats() const
Definition TTree.h:585
virtual void IncrementTotalBuffers(Int_t nbytes)
Definition TTree.h:625
TTreeCache * GetReadCache(TFile *file) const
Find and return the TTreeCache registered with the file and which may contain branches for us.
Definition TTree.cxx:6429
Float_t GetTargetMemoryRatio() const
Definition TTree.h:599
Provides the interface for the an internal performance measurement and event tracing.
Short_t Max(Short_t a, Short_t b)
Returns the largest of a and b.
Definition TMathBase.h:251
EValues
Note: this is only temporarily a struct and will become a enum class hence the name convention used.
Definition Compression.h:88
@ kInherit
Some objects use this value to denote that the compression algorithm should be inherited from the par...
Definition Compression.h:91
@ kInherit
Some objects use this value to denote that the compression algorithm should be inherited from the par...
Definition Compression.h:68