@ -132,6 +132,10 @@ typedef struct AllocFreeListLink
# define GetFreeListLink(chkptr) \
# define GetFreeListLink(chkptr) \
( AllocFreeListLink * ) ( ( char * ) ( chkptr ) + ALLOC_CHUNKHDRSZ )
( AllocFreeListLink * ) ( ( char * ) ( chkptr ) + ALLOC_CHUNKHDRSZ )
/* Validate a freelist index retrieved from a chunk header */
# define FreeListIdxIsValid(fidx) \
( ( fidx ) > = 0 & & ( fidx ) < ALLOCSET_NUM_FREELISTS )
/* Determine the size of the chunk based on the freelist index */
/* Determine the size of the chunk based on the freelist index */
# define GetChunkSizeFromFreeListIdx(fidx) \
# define GetChunkSizeFromFreeListIdx(fidx) \
( ( ( ( Size ) 1 ) < < ALLOC_MINBITS ) < < ( fidx ) )
( ( ( ( Size ) 1 ) < < ALLOC_MINBITS ) < < ( fidx ) )
@ -202,7 +206,15 @@ typedef struct AllocBlockData
* AllocSetIsValid
* AllocSetIsValid
* True iff set is valid allocation set .
* True iff set is valid allocation set .
*/
*/
# define AllocSetIsValid(set) PointerIsValid(set)
# define AllocSetIsValid(set) \
( PointerIsValid ( set ) & & IsA ( set , AllocSetContext ) )
/*
* AllocBlockIsValid
* True iff block is valid block of allocation set .
*/
# define AllocBlockIsValid(block) \
( PointerIsValid ( block ) & & AllocSetIsValid ( ( block ) - > aset ) )
/*
/*
* We always store external chunks on a dedicated block . This makes fetching
* We always store external chunks on a dedicated block . This makes fetching
@ -530,8 +542,7 @@ AllocSetReset(MemoryContext context)
{
{
AllocSet set = ( AllocSet ) context ;
AllocSet set = ( AllocSet ) context ;
AllocBlock block ;
AllocBlock block ;
Size keepersize PG_USED_FOR_ASSERTS_ONLY
Size keepersize PG_USED_FOR_ASSERTS_ONLY ;
= set - > keeper - > endptr - ( ( char * ) set ) ;
AssertArg ( AllocSetIsValid ( set ) ) ;
AssertArg ( AllocSetIsValid ( set ) ) ;
@ -540,6 +551,9 @@ AllocSetReset(MemoryContext context)
AllocSetCheck ( context ) ;
AllocSetCheck ( context ) ;
# endif
# endif
/* Remember keeper block size for Assert below */
keepersize = set - > keeper - > endptr - ( ( char * ) set ) ;
/* Clear chunk freelists */
/* Clear chunk freelists */
MemSetAligned ( set - > freelist , 0 , sizeof ( set - > freelist ) ) ;
MemSetAligned ( set - > freelist , 0 , sizeof ( set - > freelist ) ) ;
@ -598,8 +612,7 @@ AllocSetDelete(MemoryContext context)
{
{
AllocSet set = ( AllocSet ) context ;
AllocSet set = ( AllocSet ) context ;
AllocBlock block = set - > blocks ;
AllocBlock block = set - > blocks ;
Size keepersize PG_USED_FOR_ASSERTS_ONLY
Size keepersize PG_USED_FOR_ASSERTS_ONLY ;
= set - > keeper - > endptr - ( ( char * ) set ) ;
AssertArg ( AllocSetIsValid ( set ) ) ;
AssertArg ( AllocSetIsValid ( set ) ) ;
@ -608,6 +621,9 @@ AllocSetDelete(MemoryContext context)
AllocSetCheck ( context ) ;
AllocSetCheck ( context ) ;
# endif
# endif
/* Remember keeper block size for Assert below */
keepersize = set - > keeper - > endptr - ( ( char * ) set ) ;
/*
/*
* If the context is a candidate for a freelist , put it into that freelist
* If the context is a candidate for a freelist , put it into that freelist
* instead of destroying it .
* instead of destroying it .
@ -994,9 +1010,16 @@ AllocSetFree(void *pointer)
if ( MemoryChunkIsExternal ( chunk ) )
if ( MemoryChunkIsExternal ( chunk ) )
{
{
/* Release single-chunk block. */
AllocBlock block = ExternalChunkGetBlock ( chunk ) ;
AllocBlock block = ExternalChunkGetBlock ( chunk ) ;
/*
* Try to verify that we have a sane block pointer : the block header
* should reference an aset and the freeptr should match the endptr .
*/
if ( ! AllocBlockIsValid ( block ) | | block - > freeptr ! = block - > endptr )
elog ( ERROR , " could not find block containing chunk %p " , chunk ) ;
set = block - > aset ;
set = block - > aset ;
# ifdef MEMORY_CONTEXT_CHECKING
# ifdef MEMORY_CONTEXT_CHECKING
@ -1011,14 +1034,6 @@ AllocSetFree(void *pointer)
}
}
# endif
# endif
/*
* Try to verify that we have a sane block pointer , the freeptr should
* match the endptr .
*/
if ( block - > freeptr ! = block - > endptr )
elog ( ERROR , " could not find block containing chunk %p " , chunk ) ;
/* OK, remove block from aset's list and free it */
/* OK, remove block from aset's list and free it */
if ( block - > prev )
if ( block - > prev )
block - > prev - > next = block - > next ;
block - > prev - > next = block - > next ;
@ -1036,12 +1051,23 @@ AllocSetFree(void *pointer)
}
}
else
else
{
{
int fidx = MemoryChunkGetValue ( chunk ) ;
AllocBlock block = MemoryChunkGetBlock ( chunk ) ;
AllocBlock block = MemoryChunkGetBlock ( chunk ) ;
AllocFreeListLink * link = GetFreeListLink ( chunk ) ;
int fidx ;
AllocFreeListLink * link ;
/*
* In this path , for speed reasons we just Assert that the referenced
* block is good . We can also Assert that the value field is sane .
* Future field experience may show that these Asserts had better
* become regular runtime test - and - elog checks .
*/
AssertArg ( AllocBlockIsValid ( block ) ) ;
set = block - > aset ;
set = block - > aset ;
fidx = MemoryChunkGetValue ( chunk ) ;
Assert ( FreeListIdxIsValid ( fidx ) ) ;
link = GetFreeListLink ( chunk ) ;
# ifdef MEMORY_CONTEXT_CHECKING
# ifdef MEMORY_CONTEXT_CHECKING
/* Test for someone scribbling on unused space in chunk */
/* Test for someone scribbling on unused space in chunk */
if ( chunk - > requested_size < GetChunkSizeFromFreeListIdx ( fidx ) )
if ( chunk - > requested_size < GetChunkSizeFromFreeListIdx ( fidx ) )
@ -1089,6 +1115,7 @@ AllocSetRealloc(void *pointer, Size size)
AllocSet set ;
AllocSet set ;
MemoryChunk * chunk = PointerGetMemoryChunk ( pointer ) ;
MemoryChunk * chunk = PointerGetMemoryChunk ( pointer ) ;
Size oldsize ;
Size oldsize ;
int fidx ;
/* Allow access to private part of chunk header. */
/* Allow access to private part of chunk header. */
VALGRIND_MAKE_MEM_DEFINED ( chunk , ALLOCCHUNK_PRIVATE_LEN ) ;
VALGRIND_MAKE_MEM_DEFINED ( chunk , ALLOCCHUNK_PRIVATE_LEN ) ;
@ -1105,9 +1132,18 @@ AllocSetRealloc(void *pointer, Size size)
Size oldblksize ;
Size oldblksize ;
block = ExternalChunkGetBlock ( chunk ) ;
block = ExternalChunkGetBlock ( chunk ) ;
oldsize = block - > endptr - ( char * ) pointer ;
/*
* Try to verify that we have a sane block pointer : the block header
* should reference an aset and the freeptr should match the endptr .
*/
if ( ! AllocBlockIsValid ( block ) | | block - > freeptr ! = block - > endptr )
elog ( ERROR , " could not find block containing chunk %p " , chunk ) ;
set = block - > aset ;
set = block - > aset ;
oldsize = block - > endptr - ( char * ) pointer ;
# ifdef MEMORY_CONTEXT_CHECKING
# ifdef MEMORY_CONTEXT_CHECKING
/* Test for someone scribbling on unused space in chunk */
/* Test for someone scribbling on unused space in chunk */
Assert ( chunk - > requested_size < oldsize ) ;
Assert ( chunk - > requested_size < oldsize ) ;
@ -1116,13 +1152,6 @@ AllocSetRealloc(void *pointer, Size size)
set - > header . name , chunk ) ;
set - > header . name , chunk ) ;
# endif
# endif
/*
* Try to verify that we have a sane block pointer , the freeptr should
* match the endptr .
*/
if ( block - > freeptr ! = block - > endptr )
elog ( ERROR , " could not find block containing chunk %p " , chunk ) ;
# ifdef MEMORY_CONTEXT_CHECKING
# ifdef MEMORY_CONTEXT_CHECKING
/* ensure there's always space for the sentinel byte */
/* ensure there's always space for the sentinel byte */
chksize = MAXALIGN ( size + 1 ) ;
chksize = MAXALIGN ( size + 1 ) ;
@ -1201,9 +1230,20 @@ AllocSetRealloc(void *pointer, Size size)
}
}
block = MemoryChunkGetBlock ( chunk ) ;
block = MemoryChunkGetBlock ( chunk ) ;
oldsize = GetChunkSizeFromFreeListIdx ( MemoryChunkGetValue ( chunk ) ) ;
/*
* In this path , for speed reasons we just Assert that the referenced
* block is good . We can also Assert that the value field is sane . Future
* field experience may show that these Asserts had better become regular
* runtime test - and - elog checks .
*/
AssertArg ( AllocBlockIsValid ( block ) ) ;
set = block - > aset ;
set = block - > aset ;
fidx = MemoryChunkGetValue ( chunk ) ;
Assert ( FreeListIdxIsValid ( fidx ) ) ;
oldsize = GetChunkSizeFromFreeListIdx ( fidx ) ;
# ifdef MEMORY_CONTEXT_CHECKING
# ifdef MEMORY_CONTEXT_CHECKING
/* Test for someone scribbling on unused space in chunk */
/* Test for someone scribbling on unused space in chunk */
if ( chunk - > requested_size < oldsize )
if ( chunk - > requested_size < oldsize )
@ -1328,6 +1368,7 @@ AllocSetGetChunkContext(void *pointer)
else
else
block = ( AllocBlock ) MemoryChunkGetBlock ( chunk ) ;
block = ( AllocBlock ) MemoryChunkGetBlock ( chunk ) ;
AssertArg ( AllocBlockIsValid ( block ) ) ;
set = block - > aset ;
set = block - > aset ;
return & set - > header ;
return & set - > header ;
@ -1342,16 +1383,19 @@ Size
AllocSetGetChunkSpace ( void * pointer )
AllocSetGetChunkSpace ( void * pointer )
{
{
MemoryChunk * chunk = PointerGetMemoryChunk ( pointer ) ;
MemoryChunk * chunk = PointerGetMemoryChunk ( pointer ) ;
int fidx ;
if ( MemoryChunkIsExternal ( chunk ) )
if ( MemoryChunkIsExternal ( chunk ) )
{
{
AllocBlock block = ExternalChunkGetBlock ( chunk ) ;
AllocBlock block = ExternalChunkGetBlock ( chunk ) ;
AssertArg ( AllocBlockIsValid ( block ) ) ;
return block - > endptr - ( char * ) chunk ;
return block - > endptr - ( char * ) chunk ;
}
}
return GetChunkSizeFromFreeListIdx ( MemoryChunkGetValue ( chunk ) ) +
fidx = MemoryChunkGetValue ( chunk ) ;
ALLOC_CHUNKHDRSZ ;
Assert ( FreeListIdxIsValid ( fidx ) ) ;
return GetChunkSizeFromFreeListIdx ( fidx ) + ALLOC_CHUNKHDRSZ ;
}
}
/*
/*
@ -1361,6 +1405,8 @@ AllocSetGetChunkSpace(void *pointer)
bool
bool
AllocSetIsEmpty ( MemoryContext context )
AllocSetIsEmpty ( MemoryContext context )
{
{
AssertArg ( AllocSetIsValid ( context ) ) ;
/*
/*
* For now , we say " empty " only if the context is new or just reset . We
* For now , we say " empty " only if the context is new or just reset . We
* could examine the freelists to determine if all space has been freed ,
* could examine the freelists to determine if all space has been freed ,
@ -1394,6 +1440,8 @@ AllocSetStats(MemoryContext context,
AllocBlock block ;
AllocBlock block ;
int fidx ;
int fidx ;
AssertArg ( AllocSetIsValid ( set ) ) ;
/* Include context header in totalspace */
/* Include context header in totalspace */
totalspace = MAXALIGN ( sizeof ( AllocSetContext ) ) ;
totalspace = MAXALIGN ( sizeof ( AllocSetContext ) ) ;
@ -1405,14 +1453,14 @@ AllocSetStats(MemoryContext context,
}
}
for ( fidx = 0 ; fidx < ALLOCSET_NUM_FREELISTS ; fidx + + )
for ( fidx = 0 ; fidx < ALLOCSET_NUM_FREELISTS ; fidx + + )
{
{
Size chksz = GetChunkSizeFromFreeListIdx ( fidx ) ;
MemoryChunk * chunk = set - > freelist [ fidx ] ;
MemoryChunk * chunk = set - > freelist [ fidx ] ;
while ( chunk ! = NULL )
while ( chunk ! = NULL )
{
{
Size chksz = GetChunkSizeFromFreeListIdx ( MemoryChunkGetValue ( chunk ) ) ;
AllocFreeListLink * link = GetFreeListLink ( chunk ) ;
AllocFreeListLink * link = GetFreeListLink ( chunk ) ;
Assert ( GetChunkSizeFromFreeListIdx ( fidx ) = = chksz ) ;
Assert ( MemoryChunkGetValue ( chunk ) = = fidx ) ;
freechunks + + ;
freechunks + + ;
freespace + = chksz + ALLOC_CHUNKHDRSZ ;
freespace + = chksz + ALLOC_CHUNKHDRSZ ;
@ -1522,7 +1570,13 @@ AllocSetCheck(MemoryContext context)
}
}
else
else
{
{
chsize = GetChunkSizeFromFreeListIdx ( MemoryChunkGetValue ( chunk ) ) ; /* aligned chunk size */
int fidx = MemoryChunkGetValue ( chunk ) ;
if ( ! FreeListIdxIsValid ( fidx ) )
elog ( WARNING , " problem in alloc set %s: bad chunk size for chunk %p in block %p " ,
name , chunk , block ) ;
chsize = GetChunkSizeFromFreeListIdx ( fidx ) ; /* aligned chunk size */
/*
/*
* Check the stored block offset correctly references this
* Check the stored block offset correctly references this