Logo ROOT   6.08/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 "TBufferFile.h"
18 #include "TMath.h"
19 #include "TROOT.h"
20 #include "TTreeCache.h"
21 #include "TVirtualMutex.h"
22 #include "TVirtualPerfStats.h"
23 #include "TTimeStamp.h"
24 #include "RZip.h"
25 
26 const UInt_t kDisplacementMask = 0xFF000000; // In the streamer the two highest bytes of
27  // the fEntryOffset are used to stored displacement.
28 
30 
31 /** \class TBasket
32 \ingroup tree
33 
34 Manages buffers for branches of a Tree.
35 
36 See picture in TTree.
37 */
38 
39 ////////////////////////////////////////////////////////////////////////////////
40 /// Default contructor.
41 
42 TBasket::TBasket() : fCompressedBufferRef(0), fOwnsCompressedBuffer(kFALSE), fLastWriteBufferSize(0)
43 {
44  fDisplacement = 0;
45  fEntryOffset = 0;
46  fBufferRef = 0;
47  fBuffer = 0;
48  fHeaderOnly = kFALSE;
49  fBufferSize = 0;
50  fNevBufSize = 0;
51  fNevBuf = 0;
52  fLast = 0;
53  fBranch = 0;
54 }
55 
56 ////////////////////////////////////////////////////////////////////////////////
57 /// Constructor used during reading.
58 
59 TBasket::TBasket(TDirectory *motherDir) : TKey(motherDir),fCompressedBufferRef(0), fOwnsCompressedBuffer(kFALSE), fLastWriteBufferSize(0)
60 {
61  fDisplacement = 0;
62  fEntryOffset = 0;
63  fBufferRef = 0;
64  fBuffer = 0;
66  fBufferSize = 0;
67  fNevBufSize = 0;
68  fNevBuf = 0;
69  fLast = 0;
70  fBranch = 0;
71 }
72 
73 ////////////////////////////////////////////////////////////////////////////////
74 /// Basket normal constructor, used during writing.
75 
76 TBasket::TBasket(const char *name, const char *title, TBranch *branch) :
78 {
79  SetName(name);
80  SetTitle(title);
81  fClassName = "TBasket";
82  fBufferSize = branch->GetBasketSize();
83  fNevBufSize = branch->GetEntryOffsetLen();
84  fNevBuf = 0;
85  fEntryOffset = 0;
86  fDisplacement= 0;
87  fBuffer = 0;
89  fVersion += 1000;
90  if (branch->GetDirectory()) {
91  TFile *file = branch->GetFile();
92  fBufferRef->SetParent(file);
93  }
95  fLast = 0; // Must initialize before calling Streamer()
96  if (branch->GetTree()) {
97 #ifdef R__USE_IMT
99 #else
101 #endif
103  if (!fCompressedBufferRef) {
106  }
107  }
108  Streamer(*fBufferRef);
111  fLast = fKeylen;
112  fBuffer = 0;
113  fBranch = branch;
115  if (fNevBufSize) {
117  for (Int_t i=0;i<fNevBufSize;i++) fEntryOffset[i] = 0;
118  }
120 }
121 
122 ////////////////////////////////////////////////////////////////////////////////
123 /// Basket destructor.
124 
126 {
127  if (fDisplacement) delete [] fDisplacement;
128  if (fEntryOffset) delete [] fEntryOffset;
129  if (fBufferRef) delete fBufferRef;
130  fBufferRef = 0;
131  fBuffer = 0;
132  fDisplacement= 0;
133  fEntryOffset = 0;
134  // Note we only delete the compressed buffer if we own it
136  delete fCompressedBufferRef;
138  }
139 }
140 
141 ////////////////////////////////////////////////////////////////////////////////
142 /// Increase the size of the current fBuffer up to newsize.
143 
145 {
146  if (fBuffer == fBufferRef->Buffer()) {
147  fBufferRef->Expand(newsize);
149  } else {
150  fBufferRef->Expand(newsize);
151  }
153  fBufferSize = newsize;
154 }
155 
156 ////////////////////////////////////////////////////////////////////////////////
157 /// Copy the basket of this branch onto the file to.
158 
160 {
162  Int_t nout = fNbytes - fKeylen;
164  Create(nout, to);
166  fHeaderOnly = kTRUE;
167  Streamer(*fBufferRef);
169  Int_t nBytes = WriteFileKeepBuffer(to);
170 
171  return nBytes>0 ? nBytes : -1;
172 }
173 
174 ////////////////////////////////////////////////////////////////////////////////
175 /// Delete fEntryOffset array.
176 
178 {
179  if (fEntryOffset) delete [] fEntryOffset;
180  fEntryOffset = 0;
181  fNevBufSize = 0;
182 }
183 
184 ////////////////////////////////////////////////////////////////////////////////
185 /// Drop buffers of this basket if it is not the current basket.
186 
188 {
189  if (!fBuffer && !fBufferRef) return 0;
190 
191  if (fDisplacement) delete [] fDisplacement;
192  if (fEntryOffset) delete [] fEntryOffset;
193  if (fBufferRef) delete fBufferRef;
195  fBufferRef = 0;
197  fBuffer = 0;
198  fDisplacement= 0;
199  fEntryOffset = 0;
201  return fBufferSize;
202 }
203 
204 ////////////////////////////////////////////////////////////////////////////////
205 /// Get pointer to buffer for internal entry.
206 
208 {
209  Int_t offset;
210  if (fEntryOffset) offset = fEntryOffset[entry];
211  else offset = fKeylen + entry*fNevBufSize;
212  fBufferRef->SetBufferOffset(offset);
213  return offset;
214 }
215 
216 ////////////////////////////////////////////////////////////////////////////////
217 /// Load basket buffers in memory without unziping.
218 /// This function is called by TTreeCloner.
219 /// The function returns 0 in case of success, 1 in case of error.
220 
222 {
223  if (fBufferRef) {
224  // Reuse the buffer if it exist.
225  fBufferRef->Reset();
226 
227  // We use this buffer both for reading and writing, we need to
228  // make sure it is properly sized for writing.
230  if (fBufferRef->BufferSize() < len) {
231  fBufferRef->Expand(len);
232  }
234  } else {
236  }
237  fBufferRef->SetParent(file);
238  char *buffer = fBufferRef->Buffer();
239  file->Seek(pos);
240  TFileCacheRead *pf = file->GetCacheRead(tree);
241  if (pf) {
243  if (tree->GetPerfStats()) gPerfStats = tree->GetPerfStats();
244  Int_t st = pf->ReadBuffer(buffer,pos,len);
245  if (st < 0) {
246  return 1;
247  } else if (st == 0) {
248  // fOffset might have been changed via TFileCacheRead::ReadBuffer(), reset it
249  file->Seek(pos);
250  // If we are using a TTreeCache, disable reading from the default cache
251  // temporarily, to force reading directly from file
252  TTreeCache *fc = dynamic_cast<TTreeCache*>(file->GetCacheRead());
253  if (fc) fc->Disable();
254  Int_t ret = file->ReadBuffer(buffer,len);
255  if (fc) fc->Enable();
256  pf->AddNoCacheBytesRead(len);
257  pf->AddNoCacheReadCalls(1);
258  if (ret) {
259  return 1;
260  }
261  }
262  gPerfStats = temp;
263  // fOffset might have been changed via TFileCacheRead::ReadBuffer(), reset it
264  file->SetOffset(pos + len);
265  } else {
267  if (tree->GetPerfStats() != 0) gPerfStats = tree->GetPerfStats();
268  if (file->ReadBuffer(buffer,len)) {
269  gPerfStats = temp;
270  return 1; //error while reading
271  }
272  else gPerfStats = temp;
273  }
274 
277  Streamer(*fBufferRef);
278 
279  return 0;
280 }
281 
282 ////////////////////////////////////////////////////////////////////////////////
283 /// Remove the first dentries of this basket, moving entries at
284 /// dentries to the start of the buffer.
285 
287 {
288  Int_t i;
289 
290  if (dentries >= fNevBuf) return;
291  Int_t bufbegin;
292  Int_t moved;
293 
294  if (fEntryOffset) {
295  bufbegin = fEntryOffset[dentries];
296  moved = bufbegin-GetKeylen();
297 
298  // First store the original location in the fDisplacement array
299  // and record the new start offset
300 
301  if (!fDisplacement) {
303  }
304  for (i = 0; i<(fNevBufSize-dentries); ++i) {
305  fDisplacement[i] = fEntryOffset[i+dentries];
306  fEntryOffset[i] = fEntryOffset[i+dentries] - moved;
307  }
308  for (i = fNevBufSize-dentries; i<fNevBufSize; ++i) {
309  fDisplacement[i] = 0;
310  fEntryOffset[i] = 0;
311  }
312 
313  } else {
314  // If there is no EntryOffset array, this means
315  // that each entry has the same size and that
316  // it does not point to other objects (hence there
317  // is no need for a displacement array).
318  bufbegin = GetKeylen() + dentries*fNevBufSize;
319  moved = bufbegin-GetKeylen();
320  }
321  TBuffer *buf = GetBufferRef();
322  char *buffer = buf->Buffer();
323  memmove(buffer+GetKeylen(),buffer+bufbegin,buf->Length()-bufbegin);
324  buf->SetBufferOffset(buf->Length()-moved);
325  fNevBuf -= dentries;
326 }
327 
328 #define OLD_CASE_EXPRESSION fObjlen==fNbytes-fKeylen && GetBranch()->GetCompressionLevel()!=0 && file->GetVersion()<=30401
329 ////////////////////////////////////////////////////////////////////////////////
330 /// By-passing buffer unzipping has been requested and is
331 /// possible (only 1 entry in this basket).
332 
334 {
336 
337  // Make sure that the buffer is set at the END of the data
339 
340  // Indicate that this buffer is weird.
342 
343  // Usage of this mode assume the existance of only ONE
344  // entry in this basket.
345  delete [] fEntryOffset; fEntryOffset = 0;
346  delete [] fDisplacement; fDisplacement = 0;
347 
349  return 0;
350 }
351 
352 ////////////////////////////////////////////////////////////////////////////////
353 /// We always create the TBuffer for the basket but it hold the buffer from the cache.
354 
356 {
357  if (fBufferRef) {
358  fBufferRef->SetBuffer(buffer, size, mustFree);
360  fBufferRef->Reset();
361  } else {
362  fBufferRef = new TBufferFile(TBuffer::kRead, size, buffer, mustFree);
363  }
364  fBufferRef->SetParent(file);
365 
366  Streamer(*fBufferRef);
367 
368  if (IsZombie()) {
369  return -1;
370  }
371 
372  Bool_t oldCase = OLD_CASE_EXPRESSION;
373 
374  if ((fObjlen > fNbytes-fKeylen || oldCase) && TestBit(TBufferFile::kNotDecompressed) && (fNevBuf==1)) {
376  }
377 
379  return fObjlen+fKeylen;
380 }
381 
382 ////////////////////////////////////////////////////////////////////////////////
383 /// Initialize a buffer for reading if it is not already initialized
384 
385 static inline TBuffer* R__InitializeReadBasketBuffer(TBuffer* bufferRef, Int_t len, TFile* file)
386 {
387  TBuffer* result;
388  if (R__likely(bufferRef)) {
389  bufferRef->SetReadMode();
390  Int_t curBufferSize = bufferRef->BufferSize();
391  if (curBufferSize < len) {
392  // Experience shows that giving 5% "wiggle-room" decreases churn.
393  bufferRef->Expand(Int_t(len*1.05));
394  }
395  bufferRef->Reset();
396  result = bufferRef;
397  } else {
398  result = new TBufferFile(TBuffer::kRead, len);
399  }
400  result->SetParent(file);
401  return result;
402 }
403 
404 ////////////////////////////////////////////////////////////////////////////////
405 /// Initialize the compressed buffer; either from the TTree or create a local one.
406 
408 {
409  Bool_t compressedBufferExists = fCompressedBufferRef != NULL;
411  if (R__unlikely(!compressedBufferExists)) {
413  }
414 }
415 
416 ////////////////////////////////////////////////////////////////////////////////
417 /// Read basket buffers in memory and cleanup.
418 ///
419 /// Read a basket buffer. Check if buffers of previous ReadBasket
420 /// should not be dropped. Remember, we keep buffers in memory up to
421 /// fMaxVirtualSize.
422 /// The function returns 0 in case of success, 1 in case of error
423 /// This function was modified with the addition of the parallel
424 /// unzipping, it will try to get the unzipped file from the cache
425 /// receiving only a pointer to that buffer (so we shall not
426 /// delete that pointer), although we get a new buffer in case
427 /// it's not found in the cache.
428 /// There is a lot of code duplication but it was necesary to assure
429 /// the expected behavior when there is no cache.
430 
432 {
433  if(!fBranch->GetDirectory()) {
434  return -1;
435  }
436 
437  Bool_t oldCase;
438  char *rawUncompressedBuffer, *rawCompressedBuffer;
439  Int_t uncompressedBufferLen;
440 
441  // See if the cache has already unzipped the buffer for us.
442  TFileCacheRead *pf = nullptr;
443  {
444  R__LOCKGUARD_IMT2(gROOTMutex); // Lock for parallel TTree I/O
445  pf = file->GetCacheRead(fBranch->GetTree());
446  }
447  if (pf) {
448  Int_t res = -1;
449  Bool_t free = kTRUE;
450  char *buffer;
451  res = pf->GetUnzipBuffer(&buffer, pos, len, &free);
452  if (R__unlikely(res >= 0)) {
453  len = ReadBasketBuffersUnzip(buffer, res, free, file);
454  // Note that in the kNotDecompressed case, the above function will return 0;
455  // In such a case, we should stop processing
456  if (len <= 0) return -len;
457  goto AfterBuffer;
458  }
459  }
460 
461  // Determine which buffer to use, so that we can avoid a memcpy in case of
462  // the basket was not compressed.
463  TBuffer* readBufferRef;
465  readBufferRef = fBufferRef;
466  } else {
467  readBufferRef = fCompressedBufferRef;
468  }
469 
470  // fBufferSize is likely to be change in the Streamer call (below)
471  // and we will re-add the new size later on.
473 
474  // Initialize the buffer to hold the compressed data.
475  readBufferRef = R__InitializeReadBasketBuffer(readBufferRef, len, file);
476  if (!readBufferRef) {
477  Error("ReadBasketBuffers", "Unable to allocate buffer.");
478  return 1;
479  }
480 
481  if (pf) {
484  Int_t st = 0;
485  {
486  R__LOCKGUARD_IMT2(gROOTMutex); // Lock for parallel TTree I/O
487  st = pf->ReadBuffer(readBufferRef->Buffer(),pos,len);
488  }
489  if (st < 0) {
490  return 1;
491  } else if (st == 0) {
492  // Read directly from file, not from the cache
493  // If we are using a TTreeCache, disable reading from the default cache
494  // temporarily, to force reading directly from file
495  R__LOCKGUARD_IMT2(gROOTMutex); // Lock for parallel TTree I/O
496  TTreeCache *fc = dynamic_cast<TTreeCache*>(file->GetCacheRead());
497  if (fc) fc->Disable();
498  Int_t ret = file->ReadBuffer(readBufferRef->Buffer(),pos,len);
499  if (fc) fc->Enable();
500  pf->AddNoCacheBytesRead(len);
501  pf->AddNoCacheReadCalls(1);
502  if (ret) {
503  return 1;
504  }
505  }
506  gPerfStats = temp;
507  } else {
508  // Read from the file and unstream the header information.
511  R__LOCKGUARD_IMT2(gROOTMutex); // Lock for parallel TTree I/O
512  if (file->ReadBuffer(readBufferRef->Buffer(),pos,len)) {
513  gPerfStats = temp;
514  return 1;
515  }
516  else gPerfStats = temp;
517  }
518  Streamer(*readBufferRef);
519  if (IsZombie()) {
520  return 1;
521  }
522 
523  rawCompressedBuffer = readBufferRef->Buffer();
524 
525  // Are we done?
526  if (R__unlikely(readBufferRef == fBufferRef)) // We expect most basket to be compressed.
527  {
528  if (R__likely(fObjlen+fKeylen == fNbytes)) {
529  // The basket was really not compressed as expected.
530  goto AfterBuffer;
531  } else {
532  // Well, somehow the buffer was compressed anyway, we have the compressed data in the uncompressed buffer
533  // Make sure the compressed buffer is initialized, and memcpy.
534  InitializeCompressedBuffer(len, file);
535  if (!fCompressedBufferRef) {
536  Error("ReadBasketBuffers", "Unable to allocate buffer.");
537  return 1;
538  }
539  fBufferRef->Reset();
540  rawCompressedBuffer = fCompressedBufferRef->Buffer();
541  memcpy(rawCompressedBuffer, fBufferRef->Buffer(), len);
542  }
543  }
544 
545  // Initialize buffer to hold the uncompressed data
546  // Note that in previous versions we didn't allocate buffers until we verified
547  // the zip headers; this is no longer beforehand as the buffer lifetime is scoped
548  // to the TBranch.
549  uncompressedBufferLen = len > fObjlen+fKeylen ? len : fObjlen+fKeylen;
550  fBufferRef = R__InitializeReadBasketBuffer(fBufferRef, uncompressedBufferLen, file);
551  rawUncompressedBuffer = fBufferRef->Buffer();
552  fBuffer = rawUncompressedBuffer;
553 
554  oldCase = OLD_CASE_EXPRESSION;
555  // Case where ROOT thinks the buffer is compressed. Copy over the key and uncompress the object
556  if (fObjlen > fNbytes-fKeylen || oldCase) {
559  }
560 
561  // Optional monitor for zip time profiling.
562  Double_t start = 0;
563  if (R__unlikely(gPerfStats)) {
564  start = TTimeStamp();
565  }
566 
567  memcpy(rawUncompressedBuffer, rawCompressedBuffer, fKeylen);
568  char *rawUncompressedObjectBuffer = rawUncompressedBuffer+fKeylen;
569  UChar_t *rawCompressedObjectBuffer = (UChar_t*)rawCompressedBuffer+fKeylen;
570  Int_t nin, nbuf;
571  Int_t nout = 0, noutot = 0, nintot = 0;
572 
573  // Unzip all the compressed objects in the compressed object buffer.
574  while (1) {
575  // Check the header for errors.
576  if (R__unlikely(R__unzip_header(&nin, rawCompressedObjectBuffer, &nbuf) != 0)) {
577  Error("ReadBasketBuffers", "Inconsistency found in header (nin=%d, nbuf=%d)", nin, nbuf);
578  break;
579  }
580  if (R__unlikely(oldCase && (nin > fObjlen || nbuf > fObjlen))) {
581  //buffer was very likely not compressed in an old version
582  memcpy(rawUncompressedBuffer+fKeylen, rawCompressedObjectBuffer+fKeylen, fObjlen);
583  goto AfterBuffer;
584  }
585 
586  R__unzip(&nin, rawCompressedObjectBuffer, &nbuf, (unsigned char*) rawUncompressedObjectBuffer, &nout);
587  if (!nout) break;
588  noutot += nout;
589  nintot += nin;
590  if (noutot >= fObjlen) break;
591  rawCompressedObjectBuffer += nin;
592  rawUncompressedObjectBuffer += nout;
593  }
594 
595  // Make sure the uncompressed numbers are consistent with header.
596  if (R__unlikely(noutot != fObjlen)) {
597  Error("ReadBasketBuffers", "fNbytes = %d, fKeylen = %d, fObjlen = %d, noutot = %d, nout=%d, nin=%d, nbuf=%d", fNbytes,fKeylen,fObjlen, noutot,nout,nin,nbuf);
599  return 1;
600  }
601  len = fObjlen+fKeylen;
604  if (R__unlikely(gPerfStats)) {
605  gPerfStats->UnzipEvent(fBranch->GetTree(),pos,start,nintot,fObjlen);
606  }
607  gPerfStats = temp;
608  } else {
609  // Nothing is compressed - copy over wholesale.
610  memcpy(rawUncompressedBuffer, rawCompressedBuffer, len);
611  }
612 
613 AfterBuffer:
614 
616 
617  // Read offsets table if needed.
618  if (!fBranch->GetEntryOffsetLen()) {
619  return 0;
620  }
621  delete [] fEntryOffset;
622  fEntryOffset = 0;
625  if (!fEntryOffset) {
626  fEntryOffset = new Int_t[fNevBuf+1];
627  fEntryOffset[0] = fKeylen;
628  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);
629  return 0;
630  }
631  // Read the array of diplacement if any.
632  delete [] fDisplacement;
633  fDisplacement = 0;
634  if (fBufferRef->Length() != len) {
635  // There is more data in the buffer! It is the displacement
636  // array. If len is less than TBuffer::kMinimalSize the actual
637  // size of the buffer is too large, so we can not use the
638  // fBufferRef->BufferSize()
640  }
641 
642  return 0;
643 }
644 
645 ////////////////////////////////////////////////////////////////////////////////
646 /// Read basket buffers in memory and cleanup
647 ///
648 /// Read first bytes of a logical record starting at position pos
649 /// return record length (first 4 bytes of record).
650 
652 {
653  const Int_t len = 128;
654  char buffer[len];
655  Int_t keylen;
656  file->GetRecordHeader(buffer, pos,len, fNbytes, fObjlen, keylen);
657  fKeylen = keylen;
658  return fNbytes;
659 }
660 
661 ////////////////////////////////////////////////////////////////////////////////
662 /// Reset the basket to the starting state. i.e. as it was after calling
663 /// the constructor (and potentially attaching a TBuffer.)
664 /// Reduce memory used by fEntryOffset and the TBuffer if needed ..
665 
667 {
668  // Name, Title, fClassName, fBranch
669  // stay the same.
670 
671  // Downsize the buffer if needed.
672  Int_t curSize = fBufferRef->BufferSize();
673  // fBufferLen at this point is already reset, so use indirect measurements
674  Int_t curLen = (GetObjlen() + GetKeylen());
675  Long_t newSize = -1;
676  if (curSize > 2*curLen)
677  {
678  Long_t curBsize = fBranch->GetBasketSize();
679  if (curSize > 2*curBsize ) {
680  Long_t avgSize = (Long_t)(fBranch->GetTotBytes() / (1+fBranch->GetWriteBasket())); // Average number of bytes per basket so far
681  if (curSize > 2*avgSize) {
682  newSize = curBsize;
683  if (curLen > newSize) {
684  newSize = curLen;
685  }
686  if (avgSize > newSize) {
687  newSize = avgSize;
688  }
689  newSize = newSize + 512 - newSize%512; // Wiggle room and alignment (512 is same as in OptimizeBaskets)
690  }
691  }
692  }
693  /*
694  Philippe has asked us to keep this turned off until we finish memory fragmentation studies.
695  // If fBufferRef grew since we last saw it, shrink it to 105% of the occupied size
696  if (curSize > fLastWriteBufferSize) {
697  if (newSize == -1) {
698  newSize = Int_t(1.05*Float_t(fBufferRef->Length()));
699  }
700  fLastWriteBufferSize = newSize;
701  }
702  */
703  if (newSize != -1) {
704  fBufferRef->Expand(newSize,kFALSE); // Expand without copying the existing data.
705  }
706 
707  TKey::Reset();
708 
709  Int_t newNevBufSize = fBranch->GetEntryOffsetLen();
710  if (newNevBufSize==0) {
711  delete [] fEntryOffset;
712  fEntryOffset = 0;
713  } else if (newNevBufSize != fNevBufSize) {
714  delete [] fEntryOffset;
715  fEntryOffset = new Int_t[newNevBufSize];
716  } else if (!fEntryOffset) {
717  fEntryOffset = new Int_t[newNevBufSize];
718  }
719  fNevBufSize = newNevBufSize;
720 
721  fNevBuf = 0;
722  Int_t *storeEntryOffset = fEntryOffset;
723  fEntryOffset = 0;
724  Int_t *storeDisplacement = fDisplacement;
725  fDisplacement= 0;
726  fBuffer = 0;
727 
728  fBufferRef->Reset();
730 
731  fHeaderOnly = kTRUE;
732  fLast = 0; //Must initialize before calling Streamer()
733 
734  Streamer(*fBufferRef);
735 
738  fLast = fKeylen;
739  fBuffer = 0;
741  fDisplacement= storeDisplacement;
742  fEntryOffset = storeEntryOffset;
743  if (fNevBufSize) {
744  for (Int_t i=0;i<fNevBufSize;i++) fEntryOffset[i] = 0;
745  }
746 }
747 
748 ////////////////////////////////////////////////////////////////////////////////
749 /// Set read mode of basket.
750 
752 {
753  fLast = fBufferRef->Length();
755 }
756 
757 ////////////////////////////////////////////////////////////////////////////////
758 /// Set write mode of basket.
759 
761 {
764 }
765 
766 ////////////////////////////////////////////////////////////////////////////////
767 /// Stream a class object.
768 
769 void TBasket::Streamer(TBuffer &b)
770 {
771  char flag;
772  if (b.IsReading()) {
773  TKey::Streamer(b); //this must be first
774  Version_t v = b.ReadVersion();
775  b >> fBufferSize;
776  b >> fNevBufSize;
777  if (fNevBufSize < 0) {
778  Error("Streamer","The value of fNevBufSize is incorrect (%d) ; trying to recover by setting it to zero",fNevBufSize);
779  MakeZombie();
780  fNevBufSize = 0;
781  }
782  b >> fNevBuf;
783  b >> fLast;
784  b >> flag;
785  if (fLast > fBufferSize) fBufferSize = fLast;
786  if (!flag) {
787  return;
788  }
789  if (flag%10 != 2) {
790  delete [] fEntryOffset;
792  if (fNevBuf) b.ReadArray(fEntryOffset);
793  if (20<flag && flag<40) {
794  for(int i=0; i<fNevBuf; i++){
796  }
797  }
798  if (flag>40) {
801  }
802  }
803  if (flag == 1 || flag > 10) {
804  fBufferRef = new TBufferFile(TBuffer::kRead,fBufferSize);
806  char *buf = fBufferRef->Buffer();
807  if (v > 1) b.ReadFastArray(buf,fLast);
808  else b.ReadArray(buf);
809  fBufferRef->SetBufferOffset(fLast);
810  // This is now done in the TBranch streamer since fBranch might not
811  // yet be set correctly.
812  // fBranch->GetTree()->IncrementTotalBuffers(fBufferSize);
813  }
814  } else {
815  TKey::Streamer(b); //this must be first
816  b.WriteVersion(TBasket::IsA());
817  if (fBufferRef) {
818  Int_t curLast = fBufferRef->Length();
819  if (!fHeaderOnly && !fSeekKey && curLast > fLast) fLast = curLast;
820  }
822 
823 // static TStopwatch timer;
824 // timer.Start(kFALSE);
825 
826 // // Check may be fEntryOffset is equidistant
827 // // This attempts by Victor fails :(
828 // int equidist = 0;
829 // if (1 && fEntryOffset && fNevBuf>=3) {
830 // equidist = 1;
831 // int dist = fEntryOffset[1]-fEntryOffset[0];
832 // int curr = fEntryOffset[1];
833 // for (int i=1;i<fNevBuf;i++,curr+=dist) {
834 // if (fEntryOffset[i]==curr) continue;
835 // equidist = 0;
836 // break;
837 // }
838 // if (equidist) {
839 // fNevBufSize=dist;
840 // delete [] fEntryOffset; fEntryOffset = 0;
841 // }
842 // if (equidist) {
843 // fprintf(stderr,"detected an equidistant case fNbytes==%d fLast==%d\n",fNbytes,fLast);
844 // }
845 // }
846 // also he add (a little further
847 // if (!fEntryOffset || equidist) flag = 2;
848 
849 // timer.Stop();
850 // Double_t rt1 = timer.RealTime();
851 // Double_t cp1 = timer.CpuTime();
852 // fprintf(stderr,"equidist cost : RT=%6.2f s Cpu=%6.2f s\n",rt1,cp1);
853 
854  b << fBufferSize;
855  b << fNevBufSize;
856  b << fNevBuf;
857  b << fLast;
858  if (fHeaderOnly) {
859  flag = 0;
860  b << flag;
861  } else {
862  flag = 1;
863  if (!fEntryOffset) flag = 2;
864  if (fBufferRef) flag += 10;
865  if (fDisplacement) flag += 40;
866  b << flag;
867 
868  if (fEntryOffset && fNevBuf) {
869  b.WriteArray(fEntryOffset, fNevBuf);
870  if (fDisplacement) b.WriteArray(fDisplacement, fNevBuf);
871  }
872  if (fBufferRef) {
873  char *buf = fBufferRef->Buffer();
874  b.WriteFastArray(buf, fLast);
875  }
876  }
877  }
878 }
879 
880 ////////////////////////////////////////////////////////////////////////////////
881 /// Update basket header and EntryOffset table.
882 
883 void TBasket::Update(Int_t offset, Int_t skipped)
884 {
885  if (fEntryOffset) {
886  if (fNevBuf+1 >= fNevBufSize) {
887  Int_t newsize = TMath::Max(10,2*fNevBufSize);
888  Int_t *newoff = TStorage::ReAllocInt(fEntryOffset, newsize,
889  fNevBufSize);
890  if (fDisplacement) {
891  Int_t *newdisp = TStorage::ReAllocInt(fDisplacement, newsize,
892  fNevBufSize);
893  fDisplacement = newdisp;
894  }
895  fEntryOffset = newoff;
896  fNevBufSize = newsize;
897 
898  //Update branch only for the first 10 baskets
899  if (fBranch->GetWriteBasket() < 10) {
900  fBranch->SetEntryOffsetLen(newsize);
901  }
902  }
903  fEntryOffset[fNevBuf] = offset;
904 
905  if (skipped!=offset && !fDisplacement){
907  for (Int_t i = 0; i<fNevBufSize; i++) fDisplacement[i] = fEntryOffset[i];
908  }
909  if (fDisplacement) {
910  fDisplacement[fNevBuf] = skipped;
912  }
913  }
914 
915  fNevBuf++;
916 }
917 
918 ////////////////////////////////////////////////////////////////////////////////
919 /// Write buffer of this basket on the current file.
920 ///
921 /// The function returns the number of bytes committed to the memory.
922 /// If a write error occurs, the number of bytes returned is -1.
923 /// If no data are written, the number of bytes returned is 0.
924 
926 {
927  const Int_t kWrite = 1;
928 
929  TFile *file = fBranch->GetFile(kWrite);
930  if (!file) return 0;
931  if (!file->IsWritable()) {
932  return -1;
933  }
934  fMotherDir = file; // fBranch->GetDirectory();
935 
937  // Read the basket information that was saved inside the buffer.
938  Bool_t writing = fBufferRef->IsWriting();
941 
942  Streamer(*fBufferRef);
943  if (writing) fBufferRef->SetWriteMode();
944  Int_t nout = fNbytes - fKeylen;
945 
947 
948  Create(nout,file);
950  fHeaderOnly = kTRUE;
951 
952  Streamer(*fBufferRef); //write key itself again
953  int nBytes = WriteFileKeepBuffer();
955  return nBytes>0 ? fKeylen+nout : -1;
956  }
957 
958  // Transfer fEntryOffset table at the end of fBuffer.
959  fLast = fBufferRef->Length();
960  if (fEntryOffset) {
961  // Note: We might want to investigate the compression gain if we
962  // transform the Offsets to fBuffer in entry length to optimize
963  // compression algorithm. The aggregate gain on a (random) CMS files
964  // is around 5.5%. So the code could something like:
965  // for(Int_t z = fNevBuf; z > 0; --z) {
966  // if (fEntryOffset[z]) fEntryOffset[z] = fEntryOffset[z] - fEntryOffset[z-1];
967  // }
969  if (fDisplacement) {
971  delete [] fDisplacement; fDisplacement = 0;
972  }
973  }
974 
975  Int_t lbuf, nout, noutot, bufmax, nzip;
976  lbuf = fBufferRef->Length();
977  fObjlen = lbuf - fKeylen;
978 
979  fHeaderOnly = kTRUE;
981  Int_t cxlevel = fBranch->GetCompressionLevel();
982  Int_t cxAlgorithm = fBranch->GetCompressionAlgorithm();
983  if (cxlevel > 0) {
984  Int_t nbuffers = 1 + (fObjlen - 1) / kMAXZIPBUF;
985  Int_t buflen = fKeylen + fObjlen + 9 * nbuffers + 28; //add 28 bytes in case object is placed in a deleted gap
986  InitializeCompressedBuffer(buflen, file);
987  if (!fCompressedBufferRef) {
988  Warning("WriteBuffer", "Unable to allocate the compressed buffer");
989  return -1;
990  }
993  char *objbuf = fBufferRef->Buffer() + fKeylen;
994  char *bufcur = &fBuffer[fKeylen];
995  noutot = 0;
996  nzip = 0;
997  for (Int_t i = 0; i < nbuffers; ++i) {
998  if (i == nbuffers - 1) bufmax = fObjlen - nzip;
999  else bufmax = kMAXZIPBUF;
1000  //compress the buffer
1001  R__zipMultipleAlgorithm(cxlevel, &bufmax, objbuf, &bufmax, bufcur, &nout, cxAlgorithm);
1002 
1003  // test if buffer has really been compressed. In case of small buffers
1004  // when the buffer contains random data, it may happen that the compressed
1005  // buffer is larger than the input. In this case, we write the original uncompressed buffer
1006  if (nout == 0 || nout >= fObjlen) {
1007  nout = fObjlen;
1008  // We used to delete fBuffer here, we no longer want to since
1009  // the buffer (held by fCompressedBufferRef) might be re-used later.
1010  fBuffer = fBufferRef->Buffer();
1011  Create(fObjlen,file);
1013 
1014  Streamer(*fBufferRef); //write key itself again
1015  if ((nout+fKeylen)>buflen) {
1016  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",
1017  (nout+fKeylen-buflen),buflen,fNbytes,fObjlen,fKeylen);
1018  }
1019  goto WriteFile;
1020  }
1021  bufcur += nout;
1022  noutot += nout;
1023  objbuf += kMAXZIPBUF;
1024  nzip += kMAXZIPBUF;
1025  }
1026  nout = noutot;
1027  Create(noutot,file);
1029 
1030  Streamer(*fBufferRef); //write key itself again
1031  memcpy(fBuffer,fBufferRef->Buffer(),fKeylen);
1032  } else {
1033  fBuffer = fBufferRef->Buffer();
1034  Create(fObjlen,file);
1036 
1037  Streamer(*fBufferRef); //write key itself again
1038  nout = fObjlen;
1039  }
1040 
1041 WriteFile:
1042  Int_t nBytes = WriteFileKeepBuffer();
1043  fHeaderOnly = kFALSE;
1044  return nBytes>0 ? fKeylen+nout : -1;
1045 }
1046 
Int_t fVersion
Key version identifier.
Definition: TKey.h:40
Int_t ReadBasketBytes(Long64_t pos, TFile *file)
Read basket buffers in memory and cleanup.
Definition: TBasket.cxx:651
virtual const char * GetName() const
Returns name of object.
Definition: TNamed.h:51
void SetBufferOffset(Int_t offset=0)
Definition: TBuffer.h:90
Bool_t fHeaderOnly
True when only the basket header must be read/written.
Definition: TBasket.h:56
Bool_t IsReading() const
Definition: TBuffer.h:83
Int_t fLastWriteBufferSize
! Size of the buffer last time we wrote it to disk
Definition: TBasket.h:62
Bool_t IsWriting() const
Definition: TBuffer.h:84
virtual void SetReadMode()
Set read mode of basket.
Definition: TBasket.cxx:751
void Update(Int_t newlast)
Definition: TBasket.h:95
The concrete implementation of TBuffer for writing/reading to/from a ROOT file or socket...
Definition: TBufferFile.h:51
Int_t ReadBasketBuffers(Long64_t pos, Int_t len, TFile *file)
Read basket buffers in memory and cleanup.
Definition: TBasket.cxx:431
long long Long64_t
Definition: RtypesCore.h:69
virtual Int_t GetBasketSize() const
Definition: TBranch.h:152
Int_t * fDisplacement
![fNevBuf] Displacement of entries in fBuffer(TKey)
Definition: TBasket.h:57
virtual void IncrementTotalBuffers(Int_t nbytes)
Definition: TTree.h:472
short Version_t
Definition: RtypesCore.h:61
Provides the interface for the PROOF internal performance measurement and event tracing.
Int_t GetCompressionLevel() const
Definition: TBranch.h:234
A cache when reading files over the network.
TObject * GetParent() const
Return pointer to parent of this buffer.
Definition: TBuffer.cxx:231
Int_t fBufferSize
fBuffer length in bytes
Definition: TBasket.h:52
virtual void SetOffset(Long64_t offset, ERelativeTo pos=kBeg)
Set position from where to start reading.
Definition: TFile.cxx:2084
Int_t * fEntryOffset
[fNevBuf] Offset of entries in fBuffer(TKey)
Definition: TBasket.h:58
Bool_t TestBit(UInt_t f) const
Definition: TObject.h:157
virtual void SetName(const char *name)
Set the name of the TNamed.
Definition: TNamed.cxx:131
A specialized TFileCacheRead object for a TTree.
Definition: TTreeCache.h:34
TBranch * fBranch
Pointer to the basket support branch.
Definition: TBasket.h:59
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:2105
A ROOT file is a suite of consecutive data records (TKey instances) with a well defined format...
Definition: TFile.h:50
virtual Bool_t ReadBuffer(char *buf, Int_t len)
Read a buffer from the file.
Definition: TFile.cxx:1602
Buffer base class used for serializing objects.
Definition: TBuffer.h:42
TDirectory * GetDirectory() const
Definition: TBranch.h:158
int Int_t
Definition: RtypesCore.h:41
bool Bool_t
Definition: RtypesCore.h:59
R__EXTERN TVirtualMutex * gROOTMutex
Definition: TROOT.h:63
const Bool_t kFALSE
Definition: Rtypes.h:92
void SetParent(TObject *parent)
Set parent owning this buffer.
Definition: TBuffer.cxx:239
Int_t GetCompressionAlgorithm() const
Definition: TBranch.h:228
virtual UInt_t WriteVersion(const TClass *cl, Bool_t useBcnt=kFALSE)=0
Int_t fNevBuf
Number of entries in basket.
Definition: TBasket.h:54
char * fBuffer
Object buffer.
Definition: TKey.h:50
Int_t GetEntryOffsetLen() const
Definition: TBranch.h:161
TDirectory * fMotherDir
!pointer to mother directory
Definition: TKey.h:53
TBuffer * GetBufferRef() const
Definition: TKey.h:81
void SetBit(UInt_t f, Bool_t set)
Set or unset the user status bits as specified in f.
Definition: TObject.cxx:739
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:1629
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
virtual TVirtualPerfStats * GetPerfStats() const
Definition: TTree.h:435
char * Buffer() const
Definition: TBuffer.h:93
virtual void Reset()
Reset the basket to the starting state.
Definition: TBasket.cxx:666
virtual Int_t WriteBuffer()
Write buffer of this basket on the current file.
Definition: TBasket.cxx:925
virtual Int_t WriteFile(Int_t cycle=1, TFile *f=0)
Write the encoded object supported by this key.
Definition: TKey.cxx:1443
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:44
TString fClassName
Object Class name.
Definition: TKey.h:48
Book space in a file, create I/O buffers, to fill them, (un)compress them.
Definition: TKey.h:30
void InitializeCompressedBuffer(Int_t len, TFile *file)
Initialize the compressed buffer; either from the TTree or create a local one.
Definition: TBasket.cxx:407
virtual void Enable()
Definition: TTreeCache.h:79
virtual Int_t WriteFileKeepBuffer(TFile *f=0)
Write the encoded object supported by this key.
Definition: TKey.cxx:1484
void Expand(Int_t newsize, Bool_t copy=kTRUE)
Expand (or shrink) the I/O buffer to newsize bytes.
Definition: TBuffer.cxx:201
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:1239
Bool_t fOwnsCompressedBuffer
! Whether or not we own the compressed buffer.
Definition: TBasket.h:61
Int_t GetObjlen() const
Definition: TKey.h:89
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:144
Int_t ReadBasketBuffersUncompressedCase()
By-passing buffer unzipping has been requested and is possible (only 1 entry in this basket)...
Definition: TBasket.cxx:333
Int_t GetWriteBasket() const
Definition: TBranch.h:171
Int_t GetEntryPointer(Int_t Entry)
Get pointer to buffer for internal entry.
Definition: TBasket.cxx:207
#define OLD_CASE_EXPRESSION
Definition: TBasket.cxx:328
unsigned int UInt_t
Definition: RtypesCore.h:42
virtual void Error(const char *method, const char *msgfmt,...) const
Issue error message.
Definition: TObject.cxx:925
Manages buffers for branches of a Tree.
Definition: TBasket.h:38
TBuffer * fCompressedBufferRef
! Compressed buffer.
Definition: TBasket.h:60
void SetReadMode()
Set buffer in read mode.
Definition: TBuffer.cxx:271
virtual void Reset()
Reset the key as it had not been &#39;filled&#39; yet.
Definition: TKey.cxx:1298
TBuffer * GetTransientBuffer(Int_t size)
Returns the transient buffer currently used by this TBranch for reading/writing baskets.
Definition: TBranch.cxx:475
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:51
#define gPerfStats
Int_t fNevBufSize
Length in Int_t of fEntryOffset OR fixed length of each entry if fEntryOffset is null! ...
Definition: TBasket.h:53
Long64_t fSeekKey
Location of object on file.
Definition: TKey.h:46
long Long_t
Definition: RtypesCore.h:50
Short_t fCycle
Cycle number.
Definition: TKey.h:45
#define ClassImp(name)
Definition: Rtypes.h:279
Bool_t IsZombie() const
Definition: TObject.h:120
double Double_t
Definition: RtypesCore.h:55
Describe directory structure in memory.
Definition: TDirectory.h:44
#define R__likely(expr)
Definition: RConfig.h:533
#define free
Definition: civetweb.c:821
The TTimeStamp encapsulates seconds and ns since EPOCH.
Definition: TTimeStamp.h:76
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:385
Int_t BufferSize() const
Definition: TBuffer.h:94
virtual ~TBasket()
Basket destructor.
Definition: TBasket.cxx:125
void R__unzip(Int_t *nin, UChar_t *bufin, Int_t *lout, char *bufout, Int_t *nout)
Int_t GetKeylen() const
Definition: TKey.h:86
Int_t fObjlen
Length of uncompressed object in bytes.
Definition: TKey.h:42
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:2200
virtual void DeleteEntryOffset()
Delete fEntryOffset array.
Definition: TBasket.cxx:177
TBuffer * GetTransientBuffer(Int_t size)
Returns the transient buffer currently used by this TTree for reading/writing baskets.
Definition: TTree.cxx:918
virtual Int_t DropBuffers()
Drop buffers of this basket if it is not the current basket.
Definition: TBasket.cxx:187
#define R__unlikely(expr)
Definition: RConfig.h:532
Definition: file.py:1
Short_t Max(Short_t a, Short_t b)
Definition: TMathBase.h:202
void MakeZombie()
Definition: TObject.h:47
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
#define NULL
Definition: Rtypes.h:82
Int_t fLast
Pointer to last used byte in basket.
Definition: TBasket.h:55
TTree * GetTree() const
Definition: TBranch.h:184
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:1202
Int_t fNbytes
Number of bytes for the object on file.
Definition: TKey.h:41
A TTree object has a header with a name and a title.
Definition: TTree.h:98
Long64_t CopyTo(TFile *to)
Copy the basket of this branch onto the file to.
Definition: TBasket.cxx:159
double result[121]
unsigned char UChar_t
Definition: RtypesCore.h:34
#define R__LOCKGUARD_IMT2(mutex)
const UInt_t kDisplacementMask
Definition: TBasket.cxx:26
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:1400
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:355
A TTree is a list of TBranches.
Definition: TBranch.h:58
const Bool_t kTRUE
Definition: Rtypes.h:91
virtual void SetTitle(const char *title="")
Set the title of the TNamed.
Definition: TNamed.cxx:155
TBasket()
Default contructor.
Definition: TBasket.cxx:42
virtual void SetWriteMode()
Set write mode of basket.
Definition: TBasket.cxx:760
char name[80]
Definition: TGX11.cxx:109
virtual void Warning(const char *method, const char *msgfmt,...) const
Issue warning message.
Definition: TObject.cxx:911
static Int_t * ReAllocInt(Int_t *vp, size_t size, size_t oldsize)
Reallocate (i.e.
Definition: TStorage.cxx:290
void SetWriteMode()
Set buffer in write mode.
Definition: TBuffer.cxx:284
virtual Version_t ReadVersion(UInt_t *start=0, UInt_t *bcnt=0, const TClass *cl=0)=0
virtual void Disable()
Definition: TTreeCache.h:78
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:165
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:221
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:286