23
23
24
24
#include < fstream>
25
25
#include < iomanip>
26
+ #include < queue>
26
27
#include < set>
27
28
#include < sstream>
28
29
@@ -209,10 +210,17 @@ bool DuplicateFilter::matchDef(const Defect &def)
209
210
// implementation of RateLimitter
210
211
211
212
struct RateLimitter ::Private {
213
+ // counter of checker/key-event pairs
212
214
using TKey = std::pair<std::string, std::string>;
213
215
using TCnt = int ;
214
216
using TMap = std::map<TKey, TCnt>;
215
217
TMap counter;
218
+
219
+ // list of defects where the limit was exceeded
220
+ using TErrorList = std::queue<Defect>;
221
+ TErrorList errors;
222
+
223
+ // rate limit set during initialization
216
224
TCnt rateLimit;
217
225
};
218
226
@@ -226,50 +234,59 @@ RateLimitter::RateLimitter(AbstractWriter *agent, int rateLimit):
226
234
bool RateLimitter::matchDef (const Defect &def)
227
235
{
228
236
// resolve the checker/event pair for the key event
229
- const DefEvent & evt = def.events [def.keyEventIdx ];
237
+ DefEvent evt = def.events [def.keyEventIdx ];
230
238
const Private::TKey key (def.checker , evt.event );
231
239
232
240
// increment the counter and get the current value
233
241
const Private::TCnt cnt = ++d->counter [key];
234
242
235
243
// check whether the specified limit is exceeded
236
- return (cnt < d->rateLimit );
244
+ if (cnt < d->rateLimit )
245
+ return true ;
246
+
247
+ if (cnt == d->rateLimit ) {
248
+ // record defect prototype containing the key event only (without msg)
249
+ evt.msg .clear ();
250
+
251
+ Defect defProto = def;
252
+ defProto.events .clear ();
253
+ defProto.events .push_back (std::move (evt));
254
+ d->errors .push (std::move (defProto));
255
+ }
256
+
257
+ // limit exceeded
258
+ return false ;
237
259
}
238
260
239
261
void RateLimitter::flush ()
240
262
{
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 ;
263
+ for (; !d->errors .empty (); d->errors .pop ()) {
264
+ Defect &def = d->errors .front ();
246
265
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 ;
266
+ // resolve the count of occurrences for this checker/event pair
267
+ const DefEvent &keyEvt = def. events [def. keyEventIdx ] ;
268
+ const Private::TKey key (def. checker , keyEvt. event ) ;
269
+ const Private::TCnt cnt = d-> counter [ key] ;
251
270
252
271
// construct an error event
253
272
std::ostringstream err, note;
254
- err << cnt << " occurrences of " << keyEvtName
273
+ err << cnt << " occurrences of " << keyEvt. event
255
274
<< " exceeded the specified limit "
256
275
<< d->rateLimit ;
257
276
258
- DefEvent evtErr (" error[too-many]" );
277
+ DefEvent &evtErr = def.events .back ();
278
+ evtErr.event = " error[too-many]" ;
259
279
evtErr.msg = err.str ();
260
280
261
281
// construct a note event
262
282
note << (cnt - d->rateLimit ) << " occurrences of "
263
- << keyEvtName << " were discarded because of this" ;
283
+ << keyEvt. event << " were discarded because of this" ;
264
284
265
- DefEvent evtNote (" note" );
285
+ DefEvent evtNote = evtErr;
286
+ evtNote.event = " note" ;
266
287
evtNote.msg = note.str ();
267
288
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);
289
+ def.events .push_back (std::move (evtNote));
273
290
274
291
// process the newly constructed defect by the chain of writers
275
292
GenericAbstractFilter::handleDef (def);
0 commit comments