GCC Code Coverage Report


Directory: ./
File: include/na64calib/manager.hh
Date: 2025-09-01 06:19:01
Exec Total Coverage
Lines: 1 2 50.0%
Functions: 1 2 50.0%
Branches: 0 0 -%

Line Branch Exec Source
1 /* This file is a part of NA64SW software.
2 * Copyright (C) 2015-2022 NA64 Collaboration, CERN
3 *
4 * NA64SW is free software: you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation, either version 3 of the License, or
7 * (at your option) any later version.
8 *
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
13 *
14 * You should have received a copy of the GNU General Public License
15 * along with this program. If not, see <https://www.gnu.org/licenses/>. */
16
17 #pragma once
18
19 #include "na64util/uri.hh"
20 #include "na64detID/detectorID.hh"
21 #include "na64calib/dispatcher.hh"
22 #include "na64calib/loader.hh"
23
24 #include <log4cpp/Category.hh>
25
26 #include "na64util/na64/event-id.hh"
27
28 namespace na64dp {
29 namespace calib {
30
31 /**\brief Global singleton class indexing calibration data type aliases
32 *
33 * Provides general match between the string identifier used in runtime
34 * configuration files and internal data type identifier used to uniquely
35 * address particular calibration data type.
36 *
37 * Since aliases dictionary usually instantiated at the very early stage
38 * of application runtime (when constructors get called), logging system
39 * is not available for this isntance. App shall explicitly call the
40 * `init_logging()` afterwards to make this class cope with general
41 * logging system
42 *
43 * \note Dynamically loaded modules uses this singleton before main logging
44 * is initialized.
45 * */
46 class CIDataAliases {
47 private:
48 static CIDataAliases * _self;
49 public:
50 /// Dictionary type for aliases (name to RTTI data type)
51 typedef std::unordered_map<std::string, Dispatcher::CIDataID>
52 TypeIDByName;
53 /// Dictionary type for aliases (RTTI data type to name)
54 typedef std::unordered_map<Dispatcher::CIDataID, std::string, util::PairHash>
55 NameByTypeID;
56 /// List of calib data type dependencies
57 ///
58 /// Organized as unordered multimap internally (pairs of "product" and
59 /// "requirement"). Required type aliases are not resolved in this
60 /// container. This way user code may mention dependencies before they
61 /// actually appear at a runtime.
62 typedef std::unordered_multimap< Dispatcher::CIDataID
63 , std::string
64 , util::PairHash > Dependencies;
65 protected:
66 /// Aliases dictionary, RTTI data type by str name
67 TypeIDByName _nameToTypeID;
68 /// Reverse aliases dictionary, str name by RTTI data type
69 NameByTypeID _typeIDToName;
70 /// Type's dependencies
71 Dependencies _depends;
72 /// Ptr to logging category
73 log4cpp::Category * _logPtr;
74
75 /// Dependencies cache validity flag
76 mutable bool _depsCacheValid;
77 /// Dependencies cache
78 mutable std::unordered_multimap< Dispatcher::CIDataID
79 , Dispatcher::CIDataID
80 , util::PairHash > _depsCache;
81
82
83 CIDataAliases();
84 public:
85 CIDataAliases(const CIDataAliases &) = delete;
86
87 ///\brief Adds new alias for calibration data type
88 ///
89 ///\throw Runtime error on type collision.
90 void add_alias( const std::string &, Dispatcher::CIDataID );
91 /// Adds new alias for calibration data type (CIDataID derived
92 /// automatically)
93 template<typename T> Dispatcher::CIDataID
94 add_alias_of( const std::string aliasName
95 , const std::string strTypeID ) {
96 auto td = Dispatcher::info_id<T>(strTypeID);
97 add_alias(aliasName, td);
98 return td;
99 }
100 /// Returns calibration data type aliases names indexed by type ID
101 71 const NameByTypeID & name_by_type_id() const { return _typeIDToName; }
102 /// Returns calibration data type IDs indexed by alias
103 const TypeIDByName & type_id_by_name() const { return _nameToTypeID; }
104
105 /// Defines calibration data dependency
106 void add_dependency( const std::string & product
107 , const std::string & requirement
108 );
109 /// Returns map of dependencies between types
110 const std::unordered_multimap< Dispatcher::CIDataID
111 , Dispatcher::CIDataID
112 , util::PairHash > &
113 dependency_map() const;
114
115
116 /// Has to be invoked once the logging subsystem is initialized.
117 void init_logging();
118
119 /// Returns instance
120 static CIDataAliases & self();
121 };
122
123 /// Macro for runtime register of the new calibration data type
124 #define REGISTER_CALIB_DATA_TYPE(T, alias, subClass) \
125 static const na64dp::calib::Dispatcher::CIDataID _calibDataTypeID_ ## alias \
126 = ::na64dp::calib::CIDataAliases::self().add_alias_of<T>( \
127 # alias, subClass );
128
129 /**\brief Provides highest level API to access calibration data of all types
130 *
131 * Manages runtime calibration data fetch, retrieval, storage and
132 * on-change notifications.
133 *
134 * Has multiple instances of run indexes and calibration data loader imposed
135 * at a runtime. The first kind of entities implements interface
136 * `iIndex` that shall define what kind of calibration data must be
137 * updated and from which source. The former (loader) will load it.
138 *
139 * Order of insertion of the run indexes matters in case of collisions:
140 * typically the last inserted will displace updates imposed by previous. This
141 * behaviour is not strict and defined by index: `iIndex` instances
142 * get the reentrant updates dictionary and may abstain from displacing
143 * calibration data, depending on implementation (though, displacing is
144 * implied).
145 *
146 * Manager does not maintain the lifetime run indexes and loaders.
147 *
148 * There must be a single instance of the manager in process.
149 *
150 * \todo Threading synchronization primitives as it can be accessed from
151 * different threads.
152 * */
153 class Manager : public Dispatcher
154 {
155 protected:
156 /// Ordered sequence of indeces to collect the updates
157 std::vector<std::shared_ptr<iIndex>> _indeces;
158 /// Ordered list of loaders to load the update; names used by some kind
159 /// of indexes
160 std::vector<std::pair<std::string, std::shared_ptr<iLoader>>> _loaders;
161 /// Index of loaders by name (used for aux utils)
162 std::unordered_map<std::string, std::shared_ptr<iLoader>> _loadersByName;
163
164 /// Current event ID
165 EventID _cEventID;
166 /// Date+time of the current event (or 0)
167 std::pair<time_t, uint32_t> _cDatetime;
168 protected:
169 /// Collects updates from runs indexes returning a list of updates that
170 /// have to be applied at certain event ID. Does not modify the state of
171 /// calibration data.
172 void _collect_updates( Updates & upds
173 , EventID eventID
174 , const std::pair<time_t, uint32_t> & eventTime
175 ) const;
176
177 /// Sorts updates taking into account their dependencies
178 ///
179 /// Updates list not necessarily contains all the dependencies of depndee.
180 /// They must be loaded beforehead (in previous invokations), so this
181 /// method does not controll all the dependencies are satisfied, it just
182 /// re-shuffles updates it got in a proper order.
183 void _sort_updates( Updates & );
184
185 /// Forwards update loading to appropriate loader
186 void _load_updates( const Updates & updates );
187 public:
188 Manager(log4cpp::Category & L);
189 virtual ~Manager();
190
191 /// Returns current run number
192 EventID event_id() const { return _cEventID; }
193 /// Returns time structure associated with the current event
194 const std::pair<time_t, uint32_t> time() const { return _cDatetime; }
195
196 /// Sets current event ID
197 ///
198 /// Forwards execution to `collect_updates()` and, if at least one update
199 /// was found, calls `load_updates()`. Then sets the `_cEventID`.
200 void event_id( EventID, const std::pair<time_t, uint32_t> & );
201
202
203 void add_index( std::shared_ptr<iIndex> iPtr ) {
204 _indeces.push_back( iPtr );
205 }
206
207 void add_loader( const std::string & name
208 , std::shared_ptr<iLoader> lPtr
209 ) {
210 _loaders.push_back(std::pair<std::string, std::shared_ptr<iLoader>>(name, lPtr));
211 _loadersByName.emplace(name, lPtr);
212 }
213
214 const std::unordered_map<std::string, std::shared_ptr<iLoader>> &
215 loaders_by_name() const { return _loadersByName; }
216
217 ///\brief Returns registered loader identified by name
218 ///
219 /// Since application usually provides some generalized loaders that have
220 /// to be extended at a runtime, user code must be able to retrieve them
221 /// for modification (yet, the modification of the list of the loaders
222 /// itself is steered by `add_loader()`).
223 ///
224 /// \throw runtime error if loader is not found or wrong type is requested
225 // for cast.
226 template<typename LoaderT>
227 LoaderT & get_loader(const std::string & loaderName) {
228 auto it = _loadersByName.find(loaderName);
229 if( _loadersByName.end() == it ) {
230 NA64DP_RUNTIME_ERROR( "No loader \"%s\" known to calibration data"
231 " dispatcher.", loaderName.c_str() );
232 }
233 try {
234 return dynamic_cast<LoaderT&>(*it->second);
235 } catch( std::bad_cast & ) {
236 NA64DP_RUNTIME_ERROR( "Bad downcast of loader \"%s\"."
237 , loaderName.c_str()
238 );
239 }
240 }
241
242 /// Dumps calibration data hierarchy to YAML node for inspection
243 void to_yaml( YAML::Node & ) const;
244
245 #if 0
246 /// Adds calibration data loader instance
247 virtual void add_loader( const std::string & loaderName
248 , iLoader * loaderPtr );
249 /// Adds run index instance
250 virtual void add_run_index( iIndex * runIndex );
251
252 /// Returns reference to the list of registered loaders
253 const std::unordered_map<std::string, iLoader *> & loaders() const { return _ciLoaders; }
254 #endif
255 };
256
257 } // namespace ::na64dp::calib
258 } // namespace na64dp
259
260