diff --git a/Makefile b/Makefile index c7017e5ea..37439c30e 100644 --- a/Makefile +++ b/Makefile @@ -215,9 +215,9 @@ 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/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..cc8004086 100644 --- a/Makefile.bsd +++ b/Makefile.bsd @@ -85,10 +85,10 @@ 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/ev_kqueue.o src/acl.o src/memory.o all: haproxy diff --git a/Makefile.osx b/Makefile.osx index 15db775cd..5cf4f08fd 100644 --- a/Makefile.osx +++ b/Makefile.osx @@ -85,9 +85,10 @@ 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/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/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/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..835d79df0 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,9 +25,8 @@ #include #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 * dynamically allocated. In the first case, <__pool> is updated to point to @@ -112,6 +111,91 @@ 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_* */ + unsigned int users; /* number of pools sharing this zone */ + char name[12]; /* 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 *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 + * 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); + +/* + * 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 + * 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/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/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/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/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/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/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/include/types/capture.h b/include/types/capture.h index d0271a2e2..e37cc483f 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; @@ -30,10 +31,10 @@ 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 void **pool_capture; +extern struct pool_head *pool2_capture; #endif /* _TYPES_CAPTURE_H */ 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/include/types/proxy.h b/include/types/proxy.h index 532348ec9..bfbe63125 100644 --- a/include/types/proxy.h +++ b/include/types/proxy.h @@ -140,8 +140,9 @@ 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 */ - void *hdr_idx_pool; /* pools of pre-allocated int* used for headers indexing */ + struct pool_head *req_cap_pool, /* pools of pre-allocated char ** used to build the sessions */ + *rsp_cap_pool; + 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/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/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..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"); @@ -111,15 +123,15 @@ 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; 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/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/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/cfgparse.c b/src/cfgparse.c index 1edaa8fc0..516547445 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,20 @@ 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); + + 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. @@ -2488,7 +2504,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 +2551,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..50a0f5d2f 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; } @@ -229,15 +230,12 @@ 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_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_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 *)); @@ -245,30 +243,30 @@ 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_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 *)); } - 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_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_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); @@ -346,16 +344,16 @@ 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); + pool_free2(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_free(task, t); - pool_free(session, s); + pool_free2(pool2_task, t); + pool_free2(pool2_session, s); return 0; } @@ -368,17 +366,17 @@ 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); + pool_free2(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_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..a86abeb31 100644 --- a/src/haproxy.c +++ b/src/haproxy.c @@ -87,6 +87,7 @@ #include #include #include +#include #include #include @@ -202,6 +203,7 @@ void usage(char *name) void sig_soft_stop(int sig) { soft_stop(); + pool_gc2(); signal(sig, SIG_IGN); } @@ -211,6 +213,7 @@ void sig_soft_stop(int sig) void sig_pause(int sig) { pause_proxies(); + pool_gc2(); signal(sig, sig_pause); } @@ -292,6 +295,9 @@ void dump(int sig) ); } #endif + /* dump memory usage then free everything possible */ + dump_pools(); + pool_gc2(); } #ifdef DEBUG_MEMORY @@ -314,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); } @@ -326,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); } @@ -370,6 +378,10 @@ void init(int argc, char **argv) localtime((time_t *)&now.tv_sec); start_date = now; + init_task(); + init_session(); + init_buffer(); + init_pendconn(); init_proto_http(); cfg_polling_mechanism = POLL_USE_SELECT; /* select() is always available */ @@ -572,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; @@ -608,7 +620,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) */ @@ -619,7 +631,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) */ @@ -644,9 +656,11 @@ 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); + p0 = p; p = p->next; + free(p0); }/* end while(p) */ if (global.chroot) free(global.chroot); @@ -654,16 +668,17 @@ void deinit(void) if (fdtab) free(fdtab); - pool_destroy(pool_session); - pool_destroy(pool_buffer); - pool_destroy(pool_requri); - pool_destroy(pool_task); - pool_destroy(pool_capture); - pool_destroy(pool_appsess); + pool_destroy2(pool2_session); + pool_destroy2(pool2_buffer); + pool_destroy2(pool2_requri); + pool_destroy2(pool2_task); + pool_destroy2(pool2_capture); + 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/memory.c b/src/memory.c new file mode 100644 index 000000000..800922714 --- /dev/null +++ b/src/memory.c @@ -0,0 +1,187 @@ +/* + * 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; + struct pool_head *entry; + struct list *start; + 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 = 16; + size = (size + align - 1) & -align; + + start = &pools; + pool = NULL; + + 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) { + 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(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. A call + * to the garbage collector is performed before returning NULL. + */ +void *pool_refill_alloc(struct pool_head *pool) +{ + void *ret; + + if (pool->limit && (pool->allocated >= pool->limit)) + return NULL; + ret = MALLOC(pool->size); + if (!ret) { + pool_gc2(); + ret = MALLOC(pool->size); + if (!ret) + return NULL; + } + pool->allocated++; + pool->used++; + return ret; +} + +/* + * This function frees whatever can be freed in pool . + */ +void pool_flush2(struct pool_head *pool) +{ + void *temp, *next; + if (!pool) + return; + + 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. + * It always returns NULL, easing the clearing of the old pointer. + */ +void *pool_destroy2(struct pool_head *pool) +{ + if (pool) { + pool_flush2(pool); + FREE(pool); + } + return NULL; +} + +/* 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 (%lu bytes), %d used, %d users%s\n", + entry->name, entry->size, entry->allocated, + entry->size * entry->allocated, entry->used, + entry->users, (entry->flags & MEM_F_SHARED) ? " [SHARED]" : ""); + + allocated += entry->allocated * entry->size; + used += entry->used * entry->size; + nbpools++; + } + qfprintf(stderr, "Total: %d pools, %lu bytes allocated, %lu used.\n", + nbpools, allocated, used); +} + +/* + * Local variables: + * c-indent-level: 8 + * c-basic-offset: 8 + * End: + */ diff --git a/src/proto_http.c b/src/proto_http.c index d1bfdcf22..4e9e68361 100644 --- a/src/proto_http.c +++ b/src/proto_http.c @@ -243,6 +243,10 @@ void init_proto_http() FD_SET(*tmp, url_encode_map); tmp++; } + + /* memory allocations */ + pool2_requri = create_pool("requri", REQURI_LEN, MEM_F_SHARED); + pool2_capture = create_pool("capture", CAPTURE_LEN, MEM_F_SHARED); } /* @@ -624,7 +628,8 @@ 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; +struct pool_head *pool2_capture; /* * send a log for the session when we have enough info about it. @@ -770,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"); @@ -1592,7 +1597,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) @@ -4169,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) @@ -4298,7 +4303,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 +4315,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 +4328,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) { @@ -4704,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"); } @@ -4771,7 +4776,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 +4787,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 +4798,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 +4946,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 +4959,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 +4972,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); 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); 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); } diff --git a/src/session.c b/src/session.c index 21d34801c..d13f99504 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 @@ -21,12 +21,14 @@ #include #include +#include #include +#include #include #include -void **pool_session = NULL; +struct pool_head *pool2_session; /* * frees the context associated to a session. It must have been removed first. @@ -38,38 +40,46 @@ 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); + pool_free2(s->fe->hdr_idx_pool, txn->hdr_idx.v); if (txn->rsp.cap != NULL) { 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) - pool_free(requri, 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_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 619067094..7f6e0e7a2 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);