TBasket.cxx

Go to the documentation of this file.
00001 // @(#)root/tree:$Id: TBasket.cxx 38081 2011-02-16 00:40:07Z pcanal $
00002 // Author: Rene Brun   19/01/96
00003 /*************************************************************************
00004  * Copyright (C) 1995-2000, Rene Brun and Fons Rademakers.               *
00005  * All rights reserved.                                                  *
00006  *                                                                       *
00007  * For the licensing terms see $ROOTSYS/LICENSE.                         *
00008  * For the list of contributors see $ROOTSYS/README/CREDITS.             *
00009  *************************************************************************/
00010 
00011 #include "TBasket.h"
00012 #include "TBufferFile.h"
00013 #include "TTree.h"
00014 #include "TBranch.h"
00015 #include "TFile.h"
00016 #include "TBufferFile.h"
00017 #include "TMath.h"
00018 #include "TTreeCache.h"
00019 #include "TTreeCacheUnzip.h"
00020 
00021 extern "C" void R__zip (Int_t cxlevel, Int_t *nin, char *bufin, Int_t *lout, char *bufout, Int_t *nout);
00022 extern "C" void R__unzip(Int_t *nin, UChar_t *bufin, Int_t *lout, char *bufout, Int_t *nout);
00023 extern "C" int R__unzip_header(Int_t *nin, UChar_t *bufin, Int_t *lout);
00024 
00025 const Int_t  kMAXBUF = 0xFFFFFF;
00026 const UInt_t kDisplacementMask = 0xFF000000;  // In the streamer the two highest bytes of
00027                                               // the fEntryOffset are used to stored displacement.
00028 
00029 ClassImp(TBasket)
00030 
00031 //_______________________________________________________________________
00032 //
00033 //  Manages buffers for branches of a Tree.
00034 //  See picture in TTree.
00035 //
00036 
00037 //_______________________________________________________________________
00038 TBasket::TBasket() : fCompressedSize(0),fCompressedBuffer(0)
00039 {
00040    // Default contructor.
00041 
00042    fDisplacement  = 0;
00043    fEntryOffset   = 0;
00044    fBufferRef     = 0;
00045    fBuffer        = 0;
00046    fHeaderOnly    = kFALSE;
00047    fBufferSize    = 0;
00048    fNevBufSize    = 0;
00049    fNevBuf        = 0;
00050    fLast          = 0;
00051    fBranch        = 0;
00052 }
00053 
00054 //_______________________________________________________________________
00055 TBasket::TBasket(TDirectory *motherDir) : TKey(motherDir),fCompressedSize(0),fCompressedBuffer(0)
00056 {
00057    // Constructor used during reading.
00058 
00059    fDisplacement  = 0;
00060    fEntryOffset   = 0;
00061    fBufferRef     = 0;
00062    fBuffer        = 0;
00063    fHeaderOnly    = kFALSE;
00064    fBufferSize    = 0;
00065    fNevBufSize    = 0;
00066    fNevBuf        = 0;
00067    fLast          = 0;
00068    fBranch        = 0;
00069 }
00070 
00071 //_______________________________________________________________________
00072 TBasket::TBasket(const char *name, const char *title, TBranch *branch) : 
00073    TKey(branch->GetDirectory()),fCompressedSize(0),fCompressedBuffer(0)
00074 {
00075    // Basket normal constructor, used during writing.
00076 
00077    SetName(name);
00078    SetTitle(title);
00079    fClassName   = "TBasket";
00080    fBufferSize  = branch->GetBasketSize();
00081    fNevBufSize  = branch->GetEntryOffsetLen();
00082    fNevBuf      = 0;
00083    fEntryOffset = 0;
00084    fDisplacement= 0;
00085    fBuffer      = 0;
00086    fBufferRef   = new TBufferFile(TBuffer::kWrite, fBufferSize);
00087    fVersion    += 1000;
00088    if (branch->GetDirectory()) {
00089       TFile *file = branch->GetFile();
00090       fBufferRef->SetParent(file);
00091    }
00092    fHeaderOnly  = kTRUE;
00093    fLast        = 0; // Must initialize before calling Streamer()
00094    
00095    Streamer(*fBufferRef);
00096    fKeylen      = fBufferRef->Length();
00097    fObjlen      = fBufferSize - fKeylen;
00098    fLast        = fKeylen;
00099    fBuffer      = 0;
00100    fBranch      = branch;
00101    fHeaderOnly  = kFALSE;
00102    if (fNevBufSize) {
00103       fEntryOffset = new Int_t[fNevBufSize];
00104       for (Int_t i=0;i<fNevBufSize;i++) fEntryOffset[i] = 0;
00105    }
00106    branch->GetTree()->IncrementTotalBuffers(fBufferSize);
00107 }
00108 
00109 //_______________________________________________________________________
00110 TBasket::~TBasket()
00111 {
00112    // Basket destructor.
00113 
00114    if (fDisplacement) delete [] fDisplacement;
00115    if (fEntryOffset)  delete [] fEntryOffset;
00116    if (fBuffer == fCompressedBuffer) fBuffer = 0;
00117    if (fCompressedBuffer) delete [] fCompressedBuffer;
00118    fDisplacement= 0;
00119    fEntryOffset = 0;
00120    fCompressedSize = 0;
00121    fCompressedBuffer = 0;
00122 }
00123 
00124 //_______________________________________________________________________
00125 void TBasket::AdjustSize(Int_t newsize)
00126 {
00127    // Increase the size of the current fBuffer up to newsize.
00128    
00129    if (fBuffer == fBufferRef->Buffer()) {
00130       fBufferRef->Expand(newsize);
00131       fBuffer = fBufferRef->Buffer();
00132    } else {
00133       fBufferRef->Expand(newsize);
00134    }      
00135    fBranch->GetTree()->IncrementTotalBuffers(newsize-fBufferSize);
00136    fBufferSize  = newsize;
00137 }
00138 
00139 //_______________________________________________________________________
00140 Long64_t TBasket::CopyTo(TFile *to) 
00141 {
00142    // Copy the basket of this branch onto the file to.
00143 
00144 //   Global variables no longer required by key store   
00145 //   TDirectory::TContext c(gDirectory,to);
00146 
00147    fBufferRef->SetWriteMode();
00148    Int_t nout = fNbytes - fKeylen;
00149    fBuffer = fBufferRef->Buffer();
00150    Create(nout, to);
00151    fBufferRef->SetBufferOffset(0);
00152    fHeaderOnly = kTRUE;
00153    Streamer(*fBufferRef);
00154    fHeaderOnly = kFALSE;
00155    Int_t nBytes = WriteFileKeepBuffer(to);
00156 
00157    return nBytes>0 ? nBytes : -1;
00158 }
00159 
00160 //_______________________________________________________________________
00161 void TBasket::DeleteEntryOffset()
00162 {
00163    //  Delete fEntryOffset array.
00164 
00165    if (fEntryOffset) delete [] fEntryOffset;
00166    fEntryOffset = 0;
00167    fNevBufSize  = 0;
00168 }
00169 
00170 
00171 //_______________________________________________________________________
00172 Int_t TBasket::DropBuffers()
00173 {
00174    // Drop buffers of this basket if it is not the current basket.
00175 
00176    if (!fBuffer && !fBufferRef) return 0;
00177 
00178    if (fDisplacement) delete [] fDisplacement;
00179    if (fEntryOffset)  delete [] fEntryOffset;
00180    if (fBufferRef)    delete fBufferRef;
00181    if (fCompressedBuffer) delete [] fCompressedBuffer;
00182    fBufferRef   = 0;
00183    fBuffer      = 0;
00184    fDisplacement= 0;
00185    fEntryOffset = 0;
00186    fCompressedSize = 0;
00187    fCompressedBuffer = 0;
00188    fBranch->GetTree()->IncrementTotalBuffers(-fBufferSize);
00189    return fBufferSize;
00190 }
00191 
00192 //_______________________________________________________________________
00193 Int_t TBasket::GetEntryPointer(Int_t entry)
00194 {
00195    // Get pointer to buffer for internal entry.
00196 
00197    Int_t offset;
00198    if (fEntryOffset) offset = fEntryOffset[entry];
00199    else              offset = fKeylen + entry*fNevBufSize;
00200    fBufferRef->SetBufferOffset(offset);
00201    return offset;
00202 }
00203 
00204 //_______________________________________________________________________
00205 Int_t TBasket::LoadBasketBuffers(Long64_t pos, Int_t len, TFile *file)
00206 { 
00207    // Load basket buffers in memory without unziping.
00208    // This function is called by TTreeCloner.
00209    // The function returns 0 in case of success, 1 in case of error.
00210 
00211    if (fBufferRef) {
00212       // Reuse the buffer if it exist.
00213       fBufferRef->SetReadMode();
00214       fBufferRef->Reset();
00215       // We use this buffer both for reading and writing, we need to
00216       // make sure it is properly sized for writing.
00217       if (fBufferRef->BufferSize() < len) {
00218          fBufferRef->SetWriteMode();
00219          fBufferRef->Expand(len);
00220          fBufferRef->SetReadMode();
00221       }
00222    } else {
00223       fBufferRef = new TBufferFile(TBuffer::kRead, len);
00224    }
00225    fBufferRef->SetParent(file);
00226    char *buffer = fBufferRef->Buffer();
00227    file->Seek(pos);
00228    if (file->ReadBuffer(buffer,len)) {
00229       return 1; //error while reading
00230    }
00231 
00232    fBufferRef->SetReadMode();
00233    fBufferRef->SetBufferOffset(0);
00234    Streamer(*fBufferRef);
00235 
00236    return 0;
00237 }
00238 
00239 //_______________________________________________________________________
00240 void TBasket::MoveEntries(Int_t dentries)
00241 {
00242    // Remove the first dentries of this basket, moving entries at
00243    // dentries to the start of the buffer.
00244    
00245    Int_t i;
00246 
00247    if (dentries >= fNevBuf) return;
00248    Int_t bufbegin;
00249    Int_t moved;
00250 
00251    if (fEntryOffset) {
00252       bufbegin = fEntryOffset[dentries];
00253       moved = bufbegin-GetKeylen();
00254 
00255       // First store the original location in the fDisplacement array
00256       // and record the new start offset
00257 
00258       if (!fDisplacement) {
00259          fDisplacement = new Int_t[fNevBufSize];
00260       }
00261       for (i = 0; i<(fNevBufSize-dentries); ++i) {
00262          fDisplacement[i] = fEntryOffset[i+dentries];
00263          fEntryOffset[i]  = fEntryOffset[i+dentries] - moved;
00264       }
00265       for (i = fNevBufSize-dentries; i<fNevBufSize; ++i) {
00266          fDisplacement[i] = 0;      
00267          fEntryOffset[i]  = 0;
00268       }
00269 
00270    } else {
00271       // If there is no EntryOffset array, this means
00272       // that each entry has the same size and that 
00273       // it does not point to other objects (hence there
00274       // is no need for a displacement array).
00275       bufbegin = GetKeylen() + dentries*fNevBufSize;
00276       moved = bufbegin-GetKeylen();
00277    }
00278    TBuffer *buf = GetBufferRef();
00279    char *buffer = buf->Buffer();
00280    memmove(buffer+GetKeylen(),buffer+bufbegin,buf->Length()-bufbegin);
00281    buf->SetBufferOffset(buf->Length()-moved);
00282    fNevBuf -= dentries;
00283 }
00284 
00285 //_______________________________________________________________________
00286 Int_t TBasket::ReadBasketBuffers(Long64_t pos, Int_t len, TFile *file)
00287 {
00288    // Read basket buffers in memory and cleanup.
00289    //
00290    // Read a basket buffer. Check if buffers of previous ReadBasket
00291    // should not be dropped. Remember, we keep buffers in memory up to
00292    // fMaxVirtualSize.
00293    // The function returns 0 in case of success, 1 in case of error
00294    // This function was modified with the addition of the parallel
00295    // unzipping, it will try to get the unzipped file from the cache
00296    // receiving only a pointer to that buffer (so we shall not
00297    // delete that pointer), although we get a new buffer in case
00298    // it's not found in the cache.
00299    // There is a lot of code duplication but it was necesary to assure
00300    // the expected behavior when there is no cache.
00301 
00302 
00303    if(!fBranch->GetDirectory()) {
00304       return -1;
00305    }
00306    Int_t badread= 0;
00307 
00308    TFileCacheRead *pf = file->GetCacheRead();
00309    char *buffer = 0;
00310    Bool_t free = kTRUE; // Must we free this buffer or does it make part of the cache? 
00311    Int_t res = -1;
00312 
00313    if (pf) res = pf->GetUnzipBuffer(&buffer, pos, len, &free);
00314 
00315    if (res >= 0) {
00316 
00317       // We always create the TBuffer for the basket but it will be a shell only,
00318       // since we pass the pointer to the low level buffer
00319       if (fBufferRef) {
00320          fBufferRef->SetBuffer(buffer, res, free);
00321          fBufferRef->SetReadMode();
00322          fBufferRef->Reset();
00323       } else {
00324          fBufferRef = new TBufferFile(TBuffer::kRead, res, buffer, free);
00325       }
00326       fBufferRef->SetParent(file);
00327 
00328       Streamer(*fBufferRef);
00329    
00330       if (IsZombie()) {
00331          badread = 1;
00332          return badread;         
00333       }
00334 
00335       Bool_t oldCase = fObjlen==fNbytes-fKeylen
00336          && GetBranch()->GetCompressionLevel()!=0
00337          && file->GetVersion()<=30401;
00338       if (fObjlen > fNbytes-fKeylen || oldCase) {
00339          if (TestBit(TBufferFile::kNotDecompressed) && (fNevBuf==1)) {
00340             // By-passing buffer unzipping has been requested and is
00341             // possible (only 1 entry in this basket).
00342             fBuffer = fBufferRef->Buffer();
00343 
00344             // Make sure that the buffer is set at the END of the data
00345             fBufferRef->SetBufferOffset(fNbytes);
00346 
00347             // Indicate that this buffer is weird.
00348             fBufferRef->SetBit(TBufferFile::kNotDecompressed);
00349 
00350             // Usage of this mode assume the existance of only ONE
00351             // entry in this basket.
00352             delete [] fEntryOffset; fEntryOffset = 0;
00353             delete [] fDisplacement; fDisplacement = 0;
00354 
00355             fBranch->GetTree()->IncrementTotalBuffers(fBufferSize);
00356             return badread;
00357          }
00358       }
00359 
00360       fBuffer = fBufferRef->Buffer();
00361       len = fObjlen+fKeylen;
00362    }
00363    else{
00364       if (fBufferRef) {
00365          fBufferRef->SetReadMode();
00366          if (fBufferRef->BufferSize() < len) {
00367             fBufferRef->Expand(len);
00368          }
00369          fBufferRef->Reset();
00370       } else {
00371          fBufferRef = new TBufferFile(TBuffer::kRead, len);
00372       }
00373       fBufferRef->SetParent(file);
00374 
00375       buffer = fBufferRef->Buffer();
00376       if (file->ReadBuffer(buffer,pos,len)) {
00377          badread = 1;
00378          return badread;
00379       }
00380 
00381       Streamer(*fBufferRef);
00382 
00383       if (IsZombie()) {
00384          badread = 1;
00385          return badread;         
00386       }
00387       
00388       Bool_t oldCase = fObjlen==fNbytes-fKeylen
00389          && GetBranch()->GetCompressionLevel()!=0
00390          && file->GetVersion()<=30401;
00391       if (fObjlen > fNbytes-fKeylen || oldCase) {
00392          if (TestBit(TBufferFile::kNotDecompressed) && (fNevBuf==1)) {
00393             // By-passing buffer unzipping has been requested and is
00394             // possible (only 1 entry in this basket).
00395             fBuffer = fBufferRef->Buffer();
00396             
00397             // Make sure that the buffer is set at the END of the data
00398             fBufferRef->SetBufferOffset(fNbytes);
00399             
00400             // Indicate that this buffer is weird.
00401             fBufferRef->SetBit(TBufferFile::kNotDecompressed);
00402             
00403             // Usage of this mode assume the existance of only ONE
00404             // entry in this basket.
00405             delete [] fEntryOffset; fEntryOffset = 0;
00406             delete [] fDisplacement; fDisplacement = 0;
00407             
00408             fBranch->GetTree()->IncrementTotalBuffers(fBufferSize);
00409             return badread;
00410          }
00411 
00412          if ((fObjlen+fKeylen) > fCompressedSize) {
00413             /* early consistency check before potentially large memory is being allocated */
00414             Int_t nin, nbuf;
00415             UChar_t *bufcur = (UChar_t *)&buffer[fKeylen];
00416             if (R__unzip_header(&nin, bufcur, &nbuf)!=0) {
00417                Error("ReadBasketBuffers", "Inconsistency found in header (nin=%d, nbuf=%d)", nin, nbuf);
00418                badread = 1;
00419                return badread;
00420             }
00421             if (fCompressedSize) delete [] fCompressedBuffer;
00422             fCompressedSize = fObjlen+fKeylen;
00423             fCompressedBuffer = new char[fCompressedSize];
00424          }
00425          fBuffer = fCompressedBuffer;
00426          memcpy(fBuffer,buffer,fKeylen);
00427          char *objbuf = fBuffer + fKeylen;
00428          UChar_t *bufcur = (UChar_t *)&buffer[fKeylen];
00429          Int_t nin, nout, nbuf;
00430          Int_t noutot = 0;
00431          while (1) {
00432             Int_t hc = R__unzip_header(&nin, bufcur, &nbuf);
00433             if (hc!=0) break;
00434             if (oldCase && (nin > fObjlen || nbuf > fObjlen)) {
00435                //buffer was very likely not compressed in an old version
00436                delete [] fBuffer;
00437                fBuffer = fBufferRef->Buffer();
00438                goto AfterBuffer;
00439             }
00440             R__unzip(&nin, bufcur, &nbuf, objbuf, &nout);
00441             if (!nout) break;
00442             noutot += nout;
00443             if (noutot >= fObjlen) break;
00444             bufcur += nin;
00445             objbuf += nout;
00446          }
00447          if (noutot != fObjlen) {
00448             Error("ReadBasketBuffers", "fNbytes = %d, fKeylen = %d, fObjlen = %d, noutot = %d, nout=%d, nin=%d, nbuf=%d", fNbytes,fKeylen,fObjlen, noutot,nout,nin,nbuf);
00449             badread = 1;
00450          }
00451          // Switch the 2 buffers
00452          char *temp = fBufferRef->Buffer();
00453          Int_t templen = fBufferRef->BufferSize();
00454          fBufferRef->ResetBit(TBuffer::kIsOwner);
00455          fBufferRef->SetBuffer(fBuffer, fCompressedSize, kTRUE); // Do adopt the buffer.
00456          fCompressedBuffer = temp;
00457          fCompressedSize = templen;
00458          len = fObjlen+fKeylen;
00459       } else {
00460          fBuffer = fBufferRef->Buffer();
00461       }
00462    }
00463  AfterBuffer:
00464 
00465    fBranch->GetTree()->IncrementTotalBuffers(fBufferSize);
00466 
00467    // read offsets table
00468    if (badread || !fBranch->GetEntryOffsetLen()) {
00469       return badread;
00470    }
00471    delete [] fEntryOffset;
00472    fEntryOffset = 0;
00473    fBufferRef->SetBufferOffset(fLast);
00474    fBufferRef->ReadArray(fEntryOffset);
00475    if (!fEntryOffset) {
00476       fEntryOffset = new Int_t[fNevBuf+1];
00477       fEntryOffset[0] = fKeylen;
00478       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);
00479       return badread;
00480    }
00481    delete [] fDisplacement;
00482    fDisplacement = 0;
00483    if (fBufferRef->Length() != len) {
00484       // There is more data in the buffer!  It is the displacement
00485       // array.  If len is less than TBuffer::kMinimalSize the actual
00486       // size of the buffer is too large, so we can not use the
00487       // fBufferRef->BufferSize()
00488       fBufferRef->ReadArray(fDisplacement);
00489    }
00490 
00491    return badread;
00492 }
00493 
00494 //_______________________________________________________________________
00495 Int_t TBasket::ReadBasketBytes(Long64_t pos, TFile *file)
00496 {
00497    // Read basket buffers in memory and cleanup
00498    //
00499    // Read first bytes of a logical record starting at position pos
00500    // return record length (first 4 bytes of record).
00501 
00502    const Int_t len = 128;
00503    char buffer[len];
00504    Int_t keylen;
00505    file->GetRecordHeader(buffer, pos,len, fNbytes, fObjlen, keylen);
00506    fKeylen = keylen;
00507    return fNbytes;
00508 }
00509 
00510 //_______________________________________________________________________
00511 void TBasket::Reset()
00512 {
00513    // Reset the basket to the starting state. i.e. as it was after calling
00514    // the constructor (and potentially attaching a TBuffer.)
00515    
00516    // Name, Title, fClassName, fBranch 
00517    // stay the same.
00518    
00519    // Downsize the buffer if needed.
00520    Int_t curSize = fBufferRef->BufferSize();
00521    // fBufferLen at this point is already reset, so use indirect measurements
00522    Int_t curLen = (GetObjlen() + GetKeylen());
00523    if (curSize > 2*curLen)
00524    {
00525       Int_t curBsize = fBranch->GetBasketSize();      
00526       if (curSize > 2*curBsize ) {
00527          Int_t avgSize = (fBranch->GetTotBytes() / (1+fBranch->GetWriteBasket())); // Average number of bytes per basket so far
00528          if (curSize > 2*avgSize) {
00529             Int_t newSize = curBsize;
00530             if (curLen > newSize) {
00531                newSize = curLen;
00532             }
00533             if (avgSize > newSize) {
00534                newSize = avgSize;
00535             }
00536             newSize = newSize + 512 - newSize%512;  // Wiggle room and alignment (512 is same as in OptimizeBaskets)
00537             fBufferRef->Expand(newSize);
00538          }
00539       }
00540    }
00541 
00542    TKey::Reset();
00543 
00544    Int_t newNevBufSize = fBranch->GetEntryOffsetLen();
00545    if (newNevBufSize==0) {
00546       delete [] fEntryOffset;
00547       fEntryOffset = 0;
00548    } else if (newNevBufSize > fNevBufSize) {
00549       delete [] fEntryOffset;
00550       fEntryOffset = new Int_t[newNevBufSize];
00551    } else {
00552       if (!fEntryOffset) {
00553          fEntryOffset = new Int_t[newNevBufSize];
00554       }         
00555    }
00556    fNevBufSize = newNevBufSize;
00557 
00558    fNevBuf      = 0;
00559    Int_t *storeEntryOffset = fEntryOffset;
00560    fEntryOffset = 0; 
00561    Int_t *storeDisplacement = fDisplacement;
00562    fDisplacement= 0; 
00563    fBuffer      = 0;
00564 
00565    fBufferRef->Reset();
00566    fBufferRef->SetWriteMode();
00567 
00568    fHeaderOnly  = kTRUE;
00569    fLast        = 0;  //Must initialize before calling Streamer()
00570    
00571    Streamer(*fBufferRef);
00572 
00573    fKeylen      = fBufferRef->Length();
00574    fObjlen      = fBufferSize - fKeylen;
00575    fLast        = fKeylen;
00576    fBuffer      = 0;
00577    fHeaderOnly  = kFALSE;
00578    fDisplacement= storeDisplacement;
00579    fEntryOffset = storeEntryOffset;
00580    if (fNevBufSize) {
00581       for (Int_t i=0;i<fNevBufSize;i++) fEntryOffset[i] = 0;
00582    }   
00583 }
00584 
00585 //_______________________________________________________________________
00586 void TBasket::SetReadMode()
00587 {
00588    // Set read mode of basket.
00589 
00590    fLast = fBufferRef->Length();
00591    fBufferRef->SetReadMode();
00592 }
00593 
00594 //_______________________________________________________________________
00595 void TBasket::SetWriteMode()
00596 {
00597    // Set write mode of basket.
00598 
00599    fBufferRef->SetWriteMode();
00600    fBufferRef->SetBufferOffset(fLast);
00601 }
00602 
00603 //_______________________________________________________________________
00604 void TBasket::Streamer(TBuffer &b)
00605 {
00606    // Stream a class object.
00607 
00608    char flag;
00609    if (b.IsReading()) {
00610       TKey::Streamer(b); //this must be first
00611       Version_t v = b.ReadVersion();
00612       b >> fBufferSize;
00613       b >> fNevBufSize;
00614       if (fNevBufSize < 0) {
00615          Error("Streamer","The value of fNevBufSize is incorrect (%d) ; trying to recover by setting it to zero",fNevBufSize);
00616          MakeZombie();
00617          fNevBufSize = 0;
00618       }
00619       b >> fNevBuf;
00620       b >> fLast;
00621       b >> flag;
00622       if (fLast > fBufferSize) fBufferSize = fLast;
00623       if (!flag) return;
00624       if (flag%10 != 2) {
00625          delete [] fEntryOffset;
00626          fEntryOffset = new Int_t[fNevBufSize];
00627          if (fNevBuf) b.ReadArray(fEntryOffset);
00628          if (20<flag && flag<40) {
00629             for(int i=0; i<fNevBuf; i++){
00630                fEntryOffset[i] &= ~kDisplacementMask;
00631             }
00632          }
00633          if (flag>40) {
00634             fDisplacement = new Int_t[fNevBufSize];
00635             b.ReadArray(fDisplacement);
00636          }
00637       }
00638       if (flag == 1 || flag > 10) {
00639          fBufferRef = new TBufferFile(TBuffer::kRead,fBufferSize);
00640          fBufferRef->SetParent(b.GetParent());
00641          char *buf  = fBufferRef->Buffer();
00642          if (v > 1) b.ReadFastArray(buf,fLast);
00643          else       b.ReadArray(buf);
00644          fBufferRef->SetBufferOffset(fLast);
00645          // This is now done in the TBranch streamer since fBranch might not
00646          // yet be set correctly.
00647          //   fBranch->GetTree()->IncrementTotalBuffers(fBufferSize);
00648       }
00649    } else {
00650       TKey::Streamer(b);   //this must be first
00651       b.WriteVersion(TBasket::IsA());
00652       if (fBufferRef) {
00653          Int_t curLast = fBufferRef->Length();
00654          if (!fHeaderOnly && !fSeekKey && curLast > fLast) fLast = curLast;
00655       }
00656       if (fLast > fBufferSize) fBufferSize = fLast;
00657 
00658 //   static TStopwatch timer;
00659 //   timer.Start(kFALSE);
00660 
00661 //       //  Check may be fEntryOffset is equidistant
00662 //       //  This attempts by Victor fails :(
00663 //       int equidist = 0;
00664 //       if (1 && fEntryOffset && fNevBuf>=3) {
00665 //          equidist = 1;
00666 //          int dist = fEntryOffset[1]-fEntryOffset[0];
00667 //          int curr = fEntryOffset[1];
00668 //          for (int i=1;i<fNevBuf;i++,curr+=dist) {
00669 //             if (fEntryOffset[i]==curr) continue;
00670 //             equidist = 0;
00671 //             break;
00672 //          }
00673 //          if (equidist) {
00674 //             fNevBufSize=dist;
00675 //             delete [] fEntryOffset; fEntryOffset = 0;
00676 //          }
00677 //           if (equidist) {
00678 //              fprintf(stderr,"detected an equidistant case fNbytes==%d fLast==%d\n",fNbytes,fLast);
00679 //           }
00680 //       }
00681 //  also he add (a little further
00682 //       if (!fEntryOffset || equidist)  flag  = 2;
00683     
00684 //   timer.Stop();
00685 //   Double_t rt1 = timer.RealTime();
00686 //   Double_t cp1 = timer.CpuTime();
00687 //   fprintf(stderr,"equidist cost :  RT=%6.2f s  Cpu=%6.2f s\n",rt1,cp1);
00688 
00689       b << fBufferSize;
00690       b << fNevBufSize;
00691       b << fNevBuf;
00692       b << fLast;
00693       flag = 1;
00694       if (!fEntryOffset)  flag  = 2;
00695       if (fBufferRef)     flag += 10;
00696       if (fDisplacement)  flag += 40;
00697       if (fHeaderOnly)    flag  = 0;
00698       b << flag;
00699       if (fHeaderOnly) return;
00700       if (fEntryOffset && fNevBuf) {
00701          b.WriteArray(fEntryOffset, fNevBuf);
00702          if (fDisplacement) b.WriteArray(fDisplacement, fNevBuf);
00703       }
00704       if (fBufferRef) {
00705          char *buf  = fBufferRef->Buffer();
00706          b.WriteFastArray(buf, fLast);
00707       }
00708    }
00709 }
00710 
00711 //_______________________________________________________________________
00712 void TBasket::Update(Int_t offset, Int_t skipped)
00713 {
00714    // Update basket header and EntryOffset table.
00715 
00716    if (fEntryOffset) {
00717       if (fNevBuf+1 >= fNevBufSize) {
00718          Int_t newsize = TMath::Max(10,2*fNevBufSize);
00719          Int_t *newoff = TStorage::ReAllocInt(fEntryOffset, newsize,
00720                                               fNevBufSize);
00721          if (fDisplacement) {
00722             Int_t *newdisp = TStorage::ReAllocInt(fDisplacement, newsize,
00723                                                   fNevBufSize);
00724             fDisplacement = newdisp;
00725          }
00726          fEntryOffset  = newoff;
00727          fNevBufSize   = newsize;
00728 
00729          //Update branch only for the first 10 baskets
00730          if (fBranch->GetWriteBasket() < 10) {
00731             fBranch->SetEntryOffsetLen(newsize);
00732          }
00733       }
00734       fEntryOffset[fNevBuf] = offset;
00735 
00736       if (skipped!=offset && !fDisplacement){
00737          fDisplacement = new Int_t[fNevBufSize];
00738          for (Int_t i = 0; i<fNevBufSize; i++) fDisplacement[i] = fEntryOffset[i];
00739       }
00740       if (fDisplacement) {
00741          fDisplacement[fNevBuf] = skipped;
00742          fBufferRef->SetBufferDisplacement(skipped);
00743       }
00744    }
00745 
00746    fNevBuf++;
00747 }
00748 
00749 //_______________________________________________________________________
00750 Int_t TBasket::WriteBuffer()
00751 {
00752    // Write buffer of this basket on the current file.
00753    //
00754    // The function returns the number of bytes committed to the memory.
00755    // If a write error occurs, the number of bytes returned is -1.
00756    // If no data are written, the number of bytes returned is 0.
00757    //
00758 
00759    const Int_t kWrite = 1;
00760    TDirectory::TContext ctxt(0);
00761    TFile *file = fBranch->GetFile(kWrite);
00762    if (!file) return 0;
00763    if (!file->IsWritable()) { 
00764       return -1;
00765    }
00766    fMotherDir = file; // fBranch->GetDirectory();
00767    
00768    if (fBufferRef->TestBit(TBufferFile::kNotDecompressed)) {
00769       // Read the basket information that was saved inside the buffer.
00770       Bool_t writing = fBufferRef->IsWriting();
00771       fBufferRef->SetReadMode();
00772       fBufferRef->SetBufferOffset(0);
00773 
00774       Streamer(*fBufferRef);
00775       if (writing) fBufferRef->SetWriteMode();
00776       Int_t nout = fNbytes - fKeylen;
00777 
00778       fBuffer = fBufferRef->Buffer();
00779 
00780       Create(nout,file);
00781       fBufferRef->SetBufferOffset(0);
00782       fHeaderOnly = kTRUE;
00783 
00784       Streamer(*fBufferRef);         //write key itself again
00785       int nBytes = WriteFileKeepBuffer();
00786       fHeaderOnly = kFALSE;
00787       return nBytes>0 ? fKeylen+nout : -1;
00788    }
00789 
00790 //*-*- Transfer fEntryOffset table at the end of fBuffer. Offsets to fBuffer
00791 //     are transformed in entry length to optimize compression algorithm.
00792    fLast      = fBufferRef->Length();
00793    if (fEntryOffset) {
00794       fBufferRef->WriteArray(fEntryOffset,fNevBuf+1);
00795       delete [] fEntryOffset; fEntryOffset = 0;
00796       if (fDisplacement) {
00797          fBufferRef->WriteArray(fDisplacement,fNevBuf+1);
00798          delete [] fDisplacement; fDisplacement = 0;
00799       }
00800    }
00801 
00802    Int_t lbuf, nout, noutot, bufmax, nzip;
00803    lbuf       = fBufferRef->Length();
00804    fObjlen    = lbuf - fKeylen;
00805 
00806    fHeaderOnly = kTRUE;
00807    fCycle = fBranch->GetWriteBasket();
00808    Int_t cxlevel = fBranch->GetCompressionLevel();
00809    if (cxlevel > 0) {
00810       //if (cxlevel == 2) cxlevel--; RB: I cannot remember why we had this!
00811       Int_t nbuffers = fObjlen/kMAXBUF;
00812       Int_t buflen = fKeylen + fObjlen + 28; //add 28 bytes in case object is placed in a deleted gap
00813       if (buflen > fCompressedSize) {
00814          if (fCompressedSize) delete [] fCompressedBuffer;
00815          fCompressedSize = buflen;
00816          fCompressedBuffer = new char[fCompressedSize];
00817       }
00818       fBuffer = fCompressedBuffer;
00819       char *objbuf = fBufferRef->Buffer() + fKeylen;
00820       char *bufcur = &fBuffer[fKeylen];
00821       noutot = 0;
00822       nzip   = 0;
00823       for (Int_t i=0;i<=nbuffers;i++) {
00824          if (i == nbuffers) bufmax = fObjlen -nzip;
00825          else               bufmax = kMAXBUF;
00826          //compress the buffer
00827          R__zip(cxlevel, &bufmax, objbuf, &bufmax, bufcur, &nout);
00828          
00829          // test if buffer has really been compressed. In case of small buffers 
00830          // when the buffer contains random data, it may happen that the compressed
00831          // buffer is larger than the input. In this case, we write the original uncompressed buffer
00832          if (nout == 0 || nout >= fObjlen) {
00833             nout = fObjlen;
00834             // We use do delete fBuffer here, we no longer want to since
00835             // the buffer (held by fCompressedBuffer) might be re-used later.
00836             // delete [] fBuffer;
00837             fBuffer = fBufferRef->Buffer();
00838             Create(fObjlen,file);
00839             fBufferRef->SetBufferOffset(0);
00840 
00841             Streamer(*fBufferRef);         //write key itself again
00842             if ((nout+fKeylen)>buflen) {
00843                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",
00844                   (nout+fKeylen-buflen),buflen,fNbytes,fObjlen,fKeylen);
00845             }
00846             goto WriteFile;
00847          }
00848          bufcur += nout;
00849          noutot += nout;
00850          objbuf += kMAXBUF;
00851          nzip   += kMAXBUF;
00852       }
00853       nout = noutot;
00854       Create(noutot,file);
00855       fBufferRef->SetBufferOffset(0);
00856 
00857       Streamer(*fBufferRef);         //write key itself again
00858       memcpy(fBuffer,fBufferRef->Buffer(),fKeylen);
00859    } else {
00860       fBuffer = fBufferRef->Buffer();
00861       Create(fObjlen,file);
00862       fBufferRef->SetBufferOffset(0);
00863 
00864       Streamer(*fBufferRef);         //write key itself again
00865       nout = fObjlen;
00866    }
00867 
00868 WriteFile:
00869    Int_t nBytes = WriteFileKeepBuffer();
00870    fHeaderOnly = kFALSE;
00871    return nBytes>0 ? fKeylen+nout : -1;
00872 }
00873 

Generated on Tue Jul 5 15:33:33 2011 for ROOT_528-00b_version by  doxygen 1.5.1