00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011 #ifdef __ICC
00012
00013
00014 #pragma warning(disable:2259)
00015 #endif
00016
00017 #include "GaudiPoolDb/PoolDbIOHandler.h"
00018 #include "GaudiKernel/ObjectContainerBase.h"
00019 #include "GaudiKernel/ContainedObject.h"
00020 #include "GaudiKernel/LinkManager.h"
00021 #include "GaudiKernel/IRegistry.h"
00022 #include "GaudiKernel/MsgStream.h"
00023 #include "GaudiKernel/SmartRef.h"
00024 #include <stdexcept>
00025 #include <iostream>
00026 #include "TROOT.h"
00027 #include "TFile.h"
00028 #include "TClass.h"
00029 #include "TStreamerInfo.h"
00030 #include "Cintex/Cintex.h"
00031 #include "POOLCore/Token.h"
00032 #include "POOLCore/Reference.h"
00033 #include "StorageSvc/DbReflex.h"
00034 #include "StorageSvc/DataCallBack.h"
00035 #include "StorageSvc/DbDataHandlerGuard.h"
00036
00037 #include <memory>
00038
00039 using namespace pool;
00040 using namespace ROOT::Reflex;
00041 using namespace ROOT::Cintex;
00042
00043 namespace ROOT { namespace Cintex {
00044 bool IsTypeOf(Type& typ, const std::string& base_name);
00045 }}
00046 namespace pool {
00047 const std::string typeName(const std::type_info& typ);
00048 }
00049
00050
00051 static const DataObject* last_link_object = 0;
00052 static int last_link_hint = -1;
00053
00054 void resetLastLink() {
00055 last_link_object = 0;
00056 last_link_hint = -1;
00057 }
00058
00059 using Gaudi::getCurrentDataObject;
00060
00061 void pushCurrentDataObject(DataObject** pobjAddr) {
00062 Gaudi::pushCurrentDataObject(pobjAddr);
00063 resetLastLink();
00064 }
00065
00066 void popCurrentDataObject() {
00067 Gaudi::popCurrentDataObject();
00068 resetLastLink();
00069 }
00070
00071
00072 template <class T>
00073 void PoolDbIOHandler<T>::operator()(TBuffer &b, void *obj) {
00074 try {
00075 if ( b.IsReading() ) {
00076 get(b,obj);
00077 }
00078 else {
00079 put(b,obj);
00080 }
00081 }
00082 catch( const std::exception& e ) {
00083 std::string err = "Class:" + std::string(m_root->GetName()) + "> Exception in object I/O";
00084 err += e.what();
00085 throw std::runtime_error(err);
00086 }
00087 catch( ... ) {
00088 std::string err = "Class:" + std::string(m_root->GetName()) + "> Exception in object I/O";
00089 throw std::runtime_error(err);
00090 }
00091 }
00092
00093 template <>
00094 void PoolDbIOHandler<SmartRefBase>::get(TBuffer &b, void* obj) {
00095 UInt_t start, count;
00096 SmartRefBase* ref = (SmartRefBase*)obj;
00097 Version_t version = b.ReadVersion(&start, &count, m_root);
00098 m_root->ReadBuffer(b, obj, version, start, count);
00099 switch( ref->objectType() ) {
00100 case SmartRefBase::DATAOBJECT:
00101 {
00102 SmartRef<DataObject>* r = (SmartRef<DataObject>*)obj;
00103 (*r)(getCurrentDataObject());
00104 }
00105 break;
00106 case SmartRefBase::CONTAINEDOBJECT:
00107 {
00108 SmartRef<ContainedObject>* r = (SmartRef<ContainedObject>*)obj;
00109 (*r)(getCurrentDataObject());
00110 }
00111 break;
00112 default:
00113 std::cout << "Hit uninitialized smartRef!!!!" << std::endl;
00114 break;
00115 }
00116 }
00117
00118 template <>
00119 void PoolDbIOHandler<SmartRefBase>::put(TBuffer &b, void* obj) {
00120 SmartRefBase* ref = (SmartRefBase*)obj;
00121 SmartRef<DataObject>* r1 = (SmartRef<DataObject>*)ref;
00122 DataObject* curr = getCurrentDataObject();
00123 DataObject* pDO = r1->data();
00124 int hint = r1->hintID();
00125 int link = r1->linkID();
00126 if ( pDO ) {
00127 switch( ref->objectType() ) {
00128 case SmartRefBase::CONTAINEDOBJECT:
00129 {
00130 SmartRef<ContainedObject>* r2 = (SmartRef<ContainedObject>*)ref;
00131 ContainedObject* p = r2->data();
00132 if ( p ) {
00133 const ObjectContainerBase* parent = p->parent();
00134 if ( parent ) {
00135 link = p->index();
00136 pDO = const_cast<ObjectContainerBase*>(parent);
00137 break;
00138 }
00139 }
00140 }
00141 pDO = 0;
00142 std::cout << "PoolDbIOHandler<SmartRefBase>::onWrite> "
00143 << "Found invalid smart reference with object "
00144 << "having no parent."
00145 << std::endl;
00146 throw std::runtime_error("PoolDbIOHandler<SmartRefBase>::onWrite> "
00147 "Found invalid smart reference with object "
00148 "having no parent.");
00149 break;
00150 case SmartRefBase::DATAOBJECT:
00151 link = StreamBuffer::INVALID;
00152 break;
00153 default:
00154 break;
00155 }
00156
00157
00158
00159
00160
00161 if ( pDO == last_link_object ) {
00162 ref->set(curr, last_link_hint, link);
00163 m_root->WriteBuffer(b, obj);
00164 return;
00165 }
00166 else {
00167 LinkManager* mgr = curr->linkMgr();
00168 IRegistry* reg = pDO->registry();
00169 if ( reg && mgr ) {
00170 hint = mgr->addLink(reg->identifier(), pDO);
00171 last_link_hint = hint;
00172 last_link_object = pDO;
00173 }
00174 }
00175 }
00176
00177
00178
00179
00180
00181 ref->set(curr, hint, link);
00182 m_root->WriteBuffer(b, obj);
00183 }
00184
00185 template <>
00186 void PoolDbIOHandler<ContainedObject>::get(TBuffer &b, void* obj) {
00187 UInt_t start, count;
00188 Version_t version = b.ReadVersion(&start, &count, m_root);
00189 m_root->ReadBuffer(b, obj, version, start, count);
00190 ContainedObject* p = (ContainedObject*)obj;
00191 p->setParent((ObjectContainerBase*)getCurrentDataObject());
00192 }
00193
00194 template <>
00195 void PoolDbIOHandler<ContainedObject>::put(TBuffer &b, void* obj) {
00196 m_root->WriteBuffer(b, obj);
00197 }
00198
00199
00200 #ifndef ROOT_FULL_VERSION
00201 #define ROOT_FULL_VERSION(a,b,c,p) (((a)<<24)+((b)<<16)+((c)<<8)+(p))
00202 #define ROOT_FULL_VERSION_CODE (ROOT_VERSION_CODE << 8)
00203 #endif
00204
00205 static void getOID_40000(TBuffer& b, TClass* cl, Token::OID_t& oid) {
00206 unsigned long loid[2];
00207 UInt_t start, count;
00208 #if (ROOT_FULL_VERSION_CODE < ROOT_FULL_VERSION(5,28,0,'a'))
00209 UInt_t tmp;
00210 #endif
00211
00212 b.ReadVersion(&start, &count, 0);
00213 switch(count) {
00214 case 22:
00215 #if (ROOT_FULL_VERSION_CODE < ROOT_FULL_VERSION(5,28,0,'a'))
00216 b >> tmp;
00217 #endif
00218 b.ReadFastArray(loid,2);
00219 oid.first = loid[0];
00220 oid.second = loid[1];
00221 break;
00222 #if (ROOT_FULL_VERSION_CODE < ROOT_FULL_VERSION(5,28,0,'a'))
00223 case 14:
00224 b >> tmp;
00225 case 10:
00226 case 8:
00227 #endif
00228 default:
00229 b.ReadFastArray(&oid.first, 2);
00230 break;
00231 }
00232
00233 b.CheckByteCount(start, count, cl);
00234 }
00235
00236 template <>
00237 void PoolDbIOHandler<Token>::get(TBuffer& b, void* obj) {
00238 Token* t = (Token*)obj;
00239 DataCallBack* caller = DbDataHandlerGuard::caller();
00240 Int_t file_version = ((TFile*)b.GetParent())->GetVersion();
00241 if ( file_version >= 40000 ) {
00242 getOID_40000(b, m_root, t->oid());
00243 }
00244 else {
00245 UInt_t start, count, tmp;
00246 Version_t vsn = b.ReadVersion(&start, &count, m_root);
00247 switch(vsn) {
00248 case 2:
00249 b >> tmp;
00250 b.ReadFastArray(&t->oid().first, 2);
00251 b >> tmp;
00252 break;
00253 default:
00254 b.SetBufferOffset(start+4);
00255 b.ReadFastArray(&t->oid().first, 2);
00256 break;
00257 }
00258 }
00259 if (caller) caller->notify(DataCallBack::GET,DataCallBack::TOKEN,m_type,obj,&t->oid());
00260 }
00261
00262 template <>
00263 void PoolDbIOHandler<Token>::put(TBuffer &b, void* obj) {
00264 Token::OID_t* poid = &(((Token*)obj)->oid());
00265 UInt_t count = b.WriteVersion(m_root, true);
00266 DataCallBack* caller = DbDataHandlerGuard::caller();
00267 if (caller) caller->notify(DataCallBack::PUT,DataCallBack::TOKEN,m_type,obj,poid);
00268 b.WriteFastArray(&poid->first, 2);
00269 b.SetByteCount(count, true);
00270 }
00271
00272 template <>
00273 void PoolDbIOHandler<Reference>::get(TBuffer& b, void* obj) {
00274 Token::OID_t oid(~0x0,~0x0);
00275 DataCallBack* caller = DbDataHandlerGuard::caller();
00276 Int_t file_version = ((TFile*)b.GetParent())->GetVersion();
00277 (file_version >= 40000) ? getOID_40000(b, m_root,oid) : b.ReadFastArray(&oid.first, 2);
00278 if (caller) caller->notify(DataCallBack::GET,DataCallBack::REFERENCE,m_type,obj,&oid);
00279 }
00280
00281 template <>
00282 void PoolDbIOHandler<Reference>::put(TBuffer &b, void* obj) {
00283 UInt_t count = b.WriteVersion(m_root, true);
00284 DataCallBack* caller = DbDataHandlerGuard::caller();
00285 Token::OID_t oid(~0x0, ~0x0);
00286 if (caller) caller->notify(DataCallBack::PUT,DataCallBack::REFERENCE,m_type,obj,&oid);
00287 b.WriteFastArray(&oid.first, 2);
00288 b.SetByteCount(count, true);
00289 }
00290
00291 template <class T> static bool makeStreamer(MsgStream& log) {
00292 std::string cl_name = typeName(typeid(T));
00293 ROOT::Reflex::Type t = ROOT::Reflex::Type::ByName(cl_name);
00294 if ( t ) {
00295 TClass* c = gROOT->GetClass(cl_name.c_str());
00296 if ( c ) {
00297 TClassStreamer* s = new PoolDbIOHandler<T>(t,c);
00298 c->AdoptStreamer(s);
00299 log << MSG::DEBUG << "Installed IOHandler for class " << cl_name << endmsg;
00300 return true;
00301 }
00302 else if ( !c ) {
00303 log << MSG::ERROR << "[No ROOT TClass] Failed to install IOHandler for class " << cl_name << endmsg;
00304 }
00305 }
00306 else {
00307 log << MSG::ERROR << "[No Reflection Type] Failed to install IOHandler for class " << cl_name << endmsg;
00308 }
00309 return false;
00310 }
00311
00312 namespace GaudiPoolDb {
00313 bool patchStreamers(MsgStream& s) {
00314 static bool first = true;
00315 if ( first ) {
00316 first = false;
00317 for ( Type_Iterator i=Type::Type_Begin(); i != Type::Type_End(); ++i) {
00318 Type typ = *i;
00319 if ( !(typ.IsStruct() || typ.IsClass()) ) continue;
00320 TClass* cl = 0;
00321 if ( IsTypeOf(typ,"pool::Reference") ) {
00322 cl = gROOT->GetClass(typ.Name(SCOPED).c_str());
00323 if ( cl ) cl->AdoptStreamer(new PoolDbIOHandler<Reference>(typ,cl));
00324 }
00325 else if ( IsTypeOf(typ,"pool::Token") ) {
00326 cl = gROOT->GetClass(typ.Name(SCOPED).c_str());
00327 if ( cl ) cl->AdoptStreamer(new PoolDbIOHandler<Token>(typ,cl));
00328 }
00329 }
00330 ROOT::Cintex::Cintex::Enable();
00331 bool b2 = makeStreamer<SmartRefBase>(s);
00332 bool b3 = makeStreamer<ContainedObject>(s);
00333 return b2 && b3;
00334 }
00335 return true;
00336 }
00337 }