1
0
mirror of https://github.com/postgres/postgres.git synced 2025-07-30 11:03:19 +03:00

Enlarge bit-space for MemoryContextMethodID

Reserve 4 bits for MemoryContextMethodID rather than 3.  3 bits did
technically allow a maximum of 8 memory context types, however, we've
opted to reserve some bit patterns which left us with only 4 slots, all
of which were used.

Here we add another bit which frees up 8 slots for future memory context
types.

In passing, adjust the enum names in MemoryContextMethodID to make it
more clear which ones can be used and which ones are reserved.

Author: Matthias van de Meent, David Rowley
Discussion: https://postgr.es/m/CAApHDvqGSpCU95TmM=Bp=6xjL_nLys4zdZOpfNyWBk97Xrdj2w@mail.gmail.com
This commit is contained in:
David Rowley
2024-04-07 23:32:00 +12:00
parent c4ab7da606
commit 0ba8b75e7e
4 changed files with 72 additions and 42 deletions

View File

@ -395,14 +395,14 @@ relevant MemoryContext as a parameter, operations like free and
realloc are trickier. To make those work, we require all memory
context types to produce allocated chunks that are immediately,
without any padding, preceded by a uint64 value of which the least
significant 3 bits are set to the owning context's MemoryContextMethodID.
significant 4 bits are set to the owning context's MemoryContextMethodID.
This allows the code to determine the correct MemoryContextMethods to
use by looking up the mcxt_methods[] array using the 3 bits as an index
use by looking up the mcxt_methods[] array using the 4 bits as an index
into that array.
If a type of allocator needs additional information about its chunks,
like e.g. the size of the allocation, that information can in turn
either be encoded into the remaining 61 bits of the preceding uint64 value
either be encoded into the remaining 60 bits of the preceding uint64 value
or if more space is required, additional values may be stored directly prior
to the uint64 value. It is up to the context implementation to manage this.
@ -420,13 +420,20 @@ pfree(void *pointer)
All of the current memory contexts make use of the MemoryChunk header type
which is defined in memutils_memorychunk.h. This suits all of the existing
context types well as it makes use of the remaining 61-bits of the uint64
context types well as it makes use of the remaining 60-bits of the uint64
header to efficiently encode the size of the chunk of memory (or freelist
index, in the case of aset.c) and the number of bytes which must be subtracted
from the chunk in order to obtain a reference to the block that the chunk
belongs to. 30 bits are used for each of these. If more than 30 bits are
required then the memory context must manage that itself. This can be done by
calling the MemoryChunkSetHdrMaskExternal() function on the given chunk.
belongs to. 30 bits are used for each of these, but only a total of 59 bits
as the lowest bit for the chunk to block offset is the same bit as the highest
bit of the chunk size. This overlapping is possible as the relative offset
between the block and the chunk is expected to be a MAXALIGNed value which
guarantees the lowest bit is always 0. If more than 30 bits are required for
each of these fields then the memory context must manage that itself. This
can be done by calling the MemoryChunkSetHdrMaskExternal() function on the
given chunk. Whether a chunk is an external chunk can be determined by the 1
remaining bit from the 64-bit MemoryChunk.
Currently, each memory context type stores large allocations on dedicated
blocks (which always contain only a single chunk). For these, finding the
block is simple as we know that the chunk must be the first on the given

View File

@ -37,6 +37,11 @@ static Size BogusGetChunkSpace(void *pointer);
/*****************************************************************************
* GLOBAL MEMORY *
*****************************************************************************/
#define BOGUS_MCTX(id) \
[id].free_p = BogusFree, \
[id].realloc = BogusRealloc, \
[id].get_chunk_context = BogusGetChunkContext, \
[id].get_chunk_space = BogusGetChunkSpace
static const MemoryContextMethods mcxt_methods[] = {
/* aset.c */
@ -97,33 +102,27 @@ static const MemoryContextMethods mcxt_methods[] = {
/*
* Unused (as yet) IDs should have dummy entries here. This allows us to
* fail cleanly if a bogus pointer is passed to pfree or the like. It
* Reserved and unused IDs should have dummy entries here. This allows us
* to fail cleanly if a bogus pointer is passed to pfree or the like. It
* seems sufficient to provide routines for the methods that might get
* invoked from inspection of a chunk (see MCXT_METHOD calls below).
*/
[MCTX_UNUSED1_ID].free_p = BogusFree,
[MCTX_UNUSED1_ID].realloc = BogusRealloc,
[MCTX_UNUSED1_ID].get_chunk_context = BogusGetChunkContext,
[MCTX_UNUSED1_ID].get_chunk_space = BogusGetChunkSpace,
[MCTX_UNUSED2_ID].free_p = BogusFree,
[MCTX_UNUSED2_ID].realloc = BogusRealloc,
[MCTX_UNUSED2_ID].get_chunk_context = BogusGetChunkContext,
[MCTX_UNUSED2_ID].get_chunk_space = BogusGetChunkSpace,
[MCTX_UNUSED3_ID].free_p = BogusFree,
[MCTX_UNUSED3_ID].realloc = BogusRealloc,
[MCTX_UNUSED3_ID].get_chunk_context = BogusGetChunkContext,
[MCTX_UNUSED3_ID].get_chunk_space = BogusGetChunkSpace,
[MCTX_UNUSED4_ID].free_p = BogusFree,
[MCTX_UNUSED4_ID].realloc = BogusRealloc,
[MCTX_UNUSED4_ID].get_chunk_context = BogusGetChunkContext,
[MCTX_UNUSED4_ID].get_chunk_space = BogusGetChunkSpace,
BOGUS_MCTX(MCTX_1_RESERVED_GLIBC_ID),
BOGUS_MCTX(MCTX_2_RESERVED_GLIBC_ID),
BOGUS_MCTX(MCTX_7_UNUSED_ID),
BOGUS_MCTX(MCTX_8_UNUSED_ID),
BOGUS_MCTX(MCTX_9_UNUSED_ID),
BOGUS_MCTX(MCTX_10_UNUSED_ID),
BOGUS_MCTX(MCTX_11_UNUSED_ID),
BOGUS_MCTX(MCTX_12_UNUSED_ID),
BOGUS_MCTX(MCTX_13_UNUSED_ID),
BOGUS_MCTX(MCTX_14_UNUSED_ID),
BOGUS_MCTX(MCTX_0_RESERVED_UNUSEDMEM_ID),
BOGUS_MCTX(MCTX_15_RESERVED_WIPEDMEM_ID)
};
#undef BOGUS_MCTX
/*
* CurrentMemoryContext
* Default memory context for allocations.