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 }