From 2d0ad3b35b0b0d537599f0bbf8b1d6d8ec297156 Mon Sep 17 00:00:00 2001
From: Nathan Bossart
Date: Mon, 16 Aug 2021 02:59:32 +0000
Subject: [PATCH v8 1/1] Disallow external access to MaxBackends.
Presently, MaxBackends is externally visible, but it may still be
uninitialized in places where it would be convenient to use (e.g.,
_PG_init()). This change makes MaxBackends static to postinit.c to
disallow such direct access. Instead, MaxBackends should now be
accessed via GetMaxBackends().
---
src/backend/access/nbtree/nbtutils.c | 4 +-
src/backend/access/transam/multixact.c | 8 ++-
src/backend/access/transam/twophase.c | 3 +-
src/backend/commands/async.c | 11 ++--
src/backend/libpq/pqcomm.c | 3 +-
src/backend/postmaster/auxprocess.c | 2 +-
src/backend/postmaster/postmaster.c | 4 +-
src/backend/storage/ipc/dsm.c | 2 +-
src/backend/storage/ipc/procarray.c | 2 +-
src/backend/storage/ipc/procsignal.c | 17 ++++--
src/backend/storage/ipc/sinvaladt.c | 4 +-
src/backend/storage/lmgr/deadlock.c | 31 +++++-----
src/backend/storage/lmgr/lock.c | 23 ++++----
src/backend/storage/lmgr/predicate.c | 10 ++--
src/backend/storage/lmgr/proc.c | 17 +++---
src/backend/utils/activity/backend_status.c | 63 +++++++++++----------
src/backend/utils/adt/lockfuncs.c | 5 +-
src/backend/utils/init/postinit.c | 50 ++++++++++++++--
src/include/miscadmin.h | 3 +-
19 files changed, 161 insertions(+), 101 deletions(-)
diff --git a/src/backend/access/nbtree/nbtutils.c b/src/backend/access/nbtree/nbtutils.c
index 6a651d8397..84164748b3 100644
--- a/src/backend/access/nbtree/nbtutils.c
+++ b/src/backend/access/nbtree/nbtutils.c
@@ -2072,7 +2072,7 @@ BTreeShmemSize(void)
Size size;
size = offsetof(BTVacInfo, vacuums);
- size = add_size(size, mul_size(MaxBackends, sizeof(BTOneVacInfo)));
+ size = add_size(size, mul_size(GetMaxBackends(), sizeof(BTOneVacInfo)));
return size;
}
@@ -2101,7 +2101,7 @@ BTreeShmemInit(void)
btvacinfo->cycle_ctr = (BTCycleId) time(NULL);
btvacinfo->num_vacuums = 0;
- btvacinfo->max_vacuums = MaxBackends;
+ btvacinfo->max_vacuums = GetMaxBackends();
}
else
Assert(found);
diff --git a/src/backend/access/transam/multixact.c b/src/backend/access/transam/multixact.c
index 806f2e43ba..9ee805078c 100644
--- a/src/backend/access/transam/multixact.c
+++ b/src/backend/access/transam/multixact.c
@@ -285,7 +285,7 @@ typedef struct MultiXactStateData
* Last element of OldestMemberMXactId and OldestVisibleMXactId arrays.
* Valid elements are (1..MaxOldestSlot); element 0 is never used.
*/
-#define MaxOldestSlot (MaxBackends + max_prepared_xacts)
+#define MaxOldestSlot (GetMaxBackends() + max_prepared_xacts)
/* Pointers to the state data in shared memory */
static MultiXactStateData *MultiXactState;
@@ -684,6 +684,7 @@ MultiXactIdSetOldestVisible(void)
if (!MultiXactIdIsValid(OldestVisibleMXactId[MyBackendId]))
{
MultiXactId oldestMXact;
+ int maxOldestSlot = MaxOldestSlot;
int i;
LWLockAcquire(MultiXactGenLock, LW_EXCLUSIVE);
@@ -697,7 +698,7 @@ MultiXactIdSetOldestVisible(void)
if (oldestMXact < FirstMultiXactId)
oldestMXact = FirstMultiXactId;
- for (i = 1; i <= MaxOldestSlot; i++)
+ for (i = 1; i <= maxOldestSlot; i++)
{
MultiXactId thisoldest = OldestMemberMXactId[i];
@@ -2507,6 +2508,7 @@ GetOldestMultiXactId(void)
{
MultiXactId oldestMXact;
MultiXactId nextMXact;
+ int maxOldestSlot = MaxOldestSlot;
int i;
/*
@@ -2525,7 +2527,7 @@ GetOldestMultiXactId(void)
nextMXact = FirstMultiXactId;
oldestMXact = nextMXact;
- for (i = 1; i <= MaxOldestSlot; i++)
+ for (i = 1; i <= maxOldestSlot; i++)
{
MultiXactId thisoldest;
diff --git a/src/backend/access/transam/twophase.c b/src/backend/access/transam/twophase.c
index 271a3146db..608c5149e5 100644
--- a/src/backend/access/transam/twophase.c
+++ b/src/backend/access/transam/twophase.c
@@ -260,6 +260,7 @@ TwoPhaseShmemInit(void)
{
GlobalTransaction gxacts;
int i;
+ int max_backends = GetMaxBackends();
Assert(!found);
TwoPhaseState->freeGXacts = NULL;
@@ -293,7 +294,7 @@ TwoPhaseShmemInit(void)
* prepared transaction. Currently multixact.c uses that
* technique.
*/
- gxacts[i].dummyBackendId = MaxBackends + 1 + i;
+ gxacts[i].dummyBackendId = max_backends + 1 + i;
}
}
else
diff --git a/src/backend/commands/async.c b/src/backend/commands/async.c
index 3e1b92df03..d44001a49f 100644
--- a/src/backend/commands/async.c
+++ b/src/backend/commands/async.c
@@ -518,7 +518,7 @@ AsyncShmemSize(void)
Size size;
/* This had better match AsyncShmemInit */
- size = mul_size(MaxBackends + 1, sizeof(QueueBackendStatus));
+ size = mul_size(GetMaxBackends() + 1, sizeof(QueueBackendStatus));
size = add_size(size, offsetof(AsyncQueueControl, backend));
size = add_size(size, SimpleLruShmemSize(NUM_NOTIFY_BUFFERS, 0));
@@ -534,6 +534,7 @@ AsyncShmemInit(void)
{
bool found;
Size size;
+ int max_backends = GetMaxBackends();
/*
* Create or attach to the AsyncQueueControl structure.
@@ -541,7 +542,7 @@ AsyncShmemInit(void)
* The used entries in the backend[] array run from 1 to MaxBackends; the
* zero'th entry is unused but must be allocated.
*/
- size = mul_size(MaxBackends + 1, sizeof(QueueBackendStatus));
+ size = mul_size(max_backends + 1, sizeof(QueueBackendStatus));
size = add_size(size, offsetof(AsyncQueueControl, backend));
asyncQueueControl = (AsyncQueueControl *)
@@ -556,7 +557,7 @@ AsyncShmemInit(void)
QUEUE_FIRST_LISTENER = InvalidBackendId;
asyncQueueControl->lastQueueFillWarn = 0;
/* zero'th entry won't be used, but let's initialize it anyway */
- for (int i = 0; i <= MaxBackends; i++)
+ for (int i = 0; i <= max_backends; i++)
{
QUEUE_BACKEND_PID(i) = InvalidPid;
QUEUE_BACKEND_DBOID(i) = InvalidOid;
@@ -1641,8 +1642,8 @@ SignalBackends(void)
* XXX in principle these pallocs could fail, which would be bad. Maybe
* preallocate the arrays? They're not that large, though.
*/
- pids = (int32 *) palloc(MaxBackends * sizeof(int32));
- ids = (BackendId *) palloc(MaxBackends * sizeof(BackendId));
+ pids = (int32 *) palloc(GetMaxBackends() * sizeof(int32));
+ ids = (BackendId *) palloc(GetMaxBackends() * sizeof(BackendId));
count = 0;
LWLockAcquire(NotifyQueueLock, LW_EXCLUSIVE);
diff --git a/src/backend/libpq/pqcomm.c b/src/backend/libpq/pqcomm.c
index f05723dc92..22eb04948e 100644
--- a/src/backend/libpq/pqcomm.c
+++ b/src/backend/libpq/pqcomm.c
@@ -349,6 +349,7 @@ StreamServerPort(int family, const char *hostName, unsigned short portNumber,
struct addrinfo hint;
int listen_index = 0;
int added = 0;
+ int max_backends = GetMaxBackends();
#ifdef HAVE_UNIX_SOCKETS
char unixSocketPath[MAXPGPATH];
@@ -571,7 +572,7 @@ StreamServerPort(int family, const char *hostName, unsigned short portNumber,
* intended to provide a clamp on the request on platforms where an
* overly large request provokes a kernel error (are there any?).
*/
- maxconn = MaxBackends * 2;
+ maxconn = max_backends * 2;
if (maxconn > PG_SOMAXCONN)
maxconn = PG_SOMAXCONN;
diff --git a/src/backend/postmaster/auxprocess.c b/src/backend/postmaster/auxprocess.c
index 39ac4490db..0587e45920 100644
--- a/src/backend/postmaster/auxprocess.c
+++ b/src/backend/postmaster/auxprocess.c
@@ -116,7 +116,7 @@ AuxiliaryProcessMain(AuxProcType auxtype)
* This will need rethinking if we ever want more than one of a particular
* auxiliary process type.
*/
- ProcSignalInit(MaxBackends + MyAuxProcType + 1);
+ ProcSignalInit(GetMaxBackends() + MyAuxProcType + 1);
/*
* Auxiliary processes don't run transactions, but they may need a
diff --git a/src/backend/postmaster/postmaster.c b/src/backend/postmaster/postmaster.c
index ac0ec0986a..ce90877154 100644
--- a/src/backend/postmaster/postmaster.c
+++ b/src/backend/postmaster/postmaster.c
@@ -6260,7 +6260,7 @@ save_backend_variables(BackendParameters *param, Port *port,
param->query_id_enabled = query_id_enabled;
param->max_safe_fds = max_safe_fds;
- param->MaxBackends = MaxBackends;
+ param->MaxBackends = GetMaxBackends();
#ifdef WIN32
param->PostmasterHandle = PostmasterHandle;
@@ -6494,7 +6494,7 @@ restore_backend_variables(BackendParameters *param, Port *port)
query_id_enabled = param->query_id_enabled;
max_safe_fds = param->max_safe_fds;
- MaxBackends = param->MaxBackends;
+ SetMaxBackends(param->MaxBackends);
#ifdef WIN32
PostmasterHandle = param->PostmasterHandle;
diff --git a/src/backend/storage/ipc/dsm.c b/src/backend/storage/ipc/dsm.c
index ae75141592..e9e9fae3eb 100644
--- a/src/backend/storage/ipc/dsm.c
+++ b/src/backend/storage/ipc/dsm.c
@@ -166,7 +166,7 @@ dsm_postmaster_startup(PGShmemHeader *shim)
/* Determine size for new control segment. */
maxitems = PG_DYNSHMEM_FIXED_SLOTS
- + PG_DYNSHMEM_SLOTS_PER_BACKEND * MaxBackends;
+ + PG_DYNSHMEM_SLOTS_PER_BACKEND * GetMaxBackends();
elog(DEBUG2, "dynamic shared memory system will support %u segments",
maxitems);
segsize = dsm_control_bytes_needed(maxitems);
diff --git a/src/backend/storage/ipc/procarray.c b/src/backend/storage/ipc/procarray.c
index 9d3efb7d80..3e5dca78f4 100644
--- a/src/backend/storage/ipc/procarray.c
+++ b/src/backend/storage/ipc/procarray.c
@@ -365,7 +365,7 @@ ProcArrayShmemSize(void)
Size size;
/* Size of the ProcArray structure itself */
-#define PROCARRAY_MAXPROCS (MaxBackends + max_prepared_xacts)
+#define PROCARRAY_MAXPROCS (GetMaxBackends() + max_prepared_xacts)
size = offsetof(ProcArrayStruct, pgprocnos);
size = add_size(size, mul_size(sizeof(int), PROCARRAY_MAXPROCS));
diff --git a/src/backend/storage/ipc/procsignal.c b/src/backend/storage/ipc/procsignal.c
index f1c8ff8f9e..0fbb05bc3e 100644
--- a/src/backend/storage/ipc/procsignal.c
+++ b/src/backend/storage/ipc/procsignal.c
@@ -85,7 +85,7 @@ typedef struct
* possible auxiliary process type. (This scheme assumes there is not
* more than one of any auxiliary process type at a time.)
*/
-#define NumProcSignalSlots (MaxBackends + NUM_AUXPROCTYPES)
+#define NumProcSignalSlots (GetMaxBackends() + NUM_AUXPROCTYPES)
/* Check whether the relevant type bit is set in the flags. */
#define BARRIER_SHOULD_CHECK(flags, type) \
@@ -126,6 +126,7 @@ ProcSignalShmemInit(void)
{
Size size = ProcSignalShmemSize();
bool found;
+ int numProcSignalSlots = NumProcSignalSlots;
ProcSignal = (ProcSignalHeader *)
ShmemInitStruct("ProcSignal", size, &found);
@@ -137,7 +138,7 @@ ProcSignalShmemInit(void)
pg_atomic_init_u64(&ProcSignal->psh_barrierGeneration, 0);
- for (i = 0; i < NumProcSignalSlots; ++i)
+ for (i = 0; i < numProcSignalSlots; ++i)
{
ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
@@ -291,8 +292,9 @@ SendProcSignal(pid_t pid, ProcSignalReason reason, BackendId backendId)
* process, which will have a slot near the end of the array.
*/
int i;
+ int numProcSignalSlots = NumProcSignalSlots;
- for (i = NumProcSignalSlots - 1; i >= 0; i--)
+ for (i = numProcSignalSlots - 1; i >= 0; i--)
{
slot = &ProcSignal->psh_slot[i];
@@ -333,6 +335,7 @@ EmitProcSignalBarrier(ProcSignalBarrierType type)
{
uint32 flagbit = 1 << (uint32) type;
uint64 generation;
+ int numProcSignalSlots = NumProcSignalSlots;
/*
* Set all the flags.
@@ -342,7 +345,7 @@ EmitProcSignalBarrier(ProcSignalBarrierType type)
* anything that we do afterwards. (This is also true of the later call to
* pg_atomic_add_fetch_u64.)
*/
- for (int i = 0; i < NumProcSignalSlots; i++)
+ for (int i = 0; i < numProcSignalSlots; i++)
{
volatile ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
@@ -368,7 +371,7 @@ EmitProcSignalBarrier(ProcSignalBarrierType type)
* backends that need to update state - but they won't actually need to
* change any state.
*/
- for (int i = NumProcSignalSlots - 1; i >= 0; i--)
+ for (int i = numProcSignalSlots - 1; i >= 0; i--)
{
volatile ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
pid_t pid = slot->pss_pid;
@@ -391,9 +394,11 @@ EmitProcSignalBarrier(ProcSignalBarrierType type)
void
WaitForProcSignalBarrier(uint64 generation)
{
+ int numProcSignalSlots = NumProcSignalSlots;
+
Assert(generation <= pg_atomic_read_u64(&ProcSignal->psh_barrierGeneration));
- for (int i = NumProcSignalSlots - 1; i >= 0; i--)
+ for (int i = numProcSignalSlots - 1; i >= 0; i--)
{
ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
uint64 oldval;
diff --git a/src/backend/storage/ipc/sinvaladt.c b/src/backend/storage/ipc/sinvaladt.c
index cb3ee82046..68e7160b30 100644
--- a/src/backend/storage/ipc/sinvaladt.c
+++ b/src/backend/storage/ipc/sinvaladt.c
@@ -205,7 +205,7 @@ SInvalShmemSize(void)
Size size;
size = offsetof(SISeg, procState);
- size = add_size(size, mul_size(sizeof(ProcState), MaxBackends));
+ size = add_size(size, mul_size(sizeof(ProcState), GetMaxBackends()));
return size;
}
@@ -231,7 +231,7 @@ CreateSharedInvalidationState(void)
shmInvalBuffer->maxMsgNum = 0;
shmInvalBuffer->nextThreshold = CLEANUP_MIN;
shmInvalBuffer->lastBackend = 0;
- shmInvalBuffer->maxBackends = MaxBackends;
+ shmInvalBuffer->maxBackends = GetMaxBackends();
SpinLockInit(&shmInvalBuffer->msgnumLock);
/* The buffer[] array is initially all unused, so we need not fill it */
diff --git a/src/backend/storage/lmgr/deadlock.c b/src/backend/storage/lmgr/deadlock.c
index cd9c0418ec..b5d539ba5d 100644
--- a/src/backend/storage/lmgr/deadlock.c
+++ b/src/backend/storage/lmgr/deadlock.c
@@ -143,6 +143,7 @@ void
InitDeadLockChecking(void)
{
MemoryContext oldcxt;
+ int max_backends = GetMaxBackends();
/* Make sure allocations are permanent */
oldcxt = MemoryContextSwitchTo(TopMemoryContext);
@@ -151,16 +152,16 @@ InitDeadLockChecking(void)
* FindLockCycle needs at most MaxBackends entries in visitedProcs[] and
* deadlockDetails[].
*/
- visitedProcs = (PGPROC **) palloc(MaxBackends * sizeof(PGPROC *));
- deadlockDetails = (DEADLOCK_INFO *) palloc(MaxBackends * sizeof(DEADLOCK_INFO));
+ visitedProcs = (PGPROC **) palloc(max_backends * sizeof(PGPROC *));
+ deadlockDetails = (DEADLOCK_INFO *) palloc(max_backends * sizeof(DEADLOCK_INFO));
/*
* TopoSort needs to consider at most MaxBackends wait-queue entries, and
* it needn't run concurrently with FindLockCycle.
*/
topoProcs = visitedProcs; /* re-use this space */
- beforeConstraints = (int *) palloc(MaxBackends * sizeof(int));
- afterConstraints = (int *) palloc(MaxBackends * sizeof(int));
+ beforeConstraints = (int *) palloc(max_backends * sizeof(int));
+ afterConstraints = (int *) palloc(max_backends * sizeof(int));
/*
* We need to consider rearranging at most MaxBackends/2 wait queues
@@ -169,8 +170,8 @@ InitDeadLockChecking(void)
* MaxBackends total waiters.
*/
waitOrders = (WAIT_ORDER *)
- palloc((MaxBackends / 2) * sizeof(WAIT_ORDER));
- waitOrderProcs = (PGPROC **) palloc(MaxBackends * sizeof(PGPROC *));
+ palloc((max_backends / 2) * sizeof(WAIT_ORDER));
+ waitOrderProcs = (PGPROC **) palloc(max_backends * sizeof(PGPROC *));
/*
* Allow at most MaxBackends distinct constraints in a configuration. (Is
@@ -180,7 +181,7 @@ InitDeadLockChecking(void)
* limits the maximum recursion depth of DeadLockCheckRecurse. Making it
* really big might potentially allow a stack-overflow problem.
*/
- maxCurConstraints = MaxBackends;
+ maxCurConstraints = max_backends;
curConstraints = (EDGE *) palloc(maxCurConstraints * sizeof(EDGE));
/*
@@ -191,7 +192,7 @@ InitDeadLockChecking(void)
* last MaxBackends entries in possibleConstraints[] are reserved as
* output workspace for FindLockCycle.
*/
- maxPossibleConstraints = MaxBackends * 4;
+ maxPossibleConstraints = max_backends * 4;
possibleConstraints =
(EDGE *) palloc(maxPossibleConstraints * sizeof(EDGE));
@@ -327,7 +328,7 @@ DeadLockCheckRecurse(PGPROC *proc)
if (nCurConstraints >= maxCurConstraints)
return true; /* out of room for active constraints? */
oldPossibleConstraints = nPossibleConstraints;
- if (nPossibleConstraints + nEdges + MaxBackends <= maxPossibleConstraints)
+ if (nPossibleConstraints + nEdges + GetMaxBackends() <= maxPossibleConstraints)
{
/* We can save the edge list in possibleConstraints[] */
nPossibleConstraints += nEdges;
@@ -388,7 +389,7 @@ TestConfiguration(PGPROC *startProc)
/*
* Make sure we have room for FindLockCycle's output.
*/
- if (nPossibleConstraints + MaxBackends > maxPossibleConstraints)
+ if (nPossibleConstraints + GetMaxBackends() > maxPossibleConstraints)
return -1;
/*
@@ -486,7 +487,7 @@ FindLockCycleRecurse(PGPROC *checkProc,
* record total length of cycle --- outer levels will now fill
* deadlockDetails[]
*/
- Assert(depth <= MaxBackends);
+ Assert(depth <= GetMaxBackends());
nDeadlockDetails = depth;
return true;
@@ -500,7 +501,7 @@ FindLockCycleRecurse(PGPROC *checkProc,
}
}
/* Mark proc as seen */
- Assert(nVisitedProcs < MaxBackends);
+ Assert(nVisitedProcs < GetMaxBackends());
visitedProcs[nVisitedProcs++] = checkProc;
/*
@@ -698,7 +699,7 @@ FindLockCycleRecurseMember(PGPROC *checkProc,
/*
* Add this edge to the list of soft edges in the cycle
*/
- Assert(*nSoftEdges < MaxBackends);
+ Assert(*nSoftEdges < GetMaxBackends());
softEdges[*nSoftEdges].waiter = checkProcLeader;
softEdges[*nSoftEdges].blocker = leader;
softEdges[*nSoftEdges].lock = lock;
@@ -771,7 +772,7 @@ FindLockCycleRecurseMember(PGPROC *checkProc,
/*
* Add this edge to the list of soft edges in the cycle
*/
- Assert(*nSoftEdges < MaxBackends);
+ Assert(*nSoftEdges < GetMaxBackends());
softEdges[*nSoftEdges].waiter = checkProcLeader;
softEdges[*nSoftEdges].blocker = leader;
softEdges[*nSoftEdges].lock = lock;
@@ -834,7 +835,7 @@ ExpandConstraints(EDGE *constraints,
waitOrders[nWaitOrders].procs = waitOrderProcs + nWaitOrderProcs;
waitOrders[nWaitOrders].nProcs = lock->waitProcs.size;
nWaitOrderProcs += lock->waitProcs.size;
- Assert(nWaitOrderProcs <= MaxBackends);
+ Assert(nWaitOrderProcs <= GetMaxBackends());
/*
* Do the topo sort. TopoSort need not examine constraints after this
diff --git a/src/backend/storage/lmgr/lock.c b/src/backend/storage/lmgr/lock.c
index 5f5803f681..ee2e15c17e 100644
--- a/src/backend/storage/lmgr/lock.c
+++ b/src/backend/storage/lmgr/lock.c
@@ -55,7 +55,7 @@
int max_locks_per_xact; /* set by guc.c */
#define NLOCKENTS() \
- mul_size(max_locks_per_xact, add_size(MaxBackends, max_prepared_xacts))
+ mul_size(max_locks_per_xact, add_size(GetMaxBackends(), max_prepared_xacts))
/*
@@ -2924,6 +2924,7 @@ GetLockConflicts(const LOCKTAG *locktag, LOCKMODE lockmode, int *countp)
LWLock *partitionLock;
int count = 0;
int fast_count = 0;
+ int max_backends = GetMaxBackends();
if (lockmethodid <= 0 || lockmethodid >= lengthof(LockMethods))
elog(ERROR, "unrecognized lock method: %d", lockmethodid);
@@ -2942,12 +2943,12 @@ GetLockConflicts(const LOCKTAG *locktag, LOCKMODE lockmode, int *countp)
vxids = (VirtualTransactionId *)
MemoryContextAlloc(TopMemoryContext,
sizeof(VirtualTransactionId) *
- (MaxBackends + max_prepared_xacts + 1));
+ (max_backends + max_prepared_xacts + 1));
}
else
vxids = (VirtualTransactionId *)
palloc0(sizeof(VirtualTransactionId) *
- (MaxBackends + max_prepared_xacts + 1));
+ (max_backends + max_prepared_xacts + 1));
/* Compute hash code and partition lock, and look up conflicting modes. */
hashcode = LockTagHashCode(locktag);
@@ -3104,7 +3105,7 @@ GetLockConflicts(const LOCKTAG *locktag, LOCKMODE lockmode, int *countp)
LWLockRelease(partitionLock);
- if (count > MaxBackends + max_prepared_xacts) /* should never happen */
+ if (count > max_backends + max_prepared_xacts) /* should never happen */
elog(PANIC, "too many conflicting locks found");
vxids[count].backendId = InvalidBackendId;
@@ -3651,11 +3652,12 @@ GetLockStatusData(void)
int els;
int el;
int i;
+ int max_backends = GetMaxBackends();
data = (LockData *) palloc(sizeof(LockData));
/* Guess how much space we'll need. */
- els = MaxBackends;
+ els = max_backends;
el = 0;
data->locks = (LockInstanceData *) palloc(sizeof(LockInstanceData) * els);
@@ -3689,7 +3691,7 @@ GetLockStatusData(void)
if (el >= els)
{
- els += MaxBackends;
+ els += max_backends;
data->locks = (LockInstanceData *)
repalloc(data->locks, sizeof(LockInstanceData) * els);
}
@@ -3721,7 +3723,7 @@ GetLockStatusData(void)
if (el >= els)
{
- els += MaxBackends;
+ els += max_backends;
data->locks = (LockInstanceData *)
repalloc(data->locks, sizeof(LockInstanceData) * els);
}
@@ -3850,7 +3852,7 @@ GetBlockerStatusData(int blocked_pid)
* for the procs[] array; the other two could need enlargement, though.)
*/
data->nprocs = data->nlocks = data->npids = 0;
- data->maxprocs = data->maxlocks = data->maxpids = MaxBackends;
+ data->maxprocs = data->maxlocks = data->maxpids = GetMaxBackends();
data->procs = (BlockedProcData *) palloc(sizeof(BlockedProcData) * data->maxprocs);
data->locks = (LockInstanceData *) palloc(sizeof(LockInstanceData) * data->maxlocks);
data->waiter_pids = (int *) palloc(sizeof(int) * data->maxpids);
@@ -3925,6 +3927,7 @@ GetSingleProcBlockerStatusData(PGPROC *blocked_proc, BlockedProcsData *data)
PGPROC *proc;
int queue_size;
int i;
+ int max_backends = GetMaxBackends();
/* Nothing to do if this proc is not blocked */
if (theLock == NULL)
@@ -3953,7 +3956,7 @@ GetSingleProcBlockerStatusData(PGPROC *blocked_proc, BlockedProcsData *data)
if (data->nlocks >= data->maxlocks)
{
- data->maxlocks += MaxBackends;
+ data->maxlocks += max_backends;
data->locks = (LockInstanceData *)
repalloc(data->locks, sizeof(LockInstanceData) * data->maxlocks);
}
@@ -3982,7 +3985,7 @@ GetSingleProcBlockerStatusData(PGPROC *blocked_proc, BlockedProcsData *data)
if (queue_size > data->maxpids - data->npids)
{
- data->maxpids = Max(data->maxpids + MaxBackends,
+ data->maxpids = Max(data->maxpids + max_backends,
data->npids + queue_size);
data->waiter_pids = (int *) repalloc(data->waiter_pids,
sizeof(int) * data->maxpids);
diff --git a/src/backend/storage/lmgr/predicate.c b/src/backend/storage/lmgr/predicate.c
index 25e7e4e37b..e337aad5b2 100644
--- a/src/backend/storage/lmgr/predicate.c
+++ b/src/backend/storage/lmgr/predicate.c
@@ -257,7 +257,7 @@
(&MainLWLockArray[PREDICATELOCK_MANAGER_LWLOCK_OFFSET + (i)].lock)
#define NPREDICATELOCKTARGETENTS() \
- mul_size(max_predicate_locks_per_xact, add_size(MaxBackends, max_prepared_xacts))
+ mul_size(max_predicate_locks_per_xact, add_size(GetMaxBackends(), max_prepared_xacts))
#define SxactIsOnFinishedList(sxact) (!SHMQueueIsDetached(&((sxact)->finishedLink)))
@@ -1222,7 +1222,7 @@ InitPredicateLocks(void)
* Compute size for serializable transaction hashtable. Note these
* calculations must agree with PredicateLockShmemSize!
*/
- max_table_size = (MaxBackends + max_prepared_xacts);
+ max_table_size = (GetMaxBackends() + max_prepared_xacts);
/*
* Allocate a list to hold information on transactions participating in
@@ -1375,7 +1375,7 @@ PredicateLockShmemSize(void)
size = add_size(size, size / 10);
/* transaction list */
- max_table_size = MaxBackends + max_prepared_xacts;
+ max_table_size = GetMaxBackends() + max_prepared_xacts;
max_table_size *= 10;
size = add_size(size, PredXactListDataSize);
size = add_size(size, mul_size((Size) max_table_size,
@@ -1907,7 +1907,7 @@ GetSerializableTransactionSnapshotInt(Snapshot snapshot,
{
++(PredXact->WritableSxactCount);
Assert(PredXact->WritableSxactCount <=
- (MaxBackends + max_prepared_xacts));
+ (GetMaxBackends() + max_prepared_xacts));
}
MySerializableXact = sxact;
@@ -5111,7 +5111,7 @@ predicatelock_twophase_recover(TransactionId xid, uint16 info,
{
++(PredXact->WritableSxactCount);
Assert(PredXact->WritableSxactCount <=
- (MaxBackends + max_prepared_xacts));
+ (GetMaxBackends() + max_prepared_xacts));
}
/*
diff --git a/src/backend/storage/lmgr/proc.c b/src/backend/storage/lmgr/proc.c
index e306b04738..37f032e7b9 100644
--- a/src/backend/storage/lmgr/proc.c
+++ b/src/backend/storage/lmgr/proc.c
@@ -103,7 +103,7 @@ ProcGlobalShmemSize(void)
{
Size size = 0;
Size TotalProcs =
- add_size(MaxBackends, add_size(NUM_AUXILIARY_PROCS, max_prepared_xacts));
+ add_size(GetMaxBackends(), add_size(NUM_AUXILIARY_PROCS, max_prepared_xacts));
/* ProcGlobal */
size = add_size(size, sizeof(PROC_HDR));
@@ -127,7 +127,7 @@ ProcGlobalSemas(void)
* We need a sema per backend (including autovacuum), plus one for each
* auxiliary process.
*/
- return MaxBackends + NUM_AUXILIARY_PROCS;
+ return GetMaxBackends() + NUM_AUXILIARY_PROCS;
}
/*
@@ -162,7 +162,8 @@ InitProcGlobal(void)
int i,
j;
bool found;
- uint32 TotalProcs = MaxBackends + NUM_AUXILIARY_PROCS + max_prepared_xacts;
+ int max_backends = GetMaxBackends();
+ uint32 TotalProcs = max_backends + NUM_AUXILIARY_PROCS + max_prepared_xacts;
/* Create the ProcGlobal shared structure */
ProcGlobal = (PROC_HDR *)
@@ -195,7 +196,7 @@ InitProcGlobal(void)
MemSet(procs, 0, TotalProcs * sizeof(PGPROC));
ProcGlobal->allProcs = procs;
/* XXX allProcCount isn't really all of them; it excludes prepared xacts */
- ProcGlobal->allProcCount = MaxBackends + NUM_AUXILIARY_PROCS;
+ ProcGlobal->allProcCount = max_backends + NUM_AUXILIARY_PROCS;
/*
* Allocate arrays mirroring PGPROC fields in a dense manner. See
@@ -221,7 +222,7 @@ InitProcGlobal(void)
* dummy PGPROCs don't need these though - they're never associated
* with a real process
*/
- if (i < MaxBackends + NUM_AUXILIARY_PROCS)
+ if (i < max_backends + NUM_AUXILIARY_PROCS)
{
procs[i].sem = PGSemaphoreCreate();
InitSharedLatch(&(procs[i].procLatch));
@@ -258,7 +259,7 @@ InitProcGlobal(void)
ProcGlobal->bgworkerFreeProcs = &procs[i];
procs[i].procgloballist = &ProcGlobal->bgworkerFreeProcs;
}
- else if (i < MaxBackends)
+ else if (i < max_backends)
{
/* PGPROC for walsender, add to walsenderFreeProcs list */
procs[i].links.next = (SHM_QUEUE *) ProcGlobal->walsenderFreeProcs;
@@ -286,8 +287,8 @@ InitProcGlobal(void)
* Save pointers to the blocks of PGPROC structures reserved for auxiliary
* processes and prepared transactions.
*/
- AuxiliaryProcs = &procs[MaxBackends];
- PreparedXactProcs = &procs[MaxBackends + NUM_AUXILIARY_PROCS];
+ AuxiliaryProcs = &procs[max_backends];
+ PreparedXactProcs = &procs[max_backends + NUM_AUXILIARY_PROCS];
/* Create ProcStructLock spinlock, too */
ProcStructLock = (slock_t *) ShmemAlloc(sizeof(slock_t));
diff --git a/src/backend/utils/activity/backend_status.c b/src/backend/utils/activity/backend_status.c
index c7ed1e6d7a..fc6dcd191b 100644
--- a/src/backend/utils/activity/backend_status.c
+++ b/src/backend/utils/activity/backend_status.c
@@ -35,7 +35,7 @@
* includes autovacuum workers and background workers as well.
* ----------
*/
-#define NumBackendStatSlots (MaxBackends + NUM_AUXPROCTYPES)
+#define NumBackendStatSlots (GetMaxBackends() + NUM_AUXPROCTYPES)
/* ----------
@@ -84,27 +84,28 @@ Size
BackendStatusShmemSize(void)
{
Size size;
+ int numBackendStatSlots = NumBackendStatSlots;
/* BackendStatusArray: */
- size = mul_size(sizeof(PgBackendStatus), NumBackendStatSlots);
+ size = mul_size(sizeof(PgBackendStatus), numBackendStatSlots);
/* BackendAppnameBuffer: */
size = add_size(size,
- mul_size(NAMEDATALEN, NumBackendStatSlots));
+ mul_size(NAMEDATALEN, numBackendStatSlots));
/* BackendClientHostnameBuffer: */
size = add_size(size,
- mul_size(NAMEDATALEN, NumBackendStatSlots));
+ mul_size(NAMEDATALEN, numBackendStatSlots));
/* BackendActivityBuffer: */
size = add_size(size,
- mul_size(pgstat_track_activity_query_size, NumBackendStatSlots));
+ mul_size(pgstat_track_activity_query_size, numBackendStatSlots));
#ifdef USE_SSL
/* BackendSslStatusBuffer: */
size = add_size(size,
- mul_size(sizeof(PgBackendSSLStatus), NumBackendStatSlots));
+ mul_size(sizeof(PgBackendSSLStatus), numBackendStatSlots));
#endif
#ifdef ENABLE_GSS
/* BackendGssStatusBuffer: */
size = add_size(size,
- mul_size(sizeof(PgBackendGSSStatus), NumBackendStatSlots));
+ mul_size(sizeof(PgBackendGSSStatus), numBackendStatSlots));
#endif
return size;
}
@@ -120,9 +121,10 @@ CreateSharedBackendStatus(void)
bool found;
int i;
char *buffer;
+ int numBackendStatSlots = NumBackendStatSlots;
/* Create or attach to the shared array */
- size = mul_size(sizeof(PgBackendStatus), NumBackendStatSlots);
+ size = mul_size(sizeof(PgBackendStatus), numBackendStatSlots);
BackendStatusArray = (PgBackendStatus *)
ShmemInitStruct("Backend Status Array", size, &found);
@@ -135,7 +137,7 @@ CreateSharedBackendStatus(void)
}
/* Create or attach to the shared appname buffer */
- size = mul_size(NAMEDATALEN, NumBackendStatSlots);
+ size = mul_size(NAMEDATALEN, numBackendStatSlots);
BackendAppnameBuffer = (char *)
ShmemInitStruct("Backend Application Name Buffer", size, &found);
@@ -145,7 +147,7 @@ CreateSharedBackendStatus(void)
/* Initialize st_appname pointers. */
buffer = BackendAppnameBuffer;
- for (i = 0; i < NumBackendStatSlots; i++)
+ for (i = 0; i < numBackendStatSlots; i++)
{
BackendStatusArray[i].st_appname = buffer;
buffer += NAMEDATALEN;
@@ -153,7 +155,7 @@ CreateSharedBackendStatus(void)
}
/* Create or attach to the shared client hostname buffer */
- size = mul_size(NAMEDATALEN, NumBackendStatSlots);
+ size = mul_size(NAMEDATALEN, numBackendStatSlots);
BackendClientHostnameBuffer = (char *)
ShmemInitStruct("Backend Client Host Name Buffer", size, &found);
@@ -163,7 +165,7 @@ CreateSharedBackendStatus(void)
/* Initialize st_clienthostname pointers. */
buffer = BackendClientHostnameBuffer;
- for (i = 0; i < NumBackendStatSlots; i++)
+ for (i = 0; i < numBackendStatSlots; i++)
{
BackendStatusArray[i].st_clienthostname = buffer;
buffer += NAMEDATALEN;
@@ -172,7 +174,7 @@ CreateSharedBackendStatus(void)
/* Create or attach to the shared activity buffer */
BackendActivityBufferSize = mul_size(pgstat_track_activity_query_size,
- NumBackendStatSlots);
+ numBackendStatSlots);
BackendActivityBuffer = (char *)
ShmemInitStruct("Backend Activity Buffer",
BackendActivityBufferSize,
@@ -184,7 +186,7 @@ CreateSharedBackendStatus(void)
/* Initialize st_activity pointers. */
buffer = BackendActivityBuffer;
- for (i = 0; i < NumBackendStatSlots; i++)
+ for (i = 0; i < numBackendStatSlots; i++)
{
BackendStatusArray[i].st_activity_raw = buffer;
buffer += pgstat_track_activity_query_size;
@@ -193,7 +195,7 @@ CreateSharedBackendStatus(void)
#ifdef USE_SSL
/* Create or attach to the shared SSL status buffer */
- size = mul_size(sizeof(PgBackendSSLStatus), NumBackendStatSlots);
+ size = mul_size(sizeof(PgBackendSSLStatus), numBackendStatSlots);
BackendSslStatusBuffer = (PgBackendSSLStatus *)
ShmemInitStruct("Backend SSL Status Buffer", size, &found);
@@ -205,7 +207,7 @@ CreateSharedBackendStatus(void)
/* Initialize st_sslstatus pointers. */
ptr = BackendSslStatusBuffer;
- for (i = 0; i < NumBackendStatSlots; i++)
+ for (i = 0; i < numBackendStatSlots; i++)
{
BackendStatusArray[i].st_sslstatus = ptr;
ptr++;
@@ -215,7 +217,7 @@ CreateSharedBackendStatus(void)
#ifdef ENABLE_GSS
/* Create or attach to the shared GSSAPI status buffer */
- size = mul_size(sizeof(PgBackendGSSStatus), NumBackendStatSlots);
+ size = mul_size(sizeof(PgBackendGSSStatus), numBackendStatSlots);
BackendGssStatusBuffer = (PgBackendGSSStatus *)
ShmemInitStruct("Backend GSS Status Buffer", size, &found);
@@ -227,7 +229,7 @@ CreateSharedBackendStatus(void)
/* Initialize st_gssstatus pointers. */
ptr = BackendGssStatusBuffer;
- for (i = 0; i < NumBackendStatSlots; i++)
+ for (i = 0; i < numBackendStatSlots; i++)
{
BackendStatusArray[i].st_gssstatus = ptr;
ptr++;
@@ -251,7 +253,7 @@ pgstat_beinit(void)
/* Initialize MyBEEntry */
if (MyBackendId != InvalidBackendId)
{
- Assert(MyBackendId >= 1 && MyBackendId <= MaxBackends);
+ Assert(MyBackendId >= 1 && MyBackendId <= GetMaxBackends());
MyBEEntry = &BackendStatusArray[MyBackendId - 1];
}
else
@@ -267,7 +269,7 @@ pgstat_beinit(void)
* MaxBackends + AuxBackendType + 1 as the index of the slot for an
* auxiliary process.
*/
- MyBEEntry = &BackendStatusArray[MaxBackends + MyAuxProcType];
+ MyBEEntry = &BackendStatusArray[GetMaxBackends() + MyAuxProcType];
}
/* Set up a process-exit hook to clean up */
@@ -739,6 +741,7 @@ pgstat_read_current_status(void)
PgBackendGSSStatus *localgssstatus;
#endif
int i;
+ int numBackendStatSlots = NumBackendStatSlots;
if (localBackendStatusTable)
return; /* already done */
@@ -755,32 +758,32 @@ pgstat_read_current_status(void)
*/
localtable = (LocalPgBackendStatus *)
MemoryContextAlloc(backendStatusSnapContext,
- sizeof(LocalPgBackendStatus) * NumBackendStatSlots);
+ sizeof(LocalPgBackendStatus) * numBackendStatSlots);
localappname = (char *)
MemoryContextAlloc(backendStatusSnapContext,
- NAMEDATALEN * NumBackendStatSlots);
+ NAMEDATALEN * numBackendStatSlots);
localclienthostname = (char *)
MemoryContextAlloc(backendStatusSnapContext,
- NAMEDATALEN * NumBackendStatSlots);
+ NAMEDATALEN * numBackendStatSlots);
localactivity = (char *)
MemoryContextAllocHuge(backendStatusSnapContext,
- pgstat_track_activity_query_size * NumBackendStatSlots);
+ pgstat_track_activity_query_size * numBackendStatSlots);
#ifdef USE_SSL
localsslstatus = (PgBackendSSLStatus *)
MemoryContextAlloc(backendStatusSnapContext,
- sizeof(PgBackendSSLStatus) * NumBackendStatSlots);
+ sizeof(PgBackendSSLStatus) * numBackendStatSlots);
#endif
#ifdef ENABLE_GSS
localgssstatus = (PgBackendGSSStatus *)
MemoryContextAlloc(backendStatusSnapContext,
- sizeof(PgBackendGSSStatus) * NumBackendStatSlots);
+ sizeof(PgBackendGSSStatus) * numBackendStatSlots);
#endif
localNumBackends = 0;
beentry = BackendStatusArray;
localentry = localtable;
- for (i = 1; i <= NumBackendStatSlots; i++)
+ for (i = 1; i <= numBackendStatSlots; i++)
{
/*
* Follow the protocol of retrying if st_changecount changes while we
@@ -893,9 +896,10 @@ pgstat_get_backend_current_activity(int pid, bool checkUser)
{
PgBackendStatus *beentry;
int i;
+ int max_backends = GetMaxBackends();
beentry = BackendStatusArray;
- for (i = 1; i <= MaxBackends; i++)
+ for (i = 1; i <= max_backends; i++)
{
/*
* Although we expect the target backend's entry to be stable, that
@@ -971,6 +975,7 @@ pgstat_get_crashed_backend_activity(int pid, char *buffer, int buflen)
{
volatile PgBackendStatus *beentry;
int i;
+ int max_backends = GetMaxBackends();
beentry = BackendStatusArray;
@@ -981,7 +986,7 @@ pgstat_get_crashed_backend_activity(int pid, char *buffer, int buflen)
if (beentry == NULL || BackendActivityBuffer == NULL)
return NULL;
- for (i = 1; i <= MaxBackends; i++)
+ for (i = 1; i <= max_backends; i++)
{
if (beentry->st_procpid == pid)
{
diff --git a/src/backend/utils/adt/lockfuncs.c b/src/backend/utils/adt/lockfuncs.c
index 023a004ac8..944cd6df03 100644
--- a/src/backend/utils/adt/lockfuncs.c
+++ b/src/backend/utils/adt/lockfuncs.c
@@ -559,13 +559,14 @@ pg_safe_snapshot_blocking_pids(PG_FUNCTION_ARGS)
int *blockers;
int num_blockers;
Datum *blocker_datums;
+ int max_backends = GetMaxBackends();
/* A buffer big enough for any possible blocker list without truncation */
- blockers = (int *) palloc(MaxBackends * sizeof(int));
+ blockers = (int *) palloc(max_backends * sizeof(int));
/* Collect a snapshot of processes waited for by GetSafeSnapshot */
num_blockers =
- GetSafeSnapshotBlockingPids(blocked_pid, blockers, MaxBackends);
+ GetSafeSnapshotBlockingPids(blocked_pid, blockers, max_backends);
/* Convert int array to Datum array */
if (num_blockers > 0)
diff --git a/src/backend/utils/init/postinit.c b/src/backend/utils/init/postinit.c
index 5b9ed2f6f5..ca53912f15 100644
--- a/src/backend/utils/init/postinit.c
+++ b/src/backend/utils/init/postinit.c
@@ -25,6 +25,7 @@
#include "access/session.h"
#include "access/sysattr.h"
#include "access/tableam.h"
+#include "access/twophase.h"
#include "access/xact.h"
#include "access/xlog.h"
#include "access/xloginsert.h"
@@ -65,6 +66,9 @@
#include "utils/syscache.h"
#include "utils/timeout.h"
+static int MaxBackends = 0;
+static int MaxBackendsInitialized = false;
+
static HeapTuple GetDatabaseTuple(const char *dbname);
static HeapTuple GetDatabaseTupleByOid(Oid dboid);
static void PerformAuthentication(Port *port);
@@ -495,15 +499,49 @@ pg_split_opts(char **argv, int *argcp, const char *optstr)
void
InitializeMaxBackends(void)
{
- Assert(MaxBackends == 0);
-
/* the extra unit accounts for the autovacuum launcher */
- MaxBackends = MaxConnections + autovacuum_max_workers + 1 +
- max_worker_processes + max_wal_senders;
+ SetMaxBackends(MaxConnections + autovacuum_max_workers + 1 +
+ max_worker_processes + max_wal_senders);
+}
+
+/*
+ * Safely retrieve the value of MaxBackends.
+ *
+ * Previously, MaxBackends was externally visible, but it was often used before
+ * it was initialized (e.g., in preloaded libraries' _PG_init() functions).
+ * Unfortunately, we cannot initialize MaxBackends before processing
+ * shared_preload_libraries because the libraries sometimes alter GUCs that are
+ * used to calculate its value. Instead, we provide this function for accessing
+ * MaxBackends, and we ERROR if someone calls it before it is initialized.
+ */
+int
+GetMaxBackends(void)
+{
+ if (unlikely(!MaxBackendsInitialized))
+ elog(ERROR, "MaxBackends not yet initialized");
+
+ return MaxBackends;
+}
+
+/*
+ * Set the value of MaxBackends.
+ *
+ * This should only be used by InitializeMaxBackends() and
+ * restore_backend_variables(). If MaxBackends is already initialized or the
+ * specified value is greater than the maximum, this will ERROR.
+ */
+void
+SetMaxBackends(int max_backends)
+{
+ if (MaxBackendsInitialized)
+ elog(ERROR, "MaxBackends already initialized");
/* internal error because the values were all checked previously */
- if (MaxBackends > MAX_BACKENDS)
+ if (max_backends > MAX_BACKENDS)
elog(ERROR, "too many backends configured");
+
+ MaxBackends = max_backends;
+ MaxBackendsInitialized = true;
}
/*
@@ -609,7 +647,7 @@ InitPostgres(const char *in_dbname, Oid dboid, const char *username,
SharedInvalBackendInit(false);
- if (MyBackendId > MaxBackends || MyBackendId <= 0)
+ if (MyBackendId > GetMaxBackends() || MyBackendId <= 0)
elog(FATAL, "bad backend ID: %d", MyBackendId);
/* Now that we have a BackendId, we can participate in ProcSignal */
diff --git a/src/include/miscadmin.h b/src/include/miscadmin.h
index 02276d3edd..0abc3ad540 100644
--- a/src/include/miscadmin.h
+++ b/src/include/miscadmin.h
@@ -172,7 +172,6 @@ extern PGDLLIMPORT char *DataDir;
extern PGDLLIMPORT int data_directory_mode;
extern PGDLLIMPORT int NBuffers;
-extern PGDLLIMPORT int MaxBackends;
extern PGDLLIMPORT int MaxConnections;
extern PGDLLIMPORT int max_worker_processes;
extern PGDLLIMPORT int max_parallel_workers;
@@ -457,6 +456,8 @@ extern AuxProcType MyAuxProcType;
/* in utils/init/postinit.c */
extern void pg_split_opts(char **argv, int *argcp, const char *optstr);
extern void InitializeMaxBackends(void);
+extern int GetMaxBackends(void);
+extern void SetMaxBackends(int max_backends);
extern void InitPostgres(const char *in_dbname, Oid dboid, const char *username,
Oid useroid, char *out_dbname, bool override_allow_connections);
extern void BaseInit(void);
--
2.25.1