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
36constexpr auto gMaxInt_t = std::numeric_limits<Int_t>::max();
37
38/** \class TBasket
39\ingroup tree
40
41Manages buffers for branches of a Tree.
42
43See picture in TTree.
44*/
45
46////////////////////////////////////////////////////////////////////////////////
47/// Default constructor.
48
52
53////////////////////////////////////////////////////////////////////////////////
54/// Constructor used during reading.
55
56TBasket::TBasket(TDirectory *motherDir) : TKey(motherDir)
57{
58}
59
60////////////////////////////////////////////////////////////////////////////////
61/// Basket normal constructor, used during writing.
62
63TBasket::TBasket(const char *name, const char *title, TBranch *branch)
64 : TKey(branch->GetDirectory()), fBufferSize(branch->GetBasketSize()), fNevBufSize(branch->GetEntryOffsetLen()),
65 fHeaderOnly(true), fIOBits(branch->GetIOFeatures().GetFeatures())
66{
68 SetTitle(title);
69 fClassName = "TBasket";
70 fBuffer = nullptr;
72 fVersion += 1000;
73 if (branch->GetDirectory()) {
74 TFile *file = branch->GetFile();
75 fBufferRef->SetParent(file);
76 }
77 if (branch->GetTree()) {
78#ifdef R__USE_IMT
80#else
82#endif
87 }
88 }
89 fBranch = branch;
91 fKeylen = fBufferRef->Length();
93 fLast = fKeylen;
94 fBuffer = nullptr;
95 fHeaderOnly = false;
96 if (fNevBufSize) {
98 for (Int_t i=0;i<fNevBufSize;i++) fEntryOffset[i] = 0;
99 }
101}
102
103////////////////////////////////////////////////////////////////////////////////
104/// Basket destructor.
105
107{
108 if (fDisplacement) delete [] fDisplacement;
110 if (fBufferRef) delete fBufferRef;
111 fBufferRef = nullptr;
112 fBuffer = nullptr;
113 fDisplacement= nullptr;
114 // Note we only delete the compressed buffer if we own it
117 fCompressedBufferRef = nullptr;
118 }
119 // TKey::~TKey will use fMotherDir to attempt to remove they key
120 // from the directory's list of key. A basket is never in that list
121 // and in some cases (eg. f = new TFile(); TTree t; delete f;) the
122 // directory is gone before the TTree.
123 fMotherDir = nullptr;
124}
125
126////////////////////////////////////////////////////////////////////////////////
127/// Increase the size of the current fBuffer up to newsize.
128
130{
131 if (fBuffer == fBufferRef->Buffer()) {
132 fBufferRef->Expand(newsize);
133 fBuffer = fBufferRef->Buffer();
134 } else {
135 fBufferRef->Expand(newsize);
136 }
137 fBranch->GetTree()->IncrementTotalBuffers(newsize-fBufferSize);
138 fBufferSize = newsize;
139 fLastWriteBufferSize[0] = newsize;
143}
144
145////////////////////////////////////////////////////////////////////////////////
146/// Copy the basket of this branch onto the file to.
147
149{
150 fBufferRef->SetWriteMode();
151 Int_t nout = fNbytes - fKeylen;
152 fBuffer = fBufferRef->Buffer();
153 Create(nout, to);
154 fBufferRef->SetBufferOffset(0);
155 fHeaderOnly = true;
157 fHeaderOnly = false;
158 Int_t nBytes = WriteFileKeepBuffer(to);
159
160 return nBytes>0 ? nBytes : -1;
161}
162
163////////////////////////////////////////////////////////////////////////////////
164/// Delete fEntryOffset array.
165
171
172////////////////////////////////////////////////////////////////////////////////
173/// Drop buffers of this basket if it is not the current basket.
174
176{
177 if (!fBuffer && !fBufferRef) return 0;
178
179 if (fDisplacement) delete [] fDisplacement;
181 if (fBufferRef) delete fBufferRef;
183 fBufferRef = nullptr;
184 fCompressedBufferRef = nullptr;
185 fBuffer = nullptr;
186 fDisplacement= nullptr;
187 fEntryOffset = nullptr;
188 fBranch->GetTree()->IncrementTotalBuffers(-fBufferSize);
189 return fBufferSize;
190}
191
192////////////////////////////////////////////////////////////////////////////////
193/// Calculates the entry offset array, if possible.
194///
195/// Result is cached, meaning that this should only be invoked once per basket.
196
198{
199 if (fEntryOffset != reinterpret_cast<Int_t *>(-1)) {
200 return fEntryOffset;
201 }
202
203 if (R__unlikely(!fBranch)) {
204 Error("GetCalculatedEntryOffset", "Basket entry offset calculation requested, but no associated TBranch!");
205 return nullptr;
206 }
207 if (R__unlikely(fBranch->GetNleaves() != 1)) {
208 Error("GetCalculatedEntryOffset", "Branch contains multiple leaves - unable to calculated entry offsets!");
209 return nullptr;
210 }
211 TLeaf *leaf = static_cast<TLeaf *>((*fBranch->GetListOfLeaves())[0]);
213 return fEntryOffset;
214}
215
216////////////////////////////////////////////////////////////////////////////////
217/// Determine whether we can generate the offset array when this branch is read.
218///
219
221{
222 if (fBranch->GetNleaves() != 1) {
223 return false;
224 }
225 TLeaf *leaf = static_cast<TLeaf *>((*fBranch->GetListOfLeaves())[0]);
226 return leaf->CanGenerateOffsetArray();
227}
228
229////////////////////////////////////////////////////////////////////////////////
230/// Get pointer to buffer for internal entry.
231
233{
235 Int_t *entryOffset = GetEntryOffset();
236 if (entryOffset) offset = entryOffset[entry];
237 else offset = fKeylen + entry*fNevBufSize;
238 fBufferRef->SetBufferOffset(offset);
239 return offset;
240}
241
242////////////////////////////////////////////////////////////////////////////////
243/// Load basket buffers in memory without unziping.
244/// This function is called by TTreeCloner.
245/// The function returns 0 in case of success, 1 in case of error.
246
248{
249 if (fBufferRef) {
250 // Reuse the buffer if it exist.
251 fBufferRef->Reset();
252
253 // We use this buffer both for reading and writing, we need to
254 // make sure it is properly sized for writing.
255 fBufferRef->SetWriteMode();
256 if (fBufferRef->BufferSize() < len) {
257 fBufferRef->Expand(len);
258 }
259 fBufferRef->SetReadMode();
260 } else {
262 }
263 fBufferRef->SetParent(file);
264 char *buffer = fBufferRef->Buffer();
265 file->Seek(pos);
266 TFileCacheRead *pf = tree->GetReadCache(file);
267 if (pf) {
269 if (tree->GetPerfStats()) gPerfStats = tree->GetPerfStats();
270 Int_t st = pf->ReadBuffer(buffer,pos,len);
271 if (st < 0) {
272 return 1;
273 } else if (st == 0) {
274 // fOffset might have been changed via TFileCacheRead::ReadBuffer(), reset it
275 file->Seek(pos);
276 // If we are using a TTreeCache, disable reading from the default cache
277 // temporarily, to force reading directly from file
278 TTreeCache *fc = dynamic_cast<TTreeCache*>(file->GetCacheRead());
279 if (fc) fc->Disable();
280 Int_t ret = file->ReadBuffer(buffer,len);
281 if (fc) fc->Enable();
283 pf->AddNoCacheReadCalls(1);
284 if (ret) {
285 return 1;
286 }
287 }
288 gPerfStats = temp;
289 // fOffset might have been changed via TFileCacheRead::ReadBuffer(), reset it
290 file->SetOffset(pos + len);
291 } else {
293 if (tree->GetPerfStats() != nullptr) gPerfStats = tree->GetPerfStats();
294 if (file->ReadBuffer(buffer,len)) {
295 gPerfStats = temp;
296 return 1; //error while reading
297 }
298 else gPerfStats = temp;
299 }
300
301 fBufferRef->SetReadMode();
302 fBufferRef->SetBufferOffset(0);
304
305 return 0;
306}
307
308////////////////////////////////////////////////////////////////////////////////
309/// Remove the first dentries of this basket, moving entries at
310/// dentries to the start of the buffer.
311
313{
314 Int_t i;
315
316 if (dentries >= fNevBuf) return;
317 Int_t bufbegin;
318 Int_t moved;
319
320 Int_t *entryOffset = GetEntryOffset();
321 if (entryOffset) {
322 bufbegin = entryOffset[dentries];
323 moved = bufbegin-GetKeylen();
324
325 // First store the original location in the fDisplacement array
326 // and record the new start offset
327
328 if (!fDisplacement) {
330 }
331 for (i = 0; i<(fNevBufSize-dentries); ++i) {
332 fDisplacement[i] = entryOffset[i + dentries];
333 entryOffset[i] = entryOffset[i + dentries] - moved;
334 }
335 for (i = fNevBufSize-dentries; i<fNevBufSize; ++i) {
336 fDisplacement[i] = 0;
337 entryOffset[i] = 0;
338 }
339
340 } else {
341 // If there is no EntryOffset array, this means
342 // that each entry has the same size and that
343 // it does not point to other objects (hence there
344 // is no need for a displacement array).
345 bufbegin = GetKeylen() + dentries*fNevBufSize;
346 moved = bufbegin-GetKeylen();
347 }
348 TBuffer *buf = GetBufferRef();
349 char *buffer = buf->Buffer();
350 memmove(buffer+GetKeylen(),buffer+bufbegin,buf->Length()-bufbegin);
351 buf->SetBufferOffset(buf->Length()-moved);
352 fNevBuf -= dentries;
353}
354
355#define OLD_CASE_EXPRESSION fObjlen==fNbytes-fKeylen && GetBranch()->GetCompressionLevel()!=0 && file->GetVersion()<=30401
356////////////////////////////////////////////////////////////////////////////////
357/// By-passing buffer unzipping has been requested and is
358/// possible (only 1 entry in this basket).
359
361{
362 fBuffer = fBufferRef->Buffer();
363
364 // Make sure that the buffer is set at the END of the data
365 fBufferRef->SetBufferOffset(fNbytes);
366
367 // Indicate that this buffer is weird.
369
370 // Usage of this mode assume the existence of only ONE
371 // entry in this basket.
373 delete [] fDisplacement; fDisplacement = nullptr;
374
375 fBranch->GetTree()->IncrementTotalBuffers(fBufferSize);
376 return 0;
377}
378
379////////////////////////////////////////////////////////////////////////////////
380/// We always create the TBuffer for the basket but it hold the buffer from the cache.
381
382Int_t TBasket::ReadBasketBuffersUnzip(char* buffer, Int_t size, bool mustFree, TFile* file)
383{
384 if (fBufferRef) {
385 fBufferRef->SetBuffer(buffer, size, mustFree);
386 fBufferRef->SetReadMode();
387 fBufferRef->Reset();
388 } else {
389 fBufferRef = new TBufferFile(TBuffer::kRead, size, buffer, mustFree);
390 }
391 fBufferRef->SetParent(file);
392
394
395 if (IsZombie()) {
396 return -1;
397 }
398
399 bool oldCase = OLD_CASE_EXPRESSION;
400
401 if ((fObjlen > fNbytes-fKeylen || oldCase) && TestBit(TBufferFile::kNotDecompressed) && (fNevBuf==1)) {
403 }
404
405 fBuffer = fBufferRef->Buffer();
406 return fObjlen+fKeylen;
407}
408
409////////////////////////////////////////////////////////////////////////////////
410/// Initialize a buffer for reading if it is not already initialized
411
412static inline TBuffer* R__InitializeReadBasketBuffer(TBuffer* bufferRef, Int_t len, TFile* file)
413{
415 if (R__likely(bufferRef)) {
416 bufferRef->SetReadMode();
417 Int_t curBufferSize = bufferRef->BufferSize();
418 if (curBufferSize < len) {
419 // Experience shows that giving 5% "wiggle-room" decreases churn.
420 bufferRef->Expand(Int_t(len*1.05));
421 }
422 bufferRef->Reset();
423 result = bufferRef;
424 } else {
426 }
427 result->SetParent(file);
428 return result;
429}
430
431////////////////////////////////////////////////////////////////////////////////
432/// Initialize the compressed buffer; either from the TTree or create a local one.
433
435{
436 bool compressedBufferExists = fCompressedBufferRef != nullptr;
438 if (R__unlikely(!compressedBufferExists)) {
440 }
441}
442
444{
445 if (fEntryOffset != reinterpret_cast<Int_t *>(-1)) {
446 delete[] fEntryOffset;
447 }
448 fEntryOffset = nullptr;
449}
450
451////////////////////////////////////////////////////////////////////////////////
452/// Read basket buffers in memory and cleanup.
453///
454/// Read a basket buffer. Check if buffers of previous ReadBasket
455/// should not be dropped. Remember, we keep buffers in memory up to
456/// fMaxVirtualSize.
457/// The function returns 0 in case of success, 1 in case of error
458/// This function was modified with the addition of the parallel
459/// unzipping, it will try to get the unzipped file from the cache
460/// receiving only a pointer to that buffer (so we shall not
461/// delete that pointer), although we get a new buffer in case
462/// it's not found in the cache.
463/// There is a lot of code duplication but it was necessary to assure
464/// the expected behavior when there is no cache.
465
467{
468 if(!fBranch->GetDirectory()) {
469 return -1;
470 }
471
472 bool oldCase;
473 char *rawUncompressedBuffer, *rawCompressedBuffer;
474 Int_t uncompressedBufferLen;
475
476 // See if the cache has already unzipped the buffer for us.
477 TFileCacheRead *pf = nullptr;
478 {
479 R__LOCKGUARD_IMT(gROOTMutex); // Lock for parallel TTree I/O
480 pf = fBranch->GetTree()->GetReadCache(file);
481 }
482 if (pf) {
483 Int_t res = -1;
484 bool free = true;
485 char *buffer = nullptr;
486 res = pf->GetUnzipBuffer(&buffer, pos, len, &free);
487 if (R__unlikely(res >= 0)) {
488 len = ReadBasketBuffersUnzip(buffer, res, free, file);
489 // Note that in the kNotDecompressed case, the above function will return 0;
490 // In such a case, we should stop processing
491 if (len <= 0) return -len;
492 goto AfterBuffer;
493 }
494 }
495
496 // Determine which buffer to use, so that we can avoid a memcpy in case of
497 // the basket was not compressed.
498 TBuffer* readBufferRef;
499 if (R__unlikely(fBranch->GetCompressionLevel()==0)) {
500 // Initialize the buffer to hold the uncompressed data.
502 readBufferRef = fBufferRef;
503 } else {
504 // Initialize the buffer to hold the compressed data.
506 readBufferRef = fCompressedBufferRef;
507 }
508
509 // fBufferSize is likely to be change in the Streamer call (below)
510 // and we will re-add the new size later on.
511 fBranch->GetTree()->IncrementTotalBuffers(-fBufferSize);
512
513 if (!readBufferRef) {
514 Error("ReadBasketBuffers", "Unable to allocate buffer.");
515 return 1;
516 }
517
518 if (pf) {
520 if (fBranch->GetTree()->GetPerfStats() != nullptr) gPerfStats = fBranch->GetTree()->GetPerfStats();
521 Int_t st = 0;
522 {
523 R__LOCKGUARD_IMT(gROOTMutex); // Lock for parallel TTree I/O
524 st = pf->ReadBuffer(readBufferRef->Buffer(),pos,len);
525 }
526 if (st < 0) {
527 return 1;
528 } else if (st == 0) {
529 // Read directly from file, not from the cache
530 // If we are using a TTreeCache, disable reading from the default cache
531 // temporarily, to force reading directly from file
532 R__LOCKGUARD_IMT(gROOTMutex); // Lock for parallel TTree I/O
533 TTreeCache *fc = dynamic_cast<TTreeCache*>(file->GetCacheRead());
534 if (fc) fc->Disable();
535 Int_t ret = file->ReadBuffer(readBufferRef->Buffer(),pos,len);
536 if (fc) fc->Enable();
538 pf->AddNoCacheReadCalls(1);
539 if (ret) {
540 return 1;
541 }
542 }
543 gPerfStats = temp;
544 } else {
545 // Read from the file and unstream the header information.
547 if (fBranch->GetTree()->GetPerfStats() != nullptr) gPerfStats = fBranch->GetTree()->GetPerfStats();
548 R__LOCKGUARD_IMT(gROOTMutex); // Lock for parallel TTree I/O
549 if (file->ReadBuffer(readBufferRef->Buffer(),pos,len)) {
550 gPerfStats = temp;
551 return 1;
552 }
553 else gPerfStats = temp;
554 }
555 Streamer(*readBufferRef);
556 if (IsZombie()) {
557 return 1;
558 }
559
560 rawCompressedBuffer = readBufferRef->Buffer();
561
562 // Are we done?
563 if (R__unlikely(readBufferRef == fBufferRef)) // We expect most basket to be compressed.
564 {
566 // The basket was really not compressed as expected.
567 goto AfterBuffer;
568 } else {
569 // Well, somehow the buffer was compressed anyway, we have the compressed data in the uncompressed buffer
570 // Make sure the compressed buffer is initialized, and memcpy.
573 Error("ReadBasketBuffers", "Unable to allocate buffer.");
574 return 1;
575 }
576 fBufferRef->Reset();
577 rawCompressedBuffer = fCompressedBufferRef->Buffer();
578 memcpy(rawCompressedBuffer, fBufferRef->Buffer(), len);
579 }
580 }
581 // Sanitize nbytes and lengths
582 if (fKeylen < 0) {
583 Error("ReadBasketBuffers", "The value of fKeylen is incorrect (%d) ; trying to recover by setting it to zero", fKeylen);
584 MakeZombie();
585 fKeylen = 0;
586 return 1;
587 }
588 if (fObjlen < 0) {
589 Error("ReadBasketBuffers", "The value of fObjlen is incorrect (%d) ; trying to recover by setting it to zero", fObjlen);
590 MakeZombie();
591 fObjlen = 0;
592 return 1;
593 }
594 if (fNbytes < 0) {
595 Error("ReadBasketBuffers", "The value of fNbytes is incorrect (%d) ; trying to recover by setting it to zero", fNbytes);
596 MakeZombie();
597 fNbytes = 0;
598 return 1;
599 }
600 if (fKeylen > (gMaxInt_t - fObjlen)) {
601 Error("ReadBasketBuffers", "fObjlen (%d) + fKeylen (%d) > max int (%d): cannot continue to read the key buffer.",
603 MakeZombie();
604 return 1;
605 }
606
607 // Initialize buffer to hold the uncompressed data
608 // Note that in previous versions we didn't allocate buffers until we verified
609 // the zip headers; this is no longer beforehand as the buffer lifetime is scoped
610 // to the TBranch.
611 uncompressedBufferLen = len > fObjlen+fKeylen ? len : fObjlen+fKeylen;
612 fBufferRef = R__InitializeReadBasketBuffer(fBufferRef, uncompressedBufferLen, file);
613 rawUncompressedBuffer = fBufferRef->Buffer();
614 fBuffer = rawUncompressedBuffer;
615
616 oldCase = OLD_CASE_EXPRESSION;
617 // Case where ROOT thinks the buffer is compressed. Copy over the key and uncompress the object
618 if (fObjlen > fNbytes-fKeylen || oldCase) {
621 }
622
623 // Optional monitor for zip time profiling.
624 Double_t start = 0;
625 if (R__unlikely(gPerfStats)) {
626 start = TTimeStamp();
627 }
628
629 memcpy(rawUncompressedBuffer, rawCompressedBuffer, fKeylen);
630 char *rawUncompressedObjectBuffer = rawUncompressedBuffer+fKeylen;
631 UChar_t *rawCompressedObjectBuffer = (UChar_t*)rawCompressedBuffer+fKeylen;
632 Int_t nin, nbuf;
633 Int_t nout = 0, noutot = 0, nintot = 0;
634
635 // Unzip all the compressed objects in the compressed object buffer.
636 while (true) {
637 // Check the header for errors.
638 if (R__unlikely(R__unzip_header(&nin, rawCompressedObjectBuffer, &nbuf) != 0)) {
639 Error("ReadBasketBuffers", "Inconsistency found in header (nin=%d, nbuf=%d)", nin, nbuf);
640 break;
641 }
642 if (R__unlikely(oldCase && (nin > fObjlen || nbuf > fObjlen))) {
643 //buffer was very likely not compressed in an old version
644 memcpy(rawUncompressedBuffer+fKeylen, rawCompressedObjectBuffer+fKeylen, fObjlen);
645 goto AfterBuffer;
646 }
647
648 R__unzip(&nin, rawCompressedObjectBuffer, &nbuf, (unsigned char*) rawUncompressedObjectBuffer, &nout);
649 if (!nout) break;
650 noutot += nout;
651 nintot += nin;
652 if (noutot >= fObjlen) break;
653 rawCompressedObjectBuffer += nin;
654 rawUncompressedObjectBuffer += nout;
655 }
656
657 // Make sure the uncompressed numbers are consistent with header.
658 if (R__unlikely(noutot != fObjlen)) {
659 Error("ReadBasketBuffers", "fNbytes = %d, fKeylen = %d, fObjlen = %d, noutot = %d, nout=%d, nin=%d, nbuf=%d", fNbytes,fKeylen,fObjlen, noutot,nout,nin,nbuf);
660 fBranch->GetTree()->IncrementTotalBuffers(fBufferSize);
661 return 1;
662 }
665 if (fBranch->GetTree()->GetPerfStats() != nullptr) gPerfStats = fBranch->GetTree()->GetPerfStats();
666 if (R__unlikely(gPerfStats)) {
667 gPerfStats->UnzipEvent(fBranch->GetTree(),pos,start,nintot,fObjlen);
668 }
669 gPerfStats = temp;
670 } else {
671 // Nothing is compressed - copy over wholesale.
672 memcpy(rawUncompressedBuffer, rawCompressedBuffer, len);
673 }
674
675AfterBuffer:
676
677 fBranch->GetTree()->IncrementTotalBuffers(fBufferSize);
678
679 // Read offsets table if needed.
680 // If there's no EntryOffsetLen in the branch -- or the fEntryOffset is marked to be calculated-on-demand --
681 // then we skip reading out.
682 if (!fBranch->GetEntryOffsetLen() || (fEntryOffset == reinterpret_cast<Int_t *>(-1))) {
683 return 0;
684 }
685 // At this point, we're required to read out an offset array.
686 ResetEntryOffset(); // TODO: every basket, we reset the offset array. Is this necessary?
687 // Could we instead switch to std::vector?
688 fBufferRef->SetBufferOffset(fLast);
689 fBufferRef->ReadArray(fEntryOffset);
691 fEntryOffset = new Int_t[fNevBuf+1];
693 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);
694 return 0;
695 }
697 // In this case, we cannot regenerate the offset array at runtime -- but we wrote out an array of
698 // sizes instead of offsets (as sizes compress much better).
700 for (Int_t idx = 1; idx < fNevBuf + 1; idx++) {
701 fEntryOffset[idx] += fEntryOffset[idx - 1];
702 }
703 }
704 fReadEntryOffset = true;
705 // Read the array of displacement if any.
706 delete [] fDisplacement;
707 fDisplacement = nullptr;
708 if (fBufferRef->Length() != len) {
709 // There is more data in the buffer! It is the displacement
710 // array. If len is less than TBuffer::kMinimalSize the actual
711 // size of the buffer is too large, so we can not use the
712 // fBufferRef->BufferSize()
713 fBufferRef->ReadArray(fDisplacement);
714 }
715
716 return 0;
717}
718
719////////////////////////////////////////////////////////////////////////////////
720/// Read basket buffers in memory and cleanup
721///
722/// Read first bytes of a logical record starting at position pos
723/// return record length (first 4 bytes of record).
724
726{
727 const Int_t len = 128;
728 char buffer[len];
729 Int_t keylen;
730 file->GetRecordHeader(buffer, pos,len, fNbytes, fObjlen, keylen);
731 fKeylen = keylen;
732 return fNbytes;
733}
734
735////////////////////////////////////////////////////////////////////////////////
736/// Disown all references to the internal buffer - some other object likely now
737/// owns it.
738///
739/// This TBasket is now useless and invalid until it is told to adopt a buffer.
741{
742 fBufferRef = nullptr;
743}
744
745
746////////////////////////////////////////////////////////////////////////////////
747/// Adopt a buffer from an external entity
749{
750 delete fBufferRef;
751 fBufferRef = user_buffer;
752}
753
754////////////////////////////////////////////////////////////////////////////////
755/// Reset the read basket TBuffer memory allocation if needed.
756///
757/// This allows to reduce the number of memory allocation while avoiding to
758/// always use the maximum size.
759
761{
762 // By default, we don't reallocate.
763 fResetAllocation = false;
764#ifdef R__TRACK_BASKET_ALLOC_TIME
765 fResetAllocationTime = 0;
766#endif
767
768 // Downsize the buffer if needed.
769
770 const auto maxbaskets = fBranch->GetMaxBaskets();
771 if (!fBufferRef || basketnumber >= maxbaskets)
772 return;
773
774 Int_t curSize = fBufferRef->BufferSize();
775
776 const Float_t target_mem_ratio = fBranch->GetTree()->GetTargetMemoryRatio();
777 const auto basketbytes = fBranch->GetBasketBytes();
778
779 Int_t max_size = basketbytes[basketnumber];
780 for(Int_t b = basketnumber + 1; (b < maxbaskets) && (b < (basketnumber+10)); ++b) {
781 max_size = std::max(max_size, basketbytes[b]);
782 }
783
784 Float_t cx = 1;
785 if (fBranch->GetZipBytes())
786 cx = (Float_t)fBranch->GetTotBytes()/fBranch->GetZipBytes();
787
788 Int_t target_size = static_cast<Int_t>(cx * target_mem_ratio * Float_t(max_size));
789
790 if (target_size && (curSize > target_size)) {
791 /// Only reduce the size if significant enough?
792 Int_t newSize = max_size + 512 - max_size % 512; // Wiggle room and alignment, as above.
793 // We only bother with a resize if it saves 8KB (two normal memory pages).
794 if ((newSize <= curSize - 8 * 1024) &&
795 (static_cast<Float_t>(curSize) / static_cast<Float_t>(newSize) > target_mem_ratio))
796 {
797 if (gDebug > 0) {
798 Info("ReadResetBuffer",
799 "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 ",
800 basketnumber, newSize, curSize,
801 basketbytes[basketnumber],
802 (basketnumber + 1) < maxbaskets ? basketbytes[basketnumber + 1] : 0,
803 (basketnumber + 2) < maxbaskets ? basketbytes[basketnumber + 2] : 0,
804 (basketnumber + 3) < maxbaskets ? basketbytes[basketnumber + 3] : 0,
805 (basketnumber + 4) < maxbaskets ? basketbytes[basketnumber + 4] : 0,
806 (basketnumber + 5) < maxbaskets ? basketbytes[basketnumber + 5] : 0,
807 (basketnumber + 6) < maxbaskets ? basketbytes[basketnumber + 6] : 0,
808 (basketnumber + 7) < maxbaskets ? basketbytes[basketnumber + 7] : 0,
809 (basketnumber + 8) < maxbaskets ? basketbytes[basketnumber + 8] : 0,
810 (basketnumber + 9) < maxbaskets ? basketbytes[basketnumber + 9] : 0,
811 cx, target_mem_ratio, max_size);
812 }
813 fResetAllocation = true;
814#ifdef R__TRACK_BASKET_ALLOC_TIME
815 std::chrono::time_point<std::chrono::system_clock> start, end;
816 start = std::chrono::high_resolution_clock::now();
817#endif
818 fBufferRef->Expand(newSize, false); // Expand without copying the existing data.
819#ifdef R__TRACK_BASKET_ALLOC_TIME
820 end = std::chrono::high_resolution_clock::now();
821 auto us = std::chrono::duration_cast<std::chrono::microseconds>(end - start);
822 fResetAllocationTime = us.count();
823#endif
824 }
825 }
826}
827
828////////////////////////////////////////////////////////////////////////////////
829/// Reset the write basket to the starting state. i.e. as it was after calling
830/// the constructor (and potentially attaching a TBuffer.)
831/// Reduce memory used by fEntryOffset and the TBuffer if needed ..
832
834{
835 // By default, we don't reallocate.
836 fResetAllocation = false;
837#ifdef R__TRACK_BASKET_ALLOC_TIME
838 fResetAllocationTime = 0;
839#endif
840
841 // Name, Title, fClassName, fBranch
842 // stay the same.
843
844 // Downsize the buffer if needed.
845 // See if our current buffer size is significantly larger (>2x) than the historical average.
846 // If so, try decreasing it at this flush boundary to closer to the size from OptimizeBaskets
847 // (or this historical average).
848 Int_t curSize = fBufferRef->BufferSize();
849 // fBufferLen at this point is already reset, so use indirect measurements
850 Int_t curLen = (GetObjlen() + GetKeylen());
851 Longptr_t newSize = -1;
852 if (curSize > 2*curLen)
853 {
854 Longptr_t curBsize = fBranch->GetBasketSize();
855 if (curSize > 2*curBsize ) {
856 Longptr_t avgSize = (Longptr_t)(fBranch->GetTotBytes() / (1+fBranch->GetWriteBasket())); // Average number of bytes per basket so far
857 if (curSize > 2*avgSize) {
858 newSize = curBsize;
859 if (curLen > newSize) {
860 newSize = curLen;
861 }
862 if (avgSize > newSize) {
863 newSize = avgSize;
864 }
865 newSize = newSize + 512 - newSize%512; // Wiggle room and alignment (512 is same as in OptimizeBaskets)
866 }
867 }
868 }
869 // If fBufferRef grew since we last saw it, shrink it to "target memory ratio" of the occupied size
870 // This discourages us from having poorly-occupied buffers on branches with little variability.
871 //
872 // Does not help protect against a burst in event sizes, but does help in the cases where the basket
873 // size jumps from 4MB to 8MB while filling the basket, but we only end up utilizing 4.1MB.
874 //
875 // The above code block is meant to protect against extremely large events.
876
877 Float_t target_mem_ratio = fBranch->GetTree()->GetTargetMemoryRatio();
879 Int_t target_size = static_cast<Int_t>(target_mem_ratio * Float_t(max_size));
880 if (max_size && (curSize > target_size) && (newSize == -1)) {
881 newSize = target_size;
882 newSize = newSize + 512 - newSize % 512; // Wiggle room and alignment, as above.
883 // We only bother with a resize if it saves 8KB (two normal memory pages).
884 if ((newSize > curSize - 8 * 1024) ||
885 (static_cast<Float_t>(curSize) / static_cast<Float_t>(newSize) < target_mem_ratio)) {
886 newSize = -1;
887 } else if (gDebug > 0) {
888 Info("Reset", "Resizing to %ld bytes (was %d); last three sizes were [%d, %d, %d].", newSize, curSize,
890 }
891 }
892
893 if (newSize != -1) {
894 fResetAllocation = true;
895#ifdef R__TRACK_BASKET_ALLOC_TIME
896 std::chrono::time_point<std::chrono::system_clock> start, end;
897 start = std::chrono::high_resolution_clock::now();
898#endif
899 fBufferRef->Expand(newSize,false); // Expand without copying the existing data.
900#ifdef R__TRACK_BASKET_ALLOC_TIME
901 end = std::chrono::high_resolution_clock::now();
902 auto us = std::chrono::duration_cast<std::chrono::microseconds>(end - start);
903 fResetAllocationTime = us.count();
904#endif
905 }
906
907 // Record the actual occupied size of the buffer.
910
911 TKey::Reset();
912
913 Int_t newNevBufSize = fBranch->GetEntryOffsetLen();
914 if (newNevBufSize==0) {
916 } else if ((newNevBufSize != fNevBufSize) || (fEntryOffset <= reinterpret_cast<Int_t *>(-1))) {
918 fEntryOffset = new Int_t[newNevBufSize];
919 }
920 fNevBufSize = newNevBufSize;
921
922 fNevBuf = 0;
923 Int_t *storeEntryOffset = fEntryOffset;
924 fEntryOffset = nullptr;
925 Int_t *storeDisplacement = fDisplacement;
926 fDisplacement= nullptr;
927 fBuffer = nullptr;
928
929 fBufferRef->Reset();
930 fBufferRef->SetWriteMode();
931
932 fHeaderOnly = true;
933 fLast = 0; //Must initialize before calling Streamer()
934
936
937 fKeylen = fBufferRef->Length();
939 fLast = fKeylen;
940 fBuffer = nullptr;
941 fHeaderOnly = false;
942 fDisplacement= storeDisplacement;
943 fEntryOffset = storeEntryOffset;
944 if (fNevBufSize) {
945 for (Int_t i=0;i<fNevBufSize;i++) fEntryOffset[i] = 0;
946 }
947}
948
949////////////////////////////////////////////////////////////////////////////////
950/// Set read mode of basket.
951
953{
954 fLast = fBufferRef->Length();
955 fBufferRef->SetReadMode();
956}
957
958////////////////////////////////////////////////////////////////////////////////
959/// Set write mode of basket.
960
962{
963 fBufferRef->SetWriteMode();
964 fBufferRef->SetBufferOffset(fLast);
965}
966
967////////////////////////////////////////////////////////////////////////////////
968/// Stream a class object.
969
971{
972 // As in TBranch::GetBasket, this is used as a half-hearted measure to suppress
973 // the error reporting when many failures occur.
974 static std::atomic<Int_t> nerrors(0);
975
976 char flag;
977 if (b.IsReading()) {
978 TKey::Streamer(b); //this must be first
979 Version_t v = b.ReadVersion();
980 b >> fBufferSize;
981 // NOTE: we now use the upper-bit of the fNevBufSize to see if we have serialized any of the
982 // optional IOBits. If that bit is set, we immediately read out the IOBits; to replace this
983 // (minimal) safeguard against corruption, we will set aside the upper-bit of fIOBits to do
984 // the same thing (the fact this bit is reserved is tested in the unit tests). If there is
985 // someday a need for more than 7 IOBits, we'll widen the field using the same trick.
986 //
987 // We like to keep this safeguard because we immediately will allocate a buffer based on
988 // the value of fNevBufSize -- and would like to avoid wildly inappropriate allocations.
989 b >> fNevBufSize;
990 if (fNevBufSize < 0) {
992 b >> fIOBits;
993 if (!fIOBits || (fIOBits & (1 << 7))) {
994 Error("TBasket::Streamer",
995 "The value of fNevBufSize (%d) or fIOBits (%d) is incorrect ; setting the buffer to a zombie.",
997 MakeZombie();
998 fNevBufSize = 0;
999 } else if (fIOBits && (fIOBits & ~static_cast<Int_t>(EIOBits::kSupported))) {
1000 nerrors++;
1001 if (nerrors < 10) {
1002 Error("Streamer", "The value of fIOBits (%s) contains unknown flags (supported flags "
1003 "are %s), indicating this was written with a newer version of ROOT "
1004 "utilizing critical IO features this version of ROOT does not support."
1005 " Refusing to deserialize.",
1006 std::bitset<32>(static_cast<Int_t>(fIOBits)).to_string().c_str(),
1007 std::bitset<32>(static_cast<Int_t>(EIOBits::kSupported)).to_string().c_str());
1008 } else if (nerrors == 10) {
1009 Error("Streamer", "Maximum number of errors has been reported; disabling further messages"
1010 "from this location until the process exits.");
1011 }
1012 fNevBufSize = 0;
1013 MakeZombie();
1014 }
1015 }
1016 b >> fNevBuf;
1017 b >> fLast;
1018 b >> flag;
1020 bool mustGenerateOffsets = false;
1021 if (flag >= 80) {
1022 mustGenerateOffsets = true;
1023 flag -= 80;
1024 }
1025 if (!mustGenerateOffsets && flag && (flag % 10 != 2)) {
1028 if (fNevBuf) b.ReadArray(fEntryOffset);
1029 if (20<flag && flag<40) {
1030 for(int i=0; i<fNevBuf; i++){
1032 }
1033 }
1034 if (flag>40) {
1036 b.ReadArray(fDisplacement);
1037 }
1038 } else if (mustGenerateOffsets) {
1039 // We currently believe that in all cases when offsets can be generated, then the
1040 // displacement array must be zero.
1041 assert(flag <= 40);
1042 fEntryOffset = reinterpret_cast<Int_t *>(-1);
1043 }
1044 if (flag == 1 || flag > 10) {
1046 fBufferRef->SetParent(b.GetParent());
1047 char *buf = fBufferRef->Buffer();
1048 if (v > 1) b.ReadFastArray(buf,fLast);
1049 else b.ReadArray(buf);
1050 fBufferRef->SetBufferOffset(fLast);
1051 // This is now done in the TBranch streamer since fBranch might not
1052 // yet be set correctly.
1053 // fBranch->GetTree()->IncrementTotalBuffers(fBufferSize);
1054 }
1055 } else {
1056
1057 TKey::Streamer(b); //this must be first
1058 b.WriteVersion(TBasket::IsA());
1059 if (fBufferRef) {
1060 Int_t curLast = fBufferRef->Length();
1061 if (!fHeaderOnly && !fSeekKey && curLast > fLast) fLast = curLast;
1062 }
1064
1065 b << fBufferSize;
1066 if (fIOBits) {
1067 b << -fNevBufSize;
1068 b << fIOBits;
1069 } else {
1070 b << fNevBufSize;
1071 }
1072 b << fNevBuf;
1073 b << fLast;
1074 bool mustGenerateOffsets = fEntryOffset && fNevBuf &&
1077 // We currently believe that in all cases when offsets can be generated, then the
1078 // displacement array must be zero.
1079 assert(!mustGenerateOffsets || fDisplacement == nullptr);
1080 if (fHeaderOnly) {
1081 flag = mustGenerateOffsets ? 80 : 0;
1082 b << flag;
1083 } else {
1084 // On return from this function, we are guaranteed that fEntryOffset
1085 // is either a valid pointer or nullptr.
1086 if (fNevBuf) {
1088 }
1089 flag = 1;
1090 if (!fNevBuf || !fEntryOffset)
1091 flag = 2;
1092 if (fBufferRef) flag += 10;
1093 if (fDisplacement) flag += 40;
1094 // Test if we can skip writing out the offset map.
1095 if (mustGenerateOffsets) {
1096 flag += 80;
1097 }
1098 b << flag;
1099
1100 if (!mustGenerateOffsets && fEntryOffset && fNevBuf) {
1101 b.WriteArray(fEntryOffset, fNevBuf);
1102 if (fDisplacement) b.WriteArray(fDisplacement, fNevBuf);
1103 }
1104 if (fBufferRef) {
1105 char *buf = fBufferRef->Buffer();
1106 b.WriteFastArray(buf, fLast);
1107 }
1108 }
1109 }
1110}
1111
1112////////////////////////////////////////////////////////////////////////////////
1113/// Update basket header and EntryOffset table.
1114
1116{
1117 Int_t *entryOffset = GetEntryOffset();
1118 if (entryOffset) {
1119 if (fNevBuf+1 >= fNevBufSize) {
1120 Int_t newsize = TMath::Max(10,2*fNevBufSize);
1121 Int_t *newoff = TStorage::ReAllocInt(fEntryOffset, newsize,
1122 fNevBufSize);
1123 if (fDisplacement) {
1124 Int_t *newdisp = TStorage::ReAllocInt(fDisplacement, newsize,
1125 fNevBufSize);
1126 fDisplacement = newdisp;
1127 }
1128 fEntryOffset = newoff;
1129 fNevBufSize = newsize;
1130
1131 //Update branch only for the first 10 baskets
1132 if (fBranch->GetWriteBasket() < 10) {
1133 fBranch->SetEntryOffsetLen(newsize);
1134 }
1135 }
1137
1138 if (skipped!=offset && !fDisplacement){
1140 for (Int_t i = 0; i<fNevBufSize; i++) fDisplacement[i] = fEntryOffset[i];
1141 }
1142 if (fDisplacement) {
1143 fDisplacement[fNevBuf] = skipped;
1144 fBufferRef->SetBufferDisplacement(skipped);
1145 }
1146 }
1147
1148 fNevBuf++;
1149}
1150
1151////////////////////////////////////////////////////////////////////////////////
1152/// Write buffer of this basket on the current file.
1153///
1154/// The function returns the number of bytes committed to the memory.
1155/// If a write error occurs, the number of bytes returned is -1.
1156/// If no data are written, the number of bytes returned is 0.
1157
1159{
1160 constexpr Int_t kWrite = 1;
1161
1162 TFile *file = fBranch->GetFile(kWrite);
1163 if (!file) return 0;
1164 if (!file->IsWritable()) {
1165 return -1;
1166 }
1167 fMotherDir = file; // fBranch->GetDirectory();
1168
1169 // This mutex prevents multiple TBasket::WriteBuffer invocations from interacting
1170 // with the underlying TFile at once - TFile is assumed to *not* be thread-safe.
1171 //
1172 // The only parallelism we'd like to exploit (right now!) is the compression
1173 // step - everything else should be serialized at the TFile level.
1174#ifdef R__USE_IMT
1175 std::unique_lock<std::mutex> sentry(file->fWriteMutex);
1176#endif // R__USE_IMT
1177
1179 // Read the basket information that was saved inside the buffer.
1180 bool writing = fBufferRef->IsWriting();
1181 fBufferRef->SetReadMode();
1182 fBufferRef->SetBufferOffset(0);
1183
1185 if (writing) fBufferRef->SetWriteMode();
1186 Int_t nout = fNbytes - fKeylen;
1187
1188 fBuffer = fBufferRef->Buffer();
1189
1190 Create(nout,file);
1191 fBufferRef->SetBufferOffset(0);
1192 fHeaderOnly = true;
1193
1194 Streamer(*fBufferRef); //write key itself again
1195 int nBytes = WriteFileKeepBuffer();
1196 fHeaderOnly = false;
1197 return nBytes>0 ? fKeylen+nout : -1;
1198 }
1199
1200 // Transfer fEntryOffset table at the end of fBuffer.
1201 fLast = fBufferRef->Length();
1202 Int_t *entryOffset = GetEntryOffset();
1203 if (entryOffset) {
1204 bool hasOffsetBit = fIOBits & static_cast<UChar_t>(TBasket::EIOBits::kGenerateOffsetMap);
1205 if (!CanGenerateOffsetArray()) {
1206 // If we have set the offset map flag, but cannot dynamically generate the map, then
1207 // we should at least convert the offset array to a size array. Note that we always
1208 // write out (fNevBuf+1) entries to match the original case.
1209 if (hasOffsetBit) {
1210 for (Int_t idx = fNevBuf; idx > 0; idx--) {
1211 entryOffset[idx] -= entryOffset[idx - 1];
1212 }
1213 entryOffset[0] = 0;
1214 }
1215 fBufferRef->WriteArray(entryOffset, fNevBuf + 1);
1216 // Convert back to offset format: keeping both sizes and offsets in-memory were considered,
1217 // but it seems better to use CPU than memory.
1218 if (hasOffsetBit) {
1219 entryOffset[0] = fKeylen;
1220 for (Int_t idx = 1; idx < fNevBuf + 1; idx++) {
1221 entryOffset[idx] += entryOffset[idx - 1];
1222 }
1223 }
1224 } else if (!hasOffsetBit) { // In this case, write out as normal
1225 fBufferRef->WriteArray(entryOffset, fNevBuf + 1);
1226 }
1227 if (fDisplacement) {
1228 fBufferRef->WriteArray(fDisplacement, fNevBuf + 1);
1229 delete[] fDisplacement;
1230 fDisplacement = nullptr;
1231 }
1232 }
1233
1234 Int_t nout, noutot, bufmax, nzip;
1235
1236 fObjlen = fBufferRef->Length() - fKeylen;
1237
1238 fHeaderOnly = true;
1239 fCycle = fBranch->GetWriteBasket();
1240 Int_t cxlevel = fBranch->GetCompressionLevel();
1242 cxlevel = file->GetCompressionLevel();
1246 if (cxlevel > 0) {
1247 Int_t nbuffers = 1 + (fObjlen - 1) / kMAXZIPBUF;
1248 Int_t buflen = fKeylen + fObjlen + 9 * nbuffers + 28; //add 28 bytes in case object is placed in a deleted gap
1249 InitializeCompressedBuffer(buflen, file);
1250 if (!fCompressedBufferRef) {
1251 Warning("WriteBuffer", "Unable to allocate the compressed buffer");
1252 return -1;
1253 }
1254 fCompressedBufferRef->SetWriteMode();
1255 fBuffer = fCompressedBufferRef->Buffer();
1256 char *objbuf = fBufferRef->Buffer() + fKeylen;
1257 char *bufcur = &fBuffer[fKeylen];
1258 noutot = 0;
1259 nzip = 0;
1260 for (Int_t i = 0; i < nbuffers; ++i) {
1261 if (i == nbuffers - 1) bufmax = fObjlen - nzip;
1262 else bufmax = kMAXZIPBUF;
1263 // Compress the buffer. Note that we allow multiple TBasket compressions to occur at once
1264 // for a given TFile: that's because the compression buffer when we use IMT is no longer
1265 // shared amongst several threads.
1266#ifdef R__USE_IMT
1267 sentry.unlock();
1268#endif // R__USE_IMT
1269 // NOTE this is declared with C linkage, so it shouldn't except. Also, when
1270 // USE_IMT is defined, we are guaranteed that the compression buffer is unique per-branch.
1271 // (see fCompressedBufferRef in constructor).
1272 R__zipMultipleAlgorithm(cxlevel, &bufmax, objbuf, &bufmax, bufcur, &nout, cxAlgorithm);
1273#ifdef R__USE_IMT
1274 sentry.lock();
1275#endif // R__USE_IMT
1276
1277 // test if buffer has really been compressed. In case of small buffers
1278 // when the buffer contains random data, it may happen that the compressed
1279 // buffer is larger than the input. In this case, we write the original uncompressed buffer
1280 if (nout == 0 || nout >= fObjlen) {
1281 nout = fObjlen;
1282 // We used to delete fBuffer here, we no longer want to since
1283 // the buffer (held by fCompressedBufferRef) might be re-used later.
1284 fBuffer = fBufferRef->Buffer();
1285 Create(fObjlen,file);
1286 fBufferRef->SetBufferOffset(0);
1287
1288 Streamer(*fBufferRef); //write key itself again
1289 if ((nout+fKeylen)>buflen) {
1290 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",
1291 (nout+fKeylen-buflen),buflen,fNbytes,fObjlen,fKeylen);
1292 }
1293 goto WriteFile;
1294 }
1295 bufcur += nout;
1296 noutot += nout;
1297 objbuf += kMAXZIPBUF;
1298 nzip += kMAXZIPBUF;
1299 }
1300 nout = noutot;
1301 Create(noutot,file);
1302 fBufferRef->SetBufferOffset(0);
1303
1304 Streamer(*fBufferRef); //write key itself again
1305 memcpy(fBuffer,fBufferRef->Buffer(),fKeylen);
1306 } else {
1307 fBuffer = fBufferRef->Buffer();
1308 Create(fObjlen,file);
1309 fBufferRef->SetBufferOffset(0);
1310
1311 Streamer(*fBufferRef); //write key itself again
1312 nout = fObjlen;
1313 }
1314
1315WriteFile:
1316 Int_t nBytes = WriteFileKeepBuffer();
1317 fHeaderOnly = false;
1318 return nBytes>0 ? fKeylen+nout : -1;
1319}
#define R__likely(expr)
Definition RConfig.hxx:579
#define R__unlikely(expr)
Definition RConfig.hxx:578
true
Register systematic variations for multiple existing columns using auto-generated tags.
#define b(i)
Definition RSha256.hxx:100
size_t size(const MatrixT &matrix)
retrieve the size of a square matrix
int Int_t
Definition RtypesCore.h:45
long Longptr_t
Definition RtypesCore.h:82
short Version_t
Definition RtypesCore.h:65
unsigned char UChar_t
Definition RtypesCore.h:38
unsigned int UInt_t
Definition RtypesCore.h:46
float Float_t
Definition RtypesCore.h:57
double Double_t
Definition RtypesCore.h:59
long long Long64_t
Definition RtypesCore.h:80
#define ClassImp(name)
Definition Rtypes.h:377
constexpr auto gMaxInt_t
Definition TBasket.cxx:36
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:412
#define OLD_CASE_EXPRESSION
Definition TBasket.cxx:355
const UInt_t kDisplacementMask
Definition TBasket.cxx:32
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 i
Int_t gDebug
Definition TROOT.cxx:622
externTVirtualMutex * 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
#define free
Definition civetweb.c:1539
Manages buffers for branches of a Tree.
Definition TBasket.h:34
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:232
void AdoptBuffer(TBuffer *user_buffer)
Adopt a buffer from an external entity.
Definition TBasket.cxx:748
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:148
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:434
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:382
void DisownBuffer()
Disown all references to the internal buffer - some other object likely now owns it.
Definition TBasket.cxx:740
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:466
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:175
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:312
bool fOwnsCompressedBuffer
! Whether or not we own the compressed buffer.
Definition TBasket.h:68
void ResetEntryOffset()
Definition TBasket.cxx:443
TBasket()
Default constructor.
Definition TBasket.cxx:49
virtual void AdjustSize(Int_t newsize)
Increase the size of the current fBuffer up to newsize.
Definition TBasket.cxx:129
virtual void SetReadMode()
Set read mode of basket.
Definition TBasket.cxx:952
virtual void SetWriteMode()
Set write mode of basket.
Definition TBasket.cxx:961
Int_t ReadBasketBuffersUncompressedCase()
By-passing buffer unzipping has been requested and is possible (only 1 entry in this basket).
Definition TBasket.cxx:360
friend class TBranch
Definition TBasket.h:35
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:725
virtual void ReadResetBuffer(Int_t basketnumber)
Reset the read basket TBuffer memory allocation if needed.
Definition TBasket.cxx:760
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:1158
void Streamer(TBuffer &) override
Stream a class object.
Definition TBasket.cxx:970
Int_t LoadBasketBuffers(Long64_t pos, Int_t len, TFile *file, TTree *tree=nullptr)
Load basket buffers in memory without unziping.
Definition TBasket.cxx:247
~TBasket() override
Basket destructor.
Definition TBasket.cxx:106
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:197
TClass * IsA() const override
Definition TBasket.h:156
virtual void DeleteEntryOffset()
Delete fEntryOffset array.
Definition TBasket.cxx:166
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:220
virtual void WriteReset()
Reset the write basket to the starting state.
Definition TBasket.cxx:833
TTree * GetTree() const
Definition TBranch.h:252
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:1853
TDirectory * GetDirectory() const
Definition TBranch.h:224
TBuffer * GetTransientBuffer(Int_t size)
Returns the transient buffer currently used by this TBranch for reading/writing baskets.
Definition TBranch.cxx:523
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
virtual void Reset()=0
void Expand(Int_t newsize, Bool_t copy=kTRUE)
Expand (or shrink) the I/O buffer to newsize bytes.
Definition TBuffer.cxx:223
Int_t BufferSize() const
Definition TBuffer.h:98
@ 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:302
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.
virtual Int_t GetUnzipBuffer(char **, Long64_t, Int_t, Bool_t *)
virtual Int_t ReadBuffer(char *buf, Long64_t pos, Int_t len)
Read buffer at position pos.
virtual void AddNoCacheReadCalls(Int_t reads)
virtual void AddNoCacheBytesRead(Long64_t len)
A file, usually with extension .root, that stores data and code in the form of serialized objects in ...
Definition TFile.h:53
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:2295
Int_t GetCompressionLevel() const
Definition TFile.h:391
std::mutex fWriteMutex
!Lock for writing baskets / keys into the file.
Definition TFile.h:118
virtual void SetOffset(Long64_t offset, ERelativeTo pos=kBeg)
Set position from where to start reading.
Definition TFile.cxx:2274
Int_t GetCompressionAlgorithm() const
Definition TFile.h:385
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:1322
virtual Bool_t ReadBuffer(char *buf, Int_t len)
Read a buffer from the file.
Definition TFile.cxx:1791
TFileCacheRead * GetCacheRead(const TObject *tree=nullptr) const
Return a pointer to the current read cache.
Definition TFile.cxx:1283
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
TKey(const TKey &)=delete
virtual Int_t WriteFileKeepBuffer(TFile *f=nullptr)
Write the encoded object supported by this key.
Definition TKey.cxx:1552
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:1359
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:476
virtual Int_t WriteFile(Int_t cycle=1, TFile *f=nullptr)
Write the encoded object supported by this key.
Definition TKey.cxx:1511
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:1410
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 bool CanGenerateOffsetArray()
Definition TLeaf.h:112
virtual Int_t * GenerateOffsetArray(Int_t base, Int_t events)
Definition TLeaf.h:115
virtual void SetTitle(const char *title="")
Set the title of the TNamed.
Definition TNamed.cxx:164
const char * GetName() const override
Returns name of object.
Definition TNamed.h:47
virtual void SetName(const char *name)
Set the name of the TNamed.
Definition TNamed.cxx:140
R__ALWAYS_INLINE Bool_t TestBit(UInt_t f) const
Definition TObject.h:196
virtual void Warning(const char *method, const char *msgfmt,...) const
Issue warning message.
Definition TObject.cxx:973
R__ALWAYS_INLINE Bool_t IsZombie() const
Definition TObject.h:153
virtual void Error(const char *method, const char *msgfmt,...) const
Issue error message.
Definition TObject.cxx:987
void MakeZombie()
Definition TObject.h:53
virtual void Info(const char *method, const char *msgfmt,...) const
Issue info message.
Definition TObject.cxx:961
static Int_t * ReAllocInt(Int_t *vp, size_t size, size_t oldsize)
Reallocate (i.e.
Definition TStorage.cxx:258
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
virtual void Disable()
Definition TTreeCache.h:136
virtual void Enable()
Definition TTreeCache.h:137
A TTree represents a columnar dataset.
Definition TTree.h:79
virtual void IncrementTotalBuffers(Int_t nbytes)
Definition TTree.h:549
TBuffer * GetTransientBuffer(Int_t size)
Returns the transient buffer currently used by this TTree for reading/writing baskets.
Definition TTree.cxx:1037
Provides the interface for the PROOF 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:250
EValues
Note: this is only temporarily a struct and will become a enum class hence the name convention used.
Definition Compression.h:85
@ kInherit
Some objects use this value to denote that the compression algorithm should be inherited from the par...
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:66