pgpool2.git / summary / log / commit / refs

commit    2764121ff36897a30d61ee90d357d8c834bed6b1
Author:   Yoshiyuki Asaba <y-asaba at pgfoundry.org>
Date:     Fri Jan 11 02:30:20 2008 +0000

    Fix memory leak at prepared statement list.
    
    pgpool caches a parse tree in prepared statement list. The parse tree
    copy deeply, but we freed only the top node of the parse tree.


ChangeLog | 8 +++ main.c | 2 +- parser/parser.c | 2 +- parser/pool_memory.c | 16 +++--- parser/pool_memory.h | 6 ++- pool_hba.c | 2 +- pool_process_query.c | 138 +++++++++++++++++++++++++++------------------------ 7 files changed, 98 insertions(+), 76 deletions(-) diff --git a/ChangeLog b/ChangeLog index ad89529f0..f4b6172f1 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,11 @@ +2008-01-11 Yoshiyuki Asaba <y-asaba@sraoss.co.jp> + + * main.c, pool_hba.c, pool_process_query.c, parser/parser.c, + parser/pool_memory.c, parser/pool_memory.h: Fix memory leak at + prepared statement list. pgpool caches a parse tree in prepared + statement list. The parse tree copy deeply, but we freed only + the top node of the parse tree. + 2007-12-27 Yoshiyuki Asaba <y-asaba@sraoss.co.jp> * main.c, pgpool.conf.sample, doc/pgpool-en.html, diff --git a/main.c b/main.c index 0c8177af4..939c85423 100644 --- a/main.c +++ b/main.c @@ -1706,7 +1706,7 @@ static int trigger_failover_command(int node, const char *command_line) return -1; buf[1] = '\0'; - pool_memory = pool_memory_create(); + pool_memory = pool_memory_create(PREPARE_BLOCK_SIZE); if (!pool_memory) { pool_error("trigger_failover_command: pool_memory_create() failed"); diff --git a/parser/parser.c b/parser/parser.c index fa5889ce7..17c5d74ab 100644 --- a/parser/parser.c +++ b/parser/parser.c @@ -48,7 +48,7 @@ raw_parser(const char *str) int yyresult; if (pool_memory == NULL) - pool_memory = pool_memory_create(); + pool_memory = pool_memory_create(PARSER_BLOCK_SIZE); parsetree = NIL; /* in case grammar forgets to set it */ have_lookahead = false; diff --git a/parser/pool_memory.c b/parser/pool_memory.c index 89f6be4af..8264aaf5a 100644 --- a/parser/pool_memory.c +++ b/parser/pool_memory.c @@ -28,7 +28,6 @@ #include <stdlib.h> #include <string.h> -#define MAX_SIZE 8192 #define ALIGN 3 #define POOL_HEADER_SIZE (sizeof (POOL_CHUNK_HEADER)) @@ -61,7 +60,7 @@ void *pool_memory_alloc(POOL_MEMORY_POOL *pool, unsigned int size) POOL_BLOCK *block; POOL_CHUNK *chunk; - if ((size + POOL_HEADER_SIZE) > MAX_SIZE) + if ((size + POOL_HEADER_SIZE) > pool->blocksize) { block = malloc(sizeof(POOL_BLOCK)); if (block == NULL) @@ -106,9 +105,9 @@ void *pool_memory_alloc(POOL_MEMORY_POOL *pool, unsigned int size) pool_error("pool_memory_alloc: malloc failed: %s", strerror(errno)); child_exit(1); } - block->size = MAX_SIZE; + block->size = pool->blocksize; block->allocsize = 0; - block->block = malloc(MAX_SIZE); + block->block = malloc(pool->blocksize); if (block->block == NULL) { pool_error("pool_memory_alloc: malloc failed: %s", strerror(errno)); @@ -153,7 +152,7 @@ void pool_memory_free(POOL_MEMORY_POOL *pool, void *ptr) if (ptr == NULL) return; - if (chunk->header.size > MAX_SIZE) + if (chunk->header.size > pool->blocksize) { POOL_BLOCK *block, *ptr = NULL; @@ -204,8 +203,8 @@ void *pool_memory_realloc(POOL_MEMORY_POOL *pool, void *ptr, unsigned int size) return ptr; fidx = get_free_index(size + POOL_HEADER_SIZE); - if (size + POOL_HEADER_SIZE <= MAX_SIZE && - chunk->header.size <= MAX_SIZE && + if (size + POOL_HEADER_SIZE <= pool->blocksize && + chunk->header.size <= pool->blocksize && fidx == get_free_index(chunk->header.size)) { return ptr; @@ -222,7 +221,7 @@ void *pool_memory_realloc(POOL_MEMORY_POOL *pool, void *ptr, unsigned int size) * pool_memory_create: * Create a new memory pool. */ -POOL_MEMORY_POOL *pool_memory_create(void) +POOL_MEMORY_POOL *pool_memory_create(int blocksize) { POOL_MEMORY_POOL *pool; int i; @@ -235,6 +234,7 @@ POOL_MEMORY_POOL *pool_memory_create(void) } pool->blocks = NULL; pool->largeblocks = NULL; + pool->blocksize = blocksize; for (i = 0; i < SLOT_NUM; i++) { diff --git a/parser/pool_memory.h b/parser/pool_memory.h index 3ef73663c..ce2f770d5 100644 --- a/parser/pool_memory.h +++ b/parser/pool_memory.h @@ -27,6 +27,9 @@ #define SLOT_NUM 11 +#define PARSER_BLOCK_SIZE 8192 +#define PREPARE_BLOCK_SIZE 1024 + typedef struct POOL_BLOCK { int size; int allocsize; @@ -47,6 +50,7 @@ typedef struct POOL_CHUNK { typedef struct { int size; + int blocksize; POOL_BLOCK *blocks; POOL_BLOCK *largeblocks; POOL_CHUNK *freelist[SLOT_NUM]; @@ -57,7 +61,7 @@ extern POOL_MEMORY_POOL *pool_memory; extern void *pool_memory_alloc(POOL_MEMORY_POOL *pool, unsigned int size); extern void pool_memory_free(POOL_MEMORY_POOL *pool, void *ptr); extern void *pool_memory_realloc(POOL_MEMORY_POOL *pool, void *ptr, unsigned int size); -extern POOL_MEMORY_POOL *pool_memory_create(void); +extern POOL_MEMORY_POOL *pool_memory_create(int blocksize); extern void pool_memory_delete(POOL_MEMORY_POOL *pool_memory, int reuse); extern char *pool_memory_strdup(POOL_MEMORY_POOL *pool_memory, const char *string); extern void *pool_memory_alloc_zero(POOL_MEMORY_POOL *pool_memory, unsigned int size); diff --git a/pool_hba.c b/pool_hba.c index de9ed6a74..cb28b83ba 100644 --- a/pool_hba.c +++ b/pool_hba.c @@ -102,7 +102,7 @@ void load_hba(char *hbapath) POOL_MEMORY_POOL *old_context; if (hba_memory_context == NULL) { - hba_memory_context = pool_memory_create(); + hba_memory_context = pool_memory_create(PARSER_BLOCK_SIZE); if (hba_memory_context == NULL) { pool_error("load_hba: pool_memory_create() failed"); diff --git a/pool_process_query.c b/pool_process_query.c index f5cc0487b..83395eabd 100644 --- a/pool_process_query.c +++ b/pool_process_query.c @@ -64,6 +64,7 @@ typedef struct { char *portal_name; Node *stmt; + POOL_MEMORY_POOL *prepare_ctxt; } Portal; /* @@ -168,6 +169,7 @@ static int send_deallocate(POOL_CONNECTION_POOL *backend, PreparedStatementList static char *parse_copy_data(char *buf, int len, char delimiter, int col_id); static Portal *lookup_prepared_statement_by_statement(PreparedStatementList *p, const char *name); static Portal *lookup_prepared_statement_by_portal(PreparedStatementList *p, const char *name); +static Portal *create_portal(void); #ifdef NOT_USED static POOL_CONNECTION_POOL_SLOT *slots[MAX_CONNECTION_SLOTS]; @@ -208,7 +210,6 @@ static int is_select_pgcatalog = 0; static int is_select_for_update = 0; /* also for SELECT ... INTO */ static bool is_parallel_table = false; static char *parsed_query = NULL; -static POOL_MEMORY_POOL *prepare_memory_context = NULL; static void query_cache_register(char kind, POOL_CONNECTION *frontend, char *database, char *data, int data_len); static POOL_STATUS start_internal_transaction(POOL_CONNECTION_POOL *backend, Node *node); @@ -1059,26 +1060,23 @@ static POOL_STATUS SimpleQuery(POOL_CONNECTION *frontend, if (frontend) { - POOL_MEMORY_POOL *old_context; + POOL_MEMORY_POOL *old_context = NULL; Portal *portal; - if (prepare_memory_context == NULL) + if (IsA(node, PrepareStmt)) { - prepare_memory_context = pool_memory_create(); - if (prepare_memory_context == NULL) + pending_function = add_prepared_list; + portal = create_portal(); + if (portal == NULL) { - pool_error("Simple Query: pool_memory_create() failed"); - return POOL_ERROR; + pool_error("SimpleQuery: create_portal() failed"); + return POOL_END; } - } - /* switch memory context */ - old_context = pool_memory; - pool_memory = prepare_memory_context; - if (IsA(node, PrepareStmt)) - { - pending_function = add_prepared_list; - portal = malloc(sizeof(Portal)); + /* switch memory context */ + old_context = pool_memory; + pool_memory = portal->prepare_ctxt; + portal->portal_name = NULL; portal->stmt = copyObject(node); pending_prepared_portal = portal; @@ -1086,7 +1084,17 @@ static POOL_STATUS SimpleQuery(POOL_CONNECTION *frontend, else if (IsA(node, DeallocateStmt)) { pending_function = del_prepared_list; - portal = malloc(sizeof(Portal)); + portal = create_portal(); + if (portal == NULL) + { + pool_error("SimpleQuery: create_portal() failed"); + return POOL_END; + } + + /* switch memory context */ + old_context = pool_memory; + pool_memory = portal->prepare_ctxt; + portal->portal_name = NULL; portal->stmt = copyObject(node); pending_prepared_portal = portal; @@ -1102,7 +1110,8 @@ static POOL_STATUS SimpleQuery(POOL_CONNECTION *frontend, } /* switch old memory context */ - pool_memory = old_context; + if (old_context) + pool_memory = old_context; } } @@ -1348,12 +1357,10 @@ static POOL_STATUS Execute(POOL_CONNECTION *frontend, /* load balance trick */ if (portal) { - POOL_MEMORY_POOL *pool_mem; Node *node; p_stmt = (PrepareStmt *)portal->stmt; - pool_mem = pool_memory_create(); string1 = nodeToString(p_stmt->query); node = (Node *)p_stmt->query; @@ -1385,7 +1392,6 @@ static POOL_STATUS Execute(POOL_CONNECTION *frontend, */ commit = is_commit_query((Node *)p_stmt->query); - pool_memory_delete(pool_mem, 0); } else if (MASTER_SLAVE) { @@ -1595,20 +1601,17 @@ static POOL_STATUS Parse(POOL_CONNECTION *frontend, insert_stmt_with_lock = need_insert_lock(backend, stmt, node); - if (prepare_memory_context == NULL) + portal = create_portal(); + if (portal == NULL) { - prepare_memory_context = pool_memory_create(); - if (prepare_memory_context == NULL) - { - pool_error("Simple Query: pool_memory_create() failed"); - return POOL_ERROR; - } + pool_error("Parse: create_portal() failed"); + return POOL_END; } + /* switch memory context */ old_context = pool_memory; - pool_memory = prepare_memory_context; + pool_memory = portal->prepare_ctxt; - portal = malloc(sizeof(Portal)); /* translate Parse message to PrepareStmt */ p_stmt = palloc(sizeof(PrepareStmt)); p_stmt->type = T_PrepareStmt; @@ -3635,13 +3638,9 @@ POOL_STATUS SimpleForwardToFrontend(char kind, POOL_CONNECTION *frontend, POOL_C IsA(pending_prepared_portal->stmt, DeallocateStmt)) { DeallocateStmt *s = (DeallocateStmt *)pending_prepared_portal->stmt; - POOL_MEMORY_POOL *old_context = pool_memory; free(pending_prepared_portal->portal_name); - pool_memory = prepare_memory_context; - pfree(s->name); - pfree(s); - pool_memory = old_context; + pool_memory_delete(pending_prepared_portal->prepare_ctxt, 0); free(pending_prepared_portal); } } @@ -3650,6 +3649,8 @@ POOL_STATUS SimpleForwardToFrontend(char kind, POOL_CONNECTION *frontend, POOL_C /* PREPARE or DEALLOCATE is error. * Free pending portal object. */ + free(pending_prepared_portal->portal_name); + pool_memory_delete(pending_prepared_portal->prepare_ctxt, 0); free(pending_prepared_portal); } else if (kind == 'C' && select_in_transaction) @@ -3982,7 +3983,14 @@ POOL_STATUS SimpleForwardToBackend(char kind, POOL_CONNECTION *frontend, POOL_CO POOL_MEMORY_POOL *old_context = pool_memory; DeallocateStmt *deallocate_stmt; - pool_memory = prepare_memory_context; + pending_prepared_portal = create_portal(); + if (pending_prepared_portal == NULL) + { + pool_error("SimpleForwardToBackend: malloc failed: %s", strerror(errno)); + return POOL_END; + } + + pool_memory = pending_prepared_portal->prepare_ctxt; name = pstrdup(p+1); if (name == NULL) { @@ -4000,14 +4008,6 @@ POOL_STATUS SimpleForwardToBackend(char kind, POOL_CONNECTION *frontend, POOL_CO return POOL_END; } deallocate_stmt->name = name; - - pending_prepared_portal = malloc(sizeof(Portal)); - if (pending_prepared_portal == NULL) - { - pool_error("SimpleForwardToBackend: malloc failed: %s", strerror(errno)); - pool_memory = old_context; - return POOL_END; - } pending_prepared_portal->stmt = (Node *)deallocate_stmt; pending_prepared_portal->portal_name = NULL; pending_function = del_prepared_list; @@ -5025,6 +5025,27 @@ static POOL_STATUS read_kind_from_backend(POOL_CONNECTION *frontend, POOL_CONNEC return POOL_CONTINUE; } +/* + * Create portal object + * Return object is allocated from heap memory. + */ + +static Portal *create_portal(void) +{ + Portal *p; + + if ((p = malloc(sizeof(Portal))) == NULL) + return NULL; + + p->prepare_ctxt = pool_memory_create(PREPARE_BLOCK_SIZE); + if (p->prepare_ctxt == NULL) + { + free(p); + return NULL; + } + return p; +} + void init_prepared_list(void) { prepared_list.cnt = 0; @@ -5054,19 +5075,9 @@ static void add_prepared_list(PreparedStatementList *p, Portal *portal) static void add_unnamed_portal(PreparedStatementList *p, Portal *portal) { - POOL_MEMORY_POOL *old_context; - if (unnamed_statement) { - PrepareStmt *p_stmt = (PrepareStmt *)unnamed_statement->stmt; - if (p_stmt->name == NULL) - { - old_context = pool_memory; - pool_memory = prepare_memory_context; - pfree(p_stmt->query); - pfree(p_stmt); - pool_memory = old_context; - } + pool_memory_delete(unnamed_statement->prepare_ctxt, 0); free(unnamed_statement); } @@ -5078,7 +5089,6 @@ static void del_prepared_list(PreparedStatementList *p, Portal *portal) { int i; DeallocateStmt *s = (DeallocateStmt *)portal->stmt; - POOL_MEMORY_POOL *old_context; for (i = 0; i < p->cnt; i++) { @@ -5090,10 +5100,7 @@ static void del_prepared_list(PreparedStatementList *p, Portal *portal) if (i == p->cnt) return; - old_context = pool_memory; - pool_memory = prepare_memory_context; - pfree((PrepareStmt *)p->portal_list[i]->stmt); - pool_memory = old_context; + pool_memory_delete(p->portal_list[i]->prepare_ctxt, 0); free(p->portal_list[i]->portal_name); free(p->portal_list[i]); if (i != p->cnt - 1) @@ -5113,20 +5120,23 @@ static void reset_prepared_list(PreparedStatementList *p) { int i; - if (prepare_memory_context) + if (p) { for (i = 0; i < p->cnt; i++) { + pool_memory_delete(p->portal_list[i]->prepare_ctxt, 0); free(p->portal_list[i]->portal_name); free(p->portal_list[i]); } - pool_memory_delete(prepare_memory_context, 0); - prepare_memory_context = NULL; - free(unnamed_statement); + if (unnamed_statement) + { + pool_memory_delete(unnamed_statement->prepare_ctxt, 0); + free(unnamed_statement); + } unnamed_portal = NULL; unnamed_statement = NULL; + p->cnt = 0; } - p->cnt = 0; } static Portal *lookup_prepared_statement_by_statement(PreparedStatementList *p, const char *name) [parent: a7f10186d3ed]