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