Module: sip-router
Branch: master
Commit: b24b560af3acaec10c61d0709d7b1ad63c377b92
URL:    
http://git.sip-router.org/cgi-bin/gitweb.cgi/sip-router/?a=commit;h=b24b560af3acaec10c61d0709d7b1ad63c377b92

Author: Daniel-Constantin Mierla <[email protected]>
Committer: Daniel-Constantin Mierla <[email protected]>
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);
 


_______________________________________________
sr-dev mailing list
[email protected]
http://lists.sip-router.org/cgi-bin/mailman/listinfo/sr-dev

Reply via email to