Code review for palloc0 patch --- avoid dangerous and unnecessary
practice of evaluating MemSet's arguments multiple times, except for the special case of newNode(), where we can assume the argument is a constant sizeof() operator. Also, add GetMemoryChunkContext() to mcxt.c's API, in preparation for fixing recent GEQO breakage.
This commit is contained in:
parent
e64c7feb2f
commit
88177f77b1
|
@ -9,7 +9,7 @@
|
||||||
*
|
*
|
||||||
*
|
*
|
||||||
* IDENTIFICATION
|
* IDENTIFICATION
|
||||||
* $Header: /cvsroot/pgsql/src/backend/nodes/nodes.c,v 1.18 2002/11/10 02:17:25 momjian Exp $
|
* $Header: /cvsroot/pgsql/src/backend/nodes/nodes.c,v 1.19 2002/12/16 16:22:46 tgl Exp $
|
||||||
*
|
*
|
||||||
* HISTORY
|
* HISTORY
|
||||||
* Andrew Yu Oct 20, 1994 file creation
|
* Andrew Yu Oct 20, 1994 file creation
|
||||||
|
@ -17,16 +17,11 @@
|
||||||
*-------------------------------------------------------------------------
|
*-------------------------------------------------------------------------
|
||||||
*/
|
*/
|
||||||
#include "postgres.h"
|
#include "postgres.h"
|
||||||
|
|
||||||
#include "nodes/nodes.h"
|
#include "nodes/nodes.h"
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* newNode -
|
* Support for newNode() macro
|
||||||
* create a new node of the specified size and tag the node with the
|
|
||||||
* specified tag.
|
|
||||||
*
|
|
||||||
* !WARNING!: Avoid using newNode directly. You should be using the
|
|
||||||
* macro makeNode. eg. to create a Resdom node, use makeNode(Resdom)
|
|
||||||
*
|
|
||||||
*/
|
*/
|
||||||
Node *newNodeMacroHolder;
|
|
||||||
|
|
||||||
|
Node *newNodeMacroHolder;
|
||||||
|
|
|
@ -14,7 +14,7 @@
|
||||||
*
|
*
|
||||||
*
|
*
|
||||||
* IDENTIFICATION
|
* IDENTIFICATION
|
||||||
* $Header: /cvsroot/pgsql/src/backend/utils/mmgr/mcxt.c,v 1.37 2002/12/15 21:01:34 tgl Exp $
|
* $Header: /cvsroot/pgsql/src/backend/utils/mmgr/mcxt.c,v 1.38 2002/12/16 16:22:46 tgl Exp $
|
||||||
*
|
*
|
||||||
*-------------------------------------------------------------------------
|
*-------------------------------------------------------------------------
|
||||||
*/
|
*/
|
||||||
|
@ -257,6 +257,35 @@ GetMemoryChunkSpace(void *pointer)
|
||||||
pointer);
|
pointer);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* GetMemoryChunkContext
|
||||||
|
* Given a currently-allocated chunk, determine the context
|
||||||
|
* it belongs to.
|
||||||
|
*/
|
||||||
|
MemoryContext
|
||||||
|
GetMemoryChunkContext(void *pointer)
|
||||||
|
{
|
||||||
|
StandardChunkHeader *header;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Try to detect bogus pointers handed to us, poorly though we can.
|
||||||
|
* Presumably, a pointer that isn't MAXALIGNED isn't pointing at an
|
||||||
|
* allocated chunk.
|
||||||
|
*/
|
||||||
|
Assert(pointer != NULL);
|
||||||
|
Assert(pointer == (void *) MAXALIGN(pointer));
|
||||||
|
|
||||||
|
/*
|
||||||
|
* OK, it's probably safe to look at the chunk header.
|
||||||
|
*/
|
||||||
|
header = (StandardChunkHeader *)
|
||||||
|
((char *) pointer - STANDARDCHUNKHEADERSIZE);
|
||||||
|
|
||||||
|
AssertArg(MemoryContextIsValid(header->context));
|
||||||
|
|
||||||
|
return header->context;
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* MemoryContextStats
|
* MemoryContextStats
|
||||||
* Print statistics about the named context and all its descendants.
|
* Print statistics about the named context and all its descendants.
|
||||||
|
@ -453,25 +482,52 @@ MemoryContextAlloc(MemoryContext context, Size size)
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* MemoryContextAllocPalloc0
|
* MemoryContextAllocZero
|
||||||
* Like MemoryContextAlloc, but clears allocated memory
|
* Like MemoryContextAlloc, but clears allocated memory
|
||||||
*
|
*
|
||||||
* We could just call MemoryContextAlloc then clear the memory, but this
|
* We could just call MemoryContextAlloc then clear the memory, but this
|
||||||
* function is called too many times, so we have a separate version.
|
* is a very common combination, so we provide the combined operation.
|
||||||
*/
|
*/
|
||||||
void *
|
void *
|
||||||
MemoryContextAllocPalloc0(MemoryContext context, Size size)
|
MemoryContextAllocZero(MemoryContext context, Size size)
|
||||||
{
|
{
|
||||||
void *ret;
|
void *ret;
|
||||||
|
|
||||||
AssertArg(MemoryContextIsValid(context));
|
AssertArg(MemoryContextIsValid(context));
|
||||||
|
|
||||||
if (!AllocSizeIsValid(size))
|
if (!AllocSizeIsValid(size))
|
||||||
elog(ERROR, "MemoryContextAllocZero: invalid request size %lu",
|
elog(ERROR, "MemoryContextAlloc: invalid request size %lu",
|
||||||
(unsigned long) size);
|
(unsigned long) size);
|
||||||
|
|
||||||
ret = (*context->methods->alloc) (context, size);
|
ret = (*context->methods->alloc) (context, size);
|
||||||
|
|
||||||
|
MemSetAligned(ret, 0, size);
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* MemoryContextAllocZeroAligned
|
||||||
|
* MemoryContextAllocZero where length is suitable for MemSetLoop
|
||||||
|
*
|
||||||
|
* This might seem overly specialized, but it's not because newNode()
|
||||||
|
* is so often called with compile-time-constant sizes.
|
||||||
|
*/
|
||||||
|
void *
|
||||||
|
MemoryContextAllocZeroAligned(MemoryContext context, Size size)
|
||||||
|
{
|
||||||
|
void *ret;
|
||||||
|
|
||||||
|
AssertArg(MemoryContextIsValid(context));
|
||||||
|
|
||||||
|
if (!AllocSizeIsValid(size))
|
||||||
|
elog(ERROR, "MemoryContextAlloc: invalid request size %lu",
|
||||||
|
(unsigned long) size);
|
||||||
|
|
||||||
|
ret = (*context->methods->alloc) (context, size);
|
||||||
|
|
||||||
MemSetLoop(ret, 0, size);
|
MemSetLoop(ret, 0, size);
|
||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -12,7 +12,7 @@
|
||||||
* Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group
|
* Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group
|
||||||
* Portions Copyright (c) 1994, Regents of the University of California
|
* Portions Copyright (c) 1994, Regents of the University of California
|
||||||
*
|
*
|
||||||
* $Id: c.h,v 1.133 2002/12/05 04:04:48 momjian Exp $
|
* $Id: c.h,v 1.134 2002/12/16 16:22:46 tgl Exp $
|
||||||
*
|
*
|
||||||
*-------------------------------------------------------------------------
|
*-------------------------------------------------------------------------
|
||||||
*/
|
*/
|
||||||
|
@ -579,13 +579,64 @@ typedef NameData *Name;
|
||||||
* memset() functions. More research needs to be done, perhaps with
|
* memset() functions. More research needs to be done, perhaps with
|
||||||
* platform-specific MEMSET_LOOP_LIMIT values or tests in configure.
|
* platform-specific MEMSET_LOOP_LIMIT values or tests in configure.
|
||||||
*
|
*
|
||||||
* MemSet has been split into two parts so MemSetTest can be optimized
|
|
||||||
* away for constant 'val' and 'len'. This is used by palloc0().
|
|
||||||
*
|
|
||||||
* Note, arguments are evaluated more than once.
|
|
||||||
*
|
|
||||||
* bjm 2002-10-08
|
* bjm 2002-10-08
|
||||||
*/
|
*/
|
||||||
|
#define MemSet(start, val, len) \
|
||||||
|
do \
|
||||||
|
{ \
|
||||||
|
int32 * _start = (int32 *) (start); \
|
||||||
|
int _val = (val); \
|
||||||
|
Size _len = (len); \
|
||||||
|
\
|
||||||
|
if ((((long) _start) & INT_ALIGN_MASK) == 0 && \
|
||||||
|
(_len & INT_ALIGN_MASK) == 0 && \
|
||||||
|
_val == 0 && \
|
||||||
|
_len <= MEMSET_LOOP_LIMIT) \
|
||||||
|
{ \
|
||||||
|
int32 * _stop = (int32 *) ((char *) _start + _len); \
|
||||||
|
while (_start < _stop) \
|
||||||
|
*_start++ = 0; \
|
||||||
|
} \
|
||||||
|
else \
|
||||||
|
memset((char *) _start, _val, _len); \
|
||||||
|
} while (0)
|
||||||
|
|
||||||
|
#define MEMSET_LOOP_LIMIT 1024
|
||||||
|
|
||||||
|
/*
|
||||||
|
* MemSetAligned is the same as MemSet except it omits the test to see if
|
||||||
|
* "start" is word-aligned. This is okay to use if the caller knows a-priori
|
||||||
|
* that the pointer is suitably aligned (typically, because he just got it
|
||||||
|
* from palloc(), which always delivers a max-aligned pointer).
|
||||||
|
*/
|
||||||
|
#define MemSetAligned(start, val, len) \
|
||||||
|
do \
|
||||||
|
{ \
|
||||||
|
int32 * _start = (int32 *) (start); \
|
||||||
|
int _val = (val); \
|
||||||
|
Size _len = (len); \
|
||||||
|
\
|
||||||
|
if ((_len & INT_ALIGN_MASK) == 0 && \
|
||||||
|
_val == 0 && \
|
||||||
|
_len <= MEMSET_LOOP_LIMIT) \
|
||||||
|
{ \
|
||||||
|
int32 * _stop = (int32 *) ((char *) _start + _len); \
|
||||||
|
while (_start < _stop) \
|
||||||
|
*_start++ = 0; \
|
||||||
|
} \
|
||||||
|
else \
|
||||||
|
memset((char *) _start, _val, _len); \
|
||||||
|
} while (0)
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
* MemSetTest/MemSetLoop are a variant version that allow all the tests in
|
||||||
|
* MemSet to be done at compile time in cases where "val" and "len" are
|
||||||
|
* constants *and* we know the "start" pointer must be word-aligned.
|
||||||
|
* If MemSetTest succeeds, then it is okay to use MemSetLoop, otherwise use
|
||||||
|
* MemSetAligned. Beware of multiple evaluations of the arguments when using
|
||||||
|
* this approach.
|
||||||
|
*/
|
||||||
#define MemSetTest(val, len) \
|
#define MemSetTest(val, len) \
|
||||||
( ((len) & INT_ALIGN_MASK) == 0 && \
|
( ((len) & INT_ALIGN_MASK) == 0 && \
|
||||||
(len) <= MEMSET_LOOP_LIMIT && \
|
(len) <= MEMSET_LOOP_LIMIT && \
|
||||||
|
@ -595,23 +646,12 @@ typedef NameData *Name;
|
||||||
do \
|
do \
|
||||||
{ \
|
{ \
|
||||||
int32 * _start = (int32 *) (start); \
|
int32 * _start = (int32 *) (start); \
|
||||||
int32 * _stop = (int32 *) ((char *) _start + (len)); \
|
int32 * _stop = (int32 *) ((char *) _start + (Size) (len)); \
|
||||||
\
|
\
|
||||||
while (_start < _stop) \
|
while (_start < _stop) \
|
||||||
*_start++ = 0; \
|
*_start++ = 0; \
|
||||||
} while (0)
|
} while (0)
|
||||||
|
|
||||||
#define MemSet(start, val, len) \
|
|
||||||
do \
|
|
||||||
{ \
|
|
||||||
if (MemSetTest(val, len) && ((long)(start) & INT_ALIGN_MASK) == 0 ) \
|
|
||||||
MemSetLoop(start, val, len); \
|
|
||||||
else \
|
|
||||||
memset((char *)(start), (val), (len)); \
|
|
||||||
} while (0)
|
|
||||||
|
|
||||||
#define MEMSET_LOOP_LIMIT 1024
|
|
||||||
|
|
||||||
|
|
||||||
/* ----------------------------------------------------------------
|
/* ----------------------------------------------------------------
|
||||||
* Section 7: random stuff
|
* Section 7: random stuff
|
||||||
|
|
|
@ -7,7 +7,7 @@
|
||||||
* Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group
|
* Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group
|
||||||
* Portions Copyright (c) 1994, Regents of the University of California
|
* Portions Copyright (c) 1994, Regents of the University of California
|
||||||
*
|
*
|
||||||
* $Id: nodes.h,v 1.133 2002/12/14 00:17:59 tgl Exp $
|
* $Id: nodes.h,v 1.134 2002/12/16 16:22:46 tgl Exp $
|
||||||
*
|
*
|
||||||
*-------------------------------------------------------------------------
|
*-------------------------------------------------------------------------
|
||||||
*/
|
*/
|
||||||
|
@ -293,9 +293,16 @@ typedef struct Node
|
||||||
#define nodeTag(nodeptr) (((Node*)(nodeptr))->type)
|
#define nodeTag(nodeptr) (((Node*)(nodeptr))->type)
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
* newNode -
|
||||||
|
* create a new node of the specified size and tag the node with the
|
||||||
|
* specified tag.
|
||||||
|
*
|
||||||
|
* !WARNING!: Avoid using newNode directly. You should be using the
|
||||||
|
* macro makeNode. eg. to create a Query node, use makeNode(Query)
|
||||||
|
*
|
||||||
* There is no way to dereference the palloc'ed pointer to assign the
|
* There is no way to dereference the palloc'ed pointer to assign the
|
||||||
* tag, and return the pointer itself, so we need a holder variable.
|
* tag, and also return the pointer itself, so we need a holder variable.
|
||||||
* Fortunately, this function isn't recursive so we just define
|
* Fortunately, this macro isn't recursive so we just define
|
||||||
* a global variable for this purpose.
|
* a global variable for this purpose.
|
||||||
*/
|
*/
|
||||||
extern Node *newNodeMacroHolder;
|
extern Node *newNodeMacroHolder;
|
||||||
|
@ -303,8 +310,7 @@ extern Node *newNodeMacroHolder;
|
||||||
#define newNode(size, tag) \
|
#define newNode(size, tag) \
|
||||||
( \
|
( \
|
||||||
AssertMacro((size) >= sizeof(Node)), /* need the tag, at least */ \
|
AssertMacro((size) >= sizeof(Node)), /* need the tag, at least */ \
|
||||||
\
|
newNodeMacroHolder = (Node *) palloc0fast(size), \
|
||||||
newNodeMacroHolder = (Node *) palloc0(size), \
|
|
||||||
newNodeMacroHolder->type = (tag), \
|
newNodeMacroHolder->type = (tag), \
|
||||||
newNodeMacroHolder \
|
newNodeMacroHolder \
|
||||||
)
|
)
|
||||||
|
|
|
@ -10,7 +10,7 @@
|
||||||
* Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group
|
* Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group
|
||||||
* Portions Copyright (c) 1994, Regents of the University of California
|
* Portions Copyright (c) 1994, Regents of the University of California
|
||||||
*
|
*
|
||||||
* $Id: memutils.h,v 1.49 2002/12/15 21:01:34 tgl Exp $
|
* $Id: memutils.h,v 1.50 2002/12/16 16:22:46 tgl Exp $
|
||||||
*
|
*
|
||||||
*-------------------------------------------------------------------------
|
*-------------------------------------------------------------------------
|
||||||
*/
|
*/
|
||||||
|
@ -83,6 +83,7 @@ extern void MemoryContextResetChildren(MemoryContext context);
|
||||||
extern void MemoryContextDeleteChildren(MemoryContext context);
|
extern void MemoryContextDeleteChildren(MemoryContext context);
|
||||||
extern void MemoryContextResetAndDeleteChildren(MemoryContext context);
|
extern void MemoryContextResetAndDeleteChildren(MemoryContext context);
|
||||||
extern Size GetMemoryChunkSpace(void *pointer);
|
extern Size GetMemoryChunkSpace(void *pointer);
|
||||||
|
extern MemoryContext GetMemoryChunkContext(void *pointer);
|
||||||
extern void MemoryContextStats(MemoryContext context);
|
extern void MemoryContextStats(MemoryContext context);
|
||||||
|
|
||||||
#ifdef MEMORY_CONTEXT_CHECKING
|
#ifdef MEMORY_CONTEXT_CHECKING
|
||||||
|
|
|
@ -21,7 +21,7 @@
|
||||||
* Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group
|
* Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group
|
||||||
* Portions Copyright (c) 1994, Regents of the University of California
|
* Portions Copyright (c) 1994, Regents of the University of California
|
||||||
*
|
*
|
||||||
* $Id: palloc.h,v 1.23 2002/11/13 00:37:06 momjian Exp $
|
* $Id: palloc.h,v 1.24 2002/12/16 16:22:46 tgl Exp $
|
||||||
*
|
*
|
||||||
*-------------------------------------------------------------------------
|
*-------------------------------------------------------------------------
|
||||||
*/
|
*/
|
||||||
|
@ -46,15 +46,25 @@ extern DLLIMPORT MemoryContext CurrentMemoryContext;
|
||||||
* Fundamental memory-allocation operations (more are in utils/memutils.h)
|
* Fundamental memory-allocation operations (more are in utils/memutils.h)
|
||||||
*/
|
*/
|
||||||
extern void *MemoryContextAlloc(MemoryContext context, Size size);
|
extern void *MemoryContextAlloc(MemoryContext context, Size size);
|
||||||
extern void *MemoryContextAllocPalloc0(MemoryContext context, Size size);
|
extern void *MemoryContextAllocZero(MemoryContext context, Size size);
|
||||||
|
extern void *MemoryContextAllocZeroAligned(MemoryContext context, Size size);
|
||||||
|
|
||||||
#define palloc(sz) MemoryContextAlloc(CurrentMemoryContext, (sz))
|
#define palloc(sz) MemoryContextAlloc(CurrentMemoryContext, (sz))
|
||||||
|
|
||||||
/* We assume palloc() is already int-aligned */
|
#define palloc0(sz) MemoryContextAllocZero(CurrentMemoryContext, (sz))
|
||||||
#define palloc0(sz) \
|
|
||||||
( MemSetTest(0, (sz)) ? \
|
/*
|
||||||
MemoryContextAllocPalloc0(CurrentMemoryContext, (sz)) : \
|
* The result of palloc() is always word-aligned, so we can skip testing
|
||||||
memset(palloc(sz), 0, (sz)))
|
* alignment of the pointer when deciding which MemSet variant to use.
|
||||||
|
* Note that this variant does not offer any advantage, and should not be
|
||||||
|
* used, unless its "sz" argument is a compile-time constant; therefore, the
|
||||||
|
* issue that it evaluates the argument multiple times isn't a problem in
|
||||||
|
* practice.
|
||||||
|
*/
|
||||||
|
#define palloc0fast(sz) \
|
||||||
|
( MemSetTest(0, sz) ? \
|
||||||
|
MemoryContextAllocZeroAligned(CurrentMemoryContext, sz) : \
|
||||||
|
MemoryContextAllocZero(CurrentMemoryContext, sz) )
|
||||||
|
|
||||||
extern void pfree(void *pointer);
|
extern void pfree(void *pointer);
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue