LArSoft  v09_90_00
Liquid Argon Software toolkit - https://larsoft.org/
ServicesManager.cc
Go to the documentation of this file.
2 // vim: set sw=2 expandtab :
3 
11 #include "cetlib/LibraryManager.h"
12 #include "cetlib_except/demangle.h"
13 #include "fhiclcpp/ParameterSet.h"
15 #include "range/v3/view.hpp"
16 
17 #include <memory>
18 #include <stack>
19 #include <string>
20 #include <utility>
21 #include <vector>
22 
23 using namespace std;
26 
27 namespace {
28 
29  void
30  addService(string const& name, vector<ParameterSet>& service_set)
31  {
33  tmp.put("service_type", name);
34  ParameterSetRegistry::put(tmp);
35  service_set.emplace_back(std::move(tmp));
36  }
37 
38  void
39  addService(string const& name,
40  ParameterSet const& source,
41  vector<ParameterSet>& service_set)
42  {
43  if (auto service = source.get_if_present<ParameterSet>(name)) {
44  service_set.emplace_back(std::move(*service));
45  return;
46  }
47  addService(name, service_set);
48  }
49 
50 } // unnamed namespace
51 
52 namespace art {
53 
54  ServicesManager::~ServicesManager()
55  {
56  // Force the Service destructors to execute in the reverse order
57  // of construction. We first clear the the services cache, which
58  // is safe to do as the services owned by it are co-owned by the
59  // actualCreationOrder_ data member.
60  services_.clear();
61  while (!actualCreationOrder_.empty()) {
62  actualCreationOrder_.pop();
63  }
64  }
65 
66  std::vector<std::string>
67  ServicesManager::registerProducts(ProductDescriptions& productsToProduce,
68  ProducingServiceSignals& signals,
69  ProcessConfiguration const& pc)
70  {
71  std::vector<std::string> producing_services;
72  for (auto& serviceEntry : services_ | ::ranges::views::values) {
73  // Service interfaces cannot be used for product insertion.
74  if (serviceEntry.is_interface())
75  continue;
76 
77  // The value of service_type becomes the "module name/label" for
78  // the ModuleDescription object.
79  auto const& pset = serviceEntry.getParameterSet();
80  std::string moduleLabel{};
81  if (!pset.get_if_present("service_type", moduleLabel)) {
82  // System services do not insert products.
83  continue;
84  }
85 
86  auto const before = productsToProduce.size();
87  ModuleDescription const md{
88  pset.id(), moduleLabel, moduleLabel, ModuleThreadingType::shared, pc};
89  serviceEntry.registerProducts(productsToProduce, signals, md);
90  if (productsToProduce.size() != before) {
91  // Registering the products for this service has changed the
92  // size of productsToProduce. We make the reasonable
93  // assumption that productsToProduce has increased in size.
94  producing_services.push_back(moduleLabel);
95  }
96  }
97  return producing_services;
98  }
99 
100  ServicesManager::ServicesManager(ParameterSet&& servicesPSet,
101  ActivityRegistry& actReg,
102  detail::SharedResources& resources)
103  : actReg_{actReg}, resources_{resources}
104  {
105  vector<ParameterSet> psets;
106  {
107  // Force presence of FileCatalogMetadata service.
108  addService("FileCatalogMetadata", servicesPSet, psets);
109  servicesPSet.erase("FileCatalogMetadata");
110  // Force presence of DatabaseConnection service.
111  addService("DatabaseConnection", servicesPSet, psets);
112  servicesPSet.erase("DatabaseConnection");
113  // Extract all
114  for (auto const& key : servicesPSet.get_pset_names()) {
115  addService(key, servicesPSet, psets);
116  }
117  }
118  using SHBCREATOR_t = std::unique_ptr<detail::ServiceHelperBase> (*)();
119  for (auto const& ps : psets) {
120  auto const service_name = ps.get<string>("service_type");
121  auto const service_provider =
122  ps.get<string>("service_provider", service_name);
123  // Get the helper from the library.
124  unique_ptr<detail::ServiceHelperBase> service_helper{
125  lm_.getSymbolByLibspec<SHBCREATOR_t>(service_provider,
126  "create_service_helper")()};
127  if (service_helper->is_interface()) {
129  << "Service " << service_name << " (of type "
130  << service_helper->get_typeid().className()
131  << ")\nhas been registered as an interface in its header using\n"
132  << "DECLARE_ART_SERVICE_INTERFACE.\n"
133  << "Use DECLARE_ART_SERVICE OR DECLARE_ART_SERVICE_INTERFACE_IMPL\n"
134  << "as appropriate. A true service interface should *not* be\n"
135  << "compiled into a _service.so plugin library.\n";
136  }
137  unique_ptr<detail::ServiceInterfaceHelper> iface_helper;
138  if (service_helper->is_interface_impl()) { // Expect an interface helper
139  iface_helper.reset(dynamic_cast<detail::ServiceInterfaceHelper*>(
140  lm_
141  .getSymbolByLibspec<SHBCREATOR_t>(service_provider,
142  "create_iface_helper")()
143  .release()));
144  if (dynamic_cast<detail::ServiceInterfaceImplHelper*>(
145  service_helper.get())
146  ->get_interface_typeid() != iface_helper->get_typeid()) {
148  << "Service registration for " << service_provider
149  << " is internally inconsistent: " << iface_helper->get_typeid()
150  << " (" << iface_helper->get_typeid().className() << ") != "
151  << dynamic_cast<detail::ServiceInterfaceImplHelper*>(
152  service_helper.get())
153  ->get_interface_typeid()
154  << " ("
155  << dynamic_cast<detail::ServiceInterfaceImplHelper*>(
156  service_helper.get())
157  ->get_interface_typeid()
158  .className()
159  << ").\n"
160  << "Contact the art developers <artists@fnal.gov>.\n";
161  }
162  if (service_provider == service_name) {
163  string iface_name{
164  cet::demangle_symbol(iface_helper->get_typeid().name())};
165  // Remove any namespace qualification if necessary
166  auto const colon_pos = iface_name.find_last_of(":");
167  if (colon_pos != std::string::npos) {
168  iface_name.erase(0, colon_pos + 1);
169  }
171  << "Illegal use of service interface implementation as service "
172  "name in configuration.\n"
173  << "Correct use: services." << iface_name
174  << ": { service_provider: \"" << service_provider << "\" }\n";
175  }
176  }
177  // Insert the cache entry for the main service implementation. Note
178  // we save the typeid of the implementation because we're about to
179  // give away the helper.
180  TypeID service_typeid{service_helper->get_typeid()};
181 
182  // Need temporary because we can't guarantee the order of evaluation
183  // of the arguments to make_pair() below.
184  TypeID const sType{service_helper->get_typeid()};
185  auto svc = services_.emplace(
186  sType, detail::ServiceCacheEntry(ps, std::move(service_helper)));
187 
188  if (iface_helper) {
189  // Need temporary because we can't guarantee the order of evaluation
190  // of the arguments to make_pair() below.
191  TypeID const iType{iface_helper->get_typeid()};
192  services_.emplace(iType,
194  ps, std::move(iface_helper), svc.first->second));
195  }
196  requestedCreationOrder_.emplace_back(std::move(service_typeid));
197  }
199  }
200 
201  void
202  ServicesManager::getParameterSets(std::vector<fhicl::ParameterSet>& out) const
203  {
204  using namespace ::ranges;
205  out =
207  views::transform([](auto const& sce) { return sce.getParameterSet(); }) |
208  to<std::vector>();
209  }
210 
211  void
213  {
214  for (auto const& typeID : requestedCreationOrder_) {
215  if (auto it = services_.find(typeID); it != services_.end()) {
216  auto const& sce = it->second;
217  sce.forceCreation(actReg_, resources_);
218  }
219  }
220  }
221 
222 } // namespace art
ActivityRegistry & actReg_
std::vector< TypeID > requestedCreationOrder_
STL namespace.
Float_t tmp
Definition: plot.C:35
std::vector< BranchDescription > ProductDescriptions
static ServiceRegistry & instance() noexcept
detail::SharedResources & resources_
decltype(auto) values(Coll &&coll)
Range-for loop helper iterating across the values of the specified collection.
void setManager(ServicesManager *)
void getParameterSets(std::vector< fhicl::ParameterSet > &out) const
cet::coded_exception< errors::ErrorCodes, ExceptionDetail::translate > Exception
Definition: Exception.h:66
std::map< TypeID, detail::ServiceCacheEntry > services_
std::optional< T > get_if_present(std::string const &key) const
Definition: ParameterSet.h:267
Definition: MVAAlg.h:12
void put(std::string const &key)
cet::LibraryManager lm_