@@ -203,3 +203,78 @@ bool DuplicateFilter::matchDef(const Defect &def)
203203
204204 return d->lookup .insert (evt)./* inserted */ second;
205205}
206+
207+
208+ // /////////////////////////////////////////////////////////////////////////////
209+ // implementation of RateLimitter
210+
211+ struct RateLimitter ::Private {
212+ using TKey = std::pair<std::string, std::string>;
213+ using TCnt = int ;
214+ using TMap = std::map<TKey, TCnt>;
215+ TMap counter;
216+ TCnt rateLimit;
217+ };
218+
219+ RateLimitter::RateLimitter (AbstractWriter *agent, int rateLimit):
220+ AbstractFilter(agent),
221+ d(new Private)
222+ {
223+ d->rateLimit = rateLimit;
224+ }
225+
226+ bool RateLimitter::matchDef (const Defect &def)
227+ {
228+ // resolve the checker/event pair for the key event
229+ const DefEvent &evt = def.events [def.keyEventIdx ];
230+ const Private::TKey key (def.checker , evt.event );
231+
232+ // increment the counter and get the current value
233+ const Private::TCnt cnt = ++d->counter [key];
234+
235+ // check whether the specified limit is exceeded
236+ return (cnt < d->rateLimit );
237+ }
238+
239+ void RateLimitter::flush ()
240+ {
241+ for (const auto &item : d->counter ) {
242+ const Private::TCnt cnt = item.second ;
243+ if (cnt < d->rateLimit )
244+ // limit not exceeded for this checker/event pair
245+ continue ;
246+
247+ // resolve the checker/event pair
248+ const Private::TKey &key = item.first ;
249+ const std::string &checker = key.first ;
250+ const std::string &keyEvtName = key.second ;
251+
252+ // construct an error event
253+ std::ostringstream err, note;
254+ err << cnt << " occurrences of " << keyEvtName
255+ << " exceeded the specified limit "
256+ << d->rateLimit ;
257+
258+ DefEvent evtErr (" error[too-many]" );
259+ evtErr.msg = err.str ();
260+
261+ // construct a note event
262+ note << (cnt - d->rateLimit ) << " occurrences of "
263+ << keyEvtName << " were discarded because of this" ;
264+
265+ DefEvent evtNote (" note" );
266+ evtNote.msg = note.str ();
267+ evtNote.verbosityLevel = /* info */ 1 ;
268+
269+ // construct a defect containing the above events
270+ Defect def (checker);
271+ def.events .push_back (evtErr);
272+ def.events .push_back (evtNote);
273+
274+ // process the newly constructed defect by the chain of writers
275+ GenericAbstractFilter::handleDef (def);
276+ }
277+
278+ // forward the call through the chain of writers
279+ AbstractFilter::flush ();
280+ }
0 commit comments