mirror of
https://github.com/postgres/postgres.git
synced 2026-02-25 02:44:39 -05:00
I found that half a dozen (nearly 5%) of our AllocSetContextCreate calls had typos in the context-sizing parameters. While none of these led to especially significant problems, they did create minor inefficiencies, and it's now clear that expecting people to copy-and-paste those calls accurately is not a great idea. Let's reduce the risk of future errors by introducing single macros that encapsulate the common use-cases. Three such macros are enough to cover all but two special-purpose contexts; those two calls can be left as-is, I think. While this patch doesn't in itself improve matters for third-party extensions, it doesn't break anything for them either, and they can gradually adopt the simplified notation over time. In passing, change TopMemoryContext to use the default allocation parameters. Formerly it could only be extended 8K at a time. That was probably reasonable when this code was written; but nowadays we create many more contexts than we did then, so that it's not unusual to have a couple hundred K in TopMemoryContext, even without considering various dubious code that sticks other things there. There seems no good reason not to let it use growing blocks like most other contexts. Back-patch to 9.6, mostly because that's still close enough to HEAD that it's easy to do so, and keeping the branches in sync can be expected to avoid some future back-patching pain. The bugs fixed by these changes don't seem to be significant enough to justify fixing them further back. Discussion: <21072.1472321324@sss.pgh.pa.us>
174 lines
6.2 KiB
C
174 lines
6.2 KiB
C
/*-------------------------------------------------------------------------
|
|
*
|
|
* memutils.h
|
|
* This file contains declarations for memory allocation utility
|
|
* functions. These are functions that are not quite widely used
|
|
* enough to justify going in utils/palloc.h, but are still part
|
|
* of the API of the memory management subsystem.
|
|
*
|
|
*
|
|
* Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group
|
|
* Portions Copyright (c) 1994, Regents of the University of California
|
|
*
|
|
* src/include/utils/memutils.h
|
|
*
|
|
*-------------------------------------------------------------------------
|
|
*/
|
|
#ifndef MEMUTILS_H
|
|
#define MEMUTILS_H
|
|
|
|
#include "nodes/memnodes.h"
|
|
|
|
|
|
/*
|
|
* MaxAllocSize, MaxAllocHugeSize
|
|
* Quasi-arbitrary limits on size of allocations.
|
|
*
|
|
* Note:
|
|
* There is no guarantee that smaller allocations will succeed, but
|
|
* larger requests will be summarily denied.
|
|
*
|
|
* palloc() enforces MaxAllocSize, chosen to correspond to the limiting size
|
|
* of varlena objects under TOAST. See VARSIZE_4B() and related macros in
|
|
* postgres.h. Many datatypes assume that any allocatable size can be
|
|
* represented in a varlena header. This limit also permits a caller to use
|
|
* an "int" variable for an index into or length of an allocation. Callers
|
|
* careful to avoid these hazards can access the higher limit with
|
|
* MemoryContextAllocHuge(). Both limits permit code to assume that it may
|
|
* compute twice an allocation's size without overflow.
|
|
*/
|
|
#define MaxAllocSize ((Size) 0x3fffffff) /* 1 gigabyte - 1 */
|
|
|
|
#define AllocSizeIsValid(size) ((Size) (size) <= MaxAllocSize)
|
|
|
|
#define MaxAllocHugeSize ((Size) -1 >> 1) /* SIZE_MAX / 2 */
|
|
|
|
#define AllocHugeSizeIsValid(size) ((Size) (size) <= MaxAllocHugeSize)
|
|
|
|
/*
|
|
* All chunks allocated by any memory context manager are required to be
|
|
* preceded by a StandardChunkHeader at a spacing of STANDARDCHUNKHEADERSIZE.
|
|
* A currently-allocated chunk must contain a backpointer to its owning
|
|
* context as well as the allocated size of the chunk. The backpointer is
|
|
* used by pfree() and repalloc() to find the context to call. The allocated
|
|
* size is not absolutely essential, but it's expected to be needed by any
|
|
* reasonable implementation.
|
|
*/
|
|
typedef struct StandardChunkHeader
|
|
{
|
|
MemoryContext context; /* owning context */
|
|
Size size; /* size of data space allocated in chunk */
|
|
#ifdef MEMORY_CONTEXT_CHECKING
|
|
/* when debugging memory usage, also store actual requested size */
|
|
Size requested_size;
|
|
#endif
|
|
} StandardChunkHeader;
|
|
|
|
#define STANDARDCHUNKHEADERSIZE MAXALIGN(sizeof(StandardChunkHeader))
|
|
|
|
|
|
/*
|
|
* Standard top-level memory contexts.
|
|
*
|
|
* Only TopMemoryContext and ErrorContext are initialized by
|
|
* MemoryContextInit() itself.
|
|
*/
|
|
extern PGDLLIMPORT MemoryContext TopMemoryContext;
|
|
extern PGDLLIMPORT MemoryContext ErrorContext;
|
|
extern PGDLLIMPORT MemoryContext PostmasterContext;
|
|
extern PGDLLIMPORT MemoryContext CacheMemoryContext;
|
|
extern PGDLLIMPORT MemoryContext MessageContext;
|
|
extern PGDLLIMPORT MemoryContext TopTransactionContext;
|
|
extern PGDLLIMPORT MemoryContext CurTransactionContext;
|
|
|
|
/* This is a transient link to the active portal's memory context: */
|
|
extern PGDLLIMPORT MemoryContext PortalContext;
|
|
|
|
/* Backwards compatibility macro */
|
|
#define MemoryContextResetAndDeleteChildren(ctx) MemoryContextReset(ctx)
|
|
|
|
|
|
/*
|
|
* Memory-context-type-independent functions in mcxt.c
|
|
*/
|
|
extern void MemoryContextInit(void);
|
|
extern void MemoryContextReset(MemoryContext context);
|
|
extern void MemoryContextDelete(MemoryContext context);
|
|
extern void MemoryContextResetOnly(MemoryContext context);
|
|
extern void MemoryContextResetChildren(MemoryContext context);
|
|
extern void MemoryContextDeleteChildren(MemoryContext context);
|
|
extern void MemoryContextSetParent(MemoryContext context,
|
|
MemoryContext new_parent);
|
|
extern Size GetMemoryChunkSpace(void *pointer);
|
|
extern MemoryContext GetMemoryChunkContext(void *pointer);
|
|
extern MemoryContext MemoryContextGetParent(MemoryContext context);
|
|
extern bool MemoryContextIsEmpty(MemoryContext context);
|
|
extern void MemoryContextStats(MemoryContext context);
|
|
extern void MemoryContextStatsDetail(MemoryContext context, int max_children);
|
|
extern void MemoryContextAllowInCriticalSection(MemoryContext context,
|
|
bool allow);
|
|
|
|
#ifdef MEMORY_CONTEXT_CHECKING
|
|
extern void MemoryContextCheck(MemoryContext context);
|
|
#endif
|
|
extern bool MemoryContextContains(MemoryContext context, void *pointer);
|
|
|
|
/*
|
|
* This routine handles the context-type-independent part of memory
|
|
* context creation. It's intended to be called from context-type-
|
|
* specific creation routines, and noplace else.
|
|
*/
|
|
extern MemoryContext MemoryContextCreate(NodeTag tag, Size size,
|
|
MemoryContextMethods *methods,
|
|
MemoryContext parent,
|
|
const char *name);
|
|
|
|
|
|
/*
|
|
* Memory-context-type-specific functions
|
|
*/
|
|
|
|
/* aset.c */
|
|
extern MemoryContext AllocSetContextCreate(MemoryContext parent,
|
|
const char *name,
|
|
Size minContextSize,
|
|
Size initBlockSize,
|
|
Size maxBlockSize);
|
|
|
|
/*
|
|
* Recommended default alloc parameters, suitable for "ordinary" contexts
|
|
* that might hold quite a lot of data.
|
|
*/
|
|
#define ALLOCSET_DEFAULT_MINSIZE 0
|
|
#define ALLOCSET_DEFAULT_INITSIZE (8 * 1024)
|
|
#define ALLOCSET_DEFAULT_MAXSIZE (8 * 1024 * 1024)
|
|
#define ALLOCSET_DEFAULT_SIZES \
|
|
ALLOCSET_DEFAULT_MINSIZE, ALLOCSET_DEFAULT_INITSIZE, ALLOCSET_DEFAULT_MAXSIZE
|
|
|
|
/*
|
|
* Recommended alloc parameters for "small" contexts that are never expected
|
|
* to contain much data (for example, a context to contain a query plan).
|
|
*/
|
|
#define ALLOCSET_SMALL_MINSIZE 0
|
|
#define ALLOCSET_SMALL_INITSIZE (1 * 1024)
|
|
#define ALLOCSET_SMALL_MAXSIZE (8 * 1024)
|
|
#define ALLOCSET_SMALL_SIZES \
|
|
ALLOCSET_SMALL_MINSIZE, ALLOCSET_SMALL_INITSIZE, ALLOCSET_SMALL_MAXSIZE
|
|
|
|
/*
|
|
* Recommended alloc parameters for contexts that should start out small,
|
|
* but might sometimes grow big.
|
|
*/
|
|
#define ALLOCSET_START_SMALL_SIZES \
|
|
ALLOCSET_SMALL_MINSIZE, ALLOCSET_SMALL_INITSIZE, ALLOCSET_DEFAULT_MAXSIZE
|
|
|
|
|
|
/*
|
|
* Threshold above which a request in an AllocSet context is certain to be
|
|
* allocated separately (and thereby have constant allocation overhead).
|
|
* Few callers should be interested in this, but tuplesort/tuplestore need
|
|
* to know it.
|
|
*/
|
|
#define ALLOCSET_SEPARATE_THRESHOLD 8192
|
|
|
|
#endif /* MEMUTILS_H */
|