Browse code

core: pv - new parameters to control the size of pv cache

- pv_cache_limit - the limit how many pv declarations in the cache
after which an action is taken. Default value is 2048
- pv_cache_action - specify what action to be done when the size
of pv cache is exceeded. If 0, print an warning log message when
the limit is exceeded. If 1, warning log messages is printed and
the cache systems tries to drop a $sht(...) declaration. Default is 0

This tries to cope better with the situation of declaring too many
variables when using kemi scripts

Daniel-Constantin Mierla authored on 21/11/2017 10:02:38
Showing 5 changed files
... ...
@@ -437,6 +437,8 @@ KILL_TIMEOUT	"exit_timeout"|"ser_kill_timeout"
437 437
 MAX_WLOOPS		"max_while_loops"
438 438
 PVBUFSIZE		"pv_buffer_size"
439 439
 PVBUFSLOTS		"pv_buffer_slots"
440
+PVCACHELIMIT	"pv_cache_limit"
441
+PVCACHEACTION	"pv_cache_action"
440 442
 HTTP_REPLY_PARSE	"http_reply_hack"|"http_reply_parse"
441 443
 VERSION_TABLE_CFG	"version_table"
442 444
 VERBOSE_STARTUP		"verbose_startup"
... ...
@@ -917,6 +919,10 @@ IMPORTFILE      "import_file"
917 919
 									return PVBUFSIZE; }
918 920
 <INITIAL>{PVBUFSLOTS}			{	count(); yylval.strval=yytext;
919 921
 									return PVBUFSLOTS; }
922
+<INITIAL>{PVCACHELIMIT}			{	count(); yylval.strval=yytext;
923
+									return PVCACHELIMIT; }
924
+<INITIAL>{PVCACHEACTION}		{	count(); yylval.strval=yytext;
925
+									return PVCACHEACTION; }
920 926
 <INITIAL>{HTTP_REPLY_PARSE}		{	count(); yylval.strval=yytext;
921 927
 									return HTTP_REPLY_PARSE; }
922 928
 <INITIAL>{VERSION_TABLE_CFG}  { count(); yylval.strval=yytext; return VERSION_TABLE_CFG;}
... ...
@@ -475,6 +475,8 @@ extern char *default_routename;
475 475
 %token MAX_WLOOPS
476 476
 %token PVBUFSIZE
477 477
 %token PVBUFSLOTS
478
+%token PVCACHELIMIT
479
+%token PVCACHEACTION
478 480
 %token HTTP_REPLY_PARSE
479 481
 %token VERSION_TABLE_CFG
480 482
 %token VERBOSE_STARTUP
... ...
@@ -1554,8 +1556,12 @@ assign_stm:
1554 1556
 	| MAX_WLOOPS EQUAL error { yyerror("number expected"); }
1555 1557
 	| PVBUFSIZE EQUAL NUMBER { pv_set_buffer_size($3); }
1556 1558
 	| PVBUFSIZE EQUAL error { yyerror("number expected"); }
1557
-	| PVBUFSLOTS EQUAL NUMBER { pv_set_buffer_slots($3); }
1559
+	| PVBUFSLOTS EQUAL NUMBER { default_core_cfg.pv_cache_limit=$3; }
1558 1560
 	| PVBUFSLOTS EQUAL error { yyerror("number expected"); }
1561
+	| PVCACHELIMIT EQUAL NUMBER { default_core_cfg.pv_cache_action=$3; }
1562
+	| PVCACHELIMIT EQUAL error { yyerror("number expected"); }
1563
+	| PVCACHEACTION EQUAL NUMBER { pv_set_buffer_slots($3); }
1564
+	| PVCACHEACTION EQUAL error { yyerror("number expected"); }
1559 1565
 	| HTTP_REPLY_PARSE EQUAL NUMBER { http_reply_parse=$3; }
1560 1566
 	| HTTP_REPLY_PARSE EQUAL error { yyerror("boolean value expected"); }
1561 1567
 	| VERBOSE_STARTUP EQUAL NUMBER { ksr_verbose_startup=$3; }
... ...
@@ -120,7 +120,9 @@ struct cfg_group_core default_core_cfg = {
120 120
 	L_DBG, /*!< latency cfg log */
121 121
 	L_ERR, /*!< latency log */
122 122
 	0, /*!< latency limit db */
123
-	0 /*!< latency limit action */
123
+	0, /*!< latency limit action */
124
+	2048,  /*!< pv_cache_limit */
125
+	0  /*!< pv_cache_action */
124 126
 };
125 127
 
126 128
 void	*core_cfg = &default_core_cfg;
... ...
@@ -323,8 +325,12 @@ cfg_def_t core_cfg_def[] = {
323 325
 	{"latency_log",		CFG_VAR_INT|CFG_ATOMIC,	0, 0, 0, 0,
324 326
 		"log level for latency limits alert messages"},
325 327
 	{"latency_limit_db",		CFG_VAR_INT|CFG_ATOMIC,	0, 0, 0, 0,
326
-		"limit is ms for alerting on time consuming db commands"},
328
+		"limit in ms for alerting on time consuming db commands"},
327 329
 	{"latency_limit_action",		CFG_VAR_INT|CFG_ATOMIC,	0, 0, 0, 0,
328
-		"limit is ms for alerting on time consuming config actions"},
330
+		"limit in ms for alerting on time consuming config actions"},
331
+	{"pv_cache_limit",		CFG_VAR_INT|CFG_ATOMIC,	0, 0, 0, 0,
332
+		"limit to alert if too many vars in pv cache"},
333
+	{"pv_cache_action",		CFG_VAR_INT|CFG_ATOMIC,	0, 0, 0, 0,
334
+		"action to do if too many vars in pv cache"},
329 335
 	{0, 0, 0, 0, 0, 0}
330 336
 };
... ...
@@ -109,6 +109,8 @@ struct cfg_group_core {
109 109
 	int latency_log; /*!< log level for latency limits messages */
110 110
 	int latency_limit_db; /*!< alert limit of running db commands */
111 111
 	int latency_limit_action; /*!< alert limit of running cfg actions */
112
+	int pv_cache_limit; /*!< alert limit of having too many vars in pv cache */
113
+	int pv_cache_action; /*!< action to be taken on pv cache limit */
112 114
 };
113 115
 
114 116
 extern struct cfg_group_core default_core_cfg;
... ...
@@ -59,6 +59,8 @@ static int _pv_table_set = 0;
59 59
 
60 60
 static pv_cache_t* _pv_cache[PV_CACHE_SIZE];
61 61
 static int _pv_cache_set = 0;
62
+static int _pv_cache_counter = 0;
63
+static int _pv_cache_drop_index = 0;
62 64
 
63 65
 /**
64 66
  *
... ...
@@ -254,6 +256,67 @@ done:
254 256
 	return 0;
255 257
 }
256 258
 
259
+/**
260
+ *
261
+ */
262
+int pv_cache_drop(void)
263
+{
264
+	int i;
265
+	pv_cache_t *pvp;
266
+	pv_cache_t *pvi;
267
+
268
+	if(_pv_cache_set==0) {
269
+		LM_DBG("PV cache not initialized\n");
270
+		return 0;
271
+	}
272
+	/* round-robin on slots to find a $sht(...) to drop */
273
+	_pv_cache_drop_index = (_pv_cache_drop_index + 1) % PV_CACHE_SIZE;
274
+	for(i=_pv_cache_drop_index; i<PV_CACHE_SIZE; i++) {
275
+		pvi = _pv_cache[i];
276
+		pvp = NULL;
277
+		while(pvi) {
278
+			if(pvi->pvname.len>5 && strncmp(pvi->pvname.s, "$sht(", 5)==0) {
279
+				LM_DBG("dropping from pv cache [%d]: %.*s\n", i,
280
+						pvi->pvname.len, pvi->pvname.s);
281
+				if(pvp) {
282
+					pvp->next = pvi->next;
283
+				} else {
284
+					_pv_cache[i] = pvi->next;
285
+				}
286
+				if(pvi->spec.pvp.pvn.nfree) {
287
+					pvi->spec.pvp.pvn.nfree((void*)(&pvi->spec.pvp.pvn));
288
+				}
289
+				pkg_free(pvi);
290
+				return 1;
291
+			}
292
+			pvi = pvi->next;
293
+		}
294
+	}
295
+	for(i=0; i<_pv_cache_drop_index; i++) {
296
+		pvi = _pv_cache[i];
297
+		pvp = NULL;
298
+		while(pvi) {
299
+			if(pvi->pvname.len>5 && strncmp(pvi->pvname.s, "$sht(", 5)==0) {
300
+				LM_DBG("dropping from pv cache [%d]: %.*s\n", i,
301
+						pvi->pvname.len, pvi->pvname.s);
302
+				if(pvp) {
303
+					pvp->next = pvi->next;
304
+				} else {
305
+					_pv_cache[i] = pvi->next;
306
+				}
307
+				if(pvi->spec.pvp.pvn.nfree) {
308
+					pvi->spec.pvp.pvn.nfree((void*)(&pvi->spec.pvp.pvn));
309
+				}
310
+				pkg_free(pvi);
311
+				return 1;
312
+			}
313
+			pvi = pvi->next;
314
+		}
315
+	}
316
+	LM_WARN("no suitable variable found to drop from pv cache\n");
317
+	return 0;
318
+}
319
+
257 320
 /**
258 321
  *
259 322
  */
... ...
@@ -268,6 +331,16 @@ pv_spec_t* pv_cache_add(str *name)
268 331
 		LM_DBG("PV cache not initialized, doing it now\n");
269 332
 		pv_init_cache();
270 333
 	}
334
+	if(_pv_cache_counter+1>=cfg_get(core, core_cfg, pv_cache_limit)) {
335
+		if(_pv_cache_counter+1==cfg_get(core, core_cfg, pv_cache_limit)) {
336
+			LM_WARN("pv cache limit is going to be exceeded"
337
+					" - pkg memory may get filled with pv declarations\n");
338
+		} else {
339
+			if(cfg_get(core, core_cfg, pv_cache_action)==1) {
340
+				pv_cache_drop();
341
+			}
342
+		}
343
+	}
271 344
 	pvid = get_hash1_raw(name->s, name->len);
272 345
 	pvn = (pv_cache_t*)pkg_malloc(sizeof(pv_cache_t) + name->len + 1);
273 346
 	if(pvn==0)