agora inbox for [email protected]  
help / color / mirror / Atom feed
[PATCH v2] Fix various shared memory estimates.
2+ messages / 2 participants
[nested] [flat]

* [PATCH v2] Fix various shared memory estimates.
@ 2021-02-27 07:45  Julien Rouhaud <[email protected]>
  0 siblings, 0 replies; 2+ messages in thread

From: Julien Rouhaud @ 2021-02-27 07:45 UTC (permalink / raw)

---
 contrib/pg_prewarm/autoprewarm.c              |  2 +-
 .../pg_stat_statements/pg_stat_statements.c   |  2 +-
 src/backend/access/common/syncscan.c          |  2 +-
 src/backend/access/nbtree/nbtutils.c          |  3 +-
 src/backend/access/transam/multixact.c        |  2 +-
 src/backend/access/transam/slru.c             |  2 +-
 src/backend/access/transam/twophase.c         |  2 +-
 src/backend/access/transam/xlog.c             |  2 +-
 src/backend/commands/async.c                  |  1 +
 src/backend/postmaster/autovacuum.c           |  3 +-
 src/backend/postmaster/bgworker.c             |  2 +-
 src/backend/postmaster/checkpointer.c         |  2 +-
 src/backend/postmaster/pgstat.c               | 17 ++---
 src/backend/postmaster/postmaster.c           |  2 +-
 src/backend/replication/logical/launcher.c    |  3 +-
 src/backend/replication/logical/origin.c      |  3 +-
 src/backend/replication/slot.c                |  2 +-
 src/backend/replication/walreceiverfuncs.c    |  2 +-
 src/backend/replication/walsender.c           |  2 +-
 src/backend/storage/buffer/buf_init.c         | 14 ++--
 src/backend/storage/buffer/buf_table.c        |  3 +-
 src/backend/storage/buffer/freelist.c         |  2 +-
 src/backend/storage/ipc/dsm.c                 |  2 +-
 src/backend/storage/ipc/pmsignal.c            |  2 +-
 src/backend/storage/ipc/procarray.c           |  8 +--
 src/backend/storage/ipc/procsignal.c          |  2 +-
 src/backend/storage/ipc/sinvaladt.c           |  2 +-
 src/backend/storage/lmgr/lock.c               | 16 ++++-
 src/backend/storage/lmgr/lwlock.c             |  2 +-
 src/backend/storage/lmgr/predicate.c          | 22 +++---
 src/backend/storage/lmgr/proc.c               | 12 ++--
 src/backend/utils/hash/dynahash.c             | 69 ++++++++++++++-----
 src/backend/utils/time/snapmgr.c              |  2 +-
 src/include/storage/predicate_internals.h     |  4 +-
 src/include/storage/shmem.h                   | 13 ++++
 src/include/utils/hsearch.h                   |  2 +
 36 files changed, 146 insertions(+), 87 deletions(-)

diff --git a/contrib/pg_prewarm/autoprewarm.c b/contrib/pg_prewarm/autoprewarm.c
index b3f73ea92d..887e68b288 100644
--- a/contrib/pg_prewarm/autoprewarm.c
+++ b/contrib/pg_prewarm/autoprewarm.c
@@ -138,7 +138,7 @@ _PG_init(void)
 
 	EmitWarningsOnPlaceholders("pg_prewarm");
 
-	RequestAddinShmemSpace(MAXALIGN(sizeof(AutoPrewarmSharedState)));
+	RequestAddinShmemSpace(CACHELINEALIGN(sizeof(AutoPrewarmSharedState)));
 
 	/* Register autoprewarm worker, if enabled. */
 	if (autoprewarm)
diff --git a/contrib/pg_stat_statements/pg_stat_statements.c b/contrib/pg_stat_statements/pg_stat_statements.c
index 62cccbfa44..4e045ffba7 100644
--- a/contrib/pg_stat_statements/pg_stat_statements.c
+++ b/contrib/pg_stat_statements/pg_stat_statements.c
@@ -1933,7 +1933,7 @@ pgss_memsize(void)
 {
 	Size		size;
 
-	size = MAXALIGN(sizeof(pgssSharedState));
+	size = CACHELINEALIGN(sizeof(pgssSharedState));
 	size = add_size(size, hash_estimate_size(pgss_max, sizeof(pgssEntry)));
 
 	return size;
diff --git a/src/backend/access/common/syncscan.c b/src/backend/access/common/syncscan.c
index b7a28af4ad..c19f9cab59 100644
--- a/src/backend/access/common/syncscan.c
+++ b/src/backend/access/common/syncscan.c
@@ -125,7 +125,7 @@ static BlockNumber ss_search(RelFileNode relfilenode,
 Size
 SyncScanShmemSize(void)
 {
-	return SizeOfScanLocations(SYNC_SCAN_NELEM);
+	return (Size) CACHELINEALIGN(SizeOfScanLocations(SYNC_SCAN_NELEM));
 }
 
 /*
diff --git a/src/backend/access/nbtree/nbtutils.c b/src/backend/access/nbtree/nbtutils.c
index d524310723..310ea904df 100644
--- a/src/backend/access/nbtree/nbtutils.c
+++ b/src/backend/access/nbtree/nbtutils.c
@@ -2066,7 +2066,8 @@ BTreeShmemSize(void)
 
 	size = offsetof(BTVacInfo, vacuums);
 	size = add_size(size, mul_size(MaxBackends, sizeof(BTOneVacInfo)));
-	return size;
+
+	return (Size) CACHELINEALIGN(size);
 }
 
 /*
diff --git a/src/backend/access/transam/multixact.c b/src/backend/access/transam/multixact.c
index 1f9f1a1fa1..c789623c34 100644
--- a/src/backend/access/transam/multixact.c
+++ b/src/backend/access/transam/multixact.c
@@ -1830,7 +1830,7 @@ MultiXactShmemSize(void)
 	add_size(offsetof(MultiXactStateData, perBackendXactIds) + sizeof(MultiXactId), \
 			 mul_size(sizeof(MultiXactId) * 2, MaxOldestSlot))
 
-	size = SHARED_MULTIXACT_STATE_SIZE;
+	size = CACHELINEALIGN(SHARED_MULTIXACT_STATE_SIZE);
 	size = add_size(size, SimpleLruShmemSize(NUM_MULTIXACTOFFSET_BUFFERS, 0));
 	size = add_size(size, SimpleLruShmemSize(NUM_MULTIXACTMEMBER_BUFFERS, 0));
 
diff --git a/src/backend/access/transam/slru.c b/src/backend/access/transam/slru.c
index 82149ad782..2271e092e9 100644
--- a/src/backend/access/transam/slru.c
+++ b/src/backend/access/transam/slru.c
@@ -168,7 +168,7 @@ SimpleLruShmemSize(int nslots, int nlsns)
 	if (nlsns > 0)
 		sz += MAXALIGN(nslots * nlsns * sizeof(XLogRecPtr));	/* group_lsn[] */
 
-	return BUFFERALIGN(sz) + BLCKSZ * nslots;
+	return (Size) CACHELINEALIGN(BUFFERALIGN(sz) + BLCKSZ * nslots);
 }
 
 /*
diff --git a/src/backend/access/transam/twophase.c b/src/backend/access/transam/twophase.c
index 80d2d20d6c..fca70fabac 100644
--- a/src/backend/access/transam/twophase.c
+++ b/src/backend/access/transam/twophase.c
@@ -245,7 +245,7 @@ TwoPhaseShmemSize(void)
 	size = add_size(size, mul_size(max_prepared_xacts,
 								   sizeof(GlobalTransactionData)));
 
-	return size;
+	return (Size) CACHELINEALIGN(size);
 }
 
 void
diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c
index 377afb8732..64de453340 100644
--- a/src/backend/access/transam/xlog.c
+++ b/src/backend/access/transam/xlog.c
@@ -5096,7 +5096,7 @@ XLOGShmemSize(void)
 	 * routine again below to compute the actual allocation size.
 	 */
 
-	return size;
+	return (Size) CACHELINEALIGN(size);
 }
 
 void
diff --git a/src/backend/commands/async.c b/src/backend/commands/async.c
index 4b16fb5682..6a0fd6ca10 100644
--- a/src/backend/commands/async.c
+++ b/src/backend/commands/async.c
@@ -513,6 +513,7 @@ AsyncShmemSize(void)
 	/* This had better match AsyncShmemInit */
 	size = mul_size(MaxBackends + 1, sizeof(QueueBackendStatus));
 	size = add_size(size, offsetof(AsyncQueueControl, backend));
+	size = (Size) CACHELINEALIGN(size);
 
 	size = add_size(size, SimpleLruShmemSize(NUM_NOTIFY_BUFFERS, 0));
 
diff --git a/src/backend/postmaster/autovacuum.c b/src/backend/postmaster/autovacuum.c
index 23ef23c13e..7ddf86af74 100644
--- a/src/backend/postmaster/autovacuum.c
+++ b/src/backend/postmaster/autovacuum.c
@@ -3414,7 +3414,8 @@ AutoVacuumShmemSize(void)
 	size = MAXALIGN(size);
 	size = add_size(size, mul_size(autovacuum_max_workers,
 								   sizeof(WorkerInfoData)));
-	return size;
+
+	return (Size) CACHELINEALIGN(size);
 }
 
 /*
diff --git a/src/backend/postmaster/bgworker.c b/src/backend/postmaster/bgworker.c
index bbbc09b0b5..d2f838eaed 100644
--- a/src/backend/postmaster/bgworker.c
+++ b/src/backend/postmaster/bgworker.c
@@ -148,7 +148,7 @@ BackgroundWorkerShmemSize(void)
 	size = add_size(size, mul_size(max_worker_processes,
 								   sizeof(BackgroundWorkerSlot)));
 
-	return size;
+	return (Size) CACHELINEALIGN(size);
 }
 
 /*
diff --git a/src/backend/postmaster/checkpointer.c b/src/backend/postmaster/checkpointer.c
index 76f9f98ebb..6acd5e4c2b 100644
--- a/src/backend/postmaster/checkpointer.c
+++ b/src/backend/postmaster/checkpointer.c
@@ -862,7 +862,7 @@ CheckpointerShmemSize(void)
 	size = offsetof(CheckpointerShmemStruct, requests);
 	size = add_size(size, mul_size(NBuffers, sizeof(CheckpointerRequest)));
 
-	return size;
+	return (Size) CACHELINEALIGN(size);
 }
 
 /*
diff --git a/src/backend/postmaster/pgstat.c b/src/backend/postmaster/pgstat.c
index f75b52719d..b08f7f1d56 100644
--- a/src/backend/postmaster/pgstat.c
+++ b/src/backend/postmaster/pgstat.c
@@ -2930,25 +2930,20 @@ BackendStatusShmemSize(void)
 	Size		size;
 
 	/* BackendStatusArray: */
-	size = mul_size(sizeof(PgBackendStatus), NumBackendStatSlots);
+	size = mul_size_and_shmem_align(sizeof(PgBackendStatus), NumBackendStatSlots);
 	/* BackendAppnameBuffer: */
-	size = add_size(size,
-					mul_size(NAMEDATALEN, NumBackendStatSlots));
+	size = add_shmem_aligned_size(size, mul_size(NAMEDATALEN, NumBackendStatSlots));
 	/* BackendClientHostnameBuffer: */
-	size = add_size(size,
-					mul_size(NAMEDATALEN, NumBackendStatSlots));
+	size = add_shmem_aligned_size(size, mul_size(NAMEDATALEN, NumBackendStatSlots));
 	/* BackendActivityBuffer: */
-	size = add_size(size,
-					mul_size(pgstat_track_activity_query_size, NumBackendStatSlots));
+	size = add_shmem_aligned_size(size, mul_size(pgstat_track_activity_query_size, NumBackendStatSlots));
 #ifdef USE_SSL
 	/* BackendSslStatusBuffer: */
-	size = add_size(size,
-					mul_size(sizeof(PgBackendSSLStatus), NumBackendStatSlots));
+	size = add_shmem_aligned_size(size, mul_size(sizeof(PgBackendSSLStatus), NumBackendStatSlots));
 #endif
 #ifdef ENABLE_GSS
 	/* BackendGssStatusBuffer: */
-	size = add_size(size,
-					mul_size(sizeof(PgBackendGSSStatus), NumBackendStatSlots));
+	size = add_shmem_aligned_size(size, mul_size(sizeof(PgBackendGSSStatus), NumBackendStatSlots));
 #endif
 	return size;
 }
diff --git a/src/backend/postmaster/postmaster.c b/src/backend/postmaster/postmaster.c
index edab95a19e..716f7434e6 100644
--- a/src/backend/postmaster/postmaster.c
+++ b/src/backend/postmaster/postmaster.c
@@ -6425,7 +6425,7 @@ restore_backend_variables(BackendParameters *param, Port *port)
 Size
 ShmemBackendArraySize(void)
 {
-	return mul_size(MaxLivePostmasterChildren(), sizeof(Backend));
+	return mul_size_and_shmem_align(MaxLivePostmasterChildren(), sizeof(Backend));
 }
 
 void
diff --git a/src/backend/replication/logical/launcher.c b/src/backend/replication/logical/launcher.c
index cb462a052a..7d20877920 100644
--- a/src/backend/replication/logical/launcher.c
+++ b/src/backend/replication/logical/launcher.c
@@ -697,7 +697,8 @@ ApplyLauncherShmemSize(void)
 	size = MAXALIGN(size);
 	size = add_size(size, mul_size(max_logical_replication_workers,
 								   sizeof(LogicalRepWorker)));
-	return size;
+
+	return (Size) CACHELINEALIGN(size);
 }
 
 /*
diff --git a/src/backend/replication/logical/origin.c b/src/backend/replication/logical/origin.c
index 39471fddad..b9e9fa121a 100644
--- a/src/backend/replication/logical/origin.c
+++ b/src/backend/replication/logical/origin.c
@@ -503,7 +503,8 @@ ReplicationOriginShmemSize(void)
 
 	size = add_size(size,
 					mul_size(max_replication_slots, sizeof(ReplicationState)));
-	return size;
+
+	return (Size) CACHELINEALIGN(size);
 }
 
 void
diff --git a/src/backend/replication/slot.c b/src/backend/replication/slot.c
index 75a087c2f9..c399c491e9 100644
--- a/src/backend/replication/slot.c
+++ b/src/backend/replication/slot.c
@@ -124,7 +124,7 @@ ReplicationSlotsShmemSize(void)
 	size = add_size(size,
 					mul_size(max_replication_slots, sizeof(ReplicationSlot)));
 
-	return size;
+	return (Size) CACHELINEALIGN(size);
 }
 
 /*
diff --git a/src/backend/replication/walreceiverfuncs.c b/src/backend/replication/walreceiverfuncs.c
index 63e60478ea..a8cab3fa28 100644
--- a/src/backend/replication/walreceiverfuncs.c
+++ b/src/backend/replication/walreceiverfuncs.c
@@ -45,7 +45,7 @@ WalRcvShmemSize(void)
 
 	size = add_size(size, sizeof(WalRcvData));
 
-	return size;
+	return (Size) CACHELINEALIGN(size);
 }
 
 /* Allocate and initialize walreceiver-related shared memory */
diff --git a/src/backend/replication/walsender.c b/src/backend/replication/walsender.c
index 23baa4498a..d1c91cf354 100644
--- a/src/backend/replication/walsender.c
+++ b/src/backend/replication/walsender.c
@@ -3055,7 +3055,7 @@ WalSndShmemSize(void)
 	size = offsetof(WalSndCtlData, walsnds);
 	size = add_size(size, mul_size(max_wal_senders, sizeof(WalSnd)));
 
-	return size;
+	return (Size) CACHELINEALIGN(size);
 }
 
 /* Allocate and initialize walsender-related shared memory */
diff --git a/src/backend/storage/buffer/buf_init.c b/src/backend/storage/buffer/buf_init.c
index e9e4f35bb5..b92fdeef14 100644
--- a/src/backend/storage/buffer/buf_init.c
+++ b/src/backend/storage/buffer/buf_init.c
@@ -159,15 +159,13 @@ BufferShmemSize(void)
 	Size		size = 0;
 
 	/* size of buffer descriptors */
-	size = add_size(size, mul_size(NBuffers, sizeof(BufferDescPadded)));
-	/* to allow aligning buffer descriptors */
-	size = add_size(size, PG_CACHE_LINE_SIZE);
+	size = add_shmem_aligned_size(size, mul_size(NBuffers, sizeof(BufferDescPadded)));
 
 	/* size of data pages */
-	size = add_size(size, mul_size(NBuffers, BLCKSZ));
+	size = add_shmem_aligned_size(size, mul_size(NBuffers, BLCKSZ));
 
 	/* size of stuff controlled by freelist.c */
-	size = add_size(size, StrategyShmemSize());
+	size = add_shmem_aligned_size(size, StrategyShmemSize());
 
 	/*
 	 * It would be nice to include the I/O locks in the BufferDesc, but that
@@ -178,12 +176,10 @@ BufferShmemSize(void)
 	 * locks are not highly contended, we lay out the array with minimal
 	 * padding.
 	 */
-	size = add_size(size, mul_size(NBuffers, sizeof(LWLockMinimallyPadded)));
-	/* to allow aligning the above */
-	size = add_size(size, PG_CACHE_LINE_SIZE);
+	size = add_shmem_aligned_size(size, mul_size(NBuffers, sizeof(LWLockMinimallyPadded)));
 
 	/* size of checkpoint sort array in bufmgr.c */
-	size = add_size(size, mul_size(NBuffers, sizeof(CkptSortItem)));
+	size = add_shmem_aligned_size(size, mul_size(NBuffers, sizeof(CkptSortItem)));
 
 	return size;
 }
diff --git a/src/backend/storage/buffer/buf_table.c b/src/backend/storage/buffer/buf_table.c
index caa03ae123..4200f99340 100644
--- a/src/backend/storage/buffer/buf_table.c
+++ b/src/backend/storage/buffer/buf_table.c
@@ -41,7 +41,8 @@ static HTAB *SharedBufHash;
 Size
 BufTableShmemSize(int size)
 {
-	return hash_estimate_size(size, sizeof(BufferLookupEnt));
+	return hash_estimate_size_ext(size, sizeof(BufferLookupEnt),
+								  size, true);
 }
 
 /*
diff --git a/src/backend/storage/buffer/freelist.c b/src/backend/storage/buffer/freelist.c
index 6be80476db..33e9e74f40 100644
--- a/src/backend/storage/buffer/freelist.c
+++ b/src/backend/storage/buffer/freelist.c
@@ -459,7 +459,7 @@ StrategyShmemSize(void)
 	size = add_size(size, BufTableShmemSize(NBuffers + NUM_BUFFER_PARTITIONS));
 
 	/* size of the shared replacement strategy control block */
-	size = add_size(size, MAXALIGN(sizeof(BufferStrategyControl)));
+	size = add_shmem_aligned_size(size, sizeof(BufferStrategyControl));
 
 	return size;
 }
diff --git a/src/backend/storage/ipc/dsm.c b/src/backend/storage/ipc/dsm.c
index b461a5f7e9..6ecf195c55 100644
--- a/src/backend/storage/ipc/dsm.c
+++ b/src/backend/storage/ipc/dsm.c
@@ -440,7 +440,7 @@ dsm_set_control_handle(dsm_handle h)
 size_t
 dsm_estimate_size(void)
 {
-	return 1024 * 1024 * (size_t) min_dynamic_shared_memory;
+	return (size_t) CACHELINEALIGN(1024 * 1024 * min_dynamic_shared_memory);
 }
 
 /*
diff --git a/src/backend/storage/ipc/pmsignal.c b/src/backend/storage/ipc/pmsignal.c
index 280c2395c9..d25080224a 100644
--- a/src/backend/storage/ipc/pmsignal.c
+++ b/src/backend/storage/ipc/pmsignal.c
@@ -124,7 +124,7 @@ PMSignalShmemSize(void)
 	size = add_size(size, mul_size(MaxLivePostmasterChildren(),
 								   sizeof(sig_atomic_t)));
 
-	return size;
+	return (Size) CACHELINEALIGN(size);
 }
 
 /*
diff --git a/src/backend/storage/ipc/procarray.c b/src/backend/storage/ipc/procarray.c
index 4fc6ffb917..9b804f1152 100644
--- a/src/backend/storage/ipc/procarray.c
+++ b/src/backend/storage/ipc/procarray.c
@@ -358,6 +358,7 @@ ProcArrayShmemSize(void)
 
 	size = offsetof(ProcArrayStruct, pgprocnos);
 	size = add_size(size, mul_size(sizeof(int), PROCARRAY_MAXPROCS));
+	size = CACHELINEALIGN(size);
 
 	/*
 	 * During Hot Standby processing we have a data structure called
@@ -377,11 +378,8 @@ ProcArrayShmemSize(void)
 
 	if (EnableHotStandby)
 	{
-		size = add_size(size,
-						mul_size(sizeof(TransactionId),
-								 TOTAL_MAX_CACHED_SUBXIDS));
-		size = add_size(size,
-						mul_size(sizeof(bool), TOTAL_MAX_CACHED_SUBXIDS));
+		size = add_shmem_aligned_size(size, mul_size(sizeof(TransactionId), TOTAL_MAX_CACHED_SUBXIDS));
+		size = add_shmem_aligned_size(size, mul_size(sizeof(bool), TOTAL_MAX_CACHED_SUBXIDS));
 	}
 
 	return size;
diff --git a/src/backend/storage/ipc/procsignal.c b/src/backend/storage/ipc/procsignal.c
index c6a8d4611e..2af7f3e343 100644
--- a/src/backend/storage/ipc/procsignal.c
+++ b/src/backend/storage/ipc/procsignal.c
@@ -113,7 +113,7 @@ ProcSignalShmemSize(void)
 
 	size = mul_size(NumProcSignalSlots, sizeof(ProcSignalSlot));
 	size = add_size(size, offsetof(ProcSignalHeader, psh_slot));
-	return size;
+	return (Size) CACHELINEALIGN(size);
 }
 
 /*
diff --git a/src/backend/storage/ipc/sinvaladt.c b/src/backend/storage/ipc/sinvaladt.c
index 946bd8e3cb..8379bf12e7 100644
--- a/src/backend/storage/ipc/sinvaladt.c
+++ b/src/backend/storage/ipc/sinvaladt.c
@@ -207,7 +207,7 @@ SInvalShmemSize(void)
 	size = offsetof(SISeg, procState);
 	size = add_size(size, mul_size(sizeof(ProcState), MaxBackends));
 
-	return size;
+	return (Size) CACHELINEALIGN(size);
 }
 
 /*
diff --git a/src/backend/storage/lmgr/lock.c b/src/backend/storage/lmgr/lock.c
index 108b4d9023..f2fc8af5c5 100644
--- a/src/backend/storage/lmgr/lock.c
+++ b/src/backend/storage/lmgr/lock.c
@@ -54,7 +54,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_and_shmem_align(max_locks_per_xact, add_size(MaxBackends, max_prepared_xacts))
 
 
 /*
@@ -3527,17 +3527,27 @@ LockShmemSize(void)
 
 	/* lock hash table */
 	max_table_size = NLOCKENTS();
-	size = add_size(size, hash_estimate_size(max_table_size, sizeof(LOCK)));
+	size = add_size(size, hash_estimate_size_ext(max_table_size, sizeof(LOCK),
+												 max_table_size / 2,
+												 true));
 
 	/* proclock hash table */
 	max_table_size *= 2;
-	size = add_size(size, hash_estimate_size(max_table_size, sizeof(PROCLOCK)));
+	size = add_size(size, hash_estimate_size_ext(max_table_size, sizeof(PROCLOCK),
+												 max_table_size / 2,
+												 true));
 
 	/*
 	 * Since NLOCKENTS is only an estimate, add 10% safety margin.
 	 */
 	size = add_size(size, size / 10);
 
+	/*
+	 * Note: we don't count fast-path structure, it comes out of the "slop
+	 * factor" added by CreateSharedMemoryAndSemaphores.  This lets us use this
+	 * routine again below to compute the actual allocation size.
+	 */
+
 	return size;
 }
 
diff --git a/src/backend/storage/lmgr/lwlock.c b/src/backend/storage/lmgr/lwlock.c
index 8cb6a6f042..6a47918616 100644
--- a/src/backend/storage/lmgr/lwlock.c
+++ b/src/backend/storage/lmgr/lwlock.c
@@ -456,7 +456,7 @@ LWLockShmemSize(void)
 	/* Disallow adding any more named tranches. */
 	lock_named_request_allowed = false;
 
-	return size;
+	return (Size) CACHELINEALIGN(size);
 }
 
 /*
diff --git a/src/backend/storage/lmgr/predicate.c b/src/backend/storage/lmgr/predicate.c
index d493aeef0f..1dcadc00ae 100644
--- a/src/backend/storage/lmgr/predicate.c
+++ b/src/backend/storage/lmgr/predicate.c
@@ -1359,13 +1359,17 @@ PredicateLockShmemSize(void)
 
 	/* predicate lock target hash table */
 	max_table_size = NPREDICATELOCKTARGETENTS();
-	size = add_size(size, hash_estimate_size(max_table_size,
-											 sizeof(PREDICATELOCKTARGET)));
+	size = add_size(size, hash_estimate_size_ext(max_table_size,
+												 sizeof(PREDICATELOCKTARGET),
+												 max_table_size,
+												 true));
 
 	/* predicate lock hash table */
 	max_table_size *= 2;
-	size = add_size(size, hash_estimate_size(max_table_size,
-											 sizeof(PREDICATELOCK)));
+	size = add_size(size, hash_estimate_size_ext(max_table_size,
+												 sizeof(PREDICATELOCK),
+												 max_table_size,
+												 true));
 
 	/*
 	 * Since NPREDICATELOCKTARGETENTS is only an estimate, add 10% safety
@@ -1377,8 +1381,7 @@ PredicateLockShmemSize(void)
 	max_table_size = MaxBackends + max_prepared_xacts;
 	max_table_size *= 10;
 	size = add_size(size, PredXactListDataSize);
-	size = add_size(size, mul_size((Size) max_table_size,
-								   PredXactListElementDataSize));
+	size = add_shmem_aligned_size(size, mul_size((Size) max_table_size, PredXactListElementDataSize));
 
 	/* transaction xid table */
 	size = add_size(size, hash_estimate_size(max_table_size,
@@ -1387,14 +1390,13 @@ PredicateLockShmemSize(void)
 	/* rw-conflict pool */
 	max_table_size *= 5;
 	size = add_size(size, RWConflictPoolHeaderDataSize);
-	size = add_size(size, mul_size((Size) max_table_size,
-								   RWConflictDataSize));
+	size = add_shmem_aligned_size(size, mul_size((Size) max_table_size, RWConflictDataSize));
 
 	/* Head for list of finished serializable transactions. */
-	size = add_size(size, sizeof(SHM_QUEUE));
+	size = add_shmem_aligned_size(size, sizeof(SHM_QUEUE));
 
 	/* Shared memory structures for SLRU tracking of old committed xids. */
-	size = add_size(size, sizeof(SerialControlData));
+	size = add_shmem_aligned_size(size, sizeof(SerialControlData));
 	size = add_size(size, SimpleLruShmemSize(NUM_SERIAL_BUFFERS, 0));
 
 	return size;
diff --git a/src/backend/storage/lmgr/proc.c b/src/backend/storage/lmgr/proc.c
index 897045ee27..28031c7d22 100644
--- a/src/backend/storage/lmgr/proc.c
+++ b/src/backend/storage/lmgr/proc.c
@@ -106,13 +106,13 @@ ProcGlobalShmemSize(void)
 		add_size(MaxBackends, add_size(NUM_AUXILIARY_PROCS, max_prepared_xacts));
 
 	/* ProcGlobal */
-	size = add_size(size, sizeof(PROC_HDR));
-	size = add_size(size, mul_size(TotalProcs, sizeof(PGPROC)));
-	size = add_size(size, sizeof(slock_t));
+	size = add_shmem_aligned_size(size, sizeof(PROC_HDR));
+	size = add_shmem_aligned_size(size, mul_size(TotalProcs, sizeof(PGPROC)));
+	size = add_shmem_aligned_size(size, sizeof(slock_t));
 
-	size = add_size(size, mul_size(TotalProcs, sizeof(*ProcGlobal->xids)));
-	size = add_size(size, mul_size(TotalProcs, sizeof(*ProcGlobal->subxidStates)));
-	size = add_size(size, mul_size(TotalProcs, sizeof(*ProcGlobal->statusFlags)));
+	size = add_shmem_aligned_size(size, mul_size(TotalProcs, sizeof(*ProcGlobal->xids)));
+	size = add_shmem_aligned_size(size, mul_size(TotalProcs, sizeof(*ProcGlobal->subxidStates)));
+	size = add_shmem_aligned_size(size, mul_size(TotalProcs, sizeof(*ProcGlobal->statusFlags)));
 
 	return size;
 }
diff --git a/src/backend/utils/hash/dynahash.c b/src/backend/utils/hash/dynahash.c
index 6546e3c7c7..030ca3917c 100644
--- a/src/backend/utils/hash/dynahash.c
+++ b/src/backend/utils/hash/dynahash.c
@@ -769,23 +769,43 @@ init_htab(HTAB *hashp, long nelem)
 	return true;
 }
 
+/*
+ * Wrapper around hash_estimate_size for non partitioned hash table and all
+ * entries preallocated.
+ */
+Size
+hash_estimate_size(long num_entries, Size entrysize)
+{
+	return hash_estimate_size_ext(num_entries, entrysize, num_entries, false);
+}
+
 /*
  * Estimate the space needed for a hashtable containing the given number
- * of entries of given size.
+ * of entries of given size, and given it's partitioned or not.
  * NOTE: this is used to estimate the footprint of hashtables in shared
  * memory; therefore it does not count HTAB which is in local memory.
  * NB: assumes that all hash structure parameters have default values!
  */
 Size
-hash_estimate_size(long num_entries, Size entrysize)
+hash_estimate_size_ext(long num_entries, Size entrysize, long init_entries,
+					   bool partitioned)
 {
-	Size		size;
+	Size		size,
+				segmentSize,
+				freelistAllocSize;
 	long		nBuckets,
 				nSegments,
 				nDirEntries,
-				nElementAllocs,
 				elementSize,
-				elementAllocCnt;
+				nelemFreelist;
+	int			nFreelists;
+
+	if (partitioned)
+		nFreelists = NUM_FREELISTS;
+	else
+		nFreelists = 1;
+
+	Assert(init_entries <= num_entries);
 
 	/* estimate number of buckets wanted */
 	nBuckets = next_pow2_long(num_entries);
@@ -797,19 +817,36 @@ hash_estimate_size(long num_entries, Size entrysize)
 		nDirEntries <<= 1;		/* dir_alloc doubles dsize at each call */
 
 	/* fixed control info */
-	size = MAXALIGN(sizeof(HASHHDR));	/* but not HTAB, per above */
+	size = CACHELINEALIGN(sizeof(HASHHDR));	/* but not HTAB, per above */
 	/* directory */
-	size = add_size(size, mul_size(nDirEntries, sizeof(HASHSEGMENT)));
+	size = add_shmem_aligned_size(size, mul_size(nDirEntries, sizeof(HASHSEGMENT)));
 	/* segments */
-	size = add_size(size, mul_size(nSegments,
-								   MAXALIGN(DEF_SEGSIZE * sizeof(HASHBUCKET))));
-	/* elements --- allocated in groups of choose_nelem_alloc() entries */
-	elementAllocCnt = choose_nelem_alloc(entrysize);
-	nElementAllocs = (num_entries - 1) / elementAllocCnt + 1;
+	segmentSize = CACHELINEALIGN(DEF_SEGSIZE * sizeof(HASHBUCKET));
+	size = add_size(size, mul_size(nSegments, segmentSize));
+
 	elementSize = MAXALIGN(sizeof(HASHELEMENT)) + MAXALIGN(entrysize);
-	size = add_size(size,
-					mul_size(nElementAllocs,
-							 mul_size(elementAllocCnt, elementSize)));
+
+	/*
+	 * elements --- allocated in groups of choose_nelem_alloc() entries, except
+	 * for the first init_entries, allocated in num_freelists groups.
+	 */
+	nelemFreelist = init_entries / nFreelists;
+	freelistAllocSize = mul_size_and_shmem_align(nelemFreelist, elementSize);
+
+	size = add_size(size, mul_size(nFreelists, freelistAllocSize));
+
+	if (num_entries > init_entries)
+	{
+		Size	nelem,
+				nAlloc,
+				allocSize;
+
+		nelem = choose_nelem_alloc(entrysize);
+		nAlloc = (num_entries - init_entries - 1) / nelem + 1;
+		allocSize = mul_size_and_shmem_align(nelem, elementSize);
+
+		size = add_size(size, mul_size(nAlloc, allocSize));
+	}
 
 	return size;
 }
@@ -852,7 +889,7 @@ hash_get_shared_size(HASHCTL *info, int flags)
 {
 	Assert(flags & HASH_DIRSIZE);
 	Assert(info->dsize == info->max_dsize);
-	return sizeof(HASHHDR) + info->dsize * sizeof(HASHSEGMENT);
+	return (Size) CACHELINEALIGN(sizeof(HASHHDR) + info->dsize * sizeof(HASHSEGMENT));
 }
 
 
diff --git a/src/backend/utils/time/snapmgr.c b/src/backend/utils/time/snapmgr.c
index 95704265b6..b66278e466 100644
--- a/src/backend/utils/time/snapmgr.c
+++ b/src/backend/utils/time/snapmgr.c
@@ -203,7 +203,7 @@ SnapMgrShmemSize(void)
 		size = add_size(size, mul_size(sizeof(TransactionId),
 									   OLD_SNAPSHOT_TIME_MAP_ENTRIES));
 
-	return size;
+	return (Size) CACHELINEALIGN(size);
 }
 
 /*
diff --git a/src/include/storage/predicate_internals.h b/src/include/storage/predicate_internals.h
index 104f560d38..bbc6ca4cbf 100644
--- a/src/include/storage/predicate_internals.h
+++ b/src/include/storage/predicate_internals.h
@@ -192,7 +192,7 @@ typedef struct PredXactListData
 typedef struct PredXactListData *PredXactList;
 
 #define PredXactListDataSize \
-		((Size)MAXALIGN(sizeof(PredXactListData)))
+		((Size)CACHELINEALIGN(sizeof(PredXactListData)))
 
 
 /*
@@ -227,7 +227,7 @@ typedef struct RWConflictPoolHeaderData
 typedef struct RWConflictPoolHeaderData *RWConflictPoolHeader;
 
 #define RWConflictPoolHeaderDataSize \
-		((Size)MAXALIGN(sizeof(RWConflictPoolHeaderData)))
+		((Size)CACHELINEALIGN(sizeof(RWConflictPoolHeaderData)))
 
 
 /*
diff --git a/src/include/storage/shmem.h b/src/include/storage/shmem.h
index 31024e5a50..897672bc8e 100644
--- a/src/include/storage/shmem.h
+++ b/src/include/storage/shmem.h
@@ -45,6 +45,19 @@ extern void *ShmemInitStruct(const char *name, Size size, bool *foundPtr);
 extern Size add_size(Size s1, Size s2);
 extern Size mul_size(Size s1, Size s2);
 
+/*
+ * Macro around add_size and mul_size to account for extra padding as done in
+ * ShmemAlloc().
+ *
+ * add_shmem_aligned_size() will add the padding bytes to the 2nd argument
+ * mul_size_and_shmem_align will return the aligned size
+ */
+#define add_shmem_aligned_size(s1, s2)	add_size((s1), \
+		(Size) CACHELINEALIGN(s2))
+
+#define mul_size_and_shmem_align(s1, s2)	add_shmem_aligned_size(0, \
+		mul_size((s1), (s2)))
+
 /* ipci.c */
 extern void RequestAddinShmemSpace(Size size);
 
diff --git a/src/include/utils/hsearch.h b/src/include/utils/hsearch.h
index d7af0239c8..20c0ff3036 100644
--- a/src/include/utils/hsearch.h
+++ b/src/include/utils/hsearch.h
@@ -145,6 +145,8 @@ extern void *hash_seq_search(HASH_SEQ_STATUS *status);
 extern void hash_seq_term(HASH_SEQ_STATUS *status);
 extern void hash_freeze(HTAB *hashp);
 extern Size hash_estimate_size(long num_entries, Size entrysize);
+extern Size hash_estimate_size_ext(long num_entries, Size entrysize,
+								   long init_entries, bool num_freelists);
 extern long hash_select_dirsize(long num_entries);
 extern Size hash_get_shared_size(HASHCTL *info, int flags);
 extern void AtEOXact_HashTables(bool isCommit);
-- 
2.30.1


--qghjt52pj73pl6gt--





^ permalink  raw  reply  [nested|flat] 2+ messages in thread

* [PATCH 3/4] Reindent and wrap between added sect1 tags
@ 2022-02-22 02:21  Chapman Flack <[email protected]>
  0 siblings, 0 replies; 2+ messages in thread

From: Chapman Flack @ 2022-02-22 02:21 UTC (permalink / raw)

A whitespace-only commit.
---
 doc/src/sgml/plhandler.sgml | 638 ++++++++++++++++++++++----------------------
 1 file changed, 321 insertions(+), 317 deletions(-)

diff --git a/doc/src/sgml/plhandler.sgml b/doc/src/sgml/plhandler.sgml
index 95e8515..003a6c9 100644
--- a/doc/src/sgml/plhandler.sgml
+++ b/doc/src/sgml/plhandler.sgml
@@ -57,385 +57,389 @@
    <sect1 id="plhandler-call">
     <title>Call handler function</title>
 
-   <para>
-    Every routine defined with a language name other than
-    <literal>internal</literal> (as defined in <xref linkend="xfunc-internal"/>)
-    or <literal>c</literal> (<xref linkend="xfunc-c"/>) will be called by
-    invoking the procedural language's call handler.
-    <footnote>
-     <para>
-      This is true even of routines with language name <literal>sql</literal>,
-      though, as a special case, that call handler has no entry in the system
-      catalogs.
-     </para>
-    </footnote>
-    It is the responsibility of
-    the call handler to execute the routine in a meaningful way, such
-    as by interpreting the supplied source text.
-   </para>
-
-   <para>
-    The call handler is a <quote>normal</quote> user-defined function that must
-    be declared to <productname>PostgreSQL</productname> as taking no arguments
-    and returning the type <type>language_handler</type>.  This
-    special pseudo-type identifies the function as a call handler and
-    prevents it from being called directly in SQL commands.
-    This handler must not require a call handler of its own, which makes
-    the predefined languages <literal>internal</literal> or <literal>c</literal>
-    the only choices for the handler's own declaration.
-    Typically, it will be a loadable function in language
-    <literal>c</literal>, as described in <xref linkend="xfunc-c"/>.
-    <footnote>
-     <para>
-      It may be implemented in a language other than C, as long as it can be
-      built into a loadable object with compatible calling conventions.
-     </para>
-    </footnote>
-   </para>
-
-   <para>
-    The call handler is called in the same way as any other function:
-    It receives a pointer to a
-    <structname>FunctionCallInfoBaseData</structname> <type>struct</type> containing
-    argument values and information about the called routine, and it
-    is expected to return a <type>Datum</type> result (and possibly
-    set the <structfield>isnull</structfield> field of the
-    <structname>FunctionCallInfoBaseData</structname> structure, if it wishes
-    to return an SQL null result).  The difference between a call
-    handler and an ordinary callee is that the
-    <structfield>flinfo-&gt;fn_oid</structfield> field of the
-    <structname>FunctionCallInfoBaseData</structname> structure will contain
-    the OID of the actual routine to be called, not of the call
-    handler itself.  The call handler must use this field to determine
-    which routine to execute.  Also, the passed argument list has
-    been set up according to the declaration of the target routine,
-    not of the call handler.
-   </para>
-
-   <para>
-    It's up to the call handler to fetch the routine's defining
-    <classname>pg_proc</classname> row from the system catalog cache
-    to determine what to execute, what parameter and return types are expected,
-    and so on.
-    The <literal>AS</literal> clause from the
-    <command>CREATE FUNCTION</command> or <command>CREATE PROCEDURE</command>
-    command for the routine will be found
-    in the <literal>prosrc</literal> column of the
-    <classname>pg_proc</classname> row. This is commonly source
-    text in the procedural language, but in theory it could be something else,
-    such as a path name to a file, or anything else that tells the call handler
-    what to do in detail.
-   </para>
-
-   <para>
-    The handler may also examine the passed
-    <structname>FunctionCallInfoBaseData</structname> structure for information
-    on the context of the call. If the procedural language will support
-    returning sets, the structure may contain a pointer to a
-    <structname>ReturnSetInfo</structname> structure for use as described in
-    <xref linkend="xfunc-c-return-set"/>. If the language will support triggers
-    or event triggers, the structure may hold a pointer to one of the structures
-    described in <xref linkend="trigger-interface"/> or
-    <xref linkend="event-trigger-interface"/>, and the procedural language
-    should provide some way for the called function to use the information
-    they carry.
-   </para>
-
-   <sect2 id="plhandler-call-args">
-    <title>Parameter and return type resolution</title>
-
     <para>
-     A routine's statically-declared parameter types (and, for a function,
-     return type) are found in the <literal>proargtypes</literal> and
-     <literal>prorettype</literal> columns of the <classname>pg_proc</classname>
-     row.
-     If a routine has <literal>OUT</literal> parameters, those types are
-     included in the <literal>proallargtypes</literal> column, and their names
-     in <literal>proargnames</literal>.
-     Convenience functions declared in <filename>funcapi.h</filename> are
-     available for extracting that information.
+     Every routine defined with a language name other than
+     <literal>internal</literal> (as defined in
+     <xref linkend="xfunc-internal"/>)
+     or <literal>c</literal> (<xref linkend="xfunc-c"/>) will be called by
+     invoking the procedural language's call handler.
+     <footnote>
+      <para>
+       This is true even of routines with language name <literal>sql</literal>,
+       though, as a special case, that call handler has no entry in the system
+       catalogs.
+      </para>
+     </footnote>
+     It is the responsibility of
+     the call handler to execute the routine in a meaningful way, such
+     as by interpreting the supplied source text.
     </para>
 
     <para>
-     The statically-declared types may include polymorphic types that need
-     to be resolved according to the actual types present at the call site,
-     as described in <xref linkend="xfunc-c-polymorphism"/>.
+     The call handler is a <quote>normal</quote> user-defined function that must
+     be declared to <productname>PostgreSQL</productname> as taking no arguments
+     and returning the type <type>language_handler</type>.  This
+     special pseudo-type identifies the function as a call handler and
+     prevents it from being called directly in SQL commands.
+     This handler must not require a call handler of its own, which makes
+     the predefined languages <literal>internal</literal> or
+     <literal>c</literal> the only choices for the handler's own declaration.
+     Typically, it will be a loadable function in language
+     <literal>c</literal>, as described in <xref linkend="xfunc-c"/>.
+     <footnote>
+      <para>
+       It may be implemented in a language other than C, as long as it can be
+       built into a loadable object with compatible calling conventions.
+      </para>
+     </footnote>
     </para>
 
-   </sect2>
-
-   <sect2 id="plhandler-call-types">
-    <title>Mapping to procedural language types</title>
+    <para>
+     The call handler is called in the same way as any other function:
+     It receives a pointer to a
+     <structname>FunctionCallInfoBaseData</structname> <type>struct</type>
+     containing argument values and information about the called routine, and it
+     is expected to return a <type>Datum</type> result (and possibly
+     set the <structfield>isnull</structfield> field of the
+     <structname>FunctionCallInfoBaseData</structname> structure, if it wishes
+     to return an SQL null result).  The difference between a call
+     handler and an ordinary callee is that the
+     <structfield>flinfo-&gt;fn_oid</structfield> field of the
+     <structname>FunctionCallInfoBaseData</structname> structure will contain
+     the OID of the actual routine to be called, not of the call
+     handler itself.  The call handler must use this field to determine
+     which routine to execute.  Also, the passed argument list has
+     been set up according to the declaration of the target routine,
+     not of the call handler.
+    </para>
 
     <para>
-     Once the <productname>PostgreSQL</productname> types of any parameters
-     and results have been resolved, the handler must determine how it will
-     map their values to and from suitable types that exist in the procedural
-     language.
+     It's up to the call handler to fetch the routine's defining
+     <classname>pg_proc</classname> row from the system catalog cache
+     to determine what to execute, what parameter and return types are expected,
+     and so on.
+     The <literal>AS</literal> clause from the
+     <command>CREATE FUNCTION</command> or <command>CREATE PROCEDURE</command>
+     command for the routine will be found
+     in the <literal>prosrc</literal> column of the
+     <classname>pg_proc</classname> row. This is commonly source
+     text in the procedural language, but in theory it could be something else,
+     such as a path name to a file, or anything else that tells the call handler
+     what to do in detail.
     </para>
 
     <para>
-     The designer of a procedural language will typically document what types
-     will be supported and how they will be mapped, which could be as simple
-     as using every type's text input/output format to map it to the target
-     language's string type, or could directly map many types to corresponding
-     ones the target language provides. The handler function will implement
-     those rules.
+     The handler may also examine the passed
+     <structname>FunctionCallInfoBaseData</structname> structure for information
+     on the context of the call. If the procedural language will support
+     returning sets, the structure may contain a pointer to a
+     <structname>ReturnSetInfo</structname> structure for use as described in
+     <xref linkend="xfunc-c-return-set"/>. If the language will support triggers
+     or event triggers, the structure may hold a pointer to one of
+     the structures described in <xref linkend="trigger-interface"/> or
+     <xref linkend="event-trigger-interface"/>, and the procedural language
+     should provide some way for the called function to use the information
+     they carry.
     </para>
 
-    <sect3 id="plhandler-call-types-transform">
-     <title>Type transforms</title>
+    <sect2 id="plhandler-call-args">
+     <title>Parameter and return type resolution</title>
 
      <para>
-      Because <productname>PostgreSQL</productname> is extensible, and
-      an extension can easily supply new types, a procedural language handler
-      may encounter types it has no predefined mappings for, or only an awkward
-      default mapping such as to a text string. A procedural language can be
-      designed so that its type mappings are also extensible, and an extension
-      can add mappings between new <productname>PostgreSQL</productname> types
-      and suitable types in the target language.
+      A routine's statically-declared parameter types (and, for a function,
+      return type) are found in the <literal>proargtypes</literal> and
+      <literal>prorettype</literal> columns of the
+      <classname>pg_proc</classname> row.
+      If a routine has <literal>OUT</literal> parameters, those types are
+      included in the <literal>proallargtypes</literal> column, and their names
+      in <literal>proargnames</literal>.
+      Convenience functions declared in <filename>funcapi.h</filename> are
+      available for extracting that information.
      </para>
 
      <para>
-      One mechanism <productname>PostgreSQL</productname> provides that may be
-      used for that purpose is <xref linkend="sql-createtransform"/>.
-      The command associates a <productname>PostgreSQL</productname> type and
-      a specific procedural language with a pair of functions to handle the
-      mapping of that type to a corresponding procedural language type and back.
+      The statically-declared types may include polymorphic types that need
+      to be resolved according to the actual types present at the call site,
+      as described in <xref linkend="xfunc-c-polymorphism"/>.
      </para>
 
-     <para>
-      For a procedural language to support transforms, its call handler is
-      responsible for consulting the <literal>protrftypes</literal> column of
-      a routine's <classname>pg_proc</classname> row to determine which types
-      should have transforms applied.
-      A convenience function <function>get_call_trftypes</function> is
-      available.
-      The call handler must then resolve the <quote>from SQL</quote> function
-      for each affected parameter type, and the <quote>to SQL</quote> function
-      for any affected result.
-      It may use the <function>get_transform_fromsql</function> and
-      <function>get_transform_tosql</function> functions for that.
-     </para>
+    </sect2>
 
-     <para>
-      The handler must then apply the proper <quote>from SQL</quote> functions
-      to all affected inputs (including elements within array or composite
-      types) and, after calling the target routine, apply the proper
-      <quote>to SQL</quote> functions similarly to any results.
-      If the target routine might interact with the database using SPI,
-      the handler may arrange for the requested transforms to be applied
-      in those operations as well.
-     </para>
+    <sect2 id="plhandler-call-types">
+     <title>Mapping to procedural language types</title>
 
      <para>
-      Because the procedural language implementation, and not
-      <productname>PostgreSQL</productname> itself, is responsible for calling
-      the transform functions, it is free to define what it will pass as the
-      parameter to each function (declared as <type>internal</type> for both),
-      and how it will interpret the result (also declared <type>internal</type>)
-      of the <quote>from SQL</quote> function. Effectively, each procedural
-      language's implementation defines the API that must be adhered to
-      by any author of transforms for that language.
+      Once the <productname>PostgreSQL</productname> types of any parameters
+      and results have been resolved, the handler must determine how it will
+      map their values to and from suitable types that exist in the procedural
+      language.
      </para>
 
      <para>
-      A procedural language might impose limits on where and how it will apply
-      transforms (such as on array or domain types). The
-      <function>get_transform_fromsql</function> and
-      <function>get_transform_tosql</function> functions mentioned above
-      consider each type only shallowly, and will not, for example, return
-      a transform function for a domain type if only its base type was listed in
-      the <literal>TRANSFORM</literal> clause.
-      If a procedural language's call handler does not implement transforms
-      at all, no <literal>TRANSFORM</literal> clause will have any effect
-      for routines declared in that language.
-      The language's validator function can be used to give immediate feedback
-      if a routine is declared with <literal>TRANSFORM</literal> clauses
-      the implementation cannot support.
+      The designer of a procedural language will typically document what types
+      will be supported and how they will be mapped, which could be as simple
+      as using every type's text input/output format to map it to the target
+      language's string type, or could directly map many types to corresponding
+      ones the target language provides. The handler function will implement
+      those rules.
      </para>
 
-    </sect3>
-
-   </sect2>
-
-   <sect2 id="plhandler-call-cache">
-    <title>Caching resolved routine information</title>
+     <sect3 id="plhandler-call-types-transform">
+      <title>Type transforms</title>
+
+      <para>
+       Because <productname>PostgreSQL</productname> is extensible, and
+       an extension can easily supply new types, a procedural language handler
+       may encounter types it has no predefined mappings for, or only an awkward
+       default mapping such as to a text string. A procedural language can be
+       designed so that its type mappings are also extensible, and an extension
+       can add mappings between new <productname>PostgreSQL</productname> types
+       and suitable types in the target language.
+      </para>
+
+      <para>
+       One mechanism <productname>PostgreSQL</productname> provides that may be
+       used for that purpose is <xref linkend="sql-createtransform"/>.
+       The command associates a <productname>PostgreSQL</productname> type and
+       a specific procedural language with a pair of functions to handle the
+       mapping of that type to a corresponding procedural language type
+       and back.
+      </para>
+
+      <para>
+       For a procedural language to support transforms, its call handler is
+       responsible for consulting the <literal>protrftypes</literal> column of
+       a routine's <classname>pg_proc</classname> row to determine which types
+       should have transforms applied.
+       A convenience function <function>get_call_trftypes</function> is
+       available.
+       The call handler must then resolve the <quote>from SQL</quote> function
+       for each affected parameter type, and the <quote>to SQL</quote> function
+       for any affected result.
+       It may use the <function>get_transform_fromsql</function> and
+       <function>get_transform_tosql</function> functions for that.
+      </para>
+
+      <para>
+       The handler must then apply the proper <quote>from SQL</quote> functions
+       to all affected inputs (including elements within array or composite
+       types) and, after calling the target routine, apply the proper
+       <quote>to SQL</quote> functions similarly to any results.
+       If the target routine might interact with the database using SPI,
+       the handler may arrange for the requested transforms to be applied
+       in those operations as well.
+      </para>
+
+      <para>
+       Because the procedural language implementation, and not
+       <productname>PostgreSQL</productname> itself, is responsible for calling
+       the transform functions, it is free to define what it will pass as the
+       parameter to each function (declared as <type>internal</type> for both),
+       and how it will interpret the result (also declared
+       <type>internal</type>) of the <quote>from SQL</quote> function.
+       Effectively, each procedural language's implementation defines the API
+       that must be adhered to by any author of transforms for that language.
+      </para>
+
+      <para>
+       A procedural language might impose limits on where and how it will apply
+       transforms (such as on array or domain types). The
+       <function>get_transform_fromsql</function> and
+       <function>get_transform_tosql</function> functions mentioned above
+       consider each type only shallowly, and will not, for example, return
+       a transform function for a domain type if only its base type was listed
+       in the <literal>TRANSFORM</literal> clause.
+       If a procedural language's call handler does not implement transforms
+       at all, no <literal>TRANSFORM</literal> clause will have any effect
+       for routines declared in that language.
+       The language's validator function can be used to give immediate feedback
+       if a routine is declared with <literal>TRANSFORM</literal> clauses
+       the implementation cannot support.
+      </para>
+
+     </sect3>
+
+    </sect2>
+
+    <sect2 id="plhandler-call-cache">
+     <title>Caching resolved routine information</title>
 
-   <para>
-    Often, the same routine is called many times per SQL statement.
-    A call handler can avoid repeated lookups of information about the
-    called routine by using the
-    <structfield>flinfo-&gt;fn_extra</structfield> field.  This will
-    initially be <symbol>NULL</symbol>, but can be set by the call handler to point at
-    information about the called routine.  On subsequent calls, if
-    <structfield>flinfo-&gt;fn_extra</structfield> is already non-<symbol>NULL</symbol>
-    then it can be used and the information lookup step skipped.  The
-    call handler must make sure that
-    <structfield>flinfo-&gt;fn_extra</structfield> is made to point at
-    memory that will live at least until the end of the current query,
-    since an <structname>FmgrInfo</structname> data structure could be
-    kept that long.  One way to do this is to allocate the extra data
-    in the memory context specified by
-    <structfield>flinfo-&gt;fn_mcxt</structfield>; such data will
-    normally have the same lifespan as the
-    <structname>FmgrInfo</structname> itself.  But the handler could
-    also choose to use a longer-lived memory context so that it can cache
-    routine definition information across queries.
-   </para>
+    <para>
+     Often, the same routine is called many times per SQL statement.
+     A call handler can avoid repeated lookups of information about the
+     called routine by using the
+     <structfield>flinfo-&gt;fn_extra</structfield> field.  This will
+     initially be <symbol>NULL</symbol>, but can be set by the call handler
+     to point at information about the called routine.  On subsequent calls,
+     if <structfield>flinfo-&gt;fn_extra</structfield> is already
+     non-<symbol>NULL</symbol> then it can be used and the information lookup
+     step skipped.  The call handler must make sure that
+     <structfield>flinfo-&gt;fn_extra</structfield> is made to point at
+     memory that will live at least until the end of the current query,
+     since an <structname>FmgrInfo</structname> data structure could be
+     kept that long.  One way to do this is to allocate the extra data
+     in the memory context specified by
+     <structfield>flinfo-&gt;fn_mcxt</structfield>; such data will
+     normally have the same lifespan as the
+     <structname>FmgrInfo</structname> itself.  But the handler could
+     also choose to use a longer-lived memory context so that it can cache
+     routine definition information across queries.
+    </para>
 
-   <para>
-    If the handler supports returning sets, and uses the ValuePerCall mode
-    helper macros described in <xref linkend="xfunc-c-return-set"/>, it must
-    not use <structfield>fn_extra</structfield> during set-returning calls.
-    The helper macros use that field for their own purposes. After
-    <literal>SRF_FIRSTCALL_INIT</literal> has been called, the field will point
-    to a <structname>FuncCallContext</structname> structure, which has
-    a <structfield>user_fctx</structfield> field that can be used similarly,
-    but only through the sequence of calls returning one set result.
-   </para>
+    <para>
+     If the handler supports returning sets, and uses the ValuePerCall mode
+     helper macros described in <xref linkend="xfunc-c-return-set"/>, it must
+     not use <structfield>fn_extra</structfield> during set-returning calls.
+     The helper macros use that field for their own purposes. After
+     <literal>SRF_FIRSTCALL_INIT</literal> has been called, the field will point
+     to a <structname>FuncCallContext</structname> structure, which has
+     a <structfield>user_fctx</structfield> field that can be used similarly,
+     but only through the sequence of calls returning one set result.
+    </para>
 
-   </sect2>
+    </sect2>
 
    </sect1>
 
    <sect1 id="plhandler-validator">
     <title>Validator function</title>
 
-   <para>
-    If a validator is provided by a procedural language, it
-    must be declared as a function taking a single parameter of type
-    <type>oid</type>.  The validator's result is ignored, so it is customarily
-    declared to return <type>void</type>.
-    The validator itself may be written in any procedural language able to
-    receive an <type>oid</type>-typed parameter and query system catalogs.
-   </para>
+    <para>
+     If a validator is provided by a procedural language, it
+     must be declared as a function taking a single parameter of type
+     <type>oid</type>.  The validator's result is ignored, so it is customarily
+     declared to return <type>void</type>.
+     The validator itself may be written in any procedural language able to
+     receive an <type>oid</type>-typed parameter and query system catalogs.
+    </para>
 
-   <para>
-    The validator will be called at
-    the end of a <command>CREATE FUNCTION</command> or
-    <command>CREATE PROCEDURE</command> command that has created
-    or updated a routine written in the procedural language.
-    The passed-in OID is the OID of the routine's <classname>pg_proc</classname>
-    row.  The validator must fetch this row in the usual way, and do
-    whatever checking is appropriate.
-   </para>
+    <para>
+     The validator will be called at
+     the end of a <command>CREATE FUNCTION</command> or
+     <command>CREATE PROCEDURE</command> command that has created
+     or updated a routine written in the procedural language.
+     The passed-in OID is the OID of the routine's
+     <classname>pg_proc</classname> row.  The validator must fetch this row
+     in the usual way, and do whatever checking is appropriate.
+    </para>
 
-   <para>
-    First, call <function>CheckFunctionValidatorAccess()</function> to diagnose
-    explicit calls to the validator that the user could not achieve through
-    <command>CREATE FUNCTION</command> or <command>CREATE PROCEDURE</command>.
-    Typical checks then include verifying
-    that the routine's argument and result types are supported by the
-    language, and that the routine's body is syntactically correct
-    in the language.  If the validator finds the routine to be okay,
-    it should just return.  If it finds an error, it should report that
-    via the normal <function>ereport()</function> error reporting mechanism.
-    Throwing an error will force a transaction rollback and thus prevent
-    the incorrect routine definition from being committed.
-   </para>
+    <para>
+     First, call <function>CheckFunctionValidatorAccess()</function>
+     to diagnose explicit calls to the validator that the user could not achieve
+     through <command>CREATE FUNCTION</command> or
+     <command>CREATE PROCEDURE</command>.
+     Typical checks then include verifying
+     that the routine's argument and result types are supported by the
+     language, and that the routine's body is syntactically correct
+     in the language.  If the validator finds the routine to be okay,
+     it should just return.  If it finds an error, it should report that
+     via the normal <function>ereport()</function> error reporting mechanism.
+     Throwing an error will force a transaction rollback and thus prevent
+     the incorrect routine definition from being committed.
+    </para>
 
-   <para>
-    Validator functions should typically honor the <xref
-    linkend="guc-check-function-bodies"/> parameter: if it is turned off then
-    any expensive or context-sensitive checking should be skipped.  If the
-    language provides for code execution at compilation time, the validator
-    must suppress checks that would induce such execution.  In particular,
-    this parameter is turned off by <application>pg_dump</application> so that it can
-    load procedural language routines without worrying about side effects or
-    dependencies of the routine bodies on other database objects.
-    (Because of this requirement, the call handler should avoid
-    assuming that the validator has fully checked the routine.  The point
-    of having a validator is not to let the call handler omit checks, but
-    to notify the user immediately if there are obvious errors in a
-    <command>CREATE FUNCTION</command> or <command>CREATE PROCEDURE</command>
-    command.)
-   </para>
+    <para>
+     Validator functions should typically honor the <xref
+     linkend="guc-check-function-bodies"/> parameter: if it is turned off then
+     any expensive or context-sensitive checking should be skipped.  If the
+     language provides for code execution at compilation time, the validator
+     must suppress checks that would induce such execution.  In particular,
+     this parameter is turned off by <application>pg_dump</application> so that
+     it can load procedural language routines without worrying about
+     side effects or dependencies of the routine bodies on other database
+     objects.
+     (Because of this requirement, the call handler should avoid
+     assuming that the validator has fully checked the routine.  The point
+     of having a validator is not to let the call handler omit checks, but
+     to notify the user immediately if there are obvious errors in a
+     <command>CREATE FUNCTION</command> or <command>CREATE PROCEDURE</command>
+     command.)
+    </para>
 
-   <para>
-    While the choice of exactly what to check is mostly left to the
-    discretion of the validator function, note that the core
-    <command>CREATE FUNCTION</command> and <command>CREATE PROCEDURE</command>
-    code only executes <literal>SET</literal> clauses
-    attached to a routine when <varname>check_function_bodies</varname> is on.
-    Therefore, checks whose results might be affected by GUC parameters
-    definitely should be skipped when <varname>check_function_bodies</varname> is
-    off, to avoid false failures when reloading a dump.
-   </para>
+    <para>
+     While the choice of exactly what to check is mostly left to the
+     discretion of the validator function, note that the core
+     <command>CREATE FUNCTION</command> and <command>CREATE PROCEDURE</command>
+     code only executes <literal>SET</literal> clauses
+     attached to a routine when <varname>check_function_bodies</varname> is on.
+     Therefore, checks whose results might be affected by GUC parameters
+     definitely should be skipped when <varname>check_function_bodies</varname>
+     is off, to avoid false failures when reloading a dump.
+    </para>
 
-   <para>
-    If a language's call handler does not apply parameter and return type
-    transforms, then no <literal>TRANSFORM</literal> clause in a routine
-    declaration will have any effect. To provide immediate feedback if a
-    declaration contains such a clause, the validator can report a suitable
-    error whenever the <literal>protrftypes</literal> column of the routine's
-    <classname>pg_proc</classname> row is non-null.
-   </para>
+    <para>
+     If a language's call handler does not apply parameter and return type
+     transforms, then no <literal>TRANSFORM</literal> clause in a routine
+     declaration will have any effect. To provide immediate feedback if a
+     declaration contains such a clause, the validator can report a suitable
+     error whenever the <literal>protrftypes</literal> column of the routine's
+     <classname>pg_proc</classname> row is non-null.
+    </para>
 
    </sect1>
 
    <sect1 id="plhandler-inline">
     <title>Inline handler function</title>
 
-   <para>
-    If this handler is provided by a procedural language, it
-    must be declared as a function taking a single parameter of type
-    <type>internal</type>, which will be a pointer
-    to an <structname>InlineCodeBlock</structname> struct when the handler
-    is called.  The result is ignored, so the return type is customarily
-    declared as <type>void</type>.
-    The inline handler itself may be written in any procedural language that
-    permits declaring an <type>internal</type> parameter with a suitable
-    language binding for accessing it as an
-    <structname>InlineCodeBlock</structname> struct.
-   </para>
+    <para>
+     If this handler is provided by a procedural language, it
+     must be declared as a function taking a single parameter of type
+     <type>internal</type>, which will be a pointer
+     to an <structname>InlineCodeBlock</structname> struct when the handler
+     is called.  The result is ignored, so the return type is customarily
+     declared as <type>void</type>.
+     The inline handler itself may be written in any procedural language that
+     permits declaring an <type>internal</type> parameter with a suitable
+     language binding for accessing it as an
+     <structname>InlineCodeBlock</structname> struct.
+    </para>
 
-   <para>
-    The inline handler
-    will be called when a <command>DO</command> statement is executed specifying
-    the procedural language.  The <structname>InlineCodeBlock</structname>
-    struct contains information
-    about the <command>DO</command> statement's parameters, in particular the
-    text of the anonymous code block to be executed.
-    It also contains the OID of the intended procedural language and whether
-    that procedural language is declared as <literal>TRUSTED</literal>, useful
-    if a single inline handler is supporting more than one procedural language.
-    The inline handler should execute the code block and return.
-   </para>
+    <para>
+     The inline handler
+     will be called when a <command>DO</command> statement is executed
+     specifying the procedural language.
+     The <structname>InlineCodeBlock</structname> struct contains information
+     about the <command>DO</command> statement's parameters, in particular the
+     text of the anonymous code block to be executed.
+     It also contains the OID of the intended procedural language and whether
+     that procedural language is declared as <literal>TRUSTED</literal>, useful
+     if a single inline handler is supporting more than one procedural language.
+     The inline handler should execute the code block and return.
+    </para>
 
    </sect1>
 
    <sect1 id="plhandler-packaging">
     <title>Packaging the language handlers</title>
 
-   <para>
-    It's recommended that you wrap all these function declarations,
-    as well as the <command>CREATE LANGUAGE</command> command itself, into
-    an <firstterm>extension</firstterm> so that a simple <command>CREATE EXTENSION</command>
-    command is sufficient to install the language.  See
-    <xref linkend="extend-extensions"/> for information about writing
-    extensions.
-   </para>
+    <para>
+     It's recommended that you wrap all these function declarations,
+     as well as the <command>CREATE LANGUAGE</command> command itself, into
+     an <firstterm>extension</firstterm> so that a simple
+     <command>CREATE EXTENSION</command> command is sufficient to install
+     the language.  See <xref linkend="extend-extensions"/> for information
+     about writing extensions.
+    </para>
 
    </sect1>
 
    <sect1 id="plhandler-examples">
     <title>Example code</title>
 
-   <para>
-    A template for a procedural-language handler written as a C extension is
-    provided in <literal>src/test/modules/plsample</literal>.  This is a
-    working sample demonstrating one way to create a procedural-language
-    handler, process parameters, and return a value.
-   </para>
+    <para>
+     A template for a procedural-language handler written as a C extension is
+     provided in <literal>src/test/modules/plsample</literal>.  This is a
+     working sample demonstrating one way to create a procedural-language
+     handler, process parameters, and return a value.
+    </para>
 
-   <para>
-    The procedural languages included in the standard distribution
-    are good references when trying to write your own language handler.
-    Look into the <filename>src/pl</filename> subdirectory of the source tree.
-    The <xref linkend="sql-createlanguage"/>
-    reference page also has some useful details.
-   </para>
+    <para>
+     The procedural languages included in the standard distribution
+     are good references when trying to write your own language handler.
+     Look into the <filename>src/pl</filename> subdirectory of the source tree.
+     The <xref linkend="sql-createlanguage"/>
+     reference page also has some useful details.
+    </para>
 
    </sect1>
 
-- 
2.7.3


--------------070002080407000808050907
Content-Type: text/x-patch;
 name="4.patch"
Content-Transfer-Encoding: 7bit
Content-Disposition: attachment;
 filename="4.patch"



^ permalink  raw  reply  [nested|flat] 2+ messages in thread


end of thread, other threads:[~2022-02-22 02:21 UTC | newest]

Thread overview: 2+ messages (download: mbox mbox.gz follow: Atom feed)
-- links below jump to the message on this page --
2021-02-27 07:45 [PATCH v2] Fix various shared memory estimates. Julien Rouhaud <[email protected]>
2022-02-22 02:21 [PATCH 3/4] Reindent and wrap between added sect1 tags Chapman Flack <[email protected]>

This inbox is served by agora; see mirroring instructions
for how to clone and mirror all data and code used for this inbox