Module: sip-router
Branch: master
Commit: b24b560af3acaec10c61d0709d7b1ad63c377b92
URL:
http://git.sip-router.org/cgi-bin/gitweb.cgi/sip-router/?a=commit;h=b24b560…
Author: Daniel-Constantin Mierla <miconda(a)gmail.com>
Committer: Daniel-Constantin Mierla <miconda(a)gmail.com>
Date: Tue Sep 6 21:44:12 2011 +0200
core: caching support for pv spec parsing
- can be used to reduce pkg memory usage by PVs
- solves memory leak of using PVs with dynamic names from embedded
languages
---
pvapi.c | 196 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++-
pvar.h | 3 +
2 files changed, 197 insertions(+), 2 deletions(-)
diff --git a/pvapi.c b/pvapi.c
index ff76eb2..940f017 100644
--- a/pvapi.c
+++ b/pvapi.c
@@ -40,8 +40,9 @@
#include "pvapi.h"
#include "pvar.h"
-#define PV_TABLE_SIZE 16 /*!< pseudo-variable table size */
-#define TR_TABLE_SIZE 4 /*!< PV transformation size */
+#define PV_TABLE_SIZE 32 /*!< pseudo-variables table size */
+#define PV_CACHE_SIZE 32 /*!< pseudo-variables table size */
+#define TR_TABLE_SIZE 16 /*!< transformations table size */
void tr_destroy(trans_t *t);
@@ -57,6 +58,16 @@ typedef struct _pv_item
static pv_item_t* _pv_table[PV_TABLE_SIZE];
static int _pv_table_set = 0;
+typedef struct _pv_cache
+{
+ str pvname;
+ unsigned int pvid;
+ pv_spec_t spec;
+ struct _pv_cache *next;
+} pv_cache_t;
+
+static pv_cache_t* _pv_cache[PV_CACHE_SIZE];
+static int _pv_cache_set = 0;
/**
*
@@ -68,6 +79,16 @@ void pv_init_table(void)
}
/**
+ *
+ */
+void pv_init_cache(void)
+{
+ memset(_pv_cache, 0, sizeof(pv_cache_t*)*PV_CACHE_SIZE);
+ _pv_cache_set = 1;
+}
+
+
+/**
* @brief Check if a char is valid according to the PV syntax
* @param c checked char
* @return 1 if char is valid, 0 if not valid
@@ -83,6 +104,75 @@ static int is_pv_valid_char(char c)
/**
*
*/
+int pv_locate_name(str *in)
+{
+ int i;
+ int pcount;
+
+ if(in==NULL || in->s==NULL || in->len<2)
+ {
+ LM_ERR("bad parameters\n");
+ return -1;
+ }
+
+ if(in->s[0]!=PV_MARKER)
+ {
+ LM_ERR("missing pv marker [%.*s]\n", in->len, in->s);
+ return -1;
+ }
+ pcount = 0;
+ if(in->s[1]==PV_LNBRACKET)
+ {
+ /* name with parenthesis: $(...) */
+ pcount = 1;
+ for(i=1; i<in->len; i++)
+ {
+ if(in->s[i]==PV_LNBRACKET)
+ pcount++;
+ else if(in->s[i]==PV_RNBRACKET)
+ pcount--;
+ if(pcount==0)
+ return i+1;
+ }
+ /* non-closing name parenthesis */
+ return -1;
+ }
+
+ /* name without parenthesis: $xyz(...) */
+ for(i=1; i<in->len; i++)
+ {
+ if(!is_pv_valid_char(in->s[i]))
+ {
+ if(in->s[i]==PV_LNBRACKET)
+ {
+ /* inner-name parenthesis */
+ pcount = 1;
+ break;
+ } else {
+ return i;
+ }
+ }
+ }
+ if(pcount==0)
+ return i;
+
+ i++;
+ for( ; i<in->len; i++)
+ {
+ if(in->s[i]==PV_LNBRACKET)
+ pcount++;
+ else if(in->s[i]==PV_RNBRACKET)
+ pcount--;
+ if(pcount==0)
+ return i+1;
+ }
+ /* non-closing inner-name parenthesis */
+ return -1;
+}
+
+/**
+ *
+ */
int pv_table_add(pv_export_t *e)
{
char *p;
@@ -162,6 +252,108 @@ done:
/**
*
*/
+pv_spec_t* pv_cache_add(str *name)
+{
+ pv_cache_t *pvn;
+ unsigned int pvid;
+ char *p;
+
+ if(_pv_cache_set==0)
+ {
+ LM_DBG("PV cache not initialized, doing it now\n");
+ pv_init_cache();
+ }
+ pvid = get_hash1_raw(name->s, name->len);
+ pvn = (pv_cache_t*)pkg_malloc(sizeof(pv_cache_t) + name->len + 1);
+ if(pvn==0)
+ {
+ LM_ERR("no more memory\n");
+ return NULL;
+ }
+ memset(pvn, 0, sizeof(pv_item_t) + name->len + 1);
+ p = pv_parse_spec(name, &pvn->spec);
+
+ if(p==NULL)
+ {
+ pkg_free(pvn);
+ return NULL;
+ }
+ pvn->pvname.len = name->len;
+ pvn->pvname.s = (char*)pvn + sizeof(pv_cache_t);
+ memcpy(pvn->pvname.s, name->s, name->len);
+ pvn->pvid = pvid;
+ pvn->next = _pv_cache[pvid%PV_CACHE_SIZE];
+ _pv_cache[pvid%PV_CACHE_SIZE] = pvn;
+
+ LM_DBG("pvar [%.*s] added in cache\n", name->len, name->s);
+ return &pvn->spec;
+}
+
+/**
+ *
+ */
+pv_spec_t* pv_cache_lookup(str *name)
+{
+ pv_cache_t *pvi;
+ unsigned int pvid;
+ int found;
+
+ if(_pv_cache_set==0)
+ return NULL;
+
+ pvid = get_hash1_raw(name->s, name->len);
+ pvi = _pv_cache[pvid%PV_CACHE_SIZE];
+ while(pvi)
+ {
+ if(pvi->pvid == pvid) {
+ if(pvi->pvname.len==name->len)
+ {
+ found = strncmp(pvi->pvname.s, name->s, name->len);
+
+ if(found==0)
+ {
+ LM_DBG("pvar [%.*s] found in cache\n",
+ name->len, name->s);
+ return &pvi->spec;
+ }
+ }
+ }
+ pvi = pvi->next;
+ }
+ return NULL;
+}
+
+/**
+ *
+ */
+pv_spec_t* pv_cache_get(str *name)
+{
+ pv_spec_t *pvs;
+ str tname;
+
+ if(name->s==NULL || name->len==0)
+ {
+ LM_ERR("invalid parameters\n");
+ return NULL;
+ }
+
+ tname.s = name->s;
+ tname.len = pv_locate_name(name);
+
+ if(tname.len < 0)
+ return NULL;
+
+ pvs = pv_cache_lookup(&tname);
+
+ if(pvs!=NULL)
+ return pvs;
+
+ return pv_cache_add(&tname);
+}
+
+/**
+ *
+ */
int register_pvars_mod(char *mod_name, pv_export_t *items)
{
int ret;
diff --git a/pvar.h b/pvar.h
index e7701f2..df83e69 100644
--- a/pvar.h
+++ b/pvar.h
@@ -204,6 +204,9 @@ pvname_list_t* parse_pvname_list(str *in, unsigned int type);
int register_pvars_mod(char *mod_name, pv_export_t *items);
int pv_free_extra_list(void);
+int pv_locate_name(str *in);
+pv_spec_t* pv_cache_get(str *name);
+
/*! \brief PV helper functions */
int pv_get_null(struct sip_msg *msg, pv_param_t *param, pv_value_t *res);