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