- transactions are now deleted when their reference counter reaches 0
authorAndrei Pelinescu-Onciul <andrei@iptel.org>
Tue, 29 May 2007 23:59:34 +0000 (23:59 +0000)
committerAndrei Pelinescu-Onciul <andrei@iptel.org>
Tue, 29 May 2007 23:59:34 +0000 (23:59 +0000)
 (this removes the need for the delete timer hack and some extra locking and
  it should reduce memory usage in very busy situations). For now it's still
  possible to revert to the old behaviour by removing the TM_DEL_UNREF define
  in h_table.h.

Makefile.defs
modules/tm/h_table.h
modules/tm/t_funcs.h
modules/tm/t_lookup.c
modules/tm/timer.c
modules/tm/timer.h
modules/tm/uac.c

index bccbe70..4db5e8d 100644 (file)
@@ -75,7 +75,7 @@ MAIN_NAME=ser
 VERSION = 2
 PATCHLEVEL = 1
 SUBLEVEL =  0
-EXTRAVERSION = -dev3
+EXTRAVERSION = -dev4-tm
 
 SER_VER = $(shell expr $(VERSION) \* 1000000 + $(PATCHLEVEL) \* 1000 + \
                        $(SUBLEVEL) )
index 3044afa..678199c 100644 (file)
  * 2004-08-23  avp support added - avp list linked in transaction (bogdan)
  * 2005-11-03  updated to the new timer interface (dropped tm timers) (andrei)
  * 2006-08-11  dns failover support (andrei)
+ * 2007-05-29  switch ref_count to atomic and delete a cell automatically on
+ *             UNREF if the ref_count reaches 0 (andrei)
  */
 
 #include "defs.h"
 
 
+#define TM_DEL_UNREF
+
 #ifndef _H_TABLE_H
 #define _H_TABLE_H
 
@@ -55,6 +59,7 @@
 #include "../../md5utils.h"
 #include "../../usr_avp.h"
 #include "../../timer.h"
+#include "../../atomic_ops.h"
 #include "config.h"
 
 struct s_table;
@@ -72,6 +77,7 @@ struct retr_buf;
 #include "../../dns_cache.h"
 #endif
 
+
 #define LOCK_HASH(_h) lock_hash((_h))
 #define UNLOCK_HASH(_h) unlock_hash((_h))
 
@@ -223,6 +229,19 @@ typedef struct cell
        /* number of forks */
        short nr_of_outgoings;
 
+#ifdef TM_DEL_UNREF
+       /* every time the transaction/cell is referenced from somewhere this
+        * ref_count should be increased (via REF()) and every time the reference
+        * is removed the ref_count should be decreased (via UNREF()).
+        * This includes adding the cell to the hash table (REF() before adding)
+        * and removing it from the hash table (UNREF_FREE() after unlinking).
+        * Exception: it does not include starting/stopping timers (timers are 
+        * forced-stopped every time when ref_count reaches 0)
+        * If the cell is no longer referenced (ref_count==0 after an UNREF),
+        * it will be automatically deleted by the UNREF() operation.
+        */
+       atomic_t ref_count;
+#else 
        /* how many processes are currently processing this transaction ;
           note that only processes working on a request/reply belonging
           to a transaction increase ref_count -- timers don't, since we
@@ -233,6 +252,7 @@ typedef struct cell
           tries to delete a transaction whereas at the same time 
           a delayed message belonging to the transaction is received */
        volatile unsigned int ref_count;
+#endif
 
        /* needed for generating local ACK/CANCEL for local
           transactions; all but cseq_n include the entire
index 0495b58..43d49aa 100644 (file)
@@ -59,6 +59,7 @@
 #include "../../ip_addr.h"
 #include "../../parser/parse_uri.h"
 #include "../../usr_avp.h"
+#include "../../atomic_ops.h"
 
 #include "config.h"
 #include "lock.h"
@@ -104,6 +105,27 @@ int send_pr_buffer( struct retr_buf *rb, void *buf, int len);
        SEND_PR_BUFFER( (_rb) , (_rb)->buffer , (_rb)->buffer_len )
 
 
+
+#ifdef TM_DEL_UNREF
+
+
+#define UNREF_FREE(_T_cell) \
+       do{\
+               if (atomic_dec_and_test(&(_T_cell)->ref_count)){ \
+                       unlink_timers((_T_cell)); \
+                       free_cell((_T_cell)); \
+               }\
+       }while(0)
+
+#define UNREF_UNSAFE(_T_cell) UNREF_FREE(_T_cell)
+/* all the version are safe when using atomic ops */
+#define UNREF(_T_cell) UNREF_UNSAFE(_T_cell); 
+#define REF(_T_cell) (atomic_inc(&(_T_cell)->ref_count))
+#define REF_UNSAFE(_T_cell)  REF(_T_cell)
+#define INIT_REF(_T_cell, v) atomic_set(&(_T_cell)->ref_count, v)
+
+#else
+
 #define UNREF_UNSAFE(_T_cell) ((_T_cell)->ref_count--)
 #define UNREF(_T_cell) do{ \
        LOCK_HASH( (_T_cell)->hash_index ); \
@@ -113,6 +135,7 @@ int send_pr_buffer( struct retr_buf *rb, void *buf, int len);
 #define INIT_REF_UNSAFE(_T_cell) ((_T_cell)->ref_count=1)
 #define IS_REFFED_UNSAFE(_T_cell) ((_T_cell)->ref_count!=0)
 
+#endif
 /*
  * Parse and fixup the fr_*_timer AVP specs
  */
index 656b088..230bf40 100644 (file)
@@ -1131,9 +1131,15 @@ static inline int new_t(struct sip_msg *p_msg)
                return E_OUT_OF_MEM;
        } 
 
+#ifdef TM_DEL_UNREF
+       INIT_REF(new_cell, 2); /* 1 because it will be ref'ed from the
+                                                                          hash and +1 because we set T to it */
+#endif
        insert_into_hash_table_unsafe( new_cell, p_msg->hash_index );
        set_t(new_cell);
+#ifndef TM_DEL_UNREF
        INIT_REF_UNSAFE(T);
+#endif
        /* init pointers to headers needed to construct local
           requests such as CANCEL/ACK
        */
index 23aebe4..e3288de 100644 (file)
  *              set the corresponding "faked" failure route sip_msg->msg_flags 
  *               on timeout or if the branch received a reply (andrei)
  *  2007-03-15  TMCB_ONSEND callbacks support (andrei)
+ *  2007-05-29  delete on transaction ref_count==0 : removed the delete timer
+ *               (andrei)
  */
 
 #include "defs.h"
@@ -184,28 +186,7 @@ int tm_init_timers()
 /******************** handlers ***************************/
 
 
-
-inline static void cleanup_localcancel_timers( struct cell *t )
-{
-       int i;
-       for (i=0; i<t->nr_of_outgoings; i++ )
-               stop_rb_timers(&t->uac[i].local_cancel);
-}
-
-
-
-inline static void unlink_timers( struct cell *t )
-{
-       int i;
-
-       stop_rb_timers(&t->uas.response);
-       for (i=0; i<t->nr_of_outgoings; i++)
-               stop_rb_timers(&t->uac[i].request);
-       cleanup_localcancel_timers(t);
-}
-
-
-
+#ifndef TM_DEL_UNREF
 /* returns number of ticks before retrying the del, or 0 if the del.
  * was succesfull */
 inline static ticks_t  delete_cell( struct cell *p_cell, int unlock )
@@ -233,6 +214,7 @@ inline static ticks_t  delete_cell( struct cell *p_cell, int unlock )
                return 0;
        }
 }
+#endif /* TM_DEL_UNREF */
 
 
 
@@ -547,6 +529,17 @@ ticks_t wait_handler(ticks_t ti, struct timer_ln *wait_tl, void* data)
                        ti, p_cell, wait_tl);
 #endif
 
+#ifdef TM_DEL_UNREF
+       /* stop cancel timers if any running */
+       if ( is_invite(p_cell) ) cleanup_localcancel_timers( p_cell );
+       /* remove the cell from the hash table */
+       LOCK_HASH( p_cell->hash_index );
+       remove_from_hash_table_unsafe(  p_cell );
+       UNLOCK_HASH( p_cell->hash_index );
+       p_cell->flags |= T_IN_AGONY;
+       UNREF_FREE(p_cell);
+       ret=0;
+#else /* TM_DEL_UNREF */
        if (p_cell->flags & T_IN_AGONY){
                /* delayed delete */
                /* we call delete now without any locking on hash/ref_count;
@@ -559,7 +552,7 @@ ticks_t wait_handler(ticks_t ti, struct timer_ln *wait_tl, void* data)
                   zero safely without locking
                */
                ret=delete_cell( p_cell, 0 /* don't unlock on return */ );
-       }else{
+       }else {
                /* stop cancel timers if any running */
                if ( is_invite(p_cell) ) cleanup_localcancel_timers( p_cell );
                /* remove the cell from the hash table */
@@ -569,6 +562,7 @@ ticks_t wait_handler(ticks_t ti, struct timer_ln *wait_tl, void* data)
                /* delete (returns with UNLOCK-ed_HASH) */
                ret=delete_cell( p_cell, 1 /* unlock on return */ );
        }
+#endif /* TM_DEL_UNREF */
        return ret;
 }
 
index 9d608bb..f8a8f43 100644 (file)
@@ -162,4 +162,25 @@ inline static void change_fr(struct cell* t, ticks_t fr_inv, ticks_t fr)
 }
 
 
+inline static void cleanup_localcancel_timers( struct cell *t )
+{
+       int i;
+       for (i=0; i<t->nr_of_outgoings; i++ )
+               stop_rb_timers(&t->uac[i].local_cancel);
+}
+
+
+
+inline static void unlink_timers( struct cell *t )
+{
+       int i;
+
+       stop_rb_timers(&t->uas.response);
+       for (i=0; i<t->nr_of_outgoings; i++)
+               stop_rb_timers(&t->uac[i].request);
+       cleanup_localcancel_timers(t);
+}
+
+
+
 #endif
index 46d3adb..9228a7c 100644 (file)
@@ -169,6 +169,13 @@ static inline unsigned int dlg2hash( dlg_t* dlg )
        return hashid;
 }
 
+
+/* WARNING: - dst_cell contains the created cell, but it is un-referenced
+ *            (before using it make sure you REF() it first)
+ *          - if  ACK (method==ACK), a cell will be created but it will not
+ *            be added in the hash table (should be either deleted by the 
+ *            caller) 
+ */
 static inline int t_uac_prepare(str* method, str* headers, str* body, 
                dlg_t* dialog, transaction_cb cb, void* cbp, struct retr_buf **dst_req,
                struct cell **dst_cell)
@@ -276,6 +283,9 @@ static inline int t_uac_prepare(str* method, str* headers, str* body,
        request->dst = dst;
 
        if (!is_ack) {
+#ifdef TM_DEL_UNREF
+               INIT_REF(new_cell, 1); /* ref'ed only from the hash */
+#endif
                hi=dlg2hash(dialog);
                LOCK_HASH(hi);
                insert_into_hash_table_unsafe(new_cell, hi);
@@ -304,6 +314,9 @@ static inline int t_uac_prepare(str* method, str* headers, str* body,
 #endif /* DIALOG_CALLBACKS */
        if (dst_req) *dst_req = request;
        if (dst_cell) *dst_cell = new_cell;
+       else if(is_ack && dst_req==0){
+               free_cell(new_cell);
+       }
        
        return 1;
 
@@ -312,8 +325,13 @@ static inline int t_uac_prepare(str* method, str* headers, str* body,
                LOCK_HASH(hi);
                remove_from_hash_table_unsafe(new_cell);
                UNLOCK_HASH(hi);
+#ifdef TM_DEL_UNREF
+               UNREF_FREE(new_cell);
+       }else
+#else
        }
-       free_cell(new_cell);
+#endif
+               free_cell(new_cell);
 error2:
        return ret;
 }