#include "TTreeCache.h"
#include "TChain.h"
#include "TList.h"
#include "TBranch.h"
#include "TEventList.h"
#include "TObjString.h"
#include "TRegexp.h"
#include "TLeaf.h"
#include "TFriendElement.h"
#include "TFile.h"
Int_t TTreeCache::fgLearnEntries = 100;
ClassImp(TTreeCache)
TTreeCache::TTreeCache() : TFileCacheRead(),
fEntryMin(0),
fEntryMax(1),
fEntryNext(1),
fZipBytes(0),
fNbranches(0),
fNReadOk(0),
fNReadMiss(0),
fNReadPref(0),
fBranches(0),
fBrNames(0),
fOwner(0),
fTree(0),
fIsLearning(kTRUE),
fIsManual(kFALSE)
{
}
TTreeCache::TTreeCache(TTree *tree, Int_t buffersize) : TFileCacheRead(tree->GetCurrentFile(),buffersize),
fEntryMin(0),
fEntryMax(tree->GetEntriesFast()),
fEntryNext(0),
fZipBytes(0),
fNbranches(0),
fNReadOk(0),
fNReadMiss(0),
fNReadPref(0),
fBranches(0),
fBrNames(new TList),
fOwner(tree),
fTree(0),
fIsLearning(kTRUE),
fIsManual(kFALSE)
{
fEntryNext = fEntryMin + fgLearnEntries;
Int_t nleaves = tree->GetListOfLeaves()->GetEntries();
fBranches = new TObjArray(nleaves);
}
TTreeCache::~TTreeCache()
{
delete fBranches;
if (fBrNames) {fBrNames->Delete(); delete fBrNames; fBrNames=0;}
}
void TTreeCache::AddBranch(TBranch *b, Bool_t subbranches )
{
if (!fIsLearning) return;
if (!b || fOwner->GetTree() != b->GetTree()) return;
Bool_t isNew = kTRUE;
for (int i=0;i<fNbranches;i++) {
if (fBranches->UncheckedAt(i) == b) {isNew = kFALSE; break;}
}
if (isNew) {
fTree = b->GetTree();
fBranches->AddAtAndExpand(b, fNbranches);
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());
}
if (subbranches) {
TObjArray *lb = b->GetListOfBranches();
Int_t nb = lb->GetEntriesFast();
for (Int_t j = 0; j < nb; j++) {
TBranch* branch = (TBranch*) lb->UncheckedAt(j);
if (!branch) continue;
AddBranch(branch, subbranches);
}
}
}
void TTreeCache::AddBranch(const char *bname, Bool_t subbranches )
{
TBranch *branch, *bcount;
TLeaf *leaf, *leafcount;
Int_t i;
Int_t nleaves = (fOwner->GetListOfLeaves())->GetEntriesFast();
TRegexp re(bname,kTRUE);
Int_t nb = 0;
for (i=0;i<nleaves;i++) {
leaf = (TLeaf*)(fOwner->GetListOfLeaves())->UncheckedAt(i);
branch = (TBranch*)leaf->GetBranch();
TString s = branch->GetName();
if (strcmp(bname,"*")) {
TString longname;
longname.Form("%s.%s",fOwner->GetName(),branch->GetName());
if (strcmp(bname,branch->GetName())
&& longname != bname
&& s.Index(re) == kNPOS) continue;
}
nb++;
AddBranch(branch, subbranches);
leafcount = leaf->GetLeafCount();
if (leafcount) {
bcount = leafcount->GetBranch();
AddBranch(bcount, subbranches);
}
}
if (nb==0 && strchr(bname,'*')==0) {
branch = fOwner->GetBranch(bname);
if (branch) {
AddBranch(branch, subbranches);
++nb;
}
}
UInt_t foundInFriend = 0;
if (fOwner->GetListOfFriends()) {
TIter nextf(fOwner->GetListOfFriends());
TFriendElement *fe;
TString name;
while ((fe = (TFriendElement*)nextf())) {
TTree *t = fe->GetTree();
if (t==0) continue;
char *subbranch = (char*)strstr(bname,fe->GetName());
if (subbranch!=bname) subbranch = 0;
if (subbranch) {
subbranch += strlen(fe->GetName());
if ( *subbranch != '.' ) subbranch = 0;
else subbranch ++;
}
if (subbranch) {
name.Form("%s.%s",t->GetName(),subbranch);
} else {
name = bname;
}
AddBranch(name, subbranches);
}
}
if (!nb && !foundInFriend) {
if (gDebug > 0) printf("AddBranch: unknown branch -> %s \n", bname);
return;
}
}
Bool_t TTreeCache::FillBuffer()
{
if (fNbranches <= 0) return kFALSE;
TTree *tree = ((TBranch*)fBranches->UncheckedAt(0))->GetTree();
Long64_t entry = tree->GetReadEntry();
if (!fIsManual && fIsLearning && entry < fEntryNext) return kFALSE;
if (entry == -1) entry=0;
if (fZipBytes==0) {
fEntryNext = entry + tree->GetEntries();;
} else {
fEntryNext = entry + tree->GetEntries()*fBufferSizeMin/fZipBytes;
}
if (fEntryMax <= 0) fEntryMax = tree->GetEntries();
if (fEntryNext > fEntryMax) fEntryNext = fEntryMax+1;
TEventList *elist = fOwner->GetEventList();
Long64_t chainOffset = 0;
if (elist) {
if (fOwner->IsA() ==TChain::Class()) {
TChain *chain = (TChain*)fOwner;
Int_t t = chain->GetTreeNumber();
chainOffset = chain->GetTreeOffset()[t];
}
}
TFileCacheRead::Prefetch(0,0);
Bool_t mustBreak = kFALSE;
for (Int_t i=0;i<fNbranches;i++) {
if (mustBreak) break;
TBranch *b = (TBranch*)fBranches->UncheckedAt(i);
if (b->GetDirectory()==0) continue;
if (b->GetDirectory()->GetFile() != fFile) continue;
Int_t nb = b->GetMaxBaskets();
Int_t *lbaskets = b->GetBasketBytes();
Long64_t *entries = b->GetBasketEntry();
if (!lbaskets || !entries) continue;
Int_t blistsize = b->GetListOfBaskets()->GetSize();
for (Int_t j=0;j<nb;j++) {
if (j<blistsize && b->GetListOfBaskets()->UncheckedAt(j)) continue;
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;
}
fNReadPref++;
TFileCacheRead::Prefetch(pos,len);
if (fNtot > 2*fBufferSizeMin) {TFileCacheRead::Prefetch(0,0);mustBreak = kTRUE; break;}
}
if (gDebug > 0) printf("Entry: %lld, registering baskets branch %s, fEntryNext=%lld, fNseek=%d, fNtot=%d\n",entry,((TBranch*)fBranches->UncheckedAt(i))->GetName(),fEntryNext,fNseek,fNtot);
}
fIsLearning = kFALSE;
if (mustBreak) return kFALSE;
return kTRUE;
}
Double_t TTreeCache::GetEfficiency()
{
if ( !fNReadPref )
return 0;
return ((Double_t)fNReadOk / (Double_t)fNReadPref);
}
Double_t TTreeCache::GetEfficiencyRel()
{
if ( !fNReadOk && !fNReadMiss )
return 0;
return ((Double_t)fNReadOk / (Double_t)(fNReadOk + fNReadMiss));
}
Int_t TTreeCache::GetLearnEntries()
{
return fgLearnEntries;
}
TTree *TTreeCache::GetOwner() const
{
return fOwner;
}
TTree *TTreeCache::GetTree() const
{
if (fNbranches <= 0) return 0;
return ((TBranch*)(fBranches->UncheckedAt(0)))->GetTree();
}
Int_t TTreeCache::ReadBuffer(char *buf, Long64_t pos, Int_t len)
{
if (TFileCacheRead::ReadBuffer(buf,pos,len) == 1){
fNReadOk++;
return 1;
}
Bool_t bufferFilled = FillBuffer();
if (bufferFilled) {
Int_t res = TFileCacheRead::ReadBuffer(buf,pos,len);
if (res == 1)
fNReadOk++;
else if (res == 0)
fNReadMiss++;
return res;
}
fNReadMiss++;
return 0;
}
void TTreeCache::ResetCache()
{
TFileCacheRead::Prefetch(0,0);
}
void TTreeCache::SetEntryRange(Long64_t emin, Long64_t emax)
{
if(fIsManual)
return;
fEntryMin = emin;
fEntryMax = emax;
fEntryNext = fEntryMin + fgLearnEntries;
if (gDebug > 0)
Info("SetEntryRange", "fEntryMin=%lld, fEntryMax=%lld, fEntryNext=%lld",
fEntryMin, fEntryMax, fEntryNext);
if (fIsLearning) {
fIsLearning = kTRUE;
fIsManual = kFALSE;
fNbranches = 0;
fZipBytes = 0;
if (fBrNames) fBrNames->Delete();
}
}
void TTreeCache::SetLearnEntries(Int_t n)
{
if (n < 1) n = 1;
fgLearnEntries = n;
}
void TTreeCache::StartLearningPhase()
{
fIsLearning = kTRUE;
fIsManual = kFALSE;
fNbranches = 0;
fZipBytes = 0;
if (fBrNames) fBrNames->Delete();
fIsTransferred = kFALSE;
}
void TTreeCache::StopLearningPhase()
{
fIsLearning = kFALSE;
fIsManual = kTRUE;
FillBuffer();
if (fNseek > 0 && !fIsSorted) {
Sort();
fFile->ReadBuffers(fBuffer,fPos,fLen,fNb);
fIsTransferred = kTRUE;
}
}
void TTreeCache::UpdateBranches(TTree *tree, Bool_t owner)
{
if (owner) {
fOwner = tree;
SetFile(tree->GetCurrentFile());
}
fTree = tree;
fEntryMin = 0;
fEntryMax = fTree->GetEntries();
fEntryNext = fEntryMin + fgLearnEntries;
if (fBrNames->GetEntries() > 0) {
fIsLearning = kFALSE;
}
fZipBytes = 0;
fNbranches = 0;
TIter next(fBrNames);
TObjString *os;
while ((os = (TObjString*)next())) {
TBranch *b = fTree->GetBranch(os->GetName());
if (!b) {
continue;
}
fBranches->AddAt(b, fNbranches);
fZipBytes += b->GetZipBytes();
fNbranches++;
}
}