#include "TEnv.h"
#include "TFile.h"
#include "TFileCacheRead.h"
#include "TFileCacheWrite.h"
#include "TMath.h"
ClassImp(TFileCacheRead)
TFileCacheRead::TFileCacheRead() : TObject()
{
fBufferSizeMin = 0;
fBufferSize = 0;
fBufferLen = 0;
fNseek = 0;
fNtot = 0;
fNb = 0;
fSeekSize = 0;
fSeek = 0;
fSeekIndex = 0;
fSeekSort = 0;
fPos = 0;
fSeekLen = 0;
fSeekSortLen = 0;
fSeekPos = 0;
fLen = 0;
fFile = 0;
fBuffer = 0;
fIsSorted = kFALSE;
fIsTransferred = kFALSE;
fAsyncReading = kFALSE;
}
TFileCacheRead::TFileCacheRead(TFile *file, Int_t buffersize)
: TObject()
{
if (buffersize <=10000) fBufferSize = 100000;
else fBufferSize = buffersize;
fBufferSizeMin = fBufferSize;
fBufferLen = 0;
fNseek = 0;
fNtot = 0;
fNb = 0;
fSeekSize = 10000;
fSeek = new Long64_t[fSeekSize];
fSeekIndex = new Int_t[fSeekSize];
fSeekSort = new Long64_t[fSeekSize];
fPos = new Long64_t[fSeekSize];
fSeekLen = new Int_t[fSeekSize];
fSeekSortLen = new Int_t[fSeekSize];
fSeekPos = new Int_t[fSeekSize];
fLen = new Int_t[fSeekSize];
fFile = file;
fBuffer = 0;
fAsyncReading = gEnv->GetValue("TFile.AsyncReading", 1);
if (fAsyncReading) {
fAsyncReading = kFALSE;
if (file && !(file->ReadBufferAsync(0, 0)))
fAsyncReading = kTRUE;
}
if (!fAsyncReading) {
fBuffer = new char[fBufferSize];
}
fIsSorted = kFALSE;
fIsTransferred = kFALSE;
if (file) file->SetCacheRead(this);
}
TFileCacheRead::~TFileCacheRead()
{
delete [] fSeek;
delete [] fSeekIndex;
delete [] fSeekSort;
delete [] fPos;
delete [] fSeekLen;
delete [] fSeekSortLen;
delete [] fSeekPos;
delete [] fLen;
delete [] fBuffer;
}
void TFileCacheRead::Prefetch(Long64_t pos, Int_t len)
{
fIsSorted = kFALSE;
fIsTransferred = kFALSE;
if (pos <= 0) {
fNseek = 0;
fNtot = 0;
return;
}
if (fNseek >= fSeekSize) {
fSeekSize *= 2;
Long64_t *aSeek = new Long64_t[fSeekSize];
Int_t *aSeekIndex = new Int_t[fSeekSize];
Long64_t *aSeekSort = new Long64_t[fSeekSize];
Long64_t *aPos = new Long64_t[fSeekSize];
Int_t *aSeekLen = new Int_t[fSeekSize];
Int_t *aSeekSortLen = new Int_t[fSeekSize];
Int_t *aSeekPos = new Int_t[fSeekSize];
Int_t *aLen = new Int_t[fSeekSize];
for (Int_t i=0;i<fNseek;i++) {
aSeek[i] = fSeek[i];
aSeekIndex[i] = fSeekIndex[i];
aSeekSort[i] = fSeekSort[i];
aPos[i] = fPos[i];
aSeekLen[i] = fSeekLen[i];
aSeekSortLen[i] = fSeekSortLen[i];
aSeekPos[i] = fSeekPos[i];
aLen[i] = fLen[i];
}
delete [] fSeek;
delete [] fSeekIndex;
delete [] fSeekSort;
delete [] fPos;
delete [] fSeekLen;
delete [] fSeekSortLen;
delete [] fSeekPos;
delete [] fLen;
fSeek = aSeek;
fSeekIndex = aSeekIndex;
fSeekSort = aSeekSort;
fPos = aPos;
fSeekLen = aSeekLen;
fSeekSortLen = aSeekSortLen;
fSeekPos = aSeekPos;
fLen = aLen;
}
fSeek[fNseek] = pos;
fSeekLen[fNseek] = len;
fNseek++;
fNtot += len;
}
void TFileCacheRead::Print(Option_t *option) const
{
TString opt = option;
opt.ToLower();
printf("******TreeCache statistics for file: %s ******\n",fFile->GetName());
printf("Reading %lld bytes in %d transactions\n",fFile->GetBytesRead(), fFile->GetReadCalls());
printf("Readahead = %d bytes with overhead = %lld bytes\n",TFile::GetReadaheadSize(),fFile->GetBytesReadExtra());
printf("Average transaction = %f Kbytes\n",0.001*Double_t(fFile->GetBytesRead())/Double_t(fFile->GetReadCalls()));
printf("Number of blocks in current cache: %d, total size : %d\n",fNseek,fNtot);
if (!opt.Contains("a")) return;
for (Int_t i=0;i<fNseek;i++) {
if (fIsSorted && !opt.Contains("s")) {
printf("block: %5d, from: %lld to %lld, len=%d bytes\n",i,fSeekSort[i],fSeekSort[i]+fSeekSortLen[i],fSeekSortLen[i]);
} else {
printf("block: %5d, from: %lld to %lld, len=%d bytes\n",i,fSeek[i],fSeek[i]+fSeekLen[i],fSeekLen[i]);
}
}
printf ("Number of long buffers = %d\n",fNb);
for (Int_t j=0;j<fNb;j++) {
printf("fPos[%d]=%lld, fLen=%d\n",j,fPos[j],fLen[j]);
}
}
Int_t TFileCacheRead::ReadBuffer(char *buf, Long64_t pos, Int_t len)
{
Int_t loc = -1;
return ReadBufferExt(buf, pos, len, loc);
}
Int_t TFileCacheRead::ReadBufferExt(char *buf, Long64_t pos, Int_t len, Int_t &loc)
{
if (fNseek > 0 && !fIsSorted) {
Sort();
loc = -1;
if (!fAsyncReading) {
if (fFile->ReadBuffers(fBuffer,fPos,fLen,fNb)) {
return -1;
}
fIsTransferred = kTRUE;
} else {
fFile->ReadBuffers(0, 0, 0, 0);
if (fFile->ReadBuffers(0,fPos,fLen,fNb)) {
return -1;
}
fIsTransferred = kTRUE;
}
}
if (TFileCacheWrite *cachew = fFile->GetCacheWrite()) {
if (cachew->ReadBuffer(buf,pos,len) == 0) {
fFile->Seek(pos+len);
return 1;
}
}
if (fAsyncReading) {
Int_t retval;
if (loc < 0)
loc = (Int_t)TMath::BinarySearch(fNseek,fSeekSort,pos);
if (loc >= 0 && loc < fNseek && pos == fSeekSort[loc]) {
if (buf) {
fFile->Seek(pos);
if (fFile->ReadBuffer(buf, len)) {
return -1;
}
fFile->Seek(pos+len);
}
retval = 1;
} else {
retval = 0;
}
if (gDebug > 0)
Info("ReadBuffer","pos=%lld, len=%d, retval=%d, loc=%d, fseekSort[loc]=%d, fSeekLen[loc]=%d", pos, len, retval, loc, fSeekSort[loc], fSeekLen[loc]);
return retval;
} else {
if (loc < 0)
loc = (Int_t)TMath::BinarySearch(fNseek,fSeekSort,pos);
if (loc >= 0 && loc <fNseek && pos == fSeekSort[loc]) {
if (buf) {
memcpy(buf,&fBuffer[fSeekPos[loc]],len);
fFile->Seek(pos+len);
}
return 1;
}
}
return 0;
}
void TFileCacheRead::SetFile(TFile *file)
{
fFile = file;
if (fAsyncReading) {
if (file && file->ReadBufferAsync(0, 0)) {
fAsyncReading = kFALSE;
fBuffer = new char[fBufferSize];
}
}
Prefetch(0,0);
}
void TFileCacheRead::Sort()
{
if (!fNseek) return;
TMath::Sort(fNseek,fSeek,fSeekIndex,kFALSE);
Int_t i;
Int_t nb = 0;
for (i=0;i<fNseek;i++) {
Int_t ind = fSeekIndex[i];
fSeekSort[i] = fSeek[ind];
fSeekSortLen[i] = fSeekLen[ind];
}
if (fNtot > fBufferSizeMin) {
fBufferSize = fNtot + 100;
delete [] fBuffer;
fBuffer = 0;
if (!fAsyncReading)
fBuffer = new char[fBufferSize];
}
fPos[0] = fSeekSort[0];
fLen[0] = fSeekSortLen[0];
fSeekPos[0] = 0;
for (i=1;i<fNseek;i++) {
fSeekPos[i] = fSeekPos[i-1] + fSeekSortLen[i-1];
if ((fSeekSort[i] != fSeekSort[i-1]+fSeekSortLen[i-1]) ||
(fLen[nb] > 2000000)) {
nb++;
fPos[nb] = fSeekSort[i];
fLen[nb] = fSeekSortLen[i];
} else {
fLen[nb] += fSeekSortLen[i];
}
}
fNb = nb+1;
fIsSorted = kTRUE;
}