OpenSDN source code
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Pages
derived_stats.h
Go to the documentation of this file.
1 /*
2  * Copyright (c) 2016 Juniper Networks, Inc. All rights reserved.
3  */
4 
5 //
6 // derived_stats.h
7 //
8 // This file has the interface for derived stats
9 // towards the sandesh generated code, and
10 // the derived stats base class
11 //
12 
13 #ifndef __DERIVED_STATS_H__
14 #define __DERIVED_STATS_H__
15 
16 #include <string>
17 #include <boost/shared_ptr.hpp>
18 #include <boost/make_shared.hpp>
19 #include <boost/function.hpp>
20 #include <base/time_util.h>
21 
22 template <typename T>
24 
25 namespace contrail {
26 namespace sandesh {
27 
32 };
33 
34 template<typename ElemT>
35 std::map<std::string, ElemT> DerivedStatsAgg(const std::map<std::string, ElemT> & raw,
36  std::map<std::string, ElemT> & agg,
37  const std::map<std::string, bool> &del) {
38 
39  std::map<std::string, ElemT> diff;
40 
41  typename std::map<std::string, ElemT>::const_iterator rit;
42  typename std::map<std::string, ElemT>::iterator ait;
43 
44  // Go through all raw elements to generate diff and update agg
45  for (rit=raw.begin(); rit!= raw.end(); rit++) {
46  ait=agg.find(rit->first);
47  // The aggregate already has this element
48  if (ait!=agg.end()) {
49  diff[rit->first] = rit->second - ait->second;
50  // Remove from agg if this element is marked for deletion
51  // (It will still be in the diff)
52  if (!del.at(rit->first)) ait->second = ait->second + diff[rit->first];
53  else agg.erase(ait);
54  } else {
55  diff[rit->first] = rit->second;
56  if (!del.at(rit->first)) agg[rit->first] = diff[rit->first];
57  }
58  }
59  return diff;
60 }
61 
62 
63 template<template<class,class> class DSTT, typename ElemT, typename ResultT>
64 void DerivedStatsMerge(const std::map<std::string, ElemT> & raw,
65  std::map<std::string, boost::shared_ptr<DSTT<ElemT,ResultT> > > & dsm,
66  std::string annotation, const std::map<std::string, bool> &del,
67  uint64_t mono_usec) {
68 
69  std::map<std::string, bool> srcmap;
70  typename std::map<std::string, ElemT>::const_iterator rit;
71  std::map<std::string, bool>::const_iterator dlt;
72 
73  // If the new map is empty, clear all DS objects
74  if (raw.empty()) {
75  dsm.clear();
76  return;
77  }
78 
79  for(rit=raw.begin(); rit!= raw.end(); rit++) {
80  srcmap[rit->first] = false;
81  }
82 
83  // Go through all existing DS object
84  typename std::map<std::string,
85  boost::shared_ptr<DSTT<
86  ElemT,ResultT> > >::iterator dt = dsm.begin();
87  while (dt != dsm.end()) {
88  rit = raw.find(dt->first);
89  dlt = del.find(dt->first);
90  if (rit != raw.end()) {
91  assert(dlt!=del.end());
92  // we have information about this element
93  srcmap[rit->first] = true;
94  if (dlt->second) {
95  // raw element is requesting deletion
96  typename std::map<std::string,
97  boost::shared_ptr<DSTT<
98  ElemT,ResultT> > >::iterator et = dt;
99  dt++;
100  dsm.erase(et);
101  } else {
102  dt->second->Update(rit->second, mono_usec);
103  ++dt;
104  }
105  } else {
106  // We have no information about this element
107  ++dt;
108  }
109  }
110 
111  // Now add all new entries that are not requesting deletion
112  std::map<std::string, bool>::iterator mt;
113  for (mt = srcmap.begin(); mt != srcmap.end(); mt++) {
114  rit = raw.find(mt->first);
115  dlt = del.find(mt->first);
116  if ((mt->second == false) && (!dlt->second)) {
117  assert(dsm.find(mt->first) == dsm.end());
118  dsm[mt->first] = boost::make_shared<DSTT<ElemT,ResultT> >(annotation);
119  dsm[mt->first]->Update((raw.find(mt->first))->second, mono_usec);
120  }
121  }
122 }
123 
124 template <template<class,class> class DSTT, typename ElemT, typename ResultT>
126  private:
127  typedef std::map<std::string, boost::shared_ptr<DSTT<ElemT,ResultT> > > result_map;
128 
129  boost::shared_ptr<result_map> dsm_;
130 
131  boost::shared_ptr<DSTT<ElemT,ResultT> > ds_;
132 
133  std::string annotation_;
134 
135  bool is_agg_;
136  ElemT agg_;
137  std::map<std::string, ElemT> aggm_;
138  ElemT diff_;
139  std::map<std::string, ElemT> diffm_;
140 
141 
142  public:
143  DerivedStatsIf(std::string annotation, bool is_agg = false):
144  annotation_(annotation), is_agg_(is_agg) {}
145 
146  template<template<class,class> class, typename,
147  template<class,class> class, typename> friend class DerivedStatsPeriodicAnomalyIf;
148 
149  bool IsResult(void) const {
150  if ((!ds_) && (!dsm_)) return false;
151  else return true;
152  }
153 
154  // This is the interface to retrieve the current value
155  // of the DerivedStat object.
156  void FillResult(ResultT &res, bool& isset, bool force=false) const {
157  isset = false;
158  if (ds_) {
159  DSReturnType rt = ds_->FillResult(res);
160  if ((force && rt) || (!force && rt == DSR_OK)) {
161  isset = true;
162  }
163  }
164  }
165 
166  void FillResult(std::map<std::string, ResultT> &mres, bool& isset, bool force=false) const {
167  mres.clear();
168  if (dsm_) {
169  for (typename result_map::const_iterator dit = dsm_->begin();
170  dit != dsm_->end(); dit++) {
171  ResultT res;
172  DSReturnType rt = dit->second->FillResult(res);
173  if ((force && rt) || (!force && rt == DSR_OK)) {
174  mres.insert(std::make_pair(dit->first, res));
175  }
176  }
177  }
178  isset = !mres.empty();
179  return;
180  }
181 
182  // This is the interface to feed in all updates to the raw stat
183  // on which the derived stat will be based.
184  void Update(ElemT raw, uint64_t mono_usec) {
185  if (!ds_) {
186  ds_ = boost::make_shared<DSTT<ElemT,ResultT> >(annotation_);
187  if (is_agg_) {
188  diff_ = raw;
189  agg_ = raw;
190  }
191  } else {
192  if (is_agg_) {
193  diff_ = raw - agg_;
194  agg_ = agg_ + diff_;
195  }
196  }
197  if (is_agg_) ds_->Update(diff_, mono_usec);
198  else ds_->Update(raw, mono_usec);
199  }
200 
201  void Update(const std::map<std::string, ElemT> & raw,
202  const std::map<std::string, bool> &del, uint64_t mono_usec) {
203  if (!dsm_) {
204  dsm_ = boost::make_shared<result_map>();
205  }
206  if (is_agg_) {
207  diffm_ = DerivedStatsAgg<ElemT>(raw, aggm_, del);
208  DerivedStatsMerge<DSTT,ElemT,ResultT>(diffm_, *dsm_, annotation_, del, mono_usec);
209  } else {
210  DerivedStatsMerge<DSTT,ElemT,ResultT>(raw, *dsm_, annotation_, del, mono_usec);
211  }
212  }
213 };
214 
215 template <template<class,class> class DSTT, typename ElemT,
216 typename SubResultT, typename ResultT>
218  private:
219  typedef std::map<std::string, boost::shared_ptr<DSTT<ElemT,SubResultT> > > result_map;
220  boost::shared_ptr<result_map> dsm_;
221  boost::shared_ptr< std::map<std::string,ResultT> > dsm_cache_;
222 
223  boost::shared_ptr<DSTT<ElemT,SubResultT> > ds_;
224  boost::shared_ptr<ResultT> ds_cache_;
225 
226  std::string annotation_;
227 
228  bool is_agg_;
229  bool init_;
230  ElemT agg_;
231  std::map<std::string, ElemT> aggm_;
232  ElemT diff_;
233  std::map<std::string, ElemT> diffm_;
234 
235  public:
236  DerivedStatsPeriodicIf(std::string annotation, bool is_agg=false):
237  annotation_(annotation), is_agg_(is_agg), init_(false) {}
238 
239  bool IsResult(void) const {
240  if (ds_ || ds_cache_) return true;
241  if (dsm_ || dsm_cache_) return true;
242  return false;
243  }
244 
245  // This is the interface to feed in all updates to the raw stat
246  // on which the derived stat will be based.
247  void Update(ElemT raw, uint64_t mono_usec) {
248  if (!ds_) {
249  ds_ = boost::make_shared<DSTT<ElemT,SubResultT> >(annotation_);
250  }
251  if (is_agg_) {
252  if (!init_) {
253  diff_ = raw;
254  agg_ = raw;
255  } else {
256  diff_ = raw - agg_;
257  agg_ = agg_ + diff_;
258  }
259  ds_->Update(diff_, mono_usec);
260  } else ds_->Update(raw, mono_usec);
261  init_ = true;
262  }
263 
264  void Update(const std::map<std::string, ElemT> & raw,
265  const std::map<std::string, bool> &del, uint64_t mono_usec) {
266  if (!dsm_) {
267  dsm_ = boost::make_shared<result_map>();
268  }
269  if (is_agg_) {
270  diffm_ = DerivedStatsAgg<ElemT>(raw, aggm_, del);
271  DerivedStatsMerge<DSTT,ElemT,SubResultT>(
272  diffm_, *dsm_, annotation_, del, mono_usec);
273  } else DerivedStatsMerge<DSTT,ElemT,SubResultT>(
274  raw, *dsm_, annotation_, del, mono_usec);
275  init_ = true;
276  }
277 
278  bool Flush(const ResultT &res) {
279  (void)res;
280  if (!ds_) {
281  // There were no updates to the DerivedStat
282  // since the last flush
283  ds_cache_.reset();
284  return ds_cache_.get();
285  }
286  ds_cache_ = boost::make_shared<ResultT>();
287  if (ds_->FillResult(ds_cache_->value)) {
288  ds_cache_->__isset.value = true;
289  } else ds_cache_.reset();
290 
291  // Clear the DerivedStat
292  ds_.reset();
293 
294  return ds_cache_.get();
295  }
296 
297  // This is the interface to retrieve the current value
298  // of the DerivedStat object.
299  void FillResult(ResultT &res, bool& isset, bool force=false) const {
300  isset = false;
301  if (ds_cache_) {
302  // Fill in previous information
303  res.value = ds_cache_->value;
304  res.__isset.value = true;
305  isset = true;
306  }
307  if (ds_) {
308  // Fill in current information
309  DSReturnType rt = ds_->FillResult(res.staging);
310  if ((force && rt) || (!force && rt == DSR_OK)) {
311  res.__isset.staging = true;
312  isset = true;
313  }
314  }
315  }
316 
317  bool Flush(const std::map<std::string, ResultT> &mres) {
318  (void)mres;
319  if (!dsm_) {
320  // There were no updates to the DerivedStats
321  // since the last flush
322  dsm_cache_.reset();
323  return dsm_cache_.get();
324  }
325  dsm_cache_ = boost::make_shared<std::map<std::string,ResultT> >();
326  for (typename result_map::const_iterator dit = dsm_->begin();
327  dit != dsm_->end(); dit++) {
328  ResultT res;
329  if (dit->second->FillResult(res.value)) {
330  res.__isset.value = true;
331  dsm_cache_->insert(std::make_pair(dit->first, res));
332  }
333  }
334  if (dsm_cache_->empty()) dsm_cache_.reset();
335 
336  // Clear the DerivedStats
337  dsm_.reset();
338  return dsm_cache_.get();
339  }
340 
341  // This is the interface to retrieve the current value
342  // of the DerivedStat object.
343  void FillResult(std::map<std::string, ResultT> &mres, bool& isset, bool force=false) const {
344  mres.clear();
345  if (dsm_cache_) {
346  // Fill in previous information
347  for (typename std::map<std::string,ResultT>::const_iterator dit = dsm_cache_->begin();
348  dit != dsm_cache_->end(); dit++) {
349  ResultT res;
350  res.value = dit->second.value;
351  res.__isset.value = true;
352  mres.insert(std::make_pair(dit->first, res));
353  }
354  }
355  if (dsm_) {
356  for (typename result_map::const_iterator dit = (*dsm_).begin();
357  dit != (*dsm_).end(); dit++) {
358 
359  // If this derived stat had a previous value, merge the current into it.
360  typename std::map<std::string, ResultT>::iterator wit =
361  mres.find(dit->first);
362  if (wit != mres.end()) {
363  DSReturnType rt =
364  dit->second->FillResult(wit->second.staging);
365  if ((force && rt) || (!force && rt == DSR_OK)) {
366  wit->second.__isset.staging = true;
367  }
368  } else {
369  ResultT res;
370  DSReturnType rt =
371  dit->second->FillResult(res.staging);
372  if ((force && rt) || (!force && rt == DSR_OK)) {
373  res.__isset.staging = true;
374  mres.insert(std::make_pair(dit->first, res));
375  }
376  }
377  }
378  }
379  isset = !mres.empty();
380  }
381 
382 };
383 
385  public:
386  DSPeriodicIsSet() : value(false), staging(false) {}
387  bool value;
388  bool staging;
389 };
390 
391 template <typename ElemT>
392 class DSPeriodic {
393  public:
394 
395  DSPeriodic() : value(0), staging(0) {
396  }
397 
398  ElemT value;
399  ElemT staging;
400 
402 };
403 
404 template <template<class,class> class DSTT, typename ElemT,
405 template<class,class> class PreT, typename ResultT>
407  private:
409  typedef std::map<std::string, boost::shared_ptr<DSTT<ElemT,ResultT> > > result_map;
411  bool init_;
412 
413  public:
414  DerivedStatsPeriodicAnomalyIf(std::string annotation, bool is_agg=false):
415  periodic_("", is_agg),
416  anomaly_(annotation, false),
417  init_(false) {}
418 
419  bool IsResult(void) const {
420  return periodic_.IsResult();
421  }
422 
423  // This is the interface to feed in all updates to the raw stat
424  // on which the derived stat will be based.
425  void Update(ElemT raw, uint64_t mono_usec) {
426  init_ = true;
427  periodic_.Update(raw, mono_usec);
428  }
429 
430  void Update(const std::map<std::string, ElemT> & raw,
431  const std::map<std::string, bool> &del, uint64_t mono_usec) {
432  init_ = true;
433  periodic_.Update(raw, del, mono_usec);
434  }
435 
436  bool Flush(const ResultT &res) {
437  (void) res;
438  if (!init_) return false;
439  DSPeriodic<ElemT> sres;
440  static ElemT zelem;
441 
442  if (periodic_.Flush(sres)) {
443  bool result_available;
444  periodic_.FillResult(sres, result_available);
445  }
446 
447  // If there were no samples, we will assume the sum was 0
448  // the update time is not used by anomaly detection, so we can use 0
449  anomaly_.Update(sres.value, zelem);
450  return true;
451  }
452 
453  bool Flush(const std::map<std::string, ResultT> &mres) {
454  (void) mres;
455  if (!init_) return false;
456  typename std::map<std::string, DSPeriodic<ElemT> > smres;
457  static ElemT zelem;
458 
459  if (periodic_.Flush(smres)) {
460  bool result_available;
461  periodic_.FillResult(smres, result_available);
462  }
463 
464  typename std::map<std::string, ElemT> val;
465  std::map<std::string, bool> dmap;
466 
467  // Extract the reportable value of the periodic DerivedStat
468  for (typename std::map<std::string, DSPeriodic<ElemT> >::const_iterator
469  dit = smres.begin(); dit != smres.end(); dit++) {
470  val.insert(std::make_pair(dit->first, dit->second.value));
471  dmap.insert(std::make_pair(dit->first, false));
472  }
473 
474  if (anomaly_.dsm_) {
475  // If existing element has no sample, assume 0
476  for (typename result_map::const_iterator dit =
477  anomaly_.dsm_->begin();
478  dit != anomaly_.dsm_->end(); dit++) {
479  if (val.find(dit->first) == val.end()) {
480  val.insert(std::make_pair(dit->first, zelem));
481  dmap.insert(std::make_pair(dit->first, false));
482  }
483  }
484  }
485  anomaly_.Update(val, dmap, 0);
486 
487  return true;
488  }
489 
490  // This is the interface to retrieve the current value
491  // of the DerivedStat object.
492  void FillResult(ResultT &res, bool& isset, bool force=false) const {
493  anomaly_.FillResult(res, isset, force);
494  }
495 
496  void FillResult(std::map<std::string, ResultT> &mres, bool& isset, bool force=false) const {
497  anomaly_.FillResult(mres, isset, force);
498  }
499 };
500 
501 } // namespace sandesh
502 } // namespace contrail
503 #endif
void FillResult(ResultT &res, bool &isset, bool force=false) const
boost::shared_ptr< std::map< std::string, ResultT > > dsm_cache_
DerivedStatsIf(std::string annotation, bool is_agg=false)
void Update(const std::map< std::string, ElemT > &raw, const std::map< std::string, bool > &del, uint64_t mono_usec)
DerivedStatsPeriodicIf< PreT, ElemT, ElemT, DSPeriodic< ElemT > > periodic_
boost::shared_ptr< ResultT > ds_cache_
boost::shared_ptr< DSTT< ElemT, SubResultT > > ds_
bool Flush(const std::map< std::string, ResultT > &mres)
std::map< std::string, ElemT > diffm_
DerivedStatsPeriodicIf(std::string annotation, bool is_agg=false)
bool Flush(const std::map< std::string, ResultT > &mres)
void Update(ElemT raw, uint64_t mono_usec)
DerivedStatsIf< DSTT, ElemT, ResultT > anomaly_
std::map< std::string, ElemT > aggm_
void Update(ElemT raw, uint64_t mono_usec)
std::map< std::string, boost::shared_ptr< DSTT< ElemT, ResultT > > > result_map
boost::shared_ptr< DSTT< ElemT, ResultT > > ds_
DerivedStatsPeriodicAnomalyIf(std::string annotation, bool is_agg=false)
std::map< std::string, ElemT > aggm_
void Update(ElemT raw, uint64_t mono_usec)
void Update(const std::map< std::string, ElemT > &raw, const std::map< std::string, bool > &del, uint64_t mono_usec)
void DerivedStatsMerge(const std::map< std::string, ElemT > &raw, std::map< std::string, boost::shared_ptr< DSTT< ElemT, ResultT > > > &dsm, std::string annotation, const std::map< std::string, bool > &del, uint64_t mono_usec)
Definition: derived_stats.h:64
std::map< std::string, ElemT > diffm_
void FillResult(std::map< std::string, ResultT > &mres, bool &isset, bool force=false) const
std::map< std::string, boost::shared_ptr< DSTT< ElemT, SubResultT > > > result_map
void Update(const std::map< std::string, ElemT > &raw, const std::map< std::string, bool > &del, uint64_t mono_usec)
std::map< std::string, ElemT > DerivedStatsAgg(const std::map< std::string, ElemT > &raw, std::map< std::string, ElemT > &agg, const std::map< std::string, bool > &del)
Definition: derived_stats.h:35
void FillResult(ResultT &res, bool &isset, bool force=false) const
std::map< std::string, boost::shared_ptr< DSTT< ElemT, ResultT > > > result_map
void FillResult(std::map< std::string, ResultT > &mres, bool &isset, bool force=false) const
void FillResult(std::map< std::string, ResultT > &mres, bool &isset, bool force=false) const
boost::shared_ptr< result_map > dsm_
boost::shared_ptr< result_map > dsm_
void FillResult(ResultT &res, bool &isset, bool force=false) const