// @(#)root/tree:$Name:  $:$Id: TTreeFilePrefetch.cxx,v 1.12 2006/06/19 09:35:45 brun Exp $
// Author: Rene Brun   04/06/2006

/*************************************************************************
 * Copyright (C) 1995-2000, Rene Brun and Fons Rademakers.               *
 * All rights reserved.                                                  *
 *                                                                       *
 * For the licensing terms see $ROOTSYS/LICENSE.                         *
 * For the list of contributors see $ROOTSYS/README/CREDITS.             *
 *************************************************************************/

//////////////////////////////////////////////////////////////////////////
//                                                                      //
// TTreeFilePrefetch                                                    //
//                                                                      //
//  A specialized TFilePrefetch object for a TTree                      //
//  This class acts as a file cache, registering automatically the      //
//  baskets from the branches being processed (TTree::Draw or           //
//  TTree::Process and TSelectors) when in the learning phase.          //
//  The learning phase is by default 100 entries.                       //
//  It can be changed via TTreeFileFrefetch::SetLearnEntries.           //
//                                                                      //
//  This cache speeds-up considerably the performance, in particular    //
//  when the Tree is accessed remotely via a high latency network.      //
//                                                                      //
//  The default cache size (10 Mbytes) may be changed via the function  //
//      TTreeFilePrefetch::SetCacheSize                                 //
//                                                                      //
//  Only the baskets for the requested entry range are put in the cache //
//                                                                      //
//  For each Tree being processed a TTreeFilePrefetch object is created.//
//  This object is automatically deleted when the Tree is deleted or    //
//  when the file is deleted.                                           //
//                                                                      //
//  -Special case of a TChain                                           //
//   Once the training is done on the first Tree, the list of branches  //
//   in the cache is kept for the following files.                      //
//                                                                      //
//  -Special case of a TEventlist                                       //
//   if the Tree or TChain has a TEventlist, only the buffers           //
//   referenced by the list are put in the cache.                       //
//                                                                      //
//////////////////////////////////////////////////////////////////////////

#include "TTreeFilePrefetch.h"
#include "TChain.h"
#include "TBranch.h"
#include "TEventList.h"
#include "TObjString.h"

Int_t TTreeFilePrefetch::fgLearnEntries = 100;

ClassImp(TTreeFilePrefetch)

//______________________________________________________________________________
 TTreeFilePrefetch::TTreeFilePrefetch() : TFilePrefetch(),
   fEntryMin(0),
   fEntryMax(1),
   fEntryNext(1),
   fZipBytes(0),
   fNbranches(0),
   fBranches(0),
   fBrNames(0),
   fOwner(0),
   fTree(0),
   fIsLearning(kTRUE)
{
   // Default Constructor.
}

//______________________________________________________________________________
 TTreeFilePrefetch::TTreeFilePrefetch(TTree *tree, Int_t buffersize) : TFilePrefetch(tree->GetCurrentFile(),buffersize),
   fEntryMin(0),
   fEntryMax(tree->GetEntriesFast()),
   fEntryNext(0),
   fZipBytes(0),
   fNbranches(0),
   fBranches(0),
   fBrNames(new TList),
   fOwner(tree),
   fTree(0),
   fIsLearning(kTRUE)
{
   // Constructor.
   
   fEntryNext = fEntryMin + fgLearnEntries;
   Int_t nleaves = tree->GetListOfLeaves()->GetEntries();
   fBranches = new TBranch*[nleaves+10]; //add a margin just in case in a TChain?
}

//______________________________________________________________________________
 TTreeFilePrefetch::TTreeFilePrefetch(const TTreeFilePrefetch &pf) : TFilePrefetch(pf)
{
   // Copy Constructor.
}

//______________________________________________________________________________
 TTreeFilePrefetch::~TTreeFilePrefetch()
{
   // destructor. (in general called by the TFile destructor
   
   delete [] fBranches;
   if (fBrNames) {fBrNames->Delete(); delete fBrNames;}
}

//______________________________________________________________________________
TTreeFilePrefetch& TTreeFilePrefetch::operator=(const TTreeFilePrefetch& pf)
{
   // Assignment.

   if (this != &pf) TFilePrefetch::operator=(pf);
   return *this;
}         

//_____________________________________________________________________________
 void TTreeFilePrefetch::AddBranch(TBranch *b)
{
   //add a branch to the list of branches to be stored in the cache
   //this function is called by TBranch::GetBasket
      
   if (!fIsLearning) return;

   //Is branch already in the cache?
   Bool_t isNew = kTRUE;
   for (int i=0;i<fNbranches;i++) {
      if (fBranches[i] == b) {isNew = kFALSE; break;}
   }
   if (isNew) {
      fTree = b->GetTree();
      fBranches[fNbranches] = b;
      fBrNames->Add(new TObjString(b->GetName()));
      fZipBytes += b->GetZipBytes();
      fNbranches++;
      if (gDebug > 0) printf("Entry: %lld, registering branch: %s\n",b->GetTree()->GetReadEntry(),b->GetName());
   }
}

//_____________________________________________________________________________
 Bool_t TTreeFilePrefetch::FillBuffer()
{
   //Fill the cache buffer with the branchse in the cache
   
   if (fNbranches <= 0) return kFALSE;
   TTree *tree = fBranches[0]->GetTree();
   Long64_t entry = tree->GetReadEntry();
   if (entry < fEntryNext) return kFALSE;
   
   //estimate number of entries that can fit in the cache
   fEntryNext = entry + tree->GetEntries()*fBufferSize/fZipBytes;
   if (fEntryNext > fEntryMax) fEntryNext = fEntryMax+1;

   //check if owner has a TEventList set. If yes we optimize for this special case
   //reading only the baskets containing entries in the list
   TEventList *elist = fOwner->GetEventList();
   Long64_t chainOffset = 0;
   if (elist) {
      fEntryNext = fTree->GetEntries();
      if (fOwner->IsA() ==TChain::Class()) {
         TChain *chain = (TChain*)fOwner;
         Int_t t = chain->GetTreeNumber();
         chainOffset = chain->GetTreeOffset()[t];
      }
   }
           
   //clear cache buffer
   TFilePrefetch::Prefetch(0,0);
   //store baskets
   for (Int_t i=0;i<fNbranches;i++) {
      TBranch *b = fBranches[i];
      Int_t nb = b->GetMaxBaskets();
      Int_t *lbaskets   = b->GetBasketBytes();
      Long64_t *entries = b->GetBasketEntry();
      if (!lbaskets || !entries) continue;
      //we have found the branch. We now register all its baskets
      //from the requested offset to the basket below fEntrymax
      for (Int_t j=0;j<nb;j++) {
         Long64_t pos = b->GetBasketSeek(j);
         Int_t len = lbaskets[j];
         if (pos <= 0 || len <= 0) continue;
         if (entries[j] > fEntryNext) continue;
         if (entries[j] < entry && (j<nb-1 && entries[j+1] < entry)) continue;
         if (elist) {
            Long64_t emax = fEntryMax;
            if (j<nb-1) emax = entries[j+1]-1;
            if (!elist->ContainsRange(entries[j]+chainOffset,emax+chainOffset)) continue;
         }
         TFilePrefetch::Prefetch(pos,len);
      }
      if (gDebug > 0) printf("Entry: %lld, registering baskets branch %s, fEntryNext=%lld, fNseek=%d, fNtot=%d\n",entry,fBranches[i]->GetName(),fEntryNext,fNseek,fNtot);
   }
   fIsLearning = kFALSE;
   return kTRUE;
}


//_____________________________________________________________________________
 Int_t TTreeFilePrefetch::GetLearnEntries()
{
   //static function returning the number of entries used to train the cache
   //see SetLearnEntries
   
   return fgLearnEntries;
}

//_____________________________________________________________________________
 TTree *TTreeFilePrefetch::GetTree() const
{
   //return Tree in the cache
   if (fNbranches <= 0) return 0;
   return fBranches[0]->GetTree();
}

//_____________________________________________________________________________
 Bool_t TTreeFilePrefetch::ReadBuffer(char *buf, Long64_t pos, Int_t len)
{
   // Read buffer at position pos.
   // If pos is in the list of prefetched blocks read from fBuffer,
   // then try to fill the cache from the list of selected branches,
   // otherwise normal read from file. Returns kTRUE in case of failure.
   // This function overloads TFilePrefetch::ReadBuffer.
   // It returns kFALSE if the requested block is in the cache
   
   //Is request already in the cache?
   Bool_t inCache = !TFilePrefetch::ReadBuffer(buf,pos,len);
   if (inCache) return kFALSE;
   
   //not found in cache. Do we need to fill the cache?
   Bool_t bufferFilled = FillBuffer();
   if (bufferFilled) return TFilePrefetch::ReadBuffer(buf,pos,len);
   return kTRUE;
}

//_____________________________________________________________________________
 void TTreeFilePrefetch::SetEntryRange(Long64_t emin, Long64_t emax)
{
   // Set the minimum and maximum entry number to be processed
   // this information helps to optimize the number of baskets to read
   // when prefetching the branch buffers.
   
   fEntryMin  = emin;
   fEntryMax  = emax;
   fEntryNext  = fEntryMin + fgLearnEntries;
   fIsLearning = kTRUE;
   fNbranches  = 0;
   fZipBytes   = 0;
   if (fBrNames) fBrNames->Delete();
   if (gDebug > 0) printf("SetEntryRange: fEntryMin=%lld, fEntryMax=%lld, fEntryNext=%lld\n",fEntryMin,fEntryMax,fEntryNext);
   
}

//_____________________________________________________________________________
 void TTreeFilePrefetch::SetLearnEntries(Int_t n)
{
   // Static function to set the number of entries to be used in learning mode
   // The default value for n is 10. n must be >= 1
   
   if (n < 1) n = 1;
   fgLearnEntries = n;
}

//_____________________________________________________________________________
 void TTreeFilePrefetch::UpdateBranches(TTree *tree)
{
   //update pointer to current Tree and recompute pointers to the branches in the cache
   
   fTree = tree;
   Prefetch(0,0);

   fEntryMin  = 0;
   fEntryMax  = fTree->GetEntries();
   fEntryNext = fEntryMin + fgLearnEntries;
   fZipBytes  = 0;
   fNbranches = 0;
   TIter next(fBrNames);
   TObjString *os;
   while ((os = (TObjString*)next())) {
      TBranch *b = fTree->GetBranch(os->GetName());
      if (!b) continue;
      fBranches[fNbranches] = b;
      fZipBytes   += b->GetZipBytes();
      fNbranches++;
   }
}


ROOT page - Class index - Class Hierarchy - Top of the page

This page has been automatically generated. If you have any comments or suggestions about the page layout send a mail to ROOT support, or contact the developers with any questions or problems regarding ROOT.