Jelajahi Sumber

ims_usrloc_scscf: Double check contact refs on DB

If the contact is on state CONTACT_DELAYED_DELETE
and still has refs > 0 in memory, it could be
that it failed to acquire a lock to de-ref the
contact. This brings to a leak on the contact DB
because the contact will always have refs > 0 and
no actual refs on DB. Now, as a fallback, we
actually checks on DB the real number of refs of
the contact. If this refs is 0, force the
number  of refs in the record to 0 and mark the
contact for deletion.
Federico Favaro 9 tahun lalu
induk
melakukan
3438dbe5e5

+ 21 - 1
modules/ims_usrloc_scscf/udomain.c

@@ -267,6 +267,7 @@ void mem_timer_udomain(udomain_t* _d, int istart, int istep) {
     time_t now;
     int abort = 0;
     int slot;
+	int ref_count_db;
     
     now = time(0);
     
@@ -309,7 +310,26 @@ void mem_timer_udomain(udomain_t* _d, int istart, int istep) {
                             expired_contacts[num_expired_contacts] = contact_ptr;
                             num_expired_contacts++;
                         } else {
-                            LM_DBG("contact in state CONTACT_DELATED_DELETE still has a ref count of [%d]... not doing anything for now\n", contact_ptr->ref_count);
+							/* we could fall here not because contact is still
+							 referenced but also because we failed before to
+							 get a lock to unref the contact, so we check if
+							 contact is really referenced*/
+							if (db_mode != NO_DB) {
+								LM_DBG("contact in state CONTACT_DELAYED_DELETE still has a ref count of [%d] in memory. Check on DB \n", contact_ptr->ref_count);
+								ref_count_db = db_check_if_contact_is_linked(contact_ptr);
+								if (ref_count_db < 0) {
+									LM_ERR("Unable to check if contact is unlinked\n");
+								} else if (ref_count_db == 0) {
+									LM_DBG("Contact has ref count [%d] but there's no link on the DB. Deleting contact");
+									contact_ptr->ref_count = 0;
+									expired_contacts[num_expired_contacts] = contact_ptr;
+									num_expired_contacts++;
+								} else {
+									LM_DBG("Contact in state CONTACT_DELAYED_DELETE has ref count [%d] on DB", ref_count_db);
+								}
+							} else {
+								LM_DBG("contact in state CONTACT_DELAYED_DELETE still has a ref count of [%d] in memory. Not doing anything for now \n", contact_ptr->ref_count);
+							}
                         }
                     } else if (contact_ptr->state != CONTACT_DELETED) {
                         LM_DBG("expiring contact [%.*s].... setting to CONTACT_EXPIRE_PENDING_NOTIFY\n", contact_ptr->aor.len, contact_ptr->aor.s);

+ 34 - 0
modules/ims_usrloc_scscf/usrloc_db.c

@@ -65,6 +65,9 @@ str subscriber_id_col = str_init(SUBSCRIBER_ID_COL);
 str query_buffer 		= { 0, 0 };
 int query_buffer_len		= 0;
 
+char* check_contact_links_query = "SELECT * FROM impu_contact WHERE contact_id = (SELECT contact.id from contact WHERE contact.contact='%.*s')";
+int check_contact_links_query_len;
+
 char* impu_contact_insert_query = "INSERT INTO impu_contact (impu_id, contact_id) (SELECT I.id, C.id FROM impu I, contact C WHERE I.impu='%.*s' and C.contact='%.*s')";
 int impu_contact_insert_query_len;
 char* impu_contact_delete_query = "DELETE impu_contact FROM impu_contact INNER JOIN impu ON impu_contact.impu_id = impu.id INNER JOIN contact ON contact.id = impu_contact.contact_id where impu.impu = '%.*s' and contact.contact = '%.*s'";
@@ -1074,6 +1077,37 @@ int db_link_contact_to_impu(impurecord_t* _r, ucontact_t* _c) {
     return 0;
 }
 
+int db_check_if_contact_is_linked(ucontact_t* _c) {
+	int len;
+	db1_res_t* rs;
+	int n_res_row = 0;
+
+	len = strlen(check_contact_links_query) + _c->c.len + 1;
+
+	if (!query_buffer_len || query_buffer_len < len) {
+		if (query_buffer.s) {
+			pkg_free(query_buffer.s);
+		}
+		query_buffer.s = (char*) pkg_malloc(len);
+		if (!query_buffer.s) {
+			LM_ERR("no more pkg mem\n");
+			return -1;
+		}
+		query_buffer_len = len;
+
+	}
+
+	snprintf(query_buffer.s,query_buffer_len,check_contact_links_query,_c->c.len,_c->c.s);
+	query_buffer.len = strlen(query_buffer.s);
+	if (ul_dbf.raw_query(ul_dbh, &query_buffer, &rs) != 0) {
+		LM_ERR("Unable to query DB to check if contact[%.*s] is linked\n", _c->c.len, _c->c.s);
+		return -1;
+	}
+	n_res_row = RES_ROW_N(rs);
+	ul_dbf.free_result(ul_dbh, rs);
+	return n_res_row;
+}
+
 int db_unlink_contact_from_impu(impurecord_t* _r, ucontact_t* _c) {
     int len;
     db1_res_t* rs;

+ 2 - 0
modules/ims_usrloc_scscf/usrloc_db.h

@@ -77,4 +77,6 @@ int db_link_subscriber_to_impu(impurecord_t* _r, reg_subscriber* _reg_subscriber
 
 int preload_udomain(db1_con_t* _c, udomain_t* _d);
 
+int db_check_if_contact_is_linked(ucontact_t* _c);
+
 #endif /* USRLOC_DB_H_ */