Newer
Older
//==========================================================================
//--------------------------------------------------------------------------
// Copyright (C) Organisation europeenne pour la Recherche nucleaire (CERN)
// All rights reserved.
//
// For the licensing terms see $DD4hepINSTALL/LICENSE.
// For the list of contributors see $DD4hepINSTALL/doc/CREDITS.
//
// Author : M.Frank
//
//==========================================================================
// Framework include files
#include <DDCond/ConditionsDependencyHandler.h>
#include <DDCond/ConditionsManagerObject.h>
#include <DD4hep/ConditionsProcessor.h>
#include <DD4hep/Printout.h>
#include <TTimeStamp.h>
namespace {
std::string dependency_name(const ConditionDependency* d) {
Markus Frank
committed
#if defined(DD4HEP_CONDITIONS_HAVE_NAME)
return d->target.name;
#else
char text[64];
::snprintf(text,sizeof(text),"%08X %08X",key.values.det_key, key.values.item_key);
return text;
#endif
}
}
void ConditionsDependencyHandler::Work::do_intersection(const IOV* iov_ptr) {
if ( iov_ptr ) {
if ( !this->iov ) {
this->_iov = *iov_ptr;
this->iov = &this->_iov;
}
else {
this->_iov.iov_intersection(*iov_ptr);
}
}
}
dd4hep::Condition
ConditionsDependencyHandler::Work::resolve(Work*& current) {
Work* previous = current;
current = this;
state = RESOLVED;
Markus Frank
committed
printout(ERROR,"DependencyHandler","ERROR: Cannot resolve not existing conditions.");
context.dependency->callback->resolve(condition, context);
previous->do_intersection(iov);
current = previous;
return condition;
ConditionsDependencyHandler::ConditionsDependencyHandler(ConditionsManager mgr,
UserPool& pool,
const Dependencies& dependencies,
Markus Frank
committed
ConditionUpdateUserContext* user_param)
: m_manager(mgr.access()), m_pool(pool), m_dependencies(dependencies),
m_userParam(user_param), num_callback(0)
Markus Frank
committed
unsigned char* p = new unsigned char[dependencies.size()*sizeof(Work)];
m_block = (Work*)p;
for(const auto& d : dependencies) {
Work* w = new(p) Work(this,d.second,user_param,iov);
m_todo.emplace(d.first,w);
p += sizeof(Work);
Markus Frank
committed
}
m_iovType = iov.iovType;
}
/// Default destructor
ConditionsDependencyHandler::~ConditionsDependencyHandler() {
Markus Frank
committed
m_todo.clear();
if ( m_block ) delete [] m_block;
m_block = 0;
/// ConditionResolver implementation: Access to the detector description instance
dd4hep::Detector& ConditionsDependencyHandler::detectorDescription() const {
Markus Frank
committed
/// 1rst pass: Compute/create the missing conditions
void ConditionsDependencyHandler::compute() {
m_state = CREATED;
Markus Frank
committed
for( const auto& i : m_todo ) {
if ( !i.second->condition ) {
do_callback(i.second);
if ( !i.second->condition ) {
Markus Frank
committed
except("DependencyHandler",
"Derived condition was not created after calling the creation callback!");
Markus Frank
committed
}
// printout(INFO,"UserPool","Already calcluated: %s",d->name());
}
}
/// 2nd pass: Handler callback for the second turn to resolve missing dependencies
void ConditionsDependencyHandler::resolve() {
PrintLevel prt_lvl = INFO;
Markus Frank
committed
size_t num_resolved = 0;
std::vector<Condition> tmp;
std::map<IOV::Key,std::vector<Condition> > work_pools;
Work* w;
Markus Frank
committed
m_state = RESOLVED;
for( const auto& c : m_todo ) {
w = c.second;
m_currentWork = w;
if ( w->state != RESOLVED ) {
w->resolve(m_currentWork);
}
++num_resolved;
// Fill an empty map of condition vectors for the block inserts
auto ret = work_pools.emplace(w->iov->keyData,tmp);
if ( ret.second ) {
// There is sort of the hope that most conditions go into 1 pool...
ret.first->second.reserve(m_todo.size());
}
Markus Frank
committed
}
// Optimize pool interactions: Cache pool in map assuming there are only few pools created
for( const auto& c : m_todo ) {
w = c.second;
auto& section = work_pools[w->iov->keyData];
section.emplace_back(w->condition);
printout(prt_lvl,"DependencyHandler","++ Register %s %s %s [%s]",
w->context.dependency->target.toString().c_str(),
w->context.dependency->detector.path().c_str(),
w->condition->iov->str().c_str(),
typeName(typeid(*w->condition)).c_str());
}
// Now block register all conditions to the manager AND to the user pool
// In principle at thi stage the conditions manager should be locked
// provided all the work done so far can be undone.....in case of an error
for( const auto& section : work_pools ) {
IOV iov(m_iovType, section.first);
size_t result = registerMany(iov, section.second);
if ( result != section.second.size() ) {
//
Markus Frank
committed
}
TTimeStamp stop;
printout(prt_lvl,"DependencyHandler","Inserted %ld [%ld] conditions to pool-iov: %s [%7.5f seconds]",
result, section.second.size(), iov.str().c_str(),
stop.AsDouble()-start.AsDouble());
Markus Frank
committed
}
}
/// Interface to handle multi-condition inserts by callbacks: One single insert
bool ConditionsDependencyHandler::registerOne(const IOV& iov, Condition cond) {
return m_pool.registerOne(iov, cond);
}
/// Handle multi-condition inserts by callbacks: block insertions of conditions with identical IOV
std::size_t
ConditionsDependencyHandler::registerMany(const IOV& iov, const std::vector<Condition>& values) {
return m_pool.registerMany(iov, values);
}
Markus Frank
committed
/// Interface to access conditions by hash value of the DetElement (only valid at resolve!)
std::vector<dd4hep::Condition>
ConditionsDependencyHandler::get(DetElement de) {
Markus Frank
committed
return this->get(de.key());
}
/// Interface to access conditions by hash value of the item (only valid at resolve!)
std::vector<dd4hep::Condition>
ConditionsDependencyHandler::getByItem(Condition::itemkey_type key) {
if ( m_state == RESOLVED ) {
struct item_selector {
std::vector<Condition> conditions;
Condition::itemkey_type key;
item_selector(Condition::itemkey_type k) : key(k) {}
int operator()(Condition cond) {
ConditionKey::KeyMaker maker(cond->hash);
if ( maker.values.item_key == key ) conditions.emplace_back(cond);
return 1;
}
};
item_selector proc(key);
m_pool.scan(conditionsProcessor(proc));
for (auto c : proc.conditions ) m_currentWork->do_intersection(c->iov);
return proc.conditions;
}
Markus Frank
committed
except("DependencyHandler",
"Conditions bulk accesses are only possible during conditions resolution!");
return std::vector<Condition>();
}
Markus Frank
committed
/// Interface to access conditions by hash value of the DetElement (only valid at resolve!)
std::vector<dd4hep::Condition>
ConditionsDependencyHandler::get(Condition::detkey_type det_key) {
Markus Frank
committed
if ( m_state == RESOLVED ) {
ConditionKey::KeyMaker lower(det_key, Condition::FIRST_ITEM_KEY);
ConditionKey::KeyMaker upper(det_key, Condition::LAST_ITEM_KEY);
std::vector<Condition> conditions = m_pool.get(lower.hash, upper.hash);
for (auto c : conditions ) m_currentWork->do_intersection(c->iov);
return conditions;
Markus Frank
committed
}
Markus Frank
committed
except("DependencyHandler",
Markus Frank
committed
"Conditions bulk accesses are only possible during conditions resolution!");
return std::vector<Condition>();
}
/// ConditionResolver implementation: Interface to access conditions
dd4hep::Condition
ConditionsDependencyHandler::get(Condition::key_type key, bool throw_if_not) {
Markus Frank
committed
return this->get(key, nullptr, throw_if_not);
}
/// ConditionResolver implementation: Interface to access conditions
dd4hep::Condition
ConditionsDependencyHandler::get(Condition::key_type key,
const ConditionDependency* dependency,
bool throw_if_not)
Markus Frank
committed
{
Markus Frank
committed
/// If we are not already resolving here, we follow the normal procedure
Condition c = m_pool.get(key);
if ( c.isValid() ) {
m_currentWork->do_intersection(c->iov);
Markus Frank
committed
return c;
}
auto i = m_todo.find(key);
if ( i != m_todo.end() ) {
Work* w = i->second;
if ( w->state == RESOLVED ) {
return w->condition;
}
else if ( w->state == CREATED ) {
return w->resolve(m_currentWork);
}
else if ( w->state == INVALID ) {
do_callback(w);
if ( w->condition && w->state == RESOLVED ) // cross-dependencies...
return w->condition;
else if ( w->condition )
return w->resolve(m_currentWork);
Markus Frank
committed
if ( throw_if_not ) {
Markus Frank
committed
if ( dependency ) {
// We need here more elaborate printout to ease debugging capabilities
std::string de_path = dependency->detector.path();
Markus Frank
committed
#if defined(DD4HEP_CONDITIONS_HAVE_NAME)
Markus Frank
committed
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
std::string cond_from = dependency->target.name;
std::string cond_to = "UNKNOWN";
for(const auto& d : dependency->dependencies) {
if ( d.hash == key ) {
cond_to = d.name;
break;
}
}
printout(ERROR,"DependencyHandler",
"Failed to resolve conditon:%016lX for DetElement: %s",
key, de_path.c_str());
printout(ERROR,"DependencyHandler",
"Condition: %s dependent on missing condition: %s",
cond_from.c_str(), cond_to.c_str());
#else
if ( detail::have_condition_item_inventory(-1) ) {
std::string item_from = detail::get_condition_item_name(dependency->target.hash);
std::string item_to = detail::get_condition_item_name(key);
printout(ERROR,"DependencyHandler",
"Failed to resolve conditon:%016lX for DetElement: %s",
key, de_path.c_str());
printout(ERROR,"DependencyHandler",
"Condition: %s#%s dependent on missing condition item: %s",
de_path.c_str(), item_from.c_str(), item_to.c_str());
}
#endif
except("DependencyHandler",
"Failed to resolve conditon:%016lX for DetElement: %s",
key,de_path.c_str());
}
except("ConditionsDependencyHandler","Failed to resolve conditon:%016lX",key);
return Condition();
}
void ConditionsDependencyHandler::do_callback(Work* work) {
const ConditionDependency* dep = work->context.dependency;
Work* previous = m_currentWork;
m_currentWork = work;
if ( work->callstack > 0 ) {
// if we end up here it means a previous construction call never finished
// because the bugger tried to access another condition, which in turn
// during the construction tries to access this one.
// ---> Classic dead-lock
except("DependencyHandler",
"++ Handler caught in infinite recursion loop. Key:%s %c%s%c",
work->context.dependency->target.toString().c_str(),
#if defined(DD4HEP_CONDITIONS_DEBUG)
'[',work->context.dependency->detector.path().c_str(),']'
#else
' ',"",' '
#endif
);
}
++work->callstack;
Markus Frank
committed
work->condition = (*dep->callback)(dep->target, work->context).ptr();
--work->callstack;
m_currentWork = previous;
Markus Frank
committed
if ( work->condition ) {
if ( !work->iov ) {
work->_iov = IOV(m_iovType,IOV::Key(IOV::MIN_KEY, IOV::MAX_KEY));
work->iov = &work->_iov;
}
if ( previous ) {
previous->do_intersection(work->iov);
}
work->condition->iov = work->iov;
Markus Frank
committed
work->condition->hash = dep->target.hash;
work->condition->setFlag(Condition::DERIVED);
work->state = CREATED;
Markus Frank
committed
printout(ERROR,"DependencyHandler",
"+++ Callback handler returned invalid condition. Key:%s %c%s%c",
work->context.dependency->target.toString().c_str(),
#if defined(DD4HEP_CONDITIONS_DEBUG)
'[',work->context.dependency->detector.path().c_str(),']'
throw std::runtime_error("Invalid derived condition callback");
}
}
catch(const std::exception& e) {
Markus Frank
committed
printout(ERROR,"DependencyHandler",
"+++ Exception while creating dependent Condition %s:",
dependency_name(dep).c_str());
Markus Frank
committed
printout(ERROR,"DependencyHandler","\t\t%s", e.what());
Markus Frank
committed
printout(ERROR,"DependencyHandler",
"+++ UNKNOWN exception while creating dependent Condition %s.",
dependency_name(dep).c_str());
Markus Frank
committed
except("DependencyHandler",
"++ Exception while creating dependent Condition %s.",
dependency_name(dep).c_str());