v1-0001-Disallow-external-access-to-MaxBackends.patch
application/octet-stream
Filename: v1-0001-Disallow-external-access-to-MaxBackends.patch
Type: application/octet-stream
Part: 0
Patch
Format: format-patch
Series: patch v1-0001
Subject: Disallow external access to MaxBackends.
| File | + | − |
|---|---|---|
| src/backend/access/nbtree/nbtutils.c | 2 | 2 |
| src/backend/access/transam/multixact.c | 1 | 1 |
| src/backend/access/transam/twophase.c | 1 | 1 |
| src/backend/bootstrap/bootstrap.c | 1 | 1 |
| src/backend/commands/async.c | 5 | 5 |
| src/backend/libpq/pqcomm.c | 1 | 1 |
| src/backend/postmaster/postmaster.c | 6 | 8 |
| src/backend/storage/ipc/dsm.c | 1 | 1 |
| src/backend/storage/ipc/procarray.c | 1 | 1 |
| src/backend/storage/ipc/procsignal.c | 1 | 1 |
| src/backend/storage/ipc/sinvaladt.c | 2 | 2 |
| src/backend/storage/lmgr/deadlock.c | 16 | 15 |
| src/backend/storage/lmgr/lock.c | 10 | 10 |
| src/backend/storage/lmgr/predicate.c | 5 | 5 |
| src/backend/storage/lmgr/proc.c | 8 | 9 |
| src/backend/utils/activity/backend_status.c | 5 | 5 |
| src/backend/utils/adt/lockfuncs.c | 2 | 2 |
| src/backend/utils/init/postinit.c | 39 | 10 |
| src/include/miscadmin.h | 11 | 1 |
From 67bc167c81cef9b582e37f81c59c4ebd0cbb3a8f Mon Sep 17 00:00:00 2001
From: Nathan Bossart <bossartn@amazon.com>
Date: Tue, 3 Aug 2021 23:05:55 +0000
Subject: [PATCH v1 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(). GetMaxBackends() also accepts a
couple of flags to easily include commonly added values such as
max_prepared_transactions.
Separately, adjust the comments about needing to register
background workers before initializing MaxBackends. Since
6bc8ef0b, InitializeMaxBackends() has used max_worker_processes
instead of tallying up the number of registered background workers,
so background worker registration is no longer a prerequisite. The
ordering of this logic is still useful for allowing libraries to
adjust GUCs, so the comments have been updated to mention that use-
case.
---
src/backend/access/nbtree/nbtutils.c | 4 +--
src/backend/access/transam/multixact.c | 2 +-
src/backend/access/transam/twophase.c | 2 +-
src/backend/bootstrap/bootstrap.c | 2 +-
src/backend/commands/async.c | 10 +++---
src/backend/libpq/pqcomm.c | 2 +-
src/backend/postmaster/postmaster.c | 14 ++++-----
src/backend/storage/ipc/dsm.c | 2 +-
src/backend/storage/ipc/procarray.c | 2 +-
src/backend/storage/ipc/procsignal.c | 2 +-
src/backend/storage/ipc/sinvaladt.c | 4 +--
src/backend/storage/lmgr/deadlock.c | 31 +++++++++---------
src/backend/storage/lmgr/lock.c | 20 ++++++------
src/backend/storage/lmgr/predicate.c | 10 +++---
src/backend/storage/lmgr/proc.c | 17 +++++-----
src/backend/utils/activity/backend_status.c | 10 +++---
src/backend/utils/adt/lockfuncs.c | 4 +--
src/backend/utils/init/postinit.c | 49 +++++++++++++++++++++++------
src/include/miscadmin.h | 12 ++++++-
19 files changed, 118 insertions(+), 81 deletions(-)
diff --git a/src/backend/access/nbtree/nbtutils.c b/src/backend/access/nbtree/nbtutils.c
index d524310723..578d4531a2 100644
--- a/src/backend/access/nbtree/nbtutils.c
+++ b/src/backend/access/nbtree/nbtutils.c
@@ -2065,7 +2065,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(0), sizeof(BTOneVacInfo)));
return size;
}
@@ -2094,7 +2094,7 @@ BTreeShmemInit(void)
btvacinfo->cycle_ctr = (BTCycleId) time(NULL);
btvacinfo->num_vacuums = 0;
- btvacinfo->max_vacuums = MaxBackends;
+ btvacinfo->max_vacuums = GetMaxBackends(0);
}
else
Assert(found);
diff --git a/src/backend/access/transam/multixact.c b/src/backend/access/transam/multixact.c
index e6c70ed0bc..7e9728bf88 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(GMB_MAX_PREPARED_XACTS))
/* Pointers to the state data in shared memory */
static MultiXactStateData *MultiXactState;
diff --git a/src/backend/access/transam/twophase.c b/src/backend/access/transam/twophase.c
index 6d3efb49a4..1ba84983f2 100644
--- a/src/backend/access/transam/twophase.c
+++ b/src/backend/access/transam/twophase.c
@@ -293,7 +293,7 @@ TwoPhaseShmemInit(void)
* prepared transaction. Currently multixact.c uses that
* technique.
*/
- gxacts[i].dummyBackendId = MaxBackends + 1 + i;
+ gxacts[i].dummyBackendId = GetMaxBackends(0) + 1 + i;
}
}
else
diff --git a/src/backend/bootstrap/bootstrap.c b/src/backend/bootstrap/bootstrap.c
index 67cd5ac6e9..ceb1983544 100644
--- a/src/backend/bootstrap/bootstrap.c
+++ b/src/backend/bootstrap/bootstrap.c
@@ -395,7 +395,7 @@ AuxiliaryProcessMain(int argc, char *argv[])
* This will need rethinking if we ever want more than one of a
* particular auxiliary process type.
*/
- ProcSignalInit(MaxBackends + MyAuxProcType + 1);
+ ProcSignalInit(GetMaxBackends(0) + MyAuxProcType + 1);
/* finish setting up bufmgr.c */
InitBufferPoolBackend();
diff --git a/src/backend/commands/async.c b/src/backend/commands/async.c
index 4b16fb5682..29c50595c2 100644
--- a/src/backend/commands/async.c
+++ b/src/backend/commands/async.c
@@ -511,7 +511,7 @@ AsyncShmemSize(void)
Size size;
/* This had better match AsyncShmemInit */
- size = mul_size(MaxBackends + 1, sizeof(QueueBackendStatus));
+ size = mul_size(GetMaxBackends(0) + 1, sizeof(QueueBackendStatus));
size = add_size(size, offsetof(AsyncQueueControl, backend));
size = add_size(size, SimpleLruShmemSize(NUM_NOTIFY_BUFFERS, 0));
@@ -534,7 +534,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(GetMaxBackends(0) + 1, sizeof(QueueBackendStatus));
size = add_size(size, offsetof(AsyncQueueControl, backend));
asyncQueueControl = (AsyncQueueControl *)
@@ -549,7 +549,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 <= GetMaxBackends(0); i++)
{
QUEUE_BACKEND_PID(i) = InvalidPid;
QUEUE_BACKEND_DBOID(i) = InvalidOid;
@@ -1685,8 +1685,8 @@ SignalBackends(void)
* preallocate the arrays? But in practice this is only run in trivial
* transactions, so there should surely be space available.
*/
- pids = (int32 *) palloc(MaxBackends * sizeof(int32));
- ids = (BackendId *) palloc(MaxBackends * sizeof(BackendId));
+ pids = (int32 *) palloc(GetMaxBackends(0) * sizeof(int32));
+ ids = (BackendId *) palloc(GetMaxBackends(0) * sizeof(BackendId));
count = 0;
LWLockAcquire(NotifyQueueLock, LW_EXCLUSIVE);
diff --git a/src/backend/libpq/pqcomm.c b/src/backend/libpq/pqcomm.c
index 89a5f901aa..4d74f9a3f5 100644
--- a/src/backend/libpq/pqcomm.c
+++ b/src/backend/libpq/pqcomm.c
@@ -556,7 +556,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 = GetMaxBackends(0) * 2;
if (maxconn > PG_SOMAXCONN)
maxconn = PG_SOMAXCONN;
diff --git a/src/backend/postmaster/postmaster.c b/src/backend/postmaster/postmaster.c
index 00d051d520..bf05b15455 100644
--- a/src/backend/postmaster/postmaster.c
+++ b/src/backend/postmaster/postmaster.c
@@ -990,10 +990,8 @@ PostmasterMain(int argc, char *argv[])
LocalProcessControlFile(false);
/*
- * Register the apply launcher. Since it registers a background worker,
- * it needs to be called before InitializeMaxBackends(), and it's probably
- * a good idea to call it before any modules had chance to take the
- * background worker slots.
+ * Register the apply launcher. It's probably a good idea to call it before
+ * any modules had a chance to take the background worker slots.
*/
ApplyLauncherRegister();
@@ -1014,8 +1012,8 @@ PostmasterMain(int argc, char *argv[])
#endif
/*
- * Now that loadable modules have had their chance to register background
- * workers, calculate MaxBackends.
+ * Now that loadable modules have had their chance to alter any GUCs,
+ * calculate MaxBackends.
*/
InitializeMaxBackends();
@@ -6184,7 +6182,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(0);
#ifdef WIN32
param->PostmasterHandle = PostmasterHandle;
@@ -6418,7 +6416,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 b461a5f7e9..bb279bb8d1 100644
--- a/src/backend/storage/ipc/dsm.c
+++ b/src/backend/storage/ipc/dsm.c
@@ -165,7 +165,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(0);
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 c7816fcfb3..9afd0209c8 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(GMB_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 defb75aa26..86b7c39782 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(0) + NUM_AUXPROCTYPES)
/* Check whether the relevant type bit is set in the flags. */
#define BARRIER_SHOULD_CHECK(flags, type) \
diff --git a/src/backend/storage/ipc/sinvaladt.c b/src/backend/storage/ipc/sinvaladt.c
index 946bd8e3cb..2e85a99f68 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(0)));
return size;
}
@@ -231,7 +231,7 @@ CreateSharedInvalidationState(void)
shmInvalBuffer->maxMsgNum = 0;
shmInvalBuffer->nextThreshold = CLEANUP_MIN;
shmInvalBuffer->lastBackend = 0;
- shmInvalBuffer->maxBackends = MaxBackends;
+ shmInvalBuffer->maxBackends = GetMaxBackends(0);
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 67733c0d1a..6ffc481009 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(0);
/* 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(0) <= 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(0) > 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(0));
nDeadlockDetails = depth;
return true;
@@ -500,7 +501,7 @@ FindLockCycleRecurse(PGPROC *checkProc,
}
}
/* Mark proc as seen */
- Assert(nVisitedProcs < MaxBackends);
+ Assert(nVisitedProcs < GetMaxBackends(0));
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(0));
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(0));
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(0));
/*
* 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 364654e106..581bbc29d5 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, GetMaxBackends(GMB_MAX_PREPARED_XACTS))
/*
@@ -2938,12 +2938,12 @@ GetLockConflicts(const LOCKTAG *locktag, LOCKMODE lockmode, int *countp)
vxids = (VirtualTransactionId *)
MemoryContextAlloc(TopMemoryContext,
sizeof(VirtualTransactionId) *
- (MaxBackends + max_prepared_xacts + 1));
+ (GetMaxBackends(GMB_MAX_PREPARED_XACTS) + 1));
}
else
vxids = (VirtualTransactionId *)
palloc0(sizeof(VirtualTransactionId) *
- (MaxBackends + max_prepared_xacts + 1));
+ (GetMaxBackends(GMB_MAX_PREPARED_XACTS) + 1));
/* Compute hash code and partition lock, and look up conflicting modes. */
hashcode = LockTagHashCode(locktag);
@@ -3100,7 +3100,7 @@ GetLockConflicts(const LOCKTAG *locktag, LOCKMODE lockmode, int *countp)
LWLockRelease(partitionLock);
- if (count > MaxBackends + max_prepared_xacts) /* should never happen */
+ if (count > GetMaxBackends(GMB_MAX_PREPARED_XACTS)) /* should never happen */
elog(PANIC, "too many conflicting locks found");
vxids[count].backendId = InvalidBackendId;
@@ -3651,7 +3651,7 @@ GetLockStatusData(void)
data = (LockData *) palloc(sizeof(LockData));
/* Guess how much space we'll need. */
- els = MaxBackends;
+ els = GetMaxBackends(0);
el = 0;
data->locks = (LockInstanceData *) palloc(sizeof(LockInstanceData) * els);
@@ -3685,7 +3685,7 @@ GetLockStatusData(void)
if (el >= els)
{
- els += MaxBackends;
+ els += GetMaxBackends(0);
data->locks = (LockInstanceData *)
repalloc(data->locks, sizeof(LockInstanceData) * els);
}
@@ -3717,7 +3717,7 @@ GetLockStatusData(void)
if (el >= els)
{
- els += MaxBackends;
+ els += GetMaxBackends(0);
data->locks = (LockInstanceData *)
repalloc(data->locks, sizeof(LockInstanceData) * els);
}
@@ -3846,7 +3846,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(0);
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);
@@ -3949,7 +3949,7 @@ GetSingleProcBlockerStatusData(PGPROC *blocked_proc, BlockedProcsData *data)
if (data->nlocks >= data->maxlocks)
{
- data->maxlocks += MaxBackends;
+ data->maxlocks += GetMaxBackends(0);
data->locks = (LockInstanceData *)
repalloc(data->locks, sizeof(LockInstanceData) * data->maxlocks);
}
@@ -3978,7 +3978,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 + GetMaxBackends(0),
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 56267bdc3c..d6199aa82d 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, GetMaxBackends(GMB_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(GMB_MAX_PREPARED_XACTS));
/*
* Allocate a list to hold information on transactions participating in
@@ -1374,7 +1374,7 @@ PredicateLockShmemSize(void)
size = add_size(size, size / 10);
/* transaction list */
- max_table_size = MaxBackends + max_prepared_xacts;
+ max_table_size = GetMaxBackends(GMB_MAX_PREPARED_XACTS);
max_table_size *= 10;
size = add_size(size, PredXactListDataSize);
size = add_size(size, mul_size((Size) max_table_size,
@@ -1905,7 +1905,7 @@ GetSerializableTransactionSnapshotInt(Snapshot snapshot,
{
++(PredXact->WritableSxactCount);
Assert(PredXact->WritableSxactCount <=
- (MaxBackends + max_prepared_xacts));
+ (GetMaxBackends(GMB_MAX_PREPARED_XACTS)));
}
MySerializableXact = sxact;
@@ -5107,7 +5107,7 @@ predicatelock_twophase_recover(TransactionId xid, uint16 info,
{
++(PredXact->WritableSxactCount);
Assert(PredXact->WritableSxactCount <=
- (MaxBackends + max_prepared_xacts));
+ (GetMaxBackends(GMB_MAX_PREPARED_XACTS)));
}
/*
diff --git a/src/backend/storage/lmgr/proc.c b/src/backend/storage/lmgr/proc.c
index b7d9da0aa9..9600afec16 100644
--- a/src/backend/storage/lmgr/proc.c
+++ b/src/backend/storage/lmgr/proc.c
@@ -102,8 +102,7 @@ Size
ProcGlobalShmemSize(void)
{
Size size = 0;
- Size TotalProcs =
- add_size(MaxBackends, add_size(NUM_AUXILIARY_PROCS, max_prepared_xacts));
+ Size TotalProcs = GetMaxBackends(GMB_NUM_AUXILIARY_PROCS | GMB_MAX_PREPARED_XACTS);
/* ProcGlobal */
size = add_size(size, sizeof(PROC_HDR));
@@ -127,7 +126,7 @@ ProcGlobalSemas(void)
* We need a sema per backend (including autovacuum), plus one for each
* auxiliary process.
*/
- return MaxBackends + NUM_AUXILIARY_PROCS;
+ return GetMaxBackends(GMB_NUM_AUXILIARY_PROCS);
}
/*
@@ -162,7 +161,7 @@ InitProcGlobal(void)
int i,
j;
bool found;
- uint32 TotalProcs = MaxBackends + NUM_AUXILIARY_PROCS + max_prepared_xacts;
+ uint32 TotalProcs = GetMaxBackends(GMB_NUM_AUXILIARY_PROCS | GMB_MAX_PREPARED_XACTS);
/* Create the ProcGlobal shared structure */
ProcGlobal = (PROC_HDR *)
@@ -197,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 = GetMaxBackends(GMB_NUM_AUXILIARY_PROCS);
/*
* Allocate arrays mirroring PGPROC fields in a dense manner. See
@@ -223,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 < GetMaxBackends(GMB_NUM_AUXILIARY_PROCS))
{
procs[i].sem = PGSemaphoreCreate();
InitSharedLatch(&(procs[i].procLatch));
@@ -260,7 +259,7 @@ InitProcGlobal(void)
ProcGlobal->bgworkerFreeProcs = &procs[i];
procs[i].procgloballist = &ProcGlobal->bgworkerFreeProcs;
}
- else if (i < MaxBackends)
+ else if (i < GetMaxBackends(0))
{
/* PGPROC for walsender, add to walsenderFreeProcs list */
procs[i].links.next = (SHM_QUEUE *) ProcGlobal->walsenderFreeProcs;
@@ -288,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[GetMaxBackends(0)];
+ PreparedXactProcs = &procs[GetMaxBackends(GMB_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 2901f9f5a9..4ff834bbc5 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(0) + NUM_AUXPROCTYPES)
/* ----------
@@ -251,7 +251,7 @@ pgstat_beinit(void)
/* Initialize MyBEEntry */
if (MyBackendId != InvalidBackendId)
{
- Assert(MyBackendId >= 1 && MyBackendId <= MaxBackends);
+ Assert(MyBackendId >= 1 && MyBackendId <= GetMaxBackends(0));
MyBEEntry = &BackendStatusArray[MyBackendId - 1];
}
else
@@ -267,7 +267,7 @@ pgstat_beinit(void)
* MaxBackends + AuxBackendType + 1 as the index of the slot for an
* auxiliary process.
*/
- MyBEEntry = &BackendStatusArray[MaxBackends + MyAuxProcType];
+ MyBEEntry = &BackendStatusArray[GetMaxBackends(0) + MyAuxProcType];
}
/* Set up a process-exit hook to clean up */
@@ -892,7 +892,7 @@ pgstat_get_backend_current_activity(int pid, bool checkUser)
int i;
beentry = BackendStatusArray;
- for (i = 1; i <= MaxBackends; i++)
+ for (i = 1; i <= GetMaxBackends(0); i++)
{
/*
* Although we expect the target backend's entry to be stable, that
@@ -978,7 +978,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 <= GetMaxBackends(0); i++)
{
if (beentry->st_procpid == pid)
{
diff --git a/src/backend/utils/adt/lockfuncs.c b/src/backend/utils/adt/lockfuncs.c
index 5dc0a5882c..d262965800 100644
--- a/src/backend/utils/adt/lockfuncs.c
+++ b/src/backend/utils/adt/lockfuncs.c
@@ -561,11 +561,11 @@ pg_safe_snapshot_blocking_pids(PG_FUNCTION_ARGS)
Datum *blocker_datums;
/* A buffer big enough for any possible blocker list without truncation */
- blockers = (int *) palloc(MaxBackends * sizeof(int));
+ blockers = (int *) palloc(GetMaxBackends(0) * sizeof(int));
/* Collect a snapshot of processes waited for by GetSafeSnapshot */
num_blockers =
- GetSafeSnapshotBlockingPids(blocked_pid, blockers, MaxBackends);
+ GetSafeSnapshotBlockingPids(blocked_pid, blockers, GetMaxBackends(0));
/* 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 51d1bbef30..bf02bc0283 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 "catalog/catalog.h"
@@ -63,6 +64,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);
@@ -502,9 +506,8 @@ pg_split_opts(char **argv, int *argcp, const char *optstr)
/*
* Initialize MaxBackends value from config options.
*
- * This must be called after modules have had the chance to register background
- * workers in shared_preload_libraries, and before shared memory size is
- * determined.
+ * This must be called after modules have had the change to alter GUCs in
+ * shared_preload_libraries, and before shared memory size is determined.
*
* Note that in EXEC_BACKEND environment, the value is passed down from
* postmaster to subprocesses via BackendParameters in SubPostmasterMain; only
@@ -514,15 +517,41 @@ 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);
+}
+
+int
+GetMaxBackends(uint32 flags)
+{
+ int ret;
+
+ if (!MaxBackendsInitialized)
+ elog(ERROR, "MaxBackends not yet initialized");
+
+ ret = MaxBackends;
+
+ if (flags & GMB_MAX_PREPARED_XACTS)
+ ret += max_prepared_xacts;
- /* internal error because the values were all checked previously */
- if (MaxBackends > MAX_BACKENDS)
+ if (flags & GMB_NUM_AUXILIARY_PROCS)
+ ret += NUM_AUXILIARY_PROCS;
+
+ return ret;
+}
+
+void
+SetMaxBackends(int max_backends)
+{
+ if (MaxBackendsInitialized)
+ elog(ERROR, "MaxBackends already initialized");
+
+ if (max_backends > MAX_BACKENDS)
elog(ERROR, "too many backends configured");
+
+ MaxBackends = max_backends;
+ MaxBackendsInitialized = true;
}
/*
@@ -603,7 +632,7 @@ InitPostgres(const char *in_dbname, Oid dboid, const char *username,
SharedInvalBackendInit(false);
- if (MyBackendId > MaxBackends || MyBackendId <= 0)
+ if (MyBackendId > GetMaxBackends(0) || 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 68d840d699..67902d2541 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;
@@ -455,9 +454,20 @@ extern AuxProcType MyAuxProcType;
* POSTGRES initialization and cleanup definitions. *
*****************************************************************************/
+/*
+ * Option flag bits for GetMaxBackends().
+ */
+typedef enum GMBOption
+{
+ GMB_MAX_PREPARED_XACTS = 1 << 0, /* include max_prepared_xacts */
+ GMB_NUM_AUXILIARY_PROCS = 1 << 1 /* include NUM_AUXILIARY_PROCS */
+} GMBOption;
+
/* in utils/init/postinit.c */
extern void pg_split_opts(char **argv, int *argcp, const char *optstr);
extern void InitializeMaxBackends(void);
+extern int GetMaxBackends(uint32 flags);
+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.16.6