// @(#)root/base:$Name: $:$Id: TKey.cxx,v 1.6 2000/09/12 06:43:53 brun Exp $
// Author: Rene Brun 28/12/94
/*************************************************************************
* 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. *
*************************************************************************/
//////////////////////////////////////////////////////////////////////////
// //
// The TKey class includes functions to book space on a file, //
// to create I/O buffers, to fill these buffers //
// to compress/uncompress data buffers. //
// //
// Before saving (making persistent) an object on a file, a key must //
// be created. The key structure contains all the information to //
// uniquely identify a persistent object on a file. //
// fNbytes = number of bytes for the compressed object+key //
// fObjlen = Length of uncompressed object //
// fDatime = Date/Time when the object was written //
// fKeylen = number of bytes for the key structure //
// fCycle = cycle number of the object //
// fSeekKey = Address of the object on file (points to fNbytes) //
// This is a redundant information used to cross-check //
// the data base integrity. //
// fSeekPdir = Pointer to the directory supporting this object //
// fClassName = Object class name //
// fName = name of the object //
// fTitle = title of the object //
// //
// The TKey class is used by ROOT to: //
// - to write an object in the Current Directory //
// - to write a new ntuple buffer //
// //
// The structure of a file is shown in TFile::TFile //
// The structure of a directory is shown in TDirectory::TDirectory //
// The TKey class is used by the TBasket class //
// See also TTree //
// //
//////////////////////////////////////////////////////////////////////////
#include <iostream.h>
#include "TROOT.h"
#include "TClass.h"
#include "TDirectory.h"
#include "TFile.h"
#include "TKey.h"
#include "TFree.h"
#include "TBrowser.h"
#include "Bytes.h"
extern "C" void R__zip (Int_t cxlevel, Int_t *nin, char *bufin, Int_t *lout, char *bufout, Int_t *nout);
extern "C" void R__unzip(Int_t *nin, UChar_t *bufin, Int_t *lout, char *bufout, Int_t *nout);
const Int_t kMAXFILEBUFFER = 262144;
const Int_t kMAXBUF = 0xffffff;
ClassImp(TKey)
//______________________________________________________________________________
TKey::TKey() : TNamed(), fDatime((UInt_t)0)
{
//*-*-*-*-*-*-*-*-*-*-*TKey default constructor*-*-*-*-*-*-*-*-*-*-*-*-*
//*-* ========================
fSeekKey = 0;
fNbytes = 0;
fBuffer = 0;
fKeylen = Sizeof();
fObjlen = 0;
fBufferRef = 0;
fCycle = 0;
fSeekPdir = 0;
}
//______________________________________________________________________________
TKey::TKey(Seek_t pointer, Int_t nbytes) : TNamed()
{
//*-*-*-*-*-*-*-*-*-*-*-*-*Create a TKey object to read keys*-*-*-*-*-*-*-*
//*-* =================================
// Constructor called by TDirectory::ReadKeys and by TFile::TFile
// A TKey object is created to read the keys structure itself
//
fSeekKey = pointer;
fNbytes = nbytes;
fBuffer = new char[nbytes];
fKeylen = 0;
fObjlen = 0;
fBufferRef = 0;
fCycle = 0;
fSeekPdir = 0;
}
//______________________________________________________________________________
TKey::TKey(const char *name, const char *title, TClass *cl, Int_t nbytes)
: TNamed(name,title)
{
fClassName = cl->GetName();
fNbytes = 0;
fBuffer = 0;
fKeylen = Sizeof();
fObjlen = nbytes;
fBufferRef = 0;
fCycle = 0;
Create(nbytes);
}
//______________________________________________________________________________
TKey::TKey(const TString &name, const TString &title, TClass *cl, Int_t nbytes)
: TNamed(name,title)
{
fClassName = cl->GetName();
fNbytes = 0;
fBuffer = 0;
fKeylen = Sizeof();
fObjlen = nbytes;
fBufferRef = 0;
fCycle = 0;
Create(nbytes);
}
//______________________________________________________________________________
TKey::TKey(TObject *obj, const char *name, const Int_t bufsize)
: TNamed(name, obj->GetTitle())
{
//*-*-*-*-*-*-*-*-*-*Create a TKey object and fill output buffer*-*-*-*-*-*-*
//*-* ===========================================
Int_t lbuf, nout, noutot, bufmax, nzip;
fClassName = obj->ClassName();
fNbytes = 0;
fBuffer = 0;
fBufferRef = new TBuffer(TBuffer::kWrite, bufsize);
fCycle = gDirectory->AppendKey(this);
fObjlen = 0 ; // RDK: Must initialize before calling Streamer()
fKeylen = 0 ; // RDK: Must initialize before calling Streamer()
fSeekKey = 0 ; // RDK: Must initialize before calling Streamer()
fSeekPdir = 0 ; // RDK: Must initialize before calling Streamer()
Streamer(*fBufferRef); //write key itself
fKeylen = fBufferRef->Length();
fBufferRef->MapObject(obj); //register obj in map in case of self reference
obj->Streamer(*fBufferRef); //write object
lbuf = fBufferRef->Length();
fObjlen = lbuf - fKeylen;
Int_t cxlevel = gFile->GetCompressionLevel();
if (cxlevel && fObjlen > 256) {
if (cxlevel == 2) cxlevel--;
Int_t nbuffers = fObjlen/kMAXBUF;
Int_t buflen = TMath::Max(512,fKeylen + fObjlen + 9*nbuffers + 8); //add 8 bytes in case object is placed in a deleted gap
fBuffer = new char[buflen];
char *objbuf = fBufferRef->Buffer() + fKeylen;
char *bufcur = &fBuffer[fKeylen];
noutot = 0;
nzip = 0;
for (Int_t i=0;i<=nbuffers;i++) {
if (i == nbuffers) bufmax = fObjlen -nzip;
else bufmax = kMAXBUF;
R__zip(cxlevel, &bufmax, objbuf, &bufmax, bufcur, &nout);
if (nout == 0) { //this happens when the buffer cannot be compressed
fBuffer = fBufferRef->Buffer();
Create(fObjlen);
fBufferRef->SetBufferOffset(0);
Streamer(*fBufferRef); //write key itself again
return;
}
bufcur += nout;
noutot += nout;
objbuf += kMAXBUF;
nzip += kMAXBUF;
}
Create(noutot);
fBufferRef->SetBufferOffset(0);
Streamer(*fBufferRef); //write key itself again
memcpy(fBuffer,fBufferRef->Buffer(),fKeylen);
delete fBufferRef; fBufferRef = 0;
} else {
fBuffer = fBufferRef->Buffer();
Create(fObjlen);
fBufferRef->SetBufferOffset(0);
Streamer(*fBufferRef); //write key itself again
}
}
//______________________________________________________________________________
void TKey::Browse(TBrowser *b)
{
// Read object from disk and call its Browse() method.
// If object with same name already exist in memory delete it (like
// TDirectory::Get() is doing), except when the key references a
// folder in which case we don't want to re-read the folder object
// since it might contain new objects not yet saved.
// check that key points to the current dir
if (fSeekPdir != gDirectory->GetSeekDir()) {
Error("Browse"," Key: %s is not in the current directory: %s",GetName(),gDirectory->GetName());
return;
}
TObject *obj = gDirectory->GetList()->FindObject(GetName());
if (obj && !obj->IsFolder()) {
if (obj->InheritsFrom(TCollection::Class()))
obj->Delete(); // delete also collection elements
delete obj;
obj = 0;
}
if (!obj)
obj = ReadObj();
if (b && obj) {
obj->Browse(b);
b->SetRefreshFlag(kTRUE);
}
}
//______________________________________________________________________________
void TKey::Create(Int_t nbytes)
{
//*-*-*-*-*-*-*-*-*-*-*-*-*Create a TKey object *-*-*-*-*-*-*-*-*-*-*-*-*-*
//*-* ====================
//*-*-------------------find free segment
//*-* =================
Int_t nsize = nbytes + fKeylen;
TFree *f1 = (TFree*) gFile->GetListOfFree()->First();
TFree *bestfree = f1->GetBestFree(nsize);
if (bestfree == 0) {
Error("Create","Cannot allocate %d bytes for ID = %s Title = %s",
nsize,GetName(),GetTitle());
return;
}
fDatime.Set();
fSeekKey = bestfree->GetFirst();
//*-*----------------- Case Add at the end of the file
if (fSeekKey == gFile->GetEND()) {
gFile->SetEND(fSeekKey+nsize);
bestfree->SetFirst(fSeekKey+nsize);
fLeft = -1;
if (!fBuffer) fBuffer = new char[nsize];
} else {
fLeft = Int_t(bestfree->GetLast() - fSeekKey - nsize + 1);
}
//*-*----------------- Case where new object fills exactly a deleted gap
fNbytes = nsize;
if (fLeft == 0) {
if (!fBuffer) {
fBuffer = new char[nsize];
}
gFile->GetListOfFree()->Remove(bestfree);
delete bestfree;
}
//*-*----------------- Case where new object is placed in a deleted gap larger than itself
if (fLeft > 0) { // found a bigger segment
if (!fBuffer) {
fBuffer = new char[nsize+sizeof(Int_t)];
}
char *buffer = fBuffer+nsize;
Int_t nbytesleft = -fLeft; // set header of remaining record
tobuf(buffer, nbytesleft);
bestfree->SetFirst(fSeekKey+nsize);
}
fSeekPdir = gDirectory->GetSeekDir();
}
//______________________________________________________________________________
TKey::~TKey()
{
//*-*-*-*-*-*-*-*-*-*-*TKey default destructor*-*-*-*-*-*-*-*-*-*-*-*-*
//*-* =======================
// delete [] fBuffer; fBuffer = 0;
// delete fBufferRef; fBufferRef = 0;
DeleteBuffer();
}
//______________________________________________________________________________
void TKey::Delete(Option_t *option)
{
//*-*-*-*-*-*-*-*-*-*-*-*Delete an object from the file*-*-*-*-*-*-*-*-*-*-*
//*-* ==============================
// Note: the key is not deleted. You still have to call "delete key".
// This is different from the behaviour of TObject::Delete()!
if (option && option[0] == 'v') printf("Deleting key: %s at address %d, nbytes = %dn",GetName(),fSeekKey,fNbytes);
Seek_t first = fSeekKey;
Seek_t last = fSeekKey + fNbytes -1;
gFile->MakeFree(first, last); // release space used by this key
gDirectory->GetListOfKeys()->Remove(this);
}
//______________________________________________________________________________
void TKey::DeleteBuffer()
{
//*-*-*-*-*-*-*-*-*-*-*-*Delete key buffer(s)*-*-*-*-*-*-*-*-*-*-*-*-*-*-*
//*-* ====================
if (fBufferRef) {
delete fBufferRef;
fBufferRef = 0;
} else {
if (fBuffer) delete [] fBuffer;
}
fBuffer = 0;
}
//______________________________________________________________________________
Short_t TKey::GetCycle()
{
//*-*-*-*-*-*-*-*-*-*-*-*-*Return cycle number associated to this key*-*-*-*
//*-* ==========================================
return ((fCycle >0) ? fCycle : -fCycle);
}
//______________________________________________________________________________
Short_t TKey::GetKeep()
{
//*-*-*-*-*-*-*-*-*-*-*-*-*Returns the "KEEP" status*-*-*-*-*-*-*-*-*-*-*-*
//*-* =========================
return ((fCycle >0) ? 0 : 1);
}
//______________________________________________________________________________
void TKey::FillBuffer(char *&buffer)
{
//*-*-*-*-*-*-*-*-*-*-*-*Encode key header into output buffer-*-*-*-*-*-*-*
//*-* ====================================
tobuf(buffer, fNbytes);
Version_t version = TKey::Class_Version();
tobuf(buffer, version);
tobuf(buffer, fObjlen);
fDatime.FillBuffer(buffer);
tobuf(buffer, fKeylen);
tobuf(buffer, fCycle);
tobuf(buffer, fSeekKey);
tobuf(buffer, fSeekPdir);
fClassName.FillBuffer(buffer);
fName.FillBuffer(buffer);
fTitle.FillBuffer(buffer);
}
//______________________________________________________________________________
Bool_t TKey::IsFolder() const
{
Bool_t ret = kFALSE;
TClass *classPtr = gROOT->GetClass( (const char * ) fClassName );
if( classPtr ) {
TObject *obj = ( TObject * ) classPtr->New();
if( obj ) {
ret = obj->IsFolder();
delete obj;
}
}
return( ret );
}
//______________________________________________________________________________
void TKey::Keep()
{
//*-*-*-*-*-*-*-*-*-*-*-*-*Set the "KEEP" status*-*-*-*-*-*-*-*-*-*-*-*-*-*
//*-* =====================
// When the KEEP flag is set to 1 the object cannot be purged
//
if (fCycle >0) fCycle = -fCycle;
}
//______________________________________________________________________________
void TKey::ls(Option_t *)
{
//*-*-*-*-*-*-*-*-*-*-*-*-*List Key contents-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*
//*-* =================
TROOT::IndentLevel();
cout <<"KEY: "<<fClassName<<"t"<<GetName()<<";"<<GetCycle()<<"t"<<GetTitle()<<endl;
}
//______________________________________________________________________________
void TKey::Print(Option_t *)
{
//*-*-*-*-*-*-*-*-*-*-*-*-*Print key contents*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*
//*-* ==================
printf("TKey Name = %s, Title = %s, Cycle = %dn",GetName(),GetTitle(),GetCycle());
}
//______________________________________________________________________________
TObject *TKey::ReadObj()
{
//*-*-*-*-*-*-*-*-*-*-*-*-*To read an object from the file*-*-*-*-*-*-*-*-*
//*-* ===============================
// The object associated to this key is read from the file into memory
// Once the key structure is read (via Streamer) the class identifier
// of the object is known.
// Using the class identifier we find the TClass object for this class.
// A TClass object contains a full description (i.e. dictionary) of the
// associated class. In particular the TClass object can create a new
// object of the class type it describes. This new object now calls its
// Streamer function to rebuilt itself.
//
fBufferRef = new TBuffer(TBuffer::kRead, fObjlen+fKeylen);
if (!fBufferRef) {
Error("ReadObj", "Cannot allocate buffer: fObjlen = %d", fObjlen);
return 0;
}
if (fObjlen > fNbytes-fKeylen) {
fBuffer = new char[fNbytes];
ReadFile(); //Read object structure from file
memcpy(fBufferRef->Buffer(),fBuffer,fKeylen);
} else {
fBuffer = fBufferRef->Buffer();
ReadFile(); //Read object structure from file
}
// get version of key
fBufferRef->SetBufferOffset(sizeof(fNbytes));
Version_t kvers = fBufferRef->ReadVersion();
fBufferRef->SetBufferOffset(fKeylen);
TObject *obj = 0;
TDirectory *cursav = gDirectory;
TClass *cl = gROOT->GetClass(fClassName.Data());
if (!cl) {
Error("ReadObj", "Unknown class %s", fClassName.Data());
return 0;
}
// Create an instance of this class
obj = (TObject*)cl->New();
if (!obj) {
Error("ReadObj", "Cannot create new object of class %s", fClassName.Data());
return 0;
}
if (kvers > 1)
fBufferRef->MapObject(obj); //register obj in map to handle self reference
if (fObjlen > fNbytes-fKeylen) {
char *objbuf = fBufferRef->Buffer() + fKeylen;
UChar_t *bufcur = (UChar_t *)&fBuffer[fKeylen];
Int_t nin, nout, nbuf;
Int_t noutot = 0;
while (1) {
nin = 9 + ((Int_t)bufcur[3] | ((Int_t)bufcur[4] << 8) | ((Int_t)bufcur[5] << 16));
nbuf = (Int_t)bufcur[6] | ((Int_t)bufcur[7] << 8) | ((Int_t)bufcur[8] << 16);
R__unzip(&nin, bufcur, &nbuf, objbuf, &nout);
if (!nout) break;
noutot += nout;
if (noutot >= fObjlen) break;
bufcur += nin;
objbuf += nout;
}
if (nout) obj->Streamer(*fBufferRef);
delete [] fBuffer;
} else {
obj->Streamer(*fBufferRef);
}
if (gROOT->GetForceStyle()) obj->UseCurrentStyle();
if (obj->IsA() == TDirectory::Class()) {
TDirectory *dir = (TDirectory*)obj;
dir->SetName(GetName());
dir->SetTitle(GetTitle());
gDirectory->Append(dir);
}
delete fBufferRef;
fBufferRef = 0;
fBuffer = 0;
gDirectory = cursav;
return obj;
}
//______________________________________________________________________________
Int_t TKey::Read(TObject *obj)
{
//*-*-*-*-*-*-*-*-*-*-*-*-*To read an object from the file*-*-*-*-*-*-*-*-*
//*-* ===============================
// The object associated to this key is read from the file into memory
// Before invoking this function, obj has been created via the
// default constructor.
//
if (!obj) return 0;
fBufferRef = new TBuffer(TBuffer::kRead, fObjlen+fKeylen);
if (fVersion > 1)
fBufferRef->MapObject(obj); //register obj in map to handle self reference
if (fObjlen > fNbytes-fKeylen) {
fBuffer = new char[fNbytes];
ReadFile(); //Read object structure from file
memcpy(fBufferRef->Buffer(),fBuffer,fKeylen);
} else {
fBuffer = fBufferRef->Buffer();
ReadFile(); //Read object structure from file
}
fBufferRef->SetBufferOffset(fKeylen);
TDirectory *cursav = gDirectory;
if (fObjlen > fNbytes-fKeylen) {
char *objbuf = fBufferRef->Buffer() + fKeylen;
UChar_t *bufcur = (UChar_t *)&fBuffer[fKeylen];
Int_t nin = fNbytes-fKeylen;
Int_t nout;
R__unzip(&nin, bufcur, &fObjlen, objbuf, &nout);
if (nout != fObjlen) Error("Read", "fObjlen = %d, nout = %d", fObjlen, nout);
obj->Streamer(*fBufferRef);
delete [] fBuffer;
} else {
obj->Streamer(*fBufferRef);
}
delete fBufferRef;
fBufferRef = 0;
fBuffer = 0;
gDirectory = cursav;
return fNbytes;
}
//______________________________________________________________________________
void TKey::ReadBuffer(char *&buffer)
{
//*-*-*-*-*-*-*-*-*-*-*-*Decode input buffer-*-*-*-*-*-*-*-*-*-*-*-*-*-*
//*-* ===================
frombuf(buffer, &fNbytes);
Version_t version;
frombuf(buffer,&version);
fVersion = version;
frombuf(buffer, &fObjlen);
fDatime.ReadBuffer(buffer);
frombuf(buffer, &fKeylen);
frombuf(buffer, &fCycle);
frombuf(buffer, &fSeekKey);
frombuf(buffer, &fSeekPdir);
fClassName.ReadBuffer(buffer);
fName.ReadBuffer(buffer);
fTitle.ReadBuffer(buffer);
if (!gROOT->ReadingObject()) {
if (fSeekPdir != gDirectory->GetSeekDir()) gDirectory->AppendKey(this);
}
}
//______________________________________________________________________________
void TKey::ReadFile()
{
//*-*-*-*-*-*-*-*-*-*-*-*-*Read the key structure from the file-*-*-*-*-*-*
//*-* ====================================
Int_t nsize = fNbytes;
gFile->Seek(fSeekKey);
for (Int_t i = 0; i < nsize; i += kMAXFILEBUFFER) {
int nb = kMAXFILEBUFFER;
if (i+nb > nsize) nb = nsize - i;
gFile->ReadBuffer(fBuffer+i,nb);
}
if (gDebug) {
cout << "TKey Reading "<<nsize<< " bytes at address "<<fSeekKey<<endl;
}
}
//______________________________________________________________________________
Int_t TKey::Sizeof() const
{
//*-*-*-*-*-*-*-*Return the size in bytes of the key header structure*-*-*-*
//*-*-*-*-*-*-*-*====================================================
Int_t nbytes = sizeof fNbytes;
nbytes += sizeof(Version_t);
nbytes += sizeof fObjlen;
nbytes += fDatime.Sizeof();
nbytes += sizeof fKeylen;
nbytes += sizeof fCycle;
nbytes += sizeof fSeekKey;
nbytes += sizeof fSeekPdir;
nbytes += fClassName.Sizeof();
nbytes += fName.Sizeof();
nbytes += fTitle.Sizeof();
return nbytes;
}
//_______________________________________________________________________
void TKey::Streamer(TBuffer &b)
{
//*-*-*-*-*-*-*-*-*Stream a class object*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*
//*-* =========================================
if (b.IsReading()) {
b >> fNbytes;
b.ReadVersion(); //Version_t v = b.ReadVersion();
b >> fObjlen;
fDatime.Streamer(b);
b >> fKeylen;
b >> fCycle;
b >> fSeekKey;
b >> fSeekPdir;
fClassName.Streamer(b);
fName.Streamer(b);
fTitle.Streamer(b);
} else {
b << fNbytes;
b.WriteVersion(TKey::IsA());
b << fObjlen;
if (fDatime.Get() == 0) fDatime.Set();
fDatime.Streamer(b);
b << fKeylen;
b << fCycle;
b << fSeekKey;
b << fSeekPdir;
fClassName.Streamer(b);
fName.Streamer(b);
fTitle.Streamer(b);
}
}
//______________________________________________________________________________
Int_t TKey::WriteFile(Int_t cycle)
{
//*-*-*-*-*-*-*-*-*-*-*Write the encoded object supported by this key*-*-*-*
//*-* ==============================================
Int_t nsize = fNbytes;
char *buffer = fBuffer;
if (cycle) {
fCycle = cycle;
FillBuffer(buffer);
buffer = fBuffer;
}
if (fLeft > 0) nsize += sizeof(Int_t);
gFile->Seek(fSeekKey);
for (Int_t i=0;i<nsize;i+=kMAXFILEBUFFER) {
int nb = kMAXFILEBUFFER;
if( i+nb >nsize) nb= int(nsize -i);
gFile->WriteBuffer(buffer,nb);
buffer += nb;
}
// gFile->Flush(); Flushing takes too much time.
// Let user flush the file when he wants.
if (gDebug) {
cout <<" TKey Writing "<<nsize<< " bytes at address "<<fSeekKey
<<" for ID= " <<GetName()<<" Title= "<<GetTitle()<<endl;
}
DeleteBuffer();
return nsize;
}
ROOT page - Class index - 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.