TRef.cxx

Go to the documentation of this file.
00001 // @(#)root/cont:$Id: TRef.cxx 37964 2011-02-03 11:04:55Z rdm $
00002 // Author: Rene Brun   28/09/2001
00003 
00004 /*************************************************************************
00005  * Copyright (C) 1995-2000, Rene Brun and Fons Rademakers.               *
00006  * All rights reserved.                                                  *
00007  *                                                                       *
00008  * For the licensing terms see $ROOTSYS/LICENSE.                         *
00009  * For the list of contributors see $ROOTSYS/README/CREDITS.             *
00010  *************************************************************************/
00011 
00012 //////////////////////////////////////////////////////////////////////////
00013 //
00014 // TRef
00015 //
00016 // Persistent Reference link to a TObject
00017 // A TRef is a lightweight object pointing to any TObject.
00018 // This object can be used instead of normal C++ pointers in case
00019 //  - the referenced object R and the pointer P are not written to the same file
00020 //  - P is read before R
00021 //  - R and P are written to different Tree branches
00022 //
00023 // When a top level object (eg Event *event) is a tree/graph of many objects,
00024 // the normal ROOT Streaming mechanism ensures that only one copy of each object
00025 // in the tree/graph is written to the output buffer to avoid circular
00026 // dependencies.
00027 // However if the object event is split into several files or into several
00028 // branches of one or more Trees, normal C++ pointers cannot be used because
00029 // each I/O operation will write the referenced objects.
00030 // When a TRef is used to point to a TObject *robj, for example in a class with
00031 //     TRef  fRef;
00032 // one can do:
00033 //     fRef = robj;  //to set the pointer
00034 // This TRef and robj can be written with two different I/O calls
00035 // in the same or different files, in the same or different branches of a Tree.
00036 //
00037 // If the TRef is read and the referenced object has not yet been read,
00038 // the TRef will return a null pointer. As soon as the referenced object
00039 // will be read, the TRef will point to it. If the referenced object is
00040 // contained in a TTree it can be autoloaded using the TBranchRef mechanism,
00041 // which is set up by simply calling TTree::BranchRef().
00042 //
00043 // TRef also supports the complex situation where a TFile is updated
00044 // multiple times on the same machine or a different machine.
00045 //
00046 // How does it work
00047 // ----------------
00048 // A TRef is itself a TObject with an additional transient pointer fPID.
00049 // When the statement fRef = robj is executed, the following actions happen:
00050 //   - The pointer fPID is set to the current TProcessID.
00051 //   - The current ObjectNumber (see below) is incremented by one.
00052 //   - robj::fUniqueID is set to ObjectNumber.
00053 //   - In the fPID object, the element fObjects[ObjectNumber] is set to robj
00054 //   - ref::fUniqueID is also set to ObjectNumber.
00055 // After having set fRef, one can immediatly return the value of robj
00056 // using fRef.GetObject(). This function returns directly fObjects[fUniqueID]
00057 // from the fPID object.
00058 //
00059 // When the TRef is written, the process id number pidf of fPID is written
00060 // in addition to the TObject part of TRef (fBits,fUniqueID).
00061 // When the TRef is read, its pointer fPID is set to the value
00062 // stored in the TObjArray of TFile::fProcessIDs (fProcessIDs[pidf]).
00063 // The pidf is stored in the bits 24->31 of the fUniqueID of the TRef.
00064 // This implies that the number of TRefs in one process should not
00065 // exceed 2**23 = 8388608 and that the number of processes (different jobs)
00066 // writing TRefs to one file should be less than 256.
00067 // See section "ObjectNumber" below for a recipee to minimize the object count.
00068 // If the objectnumber exceeds this limit, it could be the sign that:
00069 //   -The object count is never reset (see below)
00070 //   -TRef is misused.
00071 //
00072 // When a referenced object robj is written, TObject::Streamer writes
00073 // in addition to the standard (fBits,fUniqueID) the pidf.
00074 // When this robj is read by TObject::Streamer, the pidf is read.
00075 // At this point, robj is entered into the table of objects of the TProcessID
00076 // corresponding to pidf.
00077 //
00078 // WARNING1: If MyClass is the class of the referenced object, The TObject
00079 //          part of MyClass must be Streamed. One should not
00080 //          call MyClass::Class()->IgnoreTObjectStreamer()
00081 //
00082 //
00083 // WARNING2: A TRef cannot point to another TRef.
00084 //
00085 //
00086 // ObjectNumber
00087 // ------------
00088 // When an object is referenced (see TRef assignement operator or TRefArray::Add)
00089 // a unique identifier is computed and stored in both the fUniqueID of the
00090 // referenced and referencing object. This uniqueID is computed by incrementing
00091 // by one the static global in TProcessID::fgNumber. fUniqueID is some sort of
00092 // serial object number in the current session. One can retrieve at any time
00093 // the current value of fgNumber by calling the static function TProcessID::GetObjectCount
00094 // or set this number via TProcessID::SetObjectCount.
00095 // To avoid a growing table of fObjects in TProcessID, in case, for example,
00096 // one processes many events in a loop, it might be necessary to reset the
00097 // ObjectNumber at the end of processing of one event. See an example
00098 // in $ROOTSYS/test/Event.cxx (look at function Build).
00099 // The value of ObjectNumber (say saveNumber=TProcessID::GetObjectCount()) may be
00100 // saved at the beginning of one event and reset to this original value
00101 // at the end of the event via TProcessID::SetObjectCount(saveNumber). These
00102 // actions may be stacked.
00103 //
00104 // Action on Demand
00105 // ----------------
00106 // The normal behaviour of a TRef has been described above. In addition,
00107 // TRef supports also "Actions on Demand". It may happen that the object
00108 // referenced is not yet in memory, on a separate file or not yet computed.
00109 // In this case TRef is able to automatically execute an action:
00110 //   - call to a compiled function (static function of member function)
00111 //   - call to an interpreted function
00112 //   - execution of a CINT script
00113 //
00114 // How to select this option?
00115 // In the definition of the TRef data member in the original class, do:
00116 //   TRef  fRef;   //EXEC:execName. points to something
00117 // When the special keyword "EXEC:" is found in the comment field of the member,
00118 // the next string is assumed to be the name of a TExec object.
00119 // When a file is connected, the dictionary of the classes on the file
00120 // is read in memory (see TFile::ReadStreamerInfo). When the TStreamerElement
00121 // object is read, a TExec object is automatically created with the name
00122 // specified after the keywork "EXEC:" in case a TExec with a same name does
00123 // not already exist.
00124 // The action to be executed via this TExec can be specified with:
00125 //    - a call to the TExec constructor, if the constructor is called before
00126 //      opening the file.
00127 //    - a call to TExec::SetAction at any time.
00128 //      One can compute a pointer to an existing TExec with a name with:
00129 //        TExec *myExec = gROOT->GetExec(execName);
00130 //      myExec->SetAction(actionCommand); where
00131 //      - actionCommand is a string containing a CINT instruction. Examples:
00132 //          myExec->SetAction("LoadHits()");
00133 //          myExec->SetAction(".x script.C");
00134 //
00135 // When a TRef is dereferenced via TRef::GetObject, its TExec will be
00136 // automatically executed. In the function/script being executed, one or more
00137 // of the following actions can be executed:
00138 //  - load a file containing the referenced object. This function typically
00139 //    looks in the file catalog (GRID).
00140 //  - compute a pointer to the referenced object and communicate this pointer
00141 //    back to the calling function TRef::GetObject via:
00142 //      TRef::SetStaticObject(object).
00143 //    When the TExec is called, it has access to the dereferencing TRef
00144 //    by calling GetStaticObject() (TRef::GetObject() sets fgObject to "this"
00145 //    before the call to TExec). This can be useful for accessing the TRef's
00146 //    fUniqueID.
00147 // As soon as an object is returned to GetObject, the fUniqueID of the TRef is set
00148 // to the fUniqueID of the referenced object. At the next call to GetObject,
00149 // the pointer stored in fPid:fObjects[fUniqueID] will be returned directly.
00150 //
00151 // An example of action on demand is shown in $ROOTSYS/test/Event.h with
00152 // the member:
00153 //      TRef    fWebHistogram;   //EXEC:GetWebHistogram
00154 // When calling fWebHistogram.GetObject(), the function GetObject
00155 // will automatically invoke a script GetWebHistogram.C via the interpreter.
00156 // An example of a GetWebHistogram.C script is shown below
00157 //    void GetWebHistogram() {
00158 //       TFile *f= TFile::Open("http://root.cern.ch/files/pippa.root");
00159 //       f->cd("DM/CJ");
00160 //       TH1 *h6 = (TH1*)gDirectory->Get("h6");
00161 //       h6->SetDirectory(0);
00162 //       delete f;
00163 //       TRef::SetStaticObject(h6);
00164 //    }
00165 // In the above example, a call to fWebHistogram.GetObject() executes the
00166 // script with the function GetWebHistogram. This script connects a file
00167 // with histograms: pippa.root on the ROOT Web site and returns the object h6
00168 // to TRef::GetObject.
00169 // Note that if the definition of the TRef fWebHistogram had been:
00170 //      TRef    fWebHistogram;   //EXEC:GetWebHistogram()
00171 // then, the compiled or interpreted function GetWebHistogram() would have
00172 // been called instead of the CINT script GetWebHistogram.C
00173 //
00174 // Special case of a TRef pointing to an object with a TUUID
00175 // ----------------------------------------------------------
00176 // If the referenced object has a TUUID, its bit kHasUUID has been set.
00177 // This case is detected by the TRef assignement operator.
00178 // (For example, TFile and TDirectory have a TUUID)
00179 // The TRef fPID points directly to the single object TProcessUUID (deriving
00180 // from TProcessID) and managing the list of TUUIDs for a process.
00181 // The TRef kHasUUID bit is set and its fUniqueID is set to the fUniqueID
00182 // of the referenced object.
00183 // When the TRef is streamed to a buffer, the corresponding TUUID is also
00184 // streamed with the TRef. When a TRef is read from a buffer, the corresponding
00185 // TUUID is also read and entered into the global list of TUUIDs (if not
00186 // already there). The TRef fUniqueID is set to the UUIDNumber.
00187 // see TProcessUUID for more details.
00188 //
00189 // Array of TRef
00190 // -------------
00191 // The special class TRefArray should be used to store multiple references.
00192 // A TRefArray has one single pointer fPID for all objects in the array.
00193 // It has a dynamic compact table of fUniqueIDs. Use a TRefArray rather
00194 // then a collection of TRefs if all TRefs stem from the same process.
00195 //
00196 // Example:
00197 // Suppose a TObjArray *mytracks containing a list of Track objects
00198 // Suppose a TRefArray *pions containing pointers to the pion tracks in mytracks.
00199 // This list is created with statements like: pions->Add(track);
00200 // Suppose a TRefArray *muons containing pointers to the muon tracks in mytracks.
00201 // The 3 arrays mytracks,pions and muons may be written separately.
00202 //
00203 //////////////////////////////////////////////////////////////////////////
00204 
00205 #include "TRef.h"
00206 #include "TROOT.h"
00207 #include "TClass.h"
00208 #include "TProcessUUID.h"
00209 #include "TRefTable.h"
00210 #include "TObjArray.h"
00211 #include "TExec.h"
00212 #include "TSystem.h"
00213 #include "TObjString.h"
00214 
00215 TObjArray  *TRef::fgExecs  = 0;
00216 TObject    *TRef::fgObject = 0;
00217 
00218 ClassImp(TRef)
00219 
00220 //______________________________________________________________________________
00221 TRef::TRef(TObject *obj)
00222 {
00223    // Create a ref to obj.
00224 
00225    *this = obj;
00226 }
00227 
00228 //______________________________________________________________________________
00229 TRef::TRef(const TRef &ref) : TObject(ref)
00230 {
00231    // TRef copy ctor.
00232 
00233    *this = ref;
00234 }
00235 
00236 //______________________________________________________________________________
00237 void TRef::operator=(TObject *obj)
00238 {
00239    // Assign object to reference.
00240 
00241    UInt_t uid = 0;
00242    fPID = 0;
00243    if (obj) {
00244       if (obj->IsA()->CanIgnoreTObjectStreamer()) {
00245          Error("operator= ","Class: %s IgnoreTObjectStreamer. Cannot reference object",obj->ClassName());
00246          return;
00247       }
00248       if (obj->TestBit(kHasUUID)) {
00249          fPID = gROOT->GetUUIDs();
00250          obj->SetBit(kIsReferenced);
00251          SetBit(kHasUUID);
00252          uid = obj->GetUniqueID();
00253       } else {
00254          if (obj->TestBit(kIsReferenced)) {
00255             uid = obj->GetUniqueID();
00256             fPID = TProcessID::GetProcessWithUID(uid,obj);
00257          } else {
00258             fPID = TProcessID::GetSessionProcessID();
00259             uid = TProcessID::AssignID(obj);
00260          }
00261          ResetBit(kHasUUID);
00262       }
00263    }
00264    SetUniqueID(uid);
00265 }
00266 
00267 //______________________________________________________________________________
00268 TRef &TRef::operator=(const TRef &ref)
00269 {
00270    // TRef assignment operator.
00271 
00272    SetUniqueID(ref.GetUniqueID());
00273    fPID = ref.fPID;
00274    SetBit(kHasUUID,ref.TestBit(kHasUUID));
00275    return *this;
00276 }
00277 
00278 //______________________________________________________________________________
00279 Bool_t operator==(const TRef &r1, const TRef &r2)
00280 {
00281    // Return kTRUE if r1 and r2 point to the same object.
00282 
00283    if (r1.GetPID() == r2.GetPID() && r1.GetUniqueID() == r2.GetUniqueID()) return kTRUE;
00284    else return kFALSE;
00285 }
00286 
00287 //______________________________________________________________________________
00288 Bool_t operator!=(const TRef &r1, const TRef &r2)
00289 {
00290    // Return kTRUE if r1 and r2 do not point to the same object.
00291 
00292    if (r1.GetPID() == r2.GetPID() && r1.GetUniqueID() == r2.GetUniqueID()) return kFALSE;
00293    else return kTRUE;
00294 }
00295 
00296 //______________________________________________________________________________
00297 Int_t TRef::AddExec(const char *name)
00298 {
00299    // If Exec with name does not exist in the list of Execs, it is created.
00300    // returns the index of the Exec in the list.
00301 
00302 #ifdef R__COMPLETE_MEM_TERMINATION
00303    if (!fgExecs) GetListOfExecs();
00304 #else
00305    if (!fgExecs) fgExecs = new TObjArray(10);
00306 #endif
00307 
00308    TExec *exec = (TExec*)fgExecs->FindObject(name);
00309    if (!exec) {
00310       // we register this Exec to the list of Execs.
00311       exec = new TExec(name,"");
00312       fgExecs->Add(exec);
00313    }
00314    return fgExecs->IndexOf(exec);
00315 }
00316 
00317 //______________________________________________________________________________
00318 TObjArray *TRef::GetListOfExecs()
00319 {
00320    // Return a pointer to the static TObjArray holding the list of Execs.
00321 
00322 #ifdef R__COMPLETE_MEM_TERMINATION
00323    static TObjArray listOfExecs(10);
00324    if (!fgExecs) {
00325       listOfExecs.SetOwner(kTRUE);
00326       fgExecs = &listOfExecs;
00327    }
00328 #else
00329    if (!fgExecs) fgExecs = new TObjArray(10);
00330 #endif
00331    return fgExecs;
00332 
00333 }
00334 
00335 
00336 //______________________________________________________________________________
00337 TObject *TRef::GetObject() const
00338 {
00339    // Return a pointer to the referenced object.
00340 
00341    //TObject *obj = 0;
00342    if (!fPID) return 0;
00343    if (!TProcessID::IsValid(fPID)) return 0;
00344    UInt_t uid = GetUniqueID();
00345 
00346    //the reference may be in the TRefTable
00347    TRefTable *table = TRefTable::GetRefTable();
00348    if (table) {
00349       table->SetUID(uid, fPID);
00350       table->Notify();
00351    }
00352 
00353    //Try to find the object from the table of the corresponding PID
00354    TObject *obj = fPID->GetObjectWithID(uid);
00355 
00356    //if object not found, then exec action if an action has been defined
00357    if (!obj) {
00358       //execid in the first 8 bits
00359       Int_t execid = TestBits(0xff0000);
00360       if (execid > 0) {
00361          execid = execid>>16;
00362          TExec *exec = (TExec*)fgExecs->At(execid-1);
00363          if (exec) {
00364             //we expect the object to be returned via TRef::SetStaticObject
00365             fgObject = const_cast<TRef*>(this);
00366             exec->Exec();
00367             if ((const TRef*)fgObject != this)
00368                obj = fgObject;
00369             else obj=0;
00370             if (obj){
00371                uid = TProcessID::AssignID(obj);
00372                ((TRef*)this)->SetUniqueID(uid);
00373                fPID->PutObjectWithID(obj,uid);
00374             } else {
00375                //well may be the Exec has loaded the object
00376                obj = fPID->GetObjectWithID(uid);
00377             }
00378          }
00379       }
00380    }
00381 
00382    return obj;
00383 }
00384 
00385 //______________________________________________________________________________
00386 void TRef::SetAction(const char *name)
00387 {
00388    // Store the exec number (in the ROOT list of Execs)
00389    // into the fBits of this TRef.
00390 
00391    TExec *exec = (TExec*)GetListOfExecs()->FindObject(name);
00392    if (!exec) {
00393       Error("SetAction","Unknow TExec: %s",name);
00394       return;
00395    }
00396    Int_t execid = 1 + fgExecs->IndexOf(exec);
00397    SetBit(execid << 8);
00398 }
00399 
00400 //______________________________________________________________________________
00401 void TRef::SetAction(TObject *parent)
00402 {
00403    // Find the action to be executed in the dictionary of the parent class
00404    // and store the corresponding exec number into fBits.
00405    // This function searches a data member in the class of parent with an
00406    // offset corresponding to this.
00407    // If a comment "TEXEC:" is found in the comment field of the data member,
00408    // the function stores the exec identifier of the exec statement
00409    // following this keyword.
00410 
00411    if (!parent) return;
00412    if (gDirectory) gDirectory->SetTRefAction(this,parent);
00413 }
00414 
00415  //______________________________________________________________________________
00416 TObject *TRef::GetStaticObject() {
00417    // Returns the static object.
00418    return fgObject;
00419 }
00420 
00421 //______________________________________________________________________________
00422 void TRef::SetObject(TObject *obj)
00423 {
00424    // static Obsolete function kept for back compatibility.
00425    // In the near future will print a Warning, then will be deleted.
00426 
00427    SetStaticObject(obj);
00428 }
00429 
00430 //______________________________________________________________________________
00431 void TRef::SetStaticObject(TObject *obj)
00432 {
00433    // Static function to set the object found on the Action on Demand function.
00434    // This function may be called by the user in the function called
00435    // when a "EXEC:" keyword is specified in the data member field of the TRef.
00436    // The function can get access to the dereferencing TRef (i.e. this)using
00437    // the static function GetStaticObject().
00438 
00439    fgObject = obj;
00440 }
00441 
00442 //______________________________________________________________________________
00443 void TRef::Streamer(TBuffer &R__b)
00444 {
00445    // Stream an object of class TRef.
00446 
00447    UShort_t pidf;
00448    if (R__b.IsReading()) {
00449       TObject::Streamer(R__b);
00450       if (TestBit(kHasUUID)) {
00451          TString s;
00452          s.Streamer(R__b);
00453          TProcessUUID *pid = gROOT->GetUUIDs();
00454          UInt_t number = pid->AddUUID(s.Data());
00455          fPID = pid;
00456          SetUniqueID(number);
00457          if (gDebug > 1) {
00458             printf("Reading TRef (HasUUID) uid=%d, obj=%lx\n",GetUniqueID(),(Long_t)GetObject());
00459          }
00460       } else {
00461          R__b >> pidf;
00462          pidf += R__b.GetPidOffset();
00463          fPID = R__b.ReadProcessID(pidf);
00464          //The execid has been saved in the unique id of the TStreamerElement
00465          //being read by TStreamerElement::Streamer
00466          //The current element (fgElement) is set as a static global
00467          //by TStreamerInfo::ReadBuffer (Clones) when reading this TRef
00468          Int_t execid = R__b.GetTRefExecId();
00469          if (execid) SetBit(execid<<16);
00470          if (gDebug > 1) {
00471             printf("Reading TRef, pidf=%d, fPID=%lx, uid=%d, obj=%lx\n",pidf,(Long_t)fPID,GetUniqueID(),(Long_t)GetObject());
00472          }
00473       }
00474    } else {
00475       TObject::Streamer(R__b);
00476 
00477       if (TestBit(kHasUUID)) {
00478          TObjString *objs = gROOT->GetUUIDs()->FindUUID(GetUniqueID());
00479          objs->String().Streamer(R__b);
00480          if (gDebug > 1) {
00481             printf("Writing TRef (HasUUID) uid=%d, obj=%lx\n",GetUniqueID(),(Long_t)GetObject());
00482          }
00483       } else {
00484          pidf = R__b.WriteProcessID(fPID);
00485          R__b << pidf;
00486          if (gDebug > 1) {
00487             printf("Writing TRef, pidf=%d, fPID=%lx, uid=%d, obj=%lx\n",pidf,(Long_t)fPID,GetUniqueID(),(Long_t)GetObject());
00488          }
00489       }
00490    }
00491 }

Generated on Tue Jul 5 14:11:23 2011 for ROOT_528-00b_version by  doxygen 1.5.1