From ab7f212b7eb01ac452201f313739988af9f69017 Mon Sep 17 00:00:00 2001 From: "Roger A. Light" Date: Mon, 17 Aug 2015 21:25:30 +0100 Subject: [PATCH] [468987] Free unused topic elements. Reduces memory usage and CPU usage. Thanks to Guido Hinderberger, Martin Rauscher and Michael Hekel. Bug: https://bugs.eclipse.org/bugs/show_bug.cgi?id=468987 --- ChangeLog.txt | 1 + THANKS.txt | 3 +++ src/database.c | 2 ++ src/mosquitto_broker.h | 1 + src/subs.c | 57 ++++++++++++++++++++++++++++++++++++++++++ 5 files changed, 64 insertions(+) diff --git a/ChangeLog.txt b/ChangeLog.txt index 24c2fe5d..6c673ddf 100644 --- a/ChangeLog.txt +++ b/ChangeLog.txt @@ -5,6 +5,7 @@ Broker: autosave_interval=1. Closes #465438. - Fix handling of outgoing QoS>0 messages for bridges that could not be sent because the bridge connection was down. +- Free unused topic tree elements. Closes #468987. Client library: - Add missing error strings to mosquitto_strerror. diff --git a/THANKS.txt b/THANKS.txt index 813aafbc..31f856e1 100644 --- a/THANKS.txt +++ b/THANKS.txt @@ -37,6 +37,7 @@ Fang Chong Frank Hansen Gary Koh Gianfranco Costamagna +Guido Hinderberger Hiram van Paassen Jan-Piet Mens Joan Zapata @@ -44,11 +45,13 @@ Joe McIlvain Karl Palsson Larry Lendo Martin Assarsson +Martin Rauscher Martin van Wingerden Marty Lee Matt Daubney Michael C Michael Frisch +Michael Hekel Michael Laing Michael Rushton Mike Bush diff --git a/src/database.c b/src/database.c index 24f7a9a4..6de68a98 100644 --- a/src/database.c +++ b/src/database.c @@ -59,6 +59,7 @@ int mqtt3_db_open(struct mqtt3_config *config, struct mosquitto_db *db) _mosquitto_log_printf(NULL, MOSQ_LOG_ERR, "Error: Out of memory."); return MOSQ_ERR_NOMEM; } + child->parent = NULL; child->next = NULL; child->topic = _mosquitto_strdup(""); if(!child->topic){ @@ -75,6 +76,7 @@ int mqtt3_db_open(struct mqtt3_config *config, struct mosquitto_db *db) _mosquitto_log_printf(NULL, MOSQ_LOG_ERR, "Error: Out of memory."); return MOSQ_ERR_NOMEM; } + child->parent = NULL; child->next = NULL; child->topic = _mosquitto_strdup("$SYS"); if(!child->topic){ diff --git a/src/mosquitto_broker.h b/src/mosquitto_broker.h index 9ed012d9..19498a0b 100644 --- a/src/mosquitto_broker.h +++ b/src/mosquitto_broker.h @@ -138,6 +138,7 @@ struct _mosquitto_subleaf { }; struct _mosquitto_subhier { + struct _mosquitto_subhier *parent; struct _mosquitto_subhier *children; struct _mosquitto_subhier *next; struct _mosquitto_subleaf *subs; diff --git a/src/subs.c b/src/subs.c index 4aaff864..a7c30091 100644 --- a/src/subs.c +++ b/src/subs.c @@ -327,6 +327,7 @@ static int _sub_add(struct mosquitto_db *db, struct mosquitto *context, int qos, /* Not found */ branch = _mosquitto_calloc(1, sizeof(struct _mosquitto_subhier)); if(!branch) return MOSQ_ERR_NOMEM; + branch->parent = subhier; branch->topic = _mosquitto_strdup(tokens->topic); if(!branch->topic){ _mosquitto_free(branch); @@ -459,6 +460,7 @@ int mqtt3_sub_add(struct mosquitto_db *db, struct mosquitto *context, const char _mosquitto_log_printf(NULL, MOSQ_LOG_ERR, "Error: Out of memory."); return MOSQ_ERR_NOMEM; } + child->parent = root; child->topic = _mosquitto_strdup(tokens->topic); if(!child->topic){ _sub_topic_tokens_free(tokens); @@ -548,12 +550,56 @@ int mqtt3_db_messages_queue(struct mosquitto_db *db, const char *source_id, cons return rc; } + +/* Remove a subhier element, and return its parent if that needs freeing as well. */ +static struct _mosquitto_subhier *tmp_remove_subs(struct _mosquitto_subhier *sub) +{ + struct _mosquitto_subhier *parent; + struct _mosquitto_subhier *hier; + struct _mosquitto_subhier *last = NULL; + + if(!sub || !sub->parent){ + return NULL; + } + if(sub->children || sub->subs || sub->next){ + return NULL; + } + + parent = sub->parent; + hier = sub->parent->children; + while(hier){ + if(hier == sub){ + if(last){ + last->next = sub->next; + }else{ + parent->children = NULL; + } + if(sub->topic) _mosquitto_free(sub->topic); + _mosquitto_free(sub); + break; + } + last = hier; + hier = hier->next; + } + if(parent->subs == NULL + && parent->children == NULL + && parent->retained == NULL + && parent->parent){ + + return parent; + }else{ + return NULL; + } +} + + /* Remove all subscriptions for a client. */ int mqtt3_subs_clean_session(struct mosquitto_db *db, struct mosquitto *context) { int i; struct _mosquitto_subleaf *leaf; + struct _mosquitto_subhier *hier; for(i=0; isub_count; i++){ if(context->subs[i] == NULL){ @@ -578,6 +624,17 @@ int mqtt3_subs_clean_session(struct mosquitto_db *db, struct mosquitto *context) } leaf = leaf->next; } + if(context->subs[i]->subs == NULL + && context->subs[i]->children == NULL + && context->subs[i]->retained == NULL + && context->subs[i]->parent){ + + hier = context->subs[i]; + context->subs[i] = NULL; + do{ + hier = tmp_remove_subs(hier); + }while(hier); + } } _mosquitto_free(context->subs); context->subs = NULL;