Line data Source code
1 :
2 : #include "ErrorHandler/MessageAnalyzer/ma_rule.h"
3 : #include "ErrorHandler/MessageAnalyzer/ma_parse.h"
4 :
5 : #include <iostream>
6 :
7 : using fhicl::ParameterSet;
8 : using namespace novadaq::errorhandler;
9 :
10 0 : ma_rule::ma_rule(std::string const& rule_name, std::string const& rule_desc, bool repeat, int holdoff_time)
11 0 : : conditions()
12 0 : , conditions_idx()
13 0 : , primitive_cond()
14 0 : , cond_map(NULL)
15 0 : , name_(rule_name)
16 0 : , description_(rule_desc)
17 0 : , condition_expr()
18 0 : , alarm_count(0)
19 0 : , cond_names_()
20 0 : , alarm_msg()
21 0 : , boolean_expr()
22 0 : , domain_expr()
23 0 : , domains()
24 0 : , alarms()
25 0 : , itor_last_alarm(alarms.end())
26 0 : , repeat_alarm(repeat)
27 0 : , holdoff(holdoff_time)
28 0 : , initialized(false)
29 0 : , enabled(true)
30 0 : , actions()
31 : {
32 0 : }
33 :
34 0 : void ma_rule::parse(std::string const& cond_expr, std::string const& alarm_message, ParameterSet const& act_pset, cond_map_t* cond_map_ptr)
35 : {
36 0 : cond_map = cond_map_ptr;
37 0 : condition_expr = cond_expr;
38 :
39 : // condition expression
40 0 : if (!parse_condition_expr(cond_expr, this))
41 0 : throw std::runtime_error("rule parsing failed");
42 :
43 : // alarm message
44 0 : alarm_msg.init(this, alarm_message);
45 :
46 : // actions
47 0 : std::vector<std::string> keys = act_pset.get_pset_names();
48 0 : for (size_t i = 0; i < keys.size(); ++i)
49 : {
50 0 : ParameterSet param = act_pset.get<ParameterSet>(keys[i]);
51 0 : actions.push_back(ma_action_factory::create_instance(keys[i], this, param));
52 0 : }
53 :
54 : // init
55 0 : if (domain_expr.empty())
56 0 : domains.push_back(ma_domain_ctor_any(conditions.size()));
57 :
58 0 : initialized = true;
59 0 : }
60 :
61 : cond_idx_t
62 0 : ma_rule::insert_condition_ptr(std::string const& name, bool primitive)
63 : {
64 : // cond_map must not be empty
65 0 : assert(cond_map != NULL);
66 :
67 0 : TLOG(TLVL_DEBUG) << "insert_cond_ptr: name = " << name << " "
68 0 : << "primitive = " << primitive;
69 :
70 : // the condition has already been added
71 : {
72 0 : idx_t::const_iterator it = conditions_idx.find(name);
73 0 : if (it != conditions_idx.end())
74 : {
75 : // primitive cond overrides non-primitive cond
76 0 : primitive_cond[it->second] = primitive_cond[it->second] | primitive;
77 0 : return cond_idx_t(conditions[it->second], it->second);
78 : ;
79 : }
80 : }
81 :
82 : // look for the cond in the rule_engine container
83 0 : cond_map_t::iterator it = cond_map->find(name);
84 :
85 0 : if (it == cond_map->end()) // name not found
86 0 : throw std::runtime_error("insert_cond_ptr: condition " + name + " not found");
87 :
88 : // put this rule to the status notification list of the condition
89 0 : it->second.push_notify_status(this);
90 :
91 : // register the condition in the rule
92 0 : cond_names_.push_back(name);
93 0 : conditions.push_back(&it->second);
94 0 : primitive_cond.push_back(primitive);
95 :
96 0 : assert(conditions.size() == primitive_cond.size());
97 0 : size_t idx = conditions.size() - 1;
98 :
99 0 : conditions_idx.insert(std::make_pair(name, idx));
100 :
101 0 : return cond_idx_t(&it->second, idx);
102 : }
103 :
104 0 : void ma_rule::evaluate_domain()
105 : {
106 0 : assert(initialized);
107 :
108 : // re-evaluate domains
109 0 : domains.clear();
110 0 : domain_expr.evaluate(domains);
111 :
112 0 : TLOG(TLVL_DEBUG) << description_
113 0 : << ": domain evaluated, size = " << domains.size();
114 0 : }
115 :
116 0 : bool ma_rule::recursive_evaluate(ma_domain& value, ma_domain& alarm, ma_domain const& domain, size_t n)
117 : {
118 : // pre-conditions
119 0 : assert(!domain_is_null(domain[n]));
120 :
121 : // get range
122 0 : ma_cond_range src(D_NIL, D_NIL);
123 0 : ma_cond_range target(D_NIL, D_NIL);
124 :
125 : // a primitive condition (Cn) or non-primitive ( COUNT(Cn.$s|t) )
126 : // we only loop through possible values for primitive conditions
127 0 : if (primitive_cond[n])
128 0 : conditions[n]->get_cond_range(domain[n], src, target);
129 :
130 0 : TLOG(TLVL_DEBUG) << "depth: " << n << " "
131 0 : << "primitive_cond[n]: " << primitive_cond[n];
132 :
133 0 : for (int s = src.first; s <= src.second; ++s)
134 : {
135 0 : for (int t = target.first; t <= target.second; ++t)
136 : {
137 0 : value[n].first = s;
138 0 : value[n].second = t;
139 :
140 0 : TLOG(TLVL_DEBUG) << "depth: " << n << " "
141 0 : << "src: " << s << " "
142 0 : << "tgt: " << t;
143 :
144 0 : if (n != domain.size() - 1)
145 : {
146 0 : if (recursive_evaluate(value, alarm, domain, n + 1))
147 0 : return true;
148 : }
149 : else
150 : {
151 : // evaluate and, if found new alarm, no need to continue
152 0 : if (boolean_evaluate(value, alarm, domain))
153 0 : return true;
154 : }
155 : }
156 : }
157 :
158 0 : return false;
159 : }
160 :
161 0 : bool ma_rule::evaluate()
162 : {
163 0 : assert(initialized);
164 :
165 : // if disabled, always returns false
166 0 : if (!enabled) return false;
167 :
168 0 : TLOG(TLVL_DEBUG) << description_ << ": evaluate boolean expr...";
169 :
170 : // loop through domain alternatives
171 0 : for (ma_domains::const_iterator ait = domains.begin(); ait != domains.end(); ++ait)
172 : {
173 : // each domain consists a set of possible values for each condition
174 0 : ma_domain const& domain = *ait;
175 :
176 : // pre-condition
177 0 : assert(!domain_is_null(domain));
178 :
179 : // holds the one possible set of value
180 0 : ma_domain value = ma_domain_ctor_null(domain.size());
181 0 : ma_domain alarm = ma_domain_ctor_null(domain.size());
182 :
183 : // recursively build and evaluate possible values from domain
184 0 : if (recursive_evaluate(value, alarm, domain, 0))
185 0 : return true;
186 0 : }
187 :
188 0 : return false;
189 : }
190 :
191 0 : bool ma_rule::boolean_evaluate(ma_domain& value, ma_domain& alarm, ma_domain const& domain)
192 : {
193 0 : TLOG(TLVL_DEBUG) << "now evaluate boolean_expr with given value";
194 :
195 : // evaluate as true with given set of values
196 0 : if (boolean_expr.evaluate(value, alarm, domain))
197 : {
198 0 : TLOG(TLVL_DEBUG) << "alarm (" << alarm[0].first << ", "
199 0 : << alarm[0].second << ")";
200 :
201 0 : std::map<ma_domain, timeval>::iterator it = alarms.find(alarm);
202 0 : if (it == alarms.end())
203 : {
204 : // this is a new alarm. push the current domain to alarm list
205 : timeval tv;
206 0 : gettimeofday(&tv, 0);
207 0 : itor_last_alarm = alarms.insert(std::make_pair(alarm, tv)).first;
208 :
209 0 : alarm.clear();
210 0 : alarm = ma_domain_ctor_null(domain.size());
211 :
212 : // trigger new alarm
213 : // ...
214 :
215 0 : ++alarm_count;
216 :
217 0 : return true;
218 : }
219 :
220 0 : else if (repeat_alarm)
221 : {
222 : // not a new alarm, but the repeat_alarm flag has been set
223 : timeval tv;
224 0 : gettimeofday(&tv, 0);
225 0 : timeval lt = it->second;
226 0 : if (tv.tv_sec - lt.tv_sec > holdoff)
227 : {
228 : // passed the holdoff time, can refire a new alarm
229 0 : itor_last_alarm = alarms.insert(it, std::make_pair(alarm, tv));
230 :
231 0 : alarm.clear();
232 0 : alarm = ma_domain_ctor_null(domain.size());
233 :
234 : // trigger new alarm
235 : // ...
236 :
237 0 : ++alarm_count;
238 :
239 0 : return true;
240 : }
241 : }
242 :
243 : // otherwise, the alarm has already been triggered, or hasn't passed
244 : // the holdoff time
245 0 : TLOG(TLVL_DEBUG) << "this alarm has already been triggered";
246 : }
247 :
248 : // reset alarm
249 0 : alarm.clear();
250 0 : alarm = ma_domain_ctor_null(domain.size());
251 :
252 0 : return false;
253 : }
254 :
255 0 : int ma_rule::act()
256 : {
257 0 : int mask = 0;
258 0 : for (ma_actions::const_iterator it = actions.begin(), e = actions.end(); it != e; ++it)
259 : {
260 0 : if ((*it)->exec()) ++mask;
261 : }
262 0 : return mask;
263 : }
264 :
265 0 : void ma_rule::reset()
266 : {
267 : // clear user function state
268 0 : boolean_expr.reset();
269 :
270 : // reset all related conds
271 0 : cond_vec_t::iterator it = conditions.begin();
272 0 : for (; it != conditions.end(); ++it) (*it)->reset();
273 :
274 : // domains.clear();
275 0 : alarms.clear();
276 0 : itor_last_alarm = alarms.end();
277 0 : alarm_count = 0;
278 0 : }
279 :
280 0 : ma_domain const& ma_rule::get_alarm() const
281 : {
282 0 : if (alarms.empty())
283 0 : throw std::runtime_error("get_alarm_message(): no alarm has been triggerd");
284 :
285 : // make sure that the itor_last_alarm points to something
286 0 : assert(itor_last_alarm != alarms.end());
287 :
288 0 : return itor_last_alarm->first;
289 : }
290 :
291 0 : std::string ma_rule::get_alarm_message()
292 : {
293 0 : return alarm_msg.message();
294 : }
295 :
296 : // ----------------------------------------------------------------
297 : //
298 : // get condition index and pointer given a name
299 : cond_idx_t
300 0 : ma_rule::get_cond_idx(std::string const& name) const
301 : {
302 0 : idx_t::const_iterator it = conditions_idx.find(name);
303 0 : if (it == conditions_idx.end())
304 0 : throw std::runtime_error("get_cond_idx: name '" + name + "' not found");
305 0 : return cond_idx_t(conditions[it->second], it->second);
306 : }
307 :
308 : // get pointer to the condition
309 : ma_condition*
310 0 : ma_rule::get_cond(std::string const& name) const
311 : {
312 0 : idx_t::const_iterator it = conditions_idx.find(name);
313 0 : if (it == conditions_idx.end())
314 0 : throw std::runtime_error("get_cond: name '" + name + "' not found");
315 0 : return conditions[it->second];
316 : }
317 :
318 : // get index to the condition
319 : size_t
320 0 : ma_rule::get_idx(std::string const& name) const
321 : {
322 0 : idx_t::const_iterator it = conditions_idx.find(name);
323 0 : if (it == conditions_idx.end())
324 0 : throw std::runtime_error("get_cond: name '" + name + "' not found");
325 0 : return it->second;
326 : }
327 :
328 : // get the size of condition container
329 : size_t
330 0 : ma_rule::get_cond_size() const
331 : {
332 0 : assert(conditions.size() == conditions_idx.size());
333 0 : return conditions.size();
334 : }
335 :
336 : // update the "notify_on_source" or "notify_on_target" list
337 : // for corresponding conditions
338 0 : void ma_rule::update_notify_list(std::string const& name, arg_t arg)
339 : {
340 0 : idx_t::const_iterator it = conditions_idx.find(name);
341 :
342 0 : if (it == conditions_idx.end())
343 0 : throw std::runtime_error("update_notify_list: name '" + name + "' not found");
344 :
345 0 : (arg == SOURCE) ? conditions[it->second]->push_notify_source(this)
346 0 : : conditions[it->second]->push_notify_target(this);
347 0 : }
|