Logo ROOT   6.12/07
Reference Guide
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 "TBasket.h"
12 #include "TBuffer.h"
13 #include "TBufferFile.h"
14 #include "TTree.h"
15 #include "TBranch.h"
16 #include "TFile.h"
17 #include "TLeaf.h"
18 #include "TBufferFile.h"
19 #include "TMath.h"
20 #include "TROOT.h"
21 #include "TTreeCache.h"
22 #include "TVirtualMutex.h"
23 #include "TVirtualPerfStats.h"
24 #include "TTimeStamp.h"
25 #include "ROOT/TIOFeatures.hxx"
26 #include "RZip.h"
27 
28 #include <bitset>
29 
30 const UInt_t kDisplacementMask = 0xFF000000; // In the streamer the two highest bytes of
31  // the fEntryOffset are used to stored displacement.
32 
34 
35 /** \class TBasket
36 \ingroup tree
37 
38 Manages buffers for branches of a Tree.
39 
40 See picture in TTree.
41 */
42 
43 ////////////////////////////////////////////////////////////////////////////////
44 /// Default contructor.
45 
47 {
48 }
49 
50 ////////////////////////////////////////////////////////////////////////////////
51 /// Constructor used during reading.
52 
53 TBasket::TBasket(TDirectory *motherDir) : TKey(motherDir)
54 {
55 }
56 
57 ////////////////////////////////////////////////////////////////////////////////
58 /// Basket normal constructor, used during writing.
59 
60 TBasket::TBasket(const char *name, const char *title, TBranch *branch)
61  : TKey(branch->GetDirectory()), fBufferSize(branch->GetBasketSize()), fNevBufSize(branch->GetEntryOffsetLen()),
62  fHeaderOnly(kTRUE), fIOBits(branch->GetIOFeatures().GetFeatures())
63 {
64  SetName(name);
65  SetTitle(title);
66  fClassName = "TBasket";
67  fBuffer = nullptr;
69  fVersion += 1000;
70  if (branch->GetDirectory()) {
71  TFile *file = branch->GetFile();
72  fBufferRef->SetParent(file);
73  }
74  if (branch->GetTree()) {
75 #ifdef R__USE_IMT
77 #else
79 #endif
81  if (!fCompressedBufferRef) {
84  }
85  }
86  fBranch = branch;
87  Streamer(*fBufferRef);
90  fLast = fKeylen;
91  fBuffer = 0;
93  if (fNevBufSize) {
95  for (Int_t i=0;i<fNevBufSize;i++) fEntryOffset[i] = 0;
96  }
98 }
99 
100 ////////////////////////////////////////////////////////////////////////////////
101 /// Basket destructor.
102 
104 {
105  if (fDisplacement) delete [] fDisplacement;
107  if (fBufferRef) delete fBufferRef;
108  fBufferRef = 0;
109  fBuffer = 0;
110  fDisplacement= 0;
111  // Note we only delete the compressed buffer if we own it
113  delete fCompressedBufferRef;
115  }
116 }
117 
118 ////////////////////////////////////////////////////////////////////////////////
119 /// Increase the size of the current fBuffer up to newsize.
120 
122 {
123  if (fBuffer == fBufferRef->Buffer()) {
124  fBufferRef->Expand(newsize);
126  } else {
127  fBufferRef->Expand(newsize);
128  }
130  fBufferSize = newsize;
131 }
132 
133 ////////////////////////////////////////////////////////////////////////////////
134 /// Copy the basket of this branch onto the file to.
135 
137 {
139  Int_t nout = fNbytes - fKeylen;
141  Create(nout, to);
143  fHeaderOnly = kTRUE;
144  Streamer(*fBufferRef);
146  Int_t nBytes = WriteFileKeepBuffer(to);
147 
148  return nBytes>0 ? nBytes : -1;
149 }
150 
151 ////////////////////////////////////////////////////////////////////////////////
152 /// Delete fEntryOffset array.
153 
155 {
157  fNevBufSize = 0;
158 }
159 
160 ////////////////////////////////////////////////////////////////////////////////
161 /// Drop buffers of this basket if it is not the current basket.
162 
164 {
165  if (!fBuffer && !fBufferRef) return 0;
166 
167  if (fDisplacement) delete [] fDisplacement;
169  if (fBufferRef) delete fBufferRef;
171  fBufferRef = 0;
173  fBuffer = 0;
174  fDisplacement= 0;
175  fEntryOffset = 0;
177  return fBufferSize;
178 }
179 
180 ////////////////////////////////////////////////////////////////////////////////
181 /// Calculates the entry offset array, if possible.
182 ///
183 /// Result is cached, meaning that this should only be invoked once per basket.
184 
186 {
187  if (fEntryOffset != reinterpret_cast<Int_t *>(-1)) {
188  return fEntryOffset;
189  }
190 
191  if (R__unlikely(!fBranch)) {
192  Error("GetCalculatedEntryOffset", "Basket entry offset calculation requested, but no associated TBranch!");
193  return nullptr;
194  }
195  if (R__unlikely(fBranch->GetNleaves() != 1)) {
196  Error("GetCalculatedEntryOffset", "Branch contains multiple leaves - unable to calculated entry offsets!");
197  return nullptr;
198  }
199  TLeaf *leaf = static_cast<TLeaf *>((*fBranch->GetListOfLeaves())[0]);
201  return fEntryOffset;
202 }
203 
204 ////////////////////////////////////////////////////////////////////////////////
205 /// Determine whether we can generate the offset array when this branch is read.
206 ///
207 
209 {
210  if (fBranch->GetNleaves() != 1) {
211  return kFALSE;
212  }
213  TLeaf *leaf = static_cast<TLeaf *>((*fBranch->GetListOfLeaves())[0]);
214  return leaf->CanGenerateOffsetArray();
215 }
216 
217 ////////////////////////////////////////////////////////////////////////////////
218 /// Get pointer to buffer for internal entry.
219 
221 {
222  Int_t offset;
223  Int_t *entryOffset = GetEntryOffset();
224  if (entryOffset) offset = entryOffset[entry];
225  else offset = fKeylen + entry*fNevBufSize;
226  fBufferRef->SetBufferOffset(offset);
227  return offset;
228 }
229 
230 ////////////////////////////////////////////////////////////////////////////////
231 /// Load basket buffers in memory without unziping.
232 /// This function is called by TTreeCloner.
233 /// The function returns 0 in case of success, 1 in case of error.
234 
236 {
237  if (fBufferRef) {
238  // Reuse the buffer if it exist.
239  fBufferRef->Reset();
240 
241  // We use this buffer both for reading and writing, we need to
242  // make sure it is properly sized for writing.
244  if (fBufferRef->BufferSize() < len) {
245  fBufferRef->Expand(len);
246  }
248  } else {
250  }
251  fBufferRef->SetParent(file);
252  char *buffer = fBufferRef->Buffer();
253  file->Seek(pos);
254  TFileCacheRead *pf = file->GetCacheRead(tree);
255  if (pf) {
257  if (tree->GetPerfStats()) gPerfStats = tree->GetPerfStats();
258  Int_t st = pf->ReadBuffer(buffer,pos,len);
259  if (st < 0) {
260  return 1;
261  } else if (st == 0) {
262  // fOffset might have been changed via TFileCacheRead::ReadBuffer(), reset it
263  file->Seek(pos);
264  // If we are using a TTreeCache, disable reading from the default cache
265  // temporarily, to force reading directly from file
266  TTreeCache *fc = dynamic_cast<TTreeCache*>(file->GetCacheRead());
267  if (fc) fc->Disable();
268  Int_t ret = file->ReadBuffer(buffer,len);
269  if (fc) fc->Enable();
270  pf->AddNoCacheBytesRead(len);
271  pf->AddNoCacheReadCalls(1);
272  if (ret) {
273  return 1;
274  }
275  }
276  gPerfStats = temp;
277  // fOffset might have been changed via TFileCacheRead::ReadBuffer(), reset it
278  file->SetOffset(pos + len);
279  } else {
281  if (tree->GetPerfStats() != 0) gPerfStats = tree->GetPerfStats();
282  if (file->ReadBuffer(buffer,len)) {
283  gPerfStats = temp;
284  return 1; //error while reading
285  }
286  else gPerfStats = temp;
287  }
288 
291  Streamer(*fBufferRef);
292 
293  return 0;
294 }
295 
296 ////////////////////////////////////////////////////////////////////////////////
297 /// Remove the first dentries of this basket, moving entries at
298 /// dentries to the start of the buffer.
299 
301 {
302  Int_t i;
303 
304  if (dentries >= fNevBuf) return;
305  Int_t bufbegin;
306  Int_t moved;
307 
308  Int_t *entryOffset = GetEntryOffset();
309  if (entryOffset) {
310  bufbegin = entryOffset[dentries];
311  moved = bufbegin-GetKeylen();
312 
313  // First store the original location in the fDisplacement array
314  // and record the new start offset
315 
316  if (!fDisplacement) {
318  }
319  for (i = 0; i<(fNevBufSize-dentries); ++i) {
320  fDisplacement[i] = entryOffset[i + dentries];
321  entryOffset[i] = entryOffset[i + dentries] - moved;
322  }
323  for (i = fNevBufSize-dentries; i<fNevBufSize; ++i) {
324  fDisplacement[i] = 0;
325  entryOffset[i] = 0;
326  }
327 
328  } else {
329  // If there is no EntryOffset array, this means
330  // that each entry has the same size and that
331  // it does not point to other objects (hence there
332  // is no need for a displacement array).
333  bufbegin = GetKeylen() + dentries*fNevBufSize;
334  moved = bufbegin-GetKeylen();
335  }
336  TBuffer *buf = GetBufferRef();
337  char *buffer = buf->Buffer();
338  memmove(buffer+GetKeylen(),buffer+bufbegin,buf->Length()-bufbegin);
339  buf->SetBufferOffset(buf->Length()-moved);
340  fNevBuf -= dentries;
341 }
342 
343 #define OLD_CASE_EXPRESSION fObjlen==fNbytes-fKeylen && GetBranch()->GetCompressionLevel()!=0 && file->GetVersion()<=30401
344 ////////////////////////////////////////////////////////////////////////////////
345 /// By-passing buffer unzipping has been requested and is
346 /// possible (only 1 entry in this basket).
347 
349 {
351 
352  // Make sure that the buffer is set at the END of the data
354 
355  // Indicate that this buffer is weird.
357 
358  // Usage of this mode assume the existance of only ONE
359  // entry in this basket.
361  delete [] fDisplacement; fDisplacement = 0;
362 
364  return 0;
365 }
366 
367 ////////////////////////////////////////////////////////////////////////////////
368 /// We always create the TBuffer for the basket but it hold the buffer from the cache.
369 
371 {
372  if (fBufferRef) {
373  fBufferRef->SetBuffer(buffer, size, mustFree);
375  fBufferRef->Reset();
376  } else {
377  fBufferRef = new TBufferFile(TBuffer::kRead, size, buffer, mustFree);
378  }
379  fBufferRef->SetParent(file);
380 
381  Streamer(*fBufferRef);
382 
383  if (IsZombie()) {
384  return -1;
385  }
386 
387  Bool_t oldCase = OLD_CASE_EXPRESSION;
388 
389  if ((fObjlen > fNbytes-fKeylen || oldCase) && TestBit(TBufferFile::kNotDecompressed) && (fNevBuf==1)) {
391  }
392 
394  return fObjlen+fKeylen;
395 }
396 
397 ////////////////////////////////////////////////////////////////////////////////
398 /// Initialize a buffer for reading if it is not already initialized
399 
400 static inline TBuffer* R__InitializeReadBasketBuffer(TBuffer* bufferRef, Int_t len, TFile* file)
401 {
402  TBuffer* result;
403  if (R__likely(bufferRef)) {
404  bufferRef->SetReadMode();
405  Int_t curBufferSize = bufferRef->BufferSize();
406  if (curBufferSize < len) {
407  // Experience shows that giving 5% "wiggle-room" decreases churn.
408  bufferRef->Expand(Int_t(len*1.05));
409  }
410  bufferRef->Reset();
411  result = bufferRef;
412  } else {
413  result = new TBufferFile(TBuffer::kRead, len);
414  }
415  result->SetParent(file);
416  return result;
417 }
418 
419 ////////////////////////////////////////////////////////////////////////////////
420 /// Initialize the compressed buffer; either from the TTree or create a local one.
421 
423 {
424  Bool_t compressedBufferExists = fCompressedBufferRef != NULL;
426  if (R__unlikely(!compressedBufferExists)) {
428  }
429 }
430 
432 {
433  if (fEntryOffset != reinterpret_cast<Int_t *>(-1)) {
434  delete[] fEntryOffset;
435  }
436  fEntryOffset = nullptr;
437 }
438 
439 ////////////////////////////////////////////////////////////////////////////////
440 /// Read basket buffers in memory and cleanup.
441 ///
442 /// Read a basket buffer. Check if buffers of previous ReadBasket
443 /// should not be dropped. Remember, we keep buffers in memory up to
444 /// fMaxVirtualSize.
445 /// The function returns 0 in case of success, 1 in case of error
446 /// This function was modified with the addition of the parallel
447 /// unzipping, it will try to get the unzipped file from the cache
448 /// receiving only a pointer to that buffer (so we shall not
449 /// delete that pointer), although we get a new buffer in case
450 /// it's not found in the cache.
451 /// There is a lot of code duplication but it was necesary to assure
452 /// the expected behavior when there is no cache.
453 
455 {
456  if(!fBranch->GetDirectory()) {
457  return -1;
458  }
459 
460  Bool_t oldCase;
461  char *rawUncompressedBuffer, *rawCompressedBuffer;
462  Int_t uncompressedBufferLen;
463 
464  // See if the cache has already unzipped the buffer for us.
465  TFileCacheRead *pf = nullptr;
466  {
467  R__LOCKGUARD_IMT2(gROOTMutex); // Lock for parallel TTree I/O
468  pf = file->GetCacheRead(fBranch->GetTree());
469  }
470  if (pf) {
471  Int_t res = -1;
472  Bool_t free = kTRUE;
473  char *buffer = nullptr;
474  res = pf->GetUnzipBuffer(&buffer, pos, len, &free);
475  if (R__unlikely(res >= 0)) {
476  len = ReadBasketBuffersUnzip(buffer, res, free, file);
477  // Note that in the kNotDecompressed case, the above function will return 0;
478  // In such a case, we should stop processing
479  if (len <= 0) return -len;
480  goto AfterBuffer;
481  }
482  }
483 
484  // Determine which buffer to use, so that we can avoid a memcpy in case of
485  // the basket was not compressed.
486  TBuffer* readBufferRef;
488  readBufferRef = fBufferRef;
489  } else {
490  readBufferRef = fCompressedBufferRef;
491  }
492 
493  // fBufferSize is likely to be change in the Streamer call (below)
494  // and we will re-add the new size later on.
496 
497  // Initialize the buffer to hold the compressed data.
498  readBufferRef = R__InitializeReadBasketBuffer(readBufferRef, len, file);
499  if (!readBufferRef) {
500  Error("ReadBasketBuffers", "Unable to allocate buffer.");
501  return 1;
502  }
503 
504  if (pf) {
507  Int_t st = 0;
508  {
509  R__LOCKGUARD_IMT2(gROOTMutex); // Lock for parallel TTree I/O
510  st = pf->ReadBuffer(readBufferRef->Buffer(),pos,len);
511  }
512  if (st < 0) {
513  return 1;
514  } else if (st == 0) {
515  // Read directly from file, not from the cache
516  // If we are using a TTreeCache, disable reading from the default cache
517  // temporarily, to force reading directly from file
518  R__LOCKGUARD_IMT2(gROOTMutex); // Lock for parallel TTree I/O
519  TTreeCache *fc = dynamic_cast<TTreeCache*>(file->GetCacheRead());
520  if (fc) fc->Disable();
521  Int_t ret = file->ReadBuffer(readBufferRef->Buffer(),pos,len);
522  if (fc) fc->Enable();
523  pf->AddNoCacheBytesRead(len);
524  pf->AddNoCacheReadCalls(1);
525  if (ret) {
526  return 1;
527  }
528  }
529  gPerfStats = temp;
530  } else {
531  // Read from the file and unstream the header information.
534  R__LOCKGUARD_IMT2(gROOTMutex); // Lock for parallel TTree I/O
535  if (file->ReadBuffer(readBufferRef->Buffer(),pos,len)) {
536  gPerfStats = temp;
537  return 1;
538  }
539  else gPerfStats = temp;
540  }
541  Streamer(*readBufferRef);
542  if (IsZombie()) {
543  return 1;
544  }
545 
546  rawCompressedBuffer = readBufferRef->Buffer();
547 
548  // Are we done?
549  if (R__unlikely(readBufferRef == fBufferRef)) // We expect most basket to be compressed.
550  {
551  if (R__likely(fObjlen+fKeylen == fNbytes)) {
552  // The basket was really not compressed as expected.
553  goto AfterBuffer;
554  } else {
555  // Well, somehow the buffer was compressed anyway, we have the compressed data in the uncompressed buffer
556  // Make sure the compressed buffer is initialized, and memcpy.
557  InitializeCompressedBuffer(len, file);
558  if (!fCompressedBufferRef) {
559  Error("ReadBasketBuffers", "Unable to allocate buffer.");
560  return 1;
561  }
562  fBufferRef->Reset();
563  rawCompressedBuffer = fCompressedBufferRef->Buffer();
564  memcpy(rawCompressedBuffer, fBufferRef->Buffer(), len);
565  }
566  }
567 
568  // Initialize buffer to hold the uncompressed data
569  // Note that in previous versions we didn't allocate buffers until we verified
570  // the zip headers; this is no longer beforehand as the buffer lifetime is scoped
571  // to the TBranch.
572  uncompressedBufferLen = len > fObjlen+fKeylen ? len : fObjlen+fKeylen;
573  fBufferRef = R__InitializeReadBasketBuffer(fBufferRef, uncompressedBufferLen, file);
574  rawUncompressedBuffer = fBufferRef->Buffer();
575  fBuffer = rawUncompressedBuffer;
576 
577  oldCase = OLD_CASE_EXPRESSION;
578  // Case where ROOT thinks the buffer is compressed. Copy over the key and uncompress the object
579  if (fObjlen > fNbytes-fKeylen || oldCase) {
582  }
583 
584  // Optional monitor for zip time profiling.
585  Double_t start = 0;
586  if (R__unlikely(gPerfStats)) {
587  start = TTimeStamp();
588  }
589 
590  memcpy(rawUncompressedBuffer, rawCompressedBuffer, fKeylen);
591  char *rawUncompressedObjectBuffer = rawUncompressedBuffer+fKeylen;
592  UChar_t *rawCompressedObjectBuffer = (UChar_t*)rawCompressedBuffer+fKeylen;
593  Int_t nin, nbuf;
594  Int_t nout = 0, noutot = 0, nintot = 0;
595 
596  // Unzip all the compressed objects in the compressed object buffer.
597  while (1) {
598  // Check the header for errors.
599  if (R__unlikely(R__unzip_header(&nin, rawCompressedObjectBuffer, &nbuf) != 0)) {
600  Error("ReadBasketBuffers", "Inconsistency found in header (nin=%d, nbuf=%d)", nin, nbuf);
601  break;
602  }
603  if (R__unlikely(oldCase && (nin > fObjlen || nbuf > fObjlen))) {
604  //buffer was very likely not compressed in an old version
605  memcpy(rawUncompressedBuffer+fKeylen, rawCompressedObjectBuffer+fKeylen, fObjlen);
606  goto AfterBuffer;
607  }
608 
609  R__unzip(&nin, rawCompressedObjectBuffer, &nbuf, (unsigned char*) rawUncompressedObjectBuffer, &nout);
610  if (!nout) break;
611  noutot += nout;
612  nintot += nin;
613  if (noutot >= fObjlen) break;
614  rawCompressedObjectBuffer += nin;
615  rawUncompressedObjectBuffer += nout;
616  }
617 
618  // Make sure the uncompressed numbers are consistent with header.
619  if (R__unlikely(noutot != fObjlen)) {
620  Error("ReadBasketBuffers", "fNbytes = %d, fKeylen = %d, fObjlen = %d, noutot = %d, nout=%d, nin=%d, nbuf=%d", fNbytes,fKeylen,fObjlen, noutot,nout,nin,nbuf);
622  return 1;
623  }
624  len = fObjlen+fKeylen;
627  if (R__unlikely(gPerfStats)) {
628  gPerfStats->UnzipEvent(fBranch->GetTree(),pos,start,nintot,fObjlen);
629  }
630  gPerfStats = temp;
631  } else {
632  // Nothing is compressed - copy over wholesale.
633  memcpy(rawUncompressedBuffer, rawCompressedBuffer, len);
634  }
635 
636 AfterBuffer:
637 
639 
640  // Read offsets table if needed.
641  // If there's no EntryOffsetLen in the branch -- or the fEntryOffset is marked to be calculated-on-demand --
642  // then we skip reading out.
643  if (!fBranch->GetEntryOffsetLen() || (fEntryOffset == reinterpret_cast<Int_t *>(-1))) {
644  return 0;
645  }
646  // At this point, we're required to read out an offset array.
647  ResetEntryOffset(); // TODO: every basket, we reset the offset array. Is this necessary?
648  // Could we instead switch to std::vector?
651  if (R__unlikely(!fEntryOffset)) {
652  fEntryOffset = new Int_t[fNevBuf+1];
653  fEntryOffset[0] = fKeylen;
654  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);
655  return 0;
656  }
657  if (fIOBits & static_cast<UChar_t>(TBasket::EIOBits::kGenerateOffsetMap)) {
658  // In this case, we cannot regenerate the offset array at runtime -- but we wrote out an array of
659  // sizes instead of offsets (as sizes compress much better).
660  fEntryOffset[0] = fKeylen;
661  for (Int_t idx = 1; idx < fNevBuf + 1; idx++) {
662  fEntryOffset[idx] += fEntryOffset[idx - 1];
663  }
664  }
666  // Read the array of diplacement if any.
667  delete [] fDisplacement;
668  fDisplacement = 0;
669  if (fBufferRef->Length() != len) {
670  // There is more data in the buffer! It is the displacement
671  // array. If len is less than TBuffer::kMinimalSize the actual
672  // size of the buffer is too large, so we can not use the
673  // fBufferRef->BufferSize()
675  }
676 
677  return 0;
678 }
679 
680 ////////////////////////////////////////////////////////////////////////////////
681 /// Read basket buffers in memory and cleanup
682 ///
683 /// Read first bytes of a logical record starting at position pos
684 /// return record length (first 4 bytes of record).
685 
687 {
688  const Int_t len = 128;
689  char buffer[len];
690  Int_t keylen;
691  file->GetRecordHeader(buffer, pos,len, fNbytes, fObjlen, keylen);
692  fKeylen = keylen;
693  return fNbytes;
694 }
695 
696 ////////////////////////////////////////////////////////////////////////////////
697 /// Reset the basket to the starting state. i.e. as it was after calling
698 /// the constructor (and potentially attaching a TBuffer.)
699 /// Reduce memory used by fEntryOffset and the TBuffer if needed ..
700 
702 {
703  // Name, Title, fClassName, fBranch
704  // stay the same.
705 
706  // Downsize the buffer if needed.
707  Int_t curSize = fBufferRef->BufferSize();
708  // fBufferLen at this point is already reset, so use indirect measurements
709  Int_t curLen = (GetObjlen() + GetKeylen());
710  Long_t newSize = -1;
711  if (curSize > 2*curLen)
712  {
713  Long_t curBsize = fBranch->GetBasketSize();
714  if (curSize > 2*curBsize ) {
715  Long_t avgSize = (Long_t)(fBranch->GetTotBytes() / (1+fBranch->GetWriteBasket())); // Average number of bytes per basket so far
716  if (curSize > 2*avgSize) {
717  newSize = curBsize;
718  if (curLen > newSize) {
719  newSize = curLen;
720  }
721  if (avgSize > newSize) {
722  newSize = avgSize;
723  }
724  newSize = newSize + 512 - newSize%512; // Wiggle room and alignment (512 is same as in OptimizeBaskets)
725  }
726  }
727  }
728  /*
729  Philippe has asked us to keep this turned off until we finish memory fragmentation studies.
730  // If fBufferRef grew since we last saw it, shrink it to 105% of the occupied size
731  if (curSize > fLastWriteBufferSize) {
732  if (newSize == -1) {
733  newSize = Int_t(1.05*Float_t(fBufferRef->Length()));
734  }
735  fLastWriteBufferSize = newSize;
736  }
737  */
738  if (newSize != -1) {
739  fBufferRef->Expand(newSize,kFALSE); // Expand without copying the existing data.
740  }
741 
742  TKey::Reset();
743 
744  Int_t newNevBufSize = fBranch->GetEntryOffsetLen();
745  if (newNevBufSize==0) {
747  } else if ((newNevBufSize != fNevBufSize) || (fEntryOffset <= reinterpret_cast<Int_t *>(-1))) {
749  fEntryOffset = new Int_t[newNevBufSize];
750  }
751  fNevBufSize = newNevBufSize;
752 
753  fNevBuf = 0;
754  Int_t *storeEntryOffset = fEntryOffset;
755  fEntryOffset = 0;
756  Int_t *storeDisplacement = fDisplacement;
757  fDisplacement= 0;
758  fBuffer = 0;
759 
760  fBufferRef->Reset();
762 
763  fHeaderOnly = kTRUE;
764  fLast = 0; //Must initialize before calling Streamer()
765 
766  Streamer(*fBufferRef);
767 
770  fLast = fKeylen;
771  fBuffer = 0;
773  fDisplacement= storeDisplacement;
774  fEntryOffset = storeEntryOffset;
775  if (fNevBufSize) {
776  for (Int_t i=0;i<fNevBufSize;i++) fEntryOffset[i] = 0;
777  }
778 }
779 
780 ////////////////////////////////////////////////////////////////////////////////
781 /// Set read mode of basket.
782 
784 {
785  fLast = fBufferRef->Length();
787 }
788 
789 ////////////////////////////////////////////////////////////////////////////////
790 /// Set write mode of basket.
791 
793 {
796 }
797 
798 ////////////////////////////////////////////////////////////////////////////////
799 /// Stream a class object.
800 
801 void TBasket::Streamer(TBuffer &b)
802 {
803  // As in TBranch::GetBasket, this is used as a half-hearted measure to suppress
804  // the error reporting when many failures occur.
805  static std::atomic<Int_t> nerrors(0);
806 
807  char flag;
808  if (b.IsReading()) {
809  TKey::Streamer(b); //this must be first
810  Version_t v = b.ReadVersion();
811  b >> fBufferSize;
812  // NOTE: we now use the upper-bit of the fNevBufSize to see if we have serialized any of the
813  // optional IOBits. If that bit is set, we immediately read out the IOBits; to replace this
814  // (minimal) safeguard against corruption, we will set aside the upper-bit of fIOBits to do
815  // the same thing (the fact this bit is reserved is tested in the unit tests). If there is
816  // someday a need for more than 7 IOBits, we'll widen the field using the same trick.
817  //
818  // We like to keep this safeguard because we immediately will allocate a buffer based on
819  // the value of fNevBufSize -- and would like to avoid wildly inappropriate allocations.
820  b >> fNevBufSize;
821  if (fNevBufSize < 0) {
822  fNevBufSize = -fNevBufSize;
823  b >> fIOBits;
824  if (!fIOBits || (fIOBits & (1 << 7))) {
825  Error("TBasket::Streamer",
826  "The value of fNevBufSize (%d) or fIOBits (%d) is incorrect ; setting the buffer to a zombie.",
827  -fNevBufSize, fIOBits);
828  MakeZombie();
829  fNevBufSize = 0;
830  } else if (fIOBits && (fIOBits & ~static_cast<Int_t>(EIOBits::kSupported))) {
831  nerrors++;
832  if (nerrors < 10) {
833  Error("Streamer", "The value of fIOBits (%s) contains unknown flags (supported flags "
834  "are %s), indicating this was written with a newer version of ROOT "
835  "utilizing critical IO features this version of ROOT does not support."
836  " Refusing to deserialize.",
837  std::bitset<32>(static_cast<Int_t>(fIOBits)).to_string().c_str(),
838  std::bitset<32>(static_cast<Int_t>(EIOBits::kSupported)).to_string().c_str());
839  } else if (nerrors == 10) {
840  Error("Streamer", "Maximum number of errors has been reported; disabling further messages"
841  "from this location until the process exits.");
842  }
843  fNevBufSize = 0;
844  MakeZombie();
845  }
846  }
847  b >> fNevBuf;
848  b >> fLast;
849  b >> flag;
850  if (fLast > fBufferSize) fBufferSize = fLast;
851  Bool_t mustGenerateOffsets = false;
852  if (flag && (flag >= 80)) {
853  mustGenerateOffsets = true;
854  flag -= 80;
855  }
856  if (!mustGenerateOffsets && flag && (flag % 10 != 2)) {
859  if (fNevBuf) b.ReadArray(fEntryOffset);
860  if (20<flag && flag<40) {
861  for(int i=0; i<fNevBuf; i++){
863  }
864  }
865  if (flag>40) {
868  }
869  } else if (mustGenerateOffsets) {
870  // We currently believe that in all cases when offsets can be generated, then the
871  // displacement array must be zero.
872  assert(flag <= 40);
873  fEntryOffset = reinterpret_cast<Int_t *>(-1);
874  }
875  if (flag == 1 || flag > 10) {
876  fBufferRef = new TBufferFile(TBuffer::kRead,fBufferSize);
878  char *buf = fBufferRef->Buffer();
879  if (v > 1) b.ReadFastArray(buf,fLast);
880  else b.ReadArray(buf);
881  fBufferRef->SetBufferOffset(fLast);
882  // This is now done in the TBranch streamer since fBranch might not
883  // yet be set correctly.
884  // fBranch->GetTree()->IncrementTotalBuffers(fBufferSize);
885  }
886  } else {
887 
888  TKey::Streamer(b); //this must be first
889  b.WriteVersion(TBasket::IsA());
890  if (fBufferRef) {
891  Int_t curLast = fBufferRef->Length();
892  if (!fHeaderOnly && !fSeekKey && curLast > fLast) fLast = curLast;
893  }
895 
896  b << fBufferSize;
897  if (fIOBits) {
898  b << -fNevBufSize;
899  b << fIOBits;
900  } else {
901  b << fNevBufSize;
902  }
903  b << fNevBuf;
904  b << fLast;
905  Bool_t mustGenerateOffsets = fEntryOffset && fNevBuf &&
908  // We currently believe that in all cases when offsets can be generated, then the
909  // displacement array must be zero.
910  assert(!mustGenerateOffsets || fDisplacement == nullptr);
911  if (fHeaderOnly) {
912  flag = mustGenerateOffsets ? 80 : 0;
913  b << flag;
914  } else {
915  // On return from this function, we are guaranteed that fEntryOffset
916  // is either a valid pointer or nullptr.
917  if (fNevBuf) {
918  GetEntryOffset();
919  }
920  flag = 1;
921  if (!fNevBuf || !fEntryOffset)
922  flag = 2;
923  if (fBufferRef) flag += 10;
924  if (fDisplacement) flag += 40;
925  // Test if we can skip writing out the offset map.
926  if (mustGenerateOffsets) {
927  flag += 80;
928  }
929  b << flag;
930 
931  if (!mustGenerateOffsets && fEntryOffset && fNevBuf) {
932  b.WriteArray(fEntryOffset, fNevBuf);
933  if (fDisplacement) b.WriteArray(fDisplacement, fNevBuf);
934  }
935  if (fBufferRef) {
936  char *buf = fBufferRef->Buffer();
937  b.WriteFastArray(buf, fLast);
938  }
939  }
940  }
941 }
942 
943 ////////////////////////////////////////////////////////////////////////////////
944 /// Update basket header and EntryOffset table.
945 
946 void TBasket::Update(Int_t offset, Int_t skipped)
947 {
948  Int_t *entryOffset = GetEntryOffset();
949  if (entryOffset) {
950  if (fNevBuf+1 >= fNevBufSize) {
951  Int_t newsize = TMath::Max(10,2*fNevBufSize);
952  Int_t *newoff = TStorage::ReAllocInt(fEntryOffset, newsize,
953  fNevBufSize);
954  if (fDisplacement) {
955  Int_t *newdisp = TStorage::ReAllocInt(fDisplacement, newsize,
956  fNevBufSize);
957  fDisplacement = newdisp;
958  }
959  fEntryOffset = newoff;
960  fNevBufSize = newsize;
961 
962  //Update branch only for the first 10 baskets
963  if (fBranch->GetWriteBasket() < 10) {
964  fBranch->SetEntryOffsetLen(newsize);
965  }
966  }
967  fEntryOffset[fNevBuf] = offset;
968 
969  if (skipped!=offset && !fDisplacement){
971  for (Int_t i = 0; i<fNevBufSize; i++) fDisplacement[i] = fEntryOffset[i];
972  }
973  if (fDisplacement) {
974  fDisplacement[fNevBuf] = skipped;
976  }
977  }
978 
979  fNevBuf++;
980 }
981 
982 ////////////////////////////////////////////////////////////////////////////////
983 /// Write buffer of this basket on the current file.
984 ///
985 /// The function returns the number of bytes committed to the memory.
986 /// If a write error occurs, the number of bytes returned is -1.
987 /// If no data are written, the number of bytes returned is 0.
988 
990 {
991  const Int_t kWrite = 1;
992 
993  TFile *file = fBranch->GetFile(kWrite);
994  if (!file) return 0;
995  if (!file->IsWritable()) {
996  return -1;
997  }
998  fMotherDir = file; // fBranch->GetDirectory();
999 
1000  // This mutex prevents multiple TBasket::WriteBuffer invocations from interacting
1001  // with the underlying TFile at once - TFile is assumed to *not* be thread-safe.
1002  //
1003  // The only parallelism we'd like to exploit (right now!) is the compression
1004  // step - everything else should be serialized at the TFile level.
1005 #ifdef R__USE_IMT
1006  std::unique_lock<std::mutex> sentry(file->fWriteMutex);
1007 #endif // R__USE_IMT
1008 
1010  // Read the basket information that was saved inside the buffer.
1011  Bool_t writing = fBufferRef->IsWriting();
1014 
1015  Streamer(*fBufferRef);
1016  if (writing) fBufferRef->SetWriteMode();
1017  Int_t nout = fNbytes - fKeylen;
1018 
1019  fBuffer = fBufferRef->Buffer();
1020 
1021  Create(nout,file);
1023  fHeaderOnly = kTRUE;
1024 
1025  Streamer(*fBufferRef); //write key itself again
1026  int nBytes = WriteFileKeepBuffer();
1027  fHeaderOnly = kFALSE;
1028  return nBytes>0 ? fKeylen+nout : -1;
1029  }
1030 
1031  // Transfer fEntryOffset table at the end of fBuffer.
1032  fLast = fBufferRef->Length();
1033  Int_t *entryOffset = GetEntryOffset();
1034  if (entryOffset) {
1035  Bool_t hasOffsetBit = fIOBits & static_cast<UChar_t>(TBasket::EIOBits::kGenerateOffsetMap);
1036  if (!CanGenerateOffsetArray()) {
1037  // If we have set the offset map flag, but cannot dynamically generate the map, then
1038  // we should at least convert the offset array to a size array. Note that we always
1039  // write out (fNevBuf+1) entries to match the original case.
1040  if (hasOffsetBit) {
1041  for (Int_t idx = fNevBuf; idx > 0; idx--) {
1042  entryOffset[idx] -= entryOffset[idx - 1];
1043  }
1044  entryOffset[0] = 0;
1045  }
1046  fBufferRef->WriteArray(entryOffset, fNevBuf + 1);
1047  // Convert back to offset format: keeping both sizes and offsets in-memory were considered,
1048  // but it seems better to use CPU than memory.
1049  if (hasOffsetBit) {
1050  entryOffset[0] = fKeylen;
1051  for (Int_t idx = 1; idx < fNevBuf + 1; idx++) {
1052  entryOffset[idx] += entryOffset[idx - 1];
1053  }
1054  }
1055  } else if (!hasOffsetBit) { // In this case, write out as normal
1056  fBufferRef->WriteArray(entryOffset, fNevBuf + 1);
1057  }
1058  if (fDisplacement) {
1060  delete[] fDisplacement;
1061  fDisplacement = 0;
1062  }
1063  }
1064 
1065  Int_t lbuf, nout, noutot, bufmax, nzip;
1066  lbuf = fBufferRef->Length();
1067  fObjlen = lbuf - fKeylen;
1068 
1069  fHeaderOnly = kTRUE;
1071  Int_t cxlevel = fBranch->GetCompressionLevel();
1073  if (cxlevel > 0) {
1074  Int_t nbuffers = 1 + (fObjlen - 1) / kMAXZIPBUF;
1075  Int_t buflen = fKeylen + fObjlen + 9 * nbuffers + 28; //add 28 bytes in case object is placed in a deleted gap
1076  InitializeCompressedBuffer(buflen, file);
1077  if (!fCompressedBufferRef) {
1078  Warning("WriteBuffer", "Unable to allocate the compressed buffer");
1079  return -1;
1080  }
1083  char *objbuf = fBufferRef->Buffer() + fKeylen;
1084  char *bufcur = &fBuffer[fKeylen];
1085  noutot = 0;
1086  nzip = 0;
1087  for (Int_t i = 0; i < nbuffers; ++i) {
1088  if (i == nbuffers - 1) bufmax = fObjlen - nzip;
1089  else bufmax = kMAXZIPBUF;
1090  // Compress the buffer. Note that we allow multiple TBasket compressions to occur at once
1091  // for a given TFile: that's because the compression buffer when we use IMT is no longer
1092  // shared amongst several threads.
1093 #ifdef R__USE_IMT
1094  sentry.unlock();
1095 #endif // R__USE_IMT
1096  // NOTE this is declared with C linkage, so it shouldn't except. Also, when
1097  // USE_IMT is defined, we are guaranteed that the compression buffer is unique per-branch.
1098  // (see fCompressedBufferRef in constructor).
1099  R__zipMultipleAlgorithm(cxlevel, &bufmax, objbuf, &bufmax, bufcur, &nout, cxAlgorithm);
1100 #ifdef R__USE_IMT
1101  sentry.lock();
1102 #endif // R__USE_IMT
1103 
1104  // test if buffer has really been compressed. In case of small buffers
1105  // when the buffer contains random data, it may happen that the compressed
1106  // buffer is larger than the input. In this case, we write the original uncompressed buffer
1107  if (nout == 0 || nout >= fObjlen) {
1108  nout = fObjlen;
1109  // We used to delete fBuffer here, we no longer want to since
1110  // the buffer (held by fCompressedBufferRef) might be re-used later.
1111  fBuffer = fBufferRef->Buffer();
1112  Create(fObjlen,file);
1114 
1115  Streamer(*fBufferRef); //write key itself again
1116  if ((nout+fKeylen)>buflen) {
1117  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",
1118  (nout+fKeylen-buflen),buflen,fNbytes,fObjlen,fKeylen);
1119  }
1120  goto WriteFile;
1121  }
1122  bufcur += nout;
1123  noutot += nout;
1124  objbuf += kMAXZIPBUF;
1125  nzip += kMAXZIPBUF;
1126  }
1127  nout = noutot;
1128  Create(noutot,file);
1130 
1131  Streamer(*fBufferRef); //write key itself again
1132  memcpy(fBuffer,fBufferRef->Buffer(),fKeylen);
1133  } else {
1134  fBuffer = fBufferRef->Buffer();
1135  Create(fObjlen,file);
1137 
1138  Streamer(*fBufferRef); //write key itself again
1139  nout = fObjlen;
1140  }
1141 
1142 WriteFile:
1143  Int_t nBytes = WriteFileKeepBuffer();
1144  fHeaderOnly = kFALSE;
1145  return nBytes>0 ? fKeylen+nout : -1;
1146 }
1147 
Int_t fVersion
Key version identifier.
Definition: TKey.h:34
void ResetEntryOffset()
Definition: TBasket.cxx:431
Int_t * GetEntryOffset()
Definition: TBasket.h:112
Int_t ReadBasketBytes(Long64_t pos, TFile *file)
Read basket buffers in memory and cleanup.
Definition: TBasket.cxx:686
virtual const char * GetName() const
Returns name of object.
Definition: TNamed.h:47
void SetBufferOffset(Int_t offset=0)
Definition: TBuffer.h:90
A TLeaf describes individual elements of a TBranch See TBranch structure in TTree.
Definition: TLeaf.h:32
Bool_t fHeaderOnly
True when only the basket header must be read/written.
Definition: TBasket.h:61
Bool_t IsReading() const
Definition: TBuffer.h:83
Bool_t fReadEntryOffset
!Set to true if offset array was read from a file.
Definition: TBasket.h:64
Bool_t IsWriting() const
Definition: TBuffer.h:84
virtual void SetReadMode()
Set read mode of basket.
Definition: TBasket.cxx:783
void Update(Int_t newlast)
Definition: TBasket.h:133
The concrete implementation of TBuffer for writing/reading to/from a ROOT file or socket...
Definition: TBufferFile.h:47
Int_t ReadBasketBuffers(Long64_t pos, Int_t len, TFile *file)
Read basket buffers in memory and cleanup.
Definition: TBasket.cxx:454
long long Long64_t
Definition: RtypesCore.h:69
virtual Int_t GetBasketSize() const
Definition: TBranch.h:167
Int_t * fDisplacement
![fNevBuf] Displacement of entries in fBuffer(TKey)
Definition: TBasket.h:65
virtual void IncrementTotalBuffers(Int_t nbytes)
Definition: TTree.h:462
short Version_t
Definition: RtypesCore.h:61
virtual Int_t * GenerateOffsetArray(Int_t base, Int_t events)
Definition: TLeaf.h:70
Provides the interface for the PROOF internal performance measurement and event tracing.
Int_t GetCompressionLevel() const
Definition: TBranch.h:251
A cache when reading files over the network.
TObject * GetParent() const
Return pointer to parent of this buffer.
Definition: TBuffer.cxx:241
Int_t fBufferSize
fBuffer length in bytes
Definition: TBasket.h:57
virtual void SetOffset(Long64_t offset, ERelativeTo pos=kBeg)
Set position from where to start reading.
Definition: TFile.cxx:2129
Int_t * fEntryOffset
[fNevBuf] Offset of entries in fBuffer(TKey); generated at runtime.
Definition: TBasket.h:66
virtual void SetName(const char *name)
Set the name of the TNamed.
Definition: TNamed.cxx:140
A specialized TFileCacheRead object for a TTree.
Definition: TTreeCache.h:30
TBranch * fBranch
Pointer to the basket support branch.
Definition: TBasket.h:68
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:2150
A ROOT file is a suite of consecutive data records (TKey instances) with a well defined format...
Definition: TFile.h:46
virtual Bool_t ReadBuffer(char *buf, Int_t len)
Read a buffer from the file.
Definition: TFile.cxx:1647
Buffer base class used for serializing objects.
Definition: TBuffer.h:40
TDirectory * GetDirectory() const
Definition: TBranch.h:173
R__ALWAYS_INLINE Bool_t TestBit(UInt_t f) const
Definition: TObject.h:172
int Int_t
Definition: RtypesCore.h:41
bool Bool_t
Definition: RtypesCore.h:59
R__EXTERN TVirtualMutex * gROOTMutex
Definition: TROOT.h:57
void SetParent(TObject *parent)
Set parent owning this buffer.
Definition: TBuffer.cxx:249
Int_t GetCompressionAlgorithm() const
Definition: TBranch.h:245
virtual UInt_t WriteVersion(const TClass *cl, Bool_t useBcnt=kFALSE)=0
Int_t fNevBuf
Number of entries in basket.
Definition: TBasket.h:59
char * fBuffer
Object buffer.
Definition: TKey.h:44
Int_t GetEntryOffsetLen() const
Definition: TBranch.h:176
TDirectory * fMotherDir
!pointer to mother directory
Definition: TKey.h:47
TBuffer * GetBufferRef() const
Definition: TKey.h:75
void SetBit(UInt_t f, Bool_t set)
Set or unset the user status bits as specified in f.
Definition: TObject.cxx:694
Int_t Length() const
Definition: TBuffer.h:96
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:1787
static struct mg_connection * fc(struct mg_context *ctx)
Definition: civetweb.c:1956
virtual void WriteArray(const Bool_t *b, Int_t n)=0
virtual void Reset()=0
std::mutex fWriteMutex
!Lock for writing baskets / keys into the file.
Definition: TFile.h:110
virtual TVirtualPerfStats * GetPerfStats() const
Definition: TTree.h:425
char * Buffer() const
Definition: TBuffer.h:93
virtual void Reset()
Reset the basket to the starting state.
Definition: TBasket.cxx:701
virtual Int_t WriteBuffer()
Write buffer of this basket on the current file.
Definition: TBasket.cxx:989
virtual Int_t WriteFile(Int_t cycle=1, TFile *f=0)
Write the encoded object supported by this key.
Definition: TKey.cxx:1435
int R__unzip_header(Int_t *nin, UChar_t *bufin, Int_t *lout)
Short_t fKeylen
Number of bytes for the key itself.
Definition: TKey.h:38
TString fClassName
Object Class name.
Definition: TKey.h:42
Bool_t CanGenerateOffsetArray()
Determine whether we can generate the offset array when this branch is read.
Definition: TBasket.cxx:208
Book space in a file, create I/O buffers, to fill them, (un)compress them.
Definition: TKey.h:24
void InitializeCompressedBuffer(Int_t len, TFile *file)
Initialize the compressed buffer; either from the TTree or create a local one.
Definition: TBasket.cxx:422
virtual void Enable()
Definition: TTreeCache.h:75
R__ALWAYS_INLINE Bool_t IsZombie() const
Definition: TObject.h:134
virtual Int_t WriteFileKeepBuffer(TFile *f=0)
Write the encoded object supported by this key.
Definition: TKey.cxx:1476
void Expand(Int_t newsize, Bool_t copy=kTRUE)
Expand (or shrink) the I/O buffer to newsize bytes.
Definition: TBuffer.cxx:211
ECompressionAlgorithm
The global settings depend on a global variable named R__ZipMode which can be modified by a global fu...
Definition: Compression.h:34
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:1251
UChar_t fIOBits
!IO feature flags. Serialized in custom portion of streamer to avoid forward compat issues unless nee...
Definition: TBasket.h:62
Bool_t fOwnsCompressedBuffer
! Whether or not we own the compressed buffer.
Definition: TBasket.h:63
Int_t GetObjlen() const
Definition: TKey.h:83
virtual void AddNoCacheReadCalls(Int_t reads)
SVector< double, 2 > v
Definition: Dict.h:5
virtual void AdjustSize(Int_t newsize)
Increase the size of the current fBuffer up to newsize.
Definition: TBasket.cxx:121
Int_t ReadBasketBuffersUncompressedCase()
By-passing buffer unzipping has been requested and is possible (only 1 entry in this basket)...
Definition: TBasket.cxx:348
Int_t GetWriteBasket() const
Definition: TBranch.h:186
virtual Bool_t CanGenerateOffsetArray()
Definition: TLeaf.h:67
Int_t GetEntryPointer(Int_t Entry)
Get pointer to buffer for internal entry.
Definition: TBasket.cxx:220
#define OLD_CASE_EXPRESSION
Definition: TBasket.cxx:343
unsigned int UInt_t
Definition: RtypesCore.h:42
virtual void Error(const char *method, const char *msgfmt,...) const
Issue error message.
Definition: TObject.cxx:880
Manages buffers for branches of a Tree.
Definition: TBasket.h:34
TBuffer * fCompressedBufferRef
! Compressed buffer.
Definition: TBasket.h:69
void SetReadMode()
Set buffer in read mode.
Definition: TBuffer.cxx:281
virtual void Reset()
Reset the key as it had not been &#39;filled&#39; yet.
Definition: TKey.cxx:1290
TBuffer * GetTransientBuffer(Int_t size)
Returns the transient buffer currently used by this TBranch for reading/writing baskets.
Definition: TBranch.cxx:493
virtual void ReadFastArray(Bool_t *b, Int_t n)=0
virtual void WriteFastArray(const Bool_t *b, Int_t n)=0
TBuffer * fBufferRef
Pointer to the TBuffer object.
Definition: TKey.h:45
#define gPerfStats
Int_t fNevBufSize
Length in Int_t of fEntryOffset OR fixed length of each entry if fEntryOffset is null! ...
Definition: TBasket.h:58
const Bool_t kFALSE
Definition: RtypesCore.h:88
Long64_t fSeekKey
Location of object on file.
Definition: TKey.h:40
long Long_t
Definition: RtypesCore.h:50
Short_t fCycle
Cycle number.
Definition: TKey.h:39
#define ClassImp(name)
Definition: Rtypes.h:359
double Double_t
Definition: RtypesCore.h:55
Describe directory structure in memory.
Definition: TDirectory.h:34
#define R__likely(expr)
Definition: RConfig.h:555
#define free
Definition: civetweb.c:821
The TTimeStamp encapsulates seconds and ns since EPOCH.
Definition: TTimeStamp.h:71
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:400
TObjArray * GetListOfLeaves()
Definition: TBranch.h:195
Int_t BufferSize() const
Definition: TBuffer.h:94
virtual ~TBasket()
Basket destructor.
Definition: TBasket.cxx:103
void R__unzip(Int_t *nin, UChar_t *bufin, Int_t *lout, char *bufout, Int_t *nout)
Int_t GetKeylen() const
Definition: TKey.h:80
Int_t fObjlen
Length of uncompressed object in bytes.
Definition: TKey.h:36
virtual void Create(Int_t nbytes, TFile *f=0)
Create a TKey object of specified size.
Definition: TKey.cxx:458
virtual Int_t GetUnzipBuffer(char **, Long64_t, Int_t, Bool_t *)
virtual void SetEntryOffsetLen(Int_t len, Bool_t updateSubBranches=kFALSE)
Update the default value for the branch&#39;s fEntryOffsetLen if and only if it was already non zero (and...
Definition: TBranch.cxx:2379
virtual void DeleteEntryOffset()
Delete fEntryOffset array.
Definition: TBasket.cxx:154
TBuffer * GetTransientBuffer(Int_t size)
Returns the transient buffer currently used by this TTree for reading/writing baskets.
Definition: TTree.cxx:964
virtual Int_t DropBuffers()
Drop buffers of this basket if it is not the current basket.
Definition: TBasket.cxx:163
#define R__unlikely(expr)
Definition: RConfig.h:554
Definition: file.py:1
Short_t Max(Short_t a, Short_t b)
Definition: TMathBase.h:200
void MakeZombie()
Definition: TObject.h:49
you should not use this method at all Int_t Int_t Double_t Double_t Double_t Int_t Double_t Double_t Double_t Double_t b
Definition: TRolke.cxx:630
Int_t fLast
Pointer to last used byte in basket.
Definition: TBasket.h:60
TTree * GetTree() const
Definition: TBranch.h:200
Int_t * GetCalculatedEntryOffset()
Calculates the entry offset array, if possible.
Definition: TBasket.cxx:185
virtual Int_t ReadBuffer(char *buf, Long64_t pos, Int_t len)
Read buffer at position pos.
Definition: tree.py:1
TFileCacheRead * GetCacheRead(TObject *tree=0) const
Return a pointer to the current read cache.
Definition: TFile.cxx:1214
Int_t fNbytes
Number of bytes for the object on file.
Definition: TKey.h:35
A TTree object has a header with a name and a title.
Definition: TTree.h:70
Long64_t CopyTo(TFile *to)
Copy the basket of this branch onto the file to.
Definition: TBasket.cxx:136
unsigned char UChar_t
Definition: RtypesCore.h:34
#define R__LOCKGUARD_IMT2(mutex)
const UInt_t kDisplacementMask
Definition: TBasket.cxx:30
Bool_t IsWritable() const
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:1492
virtual void SetBufferDisplacement()=0
Int_t ReadBasketBuffersUnzip(char *, Int_t, Bool_t, TFile *)
We always create the TBuffer for the basket but it hold the buffer from the cache.
Definition: TBasket.cxx:370
A TTree is a list of TBranches.
Definition: TBranch.h:59
virtual void SetTitle(const char *title="")
Set the title of the TNamed.
Definition: TNamed.cxx:164
const Bool_t kTRUE
Definition: RtypesCore.h:87
TBasket()
Default contructor.
Definition: TBasket.cxx:46
virtual void SetWriteMode()
Set write mode of basket.
Definition: TBasket.cxx:792
char name[80]
Definition: TGX11.cxx:109
virtual void Warning(const char *method, const char *msgfmt,...) const
Issue warning message.
Definition: TObject.cxx:866
static Int_t * ReAllocInt(Int_t *vp, size_t size, size_t oldsize)
Reallocate (i.e.
Definition: TStorage.cxx:295
void SetWriteMode()
Set buffer in write mode.
Definition: TBuffer.cxx:294
virtual Version_t ReadVersion(UInt_t *start=0, UInt_t *bcnt=0, const TClass *cl=0)=0
virtual void Disable()
Definition: TTreeCache.h:74
void SetBuffer(void *buf, UInt_t bufsiz=0, Bool_t adopt=kTRUE, ReAllocCharFun_t reallocfunc=0)
Sets a new buffer in an existing TBuffer object.
Definition: TBuffer.cxx:175
virtual Int_t ReadArray(Bool_t *&b)=0
virtual void AddNoCacheBytesRead(Long64_t len)
Int_t LoadBasketBuffers(Long64_t pos, Int_t len, TFile *file, TTree *tree=0)
Load basket buffers in memory without unziping.
Definition: TBasket.cxx:235
Int_t GetNleaves() const
Definition: TBranch.h:197
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:300