From 50e608d721d9feabc1a09aa2b051a2adb75198f8 Mon Sep 17 00:00:00 2001 From: Willy Tarreau Date: Sun, 13 May 2007 18:26:08 +0200 Subject: [PATCH 01/12] [MEDIUM] implement memory pools version 2 The new pools know about their size and usage. Malloc is not used anymore, instead a dedicated function to refill the entries is used. --- Makefile | 2 +- Makefile.bsd | 2 +- Makefile.osx | 3 +- include/common/config.h | 23 ++++++++- include/common/memory.h | 70 ++++++++++++++++++++++++- src/memory.c | 111 ++++++++++++++++++++++++++++++++++++++++ 6 files changed, 206 insertions(+), 5 deletions(-) create mode 100644 src/memory.c diff --git a/Makefile b/Makefile index c7017e5ea..122f1c6fa 100644 --- a/Makefile +++ b/Makefile @@ -217,7 +217,7 @@ OBJS = src/haproxy.o src/list.o src/chtbl.o src/hashpjw.o src/base64.o \ src/time.o src/fd.o src/regex.o src/cfgparse.o src/server.o \ src/checks.o src/queue.o src/capture.o src/client.o src/proxy.o \ src/proto_http.o src/stream_sock.o src/appsession.o src/backend.o \ - src/session.o src/hdr_idx.o src/ev_select.o src/acl.o + src/session.o src/hdr_idx.o src/ev_select.o src/acl.o src/memory.o haproxy: $(OBJS) $(OPT_OBJS) $(LD) $(LDFLAGS) -o $@ $^ $(LIBS) diff --git a/Makefile.bsd b/Makefile.bsd index 76fe256bc..945b08e24 100644 --- a/Makefile.bsd +++ b/Makefile.bsd @@ -88,7 +88,7 @@ OBJS = src/haproxy.o src/list.o src/chtbl.o src/hashpjw.o src/base64.o \ src/checks.o src/queue.o src/capture.o src/client.o src/proxy.o \ src/proto_http.o src/stream_sock.o src/appsession.o src/backend.o \ src/session.o src/hdr_idx.o src/ev_select.o src/ev_poll.o \ - src/ev_kqueue.o src/acl.o + src/ev_kqueue.o src/acl.o src/memory.o all: haproxy diff --git a/Makefile.osx b/Makefile.osx index 15db775cd..0618e68c9 100644 --- a/Makefile.osx +++ b/Makefile.osx @@ -87,7 +87,8 @@ OBJS = src/haproxy.o src/list.o src/chtbl.o src/hashpjw.o src/base64.o \ src/time.o src/fd.o src/regex.o src/cfgparse.o src/server.o \ src/checks.o src/queue.o src/capture.o src/client.o src/proxy.o \ src/proto_http.o src/stream_sock.o src/appsession.o src/backend.o \ - src/session.o src/hdr_idx.o src/ev_select.o src/ev_poll.o src/acl.o + src/session.o src/hdr_idx.o src/ev_select.o src/ev_poll.o src/acl.o \ + src/memory.o all: haproxy diff --git a/include/common/config.h b/include/common/config.h index e8d8ad26b..85deeaed5 100644 --- a/include/common/config.h +++ b/include/common/config.h @@ -2,7 +2,7 @@ include/common/config.h This files contains most of the user-configurable settings. - Copyright (C) 2000-2006 Willy Tarreau - w@1wt.eu + Copyright (C) 2000-2007 Willy Tarreau - w@1wt.eu This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public @@ -39,6 +39,27 @@ # define CONFIG_HAP_MEM_OPTIM #endif /* CONFIG_HAP_NO_MEM_OPTIM */ +/* CONFIG_HAP_MALLOC / CONFIG_HAP_CALLOC / CONFIG_HAP_FREE + * This macro allows to replace the malloc function with another one. + */ +#ifdef CONFIG_HAP_MALLOC +#define MALLOC CONFIG_HAP_MALLOC +#else +#define MALLOC malloc +#endif + +#ifdef CONFIG_HAP_CALLOC +#define CALLOC CONFIG_HAP_CALLOC +#else +#define CALLOC calloc +#endif + +#ifdef CONFIG_HAP_FREE +#define FREE CONFIG_HAP_FREE +#else +#define FREE free +#endif + /* CONFIG_HAP_INLINE_FD_SET * This makes use of inline FD_* macros instead of calling equivalent diff --git a/include/common/memory.h b/include/common/memory.h index 820c1d98e..77346b706 100644 --- a/include/common/memory.h +++ b/include/common/memory.h @@ -2,7 +2,7 @@ include/common/memory.h Memory management definitions.. - Copyright (C) 2000-2006 Willy Tarreau - w@1wt.eu + Copyright (C) 2000-2007 Willy Tarreau - w@1wt.eu This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public @@ -25,6 +25,7 @@ #include #include +#include #define sizeof_requri REQURI_LEN #define sizeof_capture CAPTURE_LEN @@ -112,6 +113,73 @@ static inline void pool_destroy(void **pool) } } + +/******* pools version 2 ********/ + +#define MEM_F_SHARED 0x1 + +struct pool_head { + void **free_list; + struct list list; /* list of all known pools */ + unsigned int used; /* how many chunks are currently in use */ + unsigned int allocated; /* how many chunks have been allocated */ + unsigned int limit; /* hard limit on the number of chunks */ + unsigned int minavail; /* how many chunks are expected to be used */ + unsigned int size; /* chunk size */ + unsigned int flags; /* MEM_F_* */ + char name[9]; /* name of the pool */ +}; + + +/* Allocate a new entry for pool , and return it for immediate use. + * NULL is returned if no memory is available for a new creation. + */ +void *refill_pool_alloc(struct pool_head *pool); + +/* Try to find an existing shared pool with the same characteristics and + * returns it, otherwise creates this one. NULL is returned if no memory + * is available for a new creation. + */ +struct pool_head *create_pool(char *name, unsigned int size, unsigned int flags); + +/* Dump statistics on pools usage. + */ +void dump_pools(void); + +/* + * Returns a pointer to type taken from the + * pool or dynamically allocated. In the + * first case, is updated to point to the + * next element in the list. + */ +#define pool_alloc2(pool) \ +({ \ + void *__p; \ + if ((__p = pool.free_list) == NULL) \ + __p = pool_refill_alloc(&pool); \ + else { \ + pool.free_list = *(void **)pool.free_list; \ + pool.used++; \ + } \ + __p; \ +}) + +/* + * Puts a memory area back to the corresponding pool. + * Items are chained directly through a pointer that + * is written in the beginning of the memory area, so + * there's no need for any carrier cell. This implies + * that each memory area is at least as big as one + * pointer. + */ +#define pool_free2(pool, ptr) \ +({ \ + *(void **)ptr = (void *)pool.free_list; \ + pool.free_list = (void *)ptr; \ + pool.used--; \ +}) + + #endif /* _COMMON_MEMORY_H */ /* diff --git a/src/memory.c b/src/memory.c new file mode 100644 index 000000000..5dbbdd91f --- /dev/null +++ b/src/memory.c @@ -0,0 +1,111 @@ +/* + * Memory management functions. + * + * Copyright 2000-2007 Willy Tarreau + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version + * 2 of the License, or (at your option) any later version. + * + */ + +#include +#include +#include +#include + +#include + +static struct list pools = LIST_HEAD_INIT(pools); + +/* Try to find an existing shared pool with the same characteristics and + * returns it, otherwise creates this one. NULL is returned if no memory + * is available for a new creation. + */ +struct pool_head *create_pool(char *name, unsigned int size, unsigned int flags) +{ + struct pool_head *pool; + unsigned int align; + + /* We need to store at least a (void *) in the chunks. Since we know + * that the malloc() function will never return such a small size, + * let's round the size up to something slightly bigger, in order to + * ease merging of entries. Note that the rounding is a power of two. + */ + + align = 4 * sizeof(void *); + size = (size + align - 1) & -align; + + pool = NULL; + if (flags & MEM_F_SHARED) { + struct pool_head *entry; + list_for_each_entry(entry, &pools, list) { + if (!(entry->flags & MEM_F_SHARED)) + continue; + if (entry->size == size) { + pool = entry; + break; + } + } + } + + if (!pool) { + pool = CALLOC(1, sizeof(*pool)); + if (!pool) + return NULL; + if (name) + strlcpy2(pool->name, name, sizeof(pool->name)); + pool->size = size; + pool->flags = flags; + LIST_ADDQ(&pools, &pool->list); + } + return pool; +} + +/* Allocate a new entry for pool , and return it for immediate use. + * NULL is returned if no memory is available for a new creation. + */ +void *refill_pool_alloc(struct pool_head *pool) +{ + void *ret; + + if (pool->limit && (pool->allocated >= pool->limit)) + return NULL; + ret = MALLOC(pool->size); + if (!ret) + return NULL; + pool->allocated++; + pool->used++; + return ret; +} + +/* Dump statistics on pools usage. + */ +void dump_pools(void) +{ + struct pool_head *entry; + unsigned long allocated, used; + int nbpools; + + allocated = used = nbpools = 0; + qfprintf(stderr, "Dumping pools usage.\n"); + list_for_each_entry(entry, &pools, list) { + qfprintf(stderr, " - Pool %s (%d bytes) : %d allocated, %d used%s\n", + entry->name, entry->size, entry->allocated, entry->used, + (entry->flags & MEM_F_SHARED) ? " (SHARED)" : ""); + + allocated += entry->allocated * entry->size; + used += entry->used * entry->size; + nbpools++; + } + qfprintf(stderr, "Total: %d pools, %lu allocated, %lu used.\n", + nbpools, allocated, used); +} + +/* + * Local variables: + * c-indent-level: 8 + * c-basic-offset: 8 + * End: + */ From e6ce59deb7affe66ccbb7bd154a2310e1ad3e14a Mon Sep 17 00:00:00 2001 From: Willy Tarreau Date: Sun, 13 May 2007 19:38:49 +0200 Subject: [PATCH 02/12] [MEDIUM] add new memory management functions Implement pool_destroy2, pool_flush2, pool_gc2. It is safe to call pool_gc2 to free whatever memory possible. --- include/common/memory.h | 33 ++++++++++++++++------ src/memory.c | 62 +++++++++++++++++++++++++++++++++++++---- 2 files changed, 82 insertions(+), 13 deletions(-) diff --git a/include/common/memory.h b/include/common/memory.h index 77346b706..0f142f028 100644 --- a/include/common/memory.h +++ b/include/common/memory.h @@ -134,7 +134,7 @@ struct pool_head { /* Allocate a new entry for pool , and return it for immediate use. * NULL is returned if no memory is available for a new creation. */ -void *refill_pool_alloc(struct pool_head *pool); +void *pool_refill_alloc(struct pool_head *pool); /* Try to find an existing shared pool with the same characteristics and * returns it, otherwise creates this one. NULL is returned if no memory @@ -146,6 +146,23 @@ struct pool_head *create_pool(char *name, unsigned int size, unsigned int flags) */ void dump_pools(void); +/* + * This function frees whatever can be freed in pool . + */ +void pool_flush2(struct pool_head *pool); + +/* + * This function frees whatever can be freed in all pools, but respecting + * the minimum thresholds imposed by owners. + */ +void pool_gc2(); + +/* + * This function destroys a pull by freeing it completely. + * This should be called only under extreme circumstances. + */ +void pool_destroy2(struct pool_head *pool); + /* * Returns a pointer to type taken from the * pool or dynamically allocated. In the @@ -155,11 +172,11 @@ void dump_pools(void); #define pool_alloc2(pool) \ ({ \ void *__p; \ - if ((__p = pool.free_list) == NULL) \ - __p = pool_refill_alloc(&pool); \ + if ((__p = pool->free_list) == NULL) \ + __p = pool_refill_alloc(pool); \ else { \ - pool.free_list = *(void **)pool.free_list; \ - pool.used++; \ + pool->free_list = *(void **)pool->free_list; \ + pool->used++; \ } \ __p; \ }) @@ -174,9 +191,9 @@ void dump_pools(void); */ #define pool_free2(pool, ptr) \ ({ \ - *(void **)ptr = (void *)pool.free_list; \ - pool.free_list = (void *)ptr; \ - pool.used--; \ + *(void **)ptr = (void *)pool->free_list; \ + pool->free_list = (void *)ptr; \ + pool->used--; \ }) diff --git a/src/memory.c b/src/memory.c index 5dbbdd91f..dd542252b 100644 --- a/src/memory.c +++ b/src/memory.c @@ -66,7 +66,7 @@ struct pool_head *create_pool(char *name, unsigned int size, unsigned int flags) /* Allocate a new entry for pool , and return it for immediate use. * NULL is returned if no memory is available for a new creation. */ -void *refill_pool_alloc(struct pool_head *pool) +void *pool_refill_alloc(struct pool_head *pool) { void *ret; @@ -80,6 +80,57 @@ void *refill_pool_alloc(struct pool_head *pool) return ret; } +/* + * This function frees whatever can be freed in pool . + */ +void pool_flush2(struct pool_head *pool) +{ + void *temp, *next; + next = pool->free_list; + while (next) { + temp = next; + next = *(void **)temp; + pool->allocated--; + FREE(temp); + } + pool->free_list = next; + + /* here, we should have pool->allocate == pool->used */ +} + +/* + * This function frees whatever can be freed in all pools, but respecting + * the minimum thresholds imposed by owners. + */ +void pool_gc2() +{ + struct pool_head *entry; + list_for_each_entry(entry, &pools, list) { + void *temp, *next; + //qfprintf(stderr, "Flushing pool %s\n", entry->name); + next = entry->free_list; + while (next && + entry->allocated > entry->minavail && + entry->allocated > entry->used) { + temp = next; + next = *(void **)temp; + entry->allocated--; + FREE(temp); + } + entry->free_list = next; + } +} + +/* + * This function destroys a pull by freeing it completely. + * This should be called only under extreme circumstances. + */ +void pool_destroy2(struct pool_head *pool) +{ + pool_flush2(pool); + FREE(pool); +} + /* Dump statistics on pools usage. */ void dump_pools(void) @@ -91,15 +142,16 @@ void dump_pools(void) allocated = used = nbpools = 0; qfprintf(stderr, "Dumping pools usage.\n"); list_for_each_entry(entry, &pools, list) { - qfprintf(stderr, " - Pool %s (%d bytes) : %d allocated, %d used%s\n", - entry->name, entry->size, entry->allocated, entry->used, - (entry->flags & MEM_F_SHARED) ? " (SHARED)" : ""); + qfprintf(stderr, " - Pool %s (%d bytes) : %d allocated (%lu bytes), %d used%s\n", + entry->name, entry->size, entry->allocated, + entry->size * entry->allocated, entry->used, + (entry->flags & MEM_F_SHARED) ? " [SHARED]" : ""); allocated += entry->allocated * entry->size; used += entry->used * entry->size; nbpools++; } - qfprintf(stderr, "Total: %d pools, %lu allocated, %lu used.\n", + qfprintf(stderr, "Total: %d pools, %lu bytes allocated, %lu used.\n", nbpools, allocated, used); } From c6ca1a02aaffc6fbb6dbd98bcd33bfe3cf835892 Mon Sep 17 00:00:00 2001 From: Willy Tarreau Date: Sun, 13 May 2007 19:43:47 +0200 Subject: [PATCH 03/12] [MAJOR] migrated task, tree64 and session to pool2 task and tree64 are already very close in size and are merged together. Overall performance gained slightly by this simple change. --- include/import/tree.h | 37 +++++++++++++++++++------------------ include/proto/session.h | 7 ++++++- include/proto/task.h | 6 +++++- include/types/session.h | 6 +----- include/types/task.h | 3 --- src/appsession.c | 2 +- src/cfgparse.c | 4 ++-- src/client.c | 37 +++++++++++++++++++------------------ src/haproxy.c | 10 ++++++++-- src/session.c | 14 +++++++++++--- src/task.c | 14 +++++++++++--- 11 files changed, 83 insertions(+), 57 deletions(-) diff --git a/include/import/tree.h b/include/import/tree.h index 7c375e7ab..11ca6e00f 100644 --- a/include/import/tree.h +++ b/include/import/tree.h @@ -2,6 +2,8 @@ * tree.h : tree manipulation macros and structures. * (C) 2002 - Willy Tarreau - willy@ant-computing.com * + * 2007/05/13: adapted to mempools v2. + * */ #ifndef __TREE_H__ @@ -51,8 +53,7 @@ struct tree64 { struct tree64 *up; /* parent node. NULL = root */ }; -#define sizeof_tree64 (sizeof (struct tree64)) -extern void **pool_tree64; +extern struct pool_head *pool2_tree64; #define ULTREE_HEAD(l) struct ultree (l) = { .left=NULL, .right=NULL, .up=NULL, .low=0, .level=LONGBITS, .data=NULL } #define ULTREE_INIT(l) { (l)->data = (l)->left = (l)->right = NULL; } @@ -96,7 +97,7 @@ inline static struct ulltree *__ulltree_insert(struct ulltree *root, unsigned lo if (next == NULL) { /* we'll have to insert our node here */ - *branch = new = (struct ulltree *)pool_alloc(tree64); + *branch = new = (struct ulltree *)pool_alloc2(pool2_tree64); ULLTREE_INIT(new); new->up = root; new->value = x; @@ -111,7 +112,7 @@ inline static struct ulltree *__ulltree_insert(struct ulltree *root, unsigned lo /* ok, now we know that we must insert between both. */ /* the new interconnect node */ - *branch = node = (struct ulltree *)pool_alloc(tree64); /* was */ + *branch = node = (struct ulltree *)pool_alloc2(pool2_tree64); /* was */ ULLTREE_INIT(node); node->up = root; next->up = node; @@ -139,7 +140,7 @@ inline static struct ulltree *__ulltree_insert(struct ulltree *root, unsigned lo /* the new leaf now */ node->level = m; /* set the level to the lowest common bit */ - new = (struct ulltree *)pool_alloc(tree64); + new = (struct ulltree *)pool_alloc2(pool2_tree64); ULLTREE_INIT(new); new->value = x; new->level = ffs; @@ -186,7 +187,7 @@ inline static struct ultree *__ultree_insert(struct ultree *root, unsigned long if (next == NULL) { /* we'll have to insert our node here */ - *branch = new = (struct ultree *)pool_alloc(tree64); + *branch = new = (struct ultree *)pool_alloc2(pool2_tree64); ULTREE_INIT(new); new->up = root; new->low = x; @@ -200,7 +201,7 @@ inline static struct ultree *__ultree_insert(struct ultree *root, unsigned long /* ok, now we know that we must insert between both. */ /* the new interconnect node */ - *branch = node = (struct ultree *)pool_alloc(tree64); /* was */ + *branch = node = (struct ultree *)pool_alloc2(pool2_tree64); /* was */ ULTREE_INIT(node); node->up = root; next->up = node; @@ -228,7 +229,7 @@ inline static struct ultree *__ultree_insert(struct ultree *root, unsigned long /* the new leaf now */ node->level = m; /* set the level to the lowest common bit */ - new = (struct ultree *)pool_alloc(tree64); + new = (struct ultree *)pool_alloc2(pool2_tree64); ULTREE_INIT(new); new->low = x; new->level = ffs; @@ -279,7 +280,7 @@ inline static struct ultree *__ul2tree_insert(struct ultree *root, unsigned long if (next == NULL) { /* we'll have to insert our node here */ - *branch = new =(struct ultree *)pool_alloc(tree64); + *branch = new =(struct ultree *)pool_alloc2(pool2_tree64); UL2TREE_INIT(new); new->up = root; new->high = h; @@ -308,7 +309,7 @@ inline static struct ultree *__ul2tree_insert(struct ultree *root, unsigned long /* ok, now we know that we must insert between both. */ /* the new interconnect node */ - *branch = node = (struct ultree *)pool_alloc(tree64); /* was */ + *branch = node = (struct ultree *)pool_alloc2(pool2_tree64); /* was */ UL2TREE_INIT(node); node->up = root; next->up = node; @@ -352,7 +353,7 @@ inline static struct ultree *__ul2tree_insert(struct ultree *root, unsigned long /* the new leaf now */ node->level = m; /* set the level to the lowest common bit */ - new = (struct ultree *)pool_alloc(tree64); + new = (struct ultree *)pool_alloc2(pool2_tree64); UL2TREE_INIT(new); new->high = h; new->low = l; @@ -456,7 +457,7 @@ __right: \ goto __end; /* nothing left, don't delete the root node */ \ else { \ typeof (__root) __old; \ - pool_free(tree64, __ptr); \ + pool_free2(pool2_tree64, __ptr); \ __old = __ptr; \ __ptr = __stack[__slen]; \ if (__ptr->left == __old) { \ @@ -506,7 +507,7 @@ __right: \ goto __end; /* nothing left, don't delete the root node */ \ else { \ typeof (__root) __old; \ - pool_free(__type, __ptr); \ + pool_free2(pool##__type, __ptr); \ __old = __ptr; \ __ptr = __stack[__slen]; \ if (__ptr->left == __old) { \ @@ -561,7 +562,7 @@ __right: \ goto __end; /* nothing left, don't delete the root node */ \ else { \ typeof (__root) __old; \ - pool_free(tree64, __ptr); \ + pool_free2(pool2_tree64, __ptr); \ __old = __ptr; \ __ptr = __stack[__slen]; \ if (__ptr->left == __old) { \ @@ -617,7 +618,7 @@ __right: \ goto __end; /* nothing left, don't delete the root node */ \ else { \ typeof (__root) __old; \ - pool_free(tree64, __ptr); \ + pool_free2(pool2_tree64, __ptr); \ __old = __ptr; \ __ptr = __stack[__slen]; \ if (__ptr->left == __old) { \ @@ -671,7 +672,7 @@ inline static void *__tree_delete_only_one(void *firstnode) { */ down = node; node = node->up; - pool_free(tree64, down); + pool_free2(pool2_tree64, down); if (node->data || node->up == NULL) return node; /* now we're sure we were sharing this empty node with another branch, let's find it */ @@ -684,7 +685,7 @@ inline static void *__tree_delete_only_one(void *firstnode) { down->up = node->up; } /* free the last node */ - pool_free(tree64, node); + pool_free2(pool2_tree64, node); return down->up; } @@ -716,7 +717,7 @@ inline static void *__tree_delete(void *firstnode) { uplink = &up->right; *uplink = down; /* we relink the lower branch above us or simply cut it */ - pool_free(tree64, node); + pool_free2(pool2_tree64, node); node = up; if (down) down->up = node; diff --git a/include/proto/session.h b/include/proto/session.h index e3e523409..a18669e1d 100644 --- a/include/proto/session.h +++ b/include/proto/session.h @@ -2,7 +2,7 @@ include/proto/session.h This file defines everything related to sessions. - Copyright (C) 2000-2006 Willy Tarreau - w@1wt.eu + Copyright (C) 2000-2007 Willy Tarreau - w@1wt.eu This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public @@ -23,10 +23,15 @@ #define _PROTO_SESSION_H #include +#include #include +extern struct pool_head *pool2_session; + void session_free(struct session *s); +/* perform minimal intializations, report 0 in case of error, 1 if OK. */ +int init_session(); #endif /* _PROTO_SESSION_H */ diff --git a/include/proto/task.h b/include/proto/task.h index c594d525e..6bee1b2f1 100644 --- a/include/proto/task.h +++ b/include/proto/task.h @@ -33,6 +33,10 @@ #include extern void *run_queue; +extern struct pool_head *pool2_task; + +/* perform minimal intializations, report 0 in case of error, 1 if OK. */ +int init_task(); /* needed later */ void *tree_delete(void *node); @@ -97,7 +101,7 @@ static inline struct task *task_delete(struct task *t) */ static inline void task_free(struct task *t) { - pool_free(task, t); + pool_free2(pool2_task, t); } /* inserts into its assigned wait queue, where it may already be. In this case, it diff --git a/include/types/session.h b/include/types/session.h index 7ef138f10..819acfd74 100644 --- a/include/types/session.h +++ b/include/types/session.h @@ -2,7 +2,7 @@ include/types/session.h This file defines everything related to sessions. - Copyright (C) 2000-2006 Willy Tarreau - w@1wt.eu + Copyright (C) 2000-2007 Willy Tarreau - w@1wt.eu This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public @@ -123,10 +123,6 @@ struct session { }; -#define sizeof_session sizeof(struct session) -extern void **pool_session; - - #endif /* _TYPES_SESSION_H */ /* diff --git a/include/types/task.h b/include/types/task.h index 42699dbff..e0bbd6dac 100644 --- a/include/types/task.h +++ b/include/types/task.h @@ -42,9 +42,6 @@ struct task { void *context; /* the task's context */ }; -#define sizeof_task sizeof(struct task) -extern void **pool_task; - #endif /* _TYPES_TASK_H */ /* diff --git a/src/appsession.c b/src/appsession.c index 72b7e403f..bf26510e4 100644 --- a/src/appsession.c +++ b/src/appsession.c @@ -111,7 +111,7 @@ int appsession_task_init(void) static int initialized = 0; struct task *t; if (!initialized) { - if ((t = pool_alloc(task)) == NULL) + if ((t = pool_alloc2(pool2_task)) == NULL) return -1; t->wq = NULL; t->qlist.p = NULL; diff --git a/src/cfgparse.c b/src/cfgparse.c index 1edaa8fc0..6dd7ab617 100644 --- a/src/cfgparse.c +++ b/src/cfgparse.c @@ -2488,7 +2488,7 @@ int readcfgfile(const char *file) if (newsrv->maxconn > 0) { struct task *t; - if ((t = pool_alloc(task)) == NULL) { + if ((t = pool_alloc2(pool2_task)) == NULL) { Alert("parsing [%s:%d] : out of memory.\n", file, linenum); return -1; } @@ -2535,7 +2535,7 @@ int readcfgfile(const char *file) while (newsrv != NULL) { /* should this server be checked ? */ if (newsrv->state & SRV_CHECKED) { - if ((t = pool_alloc(task)) == NULL) { + if ((t = pool_alloc2(pool2_task)) == NULL) { Alert("parsing [%s:%d] : out of memory.\n", file, linenum); return -1; } diff --git a/src/client.c b/src/client.c index 52b281bde..6afb20636 100644 --- a/src/client.c +++ b/src/client.c @@ -41,6 +41,7 @@ #include #include #include +#include #include #include @@ -110,7 +111,7 @@ int event_accept(int fd) { } } - if ((s = pool_alloc(session)) == NULL) { /* disable this proxy for a while */ + if ((s = pool_alloc2(pool2_session)) == NULL) { /* disable this proxy for a while */ Alert("out of memory in event_accept().\n"); EV_FD_CLR(fd, DIR_RD); p->state = PR_STIDLE; @@ -127,18 +128,18 @@ int event_accept(int fd) { (((struct sockaddr_in *)&addr)->sin_addr.s_addr & p->mon_mask.s_addr) == p->mon_net.s_addr) { if (p->mode == PR_MODE_TCP) { close(cfd); - pool_free(session, s); + pool_free2(pool2_session, s); continue; } s->flags |= SN_MONITOR; } - if ((t = pool_alloc(task)) == NULL) { /* disable this proxy for a while */ + if ((t = pool_alloc2(pool2_task)) == NULL) { /* disable this proxy for a while */ Alert("out of memory in event_accept().\n"); EV_FD_CLR(fd, DIR_RD); p->state = PR_STIDLE; close(cfd); - pool_free(session, s); + pool_free2(pool2_session, s); return 0; } @@ -146,8 +147,8 @@ int event_accept(int fd) { if (cfd >= global.maxsock) { Alert("accept(): not enough free sockets. Raise -n argument. Giving up.\n"); close(cfd); - pool_free(task, t); - pool_free(session, s); + pool_free2(pool2_task, t); + pool_free2(pool2_session, s); return 0; } @@ -156,8 +157,8 @@ int event_accept(int fd) { (char *) &one, sizeof(one)) == -1)) { Alert("accept(): cannot set the socket in non blocking mode. Giving up\n"); close(cfd); - pool_free(task, t); - pool_free(session, s); + pool_free2(pool2_task, t); + pool_free2(pool2_session, s); return 0; } @@ -236,8 +237,8 @@ int event_accept(int fd) { pool_alloc_from(p->req_cap_pool, p->nb_req_cap*sizeof(char *))) == NULL) { /* no memory */ close(cfd); /* nothing can be done for this fd without memory */ - pool_free(task, t); - pool_free(session, s); + pool_free2(pool2_task, t); + pool_free2(pool2_session, s); return 0; } memset(txn->req.cap, 0, p->nb_req_cap*sizeof(char *)); @@ -251,8 +252,8 @@ int event_accept(int fd) { if (txn->req.cap != NULL) pool_free_to(p->req_cap_pool, txn->req.cap); close(cfd); /* nothing can be done for this fd without memory */ - pool_free(task, t); - pool_free(session, s); + pool_free2(pool2_task, t); + pool_free2(pool2_session, s); return 0; } memset(txn->rsp.cap, 0, p->nb_rsp_cap*sizeof(char *)); @@ -267,8 +268,8 @@ int event_accept(int fd) { if (txn->req.cap != NULL) pool_free_to(p->req_cap_pool, txn->req.cap); close(cfd); /* nothing can be done for this fd without memory */ - pool_free(task, t); - pool_free(session, s); + pool_free2(pool2_task, t); + pool_free2(pool2_session, s); return 0; } hdr_idx_init(&txn->hdr_idx); @@ -354,8 +355,8 @@ int event_accept(int fd) { if (txn->req.cap != NULL) pool_free_to(p->req_cap_pool, txn->req.cap); close(cfd); /* nothing can be done for this fd without memory */ - pool_free(task, t); - pool_free(session, s); + pool_free2(pool2_task, t); + pool_free2(pool2_session, s); return 0; } @@ -377,8 +378,8 @@ int event_accept(int fd) { if (txn->req.cap != NULL) pool_free_to(p->req_cap_pool, txn->req.cap); close(cfd); /* nothing can be done for this fd without memory */ - pool_free(task, t); - pool_free(session, s); + pool_free2(pool2_task, t); + pool_free2(pool2_session, s); return 0; } diff --git a/src/haproxy.c b/src/haproxy.c index 0acf75fb5..18bef8514 100644 --- a/src/haproxy.c +++ b/src/haproxy.c @@ -87,6 +87,7 @@ #include #include #include +#include #include #include @@ -292,6 +293,9 @@ void dump(int sig) ); } #endif + /* dump memory usage then free everything possible */ + dump_pools(); + pool_gc2(); } #ifdef DEBUG_MEMORY @@ -370,6 +374,8 @@ void init(int argc, char **argv) localtime((time_t *)&now.tv_sec); start_date = now; + init_task(); + init_session(); init_proto_http(); cfg_polling_mechanism = POLL_USE_SELECT; /* select() is always available */ @@ -654,10 +660,10 @@ void deinit(void) if (fdtab) free(fdtab); - pool_destroy(pool_session); + pool_destroy2(pool2_session); pool_destroy(pool_buffer); pool_destroy(pool_requri); - pool_destroy(pool_task); + pool_destroy2(pool2_task); pool_destroy(pool_capture); pool_destroy(pool_appsess); diff --git a/src/session.c b/src/session.c index 21d34801c..63bede3ee 100644 --- a/src/session.c +++ b/src/session.c @@ -1,7 +1,7 @@ /* * Server management functions. * - * Copyright 2000-2006 Willy Tarreau + * Copyright 2000-2007 Willy Tarreau * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License @@ -26,7 +26,7 @@ #include -void **pool_session = NULL; +struct pool_head *pool2_session; /* * frees the context associated to a session. It must have been removed first. @@ -69,7 +69,15 @@ void session_free(struct session *s) if (txn->srv_cookie) pool_free(capture, txn->srv_cookie); - pool_free(session, s); + pool_free2(pool2_session, s); +} + + +/* perform minimal intializations, report 0 in case of error, 1 if OK. */ +int init_session() +{ + pool2_session = create_pool("session", sizeof(struct session), MEM_F_SHARED); + return pool2_session != NULL; } diff --git a/src/task.c b/src/task.c index 41c0b2a2b..182de2508 100644 --- a/src/task.c +++ b/src/task.c @@ -11,6 +11,7 @@ */ #include +#include #include #include #include @@ -23,15 +24,22 @@ #include #include - -void **pool_task= NULL; -void **pool_tree64 = NULL; static struct ultree *stack[LLONGBITS]; +struct pool_head *pool2_task, *pool2_tree64; + UL2TREE_HEAD(timer_wq); void *eternity_queue = NULL; void *run_queue = NULL; +/* perform minimal intializations, report 0 in case of error, 1 if OK. */ +int init_task() +{ + pool2_task = create_pool("task", sizeof(struct task), MEM_F_SHARED); + pool2_tree64 = create_pool("tree64", sizeof(struct tree64), MEM_F_SHARED); + return pool2_task && pool2_tree64; +} + struct ultree *ul2tree_insert(struct ultree *root, unsigned long h, unsigned long l) { return __ul2tree_insert(root, h, l); From 7341d94c5d543a993c468d3ed10f45e8952b79ec Mon Sep 17 00:00:00 2001 From: Willy Tarreau Date: Sun, 13 May 2007 19:56:02 +0200 Subject: [PATCH 04/12] [MAJOR] switched buffers to mempools v2 --- include/proto/buffers.h | 8 ++++++++ include/types/buffers.h | 3 --- src/buffers.c | 12 +++++++++++- src/client.c | 6 +++--- src/haproxy.c | 3 ++- src/session.c | 5 +++-- 6 files changed, 27 insertions(+), 10 deletions(-) diff --git a/include/proto/buffers.h b/include/proto/buffers.h index 6c3996218..74efe8fdf 100644 --- a/include/proto/buffers.h +++ b/include/proto/buffers.h @@ -22,11 +22,19 @@ #ifndef _PROTO_BUFFERS_H #define _PROTO_BUFFERS_H +#include #include +#include #include +#include #include +extern struct pool_head *pool2_buffer; + +/* perform minimal intializations, report 0 in case of error, 1 if OK. */ +int init_buffer(); + /* Initializes all fields in the buffer. The ->rlim field is initialized last * so that the compiler can optimize it away if changed immediately after the * call to this function. diff --git a/include/types/buffers.h b/include/types/buffers.h index 9b781b842..09d1e3419 100644 --- a/include/types/buffers.h +++ b/include/types/buffers.h @@ -73,9 +73,6 @@ struct buffer { char data[BUFSIZE]; }; -#define sizeof_buffer sizeof(struct buffer) -extern void **pool_buffer; - #endif /* _TYPES_BUFFERS_H */ diff --git a/src/buffers.c b/src/buffers.c index 5739fcf52..658539c3a 100644 --- a/src/buffers.c +++ b/src/buffers.c @@ -15,9 +15,19 @@ #include #include +#include #include -void **pool_buffer = NULL; +struct pool_head *pool2_buffer; + + +/* perform minimal intializations, report 0 in case of error, 1 if OK. */ +int init_buffer() +{ + pool2_buffer = create_pool("buffer", sizeof(struct buffer), MEM_F_SHARED); + return pool2_buffer != NULL; +} + /* writes bytes from message to buffer . Returns 0 in case of * success, or the number of bytes available otherwise. diff --git a/src/client.c b/src/client.c index 6afb20636..6a1a3dfb6 100644 --- a/src/client.c +++ b/src/client.c @@ -347,7 +347,7 @@ int event_accept(int fd) { write(1, trash, len); } - if ((s->req = pool_alloc(buffer)) == NULL) { /* no memory */ + if ((s->req = pool_alloc2(pool2_buffer)) == NULL) { /* no memory */ if (txn->hdr_idx.v != NULL) pool_free_to(p->hdr_idx_pool, txn->hdr_idx.v); if (txn->rsp.cap != NULL) @@ -369,8 +369,8 @@ int event_accept(int fd) { s->req->wto = s->be->srvtimeout; s->req->cto = s->be->srvtimeout; - if ((s->rep = pool_alloc(buffer)) == NULL) { /* no memory */ - pool_free(buffer, s->req); + if ((s->rep = pool_alloc2(pool2_buffer)) == NULL) { /* no memory */ + pool_free2(pool2_buffer, s->req); if (txn->hdr_idx.v != NULL) pool_free_to(p->hdr_idx_pool, txn->hdr_idx.v); if (txn->rsp.cap != NULL) diff --git a/src/haproxy.c b/src/haproxy.c index 18bef8514..59c614978 100644 --- a/src/haproxy.c +++ b/src/haproxy.c @@ -374,6 +374,7 @@ void init(int argc, char **argv) localtime((time_t *)&now.tv_sec); start_date = now; + init_buffer(); init_task(); init_session(); init_proto_http(); @@ -661,7 +662,7 @@ void deinit(void) if (fdtab) free(fdtab); pool_destroy2(pool2_session); - pool_destroy(pool_buffer); + pool_destroy2(pool2_buffer); pool_destroy(pool_requri); pool_destroy2(pool2_task); pool_destroy(pool_capture); diff --git a/src/session.c b/src/session.c index 63bede3ee..1b574a00b 100644 --- a/src/session.c +++ b/src/session.c @@ -21,6 +21,7 @@ #include #include +#include #include #include #include @@ -38,9 +39,9 @@ void session_free(struct session *s) if (s->pend_pos) pendconn_free(s->pend_pos); if (s->req) - pool_free(buffer, s->req); + pool_free2(pool2_buffer, s->req); if (s->rep) - pool_free(buffer, s->rep); + pool_free2(pool2_buffer, s->rep); if (txn->hdr_idx.v != NULL) pool_free_to(s->fe->hdr_idx_pool, txn->hdr_idx.v); From e4d7e5506133133d3996242ae8e64399d9029406 Mon Sep 17 00:00:00 2001 From: Willy Tarreau Date: Sun, 13 May 2007 20:19:55 +0200 Subject: [PATCH 05/12] [MAJOR] ported pendconn to mempools v2 A pool_destroy() was also missing in deinit() --- include/proto/queue.h | 3 +++ include/types/queue.h | 4 ---- src/haproxy.c | 4 +++- src/queue.c | 14 +++++++++++--- 4 files changed, 17 insertions(+), 8 deletions(-) diff --git a/include/proto/queue.h b/include/proto/queue.h index 4370cb39d..092747a03 100644 --- a/include/proto/queue.h +++ b/include/proto/queue.h @@ -32,6 +32,9 @@ #include #include +extern struct pool_head *pool2_pendconn; + +int init_pendconn(); struct session *pendconn_get_next_sess(struct server *srv, struct proxy *px); struct pendconn *pendconn_add(struct session *sess); void pendconn_free(struct pendconn *p); diff --git a/include/types/queue.h b/include/types/queue.h index a8e7d8b01..922aa92fd 100644 --- a/include/types/queue.h +++ b/include/types/queue.h @@ -34,10 +34,6 @@ struct pendconn { struct server *srv; /* the server we are waiting for */ }; -#define sizeof_pendconn sizeof(struct pendconn) -extern void **pool_pendconn; - - #endif /* _TYPES_QUEUE_H */ /* diff --git a/src/haproxy.c b/src/haproxy.c index 59c614978..c88bffcd4 100644 --- a/src/haproxy.c +++ b/src/haproxy.c @@ -374,9 +374,10 @@ void init(int argc, char **argv) localtime((time_t *)&now.tv_sec); start_date = now; - init_buffer(); init_task(); init_session(); + init_buffer(); + init_pendconn(); init_proto_http(); cfg_polling_mechanism = POLL_USE_SELECT; /* select() is always available */ @@ -667,6 +668,7 @@ void deinit(void) pool_destroy2(pool2_task); pool_destroy(pool_capture); pool_destroy(pool_appsess); + pool_destroy2(pool2_pendconn); if (have_appsession) { pool_destroy(apools.serverid); diff --git a/src/queue.c b/src/queue.c index 37d3ed850..a4670a80c 100644 --- a/src/queue.c +++ b/src/queue.c @@ -11,6 +11,7 @@ */ #include +#include #include #include @@ -21,7 +22,14 @@ #include -void **pool_pendconn = NULL; +struct pool_head *pool2_pendconn; + +/* perform minimal intializations, report 0 in case of error, 1 if OK. */ +int init_pendconn() +{ + pool2_pendconn = create_pool("pendconn", sizeof(struct pendconn), MEM_F_SHARED); + return pool2_pendconn != NULL; +} /* returns the effective dynamic maxconn for a server, considering the minconn * and the proxy's usage relative to its dynamic connections limit. It is @@ -98,7 +106,7 @@ struct pendconn *pendconn_add(struct session *sess) { struct pendconn *p; - p = pool_alloc(pendconn); + p = pool_alloc2(pool2_pendconn); if (!p) return NULL; @@ -136,7 +144,7 @@ void pendconn_free(struct pendconn *p) else p->sess->be->nbpend--; p->sess->be->totpend--; - pool_free(pendconn, p); + pool_free2(pool2_pendconn, p); } From 63963c62e7077f2a89a1cc8b2a2fca6f20e50d34 Mon Sep 17 00:00:00 2001 From: Willy Tarreau Date: Sun, 13 May 2007 21:29:55 +0200 Subject: [PATCH 06/12] [MAJOR] ported appsession to use mempools v2 Also during this process, a bug was found in appsession_refresh(). It would not automatically requeue the task in the queue, so the old sessions would not vanish. --- include/common/appsession.h | 10 ++++---- src/appsession.c | 47 +++++++++++++++++++++++-------------- src/haproxy.c | 6 ++--- src/proto_http.c | 24 +++++++++---------- 4 files changed, 49 insertions(+), 38 deletions(-) diff --git a/include/common/appsession.h b/include/common/appsession.h index 8fa681cae..46872986b 100644 --- a/include/common/appsession.h +++ b/include/common/appsession.h @@ -10,6 +10,7 @@ #include #include #include +#include #include @@ -20,14 +21,11 @@ typedef struct appsessions { unsigned long int request_count; } appsess; -#define sizeof_appsess sizeof(struct appsessions) -extern void **pool_appsess; +extern struct pool_head *pool2_appsess; struct app_pool { - void **sessid; - void **serverid; - int ses_waste, ses_use, ses_msize; - int ser_waste, ser_use, ser_msize; + struct pool_head *sessid; + struct pool_head *serverid; }; extern struct app_pool apools; diff --git a/src/appsession.c b/src/appsession.c index bf26510e4..50554a50d 100644 --- a/src/appsession.c +++ b/src/appsession.c @@ -2,6 +2,7 @@ * AppSession functions. * * Copyright 2004-2006 Alexander Lazic, Klaus Wagner + * Copyright 2006-2007 Willy Tarreau * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License @@ -17,6 +18,7 @@ #include #include #include +#include #include #include @@ -27,7 +29,7 @@ #include -void **pool_appsess = NULL; +struct pool_head *pool2_appsess; struct app_pool apools; int have_appsession; @@ -72,30 +74,40 @@ int appsession_init(void) struct proxy *p = proxy; if (!initialized) { + pool2_appsess = create_pool("appsess", sizeof(appsess), MEM_F_SHARED); + if (pool2_appsess == NULL) + return -1; + if (!appsession_task_init()) { + int ser_msize, ses_msize; + apools.sessid = NULL; apools.serverid = NULL; - apools.ser_waste = 0; - apools.ser_use = 0; - apools.ser_msize = sizeof(void *); - apools.ses_waste = 0; - apools.ses_use = 0; - apools.ses_msize = sizeof(void *); + + ser_msize = sizeof(void *); + ses_msize = sizeof(void *); while (p) { s = p->srv; - if (apools.ses_msize < p->appsession_len) - apools.ses_msize = p->appsession_len; + if (ses_msize < p->appsession_len) + ses_msize = p->appsession_len; while (s) { idlen = strlen(s->id); - if (apools.ser_msize < idlen) - apools.ser_msize = idlen; + if (ser_msize < idlen) + ser_msize = idlen; s = s->next; } p = p->next; } /* we use strings, so reserve space for '\0' */ - apools.ser_msize ++; - apools.ses_msize ++; + ser_msize ++; + ses_msize ++; + + apools.sessid = create_pool("sessid", ses_msize, MEM_F_SHARED); + if (!apools.sessid) + return -1; + apools.serverid = create_pool("serverid", ser_msize, MEM_F_SHARED); + if (!apools.serverid) + return -1; } else { fprintf(stderr, "appsession_task_init failed\n"); @@ -118,8 +130,8 @@ int appsession_task_init(void) t->state = TASK_IDLE; t->context = NULL; tv_ms_add(&t->expire, &now, TBLCHKINT); - task_queue(t); t->process = appsession_refresh; + task_queue(t); initialized ++; } return 0; @@ -174,6 +186,7 @@ void appsession_refresh(struct task *t, struct timeval *next) p = p->next; } tv_ms_add(&t->expire, &now, TBLCHKINT); /* check expiration every 5 seconds */ + task_queue(t); *next = t->expire; } /* end appsession_refresh */ @@ -196,12 +209,12 @@ void destroy(void *data) { temp1 = (appsess *)data; if (temp1->sessid) - pool_free_to(apools.sessid, temp1->sessid); + pool_free2(apools.sessid, temp1->sessid); if (temp1->serverid) - pool_free_to(apools.serverid, temp1->serverid); + pool_free2(apools.serverid, temp1->serverid); - pool_free(appsess, temp1); + pool_free2(pool2_appsess, temp1); } /* end destroy */ void appsession_cleanup( void ) diff --git a/src/haproxy.c b/src/haproxy.c index c88bffcd4..7f5641c4f 100644 --- a/src/haproxy.c +++ b/src/haproxy.c @@ -667,12 +667,12 @@ void deinit(void) pool_destroy(pool_requri); pool_destroy2(pool2_task); pool_destroy(pool_capture); - pool_destroy(pool_appsess); + pool_destroy2(pool2_appsess); pool_destroy2(pool2_pendconn); if (have_appsession) { - pool_destroy(apools.serverid); - pool_destroy(apools.sessid); + pool_destroy2(apools.serverid); + pool_destroy2(apools.sessid); } } /* end deinit() */ diff --git a/src/proto_http.c b/src/proto_http.c index d1bfdcf22..51d265cb9 100644 --- a/src/proto_http.c +++ b/src/proto_http.c @@ -4298,7 +4298,7 @@ void manage_client_side_cookies(struct session *t, struct buffer *req) asession_temp = &local_asession; - if ((asession_temp->sessid = pool_alloc_from(apools.sessid, apools.ses_msize)) == NULL) { + if ((asession_temp->sessid = pool_alloc2(apools.sessid)) == NULL) { Alert("Not enough memory process_cli():asession->sessid:malloc().\n"); send_log(t->be, LOG_ALERT, "Not enough memory process_cli():asession->sessid:malloc().\n"); return; @@ -4310,9 +4310,9 @@ void manage_client_side_cookies(struct session *t, struct buffer *req) /* only do insert, if lookup fails */ if (chtbl_lookup(&(t->be->htbl_proxy), (void *) &asession_temp) != 0) { - if ((asession_temp = pool_alloc(appsess)) == NULL) { + if ((asession_temp = pool_alloc2(pool2_appsess)) == NULL) { /* free previously allocated memory */ - pool_free_to(apools.sessid, local_asession.sessid); + pool_free2(apools.sessid, local_asession.sessid); Alert("Not enough memory process_cli():asession:calloc().\n"); send_log(t->be, LOG_ALERT, "Not enough memory process_cli():asession:calloc().\n"); return; @@ -4323,7 +4323,7 @@ void manage_client_side_cookies(struct session *t, struct buffer *req) chtbl_insert(&(t->be->htbl_proxy), (void *) asession_temp); } else { /* free previously allocated memory */ - pool_free_to(apools.sessid, local_asession.sessid); + pool_free2(apools.sessid, local_asession.sessid); } if (asession_temp->serverid == NULL) { @@ -4771,7 +4771,7 @@ void manage_server_side_cookies(struct session *t, struct buffer *rtr) size_t server_id_len = strlen(t->srv->id) + 1; asession_temp = &local_asession; - if ((asession_temp->sessid = pool_alloc_from(apools.sessid, apools.ses_msize)) == NULL) { + if ((asession_temp->sessid = pool_alloc2(apools.sessid)) == NULL) { Alert("Not enough Memory process_srv():asession->sessid:malloc().\n"); send_log(t->be, LOG_ALERT, "Not enough Memory process_srv():asession->sessid:malloc().\n"); return; @@ -4782,7 +4782,7 @@ void manage_server_side_cookies(struct session *t, struct buffer *rtr) /* only do insert, if lookup fails */ if (chtbl_lookup(&(t->be->htbl_proxy), (void *) &asession_temp) != 0) { - if ((asession_temp = pool_alloc(appsess)) == NULL) { + if ((asession_temp = pool_alloc2(pool2_appsess)) == NULL) { Alert("Not enough Memory process_srv():asession:calloc().\n"); send_log(t->be, LOG_ALERT, "Not enough Memory process_srv():asession:calloc().\n"); return; @@ -4793,11 +4793,11 @@ void manage_server_side_cookies(struct session *t, struct buffer *rtr) }/* end if (chtbl_lookup()) */ else { /* free wasted memory */ - pool_free_to(apools.sessid, local_asession.sessid); + pool_free2(apools.sessid, local_asession.sessid); } /* end else from if (chtbl_lookup()) */ if (asession_temp->serverid == NULL) { - if ((asession_temp->serverid = pool_alloc_from(apools.serverid, apools.ser_msize)) == NULL) { + if ((asession_temp->serverid = pool_alloc2(apools.serverid)) == NULL) { Alert("Not enough Memory process_srv():asession->sessid:malloc().\n"); send_log(t->be, LOG_ALERT, "Not enough Memory process_srv():asession->sessid:malloc().\n"); return; @@ -4941,7 +4941,7 @@ void get_srv_from_appsession(struct session *t, const char *begin, int len) /* First try if we already have an appsession */ asession_temp = &local_asession; - if ((asession_temp->sessid = pool_alloc_from(apools.sessid, apools.ses_msize)) == NULL) { + if ((asession_temp->sessid = pool_alloc2(apools.sessid)) == NULL) { Alert("Not enough memory process_cli():asession_temp->sessid:calloc().\n"); send_log(t->be, LOG_ALERT, "Not enough Memory process_cli():asession_temp->sessid:calloc().\n"); return; @@ -4954,9 +4954,9 @@ void get_srv_from_appsession(struct session *t, const char *begin, int len) /* only do insert, if lookup fails */ if (chtbl_lookup(&(t->be->htbl_proxy), (void *)&asession_temp)) { - if ((asession_temp = pool_alloc(appsess)) == NULL) { + if ((asession_temp = pool_alloc2(pool2_appsess)) == NULL) { /* free previously allocated memory */ - pool_free_to(apools.sessid, local_asession.sessid); + pool_free2(apools.sessid, local_asession.sessid); Alert("Not enough memory process_cli():asession:calloc().\n"); send_log(t->be, LOG_ALERT, "Not enough memory process_cli():asession:calloc().\n"); return; @@ -4967,7 +4967,7 @@ void get_srv_from_appsession(struct session *t, const char *begin, int len) } else { /* free previously allocated memory */ - pool_free_to(apools.sessid, local_asession.sessid); + pool_free2(apools.sessid, local_asession.sessid); } tv_add(&asession_temp->expire, &now, &t->be->appsession_timeout); From 332f8bfc5b992472b2f6df58732cd8e6140a4671 Mon Sep 17 00:00:00 2001 From: Willy Tarreau Date: Sun, 13 May 2007 21:36:56 +0200 Subject: [PATCH 07/12] [MAJOR] ported requri to use mempools v2 --- include/common/memory.h | 1 - include/proto/log.h | 3 +++ include/types/log.h | 2 -- src/haproxy.c | 2 +- src/proto_http.c | 7 +++++-- src/session.c | 3 ++- 6 files changed, 11 insertions(+), 7 deletions(-) diff --git a/include/common/memory.h b/include/common/memory.h index 0f142f028..c50ab9a83 100644 --- a/include/common/memory.h +++ b/include/common/memory.h @@ -27,7 +27,6 @@ #include #include -#define sizeof_requri REQURI_LEN #define sizeof_capture CAPTURE_LEN /* * Returns a pointer to an area of <__len> bytes taken from the pool or diff --git a/include/proto/log.h b/include/proto/log.h index 4ed56ddf3..1a02ec122 100644 --- a/include/proto/log.h +++ b/include/proto/log.h @@ -27,10 +27,13 @@ #include #include +#include #include #include #include +extern struct pool_head *pool2_requri; + /* * Displays the message on stderr with the date and pid. Overrides the quiet * mode during startup. diff --git a/include/types/log.h b/include/types/log.h index dc04e6580..12f8e2767 100644 --- a/include/types/log.h +++ b/include/types/log.h @@ -44,8 +44,6 @@ #define LW_REQHDR 1024 /* request header(s) */ #define LW_RSPHDR 2048 /* response header(s) */ -extern void **pool_requri; - #endif /* _TYPES_LOG_H */ diff --git a/src/haproxy.c b/src/haproxy.c index 7f5641c4f..ed26a54e5 100644 --- a/src/haproxy.c +++ b/src/haproxy.c @@ -664,7 +664,7 @@ void deinit(void) pool_destroy2(pool2_session); pool_destroy2(pool2_buffer); - pool_destroy(pool_requri); + pool_destroy2(pool2_requri); pool_destroy2(pool2_task); pool_destroy(pool_capture); pool_destroy2(pool2_appsess); diff --git a/src/proto_http.c b/src/proto_http.c index 51d265cb9..39d2a463a 100644 --- a/src/proto_http.c +++ b/src/proto_http.c @@ -243,6 +243,9 @@ void init_proto_http() FD_SET(*tmp, url_encode_map); tmp++; } + + /* memory allocations */ + pool2_requri = create_pool("requri", REQURI_LEN, MEM_F_SHARED); } /* @@ -624,7 +627,7 @@ const char sess_cookie[4] = "NIDV"; /* No cookie, Invalid cookie, cookie fo const char sess_set_cookie[8] = "N1I3PD5R"; /* No set-cookie, unknown, Set-Cookie Inserted, unknown, Set-cookie seen and left unchanged (passive), Set-cookie Deleted, unknown, Set-cookie Rewritten */ -void **pool_requri = NULL; +struct pool_head *pool2_requri; /* * send a log for the session when we have enough info about it. @@ -1592,7 +1595,7 @@ int process_cli(struct session *t) */ if (unlikely(t->logs.logwait & LW_REQ)) { /* we have a complete HTTP request that we must log */ - if ((txn->uri = pool_alloc(requri)) != NULL) { + if ((txn->uri = pool_alloc2(pool2_requri)) != NULL) { int urilen = msg->sl.rq.l; if (urilen >= REQURI_LEN) diff --git a/src/session.c b/src/session.c index 1b574a00b..4efc1cebe 100644 --- a/src/session.c +++ b/src/session.c @@ -23,6 +23,7 @@ #include #include +#include #include #include @@ -64,7 +65,7 @@ void session_free(struct session *s) } if (txn->uri) - pool_free(requri, txn->uri); + pool_free2(pool2_requri, txn->uri); if (txn->cli_cookie) pool_free(capture, txn->cli_cookie); if (txn->srv_cookie) From 086b3b4c9f1ba70abe2a8ad822fd7c1f735aed7d Mon Sep 17 00:00:00 2001 From: Willy Tarreau Date: Sun, 13 May 2007 21:45:51 +0200 Subject: [PATCH 08/12] [MAJOR] ported the captures to use the new mempool v2 The "capture.c" file has also been removed since it was empty. --- Makefile | 2 +- Makefile.bsd | 2 +- Makefile.osx | 2 +- include/types/capture.h | 5 +++-- src/capture.c | 26 -------------------------- src/haproxy.c | 2 +- src/proto_http.c | 6 ++++-- src/session.c | 4 ++-- 8 files changed, 13 insertions(+), 36 deletions(-) delete mode 100644 src/capture.c diff --git a/Makefile b/Makefile index 122f1c6fa..37439c30e 100644 --- a/Makefile +++ b/Makefile @@ -215,7 +215,7 @@ all: haproxy OBJS = src/haproxy.o src/list.o src/chtbl.o src/hashpjw.o src/base64.o \ src/uri_auth.o src/standard.o src/buffers.o src/log.o src/task.o \ src/time.o src/fd.o src/regex.o src/cfgparse.o src/server.o \ - src/checks.o src/queue.o src/capture.o src/client.o src/proxy.o \ + src/checks.o src/queue.o src/client.o src/proxy.o \ src/proto_http.o src/stream_sock.o src/appsession.o src/backend.o \ src/session.o src/hdr_idx.o src/ev_select.o src/acl.o src/memory.o diff --git a/Makefile.bsd b/Makefile.bsd index 945b08e24..cc8004086 100644 --- a/Makefile.bsd +++ b/Makefile.bsd @@ -85,7 +85,7 @@ LDFLAGS = -g OBJS = src/haproxy.o src/list.o src/chtbl.o src/hashpjw.o src/base64.o \ src/uri_auth.o src/standard.o src/buffers.o src/log.o src/task.o \ src/time.o src/fd.o src/regex.o src/cfgparse.o src/server.o \ - src/checks.o src/queue.o src/capture.o src/client.o src/proxy.o \ + src/checks.o src/queue.o src/client.o src/proxy.o \ src/proto_http.o src/stream_sock.o src/appsession.o src/backend.o \ src/session.o src/hdr_idx.o src/ev_select.o src/ev_poll.o \ src/ev_kqueue.o src/acl.o src/memory.o diff --git a/Makefile.osx b/Makefile.osx index 0618e68c9..5cf4f08fd 100644 --- a/Makefile.osx +++ b/Makefile.osx @@ -85,7 +85,7 @@ LDFLAGS = -g -isysroot /Developer/SDKs/MacOSX10.4u.sdk -arch ppc -arch i386 OBJS = src/haproxy.o src/list.o src/chtbl.o src/hashpjw.o src/base64.o \ src/uri_auth.o src/standard.o src/buffers.o src/log.o src/task.o \ src/time.o src/fd.o src/regex.o src/cfgparse.o src/server.o \ - src/checks.o src/queue.o src/capture.o src/client.o src/proxy.o \ + src/checks.o src/queue.o src/client.o src/proxy.o \ src/proto_http.o src/stream_sock.o src/appsession.o src/backend.o \ src/session.o src/hdr_idx.o src/ev_select.o src/ev_poll.o src/acl.o \ src/memory.o diff --git a/include/types/capture.h b/include/types/capture.h index d0271a2e2..49f4d535a 100644 --- a/include/types/capture.h +++ b/include/types/capture.h @@ -2,7 +2,7 @@ include/types/capture.h This file defines everything related to captures. - Copyright (C) 2000-2006 Willy Tarreau - w@1wt.eu + Copyright (C) 2000-2007 Willy Tarreau - w@1wt.eu This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public @@ -23,6 +23,7 @@ #define _TYPES_CAPTURE_H #include +#include struct cap_hdr { struct cap_hdr *next; @@ -33,7 +34,7 @@ struct cap_hdr { void *pool; /* pool of pre-allocated memory area of (len+1) bytes */ }; -extern void **pool_capture; +extern struct pool_head *pool2_capture; #endif /* _TYPES_CAPTURE_H */ diff --git a/src/capture.c b/src/capture.c deleted file mode 100644 index c0c4a75f5..000000000 --- a/src/capture.c +++ /dev/null @@ -1,26 +0,0 @@ -/* - * Capture variables and functions. - * - * Copyright 2000-2006 Willy Tarreau - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version - * 2 of the License, or (at your option) any later version. - * - */ - -#include - -#include -#include - -void **pool_capture = NULL; - - -/* - * Local variables: - * c-indent-level: 8 - * c-basic-offset: 8 - * End: - */ diff --git a/src/haproxy.c b/src/haproxy.c index ed26a54e5..344238976 100644 --- a/src/haproxy.c +++ b/src/haproxy.c @@ -666,7 +666,7 @@ void deinit(void) pool_destroy2(pool2_buffer); pool_destroy2(pool2_requri); pool_destroy2(pool2_task); - pool_destroy(pool_capture); + pool_destroy2(pool2_capture); pool_destroy2(pool2_appsess); pool_destroy2(pool2_pendconn); diff --git a/src/proto_http.c b/src/proto_http.c index 39d2a463a..64ab50799 100644 --- a/src/proto_http.c +++ b/src/proto_http.c @@ -246,6 +246,7 @@ void init_proto_http() /* memory allocations */ pool2_requri = create_pool("requri", REQURI_LEN, MEM_F_SHARED); + pool2_capture = create_pool("capture", CAPTURE_LEN, MEM_F_SHARED); } /* @@ -628,6 +629,7 @@ const char sess_set_cookie[8] = "N1I3PD5R"; /* No set-cookie, unknown, Set-Cooki Set-cookie seen and left unchanged (passive), Set-cookie Deleted, unknown, Set-cookie Rewritten */ struct pool_head *pool2_requri; +struct pool_head *pool2_capture; /* * send a log for the session when we have enough info about it. @@ -4172,7 +4174,7 @@ void manage_client_side_cookies(struct session *t, struct buffer *req) memcmp(p1, t->fe->capture_name, t->fe->capture_namelen) == 0) { int log_len = p4 - p1; - if ((txn->cli_cookie = pool_alloc(capture)) == NULL) { + if ((txn->cli_cookie = pool_alloc2(pool2_capture)) == NULL) { Alert("HTTP logging : out of memory.\n"); } else { if (log_len > t->fe->capture_len) @@ -4707,7 +4709,7 @@ void manage_server_side_cookies(struct session *t, struct buffer *rtr) memcmp(p1, t->be->capture_name, t->be->capture_namelen) == 0) { int log_len = p4 - p1; - if ((txn->srv_cookie = pool_alloc(capture)) == NULL) { + if ((txn->srv_cookie = pool_alloc2(pool2_capture)) == NULL) { Alert("HTTP logging : out of memory.\n"); } diff --git a/src/session.c b/src/session.c index 4efc1cebe..38889c4e2 100644 --- a/src/session.c +++ b/src/session.c @@ -67,9 +67,9 @@ void session_free(struct session *s) if (txn->uri) pool_free2(pool2_requri, txn->uri); if (txn->cli_cookie) - pool_free(capture, txn->cli_cookie); + pool_free2(pool2_capture, txn->cli_cookie); if (txn->srv_cookie) - pool_free(capture, txn->srv_cookie); + pool_free2(pool2_capture, txn->srv_cookie); pool_free2(pool2_session, s); } From cf7f320f9d8ddda994ca0d8af7772da396bc00e9 Mon Sep 17 00:00:00 2001 From: Willy Tarreau Date: Sun, 13 May 2007 22:46:04 +0200 Subject: [PATCH 09/12] [MAJOR] last bunch of capture changes for mempool v2 The header captures had lots of pools. They have all been transformed. --- include/common/memory.h | 1 - include/types/capture.h | 2 +- include/types/proxy.h | 3 ++- src/cfgparse.c | 12 ++++++++++++ src/client.c | 24 +++++++++++------------- src/haproxy.c | 8 ++++---- src/proto_http.c | 2 +- src/session.c | 8 ++++---- 8 files changed, 35 insertions(+), 25 deletions(-) diff --git a/include/common/memory.h b/include/common/memory.h index c50ab9a83..45ac7f962 100644 --- a/include/common/memory.h +++ b/include/common/memory.h @@ -27,7 +27,6 @@ #include #include -#define sizeof_capture CAPTURE_LEN /* * Returns a pointer to an area of <__len> bytes taken from the pool or * dynamically allocated. In the first case, <__pool> is updated to point to diff --git a/include/types/capture.h b/include/types/capture.h index 49f4d535a..e37cc483f 100644 --- a/include/types/capture.h +++ b/include/types/capture.h @@ -31,7 +31,7 @@ struct cap_hdr { int namelen; /* length of the header name, to speed-up lookups */ int len; /* capture length, not including terminal zero */ int index; /* index in the output array */ - void *pool; /* pool of pre-allocated memory area of (len+1) bytes */ + struct pool_head *pool; /* pool of pre-allocated memory area of (len+1) bytes */ }; extern struct pool_head *pool2_capture; diff --git a/include/types/proxy.h b/include/types/proxy.h index 532348ec9..9be81d59e 100644 --- a/include/types/proxy.h +++ b/include/types/proxy.h @@ -140,7 +140,8 @@ struct proxy { int nb_req_cap, nb_rsp_cap; /* # of headers to be captured */ struct cap_hdr *req_cap; /* chained list of request headers to be captured */ struct cap_hdr *rsp_cap; /* chained list of response headers to be captured */ - void *req_cap_pool, *rsp_cap_pool; /* pools of pre-allocated char ** used to build the sessions */ + struct pool_head *req_cap_pool, /* pools of pre-allocated char ** used to build the sessions */ + *rsp_cap_pool; void *hdr_idx_pool; /* pools of pre-allocated int* used for headers indexing */ char *req_add[MAX_NEWHDR], *rsp_add[MAX_NEWHDR]; /* headers to be added */ int grace; /* grace time after stop request */ diff --git a/src/cfgparse.c b/src/cfgparse.c index 6dd7ab617..b532ce92d 100644 --- a/src/cfgparse.c +++ b/src/cfgparse.c @@ -824,6 +824,7 @@ int cfg_parse_listen(const char *file, int linenum, char **args) hdr->name = strdup(args[3]); hdr->namelen = strlen(args[3]); hdr->len = atol(args[5]); + hdr->pool = create_pool("caphdr", hdr->len + 1, MEM_F_SHARED); hdr->index = curproxy->nb_req_cap++; curproxy->req_cap = hdr; curproxy->to_log |= LW_REQHDR; @@ -846,6 +847,7 @@ int cfg_parse_listen(const char *file, int linenum, char **args) hdr->name = strdup(args[3]); hdr->namelen = strlen(args[3]); hdr->len = atol(args[5]); + hdr->pool = create_pool("caphdr", hdr->len + 1, MEM_F_SHARED); hdr->index = curproxy->nb_rsp_cap++; curproxy->rsp_cap = hdr; curproxy->to_log |= LW_RSPHDR; @@ -2401,6 +2403,16 @@ int readcfgfile(const char *file) memcpy(curproxy->check_req, sslv3_client_hello_pkt, sizeof(sslv3_client_hello_pkt)); } + /* The small pools required for the capture lists */ + if (curproxy->nb_req_cap) + curproxy->req_cap_pool = create_pool("ptrcap", + curproxy->nb_req_cap * sizeof(char *), + MEM_F_SHARED); + if (curproxy->nb_rsp_cap) + curproxy->rsp_cap_pool = create_pool("ptrcap", + curproxy->nb_rsp_cap * sizeof(char *), + MEM_F_SHARED); + /* for backwards compatibility with "listen" instances, if * fullconn is not set but maxconn is set, then maxconn * is used. diff --git a/src/client.c b/src/client.c index 6a1a3dfb6..38815e771 100644 --- a/src/client.c +++ b/src/client.c @@ -233,9 +233,8 @@ int event_accept(int fd) { txn->hdr_idx.size = MAX_HTTP_HDR; if (p->nb_req_cap > 0) { - if ((txn->req.cap = - pool_alloc_from(p->req_cap_pool, p->nb_req_cap*sizeof(char *))) - == NULL) { /* no memory */ + if ((txn->req.cap = pool_alloc2(p->req_cap_pool)) == NULL) { + /* no memory */ close(cfd); /* nothing can be done for this fd without memory */ pool_free2(pool2_task, t); pool_free2(pool2_session, s); @@ -246,11 +245,10 @@ int event_accept(int fd) { if (p->nb_rsp_cap > 0) { - if ((txn->rsp.cap = - pool_alloc_from(p->rsp_cap_pool, p->nb_rsp_cap*sizeof(char *))) - == NULL) { /* no memory */ + if ((txn->rsp.cap = pool_alloc2(p->rsp_cap_pool)) == NULL) { + /* no memory */ if (txn->req.cap != NULL) - pool_free_to(p->req_cap_pool, txn->req.cap); + pool_free2(p->req_cap_pool, txn->req.cap); close(cfd); /* nothing can be done for this fd without memory */ pool_free2(pool2_task, t); pool_free2(pool2_session, s); @@ -264,9 +262,9 @@ int event_accept(int fd) { pool_alloc_from(p->hdr_idx_pool, txn->hdr_idx.size*sizeof(*txn->hdr_idx.v))) == NULL) { /* no memory */ if (txn->rsp.cap != NULL) - pool_free_to(p->rsp_cap_pool, txn->rsp.cap); + pool_free2(p->rsp_cap_pool, txn->rsp.cap); if (txn->req.cap != NULL) - pool_free_to(p->req_cap_pool, txn->req.cap); + pool_free2(p->req_cap_pool, txn->req.cap); close(cfd); /* nothing can be done for this fd without memory */ pool_free2(pool2_task, t); pool_free2(pool2_session, s); @@ -351,9 +349,9 @@ int event_accept(int fd) { if (txn->hdr_idx.v != NULL) pool_free_to(p->hdr_idx_pool, txn->hdr_idx.v); if (txn->rsp.cap != NULL) - pool_free_to(p->rsp_cap_pool, txn->rsp.cap); + pool_free2(p->rsp_cap_pool, txn->rsp.cap); if (txn->req.cap != NULL) - pool_free_to(p->req_cap_pool, txn->req.cap); + pool_free2(p->req_cap_pool, txn->req.cap); close(cfd); /* nothing can be done for this fd without memory */ pool_free2(pool2_task, t); pool_free2(pool2_session, s); @@ -374,9 +372,9 @@ int event_accept(int fd) { if (txn->hdr_idx.v != NULL) pool_free_to(p->hdr_idx_pool, txn->hdr_idx.v); if (txn->rsp.cap != NULL) - pool_free_to(p->rsp_cap_pool, txn->rsp.cap); + pool_free2(p->rsp_cap_pool, txn->rsp.cap); if (txn->req.cap != NULL) - pool_free_to(p->req_cap_pool, txn->req.cap); + pool_free2(p->req_cap_pool, txn->req.cap); close(cfd); /* nothing can be done for this fd without memory */ pool_free2(pool2_task, t); pool_free2(pool2_session, s); diff --git a/src/haproxy.c b/src/haproxy.c index 344238976..4e22e1920 100644 --- a/src/haproxy.c +++ b/src/haproxy.c @@ -616,7 +616,7 @@ void deinit(void) h_next = h->next; if (h->name) free(h->name); - pool_destroy(h->pool); + pool_destroy2(h->pool); free(h); h = h_next; }/* end while(h) */ @@ -627,7 +627,7 @@ void deinit(void) if (h->name) free(h->name); - pool_destroy(h->pool); + pool_destroy2(h->pool); free(h); h = h_next; }/* end while(h) */ @@ -652,8 +652,8 @@ void deinit(void) l = l_next; }/* end while(l) */ - pool_destroy((void **) p->req_cap_pool); - pool_destroy((void **) p->rsp_cap_pool); + pool_destroy2(p->req_cap_pool); + pool_destroy2(p->rsp_cap_pool); p = p->next; }/* end while(p) */ diff --git a/src/proto_http.c b/src/proto_http.c index 64ab50799..4e9e68361 100644 --- a/src/proto_http.c +++ b/src/proto_http.c @@ -775,7 +775,7 @@ void capture_headers(char *som, struct hdr_idx *idx, (strncasecmp(sol, h->name, h->namelen) == 0)) { if (cap[h->index] == NULL) cap[h->index] = - pool_alloc_from(h->pool, h->len + 1); + pool_alloc2(h->pool); if (cap[h->index] == NULL) { Alert("HTTP capture : out of memory.\n"); diff --git a/src/session.c b/src/session.c index 38889c4e2..01073de62 100644 --- a/src/session.c +++ b/src/session.c @@ -51,17 +51,17 @@ void session_free(struct session *s) struct cap_hdr *h; for (h = s->fe->rsp_cap; h; h = h->next) { if (txn->rsp.cap[h->index] != NULL) - pool_free_to(h->pool, txn->rsp.cap[h->index]); + pool_free2(h->pool, txn->rsp.cap[h->index]); } - pool_free_to(s->fe->rsp_cap_pool, txn->rsp.cap); + pool_free2(s->fe->rsp_cap_pool, txn->rsp.cap); } if (txn->req.cap != NULL) { struct cap_hdr *h; for (h = s->fe->req_cap; h; h = h->next) { if (txn->req.cap[h->index] != NULL) - pool_free_to(h->pool, txn->req.cap[h->index]); + pool_free2(h->pool, txn->req.cap[h->index]); } - pool_free_to(s->fe->req_cap_pool, txn->req.cap); + pool_free2(s->fe->req_cap_pool, txn->req.cap); } if (txn->uri) From 1d4154a7c0bc44a9d036846f005b04b2d0bbead9 Mon Sep 17 00:00:00 2001 From: Willy Tarreau Date: Sun, 13 May 2007 22:57:02 +0200 Subject: [PATCH 10/12] [MAJOR] convert the header indexes to use mempool v2 --- include/types/proxy.h | 2 +- src/cfgparse.c | 4 ++++ src/client.c | 13 ++++++------- src/session.c | 2 +- 4 files changed, 12 insertions(+), 9 deletions(-) diff --git a/include/types/proxy.h b/include/types/proxy.h index 9be81d59e..bfbe63125 100644 --- a/include/types/proxy.h +++ b/include/types/proxy.h @@ -142,7 +142,7 @@ struct proxy { struct cap_hdr *rsp_cap; /* chained list of response headers to be captured */ struct pool_head *req_cap_pool, /* pools of pre-allocated char ** used to build the sessions */ *rsp_cap_pool; - void *hdr_idx_pool; /* pools of pre-allocated int* used for headers indexing */ + struct pool_head *hdr_idx_pool; /* pools of pre-allocated int* used for headers indexing */ char *req_add[MAX_NEWHDR], *rsp_add[MAX_NEWHDR]; /* headers to be added */ int grace; /* grace time after stop request */ char *check_req; /* HTTP or SSL request to use for PR_O_HTTP_CHK|PR_O_SSL3_CHK */ diff --git a/src/cfgparse.c b/src/cfgparse.c index b532ce92d..516547445 100644 --- a/src/cfgparse.c +++ b/src/cfgparse.c @@ -2413,6 +2413,10 @@ int readcfgfile(const char *file) curproxy->nb_rsp_cap * sizeof(char *), MEM_F_SHARED); + curproxy->hdr_idx_pool = create_pool("hdr_idx", + MAX_HTTP_HDR * sizeof(struct hdr_idx_elem), + MEM_F_SHARED); + /* for backwards compatibility with "listen" instances, if * fullconn is not set but maxconn is set, then maxconn * is used. diff --git a/src/client.c b/src/client.c index 38815e771..50a0f5d2f 100644 --- a/src/client.c +++ b/src/client.c @@ -230,8 +230,6 @@ int event_accept(int fd) { txn->req.som = txn->req.eoh = 0; /* relative to the buffer */ txn->auth_hdr.len = -1; - txn->hdr_idx.size = MAX_HTTP_HDR; - if (p->nb_req_cap > 0) { if ((txn->req.cap = pool_alloc2(p->req_cap_pool)) == NULL) { /* no memory */ @@ -258,9 +256,10 @@ int event_accept(int fd) { } - if ((txn->hdr_idx.v = - pool_alloc_from(p->hdr_idx_pool, txn->hdr_idx.size*sizeof(*txn->hdr_idx.v))) - == NULL) { /* no memory */ + txn->hdr_idx.size = MAX_HTTP_HDR; + + if ((txn->hdr_idx.v = pool_alloc2(p->hdr_idx_pool)) == NULL) { + /* no memory */ if (txn->rsp.cap != NULL) pool_free2(p->rsp_cap_pool, txn->rsp.cap); if (txn->req.cap != NULL) @@ -347,7 +346,7 @@ int event_accept(int fd) { if ((s->req = pool_alloc2(pool2_buffer)) == NULL) { /* no memory */ if (txn->hdr_idx.v != NULL) - pool_free_to(p->hdr_idx_pool, txn->hdr_idx.v); + pool_free2(p->hdr_idx_pool, txn->hdr_idx.v); if (txn->rsp.cap != NULL) pool_free2(p->rsp_cap_pool, txn->rsp.cap); if (txn->req.cap != NULL) @@ -370,7 +369,7 @@ int event_accept(int fd) { if ((s->rep = pool_alloc2(pool2_buffer)) == NULL) { /* no memory */ pool_free2(pool2_buffer, s->req); if (txn->hdr_idx.v != NULL) - pool_free_to(p->hdr_idx_pool, txn->hdr_idx.v); + pool_free2(p->hdr_idx_pool, txn->hdr_idx.v); if (txn->rsp.cap != NULL) pool_free2(p->rsp_cap_pool, txn->rsp.cap); if (txn->req.cap != NULL) diff --git a/src/session.c b/src/session.c index 01073de62..d13f99504 100644 --- a/src/session.c +++ b/src/session.c @@ -45,7 +45,7 @@ void session_free(struct session *s) pool_free2(pool2_buffer, s->rep); if (txn->hdr_idx.v != NULL) - pool_free_to(s->fe->hdr_idx_pool, txn->hdr_idx.v); + pool_free2(s->fe->hdr_idx_pool, txn->hdr_idx.v); if (txn->rsp.cap != NULL) { struct cap_hdr *h; From 7dcd46d4715b947e413b5a0cb13acb6c92182f59 Mon Sep 17 00:00:00 2001 From: Willy Tarreau Date: Mon, 14 May 2007 00:16:13 +0200 Subject: [PATCH 11/12] [MEDIUM] enhance behaviour of mempools v2 - keep the number of users of each pool - call the garbage collector on out of memory conditions - sort the pools by size for faster creation - force the alignment size to 16 bytes instead of 4*sizeof(void *) --- include/common/memory.h | 3 ++- src/memory.c | 43 ++++++++++++++++++++++++++++------------- 2 files changed, 32 insertions(+), 14 deletions(-) diff --git a/include/common/memory.h b/include/common/memory.h index 45ac7f962..66f789e25 100644 --- a/include/common/memory.h +++ b/include/common/memory.h @@ -125,7 +125,8 @@ struct pool_head { unsigned int minavail; /* how many chunks are expected to be used */ unsigned int size; /* chunk size */ unsigned int flags; /* MEM_F_* */ - char name[9]; /* name of the pool */ + unsigned int users; /* number of pools sharing this zone */ + char name[12]; /* name of the pool */ }; diff --git a/src/memory.c b/src/memory.c index dd542252b..589d1d270 100644 --- a/src/memory.c +++ b/src/memory.c @@ -26,6 +26,8 @@ static struct list pools = LIST_HEAD_INIT(pools); struct pool_head *create_pool(char *name, unsigned int size, unsigned int flags) { struct pool_head *pool; + struct pool_head *entry; + struct list *start; unsigned int align; /* We need to store at least a (void *) in the chunks. Since we know @@ -34,20 +36,29 @@ struct pool_head *create_pool(char *name, unsigned int size, unsigned int flags) * ease merging of entries. Note that the rounding is a power of two. */ - align = 4 * sizeof(void *); + align = 16; size = (size + align - 1) & -align; + start = &pools; pool = NULL; - if (flags & MEM_F_SHARED) { - struct pool_head *entry; - list_for_each_entry(entry, &pools, list) { - if (!(entry->flags & MEM_F_SHARED)) - continue; - if (entry->size == size) { + + list_for_each_entry(entry, &pools, list) { + if (entry->size == size) { + /* either we can share this place and we take it, or + * we look for a sharable one or for the next position + * before which we will insert a new one. + */ + if (flags & entry->flags & MEM_F_SHARED) { + /* we can share this one */ pool = entry; break; } } + else if (entry->size > size) { + /* insert before this one */ + start = &entry->list; + break; + } } if (!pool) { @@ -58,13 +69,15 @@ struct pool_head *create_pool(char *name, unsigned int size, unsigned int flags) strlcpy2(pool->name, name, sizeof(pool->name)); pool->size = size; pool->flags = flags; - LIST_ADDQ(&pools, &pool->list); + LIST_ADDQ(start, &pool->list); } + pool->users++; return pool; } /* Allocate a new entry for pool , and return it for immediate use. - * NULL is returned if no memory is available for a new creation. + * NULL is returned if no memory is available for a new creation. A call + * to the garbage collector is performed before returning NULL. */ void *pool_refill_alloc(struct pool_head *pool) { @@ -73,8 +86,12 @@ void *pool_refill_alloc(struct pool_head *pool) if (pool->limit && (pool->allocated >= pool->limit)) return NULL; ret = MALLOC(pool->size); - if (!ret) - return NULL; + if (!ret) { + pool_gc2(); + ret = MALLOC(pool->size); + if (!ret) + return NULL; + } pool->allocated++; pool->used++; return ret; @@ -142,10 +159,10 @@ void dump_pools(void) allocated = used = nbpools = 0; qfprintf(stderr, "Dumping pools usage.\n"); list_for_each_entry(entry, &pools, list) { - qfprintf(stderr, " - Pool %s (%d bytes) : %d allocated (%lu bytes), %d used%s\n", + qfprintf(stderr, " - Pool %s (%d bytes) : %d allocated (%lu bytes), %d used, %d users%s\n", entry->name, entry->size, entry->allocated, entry->size * entry->allocated, entry->used, - (entry->flags & MEM_F_SHARED) ? " [SHARED]" : ""); + entry->users, (entry->flags & MEM_F_SHARED) ? " [SHARED]" : ""); allocated += entry->allocated * entry->size; used += entry->used * entry->size; From 4d2d098ea3b41d88a9559fa52dc2bf84071c5cc3 Mon Sep 17 00:00:00 2001 From: Willy Tarreau Date: Mon, 14 May 2007 00:39:29 +0200 Subject: [PATCH 12/12] [MAJOR] call garbage collector when doing soft stop When we're interrupted by another instance, it is very likely that the other one will need some memory. Now we know how to free what is not used, so let's do it. Also only free non-null pointers. Previously, pool_destroy() did implicitly check for this case which was incidentely needed. --- include/common/memory.h | 2 +- src/haproxy.c | 8 +++++++- src/memory.c | 13 ++++++++++--- src/proxy.c | 3 +++ 4 files changed, 21 insertions(+), 5 deletions(-) diff --git a/include/common/memory.h b/include/common/memory.h index 66f789e25..835d79df0 100644 --- a/include/common/memory.h +++ b/include/common/memory.h @@ -160,7 +160,7 @@ void pool_gc2(); * This function destroys a pull by freeing it completely. * This should be called only under extreme circumstances. */ -void pool_destroy2(struct pool_head *pool); +void *pool_destroy2(struct pool_head *pool); /* * Returns a pointer to type taken from the diff --git a/src/haproxy.c b/src/haproxy.c index 4e22e1920..a86abeb31 100644 --- a/src/haproxy.c +++ b/src/haproxy.c @@ -203,6 +203,7 @@ void usage(char *name) void sig_soft_stop(int sig) { soft_stop(); + pool_gc2(); signal(sig, SIG_IGN); } @@ -212,6 +213,7 @@ void sig_soft_stop(int sig) void sig_pause(int sig) { pause_proxies(); + pool_gc2(); signal(sig, sig_pause); } @@ -318,6 +320,7 @@ void sig_int(int sig) 0 GRACE time */ fast_stop(); + pool_gc2(); /* If we are killed twice, we decide to die*/ signal(sig, SIG_DFL); } @@ -330,6 +333,7 @@ void sig_term(int sig) 0 GRACE time */ fast_stop(); + pool_gc2(); /* If we are killed twice, we decide to die*/ signal(sig, SIG_DFL); } @@ -580,7 +584,7 @@ void init(int argc, char **argv) void deinit(void) { - struct proxy *p = proxy; + struct proxy *p = proxy, *p0; struct cap_hdr *h,*h_next; struct server *s,*s_next; struct listener *l,*l_next; @@ -654,7 +658,9 @@ void deinit(void) pool_destroy2(p->req_cap_pool); pool_destroy2(p->rsp_cap_pool); + p0 = p; p = p->next; + free(p0); }/* end while(p) */ if (global.chroot) free(global.chroot); diff --git a/src/memory.c b/src/memory.c index 589d1d270..800922714 100644 --- a/src/memory.c +++ b/src/memory.c @@ -103,6 +103,9 @@ void *pool_refill_alloc(struct pool_head *pool) void pool_flush2(struct pool_head *pool) { void *temp, *next; + if (!pool) + return; + next = pool->free_list; while (next) { temp = next; @@ -141,11 +144,15 @@ void pool_gc2() /* * This function destroys a pull by freeing it completely. * This should be called only under extreme circumstances. + * It always returns NULL, easing the clearing of the old pointer. */ -void pool_destroy2(struct pool_head *pool) +void *pool_destroy2(struct pool_head *pool) { - pool_flush2(pool); - FREE(pool); + if (pool) { + pool_flush2(pool); + FREE(pool); + } + return NULL; } /* Dump statistics on pools usage. diff --git a/src/proxy.c b/src/proxy.c index dd7f993e3..7d4b2ec08 100644 --- a/src/proxy.c +++ b/src/proxy.c @@ -19,6 +19,7 @@ #include #include #include +#include #include #include @@ -230,6 +231,8 @@ void maintain_proxies(struct timeval *next) listeners--; } p->state = PR_STSTOPPED; + /* try to free more memory */ + pool_gc2(); } else { tv_bound(next, &p->stop_time);