summaryrefslogtreecommitdiff
path: root/tables/apr_hash.c
diff options
context:
space:
mode:
authorthommay <thommay@13f79535-47bb-0310-9956-ffa450edef68>2004-11-14 02:33:07 +0000
committerthommay <thommay@13f79535-47bb-0310-9956-ffa450edef68>2004-11-14 02:33:07 +0000
commit039bfdc295d8d7b09097ab29c7a07f833149ced8 (patch)
tree7ba5652486463adaaf30038d8ff2e4e907510c80 /tables/apr_hash.c
parent02f7cf7e72ea5b92d5d84873029d39e819e2c9c4 (diff)
downloadlibapr-039bfdc295d8d7b09097ab29c7a07f833149ced8.tar.gz
Prevent unbounded memory use during repeated operations on a hash table.
The hash table was allocating new memory for each new insertion of an entry, and not reclaiming it on deletions, so repetition of (insert, delete) caused the memory use to keep growing. This fix causes the memory freed by a deletion to be reused by a subsequent insertion, so that the memory used by the hash table is proportional to the maximum number of entries that it has ever held simultaneously, rather than the number of insertions that have been performed. * apr/tables/apr_hash.c: (apr_hash_t): Add new field "free", a free-list. (apr_hash_make, apr_hash_copy, apr_hash_merge): Initialise the free-list. (find_entry): Use an entry from the free-list if there is one. (apr_hash_set): Return a deleted entry to the free-list. git-svn-id: http://svn.apache.org/repos/asf/apr/apr/trunk@65572 13f79535-47bb-0310-9956-ffa450edef68
Diffstat (limited to 'tables/apr_hash.c')
-rw-r--r--tables/apr_hash.c12
1 files changed, 11 insertions, 1 deletions
diff --git a/tables/apr_hash.c b/tables/apr_hash.c
index 8b8a7f3d1..03bdfd7ce 100644
--- a/tables/apr_hash.c
+++ b/tables/apr_hash.c
@@ -73,6 +73,7 @@ struct apr_hash_t {
apr_hash_index_t iterator; /* For apr_hash_first(NULL, ...) */
unsigned int count, max;
apr_hashfunc_t hash_func;
+ apr_hash_entry_t *free; /* List of recycled entries */
};
#define INITIAL_MAX 15 /* tunable == 2^n - 1 */
@@ -92,6 +93,7 @@ APR_DECLARE(apr_hash_t *) apr_hash_make(apr_pool_t *pool)
apr_hash_t *ht;
ht = apr_palloc(pool, sizeof(apr_hash_t));
ht->pool = pool;
+ ht->free = NULL;
ht->count = 0;
ht->max = INITIAL_MAX;
ht->array = alloc_array(ht, ht->max);
@@ -264,7 +266,10 @@ static apr_hash_entry_t **find_entry(apr_hash_t *ht,
return hep;
/* add a new entry for non-NULL values */
- he = apr_palloc(ht->pool, sizeof(*he));
+ if (he = ht->free)
+ ht->free = he->next;
+ else
+ he = apr_palloc(ht->pool, sizeof(*he));
he->next = NULL;
he->hash = hash;
he->key = key;
@@ -286,6 +291,7 @@ APR_DECLARE(apr_hash_t *) apr_hash_copy(apr_pool_t *pool,
sizeof(*ht->array) * (orig->max + 1) +
sizeof(apr_hash_entry_t) * orig->count);
ht->pool = pool;
+ ht->free = NULL;
ht->count = orig->count;
ht->max = orig->max;
ht->hash_func = orig->hash_func;
@@ -333,7 +339,10 @@ APR_DECLARE(void) apr_hash_set(apr_hash_t *ht,
if (*hep) {
if (!val) {
/* delete entry */
+ apr_hash_entry_t *old = *hep;
*hep = (*hep)->next;
+ old->next = ht->free;
+ ht->free = old;
--ht->count;
}
else {
@@ -396,6 +405,7 @@ APR_DECLARE(apr_hash_t *) apr_hash_merge(apr_pool_t *p,
res = apr_palloc(p, sizeof(apr_hash_t));
res->pool = p;
+ res->free = NULL;
res->hash_func = base->hash_func;
res->count = base->count;
res->max = (overlay->max > base->max) ? overlay->max : base->max;