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