From 8f0fc94aaa6db96ef209c6136240d98ef566a004 Mon Sep 17 00:00:00 2001 From: Daniel-Constantin Mierla Date: Thu, 14 Sep 2017 09:21:08 +0200 Subject: [PATCH] tm: rpc command to clean long time expired transactions - try hard clean after 90 seconds since lifetime elapsed --- src/modules/tm/h_table.c | 59 ++++++++++++++++++++++++++++++++++++++++ src/modules/tm/h_table.h | 2 ++ src/modules/tm/t_stats.c | 9 +++++- src/modules/tm/t_stats.h | 1 + src/modules/tm/tm.c | 6 ++++ 5 files changed, 76 insertions(+), 1 deletion(-) diff --git a/src/modules/tm/h_table.c b/src/modules/tm/h_table.c index 19b5daec0bb..ee79b91fd3f 100644 --- a/src/modules/tm/h_table.c +++ b/src/modules/tm/h_table.c @@ -575,3 +575,62 @@ void tm_xdata_replace(tm_xdata_t *newxd, tm_xlinks_t *bakxd) return; } } + +void tm_log_transaction(tm_cell_t *tcell, int llev, char *ltext) +{ + LOG(llev, "%s [start] transaction %p\n", ltext, tcell); + LOG(llev, "%s - tindex=%u tlabel=%u method='%.*s' from='%.*s'" + " to='%.*s' callid='%.*s' cseq='%.*s' uas_request=%s" + " tflags=%u outgoings=%u ref_count=%u lifetime=%u\n", + ltext, (unsigned)tcell->hash_index, (unsigned)tcell->label, + tcell->method.len, tcell->method.s, + tcell->from.len, tcell->from.s, + tcell->to.len, tcell->to.s, + tcell->callid.len, tcell->callid.s, + tcell->cseq_n.len, tcell->cseq_n.s, + (tcell->uas.request)?"yes":"no", + (unsigned)tcell->flags, + (unsigned)tcell->nr_of_outgoings, +#ifdef TM_DEL_UNREF + (unsigned)atomic_get(&tcell->ref_count), +#else + tcell->ref_count, +#endif + (unsigned)TICKS_TO_S(tcell->end_of_life) + ); + + LOG(llev, "%s [end] transaction %p\n", ltext, tcell); +} + +#define TM_LIFETIME_LIMIT 90 +/* clean active but very old transactions */ +void tm_clean_lifetime(void) +{ + int r; + tm_cell_t *tcell; + ticks_t texp; + + texp = get_ticks_raw() - S_TO_TICKS(TM_LIFETIME_LIMIT); + + for (r=0; rentries[r], next_c)) { + continue; + } + lock_hash(r); + /* one more time with lock to be avoid any cpu races */ + if(clist_empty(&_tm_table->entries[r], next_c)) { + unlock_hash(r); + continue; + } + + clist_foreach(&_tm_table->entries[r], tcell, next_c) + { + if(TICKS_GT(texp, tcell->end_of_life)) { + tm_log_transaction(tcell, L_WARN, "[hard cleanup]"); + free_cell(tcell); + } + } + unlock_hash(r); + } +} diff --git a/src/modules/tm/h_table.h b/src/modules/tm/h_table.h index 904709579af..7d61ae36730 100644 --- a/src/modules/tm/h_table.h +++ b/src/modules/tm/h_table.h @@ -607,6 +607,8 @@ inline static void remove_from_hash_table_unsafe(struct cell *p_cell) t_stats_deleted(is_local(p_cell)); } +void tm_clean_lifetime(void); + /** * backup xdata from/to msg context to local var and use T lists */ diff --git a/src/modules/tm/t_stats.c b/src/modules/tm/t_stats.c index d6ae5f52e4a..6b26aedba00 100644 --- a/src/modules/tm/t_stats.c +++ b/src/modules/tm/t_stats.c @@ -252,7 +252,7 @@ void tm_rpc_hash_stats(rpc_t* rpc, void* c) #endif /* TM_HASH_STATS */ } -/* hash statistics */ +/* list active transactions */ void tm_rpc_list(rpc_t* rpc, void* c) { int r; @@ -294,3 +294,10 @@ void tm_rpc_list(rpc_t* rpc, void* c) unlock_hash(r); } } + + +/* rpc command to clean active but very old transactions */ +void tm_rpc_clean(rpc_t* rpc, void* c) +{ + tm_clean_lifetime(); +} diff --git a/src/modules/tm/t_stats.h b/src/modules/tm/t_stats.h index 0a0057c6203..bd21befd0fd 100644 --- a/src/modules/tm/t_stats.h +++ b/src/modules/tm/t_stats.h @@ -150,5 +150,6 @@ void tm_rpc_hash_stats(rpc_t* rpc, void* c); typedef int (*tm_get_stats_f)(struct t_proc_stats *all); int tm_get_stats(struct t_proc_stats *all); void tm_rpc_list(rpc_t* rpc, void* c); +void tm_rpc_clean(rpc_t* rpc, void* c); #endif diff --git a/src/modules/tm/tm.c b/src/modules/tm/tm.c index 7adaa8796d0..9bc1695a0f8 100644 --- a/src/modules/tm/tm.c +++ b/src/modules/tm/tm.c @@ -2521,6 +2521,11 @@ static const char* tm_rpc_list_doc[2] = { 0 }; +static const char* tm_rpc_clean_doc[2] = { + "Clean expired (lifetime exceeded) transactions.", + 0 +}; + /* rpc exports */ static rpc_export_t tm_rpc[] = { @@ -2532,6 +2537,7 @@ static rpc_export_t tm_rpc[] = { {"tm.t_uac_start", rpc_t_uac_start, rpc_t_uac_start_doc, 0 }, {"tm.t_uac_wait", rpc_t_uac_wait, rpc_t_uac_wait_doc, RET_ARRAY}, {"tm.list", tm_rpc_list, tm_rpc_list_doc, RET_ARRAY}, + {"tm.clean", tm_rpc_clean, tm_rpc_clean_doc, 0}, {0, 0, 0, 0} };