public inbox for [email protected]
help / color / mirror / Atom feed[PATCH v18 08/18] tableam: finish_bulk_insert().
90+ messages / 20 participants
[nested] [flat]
* [PATCH v18 08/18] tableam: finish_bulk_insert().
@ 2019-03-08 00:31 Andres Freund <[email protected]>
0 siblings, 0 replies; 90+ messages in thread
From: Andres Freund @ 2019-03-08 00:31 UTC (permalink / raw)
Author:
Reviewed-By:
Discussion: https://postgr.es/m/
Backpatch:
---
src/backend/access/heap/heapam_handler.c | 12 ++++++++++++
src/backend/commands/copy.c | 7 +------
src/backend/commands/createas.c | 5 ++---
src/backend/commands/matview.c | 5 ++---
src/backend/commands/tablecmds.c | 4 +---
src/include/access/tableam.h | 18 ++++++++++++++++++
6 files changed, 36 insertions(+), 15 deletions(-)
diff --git a/src/backend/access/heap/heapam_handler.c b/src/backend/access/heap/heapam_handler.c
index ea8e3ee9ce5..3098cb96b60 100644
--- a/src/backend/access/heap/heapam_handler.c
+++ b/src/backend/access/heap/heapam_handler.c
@@ -541,6 +541,17 @@ retry:
return result;
}
+static void
+heapam_finish_bulk_insert(Relation relation, int options)
+{
+ /*
+ * If we skipped writing WAL, then we need to sync the heap (but not
+ * indexes since those use WAL anyway)
+ */
+ if (options & HEAP_INSERT_SKIP_WAL)
+ heap_sync(relation);
+}
+
/* ------------------------------------------------------------------------
* Definition of the heap table access method.
@@ -573,6 +584,7 @@ static const TableAmRoutine heapam_methods = {
.tuple_update = heapam_heap_update,
.multi_insert = heap_multi_insert,
.tuple_lock = heapam_lock_tuple,
+ .finish_bulk_insert = heapam_finish_bulk_insert,
.tuple_fetch_row_version = heapam_fetch_row_version,
.tuple_get_latest_tid = heap_get_latest_tid,
diff --git a/src/backend/commands/copy.c b/src/backend/commands/copy.c
index 312fd3bed31..1e7a06a72fb 100644
--- a/src/backend/commands/copy.c
+++ b/src/backend/commands/copy.c
@@ -3098,12 +3098,7 @@ CopyFrom(CopyState cstate)
FreeExecutorState(estate);
- /*
- * If we skipped writing WAL, then we need to sync the heap (but not
- * indexes since those use WAL anyway)
- */
- if (hi_options & HEAP_INSERT_SKIP_WAL)
- heap_sync(cstate->rel);
+ table_finish_bulk_insert(cstate->rel, hi_options);
return processed;
}
diff --git a/src/backend/commands/createas.c b/src/backend/commands/createas.c
index 0ac295cea3f..55f61854614 100644
--- a/src/backend/commands/createas.c
+++ b/src/backend/commands/createas.c
@@ -28,6 +28,7 @@
#include "access/reloptions.h"
#include "access/htup_details.h"
#include "access/sysattr.h"
+#include "access/tableam.h"
#include "access/xact.h"
#include "access/xlog.h"
#include "catalog/namespace.h"
@@ -601,9 +602,7 @@ intorel_shutdown(DestReceiver *self)
FreeBulkInsertState(myState->bistate);
- /* If we skipped using WAL, must heap_sync before commit */
- if (myState->hi_options & HEAP_INSERT_SKIP_WAL)
- heap_sync(myState->rel);
+ table_finish_bulk_insert(myState->rel, myState->hi_options);
/* close rel, but keep lock until commit */
table_close(myState->rel, NoLock);
diff --git a/src/backend/commands/matview.c b/src/backend/commands/matview.c
index 5a47be4b33c..62b76cfd358 100644
--- a/src/backend/commands/matview.c
+++ b/src/backend/commands/matview.c
@@ -18,6 +18,7 @@
#include "access/heapam.h"
#include "access/htup_details.h"
#include "access/multixact.h"
+#include "access/tableam.h"
#include "access/xact.h"
#include "access/xlog.h"
#include "catalog/catalog.h"
@@ -509,9 +510,7 @@ transientrel_shutdown(DestReceiver *self)
FreeBulkInsertState(myState->bistate);
- /* If we skipped using WAL, must heap_sync before commit */
- if (myState->hi_options & HEAP_INSERT_SKIP_WAL)
- heap_sync(myState->transientrel);
+ table_finish_bulk_insert(myState->transientrel, myState->hi_options);
/* close transientrel, but keep lock until commit */
table_close(myState->transientrel, NoLock);
diff --git a/src/backend/commands/tablecmds.c b/src/backend/commands/tablecmds.c
index 40839e14dbe..1f5a7e93155 100644
--- a/src/backend/commands/tablecmds.c
+++ b/src/backend/commands/tablecmds.c
@@ -4951,9 +4951,7 @@ ATRewriteTable(AlteredTableInfo *tab, Oid OIDNewHeap, LOCKMODE lockmode)
{
FreeBulkInsertState(bistate);
- /* If we skipped writing WAL, then we need to sync the heap. */
- if (hi_options & HEAP_INSERT_SKIP_WAL)
- heap_sync(newrel);
+ table_finish_bulk_insert(newrel, hi_options);
table_close(newrel, NoLock);
}
diff --git a/src/include/access/tableam.h b/src/include/access/tableam.h
index 7213d425e12..2c2d388dda6 100644
--- a/src/include/access/tableam.h
+++ b/src/include/access/tableam.h
@@ -284,6 +284,16 @@ typedef struct TableAmRoutine
uint8 flags,
HeapUpdateFailureData *hufd);
+ /*
+ * Perform operations necessary to complete insertions made via
+ * tuple_insert and multi_insert with a BulkInsertState specified. This
+ * e.g. may e.g. used to flush the relation when inserting with skipping
+ * WAL.
+ *
+ * May be NULL.
+ */
+ void (*finish_bulk_insert) (Relation rel, int options);
+
} TableAmRoutine;
@@ -687,6 +697,14 @@ table_lock_tuple(Relation rel, ItemPointer tid, Snapshot snapshot,
flags, hufd);
}
+static inline void
+table_finish_bulk_insert(Relation rel, int options)
+{
+ /* optional */
+ if (rel->rd_tableam && rel->rd_tableam->finish_bulk_insert)
+ rel->rd_tableam->finish_bulk_insert(rel, options);
+}
+
/* ----------------------------------------------------------------------------
* Functions to make modifications a bit simpler.
--
2.21.0.dirty
--yvn3crbc4qf4vymf
Content-Type: text/x-diff; charset=us-ascii
Content-Disposition: attachment;
filename="v18-0009-tableam-slotify-CREATE-TABLE-AS-and-CREATE-MATER.patch"
^ permalink raw reply [nested|flat] 90+ messages in thread
* MultiXact\SLRU buffers configuration
@ 2020-05-08 16:36 Andrey M. Borodin <[email protected]>
2020-05-11 11:17 ` Re: MultiXact\SLRU buffers configuration Andrey M. Borodin <[email protected]>
0 siblings, 1 reply; 90+ messages in thread
From: Andrey M. Borodin @ 2020-05-08 16:36 UTC (permalink / raw)
To: pgsql-hackers
Hi, hackers!
*** The problem ***
I'm investigating some cases of reduced database performance due to MultiXactOffsetLock contention (80% MultiXactOffsetLock, 20% IO DataFileRead).
The problem manifested itself during index repack and constraint validation. Both being effectively full table scans.
The database workload contains a lot of select for share\select for update queries. I've tried to construct synthetic world generator and could not achieve similar lock configuration: I see a lot of different locks in wait events, particularly a lot more MultiXactMemberLocks. But from my experiments with synthetic workload, contention of MultiXactOffsetLock can be reduced by increasing NUM_MXACTOFFSET_BUFFERS=8 to bigger numbers.
*** Question 1 ***
Is it safe to increase number of buffers of MultiXact\All SLRUs, recompile and run database as usual?
I cannot experiment much with production. But I'm mostly sure that bigger buffers will solve the problem.
*** Question 2 ***
Probably, we could do GUCs for SLRU sizes? Are there any reasons not to do them configurable? I think multis, clog, subtransactions and others will benefit from bigger buffer. But, probably, too much of knobs can be confusing.
*** Question 3 ***
MultiXact offset lock is always taken as exclusive lock. It turns MultiXact Offset subsystem to single threaded. If someone have good idea how to make it more concurrency-friendly, I'm willing to put some efforts into this.
Probably, I could just add LWlocks for each offset buffer page. Is it something worth doing? Or are there any hidden cavers and difficulties?
Thanks!
Best regards, Andrey Borodin.
^ permalink raw reply [nested|flat] 90+ messages in thread
* Re: MultiXact\SLRU buffers configuration
2020-05-08 16:36 MultiXact\SLRU buffers configuration Andrey M. Borodin <[email protected]>
@ 2020-05-11 11:17 ` Andrey M. Borodin <[email protected]>
2020-05-13 18:08 ` Re: MultiXact\SLRU buffers configuration Andrey M. Borodin <[email protected]>
0 siblings, 1 reply; 90+ messages in thread
From: Andrey M. Borodin @ 2020-05-11 11:17 UTC (permalink / raw)
To: pgsql-hackers
> 8 мая 2020 г., в 21:36, Andrey M. Borodin <[email protected]> написал(а):
>
> *** The problem ***
> I'm investigating some cases of reduced database performance due to MultiXactOffsetLock contention (80% MultiXactOffsetLock, 20% IO DataFileRead).
> The problem manifested itself during index repack and constraint validation. Both being effectively full table scans.
> The database workload contains a lot of select for share\select for update queries. I've tried to construct synthetic world generator and could not achieve similar lock configuration: I see a lot of different locks in wait events, particularly a lot more MultiXactMemberLocks. But from my experiments with synthetic workload, contention of MultiXactOffsetLock can be reduced by increasing NUM_MXACTOFFSET_BUFFERS=8 to bigger numbers.
>
> *** Question 1 ***
> Is it safe to increase number of buffers of MultiXact\All SLRUs, recompile and run database as usual?
> I cannot experiment much with production. But I'm mostly sure that bigger buffers will solve the problem.
>
> *** Question 2 ***
> Probably, we could do GUCs for SLRU sizes? Are there any reasons not to do them configurable? I think multis, clog, subtransactions and others will benefit from bigger buffer. But, probably, too much of knobs can be confusing.
>
> *** Question 3 ***
> MultiXact offset lock is always taken as exclusive lock. It turns MultiXact Offset subsystem to single threaded. If someone have good idea how to make it more concurrency-friendly, I'm willing to put some efforts into this.
> Probably, I could just add LWlocks for each offset buffer page. Is it something worth doing? Or are there any hidden cavers and difficulties?
I've created benchmark[0] imitating MultiXact pressure on my laptop: 7 clients are concurrently running select "select * from table where primary_key = ANY ($1) for share" where $1 is array of identifiers so that each tuple in a table is locked by different set of XIDs. During this benchmark I observe contention of MultiXactControlLock in pg_stat_activity
пятница, 8 мая 2020 г. 15:08:37 (every 1s)
pid | wait_event | wait_event_type | state | query
-------+----------------------------+-----------------+--------+----------------------------------------------------
41344 | ClientRead | Client | idle | insert into t1 select generate_series(1,1000000,1)
41375 | MultiXactOffsetControlLock | LWLock | active | select * from t1 where i = ANY ($1) for share
41377 | MultiXactOffsetControlLock | LWLock | active | select * from t1 where i = ANY ($1) for share
41378 | | | active | select * from t1 where i = ANY ($1) for share
41379 | MultiXactOffsetControlLock | LWLock | active | select * from t1 where i = ANY ($1) for share
41381 | | | active | select * from t1 where i = ANY ($1) for share
41383 | MultiXactOffsetControlLock | LWLock | active | select * from t1 where i = ANY ($1) for share
41385 | MultiXactOffsetControlLock | LWLock | active | select * from t1 where i = ANY ($1) for share
(8 rows)
Finally, the benchmark is measuring time to execute select for update 42 times.
I've went ahead and created 3 patches:
1. Configurable SLRU buffer sizes for MultiXacOffsets and MultiXactMembers
2. Reduce locking level to shared on read of MultiXactId members
3. Configurable cache size
I've found out that:
1. When MultiXact working set does not fit into buffers - benchmark results grow very high. Yet, very big buffers slow down benchmark too. For this benchmark optimal SLRU size id 32 pages for offsets and 64 pages for members (defaults are 8 and 16 respectively).
2. Lock optimisation increases performance by 5% on default SLRU sizes. Actually, benchmark does not explicitly read MultiXactId members, but when it replaces one with another - it have to read previous set. I understand that we can construct benchmark to demonstrate dominance of any algorithm and 5% of synthetic workload is not a very big number. But it just make sense to try to take shared lock for reading.
3. Manipulations with cache size do not affect benchmark anyhow. It's somewhat expected: benchmark is designed to defeat cache, either way OffsetControlLock would not be stressed.
For our workload, I think we will just increase numbers of SLRU sizes. But patchset may be useful for tuning and as a performance optimisation of MultiXact.
Also MultiXacts seems to be not very good fit into SLRU design. I think it would be better to use B-tree as a container. Or at least make MultiXact members extendable in-place (reserve some size when multixact is created).
When we want to extend number of locks for a tuple currently we will:
1. Iterate through all SLRU buffers for offsets to read current offset (with exclusive lock for offsets)
2. Iterate through all buffers for members to find current members (with exclusive lock for members)
3. Create new members array with +1 xid
4. Iterate through all cache members to find out maybe there are any such cache item as what we are going to create
5. iterate over 1 again for write
6. Iterate over 2 again for write
Obviously this does not scale well - we cannot increase SLRU sizes for too long.
Thanks! I'd be happy to hear any feedback.
Best regards, Andrey Borodin.
[0] https://github.com/x4m/multixact_stress
Attachments:
[application/octet-stream] v1-0001-Add-GUCs-to-tune-MultiXact-SLRUs.patch (6.2K, ../../[email protected]/2-v1-0001-Add-GUCs-to-tune-MultiXact-SLRUs.patch)
download | inline diff:
From 17ba50c29aafd2de81462e0aca70c8629076e52c Mon Sep 17 00:00:00 2001
From: Andrey Borodin <[email protected]>
Date: Sat, 9 May 2020 16:42:07 +0500
Subject: [PATCH v1 1/3] Add GUCs to tune MultiXact SLRUs
---
doc/src/sgml/config.sgml | 31 ++++++++++++++++++++++++++
src/backend/access/transam/multixact.c | 8 +++----
src/backend/utils/init/globals.c | 3 +++
src/backend/utils/misc/guc.c | 22 ++++++++++++++++++
src/include/access/multixact.h | 4 ----
src/include/miscadmin.h | 2 ++
6 files changed, 62 insertions(+), 8 deletions(-)
diff --git a/doc/src/sgml/config.sgml b/doc/src/sgml/config.sgml
index 3aea1763b4..71aa5c4900 100644
--- a/doc/src/sgml/config.sgml
+++ b/doc/src/sgml/config.sgml
@@ -1746,6 +1746,37 @@ include_dir 'conf.d'
</listitem>
</varlistentry>
+ <varlistentry id="guc-multixact-offsets-slru-buffers" xreflabel="multixact_offsets_slru_buffers">
+ <term><varname>multixact_offsets_slru_buffers</varname> (<type>integer</type>)
+ <indexterm>
+ <primary><varname>multixact_offsets_slru_buffers</varname> configuration parameter</primary>
+ </indexterm>
+ </term>
+ <listitem>
+ <para>
+ Specifies the amount of memory to be used for MultiXact offsets. MultiXact offsets
+ are used to store informaion about offsets of multiple row lockers (caused by SELECT FOR UPDATE and others).
+ It defaults to 64 kilobytes (<literal>64KB</literal>).
+ </para>
+ </listitem>
+ </varlistentry>
+
+ <varlistentry id="guc-multixact-members-slru-buffers" xreflabel="multixact_members_slru_buffers">
+ <term><varname>multixact_members_slru_buffers</varname> (<type>integer</type>)
+ <indexterm>
+ <primary><varname>multixact_members_slru_buffers</varname> configuration parameter</primary>
+ </indexterm>
+ </term>
+ <listitem>
+ <para>
+ Specifies the amount of memory to be used for MultiXact members. MultiXact members
+ are used to store informaion about XIDs of multiple row lockers. Tipically <varname>multixact_members_slru_buffers</varname>
+ is twice more than <varname>multixact_offsets_slru_buffers</varname>.
+ It defaults to 128 kilobytes (<literal>128KB</literal>).
+ </para>
+ </listitem>
+ </varlistentry>
+
<varlistentry id="guc-max-stack-depth" xreflabel="max_stack_depth">
<term><varname>max_stack_depth</varname> (<type>integer</type>)
<indexterm>
diff --git a/src/backend/access/transam/multixact.c b/src/backend/access/transam/multixact.c
index e2aa5c9ce4..d2ac029b98 100644
--- a/src/backend/access/transam/multixact.c
+++ b/src/backend/access/transam/multixact.c
@@ -1812,8 +1812,8 @@ MultiXactShmemSize(void)
mul_size(sizeof(MultiXactId) * 2, MaxOldestSlot))
size = SHARED_MULTIXACT_STATE_SIZE;
- size = add_size(size, SimpleLruShmemSize(NUM_MXACTOFFSET_BUFFERS, 0));
- size = add_size(size, SimpleLruShmemSize(NUM_MXACTMEMBER_BUFFERS, 0));
+ size = add_size(size, SimpleLruShmemSize(multixact_offsets_slru_buffers, 0));
+ size = add_size(size, SimpleLruShmemSize(multixact_members_slru_buffers, 0));
return size;
}
@@ -1829,11 +1829,11 @@ MultiXactShmemInit(void)
MultiXactMemberCtl->PagePrecedes = MultiXactMemberPagePrecedes;
SimpleLruInit(MultiXactOffsetCtl,
- "multixact_offset", NUM_MXACTOFFSET_BUFFERS, 0,
+ "multixact_offset", multixact_offsets_slru_buffers, 0,
MultiXactOffsetControlLock, "pg_multixact/offsets",
LWTRANCHE_MXACTOFFSET_BUFFERS);
SimpleLruInit(MultiXactMemberCtl,
- "multixact_member", NUM_MXACTMEMBER_BUFFERS, 0,
+ "multixact_member", multixact_members_slru_buffers, 0,
MultiXactMemberControlLock, "pg_multixact/members",
LWTRANCHE_MXACTMEMBER_BUFFERS);
diff --git a/src/backend/utils/init/globals.c b/src/backend/utils/init/globals.c
index eb19644419..aebfbdb67c 100644
--- a/src/backend/utils/init/globals.c
+++ b/src/backend/utils/init/globals.c
@@ -148,3 +148,6 @@ int VacuumCostBalance = 0; /* working state for vacuum */
bool VacuumCostActive = false;
double vacuum_cleanup_index_scale_factor;
+
+int multixact_offsets_slru_buffers = 8;
+int multixact_members_slru_buffers = 16;
diff --git a/src/backend/utils/misc/guc.c b/src/backend/utils/misc/guc.c
index 5bdc02fce2..b139e387f3 100644
--- a/src/backend/utils/misc/guc.c
+++ b/src/backend/utils/misc/guc.c
@@ -2270,6 +2270,28 @@ static struct config_int ConfigureNamesInt[] =
NULL, NULL, NULL
},
+ {
+ {"multixact_offsets_slru_buffers", PGC_POSTMASTER, RESOURCES_MEM,
+ gettext_noop("Sets the number of shared memory buffers used for MultiXact offsets SLRU."),
+ NULL,
+ GUC_UNIT_BLOCKS
+ },
+ &multixact_offsets_slru_buffers,
+ 8, 2, INT_MAX / 2,
+ NULL, NULL, NULL
+ },
+
+ {
+ {"multixact_members_slru_buffers", PGC_POSTMASTER, RESOURCES_MEM,
+ gettext_noop("Sets the number of shared memory buffers used for MultiXact members SLRU."),
+ NULL,
+ GUC_UNIT_BLOCKS
+ },
+ &multixact_members_slru_buffers,
+ 16, 2, INT_MAX / 2,
+ NULL, NULL, NULL
+ },
+
{
{"temp_buffers", PGC_USERSET, RESOURCES_MEM,
gettext_noop("Sets the maximum number of temporary buffers used by each session."),
diff --git a/src/include/access/multixact.h b/src/include/access/multixact.h
index af4aac08bd..848398bf1e 100644
--- a/src/include/access/multixact.h
+++ b/src/include/access/multixact.h
@@ -28,10 +28,6 @@
#define MaxMultiXactOffset ((MultiXactOffset) 0xFFFFFFFF)
-/* Number of SLRU buffers to use for multixact */
-#define NUM_MXACTOFFSET_BUFFERS 8
-#define NUM_MXACTMEMBER_BUFFERS 16
-
/*
* Possible multixact lock modes ("status"). The first four modes are for
* tuple locks (FOR KEY SHARE, FOR SHARE, FOR NO KEY UPDATE, FOR UPDATE); the
diff --git a/src/include/miscadmin.h b/src/include/miscadmin.h
index 14fa127ab1..95f4633a88 100644
--- a/src/include/miscadmin.h
+++ b/src/include/miscadmin.h
@@ -161,6 +161,8 @@ extern PGDLLIMPORT int MaxBackends;
extern PGDLLIMPORT int MaxConnections;
extern PGDLLIMPORT int max_worker_processes;
extern PGDLLIMPORT int max_parallel_workers;
+extern PGDLLIMPORT int multixact_offsets_slru_buffers;
+extern PGDLLIMPORT int multixact_members_slru_buffers;
extern PGDLLIMPORT int MyProcPid;
extern PGDLLIMPORT pg_time_t MyStartTime;
--
2.24.2 (Apple Git-127)
[application/octet-stream] v1-0002-Use-shared-lock-in-GetMultiXactIdMembers-for-offs.patch (7.6K, ../../[email protected]/3-v1-0002-Use-shared-lock-in-GetMultiXactIdMembers-for-offs.patch)
download | inline diff:
From 0a0ebc6391c33ca77260656d886224c71fb8ad96 Mon Sep 17 00:00:00 2001
From: Andrey Borodin <[email protected]>
Date: Sat, 9 May 2020 21:19:18 +0500
Subject: [PATCH v1 2/3] Use shared lock in GetMultiXactIdMembers for offsets
and members
Previously read of multixact required exclusive control locks in
offstes and members SLRUs. This could lead to contention.
In this commit we take advantge of SimpleLruReadPage_ReadOnly
similar to CLOG usage.
---
src/backend/access/transam/clog.c | 2 +-
src/backend/access/transam/commit_ts.c | 2 +-
src/backend/access/transam/multixact.c | 12 ++++++------
src/backend/access/transam/slru.c | 8 +++++---
src/backend/access/transam/subtrans.c | 2 +-
src/backend/commands/async.c | 2 +-
src/backend/storage/lmgr/predicate.c | 2 +-
src/include/access/slru.h | 2 +-
8 files changed, 17 insertions(+), 15 deletions(-)
diff --git a/src/backend/access/transam/clog.c b/src/backend/access/transam/clog.c
index f8e7670f8d..2ae024608e 100644
--- a/src/backend/access/transam/clog.c
+++ b/src/backend/access/transam/clog.c
@@ -643,7 +643,7 @@ TransactionIdGetStatus(TransactionId xid, XLogRecPtr *lsn)
/* lock is acquired by SimpleLruReadPage_ReadOnly */
- slotno = SimpleLruReadPage_ReadOnly(ClogCtl, pageno, xid);
+ slotno = SimpleLruReadPage_ReadOnly(ClogCtl, pageno, xid, false);
byteptr = ClogCtl->shared->page_buffer[slotno] + byteno;
status = (*byteptr >> bshift) & CLOG_XACT_BITMASK;
diff --git a/src/backend/access/transam/commit_ts.c b/src/backend/access/transam/commit_ts.c
index 630df672cc..1efa269339 100644
--- a/src/backend/access/transam/commit_ts.c
+++ b/src/backend/access/transam/commit_ts.c
@@ -342,7 +342,7 @@ TransactionIdGetCommitTsData(TransactionId xid, TimestampTz *ts,
}
/* lock is acquired by SimpleLruReadPage_ReadOnly */
- slotno = SimpleLruReadPage_ReadOnly(CommitTsCtl, pageno, xid);
+ slotno = SimpleLruReadPage_ReadOnly(CommitTsCtl, pageno, xid, false);
memcpy(&entry,
CommitTsCtl->shared->page_buffer[slotno] +
SizeOfCommitTimestampEntry * entryno,
diff --git a/src/backend/access/transam/multixact.c b/src/backend/access/transam/multixact.c
index d2ac029b98..5387a3602d 100644
--- a/src/backend/access/transam/multixact.c
+++ b/src/backend/access/transam/multixact.c
@@ -1321,12 +1321,12 @@ GetMultiXactIdMembers(MultiXactId multi, MultiXactMember **members,
* time on every multixact creation.
*/
retry:
- LWLockAcquire(MultiXactOffsetControlLock, LW_EXCLUSIVE);
pageno = MultiXactIdToOffsetPage(multi);
entryno = MultiXactIdToOffsetEntry(multi);
- slotno = SimpleLruReadPage(MultiXactOffsetCtl, pageno, true, multi);
+ /* lock is acquired by SimpleLruReadPage_ReadOnly */
+ slotno = SimpleLruReadPage_ReadOnly(MultiXactOffsetCtl, pageno, multi, false);
offptr = (MultiXactOffset *) MultiXactOffsetCtl->shared->page_buffer[slotno];
offptr += entryno;
offset = *offptr;
@@ -1358,7 +1358,7 @@ retry:
entryno = MultiXactIdToOffsetEntry(tmpMXact);
if (pageno != prev_pageno)
- slotno = SimpleLruReadPage(MultiXactOffsetCtl, pageno, true, tmpMXact);
+ slotno = SimpleLruReadPage_ReadOnly(MultiXactOffsetCtl, pageno, tmpMXact, true);
offptr = (MultiXactOffset *) MultiXactOffsetCtl->shared->page_buffer[slotno];
offptr += entryno;
@@ -1382,7 +1382,7 @@ retry:
*members = ptr;
/* Now get the members themselves. */
- LWLockAcquire(MultiXactMemberControlLock, LW_EXCLUSIVE);
+ LWLockAcquire(MultiXactMemberControlLock, LW_SHARED);
truelength = 0;
prev_pageno = -1;
@@ -1399,7 +1399,7 @@ retry:
if (pageno != prev_pageno)
{
- slotno = SimpleLruReadPage(MultiXactMemberCtl, pageno, true, multi);
+ slotno = SimpleLruReadPage_ReadOnly(MultiXactMemberCtl, pageno, multi, true);
prev_pageno = pageno;
}
@@ -2745,7 +2745,7 @@ find_multixact_start(MultiXactId multi, MultiXactOffset *result)
return false;
/* lock is acquired by SimpleLruReadPage_ReadOnly */
- slotno = SimpleLruReadPage_ReadOnly(MultiXactOffsetCtl, pageno, multi);
+ slotno = SimpleLruReadPage_ReadOnly(MultiXactOffsetCtl, pageno, multi, false);
offptr = (MultiXactOffset *) MultiXactOffsetCtl->shared->page_buffer[slotno];
offptr += entryno;
offset = *offptr;
diff --git a/src/backend/access/transam/slru.c b/src/backend/access/transam/slru.c
index b2316af779..ae63ad4e6c 100644
--- a/src/backend/access/transam/slru.c
+++ b/src/backend/access/transam/slru.c
@@ -470,17 +470,19 @@ SimpleLruReadPage(SlruCtl ctl, int pageno, bool write_ok,
* Return value is the shared-buffer slot number now holding the page.
* The buffer's LRU access info is updated.
*
- * Control lock must NOT be held at entry, but will be held at exit.
+ * Control lock will be held at exit. If lock_held is true at least
+ * shared control lock must be held.
* It is unspecified whether the lock will be shared or exclusive.
*/
int
-SimpleLruReadPage_ReadOnly(SlruCtl ctl, int pageno, TransactionId xid)
+SimpleLruReadPage_ReadOnly(SlruCtl ctl, int pageno, TransactionId xid, bool lock_held)
{
SlruShared shared = ctl->shared;
int slotno;
/* Try to find the page while holding only shared lock */
- LWLockAcquire(shared->ControlLock, LW_SHARED);
+ if (!lock_held)
+ LWLockAcquire(shared->ControlLock, LW_SHARED);
/* See if page is already in a buffer */
for (slotno = 0; slotno < shared->num_slots; slotno++)
diff --git a/src/backend/access/transam/subtrans.c b/src/backend/access/transam/subtrans.c
index 25d7d739cf..98700f26a7 100644
--- a/src/backend/access/transam/subtrans.c
+++ b/src/backend/access/transam/subtrans.c
@@ -123,7 +123,7 @@ SubTransGetParent(TransactionId xid)
/* lock is acquired by SimpleLruReadPage_ReadOnly */
- slotno = SimpleLruReadPage_ReadOnly(SubTransCtl, pageno, xid);
+ slotno = SimpleLruReadPage_ReadOnly(SubTransCtl, pageno, xid, false);
ptr = (TransactionId *) SubTransCtl->shared->page_buffer[slotno];
ptr += entryno;
diff --git a/src/backend/commands/async.c b/src/backend/commands/async.c
index 0c9d20ebfc..a12447ecb5 100644
--- a/src/backend/commands/async.c
+++ b/src/backend/commands/async.c
@@ -2005,7 +2005,7 @@ asyncQueueReadAllNotifications(void)
* of the page we will actually inspect.
*/
slotno = SimpleLruReadPage_ReadOnly(AsyncCtl, curpage,
- InvalidTransactionId);
+ InvalidTransactionId, false);
if (curpage == QUEUE_POS_PAGE(head))
{
/* we only want to read as far as head */
diff --git a/src/backend/storage/lmgr/predicate.c b/src/backend/storage/lmgr/predicate.c
index 654584b77a..2969992a90 100644
--- a/src/backend/storage/lmgr/predicate.c
+++ b/src/backend/storage/lmgr/predicate.c
@@ -948,7 +948,7 @@ OldSerXidGetMinConflictCommitSeqNo(TransactionId xid)
* but will return with that lock held, which must then be released.
*/
slotno = SimpleLruReadPage_ReadOnly(OldSerXidSlruCtl,
- OldSerXidPage(xid), xid);
+ OldSerXidPage(xid), xid, false);
val = OldSerXidValue(slotno, xid);
LWLockRelease(OldSerXidLock);
return val;
diff --git a/src/include/access/slru.h b/src/include/access/slru.h
index 00dbd803e1..916dd8203e 100644
--- a/src/include/access/slru.h
+++ b/src/include/access/slru.h
@@ -144,7 +144,7 @@ extern int SimpleLruZeroPage(SlruCtl ctl, int pageno);
extern int SimpleLruReadPage(SlruCtl ctl, int pageno, bool write_ok,
TransactionId xid);
extern int SimpleLruReadPage_ReadOnly(SlruCtl ctl, int pageno,
- TransactionId xid);
+ TransactionId xid, bool lock_held);
extern void SimpleLruWritePage(SlruCtl ctl, int slotno);
extern void SimpleLruFlush(SlruCtl ctl, bool allow_redirtied);
extern void SimpleLruTruncate(SlruCtl ctl, int cutoffPage);
--
2.24.2 (Apple Git-127)
[application/octet-stream] v1-0003-Make-MultiXact-local-cache-size-configurable.patch (3.7K, ../../[email protected]/4-v1-0003-Make-MultiXact-local-cache-size-configurable.patch)
download | inline diff:
From 944551228e4c2b4ec015359821122d9676fcf7e0 Mon Sep 17 00:00:00 2001
From: Andrey Borodin <[email protected]>
Date: Mon, 11 May 2020 16:17:02 +0500
Subject: [PATCH v1 3/3] Make MultiXact local cache size configurable
---
doc/src/sgml/config.sgml | 16 ++++++++++++++++
src/backend/access/transam/multixact.c | 2 +-
src/backend/utils/init/globals.c | 1 +
src/backend/utils/misc/guc.c | 10 ++++++++++
src/include/miscadmin.h | 1 +
5 files changed, 29 insertions(+), 1 deletion(-)
diff --git a/doc/src/sgml/config.sgml b/doc/src/sgml/config.sgml
index 71aa5c4900..6dbc3ce5f1 100644
--- a/doc/src/sgml/config.sgml
+++ b/doc/src/sgml/config.sgml
@@ -1777,6 +1777,22 @@ include_dir 'conf.d'
</listitem>
</varlistentry>
+ <varlistentry id="guc-multixact-local-cache-entries" xreflabel="multixact_local-cache-entries">
+ <term><varname>multixact_local_cache_entries</varname> (<type>integer</type>)
+ <indexterm>
+ <primary><varname>multixact_local_cache_entries</varname> configuration parameter</primary>
+ </indexterm>
+ </term>
+ <listitem>
+ <para>
+ Specifies the number cached MultiXact by backend. Any SLRU lookup is preceeded
+ by cache lookup. Higher numbers of cache size help to deduplicate lock sets, while
+ lower values make cache lookup faster.
+ It defaults to 256.
+ </para>
+ </listitem>
+ </varlistentry>
+
<varlistentry id="guc-max-stack-depth" xreflabel="max_stack_depth">
<term><varname>max_stack_depth</varname> (<type>integer</type>)
<indexterm>
diff --git a/src/backend/access/transam/multixact.c b/src/backend/access/transam/multixact.c
index 5387a3602d..62f9bf73eb 100644
--- a/src/backend/access/transam/multixact.c
+++ b/src/backend/access/transam/multixact.c
@@ -1589,7 +1589,7 @@ mXactCachePut(MultiXactId multi, int nmembers, MultiXactMember *members)
qsort(entry->members, nmembers, sizeof(MultiXactMember), mxactMemberComparator);
dlist_push_head(&MXactCache, &entry->node);
- if (MXactCacheMembers++ >= MAX_CACHE_ENTRIES)
+ if (MXactCacheMembers++ >= multixact_local_cache_entries)
{
dlist_node *node;
mXactCacheEnt *entry;
diff --git a/src/backend/utils/init/globals.c b/src/backend/utils/init/globals.c
index aebfbdb67c..b17382293c 100644
--- a/src/backend/utils/init/globals.c
+++ b/src/backend/utils/init/globals.c
@@ -151,3 +151,4 @@ double vacuum_cleanup_index_scale_factor;
int multixact_offsets_slru_buffers = 8;
int multixact_members_slru_buffers = 16;
+int multixact_local_cache_entries = 256;
diff --git a/src/backend/utils/misc/guc.c b/src/backend/utils/misc/guc.c
index b139e387f3..a74f8a8f20 100644
--- a/src/backend/utils/misc/guc.c
+++ b/src/backend/utils/misc/guc.c
@@ -2292,6 +2292,16 @@ static struct config_int ConfigureNamesInt[] =
NULL, NULL, NULL
},
+ {
+ {"multixact_local_cache_entries", PGC_SUSET, RESOURCES_MEM,
+ gettext_noop("Sets the number cached MultiXact by backend."),
+ NULL
+ },
+ &multixact_local_cache_entries,
+ 256, 2, INT_MAX / 2,
+ NULL, NULL, NULL
+ },
+
{
{"temp_buffers", PGC_USERSET, RESOURCES_MEM,
gettext_noop("Sets the maximum number of temporary buffers used by each session."),
diff --git a/src/include/miscadmin.h b/src/include/miscadmin.h
index 95f4633a88..27d5170ff1 100644
--- a/src/include/miscadmin.h
+++ b/src/include/miscadmin.h
@@ -163,6 +163,7 @@ extern PGDLLIMPORT int max_worker_processes;
extern PGDLLIMPORT int max_parallel_workers;
extern PGDLLIMPORT int multixact_offsets_slru_buffers;
extern PGDLLIMPORT int multixact_members_slru_buffers;
+extern PGDLLIMPORT int multixact_local_cache_entries;
extern PGDLLIMPORT int MyProcPid;
extern PGDLLIMPORT pg_time_t MyStartTime;
--
2.24.2 (Apple Git-127)
^ permalink raw reply [nested|flat] 90+ messages in thread
* Re: MultiXact\SLRU buffers configuration
2020-05-08 16:36 MultiXact\SLRU buffers configuration Andrey M. Borodin <[email protected]>
2020-05-11 11:17 ` Re: MultiXact\SLRU buffers configuration Andrey M. Borodin <[email protected]>
@ 2020-05-13 18:08 ` Andrey M. Borodin <[email protected]>
2020-05-14 01:25 ` Re: MultiXact\SLRU buffers configuration Kyotaro Horiguchi <[email protected]>
0 siblings, 1 reply; 90+ messages in thread
From: Andrey M. Borodin @ 2020-05-13 18:08 UTC (permalink / raw)
To: pgsql-hackers
> 11 мая 2020 г., в 16:17, Andrey M. Borodin <[email protected]> написал(а):
>
> I've went ahead and created 3 patches:
> 1. Configurable SLRU buffer sizes for MultiXacOffsets and MultiXactMembers
> 2. Reduce locking level to shared on read of MultiXactId members
> 3. Configurable cache size
I'm looking more at MultiXact and it seems to me that we have a race condition there.
When we create a new MultiXact we do:
1. Generate new MultiXactId under MultiXactGenLock
2. Record new mxid with members and offset to WAL
3. Write offset to SLRU under MultiXactOffsetControlLock
4. Write members to SLRU under MultiXactMemberControlLock
When we read MultiXact we do:
1. Retrieve offset by mxid from SLRU under MultiXactOffsetControlLock
2. If offset is 0 - it's not filled in at step 4 of previous algorithm, we sleep and goto 1
3. Retrieve members from SLRU under MultiXactMemberControlLock
4. ..... what we do if there are just zeroes because step 4 is not executed yet? Nothing, return empty members list.
What am I missing?
Best regards, Andrey Borodin.
^ permalink raw reply [nested|flat] 90+ messages in thread
* Re: MultiXact\SLRU buffers configuration
2020-05-08 16:36 MultiXact\SLRU buffers configuration Andrey M. Borodin <[email protected]>
2020-05-11 11:17 ` Re: MultiXact\SLRU buffers configuration Andrey M. Borodin <[email protected]>
2020-05-13 18:08 ` Re: MultiXact\SLRU buffers configuration Andrey M. Borodin <[email protected]>
@ 2020-05-14 01:25 ` Kyotaro Horiguchi <[email protected]>
2020-05-14 05:19 ` Re: MultiXact\SLRU buffers configuration Andrey M. Borodin <[email protected]>
0 siblings, 1 reply; 90+ messages in thread
From: Kyotaro Horiguchi @ 2020-05-14 01:25 UTC (permalink / raw)
To: [email protected]; +Cc: pgsql-hackers
At Wed, 13 May 2020 23:08:37 +0500, "Andrey M. Borodin" <[email protected]> wrote in
>
>
> > 11 мая 2020 г., в 16:17, Andrey M. Borodin <[email protected]> написал(а):
> >
> > I've went ahead and created 3 patches:
> > 1. Configurable SLRU buffer sizes for MultiXacOffsets and MultiXactMembers
> > 2. Reduce locking level to shared on read of MultiXactId members
> > 3. Configurable cache size
>
> I'm looking more at MultiXact and it seems to me that we have a race condition there.
>
> When we create a new MultiXact we do:
> 1. Generate new MultiXactId under MultiXactGenLock
> 2. Record new mxid with members and offset to WAL
> 3. Write offset to SLRU under MultiXactOffsetControlLock
> 4. Write members to SLRU under MultiXactMemberControlLock
But, don't we hold exclusive lock on the buffer through all the steps
above?
> When we read MultiXact we do:
> 1. Retrieve offset by mxid from SLRU under MultiXactOffsetControlLock
> 2. If offset is 0 - it's not filled in at step 4 of previous algorithm, we sleep and goto 1
> 3. Retrieve members from SLRU under MultiXactMemberControlLock
> 4. ..... what we do if there are just zeroes because step 4 is not executed yet? Nothing, return empty members list.
So transactions never see such incomplete mxids, I believe.
> What am I missing?
regards.
--
Kyotaro Horiguchi
NTT Open Source Software Center
^ permalink raw reply [nested|flat] 90+ messages in thread
* Re: MultiXact\SLRU buffers configuration
2020-05-08 16:36 MultiXact\SLRU buffers configuration Andrey M. Borodin <[email protected]>
2020-05-11 11:17 ` Re: MultiXact\SLRU buffers configuration Andrey M. Borodin <[email protected]>
2020-05-13 18:08 ` Re: MultiXact\SLRU buffers configuration Andrey M. Borodin <[email protected]>
2020-05-14 01:25 ` Re: MultiXact\SLRU buffers configuration Kyotaro Horiguchi <[email protected]>
@ 2020-05-14 05:19 ` Andrey M. Borodin <[email protected]>
2020-05-14 06:16 ` Re: MultiXact\SLRU buffers configuration Kyotaro Horiguchi <[email protected]>
0 siblings, 1 reply; 90+ messages in thread
From: Andrey M. Borodin @ 2020-05-14 05:19 UTC (permalink / raw)
To: Kyotaro Horiguchi <[email protected]>; +Cc: pgsql-hackers
> 14 мая 2020 г., в 06:25, Kyotaro Horiguchi <[email protected]> написал(а):
>
> At Wed, 13 May 2020 23:08:37 +0500, "Andrey M. Borodin" <[email protected]> wrote in
>>
>>
>>> 11 мая 2020 г., в 16:17, Andrey M. Borodin <[email protected]> написал(а):
>>>
>>> I've went ahead and created 3 patches:
>>> 1. Configurable SLRU buffer sizes for MultiXacOffsets and MultiXactMembers
>>> 2. Reduce locking level to shared on read of MultiXactId members
>>> 3. Configurable cache size
>>
>> I'm looking more at MultiXact and it seems to me that we have a race condition there.
>>
>> When we create a new MultiXact we do:
>> 1. Generate new MultiXactId under MultiXactGenLock
>> 2. Record new mxid with members and offset to WAL
>> 3. Write offset to SLRU under MultiXactOffsetControlLock
>> 4. Write members to SLRU under MultiXactMemberControlLock
>
> But, don't we hold exclusive lock on the buffer through all the steps
> above?
Yes...Unless MultiXact is observed on StandBy. This could lead to observing inconsistent snapshot: one of lockers committed tuple delete, but standby sees it as alive.
>> When we read MultiXact we do:
>> 1. Retrieve offset by mxid from SLRU under MultiXactOffsetControlLock
>> 2. If offset is 0 - it's not filled in at step 4 of previous algorithm, we sleep and goto 1
>> 3. Retrieve members from SLRU under MultiXactMemberControlLock
>> 4. ..... what we do if there are just zeroes because step 4 is not executed yet? Nothing, return empty members list.
>
> So transactions never see such incomplete mxids, I believe.
I've observed sleep in step 2. I believe it's possible to observe special effects of step 4 too.
Maybe we could add lock on standby to dismiss this 1000us wait? Sometimes it hits hard on Standbys: if someone is locking whole table on primary - all seq scans on standbys follow him with MultiXactOffsetControlLock contention.
It looks like this:
0x00007fcd56896ff7 in __GI___select (nfds=nfds@entry=0, readfds=readfds@entry=0x0, writefds=writefds@entry=0x0, exceptfds=exceptfds@entry=0x0, timeout=timeout@entry=0x7ffd83376fe0) at ../sysdeps/unix/sysv/linux/select.c:41
#0 0x00007fcd56896ff7 in __GI___select (nfds=nfds@entry=0, readfds=readfds@entry=0x0, writefds=writefds@entry=0x0, exceptfds=exceptfds@entry=0x0, timeout=timeout@entry=0x7ffd83376fe0) at ../sysdeps/unix/sysv/linux/select.c:41
#1 0x000056186e0d54bd in pg_usleep (microsec=microsec@entry=1000) at ./build/../src/port/pgsleep.c:56
#2 0x000056186dd5edf2 in GetMultiXactIdMembers (from_pgupgrade=0 '\000', onlyLock=<optimized out>, members=0x7ffd83377080, multi=3106214809) at ./build/../src/backend/access/transam/multixact.c:1370
#3 GetMultiXactIdMembers () at ./build/../src/backend/access/transam/multixact.c:1202
#4 0x000056186dd2d2d9 in MultiXactIdGetUpdateXid (xmax=<optimized out>, t_infomask=<optimized out>) at ./build/../src/backend/access/heap/heapam.c:7039
#5 0x000056186dd35098 in HeapTupleGetUpdateXid (tuple=tuple@entry=0x7fcba3b63d58) at ./build/../src/backend/access/heap/heapam.c:7080
#6 0x000056186e0cd0f8 in HeapTupleSatisfiesMVCC (htup=<optimized out>, snapshot=0x56186f44a058, buffer=230684) at ./build/../src/backend/utils/time/tqual.c:1091
#7 0x000056186dd2d922 in heapgetpage (scan=scan@entry=0x56186f4c8e78, page=page@entry=3620) at ./build/../src/backend/access/heap/heapam.c:439
#8 0x000056186dd2ea7c in heapgettup_pagemode (key=0x0, nkeys=0, dir=ForwardScanDirection, scan=0x56186f4c8e78) at ./build/../src/backend/access/heap/heapam.c:1034
#9 heap_getnext (scan=scan@entry=0x56186f4c8e78, direction=direction@entry=ForwardScanDirection) at ./build/../src/backend/access/heap/heapam.c:1801
#10 0x000056186de84f51 in SeqNext (node=node@entry=0x56186f4a4f78) at ./build/../src/backend/executor/nodeSeqscan.c:81
#11 0x000056186de6a3f1 in ExecScanFetch (recheckMtd=0x56186de84ef0 <SeqRecheck>, accessMtd=0x56186de84f20 <SeqNext>, node=0x56186f4a4f78) at ./build/../src/backend/executor/execScan.c:97
#12 ExecScan (node=0x56186f4a4f78, accessMtd=0x56186de84f20 <SeqNext>, recheckMtd=0x56186de84ef0 <SeqRecheck>) at ./build/../src/backend/executor/execScan.c:164
Best regards, Andrey Borodin.
^ permalink raw reply [nested|flat] 90+ messages in thread
* Re: MultiXact\SLRU buffers configuration
2020-05-08 16:36 MultiXact\SLRU buffers configuration Andrey M. Borodin <[email protected]>
2020-05-11 11:17 ` Re: MultiXact\SLRU buffers configuration Andrey M. Borodin <[email protected]>
2020-05-13 18:08 ` Re: MultiXact\SLRU buffers configuration Andrey M. Borodin <[email protected]>
2020-05-14 01:25 ` Re: MultiXact\SLRU buffers configuration Kyotaro Horiguchi <[email protected]>
2020-05-14 05:19 ` Re: MultiXact\SLRU buffers configuration Andrey M. Borodin <[email protected]>
@ 2020-05-14 06:16 ` Kyotaro Horiguchi <[email protected]>
2020-05-14 06:44 ` Re: MultiXact\SLRU buffers configuration Andrey M. Borodin <[email protected]>
0 siblings, 1 reply; 90+ messages in thread
From: Kyotaro Horiguchi @ 2020-05-14 06:16 UTC (permalink / raw)
To: [email protected]; +Cc: pgsql-hackers
At Thu, 14 May 2020 10:19:42 +0500, "Andrey M. Borodin" <[email protected]> wrote in
> >> I'm looking more at MultiXact and it seems to me that we have a race condition there.
> >>
> >> When we create a new MultiXact we do:
> >> 1. Generate new MultiXactId under MultiXactGenLock
> >> 2. Record new mxid with members and offset to WAL
> >> 3. Write offset to SLRU under MultiXactOffsetControlLock
> >> 4. Write members to SLRU under MultiXactMemberControlLock
> >
> > But, don't we hold exclusive lock on the buffer through all the steps
> > above?
> Yes...Unless MultiXact is observed on StandBy. This could lead to observing inconsistent snapshot: one of lockers committed tuple delete, but standby sees it as alive.
Ah, right. I looked from GetNewMultiXactId. Actually
XLOG_MULTIXACT_CREATE_ID is not protected from concurrent reference to
the creating mxact id. And GetMultiXactIdMembers is considering that
case.
> >> When we read MultiXact we do:
> >> 1. Retrieve offset by mxid from SLRU under MultiXactOffsetControlLock
> >> 2. If offset is 0 - it's not filled in at step 4 of previous algorithm, we sleep and goto 1
> >> 3. Retrieve members from SLRU under MultiXactMemberControlLock
> >> 4. ..... what we do if there are just zeroes because step 4 is not executed yet? Nothing, return empty members list.
> >
> > So transactions never see such incomplete mxids, I believe.
> I've observed sleep in step 2. I believe it's possible to observe special effects of step 4 too.
> Maybe we could add lock on standby to dismiss this 1000us wait? Sometimes it hits hard on Standbys: if someone is locking whole table on primary - all seq scans on standbys follow him with MultiXactOffsetControlLock contention.
GetMultiXactIdMembers believes that 4 is successfully done if 2
returned valid offset, but actually that is not obvious.
If we add a single giant lock just to isolate ,say,
GetMultiXactIdMember and RecordNewMultiXact, it reduces concurrency
unnecessarily. Perhaps we need finer-grained locking-key for standby
that works similary to buffer lock on primary, that doesn't cause
confilicts between irrelevant mxids.
regards.
--
Kyotaro Horiguchi
NTT Open Source Software Center
^ permalink raw reply [nested|flat] 90+ messages in thread
* Re: MultiXact\SLRU buffers configuration
2020-05-08 16:36 MultiXact\SLRU buffers configuration Andrey M. Borodin <[email protected]>
2020-05-11 11:17 ` Re: MultiXact\SLRU buffers configuration Andrey M. Borodin <[email protected]>
2020-05-13 18:08 ` Re: MultiXact\SLRU buffers configuration Andrey M. Borodin <[email protected]>
2020-05-14 01:25 ` Re: MultiXact\SLRU buffers configuration Kyotaro Horiguchi <[email protected]>
2020-05-14 05:19 ` Re: MultiXact\SLRU buffers configuration Andrey M. Borodin <[email protected]>
2020-05-14 06:16 ` Re: MultiXact\SLRU buffers configuration Kyotaro Horiguchi <[email protected]>
@ 2020-05-14 06:44 ` Andrey M. Borodin <[email protected]>
2020-05-15 00:03 ` Re: MultiXact\SLRU buffers configuration Kyotaro Horiguchi <[email protected]>
0 siblings, 1 reply; 90+ messages in thread
From: Andrey M. Borodin @ 2020-05-14 06:44 UTC (permalink / raw)
To: Kyotaro Horiguchi <[email protected]>; +Cc: pgsql-hackers
> 14 мая 2020 г., в 11:16, Kyotaro Horiguchi <[email protected]> написал(а):
>
> At Thu, 14 May 2020 10:19:42 +0500, "Andrey M. Borodin" <[email protected]> wrote in
>>>> I'm looking more at MultiXact and it seems to me that we have a race condition there.
>>>>
>>>> When we create a new MultiXact we do:
>>>> 1. Generate new MultiXactId under MultiXactGenLock
>>>> 2. Record new mxid with members and offset to WAL
>>>> 3. Write offset to SLRU under MultiXactOffsetControlLock
>>>> 4. Write members to SLRU under MultiXactMemberControlLock
>>>
>>> But, don't we hold exclusive lock on the buffer through all the steps
>>> above?
>> Yes...Unless MultiXact is observed on StandBy. This could lead to observing inconsistent snapshot: one of lockers committed tuple delete, but standby sees it as alive.
>
> Ah, right. I looked from GetNewMultiXactId. Actually
> XLOG_MULTIXACT_CREATE_ID is not protected from concurrent reference to
> the creating mxact id. And GetMultiXactIdMembers is considering that
> case.
>
>>>> When we read MultiXact we do:
>>>> 1. Retrieve offset by mxid from SLRU under MultiXactOffsetControlLock
>>>> 2. If offset is 0 - it's not filled in at step 4 of previous algorithm, we sleep and goto 1
>>>> 3. Retrieve members from SLRU under MultiXactMemberControlLock
>>>> 4. ..... what we do if there are just zeroes because step 4 is not executed yet? Nothing, return empty members list.
>>>
>>> So transactions never see such incomplete mxids, I believe.
>> I've observed sleep in step 2. I believe it's possible to observe special effects of step 4 too.
>> Maybe we could add lock on standby to dismiss this 1000us wait? Sometimes it hits hard on Standbys: if someone is locking whole table on primary - all seq scans on standbys follow him with MultiXactOffsetControlLock contention.
>
> GetMultiXactIdMembers believes that 4 is successfully done if 2
> returned valid offset, but actually that is not obvious.
>
> If we add a single giant lock just to isolate ,say,
> GetMultiXactIdMember and RecordNewMultiXact, it reduces concurrency
> unnecessarily. Perhaps we need finer-grained locking-key for standby
> that works similary to buffer lock on primary, that doesn't cause
> confilicts between irrelevant mxids.
>
We can just replay members before offsets. If offset is already there - members are there too.
But I'd be happy if we could mitigate those 1000us too - with a hint about last maixd state in a shared MX state, for example.
Actually, if we read empty mxid array instead of something that is replayed just yet - it's not a problem of inconsistency, because transaction in this mxid could not commit before we started. ISTM.
So instead of fix, we, probably, can just add a comment. If this reasoning is correct.
Best regards, Andrey Borodin.
^ permalink raw reply [nested|flat] 90+ messages in thread
* Re: MultiXact\SLRU buffers configuration
2020-05-08 16:36 MultiXact\SLRU buffers configuration Andrey M. Borodin <[email protected]>
2020-05-11 11:17 ` Re: MultiXact\SLRU buffers configuration Andrey M. Borodin <[email protected]>
2020-05-13 18:08 ` Re: MultiXact\SLRU buffers configuration Andrey M. Borodin <[email protected]>
2020-05-14 01:25 ` Re: MultiXact\SLRU buffers configuration Kyotaro Horiguchi <[email protected]>
2020-05-14 05:19 ` Re: MultiXact\SLRU buffers configuration Andrey M. Borodin <[email protected]>
2020-05-14 06:16 ` Re: MultiXact\SLRU buffers configuration Kyotaro Horiguchi <[email protected]>
2020-05-14 06:44 ` Re: MultiXact\SLRU buffers configuration Andrey M. Borodin <[email protected]>
@ 2020-05-15 00:03 ` Kyotaro Horiguchi <[email protected]>
2020-05-15 09:01 ` Re: MultiXact\SLRU buffers configuration Andrey M. Borodin <[email protected]>
2020-07-02 12:02 ` Re: MultiXact\SLRU buffers configuration Daniel Gustafsson <[email protected]>
0 siblings, 2 replies; 90+ messages in thread
From: Kyotaro Horiguchi @ 2020-05-15 00:03 UTC (permalink / raw)
To: [email protected]; +Cc: pgsql-hackers
At Thu, 14 May 2020 11:44:01 +0500, "Andrey M. Borodin" <[email protected]> wrote in
> > GetMultiXactIdMembers believes that 4 is successfully done if 2
> > returned valid offset, but actually that is not obvious.
> >
> > If we add a single giant lock just to isolate ,say,
> > GetMultiXactIdMember and RecordNewMultiXact, it reduces concurrency
> > unnecessarily. Perhaps we need finer-grained locking-key for standby
> > that works similary to buffer lock on primary, that doesn't cause
> > confilicts between irrelevant mxids.
> >
> We can just replay members before offsets. If offset is already there - members are there too.
> But I'd be happy if we could mitigate those 1000us too - with a hint about last maixd state in a shared MX state, for example.
Generally in such cases, condition variables would work. In the
attached PoC, the reader side gets no penalty in the "likely" code
path. The writer side always calls ConditionVariableBroadcast but the
waiter list is empty in almost all cases. But I couldn't cause the
situation where the sleep 1000u is reached.
> Actually, if we read empty mxid array instead of something that is replayed just yet - it's not a problem of inconsistency, because transaction in this mxid could not commit before we started. ISTM.
> So instead of fix, we, probably, can just add a comment. If this reasoning is correct.
The step 4 of the reader side reads the members of the target mxid. It
is already written if the offset of the *next* mxid is filled-in.
regards.
--
Kyotaro Horiguchi
NTT Open Source Software Center
Attachments:
[text/x-patch] mxid_wait_instead_of_sleep.patch (3.0K, ../../[email protected]/2-mxid_wait_instead_of_sleep.patch)
download | inline diff:
diff --git a/src/backend/access/transam/multixact.c b/src/backend/access/transam/multixact.c
index e2aa5c9ce4..9db8f6cddd 100644
--- a/src/backend/access/transam/multixact.c
+++ b/src/backend/access/transam/multixact.c
@@ -82,6 +82,7 @@
#include "lib/ilist.h"
#include "miscadmin.h"
#include "pg_trace.h"
+#include "pgstat.h"
#include "postmaster/autovacuum.h"
#include "storage/lmgr.h"
#include "storage/pmsignal.h"
@@ -233,6 +234,7 @@ typedef struct MultiXactStateData
/* support for members anti-wraparound measures */
MultiXactOffset offsetStopLimit; /* known if oldestOffsetKnown */
+ ConditionVariable nextoff_cv;
/*
* Per-backend data starts here. We have two arrays stored in the area
* immediately following the MultiXactStateData struct. Each is indexed by
@@ -873,6 +875,14 @@ RecordNewMultiXact(MultiXactId multi, MultiXactOffset offset,
/* Exchange our lock */
LWLockRelease(MultiXactOffsetControlLock);
+ /*
+ * Let everybody know the offset of this mxid is recorded now. The waiters
+ * are waiting for the offset of the mxid next of the target to know the
+ * number of members of the target mxid, so we don't need to wait for
+ * members of this mxid are recorded.
+ */
+ ConditionVariableBroadcast(&MultiXactState->nextoff_cv);
+
LWLockAcquire(MultiXactMemberControlLock, LW_EXCLUSIVE);
prev_pageno = -1;
@@ -1367,9 +1377,19 @@ retry:
if (nextMXOffset == 0)
{
/* Corner case 2: next multixact is still being filled in */
+
+ /*
+ * The recorder of the next mxid is just before writing the offset.
+ * Wait for the offset to be written.
+ */
+ ConditionVariablePrepareToSleep(&MultiXactState->nextoff_cv);
+
LWLockRelease(MultiXactOffsetControlLock);
CHECK_FOR_INTERRUPTS();
- pg_usleep(1000L);
+
+ ConditionVariableSleep(&MultiXactState->nextoff_cv,
+ WAIT_EVENT_WAIT_NEXT_MXMEMBERS);
+ ConditionVariableCancelSleep();
goto retry;
}
@@ -1847,6 +1867,7 @@ MultiXactShmemInit(void)
/* Make sure we zero out the per-backend state */
MemSet(MultiXactState, 0, SHARED_MULTIXACT_STATE_SIZE);
+ ConditionVariableInit(&MultiXactState->nextoff_cv);
}
else
Assert(found);
diff --git a/src/backend/postmaster/pgstat.c b/src/backend/postmaster/pgstat.c
index 0ecd29a1d9..1ac6b37188 100644
--- a/src/backend/postmaster/pgstat.c
+++ b/src/backend/postmaster/pgstat.c
@@ -3879,6 +3879,9 @@ pgstat_get_wait_ipc(WaitEventIPC w)
case WAIT_EVENT_SYNC_REP:
event_name = "SyncRep";
break;
+ case WAIT_EVENT_WAIT_NEXT_MXMEMBERS:
+ event_name = "Mact/WaitNextXactMembers";
+ break;
/* no default case, so that compiler will warn */
}
diff --git a/src/include/pgstat.h b/src/include/pgstat.h
index ae9a39573c..e79bba0bef 100644
--- a/src/include/pgstat.h
+++ b/src/include/pgstat.h
@@ -886,7 +886,8 @@ typedef enum
WAIT_EVENT_REPLICATION_ORIGIN_DROP,
WAIT_EVENT_REPLICATION_SLOT_DROP,
WAIT_EVENT_SAFE_SNAPSHOT,
- WAIT_EVENT_SYNC_REP
+ WAIT_EVENT_SYNC_REP,
+ WAIT_EVENT_WAIT_NEXT_MXMEMBERS
} WaitEventIPC;
/* ----------
^ permalink raw reply [nested|flat] 90+ messages in thread
* Re: MultiXact\SLRU buffers configuration
2020-05-08 16:36 MultiXact\SLRU buffers configuration Andrey M. Borodin <[email protected]>
2020-05-11 11:17 ` Re: MultiXact\SLRU buffers configuration Andrey M. Borodin <[email protected]>
2020-05-13 18:08 ` Re: MultiXact\SLRU buffers configuration Andrey M. Borodin <[email protected]>
2020-05-14 01:25 ` Re: MultiXact\SLRU buffers configuration Kyotaro Horiguchi <[email protected]>
2020-05-14 05:19 ` Re: MultiXact\SLRU buffers configuration Andrey M. Borodin <[email protected]>
2020-05-14 06:16 ` Re: MultiXact\SLRU buffers configuration Kyotaro Horiguchi <[email protected]>
2020-05-14 06:44 ` Re: MultiXact\SLRU buffers configuration Andrey M. Borodin <[email protected]>
2020-05-15 00:03 ` Re: MultiXact\SLRU buffers configuration Kyotaro Horiguchi <[email protected]>
@ 2020-05-15 09:01 ` Andrey M. Borodin <[email protected]>
2020-05-20 04:54 ` Re: MultiXact\SLRU buffers configuration Kyotaro Horiguchi <[email protected]>
1 sibling, 1 reply; 90+ messages in thread
From: Andrey M. Borodin @ 2020-05-15 09:01 UTC (permalink / raw)
To: Kyotaro Horiguchi <[email protected]>; +Cc: pgsql-hackers
> 15 мая 2020 г., в 05:03, Kyotaro Horiguchi <[email protected]> написал(а):
>
> At Thu, 14 May 2020 11:44:01 +0500, "Andrey M. Borodin" <[email protected]> wrote in
>>> GetMultiXactIdMembers believes that 4 is successfully done if 2
>>> returned valid offset, but actually that is not obvious.
>>>
>>> If we add a single giant lock just to isolate ,say,
>>> GetMultiXactIdMember and RecordNewMultiXact, it reduces concurrency
>>> unnecessarily. Perhaps we need finer-grained locking-key for standby
>>> that works similary to buffer lock on primary, that doesn't cause
>>> confilicts between irrelevant mxids.
>>>
>> We can just replay members before offsets. If offset is already there - members are there too.
>> But I'd be happy if we could mitigate those 1000us too - with a hint about last maixd state in a shared MX state, for example.
>
> Generally in such cases, condition variables would work. In the
> attached PoC, the reader side gets no penalty in the "likely" code
> path. The writer side always calls ConditionVariableBroadcast but the
> waiter list is empty in almost all cases. But I couldn't cause the
> situation where the sleep 1000u is reached.
Thanks! That really looks like a good solution without magic timeouts. Beautiful!
I think I can create temporary extension which calls MultiXact API and tests edge-cases like this 1000us wait.
This extension will also be also useful for me to assess impact of bigger buffers, reduced read locking (as in my 2nd patch) and other tweaks.
>> Actually, if we read empty mxid array instead of something that is replayed just yet - it's not a problem of inconsistency, because transaction in this mxid could not commit before we started. ISTM.
>> So instead of fix, we, probably, can just add a comment. If this reasoning is correct.
>
> The step 4 of the reader side reads the members of the target mxid. It
> is already written if the offset of the *next* mxid is filled-in.
Most often - yes, but members are not guaranteed to be filled in order. Those who win MXMemberControlLock will write first.
But nobody can read members of MXID before it is returned. And its members will be written before returning MXID.
Best regards, Andrey Borodin.
^ permalink raw reply [nested|flat] 90+ messages in thread
* Re: MultiXact\SLRU buffers configuration
2020-05-08 16:36 MultiXact\SLRU buffers configuration Andrey M. Borodin <[email protected]>
2020-05-11 11:17 ` Re: MultiXact\SLRU buffers configuration Andrey M. Borodin <[email protected]>
2020-05-13 18:08 ` Re: MultiXact\SLRU buffers configuration Andrey M. Borodin <[email protected]>
2020-05-14 01:25 ` Re: MultiXact\SLRU buffers configuration Kyotaro Horiguchi <[email protected]>
2020-05-14 05:19 ` Re: MultiXact\SLRU buffers configuration Andrey M. Borodin <[email protected]>
2020-05-14 06:16 ` Re: MultiXact\SLRU buffers configuration Kyotaro Horiguchi <[email protected]>
2020-05-14 06:44 ` Re: MultiXact\SLRU buffers configuration Andrey M. Borodin <[email protected]>
2020-05-15 00:03 ` Re: MultiXact\SLRU buffers configuration Kyotaro Horiguchi <[email protected]>
2020-05-15 09:01 ` Re: MultiXact\SLRU buffers configuration Andrey M. Borodin <[email protected]>
@ 2020-05-20 04:54 ` Kyotaro Horiguchi <[email protected]>
0 siblings, 0 replies; 90+ messages in thread
From: Kyotaro Horiguchi @ 2020-05-20 04:54 UTC (permalink / raw)
To: [email protected]; +Cc: pgsql-hackers
At Fri, 15 May 2020 14:01:46 +0500, "Andrey M. Borodin" <[email protected]> wrote in
>
>
> > 15 мая 2020 г., в 05:03, Kyotaro Horiguchi <[email protected]> написал(а):
> >
> > At Thu, 14 May 2020 11:44:01 +0500, "Andrey M. Borodin" <[email protected]> wrote in
> >>> GetMultiXactIdMembers believes that 4 is successfully done if 2
> >>> returned valid offset, but actually that is not obvious.
> >>>
> >>> If we add a single giant lock just to isolate ,say,
> >>> GetMultiXactIdMember and RecordNewMultiXact, it reduces concurrency
> >>> unnecessarily. Perhaps we need finer-grained locking-key for standby
> >>> that works similary to buffer lock on primary, that doesn't cause
> >>> confilicts between irrelevant mxids.
> >>>
> >> We can just replay members before offsets. If offset is already there - members are there too.
> >> But I'd be happy if we could mitigate those 1000us too - with a hint about last maixd state in a shared MX state, for example.
> >
> > Generally in such cases, condition variables would work. In the
> > attached PoC, the reader side gets no penalty in the "likely" code
> > path. The writer side always calls ConditionVariableBroadcast but the
> > waiter list is empty in almost all cases. But I couldn't cause the
> > situation where the sleep 1000u is reached.
> Thanks! That really looks like a good solution without magic timeouts. Beautiful!
> I think I can create temporary extension which calls MultiXact API and tests edge-cases like this 1000us wait.
> This extension will also be also useful for me to assess impact of bigger buffers, reduced read locking (as in my 2nd patch) and other tweaks.
Happy to hear that, It would need to use timeout just in case, though.
> >> Actually, if we read empty mxid array instead of something that is replayed just yet - it's not a problem of inconsistency, because transaction in this mxid could not commit before we started. ISTM.
> >> So instead of fix, we, probably, can just add a comment. If this reasoning is correct.
> >
> > The step 4 of the reader side reads the members of the target mxid. It
> > is already written if the offset of the *next* mxid is filled-in.
> Most often - yes, but members are not guaranteed to be filled in order. Those who win MXMemberControlLock will write first.
> But nobody can read members of MXID before it is returned. And its members will be written before returning MXID.
Yeah, right. Otherwise assertion failure happens.
regards.
--
Kyotaro Horiguchi
NTT Open Source Software Center
^ permalink raw reply [nested|flat] 90+ messages in thread
* Re: MultiXact\SLRU buffers configuration
2020-05-08 16:36 MultiXact\SLRU buffers configuration Andrey M. Borodin <[email protected]>
2020-05-11 11:17 ` Re: MultiXact\SLRU buffers configuration Andrey M. Borodin <[email protected]>
2020-05-13 18:08 ` Re: MultiXact\SLRU buffers configuration Andrey M. Borodin <[email protected]>
2020-05-14 01:25 ` Re: MultiXact\SLRU buffers configuration Kyotaro Horiguchi <[email protected]>
2020-05-14 05:19 ` Re: MultiXact\SLRU buffers configuration Andrey M. Borodin <[email protected]>
2020-05-14 06:16 ` Re: MultiXact\SLRU buffers configuration Kyotaro Horiguchi <[email protected]>
2020-05-14 06:44 ` Re: MultiXact\SLRU buffers configuration Andrey M. Borodin <[email protected]>
2020-05-15 00:03 ` Re: MultiXact\SLRU buffers configuration Kyotaro Horiguchi <[email protected]>
@ 2020-07-02 12:02 ` Daniel Gustafsson <[email protected]>
2020-07-08 07:03 ` Re: MultiXact\SLRU buffers configuration Andrey M. Borodin <[email protected]>
1 sibling, 1 reply; 90+ messages in thread
From: Daniel Gustafsson @ 2020-07-02 12:02 UTC (permalink / raw)
To: Kyotaro Horiguchi <[email protected]>; +Cc: [email protected]; pgsql-hackers
> On 15 May 2020, at 02:03, Kyotaro Horiguchi <[email protected]> wrote:
> Generally in such cases, condition variables would work. In the
> attached PoC, the reader side gets no penalty in the "likely" code
> path. The writer side always calls ConditionVariableBroadcast but the
> waiter list is empty in almost all cases. But I couldn't cause the
> situation where the sleep 1000u is reached.
The submitted patch no longer applies, can you please submit an updated
version? I'm marking the patch Waiting on Author in the meantime.
cheers ./daniel
^ permalink raw reply [nested|flat] 90+ messages in thread
* Re: MultiXact\SLRU buffers configuration
2020-05-08 16:36 MultiXact\SLRU buffers configuration Andrey M. Borodin <[email protected]>
2020-05-11 11:17 ` Re: MultiXact\SLRU buffers configuration Andrey M. Borodin <[email protected]>
2020-05-13 18:08 ` Re: MultiXact\SLRU buffers configuration Andrey M. Borodin <[email protected]>
2020-05-14 01:25 ` Re: MultiXact\SLRU buffers configuration Kyotaro Horiguchi <[email protected]>
2020-05-14 05:19 ` Re: MultiXact\SLRU buffers configuration Andrey M. Borodin <[email protected]>
2020-05-14 06:16 ` Re: MultiXact\SLRU buffers configuration Kyotaro Horiguchi <[email protected]>
2020-05-14 06:44 ` Re: MultiXact\SLRU buffers configuration Andrey M. Borodin <[email protected]>
2020-05-15 00:03 ` Re: MultiXact\SLRU buffers configuration Kyotaro Horiguchi <[email protected]>
2020-07-02 12:02 ` Re: MultiXact\SLRU buffers configuration Daniel Gustafsson <[email protected]>
@ 2020-07-08 07:03 ` Andrey M. Borodin <[email protected]>
2020-08-02 21:30 ` Re: MultiXact\SLRU buffers configuration Daniel Gustafsson <[email protected]>
2020-08-28 18:08 ` Re: MultiXact\SLRU buffers configuration Anastasia Lubennikova <[email protected]>
0 siblings, 2 replies; 90+ messages in thread
From: Andrey M. Borodin @ 2020-07-08 07:03 UTC (permalink / raw)
To: Daniel Gustafsson <[email protected]>; +Cc: Kyotaro Horiguchi <[email protected]>; pgsql-hackers
> 2 июля 2020 г., в 17:02, Daniel Gustafsson <[email protected]> написал(а):
>
>> On 15 May 2020, at 02:03, Kyotaro Horiguchi <[email protected]> wrote:
>
>> Generally in such cases, condition variables would work. In the
>> attached PoC, the reader side gets no penalty in the "likely" code
>> path. The writer side always calls ConditionVariableBroadcast but the
>> waiter list is empty in almost all cases. But I couldn't cause the
>> situation where the sleep 1000u is reached.
>
> The submitted patch no longer applies, can you please submit an updated
> version? I'm marking the patch Waiting on Author in the meantime.
Thanks, Daniel! PFA V2
Best regards, Andrey Borodin.
Attachments:
[application/octet-stream] v2-0001-Use-shared-lock-in-GetMultiXactIdMembers-for-offs.patch (7.6K, ../../[email protected]/2-v2-0001-Use-shared-lock-in-GetMultiXactIdMembers-for-offs.patch)
download | inline diff:
From 264b475fbf6ee519dc3b4eb2cca25145d2aaa569 Mon Sep 17 00:00:00 2001
From: Andrey Borodin <[email protected]>
Date: Sat, 9 May 2020 21:19:18 +0500
Subject: [PATCH v2 1/4] Use shared lock in GetMultiXactIdMembers for offsets
and members
Previously read of multixact required exclusive control locks in
offstes and members SLRUs. This could lead to contention.
In this commit we take advantge of SimpleLruReadPage_ReadOnly
similar to CLOG usage.
---
src/backend/access/transam/clog.c | 2 +-
src/backend/access/transam/commit_ts.c | 2 +-
src/backend/access/transam/multixact.c | 12 ++++++------
src/backend/access/transam/slru.c | 8 +++++---
src/backend/access/transam/subtrans.c | 2 +-
src/backend/commands/async.c | 2 +-
src/backend/storage/lmgr/predicate.c | 2 +-
src/include/access/slru.h | 2 +-
8 files changed, 17 insertions(+), 15 deletions(-)
diff --git a/src/backend/access/transam/clog.c b/src/backend/access/transam/clog.c
index f3da40ae01..3614d0c774 100644
--- a/src/backend/access/transam/clog.c
+++ b/src/backend/access/transam/clog.c
@@ -643,7 +643,7 @@ TransactionIdGetStatus(TransactionId xid, XLogRecPtr *lsn)
/* lock is acquired by SimpleLruReadPage_ReadOnly */
- slotno = SimpleLruReadPage_ReadOnly(XactCtl, pageno, xid);
+ slotno = SimpleLruReadPage_ReadOnly(XactCtl, pageno, xid, false);
byteptr = XactCtl->shared->page_buffer[slotno] + byteno;
status = (*byteptr >> bshift) & CLOG_XACT_BITMASK;
diff --git a/src/backend/access/transam/commit_ts.c b/src/backend/access/transam/commit_ts.c
index 9cdb136435..5fbbf446e3 100644
--- a/src/backend/access/transam/commit_ts.c
+++ b/src/backend/access/transam/commit_ts.c
@@ -342,7 +342,7 @@ TransactionIdGetCommitTsData(TransactionId xid, TimestampTz *ts,
}
/* lock is acquired by SimpleLruReadPage_ReadOnly */
- slotno = SimpleLruReadPage_ReadOnly(CommitTsCtl, pageno, xid);
+ slotno = SimpleLruReadPage_ReadOnly(CommitTsCtl, pageno, xid, false);
memcpy(&entry,
CommitTsCtl->shared->page_buffer[slotno] +
SizeOfCommitTimestampEntry * entryno,
diff --git a/src/backend/access/transam/multixact.c b/src/backend/access/transam/multixact.c
index 79ec21c75a..241d9dd78d 100644
--- a/src/backend/access/transam/multixact.c
+++ b/src/backend/access/transam/multixact.c
@@ -1321,12 +1321,12 @@ GetMultiXactIdMembers(MultiXactId multi, MultiXactMember **members,
* time on every multixact creation.
*/
retry:
- LWLockAcquire(MultiXactOffsetSLRULock, LW_EXCLUSIVE);
pageno = MultiXactIdToOffsetPage(multi);
entryno = MultiXactIdToOffsetEntry(multi);
- slotno = SimpleLruReadPage(MultiXactOffsetCtl, pageno, true, multi);
+ /* lock is acquired by SimpleLruReadPage_ReadOnly */
+ slotno = SimpleLruReadPage_ReadOnly(MultiXactOffsetCtl, pageno, multi, false);
offptr = (MultiXactOffset *) MultiXactOffsetCtl->shared->page_buffer[slotno];
offptr += entryno;
offset = *offptr;
@@ -1358,7 +1358,7 @@ retry:
entryno = MultiXactIdToOffsetEntry(tmpMXact);
if (pageno != prev_pageno)
- slotno = SimpleLruReadPage(MultiXactOffsetCtl, pageno, true, tmpMXact);
+ slotno = SimpleLruReadPage_ReadOnly(MultiXactOffsetCtl, pageno, tmpMXact, true);
offptr = (MultiXactOffset *) MultiXactOffsetCtl->shared->page_buffer[slotno];
offptr += entryno;
@@ -1382,7 +1382,7 @@ retry:
*members = ptr;
/* Now get the members themselves. */
- LWLockAcquire(MultiXactMemberSLRULock, LW_EXCLUSIVE);
+ LWLockAcquire(MultiXactMemberSLRULock, LW_SHARED);
truelength = 0;
prev_pageno = -1;
@@ -1399,7 +1399,7 @@ retry:
if (pageno != prev_pageno)
{
- slotno = SimpleLruReadPage(MultiXactMemberCtl, pageno, true, multi);
+ slotno = SimpleLruReadPage_ReadOnly(MultiXactMemberCtl, pageno, multi, true);
prev_pageno = pageno;
}
@@ -2745,7 +2745,7 @@ find_multixact_start(MultiXactId multi, MultiXactOffset *result)
return false;
/* lock is acquired by SimpleLruReadPage_ReadOnly */
- slotno = SimpleLruReadPage_ReadOnly(MultiXactOffsetCtl, pageno, multi);
+ slotno = SimpleLruReadPage_ReadOnly(MultiXactOffsetCtl, pageno, multi, false);
offptr = (MultiXactOffset *) MultiXactOffsetCtl->shared->page_buffer[slotno];
offptr += entryno;
offset = *offptr;
diff --git a/src/backend/access/transam/slru.c b/src/backend/access/transam/slru.c
index 61249f4a12..96d0def5c2 100644
--- a/src/backend/access/transam/slru.c
+++ b/src/backend/access/transam/slru.c
@@ -475,17 +475,19 @@ SimpleLruReadPage(SlruCtl ctl, int pageno, bool write_ok,
* Return value is the shared-buffer slot number now holding the page.
* The buffer's LRU access info is updated.
*
- * Control lock must NOT be held at entry, but will be held at exit.
+ * Control lock will be held at exit. If lock_held is true at least
+ * shared control lock must be held.
* It is unspecified whether the lock will be shared or exclusive.
*/
int
-SimpleLruReadPage_ReadOnly(SlruCtl ctl, int pageno, TransactionId xid)
+SimpleLruReadPage_ReadOnly(SlruCtl ctl, int pageno, TransactionId xid, bool lock_held)
{
SlruShared shared = ctl->shared;
int slotno;
/* Try to find the page while holding only shared lock */
- LWLockAcquire(shared->ControlLock, LW_SHARED);
+ if (!lock_held)
+ LWLockAcquire(shared->ControlLock, LW_SHARED);
/* See if page is already in a buffer */
for (slotno = 0; slotno < shared->num_slots; slotno++)
diff --git a/src/backend/access/transam/subtrans.c b/src/backend/access/transam/subtrans.c
index f33ae407a6..8d8e0d9ec7 100644
--- a/src/backend/access/transam/subtrans.c
+++ b/src/backend/access/transam/subtrans.c
@@ -123,7 +123,7 @@ SubTransGetParent(TransactionId xid)
/* lock is acquired by SimpleLruReadPage_ReadOnly */
- slotno = SimpleLruReadPage_ReadOnly(SubTransCtl, pageno, xid);
+ slotno = SimpleLruReadPage_ReadOnly(SubTransCtl, pageno, xid, false);
ptr = (TransactionId *) SubTransCtl->shared->page_buffer[slotno];
ptr += entryno;
diff --git a/src/backend/commands/async.c b/src/backend/commands/async.c
index 71b7577afc..70085fc037 100644
--- a/src/backend/commands/async.c
+++ b/src/backend/commands/async.c
@@ -2012,7 +2012,7 @@ asyncQueueReadAllNotifications(void)
* part of the page we will actually inspect.
*/
slotno = SimpleLruReadPage_ReadOnly(NotifyCtl, curpage,
- InvalidTransactionId);
+ InvalidTransactionId, false);
if (curpage == QUEUE_POS_PAGE(head))
{
/* we only want to read as far as head */
diff --git a/src/backend/storage/lmgr/predicate.c b/src/backend/storage/lmgr/predicate.c
index d24919f76b..e2a7d00d37 100644
--- a/src/backend/storage/lmgr/predicate.c
+++ b/src/backend/storage/lmgr/predicate.c
@@ -948,7 +948,7 @@ SerialGetMinConflictCommitSeqNo(TransactionId xid)
* but will return with that lock held, which must then be released.
*/
slotno = SimpleLruReadPage_ReadOnly(SerialSlruCtl,
- SerialPage(xid), xid);
+ SerialPage(xid), xid, false);
val = SerialValue(slotno, xid);
LWLockRelease(SerialSLRULock);
return val;
diff --git a/src/include/access/slru.h b/src/include/access/slru.h
index 61fbc80ef0..471c692021 100644
--- a/src/include/access/slru.h
+++ b/src/include/access/slru.h
@@ -140,7 +140,7 @@ extern int SimpleLruZeroPage(SlruCtl ctl, int pageno);
extern int SimpleLruReadPage(SlruCtl ctl, int pageno, bool write_ok,
TransactionId xid);
extern int SimpleLruReadPage_ReadOnly(SlruCtl ctl, int pageno,
- TransactionId xid);
+ TransactionId xid, bool lock_held);
extern void SimpleLruWritePage(SlruCtl ctl, int slotno);
extern void SimpleLruFlush(SlruCtl ctl, bool allow_redirtied);
extern void SimpleLruTruncate(SlruCtl ctl, int cutoffPage);
--
2.24.2 (Apple Git-127)
[application/octet-stream] v2-0002-Make-MultiXact-local-cache-size-configurable.patch (3.7K, ../../[email protected]/3-v2-0002-Make-MultiXact-local-cache-size-configurable.patch)
download | inline diff:
From 520686d6cc22a599bc06b91391171ca218c3db75 Mon Sep 17 00:00:00 2001
From: Andrey Borodin <[email protected]>
Date: Mon, 11 May 2020 16:17:02 +0500
Subject: [PATCH v2 2/4] Make MultiXact local cache size configurable
---
doc/src/sgml/config.sgml | 16 ++++++++++++++++
src/backend/access/transam/multixact.c | 2 +-
src/backend/utils/init/globals.c | 1 +
src/backend/utils/misc/guc.c | 10 ++++++++++
src/include/miscadmin.h | 1 +
5 files changed, 29 insertions(+), 1 deletion(-)
diff --git a/doc/src/sgml/config.sgml b/doc/src/sgml/config.sgml
index 94d99373a7..31d7c1f4b3 100644
--- a/doc/src/sgml/config.sgml
+++ b/doc/src/sgml/config.sgml
@@ -1777,6 +1777,22 @@ include_dir 'conf.d'
</listitem>
</varlistentry>
+ <varlistentry id="guc-multixact-local-cache-entries" xreflabel="multixact_local-cache-entries">
+ <term><varname>multixact_local_cache_entries</varname> (<type>integer</type>)
+ <indexterm>
+ <primary><varname>multixact_local_cache_entries</varname> configuration parameter</primary>
+ </indexterm>
+ </term>
+ <listitem>
+ <para>
+ Specifies the number cached MultiXact by backend. Any SLRU lookup is preceeded
+ by cache lookup. Higher numbers of cache size help to deduplicate lock sets, while
+ lower values make cache lookup faster.
+ It defaults to 256.
+ </para>
+ </listitem>
+ </varlistentry>
+
<varlistentry id="guc-max-stack-depth" xreflabel="max_stack_depth">
<term><varname>max_stack_depth</varname> (<type>integer</type>)
<indexterm>
diff --git a/src/backend/access/transam/multixact.c b/src/backend/access/transam/multixact.c
index 241d9dd78d..445b6258a4 100644
--- a/src/backend/access/transam/multixact.c
+++ b/src/backend/access/transam/multixact.c
@@ -1589,7 +1589,7 @@ mXactCachePut(MultiXactId multi, int nmembers, MultiXactMember *members)
qsort(entry->members, nmembers, sizeof(MultiXactMember), mxactMemberComparator);
dlist_push_head(&MXactCache, &entry->node);
- if (MXactCacheMembers++ >= MAX_CACHE_ENTRIES)
+ if (MXactCacheMembers++ >= multixact_local_cache_entries)
{
dlist_node *node;
mXactCacheEnt *entry;
diff --git a/src/backend/utils/init/globals.c b/src/backend/utils/init/globals.c
index 01e739da40..f404167ad0 100644
--- a/src/backend/utils/init/globals.c
+++ b/src/backend/utils/init/globals.c
@@ -151,3 +151,4 @@ double vacuum_cleanup_index_scale_factor;
int multixact_offsets_slru_buffers = 8;
int multixact_members_slru_buffers = 16;
+int multixact_local_cache_entries = 256;
diff --git a/src/backend/utils/misc/guc.c b/src/backend/utils/misc/guc.c
index d1fbb75cd5..6443f595cc 100644
--- a/src/backend/utils/misc/guc.c
+++ b/src/backend/utils/misc/guc.c
@@ -2273,6 +2273,16 @@ static struct config_int ConfigureNamesInt[] =
NULL, NULL, NULL
},
+ {
+ {"multixact_local_cache_entries", PGC_SUSET, RESOURCES_MEM,
+ gettext_noop("Sets the number cached MultiXact by backend."),
+ NULL
+ },
+ &multixact_local_cache_entries,
+ 256, 2, INT_MAX / 2,
+ NULL, NULL, NULL
+ },
+
{
{"temp_buffers", PGC_USERSET, RESOURCES_MEM,
gettext_noop("Sets the maximum number of temporary buffers used by each session."),
diff --git a/src/include/miscadmin.h b/src/include/miscadmin.h
index bb1475ad2b..9ce2adea63 100644
--- a/src/include/miscadmin.h
+++ b/src/include/miscadmin.h
@@ -163,6 +163,7 @@ extern PGDLLIMPORT int max_worker_processes;
extern PGDLLIMPORT int max_parallel_workers;
extern PGDLLIMPORT int multixact_offsets_slru_buffers;
extern PGDLLIMPORT int multixact_members_slru_buffers;
+extern PGDLLIMPORT int multixact_local_cache_entries;
extern PGDLLIMPORT int MyProcPid;
extern PGDLLIMPORT pg_time_t MyStartTime;
--
2.24.2 (Apple Git-127)
[application/octet-stream] v2-0003-Add-conditional-variable-to-wait-for-next-MultXac.patch (3.4K, ../../[email protected]/4-v2-0003-Add-conditional-variable-to-wait-for-next-MultXac.patch)
download | inline diff:
From ddde253b10b87d060d34f8d7250be27a27c18c0a Mon Sep 17 00:00:00 2001
From: Andrey Borodin <[email protected]>
Date: Fri, 22 May 2020 14:13:33 +0500
Subject: [PATCH v2 3/4] Add conditional variable to wait for next MultXact
offset in edge case
---
src/backend/access/transam/multixact.c | 23 ++++++++++++++++++++++-
src/backend/postmaster/pgstat.c | 2 ++
src/include/pgstat.h | 1 +
3 files changed, 25 insertions(+), 1 deletion(-)
diff --git a/src/backend/access/transam/multixact.c b/src/backend/access/transam/multixact.c
index 445b6258a4..02de9a7c13 100644
--- a/src/backend/access/transam/multixact.c
+++ b/src/backend/access/transam/multixact.c
@@ -82,6 +82,7 @@
#include "lib/ilist.h"
#include "miscadmin.h"
#include "pg_trace.h"
+#include "pgstat.h"
#include "postmaster/autovacuum.h"
#include "storage/lmgr.h"
#include "storage/pmsignal.h"
@@ -233,6 +234,7 @@ typedef struct MultiXactStateData
/* support for members anti-wraparound measures */
MultiXactOffset offsetStopLimit; /* known if oldestOffsetKnown */
+ ConditionVariable nextoff_cv;
/*
* Per-backend data starts here. We have two arrays stored in the area
* immediately following the MultiXactStateData struct. Each is indexed by
@@ -873,6 +875,14 @@ RecordNewMultiXact(MultiXactId multi, MultiXactOffset offset,
/* Exchange our lock */
LWLockRelease(MultiXactOffsetSLRULock);
+ /*
+ * Let everybody know the offset of this mxid is recorded now. The waiters
+ * are waiting for the offset of the mxid next of the target to know the
+ * number of members of the target mxid, so we don't need to wait for
+ * members of this mxid are recorded.
+ */
+ ConditionVariableBroadcast(&MultiXactState->nextoff_cv);
+
LWLockAcquire(MultiXactMemberSLRULock, LW_EXCLUSIVE);
prev_pageno = -1;
@@ -1367,9 +1377,19 @@ retry:
if (nextMXOffset == 0)
{
/* Corner case 2: next multixact is still being filled in */
+
+ /*
+ * The recorder of the next mxid is just before writing the offset.
+ * Wait for the offset to be written.
+ */
+ ConditionVariablePrepareToSleep(&MultiXactState->nextoff_cv);
+
LWLockRelease(MultiXactOffsetSLRULock);
CHECK_FOR_INTERRUPTS();
- pg_usleep(1000L);
+
+ ConditionVariableSleep(&MultiXactState->nextoff_cv,
+ WAIT_EVENT_WAIT_NEXT_MXMEMBERS);
+ ConditionVariableCancelSleep();
goto retry;
}
@@ -1847,6 +1867,7 @@ MultiXactShmemInit(void)
/* Make sure we zero out the per-backend state */
MemSet(MultiXactState, 0, SHARED_MULTIXACT_STATE_SIZE);
+ ConditionVariableInit(&MultiXactState->nextoff_cv);
}
else
Assert(found);
diff --git a/src/backend/postmaster/pgstat.c b/src/backend/postmaster/pgstat.c
index edfa774ee4..4bce534c7a 100644
--- a/src/backend/postmaster/pgstat.c
+++ b/src/backend/postmaster/pgstat.c
@@ -3877,6 +3877,8 @@ pgstat_get_wait_ipc(WaitEventIPC w)
break;
case WAIT_EVENT_XACT_GROUP_UPDATE:
event_name = "XactGroupUpdate";
+ case WAIT_EVENT_WAIT_NEXT_MXMEMBERS:
+ event_name = "MultiXact/WaitNextXactMembers";
break;
/* no default case, so that compiler will warn */
}
diff --git a/src/include/pgstat.h b/src/include/pgstat.h
index 1387201382..26f828597b 100644
--- a/src/include/pgstat.h
+++ b/src/include/pgstat.h
@@ -887,6 +887,7 @@ typedef enum
WAIT_EVENT_REPLICATION_SLOT_DROP,
WAIT_EVENT_SAFE_SNAPSHOT,
WAIT_EVENT_SYNC_REP,
+ WAIT_EVENT_WAIT_NEXT_MXMEMBERS,
WAIT_EVENT_XACT_GROUP_UPDATE
} WaitEventIPC;
--
2.24.2 (Apple Git-127)
^ permalink raw reply [nested|flat] 90+ messages in thread
* Re: MultiXact\SLRU buffers configuration
2020-05-08 16:36 MultiXact\SLRU buffers configuration Andrey M. Borodin <[email protected]>
2020-05-11 11:17 ` Re: MultiXact\SLRU buffers configuration Andrey M. Borodin <[email protected]>
2020-05-13 18:08 ` Re: MultiXact\SLRU buffers configuration Andrey M. Borodin <[email protected]>
2020-05-14 01:25 ` Re: MultiXact\SLRU buffers configuration Kyotaro Horiguchi <[email protected]>
2020-05-14 05:19 ` Re: MultiXact\SLRU buffers configuration Andrey M. Borodin <[email protected]>
2020-05-14 06:16 ` Re: MultiXact\SLRU buffers configuration Kyotaro Horiguchi <[email protected]>
2020-05-14 06:44 ` Re: MultiXact\SLRU buffers configuration Andrey M. Borodin <[email protected]>
2020-05-15 00:03 ` Re: MultiXact\SLRU buffers configuration Kyotaro Horiguchi <[email protected]>
2020-07-02 12:02 ` Re: MultiXact\SLRU buffers configuration Daniel Gustafsson <[email protected]>
2020-07-08 07:03 ` Re: MultiXact\SLRU buffers configuration Andrey M. Borodin <[email protected]>
@ 2020-08-02 21:30 ` Daniel Gustafsson <[email protected]>
1 sibling, 0 replies; 90+ messages in thread
From: Daniel Gustafsson @ 2020-08-02 21:30 UTC (permalink / raw)
To: Andrey M. Borodin <[email protected]>; +Cc: Kyotaro Horiguchi <[email protected]>; pgsql-hackers
> On 8 Jul 2020, at 09:03, Andrey M. Borodin <[email protected]> wrote:
>
>
>
>> 2 июля 2020 г., в 17:02, Daniel Gustafsson <[email protected]> написал(а):
>>
>>> On 15 May 2020, at 02:03, Kyotaro Horiguchi <[email protected]> wrote:
>>
>>> Generally in such cases, condition variables would work. In the
>>> attached PoC, the reader side gets no penalty in the "likely" code
>>> path. The writer side always calls ConditionVariableBroadcast but the
>>> waiter list is empty in almost all cases. But I couldn't cause the
>>> situation where the sleep 1000u is reached.
>>
>> The submitted patch no longer applies, can you please submit an updated
>> version? I'm marking the patch Waiting on Author in the meantime.
> Thanks, Daniel! PFA V2
This version too has stopped applying according to the CFbot. I've moved it to
the next commitfest as we're out of time in this one and it was only pointed
out now, but kept it Waiting on Author.
cheers ./daniel
^ permalink raw reply [nested|flat] 90+ messages in thread
* Re: MultiXact\SLRU buffers configuration
2020-05-08 16:36 MultiXact\SLRU buffers configuration Andrey M. Borodin <[email protected]>
2020-05-11 11:17 ` Re: MultiXact\SLRU buffers configuration Andrey M. Borodin <[email protected]>
2020-05-13 18:08 ` Re: MultiXact\SLRU buffers configuration Andrey M. Borodin <[email protected]>
2020-05-14 01:25 ` Re: MultiXact\SLRU buffers configuration Kyotaro Horiguchi <[email protected]>
2020-05-14 05:19 ` Re: MultiXact\SLRU buffers configuration Andrey M. Borodin <[email protected]>
2020-05-14 06:16 ` Re: MultiXact\SLRU buffers configuration Kyotaro Horiguchi <[email protected]>
2020-05-14 06:44 ` Re: MultiXact\SLRU buffers configuration Andrey M. Borodin <[email protected]>
2020-05-15 00:03 ` Re: MultiXact\SLRU buffers configuration Kyotaro Horiguchi <[email protected]>
2020-07-02 12:02 ` Re: MultiXact\SLRU buffers configuration Daniel Gustafsson <[email protected]>
2020-07-08 07:03 ` Re: MultiXact\SLRU buffers configuration Andrey M. Borodin <[email protected]>
@ 2020-08-28 18:08 ` Anastasia Lubennikova <[email protected]>
2020-09-28 14:41 ` Re: MultiXact\SLRU buffers configuration Andrey M. Borodin <[email protected]>
1 sibling, 1 reply; 90+ messages in thread
From: Anastasia Lubennikova @ 2020-08-28 18:08 UTC (permalink / raw)
To: Andrey M. Borodin <[email protected]>; Daniel Gustafsson <[email protected]>; +Cc: Kyotaro Horiguchi <[email protected]>; pgsql-hackers
On 08.07.2020 10:03, Andrey M. Borodin wrote:
>
>> 2 июля 2020 г., в 17:02, Daniel Gustafsson <[email protected]> написал(а):
>>
>>> On 15 May 2020, at 02:03, Kyotaro Horiguchi <[email protected]> wrote:
>>> Generally in such cases, condition variables would work. In the
>>> attached PoC, the reader side gets no penalty in the "likely" code
>>> path. The writer side always calls ConditionVariableBroadcast but the
>>> waiter list is empty in almost all cases. But I couldn't cause the
>>> situation where the sleep 1000u is reached.
>> The submitted patch no longer applies, can you please submit an updated
>> version? I'm marking the patch Waiting on Author in the meantime.
> Thanks, Daniel! PFA V2
>
> Best regards, Andrey Borodin.
1) The first patch is sensible and harmless, so I think it is ready for
committer. I haven't tested the performance impact, though.
2) I like the initial proposal to make various SLRU buffers
configurable, however, I doubt if it really solves the problem, or just
moves it to another place?
The previous patch you sent was based on some version that contained
changes for other slru buffers numbers: 'multixact_offsets_slru_buffers'
and 'multixact_members_slru_buffers'. Have you just forgot to attach
them? The patch message "[PATCH v2 2/4]" hints that you had 4 patches)
Meanwhile, I attach the rebased patch to calm down the CFbot. The
changes are trivial.
2.1) I think that both min and max values for this parameter are too
extreme. Have you tested them?
+ &multixact_local_cache_entries,
+ 256, 2, INT_MAX / 2,
2.2) MAX_CACHE_ENTRIES is not used anymore, so it can be deleted.
3) No changes for third patch. I just renamed it for consistency.
--
Anastasia Lubennikova
Postgres Professional: http://www.postgrespro.com
The Russian Postgres Company
^ permalink raw reply [nested|flat] 90+ messages in thread
* Re: MultiXact\SLRU buffers configuration
2020-05-08 16:36 MultiXact\SLRU buffers configuration Andrey M. Borodin <[email protected]>
2020-05-11 11:17 ` Re: MultiXact\SLRU buffers configuration Andrey M. Borodin <[email protected]>
2020-05-13 18:08 ` Re: MultiXact\SLRU buffers configuration Andrey M. Borodin <[email protected]>
2020-05-14 01:25 ` Re: MultiXact\SLRU buffers configuration Kyotaro Horiguchi <[email protected]>
2020-05-14 05:19 ` Re: MultiXact\SLRU buffers configuration Andrey M. Borodin <[email protected]>
2020-05-14 06:16 ` Re: MultiXact\SLRU buffers configuration Kyotaro Horiguchi <[email protected]>
2020-05-14 06:44 ` Re: MultiXact\SLRU buffers configuration Andrey M. Borodin <[email protected]>
2020-05-15 00:03 ` Re: MultiXact\SLRU buffers configuration Kyotaro Horiguchi <[email protected]>
2020-07-02 12:02 ` Re: MultiXact\SLRU buffers configuration Daniel Gustafsson <[email protected]>
2020-07-08 07:03 ` Re: MultiXact\SLRU buffers configuration Andrey M. Borodin <[email protected]>
2020-08-28 18:08 ` Re: MultiXact\SLRU buffers configuration Anastasia Lubennikova <[email protected]>
@ 2020-09-28 14:41 ` Andrey M. Borodin <[email protected]>
2020-10-07 14:23 ` Re: MultiXact\SLRU buffers configuration Anastasia Lubennikova <[email protected]>
2020-10-26 01:05 ` Re: MultiXact\SLRU buffers configuration Alexander Korotkov <[email protected]>
0 siblings, 2 replies; 90+ messages in thread
From: Andrey M. Borodin @ 2020-09-28 14:41 UTC (permalink / raw)
To: Anastasia Lubennikova <[email protected]>; +Cc: Daniel Gustafsson <[email protected]>; Kyotaro Horiguchi <[email protected]>; pgsql-hackers
Hi, Anastasia!
> 28 авг. 2020 г., в 23:08, Anastasia Lubennikova <[email protected]> написал(а):
>
> 1) The first patch is sensible and harmless, so I think it is ready for committer. I haven't tested the performance impact, though.
>
> 2) I like the initial proposal to make various SLRU buffers configurable, however, I doubt if it really solves the problem, or just moves it to another place?
>
> The previous patch you sent was based on some version that contained changes for other slru buffers numbers: 'multixact_offsets_slru_buffers' and 'multixact_members_slru_buffers'. Have you just forgot to attach them? The patch message "[PATCH v2 2/4]" hints that you had 4 patches)
> Meanwhile, I attach the rebased patch to calm down the CFbot. The changes are trivial.
>
> 2.1) I think that both min and max values for this parameter are too extreme. Have you tested them?
>
> + &multixact_local_cache_entries,
> + 256, 2, INT_MAX / 2,
>
> 2.2) MAX_CACHE_ENTRIES is not used anymore, so it can be deleted.
>
> 3) No changes for third patch. I just renamed it for consistency.
Thank you for your review.
Indeed, I had 4th patch with tests, but these tests didn't work well: I still did not manage to stress SLRUs to reproduce problem from production...
You are absolutely correct in point 2: I did only tests with sane values. And observed extreme performance degradation with values ~ 64 megabytes. I do not know which highest values should we pick? 1Gb? Or highest possible functioning value?
I greatly appreciate your review, sorry for so long delay. Thanks!
Best regards, Andrey Borodin.
^ permalink raw reply [nested|flat] 90+ messages in thread
* Re: MultiXact\SLRU buffers configuration
2020-05-08 16:36 MultiXact\SLRU buffers configuration Andrey M. Borodin <[email protected]>
2020-05-11 11:17 ` Re: MultiXact\SLRU buffers configuration Andrey M. Borodin <[email protected]>
2020-05-13 18:08 ` Re: MultiXact\SLRU buffers configuration Andrey M. Borodin <[email protected]>
2020-05-14 01:25 ` Re: MultiXact\SLRU buffers configuration Kyotaro Horiguchi <[email protected]>
2020-05-14 05:19 ` Re: MultiXact\SLRU buffers configuration Andrey M. Borodin <[email protected]>
2020-05-14 06:16 ` Re: MultiXact\SLRU buffers configuration Kyotaro Horiguchi <[email protected]>
2020-05-14 06:44 ` Re: MultiXact\SLRU buffers configuration Andrey M. Borodin <[email protected]>
2020-05-15 00:03 ` Re: MultiXact\SLRU buffers configuration Kyotaro Horiguchi <[email protected]>
2020-07-02 12:02 ` Re: MultiXact\SLRU buffers configuration Daniel Gustafsson <[email protected]>
2020-07-08 07:03 ` Re: MultiXact\SLRU buffers configuration Andrey M. Borodin <[email protected]>
2020-08-28 18:08 ` Re: MultiXact\SLRU buffers configuration Anastasia Lubennikova <[email protected]>
2020-09-28 14:41 ` Re: MultiXact\SLRU buffers configuration Andrey M. Borodin <[email protected]>
@ 2020-10-07 14:23 ` Anastasia Lubennikova <[email protected]>
1 sibling, 0 replies; 90+ messages in thread
From: Anastasia Lubennikova @ 2020-10-07 14:23 UTC (permalink / raw)
To: Andrey M. Borodin <[email protected]>; +Cc: Daniel Gustafsson <[email protected]>; Kyotaro Horiguchi <[email protected]>; pgsql-hackers
On 28.09.2020 17:41, Andrey M. Borodin wrote:
> Hi, Anastasia!
>
>> 28 авг. 2020 г., в 23:08, Anastasia Lubennikova <[email protected]> написал(а):
>>
>> 1) The first patch is sensible and harmless, so I think it is ready for committer. I haven't tested the performance impact, though.
>>
>> 2) I like the initial proposal to make various SLRU buffers configurable, however, I doubt if it really solves the problem, or just moves it to another place?
>>
>> The previous patch you sent was based on some version that contained changes for other slru buffers numbers: 'multixact_offsets_slru_buffers' and 'multixact_members_slru_buffers'. Have you just forgot to attach them? The patch message "[PATCH v2 2/4]" hints that you had 4 patches)
>> Meanwhile, I attach the rebased patch to calm down the CFbot. The changes are trivial.
>>
>> 2.1) I think that both min and max values for this parameter are too extreme. Have you tested them?
>>
>> + &multixact_local_cache_entries,
>> + 256, 2, INT_MAX / 2,
>>
>> 2.2) MAX_CACHE_ENTRIES is not used anymore, so it can be deleted.
>>
>> 3) No changes for third patch. I just renamed it for consistency.
> Thank you for your review.
>
> Indeed, I had 4th patch with tests, but these tests didn't work well: I still did not manage to stress SLRUs to reproduce problem from production...
>
> You are absolutely correct in point 2: I did only tests with sane values. And observed extreme performance degradation with values ~ 64 megabytes. I do not know which highest values should we pick? 1Gb? Or highest possible functioning value?
I would go with the values that we consider adequate for this setting.
As I see, there is no strict rule about it in guc.c and many variables
have large border values. Anyway, we need to explain it at least in the
documentation and code comments.
It seems that the default was conservative enough, so it can be also a
minimal value too. As for maximum, can you provide any benchmark
results? If we have a peak and a noticeable performance degradation
after that, we can use it to calculate the preferable maxvalue.
--
Anastasia Lubennikova
Postgres Professional: http://www.postgrespro.com
The Russian Postgres Company
^ permalink raw reply [nested|flat] 90+ messages in thread
* Re: MultiXact\SLRU buffers configuration
2020-05-08 16:36 MultiXact\SLRU buffers configuration Andrey M. Borodin <[email protected]>
2020-05-11 11:17 ` Re: MultiXact\SLRU buffers configuration Andrey M. Borodin <[email protected]>
2020-05-13 18:08 ` Re: MultiXact\SLRU buffers configuration Andrey M. Borodin <[email protected]>
2020-05-14 01:25 ` Re: MultiXact\SLRU buffers configuration Kyotaro Horiguchi <[email protected]>
2020-05-14 05:19 ` Re: MultiXact\SLRU buffers configuration Andrey M. Borodin <[email protected]>
2020-05-14 06:16 ` Re: MultiXact\SLRU buffers configuration Kyotaro Horiguchi <[email protected]>
2020-05-14 06:44 ` Re: MultiXact\SLRU buffers configuration Andrey M. Borodin <[email protected]>
2020-05-15 00:03 ` Re: MultiXact\SLRU buffers configuration Kyotaro Horiguchi <[email protected]>
2020-07-02 12:02 ` Re: MultiXact\SLRU buffers configuration Daniel Gustafsson <[email protected]>
2020-07-08 07:03 ` Re: MultiXact\SLRU buffers configuration Andrey M. Borodin <[email protected]>
2020-08-28 18:08 ` Re: MultiXact\SLRU buffers configuration Anastasia Lubennikova <[email protected]>
2020-09-28 14:41 ` Re: MultiXact\SLRU buffers configuration Andrey M. Borodin <[email protected]>
@ 2020-10-26 01:05 ` Alexander Korotkov <[email protected]>
2020-10-26 15:45 ` Re: MultiXact\SLRU buffers configuration Andrey Borodin <[email protected]>
1 sibling, 1 reply; 90+ messages in thread
From: Alexander Korotkov @ 2020-10-26 01:05 UTC (permalink / raw)
To: Andrey M. Borodin <[email protected]>; +Cc: Anastasia Lubennikova <[email protected]>; Daniel Gustafsson <[email protected]>; Kyotaro Horiguchi <[email protected]>; pgsql-hackers
Hi!
On Mon, Sep 28, 2020 at 5:41 PM Andrey M. Borodin <[email protected]> wrote:
> > 28 авг. 2020 г., в 23:08, Anastasia Lubennikova <[email protected]> написал(а):
> >
> > 1) The first patch is sensible and harmless, so I think it is ready for committer. I haven't tested the performance impact, though.
> >
> > 2) I like the initial proposal to make various SLRU buffers configurable, however, I doubt if it really solves the problem, or just moves it to another place?
> >
> > The previous patch you sent was based on some version that contained changes for other slru buffers numbers: 'multixact_offsets_slru_buffers' and 'multixact_members_slru_buffers'. Have you just forgot to attach them? The patch message "[PATCH v2 2/4]" hints that you had 4 patches)
> > Meanwhile, I attach the rebased patch to calm down the CFbot. The changes are trivial.
> >
> > 2.1) I think that both min and max values for this parameter are too extreme. Have you tested them?
> >
> > + &multixact_local_cache_entries,
> > + 256, 2, INT_MAX / 2,
> >
> > 2.2) MAX_CACHE_ENTRIES is not used anymore, so it can be deleted.
> >
> > 3) No changes for third patch. I just renamed it for consistency.
>
> Thank you for your review.
>
> Indeed, I had 4th patch with tests, but these tests didn't work well: I still did not manage to stress SLRUs to reproduce problem from production...
>
> You are absolutely correct in point 2: I did only tests with sane values. And observed extreme performance degradation with values ~ 64 megabytes. I do not know which highest values should we pick? 1Gb? Or highest possible functioning value?
>
> I greatly appreciate your review, sorry for so long delay. Thanks!
I took a look at this patchset.
The 1st and 3rd patches look good to me. I made just minor improvements.
1) There is still a case when SimpleLruReadPage_ReadOnly() relocks the
SLRU lock, which is already taken in exclusive mode. I've evaded this
by passing the lock mode as a parameter to
SimpleLruReadPage_ReadOnly().
3) CHECK_FOR_INTERRUPTS() is not needed anymore, because it's called
inside ConditionVariableSleep() if needed. Also, no current wait
events use slashes, and I don't think we should introduce slashes
here. Even if we should, then we should also rename existing wait
events to be consistent with a new one. So, I've renamed the new wait
event to remove the slash.
Regarding the patch 2. I see the current documentation in the patch
doesn't explain to the user how to set the new parameter. I think we
should give users an idea what workloads need high values of
multixact_local_cache_entries parameter and what doesn't. Also, we
should explain the negative aspects of high values
multixact_local_cache_entries. Ideally, we should get the advantage
without overloading users with new nontrivial parameters, but I don't
have a particular idea here.
I'd like to propose committing 1 and 3, but leave 2 for further review.
------
Regards,
Alexander Korotkov
Attachments:
[application/octet-stream] v4-0001-Use-shared-lock-in-GetMultiXactIdMembers-for-offsets.patch (12.2K, ../../CAPpHfduekT=BrM3rLqvo4ajzKYmDk+6aCoYJrNHhK0Je+v2z=Q@mail.gmail.com/2-v4-0001-Use-shared-lock-in-GetMultiXactIdMembers-for-offsets.patch)
download | inline diff:
From 12bbf5dbd372a431d106e7e8c3ed50ffa5707a19 Mon Sep 17 00:00:00 2001
From: Alexander Korotkov <[email protected]>
Date: Mon, 26 Oct 2020 01:50:08 +0300
Subject: [PATCH 1/3] Use shared lock in GetMultiXactIdMembers for offsets and
members
Previously the read of multixact required exclusive control locks for both
offsets and members SLRUs. This could lead to the excessive lock contention.
This commit we makes multixacts SLRU take advantage of SimpleLruReadPage_ReadOnly
similar to clog, commit_ts and subtrans.
In order to evade extra reacquiring of CLRU lock, we teach
SimpleLruReadPage_ReadOnly() to take into account the current lock mode and
report resulting lock mode back.
Discussion: https://postgr.es/m/a7f1c4e1-1015-92a4-2bd4-6736bd13d03e%40postgrespro.ru#c496c4e75fc0605094a0e1f763e6a6ec
Author: Andrey Borodin
Reviewed-by: Kyotaro Horiguchi, Daniel Gustafsson
Reviewed-by: Anastasia Lubennikova, Alexander Korotkov
---
src/backend/access/transam/clog.c | 4 +++-
src/backend/access/transam/commit_ts.c | 4 +++-
src/backend/access/transam/multixact.c | 22 +++++++++++++++-------
src/backend/access/transam/slru.c | 23 +++++++++++++++++------
src/backend/access/transam/subtrans.c | 4 +++-
src/backend/commands/async.c | 4 +++-
src/backend/storage/lmgr/predicate.c | 4 +++-
src/include/access/slru.h | 2 +-
src/include/storage/lwlock.h | 2 ++
9 files changed, 50 insertions(+), 19 deletions(-)
diff --git a/src/backend/access/transam/clog.c b/src/backend/access/transam/clog.c
index 034349aa7b9..4c372065dee 100644
--- a/src/backend/access/transam/clog.c
+++ b/src/backend/access/transam/clog.c
@@ -640,10 +640,11 @@ TransactionIdGetStatus(TransactionId xid, XLogRecPtr *lsn)
int lsnindex;
char *byteptr;
XidStatus status;
+ LWLockMode lockmode = LW_NONE;
/* lock is acquired by SimpleLruReadPage_ReadOnly */
- slotno = SimpleLruReadPage_ReadOnly(XactCtl, pageno, xid);
+ slotno = SimpleLruReadPage_ReadOnly(XactCtl, pageno, xid, &lockmode);
byteptr = XactCtl->shared->page_buffer[slotno] + byteno;
status = (*byteptr >> bshift) & CLOG_XACT_BITMASK;
@@ -651,6 +652,7 @@ TransactionIdGetStatus(TransactionId xid, XLogRecPtr *lsn)
lsnindex = GetLSNIndex(slotno, xid);
*lsn = XactCtl->shared->group_lsn[lsnindex];
+ Assert(lockmode != LW_NONE);
LWLockRelease(XactSLRULock);
return status;
diff --git a/src/backend/access/transam/commit_ts.c b/src/backend/access/transam/commit_ts.c
index cb8a9688018..c19b0b5399e 100644
--- a/src/backend/access/transam/commit_ts.c
+++ b/src/backend/access/transam/commit_ts.c
@@ -288,6 +288,7 @@ TransactionIdGetCommitTsData(TransactionId xid, TimestampTz *ts,
CommitTimestampEntry entry;
TransactionId oldestCommitTsXid;
TransactionId newestCommitTsXid;
+ LWLockMode lockmode = LW_NONE;
if (!TransactionIdIsValid(xid))
ereport(ERROR,
@@ -342,7 +343,7 @@ TransactionIdGetCommitTsData(TransactionId xid, TimestampTz *ts,
}
/* lock is acquired by SimpleLruReadPage_ReadOnly */
- slotno = SimpleLruReadPage_ReadOnly(CommitTsCtl, pageno, xid);
+ slotno = SimpleLruReadPage_ReadOnly(CommitTsCtl, pageno, xid, &lockmode);
memcpy(&entry,
CommitTsCtl->shared->page_buffer[slotno] +
SizeOfCommitTimestampEntry * entryno,
@@ -352,6 +353,7 @@ TransactionIdGetCommitTsData(TransactionId xid, TimestampTz *ts,
if (nodeid)
*nodeid = entry.nodeid;
+ Assert(lockmode != LW_NONE);
LWLockRelease(CommitTsSLRULock);
return *ts != 0;
}
diff --git a/src/backend/access/transam/multixact.c b/src/backend/access/transam/multixact.c
index 43653fe5721..ccbce90f0ea 100644
--- a/src/backend/access/transam/multixact.c
+++ b/src/backend/access/transam/multixact.c
@@ -1237,6 +1237,7 @@ GetMultiXactIdMembers(MultiXactId multi, MultiXactMember **members,
MultiXactId tmpMXact;
MultiXactOffset nextOffset;
MultiXactMember *ptr;
+ LWLockMode lockmode = LW_NONE;
debug_elog3(DEBUG2, "GetMembers: asked for %u", multi);
@@ -1340,12 +1341,13 @@ GetMultiXactIdMembers(MultiXactId multi, MultiXactMember **members,
* time on every multixact creation.
*/
retry:
- LWLockAcquire(MultiXactOffsetSLRULock, LW_EXCLUSIVE);
pageno = MultiXactIdToOffsetPage(multi);
entryno = MultiXactIdToOffsetEntry(multi);
- slotno = SimpleLruReadPage(MultiXactOffsetCtl, pageno, true, multi);
+ /* lock is acquired by SimpleLruReadPage_ReadOnly */
+ slotno = SimpleLruReadPage_ReadOnly(MultiXactOffsetCtl, pageno,
+ multi, &lockmode);
offptr = (MultiXactOffset *) MultiXactOffsetCtl->shared->page_buffer[slotno];
offptr += entryno;
offset = *offptr;
@@ -1377,7 +1379,8 @@ retry:
entryno = MultiXactIdToOffsetEntry(tmpMXact);
if (pageno != prev_pageno)
- slotno = SimpleLruReadPage(MultiXactOffsetCtl, pageno, true, tmpMXact);
+ slotno = SimpleLruReadPage_ReadOnly(MultiXactOffsetCtl, pageno,
+ tmpMXact, &lockmode);
offptr = (MultiXactOffset *) MultiXactOffsetCtl->shared->page_buffer[slotno];
offptr += entryno;
@@ -1395,14 +1398,14 @@ retry:
length = nextMXOffset - offset;
}
+ Assert(lockmode != LW_NONE);
LWLockRelease(MultiXactOffsetSLRULock);
ptr = (MultiXactMember *) palloc(length * sizeof(MultiXactMember));
*members = ptr;
/* Now get the members themselves. */
- LWLockAcquire(MultiXactMemberSLRULock, LW_EXCLUSIVE);
-
+ lockmode = LW_NONE;
truelength = 0;
prev_pageno = -1;
for (i = 0; i < length; i++, offset++)
@@ -1418,7 +1421,8 @@ retry:
if (pageno != prev_pageno)
{
- slotno = SimpleLruReadPage(MultiXactMemberCtl, pageno, true, multi);
+ slotno = SimpleLruReadPage_ReadOnly(MultiXactMemberCtl, pageno,
+ multi, &lockmode);
prev_pageno = pageno;
}
@@ -1441,6 +1445,7 @@ retry:
truelength++;
}
+ Assert(lockmode != LW_NONE);
LWLockRelease(MultiXactMemberSLRULock);
/*
@@ -2733,6 +2738,7 @@ find_multixact_start(MultiXactId multi, MultiXactOffset *result)
int entryno;
int slotno;
MultiXactOffset *offptr;
+ LWLockMode lockmode = LW_NONE;
Assert(MultiXactState->finishedStartup);
@@ -2749,10 +2755,12 @@ find_multixact_start(MultiXactId multi, MultiXactOffset *result)
return false;
/* lock is acquired by SimpleLruReadPage_ReadOnly */
- slotno = SimpleLruReadPage_ReadOnly(MultiXactOffsetCtl, pageno, multi);
+ slotno = SimpleLruReadPage_ReadOnly(MultiXactOffsetCtl, pageno,
+ multi, &lockmode);
offptr = (MultiXactOffset *) MultiXactOffsetCtl->shared->page_buffer[slotno];
offptr += entryno;
offset = *offptr;
+ Assert(lockmode != LW_NONE);
LWLockRelease(MultiXactOffsetSLRULock);
*result = offset;
diff --git a/src/backend/access/transam/slru.c b/src/backend/access/transam/slru.c
index 16a78986971..ca0a23ab875 100644
--- a/src/backend/access/transam/slru.c
+++ b/src/backend/access/transam/slru.c
@@ -487,17 +487,23 @@ SimpleLruReadPage(SlruCtl ctl, int pageno, bool write_ok,
* Return value is the shared-buffer slot number now holding the page.
* The buffer's LRU access info is updated.
*
- * Control lock must NOT be held at entry, but will be held at exit.
- * It is unspecified whether the lock will be shared or exclusive.
+ * Control lock must be held in *lock_mode mode, which may be LW_NONE. Control
+ * lock will be held at exit in at least shared mode. Resulting control lock
+ * mode is set to *lock_mode.
*/
int
-SimpleLruReadPage_ReadOnly(SlruCtl ctl, int pageno, TransactionId xid)
+SimpleLruReadPage_ReadOnly(SlruCtl ctl, int pageno, TransactionId xid,
+ LWLockMode *lock_mode)
{
SlruShared shared = ctl->shared;
int slotno;
/* Try to find the page while holding only shared lock */
- LWLockAcquire(shared->ControlLock, LW_SHARED);
+ if (*lock_mode == LW_NONE)
+ {
+ LWLockAcquire(shared->ControlLock, LW_SHARED);
+ *lock_mode = LW_SHARED;
+ }
/* See if page is already in a buffer */
for (slotno = 0; slotno < shared->num_slots; slotno++)
@@ -517,8 +523,13 @@ SimpleLruReadPage_ReadOnly(SlruCtl ctl, int pageno, TransactionId xid)
}
/* No luck, so switch to normal exclusive lock and do regular read */
- LWLockRelease(shared->ControlLock);
- LWLockAcquire(shared->ControlLock, LW_EXCLUSIVE);
+ if (*lock_mode != LW_EXCLUSIVE)
+ {
+ Assert(*lock_mode == LW_NONE);
+ LWLockRelease(shared->ControlLock);
+ LWLockAcquire(shared->ControlLock, LW_EXCLUSIVE);
+ *lock_mode = LW_EXCLUSIVE;
+ }
return SimpleLruReadPage(ctl, pageno, true, xid);
}
diff --git a/src/backend/access/transam/subtrans.c b/src/backend/access/transam/subtrans.c
index 0111e867c79..7bb15431893 100644
--- a/src/backend/access/transam/subtrans.c
+++ b/src/backend/access/transam/subtrans.c
@@ -113,6 +113,7 @@ SubTransGetParent(TransactionId xid)
int slotno;
TransactionId *ptr;
TransactionId parent;
+ LWLockMode lockmode = LW_NONE;
/* Can't ask about stuff that might not be around anymore */
Assert(TransactionIdFollowsOrEquals(xid, TransactionXmin));
@@ -123,12 +124,13 @@ SubTransGetParent(TransactionId xid)
/* lock is acquired by SimpleLruReadPage_ReadOnly */
- slotno = SimpleLruReadPage_ReadOnly(SubTransCtl, pageno, xid);
+ slotno = SimpleLruReadPage_ReadOnly(SubTransCtl, pageno, xid, &lockmode);
ptr = (TransactionId *) SubTransCtl->shared->page_buffer[slotno];
ptr += entryno;
parent = *ptr;
+ Assert(lockmode != LW_NONE);
LWLockRelease(SubtransSLRULock);
return parent;
diff --git a/src/backend/commands/async.c b/src/backend/commands/async.c
index 8dbcace3f93..8b419575590 100644
--- a/src/backend/commands/async.c
+++ b/src/backend/commands/async.c
@@ -2002,6 +2002,7 @@ asyncQueueReadAllNotifications(void)
int curoffset = QUEUE_POS_OFFSET(pos);
int slotno;
int copysize;
+ LWLockMode lockmode = LW_NONE;
/*
* We copy the data from SLRU into a local buffer, so as to avoid
@@ -2010,7 +2011,7 @@ asyncQueueReadAllNotifications(void)
* part of the page we will actually inspect.
*/
slotno = SimpleLruReadPage_ReadOnly(NotifyCtl, curpage,
- InvalidTransactionId);
+ InvalidTransactionId, &lockmode);
if (curpage == QUEUE_POS_PAGE(head))
{
/* we only want to read as far as head */
@@ -2027,6 +2028,7 @@ asyncQueueReadAllNotifications(void)
NotifyCtl->shared->page_buffer[slotno] + curoffset,
copysize);
/* Release lock that we got from SimpleLruReadPage_ReadOnly() */
+ Assert(lockmode != LW_NONE);
LWLockRelease(NotifySLRULock);
/*
diff --git a/src/backend/storage/lmgr/predicate.c b/src/backend/storage/lmgr/predicate.c
index 8a365b400c6..a4df90a8aeb 100644
--- a/src/backend/storage/lmgr/predicate.c
+++ b/src/backend/storage/lmgr/predicate.c
@@ -924,6 +924,7 @@ SerialGetMinConflictCommitSeqNo(TransactionId xid)
TransactionId tailXid;
SerCommitSeqNo val;
int slotno;
+ LWLockMode lockmode = LW_NONE;
Assert(TransactionIdIsValid(xid));
@@ -946,8 +947,9 @@ SerialGetMinConflictCommitSeqNo(TransactionId xid)
* but will return with that lock held, which must then be released.
*/
slotno = SimpleLruReadPage_ReadOnly(SerialSlruCtl,
- SerialPage(xid), xid);
+ SerialPage(xid), xid, &lockmode);
val = SerialValue(slotno, xid);
+ Assert(lockmode != LW_NONE);
LWLockRelease(SerialSLRULock);
return val;
}
diff --git a/src/include/access/slru.h b/src/include/access/slru.h
index b39b43504d8..4b66d3b592b 100644
--- a/src/include/access/slru.h
+++ b/src/include/access/slru.h
@@ -142,7 +142,7 @@ extern int SimpleLruZeroPage(SlruCtl ctl, int pageno);
extern int SimpleLruReadPage(SlruCtl ctl, int pageno, bool write_ok,
TransactionId xid);
extern int SimpleLruReadPage_ReadOnly(SlruCtl ctl, int pageno,
- TransactionId xid);
+ TransactionId xid, LWLockMode *lock_mode);
extern void SimpleLruWritePage(SlruCtl ctl, int slotno);
extern void SimpleLruWriteAll(SlruCtl ctl, bool allow_redirtied);
extern void SimpleLruTruncate(SlruCtl ctl, int cutoffPage);
diff --git a/src/include/storage/lwlock.h b/src/include/storage/lwlock.h
index af9b41795d2..2684c8e51c9 100644
--- a/src/include/storage/lwlock.h
+++ b/src/include/storage/lwlock.h
@@ -129,6 +129,8 @@ extern PGDLLIMPORT int NamedLWLockTrancheRequests;
typedef enum LWLockMode
{
+ LW_NONE, /* Not a lock mode. Indicates that there is
+ * no lock. */
LW_EXCLUSIVE,
LW_SHARED,
LW_WAIT_UNTIL_FREE /* A special mode used in PGPROC->lwWaitMode,
--
2.14.3
[application/octet-stream] v4-0002-Make-MultiXact-local-cache-size-configurable.patch (3.7K, ../../CAPpHfduekT=BrM3rLqvo4ajzKYmDk+6aCoYJrNHhK0Je+v2z=Q@mail.gmail.com/3-v4-0002-Make-MultiXact-local-cache-size-configurable.patch)
download | inline diff:
From b1af887f4c4e5402dce1b6ea226ac8b81b92443f Mon Sep 17 00:00:00 2001
From: Alexander Korotkov <[email protected]>
Date: Mon, 26 Oct 2020 03:44:50 +0300
Subject: [PATCH 2/3] Make MultiXact local cache size configurable
---
doc/src/sgml/config.sgml | 16 ++++++++++++++++
src/backend/access/transam/multixact.c | 2 +-
src/backend/utils/init/globals.c | 2 ++
src/backend/utils/misc/guc.c | 10 ++++++++++
src/include/miscadmin.h | 2 ++
5 files changed, 31 insertions(+), 1 deletion(-)
diff --git a/doc/src/sgml/config.sgml b/doc/src/sgml/config.sgml
index f043433e318..fd4ca293476 100644
--- a/doc/src/sgml/config.sgml
+++ b/doc/src/sgml/config.sgml
@@ -1823,6 +1823,22 @@ include_dir 'conf.d'
</listitem>
</varlistentry>
+ <varlistentry id="guc-multixact-local-cache-entries" xreflabel="multixact_local-cache-entries">
+ <term><varname>multixact_local_cache_entries</varname> (<type>integer</type>)
+ <indexterm>
+ <primary><varname>multixact_local_cache_entries</varname> configuration parameter</primary>
+ </indexterm>
+ </term>
+ <listitem>
+ <para>
+ Specifies the number cached MultiXact by backend. Any SLRU lookup is preceeded
+ by cache lookup. Higher numbers of cache size help to deduplicate lock sets, while
+ lower values make cache lookup faster.
+ It defaults to 256.
+ </para>
+ </listitem>
+ </varlistentry>
+
<varlistentry id="guc-max-stack-depth" xreflabel="max_stack_depth">
<term><varname>max_stack_depth</varname> (<type>integer</type>)
<indexterm>
diff --git a/src/backend/access/transam/multixact.c b/src/backend/access/transam/multixact.c
index ccbce90f0ea..57be24c0cc1 100644
--- a/src/backend/access/transam/multixact.c
+++ b/src/backend/access/transam/multixact.c
@@ -1613,7 +1613,7 @@ mXactCachePut(MultiXactId multi, int nmembers, MultiXactMember *members)
qsort(entry->members, nmembers, sizeof(MultiXactMember), mxactMemberComparator);
dlist_push_head(&MXactCache, &entry->node);
- if (MXactCacheMembers++ >= MAX_CACHE_ENTRIES)
+ if (MXactCacheMembers++ >= multixact_local_cache_entries)
{
dlist_node *node;
mXactCacheEnt *entry;
diff --git a/src/backend/utils/init/globals.c b/src/backend/utils/init/globals.c
index 6ab82168398..9ca71933dcc 100644
--- a/src/backend/utils/init/globals.c
+++ b/src/backend/utils/init/globals.c
@@ -149,3 +149,5 @@ int VacuumCostBalance = 0; /* working state for vacuum */
bool VacuumCostActive = false;
double vacuum_cleanup_index_scale_factor;
+
+int multixact_local_cache_entries = 256;
diff --git a/src/backend/utils/misc/guc.c b/src/backend/utils/misc/guc.c
index a62d64eaa47..d667578cc33 100644
--- a/src/backend/utils/misc/guc.c
+++ b/src/backend/utils/misc/guc.c
@@ -2257,6 +2257,16 @@ static struct config_int ConfigureNamesInt[] =
NULL, NULL, NULL
},
+ {
+ {"multixact_local_cache_entries", PGC_SUSET, RESOURCES_MEM,
+ gettext_noop("Sets the number of cached MultiXact by backend."),
+ NULL
+ },
+ &multixact_local_cache_entries,
+ 256, 2, INT_MAX / 2,
+ NULL, NULL, NULL
+ },
+
{
{"temp_buffers", PGC_USERSET, RESOURCES_MEM,
gettext_noop("Sets the maximum number of temporary buffers used by each session."),
diff --git a/src/include/miscadmin.h b/src/include/miscadmin.h
index 72e33523984..01af61c963a 100644
--- a/src/include/miscadmin.h
+++ b/src/include/miscadmin.h
@@ -162,6 +162,8 @@ extern PGDLLIMPORT int MaxConnections;
extern PGDLLIMPORT int max_worker_processes;
extern PGDLLIMPORT int max_parallel_workers;
+extern PGDLLIMPORT int multixact_local_cache_entries;
+
extern PGDLLIMPORT int MyProcPid;
extern PGDLLIMPORT pg_time_t MyStartTime;
extern PGDLLIMPORT TimestampTz MyStartTimestamp;
--
2.14.3
[application/octet-stream] v4-0003-Add-conditional-variable-to-wait-for-next-MultXact-o.patch (4.2K, ../../CAPpHfduekT=BrM3rLqvo4ajzKYmDk+6aCoYJrNHhK0Je+v2z=Q@mail.gmail.com/4-v4-0003-Add-conditional-variable-to-wait-for-next-MultXact-o.patch)
download | inline diff:
From b878ffe74a10d34d312a7be66df7a53b423aaaec Mon Sep 17 00:00:00 2001
From: Alexander Korotkov <[email protected]>
Date: Mon, 26 Oct 2020 01:55:31 +0300
Subject: [PATCH 3/3] Add conditional variable to wait for next MultXact offset
in corner case
GetMultiXactIdMembers() has a corner case, when the next multixact offset is
not yet set. In this case GetMultiXactIdMembers() has to sleep till this offset
is set. Currently the sleeping is implemented in naive way using pg_sleep()
and retry. This commit implements sleeping with conditional variable, which
provides more efficient way for waiting till the event.
Discussion: https://postgr.es/m/a7f1c4e1-1015-92a4-2bd4-6736bd13d03e%40postgrespro.ru#c496c4e75fc0605094a0e1f763e6a6ec
Author: Andrey Borodin
Reviewed-by: Kyotaro Horiguchi, Daniel Gustafsson
Reviewed-by: Anastasia Lubennikova, Alexander Korotkov
---
src/backend/access/transam/multixact.c | 29 +++++++++++++++++++++++++++--
src/backend/postmaster/pgstat.c | 2 ++
src/include/pgstat.h | 1 +
3 files changed, 30 insertions(+), 2 deletions(-)
diff --git a/src/backend/access/transam/multixact.c b/src/backend/access/transam/multixact.c
index 57be24c0cc1..09df91899ec 100644
--- a/src/backend/access/transam/multixact.c
+++ b/src/backend/access/transam/multixact.c
@@ -82,6 +82,7 @@
#include "lib/ilist.h"
#include "miscadmin.h"
#include "pg_trace.h"
+#include "pgstat.h"
#include "postmaster/autovacuum.h"
#include "storage/lmgr.h"
#include "storage/pmsignal.h"
@@ -233,6 +234,7 @@ typedef struct MultiXactStateData
/* support for members anti-wraparound measures */
MultiXactOffset offsetStopLimit; /* known if oldestOffsetKnown */
+ ConditionVariable nextoff_cv;
/*
* Per-backend data starts here. We have two arrays stored in the area
* immediately following the MultiXactStateData struct. Each is indexed by
@@ -892,6 +894,14 @@ RecordNewMultiXact(MultiXactId multi, MultiXactOffset offset,
/* Exchange our lock */
LWLockRelease(MultiXactOffsetSLRULock);
+ /*
+ * Let everybody know the offset of this mxid is recorded now. The waiters
+ * are waiting for the offset of the mxid next of the target to know the
+ * number of members of the target mxid, so we don't need to wait for
+ * members of this mxid are recorded.
+ */
+ ConditionVariableBroadcast(&MultiXactState->nextoff_cv);
+
LWLockAcquire(MultiXactMemberSLRULock, LW_EXCLUSIVE);
prev_pageno = -1;
@@ -1389,9 +1399,23 @@ retry:
if (nextMXOffset == 0)
{
/* Corner case 2: next multixact is still being filled in */
+
+ /*
+ * The recorder of the next mxid is just before writing the offset.
+ * Wait for the offset to be written.
+ */
+ ConditionVariablePrepareToSleep(&MultiXactState->nextoff_cv);
+
+ /*
+ * We don't have to recheck if multixact was filled in during
+ * ConditionVariablePrepareToSleep(), because we were holding
+ * MultiXactOffsetSLRULock.
+ */
LWLockRelease(MultiXactOffsetSLRULock);
- CHECK_FOR_INTERRUPTS();
- pg_usleep(1000L);
+
+ ConditionVariableSleep(&MultiXactState->nextoff_cv,
+ WAIT_EVENT_WAIT_NEXT_MXMEMBERS);
+ ConditionVariableCancelSleep();
goto retry;
}
@@ -1873,6 +1897,7 @@ MultiXactShmemInit(void)
/* Make sure we zero out the per-backend state */
MemSet(MultiXactState, 0, SHARED_MULTIXACT_STATE_SIZE);
+ ConditionVariableInit(&MultiXactState->nextoff_cv);
}
else
Assert(found);
diff --git a/src/backend/postmaster/pgstat.c b/src/backend/postmaster/pgstat.c
index 822f0ebc628..b99398a97e9 100644
--- a/src/backend/postmaster/pgstat.c
+++ b/src/backend/postmaster/pgstat.c
@@ -4020,6 +4020,8 @@ pgstat_get_wait_ipc(WaitEventIPC w)
break;
case WAIT_EVENT_XACT_GROUP_UPDATE:
event_name = "XactGroupUpdate";
+ case WAIT_EVENT_WAIT_NEXT_MXMEMBERS:
+ event_name = "MultiXactWaitNextMembers";
break;
/* no default case, so that compiler will warn */
}
diff --git a/src/include/pgstat.h b/src/include/pgstat.h
index a821ff4f158..75ede141ab7 100644
--- a/src/include/pgstat.h
+++ b/src/include/pgstat.h
@@ -952,6 +952,7 @@ typedef enum
WAIT_EVENT_REPLICATION_SLOT_DROP,
WAIT_EVENT_SAFE_SNAPSHOT,
WAIT_EVENT_SYNC_REP,
+ WAIT_EVENT_WAIT_NEXT_MXMEMBERS,
WAIT_EVENT_XACT_GROUP_UPDATE
} WaitEventIPC;
--
2.14.3
^ permalink raw reply [nested|flat] 90+ messages in thread
* Re: MultiXact\SLRU buffers configuration
2020-05-08 16:36 MultiXact\SLRU buffers configuration Andrey M. Borodin <[email protected]>
2020-05-11 11:17 ` Re: MultiXact\SLRU buffers configuration Andrey M. Borodin <[email protected]>
2020-05-13 18:08 ` Re: MultiXact\SLRU buffers configuration Andrey M. Borodin <[email protected]>
2020-05-14 01:25 ` Re: MultiXact\SLRU buffers configuration Kyotaro Horiguchi <[email protected]>
2020-05-14 05:19 ` Re: MultiXact\SLRU buffers configuration Andrey M. Borodin <[email protected]>
2020-05-14 06:16 ` Re: MultiXact\SLRU buffers configuration Kyotaro Horiguchi <[email protected]>
2020-05-14 06:44 ` Re: MultiXact\SLRU buffers configuration Andrey M. Borodin <[email protected]>
2020-05-15 00:03 ` Re: MultiXact\SLRU buffers configuration Kyotaro Horiguchi <[email protected]>
2020-07-02 12:02 ` Re: MultiXact\SLRU buffers configuration Daniel Gustafsson <[email protected]>
2020-07-08 07:03 ` Re: MultiXact\SLRU buffers configuration Andrey M. Borodin <[email protected]>
2020-08-28 18:08 ` Re: MultiXact\SLRU buffers configuration Anastasia Lubennikova <[email protected]>
2020-09-28 14:41 ` Re: MultiXact\SLRU buffers configuration Andrey M. Borodin <[email protected]>
2020-10-26 01:05 ` Re: MultiXact\SLRU buffers configuration Alexander Korotkov <[email protected]>
@ 2020-10-26 15:45 ` Andrey Borodin <[email protected]>
2020-10-27 17:02 ` Re: MultiXact\SLRU buffers configuration Alexander Korotkov <[email protected]>
0 siblings, 1 reply; 90+ messages in thread
From: Andrey Borodin @ 2020-10-26 15:45 UTC (permalink / raw)
To: Alexander Korotkov <[email protected]>; +Cc: Anastasia Lubennikova <[email protected]>; Daniel Gustafsson <[email protected]>; Kyotaro Horiguchi <[email protected]>; pgsql-hackers
> 26 окт. 2020 г., в 06:05, Alexander Korotkov <[email protected]> написал(а):
>
> Hi!
>
> On Mon, Sep 28, 2020 at 5:41 PM Andrey M. Borodin <[email protected]> wrote:
>>> 28 авг. 2020 г., в 23:08, Anastasia Lubennikova <[email protected]> написал(а):
>>>
>>> 1) The first patch is sensible and harmless, so I think it is ready for committer. I haven't tested the performance impact, though.
>>>
>>> 2) I like the initial proposal to make various SLRU buffers configurable, however, I doubt if it really solves the problem, or just moves it to another place?
>>>
>>> The previous patch you sent was based on some version that contained changes for other slru buffers numbers: 'multixact_offsets_slru_buffers' and 'multixact_members_slru_buffers'. Have you just forgot to attach them? The patch message "[PATCH v2 2/4]" hints that you had 4 patches)
>>> Meanwhile, I attach the rebased patch to calm down the CFbot. The changes are trivial.
>>>
>>> 2.1) I think that both min and max values for this parameter are too extreme. Have you tested them?
>>>
>>> + &multixact_local_cache_entries,
>>> + 256, 2, INT_MAX / 2,
>>>
>>> 2.2) MAX_CACHE_ENTRIES is not used anymore, so it can be deleted.
>>>
>>> 3) No changes for third patch. I just renamed it for consistency.
>>
>> Thank you for your review.
>>
>> Indeed, I had 4th patch with tests, but these tests didn't work well: I still did not manage to stress SLRUs to reproduce problem from production...
>>
>> You are absolutely correct in point 2: I did only tests with sane values. And observed extreme performance degradation with values ~ 64 megabytes. I do not know which highest values should we pick? 1Gb? Or highest possible functioning value?
>>
>> I greatly appreciate your review, sorry for so long delay. Thanks!
>
> I took a look at this patchset.
>
> The 1st and 3rd patches look good to me. I made just minor improvements.
> 1) There is still a case when SimpleLruReadPage_ReadOnly() relocks the
> SLRU lock, which is already taken in exclusive mode. I've evaded this
> by passing the lock mode as a parameter to
> SimpleLruReadPage_ReadOnly().
> 3) CHECK_FOR_INTERRUPTS() is not needed anymore, because it's called
> inside ConditionVariableSleep() if needed. Also, no current wait
> events use slashes, and I don't think we should introduce slashes
> here. Even if we should, then we should also rename existing wait
> events to be consistent with a new one. So, I've renamed the new wait
> event to remove the slash.
>
> Regarding the patch 2. I see the current documentation in the patch
> doesn't explain to the user how to set the new parameter. I think we
> should give users an idea what workloads need high values of
> multixact_local_cache_entries parameter and what doesn't. Also, we
> should explain the negative aspects of high values
> multixact_local_cache_entries. Ideally, we should get the advantage
> without overloading users with new nontrivial parameters, but I don't
> have a particular idea here.
>
> I'd like to propose committing 1 and 3, but leave 2 for further review.
Thanks for your review, Alexander!
+1 for avoiding double locking in SimpleLruReadPage_ReadOnly().
Other changes seem correct to me too.
I've tried to find optimal value for cache size and it seems to me that it affects multixact scalability much less than sizes of offsets\members buffers. I concur that patch 2 of the patchset does not seem documented enough.
Best regards, Andrey Borodin.
^ permalink raw reply [nested|flat] 90+ messages in thread
* Re: MultiXact\SLRU buffers configuration
2020-05-08 16:36 MultiXact\SLRU buffers configuration Andrey M. Borodin <[email protected]>
2020-05-11 11:17 ` Re: MultiXact\SLRU buffers configuration Andrey M. Borodin <[email protected]>
2020-05-13 18:08 ` Re: MultiXact\SLRU buffers configuration Andrey M. Borodin <[email protected]>
2020-05-14 01:25 ` Re: MultiXact\SLRU buffers configuration Kyotaro Horiguchi <[email protected]>
2020-05-14 05:19 ` Re: MultiXact\SLRU buffers configuration Andrey M. Borodin <[email protected]>
2020-05-14 06:16 ` Re: MultiXact\SLRU buffers configuration Kyotaro Horiguchi <[email protected]>
2020-05-14 06:44 ` Re: MultiXact\SLRU buffers configuration Andrey M. Borodin <[email protected]>
2020-05-15 00:03 ` Re: MultiXact\SLRU buffers configuration Kyotaro Horiguchi <[email protected]>
2020-07-02 12:02 ` Re: MultiXact\SLRU buffers configuration Daniel Gustafsson <[email protected]>
2020-07-08 07:03 ` Re: MultiXact\SLRU buffers configuration Andrey M. Borodin <[email protected]>
2020-08-28 18:08 ` Re: MultiXact\SLRU buffers configuration Anastasia Lubennikova <[email protected]>
2020-09-28 14:41 ` Re: MultiXact\SLRU buffers configuration Andrey M. Borodin <[email protected]>
2020-10-26 01:05 ` Re: MultiXact\SLRU buffers configuration Alexander Korotkov <[email protected]>
2020-10-26 15:45 ` Re: MultiXact\SLRU buffers configuration Andrey Borodin <[email protected]>
@ 2020-10-27 17:02 ` Alexander Korotkov <[email protected]>
2020-10-27 17:23 ` Re: MultiXact\SLRU buffers configuration Alexander Korotkov <[email protected]>
0 siblings, 1 reply; 90+ messages in thread
From: Alexander Korotkov @ 2020-10-27 17:02 UTC (permalink / raw)
To: Andrey Borodin <[email protected]>; +Cc: Anastasia Lubennikova <[email protected]>; Daniel Gustafsson <[email protected]>; Kyotaro Horiguchi <[email protected]>; pgsql-hackers
On Mon, Oct 26, 2020 at 6:45 PM Andrey Borodin <[email protected]> wrote:
> Thanks for your review, Alexander!
> +1 for avoiding double locking in SimpleLruReadPage_ReadOnly().
> Other changes seem correct to me too.
>
>
> I've tried to find optimal value for cache size and it seems to me that it affects multixact scalability much less than sizes of offsets\members buffers. I concur that patch 2 of the patchset does not seem documented enough.
Thank you. I've made a few more minor adjustments to the patchset.
I'm going to push 0001 and 0003 if there are no objections.
------
Regards,
Alexander Korotkov
Attachments:
[application/octet-stream] v5-0001-Use-shared-lock-in-GetMultiXactIdMembers-for-offs.patch (12.9K, ../../CAPpHfduT0Kb+8fMt4t0EF5G_3hig+wYgeRadQnNq20F4VxP7LA@mail.gmail.com/2-v5-0001-Use-shared-lock-in-GetMultiXactIdMembers-for-offs.patch)
download | inline diff:
From e81bccfe1dbf0403163b8e1e836211e0dab1d7a4 Mon Sep 17 00:00:00 2001
From: Alexander Korotkov <[email protected]>
Date: Tue, 27 Oct 2020 19:29:56 +0300
Subject: [PATCH 1/3] Use shared lock in GetMultiXactIdMembers for offsets and
members
Previously the read of multixact required exclusive control locks for both
offsets and members SLRUs. This could lead to the excessive lock contention.
This commit we makes multixacts SLRU take advantage of SimpleLruReadPage_ReadOnly
similar to clog, commit_ts and subtrans.
In order to evade extra reacquiring of CLRU lock, we teach
SimpleLruReadPage_ReadOnly() to take into account the current lock mode and
report resulting lock mode back.
Discussion: https://postgr.es/m/a7f1c4e1-1015-92a4-2bd4-6736bd13d03e%40postgrespro.ru#c496c4e75fc0605094a0e1f763e6a6ec
Author: Andrey Borodin
Reviewed-by: Kyotaro Horiguchi, Daniel Gustafsson
Reviewed-by: Anastasia Lubennikova, Alexander Korotkov
---
src/backend/access/transam/clog.c | 4 +++-
src/backend/access/transam/commit_ts.c | 4 +++-
src/backend/access/transam/multixact.c | 22 +++++++++++++++-------
src/backend/access/transam/slru.c | 23 +++++++++++++++++------
src/backend/access/transam/subtrans.c | 4 +++-
src/backend/commands/async.c | 4 +++-
src/backend/storage/lmgr/lwlock.c | 3 +++
src/backend/storage/lmgr/predicate.c | 4 +++-
src/include/access/slru.h | 2 +-
src/include/storage/lwlock.h | 2 ++
10 files changed, 53 insertions(+), 19 deletions(-)
diff --git a/src/backend/access/transam/clog.c b/src/backend/access/transam/clog.c
index 034349aa7b9..4c372065dee 100644
--- a/src/backend/access/transam/clog.c
+++ b/src/backend/access/transam/clog.c
@@ -640,10 +640,11 @@ TransactionIdGetStatus(TransactionId xid, XLogRecPtr *lsn)
int lsnindex;
char *byteptr;
XidStatus status;
+ LWLockMode lockmode = LW_NONE;
/* lock is acquired by SimpleLruReadPage_ReadOnly */
- slotno = SimpleLruReadPage_ReadOnly(XactCtl, pageno, xid);
+ slotno = SimpleLruReadPage_ReadOnly(XactCtl, pageno, xid, &lockmode);
byteptr = XactCtl->shared->page_buffer[slotno] + byteno;
status = (*byteptr >> bshift) & CLOG_XACT_BITMASK;
@@ -651,6 +652,7 @@ TransactionIdGetStatus(TransactionId xid, XLogRecPtr *lsn)
lsnindex = GetLSNIndex(slotno, xid);
*lsn = XactCtl->shared->group_lsn[lsnindex];
+ Assert(lockmode != LW_NONE);
LWLockRelease(XactSLRULock);
return status;
diff --git a/src/backend/access/transam/commit_ts.c b/src/backend/access/transam/commit_ts.c
index cb8a9688018..c19b0b5399e 100644
--- a/src/backend/access/transam/commit_ts.c
+++ b/src/backend/access/transam/commit_ts.c
@@ -288,6 +288,7 @@ TransactionIdGetCommitTsData(TransactionId xid, TimestampTz *ts,
CommitTimestampEntry entry;
TransactionId oldestCommitTsXid;
TransactionId newestCommitTsXid;
+ LWLockMode lockmode = LW_NONE;
if (!TransactionIdIsValid(xid))
ereport(ERROR,
@@ -342,7 +343,7 @@ TransactionIdGetCommitTsData(TransactionId xid, TimestampTz *ts,
}
/* lock is acquired by SimpleLruReadPage_ReadOnly */
- slotno = SimpleLruReadPage_ReadOnly(CommitTsCtl, pageno, xid);
+ slotno = SimpleLruReadPage_ReadOnly(CommitTsCtl, pageno, xid, &lockmode);
memcpy(&entry,
CommitTsCtl->shared->page_buffer[slotno] +
SizeOfCommitTimestampEntry * entryno,
@@ -352,6 +353,7 @@ TransactionIdGetCommitTsData(TransactionId xid, TimestampTz *ts,
if (nodeid)
*nodeid = entry.nodeid;
+ Assert(lockmode != LW_NONE);
LWLockRelease(CommitTsSLRULock);
return *ts != 0;
}
diff --git a/src/backend/access/transam/multixact.c b/src/backend/access/transam/multixact.c
index 43653fe5721..ccbce90f0ea 100644
--- a/src/backend/access/transam/multixact.c
+++ b/src/backend/access/transam/multixact.c
@@ -1237,6 +1237,7 @@ GetMultiXactIdMembers(MultiXactId multi, MultiXactMember **members,
MultiXactId tmpMXact;
MultiXactOffset nextOffset;
MultiXactMember *ptr;
+ LWLockMode lockmode = LW_NONE;
debug_elog3(DEBUG2, "GetMembers: asked for %u", multi);
@@ -1340,12 +1341,13 @@ GetMultiXactIdMembers(MultiXactId multi, MultiXactMember **members,
* time on every multixact creation.
*/
retry:
- LWLockAcquire(MultiXactOffsetSLRULock, LW_EXCLUSIVE);
pageno = MultiXactIdToOffsetPage(multi);
entryno = MultiXactIdToOffsetEntry(multi);
- slotno = SimpleLruReadPage(MultiXactOffsetCtl, pageno, true, multi);
+ /* lock is acquired by SimpleLruReadPage_ReadOnly */
+ slotno = SimpleLruReadPage_ReadOnly(MultiXactOffsetCtl, pageno,
+ multi, &lockmode);
offptr = (MultiXactOffset *) MultiXactOffsetCtl->shared->page_buffer[slotno];
offptr += entryno;
offset = *offptr;
@@ -1377,7 +1379,8 @@ retry:
entryno = MultiXactIdToOffsetEntry(tmpMXact);
if (pageno != prev_pageno)
- slotno = SimpleLruReadPage(MultiXactOffsetCtl, pageno, true, tmpMXact);
+ slotno = SimpleLruReadPage_ReadOnly(MultiXactOffsetCtl, pageno,
+ tmpMXact, &lockmode);
offptr = (MultiXactOffset *) MultiXactOffsetCtl->shared->page_buffer[slotno];
offptr += entryno;
@@ -1395,14 +1398,14 @@ retry:
length = nextMXOffset - offset;
}
+ Assert(lockmode != LW_NONE);
LWLockRelease(MultiXactOffsetSLRULock);
ptr = (MultiXactMember *) palloc(length * sizeof(MultiXactMember));
*members = ptr;
/* Now get the members themselves. */
- LWLockAcquire(MultiXactMemberSLRULock, LW_EXCLUSIVE);
-
+ lockmode = LW_NONE;
truelength = 0;
prev_pageno = -1;
for (i = 0; i < length; i++, offset++)
@@ -1418,7 +1421,8 @@ retry:
if (pageno != prev_pageno)
{
- slotno = SimpleLruReadPage(MultiXactMemberCtl, pageno, true, multi);
+ slotno = SimpleLruReadPage_ReadOnly(MultiXactMemberCtl, pageno,
+ multi, &lockmode);
prev_pageno = pageno;
}
@@ -1441,6 +1445,7 @@ retry:
truelength++;
}
+ Assert(lockmode != LW_NONE);
LWLockRelease(MultiXactMemberSLRULock);
/*
@@ -2733,6 +2738,7 @@ find_multixact_start(MultiXactId multi, MultiXactOffset *result)
int entryno;
int slotno;
MultiXactOffset *offptr;
+ LWLockMode lockmode = LW_NONE;
Assert(MultiXactState->finishedStartup);
@@ -2749,10 +2755,12 @@ find_multixact_start(MultiXactId multi, MultiXactOffset *result)
return false;
/* lock is acquired by SimpleLruReadPage_ReadOnly */
- slotno = SimpleLruReadPage_ReadOnly(MultiXactOffsetCtl, pageno, multi);
+ slotno = SimpleLruReadPage_ReadOnly(MultiXactOffsetCtl, pageno,
+ multi, &lockmode);
offptr = (MultiXactOffset *) MultiXactOffsetCtl->shared->page_buffer[slotno];
offptr += entryno;
offset = *offptr;
+ Assert(lockmode != LW_NONE);
LWLockRelease(MultiXactOffsetSLRULock);
*result = offset;
diff --git a/src/backend/access/transam/slru.c b/src/backend/access/transam/slru.c
index 16a78986971..ca0a23ab875 100644
--- a/src/backend/access/transam/slru.c
+++ b/src/backend/access/transam/slru.c
@@ -487,17 +487,23 @@ SimpleLruReadPage(SlruCtl ctl, int pageno, bool write_ok,
* Return value is the shared-buffer slot number now holding the page.
* The buffer's LRU access info is updated.
*
- * Control lock must NOT be held at entry, but will be held at exit.
- * It is unspecified whether the lock will be shared or exclusive.
+ * Control lock must be held in *lock_mode mode, which may be LW_NONE. Control
+ * lock will be held at exit in at least shared mode. Resulting control lock
+ * mode is set to *lock_mode.
*/
int
-SimpleLruReadPage_ReadOnly(SlruCtl ctl, int pageno, TransactionId xid)
+SimpleLruReadPage_ReadOnly(SlruCtl ctl, int pageno, TransactionId xid,
+ LWLockMode *lock_mode)
{
SlruShared shared = ctl->shared;
int slotno;
/* Try to find the page while holding only shared lock */
- LWLockAcquire(shared->ControlLock, LW_SHARED);
+ if (*lock_mode == LW_NONE)
+ {
+ LWLockAcquire(shared->ControlLock, LW_SHARED);
+ *lock_mode = LW_SHARED;
+ }
/* See if page is already in a buffer */
for (slotno = 0; slotno < shared->num_slots; slotno++)
@@ -517,8 +523,13 @@ SimpleLruReadPage_ReadOnly(SlruCtl ctl, int pageno, TransactionId xid)
}
/* No luck, so switch to normal exclusive lock and do regular read */
- LWLockRelease(shared->ControlLock);
- LWLockAcquire(shared->ControlLock, LW_EXCLUSIVE);
+ if (*lock_mode != LW_EXCLUSIVE)
+ {
+ Assert(*lock_mode == LW_NONE);
+ LWLockRelease(shared->ControlLock);
+ LWLockAcquire(shared->ControlLock, LW_EXCLUSIVE);
+ *lock_mode = LW_EXCLUSIVE;
+ }
return SimpleLruReadPage(ctl, pageno, true, xid);
}
diff --git a/src/backend/access/transam/subtrans.c b/src/backend/access/transam/subtrans.c
index 0111e867c79..7bb15431893 100644
--- a/src/backend/access/transam/subtrans.c
+++ b/src/backend/access/transam/subtrans.c
@@ -113,6 +113,7 @@ SubTransGetParent(TransactionId xid)
int slotno;
TransactionId *ptr;
TransactionId parent;
+ LWLockMode lockmode = LW_NONE;
/* Can't ask about stuff that might not be around anymore */
Assert(TransactionIdFollowsOrEquals(xid, TransactionXmin));
@@ -123,12 +124,13 @@ SubTransGetParent(TransactionId xid)
/* lock is acquired by SimpleLruReadPage_ReadOnly */
- slotno = SimpleLruReadPage_ReadOnly(SubTransCtl, pageno, xid);
+ slotno = SimpleLruReadPage_ReadOnly(SubTransCtl, pageno, xid, &lockmode);
ptr = (TransactionId *) SubTransCtl->shared->page_buffer[slotno];
ptr += entryno;
parent = *ptr;
+ Assert(lockmode != LW_NONE);
LWLockRelease(SubtransSLRULock);
return parent;
diff --git a/src/backend/commands/async.c b/src/backend/commands/async.c
index 8dbcace3f93..8b419575590 100644
--- a/src/backend/commands/async.c
+++ b/src/backend/commands/async.c
@@ -2002,6 +2002,7 @@ asyncQueueReadAllNotifications(void)
int curoffset = QUEUE_POS_OFFSET(pos);
int slotno;
int copysize;
+ LWLockMode lockmode = LW_NONE;
/*
* We copy the data from SLRU into a local buffer, so as to avoid
@@ -2010,7 +2011,7 @@ asyncQueueReadAllNotifications(void)
* part of the page we will actually inspect.
*/
slotno = SimpleLruReadPage_ReadOnly(NotifyCtl, curpage,
- InvalidTransactionId);
+ InvalidTransactionId, &lockmode);
if (curpage == QUEUE_POS_PAGE(head))
{
/* we only want to read as far as head */
@@ -2027,6 +2028,7 @@ asyncQueueReadAllNotifications(void)
NotifyCtl->shared->page_buffer[slotno] + curoffset,
copysize);
/* Release lock that we got from SimpleLruReadPage_ReadOnly() */
+ Assert(lockmode != LW_NONE);
LWLockRelease(NotifySLRULock);
/*
diff --git a/src/backend/storage/lmgr/lwlock.c b/src/backend/storage/lmgr/lwlock.c
index 2fa90cc0954..8a7726f11c0 100644
--- a/src/backend/storage/lmgr/lwlock.c
+++ b/src/backend/storage/lmgr/lwlock.c
@@ -1068,6 +1068,8 @@ LWLockWakeup(LWLock *lock)
static void
LWLockQueueSelf(LWLock *lock, LWLockMode mode)
{
+ Assert(mode != LW_NONE);
+
/*
* If we don't have a PGPROC structure, there's no way to wait. This
* should never occur, since MyProc should only be null during shared
@@ -1828,6 +1830,7 @@ LWLockRelease(LWLock *lock)
elog(ERROR, "lock %s is not held", T_NAME(lock));
mode = held_lwlocks[i].mode;
+ Assert(mode == LW_EXCLUSIVE || mode == LW_SHARED);
num_held_lwlocks--;
for (; i < num_held_lwlocks; i++)
diff --git a/src/backend/storage/lmgr/predicate.c b/src/backend/storage/lmgr/predicate.c
index 8a365b400c6..a4df90a8aeb 100644
--- a/src/backend/storage/lmgr/predicate.c
+++ b/src/backend/storage/lmgr/predicate.c
@@ -924,6 +924,7 @@ SerialGetMinConflictCommitSeqNo(TransactionId xid)
TransactionId tailXid;
SerCommitSeqNo val;
int slotno;
+ LWLockMode lockmode = LW_NONE;
Assert(TransactionIdIsValid(xid));
@@ -946,8 +947,9 @@ SerialGetMinConflictCommitSeqNo(TransactionId xid)
* but will return with that lock held, which must then be released.
*/
slotno = SimpleLruReadPage_ReadOnly(SerialSlruCtl,
- SerialPage(xid), xid);
+ SerialPage(xid), xid, &lockmode);
val = SerialValue(slotno, xid);
+ Assert(lockmode != LW_NONE);
LWLockRelease(SerialSLRULock);
return val;
}
diff --git a/src/include/access/slru.h b/src/include/access/slru.h
index b39b43504d8..4b66d3b592b 100644
--- a/src/include/access/slru.h
+++ b/src/include/access/slru.h
@@ -142,7 +142,7 @@ extern int SimpleLruZeroPage(SlruCtl ctl, int pageno);
extern int SimpleLruReadPage(SlruCtl ctl, int pageno, bool write_ok,
TransactionId xid);
extern int SimpleLruReadPage_ReadOnly(SlruCtl ctl, int pageno,
- TransactionId xid);
+ TransactionId xid, LWLockMode *lock_mode);
extern void SimpleLruWritePage(SlruCtl ctl, int slotno);
extern void SimpleLruWriteAll(SlruCtl ctl, bool allow_redirtied);
extern void SimpleLruTruncate(SlruCtl ctl, int cutoffPage);
diff --git a/src/include/storage/lwlock.h b/src/include/storage/lwlock.h
index af9b41795d2..e680c6397aa 100644
--- a/src/include/storage/lwlock.h
+++ b/src/include/storage/lwlock.h
@@ -129,6 +129,8 @@ extern PGDLLIMPORT int NamedLWLockTrancheRequests;
typedef enum LWLockMode
{
+ LW_NONE, /* Not a lock mode. Indicates that there is no
+ * lock. */
LW_EXCLUSIVE,
LW_SHARED,
LW_WAIT_UNTIL_FREE /* A special mode used in PGPROC->lwWaitMode,
--
2.14.3
[application/octet-stream] v5-0002-Make-MultiXact-local-cache-size-configurable.patch (3.7K, ../../CAPpHfduT0Kb+8fMt4t0EF5G_3hig+wYgeRadQnNq20F4VxP7LA@mail.gmail.com/3-v5-0002-Make-MultiXact-local-cache-size-configurable.patch)
download | inline diff:
From 53ef71094688048002ffd1a62dbbb1a4a90d4691 Mon Sep 17 00:00:00 2001
From: Alexander Korotkov <[email protected]>
Date: Mon, 26 Oct 2020 03:44:50 +0300
Subject: [PATCH 2/3] Make MultiXact local cache size configurable
---
doc/src/sgml/config.sgml | 16 ++++++++++++++++
src/backend/access/transam/multixact.c | 2 +-
src/backend/utils/init/globals.c | 2 ++
src/backend/utils/misc/guc.c | 10 ++++++++++
src/include/miscadmin.h | 2 ++
5 files changed, 31 insertions(+), 1 deletion(-)
diff --git a/doc/src/sgml/config.sgml b/doc/src/sgml/config.sgml
index f043433e318..fd4ca293476 100644
--- a/doc/src/sgml/config.sgml
+++ b/doc/src/sgml/config.sgml
@@ -1823,6 +1823,22 @@ include_dir 'conf.d'
</listitem>
</varlistentry>
+ <varlistentry id="guc-multixact-local-cache-entries" xreflabel="multixact_local-cache-entries">
+ <term><varname>multixact_local_cache_entries</varname> (<type>integer</type>)
+ <indexterm>
+ <primary><varname>multixact_local_cache_entries</varname> configuration parameter</primary>
+ </indexterm>
+ </term>
+ <listitem>
+ <para>
+ Specifies the number cached MultiXact by backend. Any SLRU lookup is preceeded
+ by cache lookup. Higher numbers of cache size help to deduplicate lock sets, while
+ lower values make cache lookup faster.
+ It defaults to 256.
+ </para>
+ </listitem>
+ </varlistentry>
+
<varlistentry id="guc-max-stack-depth" xreflabel="max_stack_depth">
<term><varname>max_stack_depth</varname> (<type>integer</type>)
<indexterm>
diff --git a/src/backend/access/transam/multixact.c b/src/backend/access/transam/multixact.c
index ccbce90f0ea..57be24c0cc1 100644
--- a/src/backend/access/transam/multixact.c
+++ b/src/backend/access/transam/multixact.c
@@ -1613,7 +1613,7 @@ mXactCachePut(MultiXactId multi, int nmembers, MultiXactMember *members)
qsort(entry->members, nmembers, sizeof(MultiXactMember), mxactMemberComparator);
dlist_push_head(&MXactCache, &entry->node);
- if (MXactCacheMembers++ >= MAX_CACHE_ENTRIES)
+ if (MXactCacheMembers++ >= multixact_local_cache_entries)
{
dlist_node *node;
mXactCacheEnt *entry;
diff --git a/src/backend/utils/init/globals.c b/src/backend/utils/init/globals.c
index 6ab82168398..9ca71933dcc 100644
--- a/src/backend/utils/init/globals.c
+++ b/src/backend/utils/init/globals.c
@@ -149,3 +149,5 @@ int VacuumCostBalance = 0; /* working state for vacuum */
bool VacuumCostActive = false;
double vacuum_cleanup_index_scale_factor;
+
+int multixact_local_cache_entries = 256;
diff --git a/src/backend/utils/misc/guc.c b/src/backend/utils/misc/guc.c
index a62d64eaa47..d667578cc33 100644
--- a/src/backend/utils/misc/guc.c
+++ b/src/backend/utils/misc/guc.c
@@ -2257,6 +2257,16 @@ static struct config_int ConfigureNamesInt[] =
NULL, NULL, NULL
},
+ {
+ {"multixact_local_cache_entries", PGC_SUSET, RESOURCES_MEM,
+ gettext_noop("Sets the number of cached MultiXact by backend."),
+ NULL
+ },
+ &multixact_local_cache_entries,
+ 256, 2, INT_MAX / 2,
+ NULL, NULL, NULL
+ },
+
{
{"temp_buffers", PGC_USERSET, RESOURCES_MEM,
gettext_noop("Sets the maximum number of temporary buffers used by each session."),
diff --git a/src/include/miscadmin.h b/src/include/miscadmin.h
index 72e33523984..01af61c963a 100644
--- a/src/include/miscadmin.h
+++ b/src/include/miscadmin.h
@@ -162,6 +162,8 @@ extern PGDLLIMPORT int MaxConnections;
extern PGDLLIMPORT int max_worker_processes;
extern PGDLLIMPORT int max_parallel_workers;
+extern PGDLLIMPORT int multixact_local_cache_entries;
+
extern PGDLLIMPORT int MyProcPid;
extern PGDLLIMPORT pg_time_t MyStartTime;
extern PGDLLIMPORT TimestampTz MyStartTimestamp;
--
2.14.3
[application/octet-stream] v5-0003-Add-conditional-variable-to-wait-for-next-MultXact.patch (4.4K, ../../CAPpHfduT0Kb+8fMt4t0EF5G_3hig+wYgeRadQnNq20F4VxP7LA@mail.gmail.com/4-v5-0003-Add-conditional-variable-to-wait-for-next-MultXact.patch)
download | inline diff:
From 8876966a703f35abf98b575978c9d38ff4297473 Mon Sep 17 00:00:00 2001
From: Alexander Korotkov <[email protected]>
Date: Mon, 26 Oct 2020 01:55:31 +0300
Subject: [PATCH 3/3] Add conditional variable to wait for next MultXact offset
in corner case
GetMultiXactIdMembers() has a corner case, when the next multixact offset is
not yet set. In this case GetMultiXactIdMembers() has to sleep till this offset
is set. Currently the sleeping is implemented in naive way using pg_sleep()
and retry. This commit implements sleeping with conditional variable, which
provides more efficient way for waiting till the event.
Discussion: https://postgr.es/m/a7f1c4e1-1015-92a4-2bd4-6736bd13d03e%40postgrespro.ru#c496c4e75fc0605094a0e1f763e6a6ec
Author: Andrey Borodin
Reviewed-by: Kyotaro Horiguchi, Daniel Gustafsson
Reviewed-by: Anastasia Lubennikova, Alexander Korotkov
---
src/backend/access/transam/multixact.c | 35 ++++++++++++++++++++++++++++++++--
src/backend/postmaster/pgstat.c | 2 ++
src/include/pgstat.h | 1 +
3 files changed, 36 insertions(+), 2 deletions(-)
diff --git a/src/backend/access/transam/multixact.c b/src/backend/access/transam/multixact.c
index 57be24c0cc1..70d977cba33 100644
--- a/src/backend/access/transam/multixact.c
+++ b/src/backend/access/transam/multixact.c
@@ -82,6 +82,7 @@
#include "lib/ilist.h"
#include "miscadmin.h"
#include "pg_trace.h"
+#include "pgstat.h"
#include "postmaster/autovacuum.h"
#include "storage/lmgr.h"
#include "storage/pmsignal.h"
@@ -233,6 +234,13 @@ typedef struct MultiXactStateData
/* support for members anti-wraparound measures */
MultiXactOffset offsetStopLimit; /* known if oldestOffsetKnown */
+ /*
+ * Conditional variable for waiting till the filling of the next multixact
+ * will be finished. See GetMultiXactIdMembers() and RecordNewMultiXact()
+ * for details.
+ */
+ ConditionVariable nextoffCV;
+
/*
* Per-backend data starts here. We have two arrays stored in the area
* immediately following the MultiXactStateData struct. Each is indexed by
@@ -892,6 +900,14 @@ RecordNewMultiXact(MultiXactId multi, MultiXactOffset offset,
/* Exchange our lock */
LWLockRelease(MultiXactOffsetSLRULock);
+ /*
+ * Let everybody know the offset of this mxid is recorded now. The
+ * waiters are waiting for the offset of the mxid next of the target to
+ * know the number of members of the target mxid, so we don't need to wait
+ * for members of this mxid are recorded.
+ */
+ ConditionVariableBroadcast(&MultiXactState->nextoffCV);
+
LWLockAcquire(MultiXactMemberSLRULock, LW_EXCLUSIVE);
prev_pageno = -1;
@@ -1389,9 +1405,23 @@ retry:
if (nextMXOffset == 0)
{
/* Corner case 2: next multixact is still being filled in */
+
+ /*
+ * The recorder of the next mxid is just before writing the
+ * offset. Wait for the offset to be written.
+ */
+ ConditionVariablePrepareToSleep(&MultiXactState->nextoffCV);
+
+ /*
+ * We don't have to recheck if multixact was filled in during
+ * ConditionVariablePrepareToSleep(), because we were holding
+ * MultiXactOffsetSLRULock.
+ */
LWLockRelease(MultiXactOffsetSLRULock);
- CHECK_FOR_INTERRUPTS();
- pg_usleep(1000L);
+
+ ConditionVariableSleep(&MultiXactState->nextoffCV,
+ WAIT_EVENT_WAIT_NEXT_MXMEMBERS);
+ ConditionVariableCancelSleep();
goto retry;
}
@@ -1873,6 +1903,7 @@ MultiXactShmemInit(void)
/* Make sure we zero out the per-backend state */
MemSet(MultiXactState, 0, SHARED_MULTIXACT_STATE_SIZE);
+ ConditionVariableInit(&MultiXactState->nextoffCV);
}
else
Assert(found);
diff --git a/src/backend/postmaster/pgstat.c b/src/backend/postmaster/pgstat.c
index 822f0ebc628..b99398a97e9 100644
--- a/src/backend/postmaster/pgstat.c
+++ b/src/backend/postmaster/pgstat.c
@@ -4020,6 +4020,8 @@ pgstat_get_wait_ipc(WaitEventIPC w)
break;
case WAIT_EVENT_XACT_GROUP_UPDATE:
event_name = "XactGroupUpdate";
+ case WAIT_EVENT_WAIT_NEXT_MXMEMBERS:
+ event_name = "MultiXactWaitNextMembers";
break;
/* no default case, so that compiler will warn */
}
diff --git a/src/include/pgstat.h b/src/include/pgstat.h
index a821ff4f158..75ede141ab7 100644
--- a/src/include/pgstat.h
+++ b/src/include/pgstat.h
@@ -952,6 +952,7 @@ typedef enum
WAIT_EVENT_REPLICATION_SLOT_DROP,
WAIT_EVENT_SAFE_SNAPSHOT,
WAIT_EVENT_SYNC_REP,
+ WAIT_EVENT_WAIT_NEXT_MXMEMBERS,
WAIT_EVENT_XACT_GROUP_UPDATE
} WaitEventIPC;
--
2.14.3
^ permalink raw reply [nested|flat] 90+ messages in thread
* Re: MultiXact\SLRU buffers configuration
2020-05-08 16:36 MultiXact\SLRU buffers configuration Andrey M. Borodin <[email protected]>
2020-05-11 11:17 ` Re: MultiXact\SLRU buffers configuration Andrey M. Borodin <[email protected]>
2020-05-13 18:08 ` Re: MultiXact\SLRU buffers configuration Andrey M. Borodin <[email protected]>
2020-05-14 01:25 ` Re: MultiXact\SLRU buffers configuration Kyotaro Horiguchi <[email protected]>
2020-05-14 05:19 ` Re: MultiXact\SLRU buffers configuration Andrey M. Borodin <[email protected]>
2020-05-14 06:16 ` Re: MultiXact\SLRU buffers configuration Kyotaro Horiguchi <[email protected]>
2020-05-14 06:44 ` Re: MultiXact\SLRU buffers configuration Andrey M. Borodin <[email protected]>
2020-05-15 00:03 ` Re: MultiXact\SLRU buffers configuration Kyotaro Horiguchi <[email protected]>
2020-07-02 12:02 ` Re: MultiXact\SLRU buffers configuration Daniel Gustafsson <[email protected]>
2020-07-08 07:03 ` Re: MultiXact\SLRU buffers configuration Andrey M. Borodin <[email protected]>
2020-08-28 18:08 ` Re: MultiXact\SLRU buffers configuration Anastasia Lubennikova <[email protected]>
2020-09-28 14:41 ` Re: MultiXact\SLRU buffers configuration Andrey M. Borodin <[email protected]>
2020-10-26 01:05 ` Re: MultiXact\SLRU buffers configuration Alexander Korotkov <[email protected]>
2020-10-26 15:45 ` Re: MultiXact\SLRU buffers configuration Andrey Borodin <[email protected]>
2020-10-27 17:02 ` Re: MultiXact\SLRU buffers configuration Alexander Korotkov <[email protected]>
@ 2020-10-27 17:23 ` Alexander Korotkov <[email protected]>
2020-10-28 01:36 ` Re: MultiXact\SLRU buffers configuration Tomas Vondra <[email protected]>
0 siblings, 1 reply; 90+ messages in thread
From: Alexander Korotkov @ 2020-10-27 17:23 UTC (permalink / raw)
To: Andrey Borodin <[email protected]>; +Cc: Anastasia Lubennikova <[email protected]>; Daniel Gustafsson <[email protected]>; Kyotaro Horiguchi <[email protected]>; pgsql-hackers
On Tue, Oct 27, 2020 at 8:02 PM Alexander Korotkov <[email protected]> wrote:
> On Mon, Oct 26, 2020 at 6:45 PM Andrey Borodin <[email protected]> wrote:
> > Thanks for your review, Alexander!
> > +1 for avoiding double locking in SimpleLruReadPage_ReadOnly().
> > Other changes seem correct to me too.
> >
> >
> > I've tried to find optimal value for cache size and it seems to me that it affects multixact scalability much less than sizes of offsets\members buffers. I concur that patch 2 of the patchset does not seem documented enough.
>
> Thank you. I've made a few more minor adjustments to the patchset.
> I'm going to push 0001 and 0003 if there are no objections.
I get that patchset v5 doesn't pass the tests due to typo in assert.
The fixes version is attached.
------
Regards,
Alexander Korotkov
Attachments:
[application/octet-stream] v6-0001-Use-shared-lock-in-GetMultiXactIdMembers-for-offs.patch (12.9K, ../../CAPpHfdsUtSGxRrKn65F_wrE66sNztNY4TpDGDHh2kvAZZDOMqA@mail.gmail.com/2-v6-0001-Use-shared-lock-in-GetMultiXactIdMembers-for-offs.patch)
download | inline diff:
From 9307192bbb9d1ee48aba5c335ae54cff7b34ffb7 Mon Sep 17 00:00:00 2001
From: Alexander Korotkov <[email protected]>
Date: Tue, 27 Oct 2020 19:29:56 +0300
Subject: [PATCH 1/3] Use shared lock in GetMultiXactIdMembers for offsets and
members
Previously the read of multixact required exclusive control locks for both
offsets and members SLRUs. This could lead to the excessive lock contention.
This commit we makes multixacts SLRU take advantage of SimpleLruReadPage_ReadOnly
similar to clog, commit_ts and subtrans.
In order to evade extra reacquiring of CLRU lock, we teach
SimpleLruReadPage_ReadOnly() to take into account the current lock mode and
report resulting lock mode back.
Discussion: https://postgr.es/m/a7f1c4e1-1015-92a4-2bd4-6736bd13d03e%40postgrespro.ru#c496c4e75fc0605094a0e1f763e6a6ec
Author: Andrey Borodin
Reviewed-by: Kyotaro Horiguchi, Daniel Gustafsson
Reviewed-by: Anastasia Lubennikova, Alexander Korotkov
---
src/backend/access/transam/clog.c | 4 +++-
src/backend/access/transam/commit_ts.c | 4 +++-
src/backend/access/transam/multixact.c | 22 +++++++++++++++-------
src/backend/access/transam/slru.c | 23 +++++++++++++++++------
src/backend/access/transam/subtrans.c | 4 +++-
src/backend/commands/async.c | 4 +++-
src/backend/storage/lmgr/lwlock.c | 3 +++
src/backend/storage/lmgr/predicate.c | 4 +++-
src/include/access/slru.h | 2 +-
src/include/storage/lwlock.h | 2 ++
10 files changed, 53 insertions(+), 19 deletions(-)
diff --git a/src/backend/access/transam/clog.c b/src/backend/access/transam/clog.c
index 034349aa7b9..4c372065dee 100644
--- a/src/backend/access/transam/clog.c
+++ b/src/backend/access/transam/clog.c
@@ -640,10 +640,11 @@ TransactionIdGetStatus(TransactionId xid, XLogRecPtr *lsn)
int lsnindex;
char *byteptr;
XidStatus status;
+ LWLockMode lockmode = LW_NONE;
/* lock is acquired by SimpleLruReadPage_ReadOnly */
- slotno = SimpleLruReadPage_ReadOnly(XactCtl, pageno, xid);
+ slotno = SimpleLruReadPage_ReadOnly(XactCtl, pageno, xid, &lockmode);
byteptr = XactCtl->shared->page_buffer[slotno] + byteno;
status = (*byteptr >> bshift) & CLOG_XACT_BITMASK;
@@ -651,6 +652,7 @@ TransactionIdGetStatus(TransactionId xid, XLogRecPtr *lsn)
lsnindex = GetLSNIndex(slotno, xid);
*lsn = XactCtl->shared->group_lsn[lsnindex];
+ Assert(lockmode != LW_NONE);
LWLockRelease(XactSLRULock);
return status;
diff --git a/src/backend/access/transam/commit_ts.c b/src/backend/access/transam/commit_ts.c
index cb8a9688018..c19b0b5399e 100644
--- a/src/backend/access/transam/commit_ts.c
+++ b/src/backend/access/transam/commit_ts.c
@@ -288,6 +288,7 @@ TransactionIdGetCommitTsData(TransactionId xid, TimestampTz *ts,
CommitTimestampEntry entry;
TransactionId oldestCommitTsXid;
TransactionId newestCommitTsXid;
+ LWLockMode lockmode = LW_NONE;
if (!TransactionIdIsValid(xid))
ereport(ERROR,
@@ -342,7 +343,7 @@ TransactionIdGetCommitTsData(TransactionId xid, TimestampTz *ts,
}
/* lock is acquired by SimpleLruReadPage_ReadOnly */
- slotno = SimpleLruReadPage_ReadOnly(CommitTsCtl, pageno, xid);
+ slotno = SimpleLruReadPage_ReadOnly(CommitTsCtl, pageno, xid, &lockmode);
memcpy(&entry,
CommitTsCtl->shared->page_buffer[slotno] +
SizeOfCommitTimestampEntry * entryno,
@@ -352,6 +353,7 @@ TransactionIdGetCommitTsData(TransactionId xid, TimestampTz *ts,
if (nodeid)
*nodeid = entry.nodeid;
+ Assert(lockmode != LW_NONE);
LWLockRelease(CommitTsSLRULock);
return *ts != 0;
}
diff --git a/src/backend/access/transam/multixact.c b/src/backend/access/transam/multixact.c
index 43653fe5721..ccbce90f0ea 100644
--- a/src/backend/access/transam/multixact.c
+++ b/src/backend/access/transam/multixact.c
@@ -1237,6 +1237,7 @@ GetMultiXactIdMembers(MultiXactId multi, MultiXactMember **members,
MultiXactId tmpMXact;
MultiXactOffset nextOffset;
MultiXactMember *ptr;
+ LWLockMode lockmode = LW_NONE;
debug_elog3(DEBUG2, "GetMembers: asked for %u", multi);
@@ -1340,12 +1341,13 @@ GetMultiXactIdMembers(MultiXactId multi, MultiXactMember **members,
* time on every multixact creation.
*/
retry:
- LWLockAcquire(MultiXactOffsetSLRULock, LW_EXCLUSIVE);
pageno = MultiXactIdToOffsetPage(multi);
entryno = MultiXactIdToOffsetEntry(multi);
- slotno = SimpleLruReadPage(MultiXactOffsetCtl, pageno, true, multi);
+ /* lock is acquired by SimpleLruReadPage_ReadOnly */
+ slotno = SimpleLruReadPage_ReadOnly(MultiXactOffsetCtl, pageno,
+ multi, &lockmode);
offptr = (MultiXactOffset *) MultiXactOffsetCtl->shared->page_buffer[slotno];
offptr += entryno;
offset = *offptr;
@@ -1377,7 +1379,8 @@ retry:
entryno = MultiXactIdToOffsetEntry(tmpMXact);
if (pageno != prev_pageno)
- slotno = SimpleLruReadPage(MultiXactOffsetCtl, pageno, true, tmpMXact);
+ slotno = SimpleLruReadPage_ReadOnly(MultiXactOffsetCtl, pageno,
+ tmpMXact, &lockmode);
offptr = (MultiXactOffset *) MultiXactOffsetCtl->shared->page_buffer[slotno];
offptr += entryno;
@@ -1395,14 +1398,14 @@ retry:
length = nextMXOffset - offset;
}
+ Assert(lockmode != LW_NONE);
LWLockRelease(MultiXactOffsetSLRULock);
ptr = (MultiXactMember *) palloc(length * sizeof(MultiXactMember));
*members = ptr;
/* Now get the members themselves. */
- LWLockAcquire(MultiXactMemberSLRULock, LW_EXCLUSIVE);
-
+ lockmode = LW_NONE;
truelength = 0;
prev_pageno = -1;
for (i = 0; i < length; i++, offset++)
@@ -1418,7 +1421,8 @@ retry:
if (pageno != prev_pageno)
{
- slotno = SimpleLruReadPage(MultiXactMemberCtl, pageno, true, multi);
+ slotno = SimpleLruReadPage_ReadOnly(MultiXactMemberCtl, pageno,
+ multi, &lockmode);
prev_pageno = pageno;
}
@@ -1441,6 +1445,7 @@ retry:
truelength++;
}
+ Assert(lockmode != LW_NONE);
LWLockRelease(MultiXactMemberSLRULock);
/*
@@ -2733,6 +2738,7 @@ find_multixact_start(MultiXactId multi, MultiXactOffset *result)
int entryno;
int slotno;
MultiXactOffset *offptr;
+ LWLockMode lockmode = LW_NONE;
Assert(MultiXactState->finishedStartup);
@@ -2749,10 +2755,12 @@ find_multixact_start(MultiXactId multi, MultiXactOffset *result)
return false;
/* lock is acquired by SimpleLruReadPage_ReadOnly */
- slotno = SimpleLruReadPage_ReadOnly(MultiXactOffsetCtl, pageno, multi);
+ slotno = SimpleLruReadPage_ReadOnly(MultiXactOffsetCtl, pageno,
+ multi, &lockmode);
offptr = (MultiXactOffset *) MultiXactOffsetCtl->shared->page_buffer[slotno];
offptr += entryno;
offset = *offptr;
+ Assert(lockmode != LW_NONE);
LWLockRelease(MultiXactOffsetSLRULock);
*result = offset;
diff --git a/src/backend/access/transam/slru.c b/src/backend/access/transam/slru.c
index 16a78986971..cf89006e131 100644
--- a/src/backend/access/transam/slru.c
+++ b/src/backend/access/transam/slru.c
@@ -487,17 +487,23 @@ SimpleLruReadPage(SlruCtl ctl, int pageno, bool write_ok,
* Return value is the shared-buffer slot number now holding the page.
* The buffer's LRU access info is updated.
*
- * Control lock must NOT be held at entry, but will be held at exit.
- * It is unspecified whether the lock will be shared or exclusive.
+ * Control lock must be held in *lock_mode mode, which may be LW_NONE. Control
+ * lock will be held at exit in at least shared mode. Resulting control lock
+ * mode is set to *lock_mode.
*/
int
-SimpleLruReadPage_ReadOnly(SlruCtl ctl, int pageno, TransactionId xid)
+SimpleLruReadPage_ReadOnly(SlruCtl ctl, int pageno, TransactionId xid,
+ LWLockMode *lock_mode)
{
SlruShared shared = ctl->shared;
int slotno;
/* Try to find the page while holding only shared lock */
- LWLockAcquire(shared->ControlLock, LW_SHARED);
+ if (*lock_mode == LW_NONE)
+ {
+ LWLockAcquire(shared->ControlLock, LW_SHARED);
+ *lock_mode = LW_SHARED;
+ }
/* See if page is already in a buffer */
for (slotno = 0; slotno < shared->num_slots; slotno++)
@@ -517,8 +523,13 @@ SimpleLruReadPage_ReadOnly(SlruCtl ctl, int pageno, TransactionId xid)
}
/* No luck, so switch to normal exclusive lock and do regular read */
- LWLockRelease(shared->ControlLock);
- LWLockAcquire(shared->ControlLock, LW_EXCLUSIVE);
+ if (*lock_mode != LW_EXCLUSIVE)
+ {
+ Assert(*lock_mode != LW_NONE);
+ LWLockRelease(shared->ControlLock);
+ LWLockAcquire(shared->ControlLock, LW_EXCLUSIVE);
+ *lock_mode = LW_EXCLUSIVE;
+ }
return SimpleLruReadPage(ctl, pageno, true, xid);
}
diff --git a/src/backend/access/transam/subtrans.c b/src/backend/access/transam/subtrans.c
index 0111e867c79..7bb15431893 100644
--- a/src/backend/access/transam/subtrans.c
+++ b/src/backend/access/transam/subtrans.c
@@ -113,6 +113,7 @@ SubTransGetParent(TransactionId xid)
int slotno;
TransactionId *ptr;
TransactionId parent;
+ LWLockMode lockmode = LW_NONE;
/* Can't ask about stuff that might not be around anymore */
Assert(TransactionIdFollowsOrEquals(xid, TransactionXmin));
@@ -123,12 +124,13 @@ SubTransGetParent(TransactionId xid)
/* lock is acquired by SimpleLruReadPage_ReadOnly */
- slotno = SimpleLruReadPage_ReadOnly(SubTransCtl, pageno, xid);
+ slotno = SimpleLruReadPage_ReadOnly(SubTransCtl, pageno, xid, &lockmode);
ptr = (TransactionId *) SubTransCtl->shared->page_buffer[slotno];
ptr += entryno;
parent = *ptr;
+ Assert(lockmode != LW_NONE);
LWLockRelease(SubtransSLRULock);
return parent;
diff --git a/src/backend/commands/async.c b/src/backend/commands/async.c
index 8dbcace3f93..8b419575590 100644
--- a/src/backend/commands/async.c
+++ b/src/backend/commands/async.c
@@ -2002,6 +2002,7 @@ asyncQueueReadAllNotifications(void)
int curoffset = QUEUE_POS_OFFSET(pos);
int slotno;
int copysize;
+ LWLockMode lockmode = LW_NONE;
/*
* We copy the data from SLRU into a local buffer, so as to avoid
@@ -2010,7 +2011,7 @@ asyncQueueReadAllNotifications(void)
* part of the page we will actually inspect.
*/
slotno = SimpleLruReadPage_ReadOnly(NotifyCtl, curpage,
- InvalidTransactionId);
+ InvalidTransactionId, &lockmode);
if (curpage == QUEUE_POS_PAGE(head))
{
/* we only want to read as far as head */
@@ -2027,6 +2028,7 @@ asyncQueueReadAllNotifications(void)
NotifyCtl->shared->page_buffer[slotno] + curoffset,
copysize);
/* Release lock that we got from SimpleLruReadPage_ReadOnly() */
+ Assert(lockmode != LW_NONE);
LWLockRelease(NotifySLRULock);
/*
diff --git a/src/backend/storage/lmgr/lwlock.c b/src/backend/storage/lmgr/lwlock.c
index 2fa90cc0954..8a7726f11c0 100644
--- a/src/backend/storage/lmgr/lwlock.c
+++ b/src/backend/storage/lmgr/lwlock.c
@@ -1068,6 +1068,8 @@ LWLockWakeup(LWLock *lock)
static void
LWLockQueueSelf(LWLock *lock, LWLockMode mode)
{
+ Assert(mode != LW_NONE);
+
/*
* If we don't have a PGPROC structure, there's no way to wait. This
* should never occur, since MyProc should only be null during shared
@@ -1828,6 +1830,7 @@ LWLockRelease(LWLock *lock)
elog(ERROR, "lock %s is not held", T_NAME(lock));
mode = held_lwlocks[i].mode;
+ Assert(mode == LW_EXCLUSIVE || mode == LW_SHARED);
num_held_lwlocks--;
for (; i < num_held_lwlocks; i++)
diff --git a/src/backend/storage/lmgr/predicate.c b/src/backend/storage/lmgr/predicate.c
index 8a365b400c6..a4df90a8aeb 100644
--- a/src/backend/storage/lmgr/predicate.c
+++ b/src/backend/storage/lmgr/predicate.c
@@ -924,6 +924,7 @@ SerialGetMinConflictCommitSeqNo(TransactionId xid)
TransactionId tailXid;
SerCommitSeqNo val;
int slotno;
+ LWLockMode lockmode = LW_NONE;
Assert(TransactionIdIsValid(xid));
@@ -946,8 +947,9 @@ SerialGetMinConflictCommitSeqNo(TransactionId xid)
* but will return with that lock held, which must then be released.
*/
slotno = SimpleLruReadPage_ReadOnly(SerialSlruCtl,
- SerialPage(xid), xid);
+ SerialPage(xid), xid, &lockmode);
val = SerialValue(slotno, xid);
+ Assert(lockmode != LW_NONE);
LWLockRelease(SerialSLRULock);
return val;
}
diff --git a/src/include/access/slru.h b/src/include/access/slru.h
index b39b43504d8..4b66d3b592b 100644
--- a/src/include/access/slru.h
+++ b/src/include/access/slru.h
@@ -142,7 +142,7 @@ extern int SimpleLruZeroPage(SlruCtl ctl, int pageno);
extern int SimpleLruReadPage(SlruCtl ctl, int pageno, bool write_ok,
TransactionId xid);
extern int SimpleLruReadPage_ReadOnly(SlruCtl ctl, int pageno,
- TransactionId xid);
+ TransactionId xid, LWLockMode *lock_mode);
extern void SimpleLruWritePage(SlruCtl ctl, int slotno);
extern void SimpleLruWriteAll(SlruCtl ctl, bool allow_redirtied);
extern void SimpleLruTruncate(SlruCtl ctl, int cutoffPage);
diff --git a/src/include/storage/lwlock.h b/src/include/storage/lwlock.h
index af9b41795d2..e680c6397aa 100644
--- a/src/include/storage/lwlock.h
+++ b/src/include/storage/lwlock.h
@@ -129,6 +129,8 @@ extern PGDLLIMPORT int NamedLWLockTrancheRequests;
typedef enum LWLockMode
{
+ LW_NONE, /* Not a lock mode. Indicates that there is no
+ * lock. */
LW_EXCLUSIVE,
LW_SHARED,
LW_WAIT_UNTIL_FREE /* A special mode used in PGPROC->lwWaitMode,
--
2.14.3
[application/octet-stream] v6-0002-Make-MultiXact-local-cache-size-configurable.patch (3.7K, ../../CAPpHfdsUtSGxRrKn65F_wrE66sNztNY4TpDGDHh2kvAZZDOMqA@mail.gmail.com/3-v6-0002-Make-MultiXact-local-cache-size-configurable.patch)
download | inline diff:
From 2c40a5878da97b18e7e64a775f5caa0641e2f39c Mon Sep 17 00:00:00 2001
From: Alexander Korotkov <[email protected]>
Date: Mon, 26 Oct 2020 03:44:50 +0300
Subject: [PATCH 2/3] Make MultiXact local cache size configurable
---
doc/src/sgml/config.sgml | 16 ++++++++++++++++
src/backend/access/transam/multixact.c | 2 +-
src/backend/utils/init/globals.c | 2 ++
src/backend/utils/misc/guc.c | 10 ++++++++++
src/include/miscadmin.h | 2 ++
5 files changed, 31 insertions(+), 1 deletion(-)
diff --git a/doc/src/sgml/config.sgml b/doc/src/sgml/config.sgml
index f043433e318..fd4ca293476 100644
--- a/doc/src/sgml/config.sgml
+++ b/doc/src/sgml/config.sgml
@@ -1823,6 +1823,22 @@ include_dir 'conf.d'
</listitem>
</varlistentry>
+ <varlistentry id="guc-multixact-local-cache-entries" xreflabel="multixact_local-cache-entries">
+ <term><varname>multixact_local_cache_entries</varname> (<type>integer</type>)
+ <indexterm>
+ <primary><varname>multixact_local_cache_entries</varname> configuration parameter</primary>
+ </indexterm>
+ </term>
+ <listitem>
+ <para>
+ Specifies the number cached MultiXact by backend. Any SLRU lookup is preceeded
+ by cache lookup. Higher numbers of cache size help to deduplicate lock sets, while
+ lower values make cache lookup faster.
+ It defaults to 256.
+ </para>
+ </listitem>
+ </varlistentry>
+
<varlistentry id="guc-max-stack-depth" xreflabel="max_stack_depth">
<term><varname>max_stack_depth</varname> (<type>integer</type>)
<indexterm>
diff --git a/src/backend/access/transam/multixact.c b/src/backend/access/transam/multixact.c
index ccbce90f0ea..57be24c0cc1 100644
--- a/src/backend/access/transam/multixact.c
+++ b/src/backend/access/transam/multixact.c
@@ -1613,7 +1613,7 @@ mXactCachePut(MultiXactId multi, int nmembers, MultiXactMember *members)
qsort(entry->members, nmembers, sizeof(MultiXactMember), mxactMemberComparator);
dlist_push_head(&MXactCache, &entry->node);
- if (MXactCacheMembers++ >= MAX_CACHE_ENTRIES)
+ if (MXactCacheMembers++ >= multixact_local_cache_entries)
{
dlist_node *node;
mXactCacheEnt *entry;
diff --git a/src/backend/utils/init/globals.c b/src/backend/utils/init/globals.c
index 6ab82168398..9ca71933dcc 100644
--- a/src/backend/utils/init/globals.c
+++ b/src/backend/utils/init/globals.c
@@ -149,3 +149,5 @@ int VacuumCostBalance = 0; /* working state for vacuum */
bool VacuumCostActive = false;
double vacuum_cleanup_index_scale_factor;
+
+int multixact_local_cache_entries = 256;
diff --git a/src/backend/utils/misc/guc.c b/src/backend/utils/misc/guc.c
index a62d64eaa47..d667578cc33 100644
--- a/src/backend/utils/misc/guc.c
+++ b/src/backend/utils/misc/guc.c
@@ -2257,6 +2257,16 @@ static struct config_int ConfigureNamesInt[] =
NULL, NULL, NULL
},
+ {
+ {"multixact_local_cache_entries", PGC_SUSET, RESOURCES_MEM,
+ gettext_noop("Sets the number of cached MultiXact by backend."),
+ NULL
+ },
+ &multixact_local_cache_entries,
+ 256, 2, INT_MAX / 2,
+ NULL, NULL, NULL
+ },
+
{
{"temp_buffers", PGC_USERSET, RESOURCES_MEM,
gettext_noop("Sets the maximum number of temporary buffers used by each session."),
diff --git a/src/include/miscadmin.h b/src/include/miscadmin.h
index 72e33523984..01af61c963a 100644
--- a/src/include/miscadmin.h
+++ b/src/include/miscadmin.h
@@ -162,6 +162,8 @@ extern PGDLLIMPORT int MaxConnections;
extern PGDLLIMPORT int max_worker_processes;
extern PGDLLIMPORT int max_parallel_workers;
+extern PGDLLIMPORT int multixact_local_cache_entries;
+
extern PGDLLIMPORT int MyProcPid;
extern PGDLLIMPORT pg_time_t MyStartTime;
extern PGDLLIMPORT TimestampTz MyStartTimestamp;
--
2.14.3
[application/octet-stream] v6-0003-Add-conditional-variable-to-wait-for-next-MultXact.patch (4.4K, ../../CAPpHfdsUtSGxRrKn65F_wrE66sNztNY4TpDGDHh2kvAZZDOMqA@mail.gmail.com/4-v6-0003-Add-conditional-variable-to-wait-for-next-MultXact.patch)
download | inline diff:
From da9cc973a4e7d568466b1c4de15479f707ad04f6 Mon Sep 17 00:00:00 2001
From: Alexander Korotkov <[email protected]>
Date: Mon, 26 Oct 2020 01:55:31 +0300
Subject: [PATCH 3/3] Add conditional variable to wait for next MultXact offset
in corner case
GetMultiXactIdMembers() has a corner case, when the next multixact offset is
not yet set. In this case GetMultiXactIdMembers() has to sleep till this offset
is set. Currently the sleeping is implemented in naive way using pg_sleep()
and retry. This commit implements sleeping with conditional variable, which
provides more efficient way for waiting till the event.
Discussion: https://postgr.es/m/a7f1c4e1-1015-92a4-2bd4-6736bd13d03e%40postgrespro.ru#c496c4e75fc0605094a0e1f763e6a6ec
Author: Andrey Borodin
Reviewed-by: Kyotaro Horiguchi, Daniel Gustafsson
Reviewed-by: Anastasia Lubennikova, Alexander Korotkov
---
src/backend/access/transam/multixact.c | 35 ++++++++++++++++++++++++++++++++--
src/backend/postmaster/pgstat.c | 2 ++
src/include/pgstat.h | 1 +
3 files changed, 36 insertions(+), 2 deletions(-)
diff --git a/src/backend/access/transam/multixact.c b/src/backend/access/transam/multixact.c
index 57be24c0cc1..70d977cba33 100644
--- a/src/backend/access/transam/multixact.c
+++ b/src/backend/access/transam/multixact.c
@@ -82,6 +82,7 @@
#include "lib/ilist.h"
#include "miscadmin.h"
#include "pg_trace.h"
+#include "pgstat.h"
#include "postmaster/autovacuum.h"
#include "storage/lmgr.h"
#include "storage/pmsignal.h"
@@ -233,6 +234,13 @@ typedef struct MultiXactStateData
/* support for members anti-wraparound measures */
MultiXactOffset offsetStopLimit; /* known if oldestOffsetKnown */
+ /*
+ * Conditional variable for waiting till the filling of the next multixact
+ * will be finished. See GetMultiXactIdMembers() and RecordNewMultiXact()
+ * for details.
+ */
+ ConditionVariable nextoffCV;
+
/*
* Per-backend data starts here. We have two arrays stored in the area
* immediately following the MultiXactStateData struct. Each is indexed by
@@ -892,6 +900,14 @@ RecordNewMultiXact(MultiXactId multi, MultiXactOffset offset,
/* Exchange our lock */
LWLockRelease(MultiXactOffsetSLRULock);
+ /*
+ * Let everybody know the offset of this mxid is recorded now. The
+ * waiters are waiting for the offset of the mxid next of the target to
+ * know the number of members of the target mxid, so we don't need to wait
+ * for members of this mxid are recorded.
+ */
+ ConditionVariableBroadcast(&MultiXactState->nextoffCV);
+
LWLockAcquire(MultiXactMemberSLRULock, LW_EXCLUSIVE);
prev_pageno = -1;
@@ -1389,9 +1405,23 @@ retry:
if (nextMXOffset == 0)
{
/* Corner case 2: next multixact is still being filled in */
+
+ /*
+ * The recorder of the next mxid is just before writing the
+ * offset. Wait for the offset to be written.
+ */
+ ConditionVariablePrepareToSleep(&MultiXactState->nextoffCV);
+
+ /*
+ * We don't have to recheck if multixact was filled in during
+ * ConditionVariablePrepareToSleep(), because we were holding
+ * MultiXactOffsetSLRULock.
+ */
LWLockRelease(MultiXactOffsetSLRULock);
- CHECK_FOR_INTERRUPTS();
- pg_usleep(1000L);
+
+ ConditionVariableSleep(&MultiXactState->nextoffCV,
+ WAIT_EVENT_WAIT_NEXT_MXMEMBERS);
+ ConditionVariableCancelSleep();
goto retry;
}
@@ -1873,6 +1903,7 @@ MultiXactShmemInit(void)
/* Make sure we zero out the per-backend state */
MemSet(MultiXactState, 0, SHARED_MULTIXACT_STATE_SIZE);
+ ConditionVariableInit(&MultiXactState->nextoffCV);
}
else
Assert(found);
diff --git a/src/backend/postmaster/pgstat.c b/src/backend/postmaster/pgstat.c
index 822f0ebc628..b99398a97e9 100644
--- a/src/backend/postmaster/pgstat.c
+++ b/src/backend/postmaster/pgstat.c
@@ -4020,6 +4020,8 @@ pgstat_get_wait_ipc(WaitEventIPC w)
break;
case WAIT_EVENT_XACT_GROUP_UPDATE:
event_name = "XactGroupUpdate";
+ case WAIT_EVENT_WAIT_NEXT_MXMEMBERS:
+ event_name = "MultiXactWaitNextMembers";
break;
/* no default case, so that compiler will warn */
}
diff --git a/src/include/pgstat.h b/src/include/pgstat.h
index a821ff4f158..75ede141ab7 100644
--- a/src/include/pgstat.h
+++ b/src/include/pgstat.h
@@ -952,6 +952,7 @@ typedef enum
WAIT_EVENT_REPLICATION_SLOT_DROP,
WAIT_EVENT_SAFE_SNAPSHOT,
WAIT_EVENT_SYNC_REP,
+ WAIT_EVENT_WAIT_NEXT_MXMEMBERS,
WAIT_EVENT_XACT_GROUP_UPDATE
} WaitEventIPC;
--
2.14.3
^ permalink raw reply [nested|flat] 90+ messages in thread
* Re: MultiXact\SLRU buffers configuration
2020-05-08 16:36 MultiXact\SLRU buffers configuration Andrey M. Borodin <[email protected]>
2020-05-11 11:17 ` Re: MultiXact\SLRU buffers configuration Andrey M. Borodin <[email protected]>
2020-05-13 18:08 ` Re: MultiXact\SLRU buffers configuration Andrey M. Borodin <[email protected]>
2020-05-14 01:25 ` Re: MultiXact\SLRU buffers configuration Kyotaro Horiguchi <[email protected]>
2020-05-14 05:19 ` Re: MultiXact\SLRU buffers configuration Andrey M. Borodin <[email protected]>
2020-05-14 06:16 ` Re: MultiXact\SLRU buffers configuration Kyotaro Horiguchi <[email protected]>
2020-05-14 06:44 ` Re: MultiXact\SLRU buffers configuration Andrey M. Borodin <[email protected]>
2020-05-15 00:03 ` Re: MultiXact\SLRU buffers configuration Kyotaro Horiguchi <[email protected]>
2020-07-02 12:02 ` Re: MultiXact\SLRU buffers configuration Daniel Gustafsson <[email protected]>
2020-07-08 07:03 ` Re: MultiXact\SLRU buffers configuration Andrey M. Borodin <[email protected]>
2020-08-28 18:08 ` Re: MultiXact\SLRU buffers configuration Anastasia Lubennikova <[email protected]>
2020-09-28 14:41 ` Re: MultiXact\SLRU buffers configuration Andrey M. Borodin <[email protected]>
2020-10-26 01:05 ` Re: MultiXact\SLRU buffers configuration Alexander Korotkov <[email protected]>
2020-10-26 15:45 ` Re: MultiXact\SLRU buffers configuration Andrey Borodin <[email protected]>
2020-10-27 17:02 ` Re: MultiXact\SLRU buffers configuration Alexander Korotkov <[email protected]>
2020-10-27 17:23 ` Re: MultiXact\SLRU buffers configuration Alexander Korotkov <[email protected]>
@ 2020-10-28 01:36 ` Tomas Vondra <[email protected]>
2020-10-28 07:34 ` Re: MultiXact\SLRU buffers configuration Andrey Borodin <[email protected]>
2020-10-28 19:36 ` Re: MultiXact\SLRU buffers configuration Alexander Korotkov <[email protected]>
0 siblings, 2 replies; 90+ messages in thread
From: Tomas Vondra @ 2020-10-28 01:36 UTC (permalink / raw)
To: Alexander Korotkov <[email protected]>; +Cc: Andrey Borodin <[email protected]>; Anastasia Lubennikova <[email protected]>; Daniel Gustafsson <[email protected]>; Kyotaro Horiguchi <[email protected]>; pgsql-hackers
On Tue, Oct 27, 2020 at 08:23:26PM +0300, Alexander Korotkov wrote:
>On Tue, Oct 27, 2020 at 8:02 PM Alexander Korotkov <[email protected]> wrote:
>> On Mon, Oct 26, 2020 at 6:45 PM Andrey Borodin <[email protected]> wrote:
>> > Thanks for your review, Alexander!
>> > +1 for avoiding double locking in SimpleLruReadPage_ReadOnly().
>> > Other changes seem correct to me too.
>> >
>> >
>> > I've tried to find optimal value for cache size and it seems to me that it affects multixact scalability much less than sizes of offsets\members buffers. I concur that patch 2 of the patchset does not seem documented enough.
>>
>> Thank you. I've made a few more minor adjustments to the patchset.
>> I'm going to push 0001 and 0003 if there are no objections.
>
>I get that patchset v5 doesn't pass the tests due to typo in assert.
>The fixes version is attached.
>
I did a quick review on this patch series. A couple comments:
0001
----
This looks quite suspicious to me - SimpleLruReadPage_ReadOnly is
changed to return information about what lock was used, merely to allow
the callers to do an Assert() that the value is not LW_NONE.
IMO we could achieve exactly the same thing by passing a simple flag
that would say 'make sure we got a lock' or something like that. In
fact, aren't all callers doing the assert? That'd mean we can just do
the check always, without the flag. (I see GetMultiXactIdMembers does
two calls and only checks the second result, but I wonder if that's
intended or omission.)
In any case, it'd make the lwlock.c changes unnecessary, I think.
0002
----
Specifies the number cached MultiXact by backend. Any SLRU lookup ...
should be 'number of cached ...'
0003
----
* Conditional variable for waiting till the filling of the next multixact
* will be finished. See GetMultiXactIdMembers() and RecordNewMultiXact()
* for details.
Perhaps 'till the next multixact is filled' or 'gets full' would be
better. Not sure.
This thread started with a discussion about making the SLRU sizes
configurable, but this patch version only adds a local cache. Does this
achieve the same goal, or would we still gain something by having GUCs
for the SLRUs?
If we're claiming this improves performance, it'd be good to have some
workload demonstrating that and measurements. I don't see anything like
that in this thread, so it's a bit hand-wavy. Can someone share details
of such workload (even synthetic one) and some basic measurements?
regards
--
Tomas Vondra http://www.2ndQuadrant.com
PostgreSQL Development, 24x7 Support, Remote DBA, Training & Services
^ permalink raw reply [nested|flat] 90+ messages in thread
* Re: MultiXact\SLRU buffers configuration
2020-05-08 16:36 MultiXact\SLRU buffers configuration Andrey M. Borodin <[email protected]>
2020-05-11 11:17 ` Re: MultiXact\SLRU buffers configuration Andrey M. Borodin <[email protected]>
2020-05-13 18:08 ` Re: MultiXact\SLRU buffers configuration Andrey M. Borodin <[email protected]>
2020-05-14 01:25 ` Re: MultiXact\SLRU buffers configuration Kyotaro Horiguchi <[email protected]>
2020-05-14 05:19 ` Re: MultiXact\SLRU buffers configuration Andrey M. Borodin <[email protected]>
2020-05-14 06:16 ` Re: MultiXact\SLRU buffers configuration Kyotaro Horiguchi <[email protected]>
2020-05-14 06:44 ` Re: MultiXact\SLRU buffers configuration Andrey M. Borodin <[email protected]>
2020-05-15 00:03 ` Re: MultiXact\SLRU buffers configuration Kyotaro Horiguchi <[email protected]>
2020-07-02 12:02 ` Re: MultiXact\SLRU buffers configuration Daniel Gustafsson <[email protected]>
2020-07-08 07:03 ` Re: MultiXact\SLRU buffers configuration Andrey M. Borodin <[email protected]>
2020-08-28 18:08 ` Re: MultiXact\SLRU buffers configuration Anastasia Lubennikova <[email protected]>
2020-09-28 14:41 ` Re: MultiXact\SLRU buffers configuration Andrey M. Borodin <[email protected]>
2020-10-26 01:05 ` Re: MultiXact\SLRU buffers configuration Alexander Korotkov <[email protected]>
2020-10-26 15:45 ` Re: MultiXact\SLRU buffers configuration Andrey Borodin <[email protected]>
2020-10-27 17:02 ` Re: MultiXact\SLRU buffers configuration Alexander Korotkov <[email protected]>
2020-10-27 17:23 ` Re: MultiXact\SLRU buffers configuration Alexander Korotkov <[email protected]>
2020-10-28 01:36 ` Re: MultiXact\SLRU buffers configuration Tomas Vondra <[email protected]>
@ 2020-10-28 07:34 ` Andrey Borodin <[email protected]>
2020-10-28 23:32 ` Re: MultiXact\SLRU buffers configuration Tomas Vondra <[email protected]>
1 sibling, 1 reply; 90+ messages in thread
From: Andrey Borodin @ 2020-10-28 07:34 UTC (permalink / raw)
To: Tomas Vondra <[email protected]>; +Cc: Alexander Korotkov <[email protected]>; Anastasia Lubennikova <[email protected]>; Daniel Gustafsson <[email protected]>; Kyotaro Horiguchi <[email protected]>; pgsql-hackers
Tomas, thanks for looking into this!
> 28 окт. 2020 г., в 06:36, Tomas Vondra <[email protected]> написал(а):
>
>
> This thread started with a discussion about making the SLRU sizes
> configurable, but this patch version only adds a local cache. Does this
> achieve the same goal, or would we still gain something by having GUCs
> for the SLRUs?
>
> If we're claiming this improves performance, it'd be good to have some
> workload demonstrating that and measurements. I don't see anything like
> that in this thread, so it's a bit hand-wavy. Can someone share details
> of such workload (even synthetic one) and some basic measurements?
All patches in this thread aim at the same goal: improve performance in presence of MultiXact locks contention.
I could not build synthetical reproduction of the problem, however I did some MultiXact stressing here [0]. It's a clumsy test program, because it still is not clear to me which parameters of workload trigger MultiXact locks contention. In generic case I was encountering other locks like *GenLock: XidGenLock, MultixactGenLock etc. Yet our production system encounters this problem approximately once in a month through this year.
Test program locks for share different set of tuples in presence of concurrent full scans.
To produce a set of locks we choose one of 14 bits. If a row number has this bit set to 0 we add lock it.
I've been measuring time to lock all rows 3 time for each of 14 bits, observing total time to set all locks.
During the test I was observing locks in pg_stat_activity, if they did not contain enough MultiXact locks I was tuning parameters further (number of concurrent clients, number of bits, select queries etc).
Why is it so complicated? It seems that other reproductions of a problem were encountering other locks.
Lets describe patches in this thread from the POV of these test.
*** Configurable SLRU buffers for MultiXact members and offsets.
From tests it is clear that high and low values for these buffers affect the test time. Here are time for a one test run with different offsets and members sizes [1]
Our production currently runs with (numbers are pages of buffers)
+#define NUM_MXACTOFFSET_BUFFERS 32
+#define NUM_MXACTMEMBER_BUFFERS 64
And, looking back to incidents in summer and fall 2020, seems like it helped mostly.
But it's hard to give some tuning advises based on test results. Values (32,64) produce 10% better result than current hardcoded values (8,16). In generic case this is not what someone should tune first.
*** Configurable caches of MultiXacts.
Tests were specifically designed to beat caches. So, according to test the bigger cache is - the more time it takes to accomplish the test [2].
Anyway cache is local for backend and it's purpose is deduplication of written MultiXacts, not enhancing reads.
*** Using advantage of SimpleLruReadPage_ReadOnly() in MultiXacts.
This simply aligns MultiXact with Subtransactions and CLOG. Other SLRUs already take advantage of reading SLRU with shared lock.
On synthetical tests without background selects this patch adds another ~4.7% of performance [3] against [4]. This improvement seems consistent between different parameter values, yet within measurements deviation (see difference between warmup run [5] and closing run [6]).
All in all, these attempts to measure impact are hand-wavy too. But it makes sense to use consistent approach among similar subsystems (MultiXacts, Subtrans, CLOG etc).
*** Reduce sleep in GetMultiXactIdMembers() on standby.
The problem with pg_usleep(1000L) within GetMultiXactIdMembers() manifests on standbys during contention of MultiXactOffsetControlLock. It's even harder to reproduce.
Yet it seems obvious that reducing sleep to shorter time frame will make count of sleeping backend smaller.
For consistency I've returned patch with SLRU buffer configs to patchset (other patches are intact). But I'm mostly concerned about patches 1 and 3.
Thanks!
Best regards, Andrey Borodin.
[0] https://github.com/x4m/multixact_stress
[1] https://github.com/x4m/multixact_stress/blob/master/testresults.txt#L22-L39
[2] https://github.com/x4m/multixact_stress/blob/master/testresults.txt#L83-L99
[3] https://github.com/x4m/multixact_stress/blob/master/testresults.txt#L9
[4] https://github.com/x4m/multixact_stress/blob/master/testresults.txt#L29
[5] https://github.com/x4m/multixact_stress/blob/master/testresults.txt#L3
[6] https://github.com/x4m/multixact_stress/blob/master/testresults.txt#L19
Attachments:
[application/octet-stream] v6-0001-Use-shared-lock-in-GetMultiXactIdMembers-for-offs.patch (12.9K, ../../[email protected]/2-v6-0001-Use-shared-lock-in-GetMultiXactIdMembers-for-offs.patch)
download | inline diff:
From bcbd4f6d88d7b6dd9cf779b62e0e0261edadc71b Mon Sep 17 00:00:00 2001
From: Alexander Korotkov <[email protected]>
Date: Tue, 27 Oct 2020 19:29:56 +0300
Subject: [PATCH v6 1/4] Use shared lock in GetMultiXactIdMembers for offsets
and members
Previously the read of multixact required exclusive control locks for both
offsets and members SLRUs. This could lead to the excessive lock contention.
This commit we makes multixacts SLRU take advantage of SimpleLruReadPage_ReadOnly
similar to clog, commit_ts and subtrans.
In order to evade extra reacquiring of CLRU lock, we teach
SimpleLruReadPage_ReadOnly() to take into account the current lock mode and
report resulting lock mode back.
Discussion: https://postgr.es/m/a7f1c4e1-1015-92a4-2bd4-6736bd13d03e%40postgrespro.ru#c496c4e75fc0605094a0e1f763e6a6ec
Author: Andrey Borodin
Reviewed-by: Kyotaro Horiguchi, Daniel Gustafsson
Reviewed-by: Anastasia Lubennikova, Alexander Korotkov
---
src/backend/access/transam/clog.c | 4 +++-
src/backend/access/transam/commit_ts.c | 4 +++-
src/backend/access/transam/multixact.c | 22 +++++++++++++++-------
src/backend/access/transam/slru.c | 23 +++++++++++++++++------
src/backend/access/transam/subtrans.c | 4 +++-
src/backend/commands/async.c | 4 +++-
src/backend/storage/lmgr/lwlock.c | 3 +++
src/backend/storage/lmgr/predicate.c | 4 +++-
src/include/access/slru.h | 2 +-
src/include/storage/lwlock.h | 2 ++
10 files changed, 53 insertions(+), 19 deletions(-)
diff --git a/src/backend/access/transam/clog.c b/src/backend/access/transam/clog.c
index 034349aa7b..4c372065de 100644
--- a/src/backend/access/transam/clog.c
+++ b/src/backend/access/transam/clog.c
@@ -640,10 +640,11 @@ TransactionIdGetStatus(TransactionId xid, XLogRecPtr *lsn)
int lsnindex;
char *byteptr;
XidStatus status;
+ LWLockMode lockmode = LW_NONE;
/* lock is acquired by SimpleLruReadPage_ReadOnly */
- slotno = SimpleLruReadPage_ReadOnly(XactCtl, pageno, xid);
+ slotno = SimpleLruReadPage_ReadOnly(XactCtl, pageno, xid, &lockmode);
byteptr = XactCtl->shared->page_buffer[slotno] + byteno;
status = (*byteptr >> bshift) & CLOG_XACT_BITMASK;
@@ -651,6 +652,7 @@ TransactionIdGetStatus(TransactionId xid, XLogRecPtr *lsn)
lsnindex = GetLSNIndex(slotno, xid);
*lsn = XactCtl->shared->group_lsn[lsnindex];
+ Assert(lockmode != LW_NONE);
LWLockRelease(XactSLRULock);
return status;
diff --git a/src/backend/access/transam/commit_ts.c b/src/backend/access/transam/commit_ts.c
index cb8a968801..c19b0b5399 100644
--- a/src/backend/access/transam/commit_ts.c
+++ b/src/backend/access/transam/commit_ts.c
@@ -288,6 +288,7 @@ TransactionIdGetCommitTsData(TransactionId xid, TimestampTz *ts,
CommitTimestampEntry entry;
TransactionId oldestCommitTsXid;
TransactionId newestCommitTsXid;
+ LWLockMode lockmode = LW_NONE;
if (!TransactionIdIsValid(xid))
ereport(ERROR,
@@ -342,7 +343,7 @@ TransactionIdGetCommitTsData(TransactionId xid, TimestampTz *ts,
}
/* lock is acquired by SimpleLruReadPage_ReadOnly */
- slotno = SimpleLruReadPage_ReadOnly(CommitTsCtl, pageno, xid);
+ slotno = SimpleLruReadPage_ReadOnly(CommitTsCtl, pageno, xid, &lockmode);
memcpy(&entry,
CommitTsCtl->shared->page_buffer[slotno] +
SizeOfCommitTimestampEntry * entryno,
@@ -352,6 +353,7 @@ TransactionIdGetCommitTsData(TransactionId xid, TimestampTz *ts,
if (nodeid)
*nodeid = entry.nodeid;
+ Assert(lockmode != LW_NONE);
LWLockRelease(CommitTsSLRULock);
return *ts != 0;
}
diff --git a/src/backend/access/transam/multixact.c b/src/backend/access/transam/multixact.c
index 43653fe572..ccbce90f0e 100644
--- a/src/backend/access/transam/multixact.c
+++ b/src/backend/access/transam/multixact.c
@@ -1237,6 +1237,7 @@ GetMultiXactIdMembers(MultiXactId multi, MultiXactMember **members,
MultiXactId tmpMXact;
MultiXactOffset nextOffset;
MultiXactMember *ptr;
+ LWLockMode lockmode = LW_NONE;
debug_elog3(DEBUG2, "GetMembers: asked for %u", multi);
@@ -1340,12 +1341,13 @@ GetMultiXactIdMembers(MultiXactId multi, MultiXactMember **members,
* time on every multixact creation.
*/
retry:
- LWLockAcquire(MultiXactOffsetSLRULock, LW_EXCLUSIVE);
pageno = MultiXactIdToOffsetPage(multi);
entryno = MultiXactIdToOffsetEntry(multi);
- slotno = SimpleLruReadPage(MultiXactOffsetCtl, pageno, true, multi);
+ /* lock is acquired by SimpleLruReadPage_ReadOnly */
+ slotno = SimpleLruReadPage_ReadOnly(MultiXactOffsetCtl, pageno,
+ multi, &lockmode);
offptr = (MultiXactOffset *) MultiXactOffsetCtl->shared->page_buffer[slotno];
offptr += entryno;
offset = *offptr;
@@ -1377,7 +1379,8 @@ retry:
entryno = MultiXactIdToOffsetEntry(tmpMXact);
if (pageno != prev_pageno)
- slotno = SimpleLruReadPage(MultiXactOffsetCtl, pageno, true, tmpMXact);
+ slotno = SimpleLruReadPage_ReadOnly(MultiXactOffsetCtl, pageno,
+ tmpMXact, &lockmode);
offptr = (MultiXactOffset *) MultiXactOffsetCtl->shared->page_buffer[slotno];
offptr += entryno;
@@ -1395,14 +1398,14 @@ retry:
length = nextMXOffset - offset;
}
+ Assert(lockmode != LW_NONE);
LWLockRelease(MultiXactOffsetSLRULock);
ptr = (MultiXactMember *) palloc(length * sizeof(MultiXactMember));
*members = ptr;
/* Now get the members themselves. */
- LWLockAcquire(MultiXactMemberSLRULock, LW_EXCLUSIVE);
-
+ lockmode = LW_NONE;
truelength = 0;
prev_pageno = -1;
for (i = 0; i < length; i++, offset++)
@@ -1418,7 +1421,8 @@ retry:
if (pageno != prev_pageno)
{
- slotno = SimpleLruReadPage(MultiXactMemberCtl, pageno, true, multi);
+ slotno = SimpleLruReadPage_ReadOnly(MultiXactMemberCtl, pageno,
+ multi, &lockmode);
prev_pageno = pageno;
}
@@ -1441,6 +1445,7 @@ retry:
truelength++;
}
+ Assert(lockmode != LW_NONE);
LWLockRelease(MultiXactMemberSLRULock);
/*
@@ -2733,6 +2738,7 @@ find_multixact_start(MultiXactId multi, MultiXactOffset *result)
int entryno;
int slotno;
MultiXactOffset *offptr;
+ LWLockMode lockmode = LW_NONE;
Assert(MultiXactState->finishedStartup);
@@ -2749,10 +2755,12 @@ find_multixact_start(MultiXactId multi, MultiXactOffset *result)
return false;
/* lock is acquired by SimpleLruReadPage_ReadOnly */
- slotno = SimpleLruReadPage_ReadOnly(MultiXactOffsetCtl, pageno, multi);
+ slotno = SimpleLruReadPage_ReadOnly(MultiXactOffsetCtl, pageno,
+ multi, &lockmode);
offptr = (MultiXactOffset *) MultiXactOffsetCtl->shared->page_buffer[slotno];
offptr += entryno;
offset = *offptr;
+ Assert(lockmode != LW_NONE);
LWLockRelease(MultiXactOffsetSLRULock);
*result = offset;
diff --git a/src/backend/access/transam/slru.c b/src/backend/access/transam/slru.c
index 16a7898697..ca0a23ab87 100644
--- a/src/backend/access/transam/slru.c
+++ b/src/backend/access/transam/slru.c
@@ -487,17 +487,23 @@ SimpleLruReadPage(SlruCtl ctl, int pageno, bool write_ok,
* Return value is the shared-buffer slot number now holding the page.
* The buffer's LRU access info is updated.
*
- * Control lock must NOT be held at entry, but will be held at exit.
- * It is unspecified whether the lock will be shared or exclusive.
+ * Control lock must be held in *lock_mode mode, which may be LW_NONE. Control
+ * lock will be held at exit in at least shared mode. Resulting control lock
+ * mode is set to *lock_mode.
*/
int
-SimpleLruReadPage_ReadOnly(SlruCtl ctl, int pageno, TransactionId xid)
+SimpleLruReadPage_ReadOnly(SlruCtl ctl, int pageno, TransactionId xid,
+ LWLockMode *lock_mode)
{
SlruShared shared = ctl->shared;
int slotno;
/* Try to find the page while holding only shared lock */
- LWLockAcquire(shared->ControlLock, LW_SHARED);
+ if (*lock_mode == LW_NONE)
+ {
+ LWLockAcquire(shared->ControlLock, LW_SHARED);
+ *lock_mode = LW_SHARED;
+ }
/* See if page is already in a buffer */
for (slotno = 0; slotno < shared->num_slots; slotno++)
@@ -517,8 +523,13 @@ SimpleLruReadPage_ReadOnly(SlruCtl ctl, int pageno, TransactionId xid)
}
/* No luck, so switch to normal exclusive lock and do regular read */
- LWLockRelease(shared->ControlLock);
- LWLockAcquire(shared->ControlLock, LW_EXCLUSIVE);
+ if (*lock_mode != LW_EXCLUSIVE)
+ {
+ Assert(*lock_mode == LW_NONE);
+ LWLockRelease(shared->ControlLock);
+ LWLockAcquire(shared->ControlLock, LW_EXCLUSIVE);
+ *lock_mode = LW_EXCLUSIVE;
+ }
return SimpleLruReadPage(ctl, pageno, true, xid);
}
diff --git a/src/backend/access/transam/subtrans.c b/src/backend/access/transam/subtrans.c
index 0111e867c7..7bb1543189 100644
--- a/src/backend/access/transam/subtrans.c
+++ b/src/backend/access/transam/subtrans.c
@@ -113,6 +113,7 @@ SubTransGetParent(TransactionId xid)
int slotno;
TransactionId *ptr;
TransactionId parent;
+ LWLockMode lockmode = LW_NONE;
/* Can't ask about stuff that might not be around anymore */
Assert(TransactionIdFollowsOrEquals(xid, TransactionXmin));
@@ -123,12 +124,13 @@ SubTransGetParent(TransactionId xid)
/* lock is acquired by SimpleLruReadPage_ReadOnly */
- slotno = SimpleLruReadPage_ReadOnly(SubTransCtl, pageno, xid);
+ slotno = SimpleLruReadPage_ReadOnly(SubTransCtl, pageno, xid, &lockmode);
ptr = (TransactionId *) SubTransCtl->shared->page_buffer[slotno];
ptr += entryno;
parent = *ptr;
+ Assert(lockmode != LW_NONE);
LWLockRelease(SubtransSLRULock);
return parent;
diff --git a/src/backend/commands/async.c b/src/backend/commands/async.c
index 8dbcace3f9..8b41957559 100644
--- a/src/backend/commands/async.c
+++ b/src/backend/commands/async.c
@@ -2002,6 +2002,7 @@ asyncQueueReadAllNotifications(void)
int curoffset = QUEUE_POS_OFFSET(pos);
int slotno;
int copysize;
+ LWLockMode lockmode = LW_NONE;
/*
* We copy the data from SLRU into a local buffer, so as to avoid
@@ -2010,7 +2011,7 @@ asyncQueueReadAllNotifications(void)
* part of the page we will actually inspect.
*/
slotno = SimpleLruReadPage_ReadOnly(NotifyCtl, curpage,
- InvalidTransactionId);
+ InvalidTransactionId, &lockmode);
if (curpage == QUEUE_POS_PAGE(head))
{
/* we only want to read as far as head */
@@ -2027,6 +2028,7 @@ asyncQueueReadAllNotifications(void)
NotifyCtl->shared->page_buffer[slotno] + curoffset,
copysize);
/* Release lock that we got from SimpleLruReadPage_ReadOnly() */
+ Assert(lockmode != LW_NONE);
LWLockRelease(NotifySLRULock);
/*
diff --git a/src/backend/storage/lmgr/lwlock.c b/src/backend/storage/lmgr/lwlock.c
index 2fa90cc095..8a7726f11c 100644
--- a/src/backend/storage/lmgr/lwlock.c
+++ b/src/backend/storage/lmgr/lwlock.c
@@ -1068,6 +1068,8 @@ LWLockWakeup(LWLock *lock)
static void
LWLockQueueSelf(LWLock *lock, LWLockMode mode)
{
+ Assert(mode != LW_NONE);
+
/*
* If we don't have a PGPROC structure, there's no way to wait. This
* should never occur, since MyProc should only be null during shared
@@ -1828,6 +1830,7 @@ LWLockRelease(LWLock *lock)
elog(ERROR, "lock %s is not held", T_NAME(lock));
mode = held_lwlocks[i].mode;
+ Assert(mode == LW_EXCLUSIVE || mode == LW_SHARED);
num_held_lwlocks--;
for (; i < num_held_lwlocks; i++)
diff --git a/src/backend/storage/lmgr/predicate.c b/src/backend/storage/lmgr/predicate.c
index 8a365b400c..a4df90a8ae 100644
--- a/src/backend/storage/lmgr/predicate.c
+++ b/src/backend/storage/lmgr/predicate.c
@@ -924,6 +924,7 @@ SerialGetMinConflictCommitSeqNo(TransactionId xid)
TransactionId tailXid;
SerCommitSeqNo val;
int slotno;
+ LWLockMode lockmode = LW_NONE;
Assert(TransactionIdIsValid(xid));
@@ -946,8 +947,9 @@ SerialGetMinConflictCommitSeqNo(TransactionId xid)
* but will return with that lock held, which must then be released.
*/
slotno = SimpleLruReadPage_ReadOnly(SerialSlruCtl,
- SerialPage(xid), xid);
+ SerialPage(xid), xid, &lockmode);
val = SerialValue(slotno, xid);
+ Assert(lockmode != LW_NONE);
LWLockRelease(SerialSLRULock);
return val;
}
diff --git a/src/include/access/slru.h b/src/include/access/slru.h
index b39b43504d..4b66d3b592 100644
--- a/src/include/access/slru.h
+++ b/src/include/access/slru.h
@@ -142,7 +142,7 @@ extern int SimpleLruZeroPage(SlruCtl ctl, int pageno);
extern int SimpleLruReadPage(SlruCtl ctl, int pageno, bool write_ok,
TransactionId xid);
extern int SimpleLruReadPage_ReadOnly(SlruCtl ctl, int pageno,
- TransactionId xid);
+ TransactionId xid, LWLockMode *lock_mode);
extern void SimpleLruWritePage(SlruCtl ctl, int slotno);
extern void SimpleLruWriteAll(SlruCtl ctl, bool allow_redirtied);
extern void SimpleLruTruncate(SlruCtl ctl, int cutoffPage);
diff --git a/src/include/storage/lwlock.h b/src/include/storage/lwlock.h
index af9b41795d..e680c6397a 100644
--- a/src/include/storage/lwlock.h
+++ b/src/include/storage/lwlock.h
@@ -129,6 +129,8 @@ extern PGDLLIMPORT int NamedLWLockTrancheRequests;
typedef enum LWLockMode
{
+ LW_NONE, /* Not a lock mode. Indicates that there is no
+ * lock. */
LW_EXCLUSIVE,
LW_SHARED,
LW_WAIT_UNTIL_FREE /* A special mode used in PGPROC->lwWaitMode,
--
2.24.3 (Apple Git-128)
[application/octet-stream] v6-0004-Add-GUCs-to-tune-MultiXact-SLRUs.patch (6.3K, ../../[email protected]/3-v6-0004-Add-GUCs-to-tune-MultiXact-SLRUs.patch)
download | inline diff:
From a5e15ae42bd6c99d39bac7a9988f586c48ceba13 Mon Sep 17 00:00:00 2001
From: Andrey Borodin <[email protected]>
Date: Sat, 9 May 2020 16:42:07 +0500
Subject: [PATCH v6 4/4] Add GUCs to tune MultiXact SLRUs
---
doc/src/sgml/config.sgml | 31 ++++++++++++++++++++++++++
src/backend/access/transam/multixact.c | 8 +++----
src/backend/utils/init/globals.c | 2 ++
src/backend/utils/misc/guc.c | 22 ++++++++++++++++++
src/include/access/multixact.h | 4 ----
src/include/miscadmin.h | 2 ++
6 files changed, 61 insertions(+), 8 deletions(-)
diff --git a/doc/src/sgml/config.sgml b/doc/src/sgml/config.sgml
index fd4ca29347..d2ca4934de 100644
--- a/doc/src/sgml/config.sgml
+++ b/doc/src/sgml/config.sgml
@@ -1838,6 +1838,37 @@ include_dir 'conf.d'
</para>
</listitem>
</varlistentry>
+
+ <varlistentry id="guc-multixact-offsets-slru-buffers" xreflabel="multixact_offsets_slru_buffers">
+ <term><varname>multixact_offsets_slru_buffers</varname> (<type>integer</type>)
+ <indexterm>
+ <primary><varname>multixact_offsets_slru_buffers</varname> configuration parameter</primary>
+ </indexterm>
+ </term>
+ <listitem>
+ <para>
+ Specifies the amount of memory to be used for MultiXact offsets. MultiXact offsets
+ are used to store informaion about offsets of multiple row lockers (caused by SELECT FOR UPDATE and others).
+ It defaults to 64 kilobytes (<literal>64KB</literal>).
+ </para>
+ </listitem>
+ </varlistentry>
+
+ <varlistentry id="guc-multixact-members-slru-buffers" xreflabel="multixact_members_slru_buffers">
+ <term><varname>multixact_members_slru_buffers</varname> (<type>integer</type>)
+ <indexterm>
+ <primary><varname>multixact_members_slru_buffers</varname> configuration parameter</primary>
+ </indexterm>
+ </term>
+ <listitem>
+ <para>
+ Specifies the amount of memory to be used for MultiXact members. MultiXact members
+ are used to store informaion about XIDs of multiple row lockers. Tipically <varname>multixact_members_slru_buffers</varname>
+ is twice more than <varname>multixact_offsets_slru_buffers</varname>.
+ It defaults to 128 kilobytes (<literal>128KB</literal>).
+ </para>
+ </listitem>
+ </varlistentry>
<varlistentry id="guc-max-stack-depth" xreflabel="max_stack_depth">
<term><varname>max_stack_depth</varname> (<type>integer</type>)
diff --git a/src/backend/access/transam/multixact.c b/src/backend/access/transam/multixact.c
index 70d977cba3..1c177242c5 100644
--- a/src/backend/access/transam/multixact.c
+++ b/src/backend/access/transam/multixact.c
@@ -1866,8 +1866,8 @@ MultiXactShmemSize(void)
mul_size(sizeof(MultiXactId) * 2, MaxOldestSlot))
size = SHARED_MULTIXACT_STATE_SIZE;
- size = add_size(size, SimpleLruShmemSize(NUM_MULTIXACTOFFSET_BUFFERS, 0));
- size = add_size(size, SimpleLruShmemSize(NUM_MULTIXACTMEMBER_BUFFERS, 0));
+ size = add_size(size, SimpleLruShmemSize(multixact_offsets_slru_buffers, 0));
+ size = add_size(size, SimpleLruShmemSize(multixact_members_slru_buffers, 0));
return size;
}
@@ -1883,12 +1883,12 @@ MultiXactShmemInit(void)
MultiXactMemberCtl->PagePrecedes = MultiXactMemberPagePrecedes;
SimpleLruInit(MultiXactOffsetCtl,
- "MultiXactOffset", NUM_MULTIXACTOFFSET_BUFFERS, 0,
+ "MultiXactOffset", multixact_offsets_slru_buffers, 0,
MultiXactOffsetSLRULock, "pg_multixact/offsets",
LWTRANCHE_MULTIXACTOFFSET_BUFFER,
SYNC_HANDLER_MULTIXACT_OFFSET);
SimpleLruInit(MultiXactMemberCtl,
- "MultiXactMember", NUM_MULTIXACTMEMBER_BUFFERS, 0,
+ "MultiXactMember", multixact_members_slru_buffers, 0,
MultiXactMemberSLRULock, "pg_multixact/members",
LWTRANCHE_MULTIXACTMEMBER_BUFFER,
SYNC_HANDLER_MULTIXACT_MEMBER);
diff --git a/src/backend/utils/init/globals.c b/src/backend/utils/init/globals.c
index 9ca71933dc..a5ec7bfe88 100644
--- a/src/backend/utils/init/globals.c
+++ b/src/backend/utils/init/globals.c
@@ -151,3 +151,5 @@ bool VacuumCostActive = false;
double vacuum_cleanup_index_scale_factor;
int multixact_local_cache_entries = 256;
+int multixact_offsets_slru_buffers = 8;
+int multixact_members_slru_buffers = 16;
diff --git a/src/backend/utils/misc/guc.c b/src/backend/utils/misc/guc.c
index d667578cc3..7682c8be1e 100644
--- a/src/backend/utils/misc/guc.c
+++ b/src/backend/utils/misc/guc.c
@@ -2267,6 +2267,28 @@ static struct config_int ConfigureNamesInt[] =
NULL, NULL, NULL
},
+ {
+ {"multixact_offsets_slru_buffers", PGC_POSTMASTER, RESOURCES_MEM,
+ gettext_noop("Sets the number of shared memory buffers used for MultiXact offsets SLRU."),
+ NULL,
+ GUC_UNIT_BLOCKS
+ },
+ &multixact_offsets_slru_buffers,
+ 8, 2, INT_MAX / 2,
+ NULL, NULL, NULL
+ },
+
+ {
+ {"multixact_members_slru_buffers", PGC_POSTMASTER, RESOURCES_MEM,
+ gettext_noop("Sets the number of shared memory buffers used for MultiXact members SLRU."),
+ NULL,
+ GUC_UNIT_BLOCKS
+ },
+ &multixact_members_slru_buffers,
+ 16, 2, INT_MAX / 2,
+ NULL, NULL, NULL
+ },
+
{
{"temp_buffers", PGC_USERSET, RESOURCES_MEM,
gettext_noop("Sets the maximum number of temporary buffers used by each session."),
diff --git a/src/include/access/multixact.h b/src/include/access/multixact.h
index 9a30380901..630ceaea4d 100644
--- a/src/include/access/multixact.h
+++ b/src/include/access/multixact.h
@@ -29,10 +29,6 @@
#define MaxMultiXactOffset ((MultiXactOffset) 0xFFFFFFFF)
-/* Number of SLRU buffers to use for multixact */
-#define NUM_MULTIXACTOFFSET_BUFFERS 8
-#define NUM_MULTIXACTMEMBER_BUFFERS 16
-
/*
* Possible multixact lock modes ("status"). The first four modes are for
* tuple locks (FOR KEY SHARE, FOR SHARE, FOR NO KEY UPDATE, FOR UPDATE); the
diff --git a/src/include/miscadmin.h b/src/include/miscadmin.h
index 01af61c963..ef8abea84d 100644
--- a/src/include/miscadmin.h
+++ b/src/include/miscadmin.h
@@ -161,6 +161,8 @@ extern PGDLLIMPORT int MaxBackends;
extern PGDLLIMPORT int MaxConnections;
extern PGDLLIMPORT int max_worker_processes;
extern PGDLLIMPORT int max_parallel_workers;
+extern PGDLLIMPORT int multixact_offsets_slru_buffers;
+extern PGDLLIMPORT int multixact_members_slru_buffers;
extern PGDLLIMPORT int multixact_local_cache_entries;
--
2.24.3 (Apple Git-128)
[application/octet-stream] v6-0003-Add-conditional-variable-to-wait-for-next-MultXac.patch (4.4K, ../../[email protected]/4-v6-0003-Add-conditional-variable-to-wait-for-next-MultXac.patch)
download | inline diff:
From d25e7d68a7979fc391c5d988b256a49cdd916bfb Mon Sep 17 00:00:00 2001
From: Alexander Korotkov <[email protected]>
Date: Mon, 26 Oct 2020 01:55:31 +0300
Subject: [PATCH v6 3/4] Add conditional variable to wait for next MultXact
offset in corner case
GetMultiXactIdMembers() has a corner case, when the next multixact offset is
not yet set. In this case GetMultiXactIdMembers() has to sleep till this offset
is set. Currently the sleeping is implemented in naive way using pg_sleep()
and retry. This commit implements sleeping with conditional variable, which
provides more efficient way for waiting till the event.
Discussion: https://postgr.es/m/a7f1c4e1-1015-92a4-2bd4-6736bd13d03e%40postgrespro.ru#c496c4e75fc0605094a0e1f763e6a6ec
Author: Andrey Borodin
Reviewed-by: Kyotaro Horiguchi, Daniel Gustafsson
Reviewed-by: Anastasia Lubennikova, Alexander Korotkov
---
src/backend/access/transam/multixact.c | 35 ++++++++++++++++++++++++--
src/backend/postmaster/pgstat.c | 2 ++
src/include/pgstat.h | 1 +
3 files changed, 36 insertions(+), 2 deletions(-)
diff --git a/src/backend/access/transam/multixact.c b/src/backend/access/transam/multixact.c
index 57be24c0cc..70d977cba3 100644
--- a/src/backend/access/transam/multixact.c
+++ b/src/backend/access/transam/multixact.c
@@ -82,6 +82,7 @@
#include "lib/ilist.h"
#include "miscadmin.h"
#include "pg_trace.h"
+#include "pgstat.h"
#include "postmaster/autovacuum.h"
#include "storage/lmgr.h"
#include "storage/pmsignal.h"
@@ -233,6 +234,13 @@ typedef struct MultiXactStateData
/* support for members anti-wraparound measures */
MultiXactOffset offsetStopLimit; /* known if oldestOffsetKnown */
+ /*
+ * Conditional variable for waiting till the filling of the next multixact
+ * will be finished. See GetMultiXactIdMembers() and RecordNewMultiXact()
+ * for details.
+ */
+ ConditionVariable nextoffCV;
+
/*
* Per-backend data starts here. We have two arrays stored in the area
* immediately following the MultiXactStateData struct. Each is indexed by
@@ -892,6 +900,14 @@ RecordNewMultiXact(MultiXactId multi, MultiXactOffset offset,
/* Exchange our lock */
LWLockRelease(MultiXactOffsetSLRULock);
+ /*
+ * Let everybody know the offset of this mxid is recorded now. The
+ * waiters are waiting for the offset of the mxid next of the target to
+ * know the number of members of the target mxid, so we don't need to wait
+ * for members of this mxid are recorded.
+ */
+ ConditionVariableBroadcast(&MultiXactState->nextoffCV);
+
LWLockAcquire(MultiXactMemberSLRULock, LW_EXCLUSIVE);
prev_pageno = -1;
@@ -1389,9 +1405,23 @@ retry:
if (nextMXOffset == 0)
{
/* Corner case 2: next multixact is still being filled in */
+
+ /*
+ * The recorder of the next mxid is just before writing the
+ * offset. Wait for the offset to be written.
+ */
+ ConditionVariablePrepareToSleep(&MultiXactState->nextoffCV);
+
+ /*
+ * We don't have to recheck if multixact was filled in during
+ * ConditionVariablePrepareToSleep(), because we were holding
+ * MultiXactOffsetSLRULock.
+ */
LWLockRelease(MultiXactOffsetSLRULock);
- CHECK_FOR_INTERRUPTS();
- pg_usleep(1000L);
+
+ ConditionVariableSleep(&MultiXactState->nextoffCV,
+ WAIT_EVENT_WAIT_NEXT_MXMEMBERS);
+ ConditionVariableCancelSleep();
goto retry;
}
@@ -1873,6 +1903,7 @@ MultiXactShmemInit(void)
/* Make sure we zero out the per-backend state */
MemSet(MultiXactState, 0, SHARED_MULTIXACT_STATE_SIZE);
+ ConditionVariableInit(&MultiXactState->nextoffCV);
}
else
Assert(found);
diff --git a/src/backend/postmaster/pgstat.c b/src/backend/postmaster/pgstat.c
index 822f0ebc62..b99398a97e 100644
--- a/src/backend/postmaster/pgstat.c
+++ b/src/backend/postmaster/pgstat.c
@@ -4020,6 +4020,8 @@ pgstat_get_wait_ipc(WaitEventIPC w)
break;
case WAIT_EVENT_XACT_GROUP_UPDATE:
event_name = "XactGroupUpdate";
+ case WAIT_EVENT_WAIT_NEXT_MXMEMBERS:
+ event_name = "MultiXactWaitNextMembers";
break;
/* no default case, so that compiler will warn */
}
diff --git a/src/include/pgstat.h b/src/include/pgstat.h
index a821ff4f15..75ede141ab 100644
--- a/src/include/pgstat.h
+++ b/src/include/pgstat.h
@@ -952,6 +952,7 @@ typedef enum
WAIT_EVENT_REPLICATION_SLOT_DROP,
WAIT_EVENT_SAFE_SNAPSHOT,
WAIT_EVENT_SYNC_REP,
+ WAIT_EVENT_WAIT_NEXT_MXMEMBERS,
WAIT_EVENT_XACT_GROUP_UPDATE
} WaitEventIPC;
--
2.24.3 (Apple Git-128)
[application/octet-stream] v6-0002-Make-MultiXact-local-cache-size-configurable.patch (3.7K, ../../[email protected]/5-v6-0002-Make-MultiXact-local-cache-size-configurable.patch)
download | inline diff:
From d0cd1ce556ad3f4e7bbebf0468dc6e00765d79ae Mon Sep 17 00:00:00 2001
From: Alexander Korotkov <[email protected]>
Date: Mon, 26 Oct 2020 03:44:50 +0300
Subject: [PATCH v6 2/4] Make MultiXact local cache size configurable
---
doc/src/sgml/config.sgml | 16 ++++++++++++++++
src/backend/access/transam/multixact.c | 2 +-
src/backend/utils/init/globals.c | 2 ++
src/backend/utils/misc/guc.c | 10 ++++++++++
src/include/miscadmin.h | 2 ++
5 files changed, 31 insertions(+), 1 deletion(-)
diff --git a/doc/src/sgml/config.sgml b/doc/src/sgml/config.sgml
index f043433e31..fd4ca29347 100644
--- a/doc/src/sgml/config.sgml
+++ b/doc/src/sgml/config.sgml
@@ -1823,6 +1823,22 @@ include_dir 'conf.d'
</listitem>
</varlistentry>
+ <varlistentry id="guc-multixact-local-cache-entries" xreflabel="multixact_local-cache-entries">
+ <term><varname>multixact_local_cache_entries</varname> (<type>integer</type>)
+ <indexterm>
+ <primary><varname>multixact_local_cache_entries</varname> configuration parameter</primary>
+ </indexterm>
+ </term>
+ <listitem>
+ <para>
+ Specifies the number cached MultiXact by backend. Any SLRU lookup is preceeded
+ by cache lookup. Higher numbers of cache size help to deduplicate lock sets, while
+ lower values make cache lookup faster.
+ It defaults to 256.
+ </para>
+ </listitem>
+ </varlistentry>
+
<varlistentry id="guc-max-stack-depth" xreflabel="max_stack_depth">
<term><varname>max_stack_depth</varname> (<type>integer</type>)
<indexterm>
diff --git a/src/backend/access/transam/multixact.c b/src/backend/access/transam/multixact.c
index ccbce90f0e..57be24c0cc 100644
--- a/src/backend/access/transam/multixact.c
+++ b/src/backend/access/transam/multixact.c
@@ -1613,7 +1613,7 @@ mXactCachePut(MultiXactId multi, int nmembers, MultiXactMember *members)
qsort(entry->members, nmembers, sizeof(MultiXactMember), mxactMemberComparator);
dlist_push_head(&MXactCache, &entry->node);
- if (MXactCacheMembers++ >= MAX_CACHE_ENTRIES)
+ if (MXactCacheMembers++ >= multixact_local_cache_entries)
{
dlist_node *node;
mXactCacheEnt *entry;
diff --git a/src/backend/utils/init/globals.c b/src/backend/utils/init/globals.c
index 6ab8216839..9ca71933dc 100644
--- a/src/backend/utils/init/globals.c
+++ b/src/backend/utils/init/globals.c
@@ -149,3 +149,5 @@ int VacuumCostBalance = 0; /* working state for vacuum */
bool VacuumCostActive = false;
double vacuum_cleanup_index_scale_factor;
+
+int multixact_local_cache_entries = 256;
diff --git a/src/backend/utils/misc/guc.c b/src/backend/utils/misc/guc.c
index a62d64eaa4..d667578cc3 100644
--- a/src/backend/utils/misc/guc.c
+++ b/src/backend/utils/misc/guc.c
@@ -2257,6 +2257,16 @@ static struct config_int ConfigureNamesInt[] =
NULL, NULL, NULL
},
+ {
+ {"multixact_local_cache_entries", PGC_SUSET, RESOURCES_MEM,
+ gettext_noop("Sets the number of cached MultiXact by backend."),
+ NULL
+ },
+ &multixact_local_cache_entries,
+ 256, 2, INT_MAX / 2,
+ NULL, NULL, NULL
+ },
+
{
{"temp_buffers", PGC_USERSET, RESOURCES_MEM,
gettext_noop("Sets the maximum number of temporary buffers used by each session."),
diff --git a/src/include/miscadmin.h b/src/include/miscadmin.h
index 72e3352398..01af61c963 100644
--- a/src/include/miscadmin.h
+++ b/src/include/miscadmin.h
@@ -162,6 +162,8 @@ extern PGDLLIMPORT int MaxConnections;
extern PGDLLIMPORT int max_worker_processes;
extern PGDLLIMPORT int max_parallel_workers;
+extern PGDLLIMPORT int multixact_local_cache_entries;
+
extern PGDLLIMPORT int MyProcPid;
extern PGDLLIMPORT pg_time_t MyStartTime;
extern PGDLLIMPORT TimestampTz MyStartTimestamp;
--
2.24.3 (Apple Git-128)
^ permalink raw reply [nested|flat] 90+ messages in thread
* Re: MultiXact\SLRU buffers configuration
2020-05-08 16:36 MultiXact\SLRU buffers configuration Andrey M. Borodin <[email protected]>
2020-05-11 11:17 ` Re: MultiXact\SLRU buffers configuration Andrey M. Borodin <[email protected]>
2020-05-13 18:08 ` Re: MultiXact\SLRU buffers configuration Andrey M. Borodin <[email protected]>
2020-05-14 01:25 ` Re: MultiXact\SLRU buffers configuration Kyotaro Horiguchi <[email protected]>
2020-05-14 05:19 ` Re: MultiXact\SLRU buffers configuration Andrey M. Borodin <[email protected]>
2020-05-14 06:16 ` Re: MultiXact\SLRU buffers configuration Kyotaro Horiguchi <[email protected]>
2020-05-14 06:44 ` Re: MultiXact\SLRU buffers configuration Andrey M. Borodin <[email protected]>
2020-05-15 00:03 ` Re: MultiXact\SLRU buffers configuration Kyotaro Horiguchi <[email protected]>
2020-07-02 12:02 ` Re: MultiXact\SLRU buffers configuration Daniel Gustafsson <[email protected]>
2020-07-08 07:03 ` Re: MultiXact\SLRU buffers configuration Andrey M. Borodin <[email protected]>
2020-08-28 18:08 ` Re: MultiXact\SLRU buffers configuration Anastasia Lubennikova <[email protected]>
2020-09-28 14:41 ` Re: MultiXact\SLRU buffers configuration Andrey M. Borodin <[email protected]>
2020-10-26 01:05 ` Re: MultiXact\SLRU buffers configuration Alexander Korotkov <[email protected]>
2020-10-26 15:45 ` Re: MultiXact\SLRU buffers configuration Andrey Borodin <[email protected]>
2020-10-27 17:02 ` Re: MultiXact\SLRU buffers configuration Alexander Korotkov <[email protected]>
2020-10-27 17:23 ` Re: MultiXact\SLRU buffers configuration Alexander Korotkov <[email protected]>
2020-10-28 01:36 ` Re: MultiXact\SLRU buffers configuration Tomas Vondra <[email protected]>
2020-10-28 07:34 ` Re: MultiXact\SLRU buffers configuration Andrey Borodin <[email protected]>
@ 2020-10-28 23:32 ` Tomas Vondra <[email protected]>
2020-10-29 07:08 ` Re: MultiXact\SLRU buffers configuration Andrey Borodin <[email protected]>
0 siblings, 1 reply; 90+ messages in thread
From: Tomas Vondra @ 2020-10-28 23:32 UTC (permalink / raw)
To: Andrey Borodin <[email protected]>; +Cc: Alexander Korotkov <[email protected]>; Anastasia Lubennikova <[email protected]>; Daniel Gustafsson <[email protected]>; Kyotaro Horiguchi <[email protected]>; pgsql-hackers
Hi,
On Wed, Oct 28, 2020 at 12:34:58PM +0500, Andrey Borodin wrote:
>Tomas, thanks for looking into this!
>
>> 28 окт. 2020 г., в 06:36, Tomas Vondra <[email protected]> написал(а):
>>
>>
>> This thread started with a discussion about making the SLRU sizes
>> configurable, but this patch version only adds a local cache. Does this
>> achieve the same goal, or would we still gain something by having GUCs
>> for the SLRUs?
>>
>> If we're claiming this improves performance, it'd be good to have some
>> workload demonstrating that and measurements. I don't see anything like
>> that in this thread, so it's a bit hand-wavy. Can someone share details
>> of such workload (even synthetic one) and some basic measurements?
>
>All patches in this thread aim at the same goal: improve performance in presence of MultiXact locks contention.
>I could not build synthetical reproduction of the problem, however I did some MultiXact stressing here [0]. It's a clumsy test program, because it still is not clear to me which parameters of workload trigger MultiXact locks contention. In generic case I was encountering other locks like *GenLock: XidGenLock, MultixactGenLock etc. Yet our production system encounters this problem approximately once in a month through this year.
>
>Test program locks for share different set of tuples in presence of concurrent full scans.
>To produce a set of locks we choose one of 14 bits. If a row number has this bit set to 0 we add lock it.
>I've been measuring time to lock all rows 3 time for each of 14 bits, observing total time to set all locks.
>During the test I was observing locks in pg_stat_activity, if they did not contain enough MultiXact locks I was tuning parameters further (number of concurrent clients, number of bits, select queries etc).
>
>Why is it so complicated? It seems that other reproductions of a problem were encountering other locks.
>
It's not my intention to be mean or anything like that, but to me this
means we don't really understand the problem we're trying to solve. Had
we understood it, we should be able to construct a workload reproducing
the issue ...
I understand what the individual patches are doing, and maybe those
changes are desirable in general. But without any benchmarks from a
plausible workload I find it hard to convince myself that:
(a) it actually will help with the issue you're observing on production
and
(b) it's actually worth the extra complexity (e.g. the lwlock changes)
I'm willing to invest some of my time into reviewing/testing this, but I
think we badly need better insight into the issue, so that we can build
a workload reproducing it. Perhaps collecting some perf profiles and a
sample of the queries might help, but I assume you already tried that.
regards
--
Tomas Vondra http://www.2ndQuadrant.com
PostgreSQL Development, 24x7 Support, Remote DBA, Training & Services
^ permalink raw reply [nested|flat] 90+ messages in thread
* Re: MultiXact\SLRU buffers configuration
2020-05-08 16:36 MultiXact\SLRU buffers configuration Andrey M. Borodin <[email protected]>
2020-05-11 11:17 ` Re: MultiXact\SLRU buffers configuration Andrey M. Borodin <[email protected]>
2020-05-13 18:08 ` Re: MultiXact\SLRU buffers configuration Andrey M. Borodin <[email protected]>
2020-05-14 01:25 ` Re: MultiXact\SLRU buffers configuration Kyotaro Horiguchi <[email protected]>
2020-05-14 05:19 ` Re: MultiXact\SLRU buffers configuration Andrey M. Borodin <[email protected]>
2020-05-14 06:16 ` Re: MultiXact\SLRU buffers configuration Kyotaro Horiguchi <[email protected]>
2020-05-14 06:44 ` Re: MultiXact\SLRU buffers configuration Andrey M. Borodin <[email protected]>
2020-05-15 00:03 ` Re: MultiXact\SLRU buffers configuration Kyotaro Horiguchi <[email protected]>
2020-07-02 12:02 ` Re: MultiXact\SLRU buffers configuration Daniel Gustafsson <[email protected]>
2020-07-08 07:03 ` Re: MultiXact\SLRU buffers configuration Andrey M. Borodin <[email protected]>
2020-08-28 18:08 ` Re: MultiXact\SLRU buffers configuration Anastasia Lubennikova <[email protected]>
2020-09-28 14:41 ` Re: MultiXact\SLRU buffers configuration Andrey M. Borodin <[email protected]>
2020-10-26 01:05 ` Re: MultiXact\SLRU buffers configuration Alexander Korotkov <[email protected]>
2020-10-26 15:45 ` Re: MultiXact\SLRU buffers configuration Andrey Borodin <[email protected]>
2020-10-27 17:02 ` Re: MultiXact\SLRU buffers configuration Alexander Korotkov <[email protected]>
2020-10-27 17:23 ` Re: MultiXact\SLRU buffers configuration Alexander Korotkov <[email protected]>
2020-10-28 01:36 ` Re: MultiXact\SLRU buffers configuration Tomas Vondra <[email protected]>
2020-10-28 07:34 ` Re: MultiXact\SLRU buffers configuration Andrey Borodin <[email protected]>
2020-10-28 23:32 ` Re: MultiXact\SLRU buffers configuration Tomas Vondra <[email protected]>
@ 2020-10-29 07:08 ` Andrey Borodin <[email protected]>
2020-10-29 13:49 ` Re: MultiXact\SLRU buffers configuration Tomas Vondra <[email protected]>
0 siblings, 1 reply; 90+ messages in thread
From: Andrey Borodin @ 2020-10-29 07:08 UTC (permalink / raw)
To: Tomas Vondra <[email protected]>; +Cc: Alexander Korotkov <[email protected]>; Anastasia Lubennikova <[email protected]>; Daniel Gustafsson <[email protected]>; Kyotaro Horiguchi <[email protected]>; pgsql-hackers
> 29 окт. 2020 г., в 04:32, Tomas Vondra <[email protected]> написал(а):
>
> It's not my intention to be mean or anything like that, but to me this
> means we don't really understand the problem we're trying to solve. Had
> we understood it, we should be able to construct a workload reproducing
> the issue ...
>
> I understand what the individual patches are doing, and maybe those
> changes are desirable in general. But without any benchmarks from a
> plausible workload I find it hard to convince myself that:
>
> (a) it actually will help with the issue you're observing on production
>
> and
> (b) it's actually worth the extra complexity (e.g. the lwlock changes)
>
>
> I'm willing to invest some of my time into reviewing/testing this, but I
> think we badly need better insight into the issue, so that we can build
> a workload reproducing it. Perhaps collecting some perf profiles and a
> sample of the queries might help, but I assume you already tried that.
Thanks, Tomas! This totally makes sense.
Indeed, collecting queries did not help yet. We have loadtest environment equivalent to production (but with 10x less shards), copy of production workload queries. But the problem does not manifest there.
Why do I think the problem is in MultiXacts?
Here is a chart with number of wait events on each host
During the problem MultiXactOffsetControlLock and SLRURead dominate all other lock types. After primary switchover to another node SLRURead continued for a bit there, then disappeared.
Backtraces on standbys during the problem show that most of backends are sleeping in pg_sleep(1000L) and are not included into wait stats on these charts.
Currently I'm considering writing test that directly calls MultiXactIdExpand(), MultiXactIdCreate(), and GetMultiXactIdMembers() from an extension. How do you think, would benchmarks in such tests be meaningful?
Thanks!
Best regards, Andrey Borodin.
Attachments:
[image/png] Графика-1.png (422.0K, ../../[email protected]/3-%D0%93%D1%80%D0%B0%D1%84%D0%B8%D0%BA%D0%B0-1.png)
download | view image
^ permalink raw reply [nested|flat] 90+ messages in thread
* Re: MultiXact\SLRU buffers configuration
2020-05-08 16:36 MultiXact\SLRU buffers configuration Andrey M. Borodin <[email protected]>
2020-05-11 11:17 ` Re: MultiXact\SLRU buffers configuration Andrey M. Borodin <[email protected]>
2020-05-13 18:08 ` Re: MultiXact\SLRU buffers configuration Andrey M. Borodin <[email protected]>
2020-05-14 01:25 ` Re: MultiXact\SLRU buffers configuration Kyotaro Horiguchi <[email protected]>
2020-05-14 05:19 ` Re: MultiXact\SLRU buffers configuration Andrey M. Borodin <[email protected]>
2020-05-14 06:16 ` Re: MultiXact\SLRU buffers configuration Kyotaro Horiguchi <[email protected]>
2020-05-14 06:44 ` Re: MultiXact\SLRU buffers configuration Andrey M. Borodin <[email protected]>
2020-05-15 00:03 ` Re: MultiXact\SLRU buffers configuration Kyotaro Horiguchi <[email protected]>
2020-07-02 12:02 ` Re: MultiXact\SLRU buffers configuration Daniel Gustafsson <[email protected]>
2020-07-08 07:03 ` Re: MultiXact\SLRU buffers configuration Andrey M. Borodin <[email protected]>
2020-08-28 18:08 ` Re: MultiXact\SLRU buffers configuration Anastasia Lubennikova <[email protected]>
2020-09-28 14:41 ` Re: MultiXact\SLRU buffers configuration Andrey M. Borodin <[email protected]>
2020-10-26 01:05 ` Re: MultiXact\SLRU buffers configuration Alexander Korotkov <[email protected]>
2020-10-26 15:45 ` Re: MultiXact\SLRU buffers configuration Andrey Borodin <[email protected]>
2020-10-27 17:02 ` Re: MultiXact\SLRU buffers configuration Alexander Korotkov <[email protected]>
2020-10-27 17:23 ` Re: MultiXact\SLRU buffers configuration Alexander Korotkov <[email protected]>
2020-10-28 01:36 ` Re: MultiXact\SLRU buffers configuration Tomas Vondra <[email protected]>
2020-10-28 07:34 ` Re: MultiXact\SLRU buffers configuration Andrey Borodin <[email protected]>
2020-10-28 23:32 ` Re: MultiXact\SLRU buffers configuration Tomas Vondra <[email protected]>
2020-10-29 07:08 ` Re: MultiXact\SLRU buffers configuration Andrey Borodin <[email protected]>
@ 2020-10-29 13:49 ` Tomas Vondra <[email protected]>
2020-11-02 12:45 ` Re: MultiXact\SLRU buffers configuration Andrey Borodin <[email protected]>
0 siblings, 1 reply; 90+ messages in thread
From: Tomas Vondra @ 2020-10-29 13:49 UTC (permalink / raw)
To: Andrey Borodin <[email protected]>; +Cc: Alexander Korotkov <[email protected]>; Anastasia Lubennikova <[email protected]>; Daniel Gustafsson <[email protected]>; Kyotaro Horiguchi <[email protected]>; pgsql-hackers
On Thu, Oct 29, 2020 at 12:08:21PM +0500, Andrey Borodin wrote:
>
>
>> 29 окт. 2020 г., в 04:32, Tomas Vondra <[email protected]> написал(а):
>>
>> It's not my intention to be mean or anything like that, but to me this
>> means we don't really understand the problem we're trying to solve. Had
>> we understood it, we should be able to construct a workload reproducing
>> the issue ...
>>
>> I understand what the individual patches are doing, and maybe those
>> changes are desirable in general. But without any benchmarks from a
>> plausible workload I find it hard to convince myself that:
>>
>> (a) it actually will help with the issue you're observing on production
>>
>> and
>> (b) it's actually worth the extra complexity (e.g. the lwlock changes)
>>
>>
>> I'm willing to invest some of my time into reviewing/testing this, but I
>> think we badly need better insight into the issue, so that we can build
>> a workload reproducing it. Perhaps collecting some perf profiles and a
>> sample of the queries might help, but I assume you already tried that.
>
>Thanks, Tomas! This totally makes sense.
>
>Indeed, collecting queries did not help yet. We have loadtest environment equivalent to production (but with 10x less shards), copy of production workload queries. But the problem does not manifest there.
>Why do I think the problem is in MultiXacts?
>Here is a chart with number of wait events on each host
>
>
>During the problem MultiXactOffsetControlLock and SLRURead dominate all other lock types. After primary switchover to another node SLRURead continued for a bit there, then disappeared.
OK, so most of this seems to be due to SLRURead and
MultiXactOffsetControlLock. Could it be that there were too many
multixact members, triggering autovacuum to prevent multixact
wraparound? That might generate a lot of IO on the SLRU. Are you
monitoring the size of the pg_multixact directory?
>Backtraces on standbys during the problem show that most of backends are sleeping in pg_sleep(1000L) and are not included into wait stats on these charts.
>
>Currently I'm considering writing test that directly calls MultiXactIdExpand(), MultiXactIdCreate(), and GetMultiXactIdMembers() from an extension. How do you think, would benchmarks in such tests be meaningful?
>
I don't know. I'd much rather have a SQL-level benchmark than an
extension doing this kind of stuff.
regards
--
Tomas Vondra http://www.2ndQuadrant.com
PostgreSQL Development, 24x7 Support, Remote DBA, Training & Services
^ permalink raw reply [nested|flat] 90+ messages in thread
* Re: MultiXact\SLRU buffers configuration
2020-05-08 16:36 MultiXact\SLRU buffers configuration Andrey M. Borodin <[email protected]>
2020-05-11 11:17 ` Re: MultiXact\SLRU buffers configuration Andrey M. Borodin <[email protected]>
2020-05-13 18:08 ` Re: MultiXact\SLRU buffers configuration Andrey M. Borodin <[email protected]>
2020-05-14 01:25 ` Re: MultiXact\SLRU buffers configuration Kyotaro Horiguchi <[email protected]>
2020-05-14 05:19 ` Re: MultiXact\SLRU buffers configuration Andrey M. Borodin <[email protected]>
2020-05-14 06:16 ` Re: MultiXact\SLRU buffers configuration Kyotaro Horiguchi <[email protected]>
2020-05-14 06:44 ` Re: MultiXact\SLRU buffers configuration Andrey M. Borodin <[email protected]>
2020-05-15 00:03 ` Re: MultiXact\SLRU buffers configuration Kyotaro Horiguchi <[email protected]>
2020-07-02 12:02 ` Re: MultiXact\SLRU buffers configuration Daniel Gustafsson <[email protected]>
2020-07-08 07:03 ` Re: MultiXact\SLRU buffers configuration Andrey M. Borodin <[email protected]>
2020-08-28 18:08 ` Re: MultiXact\SLRU buffers configuration Anastasia Lubennikova <[email protected]>
2020-09-28 14:41 ` Re: MultiXact\SLRU buffers configuration Andrey M. Borodin <[email protected]>
2020-10-26 01:05 ` Re: MultiXact\SLRU buffers configuration Alexander Korotkov <[email protected]>
2020-10-26 15:45 ` Re: MultiXact\SLRU buffers configuration Andrey Borodin <[email protected]>
2020-10-27 17:02 ` Re: MultiXact\SLRU buffers configuration Alexander Korotkov <[email protected]>
2020-10-27 17:23 ` Re: MultiXact\SLRU buffers configuration Alexander Korotkov <[email protected]>
2020-10-28 01:36 ` Re: MultiXact\SLRU buffers configuration Tomas Vondra <[email protected]>
2020-10-28 07:34 ` Re: MultiXact\SLRU buffers configuration Andrey Borodin <[email protected]>
2020-10-28 23:32 ` Re: MultiXact\SLRU buffers configuration Tomas Vondra <[email protected]>
2020-10-29 07:08 ` Re: MultiXact\SLRU buffers configuration Andrey Borodin <[email protected]>
2020-10-29 13:49 ` Re: MultiXact\SLRU buffers configuration Tomas Vondra <[email protected]>
@ 2020-11-02 12:45 ` Andrey Borodin <[email protected]>
2020-11-10 00:13 ` Re: MultiXact\SLRU buffers configuration Tomas Vondra <[email protected]>
0 siblings, 1 reply; 90+ messages in thread
From: Andrey Borodin @ 2020-11-02 12:45 UTC (permalink / raw)
To: Tomas Vondra <[email protected]>; +Cc: Alexander Korotkov <[email protected]>; Anastasia Lubennikova <[email protected]>; Daniel Gustafsson <[email protected]>; Kyotaro Horiguchi <[email protected]>; pgsql-hackers
> 29 окт. 2020 г., в 18:49, Tomas Vondra <[email protected]> написал(а):
>
> On Thu, Oct 29, 2020 at 12:08:21PM +0500, Andrey Borodin wrote:
>>
>>
>>> 29 окт. 2020 г., в 04:32, Tomas Vondra <[email protected]> написал(а):
>>>
>>> It's not my intention to be mean or anything like that, but to me this
>>> means we don't really understand the problem we're trying to solve. Had
>>> we understood it, we should be able to construct a workload reproducing
>>> the issue ...
>>>
>>> I understand what the individual patches are doing, and maybe those
>>> changes are desirable in general. But without any benchmarks from a
>>> plausible workload I find it hard to convince myself that:
>>>
>>> (a) it actually will help with the issue you're observing on production
>>>
>>> and
>>> (b) it's actually worth the extra complexity (e.g. the lwlock changes)
>>>
>>>
>>> I'm willing to invest some of my time into reviewing/testing this, but I
>>> think we badly need better insight into the issue, so that we can build
>>> a workload reproducing it. Perhaps collecting some perf profiles and a
>>> sample of the queries might help, but I assume you already tried that.
>>
>> Thanks, Tomas! This totally makes sense.
>>
>> Indeed, collecting queries did not help yet. We have loadtest environment equivalent to production (but with 10x less shards), copy of production workload queries. But the problem does not manifest there.
>> Why do I think the problem is in MultiXacts?
>> Here is a chart with number of wait events on each host
>>
>>
>> During the problem MultiXactOffsetControlLock and SLRURead dominate all other lock types. After primary switchover to another node SLRURead continued for a bit there, then disappeared.
>
> OK, so most of this seems to be due to SLRURead and
> MultiXactOffsetControlLock. Could it be that there were too many
> multixact members, triggering autovacuum to prevent multixact
> wraparound? That might generate a lot of IO on the SLRU. Are you
> monitoring the size of the pg_multixact directory?
Yes, we had some problems with 'multixact "members" limit exceeded' long time ago.
We tuned autovacuum_multixact_freeze_max_age = 200000000 and vacuum_multixact_freeze_table_age = 75000000 (half of defaults) and since then did not ever encounter this problem (~5 months).
But the MultiXactOffsetControlLock problem persists. Partially the problem was solved by adding more shards. But when one of shards encounters a problem it's either MultiXacts or vacuum causing relation truncation (unrelated to this thread).
Thanks!
Best regards, Andrey Borodin.
^ permalink raw reply [nested|flat] 90+ messages in thread
* Re: MultiXact\SLRU buffers configuration
2020-05-08 16:36 MultiXact\SLRU buffers configuration Andrey M. Borodin <[email protected]>
2020-05-11 11:17 ` Re: MultiXact\SLRU buffers configuration Andrey M. Borodin <[email protected]>
2020-05-13 18:08 ` Re: MultiXact\SLRU buffers configuration Andrey M. Borodin <[email protected]>
2020-05-14 01:25 ` Re: MultiXact\SLRU buffers configuration Kyotaro Horiguchi <[email protected]>
2020-05-14 05:19 ` Re: MultiXact\SLRU buffers configuration Andrey M. Borodin <[email protected]>
2020-05-14 06:16 ` Re: MultiXact\SLRU buffers configuration Kyotaro Horiguchi <[email protected]>
2020-05-14 06:44 ` Re: MultiXact\SLRU buffers configuration Andrey M. Borodin <[email protected]>
2020-05-15 00:03 ` Re: MultiXact\SLRU buffers configuration Kyotaro Horiguchi <[email protected]>
2020-07-02 12:02 ` Re: MultiXact\SLRU buffers configuration Daniel Gustafsson <[email protected]>
2020-07-08 07:03 ` Re: MultiXact\SLRU buffers configuration Andrey M. Borodin <[email protected]>
2020-08-28 18:08 ` Re: MultiXact\SLRU buffers configuration Anastasia Lubennikova <[email protected]>
2020-09-28 14:41 ` Re: MultiXact\SLRU buffers configuration Andrey M. Borodin <[email protected]>
2020-10-26 01:05 ` Re: MultiXact\SLRU buffers configuration Alexander Korotkov <[email protected]>
2020-10-26 15:45 ` Re: MultiXact\SLRU buffers configuration Andrey Borodin <[email protected]>
2020-10-27 17:02 ` Re: MultiXact\SLRU buffers configuration Alexander Korotkov <[email protected]>
2020-10-27 17:23 ` Re: MultiXact\SLRU buffers configuration Alexander Korotkov <[email protected]>
2020-10-28 01:36 ` Re: MultiXact\SLRU buffers configuration Tomas Vondra <[email protected]>
2020-10-28 07:34 ` Re: MultiXact\SLRU buffers configuration Andrey Borodin <[email protected]>
2020-10-28 23:32 ` Re: MultiXact\SLRU buffers configuration Tomas Vondra <[email protected]>
2020-10-29 07:08 ` Re: MultiXact\SLRU buffers configuration Andrey Borodin <[email protected]>
2020-10-29 13:49 ` Re: MultiXact\SLRU buffers configuration Tomas Vondra <[email protected]>
2020-11-02 12:45 ` Re: MultiXact\SLRU buffers configuration Andrey Borodin <[email protected]>
@ 2020-11-10 00:13 ` Tomas Vondra <[email protected]>
2020-11-10 06:16 ` Re: MultiXact\SLRU buffers configuration Andrey Borodin <[email protected]>
0 siblings, 1 reply; 90+ messages in thread
From: Tomas Vondra @ 2020-11-10 00:13 UTC (permalink / raw)
To: Andrey Borodin <[email protected]>; Tomas Vondra <[email protected]>; +Cc: Alexander Korotkov <[email protected]>; Anastasia Lubennikova <[email protected]>; Daniel Gustafsson <[email protected]>; Kyotaro Horiguchi <[email protected]>; pgsql-hackers
Hi,
After the issue reported in [1] got fixed, I've restarted the multi-xact
stress test, hoping to reproduce the issue. But so far no luck :-(
I've started slightly different tests on two machines - on one machine
I've done this:
a) init.sql
create table t (a int);
insert into t select i from generate_series(1,100000000) s(i);
alter table t add primary key (a);
b) select.sql
SELECT * FROM t
WHERE a = (1+mod(abs(hashint4(extract(epoch from now())::int)),
100000000)) FOR KEY SHARE;
c) pgbench -n -c 32 -j 8 -f select.sql -T $((24*3600)) test
The idea is to have large table and many clients hitting a small random
subset of the rows. A sample of wait events from ~24h run looks like this:
e_type | e_name | sum
----------+----------------------+----------
LWLock | BufferContent | 13913863
| | 7194679
LWLock | WALWrite | 1710507
Activity | LogicalLauncherMain | 726599
Activity | AutoVacuumMain | 726127
Activity | WalWriterMain | 725183
Activity | CheckpointerMain | 604694
Client | ClientRead | 599900
IO | WALSync | 502904
Activity | BgWriterMain | 378110
Activity | BgWriterHibernate | 348464
IO | WALWrite | 129412
LWLock | ProcArray | 6633
LWLock | WALInsert | 5714
IO | SLRUWrite | 2580
IPC | ProcArrayGroupUpdate | 2216
LWLock | XactSLRU | 2196
Timeout | VacuumDelay | 1078
IPC | XactGroupUpdate | 737
LWLock | LockManager | 503
LWLock | WALBufMapping | 295
LWLock | MultiXactMemberSLRU | 267
IO | DataFileWrite | 68
LWLock | BufferIO | 59
IO | DataFileRead | 27
IO | DataFileFlush | 14
LWLock | MultiXactGen | 7
LWLock | BufferMapping | 1
So, nothing particularly interesting - there certainly are not many wait
events related to SLRU.
On the other machine I did this:
a) init.sql
create table t (a int primary key);
insert into t select i from generate_series(1,1000) s(i);
b) select.sql
select * from t for key share;
c) pgbench -n -c 32 -j 8 -f select.sql -T $((24*3600)) test
and the wait events (24h run too) look like this:
e_type | e_name | sum
-----------+-----------------------+----------
LWLock | BufferContent | 20804925
| | 2575369
Activity | LogicalLauncherMain | 745780
Activity | AutoVacuumMain | 745292
Activity | WalWriterMain | 740507
Activity | CheckpointerMain | 737691
Activity | BgWriterHibernate | 731123
LWLock | WALWrite | 570107
IO | WALSync | 452603
Client | ClientRead | 151438
BufferPin | BufferPin | 23466
LWLock | WALInsert | 21631
IO | WALWrite | 19050
LWLock | ProcArray | 15082
Activity | BgWriterMain | 14655
IPC | ProcArrayGroupUpdate | 7772
LWLock | WALBufMapping | 3555
IO | SLRUWrite | 1951
LWLock | MultiXactGen | 1661
LWLock | MultiXactMemberSLRU | 359
LWLock | MultiXactOffsetSLRU | 242
LWLock | XactSLRU | 141
IPC | XactGroupUpdate | 104
LWLock | LockManager | 28
IO | DataFileRead | 4
IO | ControlFileSyncUpdate | 1
Timeout | VacuumDelay | 1
IO | WALInitWrite | 1
Also nothing particularly interesting - few SLRU wait events.
So unfortunately this does not really reproduce the SLRU locking issues
you're observing - clearly, there has to be something else triggering
it. Perhaps this workload is too simplistic, or maybe we need to run
different queries. Or maybe the hw needs to be somewhat different (more
CPUs? different storage?)
[1]
https://www.postgresql.org/message-id/20201104013205.icogbi773przyny5@development
regards
--
Tomas Vondra
EnterpriseDB: http://www.enterprisedb.com
The Enterprise PostgreSQL Company
^ permalink raw reply [nested|flat] 90+ messages in thread
* Re: MultiXact\SLRU buffers configuration
2020-05-08 16:36 MultiXact\SLRU buffers configuration Andrey M. Borodin <[email protected]>
2020-05-11 11:17 ` Re: MultiXact\SLRU buffers configuration Andrey M. Borodin <[email protected]>
2020-05-13 18:08 ` Re: MultiXact\SLRU buffers configuration Andrey M. Borodin <[email protected]>
2020-05-14 01:25 ` Re: MultiXact\SLRU buffers configuration Kyotaro Horiguchi <[email protected]>
2020-05-14 05:19 ` Re: MultiXact\SLRU buffers configuration Andrey M. Borodin <[email protected]>
2020-05-14 06:16 ` Re: MultiXact\SLRU buffers configuration Kyotaro Horiguchi <[email protected]>
2020-05-14 06:44 ` Re: MultiXact\SLRU buffers configuration Andrey M. Borodin <[email protected]>
2020-05-15 00:03 ` Re: MultiXact\SLRU buffers configuration Kyotaro Horiguchi <[email protected]>
2020-07-02 12:02 ` Re: MultiXact\SLRU buffers configuration Daniel Gustafsson <[email protected]>
2020-07-08 07:03 ` Re: MultiXact\SLRU buffers configuration Andrey M. Borodin <[email protected]>
2020-08-28 18:08 ` Re: MultiXact\SLRU buffers configuration Anastasia Lubennikova <[email protected]>
2020-09-28 14:41 ` Re: MultiXact\SLRU buffers configuration Andrey M. Borodin <[email protected]>
2020-10-26 01:05 ` Re: MultiXact\SLRU buffers configuration Alexander Korotkov <[email protected]>
2020-10-26 15:45 ` Re: MultiXact\SLRU buffers configuration Andrey Borodin <[email protected]>
2020-10-27 17:02 ` Re: MultiXact\SLRU buffers configuration Alexander Korotkov <[email protected]>
2020-10-27 17:23 ` Re: MultiXact\SLRU buffers configuration Alexander Korotkov <[email protected]>
2020-10-28 01:36 ` Re: MultiXact\SLRU buffers configuration Tomas Vondra <[email protected]>
2020-10-28 07:34 ` Re: MultiXact\SLRU buffers configuration Andrey Borodin <[email protected]>
2020-10-28 23:32 ` Re: MultiXact\SLRU buffers configuration Tomas Vondra <[email protected]>
2020-10-29 07:08 ` Re: MultiXact\SLRU buffers configuration Andrey Borodin <[email protected]>
2020-10-29 13:49 ` Re: MultiXact\SLRU buffers configuration Tomas Vondra <[email protected]>
2020-11-02 12:45 ` Re: MultiXact\SLRU buffers configuration Andrey Borodin <[email protected]>
2020-11-10 00:13 ` Re: MultiXact\SLRU buffers configuration Tomas Vondra <[email protected]>
@ 2020-11-10 06:16 ` Andrey Borodin <[email protected]>
2020-11-10 18:07 ` Re: MultiXact\SLRU buffers configuration Tomas Vondra <[email protected]>
0 siblings, 1 reply; 90+ messages in thread
From: Andrey Borodin @ 2020-11-10 06:16 UTC (permalink / raw)
To: Tomas Vondra <[email protected]>; +Cc: Tomas Vondra <[email protected]>; Alexander Korotkov <[email protected]>; Anastasia Lubennikova <[email protected]>; Daniel Gustafsson <[email protected]>; Kyotaro Horiguchi <[email protected]>; pgsql-hackers
> 10 нояб. 2020 г., в 05:13, Tomas Vondra <[email protected]> написал(а):
> After the issue reported in [1] got fixed, I've restarted the multi-xact
> stress test, hoping to reproduce the issue. But so far no luck :-(
Tomas, many thanks for looking into this. I figured out that to make multixact sets bigger transactions must hang for a while and lock large set of tuples. But not continuous range to avoid locking on buffer_content.
I did not manage to implement this via pgbench, that's why I was trying to hack on separate go program. But, essentially, no luck either.
I was observing something resemblant though
пятница, 8 мая 2020 г. 15:08:37 (every 1s)
pid | wait_event | wait_event_type | state | query
-------+----------------------------+-----------------+--------+----------------------------------------------------
41344 | ClientRead | Client | idle | insert into t1 select generate_series(1,1000000,1)
41375 | MultiXactOffsetControlLock | LWLock | active | select * from t1 where i = ANY ($1) for share
41377 | MultiXactOffsetControlLock | LWLock | active | select * from t1 where i = ANY ($1) for share
41378 | | | active | select * from t1 where i = ANY ($1) for share
41379 | MultiXactOffsetControlLock | LWLock | active | select * from t1 where i = ANY ($1) for share
41381 | | | active | select * from t1 where i = ANY ($1) for share
41383 | MultiXactOffsetControlLock | LWLock | active | select * from t1 where i = ANY ($1) for share
41385 | MultiXactOffsetControlLock | LWLock | active | select * from t1 where i = ANY ($1) for share
(8 rows)
but this picture was not stable.
How do you collect wait events for aggregation? just insert into some table with cron?
Thanks!
Best regards, Andrey Borodin.
^ permalink raw reply [nested|flat] 90+ messages in thread
* Re: MultiXact\SLRU buffers configuration
2020-05-08 16:36 MultiXact\SLRU buffers configuration Andrey M. Borodin <[email protected]>
2020-05-11 11:17 ` Re: MultiXact\SLRU buffers configuration Andrey M. Borodin <[email protected]>
2020-05-13 18:08 ` Re: MultiXact\SLRU buffers configuration Andrey M. Borodin <[email protected]>
2020-05-14 01:25 ` Re: MultiXact\SLRU buffers configuration Kyotaro Horiguchi <[email protected]>
2020-05-14 05:19 ` Re: MultiXact\SLRU buffers configuration Andrey M. Borodin <[email protected]>
2020-05-14 06:16 ` Re: MultiXact\SLRU buffers configuration Kyotaro Horiguchi <[email protected]>
2020-05-14 06:44 ` Re: MultiXact\SLRU buffers configuration Andrey M. Borodin <[email protected]>
2020-05-15 00:03 ` Re: MultiXact\SLRU buffers configuration Kyotaro Horiguchi <[email protected]>
2020-07-02 12:02 ` Re: MultiXact\SLRU buffers configuration Daniel Gustafsson <[email protected]>
2020-07-08 07:03 ` Re: MultiXact\SLRU buffers configuration Andrey M. Borodin <[email protected]>
2020-08-28 18:08 ` Re: MultiXact\SLRU buffers configuration Anastasia Lubennikova <[email protected]>
2020-09-28 14:41 ` Re: MultiXact\SLRU buffers configuration Andrey M. Borodin <[email protected]>
2020-10-26 01:05 ` Re: MultiXact\SLRU buffers configuration Alexander Korotkov <[email protected]>
2020-10-26 15:45 ` Re: MultiXact\SLRU buffers configuration Andrey Borodin <[email protected]>
2020-10-27 17:02 ` Re: MultiXact\SLRU buffers configuration Alexander Korotkov <[email protected]>
2020-10-27 17:23 ` Re: MultiXact\SLRU buffers configuration Alexander Korotkov <[email protected]>
2020-10-28 01:36 ` Re: MultiXact\SLRU buffers configuration Tomas Vondra <[email protected]>
2020-10-28 07:34 ` Re: MultiXact\SLRU buffers configuration Andrey Borodin <[email protected]>
2020-10-28 23:32 ` Re: MultiXact\SLRU buffers configuration Tomas Vondra <[email protected]>
2020-10-29 07:08 ` Re: MultiXact\SLRU buffers configuration Andrey Borodin <[email protected]>
2020-10-29 13:49 ` Re: MultiXact\SLRU buffers configuration Tomas Vondra <[email protected]>
2020-11-02 12:45 ` Re: MultiXact\SLRU buffers configuration Andrey Borodin <[email protected]>
2020-11-10 00:13 ` Re: MultiXact\SLRU buffers configuration Tomas Vondra <[email protected]>
2020-11-10 06:16 ` Re: MultiXact\SLRU buffers configuration Andrey Borodin <[email protected]>
@ 2020-11-10 18:07 ` Tomas Vondra <[email protected]>
2020-11-10 18:41 ` Re: MultiXact\SLRU buffers configuration Thomas Munro <[email protected]>
2020-11-13 11:49 ` Re: MultiXact\SLRU buffers configuration Andrey Borodin <[email protected]>
0 siblings, 2 replies; 90+ messages in thread
From: Tomas Vondra @ 2020-11-10 18:07 UTC (permalink / raw)
To: Andrey Borodin <[email protected]>; +Cc: Tomas Vondra <[email protected]>; Alexander Korotkov <[email protected]>; Anastasia Lubennikova <[email protected]>; Daniel Gustafsson <[email protected]>; Kyotaro Horiguchi <[email protected]>; pgsql-hackers
On 11/10/20 7:16 AM, Andrey Borodin wrote:
>
>
>> 10 нояб. 2020 г., в 05:13, Tomas Vondra <[email protected]> написал(а):
>> After the issue reported in [1] got fixed, I've restarted the multi-xact
>> stress test, hoping to reproduce the issue. But so far no luck :-(
>
>
> Tomas, many thanks for looking into this. I figured out that to make multixact sets bigger transactions must hang for a while and lock large set of tuples. But not continuous range to avoid locking on buffer_content.
> I did not manage to implement this via pgbench, that's why I was trying to hack on separate go program. But, essentially, no luck either.
> I was observing something resemblant though
>
> пятница, 8 мая 2020 г. 15:08:37 (every 1s)
>
> pid | wait_event | wait_event_type | state | query
> -------+----------------------------+-----------------+--------+----------------------------------------------------
> 41344 | ClientRead | Client | idle | insert into t1 select generate_series(1,1000000,1)
> 41375 | MultiXactOffsetControlLock | LWLock | active | select * from t1 where i = ANY ($1) for share
> 41377 | MultiXactOffsetControlLock | LWLock | active | select * from t1 where i = ANY ($1) for share
> 41378 | | | active | select * from t1 where i = ANY ($1) for share
> 41379 | MultiXactOffsetControlLock | LWLock | active | select * from t1 where i = ANY ($1) for share
> 41381 | | | active | select * from t1 where i = ANY ($1) for share
> 41383 | MultiXactOffsetControlLock | LWLock | active | select * from t1 where i = ANY ($1) for share
> 41385 | MultiXactOffsetControlLock | LWLock | active | select * from t1 where i = ANY ($1) for share
> (8 rows)
>
> but this picture was not stable.
>
Seems we haven't made much progress in reproducing the issue :-( I guess
we'll need to know more about the machine where this happens. Is there
anything special about the hardware/config? Are you monitoring size of
the pg_multixact directory?
> How do you collect wait events for aggregation? just insert into some table with cron?
>
No, I have a simple shell script (attached) sampling data from
pg_stat_activity regularly. Then I load it into a table and aggregate to
get a summary.
regards
--
Tomas Vondra
EnterpriseDB: http://www.enterprisedb.com
The Enterprise PostgreSQL Company
Attachments:
[application/x-shellscript] collect-wait-events.sh (234B, ../../[email protected]/2-collect-wait-events.sh)
download
^ permalink raw reply [nested|flat] 90+ messages in thread
* Re: MultiXact\SLRU buffers configuration
2020-05-08 16:36 MultiXact\SLRU buffers configuration Andrey M. Borodin <[email protected]>
2020-05-11 11:17 ` Re: MultiXact\SLRU buffers configuration Andrey M. Borodin <[email protected]>
2020-05-13 18:08 ` Re: MultiXact\SLRU buffers configuration Andrey M. Borodin <[email protected]>
2020-05-14 01:25 ` Re: MultiXact\SLRU buffers configuration Kyotaro Horiguchi <[email protected]>
2020-05-14 05:19 ` Re: MultiXact\SLRU buffers configuration Andrey M. Borodin <[email protected]>
2020-05-14 06:16 ` Re: MultiXact\SLRU buffers configuration Kyotaro Horiguchi <[email protected]>
2020-05-14 06:44 ` Re: MultiXact\SLRU buffers configuration Andrey M. Borodin <[email protected]>
2020-05-15 00:03 ` Re: MultiXact\SLRU buffers configuration Kyotaro Horiguchi <[email protected]>
2020-07-02 12:02 ` Re: MultiXact\SLRU buffers configuration Daniel Gustafsson <[email protected]>
2020-07-08 07:03 ` Re: MultiXact\SLRU buffers configuration Andrey M. Borodin <[email protected]>
2020-08-28 18:08 ` Re: MultiXact\SLRU buffers configuration Anastasia Lubennikova <[email protected]>
2020-09-28 14:41 ` Re: MultiXact\SLRU buffers configuration Andrey M. Borodin <[email protected]>
2020-10-26 01:05 ` Re: MultiXact\SLRU buffers configuration Alexander Korotkov <[email protected]>
2020-10-26 15:45 ` Re: MultiXact\SLRU buffers configuration Andrey Borodin <[email protected]>
2020-10-27 17:02 ` Re: MultiXact\SLRU buffers configuration Alexander Korotkov <[email protected]>
2020-10-27 17:23 ` Re: MultiXact\SLRU buffers configuration Alexander Korotkov <[email protected]>
2020-10-28 01:36 ` Re: MultiXact\SLRU buffers configuration Tomas Vondra <[email protected]>
2020-10-28 07:34 ` Re: MultiXact\SLRU buffers configuration Andrey Borodin <[email protected]>
2020-10-28 23:32 ` Re: MultiXact\SLRU buffers configuration Tomas Vondra <[email protected]>
2020-10-29 07:08 ` Re: MultiXact\SLRU buffers configuration Andrey Borodin <[email protected]>
2020-10-29 13:49 ` Re: MultiXact\SLRU buffers configuration Tomas Vondra <[email protected]>
2020-11-02 12:45 ` Re: MultiXact\SLRU buffers configuration Andrey Borodin <[email protected]>
2020-11-10 00:13 ` Re: MultiXact\SLRU buffers configuration Tomas Vondra <[email protected]>
2020-11-10 06:16 ` Re: MultiXact\SLRU buffers configuration Andrey Borodin <[email protected]>
2020-11-10 18:07 ` Re: MultiXact\SLRU buffers configuration Tomas Vondra <[email protected]>
@ 2020-11-10 18:41 ` Thomas Munro <[email protected]>
1 sibling, 0 replies; 90+ messages in thread
From: Thomas Munro @ 2020-11-10 18:41 UTC (permalink / raw)
To: Tomas Vondra <[email protected]>; +Cc: Andrey Borodin <[email protected]>; Tomas Vondra <[email protected]>; Alexander Korotkov <[email protected]>; Anastasia Lubennikova <[email protected]>; Daniel Gustafsson <[email protected]>; Kyotaro Horiguchi <[email protected]>; pgsql-hackers
On Wed, Nov 11, 2020 at 7:07 AM Tomas Vondra
<[email protected]> wrote:
> Seems we haven't made much progress in reproducing the issue :-( I guess
> we'll need to know more about the machine where this happens. Is there
> anything special about the hardware/config? Are you monitoring size of
> the pg_multixact directory?
Which release was the original problem seen on?
^ permalink raw reply [nested|flat] 90+ messages in thread
* Re: MultiXact\SLRU buffers configuration
2020-05-08 16:36 MultiXact\SLRU buffers configuration Andrey M. Borodin <[email protected]>
2020-05-11 11:17 ` Re: MultiXact\SLRU buffers configuration Andrey M. Borodin <[email protected]>
2020-05-13 18:08 ` Re: MultiXact\SLRU buffers configuration Andrey M. Borodin <[email protected]>
2020-05-14 01:25 ` Re: MultiXact\SLRU buffers configuration Kyotaro Horiguchi <[email protected]>
2020-05-14 05:19 ` Re: MultiXact\SLRU buffers configuration Andrey M. Borodin <[email protected]>
2020-05-14 06:16 ` Re: MultiXact\SLRU buffers configuration Kyotaro Horiguchi <[email protected]>
2020-05-14 06:44 ` Re: MultiXact\SLRU buffers configuration Andrey M. Borodin <[email protected]>
2020-05-15 00:03 ` Re: MultiXact\SLRU buffers configuration Kyotaro Horiguchi <[email protected]>
2020-07-02 12:02 ` Re: MultiXact\SLRU buffers configuration Daniel Gustafsson <[email protected]>
2020-07-08 07:03 ` Re: MultiXact\SLRU buffers configuration Andrey M. Borodin <[email protected]>
2020-08-28 18:08 ` Re: MultiXact\SLRU buffers configuration Anastasia Lubennikova <[email protected]>
2020-09-28 14:41 ` Re: MultiXact\SLRU buffers configuration Andrey M. Borodin <[email protected]>
2020-10-26 01:05 ` Re: MultiXact\SLRU buffers configuration Alexander Korotkov <[email protected]>
2020-10-26 15:45 ` Re: MultiXact\SLRU buffers configuration Andrey Borodin <[email protected]>
2020-10-27 17:02 ` Re: MultiXact\SLRU buffers configuration Alexander Korotkov <[email protected]>
2020-10-27 17:23 ` Re: MultiXact\SLRU buffers configuration Alexander Korotkov <[email protected]>
2020-10-28 01:36 ` Re: MultiXact\SLRU buffers configuration Tomas Vondra <[email protected]>
2020-10-28 07:34 ` Re: MultiXact\SLRU buffers configuration Andrey Borodin <[email protected]>
2020-10-28 23:32 ` Re: MultiXact\SLRU buffers configuration Tomas Vondra <[email protected]>
2020-10-29 07:08 ` Re: MultiXact\SLRU buffers configuration Andrey Borodin <[email protected]>
2020-10-29 13:49 ` Re: MultiXact\SLRU buffers configuration Tomas Vondra <[email protected]>
2020-11-02 12:45 ` Re: MultiXact\SLRU buffers configuration Andrey Borodin <[email protected]>
2020-11-10 00:13 ` Re: MultiXact\SLRU buffers configuration Tomas Vondra <[email protected]>
2020-11-10 06:16 ` Re: MultiXact\SLRU buffers configuration Andrey Borodin <[email protected]>
2020-11-10 18:07 ` Re: MultiXact\SLRU buffers configuration Tomas Vondra <[email protected]>
@ 2020-11-13 11:49 ` Andrey Borodin <[email protected]>
2020-12-08 16:05 ` Re: MultiXact\SLRU buffers configuration Gilles Darold <[email protected]>
1 sibling, 1 reply; 90+ messages in thread
From: Andrey Borodin @ 2020-11-13 11:49 UTC (permalink / raw)
To: Tomas Vondra <[email protected]>; +Cc: Tomas Vondra <[email protected]>; Alexander Korotkov <[email protected]>; Anastasia Lubennikova <[email protected]>; Daniel Gustafsson <[email protected]>; Kyotaro Horiguchi <[email protected]>; pgsql-hackers
> 10 нояб. 2020 г., в 23:07, Tomas Vondra <[email protected]> написал(а):
>
> On 11/10/20 7:16 AM, Andrey Borodin wrote:
>>
>>
>> but this picture was not stable.
>>
>
> Seems we haven't made much progress in reproducing the issue :-( I guess
> we'll need to know more about the machine where this happens. Is there
> anything special about the hardware/config? Are you monitoring size of
> the pg_multixact directory?
It's Ubuntu 18.04.4 LTS, Intel Xeon E5-2660 v4, 56 CPU cores with 256Gb of RAM.
PostgreSQL 10.14, compiled by gcc 7.5.0, 64-bit
No, unfortunately we do not have signals for SLRU sizes.
3.5Tb mdadm raid10 over 28 SSD drives, 82% full.
First incident triggering investigation was on 2020-04-19, at that time cluster was running on PG 10.11. But I think it was happening before.
I'd say nothing special...
>
>> How do you collect wait events for aggregation? just insert into some table with cron?
>>
>
> No, I have a simple shell script (attached) sampling data from
> pg_stat_activity regularly. Then I load it into a table and aggregate to
> get a summary.
Thanks!
Best regards, Andrey Borodin.
^ permalink raw reply [nested|flat] 90+ messages in thread
* Re: MultiXact\SLRU buffers configuration
2020-05-08 16:36 MultiXact\SLRU buffers configuration Andrey M. Borodin <[email protected]>
2020-05-11 11:17 ` Re: MultiXact\SLRU buffers configuration Andrey M. Borodin <[email protected]>
2020-05-13 18:08 ` Re: MultiXact\SLRU buffers configuration Andrey M. Borodin <[email protected]>
2020-05-14 01:25 ` Re: MultiXact\SLRU buffers configuration Kyotaro Horiguchi <[email protected]>
2020-05-14 05:19 ` Re: MultiXact\SLRU buffers configuration Andrey M. Borodin <[email protected]>
2020-05-14 06:16 ` Re: MultiXact\SLRU buffers configuration Kyotaro Horiguchi <[email protected]>
2020-05-14 06:44 ` Re: MultiXact\SLRU buffers configuration Andrey M. Borodin <[email protected]>
2020-05-15 00:03 ` Re: MultiXact\SLRU buffers configuration Kyotaro Horiguchi <[email protected]>
2020-07-02 12:02 ` Re: MultiXact\SLRU buffers configuration Daniel Gustafsson <[email protected]>
2020-07-08 07:03 ` Re: MultiXact\SLRU buffers configuration Andrey M. Borodin <[email protected]>
2020-08-28 18:08 ` Re: MultiXact\SLRU buffers configuration Anastasia Lubennikova <[email protected]>
2020-09-28 14:41 ` Re: MultiXact\SLRU buffers configuration Andrey M. Borodin <[email protected]>
2020-10-26 01:05 ` Re: MultiXact\SLRU buffers configuration Alexander Korotkov <[email protected]>
2020-10-26 15:45 ` Re: MultiXact\SLRU buffers configuration Andrey Borodin <[email protected]>
2020-10-27 17:02 ` Re: MultiXact\SLRU buffers configuration Alexander Korotkov <[email protected]>
2020-10-27 17:23 ` Re: MultiXact\SLRU buffers configuration Alexander Korotkov <[email protected]>
2020-10-28 01:36 ` Re: MultiXact\SLRU buffers configuration Tomas Vondra <[email protected]>
2020-10-28 07:34 ` Re: MultiXact\SLRU buffers configuration Andrey Borodin <[email protected]>
2020-10-28 23:32 ` Re: MultiXact\SLRU buffers configuration Tomas Vondra <[email protected]>
2020-10-29 07:08 ` Re: MultiXact\SLRU buffers configuration Andrey Borodin <[email protected]>
2020-10-29 13:49 ` Re: MultiXact\SLRU buffers configuration Tomas Vondra <[email protected]>
2020-11-02 12:45 ` Re: MultiXact\SLRU buffers configuration Andrey Borodin <[email protected]>
2020-11-10 00:13 ` Re: MultiXact\SLRU buffers configuration Tomas Vondra <[email protected]>
2020-11-10 06:16 ` Re: MultiXact\SLRU buffers configuration Andrey Borodin <[email protected]>
2020-11-10 18:07 ` Re: MultiXact\SLRU buffers configuration Tomas Vondra <[email protected]>
2020-11-13 11:49 ` Re: MultiXact\SLRU buffers configuration Andrey Borodin <[email protected]>
@ 2020-12-08 16:05 ` Gilles Darold <[email protected]>
2020-12-08 17:52 ` Re: MultiXact\SLRU buffers configuration Andrey Borodin <[email protected]>
0 siblings, 1 reply; 90+ messages in thread
From: Gilles Darold @ 2020-12-08 16:05 UTC (permalink / raw)
To: Andrey Borodin <[email protected]>; Tomas Vondra <[email protected]>; +Cc: Tomas Vondra <[email protected]>; Alexander Korotkov <[email protected]>; Anastasia Lubennikova <[email protected]>; Daniel Gustafsson <[email protected]>; Kyotaro Horiguchi <[email protected]>; pgsql-hackers
Le 13/11/2020 à 12:49, Andrey Borodin a écrit :
>
>> 10 нояб. 2020 г., в 23:07, Tomas Vondra <[email protected]> написал(а):
>>
>> On 11/10/20 7:16 AM, Andrey Borodin wrote:
>>>
>>> but this picture was not stable.
>>>
>> Seems we haven't made much progress in reproducing the issue :-( I guess
>> we'll need to know more about the machine where this happens. Is there
>> anything special about the hardware/config? Are you monitoring size of
>> the pg_multixact directory?
> It's Ubuntu 18.04.4 LTS, Intel Xeon E5-2660 v4, 56 CPU cores with 256Gb of RAM.
> PostgreSQL 10.14, compiled by gcc 7.5.0, 64-bit
>
> No, unfortunately we do not have signals for SLRU sizes.
> 3.5Tb mdadm raid10 over 28 SSD drives, 82% full.
>
> First incident triggering investigation was on 2020-04-19, at that time cluster was running on PG 10.11. But I think it was happening before.
>
> I'd say nothing special...
>
>>> How do you collect wait events for aggregation? just insert into some table with cron?
>>>
>> No, I have a simple shell script (attached) sampling data from
>> pg_stat_activity regularly. Then I load it into a table and aggregate to
>> get a summary.
> Thanks!
>
> Best regards, Andrey Borodin.
Hi,
Some time ago I have encountered a contention on
MultiXactOffsetControlLock with a performances benchmark. Here are the
wait event monitoring result with a pooling each 10 seconds and a 30
minutes run for the benchmarl:
event_type | event | sum
------------+----------------------------+----------
Client | ClientRead | 44722952
LWLock | MultiXactOffsetControlLock | 30343060
LWLock | multixact_offset | 16735250
LWLock | MultiXactMemberControlLock | 1601470
LWLock | buffer_content | 991344
LWLock | multixact_member | 805624
Lock | transactionid | 204997
Activity | LogicalLauncherMain | 198834
Activity | CheckpointerMain | 198834
Activity | AutoVacuumMain | 198469
Activity | BgWriterMain | 184066
Activity | WalWriterMain | 171571
LWLock | WALWriteLock | 72428
IO | DataFileRead | 35708
Activity | BgWriterHibernate | 12741
IO | SLRURead | 9121
Lock | relation | 8858
LWLock | ProcArrayLock | 7309
LWLock | lock_manager | 6677
LWLock | pg_stat_statements | 4194
LWLock | buffer_mapping | 3222
After reading this thread I change the value of the buffer size to 32
and 64 and obtain the following results:
event_type | event | sum
------------+----------------------------+-----------
Client | ClientRead | 268297572
LWLock | MultiXactMemberControlLock | 65162906
LWLock | multixact_member | 33397714
LWLock | buffer_content | 4737065
Lock | transactionid | 2143750
LWLock | SubtransControlLock | 1318230
LWLock | WALWriteLock | 1038999
Activity | LogicalLauncherMain | 940598
Activity | AutoVacuumMain | 938566
Activity | CheckpointerMain | 799052
Activity | WalWriterMain | 749069
LWLock | subtrans | 710163
Activity | BgWriterHibernate | 536763
Lock | object | 514225
Activity | BgWriterMain | 394206
LWLock | lock_manager | 295616
IO | DataFileRead | 274236
LWLock | ProcArrayLock | 77099
Lock | tuple | 59043
IO | CopyFileWrite | 45611
Lock | relation | 42714
There was still contention on multixact but less than the first run. I
have increased the buffers to 128 and 512 and obtain the best results
for this bench:
event_type | event | sum
------------+----------------------------+-----------
Client | ClientRead | 160463037
LWLock | MultiXactMemberControlLock | 5334188
LWLock | buffer_content | 5228256
LWLock | buffer_mapping | 2368505
LWLock | SubtransControlLock | 2289977
IPC | ProcArrayGroupUpdate | 1560875
LWLock | ProcArrayLock | 1437750
Lock | transactionid | 825561
LWLock | subtrans | 772701
LWLock | WALWriteLock | 666138
Activity | LogicalLauncherMain | 492585
Activity | CheckpointerMain | 492458
Activity | AutoVacuumMain | 491548
LWLock | lock_manager | 426531
Lock | object | 403581
Activity | WalWriterMain | 394668
Activity | BgWriterHibernate | 293112
Activity | BgWriterMain | 195312
LWLock | MultiXactGenLock | 177820
LWLock | pg_stat_statements | 173864
IO | DataFileRead | 173009
I hope these metrics can have some interest to show the utility of this
patch but unfortunately I can not be more precise and provide reports
for the entire patch. The problem is that this benchmark is run on an
application that use PostgreSQL 11 and I can not back port the full
patch, there was too much changes since PG11. I have just increase the
size of NUM_MXACTOFFSET_BUFFERS and NUM_MXACTMEMBER_BUFFERS. This allow
us to triple the number of simultaneous connections between the first
and the last test.
I know that this report is not really helpful but at least I can give
more information on the benchmark that was used. This is the proprietary
zRef benchmark which compares the same Cobol programs (transactional and
batch) executed both on mainframes and on x86 servers. Instead of a DB2
z/os database we use PostgreSQL v11. This test has extensive use of
cursors (each select, even read only, is executed through a cursor) and
the contention was observed with update on tables with some foreign
keys. There is no explicit FOR SHARE on the queries, only some FOR
UPDATE clauses. I guess that the multixact contention is the result of
the for share locks produced for FK.
So in our case being able to tune the multixact buffers could help a lot
to improve the performances.
--
Gilles Darold
^ permalink raw reply [nested|flat] 90+ messages in thread
* Re: MultiXact\SLRU buffers configuration
2020-05-08 16:36 MultiXact\SLRU buffers configuration Andrey M. Borodin <[email protected]>
2020-05-11 11:17 ` Re: MultiXact\SLRU buffers configuration Andrey M. Borodin <[email protected]>
2020-05-13 18:08 ` Re: MultiXact\SLRU buffers configuration Andrey M. Borodin <[email protected]>
2020-05-14 01:25 ` Re: MultiXact\SLRU buffers configuration Kyotaro Horiguchi <[email protected]>
2020-05-14 05:19 ` Re: MultiXact\SLRU buffers configuration Andrey M. Borodin <[email protected]>
2020-05-14 06:16 ` Re: MultiXact\SLRU buffers configuration Kyotaro Horiguchi <[email protected]>
2020-05-14 06:44 ` Re: MultiXact\SLRU buffers configuration Andrey M. Borodin <[email protected]>
2020-05-15 00:03 ` Re: MultiXact\SLRU buffers configuration Kyotaro Horiguchi <[email protected]>
2020-07-02 12:02 ` Re: MultiXact\SLRU buffers configuration Daniel Gustafsson <[email protected]>
2020-07-08 07:03 ` Re: MultiXact\SLRU buffers configuration Andrey M. Borodin <[email protected]>
2020-08-28 18:08 ` Re: MultiXact\SLRU buffers configuration Anastasia Lubennikova <[email protected]>
2020-09-28 14:41 ` Re: MultiXact\SLRU buffers configuration Andrey M. Borodin <[email protected]>
2020-10-26 01:05 ` Re: MultiXact\SLRU buffers configuration Alexander Korotkov <[email protected]>
2020-10-26 15:45 ` Re: MultiXact\SLRU buffers configuration Andrey Borodin <[email protected]>
2020-10-27 17:02 ` Re: MultiXact\SLRU buffers configuration Alexander Korotkov <[email protected]>
2020-10-27 17:23 ` Re: MultiXact\SLRU buffers configuration Alexander Korotkov <[email protected]>
2020-10-28 01:36 ` Re: MultiXact\SLRU buffers configuration Tomas Vondra <[email protected]>
2020-10-28 07:34 ` Re: MultiXact\SLRU buffers configuration Andrey Borodin <[email protected]>
2020-10-28 23:32 ` Re: MultiXact\SLRU buffers configuration Tomas Vondra <[email protected]>
2020-10-29 07:08 ` Re: MultiXact\SLRU buffers configuration Andrey Borodin <[email protected]>
2020-10-29 13:49 ` Re: MultiXact\SLRU buffers configuration Tomas Vondra <[email protected]>
2020-11-02 12:45 ` Re: MultiXact\SLRU buffers configuration Andrey Borodin <[email protected]>
2020-11-10 00:13 ` Re: MultiXact\SLRU buffers configuration Tomas Vondra <[email protected]>
2020-11-10 06:16 ` Re: MultiXact\SLRU buffers configuration Andrey Borodin <[email protected]>
2020-11-10 18:07 ` Re: MultiXact\SLRU buffers configuration Tomas Vondra <[email protected]>
2020-11-13 11:49 ` Re: MultiXact\SLRU buffers configuration Andrey Borodin <[email protected]>
2020-12-08 16:05 ` Re: MultiXact\SLRU buffers configuration Gilles Darold <[email protected]>
@ 2020-12-08 17:52 ` Andrey Borodin <[email protected]>
2020-12-09 10:51 ` Re: MultiXact\SLRU buffers configuration Gilles Darold <[email protected]>
2020-12-10 14:45 ` Re: MultiXact\SLRU buffers configuration Gilles Darold <[email protected]>
0 siblings, 2 replies; 90+ messages in thread
From: Andrey Borodin @ 2020-12-08 17:52 UTC (permalink / raw)
To: Gilles Darold <[email protected]>; +Cc: Tomas Vondra <[email protected]>; Tomas Vondra <[email protected]>; Alexander Korotkov <[email protected]>; Anastasia Lubennikova <[email protected]>; Daniel Gustafsson <[email protected]>; Kyotaro Horiguchi <[email protected]>; pgsql-hackers
Hi Gilles!
Many thanks for your message!
> 8 дек. 2020 г., в 21:05, Gilles Darold <[email protected]> написал(а):
>
> I know that this report is not really helpful
Quite contrary - this benchmarks prove that controllable reproduction exists. I've rebased patches for PG11. Can you please benchmark them (without extending SLRU)?
Best regards, Andrey Borodin.
Attachments:
[application/octet-stream] v1106-0001-Use-shared-lock-in-GetMultiXactIdMembers-for-o.patch (12.7K, ../../[email protected]/2-v1106-0001-Use-shared-lock-in-GetMultiXactIdMembers-for-o.patch)
download | inline diff:
From dee5bf87314606e020a574b85cf1e9cbe066588d Mon Sep 17 00:00:00 2001
From: Alexander Korotkov <[email protected]>
Date: Tue, 27 Oct 2020 19:29:56 +0300
Subject: [PATCH v1106 1/4] Use shared lock in GetMultiXactIdMembers for
offsets and members
Previously the read of multixact required exclusive control locks for both
offsets and members SLRUs. This could lead to the excessive lock contention.
This commit we makes multixacts SLRU take advantage of SimpleLruReadPage_ReadOnly
similar to clog, commit_ts and subtrans.
In order to evade extra reacquiring of CLRU lock, we teach
SimpleLruReadPage_ReadOnly() to take into account the current lock mode and
report resulting lock mode back.
Discussion: https://postgr.es/m/a7f1c4e1-1015-92a4-2bd4-6736bd13d03e%40postgrespro.ru#c496c4e75fc0605094a0e1f763e6a6ec
Author: Andrey Borodin
Reviewed-by: Kyotaro Horiguchi, Daniel Gustafsson
Reviewed-by: Anastasia Lubennikova, Alexander Korotkov
---
src/backend/access/transam/clog.c | 3 ++-
src/backend/access/transam/commit_ts.c | 3 ++-
src/backend/access/transam/multixact.c | 21 ++++++++++++++-------
src/backend/access/transam/slru.c | 23 +++++++++++++++++------
src/backend/access/transam/subtrans.c | 3 ++-
src/backend/commands/async.c | 6 ++++--
src/backend/storage/lmgr/lwlock.c | 3 +++
src/backend/storage/lmgr/predicate.c | 4 +++-
src/include/access/slru.h | 8 ++++----
src/include/storage/lwlock.h | 2 ++
10 files changed, 53 insertions(+), 23 deletions(-)
diff --git a/src/backend/access/transam/clog.c b/src/backend/access/transam/clog.c
index a8d1080f17..bdfbd10f96 100644
--- a/src/backend/access/transam/clog.c
+++ b/src/backend/access/transam/clog.c
@@ -640,10 +640,11 @@ TransactionIdGetStatus(TransactionId xid, XLogRecPtr *lsn)
int lsnindex;
char *byteptr;
XidStatus status;
+ LWLockMode lockmode = LW_NONE;
/* lock is acquired by SimpleLruReadPage_ReadOnly */
- slotno = SimpleLruReadPage_ReadOnly(ClogCtl, pageno, xid);
+ slotno = SimpleLruReadPage_ReadOnly(ClogCtl, pageno, xid, &lockmode);
byteptr = ClogCtl->shared->page_buffer[slotno] + byteno;
status = (*byteptr >> bshift) & CLOG_XACT_BITMASK;
diff --git a/src/backend/access/transam/commit_ts.c b/src/backend/access/transam/commit_ts.c
index 6c4911d9bc..d7b6f583e1 100644
--- a/src/backend/access/transam/commit_ts.c
+++ b/src/backend/access/transam/commit_ts.c
@@ -288,6 +288,7 @@ TransactionIdGetCommitTsData(TransactionId xid, TimestampTz *ts,
CommitTimestampEntry entry;
TransactionId oldestCommitTsXid;
TransactionId newestCommitTsXid;
+ LWLockMode lockmode = LW_NONE;
if (!TransactionIdIsValid(xid))
ereport(ERROR,
@@ -342,7 +343,7 @@ TransactionIdGetCommitTsData(TransactionId xid, TimestampTz *ts,
}
/* lock is acquired by SimpleLruReadPage_ReadOnly */
- slotno = SimpleLruReadPage_ReadOnly(CommitTsCtl, pageno, xid);
+ slotno = SimpleLruReadPage_ReadOnly(CommitTsCtl, pageno, xid, &lockmode);
memcpy(&entry,
CommitTsCtl->shared->page_buffer[slotno] +
SizeOfCommitTimestampEntry * entryno,
diff --git a/src/backend/access/transam/multixact.c b/src/backend/access/transam/multixact.c
index 365daf153a..5ca10a139a 100644
--- a/src/backend/access/transam/multixact.c
+++ b/src/backend/access/transam/multixact.c
@@ -1216,6 +1216,7 @@ GetMultiXactIdMembers(MultiXactId multi, MultiXactMember **members,
MultiXactId tmpMXact;
MultiXactOffset nextOffset;
MultiXactMember *ptr;
+ LWLockMode lockmode = LW_NONE;
debug_elog3(DEBUG2, "GetMembers: asked for %u", multi);
@@ -1319,12 +1320,13 @@ GetMultiXactIdMembers(MultiXactId multi, MultiXactMember **members,
* time on every multixact creation.
*/
retry:
- LWLockAcquire(MultiXactOffsetControlLock, LW_EXCLUSIVE);
pageno = MultiXactIdToOffsetPage(multi);
entryno = MultiXactIdToOffsetEntry(multi);
- slotno = SimpleLruReadPage(MultiXactOffsetCtl, pageno, true, multi);
+ /* lock is acquired by SimpleLruReadPage_ReadOnly */
+ slotno = SimpleLruReadPage_ReadOnly(MultiXactOffsetCtl, pageno,
+ multi, &lockmode);
offptr = (MultiXactOffset *) MultiXactOffsetCtl->shared->page_buffer[slotno];
offptr += entryno;
offset = *offptr;
@@ -1356,7 +1358,8 @@ retry:
entryno = MultiXactIdToOffsetEntry(tmpMXact);
if (pageno != prev_pageno)
- slotno = SimpleLruReadPage(MultiXactOffsetCtl, pageno, true, tmpMXact);
+ slotno = SimpleLruReadPage_ReadOnly(MultiXactOffsetCtl, pageno,
+ tmpMXact, &lockmode);
offptr = (MultiXactOffset *) MultiXactOffsetCtl->shared->page_buffer[slotno];
offptr += entryno;
@@ -1380,8 +1383,7 @@ retry:
*members = ptr;
/* Now get the members themselves. */
- LWLockAcquire(MultiXactMemberControlLock, LW_EXCLUSIVE);
-
+ lockmode = LW_NONE;
truelength = 0;
prev_pageno = -1;
for (i = 0; i < length; i++, offset++)
@@ -1397,7 +1399,8 @@ retry:
if (pageno != prev_pageno)
{
- slotno = SimpleLruReadPage(MultiXactMemberCtl, pageno, true, multi);
+ slotno = SimpleLruReadPage_ReadOnly(MultiXactMemberCtl, pageno,
+ multi, &lockmode);
prev_pageno = pageno;
}
@@ -1420,6 +1423,7 @@ retry:
truelength++;
}
+ Assert(lockmode != LW_NONE);
LWLockRelease(MultiXactMemberControlLock);
/*
@@ -2723,6 +2727,7 @@ find_multixact_start(MultiXactId multi, MultiXactOffset *result)
int entryno;
int slotno;
MultiXactOffset *offptr;
+ LWLockMode lockmode = LW_NONE;
Assert(MultiXactState->finishedStartup);
@@ -2743,10 +2748,12 @@ find_multixact_start(MultiXactId multi, MultiXactOffset *result)
return false;
/* lock is acquired by SimpleLruReadPage_ReadOnly */
- slotno = SimpleLruReadPage_ReadOnly(MultiXactOffsetCtl, pageno, multi);
+ slotno = SimpleLruReadPage_ReadOnly(MultiXactOffsetCtl, pageno,
+ multi, &lockmode);
offptr = (MultiXactOffset *) MultiXactOffsetCtl->shared->page_buffer[slotno];
offptr += entryno;
offset = *offptr;
+ Assert(lockmode != LW_NONE);
LWLockRelease(MultiXactOffsetControlLock);
*result = offset;
diff --git a/src/backend/access/transam/slru.c b/src/backend/access/transam/slru.c
index cfe9513827..f86950eb51 100644
--- a/src/backend/access/transam/slru.c
+++ b/src/backend/access/transam/slru.c
@@ -460,17 +460,23 @@ SimpleLruReadPage(SlruCtl ctl, int pageno, bool write_ok,
* Return value is the shared-buffer slot number now holding the page.
* The buffer's LRU access info is updated.
*
- * Control lock must NOT be held at entry, but will be held at exit.
- * It is unspecified whether the lock will be shared or exclusive.
+ * Control lock must be held in *lock_mode mode, which may be LW_NONE. Control
+ * lock will be held at exit in at least shared mode. Resulting control lock
+ * mode is set to *lock_mode.
*/
int
-SimpleLruReadPage_ReadOnly(SlruCtl ctl, int pageno, TransactionId xid)
+SimpleLruReadPage_ReadOnly(SlruCtl ctl, int pageno, TransactionId xid,
+ LWLockMode *lock_mode)
{
SlruShared shared = ctl->shared;
int slotno;
/* Try to find the page while holding only shared lock */
- LWLockAcquire(shared->ControlLock, LW_SHARED);
+ if (*lock_mode == LW_NONE)
+ {
+ LWLockAcquire(shared->ControlLock, LW_SHARED);
+ *lock_mode = LW_SHARED;
+ }
/* See if page is already in a buffer */
for (slotno = 0; slotno < shared->num_slots; slotno++)
@@ -486,8 +492,13 @@ SimpleLruReadPage_ReadOnly(SlruCtl ctl, int pageno, TransactionId xid)
}
/* No luck, so switch to normal exclusive lock and do regular read */
- LWLockRelease(shared->ControlLock);
- LWLockAcquire(shared->ControlLock, LW_EXCLUSIVE);
+ if (*lock_mode != LW_EXCLUSIVE)
+ {
+ Assert(*lock_mode == LW_NONE);
+ LWLockRelease(shared->ControlLock);
+ LWLockAcquire(shared->ControlLock, LW_EXCLUSIVE);
+ *lock_mode = LW_EXCLUSIVE;
+ }
return SimpleLruReadPage(ctl, pageno, true, xid);
}
diff --git a/src/backend/access/transam/subtrans.c b/src/backend/access/transam/subtrans.c
index ef63b6d98a..440a21415a 100644
--- a/src/backend/access/transam/subtrans.c
+++ b/src/backend/access/transam/subtrans.c
@@ -113,6 +113,7 @@ SubTransGetParent(TransactionId xid)
int slotno;
TransactionId *ptr;
TransactionId parent;
+ LWLockMode lockmode = LW_NONE;
/* Can't ask about stuff that might not be around anymore */
Assert(TransactionIdFollowsOrEquals(xid, TransactionXmin));
@@ -123,7 +124,7 @@ SubTransGetParent(TransactionId xid)
/* lock is acquired by SimpleLruReadPage_ReadOnly */
- slotno = SimpleLruReadPage_ReadOnly(SubTransCtl, pageno, xid);
+ slotno = SimpleLruReadPage_ReadOnly(SubTransCtl, pageno, xid, &lockmode);
ptr = (TransactionId *) SubTransCtl->shared->page_buffer[slotno];
ptr += entryno;
diff --git a/src/backend/commands/async.c b/src/backend/commands/async.c
index 7f4e11bd90..4ebc069a5d 100644
--- a/src/backend/commands/async.c
+++ b/src/backend/commands/async.c
@@ -1834,6 +1834,7 @@ asyncQueueReadAllNotifications(void)
int curoffset = QUEUE_POS_OFFSET(pos);
int slotno;
int copysize;
+ LWLockMode lockmode = LW_NONE;
/*
* We copy the data from SLRU into a local buffer, so as to avoid
@@ -1842,7 +1843,7 @@ asyncQueueReadAllNotifications(void)
* of the page we will actually inspect.
*/
slotno = SimpleLruReadPage_ReadOnly(AsyncCtl, curpage,
- InvalidTransactionId);
+ InvalidTransactionId, &lockmode);
if (curpage == QUEUE_POS_PAGE(head))
{
/* we only want to read as far as head */
@@ -1859,7 +1860,8 @@ asyncQueueReadAllNotifications(void)
AsyncCtl->shared->page_buffer[slotno] + curoffset,
copysize);
/* Release lock that we got from SimpleLruReadPage_ReadOnly() */
- LWLockRelease(AsyncCtlLock);
+ Assert(lockmode != LW_NONE);
+ LWLockRelease(AsyncCtl);
/*
* Process messages up to the stop position, end of page, or an
diff --git a/src/backend/storage/lmgr/lwlock.c b/src/backend/storage/lmgr/lwlock.c
index 5aae233995..066dbb8ccf 100644
--- a/src/backend/storage/lmgr/lwlock.c
+++ b/src/backend/storage/lmgr/lwlock.c
@@ -982,6 +982,8 @@ LWLockWakeup(LWLock *lock)
static void
LWLockQueueSelf(LWLock *lock, LWLockMode mode)
{
+ Assert(mode != LW_NONE);
+
/*
* If we don't have a PGPROC structure, there's no way to wait. This
* should never occur, since MyProc should only be null during shared
@@ -1742,6 +1744,7 @@ LWLockRelease(LWLock *lock)
elog(ERROR, "lock %s is not held", T_NAME(lock));
mode = held_lwlocks[i].mode;
+ Assert(mode == LW_EXCLUSIVE || mode == LW_SHARED);
num_held_lwlocks--;
for (; i < num_held_lwlocks; i++)
diff --git a/src/backend/storage/lmgr/predicate.c b/src/backend/storage/lmgr/predicate.c
index 002d040ba6..9513fd915b 100644
--- a/src/backend/storage/lmgr/predicate.c
+++ b/src/backend/storage/lmgr/predicate.c
@@ -908,6 +908,7 @@ OldSerXidGetMinConflictCommitSeqNo(TransactionId xid)
TransactionId tailXid;
SerCommitSeqNo val;
int slotno;
+ LWLockMode lockmode = LW_NONE;
Assert(TransactionIdIsValid(xid));
@@ -930,8 +931,9 @@ OldSerXidGetMinConflictCommitSeqNo(TransactionId xid)
* but will return with that lock held, which must then be released.
*/
slotno = SimpleLruReadPage_ReadOnly(OldSerXidSlruCtl,
- OldSerXidPage(xid), xid);
+ OldSerXidPage(xid), xid, &lockmode);
val = OldSerXidValue(slotno, xid);
+ Assert(lockmode != LW_NONE);
LWLockRelease(OldSerXidLock);
return val;
}
diff --git a/src/include/access/slru.h b/src/include/access/slru.h
index 0e89e48c97..51a3df62e0 100644
--- a/src/include/access/slru.h
+++ b/src/include/access/slru.h
@@ -141,10 +141,10 @@ extern Size SimpleLruShmemSize(int nslots, int nlsns);
extern void SimpleLruInit(SlruCtl ctl, const char *name, int nslots, int nlsns,
LWLock *ctllock, const char *subdir, int tranche_id);
extern int SimpleLruZeroPage(SlruCtl ctl, int pageno);
-extern int SimpleLruReadPage(SlruCtl ctl, int pageno, bool write_ok,
- TransactionId xid);
-extern int SimpleLruReadPage_ReadOnly(SlruCtl ctl, int pageno,
- TransactionId xid);
+extern int SimpleLruReadPage(SlruCtl ctl, int pageno, bool write_ok,
+ TransactionId xid);
+extern int SimpleLruReadPage_ReadOnly(SlruCtl ctl, int pageno,
+ TransactionId xid, LWLockMode *lock_mode);
extern void SimpleLruWritePage(SlruCtl ctl, int slotno);
extern void SimpleLruFlush(SlruCtl ctl, bool allow_redirtied);
extern void SimpleLruTruncate(SlruCtl ctl, int cutoffPage);
diff --git a/src/include/storage/lwlock.h b/src/include/storage/lwlock.h
index c21bfe2f66..3263c0fe62 100644
--- a/src/include/storage/lwlock.h
+++ b/src/include/storage/lwlock.h
@@ -131,6 +131,8 @@ extern PGDLLIMPORT int NamedLWLockTrancheRequests;
typedef enum LWLockMode
{
+ LW_NONE, /* Not a lock mode. Indicates that there is no
+ * lock. */
LW_EXCLUSIVE,
LW_SHARED,
LW_WAIT_UNTIL_FREE /* A special mode used in PGPROC->lwlockMode,
--
2.24.3 (Apple Git-128)
[application/octet-stream] v1106-0002-Make-MultiXact-local-cache-size-configurable.patch (4.8K, ../../[email protected]/3-v1106-0002-Make-MultiXact-local-cache-size-configurable.patch)
download | inline diff:
From 649c5c25349c32aecf02fad46197234af95f9860 Mon Sep 17 00:00:00 2001
From: Alexander Korotkov <[email protected]>
Date: Mon, 26 Oct 2020 03:44:50 +0300
Subject: [PATCH v1106 2/4] Make MultiXact local cache size configurable
---
doc/src/sgml/config.sgml | 37 ++++++++++++++++++++++++++
src/backend/access/transam/multixact.c | 2 +-
src/backend/utils/init/globals.c | 2 ++
src/backend/utils/misc/guc.c | 10 +++++++
src/include/miscadmin.h | 2 ++
5 files changed, 52 insertions(+), 1 deletion(-)
diff --git a/doc/src/sgml/config.sgml b/doc/src/sgml/config.sgml
index 3570b422be..15fb2f2bde 100644
--- a/doc/src/sgml/config.sgml
+++ b/doc/src/sgml/config.sgml
@@ -1637,6 +1637,43 @@ include_dir 'conf.d'
</listitem>
</varlistentry>
+ <varlistentry id="guc-logical-decoding-work-mem" xreflabel="logical_decoding_work_mem">
+ <term><varname>logical_decoding_work_mem</varname> (<type>integer</type>)
+ <indexterm>
+ <primary><varname>logical_decoding_work_mem</varname> configuration parameter</primary>
+ </indexterm>
+ </term>
+ <listitem>
+ <para>
+ Specifies the maximum amount of memory to be used by logical decoding,
+ before some of the decoded changes are written to local disk. This
+ limits the amount of memory used by logical streaming replication
+ connections. It defaults to 64 megabytes (<literal>64MB</literal>).
+ Since each replication connection only uses a single buffer of this size,
+ and an installation normally doesn't have many such connections
+ concurrently (as limited by <varname>max_wal_senders</varname>), it's
+ safe to set this value significantly higher than <varname>work_mem</varname>,
+ reducing the amount of decoded changes written to disk.
+ </para>
+ </listitem>
+ </varlistentry>
+
+ <varlistentry id="guc-multixact-local-cache-entries" xreflabel="multixact_local-cache-entries">
+ <term><varname>multixact_local_cache_entries</varname> (<type>integer</type>)
+ <indexterm>
+ <primary><varname>multixact_local_cache_entries</varname> configuration parameter</primary>
+ </indexterm>
+ </term>
+ <listitem>
+ <para>
+ Specifies the number cached MultiXact by backend. Any SLRU lookup is preceeded
+ by cache lookup. Higher numbers of cache size help to deduplicate lock sets, while
+ lower values make cache lookup faster.
+ It defaults to 256.
+ </para>
+ </listitem>
+ </varlistentry>
+
<varlistentry id="guc-max-stack-depth" xreflabel="max_stack_depth">
<term><varname>max_stack_depth</varname> (<type>integer</type>)
<indexterm>
diff --git a/src/backend/access/transam/multixact.c b/src/backend/access/transam/multixact.c
index 5ca10a139a..6203be0aa3 100644
--- a/src/backend/access/transam/multixact.c
+++ b/src/backend/access/transam/multixact.c
@@ -1591,7 +1591,7 @@ mXactCachePut(MultiXactId multi, int nmembers, MultiXactMember *members)
qsort(entry->members, nmembers, sizeof(MultiXactMember), mxactMemberComparator);
dlist_push_head(&MXactCache, &entry->node);
- if (MXactCacheMembers++ >= MAX_CACHE_ENTRIES)
+ if (MXactCacheMembers++ >= multixact_local_cache_entries)
{
dlist_node *node;
mXactCacheEnt *entry;
diff --git a/src/backend/utils/init/globals.c b/src/backend/utils/init/globals.c
index f7d6617a13..22af834150 100644
--- a/src/backend/utils/init/globals.c
+++ b/src/backend/utils/init/globals.c
@@ -147,3 +147,5 @@ int VacuumCostBalance = 0; /* working state for vacuum */
bool VacuumCostActive = false;
double vacuum_cleanup_index_scale_factor;
+
+int multixact_local_cache_entries = 256;
diff --git a/src/backend/utils/misc/guc.c b/src/backend/utils/misc/guc.c
index 710344c72b..b54a063782 100644
--- a/src/backend/utils/misc/guc.c
+++ b/src/backend/utils/misc/guc.c
@@ -2026,6 +2026,16 @@ static struct config_int ConfigureNamesInt[] =
NULL, NULL, NULL
},
+ {
+ {"multixact_local_cache_entries", PGC_SUSET, RESOURCES_MEM,
+ gettext_noop("Sets the number of cached MultiXact by backend."),
+ NULL
+ },
+ &multixact_local_cache_entries,
+ 256, 2, INT_MAX / 2,
+ NULL, NULL, NULL
+ },
+
{
{"temp_buffers", PGC_USERSET, RESOURCES_MEM,
gettext_noop("Sets the maximum number of temporary buffers used by each session."),
diff --git a/src/include/miscadmin.h b/src/include/miscadmin.h
index 8024145535..11c3c8e6c5 100644
--- a/src/include/miscadmin.h
+++ b/src/include/miscadmin.h
@@ -161,6 +161,8 @@ extern PGDLLIMPORT int MaxConnections;
extern PGDLLIMPORT int max_worker_processes;
extern PGDLLIMPORT int max_parallel_workers;
+extern PGDLLIMPORT int multixact_local_cache_entries;
+
extern PGDLLIMPORT int MyProcPid;
extern PGDLLIMPORT pg_time_t MyStartTime;
extern PGDLLIMPORT struct Port *MyProcPort;
--
2.24.3 (Apple Git-128)
[application/octet-stream] v1106-0003-Add-conditional-variable-to-wait-for-next-Mult.patch (4.4K, ../../[email protected]/4-v1106-0003-Add-conditional-variable-to-wait-for-next-Mult.patch)
download | inline diff:
From 38dc550f363c1c8878fbf06d5616614a36112fac Mon Sep 17 00:00:00 2001
From: Alexander Korotkov <[email protected]>
Date: Mon, 26 Oct 2020 01:55:31 +0300
Subject: [PATCH v1106 3/4] Add conditional variable to wait for next MultXact
offset in corner case
GetMultiXactIdMembers() has a corner case, when the next multixact offset is
not yet set. In this case GetMultiXactIdMembers() has to sleep till this offset
is set. Currently the sleeping is implemented in naive way using pg_sleep()
and retry. This commit implements sleeping with conditional variable, which
provides more efficient way for waiting till the event.
Discussion: https://postgr.es/m/a7f1c4e1-1015-92a4-2bd4-6736bd13d03e%40postgrespro.ru#c496c4e75fc0605094a0e1f763e6a6ec
Author: Andrey Borodin
Reviewed-by: Kyotaro Horiguchi, Daniel Gustafsson
Reviewed-by: Anastasia Lubennikova, Alexander Korotkov
---
src/backend/access/transam/multixact.c | 35 ++++++++++++++++++++++++--
src/backend/postmaster/pgstat.c | 3 +++
src/include/pgstat.h | 3 ++-
3 files changed, 38 insertions(+), 3 deletions(-)
diff --git a/src/backend/access/transam/multixact.c b/src/backend/access/transam/multixact.c
index 6203be0aa3..5d2bbb1ca6 100644
--- a/src/backend/access/transam/multixact.c
+++ b/src/backend/access/transam/multixact.c
@@ -82,6 +82,7 @@
#include "lib/ilist.h"
#include "miscadmin.h"
#include "pg_trace.h"
+#include "pgstat.h"
#include "postmaster/autovacuum.h"
#include "storage/lmgr.h"
#include "storage/pmsignal.h"
@@ -233,6 +234,13 @@ typedef struct MultiXactStateData
/* support for members anti-wraparound measures */
MultiXactOffset offsetStopLimit; /* known if oldestOffsetKnown */
+ /*
+ * Conditional variable for waiting till the filling of the next multixact
+ * will be finished. See GetMultiXactIdMembers() and RecordNewMultiXact()
+ * for details.
+ */
+ ConditionVariable nextoffCV;
+
/*
* Per-backend data starts here. We have two arrays stored in the area
* immediately following the MultiXactStateData struct. Each is indexed by
@@ -871,6 +879,14 @@ RecordNewMultiXact(MultiXactId multi, MultiXactOffset offset,
/* Exchange our lock */
LWLockRelease(MultiXactOffsetControlLock);
+ /*
+ * Let everybody know the offset of this mxid is recorded now. The
+ * waiters are waiting for the offset of the mxid next of the target to
+ * know the number of members of the target mxid, so we don't need to wait
+ * for members of this mxid are recorded.
+ */
+ ConditionVariableBroadcast(&MultiXactState->nextoffCV);
+
LWLockAcquire(MultiXactMemberControlLock, LW_EXCLUSIVE);
prev_pageno = -1;
@@ -1368,9 +1384,23 @@ retry:
if (nextMXOffset == 0)
{
/* Corner case 2: next multixact is still being filled in */
+
+ /*
+ * The recorder of the next mxid is just before writing the
+ * offset. Wait for the offset to be written.
+ */
+ ConditionVariablePrepareToSleep(&MultiXactState->nextoffCV);
+
+ /*
+ * We don't have to recheck if multixact was filled in during
+ * ConditionVariablePrepareToSleep(), because we were holding
+ * MultiXactOffsetSLRULock.
+ */
LWLockRelease(MultiXactOffsetControlLock);
- CHECK_FOR_INTERRUPTS();
- pg_usleep(1000L);
+
+ ConditionVariableSleep(&MultiXactState->nextoffCV,
+ WAIT_EVENT_WAIT_NEXT_MXMEMBERS);
+ ConditionVariableCancelSleep();
goto retry;
}
@@ -1849,6 +1879,7 @@ MultiXactShmemInit(void)
/* Make sure we zero out the per-backend state */
MemSet(MultiXactState, 0, SHARED_MULTIXACT_STATE_SIZE);
+ ConditionVariableInit(&MultiXactState->nextoffCV);
}
else
Assert(found);
diff --git a/src/backend/postmaster/pgstat.c b/src/backend/postmaster/pgstat.c
index 4895354a28..8a8b9a4eef 100644
--- a/src/backend/postmaster/pgstat.c
+++ b/src/backend/postmaster/pgstat.c
@@ -3730,6 +3730,9 @@ pgstat_get_wait_ipc(WaitEventIPC w)
case WAIT_EVENT_SYNC_REP:
event_name = "SyncRep";
break;
+ case WAIT_EVENT_WAIT_NEXT_MXMEMBERS:
+ event_name = "MultiXactWaitNextMembers";
+ break;
/* no default case, so that compiler will warn */
}
diff --git a/src/include/pgstat.h b/src/include/pgstat.h
index 58e2e71c6f..e89d946669 100644
--- a/src/include/pgstat.h
+++ b/src/include/pgstat.h
@@ -832,7 +832,8 @@ typedef enum
WAIT_EVENT_REPLICATION_ORIGIN_DROP,
WAIT_EVENT_REPLICATION_SLOT_DROP,
WAIT_EVENT_SAFE_SNAPSHOT,
- WAIT_EVENT_SYNC_REP
+ WAIT_EVENT_SYNC_REP,
+ WAIT_EVENT_WAIT_NEXT_MXMEMBERS
} WaitEventIPC;
/* ----------
--
2.24.3 (Apple Git-128)
[application/octet-stream] v1106-0004-Add-GUCs-to-tune-MultiXact-SLRUs.patch (6.2K, ../../[email protected]/5-v1106-0004-Add-GUCs-to-tune-MultiXact-SLRUs.patch)
download | inline diff:
From e273a508592236dbf5c60417b5878961c2483bca Mon Sep 17 00:00:00 2001
From: Andrey Borodin <[email protected]>
Date: Sat, 9 May 2020 16:42:07 +0500
Subject: [PATCH v1106 4/4] Add GUCs to tune MultiXact SLRUs
---
doc/src/sgml/config.sgml | 31 ++++++++++++++++++++++++++
src/backend/access/transam/multixact.c | 8 +++----
src/backend/utils/init/globals.c | 2 ++
src/backend/utils/misc/guc.c | 22 ++++++++++++++++++
src/include/access/multixact.h | 4 ----
src/include/miscadmin.h | 2 ++
6 files changed, 61 insertions(+), 8 deletions(-)
diff --git a/doc/src/sgml/config.sgml b/doc/src/sgml/config.sgml
index 15fb2f2bde..44ebacc713 100644
--- a/doc/src/sgml/config.sgml
+++ b/doc/src/sgml/config.sgml
@@ -1673,6 +1673,37 @@ include_dir 'conf.d'
</para>
</listitem>
</varlistentry>
+
+ <varlistentry id="guc-multixact-offsets-slru-buffers" xreflabel="multixact_offsets_slru_buffers">
+ <term><varname>multixact_offsets_slru_buffers</varname> (<type>integer</type>)
+ <indexterm>
+ <primary><varname>multixact_offsets_slru_buffers</varname> configuration parameter</primary>
+ </indexterm>
+ </term>
+ <listitem>
+ <para>
+ Specifies the amount of memory to be used for MultiXact offsets. MultiXact offsets
+ are used to store informaion about offsets of multiple row lockers (caused by SELECT FOR UPDATE and others).
+ It defaults to 64 kilobytes (<literal>64KB</literal>).
+ </para>
+ </listitem>
+ </varlistentry>
+
+ <varlistentry id="guc-multixact-members-slru-buffers" xreflabel="multixact_members_slru_buffers">
+ <term><varname>multixact_members_slru_buffers</varname> (<type>integer</type>)
+ <indexterm>
+ <primary><varname>multixact_members_slru_buffers</varname> configuration parameter</primary>
+ </indexterm>
+ </term>
+ <listitem>
+ <para>
+ Specifies the amount of memory to be used for MultiXact members. MultiXact members
+ are used to store informaion about XIDs of multiple row lockers. Tipically <varname>multixact_members_slru_buffers</varname>
+ is twice more than <varname>multixact_offsets_slru_buffers</varname>.
+ It defaults to 128 kilobytes (<literal>128KB</literal>).
+ </para>
+ </listitem>
+ </varlistentry>
<varlistentry id="guc-max-stack-depth" xreflabel="max_stack_depth">
<term><varname>max_stack_depth</varname> (<type>integer</type>)
diff --git a/src/backend/access/transam/multixact.c b/src/backend/access/transam/multixact.c
index 5d2bbb1ca6..31324714b8 100644
--- a/src/backend/access/transam/multixact.c
+++ b/src/backend/access/transam/multixact.c
@@ -1844,8 +1844,8 @@ MultiXactShmemSize(void)
mul_size(sizeof(MultiXactId) * 2, MaxOldestSlot))
size = SHARED_MULTIXACT_STATE_SIZE;
- size = add_size(size, SimpleLruShmemSize(NUM_MXACTOFFSET_BUFFERS, 0));
- size = add_size(size, SimpleLruShmemSize(NUM_MXACTMEMBER_BUFFERS, 0));
+ size = add_size(size, SimpleLruShmemSize(multixact_offsets_slru_buffers, 0));
+ size = add_size(size, SimpleLruShmemSize(multixact_members_slru_buffers, 0));
return size;
}
@@ -1861,11 +1861,11 @@ MultiXactShmemInit(void)
MultiXactMemberCtl->PagePrecedes = MultiXactMemberPagePrecedes;
SimpleLruInit(MultiXactOffsetCtl,
- "multixact_offset", NUM_MXACTOFFSET_BUFFERS, 0,
+ "multixact_offset", multixact_offsets_slru_buffers, 0,
MultiXactOffsetControlLock, "pg_multixact/offsets",
LWTRANCHE_MXACTOFFSET_BUFFERS);
SimpleLruInit(MultiXactMemberCtl,
- "multixact_member", NUM_MXACTMEMBER_BUFFERS, 0,
+ "multixact_member", multixact_members_slru_buffers, 0,
MultiXactMemberControlLock, "pg_multixact/members",
LWTRANCHE_MXACTMEMBER_BUFFERS);
diff --git a/src/backend/utils/init/globals.c b/src/backend/utils/init/globals.c
index 22af834150..5a8517f8eb 100644
--- a/src/backend/utils/init/globals.c
+++ b/src/backend/utils/init/globals.c
@@ -149,3 +149,5 @@ bool VacuumCostActive = false;
double vacuum_cleanup_index_scale_factor;
int multixact_local_cache_entries = 256;
+int multixact_offsets_slru_buffers = 8;
+int multixact_members_slru_buffers = 16;
diff --git a/src/backend/utils/misc/guc.c b/src/backend/utils/misc/guc.c
index b54a063782..578452d757 100644
--- a/src/backend/utils/misc/guc.c
+++ b/src/backend/utils/misc/guc.c
@@ -2036,6 +2036,28 @@ static struct config_int ConfigureNamesInt[] =
NULL, NULL, NULL
},
+ {
+ {"multixact_offsets_slru_buffers", PGC_POSTMASTER, RESOURCES_MEM,
+ gettext_noop("Sets the number of shared memory buffers used for MultiXact offsets SLRU."),
+ NULL,
+ GUC_UNIT_BLOCKS
+ },
+ &multixact_offsets_slru_buffers,
+ 8, 2, INT_MAX / 2,
+ NULL, NULL, NULL
+ },
+
+ {
+ {"multixact_members_slru_buffers", PGC_POSTMASTER, RESOURCES_MEM,
+ gettext_noop("Sets the number of shared memory buffers used for MultiXact members SLRU."),
+ NULL,
+ GUC_UNIT_BLOCKS
+ },
+ &multixact_members_slru_buffers,
+ 16, 2, INT_MAX / 2,
+ NULL, NULL, NULL
+ },
+
{
{"temp_buffers", PGC_USERSET, RESOURCES_MEM,
gettext_noop("Sets the maximum number of temporary buffers used by each session."),
diff --git a/src/include/access/multixact.h b/src/include/access/multixact.h
index 18fe380c5f..6e14fb7b29 100644
--- a/src/include/access/multixact.h
+++ b/src/include/access/multixact.h
@@ -28,10 +28,6 @@
#define MaxMultiXactOffset ((MultiXactOffset) 0xFFFFFFFF)
-/* Number of SLRU buffers to use for multixact */
-#define NUM_MXACTOFFSET_BUFFERS 8
-#define NUM_MXACTMEMBER_BUFFERS 16
-
/*
* Possible multixact lock modes ("status"). The first four modes are for
* tuple locks (FOR KEY SHARE, FOR SHARE, FOR NO KEY UPDATE, FOR UPDATE); the
diff --git a/src/include/miscadmin.h b/src/include/miscadmin.h
index 11c3c8e6c5..e3fd0a264d 100644
--- a/src/include/miscadmin.h
+++ b/src/include/miscadmin.h
@@ -160,6 +160,8 @@ extern PGDLLIMPORT int MaxBackends;
extern PGDLLIMPORT int MaxConnections;
extern PGDLLIMPORT int max_worker_processes;
extern PGDLLIMPORT int max_parallel_workers;
+extern PGDLLIMPORT int multixact_offsets_slru_buffers;
+extern PGDLLIMPORT int multixact_members_slru_buffers;
extern PGDLLIMPORT int multixact_local_cache_entries;
--
2.24.3 (Apple Git-128)
^ permalink raw reply [nested|flat] 90+ messages in thread
* Re: MultiXact\SLRU buffers configuration
2020-05-08 16:36 MultiXact\SLRU buffers configuration Andrey M. Borodin <[email protected]>
2020-05-11 11:17 ` Re: MultiXact\SLRU buffers configuration Andrey M. Borodin <[email protected]>
2020-05-13 18:08 ` Re: MultiXact\SLRU buffers configuration Andrey M. Borodin <[email protected]>
2020-05-14 01:25 ` Re: MultiXact\SLRU buffers configuration Kyotaro Horiguchi <[email protected]>
2020-05-14 05:19 ` Re: MultiXact\SLRU buffers configuration Andrey M. Borodin <[email protected]>
2020-05-14 06:16 ` Re: MultiXact\SLRU buffers configuration Kyotaro Horiguchi <[email protected]>
2020-05-14 06:44 ` Re: MultiXact\SLRU buffers configuration Andrey M. Borodin <[email protected]>
2020-05-15 00:03 ` Re: MultiXact\SLRU buffers configuration Kyotaro Horiguchi <[email protected]>
2020-07-02 12:02 ` Re: MultiXact\SLRU buffers configuration Daniel Gustafsson <[email protected]>
2020-07-08 07:03 ` Re: MultiXact\SLRU buffers configuration Andrey M. Borodin <[email protected]>
2020-08-28 18:08 ` Re: MultiXact\SLRU buffers configuration Anastasia Lubennikova <[email protected]>
2020-09-28 14:41 ` Re: MultiXact\SLRU buffers configuration Andrey M. Borodin <[email protected]>
2020-10-26 01:05 ` Re: MultiXact\SLRU buffers configuration Alexander Korotkov <[email protected]>
2020-10-26 15:45 ` Re: MultiXact\SLRU buffers configuration Andrey Borodin <[email protected]>
2020-10-27 17:02 ` Re: MultiXact\SLRU buffers configuration Alexander Korotkov <[email protected]>
2020-10-27 17:23 ` Re: MultiXact\SLRU buffers configuration Alexander Korotkov <[email protected]>
2020-10-28 01:36 ` Re: MultiXact\SLRU buffers configuration Tomas Vondra <[email protected]>
2020-10-28 07:34 ` Re: MultiXact\SLRU buffers configuration Andrey Borodin <[email protected]>
2020-10-28 23:32 ` Re: MultiXact\SLRU buffers configuration Tomas Vondra <[email protected]>
2020-10-29 07:08 ` Re: MultiXact\SLRU buffers configuration Andrey Borodin <[email protected]>
2020-10-29 13:49 ` Re: MultiXact\SLRU buffers configuration Tomas Vondra <[email protected]>
2020-11-02 12:45 ` Re: MultiXact\SLRU buffers configuration Andrey Borodin <[email protected]>
2020-11-10 00:13 ` Re: MultiXact\SLRU buffers configuration Tomas Vondra <[email protected]>
2020-11-10 06:16 ` Re: MultiXact\SLRU buffers configuration Andrey Borodin <[email protected]>
2020-11-10 18:07 ` Re: MultiXact\SLRU buffers configuration Tomas Vondra <[email protected]>
2020-11-13 11:49 ` Re: MultiXact\SLRU buffers configuration Andrey Borodin <[email protected]>
2020-12-08 16:05 ` Re: MultiXact\SLRU buffers configuration Gilles Darold <[email protected]>
2020-12-08 17:52 ` Re: MultiXact\SLRU buffers configuration Andrey Borodin <[email protected]>
@ 2020-12-09 10:51 ` Gilles Darold <[email protected]>
2020-12-09 11:06 ` Re: MultiXact\SLRU buffers configuration Gilles Darold <[email protected]>
1 sibling, 1 reply; 90+ messages in thread
From: Gilles Darold @ 2020-12-09 10:51 UTC (permalink / raw)
To: Andrey Borodin <[email protected]>; +Cc: Tomas Vondra <[email protected]>; Tomas Vondra <[email protected]>; Alexander Korotkov <[email protected]>; Anastasia Lubennikova <[email protected]>; Daniel Gustafsson <[email protected]>; Kyotaro Horiguchi <[email protected]>; pgsql-hackers
Hi Andrey,
Thanks for the backport. I have issue with the first patch "Use shared
lock in GetMultiXactIdMembers for offsets and members"
(v1106-0001-Use-shared-lock-in-GetMultiXactIdMembers-for-o.patch) the
applications are not working anymore when I'm applying it. Also PG
regression tests are failing too on several part.
test insert_conflict ... ok
test create_function_1 ... FAILED
test create_type ... FAILED
test create_table ... FAILED
test create_function_2 ... FAILED
test copy ... FAILED
test copyselect ... ok
test copydml ... ok
test create_misc ... FAILED
test create_operator ... FAILED
test create_procedure ... ok
test create_index ... FAILED
test index_including ... ok
test create_view ... FAILED
test create_aggregate ... ok
test create_function_3 ... ok
test create_cast ... ok
test constraints ... FAILED
test triggers ... FAILED
test inherit ...
^C
This is also where I left my last try to back port for PG11, I will try
to fix it again but it could take time to have it working.
Best regards,
--
Gilles Darold
Le 08/12/2020 à 18:52, Andrey Borodin a écrit :
> Hi Gilles!
>
> Many thanks for your message!
>
>> 8 дек. 2020 г., в 21:05, Gilles Darold <[email protected]> написал(а):
>>
>> I know that this report is not really helpful
> Quite contrary - this benchmarks prove that controllable reproduction exists. I've rebased patches for PG11. Can you please benchmark them (without extending SLRU)?
>
> Best regards, Andrey Borodin.
>
^ permalink raw reply [nested|flat] 90+ messages in thread
* Re: MultiXact\SLRU buffers configuration
2020-05-08 16:36 MultiXact\SLRU buffers configuration Andrey M. Borodin <[email protected]>
2020-05-11 11:17 ` Re: MultiXact\SLRU buffers configuration Andrey M. Borodin <[email protected]>
2020-05-13 18:08 ` Re: MultiXact\SLRU buffers configuration Andrey M. Borodin <[email protected]>
2020-05-14 01:25 ` Re: MultiXact\SLRU buffers configuration Kyotaro Horiguchi <[email protected]>
2020-05-14 05:19 ` Re: MultiXact\SLRU buffers configuration Andrey M. Borodin <[email protected]>
2020-05-14 06:16 ` Re: MultiXact\SLRU buffers configuration Kyotaro Horiguchi <[email protected]>
2020-05-14 06:44 ` Re: MultiXact\SLRU buffers configuration Andrey M. Borodin <[email protected]>
2020-05-15 00:03 ` Re: MultiXact\SLRU buffers configuration Kyotaro Horiguchi <[email protected]>
2020-07-02 12:02 ` Re: MultiXact\SLRU buffers configuration Daniel Gustafsson <[email protected]>
2020-07-08 07:03 ` Re: MultiXact\SLRU buffers configuration Andrey M. Borodin <[email protected]>
2020-08-28 18:08 ` Re: MultiXact\SLRU buffers configuration Anastasia Lubennikova <[email protected]>
2020-09-28 14:41 ` Re: MultiXact\SLRU buffers configuration Andrey M. Borodin <[email protected]>
2020-10-26 01:05 ` Re: MultiXact\SLRU buffers configuration Alexander Korotkov <[email protected]>
2020-10-26 15:45 ` Re: MultiXact\SLRU buffers configuration Andrey Borodin <[email protected]>
2020-10-27 17:02 ` Re: MultiXact\SLRU buffers configuration Alexander Korotkov <[email protected]>
2020-10-27 17:23 ` Re: MultiXact\SLRU buffers configuration Alexander Korotkov <[email protected]>
2020-10-28 01:36 ` Re: MultiXact\SLRU buffers configuration Tomas Vondra <[email protected]>
2020-10-28 07:34 ` Re: MultiXact\SLRU buffers configuration Andrey Borodin <[email protected]>
2020-10-28 23:32 ` Re: MultiXact\SLRU buffers configuration Tomas Vondra <[email protected]>
2020-10-29 07:08 ` Re: MultiXact\SLRU buffers configuration Andrey Borodin <[email protected]>
2020-10-29 13:49 ` Re: MultiXact\SLRU buffers configuration Tomas Vondra <[email protected]>
2020-11-02 12:45 ` Re: MultiXact\SLRU buffers configuration Andrey Borodin <[email protected]>
2020-11-10 00:13 ` Re: MultiXact\SLRU buffers configuration Tomas Vondra <[email protected]>
2020-11-10 06:16 ` Re: MultiXact\SLRU buffers configuration Andrey Borodin <[email protected]>
2020-11-10 18:07 ` Re: MultiXact\SLRU buffers configuration Tomas Vondra <[email protected]>
2020-11-13 11:49 ` Re: MultiXact\SLRU buffers configuration Andrey Borodin <[email protected]>
2020-12-08 16:05 ` Re: MultiXact\SLRU buffers configuration Gilles Darold <[email protected]>
2020-12-08 17:52 ` Re: MultiXact\SLRU buffers configuration Andrey Borodin <[email protected]>
2020-12-09 10:51 ` Re: MultiXact\SLRU buffers configuration Gilles Darold <[email protected]>
@ 2020-12-09 11:06 ` Gilles Darold <[email protected]>
0 siblings, 0 replies; 90+ messages in thread
From: Gilles Darold @ 2020-12-09 11:06 UTC (permalink / raw)
To: Andrey Borodin <[email protected]>; +Cc: Tomas Vondra <[email protected]>; Tomas Vondra <[email protected]>; Alexander Korotkov <[email protected]>; Anastasia Lubennikova <[email protected]>; Daniel Gustafsson <[email protected]>; Kyotaro Horiguchi <[email protected]>; pgsql-hackers
Le 09/12/2020 à 11:51, Gilles Darold a écrit :
> Also PG regression tests are failing too on several part.
Forget this, I have not run the regression tests in the right repository:
...
=======================
All 189 tests passed.
=======================
I'm looking why the application is failing.
--
Gilles Darold
http://www.darold.net/
^ permalink raw reply [nested|flat] 90+ messages in thread
* Re: MultiXact\SLRU buffers configuration
2020-05-08 16:36 MultiXact\SLRU buffers configuration Andrey M. Borodin <[email protected]>
2020-05-11 11:17 ` Re: MultiXact\SLRU buffers configuration Andrey M. Borodin <[email protected]>
2020-05-13 18:08 ` Re: MultiXact\SLRU buffers configuration Andrey M. Borodin <[email protected]>
2020-05-14 01:25 ` Re: MultiXact\SLRU buffers configuration Kyotaro Horiguchi <[email protected]>
2020-05-14 05:19 ` Re: MultiXact\SLRU buffers configuration Andrey M. Borodin <[email protected]>
2020-05-14 06:16 ` Re: MultiXact\SLRU buffers configuration Kyotaro Horiguchi <[email protected]>
2020-05-14 06:44 ` Re: MultiXact\SLRU buffers configuration Andrey M. Borodin <[email protected]>
2020-05-15 00:03 ` Re: MultiXact\SLRU buffers configuration Kyotaro Horiguchi <[email protected]>
2020-07-02 12:02 ` Re: MultiXact\SLRU buffers configuration Daniel Gustafsson <[email protected]>
2020-07-08 07:03 ` Re: MultiXact\SLRU buffers configuration Andrey M. Borodin <[email protected]>
2020-08-28 18:08 ` Re: MultiXact\SLRU buffers configuration Anastasia Lubennikova <[email protected]>
2020-09-28 14:41 ` Re: MultiXact\SLRU buffers configuration Andrey M. Borodin <[email protected]>
2020-10-26 01:05 ` Re: MultiXact\SLRU buffers configuration Alexander Korotkov <[email protected]>
2020-10-26 15:45 ` Re: MultiXact\SLRU buffers configuration Andrey Borodin <[email protected]>
2020-10-27 17:02 ` Re: MultiXact\SLRU buffers configuration Alexander Korotkov <[email protected]>
2020-10-27 17:23 ` Re: MultiXact\SLRU buffers configuration Alexander Korotkov <[email protected]>
2020-10-28 01:36 ` Re: MultiXact\SLRU buffers configuration Tomas Vondra <[email protected]>
2020-10-28 07:34 ` Re: MultiXact\SLRU buffers configuration Andrey Borodin <[email protected]>
2020-10-28 23:32 ` Re: MultiXact\SLRU buffers configuration Tomas Vondra <[email protected]>
2020-10-29 07:08 ` Re: MultiXact\SLRU buffers configuration Andrey Borodin <[email protected]>
2020-10-29 13:49 ` Re: MultiXact\SLRU buffers configuration Tomas Vondra <[email protected]>
2020-11-02 12:45 ` Re: MultiXact\SLRU buffers configuration Andrey Borodin <[email protected]>
2020-11-10 00:13 ` Re: MultiXact\SLRU buffers configuration Tomas Vondra <[email protected]>
2020-11-10 06:16 ` Re: MultiXact\SLRU buffers configuration Andrey Borodin <[email protected]>
2020-11-10 18:07 ` Re: MultiXact\SLRU buffers configuration Tomas Vondra <[email protected]>
2020-11-13 11:49 ` Re: MultiXact\SLRU buffers configuration Andrey Borodin <[email protected]>
2020-12-08 16:05 ` Re: MultiXact\SLRU buffers configuration Gilles Darold <[email protected]>
2020-12-08 17:52 ` Re: MultiXact\SLRU buffers configuration Andrey Borodin <[email protected]>
@ 2020-12-10 14:45 ` Gilles Darold <[email protected]>
2020-12-11 17:50 ` Re: MultiXact\SLRU buffers configuration Gilles Darold <[email protected]>
1 sibling, 1 reply; 90+ messages in thread
From: Gilles Darold @ 2020-12-10 14:45 UTC (permalink / raw)
To: Andrey Borodin <[email protected]>; +Cc: Tomas Vondra <[email protected]>; Tomas Vondra <[email protected]>; Alexander Korotkov <[email protected]>; Anastasia Lubennikova <[email protected]>; Daniel Gustafsson <[email protected]>; Kyotaro Horiguchi <[email protected]>; pgsql-hackers
Le 08/12/2020 à 18:52, Andrey Borodin a écrit :
> Hi Gilles!
>
> Many thanks for your message!
>
>> 8 дек. 2020 г., в 21:05, Gilles Darold <[email protected]> написал(а):
>>
>> I know that this report is not really helpful
> Quite contrary - this benchmarks prove that controllable reproduction exists. I've rebased patches for PG11. Can you please benchmark them (without extending SLRU)?
>
> Best regards, Andrey Borodin.
>
Hi,
Running tests yesterday with the patches has reported log of failures
with error on INSERT and UPDATE statements:
ERROR: lock MultiXactOffsetControlLock is not held
After a patch review this morning I think I have found what's going
wrong. In patch
v6-0001-Use-shared-lock-in-GetMultiXactIdMembers-for-offs.patch I think
there is a missing reinitialisation of the lockmode variable to LW_NONE
inside the retry loop after the call to LWLockRelease() in
src/backend/access/transam/multixact.c:1392:GetMultiXactIdMembers().
I've attached a new version of the patch for master that include the fix
I'm using now with PG11 and with which everything works very well now.
I'm running more tests to see the impact on the performances to play
with multixact_offsets_slru_buffers, multixact_members_slru_buffers and
multixact_local_cache_entries. I will reports the results later today.
--
Gilles Darold
http://www.darold.net/
Attachments:
[text/x-patch] v7-0001-Use-shared-lock-in-GetMultiXactIdMembers-for-offs.patch (11.6K, ../../[email protected]/3-v7-0001-Use-shared-lock-in-GetMultiXactIdMembers-for-offs.patch)
download | inline diff:
diff --git a/src/backend/access/transam/clog.c b/src/backend/access/transam/clog.c
index 034349aa7b..4c372065de 100644
--- a/src/backend/access/transam/clog.c
+++ b/src/backend/access/transam/clog.c
@@ -640,10 +640,11 @@ TransactionIdGetStatus(TransactionId xid, XLogRecPtr *lsn)
int lsnindex;
char *byteptr;
XidStatus status;
+ LWLockMode lockmode = LW_NONE;
/* lock is acquired by SimpleLruReadPage_ReadOnly */
- slotno = SimpleLruReadPage_ReadOnly(XactCtl, pageno, xid);
+ slotno = SimpleLruReadPage_ReadOnly(XactCtl, pageno, xid, &lockmode);
byteptr = XactCtl->shared->page_buffer[slotno] + byteno;
status = (*byteptr >> bshift) & CLOG_XACT_BITMASK;
@@ -651,6 +652,7 @@ TransactionIdGetStatus(TransactionId xid, XLogRecPtr *lsn)
lsnindex = GetLSNIndex(slotno, xid);
*lsn = XactCtl->shared->group_lsn[lsnindex];
+ Assert(lockmode != LW_NONE);
LWLockRelease(XactSLRULock);
return status;
diff --git a/src/backend/access/transam/commit_ts.c b/src/backend/access/transam/commit_ts.c
index 2fe551f17e..2699de033d 100644
--- a/src/backend/access/transam/commit_ts.c
+++ b/src/backend/access/transam/commit_ts.c
@@ -288,6 +288,7 @@ TransactionIdGetCommitTsData(TransactionId xid, TimestampTz *ts,
CommitTimestampEntry entry;
TransactionId oldestCommitTsXid;
TransactionId newestCommitTsXid;
+ LWLockMode lockmode = LW_NONE;
if (!TransactionIdIsValid(xid))
ereport(ERROR,
@@ -342,7 +343,7 @@ TransactionIdGetCommitTsData(TransactionId xid, TimestampTz *ts,
}
/* lock is acquired by SimpleLruReadPage_ReadOnly */
- slotno = SimpleLruReadPage_ReadOnly(CommitTsCtl, pageno, xid);
+ slotno = SimpleLruReadPage_ReadOnly(CommitTsCtl, pageno, xid, &lockmode);
memcpy(&entry,
CommitTsCtl->shared->page_buffer[slotno] +
SizeOfCommitTimestampEntry * entryno,
@@ -352,6 +353,7 @@ TransactionIdGetCommitTsData(TransactionId xid, TimestampTz *ts,
if (nodeid)
*nodeid = entry.nodeid;
+ Assert(lockmode != LW_NONE);
LWLockRelease(CommitTsSLRULock);
return *ts != 0;
}
diff --git a/src/backend/access/transam/multixact.c b/src/backend/access/transam/multixact.c
index eb8de7cf32..56bdd04364 100644
--- a/src/backend/access/transam/multixact.c
+++ b/src/backend/access/transam/multixact.c
@@ -1237,6 +1237,7 @@ GetMultiXactIdMembers(MultiXactId multi, MultiXactMember **members,
MultiXactId tmpMXact;
MultiXactOffset nextOffset;
MultiXactMember *ptr;
+ LWLockMode lockmode = LW_NONE;
debug_elog3(DEBUG2, "GetMembers: asked for %u", multi);
@@ -1340,12 +1341,13 @@ GetMultiXactIdMembers(MultiXactId multi, MultiXactMember **members,
* time on every multixact creation.
*/
retry:
- LWLockAcquire(MultiXactOffsetSLRULock, LW_EXCLUSIVE);
pageno = MultiXactIdToOffsetPage(multi);
entryno = MultiXactIdToOffsetEntry(multi);
- slotno = SimpleLruReadPage(MultiXactOffsetCtl, pageno, true, multi);
+ /* lock is acquired by SimpleLruReadPage_ReadOnly */
+ slotno = SimpleLruReadPage_ReadOnly(MultiXactOffsetCtl, pageno,
+ multi, &lockmode);
offptr = (MultiXactOffset *) MultiXactOffsetCtl->shared->page_buffer[slotno];
offptr += entryno;
offset = *offptr;
@@ -1377,7 +1379,8 @@ retry:
entryno = MultiXactIdToOffsetEntry(tmpMXact);
if (pageno != prev_pageno)
- slotno = SimpleLruReadPage(MultiXactOffsetCtl, pageno, true, tmpMXact);
+ slotno = SimpleLruReadPage_ReadOnly(MultiXactOffsetCtl, pageno,
+ tmpMXact, &lockmode);
offptr = (MultiXactOffset *) MultiXactOffsetCtl->shared->page_buffer[slotno];
offptr += entryno;
@@ -1387,6 +1390,7 @@ retry:
{
/* Corner case 2: next multixact is still being filled in */
LWLockRelease(MultiXactOffsetSLRULock);
+ lockmode = LW_NONE;
CHECK_FOR_INTERRUPTS();
pg_usleep(1000L);
goto retry;
@@ -1395,14 +1399,14 @@ retry:
length = nextMXOffset - offset;
}
+ Assert(lockmode != LW_NONE);
LWLockRelease(MultiXactOffsetSLRULock);
ptr = (MultiXactMember *) palloc(length * sizeof(MultiXactMember));
*members = ptr;
/* Now get the members themselves. */
- LWLockAcquire(MultiXactMemberSLRULock, LW_EXCLUSIVE);
-
+ lockmode = LW_NONE;
truelength = 0;
prev_pageno = -1;
for (i = 0; i < length; i++, offset++)
@@ -1418,7 +1422,8 @@ retry:
if (pageno != prev_pageno)
{
- slotno = SimpleLruReadPage(MultiXactMemberCtl, pageno, true, multi);
+ slotno = SimpleLruReadPage_ReadOnly(MultiXactMemberCtl, pageno,
+ multi, &lockmode);
prev_pageno = pageno;
}
@@ -1441,6 +1446,7 @@ retry:
truelength++;
}
+ Assert(lockmode != LW_NONE);
LWLockRelease(MultiXactMemberSLRULock);
/*
@@ -2733,6 +2739,7 @@ find_multixact_start(MultiXactId multi, MultiXactOffset *result)
int entryno;
int slotno;
MultiXactOffset *offptr;
+ LWLockMode lockmode = LW_NONE;
Assert(MultiXactState->finishedStartup);
@@ -2749,10 +2756,12 @@ find_multixact_start(MultiXactId multi, MultiXactOffset *result)
return false;
/* lock is acquired by SimpleLruReadPage_ReadOnly */
- slotno = SimpleLruReadPage_ReadOnly(MultiXactOffsetCtl, pageno, multi);
+ slotno = SimpleLruReadPage_ReadOnly(MultiXactOffsetCtl, pageno,
+ multi, &lockmode);
offptr = (MultiXactOffset *) MultiXactOffsetCtl->shared->page_buffer[slotno];
offptr += entryno;
offset = *offptr;
+ Assert(lockmode != LW_NONE);
LWLockRelease(MultiXactOffsetSLRULock);
*result = offset;
diff --git a/src/backend/access/transam/slru.c b/src/backend/access/transam/slru.c
index cec17cb2ae..e271b37d7b 100644
--- a/src/backend/access/transam/slru.c
+++ b/src/backend/access/transam/slru.c
@@ -487,17 +487,23 @@ SimpleLruReadPage(SlruCtl ctl, int pageno, bool write_ok,
* Return value is the shared-buffer slot number now holding the page.
* The buffer's LRU access info is updated.
*
- * Control lock must NOT be held at entry, but will be held at exit.
- * It is unspecified whether the lock will be shared or exclusive.
+ * Control lock must be held in *lock_mode mode, which may be LW_NONE. Control
+ * lock will be held at exit in at least shared mode. Resulting control lock
+ * mode is set to *lock_mode.
*/
int
-SimpleLruReadPage_ReadOnly(SlruCtl ctl, int pageno, TransactionId xid)
+SimpleLruReadPage_ReadOnly(SlruCtl ctl, int pageno, TransactionId xid,
+ LWLockMode *lock_mode)
{
SlruShared shared = ctl->shared;
int slotno;
/* Try to find the page while holding only shared lock */
- LWLockAcquire(shared->ControlLock, LW_SHARED);
+ if (*lock_mode == LW_NONE)
+ {
+ LWLockAcquire(shared->ControlLock, LW_SHARED);
+ *lock_mode = LW_SHARED;
+ }
/* See if page is already in a buffer */
for (slotno = 0; slotno < shared->num_slots; slotno++)
@@ -517,8 +523,13 @@ SimpleLruReadPage_ReadOnly(SlruCtl ctl, int pageno, TransactionId xid)
}
/* No luck, so switch to normal exclusive lock and do regular read */
- LWLockRelease(shared->ControlLock);
- LWLockAcquire(shared->ControlLock, LW_EXCLUSIVE);
+ if (*lock_mode != LW_EXCLUSIVE)
+ {
+ Assert(*lock_mode == LW_NONE);
+ LWLockRelease(shared->ControlLock);
+ LWLockAcquire(shared->ControlLock, LW_EXCLUSIVE);
+ *lock_mode = LW_EXCLUSIVE;
+ }
return SimpleLruReadPage(ctl, pageno, true, xid);
}
diff --git a/src/backend/access/transam/subtrans.c b/src/backend/access/transam/subtrans.c
index 0111e867c7..7bb1543189 100644
--- a/src/backend/access/transam/subtrans.c
+++ b/src/backend/access/transam/subtrans.c
@@ -113,6 +113,7 @@ SubTransGetParent(TransactionId xid)
int slotno;
TransactionId *ptr;
TransactionId parent;
+ LWLockMode lockmode = LW_NONE;
/* Can't ask about stuff that might not be around anymore */
Assert(TransactionIdFollowsOrEquals(xid, TransactionXmin));
@@ -123,12 +124,13 @@ SubTransGetParent(TransactionId xid)
/* lock is acquired by SimpleLruReadPage_ReadOnly */
- slotno = SimpleLruReadPage_ReadOnly(SubTransCtl, pageno, xid);
+ slotno = SimpleLruReadPage_ReadOnly(SubTransCtl, pageno, xid, &lockmode);
ptr = (TransactionId *) SubTransCtl->shared->page_buffer[slotno];
ptr += entryno;
parent = *ptr;
+ Assert(lockmode != LW_NONE);
LWLockRelease(SubtransSLRULock);
return parent;
diff --git a/src/backend/commands/async.c b/src/backend/commands/async.c
index c0763c63e2..ef1dbbe53d 100644
--- a/src/backend/commands/async.c
+++ b/src/backend/commands/async.c
@@ -2011,6 +2011,7 @@ asyncQueueReadAllNotifications(void)
int curoffset = QUEUE_POS_OFFSET(pos);
int slotno;
int copysize;
+ LWLockMode lockmode = LW_NONE;
/*
* We copy the data from SLRU into a local buffer, so as to avoid
@@ -2019,7 +2020,7 @@ asyncQueueReadAllNotifications(void)
* part of the page we will actually inspect.
*/
slotno = SimpleLruReadPage_ReadOnly(NotifyCtl, curpage,
- InvalidTransactionId);
+ InvalidTransactionId, &lockmode);
if (curpage == QUEUE_POS_PAGE(head))
{
/* we only want to read as far as head */
@@ -2036,6 +2037,7 @@ asyncQueueReadAllNotifications(void)
NotifyCtl->shared->page_buffer[slotno] + curoffset,
copysize);
/* Release lock that we got from SimpleLruReadPage_ReadOnly() */
+ Assert(lockmode != LW_NONE);
LWLockRelease(NotifySLRULock);
/*
diff --git a/src/backend/storage/lmgr/lwlock.c b/src/backend/storage/lmgr/lwlock.c
index 108e652179..ad1dcc7140 100644
--- a/src/backend/storage/lmgr/lwlock.c
+++ b/src/backend/storage/lmgr/lwlock.c
@@ -1067,6 +1067,8 @@ LWLockWakeup(LWLock *lock)
static void
LWLockQueueSelf(LWLock *lock, LWLockMode mode)
{
+ Assert(mode != LW_NONE);
+
/*
* If we don't have a PGPROC structure, there's no way to wait. This
* should never occur, since MyProc should only be null during shared
@@ -1827,6 +1829,7 @@ LWLockRelease(LWLock *lock)
elog(ERROR, "lock %s is not held", T_NAME(lock));
mode = held_lwlocks[i].mode;
+ Assert(mode == LW_EXCLUSIVE || mode == LW_SHARED);
num_held_lwlocks--;
for (; i < num_held_lwlocks; i++)
diff --git a/src/backend/storage/lmgr/predicate.c b/src/backend/storage/lmgr/predicate.c
index 8a365b400c..a4df90a8ae 100644
--- a/src/backend/storage/lmgr/predicate.c
+++ b/src/backend/storage/lmgr/predicate.c
@@ -924,6 +924,7 @@ SerialGetMinConflictCommitSeqNo(TransactionId xid)
TransactionId tailXid;
SerCommitSeqNo val;
int slotno;
+ LWLockMode lockmode = LW_NONE;
Assert(TransactionIdIsValid(xid));
@@ -946,8 +947,9 @@ SerialGetMinConflictCommitSeqNo(TransactionId xid)
* but will return with that lock held, which must then be released.
*/
slotno = SimpleLruReadPage_ReadOnly(SerialSlruCtl,
- SerialPage(xid), xid);
+ SerialPage(xid), xid, &lockmode);
val = SerialValue(slotno, xid);
+ Assert(lockmode != LW_NONE);
LWLockRelease(SerialSLRULock);
return val;
}
diff --git a/src/include/access/slru.h b/src/include/access/slru.h
index b39b43504d..4b66d3b592 100644
--- a/src/include/access/slru.h
+++ b/src/include/access/slru.h
@@ -142,7 +142,7 @@ extern int SimpleLruZeroPage(SlruCtl ctl, int pageno);
extern int SimpleLruReadPage(SlruCtl ctl, int pageno, bool write_ok,
TransactionId xid);
extern int SimpleLruReadPage_ReadOnly(SlruCtl ctl, int pageno,
- TransactionId xid);
+ TransactionId xid, LWLockMode *lock_mode);
extern void SimpleLruWritePage(SlruCtl ctl, int slotno);
extern void SimpleLruWriteAll(SlruCtl ctl, bool allow_redirtied);
extern void SimpleLruTruncate(SlruCtl ctl, int cutoffPage);
diff --git a/src/include/storage/lwlock.h b/src/include/storage/lwlock.h
index af9b41795d..e680c6397a 100644
--- a/src/include/storage/lwlock.h
+++ b/src/include/storage/lwlock.h
@@ -129,6 +129,8 @@ extern PGDLLIMPORT int NamedLWLockTrancheRequests;
typedef enum LWLockMode
{
+ LW_NONE, /* Not a lock mode. Indicates that there is no
+ * lock. */
LW_EXCLUSIVE,
LW_SHARED,
LW_WAIT_UNTIL_FREE /* A special mode used in PGPROC->lwWaitMode,
^ permalink raw reply [nested|flat] 90+ messages in thread
* Re: MultiXact\SLRU buffers configuration
2020-05-08 16:36 MultiXact\SLRU buffers configuration Andrey M. Borodin <[email protected]>
2020-05-11 11:17 ` Re: MultiXact\SLRU buffers configuration Andrey M. Borodin <[email protected]>
2020-05-13 18:08 ` Re: MultiXact\SLRU buffers configuration Andrey M. Borodin <[email protected]>
2020-05-14 01:25 ` Re: MultiXact\SLRU buffers configuration Kyotaro Horiguchi <[email protected]>
2020-05-14 05:19 ` Re: MultiXact\SLRU buffers configuration Andrey M. Borodin <[email protected]>
2020-05-14 06:16 ` Re: MultiXact\SLRU buffers configuration Kyotaro Horiguchi <[email protected]>
2020-05-14 06:44 ` Re: MultiXact\SLRU buffers configuration Andrey M. Borodin <[email protected]>
2020-05-15 00:03 ` Re: MultiXact\SLRU buffers configuration Kyotaro Horiguchi <[email protected]>
2020-07-02 12:02 ` Re: MultiXact\SLRU buffers configuration Daniel Gustafsson <[email protected]>
2020-07-08 07:03 ` Re: MultiXact\SLRU buffers configuration Andrey M. Borodin <[email protected]>
2020-08-28 18:08 ` Re: MultiXact\SLRU buffers configuration Anastasia Lubennikova <[email protected]>
2020-09-28 14:41 ` Re: MultiXact\SLRU buffers configuration Andrey M. Borodin <[email protected]>
2020-10-26 01:05 ` Re: MultiXact\SLRU buffers configuration Alexander Korotkov <[email protected]>
2020-10-26 15:45 ` Re: MultiXact\SLRU buffers configuration Andrey Borodin <[email protected]>
2020-10-27 17:02 ` Re: MultiXact\SLRU buffers configuration Alexander Korotkov <[email protected]>
2020-10-27 17:23 ` Re: MultiXact\SLRU buffers configuration Alexander Korotkov <[email protected]>
2020-10-28 01:36 ` Re: MultiXact\SLRU buffers configuration Tomas Vondra <[email protected]>
2020-10-28 07:34 ` Re: MultiXact\SLRU buffers configuration Andrey Borodin <[email protected]>
2020-10-28 23:32 ` Re: MultiXact\SLRU buffers configuration Tomas Vondra <[email protected]>
2020-10-29 07:08 ` Re: MultiXact\SLRU buffers configuration Andrey Borodin <[email protected]>
2020-10-29 13:49 ` Re: MultiXact\SLRU buffers configuration Tomas Vondra <[email protected]>
2020-11-02 12:45 ` Re: MultiXact\SLRU buffers configuration Andrey Borodin <[email protected]>
2020-11-10 00:13 ` Re: MultiXact\SLRU buffers configuration Tomas Vondra <[email protected]>
2020-11-10 06:16 ` Re: MultiXact\SLRU buffers configuration Andrey Borodin <[email protected]>
2020-11-10 18:07 ` Re: MultiXact\SLRU buffers configuration Tomas Vondra <[email protected]>
2020-11-13 11:49 ` Re: MultiXact\SLRU buffers configuration Andrey Borodin <[email protected]>
2020-12-08 16:05 ` Re: MultiXact\SLRU buffers configuration Gilles Darold <[email protected]>
2020-12-08 17:52 ` Re: MultiXact\SLRU buffers configuration Andrey Borodin <[email protected]>
2020-12-10 14:45 ` Re: MultiXact\SLRU buffers configuration Gilles Darold <[email protected]>
@ 2020-12-11 17:50 ` Gilles Darold <[email protected]>
2020-12-13 09:17 ` Re: MultiXact\SLRU buffers configuration Gilles Darold <[email protected]>
0 siblings, 1 reply; 90+ messages in thread
From: Gilles Darold @ 2020-12-11 17:50 UTC (permalink / raw)
To: Andrey Borodin <[email protected]>; +Cc: Tomas Vondra <[email protected]>; Tomas Vondra <[email protected]>; Alexander Korotkov <[email protected]>; Anastasia Lubennikova <[email protected]>; Daniel Gustafsson <[email protected]>; Kyotaro Horiguchi <[email protected]>; pgsql-hackers
Le 10/12/2020 à 15:45, Gilles Darold a écrit :
> Le 08/12/2020 à 18:52, Andrey Borodin a écrit :
>> Hi Gilles!
>>
>> Many thanks for your message!
>>
>>> 8 дек. 2020 г., в 21:05, Gilles Darold<[email protected]> написал(а):
>>>
>>> I know that this report is not really helpful
>> Quite contrary - this benchmarks prove that controllable reproduction exists. I've rebased patches for PG11. Can you please benchmark them (without extending SLRU)?
>>
>> Best regards, Andrey Borodin.
>>
> Hi,
>
>
> Running tests yesterday with the patches has reported log of failures
> with error on INSERT and UPDATE statements:
>
>
> ERROR: lock MultiXactOffsetControlLock is not held
>
>
> After a patch review this morning I think I have found what's going
> wrong. In patch
> v6-0001-Use-shared-lock-in-GetMultiXactIdMembers-for-offs.patch I
> think there is a missing reinitialisation of the lockmode variable to
> LW_NONE inside the retry loop after the call to LWLockRelease() in
> src/backend/access/transam/multixact.c:1392:GetMultiXactIdMembers().
> I've attached a new version of the patch for master that include the
> fix I'm using now with PG11 and with which everything works very well now.
>
>
> I'm running more tests to see the impact on the performances to play
> with multixact_offsets_slru_buffers, multixact_members_slru_buffers
> and multixact_local_cache_entries. I will reports the results later today.
>
Hi,
Sorry for the delay, I have done some further tests to try to reach the
limit without bottlenecks on multixact or shared buffers. The tests was
done on a Microsoft Asure machine with 2TB of RAM and 4 sockets Intel
Xeon Platinum 8280M (128 cpu). PG configuration:
max_connections = 4096
shared_buffers = 64GB
max_prepared_transactions = 2048
work_mem = 256MB
maintenance_work_mem = 2GB
wal_level = minimal
synchronous_commit = off
commit_delay = 1000
commit_siblings = 10
checkpoint_timeout = 1h
max_wal_size = 32GB
checkpoint_completion_target = 0.9
I have tested with several values for the different buffer's variables
starting from:
multixact_offsets_slru_buffers = 64
multixact_members_slru_buffers = 128
multixact_local_cache_entries = 256
to the values with the best performances we achieve with this test to
avoid MultiXactOffsetControlLock or MultiXactMemberControlLock:
multixact_offsets_slru_buffers = 128
multixact_members_slru_buffers = 512
multixact_local_cache_entries = 1024
Also shared_buffers have been increased up to 256GB to avoid
buffer_mapping contention.
Our last best test reports the following wait events:
event_type | event | sum
------------+----------------------------+-----------
Client | ClientRead | 321690211
LWLock | buffer_content | 2970016
IPC | ProcArrayGroupUpdate | 2317388
LWLock | ProcArrayLock | 1445828
LWLock | WALWriteLock | 1187606
LWLock | SubtransControlLock | 972889
Lock | transactionid | 840560
Lock | relation | 587600
Activity | LogicalLauncherMain | 529599
Activity | AutoVacuumMain | 528097
At this stage I don't think we can have better performances by tuning
these buffers at least with PG11.
About performances gain related to the patch for shared lock in
GetMultiXactIdMembers unfortunately I can not see a difference with or
without this patch, it could be related to our particular benchmark. But
clearly the patch on multixact buffers should be committed as this is
really helpfull to be able to tuned PG when multixact bottlenecks are found.
Best regards,
--
Gilles Darold
LzLabs GmbH
https://www.lzlabs.com/
^ permalink raw reply [nested|flat] 90+ messages in thread
* Re: MultiXact\SLRU buffers configuration
2020-05-08 16:36 MultiXact\SLRU buffers configuration Andrey M. Borodin <[email protected]>
2020-05-11 11:17 ` Re: MultiXact\SLRU buffers configuration Andrey M. Borodin <[email protected]>
2020-05-13 18:08 ` Re: MultiXact\SLRU buffers configuration Andrey M. Borodin <[email protected]>
2020-05-14 01:25 ` Re: MultiXact\SLRU buffers configuration Kyotaro Horiguchi <[email protected]>
2020-05-14 05:19 ` Re: MultiXact\SLRU buffers configuration Andrey M. Borodin <[email protected]>
2020-05-14 06:16 ` Re: MultiXact\SLRU buffers configuration Kyotaro Horiguchi <[email protected]>
2020-05-14 06:44 ` Re: MultiXact\SLRU buffers configuration Andrey M. Borodin <[email protected]>
2020-05-15 00:03 ` Re: MultiXact\SLRU buffers configuration Kyotaro Horiguchi <[email protected]>
2020-07-02 12:02 ` Re: MultiXact\SLRU buffers configuration Daniel Gustafsson <[email protected]>
2020-07-08 07:03 ` Re: MultiXact\SLRU buffers configuration Andrey M. Borodin <[email protected]>
2020-08-28 18:08 ` Re: MultiXact\SLRU buffers configuration Anastasia Lubennikova <[email protected]>
2020-09-28 14:41 ` Re: MultiXact\SLRU buffers configuration Andrey M. Borodin <[email protected]>
2020-10-26 01:05 ` Re: MultiXact\SLRU buffers configuration Alexander Korotkov <[email protected]>
2020-10-26 15:45 ` Re: MultiXact\SLRU buffers configuration Andrey Borodin <[email protected]>
2020-10-27 17:02 ` Re: MultiXact\SLRU buffers configuration Alexander Korotkov <[email protected]>
2020-10-27 17:23 ` Re: MultiXact\SLRU buffers configuration Alexander Korotkov <[email protected]>
2020-10-28 01:36 ` Re: MultiXact\SLRU buffers configuration Tomas Vondra <[email protected]>
2020-10-28 07:34 ` Re: MultiXact\SLRU buffers configuration Andrey Borodin <[email protected]>
2020-10-28 23:32 ` Re: MultiXact\SLRU buffers configuration Tomas Vondra <[email protected]>
2020-10-29 07:08 ` Re: MultiXact\SLRU buffers configuration Andrey Borodin <[email protected]>
2020-10-29 13:49 ` Re: MultiXact\SLRU buffers configuration Tomas Vondra <[email protected]>
2020-11-02 12:45 ` Re: MultiXact\SLRU buffers configuration Andrey Borodin <[email protected]>
2020-11-10 00:13 ` Re: MultiXact\SLRU buffers configuration Tomas Vondra <[email protected]>
2020-11-10 06:16 ` Re: MultiXact\SLRU buffers configuration Andrey Borodin <[email protected]>
2020-11-10 18:07 ` Re: MultiXact\SLRU buffers configuration Tomas Vondra <[email protected]>
2020-11-13 11:49 ` Re: MultiXact\SLRU buffers configuration Andrey Borodin <[email protected]>
2020-12-08 16:05 ` Re: MultiXact\SLRU buffers configuration Gilles Darold <[email protected]>
2020-12-08 17:52 ` Re: MultiXact\SLRU buffers configuration Andrey Borodin <[email protected]>
2020-12-10 14:45 ` Re: MultiXact\SLRU buffers configuration Gilles Darold <[email protected]>
2020-12-11 17:50 ` Re: MultiXact\SLRU buffers configuration Gilles Darold <[email protected]>
@ 2020-12-13 09:17 ` Gilles Darold <[email protected]>
2020-12-13 17:24 ` Re: MultiXact\SLRU buffers configuration Andrey Borodin <[email protected]>
0 siblings, 1 reply; 90+ messages in thread
From: Gilles Darold @ 2020-12-13 09:17 UTC (permalink / raw)
To: Andrey Borodin <[email protected]>; +Cc: Tomas Vondra <[email protected]>; Tomas Vondra <[email protected]>; Alexander Korotkov <[email protected]>; Anastasia Lubennikova <[email protected]>; Daniel Gustafsson <[email protected]>; Kyotaro Horiguchi <[email protected]>; pgsql-hackers
Le 11/12/2020 à 18:50, Gilles Darold a écrit :
> Le 10/12/2020 à 15:45, Gilles Darold a écrit :
>> Le 08/12/2020 à 18:52, Andrey Borodin a écrit :
>>> Hi Gilles!
>>>
>>> Many thanks for your message!
>>>
>>>> 8 дек. 2020 г., в 21:05, Gilles Darold <[email protected]> написал(а):
>>>>
>>>> I know that this report is not really helpful
>>> Quite contrary - this benchmarks prove that controllable reproduction exists. I've rebased patches for PG11. Can you please benchmark them (without extending SLRU)?
>>>
>>> Best regards, Andrey Borodin.
>>>
>> Hi,
>>
>>
>> Running tests yesterday with the patches has reported log of failures
>> with error on INSERT and UPDATE statements:
>>
>>
>> ERROR: lock MultiXactOffsetControlLock is not held
>>
>>
>> After a patch review this morning I think I have found what's going
>> wrong. In patch
>> v6-0001-Use-shared-lock-in-GetMultiXactIdMembers-for-offs.patch I
>> think there is a missing reinitialisation of the lockmode variable to
>> LW_NONE inside the retry loop after the call to LWLockRelease() in
>> src/backend/access/transam/multixact.c:1392:GetMultiXactIdMembers().
>> I've attached a new version of the patch for master that include the
>> fix I'm using now with PG11 and with which everything works very well
>> now.
>>
>>
>> I'm running more tests to see the impact on the performances to play
>> with multixact_offsets_slru_buffers, multixact_members_slru_buffers
>> and multixact_local_cache_entries. I will reports the results later
>> today.
>>
>
> Hi,
>
> Sorry for the delay, I have done some further tests to try to reach
> the limit without bottlenecks on multixact or shared buffers. The
> tests was done on a Microsoft Asure machine with 2TB of RAM and 4
> sockets Intel Xeon Platinum 8280M (128 cpu). PG configuration:
>
> max_connections = 4096
> shared_buffers = 64GB
> max_prepared_transactions = 2048
> work_mem = 256MB
> maintenance_work_mem = 2GB
> wal_level = minimal
> synchronous_commit = off
> commit_delay = 1000
> commit_siblings = 10
> checkpoint_timeout = 1h
> max_wal_size = 32GB
> checkpoint_completion_target = 0.9
>
> I have tested with several values for the different buffer's variables
> starting from:
>
> multixact_offsets_slru_buffers = 64
> multixact_members_slru_buffers = 128
> multixact_local_cache_entries = 256
>
> to the values with the best performances we achieve with this test to
> avoid MultiXactOffsetControlLock or MultiXactMemberControlLock:
>
> multixact_offsets_slru_buffers = 128
> multixact_members_slru_buffers = 512
> multixact_local_cache_entries = 1024
>
> Also shared_buffers have been increased up to 256GB to avoid
> buffer_mapping contention.
>
> Our last best test reports the following wait events:
>
> event_type | event | sum
> ------------+----------------------------+-----------
> Client | ClientRead | 321690211
> LWLock | buffer_content | 2970016
> IPC | ProcArrayGroupUpdate | 2317388
> LWLock | ProcArrayLock | 1445828
> LWLock | WALWriteLock | 1187606
> LWLock | SubtransControlLock | 972889
> Lock | transactionid | 840560
> Lock | relation | 587600
> Activity | LogicalLauncherMain | 529599
> Activity | AutoVacuumMain | 528097
>
> At this stage I don't think we can have better performances by tuning
> these buffers at least with PG11.
>
> About performances gain related to the patch for shared lock in
> GetMultiXactIdMembers unfortunately I can not see a difference with or
> without this patch, it could be related to our particular benchmark.
> But clearly the patch on multixact buffers should be committed as this
> is really helpfull to be able to tuned PG when multixact bottlenecks
> are found.
I've done more review on these patches.
1) as reported in my previous message patch 0001 looks useless as it
doesn't allow measurable performances gain.
2) In patch 0004 there is two typo: s/informaion/information/ will fix them
3) the GUC are missing in the postgresql.conf.sample file, see patch in
attachment for a proposal.
Best regards,
--
Gilles Darold
LzLabs GmbH
https://www.lzlabs.com/
Attachments:
[text/x-patch] postgresql_conf_multixact_buffers_GUCs.patch (819B, ../../[email protected]/3-postgresql_conf_multixact_buffers_GUCs.patch)
download | inline diff:
diff --git a/src/backend/utils/misc/postgresql.conf.sample b/src/backend/utils/misc/postgresql.conf.sample
index b7fb2ec1fe..1fb33809ee 100644
--- a/src/backend/utils/misc/postgresql.conf.sample
+++ b/src/backend/utils/misc/postgresql.conf.sample
@@ -189,6 +189,14 @@
# (change requires restart)
#backend_flush_after = 0 # measured in pages, 0 disables
+# - MultiXact Buffers -
+
+#multixact_offsets_slru_buffers = 8 # memory used for MultiXact offsets
+ # (change requires restart)
+#multixact_members_slru_buffers = 16 # memory used for MultiXact members
+ # (change requires restart)
+#multixact_local_cache_entries = 256 # number of cached MultiXact by backend
+ # (change requires restart)
#------------------------------------------------------------------------------
# WRITE-AHEAD LOG
^ permalink raw reply [nested|flat] 90+ messages in thread
* Re: MultiXact\SLRU buffers configuration
2020-05-08 16:36 MultiXact\SLRU buffers configuration Andrey M. Borodin <[email protected]>
2020-05-11 11:17 ` Re: MultiXact\SLRU buffers configuration Andrey M. Borodin <[email protected]>
2020-05-13 18:08 ` Re: MultiXact\SLRU buffers configuration Andrey M. Borodin <[email protected]>
2020-05-14 01:25 ` Re: MultiXact\SLRU buffers configuration Kyotaro Horiguchi <[email protected]>
2020-05-14 05:19 ` Re: MultiXact\SLRU buffers configuration Andrey M. Borodin <[email protected]>
2020-05-14 06:16 ` Re: MultiXact\SLRU buffers configuration Kyotaro Horiguchi <[email protected]>
2020-05-14 06:44 ` Re: MultiXact\SLRU buffers configuration Andrey M. Borodin <[email protected]>
2020-05-15 00:03 ` Re: MultiXact\SLRU buffers configuration Kyotaro Horiguchi <[email protected]>
2020-07-02 12:02 ` Re: MultiXact\SLRU buffers configuration Daniel Gustafsson <[email protected]>
2020-07-08 07:03 ` Re: MultiXact\SLRU buffers configuration Andrey M. Borodin <[email protected]>
2020-08-28 18:08 ` Re: MultiXact\SLRU buffers configuration Anastasia Lubennikova <[email protected]>
2020-09-28 14:41 ` Re: MultiXact\SLRU buffers configuration Andrey M. Borodin <[email protected]>
2020-10-26 01:05 ` Re: MultiXact\SLRU buffers configuration Alexander Korotkov <[email protected]>
2020-10-26 15:45 ` Re: MultiXact\SLRU buffers configuration Andrey Borodin <[email protected]>
2020-10-27 17:02 ` Re: MultiXact\SLRU buffers configuration Alexander Korotkov <[email protected]>
2020-10-27 17:23 ` Re: MultiXact\SLRU buffers configuration Alexander Korotkov <[email protected]>
2020-10-28 01:36 ` Re: MultiXact\SLRU buffers configuration Tomas Vondra <[email protected]>
2020-10-28 07:34 ` Re: MultiXact\SLRU buffers configuration Andrey Borodin <[email protected]>
2020-10-28 23:32 ` Re: MultiXact\SLRU buffers configuration Tomas Vondra <[email protected]>
2020-10-29 07:08 ` Re: MultiXact\SLRU buffers configuration Andrey Borodin <[email protected]>
2020-10-29 13:49 ` Re: MultiXact\SLRU buffers configuration Tomas Vondra <[email protected]>
2020-11-02 12:45 ` Re: MultiXact\SLRU buffers configuration Andrey Borodin <[email protected]>
2020-11-10 00:13 ` Re: MultiXact\SLRU buffers configuration Tomas Vondra <[email protected]>
2020-11-10 06:16 ` Re: MultiXact\SLRU buffers configuration Andrey Borodin <[email protected]>
2020-11-10 18:07 ` Re: MultiXact\SLRU buffers configuration Tomas Vondra <[email protected]>
2020-11-13 11:49 ` Re: MultiXact\SLRU buffers configuration Andrey Borodin <[email protected]>
2020-12-08 16:05 ` Re: MultiXact\SLRU buffers configuration Gilles Darold <[email protected]>
2020-12-08 17:52 ` Re: MultiXact\SLRU buffers configuration Andrey Borodin <[email protected]>
2020-12-10 14:45 ` Re: MultiXact\SLRU buffers configuration Gilles Darold <[email protected]>
2020-12-11 17:50 ` Re: MultiXact\SLRU buffers configuration Gilles Darold <[email protected]>
2020-12-13 09:17 ` Re: MultiXact\SLRU buffers configuration Gilles Darold <[email protected]>
@ 2020-12-13 17:24 ` Andrey Borodin <[email protected]>
2020-12-14 06:31 ` Re: MultiXact\SLRU buffers configuration Andrey Borodin <[email protected]>
2020-12-23 16:31 ` Re: MultiXact\SLRU buffers configuration Gilles Darold <[email protected]>
0 siblings, 2 replies; 90+ messages in thread
From: Andrey Borodin @ 2020-12-13 17:24 UTC (permalink / raw)
To: Gilles Darold <[email protected]>; +Cc: Tomas Vondra <[email protected]>; Tomas Vondra <[email protected]>; Alexander Korotkov <[email protected]>; Anastasia Lubennikova <[email protected]>; Daniel Gustafsson <[email protected]>; Kyotaro Horiguchi <[email protected]>; pgsql-hackers
> 13 дек. 2020 г., в 14:17, Gilles Darold <[email protected]> написал(а):
>
> I've done more review on these patches.
Thanks, Gilles! I'll incorporate all your fixes to patchset.
Can you also benchmark conditional variable sleep? The patch "Add conditional variable to wait for next MultXact offset in corner case"?
The problem manifests on Standby when Primary is heavily loaded with MultiXactOffsetControlLock.
Thanks!
Best regards, Andrey Borodin.
^ permalink raw reply [nested|flat] 90+ messages in thread
* Re: MultiXact\SLRU buffers configuration
2020-05-08 16:36 MultiXact\SLRU buffers configuration Andrey M. Borodin <[email protected]>
2020-05-11 11:17 ` Re: MultiXact\SLRU buffers configuration Andrey M. Borodin <[email protected]>
2020-05-13 18:08 ` Re: MultiXact\SLRU buffers configuration Andrey M. Borodin <[email protected]>
2020-05-14 01:25 ` Re: MultiXact\SLRU buffers configuration Kyotaro Horiguchi <[email protected]>
2020-05-14 05:19 ` Re: MultiXact\SLRU buffers configuration Andrey M. Borodin <[email protected]>
2020-05-14 06:16 ` Re: MultiXact\SLRU buffers configuration Kyotaro Horiguchi <[email protected]>
2020-05-14 06:44 ` Re: MultiXact\SLRU buffers configuration Andrey M. Borodin <[email protected]>
2020-05-15 00:03 ` Re: MultiXact\SLRU buffers configuration Kyotaro Horiguchi <[email protected]>
2020-07-02 12:02 ` Re: MultiXact\SLRU buffers configuration Daniel Gustafsson <[email protected]>
2020-07-08 07:03 ` Re: MultiXact\SLRU buffers configuration Andrey M. Borodin <[email protected]>
2020-08-28 18:08 ` Re: MultiXact\SLRU buffers configuration Anastasia Lubennikova <[email protected]>
2020-09-28 14:41 ` Re: MultiXact\SLRU buffers configuration Andrey M. Borodin <[email protected]>
2020-10-26 01:05 ` Re: MultiXact\SLRU buffers configuration Alexander Korotkov <[email protected]>
2020-10-26 15:45 ` Re: MultiXact\SLRU buffers configuration Andrey Borodin <[email protected]>
2020-10-27 17:02 ` Re: MultiXact\SLRU buffers configuration Alexander Korotkov <[email protected]>
2020-10-27 17:23 ` Re: MultiXact\SLRU buffers configuration Alexander Korotkov <[email protected]>
2020-10-28 01:36 ` Re: MultiXact\SLRU buffers configuration Tomas Vondra <[email protected]>
2020-10-28 07:34 ` Re: MultiXact\SLRU buffers configuration Andrey Borodin <[email protected]>
2020-10-28 23:32 ` Re: MultiXact\SLRU buffers configuration Tomas Vondra <[email protected]>
2020-10-29 07:08 ` Re: MultiXact\SLRU buffers configuration Andrey Borodin <[email protected]>
2020-10-29 13:49 ` Re: MultiXact\SLRU buffers configuration Tomas Vondra <[email protected]>
2020-11-02 12:45 ` Re: MultiXact\SLRU buffers configuration Andrey Borodin <[email protected]>
2020-11-10 00:13 ` Re: MultiXact\SLRU buffers configuration Tomas Vondra <[email protected]>
2020-11-10 06:16 ` Re: MultiXact\SLRU buffers configuration Andrey Borodin <[email protected]>
2020-11-10 18:07 ` Re: MultiXact\SLRU buffers configuration Tomas Vondra <[email protected]>
2020-11-13 11:49 ` Re: MultiXact\SLRU buffers configuration Andrey Borodin <[email protected]>
2020-12-08 16:05 ` Re: MultiXact\SLRU buffers configuration Gilles Darold <[email protected]>
2020-12-08 17:52 ` Re: MultiXact\SLRU buffers configuration Andrey Borodin <[email protected]>
2020-12-10 14:45 ` Re: MultiXact\SLRU buffers configuration Gilles Darold <[email protected]>
2020-12-11 17:50 ` Re: MultiXact\SLRU buffers configuration Gilles Darold <[email protected]>
2020-12-13 09:17 ` Re: MultiXact\SLRU buffers configuration Gilles Darold <[email protected]>
2020-12-13 17:24 ` Re: MultiXact\SLRU buffers configuration Andrey Borodin <[email protected]>
@ 2020-12-14 06:31 ` Andrey Borodin <[email protected]>
1 sibling, 0 replies; 90+ messages in thread
From: Andrey Borodin @ 2020-12-14 06:31 UTC (permalink / raw)
To: Gilles Darold <[email protected]>; +Cc: Tomas Vondra <[email protected]>; Tomas Vondra <[email protected]>; Alexander Korotkov <[email protected]>; Anastasia Lubennikova <[email protected]>; Daniel Gustafsson <[email protected]>; Kyotaro Horiguchi <[email protected]>; pgsql-hackers
> 13 дек. 2020 г., в 22:24, Andrey Borodin <[email protected]> написал(а):
>
>
>
>> 13 дек. 2020 г., в 14:17, Gilles Darold <[email protected]> написал(а):
>>
>> I've done more review on these patches.
>
> Thanks, Gilles! I'll incorporate all your fixes to patchset.
PFA patches.
Also, I've noted that patch "Add conditional variable to wait for next MultXact offset in corner case" removes CHECK_FOR_INTERRUPTS();, I'm not sure it's correct.
Thanks!
Best regards, Andrey Borodin.
Attachments:
[application/octet-stream] v8-0004-Add-GUCs-to-tune-MultiXact-SLRUs.patch (7.2K, ../../[email protected]/2-v8-0004-Add-GUCs-to-tune-MultiXact-SLRUs.patch)
download | inline diff:
From 122fcbf0a0e38d6ba7880b22ec093aa8bb8011e4 Mon Sep 17 00:00:00 2001
From: Andrey Borodin <[email protected]>
Date: Sat, 9 May 2020 16:42:07 +0500
Subject: [PATCH v8 4/4] Add GUCs to tune MultiXact SLRUs
---
doc/src/sgml/config.sgml | 31 +++++++++++++++++++
src/backend/access/transam/multixact.c | 8 ++---
src/backend/utils/init/globals.c | 2 ++
src/backend/utils/misc/guc.c | 22 +++++++++++++
src/backend/utils/misc/postgresql.conf.sample | 8 +++++
src/include/access/multixact.h | 4 ---
src/include/miscadmin.h | 2 ++
7 files changed, 69 insertions(+), 8 deletions(-)
diff --git a/doc/src/sgml/config.sgml b/doc/src/sgml/config.sgml
index d9c27daa49..fab9715e83 100644
--- a/doc/src/sgml/config.sgml
+++ b/doc/src/sgml/config.sgml
@@ -1860,6 +1860,37 @@ include_dir 'conf.d'
</para>
</listitem>
</varlistentry>
+
+ <varlistentry id="guc-multixact-offsets-slru-buffers" xreflabel="multixact_offsets_slru_buffers">
+ <term><varname>multixact_offsets_slru_buffers</varname> (<type>integer</type>)
+ <indexterm>
+ <primary><varname>multixact_offsets_slru_buffers</varname> configuration parameter</primary>
+ </indexterm>
+ </term>
+ <listitem>
+ <para>
+ Specifies the amount of memory to be used for MultiXact offsets. MultiXact offsets
+ are used to store information about offsets of multiple row lockers (caused by SELECT FOR UPDATE and others).
+ It defaults to 64 kilobytes (<literal>64KB</literal>).
+ </para>
+ </listitem>
+ </varlistentry>
+
+ <varlistentry id="guc-multixact-members-slru-buffers" xreflabel="multixact_members_slru_buffers">
+ <term><varname>multixact_members_slru_buffers</varname> (<type>integer</type>)
+ <indexterm>
+ <primary><varname>multixact_members_slru_buffers</varname> configuration parameter</primary>
+ </indexterm>
+ </term>
+ <listitem>
+ <para>
+ Specifies the amount of memory to be used for MultiXact members. MultiXact members
+ are used to store information about XIDs of multiple row lockers. Tipically <varname>multixact_members_slru_buffers</varname>
+ is twice more than <varname>multixact_offsets_slru_buffers</varname>.
+ It defaults to 128 kilobytes (<literal>128KB</literal>).
+ </para>
+ </listitem>
+ </varlistentry>
<varlistentry id="guc-max-stack-depth" xreflabel="max_stack_depth">
<term><varname>max_stack_depth</varname> (<type>integer</type>)
diff --git a/src/backend/access/transam/multixact.c b/src/backend/access/transam/multixact.c
index ffd35c2aea..76b4ad75bc 100644
--- a/src/backend/access/transam/multixact.c
+++ b/src/backend/access/transam/multixact.c
@@ -1867,8 +1867,8 @@ MultiXactShmemSize(void)
mul_size(sizeof(MultiXactId) * 2, MaxOldestSlot))
size = SHARED_MULTIXACT_STATE_SIZE;
- size = add_size(size, SimpleLruShmemSize(NUM_MULTIXACTOFFSET_BUFFERS, 0));
- size = add_size(size, SimpleLruShmemSize(NUM_MULTIXACTMEMBER_BUFFERS, 0));
+ size = add_size(size, SimpleLruShmemSize(multixact_offsets_slru_buffers, 0));
+ size = add_size(size, SimpleLruShmemSize(multixact_members_slru_buffers, 0));
return size;
}
@@ -1884,12 +1884,12 @@ MultiXactShmemInit(void)
MultiXactMemberCtl->PagePrecedes = MultiXactMemberPagePrecedes;
SimpleLruInit(MultiXactOffsetCtl,
- "MultiXactOffset", NUM_MULTIXACTOFFSET_BUFFERS, 0,
+ "MultiXactOffset", multixact_offsets_slru_buffers, 0,
MultiXactOffsetSLRULock, "pg_multixact/offsets",
LWTRANCHE_MULTIXACTOFFSET_BUFFER,
SYNC_HANDLER_MULTIXACT_OFFSET);
SimpleLruInit(MultiXactMemberCtl,
- "MultiXactMember", NUM_MULTIXACTMEMBER_BUFFERS, 0,
+ "MultiXactMember", multixact_members_slru_buffers, 0,
MultiXactMemberSLRULock, "pg_multixact/members",
LWTRANCHE_MULTIXACTMEMBER_BUFFER,
SYNC_HANDLER_MULTIXACT_MEMBER);
diff --git a/src/backend/utils/init/globals.c b/src/backend/utils/init/globals.c
index 9ca71933dc..a5ec7bfe88 100644
--- a/src/backend/utils/init/globals.c
+++ b/src/backend/utils/init/globals.c
@@ -151,3 +151,5 @@ bool VacuumCostActive = false;
double vacuum_cleanup_index_scale_factor;
int multixact_local_cache_entries = 256;
+int multixact_offsets_slru_buffers = 8;
+int multixact_members_slru_buffers = 16;
diff --git a/src/backend/utils/misc/guc.c b/src/backend/utils/misc/guc.c
index ae2a3e1304..d86d34b4a5 100644
--- a/src/backend/utils/misc/guc.c
+++ b/src/backend/utils/misc/guc.c
@@ -2257,6 +2257,28 @@ static struct config_int ConfigureNamesInt[] =
NULL, NULL, NULL
},
+ {
+ {"multixact_offsets_slru_buffers", PGC_POSTMASTER, RESOURCES_MEM,
+ gettext_noop("Sets the number of shared memory buffers used for MultiXact offsets SLRU."),
+ NULL,
+ GUC_UNIT_BLOCKS
+ },
+ &multixact_offsets_slru_buffers,
+ 8, 2, INT_MAX / 2,
+ NULL, NULL, NULL
+ },
+
+ {
+ {"multixact_members_slru_buffers", PGC_POSTMASTER, RESOURCES_MEM,
+ gettext_noop("Sets the number of shared memory buffers used for MultiXact members SLRU."),
+ NULL,
+ GUC_UNIT_BLOCKS
+ },
+ &multixact_members_slru_buffers,
+ 16, 2, INT_MAX / 2,
+ NULL, NULL, NULL
+ },
+
{
{"temp_buffers", PGC_USERSET, RESOURCES_MEM,
gettext_noop("Sets the maximum number of temporary buffers used by each session."),
diff --git a/src/backend/utils/misc/postgresql.conf.sample b/src/backend/utils/misc/postgresql.conf.sample
index b7fb2ec1fe..1fb33809ee 100644
--- a/src/backend/utils/misc/postgresql.conf.sample
+++ b/src/backend/utils/misc/postgresql.conf.sample
@@ -189,6 +189,14 @@
# (change requires restart)
#backend_flush_after = 0 # measured in pages, 0 disables
+# - MultiXact Buffers -
+
+#multixact_offsets_slru_buffers = 8 # memory used for MultiXact offsets
+ # (change requires restart)
+#multixact_members_slru_buffers = 16 # memory used for MultiXact members
+ # (change requires restart)
+#multixact_local_cache_entries = 256 # number of cached MultiXact by backend
+ # (change requires restart)
#------------------------------------------------------------------------------
# WRITE-AHEAD LOG
diff --git a/src/include/access/multixact.h b/src/include/access/multixact.h
index 9a30380901..630ceaea4d 100644
--- a/src/include/access/multixact.h
+++ b/src/include/access/multixact.h
@@ -29,10 +29,6 @@
#define MaxMultiXactOffset ((MultiXactOffset) 0xFFFFFFFF)
-/* Number of SLRU buffers to use for multixact */
-#define NUM_MULTIXACTOFFSET_BUFFERS 8
-#define NUM_MULTIXACTMEMBER_BUFFERS 16
-
/*
* Possible multixact lock modes ("status"). The first four modes are for
* tuple locks (FOR KEY SHARE, FOR SHARE, FOR NO KEY UPDATE, FOR UPDATE); the
diff --git a/src/include/miscadmin.h b/src/include/miscadmin.h
index 01af61c963..ef8abea84d 100644
--- a/src/include/miscadmin.h
+++ b/src/include/miscadmin.h
@@ -161,6 +161,8 @@ extern PGDLLIMPORT int MaxBackends;
extern PGDLLIMPORT int MaxConnections;
extern PGDLLIMPORT int max_worker_processes;
extern PGDLLIMPORT int max_parallel_workers;
+extern PGDLLIMPORT int multixact_offsets_slru_buffers;
+extern PGDLLIMPORT int multixact_members_slru_buffers;
extern PGDLLIMPORT int multixact_local_cache_entries;
--
2.24.3 (Apple Git-128)
[application/octet-stream] v8-0003-Add-conditional-variable-to-wait-for-next-MultXac.patch (4.4K, ../../[email protected]/3-v8-0003-Add-conditional-variable-to-wait-for-next-MultXac.patch)
download | inline diff:
From 2706550cd4fc9ef53b8fa09d7414e88a31ea6e0e Mon Sep 17 00:00:00 2001
From: Alexander Korotkov <[email protected]>
Date: Mon, 26 Oct 2020 01:55:31 +0300
Subject: [PATCH v8 3/4] Add conditional variable to wait for next MultXact
offset in corner case
GetMultiXactIdMembers() has a corner case, when the next multixact offset is
not yet set. In this case GetMultiXactIdMembers() has to sleep till this offset
is set. Currently the sleeping is implemented in naive way using pg_sleep()
and retry. This commit implements sleeping with conditional variable, which
provides more efficient way for waiting till the event.
Discussion: https://postgr.es/m/a7f1c4e1-1015-92a4-2bd4-6736bd13d03e%40postgrespro.ru#c496c4e75fc0605094a0e1f763e6a6ec
Author: Andrey Borodin
Reviewed-by: Kyotaro Horiguchi, Daniel Gustafsson
Reviewed-by: Anastasia Lubennikova, Alexander Korotkov
---
src/backend/access/transam/multixact.c | 35 ++++++++++++++++++++++++--
src/backend/postmaster/pgstat.c | 2 ++
src/include/pgstat.h | 1 +
3 files changed, 36 insertions(+), 2 deletions(-)
diff --git a/src/backend/access/transam/multixact.c b/src/backend/access/transam/multixact.c
index 171e2ab681..ffd35c2aea 100644
--- a/src/backend/access/transam/multixact.c
+++ b/src/backend/access/transam/multixact.c
@@ -82,6 +82,7 @@
#include "lib/ilist.h"
#include "miscadmin.h"
#include "pg_trace.h"
+#include "pgstat.h"
#include "postmaster/autovacuum.h"
#include "storage/lmgr.h"
#include "storage/pmsignal.h"
@@ -233,6 +234,13 @@ typedef struct MultiXactStateData
/* support for members anti-wraparound measures */
MultiXactOffset offsetStopLimit; /* known if oldestOffsetKnown */
+ /*
+ * Conditional variable for waiting till the filling of the next multixact
+ * will be finished. See GetMultiXactIdMembers() and RecordNewMultiXact()
+ * for details.
+ */
+ ConditionVariable nextoffCV;
+
/*
* Per-backend data starts here. We have two arrays stored in the area
* immediately following the MultiXactStateData struct. Each is indexed by
@@ -892,6 +900,14 @@ RecordNewMultiXact(MultiXactId multi, MultiXactOffset offset,
/* Exchange our lock */
LWLockRelease(MultiXactOffsetSLRULock);
+ /*
+ * Let everybody know the offset of this mxid is recorded now. The
+ * waiters are waiting for the offset of the mxid next of the target to
+ * know the number of members of the target mxid, so we don't need to wait
+ * for members of this mxid are recorded.
+ */
+ ConditionVariableBroadcast(&MultiXactState->nextoffCV);
+
LWLockAcquire(MultiXactMemberSLRULock, LW_EXCLUSIVE);
prev_pageno = -1;
@@ -1389,10 +1405,24 @@ retry:
if (nextMXOffset == 0)
{
/* Corner case 2: next multixact is still being filled in */
+
+ /*
+ * The recorder of the next mxid is just before writing the
+ * offset. Wait for the offset to be written.
+ */
+ ConditionVariablePrepareToSleep(&MultiXactState->nextoffCV);
+
+ /*
+ * We don't have to recheck if multixact was filled in during
+ * ConditionVariablePrepareToSleep(), because we were holding
+ * MultiXactOffsetSLRULock.
+ */
LWLockRelease(MultiXactOffsetSLRULock);
lockmode = LW_NONE;
- CHECK_FOR_INTERRUPTS();
- pg_usleep(1000L);
+
+ ConditionVariableSleep(&MultiXactState->nextoffCV,
+ WAIT_EVENT_WAIT_NEXT_MXMEMBERS);
+ ConditionVariableCancelSleep();
goto retry;
}
@@ -1874,6 +1904,7 @@ MultiXactShmemInit(void)
/* Make sure we zero out the per-backend state */
MemSet(MultiXactState, 0, SHARED_MULTIXACT_STATE_SIZE);
+ ConditionVariableInit(&MultiXactState->nextoffCV);
}
else
Assert(found);
diff --git a/src/backend/postmaster/pgstat.c b/src/backend/postmaster/pgstat.c
index 7c75a25d21..20879fc90e 100644
--- a/src/backend/postmaster/pgstat.c
+++ b/src/backend/postmaster/pgstat.c
@@ -4041,6 +4041,8 @@ pgstat_get_wait_ipc(WaitEventIPC w)
break;
case WAIT_EVENT_XACT_GROUP_UPDATE:
event_name = "XactGroupUpdate";
+ case WAIT_EVENT_WAIT_NEXT_MXMEMBERS:
+ event_name = "MultiXactWaitNextMembers";
break;
/* no default case, so that compiler will warn */
}
diff --git a/src/include/pgstat.h b/src/include/pgstat.h
index 5954068dec..630ddcf1a5 100644
--- a/src/include/pgstat.h
+++ b/src/include/pgstat.h
@@ -964,6 +964,7 @@ typedef enum
WAIT_EVENT_REPLICATION_SLOT_DROP,
WAIT_EVENT_SAFE_SNAPSHOT,
WAIT_EVENT_SYNC_REP,
+ WAIT_EVENT_WAIT_NEXT_MXMEMBERS,
WAIT_EVENT_XACT_GROUP_UPDATE
} WaitEventIPC;
--
2.24.3 (Apple Git-128)
[application/octet-stream] v8-0002-Make-MultiXact-local-cache-size-configurable.patch (3.7K, ../../[email protected]/4-v8-0002-Make-MultiXact-local-cache-size-configurable.patch)
download | inline diff:
From 25f78196b00d5489924cb09e802ddda48c410d8d Mon Sep 17 00:00:00 2001
From: Alexander Korotkov <[email protected]>
Date: Mon, 26 Oct 2020 03:44:50 +0300
Subject: [PATCH v8 2/4] Make MultiXact local cache size configurable
---
doc/src/sgml/config.sgml | 16 ++++++++++++++++
src/backend/access/transam/multixact.c | 2 +-
src/backend/utils/init/globals.c | 2 ++
src/backend/utils/misc/guc.c | 10 ++++++++++
src/include/miscadmin.h | 2 ++
5 files changed, 31 insertions(+), 1 deletion(-)
diff --git a/doc/src/sgml/config.sgml b/doc/src/sgml/config.sgml
index 4b60382778..d9c27daa49 100644
--- a/doc/src/sgml/config.sgml
+++ b/doc/src/sgml/config.sgml
@@ -1845,6 +1845,22 @@ include_dir 'conf.d'
</listitem>
</varlistentry>
+ <varlistentry id="guc-multixact-local-cache-entries" xreflabel="multixact_local-cache-entries">
+ <term><varname>multixact_local_cache_entries</varname> (<type>integer</type>)
+ <indexterm>
+ <primary><varname>multixact_local_cache_entries</varname> configuration parameter</primary>
+ </indexterm>
+ </term>
+ <listitem>
+ <para>
+ Specifies the number cached MultiXact by backend. Any SLRU lookup is preceeded
+ by cache lookup. Higher numbers of cache size help to deduplicate lock sets, while
+ lower values make cache lookup faster.
+ It defaults to 256.
+ </para>
+ </listitem>
+ </varlistentry>
+
<varlistentry id="guc-max-stack-depth" xreflabel="max_stack_depth">
<term><varname>max_stack_depth</varname> (<type>integer</type>)
<indexterm>
diff --git a/src/backend/access/transam/multixact.c b/src/backend/access/transam/multixact.c
index 56bdd04364..171e2ab681 100644
--- a/src/backend/access/transam/multixact.c
+++ b/src/backend/access/transam/multixact.c
@@ -1614,7 +1614,7 @@ mXactCachePut(MultiXactId multi, int nmembers, MultiXactMember *members)
qsort(entry->members, nmembers, sizeof(MultiXactMember), mxactMemberComparator);
dlist_push_head(&MXactCache, &entry->node);
- if (MXactCacheMembers++ >= MAX_CACHE_ENTRIES)
+ if (MXactCacheMembers++ >= multixact_local_cache_entries)
{
dlist_node *node;
mXactCacheEnt *entry;
diff --git a/src/backend/utils/init/globals.c b/src/backend/utils/init/globals.c
index 6ab8216839..9ca71933dc 100644
--- a/src/backend/utils/init/globals.c
+++ b/src/backend/utils/init/globals.c
@@ -149,3 +149,5 @@ int VacuumCostBalance = 0; /* working state for vacuum */
bool VacuumCostActive = false;
double vacuum_cleanup_index_scale_factor;
+
+int multixact_local_cache_entries = 256;
diff --git a/src/backend/utils/misc/guc.c b/src/backend/utils/misc/guc.c
index dabcbb0736..ae2a3e1304 100644
--- a/src/backend/utils/misc/guc.c
+++ b/src/backend/utils/misc/guc.c
@@ -2247,6 +2247,16 @@ static struct config_int ConfigureNamesInt[] =
NULL, NULL, NULL
},
+ {
+ {"multixact_local_cache_entries", PGC_SUSET, RESOURCES_MEM,
+ gettext_noop("Sets the number of cached MultiXact by backend."),
+ NULL
+ },
+ &multixact_local_cache_entries,
+ 256, 2, INT_MAX / 2,
+ NULL, NULL, NULL
+ },
+
{
{"temp_buffers", PGC_USERSET, RESOURCES_MEM,
gettext_noop("Sets the maximum number of temporary buffers used by each session."),
diff --git a/src/include/miscadmin.h b/src/include/miscadmin.h
index 72e3352398..01af61c963 100644
--- a/src/include/miscadmin.h
+++ b/src/include/miscadmin.h
@@ -162,6 +162,8 @@ extern PGDLLIMPORT int MaxConnections;
extern PGDLLIMPORT int max_worker_processes;
extern PGDLLIMPORT int max_parallel_workers;
+extern PGDLLIMPORT int multixact_local_cache_entries;
+
extern PGDLLIMPORT int MyProcPid;
extern PGDLLIMPORT pg_time_t MyStartTime;
extern PGDLLIMPORT TimestampTz MyStartTimestamp;
--
2.24.3 (Apple Git-128)
[application/octet-stream] v8-0001-Use-shared-lock-in-GetMultiXactIdMembers-for.patch (13.2K, ../../[email protected]/5-v8-0001-Use-shared-lock-in-GetMultiXactIdMembers-for.patch)
download | inline diff:
From 4c8c7d0f24fdce994412b6c104d72659cf6fc14f Mon Sep 17 00:00:00 2001
From: Andrey Borodin <[email protected]>
Date: Mon, 14 Dec 2020 11:24:46 +0500
Subject: [PATCH v8 1/4] Use shared lock in GetMultiXactIdMembers for offsets
and members
Previously the read of multixact required exclusive control locks for both
offsets and members SLRUs. This could lead to the excessive lock contention.
This commit we makes multixacts SLRU take advantage of SimpleLruReadPage_ReadOnly
similar to clog, commit_ts and subtrans.
In order to evade extra reacquiring of CLRU lock, we teach
SimpleLruReadPage_ReadOnly() to take into account the current lock mode and
report resulting lock mode back.
Discussion: https://postgr.es/m/a7f1c4e1-1015-92a4-2bd4-6736bd13d03e%40postgrespro.ru#c496c4e75fc0605094a0e1f763e6a6ec
Author: Andrey Borodin
Reviewed-by: Kyotaro Horiguchi, Daniel Gustafsson
Reviewed-by: Anastasia Lubennikova, Alexander Korotkov
---
src/backend/access/transam/clog.c | 4 +++-
src/backend/access/transam/commit_ts.c | 4 +++-
src/backend/access/transam/multixact.c | 23 ++++++++++++++++-------
src/backend/access/transam/slru.c | 23 +++++++++++++++++------
src/backend/access/transam/subtrans.c | 4 +++-
src/backend/commands/async.c | 4 +++-
src/backend/storage/lmgr/lwlock.c | 3 +++
src/backend/storage/lmgr/predicate.c | 4 +++-
src/include/access/slru.h | 2 +-
src/include/storage/lwlock.h | 2 ++
10 files changed, 54 insertions(+), 19 deletions(-)
diff --git a/src/backend/access/transam/clog.c b/src/backend/access/transam/clog.c
index 034349aa7b..4c372065de 100644
--- a/src/backend/access/transam/clog.c
+++ b/src/backend/access/transam/clog.c
@@ -640,10 +640,11 @@ TransactionIdGetStatus(TransactionId xid, XLogRecPtr *lsn)
int lsnindex;
char *byteptr;
XidStatus status;
+ LWLockMode lockmode = LW_NONE;
/* lock is acquired by SimpleLruReadPage_ReadOnly */
- slotno = SimpleLruReadPage_ReadOnly(XactCtl, pageno, xid);
+ slotno = SimpleLruReadPage_ReadOnly(XactCtl, pageno, xid, &lockmode);
byteptr = XactCtl->shared->page_buffer[slotno] + byteno;
status = (*byteptr >> bshift) & CLOG_XACT_BITMASK;
@@ -651,6 +652,7 @@ TransactionIdGetStatus(TransactionId xid, XLogRecPtr *lsn)
lsnindex = GetLSNIndex(slotno, xid);
*lsn = XactCtl->shared->group_lsn[lsnindex];
+ Assert(lockmode != LW_NONE);
LWLockRelease(XactSLRULock);
return status;
diff --git a/src/backend/access/transam/commit_ts.c b/src/backend/access/transam/commit_ts.c
index 2fe551f17e..2699de033d 100644
--- a/src/backend/access/transam/commit_ts.c
+++ b/src/backend/access/transam/commit_ts.c
@@ -288,6 +288,7 @@ TransactionIdGetCommitTsData(TransactionId xid, TimestampTz *ts,
CommitTimestampEntry entry;
TransactionId oldestCommitTsXid;
TransactionId newestCommitTsXid;
+ LWLockMode lockmode = LW_NONE;
if (!TransactionIdIsValid(xid))
ereport(ERROR,
@@ -342,7 +343,7 @@ TransactionIdGetCommitTsData(TransactionId xid, TimestampTz *ts,
}
/* lock is acquired by SimpleLruReadPage_ReadOnly */
- slotno = SimpleLruReadPage_ReadOnly(CommitTsCtl, pageno, xid);
+ slotno = SimpleLruReadPage_ReadOnly(CommitTsCtl, pageno, xid, &lockmode);
memcpy(&entry,
CommitTsCtl->shared->page_buffer[slotno] +
SizeOfCommitTimestampEntry * entryno,
@@ -352,6 +353,7 @@ TransactionIdGetCommitTsData(TransactionId xid, TimestampTz *ts,
if (nodeid)
*nodeid = entry.nodeid;
+ Assert(lockmode != LW_NONE);
LWLockRelease(CommitTsSLRULock);
return *ts != 0;
}
diff --git a/src/backend/access/transam/multixact.c b/src/backend/access/transam/multixact.c
index eb8de7cf32..56bdd04364 100644
--- a/src/backend/access/transam/multixact.c
+++ b/src/backend/access/transam/multixact.c
@@ -1237,6 +1237,7 @@ GetMultiXactIdMembers(MultiXactId multi, MultiXactMember **members,
MultiXactId tmpMXact;
MultiXactOffset nextOffset;
MultiXactMember *ptr;
+ LWLockMode lockmode = LW_NONE;
debug_elog3(DEBUG2, "GetMembers: asked for %u", multi);
@@ -1340,12 +1341,13 @@ GetMultiXactIdMembers(MultiXactId multi, MultiXactMember **members,
* time on every multixact creation.
*/
retry:
- LWLockAcquire(MultiXactOffsetSLRULock, LW_EXCLUSIVE);
pageno = MultiXactIdToOffsetPage(multi);
entryno = MultiXactIdToOffsetEntry(multi);
- slotno = SimpleLruReadPage(MultiXactOffsetCtl, pageno, true, multi);
+ /* lock is acquired by SimpleLruReadPage_ReadOnly */
+ slotno = SimpleLruReadPage_ReadOnly(MultiXactOffsetCtl, pageno,
+ multi, &lockmode);
offptr = (MultiXactOffset *) MultiXactOffsetCtl->shared->page_buffer[slotno];
offptr += entryno;
offset = *offptr;
@@ -1377,7 +1379,8 @@ retry:
entryno = MultiXactIdToOffsetEntry(tmpMXact);
if (pageno != prev_pageno)
- slotno = SimpleLruReadPage(MultiXactOffsetCtl, pageno, true, tmpMXact);
+ slotno = SimpleLruReadPage_ReadOnly(MultiXactOffsetCtl, pageno,
+ tmpMXact, &lockmode);
offptr = (MultiXactOffset *) MultiXactOffsetCtl->shared->page_buffer[slotno];
offptr += entryno;
@@ -1387,6 +1390,7 @@ retry:
{
/* Corner case 2: next multixact is still being filled in */
LWLockRelease(MultiXactOffsetSLRULock);
+ lockmode = LW_NONE;
CHECK_FOR_INTERRUPTS();
pg_usleep(1000L);
goto retry;
@@ -1395,14 +1399,14 @@ retry:
length = nextMXOffset - offset;
}
+ Assert(lockmode != LW_NONE);
LWLockRelease(MultiXactOffsetSLRULock);
ptr = (MultiXactMember *) palloc(length * sizeof(MultiXactMember));
*members = ptr;
/* Now get the members themselves. */
- LWLockAcquire(MultiXactMemberSLRULock, LW_EXCLUSIVE);
-
+ lockmode = LW_NONE;
truelength = 0;
prev_pageno = -1;
for (i = 0; i < length; i++, offset++)
@@ -1418,7 +1422,8 @@ retry:
if (pageno != prev_pageno)
{
- slotno = SimpleLruReadPage(MultiXactMemberCtl, pageno, true, multi);
+ slotno = SimpleLruReadPage_ReadOnly(MultiXactMemberCtl, pageno,
+ multi, &lockmode);
prev_pageno = pageno;
}
@@ -1441,6 +1446,7 @@ retry:
truelength++;
}
+ Assert(lockmode != LW_NONE);
LWLockRelease(MultiXactMemberSLRULock);
/*
@@ -2733,6 +2739,7 @@ find_multixact_start(MultiXactId multi, MultiXactOffset *result)
int entryno;
int slotno;
MultiXactOffset *offptr;
+ LWLockMode lockmode = LW_NONE;
Assert(MultiXactState->finishedStartup);
@@ -2749,10 +2756,12 @@ find_multixact_start(MultiXactId multi, MultiXactOffset *result)
return false;
/* lock is acquired by SimpleLruReadPage_ReadOnly */
- slotno = SimpleLruReadPage_ReadOnly(MultiXactOffsetCtl, pageno, multi);
+ slotno = SimpleLruReadPage_ReadOnly(MultiXactOffsetCtl, pageno,
+ multi, &lockmode);
offptr = (MultiXactOffset *) MultiXactOffsetCtl->shared->page_buffer[slotno];
offptr += entryno;
offset = *offptr;
+ Assert(lockmode != LW_NONE);
LWLockRelease(MultiXactOffsetSLRULock);
*result = offset;
diff --git a/src/backend/access/transam/slru.c b/src/backend/access/transam/slru.c
index cec17cb2ae..e271b37d7b 100644
--- a/src/backend/access/transam/slru.c
+++ b/src/backend/access/transam/slru.c
@@ -487,17 +487,23 @@ SimpleLruReadPage(SlruCtl ctl, int pageno, bool write_ok,
* Return value is the shared-buffer slot number now holding the page.
* The buffer's LRU access info is updated.
*
- * Control lock must NOT be held at entry, but will be held at exit.
- * It is unspecified whether the lock will be shared or exclusive.
+ * Control lock must be held in *lock_mode mode, which may be LW_NONE. Control
+ * lock will be held at exit in at least shared mode. Resulting control lock
+ * mode is set to *lock_mode.
*/
int
-SimpleLruReadPage_ReadOnly(SlruCtl ctl, int pageno, TransactionId xid)
+SimpleLruReadPage_ReadOnly(SlruCtl ctl, int pageno, TransactionId xid,
+ LWLockMode *lock_mode)
{
SlruShared shared = ctl->shared;
int slotno;
/* Try to find the page while holding only shared lock */
- LWLockAcquire(shared->ControlLock, LW_SHARED);
+ if (*lock_mode == LW_NONE)
+ {
+ LWLockAcquire(shared->ControlLock, LW_SHARED);
+ *lock_mode = LW_SHARED;
+ }
/* See if page is already in a buffer */
for (slotno = 0; slotno < shared->num_slots; slotno++)
@@ -517,8 +523,13 @@ SimpleLruReadPage_ReadOnly(SlruCtl ctl, int pageno, TransactionId xid)
}
/* No luck, so switch to normal exclusive lock and do regular read */
- LWLockRelease(shared->ControlLock);
- LWLockAcquire(shared->ControlLock, LW_EXCLUSIVE);
+ if (*lock_mode != LW_EXCLUSIVE)
+ {
+ Assert(*lock_mode == LW_NONE);
+ LWLockRelease(shared->ControlLock);
+ LWLockAcquire(shared->ControlLock, LW_EXCLUSIVE);
+ *lock_mode = LW_EXCLUSIVE;
+ }
return SimpleLruReadPage(ctl, pageno, true, xid);
}
diff --git a/src/backend/access/transam/subtrans.c b/src/backend/access/transam/subtrans.c
index 0111e867c7..7bb1543189 100644
--- a/src/backend/access/transam/subtrans.c
+++ b/src/backend/access/transam/subtrans.c
@@ -113,6 +113,7 @@ SubTransGetParent(TransactionId xid)
int slotno;
TransactionId *ptr;
TransactionId parent;
+ LWLockMode lockmode = LW_NONE;
/* Can't ask about stuff that might not be around anymore */
Assert(TransactionIdFollowsOrEquals(xid, TransactionXmin));
@@ -123,12 +124,13 @@ SubTransGetParent(TransactionId xid)
/* lock is acquired by SimpleLruReadPage_ReadOnly */
- slotno = SimpleLruReadPage_ReadOnly(SubTransCtl, pageno, xid);
+ slotno = SimpleLruReadPage_ReadOnly(SubTransCtl, pageno, xid, &lockmode);
ptr = (TransactionId *) SubTransCtl->shared->page_buffer[slotno];
ptr += entryno;
parent = *ptr;
+ Assert(lockmode != LW_NONE);
LWLockRelease(SubtransSLRULock);
return parent;
diff --git a/src/backend/commands/async.c b/src/backend/commands/async.c
index c0763c63e2..ef1dbbe53d 100644
--- a/src/backend/commands/async.c
+++ b/src/backend/commands/async.c
@@ -2011,6 +2011,7 @@ asyncQueueReadAllNotifications(void)
int curoffset = QUEUE_POS_OFFSET(pos);
int slotno;
int copysize;
+ LWLockMode lockmode = LW_NONE;
/*
* We copy the data from SLRU into a local buffer, so as to avoid
@@ -2019,7 +2020,7 @@ asyncQueueReadAllNotifications(void)
* part of the page we will actually inspect.
*/
slotno = SimpleLruReadPage_ReadOnly(NotifyCtl, curpage,
- InvalidTransactionId);
+ InvalidTransactionId, &lockmode);
if (curpage == QUEUE_POS_PAGE(head))
{
/* we only want to read as far as head */
@@ -2036,6 +2037,7 @@ asyncQueueReadAllNotifications(void)
NotifyCtl->shared->page_buffer[slotno] + curoffset,
copysize);
/* Release lock that we got from SimpleLruReadPage_ReadOnly() */
+ Assert(lockmode != LW_NONE);
LWLockRelease(NotifySLRULock);
/*
diff --git a/src/backend/storage/lmgr/lwlock.c b/src/backend/storage/lmgr/lwlock.c
index 108e652179..ad1dcc7140 100644
--- a/src/backend/storage/lmgr/lwlock.c
+++ b/src/backend/storage/lmgr/lwlock.c
@@ -1067,6 +1067,8 @@ LWLockWakeup(LWLock *lock)
static void
LWLockQueueSelf(LWLock *lock, LWLockMode mode)
{
+ Assert(mode != LW_NONE);
+
/*
* If we don't have a PGPROC structure, there's no way to wait. This
* should never occur, since MyProc should only be null during shared
@@ -1827,6 +1829,7 @@ LWLockRelease(LWLock *lock)
elog(ERROR, "lock %s is not held", T_NAME(lock));
mode = held_lwlocks[i].mode;
+ Assert(mode == LW_EXCLUSIVE || mode == LW_SHARED);
num_held_lwlocks--;
for (; i < num_held_lwlocks; i++)
diff --git a/src/backend/storage/lmgr/predicate.c b/src/backend/storage/lmgr/predicate.c
index 8a365b400c..a4df90a8ae 100644
--- a/src/backend/storage/lmgr/predicate.c
+++ b/src/backend/storage/lmgr/predicate.c
@@ -924,6 +924,7 @@ SerialGetMinConflictCommitSeqNo(TransactionId xid)
TransactionId tailXid;
SerCommitSeqNo val;
int slotno;
+ LWLockMode lockmode = LW_NONE;
Assert(TransactionIdIsValid(xid));
@@ -946,8 +947,9 @@ SerialGetMinConflictCommitSeqNo(TransactionId xid)
* but will return with that lock held, which must then be released.
*/
slotno = SimpleLruReadPage_ReadOnly(SerialSlruCtl,
- SerialPage(xid), xid);
+ SerialPage(xid), xid, &lockmode);
val = SerialValue(slotno, xid);
+ Assert(lockmode != LW_NONE);
LWLockRelease(SerialSLRULock);
return val;
}
diff --git a/src/include/access/slru.h b/src/include/access/slru.h
index b39b43504d..4b66d3b592 100644
--- a/src/include/access/slru.h
+++ b/src/include/access/slru.h
@@ -142,7 +142,7 @@ extern int SimpleLruZeroPage(SlruCtl ctl, int pageno);
extern int SimpleLruReadPage(SlruCtl ctl, int pageno, bool write_ok,
TransactionId xid);
extern int SimpleLruReadPage_ReadOnly(SlruCtl ctl, int pageno,
- TransactionId xid);
+ TransactionId xid, LWLockMode *lock_mode);
extern void SimpleLruWritePage(SlruCtl ctl, int slotno);
extern void SimpleLruWriteAll(SlruCtl ctl, bool allow_redirtied);
extern void SimpleLruTruncate(SlruCtl ctl, int cutoffPage);
diff --git a/src/include/storage/lwlock.h b/src/include/storage/lwlock.h
index af9b41795d..e680c6397a 100644
--- a/src/include/storage/lwlock.h
+++ b/src/include/storage/lwlock.h
@@ -129,6 +129,8 @@ extern PGDLLIMPORT int NamedLWLockTrancheRequests;
typedef enum LWLockMode
{
+ LW_NONE, /* Not a lock mode. Indicates that there is no
+ * lock. */
LW_EXCLUSIVE,
LW_SHARED,
LW_WAIT_UNTIL_FREE /* A special mode used in PGPROC->lwWaitMode,
--
2.24.3 (Apple Git-128)
^ permalink raw reply [nested|flat] 90+ messages in thread
* Re: MultiXact\SLRU buffers configuration
2020-05-08 16:36 MultiXact\SLRU buffers configuration Andrey M. Borodin <[email protected]>
2020-05-11 11:17 ` Re: MultiXact\SLRU buffers configuration Andrey M. Borodin <[email protected]>
2020-05-13 18:08 ` Re: MultiXact\SLRU buffers configuration Andrey M. Borodin <[email protected]>
2020-05-14 01:25 ` Re: MultiXact\SLRU buffers configuration Kyotaro Horiguchi <[email protected]>
2020-05-14 05:19 ` Re: MultiXact\SLRU buffers configuration Andrey M. Borodin <[email protected]>
2020-05-14 06:16 ` Re: MultiXact\SLRU buffers configuration Kyotaro Horiguchi <[email protected]>
2020-05-14 06:44 ` Re: MultiXact\SLRU buffers configuration Andrey M. Borodin <[email protected]>
2020-05-15 00:03 ` Re: MultiXact\SLRU buffers configuration Kyotaro Horiguchi <[email protected]>
2020-07-02 12:02 ` Re: MultiXact\SLRU buffers configuration Daniel Gustafsson <[email protected]>
2020-07-08 07:03 ` Re: MultiXact\SLRU buffers configuration Andrey M. Borodin <[email protected]>
2020-08-28 18:08 ` Re: MultiXact\SLRU buffers configuration Anastasia Lubennikova <[email protected]>
2020-09-28 14:41 ` Re: MultiXact\SLRU buffers configuration Andrey M. Borodin <[email protected]>
2020-10-26 01:05 ` Re: MultiXact\SLRU buffers configuration Alexander Korotkov <[email protected]>
2020-10-26 15:45 ` Re: MultiXact\SLRU buffers configuration Andrey Borodin <[email protected]>
2020-10-27 17:02 ` Re: MultiXact\SLRU buffers configuration Alexander Korotkov <[email protected]>
2020-10-27 17:23 ` Re: MultiXact\SLRU buffers configuration Alexander Korotkov <[email protected]>
2020-10-28 01:36 ` Re: MultiXact\SLRU buffers configuration Tomas Vondra <[email protected]>
2020-10-28 07:34 ` Re: MultiXact\SLRU buffers configuration Andrey Borodin <[email protected]>
2020-10-28 23:32 ` Re: MultiXact\SLRU buffers configuration Tomas Vondra <[email protected]>
2020-10-29 07:08 ` Re: MultiXact\SLRU buffers configuration Andrey Borodin <[email protected]>
2020-10-29 13:49 ` Re: MultiXact\SLRU buffers configuration Tomas Vondra <[email protected]>
2020-11-02 12:45 ` Re: MultiXact\SLRU buffers configuration Andrey Borodin <[email protected]>
2020-11-10 00:13 ` Re: MultiXact\SLRU buffers configuration Tomas Vondra <[email protected]>
2020-11-10 06:16 ` Re: MultiXact\SLRU buffers configuration Andrey Borodin <[email protected]>
2020-11-10 18:07 ` Re: MultiXact\SLRU buffers configuration Tomas Vondra <[email protected]>
2020-11-13 11:49 ` Re: MultiXact\SLRU buffers configuration Andrey Borodin <[email protected]>
2020-12-08 16:05 ` Re: MultiXact\SLRU buffers configuration Gilles Darold <[email protected]>
2020-12-08 17:52 ` Re: MultiXact\SLRU buffers configuration Andrey Borodin <[email protected]>
2020-12-10 14:45 ` Re: MultiXact\SLRU buffers configuration Gilles Darold <[email protected]>
2020-12-11 17:50 ` Re: MultiXact\SLRU buffers configuration Gilles Darold <[email protected]>
2020-12-13 09:17 ` Re: MultiXact\SLRU buffers configuration Gilles Darold <[email protected]>
2020-12-13 17:24 ` Re: MultiXact\SLRU buffers configuration Andrey Borodin <[email protected]>
@ 2020-12-23 16:31 ` Gilles Darold <[email protected]>
2021-02-15 17:17 ` Re: MultiXact\SLRU buffers configuration Andrey Borodin <[email protected]>
1 sibling, 1 reply; 90+ messages in thread
From: Gilles Darold @ 2020-12-23 16:31 UTC (permalink / raw)
To: Andrey Borodin <[email protected]>; +Cc: Tomas Vondra <[email protected]>; Tomas Vondra <[email protected]>; Alexander Korotkov <[email protected]>; Anastasia Lubennikova <[email protected]>; Daniel Gustafsson <[email protected]>; Kyotaro Horiguchi <[email protected]>; pgsql-hackers
Le 13/12/2020 à 18:24, Andrey Borodin a écrit :
>
>> 13 дек. 2020 г., в 14:17, Gilles Darold <[email protected]> написал(а):
>>
>> I've done more review on these patches.
> Thanks, Gilles! I'll incorporate all your fixes to patchset.
> Can you also benchmark conditional variable sleep? The patch "Add conditional variable to wait for next MultXact offset in corner case"?
> The problem manifests on Standby when Primary is heavily loaded with MultiXactOffsetControlLock.
>
> Thanks!
>
> Best regards, Andrey Borodin.
Hi Andrey,
Sorry for the response delay, we have run several others tests trying to
figure out the performances gain per patch but unfortunately we have
very heratic results. With the same parameters and patches the test
doesn't returns the same results following the day or the hour of the
day. This is very frustrating and I suppose that this is related to the
Azure architecture. The only thing that I am sure is that we had the
best performances results with all patches and
multixact_offsets_slru_buffers = 256
multixact_members_slru_buffers = 512
multixact_local_cache_entries = 4096
but I can not say if all or part of the patches are improving the
performances. My feeling is that performances gain related to patches 1
(shared lock) and 3 (conditional variable) do not have much to do with
the performances gain compared to just tuning the multixact buffers.
This is when the multixact contention is observed but perhaps they are
delaying the contention. It's all the more frustrating that we had a
test case to reproduce the contention but not the architecture apparently.
Can't do much more at this point.
Best regards,
--
Gilles Darold
LzLabs GmbH
http://www.lzlabs.com/
^ permalink raw reply [nested|flat] 90+ messages in thread
* Re: MultiXact\SLRU buffers configuration
2020-05-08 16:36 MultiXact\SLRU buffers configuration Andrey M. Borodin <[email protected]>
2020-05-11 11:17 ` Re: MultiXact\SLRU buffers configuration Andrey M. Borodin <[email protected]>
2020-05-13 18:08 ` Re: MultiXact\SLRU buffers configuration Andrey M. Borodin <[email protected]>
2020-05-14 01:25 ` Re: MultiXact\SLRU buffers configuration Kyotaro Horiguchi <[email protected]>
2020-05-14 05:19 ` Re: MultiXact\SLRU buffers configuration Andrey M. Borodin <[email protected]>
2020-05-14 06:16 ` Re: MultiXact\SLRU buffers configuration Kyotaro Horiguchi <[email protected]>
2020-05-14 06:44 ` Re: MultiXact\SLRU buffers configuration Andrey M. Borodin <[email protected]>
2020-05-15 00:03 ` Re: MultiXact\SLRU buffers configuration Kyotaro Horiguchi <[email protected]>
2020-07-02 12:02 ` Re: MultiXact\SLRU buffers configuration Daniel Gustafsson <[email protected]>
2020-07-08 07:03 ` Re: MultiXact\SLRU buffers configuration Andrey M. Borodin <[email protected]>
2020-08-28 18:08 ` Re: MultiXact\SLRU buffers configuration Anastasia Lubennikova <[email protected]>
2020-09-28 14:41 ` Re: MultiXact\SLRU buffers configuration Andrey M. Borodin <[email protected]>
2020-10-26 01:05 ` Re: MultiXact\SLRU buffers configuration Alexander Korotkov <[email protected]>
2020-10-26 15:45 ` Re: MultiXact\SLRU buffers configuration Andrey Borodin <[email protected]>
2020-10-27 17:02 ` Re: MultiXact\SLRU buffers configuration Alexander Korotkov <[email protected]>
2020-10-27 17:23 ` Re: MultiXact\SLRU buffers configuration Alexander Korotkov <[email protected]>
2020-10-28 01:36 ` Re: MultiXact\SLRU buffers configuration Tomas Vondra <[email protected]>
2020-10-28 07:34 ` Re: MultiXact\SLRU buffers configuration Andrey Borodin <[email protected]>
2020-10-28 23:32 ` Re: MultiXact\SLRU buffers configuration Tomas Vondra <[email protected]>
2020-10-29 07:08 ` Re: MultiXact\SLRU buffers configuration Andrey Borodin <[email protected]>
2020-10-29 13:49 ` Re: MultiXact\SLRU buffers configuration Tomas Vondra <[email protected]>
2020-11-02 12:45 ` Re: MultiXact\SLRU buffers configuration Andrey Borodin <[email protected]>
2020-11-10 00:13 ` Re: MultiXact\SLRU buffers configuration Tomas Vondra <[email protected]>
2020-11-10 06:16 ` Re: MultiXact\SLRU buffers configuration Andrey Borodin <[email protected]>
2020-11-10 18:07 ` Re: MultiXact\SLRU buffers configuration Tomas Vondra <[email protected]>
2020-11-13 11:49 ` Re: MultiXact\SLRU buffers configuration Andrey Borodin <[email protected]>
2020-12-08 16:05 ` Re: MultiXact\SLRU buffers configuration Gilles Darold <[email protected]>
2020-12-08 17:52 ` Re: MultiXact\SLRU buffers configuration Andrey Borodin <[email protected]>
2020-12-10 14:45 ` Re: MultiXact\SLRU buffers configuration Gilles Darold <[email protected]>
2020-12-11 17:50 ` Re: MultiXact\SLRU buffers configuration Gilles Darold <[email protected]>
2020-12-13 09:17 ` Re: MultiXact\SLRU buffers configuration Gilles Darold <[email protected]>
2020-12-13 17:24 ` Re: MultiXact\SLRU buffers configuration Andrey Borodin <[email protected]>
2020-12-23 16:31 ` Re: MultiXact\SLRU buffers configuration Gilles Darold <[email protected]>
@ 2021-02-15 17:17 ` Andrey Borodin <[email protected]>
2021-03-11 15:50 ` Re: MultiXact\SLRU buffers configuration Gilles Darold <[email protected]>
0 siblings, 1 reply; 90+ messages in thread
From: Andrey Borodin @ 2021-02-15 17:17 UTC (permalink / raw)
To: Gilles Darold <[email protected]>; +Cc: Tomas Vondra <[email protected]>; Tomas Vondra <[email protected]>; Alexander Korotkov <[email protected]>; Anastasia Lubennikova <[email protected]>; Daniel Gustafsson <[email protected]>; Kyotaro Horiguchi <[email protected]>; pgsql-hackers
> 23 дек. 2020 г., в 21:31, Gilles Darold <[email protected]> написал(а):
>
> Sorry for the response delay, we have run several others tests trying to figure out the performances gain per patch but unfortunately we have very heratic results. With the same parameters and patches the test doesn't returns the same results following the day or the hour of the day. This is very frustrating and I suppose that this is related to the Azure architecture. The only thing that I am sure is that we had the best performances results with all patches and
>
> multixact_offsets_slru_buffers = 256
> multixact_members_slru_buffers = 512
> multixact_local_cache_entries = 4096
>
>
> but I can not say if all or part of the patches are improving the performances. My feeling is that performances gain related to patches 1 (shared lock) and 3 (conditional variable) do not have much to do with the performances gain compared to just tuning the multixact buffers. This is when the multixact contention is observed but perhaps they are delaying the contention. It's all the more frustrating that we had a test case to reproduce the contention but not the architecture apparently.
Hi! Thanks for the input.
I think we have a consensus here that configuring SLRU size is beneficial for MultiXacts.
There is proposal in nearby thread [0] on changing default value of commit_ts SLRU buffers.
In my experience from time to time there can be problems with subtransactions cured by extending subtrans SLRU.
Let's make all SLRUs configurable?
PFA patch with draft of these changes.
Best regards, Andrey Borodin.
[0] https://www.postgresql.org/message-id/flat/20210115220744.GA24457%40alvherre.pgsql
Attachments:
[application/octet-stream] v9-0001-Make-all-SLRU-buffer-sizes-configurable.patch (19.1K, ../../[email protected]/2-v9-0001-Make-all-SLRU-buffer-sizes-configurable.patch)
download | inline diff:
From 1b488106f7dfc142f219bb8ba0a0c5d2b6b94ba5 Mon Sep 17 00:00:00 2001
From: Andrey Borodin <[email protected]>
Date: Mon, 15 Feb 2021 21:51:56 +0500
Subject: [PATCH v9] Make all SLRU buffer sizes configurable
---
doc/src/sgml/config.sgml | 101 ++++++++++++++++++
src/backend/access/transam/clog.c | 6 ++
src/backend/access/transam/commit_ts.c | 5 +-
src/backend/access/transam/multixact.c | 8 +-
src/backend/access/transam/subtrans.c | 5 +-
src/backend/commands/async.c | 8 +-
src/backend/storage/lmgr/predicate.c | 4 +-
src/backend/utils/init/globals.c | 8 ++
src/backend/utils/misc/guc.c | 77 +++++++++++++
src/backend/utils/misc/postgresql.conf.sample | 16 +++
src/include/access/multixact.h | 4 -
src/include/access/subtrans.h | 3 -
src/include/commands/async.h | 5 -
src/include/miscadmin.h | 8 ++
src/include/storage/predicate.h | 4 -
15 files changed, 233 insertions(+), 29 deletions(-)
diff --git a/doc/src/sgml/config.sgml b/doc/src/sgml/config.sgml
index 4df1405d2e..5b24b435f3 100644
--- a/doc/src/sgml/config.sgml
+++ b/doc/src/sgml/config.sgml
@@ -1852,6 +1852,107 @@ include_dir 'conf.d'
</para>
</listitem>
</varlistentry>
+
+ <varlistentry id="guc-multixact-offsets-slru-buffers" xreflabel="multixact_offsets_slru_buffers">
+ <term><varname>multixact_offsets_slru_buffers</varname> (<type>integer</type>)
+ <indexterm>
+ <primary><varname>multixact_offsets_slru_buffers</varname> configuration parameter</primary>
+ </indexterm>
+ </term>
+ <listitem>
+ <para>
+ Specifies the amount of memory to be used for MultiXact offsets. MultiXact offsets
+ are used to store information about offsets of multiple row lockers (caused by SELECT FOR UPDATE and others).
+ It defaults to 64 kilobytes (<literal>64KB</literal>).
+ </para>
+ </listitem>
+ </varlistentry>
+
+ <varlistentry id="guc-multixact-members-slru-buffers" xreflabel="multixact_members_slru_buffers">
+ <term><varname>multixact_members_slru_buffers</varname> (<type>integer</type>)
+ <indexterm>
+ <primary><varname>multixact_members_slru_buffers</varname> configuration parameter</primary>
+ </indexterm>
+ </term>
+ <listitem>
+ <para>
+ Specifies the amount of memory to be used for MultiXact members. MultiXact members
+ are used to store information about XIDs of multiple row lockers. Tipically <varname>multixact_members_slru_buffers</varname>
+ is twice more than <varname>multixact_offsets_slru_buffers</varname>.
+ It defaults to 128 kilobytes (<literal>128KB</literal>).
+ </para>
+ </listitem>
+ </varlistentry>
+
+ <varlistentry id="guc-subtrans-buffers" xreflabel="subtrans_slru_buffers">
+ <term><varname>subtrans_slru_buffers</varname> (<type>integer</type>)
+ <indexterm>
+ <primary><varname>subtrans_slru_buffers</varname> configuration parameter</primary>
+ </indexterm>
+ </term>
+ <listitem>
+ <para>
+ Specifies the amount of memory to be used for subtransactions.
+ It defaults to 256 kilobytes (<literal>256KB</literal>).
+ </para>
+ </listitem>
+ </varlistentry>
+
+ <varlistentry id="guc-notify-buffers" xreflabel="notify_slru_buffers">
+ <term><varname>notify_slru_buffers</varname> (<type>integer</type>)
+ <indexterm>
+ <primary><varname>notify_slru_buffers</varname> configuration parameter</primary>
+ </indexterm>
+ </term>
+ <listitem>
+ <para>
+ Specifies the amount of memory to be used for asincronous notifications (NOTIFY, LISTEN).
+ It defaults to 64 kilobytes (<literal>64KB</literal>).
+ </para>
+ </listitem>
+ </varlistentry>
+
+ <varlistentry id="guc-serial-buffers" xreflabel="serial_slru_buffers">
+ <term><varname>serial_slru_buffers</varname> (<type>integer</type>)
+ <indexterm>
+ <primary><varname>serial_slru_buffers</varname> configuration parameter</primary>
+ </indexterm>
+ </term>
+ <listitem>
+ <para>
+ Specifies the amount of memory to be used for predicate locks.
+ It defaults to 128 kilobytes (<literal>128KB</literal>).
+ </para>
+ </listitem>
+ </varlistentry>
+
+ <varlistentry id="guc-clog-buffers" xreflabel="clog_slru_buffers">
+ <term><varname>clog_slru_buffers</varname> (<type>integer</type>)
+ <indexterm>
+ <primary><varname>clog_slru_buffers</varname> configuration parameter</primary>
+ </indexterm>
+ </term>
+ <listitem>
+ <para>
+ Specifies the amount of memory to be used for CLOG.
+ It defaults to 0, in this case CLOG size is taken as <varname>shared_buffers</varname> / 512.
+ </para>
+ </listitem>
+ </varlistentry>
+
+ <varlistentry id="guc-commit-ts-buffers" xreflabel="commit_ts_slru_buffers">
+ <term><varname>commit_ts_slru_buffers</varname> (<type>integer</type>)
+ <indexterm>
+ <primary><varname>commit_ts_slru_buffers</varname> configuration parameter</primary>
+ </indexterm>
+ </term>
+ <listitem>
+ <para>
+ Specifies the amount of memory to be used for commit timestamps.
+ It defaults to 0, in this case CLOG size is taken as <varname>shared_buffers</varname> / 512.
+ </para>
+ </listitem>
+ </varlistentry>
<varlistentry id="guc-max-stack-depth" xreflabel="max_stack_depth">
<term><varname>max_stack_depth</varname> (<type>integer</type>)
diff --git a/src/backend/access/transam/clog.c b/src/backend/access/transam/clog.c
index 6fa4713fb4..e57106b374 100644
--- a/src/backend/access/transam/clog.c
+++ b/src/backend/access/transam/clog.c
@@ -659,6 +659,9 @@ TransactionIdGetStatus(TransactionId xid, XLogRecPtr *lsn)
/*
* Number of shared CLOG buffers.
*
+ * If values is confugured via GUC - just use given value. Otherwise
+ * apply following euristics.
+ *
* On larger multi-processor systems, it is possible to have many CLOG page
* requests in flight at one time which could lead to disk access for CLOG
* page if the required page is not found in memory. Testing revealed that we
@@ -675,6 +678,9 @@ TransactionIdGetStatus(TransactionId xid, XLogRecPtr *lsn)
Size
CLOGShmemBuffers(void)
{
+ /* consider 0 and 1 as unset GUC */
+ if (clog_slru_buffers > 1)
+ return clog_slru_buffers;
return Min(128, Max(4, NBuffers / 512));
}
diff --git a/src/backend/access/transam/commit_ts.c b/src/backend/access/transam/commit_ts.c
index 48e8d66286..7de3bca63d 100644
--- a/src/backend/access/transam/commit_ts.c
+++ b/src/backend/access/transam/commit_ts.c
@@ -530,7 +530,10 @@ pg_xact_commit_timestamp_origin(PG_FUNCTION_ARGS)
Size
CommitTsShmemBuffers(void)
{
- return Min(16, Max(4, NBuffers / 1024));
+ /* consider 0 and 1 as unset GUC */
+ if (commit_ts_slru_buffers > 1)
+ return commit_ts_slru_buffers;
+ return Min(16, Max(4, NBuffers / 512));
}
/*
diff --git a/src/backend/access/transam/multixact.c b/src/backend/access/transam/multixact.c
index 7dcfa02323..dd7dd19ff4 100644
--- a/src/backend/access/transam/multixact.c
+++ b/src/backend/access/transam/multixact.c
@@ -1831,8 +1831,8 @@ MultiXactShmemSize(void)
mul_size(sizeof(MultiXactId) * 2, MaxOldestSlot))
size = SHARED_MULTIXACT_STATE_SIZE;
- size = add_size(size, SimpleLruShmemSize(NUM_MULTIXACTOFFSET_BUFFERS, 0));
- size = add_size(size, SimpleLruShmemSize(NUM_MULTIXACTMEMBER_BUFFERS, 0));
+ size = add_size(size, SimpleLruShmemSize(multixact_offsets_slru_buffers, 0));
+ size = add_size(size, SimpleLruShmemSize(multixact_members_slru_buffers, 0));
return size;
}
@@ -1848,13 +1848,13 @@ MultiXactShmemInit(void)
MultiXactMemberCtl->PagePrecedes = MultiXactMemberPagePrecedes;
SimpleLruInit(MultiXactOffsetCtl,
- "MultiXactOffset", NUM_MULTIXACTOFFSET_BUFFERS, 0,
+ "MultiXactOffset", multixact_offsets_slru_buffers, 0,
MultiXactOffsetSLRULock, "pg_multixact/offsets",
LWTRANCHE_MULTIXACTOFFSET_BUFFER,
SYNC_HANDLER_MULTIXACT_OFFSET);
SlruPagePrecedesUnitTests(MultiXactOffsetCtl, MULTIXACT_OFFSETS_PER_PAGE);
SimpleLruInit(MultiXactMemberCtl,
- "MultiXactMember", NUM_MULTIXACTMEMBER_BUFFERS, 0,
+ "MultiXactMember", multixact_offsets_slru_buffers, 0,
MultiXactMemberSLRULock, "pg_multixact/members",
LWTRANCHE_MULTIXACTMEMBER_BUFFER,
SYNC_HANDLER_MULTIXACT_MEMBER);
diff --git a/src/backend/access/transam/subtrans.c b/src/backend/access/transam/subtrans.c
index 6a8e521f89..0c24353d3a 100644
--- a/src/backend/access/transam/subtrans.c
+++ b/src/backend/access/transam/subtrans.c
@@ -31,6 +31,7 @@
#include "access/slru.h"
#include "access/subtrans.h"
#include "access/transam.h"
+#include "miscadmin.h"
#include "pg_trace.h"
#include "utils/snapmgr.h"
@@ -184,14 +185,14 @@ SubTransGetTopmostTransaction(TransactionId xid)
Size
SUBTRANSShmemSize(void)
{
- return SimpleLruShmemSize(NUM_SUBTRANS_BUFFERS, 0);
+ return SimpleLruShmemSize(subtrans_slru_buffers, 0);
}
void
SUBTRANSShmemInit(void)
{
SubTransCtl->PagePrecedes = SubTransPagePrecedes;
- SimpleLruInit(SubTransCtl, "Subtrans", NUM_SUBTRANS_BUFFERS, 0,
+ SimpleLruInit(SubTransCtl, "Subtrans", subtrans_slru_buffers, 0,
SubtransSLRULock, "pg_subtrans",
LWTRANCHE_SUBTRANS_BUFFER, SYNC_HANDLER_NONE);
SlruPagePrecedesUnitTests(SubTransCtl, SUBTRANS_XACTS_PER_PAGE);
diff --git a/src/backend/commands/async.c b/src/backend/commands/async.c
index 42b232d98b..a7dd92add0 100644
--- a/src/backend/commands/async.c
+++ b/src/backend/commands/async.c
@@ -107,7 +107,7 @@
* frontend during startup.) The above design guarantees that notifies from
* other backends will never be missed by ignoring self-notifies.
*
- * The amount of shared memory used for notify management (NUM_NOTIFY_BUFFERS)
+ * The amount of shared memory used for notify management (notify_slru_buffers)
* can be varied without affecting anything but performance. The maximum
* amount of notification data that can be queued at one time is determined
* by slru.c's wraparound limit; see QUEUE_MAX_PAGE below.
@@ -225,7 +225,7 @@ typedef struct QueuePosition
*
* Resist the temptation to make this really large. While that would save
* work in some places, it would add cost in others. In particular, this
- * should likely be less than NUM_NOTIFY_BUFFERS, to ensure that backends
+ * should likely be less than notify_slru_buffers, to ensure that backends
* catch up before the pages they'll need to read fall out of SLRU cache.
*/
#define QUEUE_CLEANUP_DELAY 4
@@ -514,7 +514,7 @@ AsyncShmemSize(void)
size = mul_size(MaxBackends + 1, sizeof(QueueBackendStatus));
size = add_size(size, offsetof(AsyncQueueControl, backend));
- size = add_size(size, SimpleLruShmemSize(NUM_NOTIFY_BUFFERS, 0));
+ size = add_size(size, SimpleLruShmemSize(notify_slru_buffers, 0));
return size;
}
@@ -562,7 +562,7 @@ AsyncShmemInit(void)
* Set up SLRU management of the pg_notify data.
*/
NotifyCtl->PagePrecedes = asyncQueuePagePrecedes;
- SimpleLruInit(NotifyCtl, "Notify", NUM_NOTIFY_BUFFERS, 0,
+ SimpleLruInit(NotifyCtl, "Notify", notify_slru_buffers, 0,
NotifySLRULock, "pg_notify", LWTRANCHE_NOTIFY_BUFFER,
SYNC_HANDLER_NONE);
diff --git a/src/backend/storage/lmgr/predicate.c b/src/backend/storage/lmgr/predicate.c
index 074df5b38c..ad6d800dbd 100644
--- a/src/backend/storage/lmgr/predicate.c
+++ b/src/backend/storage/lmgr/predicate.c
@@ -872,7 +872,7 @@ SerialInit(void)
*/
SerialSlruCtl->PagePrecedes = SerialPagePrecedesLogically;
SimpleLruInit(SerialSlruCtl, "Serial",
- NUM_SERIAL_BUFFERS, 0, SerialSLRULock, "pg_serial",
+ serial_slru_buffers, 0, SerialSLRULock, "pg_serial",
LWTRANCHE_SERIAL_BUFFER, SYNC_HANDLER_NONE);
#ifdef USE_ASSERT_CHECKING
SerialPagePrecedesLogicallyUnitTests();
@@ -1395,7 +1395,7 @@ PredicateLockShmemSize(void)
/* Shared memory structures for SLRU tracking of old committed xids. */
size = add_size(size, sizeof(SerialControlData));
- size = add_size(size, SimpleLruShmemSize(NUM_SERIAL_BUFFERS, 0));
+ size = add_size(size, SimpleLruShmemSize(serial_slru_buffers, 0));
return size;
}
diff --git a/src/backend/utils/init/globals.c b/src/backend/utils/init/globals.c
index a5976ad5b1..88e785c246 100644
--- a/src/backend/utils/init/globals.c
+++ b/src/backend/utils/init/globals.c
@@ -150,3 +150,11 @@ int VacuumCostBalance = 0; /* working state for vacuum */
bool VacuumCostActive = false;
double vacuum_cleanup_index_scale_factor;
+
+int multixact_offsets_slru_buffers = 8;
+int multixact_members_slru_buffers = 16;
+int subtrans_slru_buffers = 32;
+int notify_slru_buffers = 8;
+int serial_slru_buffers = 16;
+int clog_slru_buffers = 0;
+int commit_ts_slru_buffers = 0;
diff --git a/src/backend/utils/misc/guc.c b/src/backend/utils/misc/guc.c
index eafdb1118e..d30f85bff8 100644
--- a/src/backend/utils/misc/guc.c
+++ b/src/backend/utils/misc/guc.c
@@ -2269,6 +2269,83 @@ static struct config_int ConfigureNamesInt[] =
NULL, NULL, NULL
},
+ {
+ {"multixact_offsets_slru_buffers", PGC_POSTMASTER, RESOURCES_MEM,
+ gettext_noop("Sets the number of shared memory buffers used for MultiXact offsets SLRU."),
+ NULL,
+ GUC_UNIT_BLOCKS
+ },
+ &multixact_offsets_slru_buffers,
+ 8, 2, INT_MAX / 2,
+ NULL, NULL, NULL
+ },
+
+ {
+ {"multixact_members_slru_buffers", PGC_POSTMASTER, RESOURCES_MEM,
+ gettext_noop("Sets the number of shared memory buffers used for MultiXact members SLRU."),
+ NULL,
+ GUC_UNIT_BLOCKS
+ },
+ &multixact_members_slru_buffers,
+ 16, 2, INT_MAX / 2,
+ NULL, NULL, NULL
+ },
+
+ {
+ {"subtrans_slru_buffers", PGC_POSTMASTER, RESOURCES_MEM,
+ gettext_noop("Sets the number of shared memory buffers used for substrnsactions SLRU."),
+ NULL,
+ GUC_UNIT_BLOCKS
+ },
+ &subtrans_slru_buffers,
+ 32, 2, INT_MAX / 2,
+ NULL, NULL, NULL
+ },
+
+ {
+ {"notify_slru_buffers", PGC_POSTMASTER, RESOURCES_MEM,
+ gettext_noop("Sets the number of shared memory buffers used for asyncronous notifications SLRU."),
+ NULL,
+ GUC_UNIT_BLOCKS
+ },
+ ¬ify_slru_buffers,
+ 8, 2, INT_MAX / 2,
+ NULL, NULL, NULL
+ },
+
+ {
+ {"serial_slru_buffers", PGC_POSTMASTER, RESOURCES_MEM,
+ gettext_noop("Sets the number of shared memory buffers used for predicate locks SLRU."),
+ NULL,
+ GUC_UNIT_BLOCKS
+ },
+ &serial_slru_buffers,
+ 16, 2, INT_MAX / 2,
+ NULL, NULL, NULL
+ },
+
+ {
+ {"clog_slru_buffers", PGC_POSTMASTER, RESOURCES_MEM,
+ gettext_noop("Sets the number of shared memory buffers used for commit log SLRU."),
+ NULL,
+ GUC_UNIT_BLOCKS
+ },
+ &serial_slru_buffers,
+ 0, 0, INT_MAX / 2,
+ NULL, NULL, NULL
+ },
+
+ {
+ {"commit_ts_slru_buffers", PGC_POSTMASTER, RESOURCES_MEM,
+ gettext_noop("Sets the number of shared memory buffers used for commit timestamps SLRU."),
+ NULL,
+ GUC_UNIT_BLOCKS
+ },
+ &commit_ts_slru_buffers,
+ 0, 0, INT_MAX / 2,
+ NULL, NULL, NULL
+ },
+
{
{"temp_buffers", PGC_USERSET, RESOURCES_MEM,
gettext_noop("Sets the maximum number of temporary buffers used by each session."),
diff --git a/src/backend/utils/misc/postgresql.conf.sample b/src/backend/utils/misc/postgresql.conf.sample
index db6db376eb..e88271c048 100644
--- a/src/backend/utils/misc/postgresql.conf.sample
+++ b/src/backend/utils/misc/postgresql.conf.sample
@@ -189,6 +189,22 @@
# (change requires restart)
#backend_flush_after = 0 # measured in pages, 0 disables
+# - SLRU Buffers -
+
+#multixact_offsets_slru_buffers = 8 # memory used for MultiXact offsets
+ # (change requires restart)
+#multixact_members_slru_buffers = 16 # memory used for MultiXact members
+ # (change requires restart)
+#subtrans_slru_buffers = 32 # memory used for subtransactions
+ # (change requires restart)
+#notify_slru_buffers = 8 # memory used for asynchronous notifications
+ # (change requires restart)
+#serial_slru_buffers = 16 # memory used for predicate locks
+ # (change requires restart)
+#clog_slru_buffers = 0 # memory used for CLOG
+ # (change requires restart)
+#commit_ts_slru_buffers = 0 # memory used for commit timestamps
+ # (change requires restart)
#------------------------------------------------------------------------------
# WRITE-AHEAD LOG
diff --git a/src/include/access/multixact.h b/src/include/access/multixact.h
index 4bbb035eae..97c0a46376 100644
--- a/src/include/access/multixact.h
+++ b/src/include/access/multixact.h
@@ -29,10 +29,6 @@
#define MaxMultiXactOffset ((MultiXactOffset) 0xFFFFFFFF)
-/* Number of SLRU buffers to use for multixact */
-#define NUM_MULTIXACTOFFSET_BUFFERS 8
-#define NUM_MULTIXACTMEMBER_BUFFERS 16
-
/*
* Possible multixact lock modes ("status"). The first four modes are for
* tuple locks (FOR KEY SHARE, FOR SHARE, FOR NO KEY UPDATE, FOR UPDATE); the
diff --git a/src/include/access/subtrans.h b/src/include/access/subtrans.h
index d0ab44ae82..ca0999056e 100644
--- a/src/include/access/subtrans.h
+++ b/src/include/access/subtrans.h
@@ -11,9 +11,6 @@
#ifndef SUBTRANS_H
#define SUBTRANS_H
-/* Number of SLRU buffers to use for subtrans */
-#define NUM_SUBTRANS_BUFFERS 32
-
extern void SubTransSetParent(TransactionId xid, TransactionId parent);
extern TransactionId SubTransGetParent(TransactionId xid);
extern TransactionId SubTransGetTopmostTransaction(TransactionId xid);
diff --git a/src/include/commands/async.h b/src/include/commands/async.h
index 9217f66b91..fa831e3721 100644
--- a/src/include/commands/async.h
+++ b/src/include/commands/async.h
@@ -15,11 +15,6 @@
#include <signal.h>
-/*
- * The number of SLRU page buffers we use for the notification queue.
- */
-#define NUM_NOTIFY_BUFFERS 8
-
extern bool Trace_notify;
extern volatile sig_atomic_t notifyInterruptPending;
diff --git a/src/include/miscadmin.h b/src/include/miscadmin.h
index 1bdc97e308..51c7ec8d68 100644
--- a/src/include/miscadmin.h
+++ b/src/include/miscadmin.h
@@ -162,6 +162,14 @@ extern PGDLLIMPORT int MaxBackends;
extern PGDLLIMPORT int MaxConnections;
extern PGDLLIMPORT int max_worker_processes;
extern PGDLLIMPORT int max_parallel_workers;
+extern PGDLLIMPORT int multixact_offsets_slru_buffers;
+extern PGDLLIMPORT int multixact_members_slru_buffers;
+extern PGDLLIMPORT int multixact_members_slru_buffers;
+extern PGDLLIMPORT int subtrans_slru_buffers;
+extern PGDLLIMPORT int notify_slru_buffers;
+extern PGDLLIMPORT int serial_slru_buffers;
+extern PGDLLIMPORT int clog_slru_buffers;
+extern PGDLLIMPORT int commit_ts_slru_buffers;
extern PGDLLIMPORT int MyProcPid;
extern PGDLLIMPORT pg_time_t MyStartTime;
diff --git a/src/include/storage/predicate.h b/src/include/storage/predicate.h
index 152b698611..c72779bd88 100644
--- a/src/include/storage/predicate.h
+++ b/src/include/storage/predicate.h
@@ -26,10 +26,6 @@ extern int max_predicate_locks_per_xact;
extern int max_predicate_locks_per_relation;
extern int max_predicate_locks_per_page;
-
-/* Number of SLRU buffers to use for Serial SLRU */
-#define NUM_SERIAL_BUFFERS 16
-
/*
* A handle used for sharing SERIALIZABLEXACT objects between the participants
* in a parallel query.
--
2.24.3 (Apple Git-128)
^ permalink raw reply [nested|flat] 90+ messages in thread
* Re: MultiXact\SLRU buffers configuration
2020-05-08 16:36 MultiXact\SLRU buffers configuration Andrey M. Borodin <[email protected]>
2020-05-11 11:17 ` Re: MultiXact\SLRU buffers configuration Andrey M. Borodin <[email protected]>
2020-05-13 18:08 ` Re: MultiXact\SLRU buffers configuration Andrey M. Borodin <[email protected]>
2020-05-14 01:25 ` Re: MultiXact\SLRU buffers configuration Kyotaro Horiguchi <[email protected]>
2020-05-14 05:19 ` Re: MultiXact\SLRU buffers configuration Andrey M. Borodin <[email protected]>
2020-05-14 06:16 ` Re: MultiXact\SLRU buffers configuration Kyotaro Horiguchi <[email protected]>
2020-05-14 06:44 ` Re: MultiXact\SLRU buffers configuration Andrey M. Borodin <[email protected]>
2020-05-15 00:03 ` Re: MultiXact\SLRU buffers configuration Kyotaro Horiguchi <[email protected]>
2020-07-02 12:02 ` Re: MultiXact\SLRU buffers configuration Daniel Gustafsson <[email protected]>
2020-07-08 07:03 ` Re: MultiXact\SLRU buffers configuration Andrey M. Borodin <[email protected]>
2020-08-28 18:08 ` Re: MultiXact\SLRU buffers configuration Anastasia Lubennikova <[email protected]>
2020-09-28 14:41 ` Re: MultiXact\SLRU buffers configuration Andrey M. Borodin <[email protected]>
2020-10-26 01:05 ` Re: MultiXact\SLRU buffers configuration Alexander Korotkov <[email protected]>
2020-10-26 15:45 ` Re: MultiXact\SLRU buffers configuration Andrey Borodin <[email protected]>
2020-10-27 17:02 ` Re: MultiXact\SLRU buffers configuration Alexander Korotkov <[email protected]>
2020-10-27 17:23 ` Re: MultiXact\SLRU buffers configuration Alexander Korotkov <[email protected]>
2020-10-28 01:36 ` Re: MultiXact\SLRU buffers configuration Tomas Vondra <[email protected]>
2020-10-28 07:34 ` Re: MultiXact\SLRU buffers configuration Andrey Borodin <[email protected]>
2020-10-28 23:32 ` Re: MultiXact\SLRU buffers configuration Tomas Vondra <[email protected]>
2020-10-29 07:08 ` Re: MultiXact\SLRU buffers configuration Andrey Borodin <[email protected]>
2020-10-29 13:49 ` Re: MultiXact\SLRU buffers configuration Tomas Vondra <[email protected]>
2020-11-02 12:45 ` Re: MultiXact\SLRU buffers configuration Andrey Borodin <[email protected]>
2020-11-10 00:13 ` Re: MultiXact\SLRU buffers configuration Tomas Vondra <[email protected]>
2020-11-10 06:16 ` Re: MultiXact\SLRU buffers configuration Andrey Borodin <[email protected]>
2020-11-10 18:07 ` Re: MultiXact\SLRU buffers configuration Tomas Vondra <[email protected]>
2020-11-13 11:49 ` Re: MultiXact\SLRU buffers configuration Andrey Borodin <[email protected]>
2020-12-08 16:05 ` Re: MultiXact\SLRU buffers configuration Gilles Darold <[email protected]>
2020-12-08 17:52 ` Re: MultiXact\SLRU buffers configuration Andrey Borodin <[email protected]>
2020-12-10 14:45 ` Re: MultiXact\SLRU buffers configuration Gilles Darold <[email protected]>
2020-12-11 17:50 ` Re: MultiXact\SLRU buffers configuration Gilles Darold <[email protected]>
2020-12-13 09:17 ` Re: MultiXact\SLRU buffers configuration Gilles Darold <[email protected]>
2020-12-13 17:24 ` Re: MultiXact\SLRU buffers configuration Andrey Borodin <[email protected]>
2020-12-23 16:31 ` Re: MultiXact\SLRU buffers configuration Gilles Darold <[email protected]>
2021-02-15 17:17 ` Re: MultiXact\SLRU buffers configuration Andrey Borodin <[email protected]>
@ 2021-03-11 15:50 ` Gilles Darold <[email protected]>
2021-03-12 12:44 ` Re: MultiXact\SLRU buffers configuration Andrey Borodin <[email protected]>
0 siblings, 1 reply; 90+ messages in thread
From: Gilles Darold @ 2021-03-11 15:50 UTC (permalink / raw)
To: Andrey Borodin <[email protected]>; +Cc: Tomas Vondra <[email protected]>; Tomas Vondra <[email protected]>; Alexander Korotkov <[email protected]>; Anastasia Lubennikova <[email protected]>; Daniel Gustafsson <[email protected]>; Kyotaro Horiguchi <[email protected]>; pgsql-hackers
Le 15/02/2021 à 18:17, Andrey Borodin a écrit :
>
>> 23 дек. 2020 г., в 21:31, Gilles Darold <[email protected]> написал(а):
>>
>> Sorry for the response delay, we have run several others tests trying to figure out the performances gain per patch but unfortunately we have very heratic results. With the same parameters and patches the test doesn't returns the same results following the day or the hour of the day. This is very frustrating and I suppose that this is related to the Azure architecture. The only thing that I am sure is that we had the best performances results with all patches and
>>
>> multixact_offsets_slru_buffers = 256
>> multixact_members_slru_buffers = 512
>> multixact_local_cache_entries = 4096
>>
>>
>> but I can not say if all or part of the patches are improving the performances. My feeling is that performances gain related to patches 1 (shared lock) and 3 (conditional variable) do not have much to do with the performances gain compared to just tuning the multixact buffers. This is when the multixact contention is observed but perhaps they are delaying the contention. It's all the more frustrating that we had a test case to reproduce the contention but not the architecture apparently.
> Hi! Thanks for the input.
> I think we have a consensus here that configuring SLRU size is beneficial for MultiXacts.
> There is proposal in nearby thread [0] on changing default value of commit_ts SLRU buffers.
> In my experience from time to time there can be problems with subtransactions cured by extending subtrans SLRU.
>
> Let's make all SLRUs configurable?
> PFA patch with draft of these changes.
>
> Best regards, Andrey Borodin.
>
>
> [0] https://www.postgresql.org/message-id/flat/20210115220744.GA24457%40alvherre.pgsql
>
The patch doesn't apply anymore in master cause of error: patch failed:
src/backend/utils/init/globals.c:150
An other remark about this patch is that it should be mentionned in the
documentation (doc/src/sgml/config.sgml) that the new configuration
variables need a server restart, for example by adding "This parameter
can only be set at server start." like for shared_buffers. Patch on
postgresql.conf mention it.
And some typo to be fixed:
s/Tipically/Typically/
s/asincronous/asyncronous/
s/confugured/configured/
s/substrnsactions/substransactions/
--
Gilles Darold
LzLabs GmbH
^ permalink raw reply [nested|flat] 90+ messages in thread
* Re: MultiXact\SLRU buffers configuration
2020-05-08 16:36 MultiXact\SLRU buffers configuration Andrey M. Borodin <[email protected]>
2020-05-11 11:17 ` Re: MultiXact\SLRU buffers configuration Andrey M. Borodin <[email protected]>
2020-05-13 18:08 ` Re: MultiXact\SLRU buffers configuration Andrey M. Borodin <[email protected]>
2020-05-14 01:25 ` Re: MultiXact\SLRU buffers configuration Kyotaro Horiguchi <[email protected]>
2020-05-14 05:19 ` Re: MultiXact\SLRU buffers configuration Andrey M. Borodin <[email protected]>
2020-05-14 06:16 ` Re: MultiXact\SLRU buffers configuration Kyotaro Horiguchi <[email protected]>
2020-05-14 06:44 ` Re: MultiXact\SLRU buffers configuration Andrey M. Borodin <[email protected]>
2020-05-15 00:03 ` Re: MultiXact\SLRU buffers configuration Kyotaro Horiguchi <[email protected]>
2020-07-02 12:02 ` Re: MultiXact\SLRU buffers configuration Daniel Gustafsson <[email protected]>
2020-07-08 07:03 ` Re: MultiXact\SLRU buffers configuration Andrey M. Borodin <[email protected]>
2020-08-28 18:08 ` Re: MultiXact\SLRU buffers configuration Anastasia Lubennikova <[email protected]>
2020-09-28 14:41 ` Re: MultiXact\SLRU buffers configuration Andrey M. Borodin <[email protected]>
2020-10-26 01:05 ` Re: MultiXact\SLRU buffers configuration Alexander Korotkov <[email protected]>
2020-10-26 15:45 ` Re: MultiXact\SLRU buffers configuration Andrey Borodin <[email protected]>
2020-10-27 17:02 ` Re: MultiXact\SLRU buffers configuration Alexander Korotkov <[email protected]>
2020-10-27 17:23 ` Re: MultiXact\SLRU buffers configuration Alexander Korotkov <[email protected]>
2020-10-28 01:36 ` Re: MultiXact\SLRU buffers configuration Tomas Vondra <[email protected]>
2020-10-28 07:34 ` Re: MultiXact\SLRU buffers configuration Andrey Borodin <[email protected]>
2020-10-28 23:32 ` Re: MultiXact\SLRU buffers configuration Tomas Vondra <[email protected]>
2020-10-29 07:08 ` Re: MultiXact\SLRU buffers configuration Andrey Borodin <[email protected]>
2020-10-29 13:49 ` Re: MultiXact\SLRU buffers configuration Tomas Vondra <[email protected]>
2020-11-02 12:45 ` Re: MultiXact\SLRU buffers configuration Andrey Borodin <[email protected]>
2020-11-10 00:13 ` Re: MultiXact\SLRU buffers configuration Tomas Vondra <[email protected]>
2020-11-10 06:16 ` Re: MultiXact\SLRU buffers configuration Andrey Borodin <[email protected]>
2020-11-10 18:07 ` Re: MultiXact\SLRU buffers configuration Tomas Vondra <[email protected]>
2020-11-13 11:49 ` Re: MultiXact\SLRU buffers configuration Andrey Borodin <[email protected]>
2020-12-08 16:05 ` Re: MultiXact\SLRU buffers configuration Gilles Darold <[email protected]>
2020-12-08 17:52 ` Re: MultiXact\SLRU buffers configuration Andrey Borodin <[email protected]>
2020-12-10 14:45 ` Re: MultiXact\SLRU buffers configuration Gilles Darold <[email protected]>
2020-12-11 17:50 ` Re: MultiXact\SLRU buffers configuration Gilles Darold <[email protected]>
2020-12-13 09:17 ` Re: MultiXact\SLRU buffers configuration Gilles Darold <[email protected]>
2020-12-13 17:24 ` Re: MultiXact\SLRU buffers configuration Andrey Borodin <[email protected]>
2020-12-23 16:31 ` Re: MultiXact\SLRU buffers configuration Gilles Darold <[email protected]>
2021-02-15 17:17 ` Re: MultiXact\SLRU buffers configuration Andrey Borodin <[email protected]>
2021-03-11 15:50 ` Re: MultiXact\SLRU buffers configuration Gilles Darold <[email protected]>
@ 2021-03-12 12:44 ` Andrey Borodin <[email protected]>
2021-03-15 15:41 ` Re: MultiXact\SLRU buffers configuration Gilles Darold <[email protected]>
2021-03-24 21:31 ` Re: MultiXact\SLRU buffers configuration Thomas Munro <[email protected]>
0 siblings, 2 replies; 90+ messages in thread
From: Andrey Borodin @ 2021-03-12 12:44 UTC (permalink / raw)
To: Gilles Darold <[email protected]>; +Cc: Tomas Vondra <[email protected]>; Tomas Vondra <[email protected]>; Alexander Korotkov <[email protected]>; Anastasia Lubennikova <[email protected]>; Daniel Gustafsson <[email protected]>; Kyotaro Horiguchi <[email protected]>; pgsql-hackers
> 11 марта 2021 г., в 20:50, Gilles Darold <[email protected]> написал(а):
>
>
> The patch doesn't apply anymore in master cause of error: patch failed: src/backend/utils/init/globals.c:150
>
>
>
> An other remark about this patch is that it should be mentionned in the documentation (doc/src/sgml/config.sgml) that the new configuration variables need a server restart, for example by adding "This parameter can only be set at server start." like for shared_buffers. Patch on postgresql.conf mention it.
>
> And some typo to be fixed:
>
>
>
> s/Tipically/Typically/
>
> s/asincronous/asyncronous/
>
> s/confugured/configured/
>
> s/substrnsactions/substransactions/
>
>
Thanks, Gilles! Fixed.
Best regards, Andrey Borodin.
Attachments:
[application/octet-stream] v10-0001-Make-all-SLRU-buffer-sizes-configurable.patch (19.5K, ../../[email protected]/2-v10-0001-Make-all-SLRU-buffer-sizes-configurable.patch)
download | inline diff:
From 02c5d56a65a187b0795fac246a77f9cf3107ed3b Mon Sep 17 00:00:00 2001
From: Andrey Borodin <[email protected]>
Date: Mon, 15 Feb 2021 21:51:56 +0500
Subject: [PATCH v10] Make all SLRU buffer sizes configurable
---
doc/src/sgml/config.sgml | 108 ++++++++++++++++++
src/backend/access/transam/clog.c | 6 +
src/backend/access/transam/commit_ts.c | 5 +-
src/backend/access/transam/multixact.c | 8 +-
src/backend/access/transam/subtrans.c | 5 +-
src/backend/commands/async.c | 8 +-
src/backend/storage/lmgr/predicate.c | 4 +-
src/backend/utils/init/globals.c | 8 ++
src/backend/utils/misc/guc.c | 77 +++++++++++++
src/backend/utils/misc/postgresql.conf.sample | 16 +++
src/include/access/multixact.h | 4 -
src/include/access/subtrans.h | 3 -
src/include/commands/async.h | 5 -
src/include/miscadmin.h | 8 ++
src/include/storage/predicate.h | 4 -
15 files changed, 240 insertions(+), 29 deletions(-)
diff --git a/doc/src/sgml/config.sgml b/doc/src/sgml/config.sgml
index a218d78bef..eb7f8f3c49 100644
--- a/doc/src/sgml/config.sgml
+++ b/doc/src/sgml/config.sgml
@@ -1886,6 +1886,114 @@ include_dir 'conf.d'
</para>
</listitem>
</varlistentry>
+
+ <varlistentry id="guc-multixact-offsets-slru-buffers" xreflabel="multixact_offsets_slru_buffers">
+ <term><varname>multixact_offsets_slru_buffers</varname> (<type>integer</type>)
+ <indexterm>
+ <primary><varname>multixact_offsets_slru_buffers</varname> configuration parameter</primary>
+ </indexterm>
+ </term>
+ <listitem>
+ <para>
+ Specifies the amount of memory to be used for MultiXact offsets. MultiXact offsets
+ are used to store information about offsets of multiple row lockers (caused by SELECT FOR UPDATE and others).
+ It defaults to 64 kilobytes (<literal>64KB</literal>).
+ This parameter can only be set at server start.
+ </para>
+ </listitem>
+ </varlistentry>
+
+ <varlistentry id="guc-multixact-members-slru-buffers" xreflabel="multixact_members_slru_buffers">
+ <term><varname>multixact_members_slru_buffers</varname> (<type>integer</type>)
+ <indexterm>
+ <primary><varname>multixact_members_slru_buffers</varname> configuration parameter</primary>
+ </indexterm>
+ </term>
+ <listitem>
+ <para>
+ Specifies the amount of memory to be used for MultiXact members. MultiXact members
+ are used to store information about XIDs of multiple row lockers. Typically <varname>multixact_members_slru_buffers</varname>
+ is twice more than <varname>multixact_offsets_slru_buffers</varname>.
+ It defaults to 128 kilobytes (<literal>128KB</literal>).
+ This parameter can only be set at server start.
+ </para>
+ </listitem>
+ </varlistentry>
+
+ <varlistentry id="guc-subtrans-buffers" xreflabel="subtrans_slru_buffers">
+ <term><varname>subtrans_slru_buffers</varname> (<type>integer</type>)
+ <indexterm>
+ <primary><varname>subtrans_slru_buffers</varname> configuration parameter</primary>
+ </indexterm>
+ </term>
+ <listitem>
+ <para>
+ Specifies the amount of memory to be used for subtransactions.
+ It defaults to 256 kilobytes (<literal>256KB</literal>).
+ This parameter can only be set at server start.
+ </para>
+ </listitem>
+ </varlistentry>
+
+ <varlistentry id="guc-notify-buffers" xreflabel="notify_slru_buffers">
+ <term><varname>notify_slru_buffers</varname> (<type>integer</type>)
+ <indexterm>
+ <primary><varname>notify_slru_buffers</varname> configuration parameter</primary>
+ </indexterm>
+ </term>
+ <listitem>
+ <para>
+ Specifies the amount of memory to be used for asyncronous notifications (NOTIFY, LISTEN).
+ It defaults to 64 kilobytes (<literal>64KB</literal>).
+ This parameter can only be set at server start.
+ </para>
+ </listitem>
+ </varlistentry>
+
+ <varlistentry id="guc-serial-buffers" xreflabel="serial_slru_buffers">
+ <term><varname>serial_slru_buffers</varname> (<type>integer</type>)
+ <indexterm>
+ <primary><varname>serial_slru_buffers</varname> configuration parameter</primary>
+ </indexterm>
+ </term>
+ <listitem>
+ <para>
+ Specifies the amount of memory to be used for predicate locks.
+ It defaults to 128 kilobytes (<literal>128KB</literal>).
+ This parameter can only be set at server start.
+ </para>
+ </listitem>
+ </varlistentry>
+
+ <varlistentry id="guc-clog-buffers" xreflabel="clog_slru_buffers">
+ <term><varname>clog_slru_buffers</varname> (<type>integer</type>)
+ <indexterm>
+ <primary><varname>clog_slru_buffers</varname> configuration parameter</primary>
+ </indexterm>
+ </term>
+ <listitem>
+ <para>
+ Specifies the amount of memory to be used for CLOG.
+ It defaults to 0, in this case CLOG size is taken as <varname>shared_buffers</varname> / 512.
+ This parameter can only be set at server start.
+ </para>
+ </listitem>
+ </varlistentry>
+
+ <varlistentry id="guc-commit-ts-buffers" xreflabel="commit_ts_slru_buffers">
+ <term><varname>commit_ts_slru_buffers</varname> (<type>integer</type>)
+ <indexterm>
+ <primary><varname>commit_ts_slru_buffers</varname> configuration parameter</primary>
+ </indexterm>
+ </term>
+ <listitem>
+ <para>
+ Specifies the amount of memory to be used for commit timestamps.
+ It defaults to 0, in this case CLOG size is taken as <varname>shared_buffers</varname> / 512.
+ This parameter can only be set at server start.
+ </para>
+ </listitem>
+ </varlistentry>
<varlistentry id="guc-max-stack-depth" xreflabel="max_stack_depth">
<term><varname>max_stack_depth</varname> (<type>integer</type>)
diff --git a/src/backend/access/transam/clog.c b/src/backend/access/transam/clog.c
index 6fa4713fb4..e1d34aa361 100644
--- a/src/backend/access/transam/clog.c
+++ b/src/backend/access/transam/clog.c
@@ -659,6 +659,9 @@ TransactionIdGetStatus(TransactionId xid, XLogRecPtr *lsn)
/*
* Number of shared CLOG buffers.
*
+ * If values is configured via GUC - just use given value. Otherwise
+ * apply following euristics.
+ *
* On larger multi-processor systems, it is possible to have many CLOG page
* requests in flight at one time which could lead to disk access for CLOG
* page if the required page is not found in memory. Testing revealed that we
@@ -675,6 +678,9 @@ TransactionIdGetStatus(TransactionId xid, XLogRecPtr *lsn)
Size
CLOGShmemBuffers(void)
{
+ /* consider 0 and 1 as unset GUC */
+ if (clog_slru_buffers > 1)
+ return clog_slru_buffers;
return Min(128, Max(4, NBuffers / 512));
}
diff --git a/src/backend/access/transam/commit_ts.c b/src/backend/access/transam/commit_ts.c
index 48e8d66286..7de3bca63d 100644
--- a/src/backend/access/transam/commit_ts.c
+++ b/src/backend/access/transam/commit_ts.c
@@ -530,7 +530,10 @@ pg_xact_commit_timestamp_origin(PG_FUNCTION_ARGS)
Size
CommitTsShmemBuffers(void)
{
- return Min(16, Max(4, NBuffers / 1024));
+ /* consider 0 and 1 as unset GUC */
+ if (commit_ts_slru_buffers > 1)
+ return commit_ts_slru_buffers;
+ return Min(16, Max(4, NBuffers / 512));
}
/*
diff --git a/src/backend/access/transam/multixact.c b/src/backend/access/transam/multixact.c
index 1f9f1a1fa1..370c01e72b 100644
--- a/src/backend/access/transam/multixact.c
+++ b/src/backend/access/transam/multixact.c
@@ -1831,8 +1831,8 @@ MultiXactShmemSize(void)
mul_size(sizeof(MultiXactId) * 2, MaxOldestSlot))
size = SHARED_MULTIXACT_STATE_SIZE;
- size = add_size(size, SimpleLruShmemSize(NUM_MULTIXACTOFFSET_BUFFERS, 0));
- size = add_size(size, SimpleLruShmemSize(NUM_MULTIXACTMEMBER_BUFFERS, 0));
+ size = add_size(size, SimpleLruShmemSize(multixact_offsets_slru_buffers, 0));
+ size = add_size(size, SimpleLruShmemSize(multixact_members_slru_buffers, 0));
return size;
}
@@ -1848,13 +1848,13 @@ MultiXactShmemInit(void)
MultiXactMemberCtl->PagePrecedes = MultiXactMemberPagePrecedes;
SimpleLruInit(MultiXactOffsetCtl,
- "MultiXactOffset", NUM_MULTIXACTOFFSET_BUFFERS, 0,
+ "MultiXactOffset", multixact_offsets_slru_buffers, 0,
MultiXactOffsetSLRULock, "pg_multixact/offsets",
LWTRANCHE_MULTIXACTOFFSET_BUFFER,
SYNC_HANDLER_MULTIXACT_OFFSET);
SlruPagePrecedesUnitTests(MultiXactOffsetCtl, MULTIXACT_OFFSETS_PER_PAGE);
SimpleLruInit(MultiXactMemberCtl,
- "MultiXactMember", NUM_MULTIXACTMEMBER_BUFFERS, 0,
+ "MultiXactMember", multixact_offsets_slru_buffers, 0,
MultiXactMemberSLRULock, "pg_multixact/members",
LWTRANCHE_MULTIXACTMEMBER_BUFFER,
SYNC_HANDLER_MULTIXACT_MEMBER);
diff --git a/src/backend/access/transam/subtrans.c b/src/backend/access/transam/subtrans.c
index 6a8e521f89..0c24353d3a 100644
--- a/src/backend/access/transam/subtrans.c
+++ b/src/backend/access/transam/subtrans.c
@@ -31,6 +31,7 @@
#include "access/slru.h"
#include "access/subtrans.h"
#include "access/transam.h"
+#include "miscadmin.h"
#include "pg_trace.h"
#include "utils/snapmgr.h"
@@ -184,14 +185,14 @@ SubTransGetTopmostTransaction(TransactionId xid)
Size
SUBTRANSShmemSize(void)
{
- return SimpleLruShmemSize(NUM_SUBTRANS_BUFFERS, 0);
+ return SimpleLruShmemSize(subtrans_slru_buffers, 0);
}
void
SUBTRANSShmemInit(void)
{
SubTransCtl->PagePrecedes = SubTransPagePrecedes;
- SimpleLruInit(SubTransCtl, "Subtrans", NUM_SUBTRANS_BUFFERS, 0,
+ SimpleLruInit(SubTransCtl, "Subtrans", subtrans_slru_buffers, 0,
SubtransSLRULock, "pg_subtrans",
LWTRANCHE_SUBTRANS_BUFFER, SYNC_HANDLER_NONE);
SlruPagePrecedesUnitTests(SubTransCtl, SUBTRANS_XACTS_PER_PAGE);
diff --git a/src/backend/commands/async.c b/src/backend/commands/async.c
index 4b16fb5682..f5c5592057 100644
--- a/src/backend/commands/async.c
+++ b/src/backend/commands/async.c
@@ -107,7 +107,7 @@
* frontend during startup.) The above design guarantees that notifies from
* other backends will never be missed by ignoring self-notifies.
*
- * The amount of shared memory used for notify management (NUM_NOTIFY_BUFFERS)
+ * The amount of shared memory used for notify management (notify_slru_buffers)
* can be varied without affecting anything but performance. The maximum
* amount of notification data that can be queued at one time is determined
* by slru.c's wraparound limit; see QUEUE_MAX_PAGE below.
@@ -225,7 +225,7 @@ typedef struct QueuePosition
*
* Resist the temptation to make this really large. While that would save
* work in some places, it would add cost in others. In particular, this
- * should likely be less than NUM_NOTIFY_BUFFERS, to ensure that backends
+ * should likely be less than notify_slru_buffers, to ensure that backends
* catch up before the pages they'll need to read fall out of SLRU cache.
*/
#define QUEUE_CLEANUP_DELAY 4
@@ -514,7 +514,7 @@ AsyncShmemSize(void)
size = mul_size(MaxBackends + 1, sizeof(QueueBackendStatus));
size = add_size(size, offsetof(AsyncQueueControl, backend));
- size = add_size(size, SimpleLruShmemSize(NUM_NOTIFY_BUFFERS, 0));
+ size = add_size(size, SimpleLruShmemSize(notify_slru_buffers, 0));
return size;
}
@@ -562,7 +562,7 @@ AsyncShmemInit(void)
* Set up SLRU management of the pg_notify data.
*/
NotifyCtl->PagePrecedes = asyncQueuePagePrecedes;
- SimpleLruInit(NotifyCtl, "Notify", NUM_NOTIFY_BUFFERS, 0,
+ SimpleLruInit(NotifyCtl, "Notify", notify_slru_buffers, 0,
NotifySLRULock, "pg_notify", LWTRANCHE_NOTIFY_BUFFER,
SYNC_HANDLER_NONE);
diff --git a/src/backend/storage/lmgr/predicate.c b/src/backend/storage/lmgr/predicate.c
index d493aeef0f..fad8cc572e 100644
--- a/src/backend/storage/lmgr/predicate.c
+++ b/src/backend/storage/lmgr/predicate.c
@@ -872,7 +872,7 @@ SerialInit(void)
*/
SerialSlruCtl->PagePrecedes = SerialPagePrecedesLogically;
SimpleLruInit(SerialSlruCtl, "Serial",
- NUM_SERIAL_BUFFERS, 0, SerialSLRULock, "pg_serial",
+ serial_slru_buffers, 0, SerialSLRULock, "pg_serial",
LWTRANCHE_SERIAL_BUFFER, SYNC_HANDLER_NONE);
#ifdef USE_ASSERT_CHECKING
SerialPagePrecedesLogicallyUnitTests();
@@ -1395,7 +1395,7 @@ PredicateLockShmemSize(void)
/* Shared memory structures for SLRU tracking of old committed xids. */
size = add_size(size, sizeof(SerialControlData));
- size = add_size(size, SimpleLruShmemSize(NUM_SERIAL_BUFFERS, 0));
+ size = add_size(size, SimpleLruShmemSize(serial_slru_buffers, 0));
return size;
}
diff --git a/src/backend/utils/init/globals.c b/src/backend/utils/init/globals.c
index 73e0a672ae..f163ca17e9 100644
--- a/src/backend/utils/init/globals.c
+++ b/src/backend/utils/init/globals.c
@@ -148,3 +148,11 @@ int64 VacuumPageDirty = 0;
int VacuumCostBalance = 0; /* working state for vacuum */
bool VacuumCostActive = false;
+
+int multixact_offsets_slru_buffers = 8;
+int multixact_members_slru_buffers = 16;
+int subtrans_slru_buffers = 32;
+int notify_slru_buffers = 8;
+int serial_slru_buffers = 16;
+int clog_slru_buffers = 0;
+int commit_ts_slru_buffers = 0;
diff --git a/src/backend/utils/misc/guc.c b/src/backend/utils/misc/guc.c
index 855076b1fd..080b3a9b35 100644
--- a/src/backend/utils/misc/guc.c
+++ b/src/backend/utils/misc/guc.c
@@ -2279,6 +2279,83 @@ static struct config_int ConfigureNamesInt[] =
NULL, NULL, NULL
},
+ {
+ {"multixact_offsets_slru_buffers", PGC_POSTMASTER, RESOURCES_MEM,
+ gettext_noop("Sets the number of shared memory buffers used for MultiXact offsets SLRU."),
+ NULL,
+ GUC_UNIT_BLOCKS
+ },
+ &multixact_offsets_slru_buffers,
+ 8, 2, INT_MAX / 2,
+ NULL, NULL, NULL
+ },
+
+ {
+ {"multixact_members_slru_buffers", PGC_POSTMASTER, RESOURCES_MEM,
+ gettext_noop("Sets the number of shared memory buffers used for MultiXact members SLRU."),
+ NULL,
+ GUC_UNIT_BLOCKS
+ },
+ &multixact_members_slru_buffers,
+ 16, 2, INT_MAX / 2,
+ NULL, NULL, NULL
+ },
+
+ {
+ {"subtrans_slru_buffers", PGC_POSTMASTER, RESOURCES_MEM,
+ gettext_noop("Sets the number of shared memory buffers used for substransactions SLRU."),
+ NULL,
+ GUC_UNIT_BLOCKS
+ },
+ &subtrans_slru_buffers,
+ 32, 2, INT_MAX / 2,
+ NULL, NULL, NULL
+ },
+
+ {
+ {"notify_slru_buffers", PGC_POSTMASTER, RESOURCES_MEM,
+ gettext_noop("Sets the number of shared memory buffers used for asyncronous notifications SLRU."),
+ NULL,
+ GUC_UNIT_BLOCKS
+ },
+ ¬ify_slru_buffers,
+ 8, 2, INT_MAX / 2,
+ NULL, NULL, NULL
+ },
+
+ {
+ {"serial_slru_buffers", PGC_POSTMASTER, RESOURCES_MEM,
+ gettext_noop("Sets the number of shared memory buffers used for predicate locks SLRU."),
+ NULL,
+ GUC_UNIT_BLOCKS
+ },
+ &serial_slru_buffers,
+ 16, 2, INT_MAX / 2,
+ NULL, NULL, NULL
+ },
+
+ {
+ {"clog_slru_buffers", PGC_POSTMASTER, RESOURCES_MEM,
+ gettext_noop("Sets the number of shared memory buffers used for commit log SLRU."),
+ NULL,
+ GUC_UNIT_BLOCKS
+ },
+ &serial_slru_buffers,
+ 0, 0, INT_MAX / 2,
+ NULL, NULL, NULL
+ },
+
+ {
+ {"commit_ts_slru_buffers", PGC_POSTMASTER, RESOURCES_MEM,
+ gettext_noop("Sets the number of shared memory buffers used for commit timestamps SLRU."),
+ NULL,
+ GUC_UNIT_BLOCKS
+ },
+ &commit_ts_slru_buffers,
+ 0, 0, INT_MAX / 2,
+ NULL, NULL, NULL
+ },
+
{
{"temp_buffers", PGC_USERSET, RESOURCES_MEM,
gettext_noop("Sets the maximum number of temporary buffers used by each session."),
diff --git a/src/backend/utils/misc/postgresql.conf.sample b/src/backend/utils/misc/postgresql.conf.sample
index f46c2dd7a8..9ee7d17e8b 100644
--- a/src/backend/utils/misc/postgresql.conf.sample
+++ b/src/backend/utils/misc/postgresql.conf.sample
@@ -190,6 +190,22 @@
# (change requires restart)
#backend_flush_after = 0 # measured in pages, 0 disables
+# - SLRU Buffers -
+
+#multixact_offsets_slru_buffers = 8 # memory used for MultiXact offsets
+ # (change requires restart)
+#multixact_members_slru_buffers = 16 # memory used for MultiXact members
+ # (change requires restart)
+#subtrans_slru_buffers = 32 # memory used for subtransactions
+ # (change requires restart)
+#notify_slru_buffers = 8 # memory used for asynchronous notifications
+ # (change requires restart)
+#serial_slru_buffers = 16 # memory used for predicate locks
+ # (change requires restart)
+#clog_slru_buffers = 0 # memory used for CLOG
+ # (change requires restart)
+#commit_ts_slru_buffers = 0 # memory used for commit timestamps
+ # (change requires restart)
#------------------------------------------------------------------------------
# WRITE-AHEAD LOG
diff --git a/src/include/access/multixact.h b/src/include/access/multixact.h
index 4bbb035eae..97c0a46376 100644
--- a/src/include/access/multixact.h
+++ b/src/include/access/multixact.h
@@ -29,10 +29,6 @@
#define MaxMultiXactOffset ((MultiXactOffset) 0xFFFFFFFF)
-/* Number of SLRU buffers to use for multixact */
-#define NUM_MULTIXACTOFFSET_BUFFERS 8
-#define NUM_MULTIXACTMEMBER_BUFFERS 16
-
/*
* Possible multixact lock modes ("status"). The first four modes are for
* tuple locks (FOR KEY SHARE, FOR SHARE, FOR NO KEY UPDATE, FOR UPDATE); the
diff --git a/src/include/access/subtrans.h b/src/include/access/subtrans.h
index d0ab44ae82..ca0999056e 100644
--- a/src/include/access/subtrans.h
+++ b/src/include/access/subtrans.h
@@ -11,9 +11,6 @@
#ifndef SUBTRANS_H
#define SUBTRANS_H
-/* Number of SLRU buffers to use for subtrans */
-#define NUM_SUBTRANS_BUFFERS 32
-
extern void SubTransSetParent(TransactionId xid, TransactionId parent);
extern TransactionId SubTransGetParent(TransactionId xid);
extern TransactionId SubTransGetTopmostTransaction(TransactionId xid);
diff --git a/src/include/commands/async.h b/src/include/commands/async.h
index 9217f66b91..fa831e3721 100644
--- a/src/include/commands/async.h
+++ b/src/include/commands/async.h
@@ -15,11 +15,6 @@
#include <signal.h>
-/*
- * The number of SLRU page buffers we use for the notification queue.
- */
-#define NUM_NOTIFY_BUFFERS 8
-
extern bool Trace_notify;
extern volatile sig_atomic_t notifyInterruptPending;
diff --git a/src/include/miscadmin.h b/src/include/miscadmin.h
index 54693e047a..ca88b20ffa 100644
--- a/src/include/miscadmin.h
+++ b/src/include/miscadmin.h
@@ -162,6 +162,14 @@ extern PGDLLIMPORT int MaxBackends;
extern PGDLLIMPORT int MaxConnections;
extern PGDLLIMPORT int max_worker_processes;
extern PGDLLIMPORT int max_parallel_workers;
+extern PGDLLIMPORT int multixact_offsets_slru_buffers;
+extern PGDLLIMPORT int multixact_members_slru_buffers;
+extern PGDLLIMPORT int multixact_members_slru_buffers;
+extern PGDLLIMPORT int subtrans_slru_buffers;
+extern PGDLLIMPORT int notify_slru_buffers;
+extern PGDLLIMPORT int serial_slru_buffers;
+extern PGDLLIMPORT int clog_slru_buffers;
+extern PGDLLIMPORT int commit_ts_slru_buffers;
extern PGDLLIMPORT int MyProcPid;
extern PGDLLIMPORT pg_time_t MyStartTime;
diff --git a/src/include/storage/predicate.h b/src/include/storage/predicate.h
index 152b698611..c72779bd88 100644
--- a/src/include/storage/predicate.h
+++ b/src/include/storage/predicate.h
@@ -26,10 +26,6 @@ extern int max_predicate_locks_per_xact;
extern int max_predicate_locks_per_relation;
extern int max_predicate_locks_per_page;
-
-/* Number of SLRU buffers to use for Serial SLRU */
-#define NUM_SERIAL_BUFFERS 16
-
/*
* A handle used for sharing SERIALIZABLEXACT objects between the participants
* in a parallel query.
--
2.24.3 (Apple Git-128)
^ permalink raw reply [nested|flat] 90+ messages in thread
* Re: MultiXact\SLRU buffers configuration
2020-05-08 16:36 MultiXact\SLRU buffers configuration Andrey M. Borodin <[email protected]>
2020-05-11 11:17 ` Re: MultiXact\SLRU buffers configuration Andrey M. Borodin <[email protected]>
2020-05-13 18:08 ` Re: MultiXact\SLRU buffers configuration Andrey M. Borodin <[email protected]>
2020-05-14 01:25 ` Re: MultiXact\SLRU buffers configuration Kyotaro Horiguchi <[email protected]>
2020-05-14 05:19 ` Re: MultiXact\SLRU buffers configuration Andrey M. Borodin <[email protected]>
2020-05-14 06:16 ` Re: MultiXact\SLRU buffers configuration Kyotaro Horiguchi <[email protected]>
2020-05-14 06:44 ` Re: MultiXact\SLRU buffers configuration Andrey M. Borodin <[email protected]>
2020-05-15 00:03 ` Re: MultiXact\SLRU buffers configuration Kyotaro Horiguchi <[email protected]>
2020-07-02 12:02 ` Re: MultiXact\SLRU buffers configuration Daniel Gustafsson <[email protected]>
2020-07-08 07:03 ` Re: MultiXact\SLRU buffers configuration Andrey M. Borodin <[email protected]>
2020-08-28 18:08 ` Re: MultiXact\SLRU buffers configuration Anastasia Lubennikova <[email protected]>
2020-09-28 14:41 ` Re: MultiXact\SLRU buffers configuration Andrey M. Borodin <[email protected]>
2020-10-26 01:05 ` Re: MultiXact\SLRU buffers configuration Alexander Korotkov <[email protected]>
2020-10-26 15:45 ` Re: MultiXact\SLRU buffers configuration Andrey Borodin <[email protected]>
2020-10-27 17:02 ` Re: MultiXact\SLRU buffers configuration Alexander Korotkov <[email protected]>
2020-10-27 17:23 ` Re: MultiXact\SLRU buffers configuration Alexander Korotkov <[email protected]>
2020-10-28 01:36 ` Re: MultiXact\SLRU buffers configuration Tomas Vondra <[email protected]>
2020-10-28 07:34 ` Re: MultiXact\SLRU buffers configuration Andrey Borodin <[email protected]>
2020-10-28 23:32 ` Re: MultiXact\SLRU buffers configuration Tomas Vondra <[email protected]>
2020-10-29 07:08 ` Re: MultiXact\SLRU buffers configuration Andrey Borodin <[email protected]>
2020-10-29 13:49 ` Re: MultiXact\SLRU buffers configuration Tomas Vondra <[email protected]>
2020-11-02 12:45 ` Re: MultiXact\SLRU buffers configuration Andrey Borodin <[email protected]>
2020-11-10 00:13 ` Re: MultiXact\SLRU buffers configuration Tomas Vondra <[email protected]>
2020-11-10 06:16 ` Re: MultiXact\SLRU buffers configuration Andrey Borodin <[email protected]>
2020-11-10 18:07 ` Re: MultiXact\SLRU buffers configuration Tomas Vondra <[email protected]>
2020-11-13 11:49 ` Re: MultiXact\SLRU buffers configuration Andrey Borodin <[email protected]>
2020-12-08 16:05 ` Re: MultiXact\SLRU buffers configuration Gilles Darold <[email protected]>
2020-12-08 17:52 ` Re: MultiXact\SLRU buffers configuration Andrey Borodin <[email protected]>
2020-12-10 14:45 ` Re: MultiXact\SLRU buffers configuration Gilles Darold <[email protected]>
2020-12-11 17:50 ` Re: MultiXact\SLRU buffers configuration Gilles Darold <[email protected]>
2020-12-13 09:17 ` Re: MultiXact\SLRU buffers configuration Gilles Darold <[email protected]>
2020-12-13 17:24 ` Re: MultiXact\SLRU buffers configuration Andrey Borodin <[email protected]>
2020-12-23 16:31 ` Re: MultiXact\SLRU buffers configuration Gilles Darold <[email protected]>
2021-02-15 17:17 ` Re: MultiXact\SLRU buffers configuration Andrey Borodin <[email protected]>
2021-03-11 15:50 ` Re: MultiXact\SLRU buffers configuration Gilles Darold <[email protected]>
2021-03-12 12:44 ` Re: MultiXact\SLRU buffers configuration Andrey Borodin <[email protected]>
@ 2021-03-15 15:41 ` Gilles Darold <[email protected]>
1 sibling, 0 replies; 90+ messages in thread
From: Gilles Darold @ 2021-03-15 15:41 UTC (permalink / raw)
To: Andrey Borodin <[email protected]>; Gilles Darold <[email protected]>; +Cc: Tomas Vondra <[email protected]>; Tomas Vondra <[email protected]>; Alexander Korotkov <[email protected]>; Anastasia Lubennikova <[email protected]>; Daniel Gustafsson <[email protected]>; Kyotaro Horiguchi <[email protected]>; pgsql-hackers
Le 12/03/2021 à 13:44, Andrey Borodin a écrit :
>
>> 11 марта 2021 г., в 20:50, Gilles Darold <[email protected]> написал(а):
>>
>>
>> The patch doesn't apply anymore in master cause of error: patch failed: src/backend/utils/init/globals.c:150
>>
>>
>>
>> An other remark about this patch is that it should be mentionned in the documentation (doc/src/sgml/config.sgml) that the new configuration variables need a server restart, for example by adding "This parameter can only be set at server start." like for shared_buffers. Patch on postgresql.conf mention it.
>>
>> And some typo to be fixed:
>>
>>
>>
>> s/Tipically/Typically/
>>
>> s/asincronous/asyncronous/
>>
>> s/confugured/configured/
>>
>> s/substrnsactions/substransactions/
>>
>>
> Thanks, Gilles! Fixed.
>
> Best regards, Andrey Borodin.
>
Hi Andrey,
I found two problems in this patch, first in src/include/miscadmin.h
multixact_members_slru_buffers is declared twice:
extern PGDLLIMPORT int max_parallel_workers;
+extern PGDLLIMPORT int multixact_offsets_slru_buffers;
+extern PGDLLIMPORT int multixact_members_slru_buffers;
+extern PGDLLIMPORT int multixact_members_slru_buffers; <---------
+extern PGDLLIMPORT int subtrans_slru_buffers;
In file src/backend/access/transam/multixact.c the second variable
should be multixact_buffers_slru_buffers and not
multixact_offsets_slru_buffers.
@@ -1848,13 +1848,13 @@ MultiXactShmemInit(void)
MultiXactMemberCtl->PagePrecedes = MultiXactMemberPagePrecedes;
SimpleLruInit(MultiXactOffsetCtl,
- "MultiXactOffset",
NUM_MULTIXACTOFFSET_BUFFERS, 0,
+ "MultiXactOffset",
multixact_offsets_slru_buffers, 0,
MultiXactOffsetSLRULock,
"pg_multixact/offsets",
LWTRANCHE_MULTIXACTOFFSET_BUFFER,
SYNC_HANDLER_MULTIXACT_OFFSET);
SlruPagePrecedesUnitTests(MultiXactOffsetCtl,
MULTIXACT_OFFSETS_PER_PAGE);
SimpleLruInit(MultiXactMemberCtl,
- "MultiXactMember",
NUM_MULTIXACTMEMBER_BUFFERS, 0,
+ "MultiXactMember",
multixact_offsets_slru_buffers, 0, <------------------
MultiXactMemberSLRULock,
"pg_multixact/members",
LWTRANCHE_MULTIXACTMEMBER_BUFFER,
SYNC_HANDLER_MULTIXACT_MEMBER);
Please fix them so that I can end the review.
--
Gilles Darold
LzLabs GmbH
http://www.lzlabs.com/
^ permalink raw reply [nested|flat] 90+ messages in thread
* Re: MultiXact\SLRU buffers configuration
2020-05-08 16:36 MultiXact\SLRU buffers configuration Andrey M. Borodin <[email protected]>
2020-05-11 11:17 ` Re: MultiXact\SLRU buffers configuration Andrey M. Borodin <[email protected]>
2020-05-13 18:08 ` Re: MultiXact\SLRU buffers configuration Andrey M. Borodin <[email protected]>
2020-05-14 01:25 ` Re: MultiXact\SLRU buffers configuration Kyotaro Horiguchi <[email protected]>
2020-05-14 05:19 ` Re: MultiXact\SLRU buffers configuration Andrey M. Borodin <[email protected]>
2020-05-14 06:16 ` Re: MultiXact\SLRU buffers configuration Kyotaro Horiguchi <[email protected]>
2020-05-14 06:44 ` Re: MultiXact\SLRU buffers configuration Andrey M. Borodin <[email protected]>
2020-05-15 00:03 ` Re: MultiXact\SLRU buffers configuration Kyotaro Horiguchi <[email protected]>
2020-07-02 12:02 ` Re: MultiXact\SLRU buffers configuration Daniel Gustafsson <[email protected]>
2020-07-08 07:03 ` Re: MultiXact\SLRU buffers configuration Andrey M. Borodin <[email protected]>
2020-08-28 18:08 ` Re: MultiXact\SLRU buffers configuration Anastasia Lubennikova <[email protected]>
2020-09-28 14:41 ` Re: MultiXact\SLRU buffers configuration Andrey M. Borodin <[email protected]>
2020-10-26 01:05 ` Re: MultiXact\SLRU buffers configuration Alexander Korotkov <[email protected]>
2020-10-26 15:45 ` Re: MultiXact\SLRU buffers configuration Andrey Borodin <[email protected]>
2020-10-27 17:02 ` Re: MultiXact\SLRU buffers configuration Alexander Korotkov <[email protected]>
2020-10-27 17:23 ` Re: MultiXact\SLRU buffers configuration Alexander Korotkov <[email protected]>
2020-10-28 01:36 ` Re: MultiXact\SLRU buffers configuration Tomas Vondra <[email protected]>
2020-10-28 07:34 ` Re: MultiXact\SLRU buffers configuration Andrey Borodin <[email protected]>
2020-10-28 23:32 ` Re: MultiXact\SLRU buffers configuration Tomas Vondra <[email protected]>
2020-10-29 07:08 ` Re: MultiXact\SLRU buffers configuration Andrey Borodin <[email protected]>
2020-10-29 13:49 ` Re: MultiXact\SLRU buffers configuration Tomas Vondra <[email protected]>
2020-11-02 12:45 ` Re: MultiXact\SLRU buffers configuration Andrey Borodin <[email protected]>
2020-11-10 00:13 ` Re: MultiXact\SLRU buffers configuration Tomas Vondra <[email protected]>
2020-11-10 06:16 ` Re: MultiXact\SLRU buffers configuration Andrey Borodin <[email protected]>
2020-11-10 18:07 ` Re: MultiXact\SLRU buffers configuration Tomas Vondra <[email protected]>
2020-11-13 11:49 ` Re: MultiXact\SLRU buffers configuration Andrey Borodin <[email protected]>
2020-12-08 16:05 ` Re: MultiXact\SLRU buffers configuration Gilles Darold <[email protected]>
2020-12-08 17:52 ` Re: MultiXact\SLRU buffers configuration Andrey Borodin <[email protected]>
2020-12-10 14:45 ` Re: MultiXact\SLRU buffers configuration Gilles Darold <[email protected]>
2020-12-11 17:50 ` Re: MultiXact\SLRU buffers configuration Gilles Darold <[email protected]>
2020-12-13 09:17 ` Re: MultiXact\SLRU buffers configuration Gilles Darold <[email protected]>
2020-12-13 17:24 ` Re: MultiXact\SLRU buffers configuration Andrey Borodin <[email protected]>
2020-12-23 16:31 ` Re: MultiXact\SLRU buffers configuration Gilles Darold <[email protected]>
2021-02-15 17:17 ` Re: MultiXact\SLRU buffers configuration Andrey Borodin <[email protected]>
2021-03-11 15:50 ` Re: MultiXact\SLRU buffers configuration Gilles Darold <[email protected]>
2021-03-12 12:44 ` Re: MultiXact\SLRU buffers configuration Andrey Borodin <[email protected]>
@ 2021-03-24 21:31 ` Thomas Munro <[email protected]>
2021-03-25 01:03 ` Re: MultiXact\SLRU buffers configuration Thomas Munro <[email protected]>
1 sibling, 1 reply; 90+ messages in thread
From: Thomas Munro @ 2021-03-24 21:31 UTC (permalink / raw)
To: Andrey Borodin <[email protected]>; +Cc: Gilles Darold <[email protected]>; Tomas Vondra <[email protected]>; Tomas Vondra <[email protected]>; Alexander Korotkov <[email protected]>; Anastasia Lubennikova <[email protected]>; Daniel Gustafsson <[email protected]>; Kyotaro Horiguchi <[email protected]>; pgsql-hackers
Hi Andrey,
On Sat, Mar 13, 2021 at 1:44 AM Andrey Borodin <[email protected]> wrote:
> [v10]
+int multixact_offsets_slru_buffers = 8;
+int multixact_members_slru_buffers = 16;
+int subtrans_slru_buffers = 32;
+int notify_slru_buffers = 8;
+int serial_slru_buffers = 16;
+int clog_slru_buffers = 0;
+int commit_ts_slru_buffers = 0;
I don't think we should put "slru" (the name of the buffer replacement
algorithm, implementation detail) in the GUC names.
+ It defaults to 0, in this case CLOG size is taken as
<varname>shared_buffers</varname> / 512.
We already know that increasing the number of CLOG buffers above the
current number hurts as the linear search begins to dominate
(according to the commit message for 5364b357), and it doesn't seem
great to ship a new feature that melts your CPU when you turn it up.
Perhaps, to ship this, we need to introduce a buffer mapping table? I
have attached a "one coffee" attempt at that, on top of your v10 patch
(unmodified), for discussion. It survives basic testing but I don't
know how it performs.
Attachments:
[text/x-patch] v10-0001-Make-all-SLRU-buffer-sizes-configurable.patch (19.5K, ../../CA+hUKGJ4TwipnMDmKdORu4zUo_rofsuu5FQsgV=UHJ3bY38ERw@mail.gmail.com/2-v10-0001-Make-all-SLRU-buffer-sizes-configurable.patch)
download | inline diff:
From 4817d16cfb6704d43a7bef12648e753d239c809c Mon Sep 17 00:00:00 2001
From: Andrey Borodin <[email protected]>
Date: Mon, 15 Feb 2021 21:51:56 +0500
Subject: [PATCH v10 1/2] Make all SLRU buffer sizes configurable
---
doc/src/sgml/config.sgml | 108 ++++++++++++++++++
src/backend/access/transam/clog.c | 6 +
src/backend/access/transam/commit_ts.c | 5 +-
src/backend/access/transam/multixact.c | 8 +-
src/backend/access/transam/subtrans.c | 5 +-
src/backend/commands/async.c | 8 +-
src/backend/storage/lmgr/predicate.c | 4 +-
src/backend/utils/init/globals.c | 8 ++
src/backend/utils/misc/guc.c | 77 +++++++++++++
src/backend/utils/misc/postgresql.conf.sample | 16 +++
src/include/access/multixact.h | 4 -
src/include/access/subtrans.h | 3 -
src/include/commands/async.h | 5 -
src/include/miscadmin.h | 8 ++
src/include/storage/predicate.h | 4 -
15 files changed, 240 insertions(+), 29 deletions(-)
diff --git a/doc/src/sgml/config.sgml b/doc/src/sgml/config.sgml
index ddc6d789d8..0adcf0efaf 100644
--- a/doc/src/sgml/config.sgml
+++ b/doc/src/sgml/config.sgml
@@ -1886,6 +1886,114 @@ include_dir 'conf.d'
</para>
</listitem>
</varlistentry>
+
+ <varlistentry id="guc-multixact-offsets-slru-buffers" xreflabel="multixact_offsets_slru_buffers">
+ <term><varname>multixact_offsets_slru_buffers</varname> (<type>integer</type>)
+ <indexterm>
+ <primary><varname>multixact_offsets_slru_buffers</varname> configuration parameter</primary>
+ </indexterm>
+ </term>
+ <listitem>
+ <para>
+ Specifies the amount of memory to be used for MultiXact offsets. MultiXact offsets
+ are used to store information about offsets of multiple row lockers (caused by SELECT FOR UPDATE and others).
+ It defaults to 64 kilobytes (<literal>64KB</literal>).
+ This parameter can only be set at server start.
+ </para>
+ </listitem>
+ </varlistentry>
+
+ <varlistentry id="guc-multixact-members-slru-buffers" xreflabel="multixact_members_slru_buffers">
+ <term><varname>multixact_members_slru_buffers</varname> (<type>integer</type>)
+ <indexterm>
+ <primary><varname>multixact_members_slru_buffers</varname> configuration parameter</primary>
+ </indexterm>
+ </term>
+ <listitem>
+ <para>
+ Specifies the amount of memory to be used for MultiXact members. MultiXact members
+ are used to store information about XIDs of multiple row lockers. Typically <varname>multixact_members_slru_buffers</varname>
+ is twice more than <varname>multixact_offsets_slru_buffers</varname>.
+ It defaults to 128 kilobytes (<literal>128KB</literal>).
+ This parameter can only be set at server start.
+ </para>
+ </listitem>
+ </varlistentry>
+
+ <varlistentry id="guc-subtrans-buffers" xreflabel="subtrans_slru_buffers">
+ <term><varname>subtrans_slru_buffers</varname> (<type>integer</type>)
+ <indexterm>
+ <primary><varname>subtrans_slru_buffers</varname> configuration parameter</primary>
+ </indexterm>
+ </term>
+ <listitem>
+ <para>
+ Specifies the amount of memory to be used for subtransactions.
+ It defaults to 256 kilobytes (<literal>256KB</literal>).
+ This parameter can only be set at server start.
+ </para>
+ </listitem>
+ </varlistentry>
+
+ <varlistentry id="guc-notify-buffers" xreflabel="notify_slru_buffers">
+ <term><varname>notify_slru_buffers</varname> (<type>integer</type>)
+ <indexterm>
+ <primary><varname>notify_slru_buffers</varname> configuration parameter</primary>
+ </indexterm>
+ </term>
+ <listitem>
+ <para>
+ Specifies the amount of memory to be used for asyncronous notifications (NOTIFY, LISTEN).
+ It defaults to 64 kilobytes (<literal>64KB</literal>).
+ This parameter can only be set at server start.
+ </para>
+ </listitem>
+ </varlistentry>
+
+ <varlistentry id="guc-serial-buffers" xreflabel="serial_slru_buffers">
+ <term><varname>serial_slru_buffers</varname> (<type>integer</type>)
+ <indexterm>
+ <primary><varname>serial_slru_buffers</varname> configuration parameter</primary>
+ </indexterm>
+ </term>
+ <listitem>
+ <para>
+ Specifies the amount of memory to be used for predicate locks.
+ It defaults to 128 kilobytes (<literal>128KB</literal>).
+ This parameter can only be set at server start.
+ </para>
+ </listitem>
+ </varlistentry>
+
+ <varlistentry id="guc-clog-buffers" xreflabel="clog_slru_buffers">
+ <term><varname>clog_slru_buffers</varname> (<type>integer</type>)
+ <indexterm>
+ <primary><varname>clog_slru_buffers</varname> configuration parameter</primary>
+ </indexterm>
+ </term>
+ <listitem>
+ <para>
+ Specifies the amount of memory to be used for CLOG.
+ It defaults to 0, in this case CLOG size is taken as <varname>shared_buffers</varname> / 512.
+ This parameter can only be set at server start.
+ </para>
+ </listitem>
+ </varlistentry>
+
+ <varlistentry id="guc-commit-ts-buffers" xreflabel="commit_ts_slru_buffers">
+ <term><varname>commit_ts_slru_buffers</varname> (<type>integer</type>)
+ <indexterm>
+ <primary><varname>commit_ts_slru_buffers</varname> configuration parameter</primary>
+ </indexterm>
+ </term>
+ <listitem>
+ <para>
+ Specifies the amount of memory to be used for commit timestamps.
+ It defaults to 0, in this case CLOG size is taken as <varname>shared_buffers</varname> / 512.
+ This parameter can only be set at server start.
+ </para>
+ </listitem>
+ </varlistentry>
<varlistentry id="guc-max-stack-depth" xreflabel="max_stack_depth">
<term><varname>max_stack_depth</varname> (<type>integer</type>)
diff --git a/src/backend/access/transam/clog.c b/src/backend/access/transam/clog.c
index 6fa4713fb4..e1d34aa361 100644
--- a/src/backend/access/transam/clog.c
+++ b/src/backend/access/transam/clog.c
@@ -659,6 +659,9 @@ TransactionIdGetStatus(TransactionId xid, XLogRecPtr *lsn)
/*
* Number of shared CLOG buffers.
*
+ * If values is configured via GUC - just use given value. Otherwise
+ * apply following euristics.
+ *
* On larger multi-processor systems, it is possible to have many CLOG page
* requests in flight at one time which could lead to disk access for CLOG
* page if the required page is not found in memory. Testing revealed that we
@@ -675,6 +678,9 @@ TransactionIdGetStatus(TransactionId xid, XLogRecPtr *lsn)
Size
CLOGShmemBuffers(void)
{
+ /* consider 0 and 1 as unset GUC */
+ if (clog_slru_buffers > 1)
+ return clog_slru_buffers;
return Min(128, Max(4, NBuffers / 512));
}
diff --git a/src/backend/access/transam/commit_ts.c b/src/backend/access/transam/commit_ts.c
index 48e8d66286..7de3bca63d 100644
--- a/src/backend/access/transam/commit_ts.c
+++ b/src/backend/access/transam/commit_ts.c
@@ -530,7 +530,10 @@ pg_xact_commit_timestamp_origin(PG_FUNCTION_ARGS)
Size
CommitTsShmemBuffers(void)
{
- return Min(16, Max(4, NBuffers / 1024));
+ /* consider 0 and 1 as unset GUC */
+ if (commit_ts_slru_buffers > 1)
+ return commit_ts_slru_buffers;
+ return Min(16, Max(4, NBuffers / 512));
}
/*
diff --git a/src/backend/access/transam/multixact.c b/src/backend/access/transam/multixact.c
index 1f9f1a1fa1..370c01e72b 100644
--- a/src/backend/access/transam/multixact.c
+++ b/src/backend/access/transam/multixact.c
@@ -1831,8 +1831,8 @@ MultiXactShmemSize(void)
mul_size(sizeof(MultiXactId) * 2, MaxOldestSlot))
size = SHARED_MULTIXACT_STATE_SIZE;
- size = add_size(size, SimpleLruShmemSize(NUM_MULTIXACTOFFSET_BUFFERS, 0));
- size = add_size(size, SimpleLruShmemSize(NUM_MULTIXACTMEMBER_BUFFERS, 0));
+ size = add_size(size, SimpleLruShmemSize(multixact_offsets_slru_buffers, 0));
+ size = add_size(size, SimpleLruShmemSize(multixact_members_slru_buffers, 0));
return size;
}
@@ -1848,13 +1848,13 @@ MultiXactShmemInit(void)
MultiXactMemberCtl->PagePrecedes = MultiXactMemberPagePrecedes;
SimpleLruInit(MultiXactOffsetCtl,
- "MultiXactOffset", NUM_MULTIXACTOFFSET_BUFFERS, 0,
+ "MultiXactOffset", multixact_offsets_slru_buffers, 0,
MultiXactOffsetSLRULock, "pg_multixact/offsets",
LWTRANCHE_MULTIXACTOFFSET_BUFFER,
SYNC_HANDLER_MULTIXACT_OFFSET);
SlruPagePrecedesUnitTests(MultiXactOffsetCtl, MULTIXACT_OFFSETS_PER_PAGE);
SimpleLruInit(MultiXactMemberCtl,
- "MultiXactMember", NUM_MULTIXACTMEMBER_BUFFERS, 0,
+ "MultiXactMember", multixact_offsets_slru_buffers, 0,
MultiXactMemberSLRULock, "pg_multixact/members",
LWTRANCHE_MULTIXACTMEMBER_BUFFER,
SYNC_HANDLER_MULTIXACT_MEMBER);
diff --git a/src/backend/access/transam/subtrans.c b/src/backend/access/transam/subtrans.c
index 6a8e521f89..0c24353d3a 100644
--- a/src/backend/access/transam/subtrans.c
+++ b/src/backend/access/transam/subtrans.c
@@ -31,6 +31,7 @@
#include "access/slru.h"
#include "access/subtrans.h"
#include "access/transam.h"
+#include "miscadmin.h"
#include "pg_trace.h"
#include "utils/snapmgr.h"
@@ -184,14 +185,14 @@ SubTransGetTopmostTransaction(TransactionId xid)
Size
SUBTRANSShmemSize(void)
{
- return SimpleLruShmemSize(NUM_SUBTRANS_BUFFERS, 0);
+ return SimpleLruShmemSize(subtrans_slru_buffers, 0);
}
void
SUBTRANSShmemInit(void)
{
SubTransCtl->PagePrecedes = SubTransPagePrecedes;
- SimpleLruInit(SubTransCtl, "Subtrans", NUM_SUBTRANS_BUFFERS, 0,
+ SimpleLruInit(SubTransCtl, "Subtrans", subtrans_slru_buffers, 0,
SubtransSLRULock, "pg_subtrans",
LWTRANCHE_SUBTRANS_BUFFER, SYNC_HANDLER_NONE);
SlruPagePrecedesUnitTests(SubTransCtl, SUBTRANS_XACTS_PER_PAGE);
diff --git a/src/backend/commands/async.c b/src/backend/commands/async.c
index 4b16fb5682..f5c5592057 100644
--- a/src/backend/commands/async.c
+++ b/src/backend/commands/async.c
@@ -107,7 +107,7 @@
* frontend during startup.) The above design guarantees that notifies from
* other backends will never be missed by ignoring self-notifies.
*
- * The amount of shared memory used for notify management (NUM_NOTIFY_BUFFERS)
+ * The amount of shared memory used for notify management (notify_slru_buffers)
* can be varied without affecting anything but performance. The maximum
* amount of notification data that can be queued at one time is determined
* by slru.c's wraparound limit; see QUEUE_MAX_PAGE below.
@@ -225,7 +225,7 @@ typedef struct QueuePosition
*
* Resist the temptation to make this really large. While that would save
* work in some places, it would add cost in others. In particular, this
- * should likely be less than NUM_NOTIFY_BUFFERS, to ensure that backends
+ * should likely be less than notify_slru_buffers, to ensure that backends
* catch up before the pages they'll need to read fall out of SLRU cache.
*/
#define QUEUE_CLEANUP_DELAY 4
@@ -514,7 +514,7 @@ AsyncShmemSize(void)
size = mul_size(MaxBackends + 1, sizeof(QueueBackendStatus));
size = add_size(size, offsetof(AsyncQueueControl, backend));
- size = add_size(size, SimpleLruShmemSize(NUM_NOTIFY_BUFFERS, 0));
+ size = add_size(size, SimpleLruShmemSize(notify_slru_buffers, 0));
return size;
}
@@ -562,7 +562,7 @@ AsyncShmemInit(void)
* Set up SLRU management of the pg_notify data.
*/
NotifyCtl->PagePrecedes = asyncQueuePagePrecedes;
- SimpleLruInit(NotifyCtl, "Notify", NUM_NOTIFY_BUFFERS, 0,
+ SimpleLruInit(NotifyCtl, "Notify", notify_slru_buffers, 0,
NotifySLRULock, "pg_notify", LWTRANCHE_NOTIFY_BUFFER,
SYNC_HANDLER_NONE);
diff --git a/src/backend/storage/lmgr/predicate.c b/src/backend/storage/lmgr/predicate.c
index d493aeef0f..fad8cc572e 100644
--- a/src/backend/storage/lmgr/predicate.c
+++ b/src/backend/storage/lmgr/predicate.c
@@ -872,7 +872,7 @@ SerialInit(void)
*/
SerialSlruCtl->PagePrecedes = SerialPagePrecedesLogically;
SimpleLruInit(SerialSlruCtl, "Serial",
- NUM_SERIAL_BUFFERS, 0, SerialSLRULock, "pg_serial",
+ serial_slru_buffers, 0, SerialSLRULock, "pg_serial",
LWTRANCHE_SERIAL_BUFFER, SYNC_HANDLER_NONE);
#ifdef USE_ASSERT_CHECKING
SerialPagePrecedesLogicallyUnitTests();
@@ -1395,7 +1395,7 @@ PredicateLockShmemSize(void)
/* Shared memory structures for SLRU tracking of old committed xids. */
size = add_size(size, sizeof(SerialControlData));
- size = add_size(size, SimpleLruShmemSize(NUM_SERIAL_BUFFERS, 0));
+ size = add_size(size, SimpleLruShmemSize(serial_slru_buffers, 0));
return size;
}
diff --git a/src/backend/utils/init/globals.c b/src/backend/utils/init/globals.c
index 73e0a672ae..f163ca17e9 100644
--- a/src/backend/utils/init/globals.c
+++ b/src/backend/utils/init/globals.c
@@ -148,3 +148,11 @@ int64 VacuumPageDirty = 0;
int VacuumCostBalance = 0; /* working state for vacuum */
bool VacuumCostActive = false;
+
+int multixact_offsets_slru_buffers = 8;
+int multixact_members_slru_buffers = 16;
+int subtrans_slru_buffers = 32;
+int notify_slru_buffers = 8;
+int serial_slru_buffers = 16;
+int clog_slru_buffers = 0;
+int commit_ts_slru_buffers = 0;
diff --git a/src/backend/utils/misc/guc.c b/src/backend/utils/misc/guc.c
index 0c5dc4d3e8..b65a4ae9ce 100644
--- a/src/backend/utils/misc/guc.c
+++ b/src/backend/utils/misc/guc.c
@@ -2305,6 +2305,83 @@ static struct config_int ConfigureNamesInt[] =
NULL, NULL, NULL
},
+ {
+ {"multixact_offsets_slru_buffers", PGC_POSTMASTER, RESOURCES_MEM,
+ gettext_noop("Sets the number of shared memory buffers used for MultiXact offsets SLRU."),
+ NULL,
+ GUC_UNIT_BLOCKS
+ },
+ &multixact_offsets_slru_buffers,
+ 8, 2, INT_MAX / 2,
+ NULL, NULL, NULL
+ },
+
+ {
+ {"multixact_members_slru_buffers", PGC_POSTMASTER, RESOURCES_MEM,
+ gettext_noop("Sets the number of shared memory buffers used for MultiXact members SLRU."),
+ NULL,
+ GUC_UNIT_BLOCKS
+ },
+ &multixact_members_slru_buffers,
+ 16, 2, INT_MAX / 2,
+ NULL, NULL, NULL
+ },
+
+ {
+ {"subtrans_slru_buffers", PGC_POSTMASTER, RESOURCES_MEM,
+ gettext_noop("Sets the number of shared memory buffers used for substransactions SLRU."),
+ NULL,
+ GUC_UNIT_BLOCKS
+ },
+ &subtrans_slru_buffers,
+ 32, 2, INT_MAX / 2,
+ NULL, NULL, NULL
+ },
+
+ {
+ {"notify_slru_buffers", PGC_POSTMASTER, RESOURCES_MEM,
+ gettext_noop("Sets the number of shared memory buffers used for asyncronous notifications SLRU."),
+ NULL,
+ GUC_UNIT_BLOCKS
+ },
+ ¬ify_slru_buffers,
+ 8, 2, INT_MAX / 2,
+ NULL, NULL, NULL
+ },
+
+ {
+ {"serial_slru_buffers", PGC_POSTMASTER, RESOURCES_MEM,
+ gettext_noop("Sets the number of shared memory buffers used for predicate locks SLRU."),
+ NULL,
+ GUC_UNIT_BLOCKS
+ },
+ &serial_slru_buffers,
+ 16, 2, INT_MAX / 2,
+ NULL, NULL, NULL
+ },
+
+ {
+ {"clog_slru_buffers", PGC_POSTMASTER, RESOURCES_MEM,
+ gettext_noop("Sets the number of shared memory buffers used for commit log SLRU."),
+ NULL,
+ GUC_UNIT_BLOCKS
+ },
+ &serial_slru_buffers,
+ 0, 0, INT_MAX / 2,
+ NULL, NULL, NULL
+ },
+
+ {
+ {"commit_ts_slru_buffers", PGC_POSTMASTER, RESOURCES_MEM,
+ gettext_noop("Sets the number of shared memory buffers used for commit timestamps SLRU."),
+ NULL,
+ GUC_UNIT_BLOCKS
+ },
+ &commit_ts_slru_buffers,
+ 0, 0, INT_MAX / 2,
+ NULL, NULL, NULL
+ },
+
{
{"temp_buffers", PGC_USERSET, RESOURCES_MEM,
gettext_noop("Sets the maximum number of temporary buffers used by each session."),
diff --git a/src/backend/utils/misc/postgresql.conf.sample b/src/backend/utils/misc/postgresql.conf.sample
index b234a6bfe6..308fd565d3 100644
--- a/src/backend/utils/misc/postgresql.conf.sample
+++ b/src/backend/utils/misc/postgresql.conf.sample
@@ -190,6 +190,22 @@
# (change requires restart)
#backend_flush_after = 0 # measured in pages, 0 disables
+# - SLRU Buffers -
+
+#multixact_offsets_slru_buffers = 8 # memory used for MultiXact offsets
+ # (change requires restart)
+#multixact_members_slru_buffers = 16 # memory used for MultiXact members
+ # (change requires restart)
+#subtrans_slru_buffers = 32 # memory used for subtransactions
+ # (change requires restart)
+#notify_slru_buffers = 8 # memory used for asynchronous notifications
+ # (change requires restart)
+#serial_slru_buffers = 16 # memory used for predicate locks
+ # (change requires restart)
+#clog_slru_buffers = 0 # memory used for CLOG
+ # (change requires restart)
+#commit_ts_slru_buffers = 0 # memory used for commit timestamps
+ # (change requires restart)
#------------------------------------------------------------------------------
# WRITE-AHEAD LOG
diff --git a/src/include/access/multixact.h b/src/include/access/multixact.h
index 4bbb035eae..97c0a46376 100644
--- a/src/include/access/multixact.h
+++ b/src/include/access/multixact.h
@@ -29,10 +29,6 @@
#define MaxMultiXactOffset ((MultiXactOffset) 0xFFFFFFFF)
-/* Number of SLRU buffers to use for multixact */
-#define NUM_MULTIXACTOFFSET_BUFFERS 8
-#define NUM_MULTIXACTMEMBER_BUFFERS 16
-
/*
* Possible multixact lock modes ("status"). The first four modes are for
* tuple locks (FOR KEY SHARE, FOR SHARE, FOR NO KEY UPDATE, FOR UPDATE); the
diff --git a/src/include/access/subtrans.h b/src/include/access/subtrans.h
index d0ab44ae82..ca0999056e 100644
--- a/src/include/access/subtrans.h
+++ b/src/include/access/subtrans.h
@@ -11,9 +11,6 @@
#ifndef SUBTRANS_H
#define SUBTRANS_H
-/* Number of SLRU buffers to use for subtrans */
-#define NUM_SUBTRANS_BUFFERS 32
-
extern void SubTransSetParent(TransactionId xid, TransactionId parent);
extern TransactionId SubTransGetParent(TransactionId xid);
extern TransactionId SubTransGetTopmostTransaction(TransactionId xid);
diff --git a/src/include/commands/async.h b/src/include/commands/async.h
index 9217f66b91..fa831e3721 100644
--- a/src/include/commands/async.h
+++ b/src/include/commands/async.h
@@ -15,11 +15,6 @@
#include <signal.h>
-/*
- * The number of SLRU page buffers we use for the notification queue.
- */
-#define NUM_NOTIFY_BUFFERS 8
-
extern bool Trace_notify;
extern volatile sig_atomic_t notifyInterruptPending;
diff --git a/src/include/miscadmin.h b/src/include/miscadmin.h
index 013850ac28..3d9f585fb9 100644
--- a/src/include/miscadmin.h
+++ b/src/include/miscadmin.h
@@ -162,6 +162,14 @@ extern PGDLLIMPORT int MaxBackends;
extern PGDLLIMPORT int MaxConnections;
extern PGDLLIMPORT int max_worker_processes;
extern PGDLLIMPORT int max_parallel_workers;
+extern PGDLLIMPORT int multixact_offsets_slru_buffers;
+extern PGDLLIMPORT int multixact_members_slru_buffers;
+extern PGDLLIMPORT int multixact_members_slru_buffers;
+extern PGDLLIMPORT int subtrans_slru_buffers;
+extern PGDLLIMPORT int notify_slru_buffers;
+extern PGDLLIMPORT int serial_slru_buffers;
+extern PGDLLIMPORT int clog_slru_buffers;
+extern PGDLLIMPORT int commit_ts_slru_buffers;
extern PGDLLIMPORT int MyProcPid;
extern PGDLLIMPORT pg_time_t MyStartTime;
diff --git a/src/include/storage/predicate.h b/src/include/storage/predicate.h
index 152b698611..c72779bd88 100644
--- a/src/include/storage/predicate.h
+++ b/src/include/storage/predicate.h
@@ -26,10 +26,6 @@ extern int max_predicate_locks_per_xact;
extern int max_predicate_locks_per_relation;
extern int max_predicate_locks_per_page;
-
-/* Number of SLRU buffers to use for Serial SLRU */
-#define NUM_SERIAL_BUFFERS 16
-
/*
* A handle used for sharing SERIALIZABLEXACT objects between the participants
* in a parallel query.
--
2.30.1
[text/x-patch] v10-0002-Add-buffer-mapping-table-for-SLRUs.patch (7.0K, ../../CA+hUKGJ4TwipnMDmKdORu4zUo_rofsuu5FQsgV=UHJ3bY38ERw@mail.gmail.com/3-v10-0002-Add-buffer-mapping-table-for-SLRUs.patch)
download | inline diff:
From 692d03167f4124e6daabdb8d4a72ff0b494efe96 Mon Sep 17 00:00:00 2001
From: Thomas Munro <[email protected]>
Date: Thu, 25 Mar 2021 10:11:31 +1300
Subject: [PATCH v10 2/2] Add buffer mapping table for SLRUs.
---
src/backend/access/transam/slru.c | 87 ++++++++++++++++++++++++++++---
src/include/access/slru.h | 2 +
2 files changed, 83 insertions(+), 6 deletions(-)
diff --git a/src/backend/access/transam/slru.c b/src/backend/access/transam/slru.c
index 82149ad782..2d6e84266e 100644
--- a/src/backend/access/transam/slru.c
+++ b/src/backend/access/transam/slru.c
@@ -58,6 +58,8 @@
#include "pgstat.h"
#include "storage/fd.h"
#include "storage/shmem.h"
+#include "utils/dynahash.h"
+#include "utils/hsearch.h"
#define SlruFileName(ctl, path, seg) \
snprintf(path, MAXPGPATH, "%s/%04X", (ctl)->Dir, seg)
@@ -79,6 +81,12 @@ typedef struct SlruWriteAllData
typedef struct SlruWriteAllData *SlruWriteAll;
+typedef struct SlruMappingTableEntry
+{
+ int pageno;
+ int slotno;
+} SlruMappingTableEntry;
+
/*
* Populate a file tag describing a segment file. We only use the segment
* number, since we can derive everything else we need by having separate
@@ -146,6 +154,9 @@ static int SlruSelectLRUPage(SlruCtl ctl, int pageno);
static bool SlruScanDirCbDeleteCutoff(SlruCtl ctl, char *filename,
int segpage, void *data);
static void SlruInternalDeleteSegment(SlruCtl ctl, int segno);
+static void SlruMappingAdd(SlruCtl ctl, int pageno, int slotno);
+static void SlruMappingRemove(SlruCtl ctl, int pageno);
+static int SlruMappingFind(SlruCtl ctl, int pageno);
/*
* Initialization of shared memory
@@ -168,7 +179,8 @@ SimpleLruShmemSize(int nslots, int nlsns)
if (nlsns > 0)
sz += MAXALIGN(nslots * nlsns * sizeof(XLogRecPtr)); /* group_lsn[] */
- return BUFFERALIGN(sz) + BLCKSZ * nslots;
+ return BUFFERALIGN(sz) + BLCKSZ * nslots +
+ hash_estimate_size(nslots, sizeof(SlruMappingTableEntry));
}
/*
@@ -187,6 +199,9 @@ SimpleLruInit(SlruCtl ctl, const char *name, int nslots, int nlsns,
LWLock *ctllock, const char *subdir, int tranche_id,
SyncRequestHandler sync_handler)
{
+ char mapping_table_name[SHMEM_INDEX_KEYSIZE];
+ HASHCTL mapping_table_info;
+ HTAB *mapping_table;
SlruShared shared;
bool found;
@@ -258,11 +273,21 @@ SimpleLruInit(SlruCtl ctl, const char *name, int nslots, int nlsns,
else
Assert(found);
+ /* Create or find the buffer mapping table. */
+ memset(&mapping_table_info, 0, sizeof(mapping_table_info));
+ mapping_table_info.keysize = sizeof(int);
+ mapping_table_info.entrysize = sizeof(SlruMappingTableEntry);
+ snprintf(mapping_table_name, sizeof(mapping_table_name),
+ "%s Mapping Table", name);
+ mapping_table = ShmemInitHash(mapping_table_name, nslots, nslots,
+ &mapping_table_info, HASH_ELEM | HASH_BLOBS);
+
/*
* Initialize the unshared control struct, including directory path. We
* assume caller set PagePrecedes.
*/
ctl->shared = shared;
+ ctl->mapping_table = mapping_table;
ctl->sync_handler = sync_handler;
strlcpy(ctl->Dir, subdir, sizeof(ctl->Dir));
}
@@ -289,6 +314,9 @@ SimpleLruZeroPage(SlruCtl ctl, int pageno)
shared->page_number[slotno] == pageno);
/* Mark the slot as containing this page */
+ if (shared->page_status[slotno] == SLRU_PAGE_VALID)
+ SlruMappingRemove(ctl, shared->page_number[slotno]);
+ SlruMappingAdd(ctl, pageno, slotno);
shared->page_number[slotno] = pageno;
shared->page_status[slotno] = SLRU_PAGE_VALID;
shared->page_dirty[slotno] = true;
@@ -362,7 +390,10 @@ SimpleLruWaitIO(SlruCtl ctl, int slotno)
{
/* indeed, the I/O must have failed */
if (shared->page_status[slotno] == SLRU_PAGE_READ_IN_PROGRESS)
+ {
+ SlruMappingRemove(ctl, shared->page_number[slotno]);
shared->page_status[slotno] = SLRU_PAGE_EMPTY;
+ }
else /* write_in_progress */
{
shared->page_status[slotno] = SLRU_PAGE_VALID;
@@ -436,6 +467,7 @@ SimpleLruReadPage(SlruCtl ctl, int pageno, bool write_ok,
!shared->page_dirty[slotno]));
/* Mark the slot read-busy */
+ SlruMappingAdd(ctl, pageno, slotno);
shared->page_number[slotno] = pageno;
shared->page_status[slotno] = SLRU_PAGE_READ_IN_PROGRESS;
shared->page_dirty[slotno] = false;
@@ -459,7 +491,13 @@ SimpleLruReadPage(SlruCtl ctl, int pageno, bool write_ok,
shared->page_status[slotno] == SLRU_PAGE_READ_IN_PROGRESS &&
!shared->page_dirty[slotno]);
- shared->page_status[slotno] = ok ? SLRU_PAGE_VALID : SLRU_PAGE_EMPTY;
+ if (ok)
+ shared->page_status[slotno] = SLRU_PAGE_VALID;
+ else
+ {
+ SlruMappingRemove(ctl, pageno);
+ shared->page_status[slotno] = SLRU_PAGE_EMPTY;
+ }
LWLockRelease(&shared->buffer_locks[slotno].lock);
@@ -1029,11 +1067,12 @@ SlruSelectLRUPage(SlruCtl ctl, int pageno)
int best_invalid_page_number = 0; /* keep compiler quiet */
/* See if page already has a buffer assigned */
- for (slotno = 0; slotno < shared->num_slots; slotno++)
+ slotno = SlruMappingFind(ctl, pageno);
+ if (slotno >= 0)
{
- if (shared->page_number[slotno] == pageno &&
- shared->page_status[slotno] != SLRU_PAGE_EMPTY)
- return slotno;
+ Assert(shared->page_number[slotno] == pageno);
+ Assert(shared->page_status[slotno] != SLRU_PAGE_EMPTY);
+ return slotno;
}
/*
@@ -1266,6 +1305,7 @@ restart:;
if (shared->page_status[slotno] == SLRU_PAGE_VALID &&
!shared->page_dirty[slotno])
{
+ SlruMappingRemove(ctl, shared->page_number[slotno]);
shared->page_status[slotno] = SLRU_PAGE_EMPTY;
continue;
}
@@ -1348,6 +1388,7 @@ restart:
if (shared->page_status[slotno] == SLRU_PAGE_VALID &&
!shared->page_dirty[slotno])
{
+ SlruMappingRemove(ctl, shared->page_number[slotno]);
shared->page_status[slotno] = SLRU_PAGE_EMPTY;
continue;
}
@@ -1609,3 +1650,37 @@ SlruSyncFileTag(SlruCtl ctl, const FileTag *ftag, char *path)
errno = save_errno;
return result;
}
+
+static int
+SlruMappingFind(SlruCtl ctl, int pageno)
+{
+ SlruMappingTableEntry *mapping;
+
+ mapping = hash_search(ctl->mapping_table, &pageno, HASH_FIND, NULL);
+ if (mapping)
+ return mapping->pageno;
+
+ return -1;
+}
+
+static void
+SlruMappingAdd(SlruCtl ctl, int pageno, int slotno)
+{
+ SlruMappingTableEntry *mapping;
+ bool found PG_USED_FOR_ASSERTS_ONLY;
+
+ mapping = hash_search(ctl->mapping_table, &pageno, HASH_ENTER, &found);
+ mapping->slotno = slotno;
+
+ Assert(!found);
+}
+
+static void
+SlruMappingRemove(SlruCtl ctl, int pageno)
+{
+ bool found PG_USED_FOR_ASSERTS_ONLY;
+
+ hash_search(ctl->mapping_table, &pageno, HASH_REMOVE, &found);
+
+ Assert(found);
+}
diff --git a/src/include/access/slru.h b/src/include/access/slru.h
index dd52e8cec7..8aa3efc0ee 100644
--- a/src/include/access/slru.h
+++ b/src/include/access/slru.h
@@ -16,6 +16,7 @@
#include "access/xlogdefs.h"
#include "storage/lwlock.h"
#include "storage/sync.h"
+#include "utils/hsearch.h"
/*
@@ -110,6 +111,7 @@ typedef SlruSharedData *SlruShared;
typedef struct SlruCtlData
{
SlruShared shared;
+ HTAB *mapping_table;
/*
* Which sync handler function to use when handing sync requests over to
--
2.30.1
^ permalink raw reply [nested|flat] 90+ messages in thread
* Re: MultiXact\SLRU buffers configuration
2020-05-08 16:36 MultiXact\SLRU buffers configuration Andrey M. Borodin <[email protected]>
2020-05-11 11:17 ` Re: MultiXact\SLRU buffers configuration Andrey M. Borodin <[email protected]>
2020-05-13 18:08 ` Re: MultiXact\SLRU buffers configuration Andrey M. Borodin <[email protected]>
2020-05-14 01:25 ` Re: MultiXact\SLRU buffers configuration Kyotaro Horiguchi <[email protected]>
2020-05-14 05:19 ` Re: MultiXact\SLRU buffers configuration Andrey M. Borodin <[email protected]>
2020-05-14 06:16 ` Re: MultiXact\SLRU buffers configuration Kyotaro Horiguchi <[email protected]>
2020-05-14 06:44 ` Re: MultiXact\SLRU buffers configuration Andrey M. Borodin <[email protected]>
2020-05-15 00:03 ` Re: MultiXact\SLRU buffers configuration Kyotaro Horiguchi <[email protected]>
2020-07-02 12:02 ` Re: MultiXact\SLRU buffers configuration Daniel Gustafsson <[email protected]>
2020-07-08 07:03 ` Re: MultiXact\SLRU buffers configuration Andrey M. Borodin <[email protected]>
2020-08-28 18:08 ` Re: MultiXact\SLRU buffers configuration Anastasia Lubennikova <[email protected]>
2020-09-28 14:41 ` Re: MultiXact\SLRU buffers configuration Andrey M. Borodin <[email protected]>
2020-10-26 01:05 ` Re: MultiXact\SLRU buffers configuration Alexander Korotkov <[email protected]>
2020-10-26 15:45 ` Re: MultiXact\SLRU buffers configuration Andrey Borodin <[email protected]>
2020-10-27 17:02 ` Re: MultiXact\SLRU buffers configuration Alexander Korotkov <[email protected]>
2020-10-27 17:23 ` Re: MultiXact\SLRU buffers configuration Alexander Korotkov <[email protected]>
2020-10-28 01:36 ` Re: MultiXact\SLRU buffers configuration Tomas Vondra <[email protected]>
2020-10-28 07:34 ` Re: MultiXact\SLRU buffers configuration Andrey Borodin <[email protected]>
2020-10-28 23:32 ` Re: MultiXact\SLRU buffers configuration Tomas Vondra <[email protected]>
2020-10-29 07:08 ` Re: MultiXact\SLRU buffers configuration Andrey Borodin <[email protected]>
2020-10-29 13:49 ` Re: MultiXact\SLRU buffers configuration Tomas Vondra <[email protected]>
2020-11-02 12:45 ` Re: MultiXact\SLRU buffers configuration Andrey Borodin <[email protected]>
2020-11-10 00:13 ` Re: MultiXact\SLRU buffers configuration Tomas Vondra <[email protected]>
2020-11-10 06:16 ` Re: MultiXact\SLRU buffers configuration Andrey Borodin <[email protected]>
2020-11-10 18:07 ` Re: MultiXact\SLRU buffers configuration Tomas Vondra <[email protected]>
2020-11-13 11:49 ` Re: MultiXact\SLRU buffers configuration Andrey Borodin <[email protected]>
2020-12-08 16:05 ` Re: MultiXact\SLRU buffers configuration Gilles Darold <[email protected]>
2020-12-08 17:52 ` Re: MultiXact\SLRU buffers configuration Andrey Borodin <[email protected]>
2020-12-10 14:45 ` Re: MultiXact\SLRU buffers configuration Gilles Darold <[email protected]>
2020-12-11 17:50 ` Re: MultiXact\SLRU buffers configuration Gilles Darold <[email protected]>
2020-12-13 09:17 ` Re: MultiXact\SLRU buffers configuration Gilles Darold <[email protected]>
2020-12-13 17:24 ` Re: MultiXact\SLRU buffers configuration Andrey Borodin <[email protected]>
2020-12-23 16:31 ` Re: MultiXact\SLRU buffers configuration Gilles Darold <[email protected]>
2021-02-15 17:17 ` Re: MultiXact\SLRU buffers configuration Andrey Borodin <[email protected]>
2021-03-11 15:50 ` Re: MultiXact\SLRU buffers configuration Gilles Darold <[email protected]>
2021-03-12 12:44 ` Re: MultiXact\SLRU buffers configuration Andrey Borodin <[email protected]>
2021-03-24 21:31 ` Re: MultiXact\SLRU buffers configuration Thomas Munro <[email protected]>
@ 2021-03-25 01:03 ` Thomas Munro <[email protected]>
2021-03-26 03:46 ` Re: MultiXact\SLRU buffers configuration Thomas Munro <[email protected]>
0 siblings, 1 reply; 90+ messages in thread
From: Thomas Munro @ 2021-03-25 01:03 UTC (permalink / raw)
To: Andrey Borodin <[email protected]>; +Cc: Gilles Darold <[email protected]>; Tomas Vondra <[email protected]>; Tomas Vondra <[email protected]>; Alexander Korotkov <[email protected]>; Anastasia Lubennikova <[email protected]>; Daniel Gustafsson <[email protected]>; Kyotaro Horiguchi <[email protected]>; pgsql-hackers
On Thu, Mar 25, 2021 at 10:31 AM Thomas Munro <[email protected]> wrote:
> We already know that increasing the number of CLOG buffers above the
> current number hurts as the linear search begins to dominate
> (according to the commit message for 5364b357), and it doesn't seem
> great to ship a new feature that melts your CPU when you turn it up.
> Perhaps, to ship this, we need to introduce a buffer mapping table? I
> have attached a "one coffee" attempt at that, on top of your v10 patch
> (unmodified), for discussion. It survives basic testing but I don't
> know how it performs.
Hrrr... Cfbot showed an assertion failure. Here's the two coffee
version with a couple of silly mistakes fixed.
Attachments:
[text/x-patch] v11-0001-Make-all-SLRU-buffer-sizes-configurable.patch (19.5K, ../../CA+hUKGK2bkx91=CWRuPqWdXAu2JSS0mDPBh8DNuSeKhy8eOLgg@mail.gmail.com/2-v11-0001-Make-all-SLRU-buffer-sizes-configurable.patch)
download | inline diff:
From 4817d16cfb6704d43a7bef12648e753d239c809c Mon Sep 17 00:00:00 2001
From: Andrey Borodin <[email protected]>
Date: Mon, 15 Feb 2021 21:51:56 +0500
Subject: [PATCH v11 1/2] Make all SLRU buffer sizes configurable
---
doc/src/sgml/config.sgml | 108 ++++++++++++++++++
src/backend/access/transam/clog.c | 6 +
src/backend/access/transam/commit_ts.c | 5 +-
src/backend/access/transam/multixact.c | 8 +-
src/backend/access/transam/subtrans.c | 5 +-
src/backend/commands/async.c | 8 +-
src/backend/storage/lmgr/predicate.c | 4 +-
src/backend/utils/init/globals.c | 8 ++
src/backend/utils/misc/guc.c | 77 +++++++++++++
src/backend/utils/misc/postgresql.conf.sample | 16 +++
src/include/access/multixact.h | 4 -
src/include/access/subtrans.h | 3 -
src/include/commands/async.h | 5 -
src/include/miscadmin.h | 8 ++
src/include/storage/predicate.h | 4 -
15 files changed, 240 insertions(+), 29 deletions(-)
diff --git a/doc/src/sgml/config.sgml b/doc/src/sgml/config.sgml
index ddc6d789d8..0adcf0efaf 100644
--- a/doc/src/sgml/config.sgml
+++ b/doc/src/sgml/config.sgml
@@ -1886,6 +1886,114 @@ include_dir 'conf.d'
</para>
</listitem>
</varlistentry>
+
+ <varlistentry id="guc-multixact-offsets-slru-buffers" xreflabel="multixact_offsets_slru_buffers">
+ <term><varname>multixact_offsets_slru_buffers</varname> (<type>integer</type>)
+ <indexterm>
+ <primary><varname>multixact_offsets_slru_buffers</varname> configuration parameter</primary>
+ </indexterm>
+ </term>
+ <listitem>
+ <para>
+ Specifies the amount of memory to be used for MultiXact offsets. MultiXact offsets
+ are used to store information about offsets of multiple row lockers (caused by SELECT FOR UPDATE and others).
+ It defaults to 64 kilobytes (<literal>64KB</literal>).
+ This parameter can only be set at server start.
+ </para>
+ </listitem>
+ </varlistentry>
+
+ <varlistentry id="guc-multixact-members-slru-buffers" xreflabel="multixact_members_slru_buffers">
+ <term><varname>multixact_members_slru_buffers</varname> (<type>integer</type>)
+ <indexterm>
+ <primary><varname>multixact_members_slru_buffers</varname> configuration parameter</primary>
+ </indexterm>
+ </term>
+ <listitem>
+ <para>
+ Specifies the amount of memory to be used for MultiXact members. MultiXact members
+ are used to store information about XIDs of multiple row lockers. Typically <varname>multixact_members_slru_buffers</varname>
+ is twice more than <varname>multixact_offsets_slru_buffers</varname>.
+ It defaults to 128 kilobytes (<literal>128KB</literal>).
+ This parameter can only be set at server start.
+ </para>
+ </listitem>
+ </varlistentry>
+
+ <varlistentry id="guc-subtrans-buffers" xreflabel="subtrans_slru_buffers">
+ <term><varname>subtrans_slru_buffers</varname> (<type>integer</type>)
+ <indexterm>
+ <primary><varname>subtrans_slru_buffers</varname> configuration parameter</primary>
+ </indexterm>
+ </term>
+ <listitem>
+ <para>
+ Specifies the amount of memory to be used for subtransactions.
+ It defaults to 256 kilobytes (<literal>256KB</literal>).
+ This parameter can only be set at server start.
+ </para>
+ </listitem>
+ </varlistentry>
+
+ <varlistentry id="guc-notify-buffers" xreflabel="notify_slru_buffers">
+ <term><varname>notify_slru_buffers</varname> (<type>integer</type>)
+ <indexterm>
+ <primary><varname>notify_slru_buffers</varname> configuration parameter</primary>
+ </indexterm>
+ </term>
+ <listitem>
+ <para>
+ Specifies the amount of memory to be used for asyncronous notifications (NOTIFY, LISTEN).
+ It defaults to 64 kilobytes (<literal>64KB</literal>).
+ This parameter can only be set at server start.
+ </para>
+ </listitem>
+ </varlistentry>
+
+ <varlistentry id="guc-serial-buffers" xreflabel="serial_slru_buffers">
+ <term><varname>serial_slru_buffers</varname> (<type>integer</type>)
+ <indexterm>
+ <primary><varname>serial_slru_buffers</varname> configuration parameter</primary>
+ </indexterm>
+ </term>
+ <listitem>
+ <para>
+ Specifies the amount of memory to be used for predicate locks.
+ It defaults to 128 kilobytes (<literal>128KB</literal>).
+ This parameter can only be set at server start.
+ </para>
+ </listitem>
+ </varlistentry>
+
+ <varlistentry id="guc-clog-buffers" xreflabel="clog_slru_buffers">
+ <term><varname>clog_slru_buffers</varname> (<type>integer</type>)
+ <indexterm>
+ <primary><varname>clog_slru_buffers</varname> configuration parameter</primary>
+ </indexterm>
+ </term>
+ <listitem>
+ <para>
+ Specifies the amount of memory to be used for CLOG.
+ It defaults to 0, in this case CLOG size is taken as <varname>shared_buffers</varname> / 512.
+ This parameter can only be set at server start.
+ </para>
+ </listitem>
+ </varlistentry>
+
+ <varlistentry id="guc-commit-ts-buffers" xreflabel="commit_ts_slru_buffers">
+ <term><varname>commit_ts_slru_buffers</varname> (<type>integer</type>)
+ <indexterm>
+ <primary><varname>commit_ts_slru_buffers</varname> configuration parameter</primary>
+ </indexterm>
+ </term>
+ <listitem>
+ <para>
+ Specifies the amount of memory to be used for commit timestamps.
+ It defaults to 0, in this case CLOG size is taken as <varname>shared_buffers</varname> / 512.
+ This parameter can only be set at server start.
+ </para>
+ </listitem>
+ </varlistentry>
<varlistentry id="guc-max-stack-depth" xreflabel="max_stack_depth">
<term><varname>max_stack_depth</varname> (<type>integer</type>)
diff --git a/src/backend/access/transam/clog.c b/src/backend/access/transam/clog.c
index 6fa4713fb4..e1d34aa361 100644
--- a/src/backend/access/transam/clog.c
+++ b/src/backend/access/transam/clog.c
@@ -659,6 +659,9 @@ TransactionIdGetStatus(TransactionId xid, XLogRecPtr *lsn)
/*
* Number of shared CLOG buffers.
*
+ * If values is configured via GUC - just use given value. Otherwise
+ * apply following euristics.
+ *
* On larger multi-processor systems, it is possible to have many CLOG page
* requests in flight at one time which could lead to disk access for CLOG
* page if the required page is not found in memory. Testing revealed that we
@@ -675,6 +678,9 @@ TransactionIdGetStatus(TransactionId xid, XLogRecPtr *lsn)
Size
CLOGShmemBuffers(void)
{
+ /* consider 0 and 1 as unset GUC */
+ if (clog_slru_buffers > 1)
+ return clog_slru_buffers;
return Min(128, Max(4, NBuffers / 512));
}
diff --git a/src/backend/access/transam/commit_ts.c b/src/backend/access/transam/commit_ts.c
index 48e8d66286..7de3bca63d 100644
--- a/src/backend/access/transam/commit_ts.c
+++ b/src/backend/access/transam/commit_ts.c
@@ -530,7 +530,10 @@ pg_xact_commit_timestamp_origin(PG_FUNCTION_ARGS)
Size
CommitTsShmemBuffers(void)
{
- return Min(16, Max(4, NBuffers / 1024));
+ /* consider 0 and 1 as unset GUC */
+ if (commit_ts_slru_buffers > 1)
+ return commit_ts_slru_buffers;
+ return Min(16, Max(4, NBuffers / 512));
}
/*
diff --git a/src/backend/access/transam/multixact.c b/src/backend/access/transam/multixact.c
index 1f9f1a1fa1..370c01e72b 100644
--- a/src/backend/access/transam/multixact.c
+++ b/src/backend/access/transam/multixact.c
@@ -1831,8 +1831,8 @@ MultiXactShmemSize(void)
mul_size(sizeof(MultiXactId) * 2, MaxOldestSlot))
size = SHARED_MULTIXACT_STATE_SIZE;
- size = add_size(size, SimpleLruShmemSize(NUM_MULTIXACTOFFSET_BUFFERS, 0));
- size = add_size(size, SimpleLruShmemSize(NUM_MULTIXACTMEMBER_BUFFERS, 0));
+ size = add_size(size, SimpleLruShmemSize(multixact_offsets_slru_buffers, 0));
+ size = add_size(size, SimpleLruShmemSize(multixact_members_slru_buffers, 0));
return size;
}
@@ -1848,13 +1848,13 @@ MultiXactShmemInit(void)
MultiXactMemberCtl->PagePrecedes = MultiXactMemberPagePrecedes;
SimpleLruInit(MultiXactOffsetCtl,
- "MultiXactOffset", NUM_MULTIXACTOFFSET_BUFFERS, 0,
+ "MultiXactOffset", multixact_offsets_slru_buffers, 0,
MultiXactOffsetSLRULock, "pg_multixact/offsets",
LWTRANCHE_MULTIXACTOFFSET_BUFFER,
SYNC_HANDLER_MULTIXACT_OFFSET);
SlruPagePrecedesUnitTests(MultiXactOffsetCtl, MULTIXACT_OFFSETS_PER_PAGE);
SimpleLruInit(MultiXactMemberCtl,
- "MultiXactMember", NUM_MULTIXACTMEMBER_BUFFERS, 0,
+ "MultiXactMember", multixact_offsets_slru_buffers, 0,
MultiXactMemberSLRULock, "pg_multixact/members",
LWTRANCHE_MULTIXACTMEMBER_BUFFER,
SYNC_HANDLER_MULTIXACT_MEMBER);
diff --git a/src/backend/access/transam/subtrans.c b/src/backend/access/transam/subtrans.c
index 6a8e521f89..0c24353d3a 100644
--- a/src/backend/access/transam/subtrans.c
+++ b/src/backend/access/transam/subtrans.c
@@ -31,6 +31,7 @@
#include "access/slru.h"
#include "access/subtrans.h"
#include "access/transam.h"
+#include "miscadmin.h"
#include "pg_trace.h"
#include "utils/snapmgr.h"
@@ -184,14 +185,14 @@ SubTransGetTopmostTransaction(TransactionId xid)
Size
SUBTRANSShmemSize(void)
{
- return SimpleLruShmemSize(NUM_SUBTRANS_BUFFERS, 0);
+ return SimpleLruShmemSize(subtrans_slru_buffers, 0);
}
void
SUBTRANSShmemInit(void)
{
SubTransCtl->PagePrecedes = SubTransPagePrecedes;
- SimpleLruInit(SubTransCtl, "Subtrans", NUM_SUBTRANS_BUFFERS, 0,
+ SimpleLruInit(SubTransCtl, "Subtrans", subtrans_slru_buffers, 0,
SubtransSLRULock, "pg_subtrans",
LWTRANCHE_SUBTRANS_BUFFER, SYNC_HANDLER_NONE);
SlruPagePrecedesUnitTests(SubTransCtl, SUBTRANS_XACTS_PER_PAGE);
diff --git a/src/backend/commands/async.c b/src/backend/commands/async.c
index 4b16fb5682..f5c5592057 100644
--- a/src/backend/commands/async.c
+++ b/src/backend/commands/async.c
@@ -107,7 +107,7 @@
* frontend during startup.) The above design guarantees that notifies from
* other backends will never be missed by ignoring self-notifies.
*
- * The amount of shared memory used for notify management (NUM_NOTIFY_BUFFERS)
+ * The amount of shared memory used for notify management (notify_slru_buffers)
* can be varied without affecting anything but performance. The maximum
* amount of notification data that can be queued at one time is determined
* by slru.c's wraparound limit; see QUEUE_MAX_PAGE below.
@@ -225,7 +225,7 @@ typedef struct QueuePosition
*
* Resist the temptation to make this really large. While that would save
* work in some places, it would add cost in others. In particular, this
- * should likely be less than NUM_NOTIFY_BUFFERS, to ensure that backends
+ * should likely be less than notify_slru_buffers, to ensure that backends
* catch up before the pages they'll need to read fall out of SLRU cache.
*/
#define QUEUE_CLEANUP_DELAY 4
@@ -514,7 +514,7 @@ AsyncShmemSize(void)
size = mul_size(MaxBackends + 1, sizeof(QueueBackendStatus));
size = add_size(size, offsetof(AsyncQueueControl, backend));
- size = add_size(size, SimpleLruShmemSize(NUM_NOTIFY_BUFFERS, 0));
+ size = add_size(size, SimpleLruShmemSize(notify_slru_buffers, 0));
return size;
}
@@ -562,7 +562,7 @@ AsyncShmemInit(void)
* Set up SLRU management of the pg_notify data.
*/
NotifyCtl->PagePrecedes = asyncQueuePagePrecedes;
- SimpleLruInit(NotifyCtl, "Notify", NUM_NOTIFY_BUFFERS, 0,
+ SimpleLruInit(NotifyCtl, "Notify", notify_slru_buffers, 0,
NotifySLRULock, "pg_notify", LWTRANCHE_NOTIFY_BUFFER,
SYNC_HANDLER_NONE);
diff --git a/src/backend/storage/lmgr/predicate.c b/src/backend/storage/lmgr/predicate.c
index d493aeef0f..fad8cc572e 100644
--- a/src/backend/storage/lmgr/predicate.c
+++ b/src/backend/storage/lmgr/predicate.c
@@ -872,7 +872,7 @@ SerialInit(void)
*/
SerialSlruCtl->PagePrecedes = SerialPagePrecedesLogically;
SimpleLruInit(SerialSlruCtl, "Serial",
- NUM_SERIAL_BUFFERS, 0, SerialSLRULock, "pg_serial",
+ serial_slru_buffers, 0, SerialSLRULock, "pg_serial",
LWTRANCHE_SERIAL_BUFFER, SYNC_HANDLER_NONE);
#ifdef USE_ASSERT_CHECKING
SerialPagePrecedesLogicallyUnitTests();
@@ -1395,7 +1395,7 @@ PredicateLockShmemSize(void)
/* Shared memory structures for SLRU tracking of old committed xids. */
size = add_size(size, sizeof(SerialControlData));
- size = add_size(size, SimpleLruShmemSize(NUM_SERIAL_BUFFERS, 0));
+ size = add_size(size, SimpleLruShmemSize(serial_slru_buffers, 0));
return size;
}
diff --git a/src/backend/utils/init/globals.c b/src/backend/utils/init/globals.c
index 73e0a672ae..f163ca17e9 100644
--- a/src/backend/utils/init/globals.c
+++ b/src/backend/utils/init/globals.c
@@ -148,3 +148,11 @@ int64 VacuumPageDirty = 0;
int VacuumCostBalance = 0; /* working state for vacuum */
bool VacuumCostActive = false;
+
+int multixact_offsets_slru_buffers = 8;
+int multixact_members_slru_buffers = 16;
+int subtrans_slru_buffers = 32;
+int notify_slru_buffers = 8;
+int serial_slru_buffers = 16;
+int clog_slru_buffers = 0;
+int commit_ts_slru_buffers = 0;
diff --git a/src/backend/utils/misc/guc.c b/src/backend/utils/misc/guc.c
index 0c5dc4d3e8..b65a4ae9ce 100644
--- a/src/backend/utils/misc/guc.c
+++ b/src/backend/utils/misc/guc.c
@@ -2305,6 +2305,83 @@ static struct config_int ConfigureNamesInt[] =
NULL, NULL, NULL
},
+ {
+ {"multixact_offsets_slru_buffers", PGC_POSTMASTER, RESOURCES_MEM,
+ gettext_noop("Sets the number of shared memory buffers used for MultiXact offsets SLRU."),
+ NULL,
+ GUC_UNIT_BLOCKS
+ },
+ &multixact_offsets_slru_buffers,
+ 8, 2, INT_MAX / 2,
+ NULL, NULL, NULL
+ },
+
+ {
+ {"multixact_members_slru_buffers", PGC_POSTMASTER, RESOURCES_MEM,
+ gettext_noop("Sets the number of shared memory buffers used for MultiXact members SLRU."),
+ NULL,
+ GUC_UNIT_BLOCKS
+ },
+ &multixact_members_slru_buffers,
+ 16, 2, INT_MAX / 2,
+ NULL, NULL, NULL
+ },
+
+ {
+ {"subtrans_slru_buffers", PGC_POSTMASTER, RESOURCES_MEM,
+ gettext_noop("Sets the number of shared memory buffers used for substransactions SLRU."),
+ NULL,
+ GUC_UNIT_BLOCKS
+ },
+ &subtrans_slru_buffers,
+ 32, 2, INT_MAX / 2,
+ NULL, NULL, NULL
+ },
+
+ {
+ {"notify_slru_buffers", PGC_POSTMASTER, RESOURCES_MEM,
+ gettext_noop("Sets the number of shared memory buffers used for asyncronous notifications SLRU."),
+ NULL,
+ GUC_UNIT_BLOCKS
+ },
+ ¬ify_slru_buffers,
+ 8, 2, INT_MAX / 2,
+ NULL, NULL, NULL
+ },
+
+ {
+ {"serial_slru_buffers", PGC_POSTMASTER, RESOURCES_MEM,
+ gettext_noop("Sets the number of shared memory buffers used for predicate locks SLRU."),
+ NULL,
+ GUC_UNIT_BLOCKS
+ },
+ &serial_slru_buffers,
+ 16, 2, INT_MAX / 2,
+ NULL, NULL, NULL
+ },
+
+ {
+ {"clog_slru_buffers", PGC_POSTMASTER, RESOURCES_MEM,
+ gettext_noop("Sets the number of shared memory buffers used for commit log SLRU."),
+ NULL,
+ GUC_UNIT_BLOCKS
+ },
+ &serial_slru_buffers,
+ 0, 0, INT_MAX / 2,
+ NULL, NULL, NULL
+ },
+
+ {
+ {"commit_ts_slru_buffers", PGC_POSTMASTER, RESOURCES_MEM,
+ gettext_noop("Sets the number of shared memory buffers used for commit timestamps SLRU."),
+ NULL,
+ GUC_UNIT_BLOCKS
+ },
+ &commit_ts_slru_buffers,
+ 0, 0, INT_MAX / 2,
+ NULL, NULL, NULL
+ },
+
{
{"temp_buffers", PGC_USERSET, RESOURCES_MEM,
gettext_noop("Sets the maximum number of temporary buffers used by each session."),
diff --git a/src/backend/utils/misc/postgresql.conf.sample b/src/backend/utils/misc/postgresql.conf.sample
index b234a6bfe6..308fd565d3 100644
--- a/src/backend/utils/misc/postgresql.conf.sample
+++ b/src/backend/utils/misc/postgresql.conf.sample
@@ -190,6 +190,22 @@
# (change requires restart)
#backend_flush_after = 0 # measured in pages, 0 disables
+# - SLRU Buffers -
+
+#multixact_offsets_slru_buffers = 8 # memory used for MultiXact offsets
+ # (change requires restart)
+#multixact_members_slru_buffers = 16 # memory used for MultiXact members
+ # (change requires restart)
+#subtrans_slru_buffers = 32 # memory used for subtransactions
+ # (change requires restart)
+#notify_slru_buffers = 8 # memory used for asynchronous notifications
+ # (change requires restart)
+#serial_slru_buffers = 16 # memory used for predicate locks
+ # (change requires restart)
+#clog_slru_buffers = 0 # memory used for CLOG
+ # (change requires restart)
+#commit_ts_slru_buffers = 0 # memory used for commit timestamps
+ # (change requires restart)
#------------------------------------------------------------------------------
# WRITE-AHEAD LOG
diff --git a/src/include/access/multixact.h b/src/include/access/multixact.h
index 4bbb035eae..97c0a46376 100644
--- a/src/include/access/multixact.h
+++ b/src/include/access/multixact.h
@@ -29,10 +29,6 @@
#define MaxMultiXactOffset ((MultiXactOffset) 0xFFFFFFFF)
-/* Number of SLRU buffers to use for multixact */
-#define NUM_MULTIXACTOFFSET_BUFFERS 8
-#define NUM_MULTIXACTMEMBER_BUFFERS 16
-
/*
* Possible multixact lock modes ("status"). The first four modes are for
* tuple locks (FOR KEY SHARE, FOR SHARE, FOR NO KEY UPDATE, FOR UPDATE); the
diff --git a/src/include/access/subtrans.h b/src/include/access/subtrans.h
index d0ab44ae82..ca0999056e 100644
--- a/src/include/access/subtrans.h
+++ b/src/include/access/subtrans.h
@@ -11,9 +11,6 @@
#ifndef SUBTRANS_H
#define SUBTRANS_H
-/* Number of SLRU buffers to use for subtrans */
-#define NUM_SUBTRANS_BUFFERS 32
-
extern void SubTransSetParent(TransactionId xid, TransactionId parent);
extern TransactionId SubTransGetParent(TransactionId xid);
extern TransactionId SubTransGetTopmostTransaction(TransactionId xid);
diff --git a/src/include/commands/async.h b/src/include/commands/async.h
index 9217f66b91..fa831e3721 100644
--- a/src/include/commands/async.h
+++ b/src/include/commands/async.h
@@ -15,11 +15,6 @@
#include <signal.h>
-/*
- * The number of SLRU page buffers we use for the notification queue.
- */
-#define NUM_NOTIFY_BUFFERS 8
-
extern bool Trace_notify;
extern volatile sig_atomic_t notifyInterruptPending;
diff --git a/src/include/miscadmin.h b/src/include/miscadmin.h
index 013850ac28..3d9f585fb9 100644
--- a/src/include/miscadmin.h
+++ b/src/include/miscadmin.h
@@ -162,6 +162,14 @@ extern PGDLLIMPORT int MaxBackends;
extern PGDLLIMPORT int MaxConnections;
extern PGDLLIMPORT int max_worker_processes;
extern PGDLLIMPORT int max_parallel_workers;
+extern PGDLLIMPORT int multixact_offsets_slru_buffers;
+extern PGDLLIMPORT int multixact_members_slru_buffers;
+extern PGDLLIMPORT int multixact_members_slru_buffers;
+extern PGDLLIMPORT int subtrans_slru_buffers;
+extern PGDLLIMPORT int notify_slru_buffers;
+extern PGDLLIMPORT int serial_slru_buffers;
+extern PGDLLIMPORT int clog_slru_buffers;
+extern PGDLLIMPORT int commit_ts_slru_buffers;
extern PGDLLIMPORT int MyProcPid;
extern PGDLLIMPORT pg_time_t MyStartTime;
diff --git a/src/include/storage/predicate.h b/src/include/storage/predicate.h
index 152b698611..c72779bd88 100644
--- a/src/include/storage/predicate.h
+++ b/src/include/storage/predicate.h
@@ -26,10 +26,6 @@ extern int max_predicate_locks_per_xact;
extern int max_predicate_locks_per_relation;
extern int max_predicate_locks_per_page;
-
-/* Number of SLRU buffers to use for Serial SLRU */
-#define NUM_SERIAL_BUFFERS 16
-
/*
* A handle used for sharing SERIALIZABLEXACT objects between the participants
* in a parallel query.
--
2.30.1
[text/x-patch] v11-0002-Add-buffer-mapping-table-for-SLRUs.patch (7.0K, ../../CA+hUKGK2bkx91=CWRuPqWdXAu2JSS0mDPBh8DNuSeKhy8eOLgg@mail.gmail.com/3-v11-0002-Add-buffer-mapping-table-for-SLRUs.patch)
download | inline diff:
From 65600b53939c34abf43e62f3f59be5671c43d301 Mon Sep 17 00:00:00 2001
From: Thomas Munro <[email protected]>
Date: Thu, 25 Mar 2021 10:11:31 +1300
Subject: [PATCH v11 2/2] Add buffer mapping table for SLRUs.
---
src/backend/access/transam/slru.c | 87 ++++++++++++++++++++++++++++---
src/include/access/slru.h | 2 +
2 files changed, 83 insertions(+), 6 deletions(-)
diff --git a/src/backend/access/transam/slru.c b/src/backend/access/transam/slru.c
index 82149ad782..487585bb60 100644
--- a/src/backend/access/transam/slru.c
+++ b/src/backend/access/transam/slru.c
@@ -58,6 +58,8 @@
#include "pgstat.h"
#include "storage/fd.h"
#include "storage/shmem.h"
+#include "utils/dynahash.h"
+#include "utils/hsearch.h"
#define SlruFileName(ctl, path, seg) \
snprintf(path, MAXPGPATH, "%s/%04X", (ctl)->Dir, seg)
@@ -79,6 +81,12 @@ typedef struct SlruWriteAllData
typedef struct SlruWriteAllData *SlruWriteAll;
+typedef struct SlruMappingTableEntry
+{
+ int pageno;
+ int slotno;
+} SlruMappingTableEntry;
+
/*
* Populate a file tag describing a segment file. We only use the segment
* number, since we can derive everything else we need by having separate
@@ -146,6 +154,9 @@ static int SlruSelectLRUPage(SlruCtl ctl, int pageno);
static bool SlruScanDirCbDeleteCutoff(SlruCtl ctl, char *filename,
int segpage, void *data);
static void SlruInternalDeleteSegment(SlruCtl ctl, int segno);
+static void SlruMappingAdd(SlruCtl ctl, int pageno, int slotno);
+static void SlruMappingRemove(SlruCtl ctl, int pageno);
+static int SlruMappingFind(SlruCtl ctl, int pageno);
/*
* Initialization of shared memory
@@ -168,7 +179,8 @@ SimpleLruShmemSize(int nslots, int nlsns)
if (nlsns > 0)
sz += MAXALIGN(nslots * nlsns * sizeof(XLogRecPtr)); /* group_lsn[] */
- return BUFFERALIGN(sz) + BLCKSZ * nslots;
+ return BUFFERALIGN(sz) + BLCKSZ * nslots +
+ hash_estimate_size(nslots, sizeof(SlruMappingTableEntry));
}
/*
@@ -187,6 +199,9 @@ SimpleLruInit(SlruCtl ctl, const char *name, int nslots, int nlsns,
LWLock *ctllock, const char *subdir, int tranche_id,
SyncRequestHandler sync_handler)
{
+ char mapping_table_name[SHMEM_INDEX_KEYSIZE];
+ HASHCTL mapping_table_info;
+ HTAB *mapping_table;
SlruShared shared;
bool found;
@@ -258,11 +273,21 @@ SimpleLruInit(SlruCtl ctl, const char *name, int nslots, int nlsns,
else
Assert(found);
+ /* Create or find the buffer mapping table. */
+ memset(&mapping_table_info, 0, sizeof(mapping_table_info));
+ mapping_table_info.keysize = sizeof(int);
+ mapping_table_info.entrysize = sizeof(SlruMappingTableEntry);
+ snprintf(mapping_table_name, sizeof(mapping_table_name),
+ "%s Mapping Table", name);
+ mapping_table = ShmemInitHash(mapping_table_name, nslots, nslots,
+ &mapping_table_info, HASH_ELEM | HASH_BLOBS);
+
/*
* Initialize the unshared control struct, including directory path. We
* assume caller set PagePrecedes.
*/
ctl->shared = shared;
+ ctl->mapping_table = mapping_table;
ctl->sync_handler = sync_handler;
strlcpy(ctl->Dir, subdir, sizeof(ctl->Dir));
}
@@ -289,6 +314,9 @@ SimpleLruZeroPage(SlruCtl ctl, int pageno)
shared->page_number[slotno] == pageno);
/* Mark the slot as containing this page */
+ if (shared->page_status[slotno] != SLRU_PAGE_EMPTY)
+ SlruMappingRemove(ctl, shared->page_number[slotno]);
+ SlruMappingAdd(ctl, pageno, slotno);
shared->page_number[slotno] = pageno;
shared->page_status[slotno] = SLRU_PAGE_VALID;
shared->page_dirty[slotno] = true;
@@ -362,7 +390,10 @@ SimpleLruWaitIO(SlruCtl ctl, int slotno)
{
/* indeed, the I/O must have failed */
if (shared->page_status[slotno] == SLRU_PAGE_READ_IN_PROGRESS)
+ {
+ SlruMappingRemove(ctl, shared->page_number[slotno]);
shared->page_status[slotno] = SLRU_PAGE_EMPTY;
+ }
else /* write_in_progress */
{
shared->page_status[slotno] = SLRU_PAGE_VALID;
@@ -436,6 +467,7 @@ SimpleLruReadPage(SlruCtl ctl, int pageno, bool write_ok,
!shared->page_dirty[slotno]));
/* Mark the slot read-busy */
+ SlruMappingAdd(ctl, pageno, slotno);
shared->page_number[slotno] = pageno;
shared->page_status[slotno] = SLRU_PAGE_READ_IN_PROGRESS;
shared->page_dirty[slotno] = false;
@@ -459,7 +491,13 @@ SimpleLruReadPage(SlruCtl ctl, int pageno, bool write_ok,
shared->page_status[slotno] == SLRU_PAGE_READ_IN_PROGRESS &&
!shared->page_dirty[slotno]);
- shared->page_status[slotno] = ok ? SLRU_PAGE_VALID : SLRU_PAGE_EMPTY;
+ if (ok)
+ shared->page_status[slotno] = SLRU_PAGE_VALID;
+ else
+ {
+ SlruMappingRemove(ctl, pageno);
+ shared->page_status[slotno] = SLRU_PAGE_EMPTY;
+ }
LWLockRelease(&shared->buffer_locks[slotno].lock);
@@ -1029,11 +1067,12 @@ SlruSelectLRUPage(SlruCtl ctl, int pageno)
int best_invalid_page_number = 0; /* keep compiler quiet */
/* See if page already has a buffer assigned */
- for (slotno = 0; slotno < shared->num_slots; slotno++)
+ slotno = SlruMappingFind(ctl, pageno);
+ if (slotno >= 0)
{
- if (shared->page_number[slotno] == pageno &&
- shared->page_status[slotno] != SLRU_PAGE_EMPTY)
- return slotno;
+ Assert(shared->page_number[slotno] == pageno);
+ Assert(shared->page_status[slotno] != SLRU_PAGE_EMPTY);
+ return slotno;
}
/*
@@ -1266,6 +1305,7 @@ restart:;
if (shared->page_status[slotno] == SLRU_PAGE_VALID &&
!shared->page_dirty[slotno])
{
+ SlruMappingRemove(ctl, shared->page_number[slotno]);
shared->page_status[slotno] = SLRU_PAGE_EMPTY;
continue;
}
@@ -1348,6 +1388,7 @@ restart:
if (shared->page_status[slotno] == SLRU_PAGE_VALID &&
!shared->page_dirty[slotno])
{
+ SlruMappingRemove(ctl, shared->page_number[slotno]);
shared->page_status[slotno] = SLRU_PAGE_EMPTY;
continue;
}
@@ -1609,3 +1650,37 @@ SlruSyncFileTag(SlruCtl ctl, const FileTag *ftag, char *path)
errno = save_errno;
return result;
}
+
+static int
+SlruMappingFind(SlruCtl ctl, int pageno)
+{
+ SlruMappingTableEntry *mapping;
+
+ mapping = hash_search(ctl->mapping_table, &pageno, HASH_FIND, NULL);
+ if (mapping)
+ return mapping->slotno;
+
+ return -1;
+}
+
+static void
+SlruMappingAdd(SlruCtl ctl, int pageno, int slotno)
+{
+ SlruMappingTableEntry *mapping;
+ bool found PG_USED_FOR_ASSERTS_ONLY;
+
+ mapping = hash_search(ctl->mapping_table, &pageno, HASH_ENTER, &found);
+ mapping->slotno = slotno;
+
+ Assert(!found);
+}
+
+static void
+SlruMappingRemove(SlruCtl ctl, int pageno)
+{
+ bool found PG_USED_FOR_ASSERTS_ONLY;
+
+ hash_search(ctl->mapping_table, &pageno, HASH_REMOVE, &found);
+
+ Assert(found);
+}
diff --git a/src/include/access/slru.h b/src/include/access/slru.h
index dd52e8cec7..8aa3efc0ee 100644
--- a/src/include/access/slru.h
+++ b/src/include/access/slru.h
@@ -16,6 +16,7 @@
#include "access/xlogdefs.h"
#include "storage/lwlock.h"
#include "storage/sync.h"
+#include "utils/hsearch.h"
/*
@@ -110,6 +111,7 @@ typedef SlruSharedData *SlruShared;
typedef struct SlruCtlData
{
SlruShared shared;
+ HTAB *mapping_table;
/*
* Which sync handler function to use when handing sync requests over to
--
2.30.1
^ permalink raw reply [nested|flat] 90+ messages in thread
* Re: MultiXact\SLRU buffers configuration
2020-05-08 16:36 MultiXact\SLRU buffers configuration Andrey M. Borodin <[email protected]>
2020-05-11 11:17 ` Re: MultiXact\SLRU buffers configuration Andrey M. Borodin <[email protected]>
2020-05-13 18:08 ` Re: MultiXact\SLRU buffers configuration Andrey M. Borodin <[email protected]>
2020-05-14 01:25 ` Re: MultiXact\SLRU buffers configuration Kyotaro Horiguchi <[email protected]>
2020-05-14 05:19 ` Re: MultiXact\SLRU buffers configuration Andrey M. Borodin <[email protected]>
2020-05-14 06:16 ` Re: MultiXact\SLRU buffers configuration Kyotaro Horiguchi <[email protected]>
2020-05-14 06:44 ` Re: MultiXact\SLRU buffers configuration Andrey M. Borodin <[email protected]>
2020-05-15 00:03 ` Re: MultiXact\SLRU buffers configuration Kyotaro Horiguchi <[email protected]>
2020-07-02 12:02 ` Re: MultiXact\SLRU buffers configuration Daniel Gustafsson <[email protected]>
2020-07-08 07:03 ` Re: MultiXact\SLRU buffers configuration Andrey M. Borodin <[email protected]>
2020-08-28 18:08 ` Re: MultiXact\SLRU buffers configuration Anastasia Lubennikova <[email protected]>
2020-09-28 14:41 ` Re: MultiXact\SLRU buffers configuration Andrey M. Borodin <[email protected]>
2020-10-26 01:05 ` Re: MultiXact\SLRU buffers configuration Alexander Korotkov <[email protected]>
2020-10-26 15:45 ` Re: MultiXact\SLRU buffers configuration Andrey Borodin <[email protected]>
2020-10-27 17:02 ` Re: MultiXact\SLRU buffers configuration Alexander Korotkov <[email protected]>
2020-10-27 17:23 ` Re: MultiXact\SLRU buffers configuration Alexander Korotkov <[email protected]>
2020-10-28 01:36 ` Re: MultiXact\SLRU buffers configuration Tomas Vondra <[email protected]>
2020-10-28 07:34 ` Re: MultiXact\SLRU buffers configuration Andrey Borodin <[email protected]>
2020-10-28 23:32 ` Re: MultiXact\SLRU buffers configuration Tomas Vondra <[email protected]>
2020-10-29 07:08 ` Re: MultiXact\SLRU buffers configuration Andrey Borodin <[email protected]>
2020-10-29 13:49 ` Re: MultiXact\SLRU buffers configuration Tomas Vondra <[email protected]>
2020-11-02 12:45 ` Re: MultiXact\SLRU buffers configuration Andrey Borodin <[email protected]>
2020-11-10 00:13 ` Re: MultiXact\SLRU buffers configuration Tomas Vondra <[email protected]>
2020-11-10 06:16 ` Re: MultiXact\SLRU buffers configuration Andrey Borodin <[email protected]>
2020-11-10 18:07 ` Re: MultiXact\SLRU buffers configuration Tomas Vondra <[email protected]>
2020-11-13 11:49 ` Re: MultiXact\SLRU buffers configuration Andrey Borodin <[email protected]>
2020-12-08 16:05 ` Re: MultiXact\SLRU buffers configuration Gilles Darold <[email protected]>
2020-12-08 17:52 ` Re: MultiXact\SLRU buffers configuration Andrey Borodin <[email protected]>
2020-12-10 14:45 ` Re: MultiXact\SLRU buffers configuration Gilles Darold <[email protected]>
2020-12-11 17:50 ` Re: MultiXact\SLRU buffers configuration Gilles Darold <[email protected]>
2020-12-13 09:17 ` Re: MultiXact\SLRU buffers configuration Gilles Darold <[email protected]>
2020-12-13 17:24 ` Re: MultiXact\SLRU buffers configuration Andrey Borodin <[email protected]>
2020-12-23 16:31 ` Re: MultiXact\SLRU buffers configuration Gilles Darold <[email protected]>
2021-02-15 17:17 ` Re: MultiXact\SLRU buffers configuration Andrey Borodin <[email protected]>
2021-03-11 15:50 ` Re: MultiXact\SLRU buffers configuration Gilles Darold <[email protected]>
2021-03-12 12:44 ` Re: MultiXact\SLRU buffers configuration Andrey Borodin <[email protected]>
2021-03-24 21:31 ` Re: MultiXact\SLRU buffers configuration Thomas Munro <[email protected]>
2021-03-25 01:03 ` Re: MultiXact\SLRU buffers configuration Thomas Munro <[email protected]>
@ 2021-03-26 03:46 ` Thomas Munro <[email protected]>
2021-03-26 06:00 ` Re: MultiXact\SLRU buffers configuration Andrey Borodin <[email protected]>
0 siblings, 1 reply; 90+ messages in thread
From: Thomas Munro @ 2021-03-26 03:46 UTC (permalink / raw)
To: Andrey Borodin <[email protected]>; +Cc: Gilles Darold <[email protected]>; Tomas Vondra <[email protected]>; Tomas Vondra <[email protected]>; Alexander Korotkov <[email protected]>; Anastasia Lubennikova <[email protected]>; Daniel Gustafsson <[email protected]>; Kyotaro Horiguchi <[email protected]>; pgsql-hackers
Hi Andrey, all,
I propose some changes, and I'm attaching a new version:
I renamed the GUCs as clog_buffers etc (no "_slru_"). I fixed some
copy/paste mistakes where the different GUCs were mixed up. I made
some changes to the .conf.sample. I rewrote the documentation so that
it states the correct unit and defaults, and refers to the
subdirectories that are cached by these buffers instead of trying to
give a new definition of each of the SLRUs.
Do you like those changes?
Some things I thought about but didn't change:
I'm not entirely sure if we should use the internal and historical
names well known to hackers (CLOG), or the visible directory names (I
mean, we could use pg_xact_buffers instead of clog_buffers). I am not
sure why these GUCs need to be PGDLLIMPORT, but I see that NBuffers is
like that.
I wanted to do some very simple smoke testing of CLOG sizes on my
local development machine:
pgbench -i -s1000 postgres
pgbench -t4000000 -c8 -j8 -Mprepared postgres
I disabled autovacuum after running that just to be sure it wouldn't
interfere with my experiment:
alter table pgbench_accounts set (autovacuum_enabled = off);
Then I shut the cluster down and made a copy, so I could do some
repeated experiments from the same initial conditions each time. At
this point I had 30 files 0000-001E under pg_xact, holding 256kB = ~1
million transactions each. It'd take ~960 buffers to cache it all.
So how long does VACUUM FREEZE pgbench_accounts take?
I tested with just the 0001 patch, and also with the 0002 patch
(improved version, attached):
clog_buffers=128: 0001=2:28.499, 0002=2:17:891
clog_buffers=1024: 0001=1:38.485, 0002=1:29.701
I'm sure the speedup of the 0002 patch can be amplified by increasing
the number of transactions referenced in the table OR number of
clog_buffers, considering that the linear search produces
O(transactions * clog_buffers) work. That was 32M transactions and
8MB of CLOG, but I bet if you double both of those numbers once or
twice things start to get hot. I don't see why you shouldn't be able
to opt to cache literally all of CLOG if you want (something like 50MB
assuming default autovacuum_freeze_max_age, scale to taste, up to
512MB for the theoretical maximum useful value).
I'm not saying the 0002 patch is bug-free yet though, it's a bit finickity.
Attachments:
[text/x-patch] v12-0001-Make-all-SLRU-buffer-sizes-configurable.patch (20.6K, ../../CA+hUKGL0g+Nmf=2XePaXtw82BkW9CRzoxxXB4gqZOk7tHxNJXg@mail.gmail.com/2-v12-0001-Make-all-SLRU-buffer-sizes-configurable.patch)
download | inline diff:
From e7a8b9a0e27de80bab13f004b4d7e3fa1da677c4 Mon Sep 17 00:00:00 2001
From: Andrey Borodin <[email protected]>
Date: Mon, 15 Feb 2021 21:51:56 +0500
Subject: [PATCH v12 1/2] Make all SLRU buffer sizes configurable.
Provide new GUCs to set the number of buffers, instead of using hard
coded defaults.
Author: Andrey M. Borodin <[email protected]>
Reviewed-by: Anastasia Lubennikova <[email protected]>
Reviewed-by: Tomas Vondra <[email protected]>
Reviewed-by: Alexander Korotkov <[email protected]>
Reviewed-by: Gilles Darold <[email protected]>
Reviewed-by: Thomas Munro <[email protected]>
Discussion: https://postgr.es/m/2BEC2B3F-9B61-4C1D-9FB5-5FAB0F05EF86%40yandex-team.ru
---
doc/src/sgml/config.sgml | 137 ++++++++++++++++++
src/backend/access/transam/clog.c | 6 +
src/backend/access/transam/commit_ts.c | 5 +-
src/backend/access/transam/multixact.c | 8 +-
src/backend/access/transam/subtrans.c | 5 +-
src/backend/commands/async.c | 8 +-
src/backend/storage/lmgr/predicate.c | 4 +-
src/backend/utils/init/globals.c | 8 +
src/backend/utils/misc/guc.c | 77 ++++++++++
src/backend/utils/misc/postgresql.conf.sample | 9 ++
src/include/access/multixact.h | 4 -
src/include/access/subtrans.h | 3 -
src/include/commands/async.h | 5 -
src/include/miscadmin.h | 7 +
src/include/storage/predicate.h | 4 -
15 files changed, 261 insertions(+), 29 deletions(-)
diff --git a/doc/src/sgml/config.sgml b/doc/src/sgml/config.sgml
index ddc6d789d8..f1112bfa9c 100644
--- a/doc/src/sgml/config.sgml
+++ b/doc/src/sgml/config.sgml
@@ -1886,6 +1886,143 @@ include_dir 'conf.d'
</para>
</listitem>
</varlistentry>
+
+ <varlistentry id="guc-multixact-offsets-buffers" xreflabel="multixact_offsets_buffers">
+ <term><varname>multixact_offsets_buffers</varname> (<type>integer</type>)
+ <indexterm>
+ <primary><varname>multixact_offsets_buffers</varname> configuration parameter</primary>
+ </indexterm>
+ </term>
+ <listitem>
+ <para>
+ Specifies the amount of shared memory to used to cache the contents
+ of <literal>pg_multixact/offsets</literal> (see
+ <xref linkend="pgdata-contents-table"/>).
+ If this value is specified without units, it is taken as blocks,
+ that is <symbol>BLCKSZ</symbol> bytes, typically 8kB.
+ The default value is <literal>8</literal>.
+ This parameter can only be set at server start.
+ </para>
+ </listitem>
+ </varlistentry>
+
+ <varlistentry id="guc-multixact-members-buffers" xreflabel="multixact_members_buffers">
+ <term><varname>multixact_members_buffers</varname> (<type>integer</type>)
+ <indexterm>
+ <primary><varname>multixact_members_buffers</varname> configuration parameter</primary>
+ </indexterm>
+ </term>
+ <listitem>
+ <para>
+ Specifies the amount of shared memory to used to cache the contents
+ of <literal>pg_multixact/members</literal> (see
+ <xref linkend="pgdata-contents-table"/>).
+ If this value is specified without units, it is taken as blocks,
+ that is <symbol>BLCKSZ</symbol> bytes, typically 8kB.
+ The default value is <literal>16</literal>.
+ This parameter can only be set at server start.
+ </para>
+ </listitem>
+ </varlistentry>
+
+ <varlistentry id="guc-subtrans-buffers" xreflabel="subtrans_buffers">
+ <term><varname>subtrans_buffers</varname> (<type>integer</type>)
+ <indexterm>
+ <primary><varname>subtrans_buffers</varname> configuration parameter</primary>
+ </indexterm>
+ </term>
+ <listitem>
+ <para>
+ Specifies the amount of shared memory to used to cache the contents
+ of <literal>pg_subtrans</literal> (see
+ <xref linkend="pgdata-contents-table"/>).
+ If this value is specified without units, it is taken as blocks,
+ that is <symbol>BLCKSZ</symbol> bytes, typically 8kB.
+ The default value is <literal>8</literal>.
+ This parameter can only be set at server start.
+ </para>
+ </listitem>
+ </varlistentry>
+
+ <varlistentry id="guc-notify-buffers" xreflabel="notify_buffers">
+ <term><varname>notify_buffers</varname> (<type>integer</type>)
+ <indexterm>
+ <primary><varname>notify_buffers</varname> configuration parameter</primary>
+ </indexterm>
+ </term>
+ <listitem>
+ <para>
+ Specifies the amount of shared memory to used to cache the contents
+ of <literal>pg_notify</literal> (see
+ <xref linkend="pgdata-contents-table"/>).
+ If this value is specified without units, it is taken as blocks,
+ that is <symbol>BLCKSZ</symbol> bytes, typically 8kB.
+ The default value is <literal>8</literal>.
+ This parameter can only be set at server start.
+ </para>
+ </listitem>
+ </varlistentry>
+
+ <varlistentry id="guc-serial-buffers" xreflabel="serial_buffers">
+ <term><varname>serial_buffers</varname> (<type>integer</type>)
+ <indexterm>
+ <primary><varname>serial_buffers</varname> configuration parameter</primary>
+ </indexterm>
+ </term>
+ <listitem>
+ <para>
+ Specifies the amount of shared memory to used to cache the contents
+ of <literal>pg_serial</literal> (see
+ <xref linkend="pgdata-contents-table"/>).
+ If this value is specified without units, it is taken as blocks,
+ that is <symbol>BLCKSZ</symbol> bytes, typically 8kB.
+ The default value is <literal>16</literal>.
+ This parameter can only be set at server start.
+ </para>
+ </listitem>
+ </varlistentry>
+
+ <varlistentry id="guc-clog-buffers" xreflabel="clog_buffers">
+ <term><varname>clog_buffers</varname> (<type>integer</type>)
+ <indexterm>
+ <primary><varname>clog_buffers</varname> configuration parameter</primary>
+ </indexterm>
+ </term>
+ <listitem>
+ <para>
+ Specifies the amount of shared memory to used to cache the contents
+ of <literal>pg_xact</literal> (see
+ <xref linkend="pgdata-contents-table"/>).
+ If this value is specified without units, it is taken as blocks,
+ that is <symbol>BLCKSZ</symbol> bytes, typically 8kB.
+ The default value is <literal>0</literal>, which requests
+ <varname>shared_buffers</varname> / 512, but not more than 128 or
+ fewer than 4 blocks.
+ This parameter can only be set at server start.
+ </para>
+ </listitem>
+ </varlistentry>
+
+ <varlistentry id="guc-commit-ts-buffers" xreflabel="commit_ts_buffers">
+ <term><varname>commit_ts_buffers</varname> (<type>integer</type>)
+ <indexterm>
+ <primary><varname>commit_ts_buffers</varname> configuration parameter</primary>
+ </indexterm>
+ </term>
+ <listitem>
+ <para>
+ Specifies the amount of memory to be used to cache the cotents of
+ <literal>pg_commit_ts</literal> (see
+ <xref linkend="pgdata-contents-table"/>).
+ If this value is specified without units, it is taken as blocks,
+ that is <symbol>BLCKSZ</symbol> bytes, typically 8kB.
+ The default value is <literal>0</literal>, which requests
+ <varname>shared_buffers</varname> / 512, but not more than 128 or
+ fewer than 16 blocks.
+ This parameter can only be set at server start.
+ </para>
+ </listitem>
+ </varlistentry>
<varlistentry id="guc-max-stack-depth" xreflabel="max_stack_depth">
<term><varname>max_stack_depth</varname> (<type>integer</type>)
diff --git a/src/backend/access/transam/clog.c b/src/backend/access/transam/clog.c
index 6fa4713fb4..0318e8ff59 100644
--- a/src/backend/access/transam/clog.c
+++ b/src/backend/access/transam/clog.c
@@ -659,6 +659,9 @@ TransactionIdGetStatus(TransactionId xid, XLogRecPtr *lsn)
/*
* Number of shared CLOG buffers.
*
+ * If values is configured via GUC - just use given value. Otherwise
+ * apply following euristics.
+ *
* On larger multi-processor systems, it is possible to have many CLOG page
* requests in flight at one time which could lead to disk access for CLOG
* page if the required page is not found in memory. Testing revealed that we
@@ -675,6 +678,9 @@ TransactionIdGetStatus(TransactionId xid, XLogRecPtr *lsn)
Size
CLOGShmemBuffers(void)
{
+ /* consider 0 and 1 as unset GUC */
+ if (clog_buffers > 1)
+ return clog_buffers;
return Min(128, Max(4, NBuffers / 512));
}
diff --git a/src/backend/access/transam/commit_ts.c b/src/backend/access/transam/commit_ts.c
index 268bdba339..0d2632b90e 100644
--- a/src/backend/access/transam/commit_ts.c
+++ b/src/backend/access/transam/commit_ts.c
@@ -530,7 +530,10 @@ pg_xact_commit_timestamp_origin(PG_FUNCTION_ARGS)
Size
CommitTsShmemBuffers(void)
{
- return Min(16, Max(4, NBuffers / 1024));
+ /* consider 0 and 1 as unset GUC */
+ if (commit_ts_buffers > 1)
+ return commit_ts_buffers;
+ return Min(16, Max(4, NBuffers / 512));
}
/*
diff --git a/src/backend/access/transam/multixact.c b/src/backend/access/transam/multixact.c
index 1f9f1a1fa1..21787765e2 100644
--- a/src/backend/access/transam/multixact.c
+++ b/src/backend/access/transam/multixact.c
@@ -1831,8 +1831,8 @@ MultiXactShmemSize(void)
mul_size(sizeof(MultiXactId) * 2, MaxOldestSlot))
size = SHARED_MULTIXACT_STATE_SIZE;
- size = add_size(size, SimpleLruShmemSize(NUM_MULTIXACTOFFSET_BUFFERS, 0));
- size = add_size(size, SimpleLruShmemSize(NUM_MULTIXACTMEMBER_BUFFERS, 0));
+ size = add_size(size, SimpleLruShmemSize(multixact_offsets_buffers, 0));
+ size = add_size(size, SimpleLruShmemSize(multixact_members_buffers, 0));
return size;
}
@@ -1848,13 +1848,13 @@ MultiXactShmemInit(void)
MultiXactMemberCtl->PagePrecedes = MultiXactMemberPagePrecedes;
SimpleLruInit(MultiXactOffsetCtl,
- "MultiXactOffset", NUM_MULTIXACTOFFSET_BUFFERS, 0,
+ "MultiXactOffset", multixact_offsets_buffers, 0,
MultiXactOffsetSLRULock, "pg_multixact/offsets",
LWTRANCHE_MULTIXACTOFFSET_BUFFER,
SYNC_HANDLER_MULTIXACT_OFFSET);
SlruPagePrecedesUnitTests(MultiXactOffsetCtl, MULTIXACT_OFFSETS_PER_PAGE);
SimpleLruInit(MultiXactMemberCtl,
- "MultiXactMember", NUM_MULTIXACTMEMBER_BUFFERS, 0,
+ "MultiXactMember", multixact_offsets_buffers, 0,
MultiXactMemberSLRULock, "pg_multixact/members",
LWTRANCHE_MULTIXACTMEMBER_BUFFER,
SYNC_HANDLER_MULTIXACT_MEMBER);
diff --git a/src/backend/access/transam/subtrans.c b/src/backend/access/transam/subtrans.c
index 6a8e521f89..785f2520fd 100644
--- a/src/backend/access/transam/subtrans.c
+++ b/src/backend/access/transam/subtrans.c
@@ -31,6 +31,7 @@
#include "access/slru.h"
#include "access/subtrans.h"
#include "access/transam.h"
+#include "miscadmin.h"
#include "pg_trace.h"
#include "utils/snapmgr.h"
@@ -184,14 +185,14 @@ SubTransGetTopmostTransaction(TransactionId xid)
Size
SUBTRANSShmemSize(void)
{
- return SimpleLruShmemSize(NUM_SUBTRANS_BUFFERS, 0);
+ return SimpleLruShmemSize(subtrans_buffers, 0);
}
void
SUBTRANSShmemInit(void)
{
SubTransCtl->PagePrecedes = SubTransPagePrecedes;
- SimpleLruInit(SubTransCtl, "Subtrans", NUM_SUBTRANS_BUFFERS, 0,
+ SimpleLruInit(SubTransCtl, "Subtrans", subtrans_buffers, 0,
SubtransSLRULock, "pg_subtrans",
LWTRANCHE_SUBTRANS_BUFFER, SYNC_HANDLER_NONE);
SlruPagePrecedesUnitTests(SubTransCtl, SUBTRANS_XACTS_PER_PAGE);
diff --git a/src/backend/commands/async.c b/src/backend/commands/async.c
index 4b16fb5682..de17f52cd7 100644
--- a/src/backend/commands/async.c
+++ b/src/backend/commands/async.c
@@ -107,7 +107,7 @@
* frontend during startup.) The above design guarantees that notifies from
* other backends will never be missed by ignoring self-notifies.
*
- * The amount of shared memory used for notify management (NUM_NOTIFY_BUFFERS)
+ * The amount of shared memory used for notify management (notify_buffers)
* can be varied without affecting anything but performance. The maximum
* amount of notification data that can be queued at one time is determined
* by slru.c's wraparound limit; see QUEUE_MAX_PAGE below.
@@ -225,7 +225,7 @@ typedef struct QueuePosition
*
* Resist the temptation to make this really large. While that would save
* work in some places, it would add cost in others. In particular, this
- * should likely be less than NUM_NOTIFY_BUFFERS, to ensure that backends
+ * should likely be less than notify_buffers, to ensure that backends
* catch up before the pages they'll need to read fall out of SLRU cache.
*/
#define QUEUE_CLEANUP_DELAY 4
@@ -514,7 +514,7 @@ AsyncShmemSize(void)
size = mul_size(MaxBackends + 1, sizeof(QueueBackendStatus));
size = add_size(size, offsetof(AsyncQueueControl, backend));
- size = add_size(size, SimpleLruShmemSize(NUM_NOTIFY_BUFFERS, 0));
+ size = add_size(size, SimpleLruShmemSize(notify_buffers, 0));
return size;
}
@@ -562,7 +562,7 @@ AsyncShmemInit(void)
* Set up SLRU management of the pg_notify data.
*/
NotifyCtl->PagePrecedes = asyncQueuePagePrecedes;
- SimpleLruInit(NotifyCtl, "Notify", NUM_NOTIFY_BUFFERS, 0,
+ SimpleLruInit(NotifyCtl, "Notify", notify_buffers, 0,
NotifySLRULock, "pg_notify", LWTRANCHE_NOTIFY_BUFFER,
SYNC_HANDLER_NONE);
diff --git a/src/backend/storage/lmgr/predicate.c b/src/backend/storage/lmgr/predicate.c
index d493aeef0f..b1f4f1651d 100644
--- a/src/backend/storage/lmgr/predicate.c
+++ b/src/backend/storage/lmgr/predicate.c
@@ -872,7 +872,7 @@ SerialInit(void)
*/
SerialSlruCtl->PagePrecedes = SerialPagePrecedesLogically;
SimpleLruInit(SerialSlruCtl, "Serial",
- NUM_SERIAL_BUFFERS, 0, SerialSLRULock, "pg_serial",
+ serial_buffers, 0, SerialSLRULock, "pg_serial",
LWTRANCHE_SERIAL_BUFFER, SYNC_HANDLER_NONE);
#ifdef USE_ASSERT_CHECKING
SerialPagePrecedesLogicallyUnitTests();
@@ -1395,7 +1395,7 @@ PredicateLockShmemSize(void)
/* Shared memory structures for SLRU tracking of old committed xids. */
size = add_size(size, sizeof(SerialControlData));
- size = add_size(size, SimpleLruShmemSize(NUM_SERIAL_BUFFERS, 0));
+ size = add_size(size, SimpleLruShmemSize(serial_buffers, 0));
return size;
}
diff --git a/src/backend/utils/init/globals.c b/src/backend/utils/init/globals.c
index 73e0a672ae..e90275be6c 100644
--- a/src/backend/utils/init/globals.c
+++ b/src/backend/utils/init/globals.c
@@ -148,3 +148,11 @@ int64 VacuumPageDirty = 0;
int VacuumCostBalance = 0; /* working state for vacuum */
bool VacuumCostActive = false;
+
+int multixact_offsets_buffers = 8;
+int multixact_members_buffers = 16;
+int subtrans_buffers = 32;
+int notify_buffers = 8;
+int serial_buffers = 16;
+int clog_buffers = 0;
+int commit_ts_buffers = 0;
diff --git a/src/backend/utils/misc/guc.c b/src/backend/utils/misc/guc.c
index 0c5dc4d3e8..003bc820d2 100644
--- a/src/backend/utils/misc/guc.c
+++ b/src/backend/utils/misc/guc.c
@@ -2305,6 +2305,83 @@ static struct config_int ConfigureNamesInt[] =
NULL, NULL, NULL
},
+ {
+ {"multixact_offsets_buffers", PGC_POSTMASTER, RESOURCES_MEM,
+ gettext_noop("Sets the number of shared memory buffers used for MultiXact offsets SLRU."),
+ NULL,
+ GUC_UNIT_BLOCKS
+ },
+ &multixact_offsets_buffers,
+ 8, 2, INT_MAX / 2,
+ NULL, NULL, NULL
+ },
+
+ {
+ {"multixact_members_buffers", PGC_POSTMASTER, RESOURCES_MEM,
+ gettext_noop("Sets the number of shared memory buffers used for MultiXact members SLRU."),
+ NULL,
+ GUC_UNIT_BLOCKS
+ },
+ &multixact_members_buffers,
+ 16, 2, INT_MAX / 2,
+ NULL, NULL, NULL
+ },
+
+ {
+ {"subtrans_buffers", PGC_POSTMASTER, RESOURCES_MEM,
+ gettext_noop("Sets the number of shared memory buffers used for substransactions SLRU."),
+ NULL,
+ GUC_UNIT_BLOCKS
+ },
+ &subtrans_buffers,
+ 32, 2, INT_MAX / 2,
+ NULL, NULL, NULL
+ },
+
+ {
+ {"notify_buffers", PGC_POSTMASTER, RESOURCES_MEM,
+ gettext_noop("Sets the number of shared memory buffers used for asyncronous notifications SLRU."),
+ NULL,
+ GUC_UNIT_BLOCKS
+ },
+ ¬ify_buffers,
+ 8, 2, INT_MAX / 2,
+ NULL, NULL, NULL
+ },
+
+ {
+ {"serial_buffers", PGC_POSTMASTER, RESOURCES_MEM,
+ gettext_noop("Sets the number of shared memory buffers used for predicate locks SLRU."),
+ NULL,
+ GUC_UNIT_BLOCKS
+ },
+ &serial_buffers,
+ 16, 2, INT_MAX / 2,
+ NULL, NULL, NULL
+ },
+
+ {
+ {"clog_buffers", PGC_POSTMASTER, RESOURCES_MEM,
+ gettext_noop("Sets the number of shared memory buffers used for commit log SLRU."),
+ NULL,
+ GUC_UNIT_BLOCKS
+ },
+ &clog_buffers,
+ 0, 0, INT_MAX / 2,
+ NULL, NULL, NULL
+ },
+
+ {
+ {"commit_ts_buffers", PGC_POSTMASTER, RESOURCES_MEM,
+ gettext_noop("Sets the number of shared memory buffers used for commit timestamps SLRU."),
+ NULL,
+ GUC_UNIT_BLOCKS
+ },
+ &commit_ts_buffers,
+ 0, 0, INT_MAX / 2,
+ NULL, NULL, NULL
+ },
+
{
{"temp_buffers", PGC_USERSET, RESOURCES_MEM,
gettext_noop("Sets the maximum number of temporary buffers used by each session."),
diff --git a/src/backend/utils/misc/postgresql.conf.sample b/src/backend/utils/misc/postgresql.conf.sample
index b234a6bfe6..1b8515989b 100644
--- a/src/backend/utils/misc/postgresql.conf.sample
+++ b/src/backend/utils/misc/postgresql.conf.sample
@@ -190,6 +190,15 @@
# (change requires restart)
#backend_flush_after = 0 # measured in pages, 0 disables
+# - SLRU Buffers (change requires restart) -
+
+#clog_buffers = 0 # memory for pg_xact (0 = auto)
+#subtrans_buffers = 32 # memory for pg_subtrans
+#multixact_offsets_buffers = 8 # memory for pg_multixact/offsets
+#multixact_members_buffers = 16 # memory for pg_multixact/members
+#notify_buffers = 8 # memory for pg_nofity
+#serial_buffers = 16 # memory for pg_serial
+#commit_ts_buffers = 0 # memory for pg_commit_ts (0 = auto)
#------------------------------------------------------------------------------
# WRITE-AHEAD LOG
diff --git a/src/include/access/multixact.h b/src/include/access/multixact.h
index 4bbb035eae..97c0a46376 100644
--- a/src/include/access/multixact.h
+++ b/src/include/access/multixact.h
@@ -29,10 +29,6 @@
#define MaxMultiXactOffset ((MultiXactOffset) 0xFFFFFFFF)
-/* Number of SLRU buffers to use for multixact */
-#define NUM_MULTIXACTOFFSET_BUFFERS 8
-#define NUM_MULTIXACTMEMBER_BUFFERS 16
-
/*
* Possible multixact lock modes ("status"). The first four modes are for
* tuple locks (FOR KEY SHARE, FOR SHARE, FOR NO KEY UPDATE, FOR UPDATE); the
diff --git a/src/include/access/subtrans.h b/src/include/access/subtrans.h
index d0ab44ae82..ca0999056e 100644
--- a/src/include/access/subtrans.h
+++ b/src/include/access/subtrans.h
@@ -11,9 +11,6 @@
#ifndef SUBTRANS_H
#define SUBTRANS_H
-/* Number of SLRU buffers to use for subtrans */
-#define NUM_SUBTRANS_BUFFERS 32
-
extern void SubTransSetParent(TransactionId xid, TransactionId parent);
extern TransactionId SubTransGetParent(TransactionId xid);
extern TransactionId SubTransGetTopmostTransaction(TransactionId xid);
diff --git a/src/include/commands/async.h b/src/include/commands/async.h
index 9217f66b91..fa831e3721 100644
--- a/src/include/commands/async.h
+++ b/src/include/commands/async.h
@@ -15,11 +15,6 @@
#include <signal.h>
-/*
- * The number of SLRU page buffers we use for the notification queue.
- */
-#define NUM_NOTIFY_BUFFERS 8
-
extern bool Trace_notify;
extern volatile sig_atomic_t notifyInterruptPending;
diff --git a/src/include/miscadmin.h b/src/include/miscadmin.h
index 013850ac28..9c325b4312 100644
--- a/src/include/miscadmin.h
+++ b/src/include/miscadmin.h
@@ -162,6 +162,13 @@ extern PGDLLIMPORT int MaxBackends;
extern PGDLLIMPORT int MaxConnections;
extern PGDLLIMPORT int max_worker_processes;
extern PGDLLIMPORT int max_parallel_workers;
+extern PGDLLIMPORT int multixact_offsets_buffers;
+extern PGDLLIMPORT int multixact_members_buffers;
+extern PGDLLIMPORT int subtrans_buffers;
+extern PGDLLIMPORT int notify_buffers;
+extern PGDLLIMPORT int serial_buffers;
+extern PGDLLIMPORT int clog_buffers;
+extern PGDLLIMPORT int commit_ts_buffers;
extern PGDLLIMPORT int MyProcPid;
extern PGDLLIMPORT pg_time_t MyStartTime;
diff --git a/src/include/storage/predicate.h b/src/include/storage/predicate.h
index 152b698611..c72779bd88 100644
--- a/src/include/storage/predicate.h
+++ b/src/include/storage/predicate.h
@@ -26,10 +26,6 @@ extern int max_predicate_locks_per_xact;
extern int max_predicate_locks_per_relation;
extern int max_predicate_locks_per_page;
-
-/* Number of SLRU buffers to use for Serial SLRU */
-#define NUM_SERIAL_BUFFERS 16
-
/*
* A handle used for sharing SERIALIZABLEXACT objects between the participants
* in a parallel query.
--
2.30.1
[text/x-patch] v12-0002-Add-buffer-mapping-table-for-SLRUs.patch (8.5K, ../../CA+hUKGL0g+Nmf=2XePaXtw82BkW9CRzoxxXB4gqZOk7tHxNJXg@mail.gmail.com/3-v12-0002-Add-buffer-mapping-table-for-SLRUs.patch)
download | inline diff:
From 98092b5b4e7a9a11a5bbd50c36ad8f635fdfab6f Mon Sep 17 00:00:00 2001
From: Thomas Munro <[email protected]>
Date: Thu, 25 Mar 2021 10:11:31 +1300
Subject: [PATCH v12 2/2] Add buffer mapping table for SLRUs.
Instead of doing a linear search for the buffer holding a given page
number, use a hash table.
Discussion: https://postgr.es/m/2BEC2B3F-9B61-4C1D-9FB5-5FAB0F05EF86%40yandex-team.ru
---
src/backend/access/transam/slru.c | 111 +++++++++++++++++++++++++-----
src/include/access/slru.h | 2 +
2 files changed, 96 insertions(+), 17 deletions(-)
diff --git a/src/backend/access/transam/slru.c b/src/backend/access/transam/slru.c
index 82149ad782..f823c2a0c8 100644
--- a/src/backend/access/transam/slru.c
+++ b/src/backend/access/transam/slru.c
@@ -58,6 +58,8 @@
#include "pgstat.h"
#include "storage/fd.h"
#include "storage/shmem.h"
+#include "utils/dynahash.h"
+#include "utils/hsearch.h"
#define SlruFileName(ctl, path, seg) \
snprintf(path, MAXPGPATH, "%s/%04X", (ctl)->Dir, seg)
@@ -79,6 +81,12 @@ typedef struct SlruWriteAllData
typedef struct SlruWriteAllData *SlruWriteAll;
+typedef struct SlruMappingTableEntry
+{
+ int pageno;
+ int slotno;
+} SlruMappingTableEntry;
+
/*
* Populate a file tag describing a segment file. We only use the segment
* number, since we can derive everything else we need by having separate
@@ -146,6 +154,9 @@ static int SlruSelectLRUPage(SlruCtl ctl, int pageno);
static bool SlruScanDirCbDeleteCutoff(SlruCtl ctl, char *filename,
int segpage, void *data);
static void SlruInternalDeleteSegment(SlruCtl ctl, int segno);
+static void SlruMappingAdd(SlruCtl ctl, int pageno, int slotno);
+static void SlruMappingRemove(SlruCtl ctl, int pageno);
+static int SlruMappingFind(SlruCtl ctl, int pageno);
/*
* Initialization of shared memory
@@ -168,7 +179,8 @@ SimpleLruShmemSize(int nslots, int nlsns)
if (nlsns > 0)
sz += MAXALIGN(nslots * nlsns * sizeof(XLogRecPtr)); /* group_lsn[] */
- return BUFFERALIGN(sz) + BLCKSZ * nslots;
+ return BUFFERALIGN(sz) + BLCKSZ * nslots +
+ hash_estimate_size(nslots, sizeof(SlruMappingTableEntry));
}
/*
@@ -187,6 +199,9 @@ SimpleLruInit(SlruCtl ctl, const char *name, int nslots, int nlsns,
LWLock *ctllock, const char *subdir, int tranche_id,
SyncRequestHandler sync_handler)
{
+ char mapping_table_name[SHMEM_INDEX_KEYSIZE];
+ HASHCTL mapping_table_info;
+ HTAB *mapping_table;
SlruShared shared;
bool found;
@@ -258,11 +273,21 @@ SimpleLruInit(SlruCtl ctl, const char *name, int nslots, int nlsns,
else
Assert(found);
+ /* Create or find the buffer mapping table. */
+ memset(&mapping_table_info, 0, sizeof(mapping_table_info));
+ mapping_table_info.keysize = sizeof(int);
+ mapping_table_info.entrysize = sizeof(SlruMappingTableEntry);
+ snprintf(mapping_table_name, sizeof(mapping_table_name),
+ "%s Mapping Table", name);
+ mapping_table = ShmemInitHash(mapping_table_name, nslots, nslots,
+ &mapping_table_info, HASH_ELEM | HASH_BLOBS);
+
/*
* Initialize the unshared control struct, including directory path. We
* assume caller set PagePrecedes.
*/
ctl->shared = shared;
+ ctl->mapping_table = mapping_table;
ctl->sync_handler = sync_handler;
strlcpy(ctl->Dir, subdir, sizeof(ctl->Dir));
}
@@ -289,6 +314,9 @@ SimpleLruZeroPage(SlruCtl ctl, int pageno)
shared->page_number[slotno] == pageno);
/* Mark the slot as containing this page */
+ if (shared->page_status[slotno] != SLRU_PAGE_EMPTY)
+ SlruMappingRemove(ctl, shared->page_number[slotno]);
+ SlruMappingAdd(ctl, pageno, slotno);
shared->page_number[slotno] = pageno;
shared->page_status[slotno] = SLRU_PAGE_VALID;
shared->page_dirty[slotno] = true;
@@ -362,7 +390,10 @@ SimpleLruWaitIO(SlruCtl ctl, int slotno)
{
/* indeed, the I/O must have failed */
if (shared->page_status[slotno] == SLRU_PAGE_READ_IN_PROGRESS)
+ {
+ SlruMappingRemove(ctl, shared->page_number[slotno]);
shared->page_status[slotno] = SLRU_PAGE_EMPTY;
+ }
else /* write_in_progress */
{
shared->page_status[slotno] = SLRU_PAGE_VALID;
@@ -436,6 +467,9 @@ SimpleLruReadPage(SlruCtl ctl, int pageno, bool write_ok,
!shared->page_dirty[slotno]));
/* Mark the slot read-busy */
+ if (shared->page_status[slotno] != SLRU_PAGE_EMPTY)
+ SlruMappingRemove(ctl, shared->page_number[slotno]);
+ SlruMappingAdd(ctl, pageno, slotno);
shared->page_number[slotno] = pageno;
shared->page_status[slotno] = SLRU_PAGE_READ_IN_PROGRESS;
shared->page_dirty[slotno] = false;
@@ -459,7 +493,13 @@ SimpleLruReadPage(SlruCtl ctl, int pageno, bool write_ok,
shared->page_status[slotno] == SLRU_PAGE_READ_IN_PROGRESS &&
!shared->page_dirty[slotno]);
- shared->page_status[slotno] = ok ? SLRU_PAGE_VALID : SLRU_PAGE_EMPTY;
+ if (ok)
+ shared->page_status[slotno] = SLRU_PAGE_VALID;
+ else
+ {
+ SlruMappingRemove(ctl, pageno);
+ shared->page_status[slotno] = SLRU_PAGE_EMPTY;
+ }
LWLockRelease(&shared->buffer_locks[slotno].lock);
@@ -500,20 +540,20 @@ SimpleLruReadPage_ReadOnly(SlruCtl ctl, int pageno, TransactionId xid)
LWLockAcquire(shared->ControlLock, LW_SHARED);
/* See if page is already in a buffer */
- for (slotno = 0; slotno < shared->num_slots; slotno++)
+ slotno = SlruMappingFind(ctl, pageno);
+ if (slotno >= 0 &&
+ shared->page_status[slotno] != SLRU_PAGE_READ_IN_PROGRESS)
{
- if (shared->page_number[slotno] == pageno &&
- shared->page_status[slotno] != SLRU_PAGE_EMPTY &&
- shared->page_status[slotno] != SLRU_PAGE_READ_IN_PROGRESS)
- {
- /* See comments for SlruRecentlyUsed macro */
- SlruRecentlyUsed(shared, slotno);
+ Assert(shared->page_status[slotno] != SLRU_PAGE_EMPTY);
+ Assert(shared->page_number[slotno] == pageno);
- /* update the stats counter of pages found in the SLRU */
- pgstat_count_slru_page_hit(shared->slru_stats_idx);
+ /* See comments for SlruRecentlyUsed macro */
+ SlruRecentlyUsed(shared, slotno);
- return slotno;
- }
+ /* update the stats counter of pages found in the SLRU */
+ pgstat_count_slru_page_hit(shared->slru_stats_idx);
+
+ return slotno;
}
/* No luck, so switch to normal exclusive lock and do regular read */
@@ -1029,11 +1069,12 @@ SlruSelectLRUPage(SlruCtl ctl, int pageno)
int best_invalid_page_number = 0; /* keep compiler quiet */
/* See if page already has a buffer assigned */
- for (slotno = 0; slotno < shared->num_slots; slotno++)
+ slotno = SlruMappingFind(ctl, pageno);
+ if (slotno >= 0)
{
- if (shared->page_number[slotno] == pageno &&
- shared->page_status[slotno] != SLRU_PAGE_EMPTY)
- return slotno;
+ Assert(shared->page_number[slotno] == pageno);
+ Assert(shared->page_status[slotno] != SLRU_PAGE_EMPTY);
+ return slotno;
}
/*
@@ -1266,6 +1307,7 @@ restart:;
if (shared->page_status[slotno] == SLRU_PAGE_VALID &&
!shared->page_dirty[slotno])
{
+ SlruMappingRemove(ctl, shared->page_number[slotno]);
shared->page_status[slotno] = SLRU_PAGE_EMPTY;
continue;
}
@@ -1348,6 +1390,7 @@ restart:
if (shared->page_status[slotno] == SLRU_PAGE_VALID &&
!shared->page_dirty[slotno])
{
+ SlruMappingRemove(ctl, shared->page_number[slotno]);
shared->page_status[slotno] = SLRU_PAGE_EMPTY;
continue;
}
@@ -1609,3 +1652,37 @@ SlruSyncFileTag(SlruCtl ctl, const FileTag *ftag, char *path)
errno = save_errno;
return result;
}
+
+static int
+SlruMappingFind(SlruCtl ctl, int pageno)
+{
+ SlruMappingTableEntry *mapping;
+
+ mapping = hash_search(ctl->mapping_table, &pageno, HASH_FIND, NULL);
+ if (mapping)
+ return mapping->slotno;
+
+ return -1;
+}
+
+static void
+SlruMappingAdd(SlruCtl ctl, int pageno, int slotno)
+{
+ SlruMappingTableEntry *mapping;
+ bool found PG_USED_FOR_ASSERTS_ONLY;
+
+ mapping = hash_search(ctl->mapping_table, &pageno, HASH_ENTER, &found);
+ mapping->slotno = slotno;
+
+ Assert(!found);
+}
+
+static void
+SlruMappingRemove(SlruCtl ctl, int pageno)
+{
+ bool found PG_USED_FOR_ASSERTS_ONLY;
+
+ hash_search(ctl->mapping_table, &pageno, HASH_REMOVE, &found);
+
+ Assert(found);
+}
diff --git a/src/include/access/slru.h b/src/include/access/slru.h
index dd52e8cec7..8aa3efc0ee 100644
--- a/src/include/access/slru.h
+++ b/src/include/access/slru.h
@@ -16,6 +16,7 @@
#include "access/xlogdefs.h"
#include "storage/lwlock.h"
#include "storage/sync.h"
+#include "utils/hsearch.h"
/*
@@ -110,6 +111,7 @@ typedef SlruSharedData *SlruShared;
typedef struct SlruCtlData
{
SlruShared shared;
+ HTAB *mapping_table;
/*
* Which sync handler function to use when handing sync requests over to
--
2.30.1
^ permalink raw reply [nested|flat] 90+ messages in thread
* Re: MultiXact\SLRU buffers configuration
2020-05-08 16:36 MultiXact\SLRU buffers configuration Andrey M. Borodin <[email protected]>
2020-05-11 11:17 ` Re: MultiXact\SLRU buffers configuration Andrey M. Borodin <[email protected]>
2020-05-13 18:08 ` Re: MultiXact\SLRU buffers configuration Andrey M. Borodin <[email protected]>
2020-05-14 01:25 ` Re: MultiXact\SLRU buffers configuration Kyotaro Horiguchi <[email protected]>
2020-05-14 05:19 ` Re: MultiXact\SLRU buffers configuration Andrey M. Borodin <[email protected]>
2020-05-14 06:16 ` Re: MultiXact\SLRU buffers configuration Kyotaro Horiguchi <[email protected]>
2020-05-14 06:44 ` Re: MultiXact\SLRU buffers configuration Andrey M. Borodin <[email protected]>
2020-05-15 00:03 ` Re: MultiXact\SLRU buffers configuration Kyotaro Horiguchi <[email protected]>
2020-07-02 12:02 ` Re: MultiXact\SLRU buffers configuration Daniel Gustafsson <[email protected]>
2020-07-08 07:03 ` Re: MultiXact\SLRU buffers configuration Andrey M. Borodin <[email protected]>
2020-08-28 18:08 ` Re: MultiXact\SLRU buffers configuration Anastasia Lubennikova <[email protected]>
2020-09-28 14:41 ` Re: MultiXact\SLRU buffers configuration Andrey M. Borodin <[email protected]>
2020-10-26 01:05 ` Re: MultiXact\SLRU buffers configuration Alexander Korotkov <[email protected]>
2020-10-26 15:45 ` Re: MultiXact\SLRU buffers configuration Andrey Borodin <[email protected]>
2020-10-27 17:02 ` Re: MultiXact\SLRU buffers configuration Alexander Korotkov <[email protected]>
2020-10-27 17:23 ` Re: MultiXact\SLRU buffers configuration Alexander Korotkov <[email protected]>
2020-10-28 01:36 ` Re: MultiXact\SLRU buffers configuration Tomas Vondra <[email protected]>
2020-10-28 07:34 ` Re: MultiXact\SLRU buffers configuration Andrey Borodin <[email protected]>
2020-10-28 23:32 ` Re: MultiXact\SLRU buffers configuration Tomas Vondra <[email protected]>
2020-10-29 07:08 ` Re: MultiXact\SLRU buffers configuration Andrey Borodin <[email protected]>
2020-10-29 13:49 ` Re: MultiXact\SLRU buffers configuration Tomas Vondra <[email protected]>
2020-11-02 12:45 ` Re: MultiXact\SLRU buffers configuration Andrey Borodin <[email protected]>
2020-11-10 00:13 ` Re: MultiXact\SLRU buffers configuration Tomas Vondra <[email protected]>
2020-11-10 06:16 ` Re: MultiXact\SLRU buffers configuration Andrey Borodin <[email protected]>
2020-11-10 18:07 ` Re: MultiXact\SLRU buffers configuration Tomas Vondra <[email protected]>
2020-11-13 11:49 ` Re: MultiXact\SLRU buffers configuration Andrey Borodin <[email protected]>
2020-12-08 16:05 ` Re: MultiXact\SLRU buffers configuration Gilles Darold <[email protected]>
2020-12-08 17:52 ` Re: MultiXact\SLRU buffers configuration Andrey Borodin <[email protected]>
2020-12-10 14:45 ` Re: MultiXact\SLRU buffers configuration Gilles Darold <[email protected]>
2020-12-11 17:50 ` Re: MultiXact\SLRU buffers configuration Gilles Darold <[email protected]>
2020-12-13 09:17 ` Re: MultiXact\SLRU buffers configuration Gilles Darold <[email protected]>
2020-12-13 17:24 ` Re: MultiXact\SLRU buffers configuration Andrey Borodin <[email protected]>
2020-12-23 16:31 ` Re: MultiXact\SLRU buffers configuration Gilles Darold <[email protected]>
2021-02-15 17:17 ` Re: MultiXact\SLRU buffers configuration Andrey Borodin <[email protected]>
2021-03-11 15:50 ` Re: MultiXact\SLRU buffers configuration Gilles Darold <[email protected]>
2021-03-12 12:44 ` Re: MultiXact\SLRU buffers configuration Andrey Borodin <[email protected]>
2021-03-24 21:31 ` Re: MultiXact\SLRU buffers configuration Thomas Munro <[email protected]>
2021-03-25 01:03 ` Re: MultiXact\SLRU buffers configuration Thomas Munro <[email protected]>
2021-03-26 03:46 ` Re: MultiXact\SLRU buffers configuration Thomas Munro <[email protected]>
@ 2021-03-26 06:00 ` Andrey Borodin <[email protected]>
2021-03-26 15:52 ` Re: MultiXact\SLRU buffers configuration Andrey Borodin <[email protected]>
0 siblings, 1 reply; 90+ messages in thread
From: Andrey Borodin @ 2021-03-26 06:00 UTC (permalink / raw)
To: Thomas Munro <[email protected]>; +Cc: Gilles Darold <[email protected]>; Tomas Vondra <[email protected]>; Tomas Vondra <[email protected]>; Alexander Korotkov <[email protected]>; Anastasia Lubennikova <[email protected]>; Daniel Gustafsson <[email protected]>; Kyotaro Horiguchi <[email protected]>; pgsql-hackers
Hi Thomas, Gilles, all!
Thanks for reviewing this!
> 25 марта 2021 г., в 02:31, Thomas Munro <[email protected]> написал(а):
>
> I don't think we should put "slru" (the name of the buffer replacement
> algorithm, implementation detail) in the GUC names.
+1
> + It defaults to 0, in this case CLOG size is taken as
> <varname>shared_buffers</varname> / 512.
>
> We already know that increasing the number of CLOG buffers above the
> current number hurts as the linear search begins to dominate
Uh, my intent was to copy original approach of CLOG SLRU size, I just missed that Min(,) thing in shared_buffers logic.
> 26 марта 2021 г., в 08:46, Thomas Munro <[email protected]> написал(а):
>
> Hi Andrey, all,
>
> I propose some changes, and I'm attaching a new version:
>
> I renamed the GUCs as clog_buffers etc (no "_slru_"). I fixed some
> copy/paste mistakes where the different GUCs were mixed up. I made
> some changes to the .conf.sample. I rewrote the documentation so that
> it states the correct unit and defaults, and refers to the
> subdirectories that are cached by these buffers instead of trying to
> give a new definition of each of the SLRUs.
>
> Do you like those changes?
Yes!
> Some things I thought about but didn't change:
>
> I'm not entirely sure if we should use the internal and historical
> names well known to hackers (CLOG), or the visible directory names (I
> mean, we could use pg_xact_buffers instead of clog_buffers).
While it is good idea to make notes about directory name, I think the real naming criteria is to help find this GUC when user encounters wait events in pg_stat_activity. I think there is no CLOG mentions in docs [0], only XactBuffer, XactSLRU et c.
> I'm not saying the 0002 patch is bug-free yet though, it's a bit finickity.
I think the idea of speeding up linear search is really really good for scaling SLRUs. It's not even about improving normal performance of the cluster, but it's important from preventing pathological degradation under certain circumstances. Bigger cache really saves SLAs :) I'll look into the patch more closely this weekend. Thank you!
Best regards, Andrey Borodin.
[0] https://www.postgresql.org/docs/current/monitoring-stats.html#MONITORING-PG-STAT-ACTIVITY-VIEW
^ permalink raw reply [nested|flat] 90+ messages in thread
* Re: MultiXact\SLRU buffers configuration
2020-05-08 16:36 MultiXact\SLRU buffers configuration Andrey M. Borodin <[email protected]>
2020-05-11 11:17 ` Re: MultiXact\SLRU buffers configuration Andrey M. Borodin <[email protected]>
2020-05-13 18:08 ` Re: MultiXact\SLRU buffers configuration Andrey M. Borodin <[email protected]>
2020-05-14 01:25 ` Re: MultiXact\SLRU buffers configuration Kyotaro Horiguchi <[email protected]>
2020-05-14 05:19 ` Re: MultiXact\SLRU buffers configuration Andrey M. Borodin <[email protected]>
2020-05-14 06:16 ` Re: MultiXact\SLRU buffers configuration Kyotaro Horiguchi <[email protected]>
2020-05-14 06:44 ` Re: MultiXact\SLRU buffers configuration Andrey M. Borodin <[email protected]>
2020-05-15 00:03 ` Re: MultiXact\SLRU buffers configuration Kyotaro Horiguchi <[email protected]>
2020-07-02 12:02 ` Re: MultiXact\SLRU buffers configuration Daniel Gustafsson <[email protected]>
2020-07-08 07:03 ` Re: MultiXact\SLRU buffers configuration Andrey M. Borodin <[email protected]>
2020-08-28 18:08 ` Re: MultiXact\SLRU buffers configuration Anastasia Lubennikova <[email protected]>
2020-09-28 14:41 ` Re: MultiXact\SLRU buffers configuration Andrey M. Borodin <[email protected]>
2020-10-26 01:05 ` Re: MultiXact\SLRU buffers configuration Alexander Korotkov <[email protected]>
2020-10-26 15:45 ` Re: MultiXact\SLRU buffers configuration Andrey Borodin <[email protected]>
2020-10-27 17:02 ` Re: MultiXact\SLRU buffers configuration Alexander Korotkov <[email protected]>
2020-10-27 17:23 ` Re: MultiXact\SLRU buffers configuration Alexander Korotkov <[email protected]>
2020-10-28 01:36 ` Re: MultiXact\SLRU buffers configuration Tomas Vondra <[email protected]>
2020-10-28 07:34 ` Re: MultiXact\SLRU buffers configuration Andrey Borodin <[email protected]>
2020-10-28 23:32 ` Re: MultiXact\SLRU buffers configuration Tomas Vondra <[email protected]>
2020-10-29 07:08 ` Re: MultiXact\SLRU buffers configuration Andrey Borodin <[email protected]>
2020-10-29 13:49 ` Re: MultiXact\SLRU buffers configuration Tomas Vondra <[email protected]>
2020-11-02 12:45 ` Re: MultiXact\SLRU buffers configuration Andrey Borodin <[email protected]>
2020-11-10 00:13 ` Re: MultiXact\SLRU buffers configuration Tomas Vondra <[email protected]>
2020-11-10 06:16 ` Re: MultiXact\SLRU buffers configuration Andrey Borodin <[email protected]>
2020-11-10 18:07 ` Re: MultiXact\SLRU buffers configuration Tomas Vondra <[email protected]>
2020-11-13 11:49 ` Re: MultiXact\SLRU buffers configuration Andrey Borodin <[email protected]>
2020-12-08 16:05 ` Re: MultiXact\SLRU buffers configuration Gilles Darold <[email protected]>
2020-12-08 17:52 ` Re: MultiXact\SLRU buffers configuration Andrey Borodin <[email protected]>
2020-12-10 14:45 ` Re: MultiXact\SLRU buffers configuration Gilles Darold <[email protected]>
2020-12-11 17:50 ` Re: MultiXact\SLRU buffers configuration Gilles Darold <[email protected]>
2020-12-13 09:17 ` Re: MultiXact\SLRU buffers configuration Gilles Darold <[email protected]>
2020-12-13 17:24 ` Re: MultiXact\SLRU buffers configuration Andrey Borodin <[email protected]>
2020-12-23 16:31 ` Re: MultiXact\SLRU buffers configuration Gilles Darold <[email protected]>
2021-02-15 17:17 ` Re: MultiXact\SLRU buffers configuration Andrey Borodin <[email protected]>
2021-03-11 15:50 ` Re: MultiXact\SLRU buffers configuration Gilles Darold <[email protected]>
2021-03-12 12:44 ` Re: MultiXact\SLRU buffers configuration Andrey Borodin <[email protected]>
2021-03-24 21:31 ` Re: MultiXact\SLRU buffers configuration Thomas Munro <[email protected]>
2021-03-25 01:03 ` Re: MultiXact\SLRU buffers configuration Thomas Munro <[email protected]>
2021-03-26 03:46 ` Re: MultiXact\SLRU buffers configuration Thomas Munro <[email protected]>
2021-03-26 06:00 ` Re: MultiXact\SLRU buffers configuration Andrey Borodin <[email protected]>
@ 2021-03-26 15:52 ` Andrey Borodin <[email protected]>
2021-03-26 20:26 ` Re: MultiXact\SLRU buffers configuration Thomas Munro <[email protected]>
0 siblings, 1 reply; 90+ messages in thread
From: Andrey Borodin @ 2021-03-26 15:52 UTC (permalink / raw)
To: Thomas Munro <[email protected]>; +Cc: Gilles Darold <[email protected]>; Tomas Vondra <[email protected]>; Tomas Vondra <[email protected]>; Alexander Korotkov <[email protected]>; Anastasia Lubennikova <[email protected]>; Daniel Gustafsson <[email protected]>; Kyotaro Horiguchi <[email protected]>; pgsql-hackers
> 26 марта 2021 г., в 11:00, Andrey Borodin <[email protected]> написал(а):
>
>> I'm not saying the 0002 patch is bug-free yet though, it's a bit finickity.
> I think the idea of speeding up linear search is really really good for scaling SLRUs. It's not even about improving normal performance of the cluster, but it's important from preventing pathological degradation under certain circumstances. Bigger cache really saves SLAs :) I'll look into the patch more closely this weekend. Thank you!
Some thoughts on HashTable patch:
1. Can we allocate bigger hashtable to reduce probability of collisions?
2. Can we use specialised hashtable for this case? I'm afraid hash_search() does comparable number of CPU cycles as simple cycle from 0 to 128. We could inline everything and avoid hashp->hash(keyPtr, hashp->keysize) call. I'm not insisting on special hash though, just an idea.
3. pageno in SlruMappingTableEntry seems to be unused.
Thanks!
Best regards, Andrey Borodin.
^ permalink raw reply [nested|flat] 90+ messages in thread
* Re: MultiXact\SLRU buffers configuration
2020-05-08 16:36 MultiXact\SLRU buffers configuration Andrey M. Borodin <[email protected]>
2020-05-11 11:17 ` Re: MultiXact\SLRU buffers configuration Andrey M. Borodin <[email protected]>
2020-05-13 18:08 ` Re: MultiXact\SLRU buffers configuration Andrey M. Borodin <[email protected]>
2020-05-14 01:25 ` Re: MultiXact\SLRU buffers configuration Kyotaro Horiguchi <[email protected]>
2020-05-14 05:19 ` Re: MultiXact\SLRU buffers configuration Andrey M. Borodin <[email protected]>
2020-05-14 06:16 ` Re: MultiXact\SLRU buffers configuration Kyotaro Horiguchi <[email protected]>
2020-05-14 06:44 ` Re: MultiXact\SLRU buffers configuration Andrey M. Borodin <[email protected]>
2020-05-15 00:03 ` Re: MultiXact\SLRU buffers configuration Kyotaro Horiguchi <[email protected]>
2020-07-02 12:02 ` Re: MultiXact\SLRU buffers configuration Daniel Gustafsson <[email protected]>
2020-07-08 07:03 ` Re: MultiXact\SLRU buffers configuration Andrey M. Borodin <[email protected]>
2020-08-28 18:08 ` Re: MultiXact\SLRU buffers configuration Anastasia Lubennikova <[email protected]>
2020-09-28 14:41 ` Re: MultiXact\SLRU buffers configuration Andrey M. Borodin <[email protected]>
2020-10-26 01:05 ` Re: MultiXact\SLRU buffers configuration Alexander Korotkov <[email protected]>
2020-10-26 15:45 ` Re: MultiXact\SLRU buffers configuration Andrey Borodin <[email protected]>
2020-10-27 17:02 ` Re: MultiXact\SLRU buffers configuration Alexander Korotkov <[email protected]>
2020-10-27 17:23 ` Re: MultiXact\SLRU buffers configuration Alexander Korotkov <[email protected]>
2020-10-28 01:36 ` Re: MultiXact\SLRU buffers configuration Tomas Vondra <[email protected]>
2020-10-28 07:34 ` Re: MultiXact\SLRU buffers configuration Andrey Borodin <[email protected]>
2020-10-28 23:32 ` Re: MultiXact\SLRU buffers configuration Tomas Vondra <[email protected]>
2020-10-29 07:08 ` Re: MultiXact\SLRU buffers configuration Andrey Borodin <[email protected]>
2020-10-29 13:49 ` Re: MultiXact\SLRU buffers configuration Tomas Vondra <[email protected]>
2020-11-02 12:45 ` Re: MultiXact\SLRU buffers configuration Andrey Borodin <[email protected]>
2020-11-10 00:13 ` Re: MultiXact\SLRU buffers configuration Tomas Vondra <[email protected]>
2020-11-10 06:16 ` Re: MultiXact\SLRU buffers configuration Andrey Borodin <[email protected]>
2020-11-10 18:07 ` Re: MultiXact\SLRU buffers configuration Tomas Vondra <[email protected]>
2020-11-13 11:49 ` Re: MultiXact\SLRU buffers configuration Andrey Borodin <[email protected]>
2020-12-08 16:05 ` Re: MultiXact\SLRU buffers configuration Gilles Darold <[email protected]>
2020-12-08 17:52 ` Re: MultiXact\SLRU buffers configuration Andrey Borodin <[email protected]>
2020-12-10 14:45 ` Re: MultiXact\SLRU buffers configuration Gilles Darold <[email protected]>
2020-12-11 17:50 ` Re: MultiXact\SLRU buffers configuration Gilles Darold <[email protected]>
2020-12-13 09:17 ` Re: MultiXact\SLRU buffers configuration Gilles Darold <[email protected]>
2020-12-13 17:24 ` Re: MultiXact\SLRU buffers configuration Andrey Borodin <[email protected]>
2020-12-23 16:31 ` Re: MultiXact\SLRU buffers configuration Gilles Darold <[email protected]>
2021-02-15 17:17 ` Re: MultiXact\SLRU buffers configuration Andrey Borodin <[email protected]>
2021-03-11 15:50 ` Re: MultiXact\SLRU buffers configuration Gilles Darold <[email protected]>
2021-03-12 12:44 ` Re: MultiXact\SLRU buffers configuration Andrey Borodin <[email protected]>
2021-03-24 21:31 ` Re: MultiXact\SLRU buffers configuration Thomas Munro <[email protected]>
2021-03-25 01:03 ` Re: MultiXact\SLRU buffers configuration Thomas Munro <[email protected]>
2021-03-26 03:46 ` Re: MultiXact\SLRU buffers configuration Thomas Munro <[email protected]>
2021-03-26 06:00 ` Re: MultiXact\SLRU buffers configuration Andrey Borodin <[email protected]>
2021-03-26 15:52 ` Re: MultiXact\SLRU buffers configuration Andrey Borodin <[email protected]>
@ 2021-03-26 20:26 ` Thomas Munro <[email protected]>
2021-03-27 05:31 ` Re: MultiXact\SLRU buffers configuration Andrey Borodin <[email protected]>
0 siblings, 1 reply; 90+ messages in thread
From: Thomas Munro @ 2021-03-26 20:26 UTC (permalink / raw)
To: Andrey Borodin <[email protected]>; +Cc: Gilles Darold <[email protected]>; Tomas Vondra <[email protected]>; Tomas Vondra <[email protected]>; Alexander Korotkov <[email protected]>; Anastasia Lubennikova <[email protected]>; Daniel Gustafsson <[email protected]>; Kyotaro Horiguchi <[email protected]>; pgsql-hackers
On Sat, Mar 27, 2021 at 4:52 AM Andrey Borodin <[email protected]> wrote:
> Some thoughts on HashTable patch:
> 1. Can we allocate bigger hashtable to reduce probability of collisions?
Yeah, good idea, might require some study.
> 2. Can we use specialised hashtable for this case? I'm afraid hash_search() does comparable number of CPU cycles as simple cycle from 0 to 128. We could inline everything and avoid hashp->hash(keyPtr, hashp->keysize) call. I'm not insisting on special hash though, just an idea.
I tried really hard to not fall into this rabbit h.... [hack hack
hack], OK, here's a first attempt to use simplehash, Andres's
steampunk macro-based robinhood template that we're already using for
several other things, and murmurhash which is inlineable and
branch-free. I had to tweak it to support "in-place" creation and
fixed size (in other words, no allocators, for use in shared memory).
Then I was annoyed that I had to add a "status" member to our struct,
so I tried to fix that. Definitely needs more work to think about
failure modes when running out of memory, how much spare space you
need, etc.
I have not experimented with this much beyond hacking until the tests
pass, but it *should* be more efficient...
> 3. pageno in SlruMappingTableEntry seems to be unused.
It's the key (dynahash uses the first N bytes of your struct as the
key, but in this new simplehash version it's more explicit).
Attachments:
[application/x-patch] v13-0001-Make-all-SLRU-buffer-sizes-configurable.patch (20.6K, ../../CA+hUKGKVqrxOp82zER1=XN=yPwV_-OCGAg=ez=1iz9rG+A7Smw@mail.gmail.com/2-v13-0001-Make-all-SLRU-buffer-sizes-configurable.patch)
download | inline diff:
From 5f5d4ed8ae2808766ac1fd48f68602ef530e3833 Mon Sep 17 00:00:00 2001
From: Andrey Borodin <[email protected]>
Date: Mon, 15 Feb 2021 21:51:56 +0500
Subject: [PATCH v13 1/5] Make all SLRU buffer sizes configurable.
Provide new GUCs to set the number of buffers, instead of using hard
coded defaults.
Author: Andrey M. Borodin <[email protected]>
Reviewed-by: Anastasia Lubennikova <[email protected]>
Reviewed-by: Tomas Vondra <[email protected]>
Reviewed-by: Alexander Korotkov <[email protected]>
Reviewed-by: Gilles Darold <[email protected]>
Reviewed-by: Thomas Munro <[email protected]>
Discussion: https://postgr.es/m/2BEC2B3F-9B61-4C1D-9FB5-5FAB0F05EF86%40yandex-team.ru
---
doc/src/sgml/config.sgml | 137 ++++++++++++++++++
src/backend/access/transam/clog.c | 6 +
src/backend/access/transam/commit_ts.c | 5 +-
src/backend/access/transam/multixact.c | 8 +-
src/backend/access/transam/subtrans.c | 5 +-
src/backend/commands/async.c | 8 +-
src/backend/storage/lmgr/predicate.c | 4 +-
src/backend/utils/init/globals.c | 8 +
src/backend/utils/misc/guc.c | 77 ++++++++++
src/backend/utils/misc/postgresql.conf.sample | 9 ++
src/include/access/multixact.h | 4 -
src/include/access/subtrans.h | 3 -
src/include/commands/async.h | 5 -
src/include/miscadmin.h | 7 +
src/include/storage/predicate.h | 4 -
15 files changed, 261 insertions(+), 29 deletions(-)
diff --git a/doc/src/sgml/config.sgml b/doc/src/sgml/config.sgml
index ddc6d789d8..f1112bfa9c 100644
--- a/doc/src/sgml/config.sgml
+++ b/doc/src/sgml/config.sgml
@@ -1886,6 +1886,143 @@ include_dir 'conf.d'
</para>
</listitem>
</varlistentry>
+
+ <varlistentry id="guc-multixact-offsets-buffers" xreflabel="multixact_offsets_buffers">
+ <term><varname>multixact_offsets_buffers</varname> (<type>integer</type>)
+ <indexterm>
+ <primary><varname>multixact_offsets_buffers</varname> configuration parameter</primary>
+ </indexterm>
+ </term>
+ <listitem>
+ <para>
+ Specifies the amount of shared memory to used to cache the contents
+ of <literal>pg_multixact/offsets</literal> (see
+ <xref linkend="pgdata-contents-table"/>).
+ If this value is specified without units, it is taken as blocks,
+ that is <symbol>BLCKSZ</symbol> bytes, typically 8kB.
+ The default value is <literal>8</literal>.
+ This parameter can only be set at server start.
+ </para>
+ </listitem>
+ </varlistentry>
+
+ <varlistentry id="guc-multixact-members-buffers" xreflabel="multixact_members_buffers">
+ <term><varname>multixact_members_buffers</varname> (<type>integer</type>)
+ <indexterm>
+ <primary><varname>multixact_members_buffers</varname> configuration parameter</primary>
+ </indexterm>
+ </term>
+ <listitem>
+ <para>
+ Specifies the amount of shared memory to used to cache the contents
+ of <literal>pg_multixact/members</literal> (see
+ <xref linkend="pgdata-contents-table"/>).
+ If this value is specified without units, it is taken as blocks,
+ that is <symbol>BLCKSZ</symbol> bytes, typically 8kB.
+ The default value is <literal>16</literal>.
+ This parameter can only be set at server start.
+ </para>
+ </listitem>
+ </varlistentry>
+
+ <varlistentry id="guc-subtrans-buffers" xreflabel="subtrans_buffers">
+ <term><varname>subtrans_buffers</varname> (<type>integer</type>)
+ <indexterm>
+ <primary><varname>subtrans_buffers</varname> configuration parameter</primary>
+ </indexterm>
+ </term>
+ <listitem>
+ <para>
+ Specifies the amount of shared memory to used to cache the contents
+ of <literal>pg_subtrans</literal> (see
+ <xref linkend="pgdata-contents-table"/>).
+ If this value is specified without units, it is taken as blocks,
+ that is <symbol>BLCKSZ</symbol> bytes, typically 8kB.
+ The default value is <literal>8</literal>.
+ This parameter can only be set at server start.
+ </para>
+ </listitem>
+ </varlistentry>
+
+ <varlistentry id="guc-notify-buffers" xreflabel="notify_buffers">
+ <term><varname>notify_buffers</varname> (<type>integer</type>)
+ <indexterm>
+ <primary><varname>notify_buffers</varname> configuration parameter</primary>
+ </indexterm>
+ </term>
+ <listitem>
+ <para>
+ Specifies the amount of shared memory to used to cache the contents
+ of <literal>pg_notify</literal> (see
+ <xref linkend="pgdata-contents-table"/>).
+ If this value is specified without units, it is taken as blocks,
+ that is <symbol>BLCKSZ</symbol> bytes, typically 8kB.
+ The default value is <literal>8</literal>.
+ This parameter can only be set at server start.
+ </para>
+ </listitem>
+ </varlistentry>
+
+ <varlistentry id="guc-serial-buffers" xreflabel="serial_buffers">
+ <term><varname>serial_buffers</varname> (<type>integer</type>)
+ <indexterm>
+ <primary><varname>serial_buffers</varname> configuration parameter</primary>
+ </indexterm>
+ </term>
+ <listitem>
+ <para>
+ Specifies the amount of shared memory to used to cache the contents
+ of <literal>pg_serial</literal> (see
+ <xref linkend="pgdata-contents-table"/>).
+ If this value is specified without units, it is taken as blocks,
+ that is <symbol>BLCKSZ</symbol> bytes, typically 8kB.
+ The default value is <literal>16</literal>.
+ This parameter can only be set at server start.
+ </para>
+ </listitem>
+ </varlistentry>
+
+ <varlistentry id="guc-clog-buffers" xreflabel="clog_buffers">
+ <term><varname>clog_buffers</varname> (<type>integer</type>)
+ <indexterm>
+ <primary><varname>clog_buffers</varname> configuration parameter</primary>
+ </indexterm>
+ </term>
+ <listitem>
+ <para>
+ Specifies the amount of shared memory to used to cache the contents
+ of <literal>pg_xact</literal> (see
+ <xref linkend="pgdata-contents-table"/>).
+ If this value is specified without units, it is taken as blocks,
+ that is <symbol>BLCKSZ</symbol> bytes, typically 8kB.
+ The default value is <literal>0</literal>, which requests
+ <varname>shared_buffers</varname> / 512, but not more than 128 or
+ fewer than 4 blocks.
+ This parameter can only be set at server start.
+ </para>
+ </listitem>
+ </varlistentry>
+
+ <varlistentry id="guc-commit-ts-buffers" xreflabel="commit_ts_buffers">
+ <term><varname>commit_ts_buffers</varname> (<type>integer</type>)
+ <indexterm>
+ <primary><varname>commit_ts_buffers</varname> configuration parameter</primary>
+ </indexterm>
+ </term>
+ <listitem>
+ <para>
+ Specifies the amount of memory to be used to cache the cotents of
+ <literal>pg_commit_ts</literal> (see
+ <xref linkend="pgdata-contents-table"/>).
+ If this value is specified without units, it is taken as blocks,
+ that is <symbol>BLCKSZ</symbol> bytes, typically 8kB.
+ The default value is <literal>0</literal>, which requests
+ <varname>shared_buffers</varname> / 512, but not more than 128 or
+ fewer than 16 blocks.
+ This parameter can only be set at server start.
+ </para>
+ </listitem>
+ </varlistentry>
<varlistentry id="guc-max-stack-depth" xreflabel="max_stack_depth">
<term><varname>max_stack_depth</varname> (<type>integer</type>)
diff --git a/src/backend/access/transam/clog.c b/src/backend/access/transam/clog.c
index 6fa4713fb4..0318e8ff59 100644
--- a/src/backend/access/transam/clog.c
+++ b/src/backend/access/transam/clog.c
@@ -659,6 +659,9 @@ TransactionIdGetStatus(TransactionId xid, XLogRecPtr *lsn)
/*
* Number of shared CLOG buffers.
*
+ * If values is configured via GUC - just use given value. Otherwise
+ * apply following euristics.
+ *
* On larger multi-processor systems, it is possible to have many CLOG page
* requests in flight at one time which could lead to disk access for CLOG
* page if the required page is not found in memory. Testing revealed that we
@@ -675,6 +678,9 @@ TransactionIdGetStatus(TransactionId xid, XLogRecPtr *lsn)
Size
CLOGShmemBuffers(void)
{
+ /* consider 0 and 1 as unset GUC */
+ if (clog_buffers > 1)
+ return clog_buffers;
return Min(128, Max(4, NBuffers / 512));
}
diff --git a/src/backend/access/transam/commit_ts.c b/src/backend/access/transam/commit_ts.c
index 268bdba339..0d2632b90e 100644
--- a/src/backend/access/transam/commit_ts.c
+++ b/src/backend/access/transam/commit_ts.c
@@ -530,7 +530,10 @@ pg_xact_commit_timestamp_origin(PG_FUNCTION_ARGS)
Size
CommitTsShmemBuffers(void)
{
- return Min(16, Max(4, NBuffers / 1024));
+ /* consider 0 and 1 as unset GUC */
+ if (commit_ts_buffers > 1)
+ return commit_ts_buffers;
+ return Min(16, Max(4, NBuffers / 512));
}
/*
diff --git a/src/backend/access/transam/multixact.c b/src/backend/access/transam/multixact.c
index 1f9f1a1fa1..21787765e2 100644
--- a/src/backend/access/transam/multixact.c
+++ b/src/backend/access/transam/multixact.c
@@ -1831,8 +1831,8 @@ MultiXactShmemSize(void)
mul_size(sizeof(MultiXactId) * 2, MaxOldestSlot))
size = SHARED_MULTIXACT_STATE_SIZE;
- size = add_size(size, SimpleLruShmemSize(NUM_MULTIXACTOFFSET_BUFFERS, 0));
- size = add_size(size, SimpleLruShmemSize(NUM_MULTIXACTMEMBER_BUFFERS, 0));
+ size = add_size(size, SimpleLruShmemSize(multixact_offsets_buffers, 0));
+ size = add_size(size, SimpleLruShmemSize(multixact_members_buffers, 0));
return size;
}
@@ -1848,13 +1848,13 @@ MultiXactShmemInit(void)
MultiXactMemberCtl->PagePrecedes = MultiXactMemberPagePrecedes;
SimpleLruInit(MultiXactOffsetCtl,
- "MultiXactOffset", NUM_MULTIXACTOFFSET_BUFFERS, 0,
+ "MultiXactOffset", multixact_offsets_buffers, 0,
MultiXactOffsetSLRULock, "pg_multixact/offsets",
LWTRANCHE_MULTIXACTOFFSET_BUFFER,
SYNC_HANDLER_MULTIXACT_OFFSET);
SlruPagePrecedesUnitTests(MultiXactOffsetCtl, MULTIXACT_OFFSETS_PER_PAGE);
SimpleLruInit(MultiXactMemberCtl,
- "MultiXactMember", NUM_MULTIXACTMEMBER_BUFFERS, 0,
+ "MultiXactMember", multixact_offsets_buffers, 0,
MultiXactMemberSLRULock, "pg_multixact/members",
LWTRANCHE_MULTIXACTMEMBER_BUFFER,
SYNC_HANDLER_MULTIXACT_MEMBER);
diff --git a/src/backend/access/transam/subtrans.c b/src/backend/access/transam/subtrans.c
index 6a8e521f89..785f2520fd 100644
--- a/src/backend/access/transam/subtrans.c
+++ b/src/backend/access/transam/subtrans.c
@@ -31,6 +31,7 @@
#include "access/slru.h"
#include "access/subtrans.h"
#include "access/transam.h"
+#include "miscadmin.h"
#include "pg_trace.h"
#include "utils/snapmgr.h"
@@ -184,14 +185,14 @@ SubTransGetTopmostTransaction(TransactionId xid)
Size
SUBTRANSShmemSize(void)
{
- return SimpleLruShmemSize(NUM_SUBTRANS_BUFFERS, 0);
+ return SimpleLruShmemSize(subtrans_buffers, 0);
}
void
SUBTRANSShmemInit(void)
{
SubTransCtl->PagePrecedes = SubTransPagePrecedes;
- SimpleLruInit(SubTransCtl, "Subtrans", NUM_SUBTRANS_BUFFERS, 0,
+ SimpleLruInit(SubTransCtl, "Subtrans", subtrans_buffers, 0,
SubtransSLRULock, "pg_subtrans",
LWTRANCHE_SUBTRANS_BUFFER, SYNC_HANDLER_NONE);
SlruPagePrecedesUnitTests(SubTransCtl, SUBTRANS_XACTS_PER_PAGE);
diff --git a/src/backend/commands/async.c b/src/backend/commands/async.c
index 4b16fb5682..de17f52cd7 100644
--- a/src/backend/commands/async.c
+++ b/src/backend/commands/async.c
@@ -107,7 +107,7 @@
* frontend during startup.) The above design guarantees that notifies from
* other backends will never be missed by ignoring self-notifies.
*
- * The amount of shared memory used for notify management (NUM_NOTIFY_BUFFERS)
+ * The amount of shared memory used for notify management (notify_buffers)
* can be varied without affecting anything but performance. The maximum
* amount of notification data that can be queued at one time is determined
* by slru.c's wraparound limit; see QUEUE_MAX_PAGE below.
@@ -225,7 +225,7 @@ typedef struct QueuePosition
*
* Resist the temptation to make this really large. While that would save
* work in some places, it would add cost in others. In particular, this
- * should likely be less than NUM_NOTIFY_BUFFERS, to ensure that backends
+ * should likely be less than notify_buffers, to ensure that backends
* catch up before the pages they'll need to read fall out of SLRU cache.
*/
#define QUEUE_CLEANUP_DELAY 4
@@ -514,7 +514,7 @@ AsyncShmemSize(void)
size = mul_size(MaxBackends + 1, sizeof(QueueBackendStatus));
size = add_size(size, offsetof(AsyncQueueControl, backend));
- size = add_size(size, SimpleLruShmemSize(NUM_NOTIFY_BUFFERS, 0));
+ size = add_size(size, SimpleLruShmemSize(notify_buffers, 0));
return size;
}
@@ -562,7 +562,7 @@ AsyncShmemInit(void)
* Set up SLRU management of the pg_notify data.
*/
NotifyCtl->PagePrecedes = asyncQueuePagePrecedes;
- SimpleLruInit(NotifyCtl, "Notify", NUM_NOTIFY_BUFFERS, 0,
+ SimpleLruInit(NotifyCtl, "Notify", notify_buffers, 0,
NotifySLRULock, "pg_notify", LWTRANCHE_NOTIFY_BUFFER,
SYNC_HANDLER_NONE);
diff --git a/src/backend/storage/lmgr/predicate.c b/src/backend/storage/lmgr/predicate.c
index d493aeef0f..b1f4f1651d 100644
--- a/src/backend/storage/lmgr/predicate.c
+++ b/src/backend/storage/lmgr/predicate.c
@@ -872,7 +872,7 @@ SerialInit(void)
*/
SerialSlruCtl->PagePrecedes = SerialPagePrecedesLogically;
SimpleLruInit(SerialSlruCtl, "Serial",
- NUM_SERIAL_BUFFERS, 0, SerialSLRULock, "pg_serial",
+ serial_buffers, 0, SerialSLRULock, "pg_serial",
LWTRANCHE_SERIAL_BUFFER, SYNC_HANDLER_NONE);
#ifdef USE_ASSERT_CHECKING
SerialPagePrecedesLogicallyUnitTests();
@@ -1395,7 +1395,7 @@ PredicateLockShmemSize(void)
/* Shared memory structures for SLRU tracking of old committed xids. */
size = add_size(size, sizeof(SerialControlData));
- size = add_size(size, SimpleLruShmemSize(NUM_SERIAL_BUFFERS, 0));
+ size = add_size(size, SimpleLruShmemSize(serial_buffers, 0));
return size;
}
diff --git a/src/backend/utils/init/globals.c b/src/backend/utils/init/globals.c
index 73e0a672ae..e90275be6c 100644
--- a/src/backend/utils/init/globals.c
+++ b/src/backend/utils/init/globals.c
@@ -148,3 +148,11 @@ int64 VacuumPageDirty = 0;
int VacuumCostBalance = 0; /* working state for vacuum */
bool VacuumCostActive = false;
+
+int multixact_offsets_buffers = 8;
+int multixact_members_buffers = 16;
+int subtrans_buffers = 32;
+int notify_buffers = 8;
+int serial_buffers = 16;
+int clog_buffers = 0;
+int commit_ts_buffers = 0;
diff --git a/src/backend/utils/misc/guc.c b/src/backend/utils/misc/guc.c
index 0c5dc4d3e8..003bc820d2 100644
--- a/src/backend/utils/misc/guc.c
+++ b/src/backend/utils/misc/guc.c
@@ -2305,6 +2305,83 @@ static struct config_int ConfigureNamesInt[] =
NULL, NULL, NULL
},
+ {
+ {"multixact_offsets_buffers", PGC_POSTMASTER, RESOURCES_MEM,
+ gettext_noop("Sets the number of shared memory buffers used for MultiXact offsets SLRU."),
+ NULL,
+ GUC_UNIT_BLOCKS
+ },
+ &multixact_offsets_buffers,
+ 8, 2, INT_MAX / 2,
+ NULL, NULL, NULL
+ },
+
+ {
+ {"multixact_members_buffers", PGC_POSTMASTER, RESOURCES_MEM,
+ gettext_noop("Sets the number of shared memory buffers used for MultiXact members SLRU."),
+ NULL,
+ GUC_UNIT_BLOCKS
+ },
+ &multixact_members_buffers,
+ 16, 2, INT_MAX / 2,
+ NULL, NULL, NULL
+ },
+
+ {
+ {"subtrans_buffers", PGC_POSTMASTER, RESOURCES_MEM,
+ gettext_noop("Sets the number of shared memory buffers used for substransactions SLRU."),
+ NULL,
+ GUC_UNIT_BLOCKS
+ },
+ &subtrans_buffers,
+ 32, 2, INT_MAX / 2,
+ NULL, NULL, NULL
+ },
+
+ {
+ {"notify_buffers", PGC_POSTMASTER, RESOURCES_MEM,
+ gettext_noop("Sets the number of shared memory buffers used for asyncronous notifications SLRU."),
+ NULL,
+ GUC_UNIT_BLOCKS
+ },
+ ¬ify_buffers,
+ 8, 2, INT_MAX / 2,
+ NULL, NULL, NULL
+ },
+
+ {
+ {"serial_buffers", PGC_POSTMASTER, RESOURCES_MEM,
+ gettext_noop("Sets the number of shared memory buffers used for predicate locks SLRU."),
+ NULL,
+ GUC_UNIT_BLOCKS
+ },
+ &serial_buffers,
+ 16, 2, INT_MAX / 2,
+ NULL, NULL, NULL
+ },
+
+ {
+ {"clog_buffers", PGC_POSTMASTER, RESOURCES_MEM,
+ gettext_noop("Sets the number of shared memory buffers used for commit log SLRU."),
+ NULL,
+ GUC_UNIT_BLOCKS
+ },
+ &clog_buffers,
+ 0, 0, INT_MAX / 2,
+ NULL, NULL, NULL
+ },
+
+ {
+ {"commit_ts_buffers", PGC_POSTMASTER, RESOURCES_MEM,
+ gettext_noop("Sets the number of shared memory buffers used for commit timestamps SLRU."),
+ NULL,
+ GUC_UNIT_BLOCKS
+ },
+ &commit_ts_buffers,
+ 0, 0, INT_MAX / 2,
+ NULL, NULL, NULL
+ },
+
{
{"temp_buffers", PGC_USERSET, RESOURCES_MEM,
gettext_noop("Sets the maximum number of temporary buffers used by each session."),
diff --git a/src/backend/utils/misc/postgresql.conf.sample b/src/backend/utils/misc/postgresql.conf.sample
index b234a6bfe6..1b8515989b 100644
--- a/src/backend/utils/misc/postgresql.conf.sample
+++ b/src/backend/utils/misc/postgresql.conf.sample
@@ -190,6 +190,15 @@
# (change requires restart)
#backend_flush_after = 0 # measured in pages, 0 disables
+# - SLRU Buffers (change requires restart) -
+
+#clog_buffers = 0 # memory for pg_xact (0 = auto)
+#subtrans_buffers = 32 # memory for pg_subtrans
+#multixact_offsets_buffers = 8 # memory for pg_multixact/offsets
+#multixact_members_buffers = 16 # memory for pg_multixact/members
+#notify_buffers = 8 # memory for pg_nofity
+#serial_buffers = 16 # memory for pg_serial
+#commit_ts_buffers = 0 # memory for pg_commit_ts (0 = auto)
#------------------------------------------------------------------------------
# WRITE-AHEAD LOG
diff --git a/src/include/access/multixact.h b/src/include/access/multixact.h
index 4bbb035eae..97c0a46376 100644
--- a/src/include/access/multixact.h
+++ b/src/include/access/multixact.h
@@ -29,10 +29,6 @@
#define MaxMultiXactOffset ((MultiXactOffset) 0xFFFFFFFF)
-/* Number of SLRU buffers to use for multixact */
-#define NUM_MULTIXACTOFFSET_BUFFERS 8
-#define NUM_MULTIXACTMEMBER_BUFFERS 16
-
/*
* Possible multixact lock modes ("status"). The first four modes are for
* tuple locks (FOR KEY SHARE, FOR SHARE, FOR NO KEY UPDATE, FOR UPDATE); the
diff --git a/src/include/access/subtrans.h b/src/include/access/subtrans.h
index d0ab44ae82..ca0999056e 100644
--- a/src/include/access/subtrans.h
+++ b/src/include/access/subtrans.h
@@ -11,9 +11,6 @@
#ifndef SUBTRANS_H
#define SUBTRANS_H
-/* Number of SLRU buffers to use for subtrans */
-#define NUM_SUBTRANS_BUFFERS 32
-
extern void SubTransSetParent(TransactionId xid, TransactionId parent);
extern TransactionId SubTransGetParent(TransactionId xid);
extern TransactionId SubTransGetTopmostTransaction(TransactionId xid);
diff --git a/src/include/commands/async.h b/src/include/commands/async.h
index 9217f66b91..fa831e3721 100644
--- a/src/include/commands/async.h
+++ b/src/include/commands/async.h
@@ -15,11 +15,6 @@
#include <signal.h>
-/*
- * The number of SLRU page buffers we use for the notification queue.
- */
-#define NUM_NOTIFY_BUFFERS 8
-
extern bool Trace_notify;
extern volatile sig_atomic_t notifyInterruptPending;
diff --git a/src/include/miscadmin.h b/src/include/miscadmin.h
index 013850ac28..9c325b4312 100644
--- a/src/include/miscadmin.h
+++ b/src/include/miscadmin.h
@@ -162,6 +162,13 @@ extern PGDLLIMPORT int MaxBackends;
extern PGDLLIMPORT int MaxConnections;
extern PGDLLIMPORT int max_worker_processes;
extern PGDLLIMPORT int max_parallel_workers;
+extern PGDLLIMPORT int multixact_offsets_buffers;
+extern PGDLLIMPORT int multixact_members_buffers;
+extern PGDLLIMPORT int subtrans_buffers;
+extern PGDLLIMPORT int notify_buffers;
+extern PGDLLIMPORT int serial_buffers;
+extern PGDLLIMPORT int clog_buffers;
+extern PGDLLIMPORT int commit_ts_buffers;
extern PGDLLIMPORT int MyProcPid;
extern PGDLLIMPORT pg_time_t MyStartTime;
diff --git a/src/include/storage/predicate.h b/src/include/storage/predicate.h
index 152b698611..c72779bd88 100644
--- a/src/include/storage/predicate.h
+++ b/src/include/storage/predicate.h
@@ -26,10 +26,6 @@ extern int max_predicate_locks_per_xact;
extern int max_predicate_locks_per_relation;
extern int max_predicate_locks_per_page;
-
-/* Number of SLRU buffers to use for Serial SLRU */
-#define NUM_SERIAL_BUFFERS 16
-
/*
* A handle used for sharing SERIALIZABLEXACT objects between the participants
* in a parallel query.
--
2.30.1
[application/x-patch] v13-0002-Make-simplehash-easy-to-use-in-shmem.patch (5.9K, ../../CA+hUKGKVqrxOp82zER1=XN=yPwV_-OCGAg=ez=1iz9rG+A7Smw@mail.gmail.com/3-v13-0002-Make-simplehash-easy-to-use-in-shmem.patch)
download | inline diff:
From 3441027b9ac2f135dea7ec155503be9d6331dfc1 Mon Sep 17 00:00:00 2001
From: Thomas Munro <[email protected]>
Date: Sat, 27 Mar 2021 08:34:58 +1300
Subject: [PATCH v13 2/5] Make simplehash easy to use in shmem.
Allow "in-place" creation of a simplehash hash table of fixed size,
suitable for use in shared memory. No calling out to allocators, and no
ability to grow.
---
src/include/lib/simplehash.h | 56 +++++++++++++++++++++++++++++++++---
1 file changed, 52 insertions(+), 4 deletions(-)
diff --git a/src/include/lib/simplehash.h b/src/include/lib/simplehash.h
index 395be1ca9a..32d3fa58fe 100644
--- a/src/include/lib/simplehash.h
+++ b/src/include/lib/simplehash.h
@@ -120,6 +120,7 @@
#define SH_ALLOCATE SH_MAKE_NAME(allocate)
#define SH_FREE SH_MAKE_NAME(free)
#define SH_STAT SH_MAKE_NAME(stat)
+#define SH_ESTIMATE_SIZE SH_MAKE_NAME(estimate_size)
/* internal helper functions (no externally visible prototypes) */
#define SH_COMPUTE_PARAMETERS SH_MAKE_NAME(compute_parameters)
@@ -153,16 +154,22 @@ typedef struct SH_TYPE
/* boundary after which to grow hashtable */
uint32 grow_threshold;
+#ifndef SH_IN_PLACE
/* hash buckets */
SH_ELEMENT_TYPE *data;
+#endif
-#ifndef SH_RAW_ALLOCATOR
+#if !defined(SH_RAW_ALLOCATOR) && !defined(SH_IN_PLACE)
/* memory context to use for allocations */
MemoryContext ctx;
#endif
/* user defined data, useful for callbacks */
void *private_data;
+
+#ifdef SH_IN_PLACE
+ SH_ELEMENT_TYPE data[FLEXIBLE_ARRAY_MEMBER];
+#endif
} SH_TYPE;
typedef enum SH_STATUS
@@ -182,6 +189,11 @@ typedef struct SH_ITERATOR
#ifdef SH_RAW_ALLOCATOR
/* <prefix>_hash <prefix>_create(uint32 nelements, void *private_data) */
SH_SCOPE SH_TYPE *SH_CREATE(uint32 nelements, void *private_data);
+#elif defined(SH_IN_PLACE)
+/* size_t <prefix>_estimate_size(uint32 nelements) */
+SH_SCOPE size_t SH_ESTIMATE_SIZE(uint32 nelements);
+/* void <prefix>_create(<prefix>_hash *place, uint32 nelements, void *private_data) */
+SH_SCOPE void SH_CREATE(SH_TYPE *place, uint32 nelements, void *private_data);
#else
/*
* <prefix>_hash <prefix>_create(MemoryContext ctx, uint32 nelements,
@@ -191,14 +203,18 @@ SH_SCOPE SH_TYPE *SH_CREATE(MemoryContext ctx, uint32 nelements,
void *private_data);
#endif
+#ifndef SH_IN_PLACE
/* void <prefix>_destroy(<prefix>_hash *tb) */
SH_SCOPE void SH_DESTROY(SH_TYPE * tb);
+#endif
/* void <prefix>_reset(<prefix>_hash *tb) */
SH_SCOPE void SH_RESET(SH_TYPE * tb);
+#ifndef SH_IN_PLACE
/* void <prefix>_grow(<prefix>_hash *tb) */
SH_SCOPE void SH_GROW(SH_TYPE * tb, uint32 newsize);
+#endif
/* <element> *<prefix>_insert(<prefix>_hash *tb, <key> key, bool *found) */
SH_SCOPE SH_ELEMENT_TYPE *SH_INSERT(SH_TYPE * tb, SH_KEY_TYPE key, bool *found);
@@ -241,7 +257,7 @@ SH_SCOPE void SH_STAT(SH_TYPE * tb);
/* generate implementation of the hash table */
#ifdef SH_DEFINE
-#ifndef SH_RAW_ALLOCATOR
+#if !defined(SH_RAW_ALLOCATOR) && !defined(SH_IN_PLACE)
#include "utils/memutils.h"
#endif
@@ -383,11 +399,13 @@ SH_ENTRY_HASH(SH_TYPE * tb, SH_ELEMENT_TYPE * entry)
#endif
}
+#ifndef SH_IN_PLACE
/* default memory allocator function */
static inline void *SH_ALLOCATE(SH_TYPE * type, Size size);
static inline void SH_FREE(SH_TYPE * type, void *pointer);
+#endif
-#ifndef SH_USE_NONDEFAULT_ALLOCATOR
+#if !defined(SH_USE_NONDEFAULT_ALLOCATOR) && !defined(SH_IN_PLACE)
/* default memory allocator function */
static inline void *
@@ -410,6 +428,22 @@ SH_FREE(SH_TYPE * type, void *pointer)
#endif
+#ifdef SH_IN_PLACE
+/*
+ * Compute the amount of memory required for a fixed sized in-place hash table.
+ */
+SH_SCOPE size_t
+SH_ESTIMATE_SIZE(uint32 nelements)
+{
+ size_t size;
+
+ size = Max(nelements, 2);
+ size = pg_nextpower2_64(size);
+
+ return offsetof(SH_TYPE, data) + sizeof(SH_ELEMENT_TYPE) * size;
+}
+#endif
+
/*
* Create a hash table with enough space for `nelements` distinct members.
* Memory for the hash table is allocated from the passed-in context. If
@@ -422,6 +456,9 @@ SH_FREE(SH_TYPE * type, void *pointer)
#ifdef SH_RAW_ALLOCATOR
SH_SCOPE SH_TYPE *
SH_CREATE(uint32 nelements, void *private_data)
+#elif defined(SH_IN_PLACE)
+SH_SCOPE void
+SH_CREATE(SH_TYPE *place, uint32 nelements, void *private_data)
#else
SH_SCOPE SH_TYPE *
SH_CREATE(MemoryContext ctx, uint32 nelements, void *private_data)
@@ -432,6 +469,8 @@ SH_CREATE(MemoryContext ctx, uint32 nelements, void *private_data)
#ifdef SH_RAW_ALLOCATOR
tb = SH_RAW_ALLOCATOR(sizeof(SH_TYPE));
+#elif defined(SH_IN_PLACE)
+ tb = place;
#else
tb = MemoryContextAllocZero(ctx, sizeof(SH_TYPE));
tb->ctx = ctx;
@@ -443,11 +482,15 @@ SH_CREATE(MemoryContext ctx, uint32 nelements, void *private_data)
SH_COMPUTE_PARAMETERS(tb, size);
+#if defined(SH_IN_PLACE)
+ memset(&tb->data, 0, sizeof(SH_ELEMENT_TYPE) * tb->size);
+#else
tb->data = SH_ALLOCATE(tb, sizeof(SH_ELEMENT_TYPE) * tb->size);
-
return tb;
+#endif
}
+#ifndef SH_IN_PLACE
/* destroy a previously created hash table */
SH_SCOPE void
SH_DESTROY(SH_TYPE * tb)
@@ -455,6 +498,7 @@ SH_DESTROY(SH_TYPE * tb)
SH_FREE(tb, tb->data);
pfree(tb);
}
+#endif
/* reset the contents of a previously created hash table */
SH_SCOPE void
@@ -464,6 +508,7 @@ SH_RESET(SH_TYPE * tb)
tb->members = 0;
}
+#ifndef SH_IN_PLACE
/*
* Grow a hash table to at least `newsize` buckets.
*
@@ -576,6 +621,7 @@ SH_GROW(SH_TYPE * tb, uint32 newsize)
SH_FREE(tb, olddata);
}
+#endif
/*
* This is a separate static inline function, so it can be reliably be inlined
@@ -592,6 +638,7 @@ SH_INSERT_HASH_INTERNAL(SH_TYPE * tb, SH_KEY_TYPE key, uint32 hash, bool *found)
restart:
insertdist = 0;
+#ifndef SH_IN_PLACE
/*
* We do the grow check even if the key is actually present, to avoid
* doing the check inside the loop. This also lets us avoid having to
@@ -614,6 +661,7 @@ restart:
SH_GROW(tb, tb->size * 2);
/* SH_STAT(tb); */
}
+#endif
/* perform insert, start bucket search at optimal location */
data = tb->data;
--
2.30.1
[application/x-patch] v13-0003-Support-intrusive-status-flag-in-simplehash.patch (5.7K, ../../CA+hUKGKVqrxOp82zER1=XN=yPwV_-OCGAg=ez=1iz9rG+A7Smw@mail.gmail.com/4-v13-0003-Support-intrusive-status-flag-in-simplehash.patch)
download | inline diff:
From 3bbaf8d558e1e405217e17d1a502ff68556b21e3 Mon Sep 17 00:00:00 2001
From: Thomas Munro <[email protected]>
Date: Sat, 27 Mar 2021 09:04:56 +1300
Subject: [PATCH v13 3/5] Support intrusive status flag in simplehash.
Before, you had to include a "status" member in the element type, which
simplehash.h could use to detect free space. Allow the user to specify
a special key value to use instead, for more compact representation.
---
src/include/lib/simplehash.h | 66 ++++++++++++++++++++++++++----------
1 file changed, 48 insertions(+), 18 deletions(-)
diff --git a/src/include/lib/simplehash.h b/src/include/lib/simplehash.h
index 32d3fa58fe..05c7ca8a47 100644
--- a/src/include/lib/simplehash.h
+++ b/src/include/lib/simplehash.h
@@ -131,6 +131,8 @@
#define SH_ENTRY_HASH SH_MAKE_NAME(entry_hash)
#define SH_INSERT_HASH_INTERNAL SH_MAKE_NAME(insert_hash_internal)
#define SH_LOOKUP_HASH_INTERNAL SH_MAKE_NAME(lookup_hash_internal)
+#define SH_ENTRY_IS_EMPTY SH_MAKE_NAME(entry_is_empty)
+#define SH_SET_ENTRY_EMPTY SH_MAKE_NAME(set_entry_empty)
/* generate forward declarations necessary to use the hash table */
#ifdef SH_DECLARE
@@ -172,11 +174,13 @@ typedef struct SH_TYPE
#endif
} SH_TYPE;
+#ifndef SH_IS_EMPTY_KEY
typedef enum SH_STATUS
{
SH_STATUS_EMPTY = 0x00,
SH_STATUS_IN_USE = 0x01
} SH_STATUS;
+#endif
typedef struct SH_ITERATOR
{
@@ -309,6 +313,26 @@ SH_SCOPE void SH_STAT(SH_TYPE * tb);
#endif
+static inline bool
+SH_ENTRY_IS_EMPTY(SH_TYPE * tb, SH_ELEMENT_TYPE * entry)
+{
+#ifdef SH_IS_EMPTY_KEY
+ return SH_IS_EMPTY_KEY(tb, entry->SH_KEY);
+#else
+ return entry->status == SH_STATUS_EMPTY;
+#endif
+}
+
+static inline void
+SH_SET_ENTRY_EMPTY(SH_TYPE * tb, SH_ELEMENT_TYPE *entry)
+{
+#ifdef SH_EMPTY_KEY
+ entry->SH_KEY = SH_EMPTY_KEY(tb);
+#else
+ entry->status = SH_STATUS_EMPTY;
+#endif
+}
+
/*
* Compute sizing parameters for hashtable. Called when creating and growing
* the hashtable.
@@ -483,7 +507,7 @@ SH_CREATE(MemoryContext ctx, uint32 nelements, void *private_data)
SH_COMPUTE_PARAMETERS(tb, size);
#if defined(SH_IN_PLACE)
- memset(&tb->data, 0, sizeof(SH_ELEMENT_TYPE) * tb->size);
+ SH_RESET(tb);
#else
tb->data = SH_ALLOCATE(tb, sizeof(SH_ELEMENT_TYPE) * tb->size);
return tb;
@@ -504,7 +528,12 @@ SH_DESTROY(SH_TYPE * tb)
SH_SCOPE void
SH_RESET(SH_TYPE * tb)
{
+#ifdef SH_EMPTY_KEY
+ for (size_t i = 0; i < tb->size; ++i)
+ tb->data[i].SH_KEY = SH_EMPTY_KEY(tb);
+#else
memset(tb->data, 0, sizeof(SH_ELEMENT_TYPE) * tb->size);
+#endif
tb->members = 0;
}
@@ -675,14 +704,17 @@ restart:
SH_ELEMENT_TYPE *entry = &data[curelem];
/* any empty bucket can directly be used */
- if (entry->status == SH_STATUS_EMPTY)
+ if (SH_ENTRY_IS_EMPTY(tb, entry))
{
tb->members++;
entry->SH_KEY = key;
#ifdef SH_STORE_HASH
SH_GET_HASH(tb, entry) = hash;
#endif
+#ifndef SH_IS_EMPTY_KEY
entry->status = SH_STATUS_IN_USE;
+#endif
+ Assert(!SH_ENTRY_IS_EMPTY(tb, entry));
*found = false;
return entry;
}
@@ -697,7 +729,7 @@ restart:
if (SH_COMPARE_KEYS(tb, hash, key, entry))
{
- Assert(entry->status == SH_STATUS_IN_USE);
+ Assert(!SH_ENTRY_IS_EMPTY(tb, entry));
*found = true;
return entry;
}
@@ -721,7 +753,7 @@ restart:
emptyelem = SH_NEXT(tb, emptyelem, startelem);
emptyentry = &data[emptyelem];
- if (emptyentry->status == SH_STATUS_EMPTY)
+ if (SH_ENTRY_IS_EMPTY(tb, emptyentry))
{
lastentry = emptyentry;
break;
@@ -770,7 +802,10 @@ restart:
#ifdef SH_STORE_HASH
SH_GET_HASH(tb, entry) = hash;
#endif
+#ifndef SH_IS_EMPTY_KEY
entry->status = SH_STATUS_IN_USE;
+#endif
+ Assert(!SH_ENTRY_IS_EMPTY(tb, entry));
*found = false;
return entry;
}
@@ -833,12 +868,8 @@ SH_LOOKUP_HASH_INTERNAL(SH_TYPE * tb, SH_KEY_TYPE key, uint32 hash)
{
SH_ELEMENT_TYPE *entry = &tb->data[curelem];
- if (entry->status == SH_STATUS_EMPTY)
- {
+ if (SH_ENTRY_IS_EMPTY(tb, entry))
return NULL;
- }
-
- Assert(entry->status == SH_STATUS_IN_USE);
if (SH_COMPARE_KEYS(tb, hash, key, entry))
return entry;
@@ -891,11 +922,10 @@ SH_DELETE(SH_TYPE * tb, SH_KEY_TYPE key)
{
SH_ELEMENT_TYPE *entry = &tb->data[curelem];
- if (entry->status == SH_STATUS_EMPTY)
+ if (SH_ENTRY_IS_EMPTY(tb, entry))
return false;
- if (entry->status == SH_STATUS_IN_USE &&
- SH_COMPARE_KEYS(tb, hash, key, entry))
+ if (SH_COMPARE_KEYS(tb, hash, key, entry))
{
SH_ELEMENT_TYPE *lastentry = entry;
@@ -917,9 +947,9 @@ SH_DELETE(SH_TYPE * tb, SH_KEY_TYPE key)
curelem = SH_NEXT(tb, curelem, startelem);
curentry = &tb->data[curelem];
- if (curentry->status != SH_STATUS_IN_USE)
+ if (SH_ENTRY_IS_EMPTY(tb, curentry))
{
- lastentry->status = SH_STATUS_EMPTY;
+ SH_SET_ENTRY_EMPTY(tb, lastentry);
break;
}
@@ -929,7 +959,7 @@ SH_DELETE(SH_TYPE * tb, SH_KEY_TYPE key)
/* current is at optimal position, done */
if (curoptimal == curelem)
{
- lastentry->status = SH_STATUS_EMPTY;
+ SH_SET_ENTRY_EMPTY(tb, lastentry);
break;
}
@@ -966,7 +996,7 @@ SH_START_ITERATE(SH_TYPE * tb, SH_ITERATOR * iter)
{
SH_ELEMENT_TYPE *entry = &tb->data[i];
- if (entry->status != SH_STATUS_IN_USE)
+ if (SH_ENTRY_IS_EMPTY(tb, entry))
{
startelem = i;
break;
@@ -1027,7 +1057,7 @@ SH_ITERATE(SH_TYPE * tb, SH_ITERATOR * iter)
if ((iter->cur & tb->sizemask) == (iter->end & tb->sizemask))
iter->done = true;
- if (elem->status == SH_STATUS_IN_USE)
+ if (!SH_ENTRY_IS_EMPTY(tb, elem))
{
return elem;
}
@@ -1063,7 +1093,7 @@ SH_STAT(SH_TYPE * tb)
elem = &tb->data[i];
- if (elem->status != SH_STATUS_IN_USE)
+ if (SH_ENTRY_IS_EMPTY(tb, elem))
continue;
hash = SH_ENTRY_HASH(tb, elem);
--
2.30.1
[application/x-patch] v13-0004-Add-buffer-mapping-table-for-SLRUs.patch (8.5K, ../../CA+hUKGKVqrxOp82zER1=XN=yPwV_-OCGAg=ez=1iz9rG+A7Smw@mail.gmail.com/5-v13-0004-Add-buffer-mapping-table-for-SLRUs.patch)
download | inline diff:
From 970504d304af469e494de6ca83123caf1a683ecf Mon Sep 17 00:00:00 2001
From: Thomas Munro <[email protected]>
Date: Thu, 25 Mar 2021 10:11:31 +1300
Subject: [PATCH v13 4/5] Add buffer mapping table for SLRUs.
Instead of doing a linear search for the buffer holding a given page
number, use a hash table.
Discussion: https://postgr.es/m/2BEC2B3F-9B61-4C1D-9FB5-5FAB0F05EF86%40yandex-team.ru
---
src/backend/access/transam/slru.c | 111 +++++++++++++++++++++++++-----
src/include/access/slru.h | 2 +
2 files changed, 96 insertions(+), 17 deletions(-)
diff --git a/src/backend/access/transam/slru.c b/src/backend/access/transam/slru.c
index 82149ad782..f823c2a0c8 100644
--- a/src/backend/access/transam/slru.c
+++ b/src/backend/access/transam/slru.c
@@ -58,6 +58,8 @@
#include "pgstat.h"
#include "storage/fd.h"
#include "storage/shmem.h"
+#include "utils/dynahash.h"
+#include "utils/hsearch.h"
#define SlruFileName(ctl, path, seg) \
snprintf(path, MAXPGPATH, "%s/%04X", (ctl)->Dir, seg)
@@ -79,6 +81,12 @@ typedef struct SlruWriteAllData
typedef struct SlruWriteAllData *SlruWriteAll;
+typedef struct SlruMappingTableEntry
+{
+ int pageno;
+ int slotno;
+} SlruMappingTableEntry;
+
/*
* Populate a file tag describing a segment file. We only use the segment
* number, since we can derive everything else we need by having separate
@@ -146,6 +154,9 @@ static int SlruSelectLRUPage(SlruCtl ctl, int pageno);
static bool SlruScanDirCbDeleteCutoff(SlruCtl ctl, char *filename,
int segpage, void *data);
static void SlruInternalDeleteSegment(SlruCtl ctl, int segno);
+static void SlruMappingAdd(SlruCtl ctl, int pageno, int slotno);
+static void SlruMappingRemove(SlruCtl ctl, int pageno);
+static int SlruMappingFind(SlruCtl ctl, int pageno);
/*
* Initialization of shared memory
@@ -168,7 +179,8 @@ SimpleLruShmemSize(int nslots, int nlsns)
if (nlsns > 0)
sz += MAXALIGN(nslots * nlsns * sizeof(XLogRecPtr)); /* group_lsn[] */
- return BUFFERALIGN(sz) + BLCKSZ * nslots;
+ return BUFFERALIGN(sz) + BLCKSZ * nslots +
+ hash_estimate_size(nslots, sizeof(SlruMappingTableEntry));
}
/*
@@ -187,6 +199,9 @@ SimpleLruInit(SlruCtl ctl, const char *name, int nslots, int nlsns,
LWLock *ctllock, const char *subdir, int tranche_id,
SyncRequestHandler sync_handler)
{
+ char mapping_table_name[SHMEM_INDEX_KEYSIZE];
+ HASHCTL mapping_table_info;
+ HTAB *mapping_table;
SlruShared shared;
bool found;
@@ -258,11 +273,21 @@ SimpleLruInit(SlruCtl ctl, const char *name, int nslots, int nlsns,
else
Assert(found);
+ /* Create or find the buffer mapping table. */
+ memset(&mapping_table_info, 0, sizeof(mapping_table_info));
+ mapping_table_info.keysize = sizeof(int);
+ mapping_table_info.entrysize = sizeof(SlruMappingTableEntry);
+ snprintf(mapping_table_name, sizeof(mapping_table_name),
+ "%s Mapping Table", name);
+ mapping_table = ShmemInitHash(mapping_table_name, nslots, nslots,
+ &mapping_table_info, HASH_ELEM | HASH_BLOBS);
+
/*
* Initialize the unshared control struct, including directory path. We
* assume caller set PagePrecedes.
*/
ctl->shared = shared;
+ ctl->mapping_table = mapping_table;
ctl->sync_handler = sync_handler;
strlcpy(ctl->Dir, subdir, sizeof(ctl->Dir));
}
@@ -289,6 +314,9 @@ SimpleLruZeroPage(SlruCtl ctl, int pageno)
shared->page_number[slotno] == pageno);
/* Mark the slot as containing this page */
+ if (shared->page_status[slotno] != SLRU_PAGE_EMPTY)
+ SlruMappingRemove(ctl, shared->page_number[slotno]);
+ SlruMappingAdd(ctl, pageno, slotno);
shared->page_number[slotno] = pageno;
shared->page_status[slotno] = SLRU_PAGE_VALID;
shared->page_dirty[slotno] = true;
@@ -362,7 +390,10 @@ SimpleLruWaitIO(SlruCtl ctl, int slotno)
{
/* indeed, the I/O must have failed */
if (shared->page_status[slotno] == SLRU_PAGE_READ_IN_PROGRESS)
+ {
+ SlruMappingRemove(ctl, shared->page_number[slotno]);
shared->page_status[slotno] = SLRU_PAGE_EMPTY;
+ }
else /* write_in_progress */
{
shared->page_status[slotno] = SLRU_PAGE_VALID;
@@ -436,6 +467,9 @@ SimpleLruReadPage(SlruCtl ctl, int pageno, bool write_ok,
!shared->page_dirty[slotno]));
/* Mark the slot read-busy */
+ if (shared->page_status[slotno] != SLRU_PAGE_EMPTY)
+ SlruMappingRemove(ctl, shared->page_number[slotno]);
+ SlruMappingAdd(ctl, pageno, slotno);
shared->page_number[slotno] = pageno;
shared->page_status[slotno] = SLRU_PAGE_READ_IN_PROGRESS;
shared->page_dirty[slotno] = false;
@@ -459,7 +493,13 @@ SimpleLruReadPage(SlruCtl ctl, int pageno, bool write_ok,
shared->page_status[slotno] == SLRU_PAGE_READ_IN_PROGRESS &&
!shared->page_dirty[slotno]);
- shared->page_status[slotno] = ok ? SLRU_PAGE_VALID : SLRU_PAGE_EMPTY;
+ if (ok)
+ shared->page_status[slotno] = SLRU_PAGE_VALID;
+ else
+ {
+ SlruMappingRemove(ctl, pageno);
+ shared->page_status[slotno] = SLRU_PAGE_EMPTY;
+ }
LWLockRelease(&shared->buffer_locks[slotno].lock);
@@ -500,20 +540,20 @@ SimpleLruReadPage_ReadOnly(SlruCtl ctl, int pageno, TransactionId xid)
LWLockAcquire(shared->ControlLock, LW_SHARED);
/* See if page is already in a buffer */
- for (slotno = 0; slotno < shared->num_slots; slotno++)
+ slotno = SlruMappingFind(ctl, pageno);
+ if (slotno >= 0 &&
+ shared->page_status[slotno] != SLRU_PAGE_READ_IN_PROGRESS)
{
- if (shared->page_number[slotno] == pageno &&
- shared->page_status[slotno] != SLRU_PAGE_EMPTY &&
- shared->page_status[slotno] != SLRU_PAGE_READ_IN_PROGRESS)
- {
- /* See comments for SlruRecentlyUsed macro */
- SlruRecentlyUsed(shared, slotno);
+ Assert(shared->page_status[slotno] != SLRU_PAGE_EMPTY);
+ Assert(shared->page_number[slotno] == pageno);
- /* update the stats counter of pages found in the SLRU */
- pgstat_count_slru_page_hit(shared->slru_stats_idx);
+ /* See comments for SlruRecentlyUsed macro */
+ SlruRecentlyUsed(shared, slotno);
- return slotno;
- }
+ /* update the stats counter of pages found in the SLRU */
+ pgstat_count_slru_page_hit(shared->slru_stats_idx);
+
+ return slotno;
}
/* No luck, so switch to normal exclusive lock and do regular read */
@@ -1029,11 +1069,12 @@ SlruSelectLRUPage(SlruCtl ctl, int pageno)
int best_invalid_page_number = 0; /* keep compiler quiet */
/* See if page already has a buffer assigned */
- for (slotno = 0; slotno < shared->num_slots; slotno++)
+ slotno = SlruMappingFind(ctl, pageno);
+ if (slotno >= 0)
{
- if (shared->page_number[slotno] == pageno &&
- shared->page_status[slotno] != SLRU_PAGE_EMPTY)
- return slotno;
+ Assert(shared->page_number[slotno] == pageno);
+ Assert(shared->page_status[slotno] != SLRU_PAGE_EMPTY);
+ return slotno;
}
/*
@@ -1266,6 +1307,7 @@ restart:;
if (shared->page_status[slotno] == SLRU_PAGE_VALID &&
!shared->page_dirty[slotno])
{
+ SlruMappingRemove(ctl, shared->page_number[slotno]);
shared->page_status[slotno] = SLRU_PAGE_EMPTY;
continue;
}
@@ -1348,6 +1390,7 @@ restart:
if (shared->page_status[slotno] == SLRU_PAGE_VALID &&
!shared->page_dirty[slotno])
{
+ SlruMappingRemove(ctl, shared->page_number[slotno]);
shared->page_status[slotno] = SLRU_PAGE_EMPTY;
continue;
}
@@ -1609,3 +1652,37 @@ SlruSyncFileTag(SlruCtl ctl, const FileTag *ftag, char *path)
errno = save_errno;
return result;
}
+
+static int
+SlruMappingFind(SlruCtl ctl, int pageno)
+{
+ SlruMappingTableEntry *mapping;
+
+ mapping = hash_search(ctl->mapping_table, &pageno, HASH_FIND, NULL);
+ if (mapping)
+ return mapping->slotno;
+
+ return -1;
+}
+
+static void
+SlruMappingAdd(SlruCtl ctl, int pageno, int slotno)
+{
+ SlruMappingTableEntry *mapping;
+ bool found PG_USED_FOR_ASSERTS_ONLY;
+
+ mapping = hash_search(ctl->mapping_table, &pageno, HASH_ENTER, &found);
+ mapping->slotno = slotno;
+
+ Assert(!found);
+}
+
+static void
+SlruMappingRemove(SlruCtl ctl, int pageno)
+{
+ bool found PG_USED_FOR_ASSERTS_ONLY;
+
+ hash_search(ctl->mapping_table, &pageno, HASH_REMOVE, &found);
+
+ Assert(found);
+}
diff --git a/src/include/access/slru.h b/src/include/access/slru.h
index dd52e8cec7..8aa3efc0ee 100644
--- a/src/include/access/slru.h
+++ b/src/include/access/slru.h
@@ -16,6 +16,7 @@
#include "access/xlogdefs.h"
#include "storage/lwlock.h"
#include "storage/sync.h"
+#include "utils/hsearch.h"
/*
@@ -110,6 +111,7 @@ typedef SlruSharedData *SlruShared;
typedef struct SlruCtlData
{
SlruShared shared;
+ HTAB *mapping_table;
/*
* Which sync handler function to use when handing sync requests over to
--
2.30.1
[application/x-patch] v13-0005-fixup-use-simplehash-instead-of-dynahash.patch (4.6K, ../../CA+hUKGKVqrxOp82zER1=XN=yPwV_-OCGAg=ez=1iz9rG+A7Smw@mail.gmail.com/6-v13-0005-fixup-use-simplehash-instead-of-dynahash.patch)
download | inline diff:
From ef3c1e45a1f869544280f65d1eeba8544b028735 Mon Sep 17 00:00:00 2001
From: Thomas Munro <[email protected]>
Date: Sat, 27 Mar 2021 09:07:22 +1300
Subject: [PATCH v13 5/5] fixup: use simplehash instead of dynahash
---
src/backend/access/transam/slru.c | 41 ++++++++++++++++++++-----------
src/include/access/slru.h | 4 ++-
2 files changed, 30 insertions(+), 15 deletions(-)
diff --git a/src/backend/access/transam/slru.c b/src/backend/access/transam/slru.c
index f823c2a0c8..ba9c0efc81 100644
--- a/src/backend/access/transam/slru.c
+++ b/src/backend/access/transam/slru.c
@@ -54,12 +54,11 @@
#include "access/slru.h"
#include "access/transam.h"
#include "access/xlog.h"
+#include "common/hashfn.h"
#include "miscadmin.h"
#include "pgstat.h"
#include "storage/fd.h"
#include "storage/shmem.h"
-#include "utils/dynahash.h"
-#include "utils/hsearch.h"
#define SlruFileName(ctl, path, seg) \
snprintf(path, MAXPGPATH, "%s/%04X", (ctl)->Dir, seg)
@@ -85,8 +84,24 @@ typedef struct SlruMappingTableEntry
{
int pageno;
int slotno;
+ char status;
} SlruMappingTableEntry;
+/* Instantiate specialized hash table routines. */
+#define SH_PREFIX smte
+#define SH_ELEMENT_TYPE SlruMappingTableEntry
+#define SH_KEY_TYPE int
+#define SH_KEY pageno
+#define SH_HASH_KEY(table, key) murmurhash32(key)
+#define SH_EQUAL(table, a, b) a == b
+#define SH_IS_EMPTY_KEY(table, pageno) pageno == -1
+#define SH_EMPTY_KEY(table) -1
+#define SH_DECLARE
+#define SH_DEFINE
+#define SH_SCOPE static inline
+#define SH_IN_PLACE
+#include "lib/simplehash.h"
+
/*
* Populate a file tag describing a segment file. We only use the segment
* number, since we can derive everything else we need by having separate
@@ -179,8 +194,7 @@ SimpleLruShmemSize(int nslots, int nlsns)
if (nlsns > 0)
sz += MAXALIGN(nslots * nlsns * sizeof(XLogRecPtr)); /* group_lsn[] */
- return BUFFERALIGN(sz) + BLCKSZ * nslots +
- hash_estimate_size(nslots, sizeof(SlruMappingTableEntry));
+ return BUFFERALIGN(sz) + BLCKSZ * nslots + smte_estimate_size(nslots);
}
/*
@@ -200,8 +214,7 @@ SimpleLruInit(SlruCtl ctl, const char *name, int nslots, int nlsns,
SyncRequestHandler sync_handler)
{
char mapping_table_name[SHMEM_INDEX_KEYSIZE];
- HASHCTL mapping_table_info;
- HTAB *mapping_table;
+ smte_hash *mapping_table;
SlruShared shared;
bool found;
@@ -274,13 +287,13 @@ SimpleLruInit(SlruCtl ctl, const char *name, int nslots, int nlsns,
Assert(found);
/* Create or find the buffer mapping table. */
- memset(&mapping_table_info, 0, sizeof(mapping_table_info));
- mapping_table_info.keysize = sizeof(int);
- mapping_table_info.entrysize = sizeof(SlruMappingTableEntry);
snprintf(mapping_table_name, sizeof(mapping_table_name),
"%s Mapping Table", name);
- mapping_table = ShmemInitHash(mapping_table_name, nslots, nslots,
- &mapping_table_info, HASH_ELEM | HASH_BLOBS);
+ mapping_table = ShmemInitStruct(mapping_table_name,
+ smte_estimate_size(nslots),
+ &found);
+ if (!found)
+ smte_create(mapping_table, nslots, NULL);
/*
* Initialize the unshared control struct, including directory path. We
@@ -1658,7 +1671,7 @@ SlruMappingFind(SlruCtl ctl, int pageno)
{
SlruMappingTableEntry *mapping;
- mapping = hash_search(ctl->mapping_table, &pageno, HASH_FIND, NULL);
+ mapping = smte_lookup(ctl->mapping_table, pageno);
if (mapping)
return mapping->slotno;
@@ -1671,7 +1684,7 @@ SlruMappingAdd(SlruCtl ctl, int pageno, int slotno)
SlruMappingTableEntry *mapping;
bool found PG_USED_FOR_ASSERTS_ONLY;
- mapping = hash_search(ctl->mapping_table, &pageno, HASH_ENTER, &found);
+ mapping = smte_insert(ctl->mapping_table, pageno, &found);
mapping->slotno = slotno;
Assert(!found);
@@ -1682,7 +1695,7 @@ SlruMappingRemove(SlruCtl ctl, int pageno)
{
bool found PG_USED_FOR_ASSERTS_ONLY;
- hash_search(ctl->mapping_table, &pageno, HASH_REMOVE, &found);
+ found = smte_delete(ctl->mapping_table, pageno);
Assert(found);
}
diff --git a/src/include/access/slru.h b/src/include/access/slru.h
index 8aa3efc0ee..b3d28ff135 100644
--- a/src/include/access/slru.h
+++ b/src/include/access/slru.h
@@ -104,6 +104,8 @@ typedef struct SlruSharedData
typedef SlruSharedData *SlruShared;
+struct smte_hash;
+
/*
* SlruCtlData is an unshared structure that points to the active information
* in shared memory.
@@ -111,7 +113,7 @@ typedef SlruSharedData *SlruShared;
typedef struct SlruCtlData
{
SlruShared shared;
- HTAB *mapping_table;
+ struct smte_hash *mapping_table;
/*
* Which sync handler function to use when handing sync requests over to
--
2.30.1
^ permalink raw reply [nested|flat] 90+ messages in thread
* Re: MultiXact\SLRU buffers configuration
2020-05-08 16:36 MultiXact\SLRU buffers configuration Andrey M. Borodin <[email protected]>
2020-05-11 11:17 ` Re: MultiXact\SLRU buffers configuration Andrey M. Borodin <[email protected]>
2020-05-13 18:08 ` Re: MultiXact\SLRU buffers configuration Andrey M. Borodin <[email protected]>
2020-05-14 01:25 ` Re: MultiXact\SLRU buffers configuration Kyotaro Horiguchi <[email protected]>
2020-05-14 05:19 ` Re: MultiXact\SLRU buffers configuration Andrey M. Borodin <[email protected]>
2020-05-14 06:16 ` Re: MultiXact\SLRU buffers configuration Kyotaro Horiguchi <[email protected]>
2020-05-14 06:44 ` Re: MultiXact\SLRU buffers configuration Andrey M. Borodin <[email protected]>
2020-05-15 00:03 ` Re: MultiXact\SLRU buffers configuration Kyotaro Horiguchi <[email protected]>
2020-07-02 12:02 ` Re: MultiXact\SLRU buffers configuration Daniel Gustafsson <[email protected]>
2020-07-08 07:03 ` Re: MultiXact\SLRU buffers configuration Andrey M. Borodin <[email protected]>
2020-08-28 18:08 ` Re: MultiXact\SLRU buffers configuration Anastasia Lubennikova <[email protected]>
2020-09-28 14:41 ` Re: MultiXact\SLRU buffers configuration Andrey M. Borodin <[email protected]>
2020-10-26 01:05 ` Re: MultiXact\SLRU buffers configuration Alexander Korotkov <[email protected]>
2020-10-26 15:45 ` Re: MultiXact\SLRU buffers configuration Andrey Borodin <[email protected]>
2020-10-27 17:02 ` Re: MultiXact\SLRU buffers configuration Alexander Korotkov <[email protected]>
2020-10-27 17:23 ` Re: MultiXact\SLRU buffers configuration Alexander Korotkov <[email protected]>
2020-10-28 01:36 ` Re: MultiXact\SLRU buffers configuration Tomas Vondra <[email protected]>
2020-10-28 07:34 ` Re: MultiXact\SLRU buffers configuration Andrey Borodin <[email protected]>
2020-10-28 23:32 ` Re: MultiXact\SLRU buffers configuration Tomas Vondra <[email protected]>
2020-10-29 07:08 ` Re: MultiXact\SLRU buffers configuration Andrey Borodin <[email protected]>
2020-10-29 13:49 ` Re: MultiXact\SLRU buffers configuration Tomas Vondra <[email protected]>
2020-11-02 12:45 ` Re: MultiXact\SLRU buffers configuration Andrey Borodin <[email protected]>
2020-11-10 00:13 ` Re: MultiXact\SLRU buffers configuration Tomas Vondra <[email protected]>
2020-11-10 06:16 ` Re: MultiXact\SLRU buffers configuration Andrey Borodin <[email protected]>
2020-11-10 18:07 ` Re: MultiXact\SLRU buffers configuration Tomas Vondra <[email protected]>
2020-11-13 11:49 ` Re: MultiXact\SLRU buffers configuration Andrey Borodin <[email protected]>
2020-12-08 16:05 ` Re: MultiXact\SLRU buffers configuration Gilles Darold <[email protected]>
2020-12-08 17:52 ` Re: MultiXact\SLRU buffers configuration Andrey Borodin <[email protected]>
2020-12-10 14:45 ` Re: MultiXact\SLRU buffers configuration Gilles Darold <[email protected]>
2020-12-11 17:50 ` Re: MultiXact\SLRU buffers configuration Gilles Darold <[email protected]>
2020-12-13 09:17 ` Re: MultiXact\SLRU buffers configuration Gilles Darold <[email protected]>
2020-12-13 17:24 ` Re: MultiXact\SLRU buffers configuration Andrey Borodin <[email protected]>
2020-12-23 16:31 ` Re: MultiXact\SLRU buffers configuration Gilles Darold <[email protected]>
2021-02-15 17:17 ` Re: MultiXact\SLRU buffers configuration Andrey Borodin <[email protected]>
2021-03-11 15:50 ` Re: MultiXact\SLRU buffers configuration Gilles Darold <[email protected]>
2021-03-12 12:44 ` Re: MultiXact\SLRU buffers configuration Andrey Borodin <[email protected]>
2021-03-24 21:31 ` Re: MultiXact\SLRU buffers configuration Thomas Munro <[email protected]>
2021-03-25 01:03 ` Re: MultiXact\SLRU buffers configuration Thomas Munro <[email protected]>
2021-03-26 03:46 ` Re: MultiXact\SLRU buffers configuration Thomas Munro <[email protected]>
2021-03-26 06:00 ` Re: MultiXact\SLRU buffers configuration Andrey Borodin <[email protected]>
2021-03-26 15:52 ` Re: MultiXact\SLRU buffers configuration Andrey Borodin <[email protected]>
2021-03-26 20:26 ` Re: MultiXact\SLRU buffers configuration Thomas Munro <[email protected]>
@ 2021-03-27 05:31 ` Andrey Borodin <[email protected]>
2021-03-28 21:15 ` Re: MultiXact\SLRU buffers configuration Thomas Munro <[email protected]>
0 siblings, 1 reply; 90+ messages in thread
From: Andrey Borodin @ 2021-03-27 05:31 UTC (permalink / raw)
To: Thomas Munro <[email protected]>; +Cc: Gilles Darold <[email protected]>; Tomas Vondra <[email protected]>; Tomas Vondra <[email protected]>; Alexander Korotkov <[email protected]>; Anastasia Lubennikova <[email protected]>; Daniel Gustafsson <[email protected]>; Kyotaro Horiguchi <[email protected]>; pgsql-hackers
> 27 марта 2021 г., в 01:26, Thomas Munro <[email protected]> написал(а):
>
> On Sat, Mar 27, 2021 at 4:52 AM Andrey Borodin <[email protected]> wrote:
>> Some thoughts on HashTable patch:
>> 1. Can we allocate bigger hashtable to reduce probability of collisions?
>
> Yeah, good idea, might require some study.
In a long run we always have this table filled with nslots. But the keys will be usually consecutive numbers (current working set of CLOG\Multis\etc). So in a happy hashing scenario collisions will only appear for some random backward jumps. I think just size = nslots * 2 will produce results which cannot be improved significantly.
And this reflects original growth strategy SH_GROW(tb, tb->size * 2).
>> 2. Can we use specialised hashtable for this case? I'm afraid hash_search() does comparable number of CPU cycles as simple cycle from 0 to 128. We could inline everything and avoid hashp->hash(keyPtr, hashp->keysize) call. I'm not insisting on special hash though, just an idea.
>
> I tried really hard to not fall into this rabbit h.... [hack hack
> hack], OK, here's a first attempt to use simplehash,
> Andres's
> steampunk macro-based robinhood template
Sounds magnificent.
> that we're already using for
> several other things
I could not find much tests to be sure that we do not break something...
> , and murmurhash which is inlineable and
> branch-free.
I think pageno is a hash already. Why hash any further? And pages accessed together will have smaller access time due to colocation.
> I had to tweak it to support "in-place" creation and
> fixed size (in other words, no allocators, for use in shared memory).
We really need to have a test to know what happens when this structure goes out of memory, as you mentioned below. What would be apropriate place for simplehash tests?
> Then I was annoyed that I had to add a "status" member to our struct,
> so I tried to fix that.
Indeed, sizeof(SlruMappingTableEntry) == 9 seems strange. Will simplehash align it well?
Thanks!
Best regards, Andrey Borodin.
^ permalink raw reply [nested|flat] 90+ messages in thread
* Re: MultiXact\SLRU buffers configuration
2020-05-08 16:36 MultiXact\SLRU buffers configuration Andrey M. Borodin <[email protected]>
2020-05-11 11:17 ` Re: MultiXact\SLRU buffers configuration Andrey M. Borodin <[email protected]>
2020-05-13 18:08 ` Re: MultiXact\SLRU buffers configuration Andrey M. Borodin <[email protected]>
2020-05-14 01:25 ` Re: MultiXact\SLRU buffers configuration Kyotaro Horiguchi <[email protected]>
2020-05-14 05:19 ` Re: MultiXact\SLRU buffers configuration Andrey M. Borodin <[email protected]>
2020-05-14 06:16 ` Re: MultiXact\SLRU buffers configuration Kyotaro Horiguchi <[email protected]>
2020-05-14 06:44 ` Re: MultiXact\SLRU buffers configuration Andrey M. Borodin <[email protected]>
2020-05-15 00:03 ` Re: MultiXact\SLRU buffers configuration Kyotaro Horiguchi <[email protected]>
2020-07-02 12:02 ` Re: MultiXact\SLRU buffers configuration Daniel Gustafsson <[email protected]>
2020-07-08 07:03 ` Re: MultiXact\SLRU buffers configuration Andrey M. Borodin <[email protected]>
2020-08-28 18:08 ` Re: MultiXact\SLRU buffers configuration Anastasia Lubennikova <[email protected]>
2020-09-28 14:41 ` Re: MultiXact\SLRU buffers configuration Andrey M. Borodin <[email protected]>
2020-10-26 01:05 ` Re: MultiXact\SLRU buffers configuration Alexander Korotkov <[email protected]>
2020-10-26 15:45 ` Re: MultiXact\SLRU buffers configuration Andrey Borodin <[email protected]>
2020-10-27 17:02 ` Re: MultiXact\SLRU buffers configuration Alexander Korotkov <[email protected]>
2020-10-27 17:23 ` Re: MultiXact\SLRU buffers configuration Alexander Korotkov <[email protected]>
2020-10-28 01:36 ` Re: MultiXact\SLRU buffers configuration Tomas Vondra <[email protected]>
2020-10-28 07:34 ` Re: MultiXact\SLRU buffers configuration Andrey Borodin <[email protected]>
2020-10-28 23:32 ` Re: MultiXact\SLRU buffers configuration Tomas Vondra <[email protected]>
2020-10-29 07:08 ` Re: MultiXact\SLRU buffers configuration Andrey Borodin <[email protected]>
2020-10-29 13:49 ` Re: MultiXact\SLRU buffers configuration Tomas Vondra <[email protected]>
2020-11-02 12:45 ` Re: MultiXact\SLRU buffers configuration Andrey Borodin <[email protected]>
2020-11-10 00:13 ` Re: MultiXact\SLRU buffers configuration Tomas Vondra <[email protected]>
2020-11-10 06:16 ` Re: MultiXact\SLRU buffers configuration Andrey Borodin <[email protected]>
2020-11-10 18:07 ` Re: MultiXact\SLRU buffers configuration Tomas Vondra <[email protected]>
2020-11-13 11:49 ` Re: MultiXact\SLRU buffers configuration Andrey Borodin <[email protected]>
2020-12-08 16:05 ` Re: MultiXact\SLRU buffers configuration Gilles Darold <[email protected]>
2020-12-08 17:52 ` Re: MultiXact\SLRU buffers configuration Andrey Borodin <[email protected]>
2020-12-10 14:45 ` Re: MultiXact\SLRU buffers configuration Gilles Darold <[email protected]>
2020-12-11 17:50 ` Re: MultiXact\SLRU buffers configuration Gilles Darold <[email protected]>
2020-12-13 09:17 ` Re: MultiXact\SLRU buffers configuration Gilles Darold <[email protected]>
2020-12-13 17:24 ` Re: MultiXact\SLRU buffers configuration Andrey Borodin <[email protected]>
2020-12-23 16:31 ` Re: MultiXact\SLRU buffers configuration Gilles Darold <[email protected]>
2021-02-15 17:17 ` Re: MultiXact\SLRU buffers configuration Andrey Borodin <[email protected]>
2021-03-11 15:50 ` Re: MultiXact\SLRU buffers configuration Gilles Darold <[email protected]>
2021-03-12 12:44 ` Re: MultiXact\SLRU buffers configuration Andrey Borodin <[email protected]>
2021-03-24 21:31 ` Re: MultiXact\SLRU buffers configuration Thomas Munro <[email protected]>
2021-03-25 01:03 ` Re: MultiXact\SLRU buffers configuration Thomas Munro <[email protected]>
2021-03-26 03:46 ` Re: MultiXact\SLRU buffers configuration Thomas Munro <[email protected]>
2021-03-26 06:00 ` Re: MultiXact\SLRU buffers configuration Andrey Borodin <[email protected]>
2021-03-26 15:52 ` Re: MultiXact\SLRU buffers configuration Andrey Borodin <[email protected]>
2021-03-26 20:26 ` Re: MultiXact\SLRU buffers configuration Thomas Munro <[email protected]>
2021-03-27 05:31 ` Re: MultiXact\SLRU buffers configuration Andrey Borodin <[email protected]>
@ 2021-03-28 21:15 ` Thomas Munro <[email protected]>
2021-03-29 08:26 ` Re: MultiXact\SLRU buffers configuration Andrey Borodin <[email protected]>
0 siblings, 1 reply; 90+ messages in thread
From: Thomas Munro @ 2021-03-28 21:15 UTC (permalink / raw)
To: Andrey Borodin <[email protected]>; +Cc: Gilles Darold <[email protected]>; Tomas Vondra <[email protected]>; Tomas Vondra <[email protected]>; Alexander Korotkov <[email protected]>; Anastasia Lubennikova <[email protected]>; Daniel Gustafsson <[email protected]>; Kyotaro Horiguchi <[email protected]>; pgsql-hackers
On Sat, Mar 27, 2021 at 6:31 PM Andrey Borodin <[email protected]> wrote:
> > 27 марта 2021 г., в 01:26, Thomas Munro <[email protected]> написал(а):
> > , and murmurhash which is inlineable and
> > branch-free.
> I think pageno is a hash already. Why hash any further? And pages accessed together will have smaller access time due to colocation.
Yeah, if clog_buffers is large enough then it's already a "perfect
hash", but if it's not then you might get some weird "harmonic"
effects (not sure if that's the right word), basically higher or lower
collision rate depending on coincidences in the data. If you apply a
hash, the collisions should be evenly spread out so at least it'll be
somewhat consistent. Does that make sense?
(At some point I figured out that the syscaches have lower collision
rates and perform better if you use oids directly instead of hashing
them... but then it's easy to create a pathological pattern of DDL
that turns your hash table into a linked list. Not sure what to think
about that.)
> > I had to tweak it to support "in-place" creation and
> > fixed size (in other words, no allocators, for use in shared memory).
> We really need to have a test to know what happens when this structure goes out of memory, as you mentioned below. What would be apropriate place for simplehash tests?
Good questions. This has to be based on being guaranteed to have
enough space for all of the entries, so the question is really just
"how bad can performance get with different load factors". FWIW there
were some interesting cases with clustering when simplehash was first
used in the executor (see commits ab9f2c42 and parent) which required
some work on hashing quality to fix.
> > Then I was annoyed that I had to add a "status" member to our struct,
> > so I tried to fix that.
> Indeed, sizeof(SlruMappingTableEntry) == 9 seems strange. Will simplehash align it well?
With that "intrusive status" patch, the size is back to 8. But I
think I made a mistake: I made it steal some key space to indicate
presence, but I think the presence test should really get access to
the whole entry so that you can encode it in more ways. For example,
with slotno == -1.
Alright, considering the date, if we want to get this into PostgreSQL
14 it's time to make some decisions.
1. Do we want customisable SLRU sizes in PG14?
+1 from me, we have multiple reports of performance gains from
increasing various different SLRUs, and it's easy to find workloads
that go faster.
One thought: it'd be nice if the user could *see* the current size,
when using the default. SHOW clog_buffers -> 0 isn't very helpful if
you want to increase it, but don't know what it's currently set to.
Not sure off the top of my head how best to do that.
2. What names do we want the GUCs to have? Here's what we have:
Proposed GUC Directory System views
clog_buffers pg_xact Xact
multixact_offsets_buffers pg_multixact/offsets MultiXactOffset
multixact_members_buffers pg_multixact/members MultiXactMember
notify_buffers pg_notify Notify
serial_buffers pg_serial Serial
subtrans_buffers pg_subtrans Subtrans
commit_ts_buffers pg_commit_ts CommitTs
By system views, I mean pg_stat_slru, pg_shmem_allocations and
pg_stat_activity (lock names add "SLRU" on the end).
Observations:
It seems obvious that "clog_buffers" should be renamed to "xact_buffers".
It's not clear whether the multixact GUCs should have the extra "s"
like the directories, or not, like the system views.
It see that we have "Shared Buffer Lookup Table" in
pg_shmem_allocations, so where I generated names like "Subtrans
Mapping Table" I should change that to "Lookup" to match.
3. What recommendations should we make about how to set it?
I think the answer depends partially on the next questions! I think
we should probably at least say something short about the pg_stat_slru
view (cache miss rate) and pg_stat_actitity view (waits on locks), and
how to tell if you might need to increase it. I think this probably
needs a new paragraph, separate from the docs for the individual GUC.
4. Do we want to ship the dynahash patch?
+0.9. The slight hesitation is that it's new code written very late
in the cycle, so it may still have bugs or unintended consequences,
and as you said, at small sizes the linear search must be faster than
the hash computation. Could you help test it, and try to break it?
Can we quantify the scaling effect for some interesting workloads, to
see at what size the dynahash beats the linear search, so that we can
make an informed decision? Of course, without a hash table, large
sizes will surely work badly, so it'd be tempting to restrict the size
you can set the GUC to.
If we do include the dynahash patch, then I think it would also be
reasonable to change the formula for the default, to make it higher on
large systems. The restriction to 128 buffers (= 1MB) doesn't make
much sense on a high frequency OLTP system with 128GB of shared
buffers or even 4GB. I think "unleashing better defaults" would
actually be bigger news than the GUC for typical users, because
they'll just see PG14 use a few extra MB and go faster without having
to learn about these obscure new settings.
5. Do we want to ship the simplehash patch?
-0.5. It's a bit too exciting for the last minute, so I'd be inclined
to wait until the next cycle to do some more research and testing. I
know it's a better idea in the long run.
^ permalink raw reply [nested|flat] 90+ messages in thread
* Re: MultiXact\SLRU buffers configuration
2020-05-08 16:36 MultiXact\SLRU buffers configuration Andrey M. Borodin <[email protected]>
2020-05-11 11:17 ` Re: MultiXact\SLRU buffers configuration Andrey M. Borodin <[email protected]>
2020-05-13 18:08 ` Re: MultiXact\SLRU buffers configuration Andrey M. Borodin <[email protected]>
2020-05-14 01:25 ` Re: MultiXact\SLRU buffers configuration Kyotaro Horiguchi <[email protected]>
2020-05-14 05:19 ` Re: MultiXact\SLRU buffers configuration Andrey M. Borodin <[email protected]>
2020-05-14 06:16 ` Re: MultiXact\SLRU buffers configuration Kyotaro Horiguchi <[email protected]>
2020-05-14 06:44 ` Re: MultiXact\SLRU buffers configuration Andrey M. Borodin <[email protected]>
2020-05-15 00:03 ` Re: MultiXact\SLRU buffers configuration Kyotaro Horiguchi <[email protected]>
2020-07-02 12:02 ` Re: MultiXact\SLRU buffers configuration Daniel Gustafsson <[email protected]>
2020-07-08 07:03 ` Re: MultiXact\SLRU buffers configuration Andrey M. Borodin <[email protected]>
2020-08-28 18:08 ` Re: MultiXact\SLRU buffers configuration Anastasia Lubennikova <[email protected]>
2020-09-28 14:41 ` Re: MultiXact\SLRU buffers configuration Andrey M. Borodin <[email protected]>
2020-10-26 01:05 ` Re: MultiXact\SLRU buffers configuration Alexander Korotkov <[email protected]>
2020-10-26 15:45 ` Re: MultiXact\SLRU buffers configuration Andrey Borodin <[email protected]>
2020-10-27 17:02 ` Re: MultiXact\SLRU buffers configuration Alexander Korotkov <[email protected]>
2020-10-27 17:23 ` Re: MultiXact\SLRU buffers configuration Alexander Korotkov <[email protected]>
2020-10-28 01:36 ` Re: MultiXact\SLRU buffers configuration Tomas Vondra <[email protected]>
2020-10-28 07:34 ` Re: MultiXact\SLRU buffers configuration Andrey Borodin <[email protected]>
2020-10-28 23:32 ` Re: MultiXact\SLRU buffers configuration Tomas Vondra <[email protected]>
2020-10-29 07:08 ` Re: MultiXact\SLRU buffers configuration Andrey Borodin <[email protected]>
2020-10-29 13:49 ` Re: MultiXact\SLRU buffers configuration Tomas Vondra <[email protected]>
2020-11-02 12:45 ` Re: MultiXact\SLRU buffers configuration Andrey Borodin <[email protected]>
2020-11-10 00:13 ` Re: MultiXact\SLRU buffers configuration Tomas Vondra <[email protected]>
2020-11-10 06:16 ` Re: MultiXact\SLRU buffers configuration Andrey Borodin <[email protected]>
2020-11-10 18:07 ` Re: MultiXact\SLRU buffers configuration Tomas Vondra <[email protected]>
2020-11-13 11:49 ` Re: MultiXact\SLRU buffers configuration Andrey Borodin <[email protected]>
2020-12-08 16:05 ` Re: MultiXact\SLRU buffers configuration Gilles Darold <[email protected]>
2020-12-08 17:52 ` Re: MultiXact\SLRU buffers configuration Andrey Borodin <[email protected]>
2020-12-10 14:45 ` Re: MultiXact\SLRU buffers configuration Gilles Darold <[email protected]>
2020-12-11 17:50 ` Re: MultiXact\SLRU buffers configuration Gilles Darold <[email protected]>
2020-12-13 09:17 ` Re: MultiXact\SLRU buffers configuration Gilles Darold <[email protected]>
2020-12-13 17:24 ` Re: MultiXact\SLRU buffers configuration Andrey Borodin <[email protected]>
2020-12-23 16:31 ` Re: MultiXact\SLRU buffers configuration Gilles Darold <[email protected]>
2021-02-15 17:17 ` Re: MultiXact\SLRU buffers configuration Andrey Borodin <[email protected]>
2021-03-11 15:50 ` Re: MultiXact\SLRU buffers configuration Gilles Darold <[email protected]>
2021-03-12 12:44 ` Re: MultiXact\SLRU buffers configuration Andrey Borodin <[email protected]>
2021-03-24 21:31 ` Re: MultiXact\SLRU buffers configuration Thomas Munro <[email protected]>
2021-03-25 01:03 ` Re: MultiXact\SLRU buffers configuration Thomas Munro <[email protected]>
2021-03-26 03:46 ` Re: MultiXact\SLRU buffers configuration Thomas Munro <[email protected]>
2021-03-26 06:00 ` Re: MultiXact\SLRU buffers configuration Andrey Borodin <[email protected]>
2021-03-26 15:52 ` Re: MultiXact\SLRU buffers configuration Andrey Borodin <[email protected]>
2021-03-26 20:26 ` Re: MultiXact\SLRU buffers configuration Thomas Munro <[email protected]>
2021-03-27 05:31 ` Re: MultiXact\SLRU buffers configuration Andrey Borodin <[email protected]>
2021-03-28 21:15 ` Re: MultiXact\SLRU buffers configuration Thomas Munro <[email protected]>
@ 2021-03-29 08:26 ` Andrey Borodin <[email protected]>
2021-03-31 21:09 ` Re: MultiXact\SLRU buffers configuration Andrey Borodin <[email protected]>
0 siblings, 1 reply; 90+ messages in thread
From: Andrey Borodin @ 2021-03-29 08:26 UTC (permalink / raw)
To: Thomas Munro <[email protected]>; +Cc: Gilles Darold <[email protected]>; Tomas Vondra <[email protected]>; Tomas Vondra <[email protected]>; Alexander Korotkov <[email protected]>; Anastasia Lubennikova <[email protected]>; Daniel Gustafsson <[email protected]>; Kyotaro Horiguchi <[email protected]>; pgsql-hackers
> 29 марта 2021 г., в 02:15, Thomas Munro <[email protected]> написал(а):
>
> On Sat, Mar 27, 2021 at 6:31 PM Andrey Borodin <[email protected]> wrote:
>>> 27 марта 2021 г., в 01:26, Thomas Munro <[email protected]> написал(а):
>>> , and murmurhash which is inlineable and
>>> branch-free.
>
>> I think pageno is a hash already. Why hash any further? And pages accessed together will have smaller access time due to colocation.
>
> Yeah, if clog_buffers is large enough then it's already a "perfect
> hash", but if it's not then you might get some weird "harmonic"
> effects (not sure if that's the right word), basically higher or lower
> collision rate depending on coincidences in the data. If you apply a
> hash, the collisions should be evenly spread out so at least it'll be
> somewhat consistent. Does that make sense?
As far as I understand "Harmonic" effects only make sense if the distribution is unknown. Hash protects from "periodic" data when periods are equal to hash table size. I don't think we need to protect from this case, SLRU data is expected to be localised...
Cost of this protection is necessity to calculate murmur hash on each SLRU lookup. Probably, 10-100ns. Seems like not a big deal.
> (At some point I figured out that the syscaches have lower collision
> rates and perform better if you use oids directly instead of hashing
> them... but then it's easy to create a pathological pattern of DDL
> that turns your hash table into a linked list. Not sure what to think
> about that.)
>
>>> I had to tweak it to support "in-place" creation and
>>> fixed size (in other words, no allocators, for use in shared memory).
>
>> We really need to have a test to know what happens when this structure goes out of memory, as you mentioned below. What would be apropriate place for simplehash tests?
>
> Good questions. This has to be based on being guaranteed to have
> enough space for all of the entries, so the question is really just
> "how bad can performance get with different load factors". FWIW there
> were some interesting cases with clustering when simplehash was first
> used in the executor (see commits ab9f2c42 and parent) which required
> some work on hashing quality to fix.
Interesting read, I didn't know much about simple hash, but seems like there is still many cases where it can be used for good. I always wondered why Postgres uses only Larson's linear hash.
>
>>> Then I was annoyed that I had to add a "status" member to our struct,
>>> so I tried to fix that.
>
>> Indeed, sizeof(SlruMappingTableEntry) == 9 seems strange. Will simplehash align it well?
>
> With that "intrusive status" patch, the size is back to 8. But I
> think I made a mistake: I made it steal some key space to indicate
> presence, but I think the presence test should really get access to
> the whole entry so that you can encode it in more ways. For example,
> with slotno == -1.
>
> Alright, considering the date, if we want to get this into PostgreSQL
> 14 it's time to make some decisions.
>
> 1. Do we want customisable SLRU sizes in PG14?
>
> +1 from me, we have multiple reports of performance gains from
> increasing various different SLRUs, and it's easy to find workloads
> that go faster.
Yes, this is main point of this discussion. So +1 from me too.
>
> One thought: it'd be nice if the user could *see* the current size,
> when using the default. SHOW clog_buffers -> 0 isn't very helpful if
> you want to increase it, but don't know what it's currently set to.
> Not sure off the top of my head how best to do that.
Don't we expect that SHOW command indicate exactly same value as in config or SET command? If this convention does not exist - probably showing effective value is a good idea.
> 2. What names do we want the GUCs to have? Here's what we have:
>
> Proposed GUC Directory System views
> clog_buffers pg_xact Xact
> multixact_offsets_buffers pg_multixact/offsets MultiXactOffset
> multixact_members_buffers pg_multixact/members MultiXactMember
> notify_buffers pg_notify Notify
> serial_buffers pg_serial Serial
> subtrans_buffers pg_subtrans Subtrans
> commit_ts_buffers pg_commit_ts CommitTs
>
> By system views, I mean pg_stat_slru, pg_shmem_allocations and
> pg_stat_activity (lock names add "SLRU" on the end).
>
> Observations:
>
> It seems obvious that "clog_buffers" should be renamed to "xact_buffers".
+1
> It's not clear whether the multixact GUCs should have the extra "s"
> like the directories, or not, like the system views.
I think we show break the ties by native English speaker's ears or typing habits. I'm not a native speaker.
> It see that we have "Shared Buffer Lookup Table" in
> pg_shmem_allocations, so where I generated names like "Subtrans
> Mapping Table" I should change that to "Lookup" to match.
>
> 3. What recommendations should we make about how to set it?
>
> I think the answer depends partially on the next questions! I think
> we should probably at least say something short about the pg_stat_slru
> view (cache miss rate) and pg_stat_actitity view (waits on locks), and
> how to tell if you might need to increase it. I think this probably
> needs a new paragraph, separate from the docs for the individual GUC.
I can only suggest incident-driven approach.
1. Observe ridiculous amount of backends waiting on particular SLRU.
2. Double SLRU buffers for that SLRU.
3. Goto 1.
I don't think we should mention this approach in docs.
> 4. Do we want to ship the dynahash patch?
This patch allows to throw infinite amount of memory on a problem of SLRU waiting for IO. So the scale of improvement is much higher. Do I want that we ship this patch? Definitely. Does this change much? I don't know.
>
> +0.9. The slight hesitation is that it's new code written very late
> in the cycle, so it may still have bugs or unintended consequences,
> and as you said, at small sizes the linear search must be faster than
> the hash computation. Could you help test it, and try to break it?
I'll test it and try to break.
> Can we quantify the scaling effect for some interesting workloads, to
> see at what size the dynahash beats the linear search, so that we can
> make an informed decision?
I think we cannot statistically distinguish linear search from hash search by means of SLRU. But we can create some synthetic benchmarks.
> Of course, without a hash table, large
> sizes will surely work badly, so it'd be tempting to restrict the size
> you can set the GUC to.
>
> If we do include the dynahash patch, then I think it would also be
> reasonable to change the formula for the default, to make it higher on
> large systems. The restriction to 128 buffers (= 1MB) doesn't make
> much sense on a high frequency OLTP system with 128GB of shared
> buffers or even 4GB. I think "unleashing better defaults" would
> actually be bigger news than the GUC for typical users, because
> they'll just see PG14 use a few extra MB and go faster without having
> to learn about these obscure new settings.
I agree. I don't see why we would need to limit buffers to 128 in presence of hash search.
> 5. Do we want to ship the simplehash patch?
>
> -0.5. It's a bit too exciting for the last minute, so I'd be inclined
> to wait until the next cycle to do some more research and testing. I
> know it's a better idea in the long run.
OK, obviously, it's safer decision.
My TODO list:
1. Try to break patch set v13-[0001-0004]
2. Think how to measure performance of linear search versus hash search in SLRU buffer mapping.
Thanks!
Best regards, Andrey Borodin.
^ permalink raw reply [nested|flat] 90+ messages in thread
* Re: MultiXact\SLRU buffers configuration
2020-05-08 16:36 MultiXact\SLRU buffers configuration Andrey M. Borodin <[email protected]>
2020-05-11 11:17 ` Re: MultiXact\SLRU buffers configuration Andrey M. Borodin <[email protected]>
2020-05-13 18:08 ` Re: MultiXact\SLRU buffers configuration Andrey M. Borodin <[email protected]>
2020-05-14 01:25 ` Re: MultiXact\SLRU buffers configuration Kyotaro Horiguchi <[email protected]>
2020-05-14 05:19 ` Re: MultiXact\SLRU buffers configuration Andrey M. Borodin <[email protected]>
2020-05-14 06:16 ` Re: MultiXact\SLRU buffers configuration Kyotaro Horiguchi <[email protected]>
2020-05-14 06:44 ` Re: MultiXact\SLRU buffers configuration Andrey M. Borodin <[email protected]>
2020-05-15 00:03 ` Re: MultiXact\SLRU buffers configuration Kyotaro Horiguchi <[email protected]>
2020-07-02 12:02 ` Re: MultiXact\SLRU buffers configuration Daniel Gustafsson <[email protected]>
2020-07-08 07:03 ` Re: MultiXact\SLRU buffers configuration Andrey M. Borodin <[email protected]>
2020-08-28 18:08 ` Re: MultiXact\SLRU buffers configuration Anastasia Lubennikova <[email protected]>
2020-09-28 14:41 ` Re: MultiXact\SLRU buffers configuration Andrey M. Borodin <[email protected]>
2020-10-26 01:05 ` Re: MultiXact\SLRU buffers configuration Alexander Korotkov <[email protected]>
2020-10-26 15:45 ` Re: MultiXact\SLRU buffers configuration Andrey Borodin <[email protected]>
2020-10-27 17:02 ` Re: MultiXact\SLRU buffers configuration Alexander Korotkov <[email protected]>
2020-10-27 17:23 ` Re: MultiXact\SLRU buffers configuration Alexander Korotkov <[email protected]>
2020-10-28 01:36 ` Re: MultiXact\SLRU buffers configuration Tomas Vondra <[email protected]>
2020-10-28 07:34 ` Re: MultiXact\SLRU buffers configuration Andrey Borodin <[email protected]>
2020-10-28 23:32 ` Re: MultiXact\SLRU buffers configuration Tomas Vondra <[email protected]>
2020-10-29 07:08 ` Re: MultiXact\SLRU buffers configuration Andrey Borodin <[email protected]>
2020-10-29 13:49 ` Re: MultiXact\SLRU buffers configuration Tomas Vondra <[email protected]>
2020-11-02 12:45 ` Re: MultiXact\SLRU buffers configuration Andrey Borodin <[email protected]>
2020-11-10 00:13 ` Re: MultiXact\SLRU buffers configuration Tomas Vondra <[email protected]>
2020-11-10 06:16 ` Re: MultiXact\SLRU buffers configuration Andrey Borodin <[email protected]>
2020-11-10 18:07 ` Re: MultiXact\SLRU buffers configuration Tomas Vondra <[email protected]>
2020-11-13 11:49 ` Re: MultiXact\SLRU buffers configuration Andrey Borodin <[email protected]>
2020-12-08 16:05 ` Re: MultiXact\SLRU buffers configuration Gilles Darold <[email protected]>
2020-12-08 17:52 ` Re: MultiXact\SLRU buffers configuration Andrey Borodin <[email protected]>
2020-12-10 14:45 ` Re: MultiXact\SLRU buffers configuration Gilles Darold <[email protected]>
2020-12-11 17:50 ` Re: MultiXact\SLRU buffers configuration Gilles Darold <[email protected]>
2020-12-13 09:17 ` Re: MultiXact\SLRU buffers configuration Gilles Darold <[email protected]>
2020-12-13 17:24 ` Re: MultiXact\SLRU buffers configuration Andrey Borodin <[email protected]>
2020-12-23 16:31 ` Re: MultiXact\SLRU buffers configuration Gilles Darold <[email protected]>
2021-02-15 17:17 ` Re: MultiXact\SLRU buffers configuration Andrey Borodin <[email protected]>
2021-03-11 15:50 ` Re: MultiXact\SLRU buffers configuration Gilles Darold <[email protected]>
2021-03-12 12:44 ` Re: MultiXact\SLRU buffers configuration Andrey Borodin <[email protected]>
2021-03-24 21:31 ` Re: MultiXact\SLRU buffers configuration Thomas Munro <[email protected]>
2021-03-25 01:03 ` Re: MultiXact\SLRU buffers configuration Thomas Munro <[email protected]>
2021-03-26 03:46 ` Re: MultiXact\SLRU buffers configuration Thomas Munro <[email protected]>
2021-03-26 06:00 ` Re: MultiXact\SLRU buffers configuration Andrey Borodin <[email protected]>
2021-03-26 15:52 ` Re: MultiXact\SLRU buffers configuration Andrey Borodin <[email protected]>
2021-03-26 20:26 ` Re: MultiXact\SLRU buffers configuration Thomas Munro <[email protected]>
2021-03-27 05:31 ` Re: MultiXact\SLRU buffers configuration Andrey Borodin <[email protected]>
2021-03-28 21:15 ` Re: MultiXact\SLRU buffers configuration Thomas Munro <[email protected]>
2021-03-29 08:26 ` Re: MultiXact\SLRU buffers configuration Andrey Borodin <[email protected]>
@ 2021-03-31 21:09 ` Andrey Borodin <[email protected]>
2021-04-01 03:40 ` Re: MultiXact\SLRU buffers configuration Thomas Munro <[email protected]>
0 siblings, 1 reply; 90+ messages in thread
From: Andrey Borodin @ 2021-03-31 21:09 UTC (permalink / raw)
To: Thomas Munro <[email protected]>; +Cc: Gilles Darold <[email protected]>; Tomas Vondra <[email protected]>; Tomas Vondra <[email protected]>; Alexander Korotkov <[email protected]>; Anastasia Lubennikova <[email protected]>; Daniel Gustafsson <[email protected]>; Kyotaro Horiguchi <[email protected]>; pgsql-hackers
> 29 марта 2021 г., в 11:26, Andrey Borodin <[email protected]> написал(а):
>
> My TODO list:
> 1. Try to break patch set v13-[0001-0004]
> 2. Think how to measure performance of linear search versus hash search in SLRU buffer mapping.
Hi Thomas!
I'm still doing my homework. And to this moment all my catch is that "utils/dynahash.h" is not necessary.
I'm thinking about hashtables and measuring performance near optimum of linear search does not seem a good idea now.
It's impossible to prove that difference is statistically significant on all platforms. But even on one platform measurements are just too noisy.
Shared buffers lookup table is indeed very similar to this SLRU lookup table. And it does not try to use more memory than needed. I could not find pgbench-visible impact of growing shared buffer lookup table. Obviously, because it's not a bottleneck on regular workload. And it's hard to guess representative pathological workload.
In fact, this thread started with proposal to use reader-writer lock for multis (instead of exclusive lock), and this proposal encountered same problem. It's very hard to create stable reproduction of pathological workload when this lock is heavily contented. Many people observed the problem, but still there is no open repro.
I bet it will be hard to prove that simplehash is any better then HTAB. But if it is really better, shared buffers could benefit from the same technique.
I think its just fine to use HTAB with normal size, as long as shared buffers do so. But there we allocate slightly more space InitBufTable(NBuffers + NUM_BUFFER_PARTITIONS). Don't we need to allocate nslots + 1 ? It seems that we always do SlruMappingRemove() before SlruMappingAdd() and it is not necessary.
Thanks!
Best regards, Andrey Borodin.
^ permalink raw reply [nested|flat] 90+ messages in thread
* Re: MultiXact\SLRU buffers configuration
2020-05-08 16:36 MultiXact\SLRU buffers configuration Andrey M. Borodin <[email protected]>
2020-05-11 11:17 ` Re: MultiXact\SLRU buffers configuration Andrey M. Borodin <[email protected]>
2020-05-13 18:08 ` Re: MultiXact\SLRU buffers configuration Andrey M. Borodin <[email protected]>
2020-05-14 01:25 ` Re: MultiXact\SLRU buffers configuration Kyotaro Horiguchi <[email protected]>
2020-05-14 05:19 ` Re: MultiXact\SLRU buffers configuration Andrey M. Borodin <[email protected]>
2020-05-14 06:16 ` Re: MultiXact\SLRU buffers configuration Kyotaro Horiguchi <[email protected]>
2020-05-14 06:44 ` Re: MultiXact\SLRU buffers configuration Andrey M. Borodin <[email protected]>
2020-05-15 00:03 ` Re: MultiXact\SLRU buffers configuration Kyotaro Horiguchi <[email protected]>
2020-07-02 12:02 ` Re: MultiXact\SLRU buffers configuration Daniel Gustafsson <[email protected]>
2020-07-08 07:03 ` Re: MultiXact\SLRU buffers configuration Andrey M. Borodin <[email protected]>
2020-08-28 18:08 ` Re: MultiXact\SLRU buffers configuration Anastasia Lubennikova <[email protected]>
2020-09-28 14:41 ` Re: MultiXact\SLRU buffers configuration Andrey M. Borodin <[email protected]>
2020-10-26 01:05 ` Re: MultiXact\SLRU buffers configuration Alexander Korotkov <[email protected]>
2020-10-26 15:45 ` Re: MultiXact\SLRU buffers configuration Andrey Borodin <[email protected]>
2020-10-27 17:02 ` Re: MultiXact\SLRU buffers configuration Alexander Korotkov <[email protected]>
2020-10-27 17:23 ` Re: MultiXact\SLRU buffers configuration Alexander Korotkov <[email protected]>
2020-10-28 01:36 ` Re: MultiXact\SLRU buffers configuration Tomas Vondra <[email protected]>
2020-10-28 07:34 ` Re: MultiXact\SLRU buffers configuration Andrey Borodin <[email protected]>
2020-10-28 23:32 ` Re: MultiXact\SLRU buffers configuration Tomas Vondra <[email protected]>
2020-10-29 07:08 ` Re: MultiXact\SLRU buffers configuration Andrey Borodin <[email protected]>
2020-10-29 13:49 ` Re: MultiXact\SLRU buffers configuration Tomas Vondra <[email protected]>
2020-11-02 12:45 ` Re: MultiXact\SLRU buffers configuration Andrey Borodin <[email protected]>
2020-11-10 00:13 ` Re: MultiXact\SLRU buffers configuration Tomas Vondra <[email protected]>
2020-11-10 06:16 ` Re: MultiXact\SLRU buffers configuration Andrey Borodin <[email protected]>
2020-11-10 18:07 ` Re: MultiXact\SLRU buffers configuration Tomas Vondra <[email protected]>
2020-11-13 11:49 ` Re: MultiXact\SLRU buffers configuration Andrey Borodin <[email protected]>
2020-12-08 16:05 ` Re: MultiXact\SLRU buffers configuration Gilles Darold <[email protected]>
2020-12-08 17:52 ` Re: MultiXact\SLRU buffers configuration Andrey Borodin <[email protected]>
2020-12-10 14:45 ` Re: MultiXact\SLRU buffers configuration Gilles Darold <[email protected]>
2020-12-11 17:50 ` Re: MultiXact\SLRU buffers configuration Gilles Darold <[email protected]>
2020-12-13 09:17 ` Re: MultiXact\SLRU buffers configuration Gilles Darold <[email protected]>
2020-12-13 17:24 ` Re: MultiXact\SLRU buffers configuration Andrey Borodin <[email protected]>
2020-12-23 16:31 ` Re: MultiXact\SLRU buffers configuration Gilles Darold <[email protected]>
2021-02-15 17:17 ` Re: MultiXact\SLRU buffers configuration Andrey Borodin <[email protected]>
2021-03-11 15:50 ` Re: MultiXact\SLRU buffers configuration Gilles Darold <[email protected]>
2021-03-12 12:44 ` Re: MultiXact\SLRU buffers configuration Andrey Borodin <[email protected]>
2021-03-24 21:31 ` Re: MultiXact\SLRU buffers configuration Thomas Munro <[email protected]>
2021-03-25 01:03 ` Re: MultiXact\SLRU buffers configuration Thomas Munro <[email protected]>
2021-03-26 03:46 ` Re: MultiXact\SLRU buffers configuration Thomas Munro <[email protected]>
2021-03-26 06:00 ` Re: MultiXact\SLRU buffers configuration Andrey Borodin <[email protected]>
2021-03-26 15:52 ` Re: MultiXact\SLRU buffers configuration Andrey Borodin <[email protected]>
2021-03-26 20:26 ` Re: MultiXact\SLRU buffers configuration Thomas Munro <[email protected]>
2021-03-27 05:31 ` Re: MultiXact\SLRU buffers configuration Andrey Borodin <[email protected]>
2021-03-28 21:15 ` Re: MultiXact\SLRU buffers configuration Thomas Munro <[email protected]>
2021-03-29 08:26 ` Re: MultiXact\SLRU buffers configuration Andrey Borodin <[email protected]>
2021-03-31 21:09 ` Re: MultiXact\SLRU buffers configuration Andrey Borodin <[email protected]>
@ 2021-04-01 03:40 ` Thomas Munro <[email protected]>
2021-04-03 19:57 ` Re: MultiXact\SLRU buffers configuration Andrey Borodin <[email protected]>
0 siblings, 1 reply; 90+ messages in thread
From: Thomas Munro @ 2021-04-01 03:40 UTC (permalink / raw)
To: Andrey Borodin <[email protected]>; +Cc: Gilles Darold <[email protected]>; Tomas Vondra <[email protected]>; Tomas Vondra <[email protected]>; Alexander Korotkov <[email protected]>; Anastasia Lubennikova <[email protected]>; Daniel Gustafsson <[email protected]>; Kyotaro Horiguchi <[email protected]>; pgsql-hackers
On Thu, Apr 1, 2021 at 10:09 AM Andrey Borodin <[email protected]> wrote:
> > 29 марта 2021 г., в 11:26, Andrey Borodin <[email protected]> написал(а):
> > My TODO list:
> > 1. Try to break patch set v13-[0001-0004]
> > 2. Think how to measure performance of linear search versus hash search in SLRU buffer mapping.
>
> Hi Thomas!
> I'm still doing my homework. And to this moment all my catch is that "utils/dynahash.h" is not necessary.
Thanks. Here's a new patch with that fixed, and also:
1. New names ("... Mapping Table" -> "... Lookup Table" in
pg_shmem_allocations view, "clog_buffers" -> "xact_buffers") and a
couple of typos fixed here and there.
2. Remove the cap of 128 buffers for xact_buffers as agreed. We
still need a cap though, to avoid a couple of kinds of overflow inside
slru.c, both when computing the default value and accepting a
user-provided number. I introduced SLRU_MAX_ALLOWED_BUFFERS to keep
it <= 1GB, and tested this on a 32 bit build with extreme block sizes.
Likewise, I removed the cap of 16 buffers for commit_ts_buffers, but
only if you have track_commit_timestamp enabled. It seems silly to
waste 1MB per 1GB of shared_buffers on a feature you're not using. So
the default is capped at 16 in that case to preserve existing
behaviour, but otherwise can be set very large if you want.
I think it's plausible that we'll want to make the multixact sizes
adaptive too, but I that might have to be a job for later. Likewise,
I am sure that substransaction-heavy workloads might be slower than
they need to be due to the current default, but I have not done the
research, With these new GUCs, people are free to experiment and
develop theories about what the defaults should be in v15.
3. In the special case of xact_buffers, there is a lower cap of
512MB, because there's no point trying to cache more xids than there
can be in existence, and that is computed by working backwards from
CLOG_XACTS_PER_PAGE etc. It's not possible to do the same sort of
thing for the other SLRUs without overflow problems, and it doesn't
seem worth trying to fix that right now (1GB of cached commit
timestamps ought to be enough for anyone™, while the theoretical
maximum is 10 bytes for 2b xids = 20GB).
To make this more explicit for people not following our discussion in
detail: with shared_buffers=0...512MB, the behaviour doesn't change.
But for shared_buffers=1GB you'll get twice as many xact_buffers as
today (2MB instead of being capped at 1MB), and it keeps scaling
linearly from there at 0.2%. In other words, all real world databases
will get a boost in this department.
4. Change the default for commit_ts_buffers back to shared_buffers /
1024 (with a minimum of 4), because I think you might have changed it
by a copy and paste error -- or did you intend to make the default
higher?
5. Improve descriptions for the GUCs, visible in pg_settings view, to
match the documentation for related wait events. So "for commit log
SLRU" -> "for the transaction status SLRU cache", and similar
corrections elsewhere. (I am tempted to try to find a better word
than "SLRU", which doesn't seem relevant to users, but for now
consistency is good.)
6. Added a callback so that SHOW xact_buffers and SHOW
commit_ts_buffers display the real size in effect (instead of "0" for
default).
I tried running with xact_buffers=1 and soon saw why you change it to
interpret 1 the same as 0; with 1 you hit buffer starvation and get
stuck. I wish there were some way to say "the default for this GUC is
0, but if it's not zero then it's got to be at least 4". I didn't
study the theoretical basis for the previous minimum value of 4, so I
think we should keep it that way, so that if you say 3 you get 4. I
thought it was better to express that like so:
/* Use configured value if provided. */
if (xact_buffers > 0)
return Max(4, xact_buffers);
return Min(CLOG_MAX_ALLOWED_BUFFERS, Max(4, NBuffers / 512));
> I'm thinking about hashtables and measuring performance near optimum of linear search does not seem a good idea now.
> It's impossible to prove that difference is statistically significant on all platforms. But even on one platform measurements are just too noisy.
>
> Shared buffers lookup table is indeed very similar to this SLRU lookup table. And it does not try to use more memory than needed. I could not find pgbench-visible impact of growing shared buffer lookup table. Obviously, because it's not a bottleneck on regular workload. And it's hard to guess representative pathological workload.
Thanks for testing. I agree that it's a good idea to follow the main
buffer pool's approach for our first version of this. One small
difference is that the SLRU patch performs the hash computation while
it holds the lock. If we computed the hash first and used
hash_search_with_hash_value(), we could compute it before we obtain
the lock, like the main buffer pool.
If we computed the hash value first, we could also ignore the rule in
the documentation for hash_search_with_hash_value() that says that you
must calculate it with get_hash_value(), and just call the hash
function ourselves, so that it's fully inlinable. The same
opportunity exists for the main buffer pool. That'd get you one of
the micro-optimisations that simplehash.h offers. Whether it's worth
bothering with, I don't know.
> In fact, this thread started with proposal to use reader-writer lock for multis (instead of exclusive lock), and this proposal encountered same problem. It's very hard to create stable reproduction of pathological workload when this lock is heavily contented. Many people observed the problem, but still there is no open repro.
>
> I bet it will be hard to prove that simplehash is any better then HTAB. But if it is really better, shared buffers could benefit from the same technique.
Agreed, there are a lot of interesting future projects in this area,
when you compare the main buffer pool, these special buffer pools, and
maybe also the "shared relfilenode" pool patch I have proposed for v15
(CF entry 2933). All have mapping tables and buffer replacement
algorithms (why should they be different?), one has partitions, some
have atomic-based header locks, they interlock with WAL differently
(on page LSN, FPIs and checksum support), ... etc etc.
> I think its just fine to use HTAB with normal size, as long as shared buffers do so. But there we allocate slightly more space InitBufTable(NBuffers + NUM_BUFFER_PARTITIONS). Don't we need to allocate nslots + 1 ? It seems that we always do SlruMappingRemove() before SlruMappingAdd() and it is not necessary.
Yeah, we never try to add more elements than allowed, because we have
a big lock around the mapping. The main buffer mapping table has a
more concurrent design and might temporarily have one extra entry per
partition.
Attachments:
[text/x-patch] v14-0001-Add-a-buffer-mapping-table-for-SLRUs.patch (8.6K, ../../CA+hUKGKEdeVKpOqBxzRF+Z4=j0T+CA7ERrXni5De71Mm6-dBWA@mail.gmail.com/2-v14-0001-Add-a-buffer-mapping-table-for-SLRUs.patch)
download | inline diff:
From 05ce938fef85a5f23407d6977165319650b05d63 Mon Sep 17 00:00:00 2001
From: Thomas Munro <[email protected]>
Date: Thu, 25 Mar 2021 10:11:31 +1300
Subject: [PATCH v14 1/2] Add a buffer mapping table for SLRUs.
Instead of doing a linear search for the buffer holding a given page
number, use a hash table. This will allow us to increase the size of
these caches.
Reviewed-by: Andrey M. Borodin <[email protected]>
Discussion: https://postgr.es/m/2BEC2B3F-9B61-4C1D-9FB5-5FAB0F05EF86%40yandex-team.ru
---
src/backend/access/transam/slru.c | 110 +++++++++++++++++++++++++-----
src/include/access/slru.h | 2 +
2 files changed, 95 insertions(+), 17 deletions(-)
diff --git a/src/backend/access/transam/slru.c b/src/backend/access/transam/slru.c
index 82149ad782..a88e7a38a3 100644
--- a/src/backend/access/transam/slru.c
+++ b/src/backend/access/transam/slru.c
@@ -58,6 +58,7 @@
#include "pgstat.h"
#include "storage/fd.h"
#include "storage/shmem.h"
+#include "utils/hsearch.h"
#define SlruFileName(ctl, path, seg) \
snprintf(path, MAXPGPATH, "%s/%04X", (ctl)->Dir, seg)
@@ -79,6 +80,12 @@ typedef struct SlruWriteAllData
typedef struct SlruWriteAllData *SlruWriteAll;
+typedef struct SlruMappingTableEntry
+{
+ int pageno;
+ int slotno;
+} SlruMappingTableEntry;
+
/*
* Populate a file tag describing a segment file. We only use the segment
* number, since we can derive everything else we need by having separate
@@ -146,6 +153,9 @@ static int SlruSelectLRUPage(SlruCtl ctl, int pageno);
static bool SlruScanDirCbDeleteCutoff(SlruCtl ctl, char *filename,
int segpage, void *data);
static void SlruInternalDeleteSegment(SlruCtl ctl, int segno);
+static void SlruMappingAdd(SlruCtl ctl, int pageno, int slotno);
+static void SlruMappingRemove(SlruCtl ctl, int pageno);
+static int SlruMappingFind(SlruCtl ctl, int pageno);
/*
* Initialization of shared memory
@@ -168,7 +178,8 @@ SimpleLruShmemSize(int nslots, int nlsns)
if (nlsns > 0)
sz += MAXALIGN(nslots * nlsns * sizeof(XLogRecPtr)); /* group_lsn[] */
- return BUFFERALIGN(sz) + BLCKSZ * nslots;
+ return BUFFERALIGN(sz) + BLCKSZ * nslots +
+ hash_estimate_size(nslots, sizeof(SlruMappingTableEntry));
}
/*
@@ -187,6 +198,9 @@ SimpleLruInit(SlruCtl ctl, const char *name, int nslots, int nlsns,
LWLock *ctllock, const char *subdir, int tranche_id,
SyncRequestHandler sync_handler)
{
+ char mapping_table_name[SHMEM_INDEX_KEYSIZE];
+ HASHCTL mapping_table_info;
+ HTAB *mapping_table;
SlruShared shared;
bool found;
@@ -258,11 +272,21 @@ SimpleLruInit(SlruCtl ctl, const char *name, int nslots, int nlsns,
else
Assert(found);
+ /* Create or find the buffer mapping table. */
+ memset(&mapping_table_info, 0, sizeof(mapping_table_info));
+ mapping_table_info.keysize = sizeof(int);
+ mapping_table_info.entrysize = sizeof(SlruMappingTableEntry);
+ snprintf(mapping_table_name, sizeof(mapping_table_name),
+ "%s Lookup Table", name);
+ mapping_table = ShmemInitHash(mapping_table_name, nslots, nslots,
+ &mapping_table_info, HASH_ELEM | HASH_BLOBS);
+
/*
* Initialize the unshared control struct, including directory path. We
* assume caller set PagePrecedes.
*/
ctl->shared = shared;
+ ctl->mapping_table = mapping_table;
ctl->sync_handler = sync_handler;
strlcpy(ctl->Dir, subdir, sizeof(ctl->Dir));
}
@@ -289,6 +313,9 @@ SimpleLruZeroPage(SlruCtl ctl, int pageno)
shared->page_number[slotno] == pageno);
/* Mark the slot as containing this page */
+ if (shared->page_status[slotno] != SLRU_PAGE_EMPTY)
+ SlruMappingRemove(ctl, shared->page_number[slotno]);
+ SlruMappingAdd(ctl, pageno, slotno);
shared->page_number[slotno] = pageno;
shared->page_status[slotno] = SLRU_PAGE_VALID;
shared->page_dirty[slotno] = true;
@@ -362,7 +389,10 @@ SimpleLruWaitIO(SlruCtl ctl, int slotno)
{
/* indeed, the I/O must have failed */
if (shared->page_status[slotno] == SLRU_PAGE_READ_IN_PROGRESS)
+ {
+ SlruMappingRemove(ctl, shared->page_number[slotno]);
shared->page_status[slotno] = SLRU_PAGE_EMPTY;
+ }
else /* write_in_progress */
{
shared->page_status[slotno] = SLRU_PAGE_VALID;
@@ -436,6 +466,9 @@ SimpleLruReadPage(SlruCtl ctl, int pageno, bool write_ok,
!shared->page_dirty[slotno]));
/* Mark the slot read-busy */
+ if (shared->page_status[slotno] != SLRU_PAGE_EMPTY)
+ SlruMappingRemove(ctl, shared->page_number[slotno]);
+ SlruMappingAdd(ctl, pageno, slotno);
shared->page_number[slotno] = pageno;
shared->page_status[slotno] = SLRU_PAGE_READ_IN_PROGRESS;
shared->page_dirty[slotno] = false;
@@ -459,7 +492,13 @@ SimpleLruReadPage(SlruCtl ctl, int pageno, bool write_ok,
shared->page_status[slotno] == SLRU_PAGE_READ_IN_PROGRESS &&
!shared->page_dirty[slotno]);
- shared->page_status[slotno] = ok ? SLRU_PAGE_VALID : SLRU_PAGE_EMPTY;
+ if (ok)
+ shared->page_status[slotno] = SLRU_PAGE_VALID;
+ else
+ {
+ SlruMappingRemove(ctl, pageno);
+ shared->page_status[slotno] = SLRU_PAGE_EMPTY;
+ }
LWLockRelease(&shared->buffer_locks[slotno].lock);
@@ -500,20 +539,20 @@ SimpleLruReadPage_ReadOnly(SlruCtl ctl, int pageno, TransactionId xid)
LWLockAcquire(shared->ControlLock, LW_SHARED);
/* See if page is already in a buffer */
- for (slotno = 0; slotno < shared->num_slots; slotno++)
+ slotno = SlruMappingFind(ctl, pageno);
+ if (slotno >= 0 &&
+ shared->page_status[slotno] != SLRU_PAGE_READ_IN_PROGRESS)
{
- if (shared->page_number[slotno] == pageno &&
- shared->page_status[slotno] != SLRU_PAGE_EMPTY &&
- shared->page_status[slotno] != SLRU_PAGE_READ_IN_PROGRESS)
- {
- /* See comments for SlruRecentlyUsed macro */
- SlruRecentlyUsed(shared, slotno);
+ Assert(shared->page_status[slotno] != SLRU_PAGE_EMPTY);
+ Assert(shared->page_number[slotno] == pageno);
- /* update the stats counter of pages found in the SLRU */
- pgstat_count_slru_page_hit(shared->slru_stats_idx);
+ /* See comments for SlruRecentlyUsed macro */
+ SlruRecentlyUsed(shared, slotno);
- return slotno;
- }
+ /* update the stats counter of pages found in the SLRU */
+ pgstat_count_slru_page_hit(shared->slru_stats_idx);
+
+ return slotno;
}
/* No luck, so switch to normal exclusive lock and do regular read */
@@ -1029,11 +1068,12 @@ SlruSelectLRUPage(SlruCtl ctl, int pageno)
int best_invalid_page_number = 0; /* keep compiler quiet */
/* See if page already has a buffer assigned */
- for (slotno = 0; slotno < shared->num_slots; slotno++)
+ slotno = SlruMappingFind(ctl, pageno);
+ if (slotno >= 0)
{
- if (shared->page_number[slotno] == pageno &&
- shared->page_status[slotno] != SLRU_PAGE_EMPTY)
- return slotno;
+ Assert(shared->page_number[slotno] == pageno);
+ Assert(shared->page_status[slotno] != SLRU_PAGE_EMPTY);
+ return slotno;
}
/*
@@ -1266,6 +1306,7 @@ restart:;
if (shared->page_status[slotno] == SLRU_PAGE_VALID &&
!shared->page_dirty[slotno])
{
+ SlruMappingRemove(ctl, shared->page_number[slotno]);
shared->page_status[slotno] = SLRU_PAGE_EMPTY;
continue;
}
@@ -1348,6 +1389,7 @@ restart:
if (shared->page_status[slotno] == SLRU_PAGE_VALID &&
!shared->page_dirty[slotno])
{
+ SlruMappingRemove(ctl, shared->page_number[slotno]);
shared->page_status[slotno] = SLRU_PAGE_EMPTY;
continue;
}
@@ -1609,3 +1651,37 @@ SlruSyncFileTag(SlruCtl ctl, const FileTag *ftag, char *path)
errno = save_errno;
return result;
}
+
+static int
+SlruMappingFind(SlruCtl ctl, int pageno)
+{
+ SlruMappingTableEntry *mapping;
+
+ mapping = hash_search(ctl->mapping_table, &pageno, HASH_FIND, NULL);
+ if (mapping)
+ return mapping->slotno;
+
+ return -1;
+}
+
+static void
+SlruMappingAdd(SlruCtl ctl, int pageno, int slotno)
+{
+ SlruMappingTableEntry *mapping;
+ bool found PG_USED_FOR_ASSERTS_ONLY;
+
+ mapping = hash_search(ctl->mapping_table, &pageno, HASH_ENTER, &found);
+ mapping->slotno = slotno;
+
+ Assert(!found);
+}
+
+static void
+SlruMappingRemove(SlruCtl ctl, int pageno)
+{
+ bool found PG_USED_FOR_ASSERTS_ONLY;
+
+ hash_search(ctl->mapping_table, &pageno, HASH_REMOVE, &found);
+
+ Assert(found);
+}
diff --git a/src/include/access/slru.h b/src/include/access/slru.h
index dd52e8cec7..8aa3efc0ee 100644
--- a/src/include/access/slru.h
+++ b/src/include/access/slru.h
@@ -16,6 +16,7 @@
#include "access/xlogdefs.h"
#include "storage/lwlock.h"
#include "storage/sync.h"
+#include "utils/hsearch.h"
/*
@@ -110,6 +111,7 @@ typedef SlruSharedData *SlruShared;
typedef struct SlruCtlData
{
SlruShared shared;
+ HTAB *mapping_table;
/*
* Which sync handler function to use when handing sync requests over to
--
2.30.2
[text/x-patch] v14-0002-Make-all-SLRU-buffer-sizes-configurable.patch (25.7K, ../../CA+hUKGKEdeVKpOqBxzRF+Z4=j0T+CA7ERrXni5De71Mm6-dBWA@mail.gmail.com/3-v14-0002-Make-all-SLRU-buffer-sizes-configurable.patch)
download | inline diff:
From edd07254e3f018ee3afe3f4251ab2cc0406d8b7a Mon Sep 17 00:00:00 2001
From: Andrey Borodin <[email protected]>
Date: Mon, 15 Feb 2021 21:51:56 +0500
Subject: [PATCH v14 2/2] Make all SLRU buffer sizes configurable.
Provide new GUCs to set the number of buffers, instead of using hard
coded defaults.
Remove the limits on xact_buffers and commit_ts_buffers. The default
sizes for those caches are ~0.2% and ~0.1% of shared_buffers, as before,
but now there is no cap at 128 and 16 buffers respectively (unless
track_commit_timestamp is disabled, in the latter case, then we might as
well keep it tiny). Sizes much larger than the old limits have been
shown to be useful on modern systems, and an earlier commit replaced a
linear search with a hash table to avoid problems with extreme cases.
Author: Andrey M. Borodin <[email protected]>
Reviewed-by: Anastasia Lubennikova <[email protected]>
Reviewed-by: Tomas Vondra <[email protected]>
Reviewed-by: Alexander Korotkov <[email protected]>
Reviewed-by: Gilles Darold <[email protected]>
Reviewed-by: Thomas Munro <[email protected]>
Discussion: https://postgr.es/m/2BEC2B3F-9B61-4C1D-9FB5-5FAB0F05EF86%40yandex-team.ru
---
doc/src/sgml/config.sgml | 135 ++++++++++++++++++
src/backend/access/transam/clog.c | 23 ++-
src/backend/access/transam/commit_ts.c | 10 +-
src/backend/access/transam/multixact.c | 8 +-
src/backend/access/transam/subtrans.c | 5 +-
src/backend/commands/async.c | 8 +-
src/backend/storage/lmgr/predicate.c | 4 +-
src/backend/utils/init/globals.c | 8 ++
src/backend/utils/misc/guc.c | 99 +++++++++++++
src/backend/utils/misc/postgresql.conf.sample | 9 ++
src/include/access/clog.h | 10 ++
src/include/access/commit_ts.h | 1 -
src/include/access/multixact.h | 4 -
src/include/access/slru.h | 5 +
src/include/access/subtrans.h | 2 -
src/include/commands/async.h | 5 -
src/include/miscadmin.h | 7 +
src/include/storage/predicate.h | 4 -
18 files changed, 301 insertions(+), 46 deletions(-)
diff --git a/doc/src/sgml/config.sgml b/doc/src/sgml/config.sgml
index 701cb65cc7..58388f144f 100644
--- a/doc/src/sgml/config.sgml
+++ b/doc/src/sgml/config.sgml
@@ -1886,6 +1886,141 @@ include_dir 'conf.d'
</para>
</listitem>
</varlistentry>
+
+ <varlistentry id="guc-multixact-offsets-buffers" xreflabel="multixact_offsets_buffers">
+ <term><varname>multixact_offsets_buffers</varname> (<type>integer</type>)
+ <indexterm>
+ <primary><varname>multixact_offsets_buffers</varname> configuration parameter</primary>
+ </indexterm>
+ </term>
+ <listitem>
+ <para>
+ Specifies the amount of shared memory to use to cache the contents
+ of <literal>pg_multixact/offsets</literal> (see
+ <xref linkend="pgdata-contents-table"/>).
+ If this value is specified without units, it is taken as blocks,
+ that is <symbol>BLCKSZ</symbol> bytes, typically 8kB.
+ The default value is <literal>8</literal>.
+ This parameter can only be set at server start.
+ </para>
+ </listitem>
+ </varlistentry>
+
+ <varlistentry id="guc-multixact-members-buffers" xreflabel="multixact_members_buffers">
+ <term><varname>multixact_members_buffers</varname> (<type>integer</type>)
+ <indexterm>
+ <primary><varname>multixact_members_buffers</varname> configuration parameter</primary>
+ </indexterm>
+ </term>
+ <listitem>
+ <para>
+ Specifies the amount of shared memory to use to cache the contents
+ of <literal>pg_multixact/members</literal> (see
+ <xref linkend="pgdata-contents-table"/>).
+ If this value is specified without units, it is taken as blocks,
+ that is <symbol>BLCKSZ</symbol> bytes, typically 8kB.
+ The default value is <literal>16</literal>.
+ This parameter can only be set at server start.
+ </para>
+ </listitem>
+ </varlistentry>
+
+ <varlistentry id="guc-subtrans-buffers" xreflabel="subtrans_buffers">
+ <term><varname>subtrans_buffers</varname> (<type>integer</type>)
+ <indexterm>
+ <primary><varname>subtrans_buffers</varname> configuration parameter</primary>
+ </indexterm>
+ </term>
+ <listitem>
+ <para>
+ Specifies the amount of shared memory to use to cache the contents
+ of <literal>pg_subtrans</literal> (see
+ <xref linkend="pgdata-contents-table"/>).
+ If this value is specified without units, it is taken as blocks,
+ that is <symbol>BLCKSZ</symbol> bytes, typically 8kB.
+ The default value is <literal>8</literal>.
+ This parameter can only be set at server start.
+ </para>
+ </listitem>
+ </varlistentry>
+
+ <varlistentry id="guc-notify-buffers" xreflabel="notify_buffers">
+ <term><varname>notify_buffers</varname> (<type>integer</type>)
+ <indexterm>
+ <primary><varname>notify_buffers</varname> configuration parameter</primary>
+ </indexterm>
+ </term>
+ <listitem>
+ <para>
+ Specifies the amount of shared memory to use to cache the contents
+ of <literal>pg_notify</literal> (see
+ <xref linkend="pgdata-contents-table"/>).
+ If this value is specified without units, it is taken as blocks,
+ that is <symbol>BLCKSZ</symbol> bytes, typically 8kB.
+ The default value is <literal>8</literal>.
+ This parameter can only be set at server start.
+ </para>
+ </listitem>
+ </varlistentry>
+
+ <varlistentry id="guc-serial-buffers" xreflabel="serial_buffers">
+ <term><varname>serial_buffers</varname> (<type>integer</type>)
+ <indexterm>
+ <primary><varname>serial_buffers</varname> configuration parameter</primary>
+ </indexterm>
+ </term>
+ <listitem>
+ <para>
+ Specifies the amount of shared memory to use to cache the contents
+ of <literal>pg_serial</literal> (see
+ <xref linkend="pgdata-contents-table"/>).
+ If this value is specified without units, it is taken as blocks,
+ that is <symbol>BLCKSZ</symbol> bytes, typically 8kB.
+ The default value is <literal>16</literal>.
+ This parameter can only be set at server start.
+ </para>
+ </listitem>
+ </varlistentry>
+
+ <varlistentry id="guc-xact-buffers" xreflabel="xact_buffers">
+ <term><varname>xact_buffers</varname> (<type>integer</type>)
+ <indexterm>
+ <primary><varname>xact_buffers</varname> configuration parameter</primary>
+ </indexterm>
+ </term>
+ <listitem>
+ <para>
+ Specifies the amount of shared memory to use to cache the contents
+ of <literal>pg_xact</literal> (see
+ <xref linkend="pgdata-contents-table"/>).
+ If this value is specified without units, it is taken as blocks,
+ that is <symbol>BLCKSZ</symbol> bytes, typically 8kB.
+ The default value is <literal>0</literal>, which requests
+ <varname>shared_buffers</varname> / 512, but not fewer than 4 blocks.
+ This parameter can only be set at server start.
+ </para>
+ </listitem>
+ </varlistentry>
+
+ <varlistentry id="guc-commit-ts-buffers" xreflabel="commit_ts_buffers">
+ <term><varname>commit_ts_buffers</varname> (<type>integer</type>)
+ <indexterm>
+ <primary><varname>commit_ts_buffers</varname> configuration parameter</primary>
+ </indexterm>
+ </term>
+ <listitem>
+ <para>
+ Specifies the amount of memory to use to cache the cotents of
+ <literal>pg_commit_ts</literal> (see
+ <xref linkend="pgdata-contents-table"/>).
+ If this value is specified without units, it is taken as blocks,
+ that is <symbol>BLCKSZ</symbol> bytes, typically 8kB.
+ The default value is <literal>0</literal>, which requests
+ <varname>shared_buffers</varname> / 1024, but not fewer than 4 blocks.
+ This parameter can only be set at server start.
+ </para>
+ </listitem>
+ </varlistentry>
<varlistentry id="guc-max-stack-depth" xreflabel="max_stack_depth">
<term><varname>max_stack_depth</varname> (<type>integer</type>)
diff --git a/src/backend/access/transam/clog.c b/src/backend/access/transam/clog.c
index 6fa4713fb4..dd2d7a5184 100644
--- a/src/backend/access/transam/clog.c
+++ b/src/backend/access/transam/clog.c
@@ -58,8 +58,8 @@
/* We need two bits per xact, so four xacts fit in a byte */
#define CLOG_BITS_PER_XACT 2
-#define CLOG_XACTS_PER_BYTE 4
-#define CLOG_XACTS_PER_PAGE (BLCKSZ * CLOG_XACTS_PER_BYTE)
+StaticAssertDecl((CLOG_BITS_PER_XACT * CLOG_XACTS_PER_BYTE) == BITS_PER_BYTE,
+ "CLOG_BITS_PER_XACT and CLOG_XACTS_PER_BYTE are inconsistent");
#define CLOG_XACT_BITMASK ((1 << CLOG_BITS_PER_XACT) - 1)
#define TransactionIdToPage(xid) ((xid) / (TransactionId) CLOG_XACTS_PER_PAGE)
@@ -659,23 +659,16 @@ TransactionIdGetStatus(TransactionId xid, XLogRecPtr *lsn)
/*
* Number of shared CLOG buffers.
*
- * On larger multi-processor systems, it is possible to have many CLOG page
- * requests in flight at one time which could lead to disk access for CLOG
- * page if the required page is not found in memory. Testing revealed that we
- * can get the best performance by having 128 CLOG buffers, more than that it
- * doesn't improve performance.
- *
- * Unconditionally keeping the number of CLOG buffers to 128 did not seem like
- * a good idea, because it would increase the minimum amount of shared memory
- * required to start, which could be a problem for people running very small
- * configurations. The following formula seems to represent a reasonable
- * compromise: people with very low values for shared_buffers will get fewer
- * CLOG buffers as well, and everyone else will get 128.
+ * By default, we'll use 2MB of for every 1GB of shared buffers, up to the
+ * theoretical maximum useful value, but always at least 4 buffers.
*/
Size
CLOGShmemBuffers(void)
{
- return Min(128, Max(4, NBuffers / 512));
+ /* Use configured value if provided. */
+ if (xact_buffers > 0)
+ return Max(4, xact_buffers);
+ return Min(CLOG_MAX_ALLOWED_BUFFERS, Max(4, NBuffers / 512));
}
/*
diff --git a/src/backend/access/transam/commit_ts.c b/src/backend/access/transam/commit_ts.c
index 268bdba339..729a4b9212 100644
--- a/src/backend/access/transam/commit_ts.c
+++ b/src/backend/access/transam/commit_ts.c
@@ -524,13 +524,17 @@ pg_xact_commit_timestamp_origin(PG_FUNCTION_ARGS)
/*
* Number of shared CommitTS buffers.
*
- * We use a very similar logic as for the number of CLOG buffers; see comments
- * in CLOGShmemBuffers.
+ * By default, we'll use 1MB of for every 1GB of shared buffers, up to the
+ * maximum value that slru.c will allow, but always at least 4 buffers.
*/
Size
CommitTsShmemBuffers(void)
{
- return Min(16, Max(4, NBuffers / 1024));
+ /* Use configured value if provided. */
+ if (commit_ts_buffers > 0)
+ return Max(4, commit_ts_buffers);
+ return Min(track_commit_timestamp ? SLRU_MAX_ALLOWED_BUFFERS : 16,
+ Max(4, NBuffers / 1024));
}
/*
diff --git a/src/backend/access/transam/multixact.c b/src/backend/access/transam/multixact.c
index 1f9f1a1fa1..21787765e2 100644
--- a/src/backend/access/transam/multixact.c
+++ b/src/backend/access/transam/multixact.c
@@ -1831,8 +1831,8 @@ MultiXactShmemSize(void)
mul_size(sizeof(MultiXactId) * 2, MaxOldestSlot))
size = SHARED_MULTIXACT_STATE_SIZE;
- size = add_size(size, SimpleLruShmemSize(NUM_MULTIXACTOFFSET_BUFFERS, 0));
- size = add_size(size, SimpleLruShmemSize(NUM_MULTIXACTMEMBER_BUFFERS, 0));
+ size = add_size(size, SimpleLruShmemSize(multixact_offsets_buffers, 0));
+ size = add_size(size, SimpleLruShmemSize(multixact_members_buffers, 0));
return size;
}
@@ -1848,13 +1848,13 @@ MultiXactShmemInit(void)
MultiXactMemberCtl->PagePrecedes = MultiXactMemberPagePrecedes;
SimpleLruInit(MultiXactOffsetCtl,
- "MultiXactOffset", NUM_MULTIXACTOFFSET_BUFFERS, 0,
+ "MultiXactOffset", multixact_offsets_buffers, 0,
MultiXactOffsetSLRULock, "pg_multixact/offsets",
LWTRANCHE_MULTIXACTOFFSET_BUFFER,
SYNC_HANDLER_MULTIXACT_OFFSET);
SlruPagePrecedesUnitTests(MultiXactOffsetCtl, MULTIXACT_OFFSETS_PER_PAGE);
SimpleLruInit(MultiXactMemberCtl,
- "MultiXactMember", NUM_MULTIXACTMEMBER_BUFFERS, 0,
+ "MultiXactMember", multixact_offsets_buffers, 0,
MultiXactMemberSLRULock, "pg_multixact/members",
LWTRANCHE_MULTIXACTMEMBER_BUFFER,
SYNC_HANDLER_MULTIXACT_MEMBER);
diff --git a/src/backend/access/transam/subtrans.c b/src/backend/access/transam/subtrans.c
index 6a8e521f89..785f2520fd 100644
--- a/src/backend/access/transam/subtrans.c
+++ b/src/backend/access/transam/subtrans.c
@@ -31,6 +31,7 @@
#include "access/slru.h"
#include "access/subtrans.h"
#include "access/transam.h"
+#include "miscadmin.h"
#include "pg_trace.h"
#include "utils/snapmgr.h"
@@ -184,14 +185,14 @@ SubTransGetTopmostTransaction(TransactionId xid)
Size
SUBTRANSShmemSize(void)
{
- return SimpleLruShmemSize(NUM_SUBTRANS_BUFFERS, 0);
+ return SimpleLruShmemSize(subtrans_buffers, 0);
}
void
SUBTRANSShmemInit(void)
{
SubTransCtl->PagePrecedes = SubTransPagePrecedes;
- SimpleLruInit(SubTransCtl, "Subtrans", NUM_SUBTRANS_BUFFERS, 0,
+ SimpleLruInit(SubTransCtl, "Subtrans", subtrans_buffers, 0,
SubtransSLRULock, "pg_subtrans",
LWTRANCHE_SUBTRANS_BUFFER, SYNC_HANDLER_NONE);
SlruPagePrecedesUnitTests(SubTransCtl, SUBTRANS_XACTS_PER_PAGE);
diff --git a/src/backend/commands/async.c b/src/backend/commands/async.c
index 4b16fb5682..de17f52cd7 100644
--- a/src/backend/commands/async.c
+++ b/src/backend/commands/async.c
@@ -107,7 +107,7 @@
* frontend during startup.) The above design guarantees that notifies from
* other backends will never be missed by ignoring self-notifies.
*
- * The amount of shared memory used for notify management (NUM_NOTIFY_BUFFERS)
+ * The amount of shared memory used for notify management (notify_buffers)
* can be varied without affecting anything but performance. The maximum
* amount of notification data that can be queued at one time is determined
* by slru.c's wraparound limit; see QUEUE_MAX_PAGE below.
@@ -225,7 +225,7 @@ typedef struct QueuePosition
*
* Resist the temptation to make this really large. While that would save
* work in some places, it would add cost in others. In particular, this
- * should likely be less than NUM_NOTIFY_BUFFERS, to ensure that backends
+ * should likely be less than notify_buffers, to ensure that backends
* catch up before the pages they'll need to read fall out of SLRU cache.
*/
#define QUEUE_CLEANUP_DELAY 4
@@ -514,7 +514,7 @@ AsyncShmemSize(void)
size = mul_size(MaxBackends + 1, sizeof(QueueBackendStatus));
size = add_size(size, offsetof(AsyncQueueControl, backend));
- size = add_size(size, SimpleLruShmemSize(NUM_NOTIFY_BUFFERS, 0));
+ size = add_size(size, SimpleLruShmemSize(notify_buffers, 0));
return size;
}
@@ -562,7 +562,7 @@ AsyncShmemInit(void)
* Set up SLRU management of the pg_notify data.
*/
NotifyCtl->PagePrecedes = asyncQueuePagePrecedes;
- SimpleLruInit(NotifyCtl, "Notify", NUM_NOTIFY_BUFFERS, 0,
+ SimpleLruInit(NotifyCtl, "Notify", notify_buffers, 0,
NotifySLRULock, "pg_notify", LWTRANCHE_NOTIFY_BUFFER,
SYNC_HANDLER_NONE);
diff --git a/src/backend/storage/lmgr/predicate.c b/src/backend/storage/lmgr/predicate.c
index d493aeef0f..b1f4f1651d 100644
--- a/src/backend/storage/lmgr/predicate.c
+++ b/src/backend/storage/lmgr/predicate.c
@@ -872,7 +872,7 @@ SerialInit(void)
*/
SerialSlruCtl->PagePrecedes = SerialPagePrecedesLogically;
SimpleLruInit(SerialSlruCtl, "Serial",
- NUM_SERIAL_BUFFERS, 0, SerialSLRULock, "pg_serial",
+ serial_buffers, 0, SerialSLRULock, "pg_serial",
LWTRANCHE_SERIAL_BUFFER, SYNC_HANDLER_NONE);
#ifdef USE_ASSERT_CHECKING
SerialPagePrecedesLogicallyUnitTests();
@@ -1395,7 +1395,7 @@ PredicateLockShmemSize(void)
/* Shared memory structures for SLRU tracking of old committed xids. */
size = add_size(size, sizeof(SerialControlData));
- size = add_size(size, SimpleLruShmemSize(NUM_SERIAL_BUFFERS, 0));
+ size = add_size(size, SimpleLruShmemSize(serial_buffers, 0));
return size;
}
diff --git a/src/backend/utils/init/globals.c b/src/backend/utils/init/globals.c
index 73e0a672ae..3de58042d3 100644
--- a/src/backend/utils/init/globals.c
+++ b/src/backend/utils/init/globals.c
@@ -148,3 +148,11 @@ int64 VacuumPageDirty = 0;
int VacuumCostBalance = 0; /* working state for vacuum */
bool VacuumCostActive = false;
+
+int multixact_offsets_buffers = 8;
+int multixact_members_buffers = 16;
+int subtrans_buffers = 32;
+int notify_buffers = 8;
+int serial_buffers = 16;
+int xact_buffers = 0;
+int commit_ts_buffers = 0;
diff --git a/src/backend/utils/misc/guc.c b/src/backend/utils/misc/guc.c
index 03daec9a08..e05f05ffea 100644
--- a/src/backend/utils/misc/guc.c
+++ b/src/backend/utils/misc/guc.c
@@ -29,9 +29,11 @@
#endif
#include <unistd.h>
+#include "access/clog.h"
#include "access/commit_ts.h"
#include "access/gin.h"
#include "access/rmgr.h"
+#include "access/slru.h"
#include "access/tableam.h"
#include "access/toast_compression.h"
#include "access/transam.h"
@@ -196,6 +198,8 @@ static const char *show_tcp_keepalives_idle(void);
static const char *show_tcp_keepalives_interval(void);
static const char *show_tcp_keepalives_count(void);
static const char *show_tcp_user_timeout(void);
+static const char *show_xact_buffers(void);
+static const char *show_commit_ts_buffers(void);
static bool check_maxconnections(int *newval, void **extra, GucSource source);
static bool check_max_worker_processes(int *newval, void **extra, GucSource source);
static bool check_autovacuum_max_workers(int *newval, void **extra, GucSource source);
@@ -2315,6 +2319,83 @@ static struct config_int ConfigureNamesInt[] =
NULL, NULL, NULL
},
+ {
+ {"multixact_offsets_buffers", PGC_POSTMASTER, RESOURCES_MEM,
+ gettext_noop("Sets the number of shared memory buffers used for the MultiXact offset SLRU cache."),
+ NULL,
+ GUC_UNIT_BLOCKS
+ },
+ &multixact_offsets_buffers,
+ 8, 2, SLRU_MAX_ALLOWED_BUFFERS,
+ NULL, NULL, NULL
+ },
+
+ {
+ {"multixact_members_buffers", PGC_POSTMASTER, RESOURCES_MEM,
+ gettext_noop("Sets the number of shared memory buffers used for the MultiXact member SLRU cache."),
+ NULL,
+ GUC_UNIT_BLOCKS
+ },
+ &multixact_members_buffers,
+ 16, 2, SLRU_MAX_ALLOWED_BUFFERS,
+ NULL, NULL, NULL
+ },
+
+ {
+ {"subtrans_buffers", PGC_POSTMASTER, RESOURCES_MEM,
+ gettext_noop("Sets the number of shared memory buffers used for the sub-transaction SLRU cache."),
+ NULL,
+ GUC_UNIT_BLOCKS
+ },
+ &subtrans_buffers,
+ 32, 2, SLRU_MAX_ALLOWED_BUFFERS,
+ NULL, NULL, NULL
+ },
+
+ {
+ {"notify_buffers", PGC_POSTMASTER, RESOURCES_MEM,
+ gettext_noop("Sets the number of shared memory buffers used for the NOTIFY message SLRU cache."),
+ NULL,
+ GUC_UNIT_BLOCKS
+ },
+ ¬ify_buffers,
+ 8, 2, SLRU_MAX_ALLOWED_BUFFERS,
+ NULL, NULL, NULL
+ },
+
+ {
+ {"serial_buffers", PGC_POSTMASTER, RESOURCES_MEM,
+ gettext_noop("Sets the number of shared memory buffers used for the serializable transaction SLRU cache."),
+ NULL,
+ GUC_UNIT_BLOCKS
+ },
+ &serial_buffers,
+ 16, 2, SLRU_MAX_ALLOWED_BUFFERS,
+ NULL, NULL, NULL
+ },
+
+ {
+ {"xact_buffers", PGC_POSTMASTER, RESOURCES_MEM,
+ gettext_noop("Sets the number of shared memory buffers used for the transaction status SLRU cache."),
+ NULL,
+ GUC_UNIT_BLOCKS
+ },
+ &xact_buffers,
+ 0, 0, CLOG_MAX_ALLOWED_BUFFERS,
+ NULL, NULL, show_xact_buffers
+ },
+
+ {
+ {"commit_ts_buffers", PGC_POSTMASTER, RESOURCES_MEM,
+ gettext_noop("Sets the size of the dedicated buffer pool used for the commit timestamp SLRU cache."),
+ NULL,
+ GUC_UNIT_BLOCKS
+ },
+ &commit_ts_buffers,
+ 0, 0, SLRU_MAX_ALLOWED_BUFFERS,
+ NULL, NULL, show_commit_ts_buffers
+ },
+
{
{"temp_buffers", PGC_USERSET, RESOURCES_MEM,
gettext_noop("Sets the maximum number of temporary buffers used by each session."),
@@ -11871,6 +11952,24 @@ show_tcp_user_timeout(void)
return nbuf;
}
+static const char *
+show_xact_buffers(void)
+{
+ static char nbuf[16];
+
+ snprintf(nbuf, sizeof(nbuf), "%zu", CLOGShmemBuffers());
+ return nbuf;
+}
+
+static const char *
+show_commit_ts_buffers(void)
+{
+ static char nbuf[16];
+
+ snprintf(nbuf, sizeof(nbuf), "%zu", CommitTsShmemBuffers());
+ return nbuf;
+}
+
static bool
check_maxconnections(int *newval, void **extra, GucSource source)
{
diff --git a/src/backend/utils/misc/postgresql.conf.sample b/src/backend/utils/misc/postgresql.conf.sample
index 791d39cf07..a380d063da 100644
--- a/src/backend/utils/misc/postgresql.conf.sample
+++ b/src/backend/utils/misc/postgresql.conf.sample
@@ -190,6 +190,15 @@
# (change requires restart)
#backend_flush_after = 0 # measured in pages, 0 disables
+# - SLRU Buffers (change requires restart) -
+
+#xact_buffers = 0 # memory for pg_xact (0 = auto)
+#subtrans_buffers = 32 # memory for pg_subtrans
+#multixact_offsets_buffers = 8 # memory for pg_multixact/offsets
+#multixact_members_buffers = 16 # memory for pg_multixact/members
+#notify_buffers = 8 # memory for pg_notify
+#serial_buffers = 16 # memory for pg_serial
+#commit_ts_buffers = 0 # memory for pg_commit_ts (0 = auto)
#------------------------------------------------------------------------------
# WRITE-AHEAD LOG
diff --git a/src/include/access/clog.h b/src/include/access/clog.h
index 39b8e4afa8..739a292f7f 100644
--- a/src/include/access/clog.h
+++ b/src/include/access/clog.h
@@ -15,6 +15,16 @@
#include "storage/sync.h"
#include "lib/stringinfo.h"
+/*
+ * Don't allow xact_buffers to be set higher than could possibly be useful or
+ * SLRU would allow.
+ */
+#define CLOG_XACTS_PER_BYTE 4
+#define CLOG_XACTS_PER_PAGE (BLCKSZ * CLOG_XACTS_PER_BYTE)
+#define CLOG_MAX_ALLOWED_BUFFERS \
+ Min(SLRU_MAX_ALLOWED_BUFFERS, \
+ (((MaxTransactionId / 2) + (CLOG_XACTS_PER_PAGE - 1)) / CLOG_XACTS_PER_PAGE))
+
/*
* Possible transaction statuses --- note that all-zeroes is the initial
* state.
diff --git a/src/include/access/commit_ts.h b/src/include/access/commit_ts.h
index 750369104a..e4cf988609 100644
--- a/src/include/access/commit_ts.h
+++ b/src/include/access/commit_ts.h
@@ -17,7 +17,6 @@
#include "storage/sync.h"
#include "utils/guc.h"
-
extern PGDLLIMPORT bool track_commit_timestamp;
extern bool check_track_commit_timestamp(bool *newval, void **extra,
diff --git a/src/include/access/multixact.h b/src/include/access/multixact.h
index 4bbb035eae..97c0a46376 100644
--- a/src/include/access/multixact.h
+++ b/src/include/access/multixact.h
@@ -29,10 +29,6 @@
#define MaxMultiXactOffset ((MultiXactOffset) 0xFFFFFFFF)
-/* Number of SLRU buffers to use for multixact */
-#define NUM_MULTIXACTOFFSET_BUFFERS 8
-#define NUM_MULTIXACTMEMBER_BUFFERS 16
-
/*
* Possible multixact lock modes ("status"). The first four modes are for
* tuple locks (FOR KEY SHARE, FOR SHARE, FOR NO KEY UPDATE, FOR UPDATE); the
diff --git a/src/include/access/slru.h b/src/include/access/slru.h
index 8aa3efc0ee..97ea837646 100644
--- a/src/include/access/slru.h
+++ b/src/include/access/slru.h
@@ -18,6 +18,11 @@
#include "storage/sync.h"
#include "utils/hsearch.h"
+/*
+ * To avoid overflowing internal arithmetic and the size_t data type, the
+ * number of buffers should not exceed this number.
+ */
+#define SLRU_MAX_ALLOWED_BUFFERS ((1024 * 1024 * 1024) / BLCKSZ)
/*
* Define SLRU segment size. A page is the same BLCKSZ as is used everywhere
diff --git a/src/include/access/subtrans.h b/src/include/access/subtrans.h
index d0ab44ae82..64fa86938e 100644
--- a/src/include/access/subtrans.h
+++ b/src/include/access/subtrans.h
@@ -11,8 +11,6 @@
#ifndef SUBTRANS_H
#define SUBTRANS_H
-/* Number of SLRU buffers to use for subtrans */
-#define NUM_SUBTRANS_BUFFERS 32
extern void SubTransSetParent(TransactionId xid, TransactionId parent);
extern TransactionId SubTransGetParent(TransactionId xid);
diff --git a/src/include/commands/async.h b/src/include/commands/async.h
index 9217f66b91..fa831e3721 100644
--- a/src/include/commands/async.h
+++ b/src/include/commands/async.h
@@ -15,11 +15,6 @@
#include <signal.h>
-/*
- * The number of SLRU page buffers we use for the notification queue.
- */
-#define NUM_NOTIFY_BUFFERS 8
-
extern bool Trace_notify;
extern volatile sig_atomic_t notifyInterruptPending;
diff --git a/src/include/miscadmin.h b/src/include/miscadmin.h
index 013850ac28..eb2c1f18f3 100644
--- a/src/include/miscadmin.h
+++ b/src/include/miscadmin.h
@@ -162,6 +162,13 @@ extern PGDLLIMPORT int MaxBackends;
extern PGDLLIMPORT int MaxConnections;
extern PGDLLIMPORT int max_worker_processes;
extern PGDLLIMPORT int max_parallel_workers;
+extern PGDLLIMPORT int multixact_offsets_buffers;
+extern PGDLLIMPORT int multixact_members_buffers;
+extern PGDLLIMPORT int subtrans_buffers;
+extern PGDLLIMPORT int notify_buffers;
+extern PGDLLIMPORT int serial_buffers;
+extern PGDLLIMPORT int xact_buffers;
+extern PGDLLIMPORT int commit_ts_buffers;
extern PGDLLIMPORT int MyProcPid;
extern PGDLLIMPORT pg_time_t MyStartTime;
diff --git a/src/include/storage/predicate.h b/src/include/storage/predicate.h
index 152b698611..c72779bd88 100644
--- a/src/include/storage/predicate.h
+++ b/src/include/storage/predicate.h
@@ -26,10 +26,6 @@ extern int max_predicate_locks_per_xact;
extern int max_predicate_locks_per_relation;
extern int max_predicate_locks_per_page;
-
-/* Number of SLRU buffers to use for Serial SLRU */
-#define NUM_SERIAL_BUFFERS 16
-
/*
* A handle used for sharing SERIALIZABLEXACT objects between the participants
* in a parallel query.
--
2.30.2
^ permalink raw reply [nested|flat] 90+ messages in thread
* Re: MultiXact\SLRU buffers configuration
2020-05-08 16:36 MultiXact\SLRU buffers configuration Andrey M. Borodin <[email protected]>
2020-05-11 11:17 ` Re: MultiXact\SLRU buffers configuration Andrey M. Borodin <[email protected]>
2020-05-13 18:08 ` Re: MultiXact\SLRU buffers configuration Andrey M. Borodin <[email protected]>
2020-05-14 01:25 ` Re: MultiXact\SLRU buffers configuration Kyotaro Horiguchi <[email protected]>
2020-05-14 05:19 ` Re: MultiXact\SLRU buffers configuration Andrey M. Borodin <[email protected]>
2020-05-14 06:16 ` Re: MultiXact\SLRU buffers configuration Kyotaro Horiguchi <[email protected]>
2020-05-14 06:44 ` Re: MultiXact\SLRU buffers configuration Andrey M. Borodin <[email protected]>
2020-05-15 00:03 ` Re: MultiXact\SLRU buffers configuration Kyotaro Horiguchi <[email protected]>
2020-07-02 12:02 ` Re: MultiXact\SLRU buffers configuration Daniel Gustafsson <[email protected]>
2020-07-08 07:03 ` Re: MultiXact\SLRU buffers configuration Andrey M. Borodin <[email protected]>
2020-08-28 18:08 ` Re: MultiXact\SLRU buffers configuration Anastasia Lubennikova <[email protected]>
2020-09-28 14:41 ` Re: MultiXact\SLRU buffers configuration Andrey M. Borodin <[email protected]>
2020-10-26 01:05 ` Re: MultiXact\SLRU buffers configuration Alexander Korotkov <[email protected]>
2020-10-26 15:45 ` Re: MultiXact\SLRU buffers configuration Andrey Borodin <[email protected]>
2020-10-27 17:02 ` Re: MultiXact\SLRU buffers configuration Alexander Korotkov <[email protected]>
2020-10-27 17:23 ` Re: MultiXact\SLRU buffers configuration Alexander Korotkov <[email protected]>
2020-10-28 01:36 ` Re: MultiXact\SLRU buffers configuration Tomas Vondra <[email protected]>
2020-10-28 07:34 ` Re: MultiXact\SLRU buffers configuration Andrey Borodin <[email protected]>
2020-10-28 23:32 ` Re: MultiXact\SLRU buffers configuration Tomas Vondra <[email protected]>
2020-10-29 07:08 ` Re: MultiXact\SLRU buffers configuration Andrey Borodin <[email protected]>
2020-10-29 13:49 ` Re: MultiXact\SLRU buffers configuration Tomas Vondra <[email protected]>
2020-11-02 12:45 ` Re: MultiXact\SLRU buffers configuration Andrey Borodin <[email protected]>
2020-11-10 00:13 ` Re: MultiXact\SLRU buffers configuration Tomas Vondra <[email protected]>
2020-11-10 06:16 ` Re: MultiXact\SLRU buffers configuration Andrey Borodin <[email protected]>
2020-11-10 18:07 ` Re: MultiXact\SLRU buffers configuration Tomas Vondra <[email protected]>
2020-11-13 11:49 ` Re: MultiXact\SLRU buffers configuration Andrey Borodin <[email protected]>
2020-12-08 16:05 ` Re: MultiXact\SLRU buffers configuration Gilles Darold <[email protected]>
2020-12-08 17:52 ` Re: MultiXact\SLRU buffers configuration Andrey Borodin <[email protected]>
2020-12-10 14:45 ` Re: MultiXact\SLRU buffers configuration Gilles Darold <[email protected]>
2020-12-11 17:50 ` Re: MultiXact\SLRU buffers configuration Gilles Darold <[email protected]>
2020-12-13 09:17 ` Re: MultiXact\SLRU buffers configuration Gilles Darold <[email protected]>
2020-12-13 17:24 ` Re: MultiXact\SLRU buffers configuration Andrey Borodin <[email protected]>
2020-12-23 16:31 ` Re: MultiXact\SLRU buffers configuration Gilles Darold <[email protected]>
2021-02-15 17:17 ` Re: MultiXact\SLRU buffers configuration Andrey Borodin <[email protected]>
2021-03-11 15:50 ` Re: MultiXact\SLRU buffers configuration Gilles Darold <[email protected]>
2021-03-12 12:44 ` Re: MultiXact\SLRU buffers configuration Andrey Borodin <[email protected]>
2021-03-24 21:31 ` Re: MultiXact\SLRU buffers configuration Thomas Munro <[email protected]>
2021-03-25 01:03 ` Re: MultiXact\SLRU buffers configuration Thomas Munro <[email protected]>
2021-03-26 03:46 ` Re: MultiXact\SLRU buffers configuration Thomas Munro <[email protected]>
2021-03-26 06:00 ` Re: MultiXact\SLRU buffers configuration Andrey Borodin <[email protected]>
2021-03-26 15:52 ` Re: MultiXact\SLRU buffers configuration Andrey Borodin <[email protected]>
2021-03-26 20:26 ` Re: MultiXact\SLRU buffers configuration Thomas Munro <[email protected]>
2021-03-27 05:31 ` Re: MultiXact\SLRU buffers configuration Andrey Borodin <[email protected]>
2021-03-28 21:15 ` Re: MultiXact\SLRU buffers configuration Thomas Munro <[email protected]>
2021-03-29 08:26 ` Re: MultiXact\SLRU buffers configuration Andrey Borodin <[email protected]>
2021-03-31 21:09 ` Re: MultiXact\SLRU buffers configuration Andrey Borodin <[email protected]>
2021-04-01 03:40 ` Re: MultiXact\SLRU buffers configuration Thomas Munro <[email protected]>
@ 2021-04-03 19:57 ` Andrey Borodin <[email protected]>
2021-04-07 05:59 ` Re: MultiXact\SLRU buffers configuration Thomas Munro <[email protected]>
0 siblings, 1 reply; 90+ messages in thread
From: Andrey Borodin @ 2021-04-03 19:57 UTC (permalink / raw)
To: Thomas Munro <[email protected]>; +Cc: Gilles Darold <[email protected]>; Tomas Vondra <[email protected]>; Tomas Vondra <[email protected]>; Alexander Korotkov <[email protected]>; Anastasia Lubennikova <[email protected]>; Daniel Gustafsson <[email protected]>; Kyotaro Horiguchi <[email protected]>; pgsql-hackers
> 1 апр. 2021 г., в 06:40, Thomas Munro <[email protected]> написал(а):
>
> 2. Remove the cap of 128 buffers for xact_buffers as agreed. We
> still need a cap though, to avoid a couple of kinds of overflow inside
> slru.c, both when computing the default value and accepting a
> user-provided number. I introduced SLRU_MAX_ALLOWED_BUFFERS to keep
> it <= 1GB, and tested this on a 32 bit build with extreme block sizes.
BTW we do not document maximum values right now.
I was toying around with big values. For example if we set different big xact_buffers we can get something like
FATAL: not enough shared memory for data structure "Notify" (72768 bytes requested)
FATAL: not enough shared memory for data structure "Async Queue Control" (2492 bytes requested)
FATAL: not enough shared memory for data structure "Checkpointer Data" (393280 bytes requested)
But never anything about xact_buffers. I don't think it's important, though.
>
> Likewise, I removed the cap of 16 buffers for commit_ts_buffers, but
> only if you have track_commit_timestamp enabled.
Is there a reason to leave 16 pages if commit_ts is disabled? They might be useful for some artefacts of previously enabled commit_ts?
> 4. Change the default for commit_ts_buffers back to shared_buffers /
> 1024 (with a minimum of 4), because I think you might have changed it
> by a copy and paste error -- or did you intend to make the default
> higher?
I changed default due to some experiments with https://www.postgresql.org/message-id/flat/20210115220744.GA24457%40alvherre.pgsql
In fact most important part of that thread was removing the cap, which is done by the patchset now.
Thanks!
Best regards, Andrey Borodin.
^ permalink raw reply [nested|flat] 90+ messages in thread
* Re: MultiXact\SLRU buffers configuration
2020-05-08 16:36 MultiXact\SLRU buffers configuration Andrey M. Borodin <[email protected]>
2020-05-11 11:17 ` Re: MultiXact\SLRU buffers configuration Andrey M. Borodin <[email protected]>
2020-05-13 18:08 ` Re: MultiXact\SLRU buffers configuration Andrey M. Borodin <[email protected]>
2020-05-14 01:25 ` Re: MultiXact\SLRU buffers configuration Kyotaro Horiguchi <[email protected]>
2020-05-14 05:19 ` Re: MultiXact\SLRU buffers configuration Andrey M. Borodin <[email protected]>
2020-05-14 06:16 ` Re: MultiXact\SLRU buffers configuration Kyotaro Horiguchi <[email protected]>
2020-05-14 06:44 ` Re: MultiXact\SLRU buffers configuration Andrey M. Borodin <[email protected]>
2020-05-15 00:03 ` Re: MultiXact\SLRU buffers configuration Kyotaro Horiguchi <[email protected]>
2020-07-02 12:02 ` Re: MultiXact\SLRU buffers configuration Daniel Gustafsson <[email protected]>
2020-07-08 07:03 ` Re: MultiXact\SLRU buffers configuration Andrey M. Borodin <[email protected]>
2020-08-28 18:08 ` Re: MultiXact\SLRU buffers configuration Anastasia Lubennikova <[email protected]>
2020-09-28 14:41 ` Re: MultiXact\SLRU buffers configuration Andrey M. Borodin <[email protected]>
2020-10-26 01:05 ` Re: MultiXact\SLRU buffers configuration Alexander Korotkov <[email protected]>
2020-10-26 15:45 ` Re: MultiXact\SLRU buffers configuration Andrey Borodin <[email protected]>
2020-10-27 17:02 ` Re: MultiXact\SLRU buffers configuration Alexander Korotkov <[email protected]>
2020-10-27 17:23 ` Re: MultiXact\SLRU buffers configuration Alexander Korotkov <[email protected]>
2020-10-28 01:36 ` Re: MultiXact\SLRU buffers configuration Tomas Vondra <[email protected]>
2020-10-28 07:34 ` Re: MultiXact\SLRU buffers configuration Andrey Borodin <[email protected]>
2020-10-28 23:32 ` Re: MultiXact\SLRU buffers configuration Tomas Vondra <[email protected]>
2020-10-29 07:08 ` Re: MultiXact\SLRU buffers configuration Andrey Borodin <[email protected]>
2020-10-29 13:49 ` Re: MultiXact\SLRU buffers configuration Tomas Vondra <[email protected]>
2020-11-02 12:45 ` Re: MultiXact\SLRU buffers configuration Andrey Borodin <[email protected]>
2020-11-10 00:13 ` Re: MultiXact\SLRU buffers configuration Tomas Vondra <[email protected]>
2020-11-10 06:16 ` Re: MultiXact\SLRU buffers configuration Andrey Borodin <[email protected]>
2020-11-10 18:07 ` Re: MultiXact\SLRU buffers configuration Tomas Vondra <[email protected]>
2020-11-13 11:49 ` Re: MultiXact\SLRU buffers configuration Andrey Borodin <[email protected]>
2020-12-08 16:05 ` Re: MultiXact\SLRU buffers configuration Gilles Darold <[email protected]>
2020-12-08 17:52 ` Re: MultiXact\SLRU buffers configuration Andrey Borodin <[email protected]>
2020-12-10 14:45 ` Re: MultiXact\SLRU buffers configuration Gilles Darold <[email protected]>
2020-12-11 17:50 ` Re: MultiXact\SLRU buffers configuration Gilles Darold <[email protected]>
2020-12-13 09:17 ` Re: MultiXact\SLRU buffers configuration Gilles Darold <[email protected]>
2020-12-13 17:24 ` Re: MultiXact\SLRU buffers configuration Andrey Borodin <[email protected]>
2020-12-23 16:31 ` Re: MultiXact\SLRU buffers configuration Gilles Darold <[email protected]>
2021-02-15 17:17 ` Re: MultiXact\SLRU buffers configuration Andrey Borodin <[email protected]>
2021-03-11 15:50 ` Re: MultiXact\SLRU buffers configuration Gilles Darold <[email protected]>
2021-03-12 12:44 ` Re: MultiXact\SLRU buffers configuration Andrey Borodin <[email protected]>
2021-03-24 21:31 ` Re: MultiXact\SLRU buffers configuration Thomas Munro <[email protected]>
2021-03-25 01:03 ` Re: MultiXact\SLRU buffers configuration Thomas Munro <[email protected]>
2021-03-26 03:46 ` Re: MultiXact\SLRU buffers configuration Thomas Munro <[email protected]>
2021-03-26 06:00 ` Re: MultiXact\SLRU buffers configuration Andrey Borodin <[email protected]>
2021-03-26 15:52 ` Re: MultiXact\SLRU buffers configuration Andrey Borodin <[email protected]>
2021-03-26 20:26 ` Re: MultiXact\SLRU buffers configuration Thomas Munro <[email protected]>
2021-03-27 05:31 ` Re: MultiXact\SLRU buffers configuration Andrey Borodin <[email protected]>
2021-03-28 21:15 ` Re: MultiXact\SLRU buffers configuration Thomas Munro <[email protected]>
2021-03-29 08:26 ` Re: MultiXact\SLRU buffers configuration Andrey Borodin <[email protected]>
2021-03-31 21:09 ` Re: MultiXact\SLRU buffers configuration Andrey Borodin <[email protected]>
2021-04-01 03:40 ` Re: MultiXact\SLRU buffers configuration Thomas Munro <[email protected]>
2021-04-03 19:57 ` Re: MultiXact\SLRU buffers configuration Andrey Borodin <[email protected]>
@ 2021-04-07 05:59 ` Thomas Munro <[email protected]>
2021-04-07 11:44 ` Re: MultiXact\SLRU buffers configuration Andrey Borodin <[email protected]>
0 siblings, 1 reply; 90+ messages in thread
From: Thomas Munro @ 2021-04-07 05:59 UTC (permalink / raw)
To: Andrey Borodin <[email protected]>; +Cc: Gilles Darold <[email protected]>; Tomas Vondra <[email protected]>; Tomas Vondra <[email protected]>; Alexander Korotkov <[email protected]>; Anastasia Lubennikova <[email protected]>; Daniel Gustafsson <[email protected]>; Kyotaro Horiguchi <[email protected]>; pgsql-hackers
On Sun, Apr 4, 2021 at 7:57 AM Andrey Borodin <[email protected]> wrote:
> I was toying around with big values. For example if we set different big
xact_buffers we can get something like
> FATAL: not enough shared memory for data structure "Notify" (72768 bytes
requested)
> FATAL: not enough shared memory for data structure "Async Queue Control"
(2492 bytes requested)
> FATAL: not enough shared memory for data structure "Checkpointer Data"
(393280 bytes requested)
>
> But never anything about xact_buffers. I don't think it's important,
though.
I had added the hash table size in SimpleLruShmemSize(), but then
SimpleLruInit() passed that same value in when allocating the struct, so
the struct was oversized. Oops. Fixed.
> > Likewise, I removed the cap of 16 buffers for commit_ts_buffers, but
> > only if you have track_commit_timestamp enabled.
> Is there a reason to leave 16 pages if commit_ts is disabled? They might
be useful for some artefacts of previously enabled commit_ts?
Alvaro, do you have an opinion on that?
The remaining thing that bothers me about this patch set is that there is
still a linear search in the replacement algorithm, and it runs with an
exclusive lock. That creates a serious problem for large caches that still
aren't large enough. I wonder if we can do something to improve that
situation in the time we have. I considered a bunch of ideas but could
only find one that fits with slru.c's simplistic locking while tracking
recency. What do you think about a hybrid of SLRU and random replacement,
that retains some characteristics of both? You could think of it as being
a bit like the tournament selection of the genetic algorithm, with a
tournament size of (say) 8 or 16. Any ideas on how to evaluate this and
choose the number? See attached.
Attachments:
[text/x-patch] v15-0001-Add-a-buffer-mapping-table-for-SLRUs.patch (9.0K, ../../CA+hUKGKTESKn9-BkUT8T3vwcgZQJqsV4PSQKpE+M1qUgfSTLMg@mail.gmail.com/3-v15-0001-Add-a-buffer-mapping-table-for-SLRUs.patch)
download | inline diff:
From 5f61bd7d227077f86649a890be603eae01c828f8 Mon Sep 17 00:00:00 2001
From: Thomas Munro <[email protected]>
Date: Thu, 25 Mar 2021 10:11:31 +1300
Subject: [PATCH v15 1/3] Add a buffer mapping table for SLRUs.
Instead of doing a linear search for the buffer holding a given page
number, use a hash table. This will allow us to increase the size of
these caches.
Reviewed-by: Andrey M. Borodin <[email protected]>
Discussion: https://postgr.es/m/2BEC2B3F-9B61-4C1D-9FB5-5FAB0F05EF86%40yandex-team.ru
---
src/backend/access/transam/slru.c | 121 +++++++++++++++++++++++++-----
src/include/access/slru.h | 2 +
2 files changed, 103 insertions(+), 20 deletions(-)
diff --git a/src/backend/access/transam/slru.c b/src/backend/access/transam/slru.c
index 82149ad782..82c61c475b 100644
--- a/src/backend/access/transam/slru.c
+++ b/src/backend/access/transam/slru.c
@@ -58,6 +58,7 @@
#include "pgstat.h"
#include "storage/fd.h"
#include "storage/shmem.h"
+#include "utils/hsearch.h"
#define SlruFileName(ctl, path, seg) \
snprintf(path, MAXPGPATH, "%s/%04X", (ctl)->Dir, seg)
@@ -79,6 +80,12 @@ typedef struct SlruWriteAllData
typedef struct SlruWriteAllData *SlruWriteAll;
+typedef struct SlruMappingTableEntry
+{
+ int pageno;
+ int slotno;
+} SlruMappingTableEntry;
+
/*
* Populate a file tag describing a segment file. We only use the segment
* number, since we can derive everything else we need by having separate
@@ -146,13 +153,16 @@ static int SlruSelectLRUPage(SlruCtl ctl, int pageno);
static bool SlruScanDirCbDeleteCutoff(SlruCtl ctl, char *filename,
int segpage, void *data);
static void SlruInternalDeleteSegment(SlruCtl ctl, int segno);
+static void SlruMappingAdd(SlruCtl ctl, int pageno, int slotno);
+static void SlruMappingRemove(SlruCtl ctl, int pageno);
+static int SlruMappingFind(SlruCtl ctl, int pageno);
/*
* Initialization of shared memory
*/
-Size
-SimpleLruShmemSize(int nslots, int nlsns)
+static Size
+SimpleLruStructSize(int nslots, int nlsns)
{
Size sz;
@@ -167,10 +177,16 @@ SimpleLruShmemSize(int nslots, int nlsns)
if (nlsns > 0)
sz += MAXALIGN(nslots * nlsns * sizeof(XLogRecPtr)); /* group_lsn[] */
-
return BUFFERALIGN(sz) + BLCKSZ * nslots;
}
+Size
+SimpleLruShmemSize(int nslots, int nlsns)
+{
+ return SimpleLruStructSize(nslots, nlsns) +
+ hash_estimate_size(nslots, sizeof(SlruMappingTableEntry));
+}
+
/*
* Initialize, or attach to, a simple LRU cache in shared memory.
*
@@ -187,11 +203,14 @@ SimpleLruInit(SlruCtl ctl, const char *name, int nslots, int nlsns,
LWLock *ctllock, const char *subdir, int tranche_id,
SyncRequestHandler sync_handler)
{
+ char mapping_table_name[SHMEM_INDEX_KEYSIZE];
+ HASHCTL mapping_table_info;
+ HTAB *mapping_table;
SlruShared shared;
bool found;
shared = (SlruShared) ShmemInitStruct(name,
- SimpleLruShmemSize(nslots, nlsns),
+ SimpleLruStructSize(nslots, nlsns),
&found);
if (!IsUnderPostmaster)
@@ -258,11 +277,21 @@ SimpleLruInit(SlruCtl ctl, const char *name, int nslots, int nlsns,
else
Assert(found);
+ /* Create or find the buffer mapping table. */
+ memset(&mapping_table_info, 0, sizeof(mapping_table_info));
+ mapping_table_info.keysize = sizeof(int);
+ mapping_table_info.entrysize = sizeof(SlruMappingTableEntry);
+ snprintf(mapping_table_name, sizeof(mapping_table_name),
+ "%s Lookup Table", name);
+ mapping_table = ShmemInitHash(mapping_table_name, nslots, nslots,
+ &mapping_table_info, HASH_ELEM | HASH_BLOBS);
+
/*
* Initialize the unshared control struct, including directory path. We
* assume caller set PagePrecedes.
*/
ctl->shared = shared;
+ ctl->mapping_table = mapping_table;
ctl->sync_handler = sync_handler;
strlcpy(ctl->Dir, subdir, sizeof(ctl->Dir));
}
@@ -289,6 +318,9 @@ SimpleLruZeroPage(SlruCtl ctl, int pageno)
shared->page_number[slotno] == pageno);
/* Mark the slot as containing this page */
+ if (shared->page_status[slotno] != SLRU_PAGE_EMPTY)
+ SlruMappingRemove(ctl, shared->page_number[slotno]);
+ SlruMappingAdd(ctl, pageno, slotno);
shared->page_number[slotno] = pageno;
shared->page_status[slotno] = SLRU_PAGE_VALID;
shared->page_dirty[slotno] = true;
@@ -362,7 +394,10 @@ SimpleLruWaitIO(SlruCtl ctl, int slotno)
{
/* indeed, the I/O must have failed */
if (shared->page_status[slotno] == SLRU_PAGE_READ_IN_PROGRESS)
+ {
+ SlruMappingRemove(ctl, shared->page_number[slotno]);
shared->page_status[slotno] = SLRU_PAGE_EMPTY;
+ }
else /* write_in_progress */
{
shared->page_status[slotno] = SLRU_PAGE_VALID;
@@ -436,6 +471,9 @@ SimpleLruReadPage(SlruCtl ctl, int pageno, bool write_ok,
!shared->page_dirty[slotno]));
/* Mark the slot read-busy */
+ if (shared->page_status[slotno] != SLRU_PAGE_EMPTY)
+ SlruMappingRemove(ctl, shared->page_number[slotno]);
+ SlruMappingAdd(ctl, pageno, slotno);
shared->page_number[slotno] = pageno;
shared->page_status[slotno] = SLRU_PAGE_READ_IN_PROGRESS;
shared->page_dirty[slotno] = false;
@@ -459,7 +497,13 @@ SimpleLruReadPage(SlruCtl ctl, int pageno, bool write_ok,
shared->page_status[slotno] == SLRU_PAGE_READ_IN_PROGRESS &&
!shared->page_dirty[slotno]);
- shared->page_status[slotno] = ok ? SLRU_PAGE_VALID : SLRU_PAGE_EMPTY;
+ if (ok)
+ shared->page_status[slotno] = SLRU_PAGE_VALID;
+ else
+ {
+ SlruMappingRemove(ctl, pageno);
+ shared->page_status[slotno] = SLRU_PAGE_EMPTY;
+ }
LWLockRelease(&shared->buffer_locks[slotno].lock);
@@ -500,20 +544,20 @@ SimpleLruReadPage_ReadOnly(SlruCtl ctl, int pageno, TransactionId xid)
LWLockAcquire(shared->ControlLock, LW_SHARED);
/* See if page is already in a buffer */
- for (slotno = 0; slotno < shared->num_slots; slotno++)
+ slotno = SlruMappingFind(ctl, pageno);
+ if (slotno >= 0 &&
+ shared->page_status[slotno] != SLRU_PAGE_READ_IN_PROGRESS)
{
- if (shared->page_number[slotno] == pageno &&
- shared->page_status[slotno] != SLRU_PAGE_EMPTY &&
- shared->page_status[slotno] != SLRU_PAGE_READ_IN_PROGRESS)
- {
- /* See comments for SlruRecentlyUsed macro */
- SlruRecentlyUsed(shared, slotno);
+ Assert(shared->page_status[slotno] != SLRU_PAGE_EMPTY);
+ Assert(shared->page_number[slotno] == pageno);
- /* update the stats counter of pages found in the SLRU */
- pgstat_count_slru_page_hit(shared->slru_stats_idx);
+ /* See comments for SlruRecentlyUsed macro */
+ SlruRecentlyUsed(shared, slotno);
- return slotno;
- }
+ /* update the stats counter of pages found in the SLRU */
+ pgstat_count_slru_page_hit(shared->slru_stats_idx);
+
+ return slotno;
}
/* No luck, so switch to normal exclusive lock and do regular read */
@@ -1029,11 +1073,12 @@ SlruSelectLRUPage(SlruCtl ctl, int pageno)
int best_invalid_page_number = 0; /* keep compiler quiet */
/* See if page already has a buffer assigned */
- for (slotno = 0; slotno < shared->num_slots; slotno++)
+ slotno = SlruMappingFind(ctl, pageno);
+ if (slotno >= 0)
{
- if (shared->page_number[slotno] == pageno &&
- shared->page_status[slotno] != SLRU_PAGE_EMPTY)
- return slotno;
+ Assert(shared->page_number[slotno] == pageno);
+ Assert(shared->page_status[slotno] != SLRU_PAGE_EMPTY);
+ return slotno;
}
/*
@@ -1266,6 +1311,7 @@ restart:;
if (shared->page_status[slotno] == SLRU_PAGE_VALID &&
!shared->page_dirty[slotno])
{
+ SlruMappingRemove(ctl, shared->page_number[slotno]);
shared->page_status[slotno] = SLRU_PAGE_EMPTY;
continue;
}
@@ -1348,6 +1394,7 @@ restart:
if (shared->page_status[slotno] == SLRU_PAGE_VALID &&
!shared->page_dirty[slotno])
{
+ SlruMappingRemove(ctl, shared->page_number[slotno]);
shared->page_status[slotno] = SLRU_PAGE_EMPTY;
continue;
}
@@ -1609,3 +1656,37 @@ SlruSyncFileTag(SlruCtl ctl, const FileTag *ftag, char *path)
errno = save_errno;
return result;
}
+
+static int
+SlruMappingFind(SlruCtl ctl, int pageno)
+{
+ SlruMappingTableEntry *mapping;
+
+ mapping = hash_search(ctl->mapping_table, &pageno, HASH_FIND, NULL);
+ if (mapping)
+ return mapping->slotno;
+
+ return -1;
+}
+
+static void
+SlruMappingAdd(SlruCtl ctl, int pageno, int slotno)
+{
+ SlruMappingTableEntry *mapping;
+ bool found PG_USED_FOR_ASSERTS_ONLY;
+
+ mapping = hash_search(ctl->mapping_table, &pageno, HASH_ENTER, &found);
+ mapping->slotno = slotno;
+
+ Assert(!found);
+}
+
+static void
+SlruMappingRemove(SlruCtl ctl, int pageno)
+{
+ bool found PG_USED_FOR_ASSERTS_ONLY;
+
+ hash_search(ctl->mapping_table, &pageno, HASH_REMOVE, &found);
+
+ Assert(found);
+}
diff --git a/src/include/access/slru.h b/src/include/access/slru.h
index dd52e8cec7..8aa3efc0ee 100644
--- a/src/include/access/slru.h
+++ b/src/include/access/slru.h
@@ -16,6 +16,7 @@
#include "access/xlogdefs.h"
#include "storage/lwlock.h"
#include "storage/sync.h"
+#include "utils/hsearch.h"
/*
@@ -110,6 +111,7 @@ typedef SlruSharedData *SlruShared;
typedef struct SlruCtlData
{
SlruShared shared;
+ HTAB *mapping_table;
/*
* Which sync handler function to use when handing sync requests over to
--
2.27.0
[text/x-patch] v15-0002-Make-all-SLRU-buffer-sizes-configurable.patch (25.7K, ../../CA+hUKGKTESKn9-BkUT8T3vwcgZQJqsV4PSQKpE+M1qUgfSTLMg@mail.gmail.com/4-v15-0002-Make-all-SLRU-buffer-sizes-configurable.patch)
download | inline diff:
From 3462ffe7d740ef0a8d6b217a338fa5cb55a1fbcc Mon Sep 17 00:00:00 2001
From: Andrey Borodin <[email protected]>
Date: Mon, 15 Feb 2021 21:51:56 +0500
Subject: [PATCH v15 2/3] Make all SLRU buffer sizes configurable.
Provide new GUCs to set the number of buffers, instead of using hard
coded defaults.
Remove the limits on xact_buffers and commit_ts_buffers. The default
sizes for those caches are ~0.2% and ~0.1% of shared_buffers, as before,
but now there is no cap at 128 and 16 buffers respectively (unless
track_commit_timestamp is disabled, in the latter case, then we might as
well keep it tiny). Sizes much larger than the old limits have been
shown to be useful on modern systems, and an earlier commit replaced a
linear search with a hash table to avoid problems with extreme cases.
Author: Andrey M. Borodin <[email protected]>
Reviewed-by: Anastasia Lubennikova <[email protected]>
Reviewed-by: Tomas Vondra <[email protected]>
Reviewed-by: Alexander Korotkov <[email protected]>
Reviewed-by: Gilles Darold <[email protected]>
Reviewed-by: Thomas Munro <[email protected]>
Discussion: https://postgr.es/m/2BEC2B3F-9B61-4C1D-9FB5-5FAB0F05EF86%40yandex-team.ru
---
doc/src/sgml/config.sgml | 135 ++++++++++++++++++
src/backend/access/transam/clog.c | 23 ++-
src/backend/access/transam/commit_ts.c | 10 +-
src/backend/access/transam/multixact.c | 8 +-
src/backend/access/transam/subtrans.c | 5 +-
src/backend/commands/async.c | 8 +-
src/backend/storage/lmgr/predicate.c | 4 +-
src/backend/utils/init/globals.c | 8 ++
src/backend/utils/misc/guc.c | 99 +++++++++++++
src/backend/utils/misc/postgresql.conf.sample | 9 ++
src/include/access/clog.h | 10 ++
src/include/access/commit_ts.h | 1 -
src/include/access/multixact.h | 4 -
src/include/access/slru.h | 5 +
src/include/access/subtrans.h | 2 -
src/include/commands/async.h | 5 -
src/include/miscadmin.h | 7 +
src/include/storage/predicate.h | 4 -
18 files changed, 301 insertions(+), 46 deletions(-)
diff --git a/doc/src/sgml/config.sgml b/doc/src/sgml/config.sgml
index e51639d56c..79f46a3df8 100644
--- a/doc/src/sgml/config.sgml
+++ b/doc/src/sgml/config.sgml
@@ -1924,6 +1924,141 @@ include_dir 'conf.d'
</para>
</listitem>
</varlistentry>
+
+ <varlistentry id="guc-multixact-offsets-buffers" xreflabel="multixact_offsets_buffers">
+ <term><varname>multixact_offsets_buffers</varname> (<type>integer</type>)
+ <indexterm>
+ <primary><varname>multixact_offsets_buffers</varname> configuration parameter</primary>
+ </indexterm>
+ </term>
+ <listitem>
+ <para>
+ Specifies the amount of shared memory to use to cache the contents
+ of <literal>pg_multixact/offsets</literal> (see
+ <xref linkend="pgdata-contents-table"/>).
+ If this value is specified without units, it is taken as blocks,
+ that is <symbol>BLCKSZ</symbol> bytes, typically 8kB.
+ The default value is <literal>8</literal>.
+ This parameter can only be set at server start.
+ </para>
+ </listitem>
+ </varlistentry>
+
+ <varlistentry id="guc-multixact-members-buffers" xreflabel="multixact_members_buffers">
+ <term><varname>multixact_members_buffers</varname> (<type>integer</type>)
+ <indexterm>
+ <primary><varname>multixact_members_buffers</varname> configuration parameter</primary>
+ </indexterm>
+ </term>
+ <listitem>
+ <para>
+ Specifies the amount of shared memory to use to cache the contents
+ of <literal>pg_multixact/members</literal> (see
+ <xref linkend="pgdata-contents-table"/>).
+ If this value is specified without units, it is taken as blocks,
+ that is <symbol>BLCKSZ</symbol> bytes, typically 8kB.
+ The default value is <literal>16</literal>.
+ This parameter can only be set at server start.
+ </para>
+ </listitem>
+ </varlistentry>
+
+ <varlistentry id="guc-subtrans-buffers" xreflabel="subtrans_buffers">
+ <term><varname>subtrans_buffers</varname> (<type>integer</type>)
+ <indexterm>
+ <primary><varname>subtrans_buffers</varname> configuration parameter</primary>
+ </indexterm>
+ </term>
+ <listitem>
+ <para>
+ Specifies the amount of shared memory to use to cache the contents
+ of <literal>pg_subtrans</literal> (see
+ <xref linkend="pgdata-contents-table"/>).
+ If this value is specified without units, it is taken as blocks,
+ that is <symbol>BLCKSZ</symbol> bytes, typically 8kB.
+ The default value is <literal>8</literal>.
+ This parameter can only be set at server start.
+ </para>
+ </listitem>
+ </varlistentry>
+
+ <varlistentry id="guc-notify-buffers" xreflabel="notify_buffers">
+ <term><varname>notify_buffers</varname> (<type>integer</type>)
+ <indexterm>
+ <primary><varname>notify_buffers</varname> configuration parameter</primary>
+ </indexterm>
+ </term>
+ <listitem>
+ <para>
+ Specifies the amount of shared memory to use to cache the contents
+ of <literal>pg_notify</literal> (see
+ <xref linkend="pgdata-contents-table"/>).
+ If this value is specified without units, it is taken as blocks,
+ that is <symbol>BLCKSZ</symbol> bytes, typically 8kB.
+ The default value is <literal>8</literal>.
+ This parameter can only be set at server start.
+ </para>
+ </listitem>
+ </varlistentry>
+
+ <varlistentry id="guc-serial-buffers" xreflabel="serial_buffers">
+ <term><varname>serial_buffers</varname> (<type>integer</type>)
+ <indexterm>
+ <primary><varname>serial_buffers</varname> configuration parameter</primary>
+ </indexterm>
+ </term>
+ <listitem>
+ <para>
+ Specifies the amount of shared memory to use to cache the contents
+ of <literal>pg_serial</literal> (see
+ <xref linkend="pgdata-contents-table"/>).
+ If this value is specified without units, it is taken as blocks,
+ that is <symbol>BLCKSZ</symbol> bytes, typically 8kB.
+ The default value is <literal>16</literal>.
+ This parameter can only be set at server start.
+ </para>
+ </listitem>
+ </varlistentry>
+
+ <varlistentry id="guc-xact-buffers" xreflabel="xact_buffers">
+ <term><varname>xact_buffers</varname> (<type>integer</type>)
+ <indexterm>
+ <primary><varname>xact_buffers</varname> configuration parameter</primary>
+ </indexterm>
+ </term>
+ <listitem>
+ <para>
+ Specifies the amount of shared memory to use to cache the contents
+ of <literal>pg_xact</literal> (see
+ <xref linkend="pgdata-contents-table"/>).
+ If this value is specified without units, it is taken as blocks,
+ that is <symbol>BLCKSZ</symbol> bytes, typically 8kB.
+ The default value is <literal>0</literal>, which requests
+ <varname>shared_buffers</varname> / 512, but not fewer than 4 blocks.
+ This parameter can only be set at server start.
+ </para>
+ </listitem>
+ </varlistentry>
+
+ <varlistentry id="guc-commit-ts-buffers" xreflabel="commit_ts_buffers">
+ <term><varname>commit_ts_buffers</varname> (<type>integer</type>)
+ <indexterm>
+ <primary><varname>commit_ts_buffers</varname> configuration parameter</primary>
+ </indexterm>
+ </term>
+ <listitem>
+ <para>
+ Specifies the amount of memory to use to cache the cotents of
+ <literal>pg_commit_ts</literal> (see
+ <xref linkend="pgdata-contents-table"/>).
+ If this value is specified without units, it is taken as blocks,
+ that is <symbol>BLCKSZ</symbol> bytes, typically 8kB.
+ The default value is <literal>0</literal>, which requests
+ <varname>shared_buffers</varname> / 1024, but not fewer than 4 blocks.
+ This parameter can only be set at server start.
+ </para>
+ </listitem>
+ </varlistentry>
<varlistentry id="guc-max-stack-depth" xreflabel="max_stack_depth">
<term><varname>max_stack_depth</varname> (<type>integer</type>)
diff --git a/src/backend/access/transam/clog.c b/src/backend/access/transam/clog.c
index 6fa4713fb4..dd2d7a5184 100644
--- a/src/backend/access/transam/clog.c
+++ b/src/backend/access/transam/clog.c
@@ -58,8 +58,8 @@
/* We need two bits per xact, so four xacts fit in a byte */
#define CLOG_BITS_PER_XACT 2
-#define CLOG_XACTS_PER_BYTE 4
-#define CLOG_XACTS_PER_PAGE (BLCKSZ * CLOG_XACTS_PER_BYTE)
+StaticAssertDecl((CLOG_BITS_PER_XACT * CLOG_XACTS_PER_BYTE) == BITS_PER_BYTE,
+ "CLOG_BITS_PER_XACT and CLOG_XACTS_PER_BYTE are inconsistent");
#define CLOG_XACT_BITMASK ((1 << CLOG_BITS_PER_XACT) - 1)
#define TransactionIdToPage(xid) ((xid) / (TransactionId) CLOG_XACTS_PER_PAGE)
@@ -659,23 +659,16 @@ TransactionIdGetStatus(TransactionId xid, XLogRecPtr *lsn)
/*
* Number of shared CLOG buffers.
*
- * On larger multi-processor systems, it is possible to have many CLOG page
- * requests in flight at one time which could lead to disk access for CLOG
- * page if the required page is not found in memory. Testing revealed that we
- * can get the best performance by having 128 CLOG buffers, more than that it
- * doesn't improve performance.
- *
- * Unconditionally keeping the number of CLOG buffers to 128 did not seem like
- * a good idea, because it would increase the minimum amount of shared memory
- * required to start, which could be a problem for people running very small
- * configurations. The following formula seems to represent a reasonable
- * compromise: people with very low values for shared_buffers will get fewer
- * CLOG buffers as well, and everyone else will get 128.
+ * By default, we'll use 2MB of for every 1GB of shared buffers, up to the
+ * theoretical maximum useful value, but always at least 4 buffers.
*/
Size
CLOGShmemBuffers(void)
{
- return Min(128, Max(4, NBuffers / 512));
+ /* Use configured value if provided. */
+ if (xact_buffers > 0)
+ return Max(4, xact_buffers);
+ return Min(CLOG_MAX_ALLOWED_BUFFERS, Max(4, NBuffers / 512));
}
/*
diff --git a/src/backend/access/transam/commit_ts.c b/src/backend/access/transam/commit_ts.c
index 268bdba339..729a4b9212 100644
--- a/src/backend/access/transam/commit_ts.c
+++ b/src/backend/access/transam/commit_ts.c
@@ -524,13 +524,17 @@ pg_xact_commit_timestamp_origin(PG_FUNCTION_ARGS)
/*
* Number of shared CommitTS buffers.
*
- * We use a very similar logic as for the number of CLOG buffers; see comments
- * in CLOGShmemBuffers.
+ * By default, we'll use 1MB of for every 1GB of shared buffers, up to the
+ * maximum value that slru.c will allow, but always at least 4 buffers.
*/
Size
CommitTsShmemBuffers(void)
{
- return Min(16, Max(4, NBuffers / 1024));
+ /* Use configured value if provided. */
+ if (commit_ts_buffers > 0)
+ return Max(4, commit_ts_buffers);
+ return Min(track_commit_timestamp ? SLRU_MAX_ALLOWED_BUFFERS : 16,
+ Max(4, NBuffers / 1024));
}
/*
diff --git a/src/backend/access/transam/multixact.c b/src/backend/access/transam/multixact.c
index 1f9f1a1fa1..21787765e2 100644
--- a/src/backend/access/transam/multixact.c
+++ b/src/backend/access/transam/multixact.c
@@ -1831,8 +1831,8 @@ MultiXactShmemSize(void)
mul_size(sizeof(MultiXactId) * 2, MaxOldestSlot))
size = SHARED_MULTIXACT_STATE_SIZE;
- size = add_size(size, SimpleLruShmemSize(NUM_MULTIXACTOFFSET_BUFFERS, 0));
- size = add_size(size, SimpleLruShmemSize(NUM_MULTIXACTMEMBER_BUFFERS, 0));
+ size = add_size(size, SimpleLruShmemSize(multixact_offsets_buffers, 0));
+ size = add_size(size, SimpleLruShmemSize(multixact_members_buffers, 0));
return size;
}
@@ -1848,13 +1848,13 @@ MultiXactShmemInit(void)
MultiXactMemberCtl->PagePrecedes = MultiXactMemberPagePrecedes;
SimpleLruInit(MultiXactOffsetCtl,
- "MultiXactOffset", NUM_MULTIXACTOFFSET_BUFFERS, 0,
+ "MultiXactOffset", multixact_offsets_buffers, 0,
MultiXactOffsetSLRULock, "pg_multixact/offsets",
LWTRANCHE_MULTIXACTOFFSET_BUFFER,
SYNC_HANDLER_MULTIXACT_OFFSET);
SlruPagePrecedesUnitTests(MultiXactOffsetCtl, MULTIXACT_OFFSETS_PER_PAGE);
SimpleLruInit(MultiXactMemberCtl,
- "MultiXactMember", NUM_MULTIXACTMEMBER_BUFFERS, 0,
+ "MultiXactMember", multixact_offsets_buffers, 0,
MultiXactMemberSLRULock, "pg_multixact/members",
LWTRANCHE_MULTIXACTMEMBER_BUFFER,
SYNC_HANDLER_MULTIXACT_MEMBER);
diff --git a/src/backend/access/transam/subtrans.c b/src/backend/access/transam/subtrans.c
index 6a8e521f89..785f2520fd 100644
--- a/src/backend/access/transam/subtrans.c
+++ b/src/backend/access/transam/subtrans.c
@@ -31,6 +31,7 @@
#include "access/slru.h"
#include "access/subtrans.h"
#include "access/transam.h"
+#include "miscadmin.h"
#include "pg_trace.h"
#include "utils/snapmgr.h"
@@ -184,14 +185,14 @@ SubTransGetTopmostTransaction(TransactionId xid)
Size
SUBTRANSShmemSize(void)
{
- return SimpleLruShmemSize(NUM_SUBTRANS_BUFFERS, 0);
+ return SimpleLruShmemSize(subtrans_buffers, 0);
}
void
SUBTRANSShmemInit(void)
{
SubTransCtl->PagePrecedes = SubTransPagePrecedes;
- SimpleLruInit(SubTransCtl, "Subtrans", NUM_SUBTRANS_BUFFERS, 0,
+ SimpleLruInit(SubTransCtl, "Subtrans", subtrans_buffers, 0,
SubtransSLRULock, "pg_subtrans",
LWTRANCHE_SUBTRANS_BUFFER, SYNC_HANDLER_NONE);
SlruPagePrecedesUnitTests(SubTransCtl, SUBTRANS_XACTS_PER_PAGE);
diff --git a/src/backend/commands/async.c b/src/backend/commands/async.c
index 4b16fb5682..de17f52cd7 100644
--- a/src/backend/commands/async.c
+++ b/src/backend/commands/async.c
@@ -107,7 +107,7 @@
* frontend during startup.) The above design guarantees that notifies from
* other backends will never be missed by ignoring self-notifies.
*
- * The amount of shared memory used for notify management (NUM_NOTIFY_BUFFERS)
+ * The amount of shared memory used for notify management (notify_buffers)
* can be varied without affecting anything but performance. The maximum
* amount of notification data that can be queued at one time is determined
* by slru.c's wraparound limit; see QUEUE_MAX_PAGE below.
@@ -225,7 +225,7 @@ typedef struct QueuePosition
*
* Resist the temptation to make this really large. While that would save
* work in some places, it would add cost in others. In particular, this
- * should likely be less than NUM_NOTIFY_BUFFERS, to ensure that backends
+ * should likely be less than notify_buffers, to ensure that backends
* catch up before the pages they'll need to read fall out of SLRU cache.
*/
#define QUEUE_CLEANUP_DELAY 4
@@ -514,7 +514,7 @@ AsyncShmemSize(void)
size = mul_size(MaxBackends + 1, sizeof(QueueBackendStatus));
size = add_size(size, offsetof(AsyncQueueControl, backend));
- size = add_size(size, SimpleLruShmemSize(NUM_NOTIFY_BUFFERS, 0));
+ size = add_size(size, SimpleLruShmemSize(notify_buffers, 0));
return size;
}
@@ -562,7 +562,7 @@ AsyncShmemInit(void)
* Set up SLRU management of the pg_notify data.
*/
NotifyCtl->PagePrecedes = asyncQueuePagePrecedes;
- SimpleLruInit(NotifyCtl, "Notify", NUM_NOTIFY_BUFFERS, 0,
+ SimpleLruInit(NotifyCtl, "Notify", notify_buffers, 0,
NotifySLRULock, "pg_notify", LWTRANCHE_NOTIFY_BUFFER,
SYNC_HANDLER_NONE);
diff --git a/src/backend/storage/lmgr/predicate.c b/src/backend/storage/lmgr/predicate.c
index d493aeef0f..b1f4f1651d 100644
--- a/src/backend/storage/lmgr/predicate.c
+++ b/src/backend/storage/lmgr/predicate.c
@@ -872,7 +872,7 @@ SerialInit(void)
*/
SerialSlruCtl->PagePrecedes = SerialPagePrecedesLogically;
SimpleLruInit(SerialSlruCtl, "Serial",
- NUM_SERIAL_BUFFERS, 0, SerialSLRULock, "pg_serial",
+ serial_buffers, 0, SerialSLRULock, "pg_serial",
LWTRANCHE_SERIAL_BUFFER, SYNC_HANDLER_NONE);
#ifdef USE_ASSERT_CHECKING
SerialPagePrecedesLogicallyUnitTests();
@@ -1395,7 +1395,7 @@ PredicateLockShmemSize(void)
/* Shared memory structures for SLRU tracking of old committed xids. */
size = add_size(size, sizeof(SerialControlData));
- size = add_size(size, SimpleLruShmemSize(NUM_SERIAL_BUFFERS, 0));
+ size = add_size(size, SimpleLruShmemSize(serial_buffers, 0));
return size;
}
diff --git a/src/backend/utils/init/globals.c b/src/backend/utils/init/globals.c
index 381d9e548d..c83151d5ab 100644
--- a/src/backend/utils/init/globals.c
+++ b/src/backend/utils/init/globals.c
@@ -150,3 +150,11 @@ int64 VacuumPageDirty = 0;
int VacuumCostBalance = 0; /* working state for vacuum */
bool VacuumCostActive = false;
+
+int multixact_offsets_buffers = 8;
+int multixact_members_buffers = 16;
+int subtrans_buffers = 32;
+int notify_buffers = 8;
+int serial_buffers = 16;
+int xact_buffers = 0;
+int commit_ts_buffers = 0;
diff --git a/src/backend/utils/misc/guc.c b/src/backend/utils/misc/guc.c
index c9c9da85f3..d0f0532daa 100644
--- a/src/backend/utils/misc/guc.c
+++ b/src/backend/utils/misc/guc.c
@@ -32,9 +32,11 @@
#endif
#include <unistd.h>
+#include "access/clog.h"
#include "access/commit_ts.h"
#include "access/gin.h"
#include "access/rmgr.h"
+#include "access/slru.h"
#include "access/tableam.h"
#include "access/toast_compression.h"
#include "access/transam.h"
@@ -200,6 +202,8 @@ static const char *show_tcp_keepalives_idle(void);
static const char *show_tcp_keepalives_interval(void);
static const char *show_tcp_keepalives_count(void);
static const char *show_tcp_user_timeout(void);
+static const char *show_xact_buffers(void);
+static const char *show_commit_ts_buffers(void);
static bool check_maxconnections(int *newval, void **extra, GucSource source);
static bool check_max_worker_processes(int *newval, void **extra, GucSource source);
static bool check_autovacuum_max_workers(int *newval, void **extra, GucSource source);
@@ -2330,6 +2334,83 @@ static struct config_int ConfigureNamesInt[] =
NULL, NULL, NULL
},
+ {
+ {"multixact_offsets_buffers", PGC_POSTMASTER, RESOURCES_MEM,
+ gettext_noop("Sets the number of shared memory buffers used for the MultiXact offset SLRU cache."),
+ NULL,
+ GUC_UNIT_BLOCKS
+ },
+ &multixact_offsets_buffers,
+ 8, 2, SLRU_MAX_ALLOWED_BUFFERS,
+ NULL, NULL, NULL
+ },
+
+ {
+ {"multixact_members_buffers", PGC_POSTMASTER, RESOURCES_MEM,
+ gettext_noop("Sets the number of shared memory buffers used for the MultiXact member SLRU cache."),
+ NULL,
+ GUC_UNIT_BLOCKS
+ },
+ &multixact_members_buffers,
+ 16, 2, SLRU_MAX_ALLOWED_BUFFERS,
+ NULL, NULL, NULL
+ },
+
+ {
+ {"subtrans_buffers", PGC_POSTMASTER, RESOURCES_MEM,
+ gettext_noop("Sets the number of shared memory buffers used for the sub-transaction SLRU cache."),
+ NULL,
+ GUC_UNIT_BLOCKS
+ },
+ &subtrans_buffers,
+ 32, 2, SLRU_MAX_ALLOWED_BUFFERS,
+ NULL, NULL, NULL
+ },
+
+ {
+ {"notify_buffers", PGC_POSTMASTER, RESOURCES_MEM,
+ gettext_noop("Sets the number of shared memory buffers used for the NOTIFY message SLRU cache."),
+ NULL,
+ GUC_UNIT_BLOCKS
+ },
+ ¬ify_buffers,
+ 8, 2, SLRU_MAX_ALLOWED_BUFFERS,
+ NULL, NULL, NULL
+ },
+
+ {
+ {"serial_buffers", PGC_POSTMASTER, RESOURCES_MEM,
+ gettext_noop("Sets the number of shared memory buffers used for the serializable transaction SLRU cache."),
+ NULL,
+ GUC_UNIT_BLOCKS
+ },
+ &serial_buffers,
+ 16, 2, SLRU_MAX_ALLOWED_BUFFERS,
+ NULL, NULL, NULL
+ },
+
+ {
+ {"xact_buffers", PGC_POSTMASTER, RESOURCES_MEM,
+ gettext_noop("Sets the number of shared memory buffers used for the transaction status SLRU cache."),
+ NULL,
+ GUC_UNIT_BLOCKS
+ },
+ &xact_buffers,
+ 0, 0, CLOG_MAX_ALLOWED_BUFFERS,
+ NULL, NULL, show_xact_buffers
+ },
+
+ {
+ {"commit_ts_buffers", PGC_POSTMASTER, RESOURCES_MEM,
+ gettext_noop("Sets the size of the dedicated buffer pool used for the commit timestamp SLRU cache."),
+ NULL,
+ GUC_UNIT_BLOCKS
+ },
+ &commit_ts_buffers,
+ 0, 0, SLRU_MAX_ALLOWED_BUFFERS,
+ NULL, NULL, show_commit_ts_buffers
+ },
+
{
{"temp_buffers", PGC_USERSET, RESOURCES_MEM,
gettext_noop("Sets the maximum number of temporary buffers used by each session."),
@@ -11897,6 +11978,24 @@ show_tcp_user_timeout(void)
return nbuf;
}
+static const char *
+show_xact_buffers(void)
+{
+ static char nbuf[16];
+
+ snprintf(nbuf, sizeof(nbuf), "%zu", CLOGShmemBuffers());
+ return nbuf;
+}
+
+static const char *
+show_commit_ts_buffers(void)
+{
+ static char nbuf[16];
+
+ snprintf(nbuf, sizeof(nbuf), "%zu", CommitTsShmemBuffers());
+ return nbuf;
+}
+
static bool
check_maxconnections(int *newval, void **extra, GucSource source)
{
diff --git a/src/backend/utils/misc/postgresql.conf.sample b/src/backend/utils/misc/postgresql.conf.sample
index 39da7cc942..5bbbf85923 100644
--- a/src/backend/utils/misc/postgresql.conf.sample
+++ b/src/backend/utils/misc/postgresql.conf.sample
@@ -190,6 +190,15 @@
# (change requires restart)
#backend_flush_after = 0 # measured in pages, 0 disables
+# - SLRU Buffers (change requires restart) -
+
+#xact_buffers = 0 # memory for pg_xact (0 = auto)
+#subtrans_buffers = 32 # memory for pg_subtrans
+#multixact_offsets_buffers = 8 # memory for pg_multixact/offsets
+#multixact_members_buffers = 16 # memory for pg_multixact/members
+#notify_buffers = 8 # memory for pg_notify
+#serial_buffers = 16 # memory for pg_serial
+#commit_ts_buffers = 0 # memory for pg_commit_ts (0 = auto)
#------------------------------------------------------------------------------
# WRITE-AHEAD LOG
diff --git a/src/include/access/clog.h b/src/include/access/clog.h
index 39b8e4afa8..739a292f7f 100644
--- a/src/include/access/clog.h
+++ b/src/include/access/clog.h
@@ -15,6 +15,16 @@
#include "storage/sync.h"
#include "lib/stringinfo.h"
+/*
+ * Don't allow xact_buffers to be set higher than could possibly be useful or
+ * SLRU would allow.
+ */
+#define CLOG_XACTS_PER_BYTE 4
+#define CLOG_XACTS_PER_PAGE (BLCKSZ * CLOG_XACTS_PER_BYTE)
+#define CLOG_MAX_ALLOWED_BUFFERS \
+ Min(SLRU_MAX_ALLOWED_BUFFERS, \
+ (((MaxTransactionId / 2) + (CLOG_XACTS_PER_PAGE - 1)) / CLOG_XACTS_PER_PAGE))
+
/*
* Possible transaction statuses --- note that all-zeroes is the initial
* state.
diff --git a/src/include/access/commit_ts.h b/src/include/access/commit_ts.h
index 750369104a..e4cf988609 100644
--- a/src/include/access/commit_ts.h
+++ b/src/include/access/commit_ts.h
@@ -17,7 +17,6 @@
#include "storage/sync.h"
#include "utils/guc.h"
-
extern PGDLLIMPORT bool track_commit_timestamp;
extern bool check_track_commit_timestamp(bool *newval, void **extra,
diff --git a/src/include/access/multixact.h b/src/include/access/multixact.h
index 4bbb035eae..97c0a46376 100644
--- a/src/include/access/multixact.h
+++ b/src/include/access/multixact.h
@@ -29,10 +29,6 @@
#define MaxMultiXactOffset ((MultiXactOffset) 0xFFFFFFFF)
-/* Number of SLRU buffers to use for multixact */
-#define NUM_MULTIXACTOFFSET_BUFFERS 8
-#define NUM_MULTIXACTMEMBER_BUFFERS 16
-
/*
* Possible multixact lock modes ("status"). The first four modes are for
* tuple locks (FOR KEY SHARE, FOR SHARE, FOR NO KEY UPDATE, FOR UPDATE); the
diff --git a/src/include/access/slru.h b/src/include/access/slru.h
index 8aa3efc0ee..97ea837646 100644
--- a/src/include/access/slru.h
+++ b/src/include/access/slru.h
@@ -18,6 +18,11 @@
#include "storage/sync.h"
#include "utils/hsearch.h"
+/*
+ * To avoid overflowing internal arithmetic and the size_t data type, the
+ * number of buffers should not exceed this number.
+ */
+#define SLRU_MAX_ALLOWED_BUFFERS ((1024 * 1024 * 1024) / BLCKSZ)
/*
* Define SLRU segment size. A page is the same BLCKSZ as is used everywhere
diff --git a/src/include/access/subtrans.h b/src/include/access/subtrans.h
index d0ab44ae82..64fa86938e 100644
--- a/src/include/access/subtrans.h
+++ b/src/include/access/subtrans.h
@@ -11,8 +11,6 @@
#ifndef SUBTRANS_H
#define SUBTRANS_H
-/* Number of SLRU buffers to use for subtrans */
-#define NUM_SUBTRANS_BUFFERS 32
extern void SubTransSetParent(TransactionId xid, TransactionId parent);
extern TransactionId SubTransGetParent(TransactionId xid);
diff --git a/src/include/commands/async.h b/src/include/commands/async.h
index 9217f66b91..fa831e3721 100644
--- a/src/include/commands/async.h
+++ b/src/include/commands/async.h
@@ -15,11 +15,6 @@
#include <signal.h>
-/*
- * The number of SLRU page buffers we use for the notification queue.
- */
-#define NUM_NOTIFY_BUFFERS 8
-
extern bool Trace_notify;
extern volatile sig_atomic_t notifyInterruptPending;
diff --git a/src/include/miscadmin.h b/src/include/miscadmin.h
index 95202d37af..495c1bf901 100644
--- a/src/include/miscadmin.h
+++ b/src/include/miscadmin.h
@@ -164,6 +164,13 @@ extern PGDLLIMPORT int MaxBackends;
extern PGDLLIMPORT int MaxConnections;
extern PGDLLIMPORT int max_worker_processes;
extern PGDLLIMPORT int max_parallel_workers;
+extern PGDLLIMPORT int multixact_offsets_buffers;
+extern PGDLLIMPORT int multixact_members_buffers;
+extern PGDLLIMPORT int subtrans_buffers;
+extern PGDLLIMPORT int notify_buffers;
+extern PGDLLIMPORT int serial_buffers;
+extern PGDLLIMPORT int xact_buffers;
+extern PGDLLIMPORT int commit_ts_buffers;
extern PGDLLIMPORT int MyProcPid;
extern PGDLLIMPORT pg_time_t MyStartTime;
diff --git a/src/include/storage/predicate.h b/src/include/storage/predicate.h
index 152b698611..c72779bd88 100644
--- a/src/include/storage/predicate.h
+++ b/src/include/storage/predicate.h
@@ -26,10 +26,6 @@ extern int max_predicate_locks_per_xact;
extern int max_predicate_locks_per_relation;
extern int max_predicate_locks_per_page;
-
-/* Number of SLRU buffers to use for Serial SLRU */
-#define NUM_SERIAL_BUFFERS 16
-
/*
* A handle used for sharing SERIALIZABLEXACT objects between the participants
* in a parallel query.
--
2.27.0
[text/x-patch] v15-0003-Use-hybrid-random-SLRU-replacement-for-SLRUs.patch (3.3K, ../../CA+hUKGKTESKn9-BkUT8T3vwcgZQJqsV4PSQKpE+M1qUgfSTLMg@mail.gmail.com/5-v15-0003-Use-hybrid-random-SLRU-replacement-for-SLRUs.patch)
download | inline diff:
From cea3142af73c434d11206dd39a7edaa8718269b4 Mon Sep 17 00:00:00 2001
From: Thomas Munro <[email protected]>
Date: Wed, 7 Apr 2021 16:39:09 +1200
Subject: [PATCH v15 3/3] Use hybrid random/SLRU replacement for SLRUs.
The previous algorithm would search the entire SLRU to find the least
recently used page. That doesn't seem like a good idea now that the
user can set SLRUs to large sizes. Instead, apply the existing algorithm
to a small number of randomly chosen buffers, for a cheap hybrid of SLRU
and random replacement that doesn't require a complete rewrite of
slru.c's locking.
XXX experiment
---
src/backend/access/transam/slru.c | 22 +++++++++++++++++-----
1 file changed, 17 insertions(+), 5 deletions(-)
diff --git a/src/backend/access/transam/slru.c b/src/backend/access/transam/slru.c
index 82c61c475b..95e404e856 100644
--- a/src/backend/access/transam/slru.c
+++ b/src/backend/access/transam/slru.c
@@ -71,6 +71,14 @@
*/
#define MAX_WRITEALL_BUFFERS 16
+/*
+ * We need a fast way to choose a buffer to replace, because we hold a coarse
+ * grained exclusive lock while searching. As an improvement over simple
+ * random replacement that still has some LRU tendancies, we'll compare the
+ * recency of a smallish number of randomly selected buffers.
+ */
+#define MAX_RANDOM_SEARCH 8
+
typedef struct SlruWriteAllData
{
int num_files; /* # files actually open */
@@ -1071,6 +1079,7 @@ SlruSelectLRUPage(SlruCtl ctl, int pageno)
int bestinvalidslot = 0; /* keep compiler quiet */
int best_invalid_delta = -1;
int best_invalid_page_number = 0; /* keep compiler quiet */
+ int candidates = Min(shared->num_slots, MAX_RANDOM_SEARCH);
/* See if page already has a buffer assigned */
slotno = SlruMappingFind(ctl, pageno);
@@ -1082,9 +1091,10 @@ SlruSelectLRUPage(SlruCtl ctl, int pageno)
}
/*
- * If we find any EMPTY slot, just select that one. Else choose a
- * victim page to replace. We normally take the least recently used
- * valid page, but we will never take the slot containing
+ * If we find any EMPTY slot, just select that one. Else choose a
+ * victim page to replace. We take the least recently used of a small
+ * number of randomly chosen pages, to avoid having to scan a
+ * potentially large number of pages. We skip the slot containing
* latest_page_number, even if it appears least recently used. We
* will select a slot that is already I/O busy only if there is no
* other choice: a read-busy slot will not be least recently used once
@@ -1109,11 +1119,13 @@ SlruSelectLRUPage(SlruCtl ctl, int pageno)
* multiple pages with the same lru_count.
*/
cur_count = (shared->cur_lru_count)++;
- for (slotno = 0; slotno < shared->num_slots; slotno++)
+ for (int i = 0; i < candidates; ++i)
{
int this_delta;
int this_page_number;
+retry:
+ slotno = (random() & LONG_MAX) % shared->num_slots;
if (shared->page_status[slotno] == SLRU_PAGE_EMPTY)
return slotno;
this_delta = cur_count - shared->page_lru_count[slotno];
@@ -1131,7 +1143,7 @@ SlruSelectLRUPage(SlruCtl ctl, int pageno)
}
this_page_number = shared->page_number[slotno];
if (this_page_number == shared->latest_page_number)
- continue;
+ goto retry;
if (shared->page_status[slotno] == SLRU_PAGE_VALID)
{
if (this_delta > best_valid_delta ||
--
2.27.0
^ permalink raw reply [nested|flat] 90+ messages in thread
* Re: MultiXact\SLRU buffers configuration
2020-05-08 16:36 MultiXact\SLRU buffers configuration Andrey M. Borodin <[email protected]>
2020-05-11 11:17 ` Re: MultiXact\SLRU buffers configuration Andrey M. Borodin <[email protected]>
2020-05-13 18:08 ` Re: MultiXact\SLRU buffers configuration Andrey M. Borodin <[email protected]>
2020-05-14 01:25 ` Re: MultiXact\SLRU buffers configuration Kyotaro Horiguchi <[email protected]>
2020-05-14 05:19 ` Re: MultiXact\SLRU buffers configuration Andrey M. Borodin <[email protected]>
2020-05-14 06:16 ` Re: MultiXact\SLRU buffers configuration Kyotaro Horiguchi <[email protected]>
2020-05-14 06:44 ` Re: MultiXact\SLRU buffers configuration Andrey M. Borodin <[email protected]>
2020-05-15 00:03 ` Re: MultiXact\SLRU buffers configuration Kyotaro Horiguchi <[email protected]>
2020-07-02 12:02 ` Re: MultiXact\SLRU buffers configuration Daniel Gustafsson <[email protected]>
2020-07-08 07:03 ` Re: MultiXact\SLRU buffers configuration Andrey M. Borodin <[email protected]>
2020-08-28 18:08 ` Re: MultiXact\SLRU buffers configuration Anastasia Lubennikova <[email protected]>
2020-09-28 14:41 ` Re: MultiXact\SLRU buffers configuration Andrey M. Borodin <[email protected]>
2020-10-26 01:05 ` Re: MultiXact\SLRU buffers configuration Alexander Korotkov <[email protected]>
2020-10-26 15:45 ` Re: MultiXact\SLRU buffers configuration Andrey Borodin <[email protected]>
2020-10-27 17:02 ` Re: MultiXact\SLRU buffers configuration Alexander Korotkov <[email protected]>
2020-10-27 17:23 ` Re: MultiXact\SLRU buffers configuration Alexander Korotkov <[email protected]>
2020-10-28 01:36 ` Re: MultiXact\SLRU buffers configuration Tomas Vondra <[email protected]>
2020-10-28 07:34 ` Re: MultiXact\SLRU buffers configuration Andrey Borodin <[email protected]>
2020-10-28 23:32 ` Re: MultiXact\SLRU buffers configuration Tomas Vondra <[email protected]>
2020-10-29 07:08 ` Re: MultiXact\SLRU buffers configuration Andrey Borodin <[email protected]>
2020-10-29 13:49 ` Re: MultiXact\SLRU buffers configuration Tomas Vondra <[email protected]>
2020-11-02 12:45 ` Re: MultiXact\SLRU buffers configuration Andrey Borodin <[email protected]>
2020-11-10 00:13 ` Re: MultiXact\SLRU buffers configuration Tomas Vondra <[email protected]>
2020-11-10 06:16 ` Re: MultiXact\SLRU buffers configuration Andrey Borodin <[email protected]>
2020-11-10 18:07 ` Re: MultiXact\SLRU buffers configuration Tomas Vondra <[email protected]>
2020-11-13 11:49 ` Re: MultiXact\SLRU buffers configuration Andrey Borodin <[email protected]>
2020-12-08 16:05 ` Re: MultiXact\SLRU buffers configuration Gilles Darold <[email protected]>
2020-12-08 17:52 ` Re: MultiXact\SLRU buffers configuration Andrey Borodin <[email protected]>
2020-12-10 14:45 ` Re: MultiXact\SLRU buffers configuration Gilles Darold <[email protected]>
2020-12-11 17:50 ` Re: MultiXact\SLRU buffers configuration Gilles Darold <[email protected]>
2020-12-13 09:17 ` Re: MultiXact\SLRU buffers configuration Gilles Darold <[email protected]>
2020-12-13 17:24 ` Re: MultiXact\SLRU buffers configuration Andrey Borodin <[email protected]>
2020-12-23 16:31 ` Re: MultiXact\SLRU buffers configuration Gilles Darold <[email protected]>
2021-02-15 17:17 ` Re: MultiXact\SLRU buffers configuration Andrey Borodin <[email protected]>
2021-03-11 15:50 ` Re: MultiXact\SLRU buffers configuration Gilles Darold <[email protected]>
2021-03-12 12:44 ` Re: MultiXact\SLRU buffers configuration Andrey Borodin <[email protected]>
2021-03-24 21:31 ` Re: MultiXact\SLRU buffers configuration Thomas Munro <[email protected]>
2021-03-25 01:03 ` Re: MultiXact\SLRU buffers configuration Thomas Munro <[email protected]>
2021-03-26 03:46 ` Re: MultiXact\SLRU buffers configuration Thomas Munro <[email protected]>
2021-03-26 06:00 ` Re: MultiXact\SLRU buffers configuration Andrey Borodin <[email protected]>
2021-03-26 15:52 ` Re: MultiXact\SLRU buffers configuration Andrey Borodin <[email protected]>
2021-03-26 20:26 ` Re: MultiXact\SLRU buffers configuration Thomas Munro <[email protected]>
2021-03-27 05:31 ` Re: MultiXact\SLRU buffers configuration Andrey Borodin <[email protected]>
2021-03-28 21:15 ` Re: MultiXact\SLRU buffers configuration Thomas Munro <[email protected]>
2021-03-29 08:26 ` Re: MultiXact\SLRU buffers configuration Andrey Borodin <[email protected]>
2021-03-31 21:09 ` Re: MultiXact\SLRU buffers configuration Andrey Borodin <[email protected]>
2021-04-01 03:40 ` Re: MultiXact\SLRU buffers configuration Thomas Munro <[email protected]>
2021-04-03 19:57 ` Re: MultiXact\SLRU buffers configuration Andrey Borodin <[email protected]>
2021-04-07 05:59 ` Re: MultiXact\SLRU buffers configuration Thomas Munro <[email protected]>
@ 2021-04-07 11:44 ` Andrey Borodin <[email protected]>
2021-04-07 12:13 ` Re: MultiXact\SLRU buffers configuration Andrey Borodin <[email protected]>
0 siblings, 1 reply; 90+ messages in thread
From: Andrey Borodin @ 2021-04-07 11:44 UTC (permalink / raw)
To: Thomas Munro <[email protected]>; +Cc: Gilles Darold <[email protected]>; Tomas Vondra <[email protected]>; Tomas Vondra <[email protected]>; Alexander Korotkov <[email protected]>; Anastasia Lubennikova <[email protected]>; Daniel Gustafsson <[email protected]>; Kyotaro Horiguchi <[email protected]>; pgsql-hackers
> 7 апр. 2021 г., в 08:59, Thomas Munro <[email protected]> написал(а):
>
> The remaining thing that bothers me about this patch set is that there is still a linear search in the replacement algorithm, and it runs with an exclusive lock. That creates a serious problem for large caches that still aren't large enough. I wonder if we can do something to improve that situation in the time we have. I considered a bunch of ideas but could only find one that fits with slru.c's simplistic locking while tracking recency. What do you think about a hybrid of SLRU and random replacement, that retains some characteristics of both? You could think of it as being a bit like the tournament selection of the genetic algorithm, with a tournament size of (say) 8 or 16. Any ideas on how to evaluate this and choose the number? See attached.
> <v15-0001-Add-a-buffer-mapping-table-for-SLRUs.patch><v15-0002-Make-all-SLRU-buffer-sizes-configurable.patch><v15-0003-Use-hybrid-random-SLRU-replacement-for-SLRUs.patch>
Maybe instead of fully associative cache with random replacement we could use 1-associative cache?
i.e. each page can reside only in one spcific buffer slot. If there's something else - evict it.
I think this would be as efficient as RR cache. And it's soooo fast.
Best regards, Andrey Borodin.
^ permalink raw reply [nested|flat] 90+ messages in thread
* Re: MultiXact\SLRU buffers configuration
2020-05-08 16:36 MultiXact\SLRU buffers configuration Andrey M. Borodin <[email protected]>
2020-05-11 11:17 ` Re: MultiXact\SLRU buffers configuration Andrey M. Borodin <[email protected]>
2020-05-13 18:08 ` Re: MultiXact\SLRU buffers configuration Andrey M. Borodin <[email protected]>
2020-05-14 01:25 ` Re: MultiXact\SLRU buffers configuration Kyotaro Horiguchi <[email protected]>
2020-05-14 05:19 ` Re: MultiXact\SLRU buffers configuration Andrey M. Borodin <[email protected]>
2020-05-14 06:16 ` Re: MultiXact\SLRU buffers configuration Kyotaro Horiguchi <[email protected]>
2020-05-14 06:44 ` Re: MultiXact\SLRU buffers configuration Andrey M. Borodin <[email protected]>
2020-05-15 00:03 ` Re: MultiXact\SLRU buffers configuration Kyotaro Horiguchi <[email protected]>
2020-07-02 12:02 ` Re: MultiXact\SLRU buffers configuration Daniel Gustafsson <[email protected]>
2020-07-08 07:03 ` Re: MultiXact\SLRU buffers configuration Andrey M. Borodin <[email protected]>
2020-08-28 18:08 ` Re: MultiXact\SLRU buffers configuration Anastasia Lubennikova <[email protected]>
2020-09-28 14:41 ` Re: MultiXact\SLRU buffers configuration Andrey M. Borodin <[email protected]>
2020-10-26 01:05 ` Re: MultiXact\SLRU buffers configuration Alexander Korotkov <[email protected]>
2020-10-26 15:45 ` Re: MultiXact\SLRU buffers configuration Andrey Borodin <[email protected]>
2020-10-27 17:02 ` Re: MultiXact\SLRU buffers configuration Alexander Korotkov <[email protected]>
2020-10-27 17:23 ` Re: MultiXact\SLRU buffers configuration Alexander Korotkov <[email protected]>
2020-10-28 01:36 ` Re: MultiXact\SLRU buffers configuration Tomas Vondra <[email protected]>
2020-10-28 07:34 ` Re: MultiXact\SLRU buffers configuration Andrey Borodin <[email protected]>
2020-10-28 23:32 ` Re: MultiXact\SLRU buffers configuration Tomas Vondra <[email protected]>
2020-10-29 07:08 ` Re: MultiXact\SLRU buffers configuration Andrey Borodin <[email protected]>
2020-10-29 13:49 ` Re: MultiXact\SLRU buffers configuration Tomas Vondra <[email protected]>
2020-11-02 12:45 ` Re: MultiXact\SLRU buffers configuration Andrey Borodin <[email protected]>
2020-11-10 00:13 ` Re: MultiXact\SLRU buffers configuration Tomas Vondra <[email protected]>
2020-11-10 06:16 ` Re: MultiXact\SLRU buffers configuration Andrey Borodin <[email protected]>
2020-11-10 18:07 ` Re: MultiXact\SLRU buffers configuration Tomas Vondra <[email protected]>
2020-11-13 11:49 ` Re: MultiXact\SLRU buffers configuration Andrey Borodin <[email protected]>
2020-12-08 16:05 ` Re: MultiXact\SLRU buffers configuration Gilles Darold <[email protected]>
2020-12-08 17:52 ` Re: MultiXact\SLRU buffers configuration Andrey Borodin <[email protected]>
2020-12-10 14:45 ` Re: MultiXact\SLRU buffers configuration Gilles Darold <[email protected]>
2020-12-11 17:50 ` Re: MultiXact\SLRU buffers configuration Gilles Darold <[email protected]>
2020-12-13 09:17 ` Re: MultiXact\SLRU buffers configuration Gilles Darold <[email protected]>
2020-12-13 17:24 ` Re: MultiXact\SLRU buffers configuration Andrey Borodin <[email protected]>
2020-12-23 16:31 ` Re: MultiXact\SLRU buffers configuration Gilles Darold <[email protected]>
2021-02-15 17:17 ` Re: MultiXact\SLRU buffers configuration Andrey Borodin <[email protected]>
2021-03-11 15:50 ` Re: MultiXact\SLRU buffers configuration Gilles Darold <[email protected]>
2021-03-12 12:44 ` Re: MultiXact\SLRU buffers configuration Andrey Borodin <[email protected]>
2021-03-24 21:31 ` Re: MultiXact\SLRU buffers configuration Thomas Munro <[email protected]>
2021-03-25 01:03 ` Re: MultiXact\SLRU buffers configuration Thomas Munro <[email protected]>
2021-03-26 03:46 ` Re: MultiXact\SLRU buffers configuration Thomas Munro <[email protected]>
2021-03-26 06:00 ` Re: MultiXact\SLRU buffers configuration Andrey Borodin <[email protected]>
2021-03-26 15:52 ` Re: MultiXact\SLRU buffers configuration Andrey Borodin <[email protected]>
2021-03-26 20:26 ` Re: MultiXact\SLRU buffers configuration Thomas Munro <[email protected]>
2021-03-27 05:31 ` Re: MultiXact\SLRU buffers configuration Andrey Borodin <[email protected]>
2021-03-28 21:15 ` Re: MultiXact\SLRU buffers configuration Thomas Munro <[email protected]>
2021-03-29 08:26 ` Re: MultiXact\SLRU buffers configuration Andrey Borodin <[email protected]>
2021-03-31 21:09 ` Re: MultiXact\SLRU buffers configuration Andrey Borodin <[email protected]>
2021-04-01 03:40 ` Re: MultiXact\SLRU buffers configuration Thomas Munro <[email protected]>
2021-04-03 19:57 ` Re: MultiXact\SLRU buffers configuration Andrey Borodin <[email protected]>
2021-04-07 05:59 ` Re: MultiXact\SLRU buffers configuration Thomas Munro <[email protected]>
2021-04-07 11:44 ` Re: MultiXact\SLRU buffers configuration Andrey Borodin <[email protected]>
@ 2021-04-07 12:13 ` Andrey Borodin <[email protected]>
2021-04-08 00:30 ` Re: MultiXact\SLRU buffers configuration Thomas Munro <[email protected]>
0 siblings, 1 reply; 90+ messages in thread
From: Andrey Borodin @ 2021-04-07 12:13 UTC (permalink / raw)
To: Thomas Munro <[email protected]>; +Cc: Gilles Darold <[email protected]>; Tomas Vondra <[email protected]>; Tomas Vondra <[email protected]>; Alexander Korotkov <[email protected]>; Anastasia Lubennikova <[email protected]>; Daniel Gustafsson <[email protected]>; Kyotaro Horiguchi <[email protected]>; pgsql-hackers
> 7 апр. 2021 г., в 14:44, Andrey Borodin <[email protected]> написал(а):
>
> Maybe instead of fully associative cache with random replacement we could use 1-associative cache?
> i.e. each page can reside only in one spcific buffer slot. If there's something else - evict it.
> I think this would be as efficient as RR cache. And it's soooo fast.
I thought a bit more and understood that RR is protected from two competing pages in working set, while 1-associative cache is not. So, discard that idea.
Best regards, Andrey Borodin.
^ permalink raw reply [nested|flat] 90+ messages in thread
* Re: MultiXact\SLRU buffers configuration
2020-05-08 16:36 MultiXact\SLRU buffers configuration Andrey M. Borodin <[email protected]>
2020-05-11 11:17 ` Re: MultiXact\SLRU buffers configuration Andrey M. Borodin <[email protected]>
2020-05-13 18:08 ` Re: MultiXact\SLRU buffers configuration Andrey M. Borodin <[email protected]>
2020-05-14 01:25 ` Re: MultiXact\SLRU buffers configuration Kyotaro Horiguchi <[email protected]>
2020-05-14 05:19 ` Re: MultiXact\SLRU buffers configuration Andrey M. Borodin <[email protected]>
2020-05-14 06:16 ` Re: MultiXact\SLRU buffers configuration Kyotaro Horiguchi <[email protected]>
2020-05-14 06:44 ` Re: MultiXact\SLRU buffers configuration Andrey M. Borodin <[email protected]>
2020-05-15 00:03 ` Re: MultiXact\SLRU buffers configuration Kyotaro Horiguchi <[email protected]>
2020-07-02 12:02 ` Re: MultiXact\SLRU buffers configuration Daniel Gustafsson <[email protected]>
2020-07-08 07:03 ` Re: MultiXact\SLRU buffers configuration Andrey M. Borodin <[email protected]>
2020-08-28 18:08 ` Re: MultiXact\SLRU buffers configuration Anastasia Lubennikova <[email protected]>
2020-09-28 14:41 ` Re: MultiXact\SLRU buffers configuration Andrey M. Borodin <[email protected]>
2020-10-26 01:05 ` Re: MultiXact\SLRU buffers configuration Alexander Korotkov <[email protected]>
2020-10-26 15:45 ` Re: MultiXact\SLRU buffers configuration Andrey Borodin <[email protected]>
2020-10-27 17:02 ` Re: MultiXact\SLRU buffers configuration Alexander Korotkov <[email protected]>
2020-10-27 17:23 ` Re: MultiXact\SLRU buffers configuration Alexander Korotkov <[email protected]>
2020-10-28 01:36 ` Re: MultiXact\SLRU buffers configuration Tomas Vondra <[email protected]>
2020-10-28 07:34 ` Re: MultiXact\SLRU buffers configuration Andrey Borodin <[email protected]>
2020-10-28 23:32 ` Re: MultiXact\SLRU buffers configuration Tomas Vondra <[email protected]>
2020-10-29 07:08 ` Re: MultiXact\SLRU buffers configuration Andrey Borodin <[email protected]>
2020-10-29 13:49 ` Re: MultiXact\SLRU buffers configuration Tomas Vondra <[email protected]>
2020-11-02 12:45 ` Re: MultiXact\SLRU buffers configuration Andrey Borodin <[email protected]>
2020-11-10 00:13 ` Re: MultiXact\SLRU buffers configuration Tomas Vondra <[email protected]>
2020-11-10 06:16 ` Re: MultiXact\SLRU buffers configuration Andrey Borodin <[email protected]>
2020-11-10 18:07 ` Re: MultiXact\SLRU buffers configuration Tomas Vondra <[email protected]>
2020-11-13 11:49 ` Re: MultiXact\SLRU buffers configuration Andrey Borodin <[email protected]>
2020-12-08 16:05 ` Re: MultiXact\SLRU buffers configuration Gilles Darold <[email protected]>
2020-12-08 17:52 ` Re: MultiXact\SLRU buffers configuration Andrey Borodin <[email protected]>
2020-12-10 14:45 ` Re: MultiXact\SLRU buffers configuration Gilles Darold <[email protected]>
2020-12-11 17:50 ` Re: MultiXact\SLRU buffers configuration Gilles Darold <[email protected]>
2020-12-13 09:17 ` Re: MultiXact\SLRU buffers configuration Gilles Darold <[email protected]>
2020-12-13 17:24 ` Re: MultiXact\SLRU buffers configuration Andrey Borodin <[email protected]>
2020-12-23 16:31 ` Re: MultiXact\SLRU buffers configuration Gilles Darold <[email protected]>
2021-02-15 17:17 ` Re: MultiXact\SLRU buffers configuration Andrey Borodin <[email protected]>
2021-03-11 15:50 ` Re: MultiXact\SLRU buffers configuration Gilles Darold <[email protected]>
2021-03-12 12:44 ` Re: MultiXact\SLRU buffers configuration Andrey Borodin <[email protected]>
2021-03-24 21:31 ` Re: MultiXact\SLRU buffers configuration Thomas Munro <[email protected]>
2021-03-25 01:03 ` Re: MultiXact\SLRU buffers configuration Thomas Munro <[email protected]>
2021-03-26 03:46 ` Re: MultiXact\SLRU buffers configuration Thomas Munro <[email protected]>
2021-03-26 06:00 ` Re: MultiXact\SLRU buffers configuration Andrey Borodin <[email protected]>
2021-03-26 15:52 ` Re: MultiXact\SLRU buffers configuration Andrey Borodin <[email protected]>
2021-03-26 20:26 ` Re: MultiXact\SLRU buffers configuration Thomas Munro <[email protected]>
2021-03-27 05:31 ` Re: MultiXact\SLRU buffers configuration Andrey Borodin <[email protected]>
2021-03-28 21:15 ` Re: MultiXact\SLRU buffers configuration Thomas Munro <[email protected]>
2021-03-29 08:26 ` Re: MultiXact\SLRU buffers configuration Andrey Borodin <[email protected]>
2021-03-31 21:09 ` Re: MultiXact\SLRU buffers configuration Andrey Borodin <[email protected]>
2021-04-01 03:40 ` Re: MultiXact\SLRU buffers configuration Thomas Munro <[email protected]>
2021-04-03 19:57 ` Re: MultiXact\SLRU buffers configuration Andrey Borodin <[email protected]>
2021-04-07 05:59 ` Re: MultiXact\SLRU buffers configuration Thomas Munro <[email protected]>
2021-04-07 11:44 ` Re: MultiXact\SLRU buffers configuration Andrey Borodin <[email protected]>
2021-04-07 12:13 ` Re: MultiXact\SLRU buffers configuration Andrey Borodin <[email protected]>
@ 2021-04-08 00:30 ` Thomas Munro <[email protected]>
2021-04-08 07:24 ` Re: MultiXact\SLRU buffers configuration Andrey Borodin <[email protected]>
0 siblings, 1 reply; 90+ messages in thread
From: Thomas Munro @ 2021-04-08 00:30 UTC (permalink / raw)
To: Andrey Borodin <[email protected]>; +Cc: Gilles Darold <[email protected]>; Tomas Vondra <[email protected]>; Tomas Vondra <[email protected]>; Alexander Korotkov <[email protected]>; Anastasia Lubennikova <[email protected]>; Daniel Gustafsson <[email protected]>; Kyotaro Horiguchi <[email protected]>; pgsql-hackers
On Thu, Apr 8, 2021 at 12:13 AM Andrey Borodin <[email protected]> wrote:
> > 7 апр. 2021 г., в 14:44, Andrey Borodin <[email protected]> написал(а):
> > Maybe instead of fully associative cache with random replacement we could use 1-associative cache?
> > i.e. each page can reside only in one spcific buffer slot. If there's something else - evict it.
> > I think this would be as efficient as RR cache. And it's soooo fast.
>
> I thought a bit more and understood that RR is protected from two competing pages in working set, while 1-associative cache is not. So, discard that idea.
It's an interesting idea. I know that at least one proprietary fork
just puts the whole CLOG in memory for direct indexing, which is what
we'd have here if we said "oh, your xact_buffers setting is so large
I'm just going to use slotno = pageno & mask".
Here's another approach that is a little less exciting than
"tournament RR" (or whatever that should be called; I couldn't find an
established name for it). This version is just our traditional linear
search, except that it stops at 128, and remembers where to start from
next time (like a sort of Fisher-Price GCLOCK hand). This feels more
committable to me. You can argue that all buffers above 128 are bonus
buffers that PostgreSQL 13 didn't have, so the fact that we can no
longer find the globally least recently used page when you set
xact_buffers > 128 doesn't seem too bad to me, as an incremental step
(but to be clear, of course we can do better than this with more work
in later releases).
Attachments:
[text/x-patch] v16-0001-Add-a-buffer-mapping-table-for-SLRUs.patch (9.0K, ../../CA+hUKGLCLDtgDj2Xsf0uBk5WXDCeHxBDDJPsyY7m65Fde-=pyg@mail.gmail.com/2-v16-0001-Add-a-buffer-mapping-table-for-SLRUs.patch)
download | inline diff:
From 72ebd5052851aa4b9aa281df30b9bf42c0ad5de4 Mon Sep 17 00:00:00 2001
From: Thomas Munro <[email protected]>
Date: Thu, 25 Mar 2021 10:11:31 +1300
Subject: [PATCH v16 1/3] Add a buffer mapping table for SLRUs.
Instead of doing a linear search for the buffer holding a given page
number, use a hash table. This will allow us to increase the size of
these caches.
Reviewed-by: Andrey M. Borodin <[email protected]>
Discussion: https://postgr.es/m/2BEC2B3F-9B61-4C1D-9FB5-5FAB0F05EF86%40yandex-team.ru
---
src/backend/access/transam/slru.c | 121 +++++++++++++++++++++++++-----
src/include/access/slru.h | 2 +
2 files changed, 103 insertions(+), 20 deletions(-)
diff --git a/src/backend/access/transam/slru.c b/src/backend/access/transam/slru.c
index 82149ad782..82c61c475b 100644
--- a/src/backend/access/transam/slru.c
+++ b/src/backend/access/transam/slru.c
@@ -58,6 +58,7 @@
#include "pgstat.h"
#include "storage/fd.h"
#include "storage/shmem.h"
+#include "utils/hsearch.h"
#define SlruFileName(ctl, path, seg) \
snprintf(path, MAXPGPATH, "%s/%04X", (ctl)->Dir, seg)
@@ -79,6 +80,12 @@ typedef struct SlruWriteAllData
typedef struct SlruWriteAllData *SlruWriteAll;
+typedef struct SlruMappingTableEntry
+{
+ int pageno;
+ int slotno;
+} SlruMappingTableEntry;
+
/*
* Populate a file tag describing a segment file. We only use the segment
* number, since we can derive everything else we need by having separate
@@ -146,13 +153,16 @@ static int SlruSelectLRUPage(SlruCtl ctl, int pageno);
static bool SlruScanDirCbDeleteCutoff(SlruCtl ctl, char *filename,
int segpage, void *data);
static void SlruInternalDeleteSegment(SlruCtl ctl, int segno);
+static void SlruMappingAdd(SlruCtl ctl, int pageno, int slotno);
+static void SlruMappingRemove(SlruCtl ctl, int pageno);
+static int SlruMappingFind(SlruCtl ctl, int pageno);
/*
* Initialization of shared memory
*/
-Size
-SimpleLruShmemSize(int nslots, int nlsns)
+static Size
+SimpleLruStructSize(int nslots, int nlsns)
{
Size sz;
@@ -167,10 +177,16 @@ SimpleLruShmemSize(int nslots, int nlsns)
if (nlsns > 0)
sz += MAXALIGN(nslots * nlsns * sizeof(XLogRecPtr)); /* group_lsn[] */
-
return BUFFERALIGN(sz) + BLCKSZ * nslots;
}
+Size
+SimpleLruShmemSize(int nslots, int nlsns)
+{
+ return SimpleLruStructSize(nslots, nlsns) +
+ hash_estimate_size(nslots, sizeof(SlruMappingTableEntry));
+}
+
/*
* Initialize, or attach to, a simple LRU cache in shared memory.
*
@@ -187,11 +203,14 @@ SimpleLruInit(SlruCtl ctl, const char *name, int nslots, int nlsns,
LWLock *ctllock, const char *subdir, int tranche_id,
SyncRequestHandler sync_handler)
{
+ char mapping_table_name[SHMEM_INDEX_KEYSIZE];
+ HASHCTL mapping_table_info;
+ HTAB *mapping_table;
SlruShared shared;
bool found;
shared = (SlruShared) ShmemInitStruct(name,
- SimpleLruShmemSize(nslots, nlsns),
+ SimpleLruStructSize(nslots, nlsns),
&found);
if (!IsUnderPostmaster)
@@ -258,11 +277,21 @@ SimpleLruInit(SlruCtl ctl, const char *name, int nslots, int nlsns,
else
Assert(found);
+ /* Create or find the buffer mapping table. */
+ memset(&mapping_table_info, 0, sizeof(mapping_table_info));
+ mapping_table_info.keysize = sizeof(int);
+ mapping_table_info.entrysize = sizeof(SlruMappingTableEntry);
+ snprintf(mapping_table_name, sizeof(mapping_table_name),
+ "%s Lookup Table", name);
+ mapping_table = ShmemInitHash(mapping_table_name, nslots, nslots,
+ &mapping_table_info, HASH_ELEM | HASH_BLOBS);
+
/*
* Initialize the unshared control struct, including directory path. We
* assume caller set PagePrecedes.
*/
ctl->shared = shared;
+ ctl->mapping_table = mapping_table;
ctl->sync_handler = sync_handler;
strlcpy(ctl->Dir, subdir, sizeof(ctl->Dir));
}
@@ -289,6 +318,9 @@ SimpleLruZeroPage(SlruCtl ctl, int pageno)
shared->page_number[slotno] == pageno);
/* Mark the slot as containing this page */
+ if (shared->page_status[slotno] != SLRU_PAGE_EMPTY)
+ SlruMappingRemove(ctl, shared->page_number[slotno]);
+ SlruMappingAdd(ctl, pageno, slotno);
shared->page_number[slotno] = pageno;
shared->page_status[slotno] = SLRU_PAGE_VALID;
shared->page_dirty[slotno] = true;
@@ -362,7 +394,10 @@ SimpleLruWaitIO(SlruCtl ctl, int slotno)
{
/* indeed, the I/O must have failed */
if (shared->page_status[slotno] == SLRU_PAGE_READ_IN_PROGRESS)
+ {
+ SlruMappingRemove(ctl, shared->page_number[slotno]);
shared->page_status[slotno] = SLRU_PAGE_EMPTY;
+ }
else /* write_in_progress */
{
shared->page_status[slotno] = SLRU_PAGE_VALID;
@@ -436,6 +471,9 @@ SimpleLruReadPage(SlruCtl ctl, int pageno, bool write_ok,
!shared->page_dirty[slotno]));
/* Mark the slot read-busy */
+ if (shared->page_status[slotno] != SLRU_PAGE_EMPTY)
+ SlruMappingRemove(ctl, shared->page_number[slotno]);
+ SlruMappingAdd(ctl, pageno, slotno);
shared->page_number[slotno] = pageno;
shared->page_status[slotno] = SLRU_PAGE_READ_IN_PROGRESS;
shared->page_dirty[slotno] = false;
@@ -459,7 +497,13 @@ SimpleLruReadPage(SlruCtl ctl, int pageno, bool write_ok,
shared->page_status[slotno] == SLRU_PAGE_READ_IN_PROGRESS &&
!shared->page_dirty[slotno]);
- shared->page_status[slotno] = ok ? SLRU_PAGE_VALID : SLRU_PAGE_EMPTY;
+ if (ok)
+ shared->page_status[slotno] = SLRU_PAGE_VALID;
+ else
+ {
+ SlruMappingRemove(ctl, pageno);
+ shared->page_status[slotno] = SLRU_PAGE_EMPTY;
+ }
LWLockRelease(&shared->buffer_locks[slotno].lock);
@@ -500,20 +544,20 @@ SimpleLruReadPage_ReadOnly(SlruCtl ctl, int pageno, TransactionId xid)
LWLockAcquire(shared->ControlLock, LW_SHARED);
/* See if page is already in a buffer */
- for (slotno = 0; slotno < shared->num_slots; slotno++)
+ slotno = SlruMappingFind(ctl, pageno);
+ if (slotno >= 0 &&
+ shared->page_status[slotno] != SLRU_PAGE_READ_IN_PROGRESS)
{
- if (shared->page_number[slotno] == pageno &&
- shared->page_status[slotno] != SLRU_PAGE_EMPTY &&
- shared->page_status[slotno] != SLRU_PAGE_READ_IN_PROGRESS)
- {
- /* See comments for SlruRecentlyUsed macro */
- SlruRecentlyUsed(shared, slotno);
+ Assert(shared->page_status[slotno] != SLRU_PAGE_EMPTY);
+ Assert(shared->page_number[slotno] == pageno);
- /* update the stats counter of pages found in the SLRU */
- pgstat_count_slru_page_hit(shared->slru_stats_idx);
+ /* See comments for SlruRecentlyUsed macro */
+ SlruRecentlyUsed(shared, slotno);
- return slotno;
- }
+ /* update the stats counter of pages found in the SLRU */
+ pgstat_count_slru_page_hit(shared->slru_stats_idx);
+
+ return slotno;
}
/* No luck, so switch to normal exclusive lock and do regular read */
@@ -1029,11 +1073,12 @@ SlruSelectLRUPage(SlruCtl ctl, int pageno)
int best_invalid_page_number = 0; /* keep compiler quiet */
/* See if page already has a buffer assigned */
- for (slotno = 0; slotno < shared->num_slots; slotno++)
+ slotno = SlruMappingFind(ctl, pageno);
+ if (slotno >= 0)
{
- if (shared->page_number[slotno] == pageno &&
- shared->page_status[slotno] != SLRU_PAGE_EMPTY)
- return slotno;
+ Assert(shared->page_number[slotno] == pageno);
+ Assert(shared->page_status[slotno] != SLRU_PAGE_EMPTY);
+ return slotno;
}
/*
@@ -1266,6 +1311,7 @@ restart:;
if (shared->page_status[slotno] == SLRU_PAGE_VALID &&
!shared->page_dirty[slotno])
{
+ SlruMappingRemove(ctl, shared->page_number[slotno]);
shared->page_status[slotno] = SLRU_PAGE_EMPTY;
continue;
}
@@ -1348,6 +1394,7 @@ restart:
if (shared->page_status[slotno] == SLRU_PAGE_VALID &&
!shared->page_dirty[slotno])
{
+ SlruMappingRemove(ctl, shared->page_number[slotno]);
shared->page_status[slotno] = SLRU_PAGE_EMPTY;
continue;
}
@@ -1609,3 +1656,37 @@ SlruSyncFileTag(SlruCtl ctl, const FileTag *ftag, char *path)
errno = save_errno;
return result;
}
+
+static int
+SlruMappingFind(SlruCtl ctl, int pageno)
+{
+ SlruMappingTableEntry *mapping;
+
+ mapping = hash_search(ctl->mapping_table, &pageno, HASH_FIND, NULL);
+ if (mapping)
+ return mapping->slotno;
+
+ return -1;
+}
+
+static void
+SlruMappingAdd(SlruCtl ctl, int pageno, int slotno)
+{
+ SlruMappingTableEntry *mapping;
+ bool found PG_USED_FOR_ASSERTS_ONLY;
+
+ mapping = hash_search(ctl->mapping_table, &pageno, HASH_ENTER, &found);
+ mapping->slotno = slotno;
+
+ Assert(!found);
+}
+
+static void
+SlruMappingRemove(SlruCtl ctl, int pageno)
+{
+ bool found PG_USED_FOR_ASSERTS_ONLY;
+
+ hash_search(ctl->mapping_table, &pageno, HASH_REMOVE, &found);
+
+ Assert(found);
+}
diff --git a/src/include/access/slru.h b/src/include/access/slru.h
index dd52e8cec7..8aa3efc0ee 100644
--- a/src/include/access/slru.h
+++ b/src/include/access/slru.h
@@ -16,6 +16,7 @@
#include "access/xlogdefs.h"
#include "storage/lwlock.h"
#include "storage/sync.h"
+#include "utils/hsearch.h"
/*
@@ -110,6 +111,7 @@ typedef SlruSharedData *SlruShared;
typedef struct SlruCtlData
{
SlruShared shared;
+ HTAB *mapping_table;
/*
* Which sync handler function to use when handing sync requests over to
--
2.30.1
[text/x-patch] v16-0002-Make-all-SLRU-buffer-sizes-configurable.patch (25.7K, ../../CA+hUKGLCLDtgDj2Xsf0uBk5WXDCeHxBDDJPsyY7m65Fde-=pyg@mail.gmail.com/3-v16-0002-Make-all-SLRU-buffer-sizes-configurable.patch)
download | inline diff:
From 97c5078f661a41617450826173dd252fc4d0c856 Mon Sep 17 00:00:00 2001
From: Andrey Borodin <[email protected]>
Date: Mon, 15 Feb 2021 21:51:56 +0500
Subject: [PATCH v16 2/3] Make all SLRU buffer sizes configurable.
Provide new GUCs to set the number of buffers, instead of using hard
coded defaults.
Remove the limits on xact_buffers and commit_ts_buffers. The default
sizes for those caches are ~0.2% and ~0.1% of shared_buffers, as before,
but now there is no cap at 128 and 16 buffers respectively (unless
track_commit_timestamp is disabled, in the latter case, then we might as
well keep it tiny). Sizes much larger than the old limits have been
shown to be useful on modern systems, and an earlier commit replaced a
linear search with a hash table to avoid problems with extreme cases.
Author: Andrey M. Borodin <[email protected]>
Reviewed-by: Anastasia Lubennikova <[email protected]>
Reviewed-by: Tomas Vondra <[email protected]>
Reviewed-by: Alexander Korotkov <[email protected]>
Reviewed-by: Gilles Darold <[email protected]>
Reviewed-by: Thomas Munro <[email protected]>
Discussion: https://postgr.es/m/2BEC2B3F-9B61-4C1D-9FB5-5FAB0F05EF86%40yandex-team.ru
---
doc/src/sgml/config.sgml | 135 ++++++++++++++++++
src/backend/access/transam/clog.c | 23 ++-
src/backend/access/transam/commit_ts.c | 10 +-
src/backend/access/transam/multixact.c | 8 +-
src/backend/access/transam/subtrans.c | 5 +-
src/backend/commands/async.c | 8 +-
src/backend/storage/lmgr/predicate.c | 4 +-
src/backend/utils/init/globals.c | 8 ++
src/backend/utils/misc/guc.c | 99 +++++++++++++
src/backend/utils/misc/postgresql.conf.sample | 9 ++
src/include/access/clog.h | 10 ++
src/include/access/commit_ts.h | 1 -
src/include/access/multixact.h | 4 -
src/include/access/slru.h | 5 +
src/include/access/subtrans.h | 2 -
src/include/commands/async.h | 5 -
src/include/miscadmin.h | 7 +
src/include/storage/predicate.h | 4 -
18 files changed, 301 insertions(+), 46 deletions(-)
diff --git a/doc/src/sgml/config.sgml b/doc/src/sgml/config.sgml
index 963824d050..58c46edf62 100644
--- a/doc/src/sgml/config.sgml
+++ b/doc/src/sgml/config.sgml
@@ -1924,6 +1924,141 @@ include_dir 'conf.d'
</para>
</listitem>
</varlistentry>
+
+ <varlistentry id="guc-multixact-offsets-buffers" xreflabel="multixact_offsets_buffers">
+ <term><varname>multixact_offsets_buffers</varname> (<type>integer</type>)
+ <indexterm>
+ <primary><varname>multixact_offsets_buffers</varname> configuration parameter</primary>
+ </indexterm>
+ </term>
+ <listitem>
+ <para>
+ Specifies the amount of shared memory to use to cache the contents
+ of <literal>pg_multixact/offsets</literal> (see
+ <xref linkend="pgdata-contents-table"/>).
+ If this value is specified without units, it is taken as blocks,
+ that is <symbol>BLCKSZ</symbol> bytes, typically 8kB.
+ The default value is <literal>8</literal>.
+ This parameter can only be set at server start.
+ </para>
+ </listitem>
+ </varlistentry>
+
+ <varlistentry id="guc-multixact-members-buffers" xreflabel="multixact_members_buffers">
+ <term><varname>multixact_members_buffers</varname> (<type>integer</type>)
+ <indexterm>
+ <primary><varname>multixact_members_buffers</varname> configuration parameter</primary>
+ </indexterm>
+ </term>
+ <listitem>
+ <para>
+ Specifies the amount of shared memory to use to cache the contents
+ of <literal>pg_multixact/members</literal> (see
+ <xref linkend="pgdata-contents-table"/>).
+ If this value is specified without units, it is taken as blocks,
+ that is <symbol>BLCKSZ</symbol> bytes, typically 8kB.
+ The default value is <literal>16</literal>.
+ This parameter can only be set at server start.
+ </para>
+ </listitem>
+ </varlistentry>
+
+ <varlistentry id="guc-subtrans-buffers" xreflabel="subtrans_buffers">
+ <term><varname>subtrans_buffers</varname> (<type>integer</type>)
+ <indexterm>
+ <primary><varname>subtrans_buffers</varname> configuration parameter</primary>
+ </indexterm>
+ </term>
+ <listitem>
+ <para>
+ Specifies the amount of shared memory to use to cache the contents
+ of <literal>pg_subtrans</literal> (see
+ <xref linkend="pgdata-contents-table"/>).
+ If this value is specified without units, it is taken as blocks,
+ that is <symbol>BLCKSZ</symbol> bytes, typically 8kB.
+ The default value is <literal>8</literal>.
+ This parameter can only be set at server start.
+ </para>
+ </listitem>
+ </varlistentry>
+
+ <varlistentry id="guc-notify-buffers" xreflabel="notify_buffers">
+ <term><varname>notify_buffers</varname> (<type>integer</type>)
+ <indexterm>
+ <primary><varname>notify_buffers</varname> configuration parameter</primary>
+ </indexterm>
+ </term>
+ <listitem>
+ <para>
+ Specifies the amount of shared memory to use to cache the contents
+ of <literal>pg_notify</literal> (see
+ <xref linkend="pgdata-contents-table"/>).
+ If this value is specified without units, it is taken as blocks,
+ that is <symbol>BLCKSZ</symbol> bytes, typically 8kB.
+ The default value is <literal>8</literal>.
+ This parameter can only be set at server start.
+ </para>
+ </listitem>
+ </varlistentry>
+
+ <varlistentry id="guc-serial-buffers" xreflabel="serial_buffers">
+ <term><varname>serial_buffers</varname> (<type>integer</type>)
+ <indexterm>
+ <primary><varname>serial_buffers</varname> configuration parameter</primary>
+ </indexterm>
+ </term>
+ <listitem>
+ <para>
+ Specifies the amount of shared memory to use to cache the contents
+ of <literal>pg_serial</literal> (see
+ <xref linkend="pgdata-contents-table"/>).
+ If this value is specified without units, it is taken as blocks,
+ that is <symbol>BLCKSZ</symbol> bytes, typically 8kB.
+ The default value is <literal>16</literal>.
+ This parameter can only be set at server start.
+ </para>
+ </listitem>
+ </varlistentry>
+
+ <varlistentry id="guc-xact-buffers" xreflabel="xact_buffers">
+ <term><varname>xact_buffers</varname> (<type>integer</type>)
+ <indexterm>
+ <primary><varname>xact_buffers</varname> configuration parameter</primary>
+ </indexterm>
+ </term>
+ <listitem>
+ <para>
+ Specifies the amount of shared memory to use to cache the contents
+ of <literal>pg_xact</literal> (see
+ <xref linkend="pgdata-contents-table"/>).
+ If this value is specified without units, it is taken as blocks,
+ that is <symbol>BLCKSZ</symbol> bytes, typically 8kB.
+ The default value is <literal>0</literal>, which requests
+ <varname>shared_buffers</varname> / 512, but not fewer than 4 blocks.
+ This parameter can only be set at server start.
+ </para>
+ </listitem>
+ </varlistentry>
+
+ <varlistentry id="guc-commit-ts-buffers" xreflabel="commit_ts_buffers">
+ <term><varname>commit_ts_buffers</varname> (<type>integer</type>)
+ <indexterm>
+ <primary><varname>commit_ts_buffers</varname> configuration parameter</primary>
+ </indexterm>
+ </term>
+ <listitem>
+ <para>
+ Specifies the amount of memory to use to cache the cotents of
+ <literal>pg_commit_ts</literal> (see
+ <xref linkend="pgdata-contents-table"/>).
+ If this value is specified without units, it is taken as blocks,
+ that is <symbol>BLCKSZ</symbol> bytes, typically 8kB.
+ The default value is <literal>0</literal>, which requests
+ <varname>shared_buffers</varname> / 1024, but not fewer than 4 blocks.
+ This parameter can only be set at server start.
+ </para>
+ </listitem>
+ </varlistentry>
<varlistentry id="guc-max-stack-depth" xreflabel="max_stack_depth">
<term><varname>max_stack_depth</varname> (<type>integer</type>)
diff --git a/src/backend/access/transam/clog.c b/src/backend/access/transam/clog.c
index 6fa4713fb4..dd2d7a5184 100644
--- a/src/backend/access/transam/clog.c
+++ b/src/backend/access/transam/clog.c
@@ -58,8 +58,8 @@
/* We need two bits per xact, so four xacts fit in a byte */
#define CLOG_BITS_PER_XACT 2
-#define CLOG_XACTS_PER_BYTE 4
-#define CLOG_XACTS_PER_PAGE (BLCKSZ * CLOG_XACTS_PER_BYTE)
+StaticAssertDecl((CLOG_BITS_PER_XACT * CLOG_XACTS_PER_BYTE) == BITS_PER_BYTE,
+ "CLOG_BITS_PER_XACT and CLOG_XACTS_PER_BYTE are inconsistent");
#define CLOG_XACT_BITMASK ((1 << CLOG_BITS_PER_XACT) - 1)
#define TransactionIdToPage(xid) ((xid) / (TransactionId) CLOG_XACTS_PER_PAGE)
@@ -659,23 +659,16 @@ TransactionIdGetStatus(TransactionId xid, XLogRecPtr *lsn)
/*
* Number of shared CLOG buffers.
*
- * On larger multi-processor systems, it is possible to have many CLOG page
- * requests in flight at one time which could lead to disk access for CLOG
- * page if the required page is not found in memory. Testing revealed that we
- * can get the best performance by having 128 CLOG buffers, more than that it
- * doesn't improve performance.
- *
- * Unconditionally keeping the number of CLOG buffers to 128 did not seem like
- * a good idea, because it would increase the minimum amount of shared memory
- * required to start, which could be a problem for people running very small
- * configurations. The following formula seems to represent a reasonable
- * compromise: people with very low values for shared_buffers will get fewer
- * CLOG buffers as well, and everyone else will get 128.
+ * By default, we'll use 2MB of for every 1GB of shared buffers, up to the
+ * theoretical maximum useful value, but always at least 4 buffers.
*/
Size
CLOGShmemBuffers(void)
{
- return Min(128, Max(4, NBuffers / 512));
+ /* Use configured value if provided. */
+ if (xact_buffers > 0)
+ return Max(4, xact_buffers);
+ return Min(CLOG_MAX_ALLOWED_BUFFERS, Max(4, NBuffers / 512));
}
/*
diff --git a/src/backend/access/transam/commit_ts.c b/src/backend/access/transam/commit_ts.c
index 268bdba339..729a4b9212 100644
--- a/src/backend/access/transam/commit_ts.c
+++ b/src/backend/access/transam/commit_ts.c
@@ -524,13 +524,17 @@ pg_xact_commit_timestamp_origin(PG_FUNCTION_ARGS)
/*
* Number of shared CommitTS buffers.
*
- * We use a very similar logic as for the number of CLOG buffers; see comments
- * in CLOGShmemBuffers.
+ * By default, we'll use 1MB of for every 1GB of shared buffers, up to the
+ * maximum value that slru.c will allow, but always at least 4 buffers.
*/
Size
CommitTsShmemBuffers(void)
{
- return Min(16, Max(4, NBuffers / 1024));
+ /* Use configured value if provided. */
+ if (commit_ts_buffers > 0)
+ return Max(4, commit_ts_buffers);
+ return Min(track_commit_timestamp ? SLRU_MAX_ALLOWED_BUFFERS : 16,
+ Max(4, NBuffers / 1024));
}
/*
diff --git a/src/backend/access/transam/multixact.c b/src/backend/access/transam/multixact.c
index 1f9f1a1fa1..21787765e2 100644
--- a/src/backend/access/transam/multixact.c
+++ b/src/backend/access/transam/multixact.c
@@ -1831,8 +1831,8 @@ MultiXactShmemSize(void)
mul_size(sizeof(MultiXactId) * 2, MaxOldestSlot))
size = SHARED_MULTIXACT_STATE_SIZE;
- size = add_size(size, SimpleLruShmemSize(NUM_MULTIXACTOFFSET_BUFFERS, 0));
- size = add_size(size, SimpleLruShmemSize(NUM_MULTIXACTMEMBER_BUFFERS, 0));
+ size = add_size(size, SimpleLruShmemSize(multixact_offsets_buffers, 0));
+ size = add_size(size, SimpleLruShmemSize(multixact_members_buffers, 0));
return size;
}
@@ -1848,13 +1848,13 @@ MultiXactShmemInit(void)
MultiXactMemberCtl->PagePrecedes = MultiXactMemberPagePrecedes;
SimpleLruInit(MultiXactOffsetCtl,
- "MultiXactOffset", NUM_MULTIXACTOFFSET_BUFFERS, 0,
+ "MultiXactOffset", multixact_offsets_buffers, 0,
MultiXactOffsetSLRULock, "pg_multixact/offsets",
LWTRANCHE_MULTIXACTOFFSET_BUFFER,
SYNC_HANDLER_MULTIXACT_OFFSET);
SlruPagePrecedesUnitTests(MultiXactOffsetCtl, MULTIXACT_OFFSETS_PER_PAGE);
SimpleLruInit(MultiXactMemberCtl,
- "MultiXactMember", NUM_MULTIXACTMEMBER_BUFFERS, 0,
+ "MultiXactMember", multixact_offsets_buffers, 0,
MultiXactMemberSLRULock, "pg_multixact/members",
LWTRANCHE_MULTIXACTMEMBER_BUFFER,
SYNC_HANDLER_MULTIXACT_MEMBER);
diff --git a/src/backend/access/transam/subtrans.c b/src/backend/access/transam/subtrans.c
index 6a8e521f89..785f2520fd 100644
--- a/src/backend/access/transam/subtrans.c
+++ b/src/backend/access/transam/subtrans.c
@@ -31,6 +31,7 @@
#include "access/slru.h"
#include "access/subtrans.h"
#include "access/transam.h"
+#include "miscadmin.h"
#include "pg_trace.h"
#include "utils/snapmgr.h"
@@ -184,14 +185,14 @@ SubTransGetTopmostTransaction(TransactionId xid)
Size
SUBTRANSShmemSize(void)
{
- return SimpleLruShmemSize(NUM_SUBTRANS_BUFFERS, 0);
+ return SimpleLruShmemSize(subtrans_buffers, 0);
}
void
SUBTRANSShmemInit(void)
{
SubTransCtl->PagePrecedes = SubTransPagePrecedes;
- SimpleLruInit(SubTransCtl, "Subtrans", NUM_SUBTRANS_BUFFERS, 0,
+ SimpleLruInit(SubTransCtl, "Subtrans", subtrans_buffers, 0,
SubtransSLRULock, "pg_subtrans",
LWTRANCHE_SUBTRANS_BUFFER, SYNC_HANDLER_NONE);
SlruPagePrecedesUnitTests(SubTransCtl, SUBTRANS_XACTS_PER_PAGE);
diff --git a/src/backend/commands/async.c b/src/backend/commands/async.c
index 4b16fb5682..de17f52cd7 100644
--- a/src/backend/commands/async.c
+++ b/src/backend/commands/async.c
@@ -107,7 +107,7 @@
* frontend during startup.) The above design guarantees that notifies from
* other backends will never be missed by ignoring self-notifies.
*
- * The amount of shared memory used for notify management (NUM_NOTIFY_BUFFERS)
+ * The amount of shared memory used for notify management (notify_buffers)
* can be varied without affecting anything but performance. The maximum
* amount of notification data that can be queued at one time is determined
* by slru.c's wraparound limit; see QUEUE_MAX_PAGE below.
@@ -225,7 +225,7 @@ typedef struct QueuePosition
*
* Resist the temptation to make this really large. While that would save
* work in some places, it would add cost in others. In particular, this
- * should likely be less than NUM_NOTIFY_BUFFERS, to ensure that backends
+ * should likely be less than notify_buffers, to ensure that backends
* catch up before the pages they'll need to read fall out of SLRU cache.
*/
#define QUEUE_CLEANUP_DELAY 4
@@ -514,7 +514,7 @@ AsyncShmemSize(void)
size = mul_size(MaxBackends + 1, sizeof(QueueBackendStatus));
size = add_size(size, offsetof(AsyncQueueControl, backend));
- size = add_size(size, SimpleLruShmemSize(NUM_NOTIFY_BUFFERS, 0));
+ size = add_size(size, SimpleLruShmemSize(notify_buffers, 0));
return size;
}
@@ -562,7 +562,7 @@ AsyncShmemInit(void)
* Set up SLRU management of the pg_notify data.
*/
NotifyCtl->PagePrecedes = asyncQueuePagePrecedes;
- SimpleLruInit(NotifyCtl, "Notify", NUM_NOTIFY_BUFFERS, 0,
+ SimpleLruInit(NotifyCtl, "Notify", notify_buffers, 0,
NotifySLRULock, "pg_notify", LWTRANCHE_NOTIFY_BUFFER,
SYNC_HANDLER_NONE);
diff --git a/src/backend/storage/lmgr/predicate.c b/src/backend/storage/lmgr/predicate.c
index d493aeef0f..b1f4f1651d 100644
--- a/src/backend/storage/lmgr/predicate.c
+++ b/src/backend/storage/lmgr/predicate.c
@@ -872,7 +872,7 @@ SerialInit(void)
*/
SerialSlruCtl->PagePrecedes = SerialPagePrecedesLogically;
SimpleLruInit(SerialSlruCtl, "Serial",
- NUM_SERIAL_BUFFERS, 0, SerialSLRULock, "pg_serial",
+ serial_buffers, 0, SerialSLRULock, "pg_serial",
LWTRANCHE_SERIAL_BUFFER, SYNC_HANDLER_NONE);
#ifdef USE_ASSERT_CHECKING
SerialPagePrecedesLogicallyUnitTests();
@@ -1395,7 +1395,7 @@ PredicateLockShmemSize(void)
/* Shared memory structures for SLRU tracking of old committed xids. */
size = add_size(size, sizeof(SerialControlData));
- size = add_size(size, SimpleLruShmemSize(NUM_SERIAL_BUFFERS, 0));
+ size = add_size(size, SimpleLruShmemSize(serial_buffers, 0));
return size;
}
diff --git a/src/backend/utils/init/globals.c b/src/backend/utils/init/globals.c
index 381d9e548d..c83151d5ab 100644
--- a/src/backend/utils/init/globals.c
+++ b/src/backend/utils/init/globals.c
@@ -150,3 +150,11 @@ int64 VacuumPageDirty = 0;
int VacuumCostBalance = 0; /* working state for vacuum */
bool VacuumCostActive = false;
+
+int multixact_offsets_buffers = 8;
+int multixact_members_buffers = 16;
+int subtrans_buffers = 32;
+int notify_buffers = 8;
+int serial_buffers = 16;
+int xact_buffers = 0;
+int commit_ts_buffers = 0;
diff --git a/src/backend/utils/misc/guc.c b/src/backend/utils/misc/guc.c
index bee976bae8..250cef80bd 100644
--- a/src/backend/utils/misc/guc.c
+++ b/src/backend/utils/misc/guc.c
@@ -32,9 +32,11 @@
#endif
#include <unistd.h>
+#include "access/clog.h"
#include "access/commit_ts.h"
#include "access/gin.h"
#include "access/rmgr.h"
+#include "access/slru.h"
#include "access/tableam.h"
#include "access/toast_compression.h"
#include "access/transam.h"
@@ -200,6 +202,8 @@ static const char *show_tcp_keepalives_idle(void);
static const char *show_tcp_keepalives_interval(void);
static const char *show_tcp_keepalives_count(void);
static const char *show_tcp_user_timeout(void);
+static const char *show_xact_buffers(void);
+static const char *show_commit_ts_buffers(void);
static bool check_maxconnections(int *newval, void **extra, GucSource source);
static bool check_max_worker_processes(int *newval, void **extra, GucSource source);
static bool check_autovacuum_max_workers(int *newval, void **extra, GucSource source);
@@ -2340,6 +2344,83 @@ static struct config_int ConfigureNamesInt[] =
NULL, NULL, NULL
},
+ {
+ {"multixact_offsets_buffers", PGC_POSTMASTER, RESOURCES_MEM,
+ gettext_noop("Sets the number of shared memory buffers used for the MultiXact offset SLRU cache."),
+ NULL,
+ GUC_UNIT_BLOCKS
+ },
+ &multixact_offsets_buffers,
+ 8, 2, SLRU_MAX_ALLOWED_BUFFERS,
+ NULL, NULL, NULL
+ },
+
+ {
+ {"multixact_members_buffers", PGC_POSTMASTER, RESOURCES_MEM,
+ gettext_noop("Sets the number of shared memory buffers used for the MultiXact member SLRU cache."),
+ NULL,
+ GUC_UNIT_BLOCKS
+ },
+ &multixact_members_buffers,
+ 16, 2, SLRU_MAX_ALLOWED_BUFFERS,
+ NULL, NULL, NULL
+ },
+
+ {
+ {"subtrans_buffers", PGC_POSTMASTER, RESOURCES_MEM,
+ gettext_noop("Sets the number of shared memory buffers used for the sub-transaction SLRU cache."),
+ NULL,
+ GUC_UNIT_BLOCKS
+ },
+ &subtrans_buffers,
+ 32, 2, SLRU_MAX_ALLOWED_BUFFERS,
+ NULL, NULL, NULL
+ },
+
+ {
+ {"notify_buffers", PGC_POSTMASTER, RESOURCES_MEM,
+ gettext_noop("Sets the number of shared memory buffers used for the NOTIFY message SLRU cache."),
+ NULL,
+ GUC_UNIT_BLOCKS
+ },
+ ¬ify_buffers,
+ 8, 2, SLRU_MAX_ALLOWED_BUFFERS,
+ NULL, NULL, NULL
+ },
+
+ {
+ {"serial_buffers", PGC_POSTMASTER, RESOURCES_MEM,
+ gettext_noop("Sets the number of shared memory buffers used for the serializable transaction SLRU cache."),
+ NULL,
+ GUC_UNIT_BLOCKS
+ },
+ &serial_buffers,
+ 16, 2, SLRU_MAX_ALLOWED_BUFFERS,
+ NULL, NULL, NULL
+ },
+
+ {
+ {"xact_buffers", PGC_POSTMASTER, RESOURCES_MEM,
+ gettext_noop("Sets the number of shared memory buffers used for the transaction status SLRU cache."),
+ NULL,
+ GUC_UNIT_BLOCKS
+ },
+ &xact_buffers,
+ 0, 0, CLOG_MAX_ALLOWED_BUFFERS,
+ NULL, NULL, show_xact_buffers
+ },
+
+ {
+ {"commit_ts_buffers", PGC_POSTMASTER, RESOURCES_MEM,
+ gettext_noop("Sets the size of the dedicated buffer pool used for the commit timestamp SLRU cache."),
+ NULL,
+ GUC_UNIT_BLOCKS
+ },
+ &commit_ts_buffers,
+ 0, 0, SLRU_MAX_ALLOWED_BUFFERS,
+ NULL, NULL, show_commit_ts_buffers
+ },
+
{
{"temp_buffers", PGC_USERSET, RESOURCES_MEM,
gettext_noop("Sets the maximum number of temporary buffers used by each session."),
@@ -11959,6 +12040,24 @@ show_tcp_user_timeout(void)
return nbuf;
}
+static const char *
+show_xact_buffers(void)
+{
+ static char nbuf[16];
+
+ snprintf(nbuf, sizeof(nbuf), "%zu", CLOGShmemBuffers());
+ return nbuf;
+}
+
+static const char *
+show_commit_ts_buffers(void)
+{
+ static char nbuf[16];
+
+ snprintf(nbuf, sizeof(nbuf), "%zu", CommitTsShmemBuffers());
+ return nbuf;
+}
+
static bool
check_maxconnections(int *newval, void **extra, GucSource source)
{
diff --git a/src/backend/utils/misc/postgresql.conf.sample b/src/backend/utils/misc/postgresql.conf.sample
index ff9fa006fe..7e14df3b51 100644
--- a/src/backend/utils/misc/postgresql.conf.sample
+++ b/src/backend/utils/misc/postgresql.conf.sample
@@ -190,6 +190,15 @@
# (change requires restart)
#backend_flush_after = 0 # measured in pages, 0 disables
+# - SLRU Buffers (change requires restart) -
+
+#xact_buffers = 0 # memory for pg_xact (0 = auto)
+#subtrans_buffers = 32 # memory for pg_subtrans
+#multixact_offsets_buffers = 8 # memory for pg_multixact/offsets
+#multixact_members_buffers = 16 # memory for pg_multixact/members
+#notify_buffers = 8 # memory for pg_notify
+#serial_buffers = 16 # memory for pg_serial
+#commit_ts_buffers = 0 # memory for pg_commit_ts (0 = auto)
#------------------------------------------------------------------------------
# WRITE-AHEAD LOG
diff --git a/src/include/access/clog.h b/src/include/access/clog.h
index 39b8e4afa8..739a292f7f 100644
--- a/src/include/access/clog.h
+++ b/src/include/access/clog.h
@@ -15,6 +15,16 @@
#include "storage/sync.h"
#include "lib/stringinfo.h"
+/*
+ * Don't allow xact_buffers to be set higher than could possibly be useful or
+ * SLRU would allow.
+ */
+#define CLOG_XACTS_PER_BYTE 4
+#define CLOG_XACTS_PER_PAGE (BLCKSZ * CLOG_XACTS_PER_BYTE)
+#define CLOG_MAX_ALLOWED_BUFFERS \
+ Min(SLRU_MAX_ALLOWED_BUFFERS, \
+ (((MaxTransactionId / 2) + (CLOG_XACTS_PER_PAGE - 1)) / CLOG_XACTS_PER_PAGE))
+
/*
* Possible transaction statuses --- note that all-zeroes is the initial
* state.
diff --git a/src/include/access/commit_ts.h b/src/include/access/commit_ts.h
index 750369104a..e4cf988609 100644
--- a/src/include/access/commit_ts.h
+++ b/src/include/access/commit_ts.h
@@ -17,7 +17,6 @@
#include "storage/sync.h"
#include "utils/guc.h"
-
extern PGDLLIMPORT bool track_commit_timestamp;
extern bool check_track_commit_timestamp(bool *newval, void **extra,
diff --git a/src/include/access/multixact.h b/src/include/access/multixact.h
index 4bbb035eae..97c0a46376 100644
--- a/src/include/access/multixact.h
+++ b/src/include/access/multixact.h
@@ -29,10 +29,6 @@
#define MaxMultiXactOffset ((MultiXactOffset) 0xFFFFFFFF)
-/* Number of SLRU buffers to use for multixact */
-#define NUM_MULTIXACTOFFSET_BUFFERS 8
-#define NUM_MULTIXACTMEMBER_BUFFERS 16
-
/*
* Possible multixact lock modes ("status"). The first four modes are for
* tuple locks (FOR KEY SHARE, FOR SHARE, FOR NO KEY UPDATE, FOR UPDATE); the
diff --git a/src/include/access/slru.h b/src/include/access/slru.h
index 8aa3efc0ee..97ea837646 100644
--- a/src/include/access/slru.h
+++ b/src/include/access/slru.h
@@ -18,6 +18,11 @@
#include "storage/sync.h"
#include "utils/hsearch.h"
+/*
+ * To avoid overflowing internal arithmetic and the size_t data type, the
+ * number of buffers should not exceed this number.
+ */
+#define SLRU_MAX_ALLOWED_BUFFERS ((1024 * 1024 * 1024) / BLCKSZ)
/*
* Define SLRU segment size. A page is the same BLCKSZ as is used everywhere
diff --git a/src/include/access/subtrans.h b/src/include/access/subtrans.h
index d0ab44ae82..64fa86938e 100644
--- a/src/include/access/subtrans.h
+++ b/src/include/access/subtrans.h
@@ -11,8 +11,6 @@
#ifndef SUBTRANS_H
#define SUBTRANS_H
-/* Number of SLRU buffers to use for subtrans */
-#define NUM_SUBTRANS_BUFFERS 32
extern void SubTransSetParent(TransactionId xid, TransactionId parent);
extern TransactionId SubTransGetParent(TransactionId xid);
diff --git a/src/include/commands/async.h b/src/include/commands/async.h
index 9217f66b91..fa831e3721 100644
--- a/src/include/commands/async.h
+++ b/src/include/commands/async.h
@@ -15,11 +15,6 @@
#include <signal.h>
-/*
- * The number of SLRU page buffers we use for the notification queue.
- */
-#define NUM_NOTIFY_BUFFERS 8
-
extern bool Trace_notify;
extern volatile sig_atomic_t notifyInterruptPending;
diff --git a/src/include/miscadmin.h b/src/include/miscadmin.h
index 95202d37af..495c1bf901 100644
--- a/src/include/miscadmin.h
+++ b/src/include/miscadmin.h
@@ -164,6 +164,13 @@ extern PGDLLIMPORT int MaxBackends;
extern PGDLLIMPORT int MaxConnections;
extern PGDLLIMPORT int max_worker_processes;
extern PGDLLIMPORT int max_parallel_workers;
+extern PGDLLIMPORT int multixact_offsets_buffers;
+extern PGDLLIMPORT int multixact_members_buffers;
+extern PGDLLIMPORT int subtrans_buffers;
+extern PGDLLIMPORT int notify_buffers;
+extern PGDLLIMPORT int serial_buffers;
+extern PGDLLIMPORT int xact_buffers;
+extern PGDLLIMPORT int commit_ts_buffers;
extern PGDLLIMPORT int MyProcPid;
extern PGDLLIMPORT pg_time_t MyStartTime;
diff --git a/src/include/storage/predicate.h b/src/include/storage/predicate.h
index 152b698611..c72779bd88 100644
--- a/src/include/storage/predicate.h
+++ b/src/include/storage/predicate.h
@@ -26,10 +26,6 @@ extern int max_predicate_locks_per_xact;
extern int max_predicate_locks_per_relation;
extern int max_predicate_locks_per_page;
-
-/* Number of SLRU buffers to use for Serial SLRU */
-#define NUM_SERIAL_BUFFERS 16
-
/*
* A handle used for sharing SERIALIZABLEXACT objects between the participants
* in a parallel query.
--
2.30.1
[text/x-patch] v16-0003-Limit-SLRU-buffer-replacement-search.patch (3.0K, ../../CA+hUKGLCLDtgDj2Xsf0uBk5WXDCeHxBDDJPsyY7m65Fde-=pyg@mail.gmail.com/4-v16-0003-Limit-SLRU-buffer-replacement-search.patch)
download | inline diff:
From 79c15f73a21cfb67cb6157fc5b6822bcdc696383 Mon Sep 17 00:00:00 2001
From: Thomas Munro <[email protected]>
Date: Thu, 8 Apr 2021 12:18:25 +1200
Subject: [PATCH v16 3/3] Limit SLRU buffer replacement search.
Now that users can configure large SLRU caches, slru.c's simple buffer
replacement algorithm needs some adjustment. For now, limit its linear
search for the least recently accessed buffer to an arbitrary cap. This
means it won't find the globally least recently used buffer, just the
least recently used in a given range of pages. The cap is initially set
as large as the previous hard-coded search size.
Discussion: https://postgr.es/m/2BEC2B3F-9B61-4C1D-9FB5-5FAB0F05EF86%40yandex-team.ru
---
src/backend/access/transam/slru.c | 15 ++++++++++++++-
src/include/access/slru.h | 3 +++
2 files changed, 17 insertions(+), 1 deletion(-)
diff --git a/src/backend/access/transam/slru.c b/src/backend/access/transam/slru.c
index 82c61c475b..131f7a48d7 100644
--- a/src/backend/access/transam/slru.c
+++ b/src/backend/access/transam/slru.c
@@ -71,6 +71,12 @@
*/
#define MAX_WRITEALL_BUFFERS 16
+/*
+ * When searching for buffers to replace, we will limit the scope of our search
+ * for now, to avoid holding an exclusive lock for too long.
+ */
+#define MAX_REPLACEMENT_SEARCH 128
+
typedef struct SlruWriteAllData
{
int num_files; /* # files actually open */
@@ -1060,6 +1066,7 @@ SlruSelectLRUPage(SlruCtl ctl, int pageno)
{
SlruShared shared = ctl->shared;
+
/* Outer loop handles restart after I/O */
for (;;)
{
@@ -1071,6 +1078,7 @@ SlruSelectLRUPage(SlruCtl ctl, int pageno)
int bestinvalidslot = 0; /* keep compiler quiet */
int best_invalid_delta = -1;
int best_invalid_page_number = 0; /* keep compiler quiet */
+ int max_search;
/* See if page already has a buffer assigned */
slotno = SlruMappingFind(ctl, pageno);
@@ -1108,12 +1116,17 @@ SlruSelectLRUPage(SlruCtl ctl, int pageno)
* That gets us back on the path to having good data when there are
* multiple pages with the same lru_count.
*/
+ max_search = Min(shared->num_slots, MAX_REPLACEMENT_SEARCH);
cur_count = (shared->cur_lru_count)++;
- for (slotno = 0; slotno < shared->num_slots; slotno++)
+ for (int i = 0; i < max_search; ++i)
{
int this_delta;
int this_page_number;
+ slotno = shared->search_slotno++;
+ if (shared->search_slotno == shared->num_slots)
+ shared->search_slotno = 0;
+
if (shared->page_status[slotno] == SLRU_PAGE_EMPTY)
return slotno;
this_delta = cur_count - shared->page_lru_count[slotno];
diff --git a/src/include/access/slru.h b/src/include/access/slru.h
index 97ea837646..fb8a03972d 100644
--- a/src/include/access/slru.h
+++ b/src/include/access/slru.h
@@ -63,6 +63,9 @@ typedef struct SlruSharedData
/* Number of buffers managed by this SLRU structure */
int num_slots;
+ /* Where to start buffer replacement search. */
+ int search_slotno;
+
/*
* Arrays holding info for each buffer slot. Page number is undefined
* when status is EMPTY, as is page_lru_count.
--
2.30.1
^ permalink raw reply [nested|flat] 90+ messages in thread
* Re: MultiXact\SLRU buffers configuration
2020-05-08 16:36 MultiXact\SLRU buffers configuration Andrey M. Borodin <[email protected]>
2020-05-11 11:17 ` Re: MultiXact\SLRU buffers configuration Andrey M. Borodin <[email protected]>
2020-05-13 18:08 ` Re: MultiXact\SLRU buffers configuration Andrey M. Borodin <[email protected]>
2020-05-14 01:25 ` Re: MultiXact\SLRU buffers configuration Kyotaro Horiguchi <[email protected]>
2020-05-14 05:19 ` Re: MultiXact\SLRU buffers configuration Andrey M. Borodin <[email protected]>
2020-05-14 06:16 ` Re: MultiXact\SLRU buffers configuration Kyotaro Horiguchi <[email protected]>
2020-05-14 06:44 ` Re: MultiXact\SLRU buffers configuration Andrey M. Borodin <[email protected]>
2020-05-15 00:03 ` Re: MultiXact\SLRU buffers configuration Kyotaro Horiguchi <[email protected]>
2020-07-02 12:02 ` Re: MultiXact\SLRU buffers configuration Daniel Gustafsson <[email protected]>
2020-07-08 07:03 ` Re: MultiXact\SLRU buffers configuration Andrey M. Borodin <[email protected]>
2020-08-28 18:08 ` Re: MultiXact\SLRU buffers configuration Anastasia Lubennikova <[email protected]>
2020-09-28 14:41 ` Re: MultiXact\SLRU buffers configuration Andrey M. Borodin <[email protected]>
2020-10-26 01:05 ` Re: MultiXact\SLRU buffers configuration Alexander Korotkov <[email protected]>
2020-10-26 15:45 ` Re: MultiXact\SLRU buffers configuration Andrey Borodin <[email protected]>
2020-10-27 17:02 ` Re: MultiXact\SLRU buffers configuration Alexander Korotkov <[email protected]>
2020-10-27 17:23 ` Re: MultiXact\SLRU buffers configuration Alexander Korotkov <[email protected]>
2020-10-28 01:36 ` Re: MultiXact\SLRU buffers configuration Tomas Vondra <[email protected]>
2020-10-28 07:34 ` Re: MultiXact\SLRU buffers configuration Andrey Borodin <[email protected]>
2020-10-28 23:32 ` Re: MultiXact\SLRU buffers configuration Tomas Vondra <[email protected]>
2020-10-29 07:08 ` Re: MultiXact\SLRU buffers configuration Andrey Borodin <[email protected]>
2020-10-29 13:49 ` Re: MultiXact\SLRU buffers configuration Tomas Vondra <[email protected]>
2020-11-02 12:45 ` Re: MultiXact\SLRU buffers configuration Andrey Borodin <[email protected]>
2020-11-10 00:13 ` Re: MultiXact\SLRU buffers configuration Tomas Vondra <[email protected]>
2020-11-10 06:16 ` Re: MultiXact\SLRU buffers configuration Andrey Borodin <[email protected]>
2020-11-10 18:07 ` Re: MultiXact\SLRU buffers configuration Tomas Vondra <[email protected]>
2020-11-13 11:49 ` Re: MultiXact\SLRU buffers configuration Andrey Borodin <[email protected]>
2020-12-08 16:05 ` Re: MultiXact\SLRU buffers configuration Gilles Darold <[email protected]>
2020-12-08 17:52 ` Re: MultiXact\SLRU buffers configuration Andrey Borodin <[email protected]>
2020-12-10 14:45 ` Re: MultiXact\SLRU buffers configuration Gilles Darold <[email protected]>
2020-12-11 17:50 ` Re: MultiXact\SLRU buffers configuration Gilles Darold <[email protected]>
2020-12-13 09:17 ` Re: MultiXact\SLRU buffers configuration Gilles Darold <[email protected]>
2020-12-13 17:24 ` Re: MultiXact\SLRU buffers configuration Andrey Borodin <[email protected]>
2020-12-23 16:31 ` Re: MultiXact\SLRU buffers configuration Gilles Darold <[email protected]>
2021-02-15 17:17 ` Re: MultiXact\SLRU buffers configuration Andrey Borodin <[email protected]>
2021-03-11 15:50 ` Re: MultiXact\SLRU buffers configuration Gilles Darold <[email protected]>
2021-03-12 12:44 ` Re: MultiXact\SLRU buffers configuration Andrey Borodin <[email protected]>
2021-03-24 21:31 ` Re: MultiXact\SLRU buffers configuration Thomas Munro <[email protected]>
2021-03-25 01:03 ` Re: MultiXact\SLRU buffers configuration Thomas Munro <[email protected]>
2021-03-26 03:46 ` Re: MultiXact\SLRU buffers configuration Thomas Munro <[email protected]>
2021-03-26 06:00 ` Re: MultiXact\SLRU buffers configuration Andrey Borodin <[email protected]>
2021-03-26 15:52 ` Re: MultiXact\SLRU buffers configuration Andrey Borodin <[email protected]>
2021-03-26 20:26 ` Re: MultiXact\SLRU buffers configuration Thomas Munro <[email protected]>
2021-03-27 05:31 ` Re: MultiXact\SLRU buffers configuration Andrey Borodin <[email protected]>
2021-03-28 21:15 ` Re: MultiXact\SLRU buffers configuration Thomas Munro <[email protected]>
2021-03-29 08:26 ` Re: MultiXact\SLRU buffers configuration Andrey Borodin <[email protected]>
2021-03-31 21:09 ` Re: MultiXact\SLRU buffers configuration Andrey Borodin <[email protected]>
2021-04-01 03:40 ` Re: MultiXact\SLRU buffers configuration Thomas Munro <[email protected]>
2021-04-03 19:57 ` Re: MultiXact\SLRU buffers configuration Andrey Borodin <[email protected]>
2021-04-07 05:59 ` Re: MultiXact\SLRU buffers configuration Thomas Munro <[email protected]>
2021-04-07 11:44 ` Re: MultiXact\SLRU buffers configuration Andrey Borodin <[email protected]>
2021-04-07 12:13 ` Re: MultiXact\SLRU buffers configuration Andrey Borodin <[email protected]>
2021-04-08 00:30 ` Re: MultiXact\SLRU buffers configuration Thomas Munro <[email protected]>
@ 2021-04-08 07:24 ` Andrey Borodin <[email protected]>
2021-04-08 12:22 ` Re: MultiXact\SLRU buffers configuration Thomas Munro <[email protected]>
0 siblings, 1 reply; 90+ messages in thread
From: Andrey Borodin @ 2021-04-08 07:24 UTC (permalink / raw)
To: Thomas Munro <[email protected]>; +Cc: Gilles Darold <[email protected]>; Tomas Vondra <[email protected]>; Tomas Vondra <[email protected]>; Alexander Korotkov <[email protected]>; Anastasia Lubennikova <[email protected]>; Daniel Gustafsson <[email protected]>; Kyotaro Horiguchi <[email protected]>; pgsql-hackers
> 8 апр. 2021 г., в 03:30, Thomas Munro <[email protected]> написал(а):
>
> Here's another approach that is a little less exciting than
> "tournament RR" (or whatever that should be called; I couldn't find an
> established name for it). This version is just our traditional linear
> search, except that it stops at 128, and remembers where to start from
> next time (like a sort of Fisher-Price GCLOCK hand). This feels more
> committable to me. You can argue that all buffers above 128 are bonus
> buffers that PostgreSQL 13 didn't have, so the fact that we can no
> longer find the globally least recently used page when you set
> xact_buffers > 128 doesn't seem too bad to me, as an incremental step
> (but to be clear, of course we can do better than this with more work
> in later releases).
I agree that this version of eviction seems much more effective and less intrusive than RR. And it's still LRU, which is important for subsystem that is called SLRU.
shared->search_slotno is initialized implicitly with memset(). But this seems like a common practice.
Also comment above "max_search = Min(shared->num_slots, MAX_REPLACEMENT_SEARCH);" does not reflect changes.
Besides this patch looks good to me.
Thanks!
Best regards, Andrey Borodin.
^ permalink raw reply [nested|flat] 90+ messages in thread
* Re: MultiXact\SLRU buffers configuration
2020-05-08 16:36 MultiXact\SLRU buffers configuration Andrey M. Borodin <[email protected]>
2020-05-11 11:17 ` Re: MultiXact\SLRU buffers configuration Andrey M. Borodin <[email protected]>
2020-05-13 18:08 ` Re: MultiXact\SLRU buffers configuration Andrey M. Borodin <[email protected]>
2020-05-14 01:25 ` Re: MultiXact\SLRU buffers configuration Kyotaro Horiguchi <[email protected]>
2020-05-14 05:19 ` Re: MultiXact\SLRU buffers configuration Andrey M. Borodin <[email protected]>
2020-05-14 06:16 ` Re: MultiXact\SLRU buffers configuration Kyotaro Horiguchi <[email protected]>
2020-05-14 06:44 ` Re: MultiXact\SLRU buffers configuration Andrey M. Borodin <[email protected]>
2020-05-15 00:03 ` Re: MultiXact\SLRU buffers configuration Kyotaro Horiguchi <[email protected]>
2020-07-02 12:02 ` Re: MultiXact\SLRU buffers configuration Daniel Gustafsson <[email protected]>
2020-07-08 07:03 ` Re: MultiXact\SLRU buffers configuration Andrey M. Borodin <[email protected]>
2020-08-28 18:08 ` Re: MultiXact\SLRU buffers configuration Anastasia Lubennikova <[email protected]>
2020-09-28 14:41 ` Re: MultiXact\SLRU buffers configuration Andrey M. Borodin <[email protected]>
2020-10-26 01:05 ` Re: MultiXact\SLRU buffers configuration Alexander Korotkov <[email protected]>
2020-10-26 15:45 ` Re: MultiXact\SLRU buffers configuration Andrey Borodin <[email protected]>
2020-10-27 17:02 ` Re: MultiXact\SLRU buffers configuration Alexander Korotkov <[email protected]>
2020-10-27 17:23 ` Re: MultiXact\SLRU buffers configuration Alexander Korotkov <[email protected]>
2020-10-28 01:36 ` Re: MultiXact\SLRU buffers configuration Tomas Vondra <[email protected]>
2020-10-28 07:34 ` Re: MultiXact\SLRU buffers configuration Andrey Borodin <[email protected]>
2020-10-28 23:32 ` Re: MultiXact\SLRU buffers configuration Tomas Vondra <[email protected]>
2020-10-29 07:08 ` Re: MultiXact\SLRU buffers configuration Andrey Borodin <[email protected]>
2020-10-29 13:49 ` Re: MultiXact\SLRU buffers configuration Tomas Vondra <[email protected]>
2020-11-02 12:45 ` Re: MultiXact\SLRU buffers configuration Andrey Borodin <[email protected]>
2020-11-10 00:13 ` Re: MultiXact\SLRU buffers configuration Tomas Vondra <[email protected]>
2020-11-10 06:16 ` Re: MultiXact\SLRU buffers configuration Andrey Borodin <[email protected]>
2020-11-10 18:07 ` Re: MultiXact\SLRU buffers configuration Tomas Vondra <[email protected]>
2020-11-13 11:49 ` Re: MultiXact\SLRU buffers configuration Andrey Borodin <[email protected]>
2020-12-08 16:05 ` Re: MultiXact\SLRU buffers configuration Gilles Darold <[email protected]>
2020-12-08 17:52 ` Re: MultiXact\SLRU buffers configuration Andrey Borodin <[email protected]>
2020-12-10 14:45 ` Re: MultiXact\SLRU buffers configuration Gilles Darold <[email protected]>
2020-12-11 17:50 ` Re: MultiXact\SLRU buffers configuration Gilles Darold <[email protected]>
2020-12-13 09:17 ` Re: MultiXact\SLRU buffers configuration Gilles Darold <[email protected]>
2020-12-13 17:24 ` Re: MultiXact\SLRU buffers configuration Andrey Borodin <[email protected]>
2020-12-23 16:31 ` Re: MultiXact\SLRU buffers configuration Gilles Darold <[email protected]>
2021-02-15 17:17 ` Re: MultiXact\SLRU buffers configuration Andrey Borodin <[email protected]>
2021-03-11 15:50 ` Re: MultiXact\SLRU buffers configuration Gilles Darold <[email protected]>
2021-03-12 12:44 ` Re: MultiXact\SLRU buffers configuration Andrey Borodin <[email protected]>
2021-03-24 21:31 ` Re: MultiXact\SLRU buffers configuration Thomas Munro <[email protected]>
2021-03-25 01:03 ` Re: MultiXact\SLRU buffers configuration Thomas Munro <[email protected]>
2021-03-26 03:46 ` Re: MultiXact\SLRU buffers configuration Thomas Munro <[email protected]>
2021-03-26 06:00 ` Re: MultiXact\SLRU buffers configuration Andrey Borodin <[email protected]>
2021-03-26 15:52 ` Re: MultiXact\SLRU buffers configuration Andrey Borodin <[email protected]>
2021-03-26 20:26 ` Re: MultiXact\SLRU buffers configuration Thomas Munro <[email protected]>
2021-03-27 05:31 ` Re: MultiXact\SLRU buffers configuration Andrey Borodin <[email protected]>
2021-03-28 21:15 ` Re: MultiXact\SLRU buffers configuration Thomas Munro <[email protected]>
2021-03-29 08:26 ` Re: MultiXact\SLRU buffers configuration Andrey Borodin <[email protected]>
2021-03-31 21:09 ` Re: MultiXact\SLRU buffers configuration Andrey Borodin <[email protected]>
2021-04-01 03:40 ` Re: MultiXact\SLRU buffers configuration Thomas Munro <[email protected]>
2021-04-03 19:57 ` Re: MultiXact\SLRU buffers configuration Andrey Borodin <[email protected]>
2021-04-07 05:59 ` Re: MultiXact\SLRU buffers configuration Thomas Munro <[email protected]>
2021-04-07 11:44 ` Re: MultiXact\SLRU buffers configuration Andrey Borodin <[email protected]>
2021-04-07 12:13 ` Re: MultiXact\SLRU buffers configuration Andrey Borodin <[email protected]>
2021-04-08 00:30 ` Re: MultiXact\SLRU buffers configuration Thomas Munro <[email protected]>
2021-04-08 07:24 ` Re: MultiXact\SLRU buffers configuration Andrey Borodin <[email protected]>
@ 2021-04-08 12:22 ` Thomas Munro <[email protected]>
2021-04-11 18:37 ` Re: MultiXact\SLRU buffers configuration Andrey Borodin <[email protected]>
2022-07-21 13:00 ` Re: MultiXact\SLRU buffers configuration Yura Sokolov <[email protected]>
0 siblings, 2 replies; 90+ messages in thread
From: Thomas Munro @ 2021-04-08 12:22 UTC (permalink / raw)
To: Andrey Borodin <[email protected]>; +Cc: Gilles Darold <[email protected]>; Tomas Vondra <[email protected]>; Tomas Vondra <[email protected]>; Alexander Korotkov <[email protected]>; Anastasia Lubennikova <[email protected]>; Daniel Gustafsson <[email protected]>; Kyotaro Horiguchi <[email protected]>; pgsql-hackers
On Thu, Apr 8, 2021 at 7:24 PM Andrey Borodin <[email protected]> wrote:
> I agree that this version of eviction seems much more effective and less intrusive than RR. And it's still LRU, which is important for subsystem that is called SLRU.
> shared->search_slotno is initialized implicitly with memset(). But this seems like a common practice.
> Also comment above "max_search = Min(shared->num_slots, MAX_REPLACEMENT_SEARCH);" does not reflect changes.
>
> Besides this patch looks good to me.
Thanks! I chickened out of committing a buffer replacement algorithm
patch written 11 hours before the feature freeze, but I also didn't
really want to commit the GUC patch without that. Ahh, if only we'd
latched onto the real problems here just a little sooner, but there is
always PostgreSQL 15, I heard it's going to be amazing. Moved to next
CF.
^ permalink raw reply [nested|flat] 90+ messages in thread
* Re: MultiXact\SLRU buffers configuration
2020-05-08 16:36 MultiXact\SLRU buffers configuration Andrey M. Borodin <[email protected]>
2020-05-11 11:17 ` Re: MultiXact\SLRU buffers configuration Andrey M. Borodin <[email protected]>
2020-05-13 18:08 ` Re: MultiXact\SLRU buffers configuration Andrey M. Borodin <[email protected]>
2020-05-14 01:25 ` Re: MultiXact\SLRU buffers configuration Kyotaro Horiguchi <[email protected]>
2020-05-14 05:19 ` Re: MultiXact\SLRU buffers configuration Andrey M. Borodin <[email protected]>
2020-05-14 06:16 ` Re: MultiXact\SLRU buffers configuration Kyotaro Horiguchi <[email protected]>
2020-05-14 06:44 ` Re: MultiXact\SLRU buffers configuration Andrey M. Borodin <[email protected]>
2020-05-15 00:03 ` Re: MultiXact\SLRU buffers configuration Kyotaro Horiguchi <[email protected]>
2020-07-02 12:02 ` Re: MultiXact\SLRU buffers configuration Daniel Gustafsson <[email protected]>
2020-07-08 07:03 ` Re: MultiXact\SLRU buffers configuration Andrey M. Borodin <[email protected]>
2020-08-28 18:08 ` Re: MultiXact\SLRU buffers configuration Anastasia Lubennikova <[email protected]>
2020-09-28 14:41 ` Re: MultiXact\SLRU buffers configuration Andrey M. Borodin <[email protected]>
2020-10-26 01:05 ` Re: MultiXact\SLRU buffers configuration Alexander Korotkov <[email protected]>
2020-10-26 15:45 ` Re: MultiXact\SLRU buffers configuration Andrey Borodin <[email protected]>
2020-10-27 17:02 ` Re: MultiXact\SLRU buffers configuration Alexander Korotkov <[email protected]>
2020-10-27 17:23 ` Re: MultiXact\SLRU buffers configuration Alexander Korotkov <[email protected]>
2020-10-28 01:36 ` Re: MultiXact\SLRU buffers configuration Tomas Vondra <[email protected]>
2020-10-28 07:34 ` Re: MultiXact\SLRU buffers configuration Andrey Borodin <[email protected]>
2020-10-28 23:32 ` Re: MultiXact\SLRU buffers configuration Tomas Vondra <[email protected]>
2020-10-29 07:08 ` Re: MultiXact\SLRU buffers configuration Andrey Borodin <[email protected]>
2020-10-29 13:49 ` Re: MultiXact\SLRU buffers configuration Tomas Vondra <[email protected]>
2020-11-02 12:45 ` Re: MultiXact\SLRU buffers configuration Andrey Borodin <[email protected]>
2020-11-10 00:13 ` Re: MultiXact\SLRU buffers configuration Tomas Vondra <[email protected]>
2020-11-10 06:16 ` Re: MultiXact\SLRU buffers configuration Andrey Borodin <[email protected]>
2020-11-10 18:07 ` Re: MultiXact\SLRU buffers configuration Tomas Vondra <[email protected]>
2020-11-13 11:49 ` Re: MultiXact\SLRU buffers configuration Andrey Borodin <[email protected]>
2020-12-08 16:05 ` Re: MultiXact\SLRU buffers configuration Gilles Darold <[email protected]>
2020-12-08 17:52 ` Re: MultiXact\SLRU buffers configuration Andrey Borodin <[email protected]>
2020-12-10 14:45 ` Re: MultiXact\SLRU buffers configuration Gilles Darold <[email protected]>
2020-12-11 17:50 ` Re: MultiXact\SLRU buffers configuration Gilles Darold <[email protected]>
2020-12-13 09:17 ` Re: MultiXact\SLRU buffers configuration Gilles Darold <[email protected]>
2020-12-13 17:24 ` Re: MultiXact\SLRU buffers configuration Andrey Borodin <[email protected]>
2020-12-23 16:31 ` Re: MultiXact\SLRU buffers configuration Gilles Darold <[email protected]>
2021-02-15 17:17 ` Re: MultiXact\SLRU buffers configuration Andrey Borodin <[email protected]>
2021-03-11 15:50 ` Re: MultiXact\SLRU buffers configuration Gilles Darold <[email protected]>
2021-03-12 12:44 ` Re: MultiXact\SLRU buffers configuration Andrey Borodin <[email protected]>
2021-03-24 21:31 ` Re: MultiXact\SLRU buffers configuration Thomas Munro <[email protected]>
2021-03-25 01:03 ` Re: MultiXact\SLRU buffers configuration Thomas Munro <[email protected]>
2021-03-26 03:46 ` Re: MultiXact\SLRU buffers configuration Thomas Munro <[email protected]>
2021-03-26 06:00 ` Re: MultiXact\SLRU buffers configuration Andrey Borodin <[email protected]>
2021-03-26 15:52 ` Re: MultiXact\SLRU buffers configuration Andrey Borodin <[email protected]>
2021-03-26 20:26 ` Re: MultiXact\SLRU buffers configuration Thomas Munro <[email protected]>
2021-03-27 05:31 ` Re: MultiXact\SLRU buffers configuration Andrey Borodin <[email protected]>
2021-03-28 21:15 ` Re: MultiXact\SLRU buffers configuration Thomas Munro <[email protected]>
2021-03-29 08:26 ` Re: MultiXact\SLRU buffers configuration Andrey Borodin <[email protected]>
2021-03-31 21:09 ` Re: MultiXact\SLRU buffers configuration Andrey Borodin <[email protected]>
2021-04-01 03:40 ` Re: MultiXact\SLRU buffers configuration Thomas Munro <[email protected]>
2021-04-03 19:57 ` Re: MultiXact\SLRU buffers configuration Andrey Borodin <[email protected]>
2021-04-07 05:59 ` Re: MultiXact\SLRU buffers configuration Thomas Munro <[email protected]>
2021-04-07 11:44 ` Re: MultiXact\SLRU buffers configuration Andrey Borodin <[email protected]>
2021-04-07 12:13 ` Re: MultiXact\SLRU buffers configuration Andrey Borodin <[email protected]>
2021-04-08 00:30 ` Re: MultiXact\SLRU buffers configuration Thomas Munro <[email protected]>
2021-04-08 07:24 ` Re: MultiXact\SLRU buffers configuration Andrey Borodin <[email protected]>
2021-04-08 12:22 ` Re: MultiXact\SLRU buffers configuration Thomas Munro <[email protected]>
@ 2021-04-11 18:37 ` Andrey Borodin <[email protected]>
2021-06-14 17:40 ` Re: MultiXact\SLRU buffers configuration Васильев Дмитрий <[email protected]>
2021-12-26 10:09 ` Re: MultiXact\SLRU buffers configuration Andrey Borodin <[email protected]>
1 sibling, 2 replies; 90+ messages in thread
From: Andrey Borodin @ 2021-04-11 18:37 UTC (permalink / raw)
To: Thomas Munro <[email protected]>; +Cc: Gilles Darold <[email protected]>; Tomas Vondra <[email protected]>; Tomas Vondra <[email protected]>; Alexander Korotkov <[email protected]>; Anastasia Lubennikova <[email protected]>; Daniel Gustafsson <[email protected]>; Kyotaro Horiguchi <[email protected]>; pgsql-hackers
> 8 апр. 2021 г., в 15:22, Thomas Munro <[email protected]> написал(а):
>
> On Thu, Apr 8, 2021 at 7:24 PM Andrey Borodin <[email protected]> wrote:
>> I agree that this version of eviction seems much more effective and less intrusive than RR. And it's still LRU, which is important for subsystem that is called SLRU.
>> shared->search_slotno is initialized implicitly with memset(). But this seems like a common practice.
>> Also comment above "max_search = Min(shared->num_slots, MAX_REPLACEMENT_SEARCH);" does not reflect changes.
>>
>> Besides this patch looks good to me.
>
> Thanks! I chickened out of committing a buffer replacement algorithm
> patch written 11 hours before the feature freeze, but I also didn't
> really want to commit the GUC patch without that. Ahh, if only we'd
> latched onto the real problems here just a little sooner, but there is
> always PostgreSQL 15, I heard it's going to be amazing. Moved to next
> CF.
I have one more idea inspired by CPU caches.
Let's make SLRU n-associative, where n ~ 8.
We can divide buffers into "banks", number of banks must be power of 2.
All banks are of equal size. We choose bank size to approximately satisfy user's configured buffer size.
Each page can live only within one bank. We use same search and eviction algorithms as we used in SLRU, but we only need to search\evict over 8 elements.
All SLRU data of a single bank will be colocated within at most 2 cache line.
I did not come up with idea how to avoid multiplication of bank_number * bank_size in case when user configured 31337 buffers (any number that is radically not a power of 2).
PFA patch implementing this idea.
Best regards, Andrey Borodin.
Attachments:
[application/octet-stream] v17-0002-Divide-SLRU-buffers-into-n-associative-banks.patch (4.2K, ../../[email protected]/2-v17-0002-Divide-SLRU-buffers-into-n-associative-banks.patch)
download | inline diff:
From b418d7eafacfd9aa6d44951deda9690752732197 Mon Sep 17 00:00:00 2001
From: Andrey Borodin <[email protected]>
Date: Sun, 11 Apr 2021 21:18:10 +0300
Subject: [PATCH v17 2/2] Divide SLRU buffers into n-associative banks
---
src/backend/access/transam/slru.c | 36 +++++++++++++++++++++++++++----
src/include/access/slru.h | 2 ++
2 files changed, 34 insertions(+), 4 deletions(-)
diff --git a/src/backend/access/transam/slru.c b/src/backend/access/transam/slru.c
index 82149ad782..84321b7509 100644
--- a/src/backend/access/transam/slru.c
+++ b/src/backend/access/transam/slru.c
@@ -133,7 +133,7 @@ typedef enum
static SlruErrorCause slru_errcause;
static int slru_errno;
-
+static void SlruAdjustNSlots(int* nslots, int* banksize, int* bankoffset);
static void SimpleLruZeroLSNs(SlruCtl ctl, int slotno);
static void SimpleLruWaitIO(SlruCtl ctl, int slotno);
static void SlruInternalWritePage(SlruCtl ctl, int slotno, SlruWriteAll fdata);
@@ -147,6 +147,23 @@ static bool SlruScanDirCbDeleteCutoff(SlruCtl ctl, char *filename,
int segpage, void *data);
static void SlruInternalDeleteSegment(SlruCtl ctl, int segno);
+static void SlruAdjustNSlots(int* nslots, int* banksize, int* bankoffset)
+{
+ *banksize = *nslots;
+ int nbanks = 1;
+ *bankoffset = 0;
+ while (*banksize > 15)
+ {
+ if ((*banksize & 1) != 0)
+ *banksize +=1;
+ *banksize /= 2;
+ nbanks *= 2;
+ *bankoffset += 1;
+ }
+ elog(DEBUG5, "nslots %d banksize %d nbanks %d ", *nslots, *banksize, nbanks);
+ *nslots = *banksize * nbanks;
+}
+
/*
* Initialization of shared memory
*/
@@ -155,6 +172,8 @@ Size
SimpleLruShmemSize(int nslots, int nlsns)
{
Size sz;
+ int bankoffset, banksize;
+ SlruAdjustNSlots(&nslots, &banksize, &bankoffset);
/* we assume nslots isn't so large as to risk overflow */
sz = MAXALIGN(sizeof(SlruSharedData));
@@ -189,6 +208,8 @@ SimpleLruInit(SlruCtl ctl, const char *name, int nslots, int nlsns,
{
SlruShared shared;
bool found;
+ int bankoffset, banksize;
+ SlruAdjustNSlots(&nslots, &banksize, &bankoffset);
shared = (SlruShared) ShmemInitStruct(name,
SimpleLruShmemSize(nslots, nlsns),
@@ -208,6 +229,9 @@ SimpleLruInit(SlruCtl ctl, const char *name, int nslots, int nlsns,
shared->ControlLock = ctllock;
shared->num_slots = nslots;
+ shared->bank_mask = (1 << bankoffset) - 1;
+ shared->bank_size = banksize;
+
shared->lsn_groups_per_page = nlsns;
shared->cur_lru_count = 0;
@@ -500,7 +524,9 @@ SimpleLruReadPage_ReadOnly(SlruCtl ctl, int pageno, TransactionId xid)
LWLockAcquire(shared->ControlLock, LW_SHARED);
/* See if page is already in a buffer */
- for (slotno = 0; slotno < shared->num_slots; slotno++)
+ int bankstart = (pageno & shared->bank_mask) * shared->bank_size;
+ int bankend = bankstart + shared->bank_size;
+ for (slotno = bankstart; slotno < bankend; slotno++)
{
if (shared->page_number[slotno] == pageno &&
shared->page_status[slotno] != SLRU_PAGE_EMPTY &&
@@ -1029,7 +1055,9 @@ SlruSelectLRUPage(SlruCtl ctl, int pageno)
int best_invalid_page_number = 0; /* keep compiler quiet */
/* See if page already has a buffer assigned */
- for (slotno = 0; slotno < shared->num_slots; slotno++)
+ int bankstart = (pageno & shared->bank_mask) * shared->bank_size;
+ int bankend = bankstart + shared->bank_size;
+ for (slotno = bankstart; slotno < bankend; slotno++)
{
if (shared->page_number[slotno] == pageno &&
shared->page_status[slotno] != SLRU_PAGE_EMPTY)
@@ -1064,7 +1092,7 @@ SlruSelectLRUPage(SlruCtl ctl, int pageno)
* multiple pages with the same lru_count.
*/
cur_count = (shared->cur_lru_count)++;
- for (slotno = 0; slotno < shared->num_slots; slotno++)
+ for (slotno = bankstart; slotno < bankend; slotno++)
{
int this_delta;
int this_page_number;
diff --git a/src/include/access/slru.h b/src/include/access/slru.h
index 793c045f16..f4df54d3c1 100644
--- a/src/include/access/slru.h
+++ b/src/include/access/slru.h
@@ -61,6 +61,8 @@ typedef struct SlruSharedData
/* Number of buffers managed by this SLRU structure */
int num_slots;
+ int bank_size;
+ int bank_mask;
/*
* Arrays holding info for each buffer slot. Page number is undefined
--
2.24.3 (Apple Git-128)
[application/octet-stream] v17-0001-Make-all-SLRU-buffer-sizes-configurable.patch (25.7K, ../../[email protected]/3-v17-0001-Make-all-SLRU-buffer-sizes-configurable.patch)
download | inline diff:
From 46b3aff4ebede9378ea5471d578e8466f0639919 Mon Sep 17 00:00:00 2001
From: Andrey Borodin <[email protected]>
Date: Mon, 15 Feb 2021 21:51:56 +0500
Subject: [PATCH v17 1/2] Make all SLRU buffer sizes configurable.
Provide new GUCs to set the number of buffers, instead of using hard
coded defaults.
Remove the limits on xact_buffers and commit_ts_buffers. The default
sizes for those caches are ~0.2% and ~0.1% of shared_buffers, as before,
but now there is no cap at 128 and 16 buffers respectively (unless
track_commit_timestamp is disabled, in the latter case, then we might as
well keep it tiny). Sizes much larger than the old limits have been
shown to be useful on modern systems, and an earlier commit replaced a
linear search with a hash table to avoid problems with extreme cases.
Author: Andrey M. Borodin <[email protected]>
Reviewed-by: Anastasia Lubennikova <[email protected]>
Reviewed-by: Tomas Vondra <[email protected]>
Reviewed-by: Alexander Korotkov <[email protected]>
Reviewed-by: Gilles Darold <[email protected]>
Reviewed-by: Thomas Munro <[email protected]>
Discussion: https://postgr.es/m/2BEC2B3F-9B61-4C1D-9FB5-5FAB0F05EF86%40yandex-team.ru
---
doc/src/sgml/config.sgml | 135 ++++++++++++++++++
src/backend/access/transam/clog.c | 23 ++-
src/backend/access/transam/commit_ts.c | 10 +-
src/backend/access/transam/multixact.c | 8 +-
src/backend/access/transam/subtrans.c | 5 +-
src/backend/commands/async.c | 8 +-
src/backend/storage/lmgr/predicate.c | 4 +-
src/backend/utils/init/globals.c | 8 ++
src/backend/utils/misc/guc.c | 99 +++++++++++++
src/backend/utils/misc/postgresql.conf.sample | 9 ++
src/include/access/clog.h | 10 ++
src/include/access/commit_ts.h | 1 -
src/include/access/multixact.h | 4 -
src/include/access/slru.h | 5 +
src/include/access/subtrans.h | 2 -
src/include/commands/async.h | 5 -
src/include/miscadmin.h | 7 +
src/include/storage/predicate.h | 4 -
18 files changed, 301 insertions(+), 46 deletions(-)
diff --git a/doc/src/sgml/config.sgml b/doc/src/sgml/config.sgml
index ea5cf3a2dc..43bd93ccf4 100644
--- a/doc/src/sgml/config.sgml
+++ b/doc/src/sgml/config.sgml
@@ -1924,6 +1924,141 @@ include_dir 'conf.d'
</para>
</listitem>
</varlistentry>
+
+ <varlistentry id="guc-multixact-offsets-buffers" xreflabel="multixact_offsets_buffers">
+ <term><varname>multixact_offsets_buffers</varname> (<type>integer</type>)
+ <indexterm>
+ <primary><varname>multixact_offsets_buffers</varname> configuration parameter</primary>
+ </indexterm>
+ </term>
+ <listitem>
+ <para>
+ Specifies the amount of shared memory to use to cache the contents
+ of <literal>pg_multixact/offsets</literal> (see
+ <xref linkend="pgdata-contents-table"/>).
+ If this value is specified without units, it is taken as blocks,
+ that is <symbol>BLCKSZ</symbol> bytes, typically 8kB.
+ The default value is <literal>8</literal>.
+ This parameter can only be set at server start.
+ </para>
+ </listitem>
+ </varlistentry>
+
+ <varlistentry id="guc-multixact-members-buffers" xreflabel="multixact_members_buffers">
+ <term><varname>multixact_members_buffers</varname> (<type>integer</type>)
+ <indexterm>
+ <primary><varname>multixact_members_buffers</varname> configuration parameter</primary>
+ </indexterm>
+ </term>
+ <listitem>
+ <para>
+ Specifies the amount of shared memory to use to cache the contents
+ of <literal>pg_multixact/members</literal> (see
+ <xref linkend="pgdata-contents-table"/>).
+ If this value is specified without units, it is taken as blocks,
+ that is <symbol>BLCKSZ</symbol> bytes, typically 8kB.
+ The default value is <literal>16</literal>.
+ This parameter can only be set at server start.
+ </para>
+ </listitem>
+ </varlistentry>
+
+ <varlistentry id="guc-subtrans-buffers" xreflabel="subtrans_buffers">
+ <term><varname>subtrans_buffers</varname> (<type>integer</type>)
+ <indexterm>
+ <primary><varname>subtrans_buffers</varname> configuration parameter</primary>
+ </indexterm>
+ </term>
+ <listitem>
+ <para>
+ Specifies the amount of shared memory to use to cache the contents
+ of <literal>pg_subtrans</literal> (see
+ <xref linkend="pgdata-contents-table"/>).
+ If this value is specified without units, it is taken as blocks,
+ that is <symbol>BLCKSZ</symbol> bytes, typically 8kB.
+ The default value is <literal>8</literal>.
+ This parameter can only be set at server start.
+ </para>
+ </listitem>
+ </varlistentry>
+
+ <varlistentry id="guc-notify-buffers" xreflabel="notify_buffers">
+ <term><varname>notify_buffers</varname> (<type>integer</type>)
+ <indexterm>
+ <primary><varname>notify_buffers</varname> configuration parameter</primary>
+ </indexterm>
+ </term>
+ <listitem>
+ <para>
+ Specifies the amount of shared memory to use to cache the contents
+ of <literal>pg_notify</literal> (see
+ <xref linkend="pgdata-contents-table"/>).
+ If this value is specified without units, it is taken as blocks,
+ that is <symbol>BLCKSZ</symbol> bytes, typically 8kB.
+ The default value is <literal>8</literal>.
+ This parameter can only be set at server start.
+ </para>
+ </listitem>
+ </varlistentry>
+
+ <varlistentry id="guc-serial-buffers" xreflabel="serial_buffers">
+ <term><varname>serial_buffers</varname> (<type>integer</type>)
+ <indexterm>
+ <primary><varname>serial_buffers</varname> configuration parameter</primary>
+ </indexterm>
+ </term>
+ <listitem>
+ <para>
+ Specifies the amount of shared memory to use to cache the contents
+ of <literal>pg_serial</literal> (see
+ <xref linkend="pgdata-contents-table"/>).
+ If this value is specified without units, it is taken as blocks,
+ that is <symbol>BLCKSZ</symbol> bytes, typically 8kB.
+ The default value is <literal>16</literal>.
+ This parameter can only be set at server start.
+ </para>
+ </listitem>
+ </varlistentry>
+
+ <varlistentry id="guc-xact-buffers" xreflabel="xact_buffers">
+ <term><varname>xact_buffers</varname> (<type>integer</type>)
+ <indexterm>
+ <primary><varname>xact_buffers</varname> configuration parameter</primary>
+ </indexterm>
+ </term>
+ <listitem>
+ <para>
+ Specifies the amount of shared memory to use to cache the contents
+ of <literal>pg_xact</literal> (see
+ <xref linkend="pgdata-contents-table"/>).
+ If this value is specified without units, it is taken as blocks,
+ that is <symbol>BLCKSZ</symbol> bytes, typically 8kB.
+ The default value is <literal>0</literal>, which requests
+ <varname>shared_buffers</varname> / 512, but not fewer than 4 blocks.
+ This parameter can only be set at server start.
+ </para>
+ </listitem>
+ </varlistentry>
+
+ <varlistentry id="guc-commit-ts-buffers" xreflabel="commit_ts_buffers">
+ <term><varname>commit_ts_buffers</varname> (<type>integer</type>)
+ <indexterm>
+ <primary><varname>commit_ts_buffers</varname> configuration parameter</primary>
+ </indexterm>
+ </term>
+ <listitem>
+ <para>
+ Specifies the amount of memory to use to cache the cotents of
+ <literal>pg_commit_ts</literal> (see
+ <xref linkend="pgdata-contents-table"/>).
+ If this value is specified without units, it is taken as blocks,
+ that is <symbol>BLCKSZ</symbol> bytes, typically 8kB.
+ The default value is <literal>0</literal>, which requests
+ <varname>shared_buffers</varname> / 1024, but not fewer than 4 blocks.
+ This parameter can only be set at server start.
+ </para>
+ </listitem>
+ </varlistentry>
<varlistentry id="guc-max-stack-depth" xreflabel="max_stack_depth">
<term><varname>max_stack_depth</varname> (<type>integer</type>)
diff --git a/src/backend/access/transam/clog.c b/src/backend/access/transam/clog.c
index 6fa4713fb4..dd2d7a5184 100644
--- a/src/backend/access/transam/clog.c
+++ b/src/backend/access/transam/clog.c
@@ -58,8 +58,8 @@
/* We need two bits per xact, so four xacts fit in a byte */
#define CLOG_BITS_PER_XACT 2
-#define CLOG_XACTS_PER_BYTE 4
-#define CLOG_XACTS_PER_PAGE (BLCKSZ * CLOG_XACTS_PER_BYTE)
+StaticAssertDecl((CLOG_BITS_PER_XACT * CLOG_XACTS_PER_BYTE) == BITS_PER_BYTE,
+ "CLOG_BITS_PER_XACT and CLOG_XACTS_PER_BYTE are inconsistent");
#define CLOG_XACT_BITMASK ((1 << CLOG_BITS_PER_XACT) - 1)
#define TransactionIdToPage(xid) ((xid) / (TransactionId) CLOG_XACTS_PER_PAGE)
@@ -659,23 +659,16 @@ TransactionIdGetStatus(TransactionId xid, XLogRecPtr *lsn)
/*
* Number of shared CLOG buffers.
*
- * On larger multi-processor systems, it is possible to have many CLOG page
- * requests in flight at one time which could lead to disk access for CLOG
- * page if the required page is not found in memory. Testing revealed that we
- * can get the best performance by having 128 CLOG buffers, more than that it
- * doesn't improve performance.
- *
- * Unconditionally keeping the number of CLOG buffers to 128 did not seem like
- * a good idea, because it would increase the minimum amount of shared memory
- * required to start, which could be a problem for people running very small
- * configurations. The following formula seems to represent a reasonable
- * compromise: people with very low values for shared_buffers will get fewer
- * CLOG buffers as well, and everyone else will get 128.
+ * By default, we'll use 2MB of for every 1GB of shared buffers, up to the
+ * theoretical maximum useful value, but always at least 4 buffers.
*/
Size
CLOGShmemBuffers(void)
{
- return Min(128, Max(4, NBuffers / 512));
+ /* Use configured value if provided. */
+ if (xact_buffers > 0)
+ return Max(4, xact_buffers);
+ return Min(CLOG_MAX_ALLOWED_BUFFERS, Max(4, NBuffers / 512));
}
/*
diff --git a/src/backend/access/transam/commit_ts.c b/src/backend/access/transam/commit_ts.c
index 268bdba339..729a4b9212 100644
--- a/src/backend/access/transam/commit_ts.c
+++ b/src/backend/access/transam/commit_ts.c
@@ -524,13 +524,17 @@ pg_xact_commit_timestamp_origin(PG_FUNCTION_ARGS)
/*
* Number of shared CommitTS buffers.
*
- * We use a very similar logic as for the number of CLOG buffers; see comments
- * in CLOGShmemBuffers.
+ * By default, we'll use 1MB of for every 1GB of shared buffers, up to the
+ * maximum value that slru.c will allow, but always at least 4 buffers.
*/
Size
CommitTsShmemBuffers(void)
{
- return Min(16, Max(4, NBuffers / 1024));
+ /* Use configured value if provided. */
+ if (commit_ts_buffers > 0)
+ return Max(4, commit_ts_buffers);
+ return Min(track_commit_timestamp ? SLRU_MAX_ALLOWED_BUFFERS : 16,
+ Max(4, NBuffers / 1024));
}
/*
diff --git a/src/backend/access/transam/multixact.c b/src/backend/access/transam/multixact.c
index 1f9f1a1fa1..21787765e2 100644
--- a/src/backend/access/transam/multixact.c
+++ b/src/backend/access/transam/multixact.c
@@ -1831,8 +1831,8 @@ MultiXactShmemSize(void)
mul_size(sizeof(MultiXactId) * 2, MaxOldestSlot))
size = SHARED_MULTIXACT_STATE_SIZE;
- size = add_size(size, SimpleLruShmemSize(NUM_MULTIXACTOFFSET_BUFFERS, 0));
- size = add_size(size, SimpleLruShmemSize(NUM_MULTIXACTMEMBER_BUFFERS, 0));
+ size = add_size(size, SimpleLruShmemSize(multixact_offsets_buffers, 0));
+ size = add_size(size, SimpleLruShmemSize(multixact_members_buffers, 0));
return size;
}
@@ -1848,13 +1848,13 @@ MultiXactShmemInit(void)
MultiXactMemberCtl->PagePrecedes = MultiXactMemberPagePrecedes;
SimpleLruInit(MultiXactOffsetCtl,
- "MultiXactOffset", NUM_MULTIXACTOFFSET_BUFFERS, 0,
+ "MultiXactOffset", multixact_offsets_buffers, 0,
MultiXactOffsetSLRULock, "pg_multixact/offsets",
LWTRANCHE_MULTIXACTOFFSET_BUFFER,
SYNC_HANDLER_MULTIXACT_OFFSET);
SlruPagePrecedesUnitTests(MultiXactOffsetCtl, MULTIXACT_OFFSETS_PER_PAGE);
SimpleLruInit(MultiXactMemberCtl,
- "MultiXactMember", NUM_MULTIXACTMEMBER_BUFFERS, 0,
+ "MultiXactMember", multixact_offsets_buffers, 0,
MultiXactMemberSLRULock, "pg_multixact/members",
LWTRANCHE_MULTIXACTMEMBER_BUFFER,
SYNC_HANDLER_MULTIXACT_MEMBER);
diff --git a/src/backend/access/transam/subtrans.c b/src/backend/access/transam/subtrans.c
index 6a8e521f89..785f2520fd 100644
--- a/src/backend/access/transam/subtrans.c
+++ b/src/backend/access/transam/subtrans.c
@@ -31,6 +31,7 @@
#include "access/slru.h"
#include "access/subtrans.h"
#include "access/transam.h"
+#include "miscadmin.h"
#include "pg_trace.h"
#include "utils/snapmgr.h"
@@ -184,14 +185,14 @@ SubTransGetTopmostTransaction(TransactionId xid)
Size
SUBTRANSShmemSize(void)
{
- return SimpleLruShmemSize(NUM_SUBTRANS_BUFFERS, 0);
+ return SimpleLruShmemSize(subtrans_buffers, 0);
}
void
SUBTRANSShmemInit(void)
{
SubTransCtl->PagePrecedes = SubTransPagePrecedes;
- SimpleLruInit(SubTransCtl, "Subtrans", NUM_SUBTRANS_BUFFERS, 0,
+ SimpleLruInit(SubTransCtl, "Subtrans", subtrans_buffers, 0,
SubtransSLRULock, "pg_subtrans",
LWTRANCHE_SUBTRANS_BUFFER, SYNC_HANDLER_NONE);
SlruPagePrecedesUnitTests(SubTransCtl, SUBTRANS_XACTS_PER_PAGE);
diff --git a/src/backend/commands/async.c b/src/backend/commands/async.c
index 4b16fb5682..de17f52cd7 100644
--- a/src/backend/commands/async.c
+++ b/src/backend/commands/async.c
@@ -107,7 +107,7 @@
* frontend during startup.) The above design guarantees that notifies from
* other backends will never be missed by ignoring self-notifies.
*
- * The amount of shared memory used for notify management (NUM_NOTIFY_BUFFERS)
+ * The amount of shared memory used for notify management (notify_buffers)
* can be varied without affecting anything but performance. The maximum
* amount of notification data that can be queued at one time is determined
* by slru.c's wraparound limit; see QUEUE_MAX_PAGE below.
@@ -225,7 +225,7 @@ typedef struct QueuePosition
*
* Resist the temptation to make this really large. While that would save
* work in some places, it would add cost in others. In particular, this
- * should likely be less than NUM_NOTIFY_BUFFERS, to ensure that backends
+ * should likely be less than notify_buffers, to ensure that backends
* catch up before the pages they'll need to read fall out of SLRU cache.
*/
#define QUEUE_CLEANUP_DELAY 4
@@ -514,7 +514,7 @@ AsyncShmemSize(void)
size = mul_size(MaxBackends + 1, sizeof(QueueBackendStatus));
size = add_size(size, offsetof(AsyncQueueControl, backend));
- size = add_size(size, SimpleLruShmemSize(NUM_NOTIFY_BUFFERS, 0));
+ size = add_size(size, SimpleLruShmemSize(notify_buffers, 0));
return size;
}
@@ -562,7 +562,7 @@ AsyncShmemInit(void)
* Set up SLRU management of the pg_notify data.
*/
NotifyCtl->PagePrecedes = asyncQueuePagePrecedes;
- SimpleLruInit(NotifyCtl, "Notify", NUM_NOTIFY_BUFFERS, 0,
+ SimpleLruInit(NotifyCtl, "Notify", notify_buffers, 0,
NotifySLRULock, "pg_notify", LWTRANCHE_NOTIFY_BUFFER,
SYNC_HANDLER_NONE);
diff --git a/src/backend/storage/lmgr/predicate.c b/src/backend/storage/lmgr/predicate.c
index d493aeef0f..b1f4f1651d 100644
--- a/src/backend/storage/lmgr/predicate.c
+++ b/src/backend/storage/lmgr/predicate.c
@@ -872,7 +872,7 @@ SerialInit(void)
*/
SerialSlruCtl->PagePrecedes = SerialPagePrecedesLogically;
SimpleLruInit(SerialSlruCtl, "Serial",
- NUM_SERIAL_BUFFERS, 0, SerialSLRULock, "pg_serial",
+ serial_buffers, 0, SerialSLRULock, "pg_serial",
LWTRANCHE_SERIAL_BUFFER, SYNC_HANDLER_NONE);
#ifdef USE_ASSERT_CHECKING
SerialPagePrecedesLogicallyUnitTests();
@@ -1395,7 +1395,7 @@ PredicateLockShmemSize(void)
/* Shared memory structures for SLRU tracking of old committed xids. */
size = add_size(size, sizeof(SerialControlData));
- size = add_size(size, SimpleLruShmemSize(NUM_SERIAL_BUFFERS, 0));
+ size = add_size(size, SimpleLruShmemSize(serial_buffers, 0));
return size;
}
diff --git a/src/backend/utils/init/globals.c b/src/backend/utils/init/globals.c
index 381d9e548d..c83151d5ab 100644
--- a/src/backend/utils/init/globals.c
+++ b/src/backend/utils/init/globals.c
@@ -150,3 +150,11 @@ int64 VacuumPageDirty = 0;
int VacuumCostBalance = 0; /* working state for vacuum */
bool VacuumCostActive = false;
+
+int multixact_offsets_buffers = 8;
+int multixact_members_buffers = 16;
+int subtrans_buffers = 32;
+int notify_buffers = 8;
+int serial_buffers = 16;
+int xact_buffers = 0;
+int commit_ts_buffers = 0;
diff --git a/src/backend/utils/misc/guc.c b/src/backend/utils/misc/guc.c
index bee976bae8..250cef80bd 100644
--- a/src/backend/utils/misc/guc.c
+++ b/src/backend/utils/misc/guc.c
@@ -32,9 +32,11 @@
#endif
#include <unistd.h>
+#include "access/clog.h"
#include "access/commit_ts.h"
#include "access/gin.h"
#include "access/rmgr.h"
+#include "access/slru.h"
#include "access/tableam.h"
#include "access/toast_compression.h"
#include "access/transam.h"
@@ -200,6 +202,8 @@ static const char *show_tcp_keepalives_idle(void);
static const char *show_tcp_keepalives_interval(void);
static const char *show_tcp_keepalives_count(void);
static const char *show_tcp_user_timeout(void);
+static const char *show_xact_buffers(void);
+static const char *show_commit_ts_buffers(void);
static bool check_maxconnections(int *newval, void **extra, GucSource source);
static bool check_max_worker_processes(int *newval, void **extra, GucSource source);
static bool check_autovacuum_max_workers(int *newval, void **extra, GucSource source);
@@ -2340,6 +2344,83 @@ static struct config_int ConfigureNamesInt[] =
NULL, NULL, NULL
},
+ {
+ {"multixact_offsets_buffers", PGC_POSTMASTER, RESOURCES_MEM,
+ gettext_noop("Sets the number of shared memory buffers used for the MultiXact offset SLRU cache."),
+ NULL,
+ GUC_UNIT_BLOCKS
+ },
+ &multixact_offsets_buffers,
+ 8, 2, SLRU_MAX_ALLOWED_BUFFERS,
+ NULL, NULL, NULL
+ },
+
+ {
+ {"multixact_members_buffers", PGC_POSTMASTER, RESOURCES_MEM,
+ gettext_noop("Sets the number of shared memory buffers used for the MultiXact member SLRU cache."),
+ NULL,
+ GUC_UNIT_BLOCKS
+ },
+ &multixact_members_buffers,
+ 16, 2, SLRU_MAX_ALLOWED_BUFFERS,
+ NULL, NULL, NULL
+ },
+
+ {
+ {"subtrans_buffers", PGC_POSTMASTER, RESOURCES_MEM,
+ gettext_noop("Sets the number of shared memory buffers used for the sub-transaction SLRU cache."),
+ NULL,
+ GUC_UNIT_BLOCKS
+ },
+ &subtrans_buffers,
+ 32, 2, SLRU_MAX_ALLOWED_BUFFERS,
+ NULL, NULL, NULL
+ },
+
+ {
+ {"notify_buffers", PGC_POSTMASTER, RESOURCES_MEM,
+ gettext_noop("Sets the number of shared memory buffers used for the NOTIFY message SLRU cache."),
+ NULL,
+ GUC_UNIT_BLOCKS
+ },
+ ¬ify_buffers,
+ 8, 2, SLRU_MAX_ALLOWED_BUFFERS,
+ NULL, NULL, NULL
+ },
+
+ {
+ {"serial_buffers", PGC_POSTMASTER, RESOURCES_MEM,
+ gettext_noop("Sets the number of shared memory buffers used for the serializable transaction SLRU cache."),
+ NULL,
+ GUC_UNIT_BLOCKS
+ },
+ &serial_buffers,
+ 16, 2, SLRU_MAX_ALLOWED_BUFFERS,
+ NULL, NULL, NULL
+ },
+
+ {
+ {"xact_buffers", PGC_POSTMASTER, RESOURCES_MEM,
+ gettext_noop("Sets the number of shared memory buffers used for the transaction status SLRU cache."),
+ NULL,
+ GUC_UNIT_BLOCKS
+ },
+ &xact_buffers,
+ 0, 0, CLOG_MAX_ALLOWED_BUFFERS,
+ NULL, NULL, show_xact_buffers
+ },
+
+ {
+ {"commit_ts_buffers", PGC_POSTMASTER, RESOURCES_MEM,
+ gettext_noop("Sets the size of the dedicated buffer pool used for the commit timestamp SLRU cache."),
+ NULL,
+ GUC_UNIT_BLOCKS
+ },
+ &commit_ts_buffers,
+ 0, 0, SLRU_MAX_ALLOWED_BUFFERS,
+ NULL, NULL, show_commit_ts_buffers
+ },
+
{
{"temp_buffers", PGC_USERSET, RESOURCES_MEM,
gettext_noop("Sets the maximum number of temporary buffers used by each session."),
@@ -11959,6 +12040,24 @@ show_tcp_user_timeout(void)
return nbuf;
}
+static const char *
+show_xact_buffers(void)
+{
+ static char nbuf[16];
+
+ snprintf(nbuf, sizeof(nbuf), "%zu", CLOGShmemBuffers());
+ return nbuf;
+}
+
+static const char *
+show_commit_ts_buffers(void)
+{
+ static char nbuf[16];
+
+ snprintf(nbuf, sizeof(nbuf), "%zu", CommitTsShmemBuffers());
+ return nbuf;
+}
+
static bool
check_maxconnections(int *newval, void **extra, GucSource source)
{
diff --git a/src/backend/utils/misc/postgresql.conf.sample b/src/backend/utils/misc/postgresql.conf.sample
index ff9fa006fe..7e14df3b51 100644
--- a/src/backend/utils/misc/postgresql.conf.sample
+++ b/src/backend/utils/misc/postgresql.conf.sample
@@ -190,6 +190,15 @@
# (change requires restart)
#backend_flush_after = 0 # measured in pages, 0 disables
+# - SLRU Buffers (change requires restart) -
+
+#xact_buffers = 0 # memory for pg_xact (0 = auto)
+#subtrans_buffers = 32 # memory for pg_subtrans
+#multixact_offsets_buffers = 8 # memory for pg_multixact/offsets
+#multixact_members_buffers = 16 # memory for pg_multixact/members
+#notify_buffers = 8 # memory for pg_notify
+#serial_buffers = 16 # memory for pg_serial
+#commit_ts_buffers = 0 # memory for pg_commit_ts (0 = auto)
#------------------------------------------------------------------------------
# WRITE-AHEAD LOG
diff --git a/src/include/access/clog.h b/src/include/access/clog.h
index 39b8e4afa8..739a292f7f 100644
--- a/src/include/access/clog.h
+++ b/src/include/access/clog.h
@@ -15,6 +15,16 @@
#include "storage/sync.h"
#include "lib/stringinfo.h"
+/*
+ * Don't allow xact_buffers to be set higher than could possibly be useful or
+ * SLRU would allow.
+ */
+#define CLOG_XACTS_PER_BYTE 4
+#define CLOG_XACTS_PER_PAGE (BLCKSZ * CLOG_XACTS_PER_BYTE)
+#define CLOG_MAX_ALLOWED_BUFFERS \
+ Min(SLRU_MAX_ALLOWED_BUFFERS, \
+ (((MaxTransactionId / 2) + (CLOG_XACTS_PER_PAGE - 1)) / CLOG_XACTS_PER_PAGE))
+
/*
* Possible transaction statuses --- note that all-zeroes is the initial
* state.
diff --git a/src/include/access/commit_ts.h b/src/include/access/commit_ts.h
index 750369104a..e4cf988609 100644
--- a/src/include/access/commit_ts.h
+++ b/src/include/access/commit_ts.h
@@ -17,7 +17,6 @@
#include "storage/sync.h"
#include "utils/guc.h"
-
extern PGDLLIMPORT bool track_commit_timestamp;
extern bool check_track_commit_timestamp(bool *newval, void **extra,
diff --git a/src/include/access/multixact.h b/src/include/access/multixact.h
index 4bbb035eae..97c0a46376 100644
--- a/src/include/access/multixact.h
+++ b/src/include/access/multixact.h
@@ -29,10 +29,6 @@
#define MaxMultiXactOffset ((MultiXactOffset) 0xFFFFFFFF)
-/* Number of SLRU buffers to use for multixact */
-#define NUM_MULTIXACTOFFSET_BUFFERS 8
-#define NUM_MULTIXACTMEMBER_BUFFERS 16
-
/*
* Possible multixact lock modes ("status"). The first four modes are for
* tuple locks (FOR KEY SHARE, FOR SHARE, FOR NO KEY UPDATE, FOR UPDATE); the
diff --git a/src/include/access/slru.h b/src/include/access/slru.h
index dd52e8cec7..793c045f16 100644
--- a/src/include/access/slru.h
+++ b/src/include/access/slru.h
@@ -17,6 +17,11 @@
#include "storage/lwlock.h"
#include "storage/sync.h"
+/*
+ * To avoid overflowing internal arithmetic and the size_t data type, the
+ * number of buffers should not exceed this number.
+ */
+#define SLRU_MAX_ALLOWED_BUFFERS ((1024 * 1024 * 1024) / BLCKSZ)
/*
* Define SLRU segment size. A page is the same BLCKSZ as is used everywhere
diff --git a/src/include/access/subtrans.h b/src/include/access/subtrans.h
index d0ab44ae82..64fa86938e 100644
--- a/src/include/access/subtrans.h
+++ b/src/include/access/subtrans.h
@@ -11,8 +11,6 @@
#ifndef SUBTRANS_H
#define SUBTRANS_H
-/* Number of SLRU buffers to use for subtrans */
-#define NUM_SUBTRANS_BUFFERS 32
extern void SubTransSetParent(TransactionId xid, TransactionId parent);
extern TransactionId SubTransGetParent(TransactionId xid);
diff --git a/src/include/commands/async.h b/src/include/commands/async.h
index 9217f66b91..fa831e3721 100644
--- a/src/include/commands/async.h
+++ b/src/include/commands/async.h
@@ -15,11 +15,6 @@
#include <signal.h>
-/*
- * The number of SLRU page buffers we use for the notification queue.
- */
-#define NUM_NOTIFY_BUFFERS 8
-
extern bool Trace_notify;
extern volatile sig_atomic_t notifyInterruptPending;
diff --git a/src/include/miscadmin.h b/src/include/miscadmin.h
index 95202d37af..495c1bf901 100644
--- a/src/include/miscadmin.h
+++ b/src/include/miscadmin.h
@@ -164,6 +164,13 @@ extern PGDLLIMPORT int MaxBackends;
extern PGDLLIMPORT int MaxConnections;
extern PGDLLIMPORT int max_worker_processes;
extern PGDLLIMPORT int max_parallel_workers;
+extern PGDLLIMPORT int multixact_offsets_buffers;
+extern PGDLLIMPORT int multixact_members_buffers;
+extern PGDLLIMPORT int subtrans_buffers;
+extern PGDLLIMPORT int notify_buffers;
+extern PGDLLIMPORT int serial_buffers;
+extern PGDLLIMPORT int xact_buffers;
+extern PGDLLIMPORT int commit_ts_buffers;
extern PGDLLIMPORT int MyProcPid;
extern PGDLLIMPORT pg_time_t MyStartTime;
diff --git a/src/include/storage/predicate.h b/src/include/storage/predicate.h
index 152b698611..c72779bd88 100644
--- a/src/include/storage/predicate.h
+++ b/src/include/storage/predicate.h
@@ -26,10 +26,6 @@ extern int max_predicate_locks_per_xact;
extern int max_predicate_locks_per_relation;
extern int max_predicate_locks_per_page;
-
-/* Number of SLRU buffers to use for Serial SLRU */
-#define NUM_SERIAL_BUFFERS 16
-
/*
* A handle used for sharing SERIALIZABLEXACT objects between the participants
* in a parallel query.
--
2.24.3 (Apple Git-128)
^ permalink raw reply [nested|flat] 90+ messages in thread
* Re: MultiXact\SLRU buffers configuration
2020-05-08 16:36 MultiXact\SLRU buffers configuration Andrey M. Borodin <[email protected]>
2020-05-11 11:17 ` Re: MultiXact\SLRU buffers configuration Andrey M. Borodin <[email protected]>
2020-05-13 18:08 ` Re: MultiXact\SLRU buffers configuration Andrey M. Borodin <[email protected]>
2020-05-14 01:25 ` Re: MultiXact\SLRU buffers configuration Kyotaro Horiguchi <[email protected]>
2020-05-14 05:19 ` Re: MultiXact\SLRU buffers configuration Andrey M. Borodin <[email protected]>
2020-05-14 06:16 ` Re: MultiXact\SLRU buffers configuration Kyotaro Horiguchi <[email protected]>
2020-05-14 06:44 ` Re: MultiXact\SLRU buffers configuration Andrey M. Borodin <[email protected]>
2020-05-15 00:03 ` Re: MultiXact\SLRU buffers configuration Kyotaro Horiguchi <[email protected]>
2020-07-02 12:02 ` Re: MultiXact\SLRU buffers configuration Daniel Gustafsson <[email protected]>
2020-07-08 07:03 ` Re: MultiXact\SLRU buffers configuration Andrey M. Borodin <[email protected]>
2020-08-28 18:08 ` Re: MultiXact\SLRU buffers configuration Anastasia Lubennikova <[email protected]>
2020-09-28 14:41 ` Re: MultiXact\SLRU buffers configuration Andrey M. Borodin <[email protected]>
2020-10-26 01:05 ` Re: MultiXact\SLRU buffers configuration Alexander Korotkov <[email protected]>
2020-10-26 15:45 ` Re: MultiXact\SLRU buffers configuration Andrey Borodin <[email protected]>
2020-10-27 17:02 ` Re: MultiXact\SLRU buffers configuration Alexander Korotkov <[email protected]>
2020-10-27 17:23 ` Re: MultiXact\SLRU buffers configuration Alexander Korotkov <[email protected]>
2020-10-28 01:36 ` Re: MultiXact\SLRU buffers configuration Tomas Vondra <[email protected]>
2020-10-28 07:34 ` Re: MultiXact\SLRU buffers configuration Andrey Borodin <[email protected]>
2020-10-28 23:32 ` Re: MultiXact\SLRU buffers configuration Tomas Vondra <[email protected]>
2020-10-29 07:08 ` Re: MultiXact\SLRU buffers configuration Andrey Borodin <[email protected]>
2020-10-29 13:49 ` Re: MultiXact\SLRU buffers configuration Tomas Vondra <[email protected]>
2020-11-02 12:45 ` Re: MultiXact\SLRU buffers configuration Andrey Borodin <[email protected]>
2020-11-10 00:13 ` Re: MultiXact\SLRU buffers configuration Tomas Vondra <[email protected]>
2020-11-10 06:16 ` Re: MultiXact\SLRU buffers configuration Andrey Borodin <[email protected]>
2020-11-10 18:07 ` Re: MultiXact\SLRU buffers configuration Tomas Vondra <[email protected]>
2020-11-13 11:49 ` Re: MultiXact\SLRU buffers configuration Andrey Borodin <[email protected]>
2020-12-08 16:05 ` Re: MultiXact\SLRU buffers configuration Gilles Darold <[email protected]>
2020-12-08 17:52 ` Re: MultiXact\SLRU buffers configuration Andrey Borodin <[email protected]>
2020-12-10 14:45 ` Re: MultiXact\SLRU buffers configuration Gilles Darold <[email protected]>
2020-12-11 17:50 ` Re: MultiXact\SLRU buffers configuration Gilles Darold <[email protected]>
2020-12-13 09:17 ` Re: MultiXact\SLRU buffers configuration Gilles Darold <[email protected]>
2020-12-13 17:24 ` Re: MultiXact\SLRU buffers configuration Andrey Borodin <[email protected]>
2020-12-23 16:31 ` Re: MultiXact\SLRU buffers configuration Gilles Darold <[email protected]>
2021-02-15 17:17 ` Re: MultiXact\SLRU buffers configuration Andrey Borodin <[email protected]>
2021-03-11 15:50 ` Re: MultiXact\SLRU buffers configuration Gilles Darold <[email protected]>
2021-03-12 12:44 ` Re: MultiXact\SLRU buffers configuration Andrey Borodin <[email protected]>
2021-03-24 21:31 ` Re: MultiXact\SLRU buffers configuration Thomas Munro <[email protected]>
2021-03-25 01:03 ` Re: MultiXact\SLRU buffers configuration Thomas Munro <[email protected]>
2021-03-26 03:46 ` Re: MultiXact\SLRU buffers configuration Thomas Munro <[email protected]>
2021-03-26 06:00 ` Re: MultiXact\SLRU buffers configuration Andrey Borodin <[email protected]>
2021-03-26 15:52 ` Re: MultiXact\SLRU buffers configuration Andrey Borodin <[email protected]>
2021-03-26 20:26 ` Re: MultiXact\SLRU buffers configuration Thomas Munro <[email protected]>
2021-03-27 05:31 ` Re: MultiXact\SLRU buffers configuration Andrey Borodin <[email protected]>
2021-03-28 21:15 ` Re: MultiXact\SLRU buffers configuration Thomas Munro <[email protected]>
2021-03-29 08:26 ` Re: MultiXact\SLRU buffers configuration Andrey Borodin <[email protected]>
2021-03-31 21:09 ` Re: MultiXact\SLRU buffers configuration Andrey Borodin <[email protected]>
2021-04-01 03:40 ` Re: MultiXact\SLRU buffers configuration Thomas Munro <[email protected]>
2021-04-03 19:57 ` Re: MultiXact\SLRU buffers configuration Andrey Borodin <[email protected]>
2021-04-07 05:59 ` Re: MultiXact\SLRU buffers configuration Thomas Munro <[email protected]>
2021-04-07 11:44 ` Re: MultiXact\SLRU buffers configuration Andrey Borodin <[email protected]>
2021-04-07 12:13 ` Re: MultiXact\SLRU buffers configuration Andrey Borodin <[email protected]>
2021-04-08 00:30 ` Re: MultiXact\SLRU buffers configuration Thomas Munro <[email protected]>
2021-04-08 07:24 ` Re: MultiXact\SLRU buffers configuration Andrey Borodin <[email protected]>
2021-04-08 12:22 ` Re: MultiXact\SLRU buffers configuration Thomas Munro <[email protected]>
2021-04-11 18:37 ` Re: MultiXact\SLRU buffers configuration Andrey Borodin <[email protected]>
@ 2021-06-14 17:40 ` Васильев Дмитрий <[email protected]>
1 sibling, 0 replies; 90+ messages in thread
From: Васильев Дмитрий @ 2021-06-14 17:40 UTC (permalink / raw)
To: Andrey Borodin <[email protected]>; +Cc: Thomas Munro <[email protected]>; Gilles Darold <[email protected]>; Tomas Vondra <[email protected]>; Tomas Vondra <[email protected]>; Alexander Korotkov <[email protected]>; Anastasia Lubennikova <[email protected]>; Daniel Gustafsson <[email protected]>; Kyotaro Horiguchi <[email protected]>; pgsql-hackers
пн, 14 июн. 2021 г. в 15:07, Andrey Borodin <[email protected]>:
> PFA patch implementing this idea.
>
I'm benchmarked v17 patches.
Testing was done on a 96-core machine, with PGDATA completely placed in
tmpfs.
PostgreSQL was built with CFLAGS -O2.
for-update PgBench script:
\set aid random_zipfian(1, 100, 2)
begin;
select :aid from pgbench_accounts where aid = :aid for update;
update pgbench_accounts set abalance = abalance + 1 where aid = :aid;
update pgbench_accounts set abalance = abalance * 2 where aid = :aid;
update pgbench_accounts set abalance = abalance - 2 where aid = :aid;
end;
Before each test sample data was filled with "pgbench -i -s 100", testing
was performed 3 times for 1 hour each test.
The benchmark results are presented with changing
multi_xact_members_buffers and multicast_offsets_buffers (1:2 respectively):
settings tps
multixact_members_buffers_64Kb 693.2
multixact_members_buffers_128Kb 691.4
multixact_members_buffers_192Kb 696.3
multixact_members_buffers_256Kb 694.4
multixact_members_buffers_320Kb 692.3
multixact_members_buffers_448Kb 693.7
multixact_members_buffers_512Kb 693.3
vanilla 676.1
Best regards, Dmitry Vasiliev.
^ permalink raw reply [nested|flat] 90+ messages in thread
* Re: MultiXact\SLRU buffers configuration
2020-05-08 16:36 MultiXact\SLRU buffers configuration Andrey M. Borodin <[email protected]>
2020-05-11 11:17 ` Re: MultiXact\SLRU buffers configuration Andrey M. Borodin <[email protected]>
2020-05-13 18:08 ` Re: MultiXact\SLRU buffers configuration Andrey M. Borodin <[email protected]>
2020-05-14 01:25 ` Re: MultiXact\SLRU buffers configuration Kyotaro Horiguchi <[email protected]>
2020-05-14 05:19 ` Re: MultiXact\SLRU buffers configuration Andrey M. Borodin <[email protected]>
2020-05-14 06:16 ` Re: MultiXact\SLRU buffers configuration Kyotaro Horiguchi <[email protected]>
2020-05-14 06:44 ` Re: MultiXact\SLRU buffers configuration Andrey M. Borodin <[email protected]>
2020-05-15 00:03 ` Re: MultiXact\SLRU buffers configuration Kyotaro Horiguchi <[email protected]>
2020-07-02 12:02 ` Re: MultiXact\SLRU buffers configuration Daniel Gustafsson <[email protected]>
2020-07-08 07:03 ` Re: MultiXact\SLRU buffers configuration Andrey M. Borodin <[email protected]>
2020-08-28 18:08 ` Re: MultiXact\SLRU buffers configuration Anastasia Lubennikova <[email protected]>
2020-09-28 14:41 ` Re: MultiXact\SLRU buffers configuration Andrey M. Borodin <[email protected]>
2020-10-26 01:05 ` Re: MultiXact\SLRU buffers configuration Alexander Korotkov <[email protected]>
2020-10-26 15:45 ` Re: MultiXact\SLRU buffers configuration Andrey Borodin <[email protected]>
2020-10-27 17:02 ` Re: MultiXact\SLRU buffers configuration Alexander Korotkov <[email protected]>
2020-10-27 17:23 ` Re: MultiXact\SLRU buffers configuration Alexander Korotkov <[email protected]>
2020-10-28 01:36 ` Re: MultiXact\SLRU buffers configuration Tomas Vondra <[email protected]>
2020-10-28 07:34 ` Re: MultiXact\SLRU buffers configuration Andrey Borodin <[email protected]>
2020-10-28 23:32 ` Re: MultiXact\SLRU buffers configuration Tomas Vondra <[email protected]>
2020-10-29 07:08 ` Re: MultiXact\SLRU buffers configuration Andrey Borodin <[email protected]>
2020-10-29 13:49 ` Re: MultiXact\SLRU buffers configuration Tomas Vondra <[email protected]>
2020-11-02 12:45 ` Re: MultiXact\SLRU buffers configuration Andrey Borodin <[email protected]>
2020-11-10 00:13 ` Re: MultiXact\SLRU buffers configuration Tomas Vondra <[email protected]>
2020-11-10 06:16 ` Re: MultiXact\SLRU buffers configuration Andrey Borodin <[email protected]>
2020-11-10 18:07 ` Re: MultiXact\SLRU buffers configuration Tomas Vondra <[email protected]>
2020-11-13 11:49 ` Re: MultiXact\SLRU buffers configuration Andrey Borodin <[email protected]>
2020-12-08 16:05 ` Re: MultiXact\SLRU buffers configuration Gilles Darold <[email protected]>
2020-12-08 17:52 ` Re: MultiXact\SLRU buffers configuration Andrey Borodin <[email protected]>
2020-12-10 14:45 ` Re: MultiXact\SLRU buffers configuration Gilles Darold <[email protected]>
2020-12-11 17:50 ` Re: MultiXact\SLRU buffers configuration Gilles Darold <[email protected]>
2020-12-13 09:17 ` Re: MultiXact\SLRU buffers configuration Gilles Darold <[email protected]>
2020-12-13 17:24 ` Re: MultiXact\SLRU buffers configuration Andrey Borodin <[email protected]>
2020-12-23 16:31 ` Re: MultiXact\SLRU buffers configuration Gilles Darold <[email protected]>
2021-02-15 17:17 ` Re: MultiXact\SLRU buffers configuration Andrey Borodin <[email protected]>
2021-03-11 15:50 ` Re: MultiXact\SLRU buffers configuration Gilles Darold <[email protected]>
2021-03-12 12:44 ` Re: MultiXact\SLRU buffers configuration Andrey Borodin <[email protected]>
2021-03-24 21:31 ` Re: MultiXact\SLRU buffers configuration Thomas Munro <[email protected]>
2021-03-25 01:03 ` Re: MultiXact\SLRU buffers configuration Thomas Munro <[email protected]>
2021-03-26 03:46 ` Re: MultiXact\SLRU buffers configuration Thomas Munro <[email protected]>
2021-03-26 06:00 ` Re: MultiXact\SLRU buffers configuration Andrey Borodin <[email protected]>
2021-03-26 15:52 ` Re: MultiXact\SLRU buffers configuration Andrey Borodin <[email protected]>
2021-03-26 20:26 ` Re: MultiXact\SLRU buffers configuration Thomas Munro <[email protected]>
2021-03-27 05:31 ` Re: MultiXact\SLRU buffers configuration Andrey Borodin <[email protected]>
2021-03-28 21:15 ` Re: MultiXact\SLRU buffers configuration Thomas Munro <[email protected]>
2021-03-29 08:26 ` Re: MultiXact\SLRU buffers configuration Andrey Borodin <[email protected]>
2021-03-31 21:09 ` Re: MultiXact\SLRU buffers configuration Andrey Borodin <[email protected]>
2021-04-01 03:40 ` Re: MultiXact\SLRU buffers configuration Thomas Munro <[email protected]>
2021-04-03 19:57 ` Re: MultiXact\SLRU buffers configuration Andrey Borodin <[email protected]>
2021-04-07 05:59 ` Re: MultiXact\SLRU buffers configuration Thomas Munro <[email protected]>
2021-04-07 11:44 ` Re: MultiXact\SLRU buffers configuration Andrey Borodin <[email protected]>
2021-04-07 12:13 ` Re: MultiXact\SLRU buffers configuration Andrey Borodin <[email protected]>
2021-04-08 00:30 ` Re: MultiXact\SLRU buffers configuration Thomas Munro <[email protected]>
2021-04-08 07:24 ` Re: MultiXact\SLRU buffers configuration Andrey Borodin <[email protected]>
2021-04-08 12:22 ` Re: MultiXact\SLRU buffers configuration Thomas Munro <[email protected]>
2021-04-11 18:37 ` Re: MultiXact\SLRU buffers configuration Andrey Borodin <[email protected]>
@ 2021-12-26 10:09 ` Andrey Borodin <[email protected]>
1 sibling, 0 replies; 90+ messages in thread
From: Andrey Borodin @ 2021-12-26 10:09 UTC (permalink / raw)
To: Andrey Borodin <[email protected]>; +Cc: Gilles Darold <[email protected]>; Tomas Vondra <[email protected]>; Tomas Vondra <[email protected]>; Alexander Korotkov <[email protected]>; Anastasia Lubennikova <[email protected]>; Daniel Gustafsson <[email protected]>; Kyotaro Horiguchi <[email protected]>; pgsql-hackers; Thomas Munro <[email protected]>
>> 8 апр. 2021 г., в 15:22, Thomas Munro <[email protected]> написал(а):
>>
> I have one more idea inspired by CPU caches.
> Let's make SLRU n-associative, where n ~ 8.
> We can divide buffers into "banks", number of banks must be power of 2.
> All banks are of equal size. We choose bank size to approximately satisfy user's configured buffer size.
> Each page can live only within one bank. We use same search and eviction algorithms as we used in SLRU, but we only need to search\evict over 8 elements.
> All SLRU data of a single bank will be colocated within at most 2 cache line.
>
> I did not come up with idea how to avoid multiplication of bank_number * bank_size in case when user configured 31337 buffers (any number that is radically not a power of 2).
We can avoid this multiplication by using gapped memory under SLRU page_statuses, but from my POV here complexity does not worth possible performance gain.
PFA rebase of the patchset. Also I've added a patch to combine page_number, page_status, and page_dirty together to touch less cachelines.
Best regards, Andrey Borodin.
Attachments:
[text/x-diff] v-18-0001-Make-all-SLRU-buffer-sizes-configurable.patch (25.7K, ../../[email protected]/2-v-18-0001-Make-all-SLRU-buffer-sizes-configurable.patch)
download | inline diff:
From ea59d2ebde818ddc2a9111858b3d956cbcc7bff2 Mon Sep 17 00:00:00 2001
From: Andrey Borodin <[email protected]>
Date: Mon, 15 Feb 2021 21:51:56 +0500
Subject: [PATCH v=18 1/3] Make all SLRU buffer sizes configurable.
Provide new GUCs to set the number of buffers, instead of using hard
coded defaults.
Remove the limits on xact_buffers and commit_ts_buffers. The default
sizes for those caches are ~0.2% and ~0.1% of shared_buffers, as before,
but now there is no cap at 128 and 16 buffers respectively (unless
track_commit_timestamp is disabled, in the latter case, then we might as
well keep it tiny). Sizes much larger than the old limits have been
shown to be useful on modern systems, and an earlier commit replaced a
linear search with a hash table to avoid problems with extreme cases.
Author: Andrey M. Borodin <[email protected]>
Reviewed-by: Anastasia Lubennikova <[email protected]>
Reviewed-by: Tomas Vondra <[email protected]>
Reviewed-by: Alexander Korotkov <[email protected]>
Reviewed-by: Gilles Darold <[email protected]>
Reviewed-by: Thomas Munro <[email protected]>
Discussion: https://postgr.es/m/2BEC2B3F-9B61-4C1D-9FB5-5FAB0F05EF86%40yandex-team.ru
---
doc/src/sgml/config.sgml | 135 ++++++++++++++++++
src/backend/access/transam/clog.c | 23 ++-
src/backend/access/transam/commit_ts.c | 5 +
src/backend/access/transam/multixact.c | 8 +-
src/backend/access/transam/subtrans.c | 5 +-
src/backend/commands/async.c | 8 +-
src/backend/storage/lmgr/predicate.c | 4 +-
src/backend/utils/init/globals.c | 8 ++
src/backend/utils/misc/guc.c | 99 +++++++++++++
src/backend/utils/misc/postgresql.conf.sample | 9 ++
src/include/access/clog.h | 10 ++
src/include/access/commit_ts.h | 1 -
src/include/access/multixact.h | 4 -
src/include/access/slru.h | 5 +
src/include/access/subtrans.h | 2 -
src/include/commands/async.h | 5 -
src/include/miscadmin.h | 7 +
src/include/storage/predicate.h | 4 -
18 files changed, 299 insertions(+), 43 deletions(-)
diff --git a/doc/src/sgml/config.sgml b/doc/src/sgml/config.sgml
index afbb6c35e30..57d9696abe8 100644
--- a/doc/src/sgml/config.sgml
+++ b/doc/src/sgml/config.sgml
@@ -1952,6 +1952,141 @@ include_dir 'conf.d'
</para>
</listitem>
</varlistentry>
+
+ <varlistentry id="guc-multixact-offsets-buffers" xreflabel="multixact_offsets_buffers">
+ <term><varname>multixact_offsets_buffers</varname> (<type>integer</type>)
+ <indexterm>
+ <primary><varname>multixact_offsets_buffers</varname> configuration parameter</primary>
+ </indexterm>
+ </term>
+ <listitem>
+ <para>
+ Specifies the amount of shared memory to use to cache the contents
+ of <literal>pg_multixact/offsets</literal> (see
+ <xref linkend="pgdata-contents-table"/>).
+ If this value is specified without units, it is taken as blocks,
+ that is <symbol>BLCKSZ</symbol> bytes, typically 8kB.
+ The default value is <literal>8</literal>.
+ This parameter can only be set at server start.
+ </para>
+ </listitem>
+ </varlistentry>
+
+ <varlistentry id="guc-multixact-members-buffers" xreflabel="multixact_members_buffers">
+ <term><varname>multixact_members_buffers</varname> (<type>integer</type>)
+ <indexterm>
+ <primary><varname>multixact_members_buffers</varname> configuration parameter</primary>
+ </indexterm>
+ </term>
+ <listitem>
+ <para>
+ Specifies the amount of shared memory to use to cache the contents
+ of <literal>pg_multixact/members</literal> (see
+ <xref linkend="pgdata-contents-table"/>).
+ If this value is specified without units, it is taken as blocks,
+ that is <symbol>BLCKSZ</symbol> bytes, typically 8kB.
+ The default value is <literal>16</literal>.
+ This parameter can only be set at server start.
+ </para>
+ </listitem>
+ </varlistentry>
+
+ <varlistentry id="guc-subtrans-buffers" xreflabel="subtrans_buffers">
+ <term><varname>subtrans_buffers</varname> (<type>integer</type>)
+ <indexterm>
+ <primary><varname>subtrans_buffers</varname> configuration parameter</primary>
+ </indexterm>
+ </term>
+ <listitem>
+ <para>
+ Specifies the amount of shared memory to use to cache the contents
+ of <literal>pg_subtrans</literal> (see
+ <xref linkend="pgdata-contents-table"/>).
+ If this value is specified without units, it is taken as blocks,
+ that is <symbol>BLCKSZ</symbol> bytes, typically 8kB.
+ The default value is <literal>8</literal>.
+ This parameter can only be set at server start.
+ </para>
+ </listitem>
+ </varlistentry>
+
+ <varlistentry id="guc-notify-buffers" xreflabel="notify_buffers">
+ <term><varname>notify_buffers</varname> (<type>integer</type>)
+ <indexterm>
+ <primary><varname>notify_buffers</varname> configuration parameter</primary>
+ </indexterm>
+ </term>
+ <listitem>
+ <para>
+ Specifies the amount of shared memory to use to cache the contents
+ of <literal>pg_notify</literal> (see
+ <xref linkend="pgdata-contents-table"/>).
+ If this value is specified without units, it is taken as blocks,
+ that is <symbol>BLCKSZ</symbol> bytes, typically 8kB.
+ The default value is <literal>8</literal>.
+ This parameter can only be set at server start.
+ </para>
+ </listitem>
+ </varlistentry>
+
+ <varlistentry id="guc-serial-buffers" xreflabel="serial_buffers">
+ <term><varname>serial_buffers</varname> (<type>integer</type>)
+ <indexterm>
+ <primary><varname>serial_buffers</varname> configuration parameter</primary>
+ </indexterm>
+ </term>
+ <listitem>
+ <para>
+ Specifies the amount of shared memory to use to cache the contents
+ of <literal>pg_serial</literal> (see
+ <xref linkend="pgdata-contents-table"/>).
+ If this value is specified without units, it is taken as blocks,
+ that is <symbol>BLCKSZ</symbol> bytes, typically 8kB.
+ The default value is <literal>16</literal>.
+ This parameter can only be set at server start.
+ </para>
+ </listitem>
+ </varlistentry>
+
+ <varlistentry id="guc-xact-buffers" xreflabel="xact_buffers">
+ <term><varname>xact_buffers</varname> (<type>integer</type>)
+ <indexterm>
+ <primary><varname>xact_buffers</varname> configuration parameter</primary>
+ </indexterm>
+ </term>
+ <listitem>
+ <para>
+ Specifies the amount of shared memory to use to cache the contents
+ of <literal>pg_xact</literal> (see
+ <xref linkend="pgdata-contents-table"/>).
+ If this value is specified without units, it is taken as blocks,
+ that is <symbol>BLCKSZ</symbol> bytes, typically 8kB.
+ The default value is <literal>0</literal>, which requests
+ <varname>shared_buffers</varname> / 512, but not fewer than 4 blocks.
+ This parameter can only be set at server start.
+ </para>
+ </listitem>
+ </varlistentry>
+
+ <varlistentry id="guc-commit-ts-buffers" xreflabel="commit_ts_buffers">
+ <term><varname>commit_ts_buffers</varname> (<type>integer</type>)
+ <indexterm>
+ <primary><varname>commit_ts_buffers</varname> configuration parameter</primary>
+ </indexterm>
+ </term>
+ <listitem>
+ <para>
+ Specifies the amount of memory to use to cache the cotents of
+ <literal>pg_commit_ts</literal> (see
+ <xref linkend="pgdata-contents-table"/>).
+ If this value is specified without units, it is taken as blocks,
+ that is <symbol>BLCKSZ</symbol> bytes, typically 8kB.
+ The default value is <literal>0</literal>, which requests
+ <varname>shared_buffers</varname> / 1024, but not fewer than 4 blocks.
+ This parameter can only be set at server start.
+ </para>
+ </listitem>
+ </varlistentry>
<varlistentry id="guc-max-stack-depth" xreflabel="max_stack_depth">
<term><varname>max_stack_depth</varname> (<type>integer</type>)
diff --git a/src/backend/access/transam/clog.c b/src/backend/access/transam/clog.c
index 3ea16a270a8..ca28ada75fa 100644
--- a/src/backend/access/transam/clog.c
+++ b/src/backend/access/transam/clog.c
@@ -58,8 +58,8 @@
/* We need two bits per xact, so four xacts fit in a byte */
#define CLOG_BITS_PER_XACT 2
-#define CLOG_XACTS_PER_BYTE 4
-#define CLOG_XACTS_PER_PAGE (BLCKSZ * CLOG_XACTS_PER_BYTE)
+StaticAssertDecl((CLOG_BITS_PER_XACT * CLOG_XACTS_PER_BYTE) == BITS_PER_BYTE,
+ "CLOG_BITS_PER_XACT and CLOG_XACTS_PER_BYTE are inconsistent");
#define CLOG_XACT_BITMASK ((1 << CLOG_BITS_PER_XACT) - 1)
#define TransactionIdToPage(xid) ((xid) / (TransactionId) CLOG_XACTS_PER_PAGE)
@@ -664,23 +664,16 @@ TransactionIdGetStatus(TransactionId xid, XLogRecPtr *lsn)
/*
* Number of shared CLOG buffers.
*
- * On larger multi-processor systems, it is possible to have many CLOG page
- * requests in flight at one time which could lead to disk access for CLOG
- * page if the required page is not found in memory. Testing revealed that we
- * can get the best performance by having 128 CLOG buffers, more than that it
- * doesn't improve performance.
- *
- * Unconditionally keeping the number of CLOG buffers to 128 did not seem like
- * a good idea, because it would increase the minimum amount of shared memory
- * required to start, which could be a problem for people running very small
- * configurations. The following formula seems to represent a reasonable
- * compromise: people with very low values for shared_buffers will get fewer
- * CLOG buffers as well, and everyone else will get 128.
+ * By default, we'll use 2MB of for every 1GB of shared buffers, up to the
+ * theoretical maximum useful value, but always at least 4 buffers.
*/
Size
CLOGShmemBuffers(void)
{
- return Min(128, Max(4, NBuffers / 512));
+ /* Use configured value if provided. */
+ if (xact_buffers > 0)
+ return Max(4, xact_buffers);
+ return Min(CLOG_MAX_ALLOWED_BUFFERS, Max(4, NBuffers / 512));
}
/*
diff --git a/src/backend/access/transam/commit_ts.c b/src/backend/access/transam/commit_ts.c
index cbbe19fea83..cb2e0ceb1c3 100644
--- a/src/backend/access/transam/commit_ts.c
+++ b/src/backend/access/transam/commit_ts.c
@@ -511,10 +511,15 @@ pg_xact_commit_timestamp_origin(PG_FUNCTION_ARGS)
* We use a very similar logic as for the number of CLOG buffers (except we
* scale up twice as fast with shared buffers, and the maximum is twice as
* high); see comments in CLOGShmemBuffers.
+ * By default, we'll use 1MB of for every 1GB of shared buffers, up to the
+ * maximum value that slru.c will allow, but always at least 4 buffers.
*/
Size
CommitTsShmemBuffers(void)
{
+ /* Use configured value if provided. */
+ if (commit_ts_buffers > 0)
+ return Max(4, commit_ts_buffers);
return Min(256, Max(4, NBuffers / 256));
}
diff --git a/src/backend/access/transam/multixact.c b/src/backend/access/transam/multixact.c
index e6c70ed0bc2..a29ab4769dc 100644
--- a/src/backend/access/transam/multixact.c
+++ b/src/backend/access/transam/multixact.c
@@ -1834,8 +1834,8 @@ MultiXactShmemSize(void)
mul_size(sizeof(MultiXactId) * 2, MaxOldestSlot))
size = SHARED_MULTIXACT_STATE_SIZE;
- size = add_size(size, SimpleLruShmemSize(NUM_MULTIXACTOFFSET_BUFFERS, 0));
- size = add_size(size, SimpleLruShmemSize(NUM_MULTIXACTMEMBER_BUFFERS, 0));
+ size = add_size(size, SimpleLruShmemSize(multixact_offsets_buffers, 0));
+ size = add_size(size, SimpleLruShmemSize(multixact_members_buffers, 0));
return size;
}
@@ -1851,13 +1851,13 @@ MultiXactShmemInit(void)
MultiXactMemberCtl->PagePrecedes = MultiXactMemberPagePrecedes;
SimpleLruInit(MultiXactOffsetCtl,
- "MultiXactOffset", NUM_MULTIXACTOFFSET_BUFFERS, 0,
+ "MultiXactOffset", multixact_offsets_buffers, 0,
MultiXactOffsetSLRULock, "pg_multixact/offsets",
LWTRANCHE_MULTIXACTOFFSET_BUFFER,
SYNC_HANDLER_MULTIXACT_OFFSET);
SlruPagePrecedesUnitTests(MultiXactOffsetCtl, MULTIXACT_OFFSETS_PER_PAGE);
SimpleLruInit(MultiXactMemberCtl,
- "MultiXactMember", NUM_MULTIXACTMEMBER_BUFFERS, 0,
+ "MultiXactMember", multixact_offsets_buffers, 0,
MultiXactMemberSLRULock, "pg_multixact/members",
LWTRANCHE_MULTIXACTMEMBER_BUFFER,
SYNC_HANDLER_MULTIXACT_MEMBER);
diff --git a/src/backend/access/transam/subtrans.c b/src/backend/access/transam/subtrans.c
index 6a8e521f894..785f2520fde 100644
--- a/src/backend/access/transam/subtrans.c
+++ b/src/backend/access/transam/subtrans.c
@@ -31,6 +31,7 @@
#include "access/slru.h"
#include "access/subtrans.h"
#include "access/transam.h"
+#include "miscadmin.h"
#include "pg_trace.h"
#include "utils/snapmgr.h"
@@ -184,14 +185,14 @@ SubTransGetTopmostTransaction(TransactionId xid)
Size
SUBTRANSShmemSize(void)
{
- return SimpleLruShmemSize(NUM_SUBTRANS_BUFFERS, 0);
+ return SimpleLruShmemSize(subtrans_buffers, 0);
}
void
SUBTRANSShmemInit(void)
{
SubTransCtl->PagePrecedes = SubTransPagePrecedes;
- SimpleLruInit(SubTransCtl, "Subtrans", NUM_SUBTRANS_BUFFERS, 0,
+ SimpleLruInit(SubTransCtl, "Subtrans", subtrans_buffers, 0,
SubtransSLRULock, "pg_subtrans",
LWTRANCHE_SUBTRANS_BUFFER, SYNC_HANDLER_NONE);
SlruPagePrecedesUnitTests(SubTransCtl, SUBTRANS_XACTS_PER_PAGE);
diff --git a/src/backend/commands/async.c b/src/backend/commands/async.c
index 85570085450..7f2b7598449 100644
--- a/src/backend/commands/async.c
+++ b/src/backend/commands/async.c
@@ -117,7 +117,7 @@
* frontend during startup.) The above design guarantees that notifies from
* other backends will never be missed by ignoring self-notifies.
*
- * The amount of shared memory used for notify management (NUM_NOTIFY_BUFFERS)
+ * The amount of shared memory used for notify management (notify_buffers)
* can be varied without affecting anything but performance. The maximum
* amount of notification data that can be queued at one time is determined
* by slru.c's wraparound limit; see QUEUE_MAX_PAGE below.
@@ -235,7 +235,7 @@ typedef struct QueuePosition
*
* Resist the temptation to make this really large. While that would save
* work in some places, it would add cost in others. In particular, this
- * should likely be less than NUM_NOTIFY_BUFFERS, to ensure that backends
+ * should likely be less than notify_buffers, to ensure that backends
* catch up before the pages they'll need to read fall out of SLRU cache.
*/
#define QUEUE_CLEANUP_DELAY 4
@@ -521,7 +521,7 @@ AsyncShmemSize(void)
size = mul_size(MaxBackends + 1, sizeof(QueueBackendStatus));
size = add_size(size, offsetof(AsyncQueueControl, backend));
- size = add_size(size, SimpleLruShmemSize(NUM_NOTIFY_BUFFERS, 0));
+ size = add_size(size, SimpleLruShmemSize(notify_buffers, 0));
return size;
}
@@ -569,7 +569,7 @@ AsyncShmemInit(void)
* Set up SLRU management of the pg_notify data.
*/
NotifyCtl->PagePrecedes = asyncQueuePagePrecedes;
- SimpleLruInit(NotifyCtl, "Notify", NUM_NOTIFY_BUFFERS, 0,
+ SimpleLruInit(NotifyCtl, "Notify", notify_buffers, 0,
NotifySLRULock, "pg_notify", LWTRANCHE_NOTIFY_BUFFER,
SYNC_HANDLER_NONE);
diff --git a/src/backend/storage/lmgr/predicate.c b/src/backend/storage/lmgr/predicate.c
index 4f4d5b0d20f..c5e66757643 100644
--- a/src/backend/storage/lmgr/predicate.c
+++ b/src/backend/storage/lmgr/predicate.c
@@ -872,7 +872,7 @@ SerialInit(void)
*/
SerialSlruCtl->PagePrecedes = SerialPagePrecedesLogically;
SimpleLruInit(SerialSlruCtl, "Serial",
- NUM_SERIAL_BUFFERS, 0, SerialSLRULock, "pg_serial",
+ serial_buffers, 0, SerialSLRULock, "pg_serial",
LWTRANCHE_SERIAL_BUFFER, SYNC_HANDLER_NONE);
#ifdef USE_ASSERT_CHECKING
SerialPagePrecedesLogicallyUnitTests();
@@ -1396,7 +1396,7 @@ PredicateLockShmemSize(void)
/* Shared memory structures for SLRU tracking of old committed xids. */
size = add_size(size, sizeof(SerialControlData));
- size = add_size(size, SimpleLruShmemSize(NUM_SERIAL_BUFFERS, 0));
+ size = add_size(size, SimpleLruShmemSize(serial_buffers, 0));
return size;
}
diff --git a/src/backend/utils/init/globals.c b/src/backend/utils/init/globals.c
index 381d9e548d1..c83151d5ab5 100644
--- a/src/backend/utils/init/globals.c
+++ b/src/backend/utils/init/globals.c
@@ -150,3 +150,11 @@ int64 VacuumPageDirty = 0;
int VacuumCostBalance = 0; /* working state for vacuum */
bool VacuumCostActive = false;
+
+int multixact_offsets_buffers = 8;
+int multixact_members_buffers = 16;
+int subtrans_buffers = 32;
+int notify_buffers = 8;
+int serial_buffers = 16;
+int xact_buffers = 0;
+int commit_ts_buffers = 0;
diff --git a/src/backend/utils/misc/guc.c b/src/backend/utils/misc/guc.c
index bff949a40bc..eb6bf4c0a04 100644
--- a/src/backend/utils/misc/guc.c
+++ b/src/backend/utils/misc/guc.c
@@ -32,9 +32,11 @@
#endif
#include <unistd.h>
+#include "access/clog.h"
#include "access/commit_ts.h"
#include "access/gin.h"
#include "access/rmgr.h"
+#include "access/slru.h"
#include "access/tableam.h"
#include "access/toast_compression.h"
#include "access/transam.h"
@@ -202,6 +204,8 @@ static const char *show_tcp_keepalives_idle(void);
static const char *show_tcp_keepalives_interval(void);
static const char *show_tcp_keepalives_count(void);
static const char *show_tcp_user_timeout(void);
+static const char *show_xact_buffers(void);
+static const char *show_commit_ts_buffers(void);
static bool check_maxconnections(int *newval, void **extra, GucSource source);
static bool check_max_worker_processes(int *newval, void **extra, GucSource source);
static bool check_autovacuum_max_workers(int *newval, void **extra, GucSource source);
@@ -2366,6 +2370,83 @@ static struct config_int ConfigureNamesInt[] =
NULL, NULL, NULL
},
+ {
+ {"multixact_offsets_buffers", PGC_POSTMASTER, RESOURCES_MEM,
+ gettext_noop("Sets the number of shared memory buffers used for the MultiXact offset SLRU cache."),
+ NULL,
+ GUC_UNIT_BLOCKS
+ },
+ &multixact_offsets_buffers,
+ 8, 2, SLRU_MAX_ALLOWED_BUFFERS,
+ NULL, NULL, NULL
+ },
+
+ {
+ {"multixact_members_buffers", PGC_POSTMASTER, RESOURCES_MEM,
+ gettext_noop("Sets the number of shared memory buffers used for the MultiXact member SLRU cache."),
+ NULL,
+ GUC_UNIT_BLOCKS
+ },
+ &multixact_members_buffers,
+ 16, 2, SLRU_MAX_ALLOWED_BUFFERS,
+ NULL, NULL, NULL
+ },
+
+ {
+ {"subtrans_buffers", PGC_POSTMASTER, RESOURCES_MEM,
+ gettext_noop("Sets the number of shared memory buffers used for the sub-transaction SLRU cache."),
+ NULL,
+ GUC_UNIT_BLOCKS
+ },
+ &subtrans_buffers,
+ 32, 2, SLRU_MAX_ALLOWED_BUFFERS,
+ NULL, NULL, NULL
+ },
+
+ {
+ {"notify_buffers", PGC_POSTMASTER, RESOURCES_MEM,
+ gettext_noop("Sets the number of shared memory buffers used for the NOTIFY message SLRU cache."),
+ NULL,
+ GUC_UNIT_BLOCKS
+ },
+ ¬ify_buffers,
+ 8, 2, SLRU_MAX_ALLOWED_BUFFERS,
+ NULL, NULL, NULL
+ },
+
+ {
+ {"serial_buffers", PGC_POSTMASTER, RESOURCES_MEM,
+ gettext_noop("Sets the number of shared memory buffers used for the serializable transaction SLRU cache."),
+ NULL,
+ GUC_UNIT_BLOCKS
+ },
+ &serial_buffers,
+ 16, 2, SLRU_MAX_ALLOWED_BUFFERS,
+ NULL, NULL, NULL
+ },
+
+ {
+ {"xact_buffers", PGC_POSTMASTER, RESOURCES_MEM,
+ gettext_noop("Sets the number of shared memory buffers used for the transaction status SLRU cache."),
+ NULL,
+ GUC_UNIT_BLOCKS
+ },
+ &xact_buffers,
+ 0, 0, CLOG_MAX_ALLOWED_BUFFERS,
+ NULL, NULL, show_xact_buffers
+ },
+
+ {
+ {"commit_ts_buffers", PGC_POSTMASTER, RESOURCES_MEM,
+ gettext_noop("Sets the size of the dedicated buffer pool used for the commit timestamp SLRU cache."),
+ NULL,
+ GUC_UNIT_BLOCKS
+ },
+ &commit_ts_buffers,
+ 0, 0, SLRU_MAX_ALLOWED_BUFFERS,
+ NULL, NULL, show_commit_ts_buffers
+ },
+
{
{"temp_buffers", PGC_USERSET, RESOURCES_MEM,
gettext_noop("Sets the maximum number of temporary buffers used by each session."),
@@ -12074,6 +12155,24 @@ show_tcp_user_timeout(void)
return nbuf;
}
+static const char *
+show_xact_buffers(void)
+{
+ static char nbuf[16];
+
+ snprintf(nbuf, sizeof(nbuf), "%zu", CLOGShmemBuffers());
+ return nbuf;
+}
+
+static const char *
+show_commit_ts_buffers(void)
+{
+ static char nbuf[16];
+
+ snprintf(nbuf, sizeof(nbuf), "%zu", CommitTsShmemBuffers());
+ return nbuf;
+}
+
static bool
check_maxconnections(int *newval, void **extra, GucSource source)
{
diff --git a/src/backend/utils/misc/postgresql.conf.sample b/src/backend/utils/misc/postgresql.conf.sample
index a1acd46b611..22bda4383ce 100644
--- a/src/backend/utils/misc/postgresql.conf.sample
+++ b/src/backend/utils/misc/postgresql.conf.sample
@@ -195,6 +195,15 @@
#old_snapshot_threshold = -1 # 1min-60d; -1 disables; 0 is immediate
# (change requires restart)
+# - SLRU Buffers (change requires restart) -
+
+#xact_buffers = 0 # memory for pg_xact (0 = auto)
+#subtrans_buffers = 32 # memory for pg_subtrans
+#multixact_offsets_buffers = 8 # memory for pg_multixact/offsets
+#multixact_members_buffers = 16 # memory for pg_multixact/members
+#notify_buffers = 8 # memory for pg_notify
+#serial_buffers = 16 # memory for pg_serial
+#commit_ts_buffers = 0 # memory for pg_commit_ts (0 = auto)
#------------------------------------------------------------------------------
# WRITE-AHEAD LOG
diff --git a/src/include/access/clog.h b/src/include/access/clog.h
index 39b8e4afa8a..739a292f7f3 100644
--- a/src/include/access/clog.h
+++ b/src/include/access/clog.h
@@ -15,6 +15,16 @@
#include "storage/sync.h"
#include "lib/stringinfo.h"
+/*
+ * Don't allow xact_buffers to be set higher than could possibly be useful or
+ * SLRU would allow.
+ */
+#define CLOG_XACTS_PER_BYTE 4
+#define CLOG_XACTS_PER_PAGE (BLCKSZ * CLOG_XACTS_PER_BYTE)
+#define CLOG_MAX_ALLOWED_BUFFERS \
+ Min(SLRU_MAX_ALLOWED_BUFFERS, \
+ (((MaxTransactionId / 2) + (CLOG_XACTS_PER_PAGE - 1)) / CLOG_XACTS_PER_PAGE))
+
/*
* Possible transaction statuses --- note that all-zeroes is the initial
* state.
diff --git a/src/include/access/commit_ts.h b/src/include/access/commit_ts.h
index a1538978c62..f86760f7240 100644
--- a/src/include/access/commit_ts.h
+++ b/src/include/access/commit_ts.h
@@ -16,7 +16,6 @@
#include "replication/origin.h"
#include "storage/sync.h"
-
extern PGDLLIMPORT bool track_commit_timestamp;
extern void TransactionTreeSetCommitTsData(TransactionId xid, int nsubxids,
diff --git a/src/include/access/multixact.h b/src/include/access/multixact.h
index 4bbb035eaea..97c0a463768 100644
--- a/src/include/access/multixact.h
+++ b/src/include/access/multixact.h
@@ -29,10 +29,6 @@
#define MaxMultiXactOffset ((MultiXactOffset) 0xFFFFFFFF)
-/* Number of SLRU buffers to use for multixact */
-#define NUM_MULTIXACTOFFSET_BUFFERS 8
-#define NUM_MULTIXACTMEMBER_BUFFERS 16
-
/*
* Possible multixact lock modes ("status"). The first four modes are for
* tuple locks (FOR KEY SHARE, FOR SHARE, FOR NO KEY UPDATE, FOR UPDATE); the
diff --git a/src/include/access/slru.h b/src/include/access/slru.h
index dd52e8cec7e..793c045f160 100644
--- a/src/include/access/slru.h
+++ b/src/include/access/slru.h
@@ -17,6 +17,11 @@
#include "storage/lwlock.h"
#include "storage/sync.h"
+/*
+ * To avoid overflowing internal arithmetic and the size_t data type, the
+ * number of buffers should not exceed this number.
+ */
+#define SLRU_MAX_ALLOWED_BUFFERS ((1024 * 1024 * 1024) / BLCKSZ)
/*
* Define SLRU segment size. A page is the same BLCKSZ as is used everywhere
diff --git a/src/include/access/subtrans.h b/src/include/access/subtrans.h
index d0ab44ae828..64fa86938e2 100644
--- a/src/include/access/subtrans.h
+++ b/src/include/access/subtrans.h
@@ -11,8 +11,6 @@
#ifndef SUBTRANS_H
#define SUBTRANS_H
-/* Number of SLRU buffers to use for subtrans */
-#define NUM_SUBTRANS_BUFFERS 32
extern void SubTransSetParent(TransactionId xid, TransactionId parent);
extern TransactionId SubTransGetParent(TransactionId xid);
diff --git a/src/include/commands/async.h b/src/include/commands/async.h
index f371ac896b9..99575974982 100644
--- a/src/include/commands/async.h
+++ b/src/include/commands/async.h
@@ -15,11 +15,6 @@
#include <signal.h>
-/*
- * The number of SLRU page buffers we use for the notification queue.
- */
-#define NUM_NOTIFY_BUFFERS 8
-
extern bool Trace_notify;
extern volatile sig_atomic_t notifyInterruptPending;
diff --git a/src/include/miscadmin.h b/src/include/miscadmin.h
index 90a30160657..22d31546ad5 100644
--- a/src/include/miscadmin.h
+++ b/src/include/miscadmin.h
@@ -176,6 +176,13 @@ extern PGDLLIMPORT int MaxBackends;
extern PGDLLIMPORT int MaxConnections;
extern PGDLLIMPORT int max_worker_processes;
extern PGDLLIMPORT int max_parallel_workers;
+extern PGDLLIMPORT int multixact_offsets_buffers;
+extern PGDLLIMPORT int multixact_members_buffers;
+extern PGDLLIMPORT int subtrans_buffers;
+extern PGDLLIMPORT int notify_buffers;
+extern PGDLLIMPORT int serial_buffers;
+extern PGDLLIMPORT int xact_buffers;
+extern PGDLLIMPORT int commit_ts_buffers;
extern PGDLLIMPORT int MyProcPid;
extern PGDLLIMPORT pg_time_t MyStartTime;
diff --git a/src/include/storage/predicate.h b/src/include/storage/predicate.h
index 152b6986114..c72779bd88d 100644
--- a/src/include/storage/predicate.h
+++ b/src/include/storage/predicate.h
@@ -26,10 +26,6 @@ extern int max_predicate_locks_per_xact;
extern int max_predicate_locks_per_relation;
extern int max_predicate_locks_per_page;
-
-/* Number of SLRU buffers to use for Serial SLRU */
-#define NUM_SERIAL_BUFFERS 16
-
/*
* A handle used for sharing SERIALIZABLEXACT objects between the participants
* in a parallel query.
--
2.33.1
[text/x-diff] v-18-0003-Pack-SLRU-page_number-page_status-and-page_dirt.patch (23.6K, ../../[email protected]/3-v-18-0003-Pack-SLRU-page_number-page_status-and-page_dirt.patch)
download | inline diff:
From 5c1aace8b1f5a2b852bf1476dffbd4a43f196ef3 Mon Sep 17 00:00:00 2001
From: Andrey Borodin <[email protected]>
Date: Sun, 26 Dec 2021 15:03:30 +0500
Subject: [PATCH v=18 3/3] Pack SLRU page_number, page_status and page_dirty
toogether
This allows to test only one cacheline during successfull
SlruSelectLRUPage().
---
src/backend/access/transam/clog.c | 12 +--
src/backend/access/transam/commit_ts.c | 6 +-
src/backend/access/transam/multixact.c | 16 +--
src/backend/access/transam/slru.c | 143 ++++++++++++-------------
src/backend/access/transam/subtrans.c | 4 +-
src/backend/commands/async.c | 2 +-
src/backend/storage/lmgr/predicate.c | 2 +-
src/include/access/slru.h | 13 ++-
8 files changed, 99 insertions(+), 99 deletions(-)
diff --git a/src/backend/access/transam/clog.c b/src/backend/access/transam/clog.c
index ca28ada75fa..7d3a0286a5f 100644
--- a/src/backend/access/transam/clog.c
+++ b/src/backend/access/transam/clog.c
@@ -375,7 +375,7 @@ TransactionIdSetPageStatusInternal(TransactionId xid, int nsubxids,
{
for (i = 0; i < nsubxids; i++)
{
- Assert(XactCtl->shared->page_number[slotno] == TransactionIdToPage(subxids[i]));
+ Assert(XactCtl->shared->page_entries[slotno].page_number == TransactionIdToPage(subxids[i]));
TransactionIdSetStatusBit(subxids[i],
TRANSACTION_STATUS_SUB_COMMITTED,
lsn, slotno);
@@ -389,11 +389,11 @@ TransactionIdSetPageStatusInternal(TransactionId xid, int nsubxids,
/* Set the subtransactions */
for (i = 0; i < nsubxids; i++)
{
- Assert(XactCtl->shared->page_number[slotno] == TransactionIdToPage(subxids[i]));
+ Assert(XactCtl->shared->page_entries[slotno].page_number == TransactionIdToPage(subxids[i]));
TransactionIdSetStatusBit(subxids[i], status, lsn, slotno);
}
- XactCtl->shared->page_dirty[slotno] = true;
+ XactCtl->shared->page_entries[slotno].page_dirty = true;
}
/*
@@ -713,7 +713,7 @@ BootStrapCLOG(void)
/* Make sure it's written out */
SimpleLruWritePage(XactCtl, slotno);
- Assert(!XactCtl->shared->page_dirty[slotno]);
+ Assert(!XactCtl->shared->page_entries[slotno].page_dirty);
LWLockRelease(XactSLRULock);
}
@@ -798,7 +798,7 @@ TrimCLOG(void)
/* Zero the rest of the page */
MemSet(byteptr + 1, 0, BLCKSZ - byteno - 1);
- XactCtl->shared->page_dirty[slotno] = true;
+ XactCtl->shared->page_entries[slotno].page_dirty = true;
}
LWLockRelease(XactSLRULock);
@@ -994,7 +994,7 @@ clog_redo(XLogReaderState *record)
slotno = ZeroCLOGPage(pageno, false);
SimpleLruWritePage(XactCtl, slotno);
- Assert(!XactCtl->shared->page_dirty[slotno]);
+ Assert(!XactCtl->shared->page_entries[slotno].page_dirty);
LWLockRelease(XactSLRULock);
}
diff --git a/src/backend/access/transam/commit_ts.c b/src/backend/access/transam/commit_ts.c
index cb2e0ceb1c3..6879ef3ec71 100644
--- a/src/backend/access/transam/commit_ts.c
+++ b/src/backend/access/transam/commit_ts.c
@@ -227,7 +227,7 @@ SetXidCommitTsInPage(TransactionId xid, int nsubxids,
for (i = 0; i < nsubxids; i++)
TransactionIdSetCommitTs(subxids[i], ts, nodeid, slotno);
- CommitTsCtl->shared->page_dirty[slotno] = true;
+ CommitTsCtl->shared->page_entries[slotno].page_dirty = true;
LWLockRelease(CommitTsSLRULock);
}
@@ -735,7 +735,7 @@ ActivateCommitTs(void)
LWLockAcquire(CommitTsSLRULock, LW_EXCLUSIVE);
slotno = ZeroCommitTsPage(pageno, false);
SimpleLruWritePage(CommitTsCtl, slotno);
- Assert(!CommitTsCtl->shared->page_dirty[slotno]);
+ Assert(!CommitTsCtl->shared->page_entries[slotno].page_dirty);
LWLockRelease(CommitTsSLRULock);
}
@@ -1005,7 +1005,7 @@ commit_ts_redo(XLogReaderState *record)
slotno = ZeroCommitTsPage(pageno, false);
SimpleLruWritePage(CommitTsCtl, slotno);
- Assert(!CommitTsCtl->shared->page_dirty[slotno]);
+ Assert(!CommitTsCtl->shared->page_entries[slotno].page_dirty);
LWLockRelease(CommitTsSLRULock);
}
diff --git a/src/backend/access/transam/multixact.c b/src/backend/access/transam/multixact.c
index a29ab4769dc..eb32821b717 100644
--- a/src/backend/access/transam/multixact.c
+++ b/src/backend/access/transam/multixact.c
@@ -887,7 +887,7 @@ RecordNewMultiXact(MultiXactId multi, MultiXactOffset offset,
*offptr = offset;
- MultiXactOffsetCtl->shared->page_dirty[slotno] = true;
+ MultiXactOffsetCtl->shared->page_entries[slotno].page_dirty = true;
/* Exchange our lock */
LWLockRelease(MultiXactOffsetSLRULock);
@@ -931,7 +931,7 @@ RecordNewMultiXact(MultiXactId multi, MultiXactOffset offset,
flagsval |= (members[i].status << bshift);
*flagsptr = flagsval;
- MultiXactMemberCtl->shared->page_dirty[slotno] = true;
+ MultiXactMemberCtl->shared->page_entries[slotno].page_dirty = true;
}
LWLockRelease(MultiXactMemberSLRULock);
@@ -1902,7 +1902,7 @@ BootStrapMultiXact(void)
/* Make sure it's written out */
SimpleLruWritePage(MultiXactOffsetCtl, slotno);
- Assert(!MultiXactOffsetCtl->shared->page_dirty[slotno]);
+ Assert(!MultiXactOffsetCtl->shared->page_entries[slotno].page_dirty);
LWLockRelease(MultiXactOffsetSLRULock);
@@ -1913,7 +1913,7 @@ BootStrapMultiXact(void)
/* Make sure it's written out */
SimpleLruWritePage(MultiXactMemberCtl, slotno);
- Assert(!MultiXactMemberCtl->shared->page_dirty[slotno]);
+ Assert(!MultiXactMemberCtl->shared->page_entries[slotno].page_dirty);
LWLockRelease(MultiXactMemberSLRULock);
}
@@ -2074,7 +2074,7 @@ TrimMultiXact(void)
MemSet(offptr, 0, BLCKSZ - (entryno * sizeof(MultiXactOffset)));
- MultiXactOffsetCtl->shared->page_dirty[slotno] = true;
+ MultiXactOffsetCtl->shared->page_entries[slotno].page_dirty = true;
}
LWLockRelease(MultiXactOffsetSLRULock);
@@ -2112,7 +2112,7 @@ TrimMultiXact(void)
* writing.
*/
- MultiXactMemberCtl->shared->page_dirty[slotno] = true;
+ MultiXactMemberCtl->shared->page_entries[slotno].page_dirty = true;
}
LWLockRelease(MultiXactMemberSLRULock);
@@ -3251,7 +3251,7 @@ multixact_redo(XLogReaderState *record)
slotno = ZeroMultiXactOffsetPage(pageno, false);
SimpleLruWritePage(MultiXactOffsetCtl, slotno);
- Assert(!MultiXactOffsetCtl->shared->page_dirty[slotno]);
+ Assert(!MultiXactOffsetCtl->shared->page_entries[slotno].page_dirty);
LWLockRelease(MultiXactOffsetSLRULock);
}
@@ -3266,7 +3266,7 @@ multixact_redo(XLogReaderState *record)
slotno = ZeroMultiXactMemberPage(pageno, false);
SimpleLruWritePage(MultiXactMemberCtl, slotno);
- Assert(!MultiXactMemberCtl->shared->page_dirty[slotno]);
+ Assert(!MultiXactMemberCtl->shared->page_entries[slotno].page_dirty);
LWLockRelease(MultiXactMemberSLRULock);
}
diff --git a/src/backend/access/transam/slru.c b/src/backend/access/transam/slru.c
index 33857bffb79..1f87e50f05c 100644
--- a/src/backend/access/transam/slru.c
+++ b/src/backend/access/transam/slru.c
@@ -186,9 +186,7 @@ SimpleLruShmemSize(int nslots, int nlsns)
/* we assume nslots isn't so large as to risk overflow */
sz = MAXALIGN(sizeof(SlruSharedData));
sz += MAXALIGN(nslots * sizeof(char *)); /* page_buffer[] */
- sz += MAXALIGN(nslots * sizeof(SlruPageStatus)); /* page_status[] */
- sz += MAXALIGN(nslots * sizeof(bool)); /* page_dirty[] */
- sz += MAXALIGN(nslots * sizeof(int)); /* page_number[] */
+ sz += MAXALIGN(nslots * sizeof(SlruPageEntry)); /* page_entries[] */
sz += MAXALIGN(nslots * sizeof(int)); /* page_lru_count[] */
sz += MAXALIGN(nslots * sizeof(LWLockPadded)); /* buffer_locks[] */
@@ -248,16 +246,13 @@ SimpleLruInit(SlruCtl ctl, const char *name, int nslots, int nlsns,
shared->slru_stats_idx = pgstat_slru_index(name);
+ Assert(sizeof(SlruPageEntry) == 8);
ptr = (char *) shared;
offset = MAXALIGN(sizeof(SlruSharedData));
shared->page_buffer = (char **) (ptr + offset);
offset += MAXALIGN(nslots * sizeof(char *));
- shared->page_status = (SlruPageStatus *) (ptr + offset);
- offset += MAXALIGN(nslots * sizeof(SlruPageStatus));
- shared->page_dirty = (bool *) (ptr + offset);
- offset += MAXALIGN(nslots * sizeof(bool));
- shared->page_number = (int *) (ptr + offset);
- offset += MAXALIGN(nslots * sizeof(int));
+ shared->page_entries = (SlruPageEntry *) (ptr + offset);
+ offset += MAXALIGN(nslots * sizeof(SlruPageEntry));
shared->page_lru_count = (int *) (ptr + offset);
offset += MAXALIGN(nslots * sizeof(int));
@@ -278,8 +273,8 @@ SimpleLruInit(SlruCtl ctl, const char *name, int nslots, int nlsns,
tranche_id);
shared->page_buffer[slotno] = ptr;
- shared->page_status[slotno] = SLRU_PAGE_EMPTY;
- shared->page_dirty[slotno] = false;
+ shared->page_entries[slotno].page_status = SLRU_PAGE_EMPTY;
+ shared->page_entries[slotno].page_dirty = false;
shared->page_lru_count[slotno] = 0;
ptr += BLCKSZ;
}
@@ -315,15 +310,15 @@ SimpleLruZeroPage(SlruCtl ctl, int pageno)
/* Find a suitable buffer slot for the page */
slotno = SlruSelectLRUPage(ctl, pageno);
- Assert(shared->page_status[slotno] == SLRU_PAGE_EMPTY ||
- (shared->page_status[slotno] == SLRU_PAGE_VALID &&
- !shared->page_dirty[slotno]) ||
- shared->page_number[slotno] == pageno);
+ Assert(shared->page_entries[slotno].page_status == SLRU_PAGE_EMPTY ||
+ (shared->page_entries[slotno].page_status == SLRU_PAGE_VALID &&
+ !shared->page_entries[slotno].page_dirty) ||
+ shared->page_entries[slotno].page_number == pageno);
/* Mark the slot as containing this page */
- shared->page_number[slotno] = pageno;
- shared->page_status[slotno] = SLRU_PAGE_VALID;
- shared->page_dirty[slotno] = true;
+ shared->page_entries[slotno].page_number = pageno;
+ shared->page_entries[slotno].page_status = SLRU_PAGE_VALID;
+ shared->page_entries[slotno].page_dirty = true;
SlruRecentlyUsed(shared, slotno);
/* Set the buffer to zeroes */
@@ -387,18 +382,18 @@ SimpleLruWaitIO(SlruCtl ctl, int slotno)
* cheaply test for failure by seeing if the buffer lock is still held (we
* assume that transaction abort would release the lock).
*/
- if (shared->page_status[slotno] == SLRU_PAGE_READ_IN_PROGRESS ||
- shared->page_status[slotno] == SLRU_PAGE_WRITE_IN_PROGRESS)
+ if (shared->page_entries[slotno].page_status == SLRU_PAGE_READ_IN_PROGRESS ||
+ shared->page_entries[slotno].page_status == SLRU_PAGE_WRITE_IN_PROGRESS)
{
if (LWLockConditionalAcquire(&shared->buffer_locks[slotno].lock, LW_SHARED))
{
/* indeed, the I/O must have failed */
- if (shared->page_status[slotno] == SLRU_PAGE_READ_IN_PROGRESS)
- shared->page_status[slotno] = SLRU_PAGE_EMPTY;
+ if (shared->page_entries[slotno].page_status == SLRU_PAGE_READ_IN_PROGRESS)
+ shared->page_entries[slotno].page_status = SLRU_PAGE_EMPTY;
else /* write_in_progress */
{
- shared->page_status[slotno] = SLRU_PAGE_VALID;
- shared->page_dirty[slotno] = true;
+ shared->page_entries[slotno].page_status = SLRU_PAGE_VALID;
+ shared->page_entries[slotno].page_dirty = true;
}
LWLockRelease(&shared->buffer_locks[slotno].lock);
}
@@ -438,15 +433,15 @@ SimpleLruReadPage(SlruCtl ctl, int pageno, bool write_ok,
slotno = SlruSelectLRUPage(ctl, pageno);
/* Did we find the page in memory? */
- if (shared->page_number[slotno] == pageno &&
- shared->page_status[slotno] != SLRU_PAGE_EMPTY)
+ if (shared->page_entries[slotno].page_number == pageno &&
+ shared->page_entries[slotno].page_status != SLRU_PAGE_EMPTY)
{
/*
* If page is still being read in, we must wait for I/O. Likewise
* if the page is being written and the caller said that's not OK.
*/
- if (shared->page_status[slotno] == SLRU_PAGE_READ_IN_PROGRESS ||
- (shared->page_status[slotno] == SLRU_PAGE_WRITE_IN_PROGRESS &&
+ if (shared->page_entries[slotno].page_status == SLRU_PAGE_READ_IN_PROGRESS ||
+ (shared->page_entries[slotno].page_status == SLRU_PAGE_WRITE_IN_PROGRESS &&
!write_ok))
{
SimpleLruWaitIO(ctl, slotno);
@@ -463,14 +458,14 @@ SimpleLruReadPage(SlruCtl ctl, int pageno, bool write_ok,
}
/* We found no match; assert we selected a freeable slot */
- Assert(shared->page_status[slotno] == SLRU_PAGE_EMPTY ||
- (shared->page_status[slotno] == SLRU_PAGE_VALID &&
- !shared->page_dirty[slotno]));
+ Assert(shared->page_entries[slotno].page_status == SLRU_PAGE_EMPTY ||
+ (shared->page_entries[slotno].page_status == SLRU_PAGE_VALID &&
+ !shared->page_entries[slotno].page_dirty));
/* Mark the slot read-busy */
- shared->page_number[slotno] = pageno;
- shared->page_status[slotno] = SLRU_PAGE_READ_IN_PROGRESS;
- shared->page_dirty[slotno] = false;
+ shared->page_entries[slotno].page_number = pageno;
+ shared->page_entries[slotno].page_status = SLRU_PAGE_READ_IN_PROGRESS;
+ shared->page_entries[slotno].page_dirty = false;
/* Acquire per-buffer lock (cannot deadlock, see notes at top) */
LWLockAcquire(&shared->buffer_locks[slotno].lock, LW_EXCLUSIVE);
@@ -487,11 +482,11 @@ SimpleLruReadPage(SlruCtl ctl, int pageno, bool write_ok,
/* Re-acquire control lock and update page state */
LWLockAcquire(shared->ControlLock, LW_EXCLUSIVE);
- Assert(shared->page_number[slotno] == pageno &&
- shared->page_status[slotno] == SLRU_PAGE_READ_IN_PROGRESS &&
- !shared->page_dirty[slotno]);
+ Assert(shared->page_entries[slotno].page_number == pageno &&
+ shared->page_entries[slotno].page_status == SLRU_PAGE_READ_IN_PROGRESS &&
+ !shared->page_entries[slotno].page_dirty);
- shared->page_status[slotno] = ok ? SLRU_PAGE_VALID : SLRU_PAGE_EMPTY;
+ shared->page_entries[slotno].page_status = ok ? SLRU_PAGE_VALID : SLRU_PAGE_EMPTY;
LWLockRelease(&shared->buffer_locks[slotno].lock);
@@ -536,9 +531,9 @@ SimpleLruReadPage_ReadOnly(SlruCtl ctl, int pageno, TransactionId xid)
int bankend = bankstart + shared->bank_size;
for (slotno = bankstart; slotno < bankend; slotno++)
{
- if (shared->page_number[slotno] == pageno &&
- shared->page_status[slotno] != SLRU_PAGE_EMPTY &&
- shared->page_status[slotno] != SLRU_PAGE_READ_IN_PROGRESS)
+ if (shared->page_entries[slotno].page_number == pageno &&
+ shared->page_entries[slotno].page_status != SLRU_PAGE_EMPTY &&
+ shared->page_entries[slotno].page_status != SLRU_PAGE_READ_IN_PROGRESS)
{
/* See comments for SlruRecentlyUsed macro */
SlruRecentlyUsed(shared, slotno);
@@ -572,12 +567,12 @@ static void
SlruInternalWritePage(SlruCtl ctl, int slotno, SlruWriteAll fdata)
{
SlruShared shared = ctl->shared;
- int pageno = shared->page_number[slotno];
+ int pageno = shared->page_entries[slotno].page_number;
bool ok;
/* If a write is in progress, wait for it to finish */
- while (shared->page_status[slotno] == SLRU_PAGE_WRITE_IN_PROGRESS &&
- shared->page_number[slotno] == pageno)
+ while (shared->page_entries[slotno].page_status == SLRU_PAGE_WRITE_IN_PROGRESS &&
+ shared->page_entries[slotno].page_number == pageno)
{
SimpleLruWaitIO(ctl, slotno);
}
@@ -586,17 +581,17 @@ SlruInternalWritePage(SlruCtl ctl, int slotno, SlruWriteAll fdata)
* Do nothing if page is not dirty, or if buffer no longer contains the
* same page we were called for.
*/
- if (!shared->page_dirty[slotno] ||
- shared->page_status[slotno] != SLRU_PAGE_VALID ||
- shared->page_number[slotno] != pageno)
+ if (!shared->page_entries[slotno].page_dirty ||
+ shared->page_entries[slotno].page_status != SLRU_PAGE_VALID ||
+ shared->page_entries[slotno].page_number != pageno)
return;
/*
* Mark the slot write-busy, and clear the dirtybit. After this point, a
* transaction status update on this page will mark it dirty again.
*/
- shared->page_status[slotno] = SLRU_PAGE_WRITE_IN_PROGRESS;
- shared->page_dirty[slotno] = false;
+ shared->page_entries[slotno].page_status = SLRU_PAGE_WRITE_IN_PROGRESS;
+ shared->page_entries[slotno].page_dirty = false;
/* Acquire per-buffer lock (cannot deadlock, see notes at top) */
LWLockAcquire(&shared->buffer_locks[slotno].lock, LW_EXCLUSIVE);
@@ -619,14 +614,14 @@ SlruInternalWritePage(SlruCtl ctl, int slotno, SlruWriteAll fdata)
/* Re-acquire control lock and update page state */
LWLockAcquire(shared->ControlLock, LW_EXCLUSIVE);
- Assert(shared->page_number[slotno] == pageno &&
- shared->page_status[slotno] == SLRU_PAGE_WRITE_IN_PROGRESS);
+ Assert(shared->page_entries[slotno].page_number == pageno &&
+ shared->page_entries[slotno].page_status == SLRU_PAGE_WRITE_IN_PROGRESS);
/* If we failed to write, mark the page dirty again */
if (!ok)
- shared->page_dirty[slotno] = true;
+ shared->page_entries[slotno].page_dirty = true;
- shared->page_status[slotno] = SLRU_PAGE_VALID;
+ shared->page_entries[slotno].page_status = SLRU_PAGE_VALID;
LWLockRelease(&shared->buffer_locks[slotno].lock);
@@ -1067,8 +1062,8 @@ SlruSelectLRUPage(SlruCtl ctl, int pageno)
int bankend = bankstart + shared->bank_size;
for (slotno = bankstart; slotno < bankend; slotno++)
{
- if (shared->page_number[slotno] == pageno &&
- shared->page_status[slotno] != SLRU_PAGE_EMPTY)
+ if (shared->page_entries[slotno].page_number == pageno &&
+ shared->page_entries[slotno].page_status != SLRU_PAGE_EMPTY)
return slotno;
}
@@ -1105,7 +1100,7 @@ SlruSelectLRUPage(SlruCtl ctl, int pageno)
int this_delta;
int this_page_number;
- if (shared->page_status[slotno] == SLRU_PAGE_EMPTY)
+ if (shared->page_entries[slotno].page_status == SLRU_PAGE_EMPTY)
return slotno;
this_delta = cur_count - shared->page_lru_count[slotno];
if (this_delta < 0)
@@ -1120,10 +1115,10 @@ SlruSelectLRUPage(SlruCtl ctl, int pageno)
shared->page_lru_count[slotno] = cur_count;
this_delta = 0;
}
- this_page_number = shared->page_number[slotno];
+ this_page_number = shared->page_entries[slotno].page_number;
if (this_page_number == shared->latest_page_number)
continue;
- if (shared->page_status[slotno] == SLRU_PAGE_VALID)
+ if (shared->page_entries[slotno].page_status == SLRU_PAGE_VALID)
{
if (this_delta > best_valid_delta ||
(this_delta == best_valid_delta &&
@@ -1165,7 +1160,7 @@ SlruSelectLRUPage(SlruCtl ctl, int pageno)
/*
* If the selected page is clean, we're set.
*/
- if (!shared->page_dirty[bestvalidslot])
+ if (!shared->page_entries[bestvalidslot].page_dirty)
return bestvalidslot;
/*
@@ -1217,9 +1212,9 @@ SimpleLruWriteAll(SlruCtl ctl, bool allow_redirtied)
* already. That's okay.
*/
Assert(allow_redirtied ||
- shared->page_status[slotno] == SLRU_PAGE_EMPTY ||
- (shared->page_status[slotno] == SLRU_PAGE_VALID &&
- !shared->page_dirty[slotno]));
+ shared->page_entries[slotno].page_status == SLRU_PAGE_EMPTY ||
+ (shared->page_entries[slotno].page_status == SLRU_PAGE_VALID &&
+ !shared->page_entries[slotno].page_dirty));
}
LWLockRelease(shared->ControlLock);
@@ -1291,18 +1286,18 @@ restart:;
for (slotno = 0; slotno < shared->num_slots; slotno++)
{
- if (shared->page_status[slotno] == SLRU_PAGE_EMPTY)
+ if (shared->page_entries[slotno].page_status == SLRU_PAGE_EMPTY)
continue;
- if (!ctl->PagePrecedes(shared->page_number[slotno], cutoffPage))
+ if (!ctl->PagePrecedes(shared->page_entries[slotno].page_number, cutoffPage))
continue;
/*
* If page is clean, just change state to EMPTY (expected case).
*/
- if (shared->page_status[slotno] == SLRU_PAGE_VALID &&
- !shared->page_dirty[slotno])
+ if (shared->page_entries[slotno].page_status == SLRU_PAGE_VALID &&
+ !shared->page_entries[slotno].page_dirty)
{
- shared->page_status[slotno] = SLRU_PAGE_EMPTY;
+ shared->page_entries[slotno].page_status = SLRU_PAGE_EMPTY;
continue;
}
@@ -1316,7 +1311,7 @@ restart:;
* won't have cause to read its data again. For now, keep the logic
* the same as it was.)
*/
- if (shared->page_status[slotno] == SLRU_PAGE_VALID)
+ if (shared->page_entries[slotno].page_status == SLRU_PAGE_VALID)
SlruInternalWritePage(ctl, slotno, NULL);
else
SimpleLruWaitIO(ctl, slotno);
@@ -1371,9 +1366,9 @@ restart:
did_write = false;
for (slotno = 0; slotno < shared->num_slots; slotno++)
{
- int pagesegno = shared->page_number[slotno] / SLRU_PAGES_PER_SEGMENT;
+ int pagesegno = shared->page_entries[slotno].page_number / SLRU_PAGES_PER_SEGMENT;
- if (shared->page_status[slotno] == SLRU_PAGE_EMPTY)
+ if (shared->page_entries[slotno].page_status == SLRU_PAGE_EMPTY)
continue;
/* not the segment we're looking for */
@@ -1381,15 +1376,15 @@ restart:
continue;
/* If page is clean, just change state to EMPTY (expected case). */
- if (shared->page_status[slotno] == SLRU_PAGE_VALID &&
- !shared->page_dirty[slotno])
+ if (shared->page_entries[slotno].page_status == SLRU_PAGE_VALID &&
+ !shared->page_entries[slotno].page_dirty)
{
- shared->page_status[slotno] = SLRU_PAGE_EMPTY;
+ shared->page_entries[slotno].page_status = SLRU_PAGE_EMPTY;
continue;
}
/* Same logic as SimpleLruTruncate() */
- if (shared->page_status[slotno] == SLRU_PAGE_VALID)
+ if (shared->page_entries[slotno].page_status == SLRU_PAGE_VALID)
SlruInternalWritePage(ctl, slotno, NULL);
else
SimpleLruWaitIO(ctl, slotno);
diff --git a/src/backend/access/transam/subtrans.c b/src/backend/access/transam/subtrans.c
index 785f2520fde..11754fdbac6 100644
--- a/src/backend/access/transam/subtrans.c
+++ b/src/backend/access/transam/subtrans.c
@@ -97,7 +97,7 @@ SubTransSetParent(TransactionId xid, TransactionId parent)
{
Assert(*ptr == InvalidTransactionId);
*ptr = parent;
- SubTransCtl->shared->page_dirty[slotno] = true;
+ SubTransCtl->shared->page_entries[slotno].page_dirty = true;
}
LWLockRelease(SubtransSLRULock);
@@ -220,7 +220,7 @@ BootStrapSUBTRANS(void)
/* Make sure it's written out */
SimpleLruWritePage(SubTransCtl, slotno);
- Assert(!SubTransCtl->shared->page_dirty[slotno]);
+ Assert(!SubTransCtl->shared->page_entries[slotno].page_dirty);
LWLockRelease(SubtransSLRULock);
}
diff --git a/src/backend/commands/async.c b/src/backend/commands/async.c
index 7f2b7598449..86a5bc2430c 100644
--- a/src/backend/commands/async.c
+++ b/src/backend/commands/async.c
@@ -1445,7 +1445,7 @@ asyncQueueAddEntries(ListCell *nextNotify)
InvalidTransactionId);
/* Note we mark the page dirty before writing in it */
- NotifyCtl->shared->page_dirty[slotno] = true;
+ NotifyCtl->shared->page_entries[slotno].page_dirty = true;
while (nextNotify != NULL)
{
diff --git a/src/backend/storage/lmgr/predicate.c b/src/backend/storage/lmgr/predicate.c
index c5e66757643..53bd7d957ce 100644
--- a/src/backend/storage/lmgr/predicate.c
+++ b/src/backend/storage/lmgr/predicate.c
@@ -963,7 +963,7 @@ SerialAdd(TransactionId xid, SerCommitSeqNo minConflictCommitSeqNo)
slotno = SimpleLruReadPage(SerialSlruCtl, targetPage, true, xid);
SerialValue(slotno, xid) = minConflictCommitSeqNo;
- SerialSlruCtl->shared->page_dirty[slotno] = true;
+ SerialSlruCtl->shared->page_entries[slotno].page_dirty = true;
LWLockRelease(SerialSLRULock);
}
diff --git a/src/include/access/slru.h b/src/include/access/slru.h
index f4df54d3c12..0a4fae91d7f 100644
--- a/src/include/access/slru.h
+++ b/src/include/access/slru.h
@@ -44,7 +44,7 @@
* in the latter case it implies that the page has been re-dirtied since
* the write started.
*/
-typedef enum
+typedef enum SlruPageStatus:int16_t
{
SLRU_PAGE_EMPTY, /* buffer is not in use */
SLRU_PAGE_READ_IN_PROGRESS, /* page is being read in */
@@ -52,6 +52,13 @@ typedef enum
SLRU_PAGE_WRITE_IN_PROGRESS /* page is being written out */
} SlruPageStatus;
+typedef struct SlruPageEntry
+{
+ int page_number;
+ SlruPageStatus page_status;
+ bool page_dirty;
+} SlruPageEntry;
+
/*
* Shared-memory state
*/
@@ -69,9 +76,7 @@ typedef struct SlruSharedData
* when status is EMPTY, as is page_lru_count.
*/
char **page_buffer;
- SlruPageStatus *page_status;
- bool *page_dirty;
- int *page_number;
+ SlruPageEntry *page_entries;
int *page_lru_count;
LWLockPadded *buffer_locks;
--
2.33.1
[text/x-diff] v-18-0002-Divide-SLRU-buffers-into-8-associative-banks.patch (4.7K, ../../[email protected]/4-v-18-0002-Divide-SLRU-buffers-into-8-associative-banks.patch)
download | inline diff:
From 12a1c31240e338c0e8c3c7211fbdd7b2e9666564 Mon Sep 17 00:00:00 2001
From: Andrey Borodin <[email protected]>
Date: Sun, 11 Apr 2021 21:18:10 +0300
Subject: [PATCH v=18 2/3] Divide SLRU buffers into 8-associative banks
We want to eliminate linear search within SLRU buffers.
To do so we divide SLRU buffers into banks. Each bank holds
approximately 8 buffers. Each SLRU pageno may reside only in one bank.
Adjacent pagenos reside in different banks.
---
src/backend/access/transam/slru.c | 43 ++++++++++++++++++++++++++++---
src/include/access/slru.h | 2 ++
2 files changed, 41 insertions(+), 4 deletions(-)
diff --git a/src/backend/access/transam/slru.c b/src/backend/access/transam/slru.c
index 7585ae24ce9..33857bffb79 100644
--- a/src/backend/access/transam/slru.c
+++ b/src/backend/access/transam/slru.c
@@ -134,7 +134,7 @@ typedef enum
static SlruErrorCause slru_errcause;
static int slru_errno;
-
+static void SlruAdjustNSlots(int* nslots, int* banksize, int* bankoffset);
static void SimpleLruZeroLSNs(SlruCtl ctl, int slotno);
static void SimpleLruWaitIO(SlruCtl ctl, int slotno);
static void SlruInternalWritePage(SlruCtl ctl, int slotno, SlruWriteAll fdata);
@@ -148,6 +148,30 @@ static bool SlruScanDirCbDeleteCutoff(SlruCtl ctl, char *filename,
int segpage, void *data);
static void SlruInternalDeleteSegment(SlruCtl ctl, int segno);
+/*
+ * Pick bank size optimal for N-assiciative SLRU buffers.
+ * We expect bank number to be picked from lowest bits of requested pageno.
+ * Thus we want number of banks to be power of 2. This routine computes number
+ * of banks aiming to make each bank of size 8. So we can pack page number and
+ * statuses of each bank on one cacheline.
+ */
+static void SlruAdjustNSlots(int* nslots, int* banksize, int* bankoffset)
+{
+ *banksize = *nslots;
+ int nbanks = 1;
+ *bankoffset = 0;
+ while (*banksize > 15)
+ {
+ if ((*banksize & 1) != 0)
+ *banksize +=1;
+ *banksize /= 2;
+ nbanks *= 2;
+ *bankoffset += 1;
+ }
+ elog(DEBUG5, "nslots %d banksize %d nbanks %d ", *nslots, *banksize, nbanks);
+ *nslots = *banksize * nbanks;
+}
+
/*
* Initialization of shared memory
*/
@@ -156,6 +180,8 @@ Size
SimpleLruShmemSize(int nslots, int nlsns)
{
Size sz;
+ int bankoffset, banksize;
+ SlruAdjustNSlots(&nslots, &banksize, &bankoffset);
/* we assume nslots isn't so large as to risk overflow */
sz = MAXALIGN(sizeof(SlruSharedData));
@@ -190,6 +216,8 @@ SimpleLruInit(SlruCtl ctl, const char *name, int nslots, int nlsns,
{
SlruShared shared;
bool found;
+ int bankoffset, banksize;
+ SlruAdjustNSlots(&nslots, &banksize, &bankoffset);
shared = (SlruShared) ShmemInitStruct(name,
SimpleLruShmemSize(nslots, nlsns),
@@ -209,6 +237,9 @@ SimpleLruInit(SlruCtl ctl, const char *name, int nslots, int nlsns,
shared->ControlLock = ctllock;
shared->num_slots = nslots;
+ shared->bank_mask = (1 << bankoffset) - 1;
+ shared->bank_size = banksize;
+
shared->lsn_groups_per_page = nlsns;
shared->cur_lru_count = 0;
@@ -501,7 +532,9 @@ SimpleLruReadPage_ReadOnly(SlruCtl ctl, int pageno, TransactionId xid)
LWLockAcquire(shared->ControlLock, LW_SHARED);
/* See if page is already in a buffer */
- for (slotno = 0; slotno < shared->num_slots; slotno++)
+ int bankstart = (pageno & shared->bank_mask) * shared->bank_size;
+ int bankend = bankstart + shared->bank_size;
+ for (slotno = bankstart; slotno < bankend; slotno++)
{
if (shared->page_number[slotno] == pageno &&
shared->page_status[slotno] != SLRU_PAGE_EMPTY &&
@@ -1030,7 +1063,9 @@ SlruSelectLRUPage(SlruCtl ctl, int pageno)
int best_invalid_page_number = 0; /* keep compiler quiet */
/* See if page already has a buffer assigned */
- for (slotno = 0; slotno < shared->num_slots; slotno++)
+ int bankstart = (pageno & shared->bank_mask) * shared->bank_size;
+ int bankend = bankstart + shared->bank_size;
+ for (slotno = bankstart; slotno < bankend; slotno++)
{
if (shared->page_number[slotno] == pageno &&
shared->page_status[slotno] != SLRU_PAGE_EMPTY)
@@ -1065,7 +1100,7 @@ SlruSelectLRUPage(SlruCtl ctl, int pageno)
* multiple pages with the same lru_count.
*/
cur_count = (shared->cur_lru_count)++;
- for (slotno = 0; slotno < shared->num_slots; slotno++)
+ for (slotno = bankstart; slotno < bankend; slotno++)
{
int this_delta;
int this_page_number;
diff --git a/src/include/access/slru.h b/src/include/access/slru.h
index 793c045f160..f4df54d3c12 100644
--- a/src/include/access/slru.h
+++ b/src/include/access/slru.h
@@ -61,6 +61,8 @@ typedef struct SlruSharedData
/* Number of buffers managed by this SLRU structure */
int num_slots;
+ int bank_size;
+ int bank_mask;
/*
* Arrays holding info for each buffer slot. Page number is undefined
--
2.33.1
^ permalink raw reply [nested|flat] 90+ messages in thread
* Re: MultiXact\SLRU buffers configuration
2020-05-08 16:36 MultiXact\SLRU buffers configuration Andrey M. Borodin <[email protected]>
2020-05-11 11:17 ` Re: MultiXact\SLRU buffers configuration Andrey M. Borodin <[email protected]>
2020-05-13 18:08 ` Re: MultiXact\SLRU buffers configuration Andrey M. Borodin <[email protected]>
2020-05-14 01:25 ` Re: MultiXact\SLRU buffers configuration Kyotaro Horiguchi <[email protected]>
2020-05-14 05:19 ` Re: MultiXact\SLRU buffers configuration Andrey M. Borodin <[email protected]>
2020-05-14 06:16 ` Re: MultiXact\SLRU buffers configuration Kyotaro Horiguchi <[email protected]>
2020-05-14 06:44 ` Re: MultiXact\SLRU buffers configuration Andrey M. Borodin <[email protected]>
2020-05-15 00:03 ` Re: MultiXact\SLRU buffers configuration Kyotaro Horiguchi <[email protected]>
2020-07-02 12:02 ` Re: MultiXact\SLRU buffers configuration Daniel Gustafsson <[email protected]>
2020-07-08 07:03 ` Re: MultiXact\SLRU buffers configuration Andrey M. Borodin <[email protected]>
2020-08-28 18:08 ` Re: MultiXact\SLRU buffers configuration Anastasia Lubennikova <[email protected]>
2020-09-28 14:41 ` Re: MultiXact\SLRU buffers configuration Andrey M. Borodin <[email protected]>
2020-10-26 01:05 ` Re: MultiXact\SLRU buffers configuration Alexander Korotkov <[email protected]>
2020-10-26 15:45 ` Re: MultiXact\SLRU buffers configuration Andrey Borodin <[email protected]>
2020-10-27 17:02 ` Re: MultiXact\SLRU buffers configuration Alexander Korotkov <[email protected]>
2020-10-27 17:23 ` Re: MultiXact\SLRU buffers configuration Alexander Korotkov <[email protected]>
2020-10-28 01:36 ` Re: MultiXact\SLRU buffers configuration Tomas Vondra <[email protected]>
2020-10-28 07:34 ` Re: MultiXact\SLRU buffers configuration Andrey Borodin <[email protected]>
2020-10-28 23:32 ` Re: MultiXact\SLRU buffers configuration Tomas Vondra <[email protected]>
2020-10-29 07:08 ` Re: MultiXact\SLRU buffers configuration Andrey Borodin <[email protected]>
2020-10-29 13:49 ` Re: MultiXact\SLRU buffers configuration Tomas Vondra <[email protected]>
2020-11-02 12:45 ` Re: MultiXact\SLRU buffers configuration Andrey Borodin <[email protected]>
2020-11-10 00:13 ` Re: MultiXact\SLRU buffers configuration Tomas Vondra <[email protected]>
2020-11-10 06:16 ` Re: MultiXact\SLRU buffers configuration Andrey Borodin <[email protected]>
2020-11-10 18:07 ` Re: MultiXact\SLRU buffers configuration Tomas Vondra <[email protected]>
2020-11-13 11:49 ` Re: MultiXact\SLRU buffers configuration Andrey Borodin <[email protected]>
2020-12-08 16:05 ` Re: MultiXact\SLRU buffers configuration Gilles Darold <[email protected]>
2020-12-08 17:52 ` Re: MultiXact\SLRU buffers configuration Andrey Borodin <[email protected]>
2020-12-10 14:45 ` Re: MultiXact\SLRU buffers configuration Gilles Darold <[email protected]>
2020-12-11 17:50 ` Re: MultiXact\SLRU buffers configuration Gilles Darold <[email protected]>
2020-12-13 09:17 ` Re: MultiXact\SLRU buffers configuration Gilles Darold <[email protected]>
2020-12-13 17:24 ` Re: MultiXact\SLRU buffers configuration Andrey Borodin <[email protected]>
2020-12-23 16:31 ` Re: MultiXact\SLRU buffers configuration Gilles Darold <[email protected]>
2021-02-15 17:17 ` Re: MultiXact\SLRU buffers configuration Andrey Borodin <[email protected]>
2021-03-11 15:50 ` Re: MultiXact\SLRU buffers configuration Gilles Darold <[email protected]>
2021-03-12 12:44 ` Re: MultiXact\SLRU buffers configuration Andrey Borodin <[email protected]>
2021-03-24 21:31 ` Re: MultiXact\SLRU buffers configuration Thomas Munro <[email protected]>
2021-03-25 01:03 ` Re: MultiXact\SLRU buffers configuration Thomas Munro <[email protected]>
2021-03-26 03:46 ` Re: MultiXact\SLRU buffers configuration Thomas Munro <[email protected]>
2021-03-26 06:00 ` Re: MultiXact\SLRU buffers configuration Andrey Borodin <[email protected]>
2021-03-26 15:52 ` Re: MultiXact\SLRU buffers configuration Andrey Borodin <[email protected]>
2021-03-26 20:26 ` Re: MultiXact\SLRU buffers configuration Thomas Munro <[email protected]>
2021-03-27 05:31 ` Re: MultiXact\SLRU buffers configuration Andrey Borodin <[email protected]>
2021-03-28 21:15 ` Re: MultiXact\SLRU buffers configuration Thomas Munro <[email protected]>
2021-03-29 08:26 ` Re: MultiXact\SLRU buffers configuration Andrey Borodin <[email protected]>
2021-03-31 21:09 ` Re: MultiXact\SLRU buffers configuration Andrey Borodin <[email protected]>
2021-04-01 03:40 ` Re: MultiXact\SLRU buffers configuration Thomas Munro <[email protected]>
2021-04-03 19:57 ` Re: MultiXact\SLRU buffers configuration Andrey Borodin <[email protected]>
2021-04-07 05:59 ` Re: MultiXact\SLRU buffers configuration Thomas Munro <[email protected]>
2021-04-07 11:44 ` Re: MultiXact\SLRU buffers configuration Andrey Borodin <[email protected]>
2021-04-07 12:13 ` Re: MultiXact\SLRU buffers configuration Andrey Borodin <[email protected]>
2021-04-08 00:30 ` Re: MultiXact\SLRU buffers configuration Thomas Munro <[email protected]>
2021-04-08 07:24 ` Re: MultiXact\SLRU buffers configuration Andrey Borodin <[email protected]>
2021-04-08 12:22 ` Re: MultiXact\SLRU buffers configuration Thomas Munro <[email protected]>
@ 2022-07-21 13:00 ` Yura Sokolov <[email protected]>
2022-07-23 08:39 ` Re: MultiXact\SLRU buffers configuration Andrey Borodin <[email protected]>
1 sibling, 1 reply; 90+ messages in thread
From: Yura Sokolov @ 2022-07-21 13:00 UTC (permalink / raw)
To: Andrey Borodin <[email protected]>; Andres Freund <[email protected]>; +Cc: Thomas Munro <[email protected]>; Gilles Darold <[email protected]>; Tomas Vondra <[email protected]>; Tomas Vondra <[email protected]>; Alexander Korotkov <[email protected]>; Anastasia Lubennikova <[email protected]>; Daniel Gustafsson <[email protected]>; Kyotaro Horiguchi <[email protected]>; pgsql-hackers
Good day, all.
I did benchmark of patch on 2 socket Xeon 5220 CPU @ 2.20GHz .
I used "benchmark" used to reproduce problems with SLRU on our
customers setup.
In opposite to Shawn's tests I concentrated on bad case: a lot
of contention.
slru-funcs.sql - function definitions
- functions creates a lot of subtrunsactions to stress subtrans
- and select random rows for share to stress multixacts
slru-call.sql - function call for benchmark
slru-ballast.sql - randomly select 1000 consequent rows
"for update skip locked" to stress multixacts
patch1 - make SLRU buffers configurable
patch2 - make "8-associative banks"
Benchmark done by pgbench.
Inited with scale 1 to induce contention.
pgbench -i -s 1 testdb
Benchmark 1:
- low number of connections (50), 60% slru-call, 40% slru-ballast
pgbench -f slru-call.sql@60 -f slru-ballast.sql@40 -c 50 -j 75 -P 1 -T 30 testdb
version | subtrans | multixact | tps
| buffers | offs/memb | func+ballast
--------+----------+-----------+------
master | 32 | 8/16 | 184+119
patch1 | 32 | 8/16 | 184+119
patch1 | 1024 | 8/16 | 121+77
patch1 | 1024 | 512/1024 | 118+75
patch2 | 32 | 8/16 | 190+122
patch2 | 1024 | 8/16 | 190+125
patch2 | 1024 | 512/1024 | 190+127
As you see, this test case degrades with dumb increase of
SLRU buffers. But use of "hash table" in form of "associative
buckets" makes performance stable.
Benchmark 2:
- high connection number (600), 98% slru-call, 2% slru-ballast
pgbench -f slru-call.sql@98 -f slru-ballast.sql@2 -c 600 -j 75 -P 1 -T 30 testdb
I don't paste "ballast" tps here since 2% make them too small,
and they're very noisy.
version | subtrans | multixact | tps
| buffers | offs/memb | func
--------+----------+-----------+------
master | 32 | 8/16 | 13
patch1 | 32
| 8/16 | 13
patch1 | 1024 | 8/16 | 31
patch1 | 1024 | 512/1024 | 53
patch2 | 32 | 8/16 | 12
patch2 | 1024 | 8/16 | 34
patch2 | 1024 | 512/1024 | 67
In this case simple buffer increase does help. But "buckets"
increase performance gain.
I didn't paste here results third part of patch ("Pack SLRU...")
because I didn't see any major performance gain from it, and
it consumes large part of patch diff.
Rebased versions of first two patch parts are attached.
regards,
Yura Sokolov
Attachments:
[application/sql] slru-ballast.sql (123B, ../../[email protected]/2-slru-ballast.sql)
download
[application/sql] slru-call.sql (25B, ../../[email protected]/3-slru-call.sql)
download
[application/sql] slru-func.sql (1.2K, ../../[email protected]/4-slru-func.sql)
download
[text/x-patch] v21-0002-Divide-SLRU-buffers-into-8-associative-banks.patch (4.9K, ../../[email protected]/5-v21-0002-Divide-SLRU-buffers-into-8-associative-banks.patch)
download | inline diff:
From 41ec9d1c54184c515d53ecc8021c4a998813f2a9 Mon Sep 17 00:00:00 2001
From: Andrey Borodin <[email protected]>
Date: Sun, 11 Apr 2021 21:18:10 +0300
Subject: [PATCH v21 2/2] Divide SLRU buffers into 8-associative banks
We want to eliminate linear search within SLRU buffers.
To do so we divide SLRU buffers into banks. Each bank holds
approximately 8 buffers. Each SLRU pageno may reside only in one bank.
Adjacent pagenos reside in different banks.
---
src/backend/access/transam/slru.c | 43 ++++++++++++++++++++++++++++---
src/include/access/slru.h | 2 ++
2 files changed, 41 insertions(+), 4 deletions(-)
diff --git a/src/backend/access/transam/slru.c b/src/backend/access/transam/slru.c
index b65cb49d7ff..abc534bbd06 100644
--- a/src/backend/access/transam/slru.c
+++ b/src/backend/access/transam/slru.c
@@ -134,7 +134,7 @@ typedef enum
static SlruErrorCause slru_errcause;
static int slru_errno;
-
+static void SlruAdjustNSlots(int* nslots, int* banksize, int* bankoffset);
static void SimpleLruZeroLSNs(SlruCtl ctl, int slotno);
static void SimpleLruWaitIO(SlruCtl ctl, int slotno);
static void SlruInternalWritePage(SlruCtl ctl, int slotno, SlruWriteAll fdata);
@@ -148,6 +148,30 @@ static bool SlruScanDirCbDeleteCutoff(SlruCtl ctl, char *filename,
int segpage, void *data);
static void SlruInternalDeleteSegment(SlruCtl ctl, int segno);
+/*
+ * Pick bank size optimal for N-assiciative SLRU buffers.
+ * We expect bank number to be picked from lowest bits of requested pageno.
+ * Thus we want number of banks to be power of 2. This routine computes number
+ * of banks aiming to make each bank of size 8. So we can pack page number and
+ * statuses of each bank on one cacheline.
+ */
+static void SlruAdjustNSlots(int* nslots, int* banksize, int* bankoffset)
+{
+ int nbanks = 1;
+ *banksize = *nslots;
+ *bankoffset = 0;
+ while (*banksize > 15)
+ {
+ if ((*banksize & 1) != 0)
+ *banksize +=1;
+ *banksize /= 2;
+ nbanks *= 2;
+ *bankoffset += 1;
+ }
+ elog(DEBUG5, "nslots %d banksize %d nbanks %d ", *nslots, *banksize, nbanks);
+ *nslots = *banksize * nbanks;
+}
+
/*
* Initialization of shared memory
*/
@@ -156,6 +180,8 @@ Size
SimpleLruShmemSize(int nslots, int nlsns)
{
Size sz;
+ int bankoffset, banksize;
+ SlruAdjustNSlots(&nslots, &banksize, &bankoffset);
/* we assume nslots isn't so large as to risk overflow */
sz = MAXALIGN(sizeof(SlruSharedData));
@@ -190,6 +216,8 @@ SimpleLruInit(SlruCtl ctl, const char *name, int nslots, int nlsns,
{
SlruShared shared;
bool found;
+ int bankoffset, banksize;
+ SlruAdjustNSlots(&nslots, &banksize, &bankoffset);
shared = (SlruShared) ShmemInitStruct(name,
SimpleLruShmemSize(nslots, nlsns),
@@ -209,6 +237,9 @@ SimpleLruInit(SlruCtl ctl, const char *name, int nslots, int nlsns,
shared->ControlLock = ctllock;
shared->num_slots = nslots;
+ shared->bank_mask = (1 << bankoffset) - 1;
+ shared->bank_size = banksize;
+
shared->lsn_groups_per_page = nlsns;
shared->cur_lru_count = 0;
@@ -496,12 +527,14 @@ SimpleLruReadPage_ReadOnly(SlruCtl ctl, int pageno, TransactionId xid)
{
SlruShared shared = ctl->shared;
int slotno;
+ int bankstart = (pageno & shared->bank_mask) * shared->bank_size;
+ int bankend = bankstart + shared->bank_size;
/* Try to find the page while holding only shared lock */
LWLockAcquire(shared->ControlLock, LW_SHARED);
/* See if page is already in a buffer */
- for (slotno = 0; slotno < shared->num_slots; slotno++)
+ for (slotno = bankstart; slotno < bankend; slotno++)
{
if (shared->page_number[slotno] == pageno &&
shared->page_status[slotno] != SLRU_PAGE_EMPTY &&
@@ -1030,7 +1063,9 @@ SlruSelectLRUPage(SlruCtl ctl, int pageno)
int best_invalid_page_number = 0; /* keep compiler quiet */
/* See if page already has a buffer assigned */
- for (slotno = 0; slotno < shared->num_slots; slotno++)
+ int bankstart = (pageno & shared->bank_mask) * shared->bank_size;
+ int bankend = bankstart + shared->bank_size;
+ for (slotno = bankstart; slotno < bankend; slotno++)
{
if (shared->page_number[slotno] == pageno &&
shared->page_status[slotno] != SLRU_PAGE_EMPTY)
@@ -1065,7 +1100,7 @@ SlruSelectLRUPage(SlruCtl ctl, int pageno)
* multiple pages with the same lru_count.
*/
cur_count = (shared->cur_lru_count)++;
- for (slotno = 0; slotno < shared->num_slots; slotno++)
+ for (slotno = bankstart; slotno < bankend; slotno++)
{
int this_delta;
int this_page_number;
diff --git a/src/include/access/slru.h b/src/include/access/slru.h
index b7e2e2b55e3..cc9cc10d271 100644
--- a/src/include/access/slru.h
+++ b/src/include/access/slru.h
@@ -61,6 +61,8 @@ typedef struct SlruSharedData
/* Number of buffers managed by this SLRU structure */
int num_slots;
+ int bank_size;
+ int bank_mask;
/*
* Arrays holding info for each buffer slot. Page number is undefined
--
2.30.2
[text/x-patch] v21-0001-Make-all-SLRU-buffer-sizes-configurable.patch (25.7K, ../../[email protected]/6-v21-0001-Make-all-SLRU-buffer-sizes-configurable.patch)
download | inline diff:
From e5f03ebac800f06f45c9ecb5f7139c96032e7fa7 Mon Sep 17 00:00:00 2001
From: Andrey Borodin <[email protected]>
Date: Mon, 15 Feb 2021 21:51:56 +0500
Subject: [PATCH v21 1/2] Make all SLRU buffer sizes configurable.
Provide new GUCs to set the number of buffers, instead of using hard
coded defaults.
Remove the limits on xact_buffers and commit_ts_buffers. The default
sizes for those caches are ~0.2% and ~0.1% of shared_buffers, as before,
but now there is no cap at 128 and 16 buffers respectively (unless
track_commit_timestamp is disabled, in the latter case, then we might as
well keep it tiny). Sizes much larger than the old limits have been
shown to be useful on modern systems, and an earlier commit replaced a
linear search with a hash table to avoid problems with extreme cases.
Author: Andrey M. Borodin <[email protected]>
Reviewed-by: Anastasia Lubennikova <[email protected]>
Reviewed-by: Tomas Vondra <[email protected]>
Reviewed-by: Alexander Korotkov <[email protected]>
Reviewed-by: Gilles Darold <[email protected]>
Reviewed-by: Thomas Munro <[email protected]>
Discussion: https://postgr.es/m/2BEC2B3F-9B61-4C1D-9FB5-5FAB0F05EF86%40yandex-team.ru
---
doc/src/sgml/config.sgml | 135 ++++++++++++++++++
src/backend/access/transam/clog.c | 23 ++-
src/backend/access/transam/commit_ts.c | 5 +
src/backend/access/transam/multixact.c | 8 +-
src/backend/access/transam/subtrans.c | 5 +-
src/backend/commands/async.c | 8 +-
src/backend/storage/lmgr/predicate.c | 4 +-
src/backend/utils/init/globals.c | 8 ++
src/backend/utils/misc/guc.c | 99 +++++++++++++
src/backend/utils/misc/postgresql.conf.sample | 9 ++
src/include/access/clog.h | 10 ++
src/include/access/commit_ts.h | 1 -
src/include/access/multixact.h | 4 -
src/include/access/slru.h | 5 +
src/include/access/subtrans.h | 2 -
src/include/commands/async.h | 5 -
src/include/miscadmin.h | 7 +
src/include/storage/predicate.h | 4 -
18 files changed, 299 insertions(+), 43 deletions(-)
diff --git a/doc/src/sgml/config.sgml b/doc/src/sgml/config.sgml
index e2d728e0c4f..991dba69757 100644
--- a/doc/src/sgml/config.sgml
+++ b/doc/src/sgml/config.sgml
@@ -1961,6 +1961,141 @@ include_dir 'conf.d'
</listitem>
</varlistentry>
+ <varlistentry id="guc-multixact-offsets-buffers" xreflabel="multixact_offsets_buffers">
+ <term><varname>multixact_offsets_buffers</varname> (<type>integer</type>)
+ <indexterm>
+ <primary><varname>multixact_offsets_buffers</varname> configuration parameter</primary>
+ </indexterm>
+ </term>
+ <listitem>
+ <para>
+ Specifies the amount of shared memory to use to cache the contents
+ of <literal>pg_multixact/offsets</literal> (see
+ <xref linkend="pgdata-contents-table"/>).
+ If this value is specified without units, it is taken as blocks,
+ that is <symbol>BLCKSZ</symbol> bytes, typically 8kB.
+ The default value is <literal>8</literal>.
+ This parameter can only be set at server start.
+ </para>
+ </listitem>
+ </varlistentry>
+
+ <varlistentry id="guc-multixact-members-buffers" xreflabel="multixact_members_buffers">
+ <term><varname>multixact_members_buffers</varname> (<type>integer</type>)
+ <indexterm>
+ <primary><varname>multixact_members_buffers</varname> configuration parameter</primary>
+ </indexterm>
+ </term>
+ <listitem>
+ <para>
+ Specifies the amount of shared memory to use to cache the contents
+ of <literal>pg_multixact/members</literal> (see
+ <xref linkend="pgdata-contents-table"/>).
+ If this value is specified without units, it is taken as blocks,
+ that is <symbol>BLCKSZ</symbol> bytes, typically 8kB.
+ The default value is <literal>16</literal>.
+ This parameter can only be set at server start.
+ </para>
+ </listitem>
+ </varlistentry>
+
+ <varlistentry id="guc-subtrans-buffers" xreflabel="subtrans_buffers">
+ <term><varname>subtrans_buffers</varname> (<type>integer</type>)
+ <indexterm>
+ <primary><varname>subtrans_buffers</varname> configuration parameter</primary>
+ </indexterm>
+ </term>
+ <listitem>
+ <para>
+ Specifies the amount of shared memory to use to cache the contents
+ of <literal>pg_subtrans</literal> (see
+ <xref linkend="pgdata-contents-table"/>).
+ If this value is specified without units, it is taken as blocks,
+ that is <symbol>BLCKSZ</symbol> bytes, typically 8kB.
+ The default value is <literal>8</literal>.
+ This parameter can only be set at server start.
+ </para>
+ </listitem>
+ </varlistentry>
+
+ <varlistentry id="guc-notify-buffers" xreflabel="notify_buffers">
+ <term><varname>notify_buffers</varname> (<type>integer</type>)
+ <indexterm>
+ <primary><varname>notify_buffers</varname> configuration parameter</primary>
+ </indexterm>
+ </term>
+ <listitem>
+ <para>
+ Specifies the amount of shared memory to use to cache the contents
+ of <literal>pg_notify</literal> (see
+ <xref linkend="pgdata-contents-table"/>).
+ If this value is specified without units, it is taken as blocks,
+ that is <symbol>BLCKSZ</symbol> bytes, typically 8kB.
+ The default value is <literal>8</literal>.
+ This parameter can only be set at server start.
+ </para>
+ </listitem>
+ </varlistentry>
+
+ <varlistentry id="guc-serial-buffers" xreflabel="serial_buffers">
+ <term><varname>serial_buffers</varname> (<type>integer</type>)
+ <indexterm>
+ <primary><varname>serial_buffers</varname> configuration parameter</primary>
+ </indexterm>
+ </term>
+ <listitem>
+ <para>
+ Specifies the amount of shared memory to use to cache the contents
+ of <literal>pg_serial</literal> (see
+ <xref linkend="pgdata-contents-table"/>).
+ If this value is specified without units, it is taken as blocks,
+ that is <symbol>BLCKSZ</symbol> bytes, typically 8kB.
+ The default value is <literal>16</literal>.
+ This parameter can only be set at server start.
+ </para>
+ </listitem>
+ </varlistentry>
+
+ <varlistentry id="guc-xact-buffers" xreflabel="xact_buffers">
+ <term><varname>xact_buffers</varname> (<type>integer</type>)
+ <indexterm>
+ <primary><varname>xact_buffers</varname> configuration parameter</primary>
+ </indexterm>
+ </term>
+ <listitem>
+ <para>
+ Specifies the amount of shared memory to use to cache the contents
+ of <literal>pg_xact</literal> (see
+ <xref linkend="pgdata-contents-table"/>).
+ If this value is specified without units, it is taken as blocks,
+ that is <symbol>BLCKSZ</symbol> bytes, typically 8kB.
+ The default value is <literal>0</literal>, which requests
+ <varname>shared_buffers</varname> / 512, but not fewer than 4 blocks.
+ This parameter can only be set at server start.
+ </para>
+ </listitem>
+ </varlistentry>
+
+ <varlistentry id="guc-commit-ts-buffers" xreflabel="commit_ts_buffers">
+ <term><varname>commit_ts_buffers</varname> (<type>integer</type>)
+ <indexterm>
+ <primary><varname>commit_ts_buffers</varname> configuration parameter</primary>
+ </indexterm>
+ </term>
+ <listitem>
+ <para>
+ Specifies the amount of memory to use to cache the cotents of
+ <literal>pg_commit_ts</literal> (see
+ <xref linkend="pgdata-contents-table"/>).
+ If this value is specified without units, it is taken as blocks,
+ that is <symbol>BLCKSZ</symbol> bytes, typically 8kB.
+ The default value is <literal>0</literal>, which requests
+ <varname>shared_buffers</varname> / 1024, but not fewer than 4 blocks.
+ This parameter can only be set at server start.
+ </para>
+ </listitem>
+ </varlistentry>
+
<varlistentry id="guc-max-stack-depth" xreflabel="max_stack_depth">
<term><varname>max_stack_depth</varname> (<type>integer</type>)
<indexterm>
diff --git a/src/backend/access/transam/clog.c b/src/backend/access/transam/clog.c
index 3d9088a7048..e96a75d6959 100644
--- a/src/backend/access/transam/clog.c
+++ b/src/backend/access/transam/clog.c
@@ -58,8 +58,8 @@
/* We need two bits per xact, so four xacts fit in a byte */
#define CLOG_BITS_PER_XACT 2
-#define CLOG_XACTS_PER_BYTE 4
-#define CLOG_XACTS_PER_PAGE (BLCKSZ * CLOG_XACTS_PER_BYTE)
+StaticAssertDecl((CLOG_BITS_PER_XACT * CLOG_XACTS_PER_BYTE) == BITS_PER_BYTE,
+ "CLOG_BITS_PER_XACT and CLOG_XACTS_PER_BYTE are inconsistent");
#define CLOG_XACT_BITMASK ((1 << CLOG_BITS_PER_XACT) - 1)
#define TransactionIdToPage(xid) ((xid) / (TransactionId) CLOG_XACTS_PER_PAGE)
@@ -665,23 +665,16 @@ TransactionIdGetStatus(TransactionId xid, XLogRecPtr *lsn)
/*
* Number of shared CLOG buffers.
*
- * On larger multi-processor systems, it is possible to have many CLOG page
- * requests in flight at one time which could lead to disk access for CLOG
- * page if the required page is not found in memory. Testing revealed that we
- * can get the best performance by having 128 CLOG buffers, more than that it
- * doesn't improve performance.
- *
- * Unconditionally keeping the number of CLOG buffers to 128 did not seem like
- * a good idea, because it would increase the minimum amount of shared memory
- * required to start, which could be a problem for people running very small
- * configurations. The following formula seems to represent a reasonable
- * compromise: people with very low values for shared_buffers will get fewer
- * CLOG buffers as well, and everyone else will get 128.
+ * By default, we'll use 2MB of for every 1GB of shared buffers, up to the
+ * theoretical maximum useful value, but always at least 4 buffers.
*/
Size
CLOGShmemBuffers(void)
{
- return Min(128, Max(4, NBuffers / 512));
+ /* Use configured value if provided. */
+ if (xact_buffers > 0)
+ return Max(4, xact_buffers);
+ return Min(CLOG_MAX_ALLOWED_BUFFERS, Max(4, NBuffers / 512));
}
/*
diff --git a/src/backend/access/transam/commit_ts.c b/src/backend/access/transam/commit_ts.c
index 4dc8d402bd3..48ca5007475 100644
--- a/src/backend/access/transam/commit_ts.c
+++ b/src/backend/access/transam/commit_ts.c
@@ -514,10 +514,15 @@ pg_xact_commit_timestamp_origin(PG_FUNCTION_ARGS)
* We use a very similar logic as for the number of CLOG buffers (except we
* scale up twice as fast with shared buffers, and the maximum is twice as
* high); see comments in CLOGShmemBuffers.
+ * By default, we'll use 1MB of for every 1GB of shared buffers, up to the
+ * maximum value that slru.c will allow, but always at least 4 buffers.
*/
Size
CommitTsShmemBuffers(void)
{
+ /* Use configured value if provided. */
+ if (commit_ts_buffers > 0)
+ return Max(4, commit_ts_buffers);
return Min(256, Max(4, NBuffers / 256));
}
diff --git a/src/backend/access/transam/multixact.c b/src/backend/access/transam/multixact.c
index 8f7d12950e5..71d17e338e9 100644
--- a/src/backend/access/transam/multixact.c
+++ b/src/backend/access/transam/multixact.c
@@ -1834,8 +1834,8 @@ MultiXactShmemSize(void)
mul_size(sizeof(MultiXactId) * 2, MaxOldestSlot))
size = SHARED_MULTIXACT_STATE_SIZE;
- size = add_size(size, SimpleLruShmemSize(NUM_MULTIXACTOFFSET_BUFFERS, 0));
- size = add_size(size, SimpleLruShmemSize(NUM_MULTIXACTMEMBER_BUFFERS, 0));
+ size = add_size(size, SimpleLruShmemSize(multixact_offsets_buffers, 0));
+ size = add_size(size, SimpleLruShmemSize(multixact_members_buffers, 0));
return size;
}
@@ -1851,13 +1851,13 @@ MultiXactShmemInit(void)
MultiXactMemberCtl->PagePrecedes = MultiXactMemberPagePrecedes;
SimpleLruInit(MultiXactOffsetCtl,
- "MultiXactOffset", NUM_MULTIXACTOFFSET_BUFFERS, 0,
+ "MultiXactOffset", multixact_offsets_buffers, 0,
MultiXactOffsetSLRULock, "pg_multixact/offsets",
LWTRANCHE_MULTIXACTOFFSET_BUFFER,
SYNC_HANDLER_MULTIXACT_OFFSET);
SlruPagePrecedesUnitTests(MultiXactOffsetCtl, MULTIXACT_OFFSETS_PER_PAGE);
SimpleLruInit(MultiXactMemberCtl,
- "MultiXactMember", NUM_MULTIXACTMEMBER_BUFFERS, 0,
+ "MultiXactMember", multixact_offsets_buffers, 0,
MultiXactMemberSLRULock, "pg_multixact/members",
LWTRANCHE_MULTIXACTMEMBER_BUFFER,
SYNC_HANDLER_MULTIXACT_MEMBER);
diff --git a/src/backend/access/transam/subtrans.c b/src/backend/access/transam/subtrans.c
index 66d35481552..862b0eab966 100644
--- a/src/backend/access/transam/subtrans.c
+++ b/src/backend/access/transam/subtrans.c
@@ -31,6 +31,7 @@
#include "access/slru.h"
#include "access/subtrans.h"
#include "access/transam.h"
+#include "miscadmin.h"
#include "pg_trace.h"
#include "utils/snapmgr.h"
@@ -184,14 +185,14 @@ SubTransGetTopmostTransaction(TransactionId xid)
Size
SUBTRANSShmemSize(void)
{
- return SimpleLruShmemSize(NUM_SUBTRANS_BUFFERS, 0);
+ return SimpleLruShmemSize(subtrans_buffers, 0);
}
void
SUBTRANSShmemInit(void)
{
SubTransCtl->PagePrecedes = SubTransPagePrecedes;
- SimpleLruInit(SubTransCtl, "Subtrans", NUM_SUBTRANS_BUFFERS, 0,
+ SimpleLruInit(SubTransCtl, "Subtrans", subtrans_buffers, 0,
SubtransSLRULock, "pg_subtrans",
LWTRANCHE_SUBTRANS_BUFFER, SYNC_HANDLER_NONE);
SlruPagePrecedesUnitTests(SubTransCtl, SUBTRANS_XACTS_PER_PAGE);
diff --git a/src/backend/commands/async.c b/src/backend/commands/async.c
index 3e1b92df030..6b980603302 100644
--- a/src/backend/commands/async.c
+++ b/src/backend/commands/async.c
@@ -117,7 +117,7 @@
* frontend during startup.) The above design guarantees that notifies from
* other backends will never be missed by ignoring self-notifies.
*
- * The amount of shared memory used for notify management (NUM_NOTIFY_BUFFERS)
+ * The amount of shared memory used for notify management (notify_buffers)
* can be varied without affecting anything but performance. The maximum
* amount of notification data that can be queued at one time is determined
* by slru.c's wraparound limit; see QUEUE_MAX_PAGE below.
@@ -235,7 +235,7 @@ typedef struct QueuePosition
*
* Resist the temptation to make this really large. While that would save
* work in some places, it would add cost in others. In particular, this
- * should likely be less than NUM_NOTIFY_BUFFERS, to ensure that backends
+ * should likely be less than notify_buffers, to ensure that backends
* catch up before the pages they'll need to read fall out of SLRU cache.
*/
#define QUEUE_CLEANUP_DELAY 4
@@ -521,7 +521,7 @@ AsyncShmemSize(void)
size = mul_size(MaxBackends + 1, sizeof(QueueBackendStatus));
size = add_size(size, offsetof(AsyncQueueControl, backend));
- size = add_size(size, SimpleLruShmemSize(NUM_NOTIFY_BUFFERS, 0));
+ size = add_size(size, SimpleLruShmemSize(notify_buffers, 0));
return size;
}
@@ -569,7 +569,7 @@ AsyncShmemInit(void)
* Set up SLRU management of the pg_notify data.
*/
NotifyCtl->PagePrecedes = asyncQueuePagePrecedes;
- SimpleLruInit(NotifyCtl, "Notify", NUM_NOTIFY_BUFFERS, 0,
+ SimpleLruInit(NotifyCtl, "Notify", notify_buffers, 0,
NotifySLRULock, "pg_notify", LWTRANCHE_NOTIFY_BUFFER,
SYNC_HANDLER_NONE);
diff --git a/src/backend/storage/lmgr/predicate.c b/src/backend/storage/lmgr/predicate.c
index 5136da6ea36..54a0d66d579 100644
--- a/src/backend/storage/lmgr/predicate.c
+++ b/src/backend/storage/lmgr/predicate.c
@@ -872,7 +872,7 @@ SerialInit(void)
*/
SerialSlruCtl->PagePrecedes = SerialPagePrecedesLogically;
SimpleLruInit(SerialSlruCtl, "Serial",
- NUM_SERIAL_BUFFERS, 0, SerialSLRULock, "pg_serial",
+ serial_buffers, 0, SerialSLRULock, "pg_serial",
LWTRANCHE_SERIAL_BUFFER, SYNC_HANDLER_NONE);
#ifdef USE_ASSERT_CHECKING
SerialPagePrecedesLogicallyUnitTests();
@@ -1396,7 +1396,7 @@ PredicateLockShmemSize(void)
/* Shared memory structures for SLRU tracking of old committed xids. */
size = add_size(size, sizeof(SerialControlData));
- size = add_size(size, SimpleLruShmemSize(NUM_SERIAL_BUFFERS, 0));
+ size = add_size(size, SimpleLruShmemSize(serial_buffers, 0));
return size;
}
diff --git a/src/backend/utils/init/globals.c b/src/backend/utils/init/globals.c
index 1a5d29ac9ba..cc0ca91a8b3 100644
--- a/src/backend/utils/init/globals.c
+++ b/src/backend/utils/init/globals.c
@@ -151,3 +151,11 @@ int64 VacuumPageDirty = 0;
int VacuumCostBalance = 0; /* working state for vacuum */
bool VacuumCostActive = false;
+
+int multixact_offsets_buffers = 8;
+int multixact_members_buffers = 16;
+int subtrans_buffers = 32;
+int notify_buffers = 8;
+int serial_buffers = 16;
+int xact_buffers = 0;
+int commit_ts_buffers = 0;
diff --git a/src/backend/utils/misc/guc.c b/src/backend/utils/misc/guc.c
index af4a1c30689..2d9121b9265 100644
--- a/src/backend/utils/misc/guc.c
+++ b/src/backend/utils/misc/guc.c
@@ -32,9 +32,11 @@
#endif
#include <unistd.h>
+#include "access/clog.h"
#include "access/commit_ts.h"
#include "access/gin.h"
#include "access/rmgr.h"
+#include "access/slru.h"
#include "access/tableam.h"
#include "access/toast_compression.h"
#include "access/transam.h"
@@ -209,6 +211,8 @@ static const char *show_tcp_keepalives_idle(void);
static const char *show_tcp_keepalives_interval(void);
static const char *show_tcp_keepalives_count(void);
static const char *show_tcp_user_timeout(void);
+static const char *show_xact_buffers(void);
+static const char *show_commit_ts_buffers(void);
static bool check_maxconnections(int *newval, void **extra, GucSource source);
static bool check_max_worker_processes(int *newval, void **extra, GucSource source);
static bool check_autovacuum_max_workers(int *newval, void **extra, GucSource source);
@@ -2426,6 +2430,83 @@ static struct config_int ConfigureNamesInt[] =
NULL, NULL, NULL
},
+ {
+ {"multixact_offsets_buffers", PGC_POSTMASTER, RESOURCES_MEM,
+ gettext_noop("Sets the number of shared memory buffers used for the MultiXact offset SLRU cache."),
+ NULL,
+ GUC_UNIT_BLOCKS
+ },
+ &multixact_offsets_buffers,
+ 8, 2, SLRU_MAX_ALLOWED_BUFFERS,
+ NULL, NULL, NULL
+ },
+
+ {
+ {"multixact_members_buffers", PGC_POSTMASTER, RESOURCES_MEM,
+ gettext_noop("Sets the number of shared memory buffers used for the MultiXact member SLRU cache."),
+ NULL,
+ GUC_UNIT_BLOCKS
+ },
+ &multixact_members_buffers,
+ 16, 2, SLRU_MAX_ALLOWED_BUFFERS,
+ NULL, NULL, NULL
+ },
+
+ {
+ {"subtrans_buffers", PGC_POSTMASTER, RESOURCES_MEM,
+ gettext_noop("Sets the number of shared memory buffers used for the sub-transaction SLRU cache."),
+ NULL,
+ GUC_UNIT_BLOCKS
+ },
+ &subtrans_buffers,
+ 32, 2, SLRU_MAX_ALLOWED_BUFFERS,
+ NULL, NULL, NULL
+ },
+
+ {
+ {"notify_buffers", PGC_POSTMASTER, RESOURCES_MEM,
+ gettext_noop("Sets the number of shared memory buffers used for the NOTIFY message SLRU cache."),
+ NULL,
+ GUC_UNIT_BLOCKS
+ },
+ ¬ify_buffers,
+ 8, 2, SLRU_MAX_ALLOWED_BUFFERS,
+ NULL, NULL, NULL
+ },
+
+ {
+ {"serial_buffers", PGC_POSTMASTER, RESOURCES_MEM,
+ gettext_noop("Sets the number of shared memory buffers used for the serializable transaction SLRU cache."),
+ NULL,
+ GUC_UNIT_BLOCKS
+ },
+ &serial_buffers,
+ 16, 2, SLRU_MAX_ALLOWED_BUFFERS,
+ NULL, NULL, NULL
+ },
+
+ {
+ {"xact_buffers", PGC_POSTMASTER, RESOURCES_MEM,
+ gettext_noop("Sets the number of shared memory buffers used for the transaction status SLRU cache."),
+ NULL,
+ GUC_UNIT_BLOCKS
+ },
+ &xact_buffers,
+ 0, 0, CLOG_MAX_ALLOWED_BUFFERS,
+ NULL, NULL, show_xact_buffers
+ },
+
+ {
+ {"commit_ts_buffers", PGC_POSTMASTER, RESOURCES_MEM,
+ gettext_noop("Sets the size of the dedicated buffer pool used for the commit timestamp SLRU cache."),
+ NULL,
+ GUC_UNIT_BLOCKS
+ },
+ &commit_ts_buffers,
+ 0, 0, SLRU_MAX_ALLOWED_BUFFERS,
+ NULL, NULL, show_commit_ts_buffers
+ },
+
{
{"temp_buffers", PGC_USERSET, RESOURCES_MEM,
gettext_noop("Sets the maximum number of temporary buffers used by each session."),
@@ -12447,6 +12528,24 @@ show_tcp_user_timeout(void)
return nbuf;
}
+static const char *
+show_xact_buffers(void)
+{
+ static char nbuf[16];
+
+ snprintf(nbuf, sizeof(nbuf), "%zu", CLOGShmemBuffers());
+ return nbuf;
+}
+
+static const char *
+show_commit_ts_buffers(void)
+{
+ static char nbuf[16];
+
+ snprintf(nbuf, sizeof(nbuf), "%zu", CommitTsShmemBuffers());
+ return nbuf;
+}
+
static bool
check_maxconnections(int *newval, void **extra, GucSource source)
{
diff --git a/src/backend/utils/misc/postgresql.conf.sample b/src/backend/utils/misc/postgresql.conf.sample
index b4bc06e5f5a..2cb827e1e3b 100644
--- a/src/backend/utils/misc/postgresql.conf.sample
+++ b/src/backend/utils/misc/postgresql.conf.sample
@@ -195,6 +195,15 @@
#old_snapshot_threshold = -1 # 1min-60d; -1 disables; 0 is immediate
# (change requires restart)
+# - SLRU Buffers (change requires restart) -
+
+#xact_buffers = 0 # memory for pg_xact (0 = auto)
+#subtrans_buffers = 32 # memory for pg_subtrans
+#multixact_offsets_buffers = 8 # memory for pg_multixact/offsets
+#multixact_members_buffers = 16 # memory for pg_multixact/members
+#notify_buffers = 8 # memory for pg_notify
+#serial_buffers = 16 # memory for pg_serial
+#commit_ts_buffers = 0 # memory for pg_commit_ts (0 = auto)
#------------------------------------------------------------------------------
# WRITE-AHEAD LOG
diff --git a/src/include/access/clog.h b/src/include/access/clog.h
index 543f2e2643a..17d103aa4da 100644
--- a/src/include/access/clog.h
+++ b/src/include/access/clog.h
@@ -15,6 +15,16 @@
#include "storage/sync.h"
#include "lib/stringinfo.h"
+/*
+ * Don't allow xact_buffers to be set higher than could possibly be useful or
+ * SLRU would allow.
+ */
+#define CLOG_XACTS_PER_BYTE 4
+#define CLOG_XACTS_PER_PAGE (BLCKSZ * CLOG_XACTS_PER_BYTE)
+#define CLOG_MAX_ALLOWED_BUFFERS \
+ Min(SLRU_MAX_ALLOWED_BUFFERS, \
+ (((MaxTransactionId / 2) + (CLOG_XACTS_PER_PAGE - 1)) / CLOG_XACTS_PER_PAGE))
+
/*
* Possible transaction statuses --- note that all-zeroes is the initial
* state.
diff --git a/src/include/access/commit_ts.h b/src/include/access/commit_ts.h
index 7662f8e1a9c..d928dcc9352 100644
--- a/src/include/access/commit_ts.h
+++ b/src/include/access/commit_ts.h
@@ -16,7 +16,6 @@
#include "replication/origin.h"
#include "storage/sync.h"
-
extern PGDLLIMPORT bool track_commit_timestamp;
extern void TransactionTreeSetCommitTsData(TransactionId xid, int nsubxids,
diff --git a/src/include/access/multixact.h b/src/include/access/multixact.h
index a5600a320ae..da7b8f0abb9 100644
--- a/src/include/access/multixact.h
+++ b/src/include/access/multixact.h
@@ -29,10 +29,6 @@
#define MaxMultiXactOffset ((MultiXactOffset) 0xFFFFFFFF)
-/* Number of SLRU buffers to use for multixact */
-#define NUM_MULTIXACTOFFSET_BUFFERS 8
-#define NUM_MULTIXACTMEMBER_BUFFERS 16
-
/*
* Possible multixact lock modes ("status"). The first four modes are for
* tuple locks (FOR KEY SHARE, FOR SHARE, FOR NO KEY UPDATE, FOR UPDATE); the
diff --git a/src/include/access/slru.h b/src/include/access/slru.h
index 130c41c8632..b7e2e2b55e3 100644
--- a/src/include/access/slru.h
+++ b/src/include/access/slru.h
@@ -17,6 +17,11 @@
#include "storage/lwlock.h"
#include "storage/sync.h"
+/*
+ * To avoid overflowing internal arithmetic and the size_t data type, the
+ * number of buffers should not exceed this number.
+ */
+#define SLRU_MAX_ALLOWED_BUFFERS ((1024 * 1024 * 1024) / BLCKSZ)
/*
* Define SLRU segment size. A page is the same BLCKSZ as is used everywhere
diff --git a/src/include/access/subtrans.h b/src/include/access/subtrans.h
index f94e116640b..1ddb62883b0 100644
--- a/src/include/access/subtrans.h
+++ b/src/include/access/subtrans.h
@@ -11,8 +11,6 @@
#ifndef SUBTRANS_H
#define SUBTRANS_H
-/* Number of SLRU buffers to use for subtrans */
-#define NUM_SUBTRANS_BUFFERS 32
extern void SubTransSetParent(TransactionId xid, TransactionId parent);
extern TransactionId SubTransGetParent(TransactionId xid);
diff --git a/src/include/commands/async.h b/src/include/commands/async.h
index 926af933d1b..402d184b9b3 100644
--- a/src/include/commands/async.h
+++ b/src/include/commands/async.h
@@ -15,11 +15,6 @@
#include <signal.h>
-/*
- * The number of SLRU page buffers we use for the notification queue.
- */
-#define NUM_NOTIFY_BUFFERS 8
-
extern PGDLLIMPORT bool Trace_notify;
extern PGDLLIMPORT volatile sig_atomic_t notifyInterruptPending;
diff --git a/src/include/miscadmin.h b/src/include/miscadmin.h
index ea9a56d3955..e65990e04e8 100644
--- a/src/include/miscadmin.h
+++ b/src/include/miscadmin.h
@@ -177,6 +177,13 @@ extern PGDLLIMPORT int MaxBackends;
extern PGDLLIMPORT int MaxConnections;
extern PGDLLIMPORT int max_worker_processes;
extern PGDLLIMPORT int max_parallel_workers;
+extern PGDLLIMPORT int multixact_offsets_buffers;
+extern PGDLLIMPORT int multixact_members_buffers;
+extern PGDLLIMPORT int subtrans_buffers;
+extern PGDLLIMPORT int notify_buffers;
+extern PGDLLIMPORT int serial_buffers;
+extern PGDLLIMPORT int xact_buffers;
+extern PGDLLIMPORT int commit_ts_buffers;
extern PGDLLIMPORT int MyProcPid;
extern PGDLLIMPORT pg_time_t MyStartTime;
diff --git a/src/include/storage/predicate.h b/src/include/storage/predicate.h
index 8dfcb3944b4..1e3f757ec30 100644
--- a/src/include/storage/predicate.h
+++ b/src/include/storage/predicate.h
@@ -26,10 +26,6 @@ extern PGDLLIMPORT int max_predicate_locks_per_xact;
extern PGDLLIMPORT int max_predicate_locks_per_relation;
extern PGDLLIMPORT int max_predicate_locks_per_page;
-
-/* Number of SLRU buffers to use for Serial SLRU */
-#define NUM_SERIAL_BUFFERS 16
-
/*
* A handle used for sharing SERIALIZABLEXACT objects between the participants
* in a parallel query.
--
2.30.2
^ permalink raw reply [nested|flat] 90+ messages in thread
* Re: MultiXact\SLRU buffers configuration
2020-05-08 16:36 MultiXact\SLRU buffers configuration Andrey M. Borodin <[email protected]>
2020-05-11 11:17 ` Re: MultiXact\SLRU buffers configuration Andrey M. Borodin <[email protected]>
2020-05-13 18:08 ` Re: MultiXact\SLRU buffers configuration Andrey M. Borodin <[email protected]>
2020-05-14 01:25 ` Re: MultiXact\SLRU buffers configuration Kyotaro Horiguchi <[email protected]>
2020-05-14 05:19 ` Re: MultiXact\SLRU buffers configuration Andrey M. Borodin <[email protected]>
2020-05-14 06:16 ` Re: MultiXact\SLRU buffers configuration Kyotaro Horiguchi <[email protected]>
2020-05-14 06:44 ` Re: MultiXact\SLRU buffers configuration Andrey M. Borodin <[email protected]>
2020-05-15 00:03 ` Re: MultiXact\SLRU buffers configuration Kyotaro Horiguchi <[email protected]>
2020-07-02 12:02 ` Re: MultiXact\SLRU buffers configuration Daniel Gustafsson <[email protected]>
2020-07-08 07:03 ` Re: MultiXact\SLRU buffers configuration Andrey M. Borodin <[email protected]>
2020-08-28 18:08 ` Re: MultiXact\SLRU buffers configuration Anastasia Lubennikova <[email protected]>
2020-09-28 14:41 ` Re: MultiXact\SLRU buffers configuration Andrey M. Borodin <[email protected]>
2020-10-26 01:05 ` Re: MultiXact\SLRU buffers configuration Alexander Korotkov <[email protected]>
2020-10-26 15:45 ` Re: MultiXact\SLRU buffers configuration Andrey Borodin <[email protected]>
2020-10-27 17:02 ` Re: MultiXact\SLRU buffers configuration Alexander Korotkov <[email protected]>
2020-10-27 17:23 ` Re: MultiXact\SLRU buffers configuration Alexander Korotkov <[email protected]>
2020-10-28 01:36 ` Re: MultiXact\SLRU buffers configuration Tomas Vondra <[email protected]>
2020-10-28 07:34 ` Re: MultiXact\SLRU buffers configuration Andrey Borodin <[email protected]>
2020-10-28 23:32 ` Re: MultiXact\SLRU buffers configuration Tomas Vondra <[email protected]>
2020-10-29 07:08 ` Re: MultiXact\SLRU buffers configuration Andrey Borodin <[email protected]>
2020-10-29 13:49 ` Re: MultiXact\SLRU buffers configuration Tomas Vondra <[email protected]>
2020-11-02 12:45 ` Re: MultiXact\SLRU buffers configuration Andrey Borodin <[email protected]>
2020-11-10 00:13 ` Re: MultiXact\SLRU buffers configuration Tomas Vondra <[email protected]>
2020-11-10 06:16 ` Re: MultiXact\SLRU buffers configuration Andrey Borodin <[email protected]>
2020-11-10 18:07 ` Re: MultiXact\SLRU buffers configuration Tomas Vondra <[email protected]>
2020-11-13 11:49 ` Re: MultiXact\SLRU buffers configuration Andrey Borodin <[email protected]>
2020-12-08 16:05 ` Re: MultiXact\SLRU buffers configuration Gilles Darold <[email protected]>
2020-12-08 17:52 ` Re: MultiXact\SLRU buffers configuration Andrey Borodin <[email protected]>
2020-12-10 14:45 ` Re: MultiXact\SLRU buffers configuration Gilles Darold <[email protected]>
2020-12-11 17:50 ` Re: MultiXact\SLRU buffers configuration Gilles Darold <[email protected]>
2020-12-13 09:17 ` Re: MultiXact\SLRU buffers configuration Gilles Darold <[email protected]>
2020-12-13 17:24 ` Re: MultiXact\SLRU buffers configuration Andrey Borodin <[email protected]>
2020-12-23 16:31 ` Re: MultiXact\SLRU buffers configuration Gilles Darold <[email protected]>
2021-02-15 17:17 ` Re: MultiXact\SLRU buffers configuration Andrey Borodin <[email protected]>
2021-03-11 15:50 ` Re: MultiXact\SLRU buffers configuration Gilles Darold <[email protected]>
2021-03-12 12:44 ` Re: MultiXact\SLRU buffers configuration Andrey Borodin <[email protected]>
2021-03-24 21:31 ` Re: MultiXact\SLRU buffers configuration Thomas Munro <[email protected]>
2021-03-25 01:03 ` Re: MultiXact\SLRU buffers configuration Thomas Munro <[email protected]>
2021-03-26 03:46 ` Re: MultiXact\SLRU buffers configuration Thomas Munro <[email protected]>
2021-03-26 06:00 ` Re: MultiXact\SLRU buffers configuration Andrey Borodin <[email protected]>
2021-03-26 15:52 ` Re: MultiXact\SLRU buffers configuration Andrey Borodin <[email protected]>
2021-03-26 20:26 ` Re: MultiXact\SLRU buffers configuration Thomas Munro <[email protected]>
2021-03-27 05:31 ` Re: MultiXact\SLRU buffers configuration Andrey Borodin <[email protected]>
2021-03-28 21:15 ` Re: MultiXact\SLRU buffers configuration Thomas Munro <[email protected]>
2021-03-29 08:26 ` Re: MultiXact\SLRU buffers configuration Andrey Borodin <[email protected]>
2021-03-31 21:09 ` Re: MultiXact\SLRU buffers configuration Andrey Borodin <[email protected]>
2021-04-01 03:40 ` Re: MultiXact\SLRU buffers configuration Thomas Munro <[email protected]>
2021-04-03 19:57 ` Re: MultiXact\SLRU buffers configuration Andrey Borodin <[email protected]>
2021-04-07 05:59 ` Re: MultiXact\SLRU buffers configuration Thomas Munro <[email protected]>
2021-04-07 11:44 ` Re: MultiXact\SLRU buffers configuration Andrey Borodin <[email protected]>
2021-04-07 12:13 ` Re: MultiXact\SLRU buffers configuration Andrey Borodin <[email protected]>
2021-04-08 00:30 ` Re: MultiXact\SLRU buffers configuration Thomas Munro <[email protected]>
2021-04-08 07:24 ` Re: MultiXact\SLRU buffers configuration Andrey Borodin <[email protected]>
2021-04-08 12:22 ` Re: MultiXact\SLRU buffers configuration Thomas Munro <[email protected]>
2022-07-21 13:00 ` Re: MultiXact\SLRU buffers configuration Yura Sokolov <[email protected]>
@ 2022-07-23 08:39 ` Andrey Borodin <[email protected]>
2022-07-23 08:47 ` Re: MultiXact\SLRU buffers configuration Thomas Munro <[email protected]>
2022-08-16 19:36 ` Re: MultiXact\SLRU buffers configuration [email protected]
0 siblings, 2 replies; 90+ messages in thread
From: Andrey Borodin @ 2022-07-23 08:39 UTC (permalink / raw)
To: Yura Sokolov <[email protected]>; +Cc: Andres Freund <[email protected]>; Thomas Munro <[email protected]>; Gilles Darold <[email protected]>; Tomas Vondra <[email protected]>; Tomas Vondra <[email protected]>; Alexander Korotkov <[email protected]>; Anastasia Lubennikova <[email protected]>; Daniel Gustafsson <[email protected]>; Kyotaro Horiguchi <[email protected]>; pgsql-hackers
> On 21 Jul 2022, at 18:00, Yura Sokolov <[email protected]> wrote:
>
> In this case simple buffer increase does help. But "buckets"
> increase performance gain.
Yura, thank you for your benchmarks!
We already knew that patch can save the day on pathological workloads, now we have a proof of this.
Also there's the evidence that user can blindly increase size of SLRU if they want (with the second patch). So there's no need for hard explanations on how to tune the buffers size.
Thomas, do you still have any doubts? Or is it certain that SLRU will be replaced by any better subsystem in 16?
Best regards, Andrey Borodin.
^ permalink raw reply [nested|flat] 90+ messages in thread
* Re: MultiXact\SLRU buffers configuration
2020-05-08 16:36 MultiXact\SLRU buffers configuration Andrey M. Borodin <[email protected]>
2020-05-11 11:17 ` Re: MultiXact\SLRU buffers configuration Andrey M. Borodin <[email protected]>
2020-05-13 18:08 ` Re: MultiXact\SLRU buffers configuration Andrey M. Borodin <[email protected]>
2020-05-14 01:25 ` Re: MultiXact\SLRU buffers configuration Kyotaro Horiguchi <[email protected]>
2020-05-14 05:19 ` Re: MultiXact\SLRU buffers configuration Andrey M. Borodin <[email protected]>
2020-05-14 06:16 ` Re: MultiXact\SLRU buffers configuration Kyotaro Horiguchi <[email protected]>
2020-05-14 06:44 ` Re: MultiXact\SLRU buffers configuration Andrey M. Borodin <[email protected]>
2020-05-15 00:03 ` Re: MultiXact\SLRU buffers configuration Kyotaro Horiguchi <[email protected]>
2020-07-02 12:02 ` Re: MultiXact\SLRU buffers configuration Daniel Gustafsson <[email protected]>
2020-07-08 07:03 ` Re: MultiXact\SLRU buffers configuration Andrey M. Borodin <[email protected]>
2020-08-28 18:08 ` Re: MultiXact\SLRU buffers configuration Anastasia Lubennikova <[email protected]>
2020-09-28 14:41 ` Re: MultiXact\SLRU buffers configuration Andrey M. Borodin <[email protected]>
2020-10-26 01:05 ` Re: MultiXact\SLRU buffers configuration Alexander Korotkov <[email protected]>
2020-10-26 15:45 ` Re: MultiXact\SLRU buffers configuration Andrey Borodin <[email protected]>
2020-10-27 17:02 ` Re: MultiXact\SLRU buffers configuration Alexander Korotkov <[email protected]>
2020-10-27 17:23 ` Re: MultiXact\SLRU buffers configuration Alexander Korotkov <[email protected]>
2020-10-28 01:36 ` Re: MultiXact\SLRU buffers configuration Tomas Vondra <[email protected]>
2020-10-28 07:34 ` Re: MultiXact\SLRU buffers configuration Andrey Borodin <[email protected]>
2020-10-28 23:32 ` Re: MultiXact\SLRU buffers configuration Tomas Vondra <[email protected]>
2020-10-29 07:08 ` Re: MultiXact\SLRU buffers configuration Andrey Borodin <[email protected]>
2020-10-29 13:49 ` Re: MultiXact\SLRU buffers configuration Tomas Vondra <[email protected]>
2020-11-02 12:45 ` Re: MultiXact\SLRU buffers configuration Andrey Borodin <[email protected]>
2020-11-10 00:13 ` Re: MultiXact\SLRU buffers configuration Tomas Vondra <[email protected]>
2020-11-10 06:16 ` Re: MultiXact\SLRU buffers configuration Andrey Borodin <[email protected]>
2020-11-10 18:07 ` Re: MultiXact\SLRU buffers configuration Tomas Vondra <[email protected]>
2020-11-13 11:49 ` Re: MultiXact\SLRU buffers configuration Andrey Borodin <[email protected]>
2020-12-08 16:05 ` Re: MultiXact\SLRU buffers configuration Gilles Darold <[email protected]>
2020-12-08 17:52 ` Re: MultiXact\SLRU buffers configuration Andrey Borodin <[email protected]>
2020-12-10 14:45 ` Re: MultiXact\SLRU buffers configuration Gilles Darold <[email protected]>
2020-12-11 17:50 ` Re: MultiXact\SLRU buffers configuration Gilles Darold <[email protected]>
2020-12-13 09:17 ` Re: MultiXact\SLRU buffers configuration Gilles Darold <[email protected]>
2020-12-13 17:24 ` Re: MultiXact\SLRU buffers configuration Andrey Borodin <[email protected]>
2020-12-23 16:31 ` Re: MultiXact\SLRU buffers configuration Gilles Darold <[email protected]>
2021-02-15 17:17 ` Re: MultiXact\SLRU buffers configuration Andrey Borodin <[email protected]>
2021-03-11 15:50 ` Re: MultiXact\SLRU buffers configuration Gilles Darold <[email protected]>
2021-03-12 12:44 ` Re: MultiXact\SLRU buffers configuration Andrey Borodin <[email protected]>
2021-03-24 21:31 ` Re: MultiXact\SLRU buffers configuration Thomas Munro <[email protected]>
2021-03-25 01:03 ` Re: MultiXact\SLRU buffers configuration Thomas Munro <[email protected]>
2021-03-26 03:46 ` Re: MultiXact\SLRU buffers configuration Thomas Munro <[email protected]>
2021-03-26 06:00 ` Re: MultiXact\SLRU buffers configuration Andrey Borodin <[email protected]>
2021-03-26 15:52 ` Re: MultiXact\SLRU buffers configuration Andrey Borodin <[email protected]>
2021-03-26 20:26 ` Re: MultiXact\SLRU buffers configuration Thomas Munro <[email protected]>
2021-03-27 05:31 ` Re: MultiXact\SLRU buffers configuration Andrey Borodin <[email protected]>
2021-03-28 21:15 ` Re: MultiXact\SLRU buffers configuration Thomas Munro <[email protected]>
2021-03-29 08:26 ` Re: MultiXact\SLRU buffers configuration Andrey Borodin <[email protected]>
2021-03-31 21:09 ` Re: MultiXact\SLRU buffers configuration Andrey Borodin <[email protected]>
2021-04-01 03:40 ` Re: MultiXact\SLRU buffers configuration Thomas Munro <[email protected]>
2021-04-03 19:57 ` Re: MultiXact\SLRU buffers configuration Andrey Borodin <[email protected]>
2021-04-07 05:59 ` Re: MultiXact\SLRU buffers configuration Thomas Munro <[email protected]>
2021-04-07 11:44 ` Re: MultiXact\SLRU buffers configuration Andrey Borodin <[email protected]>
2021-04-07 12:13 ` Re: MultiXact\SLRU buffers configuration Andrey Borodin <[email protected]>
2021-04-08 00:30 ` Re: MultiXact\SLRU buffers configuration Thomas Munro <[email protected]>
2021-04-08 07:24 ` Re: MultiXact\SLRU buffers configuration Andrey Borodin <[email protected]>
2021-04-08 12:22 ` Re: MultiXact\SLRU buffers configuration Thomas Munro <[email protected]>
2022-07-21 13:00 ` Re: MultiXact\SLRU buffers configuration Yura Sokolov <[email protected]>
2022-07-23 08:39 ` Re: MultiXact\SLRU buffers configuration Andrey Borodin <[email protected]>
@ 2022-07-23 08:47 ` Thomas Munro <[email protected]>
2022-12-20 18:39 ` Re: MultiXact\SLRU buffers configuration Andrey Borodin <[email protected]>
1 sibling, 1 reply; 90+ messages in thread
From: Thomas Munro @ 2022-07-23 08:47 UTC (permalink / raw)
To: Andrey Borodin <[email protected]>; +Cc: Yura Sokolov <[email protected]>; Andres Freund <[email protected]>; Gilles Darold <[email protected]>; Tomas Vondra <[email protected]>; Tomas Vondra <[email protected]>; Alexander Korotkov <[email protected]>; Anastasia Lubennikova <[email protected]>; Daniel Gustafsson <[email protected]>; Kyotaro Horiguchi <[email protected]>; pgsql-hackers
On Sat, Jul 23, 2022 at 8:41 PM Andrey Borodin <[email protected]> wrote:
> Thomas, do you still have any doubts? Or is it certain that SLRU will be replaced by any better subsystem in 16?
Hi Andrey,
Sorry for my lack of replies on this and the other SLRU thread -- I'm
thinking and experimenting. More soon.
^ permalink raw reply [nested|flat] 90+ messages in thread
* Re: MultiXact\SLRU buffers configuration
2020-05-08 16:36 MultiXact\SLRU buffers configuration Andrey M. Borodin <[email protected]>
2020-05-11 11:17 ` Re: MultiXact\SLRU buffers configuration Andrey M. Borodin <[email protected]>
2020-05-13 18:08 ` Re: MultiXact\SLRU buffers configuration Andrey M. Borodin <[email protected]>
2020-05-14 01:25 ` Re: MultiXact\SLRU buffers configuration Kyotaro Horiguchi <[email protected]>
2020-05-14 05:19 ` Re: MultiXact\SLRU buffers configuration Andrey M. Borodin <[email protected]>
2020-05-14 06:16 ` Re: MultiXact\SLRU buffers configuration Kyotaro Horiguchi <[email protected]>
2020-05-14 06:44 ` Re: MultiXact\SLRU buffers configuration Andrey M. Borodin <[email protected]>
2020-05-15 00:03 ` Re: MultiXact\SLRU buffers configuration Kyotaro Horiguchi <[email protected]>
2020-07-02 12:02 ` Re: MultiXact\SLRU buffers configuration Daniel Gustafsson <[email protected]>
2020-07-08 07:03 ` Re: MultiXact\SLRU buffers configuration Andrey M. Borodin <[email protected]>
2020-08-28 18:08 ` Re: MultiXact\SLRU buffers configuration Anastasia Lubennikova <[email protected]>
2020-09-28 14:41 ` Re: MultiXact\SLRU buffers configuration Andrey M. Borodin <[email protected]>
2020-10-26 01:05 ` Re: MultiXact\SLRU buffers configuration Alexander Korotkov <[email protected]>
2020-10-26 15:45 ` Re: MultiXact\SLRU buffers configuration Andrey Borodin <[email protected]>
2020-10-27 17:02 ` Re: MultiXact\SLRU buffers configuration Alexander Korotkov <[email protected]>
2020-10-27 17:23 ` Re: MultiXact\SLRU buffers configuration Alexander Korotkov <[email protected]>
2020-10-28 01:36 ` Re: MultiXact\SLRU buffers configuration Tomas Vondra <[email protected]>
2020-10-28 07:34 ` Re: MultiXact\SLRU buffers configuration Andrey Borodin <[email protected]>
2020-10-28 23:32 ` Re: MultiXact\SLRU buffers configuration Tomas Vondra <[email protected]>
2020-10-29 07:08 ` Re: MultiXact\SLRU buffers configuration Andrey Borodin <[email protected]>
2020-10-29 13:49 ` Re: MultiXact\SLRU buffers configuration Tomas Vondra <[email protected]>
2020-11-02 12:45 ` Re: MultiXact\SLRU buffers configuration Andrey Borodin <[email protected]>
2020-11-10 00:13 ` Re: MultiXact\SLRU buffers configuration Tomas Vondra <[email protected]>
2020-11-10 06:16 ` Re: MultiXact\SLRU buffers configuration Andrey Borodin <[email protected]>
2020-11-10 18:07 ` Re: MultiXact\SLRU buffers configuration Tomas Vondra <[email protected]>
2020-11-13 11:49 ` Re: MultiXact\SLRU buffers configuration Andrey Borodin <[email protected]>
2020-12-08 16:05 ` Re: MultiXact\SLRU buffers configuration Gilles Darold <[email protected]>
2020-12-08 17:52 ` Re: MultiXact\SLRU buffers configuration Andrey Borodin <[email protected]>
2020-12-10 14:45 ` Re: MultiXact\SLRU buffers configuration Gilles Darold <[email protected]>
2020-12-11 17:50 ` Re: MultiXact\SLRU buffers configuration Gilles Darold <[email protected]>
2020-12-13 09:17 ` Re: MultiXact\SLRU buffers configuration Gilles Darold <[email protected]>
2020-12-13 17:24 ` Re: MultiXact\SLRU buffers configuration Andrey Borodin <[email protected]>
2020-12-23 16:31 ` Re: MultiXact\SLRU buffers configuration Gilles Darold <[email protected]>
2021-02-15 17:17 ` Re: MultiXact\SLRU buffers configuration Andrey Borodin <[email protected]>
2021-03-11 15:50 ` Re: MultiXact\SLRU buffers configuration Gilles Darold <[email protected]>
2021-03-12 12:44 ` Re: MultiXact\SLRU buffers configuration Andrey Borodin <[email protected]>
2021-03-24 21:31 ` Re: MultiXact\SLRU buffers configuration Thomas Munro <[email protected]>
2021-03-25 01:03 ` Re: MultiXact\SLRU buffers configuration Thomas Munro <[email protected]>
2021-03-26 03:46 ` Re: MultiXact\SLRU buffers configuration Thomas Munro <[email protected]>
2021-03-26 06:00 ` Re: MultiXact\SLRU buffers configuration Andrey Borodin <[email protected]>
2021-03-26 15:52 ` Re: MultiXact\SLRU buffers configuration Andrey Borodin <[email protected]>
2021-03-26 20:26 ` Re: MultiXact\SLRU buffers configuration Thomas Munro <[email protected]>
2021-03-27 05:31 ` Re: MultiXact\SLRU buffers configuration Andrey Borodin <[email protected]>
2021-03-28 21:15 ` Re: MultiXact\SLRU buffers configuration Thomas Munro <[email protected]>
2021-03-29 08:26 ` Re: MultiXact\SLRU buffers configuration Andrey Borodin <[email protected]>
2021-03-31 21:09 ` Re: MultiXact\SLRU buffers configuration Andrey Borodin <[email protected]>
2021-04-01 03:40 ` Re: MultiXact\SLRU buffers configuration Thomas Munro <[email protected]>
2021-04-03 19:57 ` Re: MultiXact\SLRU buffers configuration Andrey Borodin <[email protected]>
2021-04-07 05:59 ` Re: MultiXact\SLRU buffers configuration Thomas Munro <[email protected]>
2021-04-07 11:44 ` Re: MultiXact\SLRU buffers configuration Andrey Borodin <[email protected]>
2021-04-07 12:13 ` Re: MultiXact\SLRU buffers configuration Andrey Borodin <[email protected]>
2021-04-08 00:30 ` Re: MultiXact\SLRU buffers configuration Thomas Munro <[email protected]>
2021-04-08 07:24 ` Re: MultiXact\SLRU buffers configuration Andrey Borodin <[email protected]>
2021-04-08 12:22 ` Re: MultiXact\SLRU buffers configuration Thomas Munro <[email protected]>
2022-07-21 13:00 ` Re: MultiXact\SLRU buffers configuration Yura Sokolov <[email protected]>
2022-07-23 08:39 ` Re: MultiXact\SLRU buffers configuration Andrey Borodin <[email protected]>
2022-07-23 08:47 ` Re: MultiXact\SLRU buffers configuration Thomas Munro <[email protected]>
@ 2022-12-20 18:39 ` Andrey Borodin <[email protected]>
0 siblings, 0 replies; 90+ messages in thread
From: Andrey Borodin @ 2022-12-20 18:39 UTC (permalink / raw)
To: Thomas Munro <[email protected]>; +Cc: Andrey Borodin <[email protected]>; Yura Sokolov <[email protected]>; Andres Freund <[email protected]>; Gilles Darold <[email protected]>; Tomas Vondra <[email protected]>; Tomas Vondra <[email protected]>; Alexander Korotkov <[email protected]>; Anastasia Lubennikova <[email protected]>; Daniel Gustafsson <[email protected]>; Kyotaro Horiguchi <[email protected]>; pgsql-hackers
On Sat, Jul 23, 2022 at 1:48 AM Thomas Munro <[email protected]> wrote:
>
> On Sat, Jul 23, 2022 at 8:41 PM Andrey Borodin <[email protected]> wrote:
> > Thomas, do you still have any doubts? Or is it certain that SLRU will be replaced by any better subsystem in 16?
>
> Hi Andrey,
>
> Sorry for my lack of replies on this and the other SLRU thread -- I'm
> thinking and experimenting. More soon.
>
Hi Thomas,
PostgreSQL 16 feature freeze is approaching again. Let's choose
something from possible solutions, even if the chosen one is
temporary.
Thank you!
Best regards, Andrey Borodin.
^ permalink raw reply [nested|flat] 90+ messages in thread
* Re: MultiXact\SLRU buffers configuration
2020-05-08 16:36 MultiXact\SLRU buffers configuration Andrey M. Borodin <[email protected]>
2020-05-11 11:17 ` Re: MultiXact\SLRU buffers configuration Andrey M. Borodin <[email protected]>
2020-05-13 18:08 ` Re: MultiXact\SLRU buffers configuration Andrey M. Borodin <[email protected]>
2020-05-14 01:25 ` Re: MultiXact\SLRU buffers configuration Kyotaro Horiguchi <[email protected]>
2020-05-14 05:19 ` Re: MultiXact\SLRU buffers configuration Andrey M. Borodin <[email protected]>
2020-05-14 06:16 ` Re: MultiXact\SLRU buffers configuration Kyotaro Horiguchi <[email protected]>
2020-05-14 06:44 ` Re: MultiXact\SLRU buffers configuration Andrey M. Borodin <[email protected]>
2020-05-15 00:03 ` Re: MultiXact\SLRU buffers configuration Kyotaro Horiguchi <[email protected]>
2020-07-02 12:02 ` Re: MultiXact\SLRU buffers configuration Daniel Gustafsson <[email protected]>
2020-07-08 07:03 ` Re: MultiXact\SLRU buffers configuration Andrey M. Borodin <[email protected]>
2020-08-28 18:08 ` Re: MultiXact\SLRU buffers configuration Anastasia Lubennikova <[email protected]>
2020-09-28 14:41 ` Re: MultiXact\SLRU buffers configuration Andrey M. Borodin <[email protected]>
2020-10-26 01:05 ` Re: MultiXact\SLRU buffers configuration Alexander Korotkov <[email protected]>
2020-10-26 15:45 ` Re: MultiXact\SLRU buffers configuration Andrey Borodin <[email protected]>
2020-10-27 17:02 ` Re: MultiXact\SLRU buffers configuration Alexander Korotkov <[email protected]>
2020-10-27 17:23 ` Re: MultiXact\SLRU buffers configuration Alexander Korotkov <[email protected]>
2020-10-28 01:36 ` Re: MultiXact\SLRU buffers configuration Tomas Vondra <[email protected]>
2020-10-28 07:34 ` Re: MultiXact\SLRU buffers configuration Andrey Borodin <[email protected]>
2020-10-28 23:32 ` Re: MultiXact\SLRU buffers configuration Tomas Vondra <[email protected]>
2020-10-29 07:08 ` Re: MultiXact\SLRU buffers configuration Andrey Borodin <[email protected]>
2020-10-29 13:49 ` Re: MultiXact\SLRU buffers configuration Tomas Vondra <[email protected]>
2020-11-02 12:45 ` Re: MultiXact\SLRU buffers configuration Andrey Borodin <[email protected]>
2020-11-10 00:13 ` Re: MultiXact\SLRU buffers configuration Tomas Vondra <[email protected]>
2020-11-10 06:16 ` Re: MultiXact\SLRU buffers configuration Andrey Borodin <[email protected]>
2020-11-10 18:07 ` Re: MultiXact\SLRU buffers configuration Tomas Vondra <[email protected]>
2020-11-13 11:49 ` Re: MultiXact\SLRU buffers configuration Andrey Borodin <[email protected]>
2020-12-08 16:05 ` Re: MultiXact\SLRU buffers configuration Gilles Darold <[email protected]>
2020-12-08 17:52 ` Re: MultiXact\SLRU buffers configuration Andrey Borodin <[email protected]>
2020-12-10 14:45 ` Re: MultiXact\SLRU buffers configuration Gilles Darold <[email protected]>
2020-12-11 17:50 ` Re: MultiXact\SLRU buffers configuration Gilles Darold <[email protected]>
2020-12-13 09:17 ` Re: MultiXact\SLRU buffers configuration Gilles Darold <[email protected]>
2020-12-13 17:24 ` Re: MultiXact\SLRU buffers configuration Andrey Borodin <[email protected]>
2020-12-23 16:31 ` Re: MultiXact\SLRU buffers configuration Gilles Darold <[email protected]>
2021-02-15 17:17 ` Re: MultiXact\SLRU buffers configuration Andrey Borodin <[email protected]>
2021-03-11 15:50 ` Re: MultiXact\SLRU buffers configuration Gilles Darold <[email protected]>
2021-03-12 12:44 ` Re: MultiXact\SLRU buffers configuration Andrey Borodin <[email protected]>
2021-03-24 21:31 ` Re: MultiXact\SLRU buffers configuration Thomas Munro <[email protected]>
2021-03-25 01:03 ` Re: MultiXact\SLRU buffers configuration Thomas Munro <[email protected]>
2021-03-26 03:46 ` Re: MultiXact\SLRU buffers configuration Thomas Munro <[email protected]>
2021-03-26 06:00 ` Re: MultiXact\SLRU buffers configuration Andrey Borodin <[email protected]>
2021-03-26 15:52 ` Re: MultiXact\SLRU buffers configuration Andrey Borodin <[email protected]>
2021-03-26 20:26 ` Re: MultiXact\SLRU buffers configuration Thomas Munro <[email protected]>
2021-03-27 05:31 ` Re: MultiXact\SLRU buffers configuration Andrey Borodin <[email protected]>
2021-03-28 21:15 ` Re: MultiXact\SLRU buffers configuration Thomas Munro <[email protected]>
2021-03-29 08:26 ` Re: MultiXact\SLRU buffers configuration Andrey Borodin <[email protected]>
2021-03-31 21:09 ` Re: MultiXact\SLRU buffers configuration Andrey Borodin <[email protected]>
2021-04-01 03:40 ` Re: MultiXact\SLRU buffers configuration Thomas Munro <[email protected]>
2021-04-03 19:57 ` Re: MultiXact\SLRU buffers configuration Andrey Borodin <[email protected]>
2021-04-07 05:59 ` Re: MultiXact\SLRU buffers configuration Thomas Munro <[email protected]>
2021-04-07 11:44 ` Re: MultiXact\SLRU buffers configuration Andrey Borodin <[email protected]>
2021-04-07 12:13 ` Re: MultiXact\SLRU buffers configuration Andrey Borodin <[email protected]>
2021-04-08 00:30 ` Re: MultiXact\SLRU buffers configuration Thomas Munro <[email protected]>
2021-04-08 07:24 ` Re: MultiXact\SLRU buffers configuration Andrey Borodin <[email protected]>
2021-04-08 12:22 ` Re: MultiXact\SLRU buffers configuration Thomas Munro <[email protected]>
2022-07-21 13:00 ` Re: MultiXact\SLRU buffers configuration Yura Sokolov <[email protected]>
2022-07-23 08:39 ` Re: MultiXact\SLRU buffers configuration Andrey Borodin <[email protected]>
@ 2022-08-16 19:36 ` [email protected]
2022-08-18 03:35 ` Re: MultiXact\SLRU buffers configuration Andrey Borodin <[email protected]>
1 sibling, 1 reply; 90+ messages in thread
From: [email protected] @ 2022-08-16 19:36 UTC (permalink / raw)
To: Andrey Borodin <[email protected]>; +Cc: Yura Sokolov <[email protected]>; Andres Freund <[email protected]>; Thomas Munro <[email protected]>; Gilles Darold <[email protected]>; Tomas Vondra <[email protected]>; Tomas Vondra <[email protected]>; Alexander Korotkov <[email protected]>; Anastasia Lubennikova <[email protected]>; Daniel Gustafsson <[email protected]>; Kyotaro Horiguchi <[email protected]>; pgsql-hackers
> Andrey Borodin wrote 2022-07-23 11:39:
>
> Yura, thank you for your benchmarks!
> We already knew that patch can save the day on pathological workloads,
> now we have a proof of this.
> Also there's the evidence that user can blindly increase size of SLRU
> if they want (with the second patch). So there's no need for hard
> explanations on how to tune the buffers size.
Hi @Andrey.Borodin, With some considerations and performance checks from
@Yura.Sokolov we simplified your approach by the following:
1. Preamble. We feel free to increase any SLRU's, since there's no
performance degradation on large Buffers count using your SLRU buckets
solution.
2. `slru_buffers_size_scale` is only one config param introduced for all
SLRUs. It scales SLRUs upper cap by power 2.
3. All SLRU buffers count are capped by both `MBuffers (shared_buffers)`
and `slru_buffers_size_scale`. see
4. Magic initial constants `NUM_*_BUFFERS << slru_buffers_size_scale`
are applied for every SLRU.
5. All SLRU buffers are always sized as power of 2, their hash bucket
size is always 8.
There's attached patch for your consideration. It does gather and
simplify both `v21-0001-Make-all-SLRU-buffer-sizes-configurable.patch`
and `v21-0002-Divide-SLRU-buffers-into-8-associative-banks.patch` to
much simpler approach.
Thank you, Yours,
- Ivan
Attachments:
[text/x-diff] v22-0006-bucketed-SLRUs-simplified_patch.patch (18.0K, ../../[email protected]/2-v22-0006-bucketed-SLRUs-simplified_patch.patch)
download | inline diff:
Index: src/include/miscadmin.h
IDEA additional info:
Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP
<+>UTF-8
===================================================================
diff --git a/src/include/miscadmin.h b/src/include/miscadmin.h
--- a/src/include/miscadmin.h (revision 020258fbd30d37ddd03d0ec68264d1544f8d2838)
+++ b/src/include/miscadmin.h (date 1660678108730)
@@ -176,6 +176,7 @@
extern PGDLLIMPORT int MaxConnections;
extern PGDLLIMPORT int max_worker_processes;
extern PGDLLIMPORT int max_parallel_workers;
+extern PGDLLIMPORT int slru_buffers_size_scale;
extern PGDLLIMPORT int MyProcPid;
extern PGDLLIMPORT pg_time_t MyStartTime;
Index: src/include/access/subtrans.h
IDEA additional info:
Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP
<+>UTF-8
===================================================================
diff --git a/src/include/access/subtrans.h b/src/include/access/subtrans.h
--- a/src/include/access/subtrans.h (revision 020258fbd30d37ddd03d0ec68264d1544f8d2838)
+++ b/src/include/access/subtrans.h (date 1660678108698)
@@ -12,7 +12,7 @@
#define SUBTRANS_H
/* Number of SLRU buffers to use for subtrans */
-#define NUM_SUBTRANS_BUFFERS 32
+#define NUM_SUBTRANS_BUFFERS (32 << slru_buffers_size_scale)
extern void SubTransSetParent(TransactionId xid, TransactionId parent);
extern TransactionId SubTransGetParent(TransactionId xid);
Index: src/backend/utils/init/globals.c
IDEA additional info:
Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP
<+>UTF-8
===================================================================
diff --git a/src/backend/utils/init/globals.c b/src/backend/utils/init/globals.c
--- a/src/backend/utils/init/globals.c (revision 020258fbd30d37ddd03d0ec68264d1544f8d2838)
+++ b/src/backend/utils/init/globals.c (date 1660678064048)
@@ -150,3 +150,5 @@
int VacuumCostBalance = 0; /* working state for vacuum */
bool VacuumCostActive = false;
+
+int slru_buffers_size_scale = 2; /* power 2 scale for SLRU buffers */
Index: src/backend/access/transam/slru.c
IDEA additional info:
Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP
<+>UTF-8
===================================================================
diff --git a/src/backend/access/transam/slru.c b/src/backend/access/transam/slru.c
--- a/src/backend/access/transam/slru.c (revision 020258fbd30d37ddd03d0ec68264d1544f8d2838)
+++ b/src/backend/access/transam/slru.c (date 1660678063980)
@@ -59,6 +59,7 @@
#include "pgstat.h"
#include "storage/fd.h"
#include "storage/shmem.h"
+#include "port/pg_bitutils.h"
#define SlruFileName(ctl, path, seg) \
snprintf(path, MAXPGPATH, "%s/%04X", (ctl)->Dir, seg)
@@ -71,6 +72,17 @@
*/
#define MAX_WRITEALL_BUFFERS 16
+/*
+ * To avoid overflowing internal arithmetic and the size_t data type, the
+ * number of buffers should not exceed this number.
+ */
+#define SLRU_MAX_ALLOWED_BUFFERS ((1024 * 1024 * 1024) / BLCKSZ)
+
+/*
+ * SLRU bank size for slotno hash banks
+ */
+#define SLRU_BANK_SIZE 8
+
typedef struct SlruWriteAllData
{
int num_files; /* # files actually open */
@@ -134,7 +146,7 @@
static SlruErrorCause slru_errcause;
static int slru_errno;
-
+static void SlruAdjustNSlots(int *nslots, int *bankmask);
static void SimpleLruZeroLSNs(SlruCtl ctl, int slotno);
static void SimpleLruWaitIO(SlruCtl ctl, int slotno);
static void SlruInternalWritePage(SlruCtl ctl, int slotno, SlruWriteAll fdata);
@@ -148,6 +160,25 @@
int segpage, void *data);
static void SlruInternalDeleteSegment(SlruCtl ctl, int segno);
+/*
+ * Pick number of slots and bank size optimal for hashed associative SLRU buffers.
+ * We declare SLRU nslots is always power of 2.
+ * We split SLRU to 8-sized hash banks, after some performance benchmarks.
+ * We hash pageno to banks by pageno masked by 3 upper bits.
+ */
+static void
+SlruAdjustNSlots(int *nslots, int *bankmask)
+{
+ Assert(*nslots > 0);
+ Assert(*nslots <= SLRU_MAX_ALLOWED_BUFFERS);
+
+ *nslots = (int) pg_nextpower2_32(Max(SLRU_BANK_SIZE, Min(*nslots, NBuffers / 256)));
+
+ *bankmask = *nslots / SLRU_BANK_SIZE - 1;
+
+ elog(DEBUG5, "nslots %d banksize %d nbanks %d bankmask %x", *nslots, SLRU_BANK_SIZE, *nslots / SLRU_BANK_SIZE, *bankmask);
+}
+
/*
* Initialization of shared memory
*/
@@ -156,6 +187,9 @@
SimpleLruShmemSize(int nslots, int nlsns)
{
Size sz;
+ int bankmask_ignore;
+
+ SlruAdjustNSlots(&nslots, &bankmask_ignore);
/* we assume nslots isn't so large as to risk overflow */
sz = MAXALIGN(sizeof(SlruSharedData));
@@ -190,6 +224,9 @@
{
SlruShared shared;
bool found;
+ int bankmask;
+
+ SlruAdjustNSlots(&nslots, &bankmask);
shared = (SlruShared) ShmemInitStruct(name,
SimpleLruShmemSize(nslots, nlsns),
@@ -257,7 +294,10 @@
Assert(ptr - (char *) shared <= SimpleLruShmemSize(nslots, nlsns));
}
else
+ {
Assert(found);
+ Assert(shared->num_slots == nslots);
+ }
/*
* Initialize the unshared control struct, including directory path. We
@@ -265,6 +305,7 @@
*/
ctl->shared = shared;
ctl->sync_handler = sync_handler;
+ ctl->bank_mask = bankmask;
strlcpy(ctl->Dir, subdir, sizeof(ctl->Dir));
}
@@ -496,12 +537,14 @@
{
SlruShared shared = ctl->shared;
int slotno;
+ int bankstart = (pageno & ctl->bank_mask) * SLRU_BANK_SIZE;
+ int bankend = bankstart + SLRU_BANK_SIZE;
/* Try to find the page while holding only shared lock */
LWLockAcquire(shared->ControlLock, LW_SHARED);
/* See if page is already in a buffer */
- for (slotno = 0; slotno < shared->num_slots; slotno++)
+ for (slotno = bankstart; slotno < bankend; slotno++)
{
if (shared->page_number[slotno] == pageno &&
shared->page_status[slotno] != SLRU_PAGE_EMPTY &&
@@ -1030,7 +1073,10 @@
int best_invalid_page_number = 0; /* keep compiler quiet */
/* See if page already has a buffer assigned */
- for (slotno = 0; slotno < shared->num_slots; slotno++)
+ int bankstart = (pageno & ctl->bank_mask) * SLRU_BANK_SIZE;
+ int bankend = bankstart + SLRU_BANK_SIZE;
+
+ for (slotno = bankstart; slotno < bankend; slotno++)
{
if (shared->page_number[slotno] == pageno &&
shared->page_status[slotno] != SLRU_PAGE_EMPTY)
@@ -1065,7 +1111,7 @@
* multiple pages with the same lru_count.
*/
cur_count = (shared->cur_lru_count)++;
- for (slotno = 0; slotno < shared->num_slots; slotno++)
+ for (slotno = bankstart; slotno < bankend; slotno++)
{
int this_delta;
int this_page_number;
Index: src/backend/access/transam/clog.c
IDEA additional info:
Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP
<+>UTF-8
===================================================================
diff --git a/src/backend/access/transam/clog.c b/src/backend/access/transam/clog.c
--- a/src/backend/access/transam/clog.c (revision 020258fbd30d37ddd03d0ec68264d1544f8d2838)
+++ b/src/backend/access/transam/clog.c (date 1660677867877)
@@ -74,6 +74,8 @@
#define GetLSNIndex(slotno, xid) ((slotno) * CLOG_LSNS_PER_PAGE + \
((xid) % (TransactionId) CLOG_XACTS_PER_PAGE) / CLOG_XACTS_PER_LSN_GROUP)
+#define NUM_CLOG_BUFFERS (128 << slru_buffers_size_scale)
+
/*
* The number of subtransactions below which we consider to apply clog group
* update optimization. Testing reveals that the number higher than this can
@@ -661,42 +663,20 @@
return status;
}
-/*
- * Number of shared CLOG buffers.
- *
- * On larger multi-processor systems, it is possible to have many CLOG page
- * requests in flight at one time which could lead to disk access for CLOG
- * page if the required page is not found in memory. Testing revealed that we
- * can get the best performance by having 128 CLOG buffers, more than that it
- * doesn't improve performance.
- *
- * Unconditionally keeping the number of CLOG buffers to 128 did not seem like
- * a good idea, because it would increase the minimum amount of shared memory
- * required to start, which could be a problem for people running very small
- * configurations. The following formula seems to represent a reasonable
- * compromise: people with very low values for shared_buffers will get fewer
- * CLOG buffers as well, and everyone else will get 128.
- */
-Size
-CLOGShmemBuffers(void)
-{
- return Min(128, Max(4, NBuffers / 512));
-}
-
/*
* Initialization of shared memory for CLOG
*/
Size
CLOGShmemSize(void)
{
- return SimpleLruShmemSize(CLOGShmemBuffers(), CLOG_LSNS_PER_PAGE);
+ return SimpleLruShmemSize(NUM_CLOG_BUFFERS, CLOG_LSNS_PER_PAGE);
}
void
CLOGShmemInit(void)
{
XactCtl->PagePrecedes = CLOGPagePrecedes;
- SimpleLruInit(XactCtl, "Xact", CLOGShmemBuffers(), CLOG_LSNS_PER_PAGE,
+ SimpleLruInit(XactCtl, "Xact", NUM_CLOG_BUFFERS, CLOG_LSNS_PER_PAGE,
XactSLRULock, "pg_xact", LWTRANCHE_XACT_BUFFER,
SYNC_HANDLER_CLOG);
SlruPagePrecedesUnitTests(XactCtl, CLOG_XACTS_PER_PAGE);
Index: src/include/storage/predicate.h
IDEA additional info:
Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP
<+>UTF-8
===================================================================
diff --git a/src/include/storage/predicate.h b/src/include/storage/predicate.h
--- a/src/include/storage/predicate.h (revision 020258fbd30d37ddd03d0ec68264d1544f8d2838)
+++ b/src/include/storage/predicate.h (date 1660678108718)
@@ -28,7 +28,7 @@
/* Number of SLRU buffers to use for Serial SLRU */
-#define NUM_SERIAL_BUFFERS 16
+#define NUM_SERIAL_BUFFERS (16 << slru_buffers_size_scale)
/*
* A handle used for sharing SERIALIZABLEXACT objects between the participants
Index: src/backend/utils/misc/postgresql.conf.sample
IDEA additional info:
Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP
<+>UTF-8
===================================================================
diff --git a/src/backend/utils/misc/postgresql.conf.sample b/src/backend/utils/misc/postgresql.conf.sample
--- a/src/backend/utils/misc/postgresql.conf.sample (revision 020258fbd30d37ddd03d0ec68264d1544f8d2838)
+++ b/src/backend/utils/misc/postgresql.conf.sample (date 1660678108650)
@@ -155,6 +155,8 @@
# mmap
# (change requires restart)
#min_dynamic_shared_memory = 0MB # (change requires restart)
+#slru_buffers_size_scale = 2 # SLRU buffers size scale of power 2, range 0..7
+ # (change requires restart)
# - Disk -
Index: src/include/access/multixact.h
IDEA additional info:
Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP
<+>UTF-8
===================================================================
diff --git a/src/include/access/multixact.h b/src/include/access/multixact.h
--- a/src/include/access/multixact.h (revision 020258fbd30d37ddd03d0ec68264d1544f8d2838)
+++ b/src/include/access/multixact.h (date 1660678108678)
@@ -30,8 +30,8 @@
#define MaxMultiXactOffset ((MultiXactOffset) 0xFFFFFFFF)
/* Number of SLRU buffers to use for multixact */
-#define NUM_MULTIXACTOFFSET_BUFFERS 8
-#define NUM_MULTIXACTMEMBER_BUFFERS 16
+#define NUM_MULTIXACTOFFSET_BUFFERS (16 << slru_buffers_size_scale)
+#define NUM_MULTIXACTMEMBER_BUFFERS (32 << slru_buffers_size_scale)
/*
* Possible multixact lock modes ("status"). The first four modes are for
Index: src/backend/utils/misc/guc.c
IDEA additional info:
Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP
<+>UTF-8
===================================================================
diff --git a/src/backend/utils/misc/guc.c b/src/backend/utils/misc/guc.c
--- a/src/backend/utils/misc/guc.c (revision 020258fbd30d37ddd03d0ec68264d1544f8d2838)
+++ b/src/backend/utils/misc/guc.c (date 1660678064216)
@@ -32,9 +32,11 @@
#endif
#include <unistd.h>
+#include "access/clog.h"
#include "access/commit_ts.h"
#include "access/gin.h"
#include "access/rmgr.h"
+#include "access/slru.h"
#include "access/tableam.h"
#include "access/toast_compression.h"
#include "access/transam.h"
@@ -2375,6 +2377,16 @@
-1, -1, INT_MAX,
NULL, NULL, NULL
},
+
+ {
+ {"slru_buffers_size_scale", PGC_POSTMASTER, RESOURCES_MEM,
+ gettext_noop("SLRU buffers size scale of power 2"),
+ NULL
+ },
+ &slru_buffers_size_scale,
+ 2, 0, 7,
+ NULL, NULL, NULL
+ },
{
{"temp_buffers", PGC_USERSET, RESOURCES_MEM,
Index: src/include/commands/async.h
IDEA additional info:
Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP
<+>UTF-8
===================================================================
diff --git a/src/include/commands/async.h b/src/include/commands/async.h
--- a/src/include/commands/async.h (revision 020258fbd30d37ddd03d0ec68264d1544f8d2838)
+++ b/src/include/commands/async.h (date 1660678108702)
@@ -18,7 +18,7 @@
/*
* The number of SLRU page buffers we use for the notification queue.
*/
-#define NUM_NOTIFY_BUFFERS 8
+#define NUM_NOTIFY_BUFFERS (16 << slru_buffers_size_scale)
extern bool Trace_notify;
extern volatile sig_atomic_t notifyInterruptPending;
Index: src/include/access/slru.h
IDEA additional info:
Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP
<+>UTF-8
===================================================================
diff --git a/src/include/access/slru.h b/src/include/access/slru.h
--- a/src/include/access/slru.h (revision 020258fbd30d37ddd03d0ec68264d1544f8d2838)
+++ b/src/include/access/slru.h (date 1660678108690)
@@ -134,6 +134,11 @@
* it's always the same, it doesn't need to be in shared memory.
*/
char Dir[64];
+
+ /*
+ * mask for slotno hash bank
+ */
+ Size bank_mask;
} SlruCtlData;
typedef SlruCtlData *SlruCtl;
Index: src/backend/access/transam/subtrans.c
IDEA additional info:
Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP
<+>UTF-8
===================================================================
diff --git a/src/backend/access/transam/subtrans.c b/src/backend/access/transam/subtrans.c
--- a/src/backend/access/transam/subtrans.c (revision 020258fbd30d37ddd03d0ec68264d1544f8d2838)
+++ b/src/backend/access/transam/subtrans.c (date 1660678064032)
@@ -31,6 +31,7 @@
#include "access/slru.h"
#include "access/subtrans.h"
#include "access/transam.h"
+#include "miscadmin.h"
#include "pg_trace.h"
#include "utils/snapmgr.h"
Index: doc/src/sgml/config.sgml
IDEA additional info:
Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP
<+>UTF-8
===================================================================
diff --git a/doc/src/sgml/config.sgml b/doc/src/sgml/config.sgml
--- a/doc/src/sgml/config.sgml (revision 020258fbd30d37ddd03d0ec68264d1544f8d2838)
+++ b/doc/src/sgml/config.sgml (date 1660677867861)
@@ -1953,6 +1953,37 @@
</listitem>
</varlistentry>
+ <varlistentry id="guc-slru-buffers-size-scale" xreflabel="slru_buffers_size_scale">
+ <term><varname>slru_buffers_size_scale</varname> (<type>integer</type>)
+ <indexterm>
+ <primary><varname>slru_buffers_size_scale</varname> configuration parameter</primary>
+ </indexterm>
+ </term>
+ <listitem>
+ <para>
+ Specifies power 2 scale for all SLRU shared memory buffers sizes. Buffers sizes depends on
+ both <literal>guc_slru_buffers_size_scale</literal> and <literal>shared_buffers</literal> params.
+ </para>
+ <para>
+ This affects on buffers in the list below (see also <xref linkend="pgdata-contents-table"/>):
+ <itemizedlist>
+ <listitem><para><literal>NUM_MULTIXACTOFFSET_BUFFERS = Min(32 << slru_buffers_size_scale, shared_buffers/256)</literal></para></listitem>
+ <listitem><para><literal>NUM_MULTIXACTMEMBER_BUFFERS = Min(64 << slru_buffers_size_scale, shared_buffers/256)</literal></para></listitem>
+ <listitem><para><literal>NUM_SUBTRANS_BUFFERS = Min(64 << slru_buffers_size_scale, shared_buffers/256)</literal></para></listitem>
+ <listitem><para><literal>NUM_NOTIFY_BUFFERS = Min(32 << slru_buffers_size_scale, shared_buffers/256)</literal></para></listitem>
+ <listitem><para><literal>NUM_SERIAL_BUFFERS = Min(32 << slru_buffers_size_scale, shared_buffers/256)</literal></para></listitem>
+ <listitem><para><literal>NUM_CLOG_BUFFERS = Min(128 << slru_buffers_size_scale, shared_buffers/256)</literal></para></listitem>
+ <listitem><para><literal>NUM_COMMIT_TS_BUFFERS = Min(128 << slru_buffers_size_scale, shared_buffers/256)</literal></para></listitem>
+ </itemizedlist>
+ </para>
+ <para>
+ Value is in <literal>0..7</literal> bounds.
+ The default value is <literal>2</literal>.
+ This parameter can only be set at server start.
+ </para>
+ </listitem>
+ </varlistentry>
+
<varlistentry id="guc-max-stack-depth" xreflabel="max_stack_depth">
<term><varname>max_stack_depth</varname> (<type>integer</type>)
<indexterm>
Index: src/backend/access/transam/commit_ts.c
IDEA additional info:
Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP
<+>UTF-8
===================================================================
diff --git a/src/backend/access/transam/commit_ts.c b/src/backend/access/transam/commit_ts.c
--- a/src/backend/access/transam/commit_ts.c (revision 020258fbd30d37ddd03d0ec68264d1544f8d2838)
+++ b/src/backend/access/transam/commit_ts.c (date 1660677867889)
@@ -73,6 +73,8 @@
#define TransactionIdToCTsEntry(xid) \
((xid) % (TransactionId) COMMIT_TS_XACTS_PER_PAGE)
+#define NUM_COMMIT_TS_BUFFERS (128 << slru_buffers_size_scale)
+
/*
* Link to shared-memory data structures for CommitTs control
*/
@@ -508,26 +510,13 @@
PG_RETURN_DATUM(HeapTupleGetDatum(htup));
}
-/*
- * Number of shared CommitTS buffers.
- *
- * We use a very similar logic as for the number of CLOG buffers (except we
- * scale up twice as fast with shared buffers, and the maximum is twice as
- * high); see comments in CLOGShmemBuffers.
- */
-Size
-CommitTsShmemBuffers(void)
-{
- return Min(256, Max(4, NBuffers / 256));
-}
-
/*
* Shared memory sizing for CommitTs
*/
Size
CommitTsShmemSize(void)
{
- return SimpleLruShmemSize(CommitTsShmemBuffers(), 0) +
+ return SimpleLruShmemSize(NUM_COMMIT_TS_BUFFERS, 0) +
sizeof(CommitTimestampShared);
}
@@ -541,7 +530,7 @@
bool found;
CommitTsCtl->PagePrecedes = CommitTsPagePrecedes;
- SimpleLruInit(CommitTsCtl, "CommitTs", CommitTsShmemBuffers(), 0,
+ SimpleLruInit(CommitTsCtl, "CommitTs", NUM_COMMIT_TS_BUFFERS, 0,
CommitTsSLRULock, "pg_commit_ts",
LWTRANCHE_COMMITTS_BUFFER,
SYNC_HANDLER_COMMIT_TS);
^ permalink raw reply [nested|flat] 90+ messages in thread
* Re: MultiXact\SLRU buffers configuration
2020-05-08 16:36 MultiXact\SLRU buffers configuration Andrey M. Borodin <[email protected]>
2020-05-11 11:17 ` Re: MultiXact\SLRU buffers configuration Andrey M. Borodin <[email protected]>
2020-05-13 18:08 ` Re: MultiXact\SLRU buffers configuration Andrey M. Borodin <[email protected]>
2020-05-14 01:25 ` Re: MultiXact\SLRU buffers configuration Kyotaro Horiguchi <[email protected]>
2020-05-14 05:19 ` Re: MultiXact\SLRU buffers configuration Andrey M. Borodin <[email protected]>
2020-05-14 06:16 ` Re: MultiXact\SLRU buffers configuration Kyotaro Horiguchi <[email protected]>
2020-05-14 06:44 ` Re: MultiXact\SLRU buffers configuration Andrey M. Borodin <[email protected]>
2020-05-15 00:03 ` Re: MultiXact\SLRU buffers configuration Kyotaro Horiguchi <[email protected]>
2020-07-02 12:02 ` Re: MultiXact\SLRU buffers configuration Daniel Gustafsson <[email protected]>
2020-07-08 07:03 ` Re: MultiXact\SLRU buffers configuration Andrey M. Borodin <[email protected]>
2020-08-28 18:08 ` Re: MultiXact\SLRU buffers configuration Anastasia Lubennikova <[email protected]>
2020-09-28 14:41 ` Re: MultiXact\SLRU buffers configuration Andrey M. Borodin <[email protected]>
2020-10-26 01:05 ` Re: MultiXact\SLRU buffers configuration Alexander Korotkov <[email protected]>
2020-10-26 15:45 ` Re: MultiXact\SLRU buffers configuration Andrey Borodin <[email protected]>
2020-10-27 17:02 ` Re: MultiXact\SLRU buffers configuration Alexander Korotkov <[email protected]>
2020-10-27 17:23 ` Re: MultiXact\SLRU buffers configuration Alexander Korotkov <[email protected]>
2020-10-28 01:36 ` Re: MultiXact\SLRU buffers configuration Tomas Vondra <[email protected]>
2020-10-28 07:34 ` Re: MultiXact\SLRU buffers configuration Andrey Borodin <[email protected]>
2020-10-28 23:32 ` Re: MultiXact\SLRU buffers configuration Tomas Vondra <[email protected]>
2020-10-29 07:08 ` Re: MultiXact\SLRU buffers configuration Andrey Borodin <[email protected]>
2020-10-29 13:49 ` Re: MultiXact\SLRU buffers configuration Tomas Vondra <[email protected]>
2020-11-02 12:45 ` Re: MultiXact\SLRU buffers configuration Andrey Borodin <[email protected]>
2020-11-10 00:13 ` Re: MultiXact\SLRU buffers configuration Tomas Vondra <[email protected]>
2020-11-10 06:16 ` Re: MultiXact\SLRU buffers configuration Andrey Borodin <[email protected]>
2020-11-10 18:07 ` Re: MultiXact\SLRU buffers configuration Tomas Vondra <[email protected]>
2020-11-13 11:49 ` Re: MultiXact\SLRU buffers configuration Andrey Borodin <[email protected]>
2020-12-08 16:05 ` Re: MultiXact\SLRU buffers configuration Gilles Darold <[email protected]>
2020-12-08 17:52 ` Re: MultiXact\SLRU buffers configuration Andrey Borodin <[email protected]>
2020-12-10 14:45 ` Re: MultiXact\SLRU buffers configuration Gilles Darold <[email protected]>
2020-12-11 17:50 ` Re: MultiXact\SLRU buffers configuration Gilles Darold <[email protected]>
2020-12-13 09:17 ` Re: MultiXact\SLRU buffers configuration Gilles Darold <[email protected]>
2020-12-13 17:24 ` Re: MultiXact\SLRU buffers configuration Andrey Borodin <[email protected]>
2020-12-23 16:31 ` Re: MultiXact\SLRU buffers configuration Gilles Darold <[email protected]>
2021-02-15 17:17 ` Re: MultiXact\SLRU buffers configuration Andrey Borodin <[email protected]>
2021-03-11 15:50 ` Re: MultiXact\SLRU buffers configuration Gilles Darold <[email protected]>
2021-03-12 12:44 ` Re: MultiXact\SLRU buffers configuration Andrey Borodin <[email protected]>
2021-03-24 21:31 ` Re: MultiXact\SLRU buffers configuration Thomas Munro <[email protected]>
2021-03-25 01:03 ` Re: MultiXact\SLRU buffers configuration Thomas Munro <[email protected]>
2021-03-26 03:46 ` Re: MultiXact\SLRU buffers configuration Thomas Munro <[email protected]>
2021-03-26 06:00 ` Re: MultiXact\SLRU buffers configuration Andrey Borodin <[email protected]>
2021-03-26 15:52 ` Re: MultiXact\SLRU buffers configuration Andrey Borodin <[email protected]>
2021-03-26 20:26 ` Re: MultiXact\SLRU buffers configuration Thomas Munro <[email protected]>
2021-03-27 05:31 ` Re: MultiXact\SLRU buffers configuration Andrey Borodin <[email protected]>
2021-03-28 21:15 ` Re: MultiXact\SLRU buffers configuration Thomas Munro <[email protected]>
2021-03-29 08:26 ` Re: MultiXact\SLRU buffers configuration Andrey Borodin <[email protected]>
2021-03-31 21:09 ` Re: MultiXact\SLRU buffers configuration Andrey Borodin <[email protected]>
2021-04-01 03:40 ` Re: MultiXact\SLRU buffers configuration Thomas Munro <[email protected]>
2021-04-03 19:57 ` Re: MultiXact\SLRU buffers configuration Andrey Borodin <[email protected]>
2021-04-07 05:59 ` Re: MultiXact\SLRU buffers configuration Thomas Munro <[email protected]>
2021-04-07 11:44 ` Re: MultiXact\SLRU buffers configuration Andrey Borodin <[email protected]>
2021-04-07 12:13 ` Re: MultiXact\SLRU buffers configuration Andrey Borodin <[email protected]>
2021-04-08 00:30 ` Re: MultiXact\SLRU buffers configuration Thomas Munro <[email protected]>
2021-04-08 07:24 ` Re: MultiXact\SLRU buffers configuration Andrey Borodin <[email protected]>
2021-04-08 12:22 ` Re: MultiXact\SLRU buffers configuration Thomas Munro <[email protected]>
2022-07-21 13:00 ` Re: MultiXact\SLRU buffers configuration Yura Sokolov <[email protected]>
2022-07-23 08:39 ` Re: MultiXact\SLRU buffers configuration Andrey Borodin <[email protected]>
2022-08-16 19:36 ` Re: MultiXact\SLRU buffers configuration [email protected]
@ 2022-08-18 03:35 ` Andrey Borodin <[email protected]>
2022-08-19 15:48 ` Re: MultiXact\SLRU buffers configuration [email protected]
0 siblings, 1 reply; 90+ messages in thread
From: Andrey Borodin @ 2022-08-18 03:35 UTC (permalink / raw)
To: [email protected]; +Cc: Yura Sokolov <[email protected]>; Andres Freund <[email protected]>; Thomas Munro <[email protected]>; Gilles Darold <[email protected]>; Tomas Vondra <[email protected]>; Tomas Vondra <[email protected]>; Alexander Korotkov <[email protected]>; Anastasia Lubennikova <[email protected]>; Daniel Gustafsson <[email protected]>; Kyotaro Horiguchi <[email protected]>; pgsql-hackers
> On 17 Aug 2022, at 00:36, [email protected] wrote:
>
>> Andrey Borodin wrote 2022-07-23 11:39:
>> Yura, thank you for your benchmarks!
>> We already knew that patch can save the day on pathological workloads,
>> now we have a proof of this.
>> Also there's the evidence that user can blindly increase size of SLRU
>> if they want (with the second patch). So there's no need for hard
>> explanations on how to tune the buffers size.
>
> Hi @Andrey.Borodin, With some considerations and performance checks from @Yura.Sokolov we simplified your approach by the following:
>
> 1. Preamble. We feel free to increase any SLRU's, since there's no performance degradation on large Buffers count using your SLRU buckets solution.
> 2. `slru_buffers_size_scale` is only one config param introduced for all SLRUs. It scales SLRUs upper cap by power 2.
> 3. All SLRU buffers count are capped by both `MBuffers (shared_buffers)` and `slru_buffers_size_scale`. see
> 4. Magic initial constants `NUM_*_BUFFERS << slru_buffers_size_scale` are applied for every SLRU.
> 5. All SLRU buffers are always sized as power of 2, their hash bucket size is always 8.
>
> There's attached patch for your consideration. It does gather and simplify both `v21-0001-Make-all-SLRU-buffer-sizes-configurable.patch` and `v21-0002-Divide-SLRU-buffers-into-8-associative-banks.patch` to much simpler approach.
I like the idea of one knob instead of one per each SLRU. Maybe we even could deduce sane value from NBuffers? That would effectively lead to 0 knobs :)
Your patch have a prefix "v22-0006", does it mean there are 5 previous steps of the patchset?
Thank you!
Best regards, Andrey Borodin.
^ permalink raw reply [nested|flat] 90+ messages in thread
* Re: MultiXact\SLRU buffers configuration
2020-05-08 16:36 MultiXact\SLRU buffers configuration Andrey M. Borodin <[email protected]>
2020-05-11 11:17 ` Re: MultiXact\SLRU buffers configuration Andrey M. Borodin <[email protected]>
2020-05-13 18:08 ` Re: MultiXact\SLRU buffers configuration Andrey M. Borodin <[email protected]>
2020-05-14 01:25 ` Re: MultiXact\SLRU buffers configuration Kyotaro Horiguchi <[email protected]>
2020-05-14 05:19 ` Re: MultiXact\SLRU buffers configuration Andrey M. Borodin <[email protected]>
2020-05-14 06:16 ` Re: MultiXact\SLRU buffers configuration Kyotaro Horiguchi <[email protected]>
2020-05-14 06:44 ` Re: MultiXact\SLRU buffers configuration Andrey M. Borodin <[email protected]>
2020-05-15 00:03 ` Re: MultiXact\SLRU buffers configuration Kyotaro Horiguchi <[email protected]>
2020-07-02 12:02 ` Re: MultiXact\SLRU buffers configuration Daniel Gustafsson <[email protected]>
2020-07-08 07:03 ` Re: MultiXact\SLRU buffers configuration Andrey M. Borodin <[email protected]>
2020-08-28 18:08 ` Re: MultiXact\SLRU buffers configuration Anastasia Lubennikova <[email protected]>
2020-09-28 14:41 ` Re: MultiXact\SLRU buffers configuration Andrey M. Borodin <[email protected]>
2020-10-26 01:05 ` Re: MultiXact\SLRU buffers configuration Alexander Korotkov <[email protected]>
2020-10-26 15:45 ` Re: MultiXact\SLRU buffers configuration Andrey Borodin <[email protected]>
2020-10-27 17:02 ` Re: MultiXact\SLRU buffers configuration Alexander Korotkov <[email protected]>
2020-10-27 17:23 ` Re: MultiXact\SLRU buffers configuration Alexander Korotkov <[email protected]>
2020-10-28 01:36 ` Re: MultiXact\SLRU buffers configuration Tomas Vondra <[email protected]>
2020-10-28 07:34 ` Re: MultiXact\SLRU buffers configuration Andrey Borodin <[email protected]>
2020-10-28 23:32 ` Re: MultiXact\SLRU buffers configuration Tomas Vondra <[email protected]>
2020-10-29 07:08 ` Re: MultiXact\SLRU buffers configuration Andrey Borodin <[email protected]>
2020-10-29 13:49 ` Re: MultiXact\SLRU buffers configuration Tomas Vondra <[email protected]>
2020-11-02 12:45 ` Re: MultiXact\SLRU buffers configuration Andrey Borodin <[email protected]>
2020-11-10 00:13 ` Re: MultiXact\SLRU buffers configuration Tomas Vondra <[email protected]>
2020-11-10 06:16 ` Re: MultiXact\SLRU buffers configuration Andrey Borodin <[email protected]>
2020-11-10 18:07 ` Re: MultiXact\SLRU buffers configuration Tomas Vondra <[email protected]>
2020-11-13 11:49 ` Re: MultiXact\SLRU buffers configuration Andrey Borodin <[email protected]>
2020-12-08 16:05 ` Re: MultiXact\SLRU buffers configuration Gilles Darold <[email protected]>
2020-12-08 17:52 ` Re: MultiXact\SLRU buffers configuration Andrey Borodin <[email protected]>
2020-12-10 14:45 ` Re: MultiXact\SLRU buffers configuration Gilles Darold <[email protected]>
2020-12-11 17:50 ` Re: MultiXact\SLRU buffers configuration Gilles Darold <[email protected]>
2020-12-13 09:17 ` Re: MultiXact\SLRU buffers configuration Gilles Darold <[email protected]>
2020-12-13 17:24 ` Re: MultiXact\SLRU buffers configuration Andrey Borodin <[email protected]>
2020-12-23 16:31 ` Re: MultiXact\SLRU buffers configuration Gilles Darold <[email protected]>
2021-02-15 17:17 ` Re: MultiXact\SLRU buffers configuration Andrey Borodin <[email protected]>
2021-03-11 15:50 ` Re: MultiXact\SLRU buffers configuration Gilles Darold <[email protected]>
2021-03-12 12:44 ` Re: MultiXact\SLRU buffers configuration Andrey Borodin <[email protected]>
2021-03-24 21:31 ` Re: MultiXact\SLRU buffers configuration Thomas Munro <[email protected]>
2021-03-25 01:03 ` Re: MultiXact\SLRU buffers configuration Thomas Munro <[email protected]>
2021-03-26 03:46 ` Re: MultiXact\SLRU buffers configuration Thomas Munro <[email protected]>
2021-03-26 06:00 ` Re: MultiXact\SLRU buffers configuration Andrey Borodin <[email protected]>
2021-03-26 15:52 ` Re: MultiXact\SLRU buffers configuration Andrey Borodin <[email protected]>
2021-03-26 20:26 ` Re: MultiXact\SLRU buffers configuration Thomas Munro <[email protected]>
2021-03-27 05:31 ` Re: MultiXact\SLRU buffers configuration Andrey Borodin <[email protected]>
2021-03-28 21:15 ` Re: MultiXact\SLRU buffers configuration Thomas Munro <[email protected]>
2021-03-29 08:26 ` Re: MultiXact\SLRU buffers configuration Andrey Borodin <[email protected]>
2021-03-31 21:09 ` Re: MultiXact\SLRU buffers configuration Andrey Borodin <[email protected]>
2021-04-01 03:40 ` Re: MultiXact\SLRU buffers configuration Thomas Munro <[email protected]>
2021-04-03 19:57 ` Re: MultiXact\SLRU buffers configuration Andrey Borodin <[email protected]>
2021-04-07 05:59 ` Re: MultiXact\SLRU buffers configuration Thomas Munro <[email protected]>
2021-04-07 11:44 ` Re: MultiXact\SLRU buffers configuration Andrey Borodin <[email protected]>
2021-04-07 12:13 ` Re: MultiXact\SLRU buffers configuration Andrey Borodin <[email protected]>
2021-04-08 00:30 ` Re: MultiXact\SLRU buffers configuration Thomas Munro <[email protected]>
2021-04-08 07:24 ` Re: MultiXact\SLRU buffers configuration Andrey Borodin <[email protected]>
2021-04-08 12:22 ` Re: MultiXact\SLRU buffers configuration Thomas Munro <[email protected]>
2022-07-21 13:00 ` Re: MultiXact\SLRU buffers configuration Yura Sokolov <[email protected]>
2022-07-23 08:39 ` Re: MultiXact\SLRU buffers configuration Andrey Borodin <[email protected]>
2022-08-16 19:36 ` Re: MultiXact\SLRU buffers configuration [email protected]
2022-08-18 03:35 ` Re: MultiXact\SLRU buffers configuration Andrey Borodin <[email protected]>
@ 2022-08-19 15:48 ` [email protected]
2024-01-20 03:31 ` Re: MultiXact\SLRU buffers configuration vignesh C <[email protected]>
0 siblings, 1 reply; 90+ messages in thread
From: [email protected] @ 2022-08-19 15:48 UTC (permalink / raw)
To: Andrey Borodin <[email protected]>; +Cc: Yura Sokolov <[email protected]>; Andres Freund <[email protected]>; Thomas Munro <[email protected]>; Gilles Darold <[email protected]>; Tomas Vondra <[email protected]>; Tomas Vondra <[email protected]>; Alexander Korotkov <[email protected]>; Anastasia Lubennikova <[email protected]>; Daniel Gustafsson <[email protected]>; Kyotaro Horiguchi <[email protected]>; pgsql-hackers
Andrey Borodin wrote 2022-08-18 06:35:
>
> I like the idea of one knob instead of one per each SLRU. Maybe we
> even could deduce sane value from NBuffers? That would effectively
> lead to 0 knobs :)
>
> Your patch have a prefix "v22-0006", does it mean there are 5 previous
> steps of the patchset?
>
> Thank you!
>
>
> Best regards, Andrey Borodin.
Not sure it's possible to deduce from NBuffers only.
slru_buffers_scale_shift looks like relief valve for systems with ultra
scaled NBuffers.
Regarding v22-0006 I just tried to choose index unique for this thread
so now it's fixed to 0001 indexing.
Attachments:
[text/x-diff] v23-0001-bucketed-SLRUs-simplified.patch (18.0K, ../../[email protected]/2-v23-0001-bucketed-SLRUs-simplified.patch)
download | inline diff:
Index: src/include/miscadmin.h
IDEA additional info:
Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP
<+>UTF-8
===================================================================
diff --git a/src/include/miscadmin.h b/src/include/miscadmin.h
--- a/src/include/miscadmin.h (revision 020258fbd30d37ddd03d0ec68264d1544f8d2838)
+++ b/src/include/miscadmin.h (date 1660678108730)
@@ -176,6 +176,7 @@
extern PGDLLIMPORT int MaxConnections;
extern PGDLLIMPORT int max_worker_processes;
extern PGDLLIMPORT int max_parallel_workers;
+extern PGDLLIMPORT int slru_buffers_size_scale;
extern PGDLLIMPORT int MyProcPid;
extern PGDLLIMPORT pg_time_t MyStartTime;
Index: src/include/access/subtrans.h
IDEA additional info:
Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP
<+>UTF-8
===================================================================
diff --git a/src/include/access/subtrans.h b/src/include/access/subtrans.h
--- a/src/include/access/subtrans.h (revision 020258fbd30d37ddd03d0ec68264d1544f8d2838)
+++ b/src/include/access/subtrans.h (date 1660678108698)
@@ -12,7 +12,7 @@
#define SUBTRANS_H
/* Number of SLRU buffers to use for subtrans */
-#define NUM_SUBTRANS_BUFFERS 32
+#define NUM_SUBTRANS_BUFFERS (32 << slru_buffers_size_scale)
extern void SubTransSetParent(TransactionId xid, TransactionId parent);
extern TransactionId SubTransGetParent(TransactionId xid);
Index: src/backend/utils/init/globals.c
IDEA additional info:
Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP
<+>UTF-8
===================================================================
diff --git a/src/backend/utils/init/globals.c b/src/backend/utils/init/globals.c
--- a/src/backend/utils/init/globals.c (revision 020258fbd30d37ddd03d0ec68264d1544f8d2838)
+++ b/src/backend/utils/init/globals.c (date 1660678064048)
@@ -150,3 +150,5 @@
int VacuumCostBalance = 0; /* working state for vacuum */
bool VacuumCostActive = false;
+
+int slru_buffers_size_scale = 2; /* power 2 scale for SLRU buffers */
Index: src/backend/access/transam/slru.c
IDEA additional info:
Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP
<+>UTF-8
===================================================================
diff --git a/src/backend/access/transam/slru.c b/src/backend/access/transam/slru.c
--- a/src/backend/access/transam/slru.c (revision 020258fbd30d37ddd03d0ec68264d1544f8d2838)
+++ b/src/backend/access/transam/slru.c (date 1660678063980)
@@ -59,6 +59,7 @@
#include "pgstat.h"
#include "storage/fd.h"
#include "storage/shmem.h"
+#include "port/pg_bitutils.h"
#define SlruFileName(ctl, path, seg) \
snprintf(path, MAXPGPATH, "%s/%04X", (ctl)->Dir, seg)
@@ -71,6 +72,17 @@
*/
#define MAX_WRITEALL_BUFFERS 16
+/*
+ * To avoid overflowing internal arithmetic and the size_t data type, the
+ * number of buffers should not exceed this number.
+ */
+#define SLRU_MAX_ALLOWED_BUFFERS ((1024 * 1024 * 1024) / BLCKSZ)
+
+/*
+ * SLRU bank size for slotno hash banks
+ */
+#define SLRU_BANK_SIZE 8
+
typedef struct SlruWriteAllData
{
int num_files; /* # files actually open */
@@ -134,7 +146,7 @@
static SlruErrorCause slru_errcause;
static int slru_errno;
-
+static void SlruAdjustNSlots(int *nslots, int *bankmask);
static void SimpleLruZeroLSNs(SlruCtl ctl, int slotno);
static void SimpleLruWaitIO(SlruCtl ctl, int slotno);
static void SlruInternalWritePage(SlruCtl ctl, int slotno, SlruWriteAll fdata);
@@ -148,6 +160,25 @@
int segpage, void *data);
static void SlruInternalDeleteSegment(SlruCtl ctl, int segno);
+/*
+ * Pick number of slots and bank size optimal for hashed associative SLRU buffers.
+ * We declare SLRU nslots is always power of 2.
+ * We split SLRU to 8-sized hash banks, after some performance benchmarks.
+ * We hash pageno to banks by pageno masked by 3 upper bits.
+ */
+static void
+SlruAdjustNSlots(int *nslots, int *bankmask)
+{
+ Assert(*nslots > 0);
+ Assert(*nslots <= SLRU_MAX_ALLOWED_BUFFERS);
+
+ *nslots = (int) pg_nextpower2_32(Max(SLRU_BANK_SIZE, Min(*nslots, NBuffers / 256)));
+
+ *bankmask = *nslots / SLRU_BANK_SIZE - 1;
+
+ elog(DEBUG5, "nslots %d banksize %d nbanks %d bankmask %x", *nslots, SLRU_BANK_SIZE, *nslots / SLRU_BANK_SIZE, *bankmask);
+}
+
/*
* Initialization of shared memory
*/
@@ -156,6 +187,9 @@
SimpleLruShmemSize(int nslots, int nlsns)
{
Size sz;
+ int bankmask_ignore;
+
+ SlruAdjustNSlots(&nslots, &bankmask_ignore);
/* we assume nslots isn't so large as to risk overflow */
sz = MAXALIGN(sizeof(SlruSharedData));
@@ -190,6 +224,9 @@
{
SlruShared shared;
bool found;
+ int bankmask;
+
+ SlruAdjustNSlots(&nslots, &bankmask);
shared = (SlruShared) ShmemInitStruct(name,
SimpleLruShmemSize(nslots, nlsns),
@@ -257,7 +294,10 @@
Assert(ptr - (char *) shared <= SimpleLruShmemSize(nslots, nlsns));
}
else
+ {
Assert(found);
+ Assert(shared->num_slots == nslots);
+ }
/*
* Initialize the unshared control struct, including directory path. We
@@ -265,6 +305,7 @@
*/
ctl->shared = shared;
ctl->sync_handler = sync_handler;
+ ctl->bank_mask = bankmask;
strlcpy(ctl->Dir, subdir, sizeof(ctl->Dir));
}
@@ -496,12 +537,14 @@
{
SlruShared shared = ctl->shared;
int slotno;
+ int bankstart = (pageno & ctl->bank_mask) * SLRU_BANK_SIZE;
+ int bankend = bankstart + SLRU_BANK_SIZE;
/* Try to find the page while holding only shared lock */
LWLockAcquire(shared->ControlLock, LW_SHARED);
/* See if page is already in a buffer */
- for (slotno = 0; slotno < shared->num_slots; slotno++)
+ for (slotno = bankstart; slotno < bankend; slotno++)
{
if (shared->page_number[slotno] == pageno &&
shared->page_status[slotno] != SLRU_PAGE_EMPTY &&
@@ -1030,7 +1073,10 @@
int best_invalid_page_number = 0; /* keep compiler quiet */
/* See if page already has a buffer assigned */
- for (slotno = 0; slotno < shared->num_slots; slotno++)
+ int bankstart = (pageno & ctl->bank_mask) * SLRU_BANK_SIZE;
+ int bankend = bankstart + SLRU_BANK_SIZE;
+
+ for (slotno = bankstart; slotno < bankend; slotno++)
{
if (shared->page_number[slotno] == pageno &&
shared->page_status[slotno] != SLRU_PAGE_EMPTY)
@@ -1065,7 +1111,7 @@
* multiple pages with the same lru_count.
*/
cur_count = (shared->cur_lru_count)++;
- for (slotno = 0; slotno < shared->num_slots; slotno++)
+ for (slotno = bankstart; slotno < bankend; slotno++)
{
int this_delta;
int this_page_number;
Index: src/backend/access/transam/clog.c
IDEA additional info:
Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP
<+>UTF-8
===================================================================
diff --git a/src/backend/access/transam/clog.c b/src/backend/access/transam/clog.c
--- a/src/backend/access/transam/clog.c (revision 020258fbd30d37ddd03d0ec68264d1544f8d2838)
+++ b/src/backend/access/transam/clog.c (date 1660677867877)
@@ -74,6 +74,8 @@
#define GetLSNIndex(slotno, xid) ((slotno) * CLOG_LSNS_PER_PAGE + \
((xid) % (TransactionId) CLOG_XACTS_PER_PAGE) / CLOG_XACTS_PER_LSN_GROUP)
+#define NUM_CLOG_BUFFERS (128 << slru_buffers_size_scale)
+
/*
* The number of subtransactions below which we consider to apply clog group
* update optimization. Testing reveals that the number higher than this can
@@ -661,42 +663,20 @@
return status;
}
-/*
- * Number of shared CLOG buffers.
- *
- * On larger multi-processor systems, it is possible to have many CLOG page
- * requests in flight at one time which could lead to disk access for CLOG
- * page if the required page is not found in memory. Testing revealed that we
- * can get the best performance by having 128 CLOG buffers, more than that it
- * doesn't improve performance.
- *
- * Unconditionally keeping the number of CLOG buffers to 128 did not seem like
- * a good idea, because it would increase the minimum amount of shared memory
- * required to start, which could be a problem for people running very small
- * configurations. The following formula seems to represent a reasonable
- * compromise: people with very low values for shared_buffers will get fewer
- * CLOG buffers as well, and everyone else will get 128.
- */
-Size
-CLOGShmemBuffers(void)
-{
- return Min(128, Max(4, NBuffers / 512));
-}
-
/*
* Initialization of shared memory for CLOG
*/
Size
CLOGShmemSize(void)
{
- return SimpleLruShmemSize(CLOGShmemBuffers(), CLOG_LSNS_PER_PAGE);
+ return SimpleLruShmemSize(NUM_CLOG_BUFFERS, CLOG_LSNS_PER_PAGE);
}
void
CLOGShmemInit(void)
{
XactCtl->PagePrecedes = CLOGPagePrecedes;
- SimpleLruInit(XactCtl, "Xact", CLOGShmemBuffers(), CLOG_LSNS_PER_PAGE,
+ SimpleLruInit(XactCtl, "Xact", NUM_CLOG_BUFFERS, CLOG_LSNS_PER_PAGE,
XactSLRULock, "pg_xact", LWTRANCHE_XACT_BUFFER,
SYNC_HANDLER_CLOG);
SlruPagePrecedesUnitTests(XactCtl, CLOG_XACTS_PER_PAGE);
Index: src/include/storage/predicate.h
IDEA additional info:
Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP
<+>UTF-8
===================================================================
diff --git a/src/include/storage/predicate.h b/src/include/storage/predicate.h
--- a/src/include/storage/predicate.h (revision 020258fbd30d37ddd03d0ec68264d1544f8d2838)
+++ b/src/include/storage/predicate.h (date 1660678108718)
@@ -28,7 +28,7 @@
/* Number of SLRU buffers to use for Serial SLRU */
-#define NUM_SERIAL_BUFFERS 16
+#define NUM_SERIAL_BUFFERS (16 << slru_buffers_size_scale)
/*
* A handle used for sharing SERIALIZABLEXACT objects between the participants
Index: src/backend/utils/misc/postgresql.conf.sample
IDEA additional info:
Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP
<+>UTF-8
===================================================================
diff --git a/src/backend/utils/misc/postgresql.conf.sample b/src/backend/utils/misc/postgresql.conf.sample
--- a/src/backend/utils/misc/postgresql.conf.sample (revision 020258fbd30d37ddd03d0ec68264d1544f8d2838)
+++ b/src/backend/utils/misc/postgresql.conf.sample (date 1660678108650)
@@ -155,6 +155,8 @@
# mmap
# (change requires restart)
#min_dynamic_shared_memory = 0MB # (change requires restart)
+#slru_buffers_size_scale = 2 # SLRU buffers size scale of power 2, range 0..7
+ # (change requires restart)
# - Disk -
Index: src/include/access/multixact.h
IDEA additional info:
Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP
<+>UTF-8
===================================================================
diff --git a/src/include/access/multixact.h b/src/include/access/multixact.h
--- a/src/include/access/multixact.h (revision 020258fbd30d37ddd03d0ec68264d1544f8d2838)
+++ b/src/include/access/multixact.h (date 1660678108678)
@@ -30,8 +30,8 @@
#define MaxMultiXactOffset ((MultiXactOffset) 0xFFFFFFFF)
/* Number of SLRU buffers to use for multixact */
-#define NUM_MULTIXACTOFFSET_BUFFERS 8
-#define NUM_MULTIXACTMEMBER_BUFFERS 16
+#define NUM_MULTIXACTOFFSET_BUFFERS (16 << slru_buffers_size_scale)
+#define NUM_MULTIXACTMEMBER_BUFFERS (32 << slru_buffers_size_scale)
/*
* Possible multixact lock modes ("status"). The first four modes are for
Index: src/backend/utils/misc/guc.c
IDEA additional info:
Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP
<+>UTF-8
===================================================================
diff --git a/src/backend/utils/misc/guc.c b/src/backend/utils/misc/guc.c
--- a/src/backend/utils/misc/guc.c (revision 020258fbd30d37ddd03d0ec68264d1544f8d2838)
+++ b/src/backend/utils/misc/guc.c (date 1660678064216)
@@ -32,9 +32,11 @@
#endif
#include <unistd.h>
+#include "access/clog.h"
#include "access/commit_ts.h"
#include "access/gin.h"
#include "access/rmgr.h"
+#include "access/slru.h"
#include "access/tableam.h"
#include "access/toast_compression.h"
#include "access/transam.h"
@@ -2375,6 +2377,16 @@
-1, -1, INT_MAX,
NULL, NULL, NULL
},
+
+ {
+ {"slru_buffers_size_scale", PGC_POSTMASTER, RESOURCES_MEM,
+ gettext_noop("SLRU buffers size scale of power 2"),
+ NULL
+ },
+ &slru_buffers_size_scale,
+ 2, 0, 7,
+ NULL, NULL, NULL
+ },
{
{"temp_buffers", PGC_USERSET, RESOURCES_MEM,
Index: src/include/commands/async.h
IDEA additional info:
Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP
<+>UTF-8
===================================================================
diff --git a/src/include/commands/async.h b/src/include/commands/async.h
--- a/src/include/commands/async.h (revision 020258fbd30d37ddd03d0ec68264d1544f8d2838)
+++ b/src/include/commands/async.h (date 1660678108702)
@@ -18,7 +18,7 @@
/*
* The number of SLRU page buffers we use for the notification queue.
*/
-#define NUM_NOTIFY_BUFFERS 8
+#define NUM_NOTIFY_BUFFERS (16 << slru_buffers_size_scale)
extern bool Trace_notify;
extern volatile sig_atomic_t notifyInterruptPending;
Index: src/include/access/slru.h
IDEA additional info:
Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP
<+>UTF-8
===================================================================
diff --git a/src/include/access/slru.h b/src/include/access/slru.h
--- a/src/include/access/slru.h (revision 020258fbd30d37ddd03d0ec68264d1544f8d2838)
+++ b/src/include/access/slru.h (date 1660678108690)
@@ -134,6 +134,11 @@
* it's always the same, it doesn't need to be in shared memory.
*/
char Dir[64];
+
+ /*
+ * mask for slotno hash bank
+ */
+ Size bank_mask;
} SlruCtlData;
typedef SlruCtlData *SlruCtl;
Index: src/backend/access/transam/subtrans.c
IDEA additional info:
Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP
<+>UTF-8
===================================================================
diff --git a/src/backend/access/transam/subtrans.c b/src/backend/access/transam/subtrans.c
--- a/src/backend/access/transam/subtrans.c (revision 020258fbd30d37ddd03d0ec68264d1544f8d2838)
+++ b/src/backend/access/transam/subtrans.c (date 1660678064032)
@@ -31,6 +31,7 @@
#include "access/slru.h"
#include "access/subtrans.h"
#include "access/transam.h"
+#include "miscadmin.h"
#include "pg_trace.h"
#include "utils/snapmgr.h"
Index: doc/src/sgml/config.sgml
IDEA additional info:
Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP
<+>UTF-8
===================================================================
diff --git a/doc/src/sgml/config.sgml b/doc/src/sgml/config.sgml
--- a/doc/src/sgml/config.sgml (revision 020258fbd30d37ddd03d0ec68264d1544f8d2838)
+++ b/doc/src/sgml/config.sgml (date 1660677867861)
@@ -1953,6 +1953,37 @@
</listitem>
</varlistentry>
+ <varlistentry id="guc-slru-buffers-size-scale" xreflabel="slru_buffers_size_scale">
+ <term><varname>slru_buffers_size_scale</varname> (<type>integer</type>)
+ <indexterm>
+ <primary><varname>slru_buffers_size_scale</varname> configuration parameter</primary>
+ </indexterm>
+ </term>
+ <listitem>
+ <para>
+ Specifies power 2 scale for all SLRU shared memory buffers sizes. Buffers sizes depends on
+ both <literal>guc_slru_buffers_size_scale</literal> and <literal>shared_buffers</literal> params.
+ </para>
+ <para>
+ This affects on buffers in the list below (see also <xref linkend="pgdata-contents-table"/>):
+ <itemizedlist>
+ <listitem><para><literal>NUM_MULTIXACTOFFSET_BUFFERS = Min(32 << slru_buffers_size_scale, shared_buffers/256)</literal></para></listitem>
+ <listitem><para><literal>NUM_MULTIXACTMEMBER_BUFFERS = Min(64 << slru_buffers_size_scale, shared_buffers/256)</literal></para></listitem>
+ <listitem><para><literal>NUM_SUBTRANS_BUFFERS = Min(64 << slru_buffers_size_scale, shared_buffers/256)</literal></para></listitem>
+ <listitem><para><literal>NUM_NOTIFY_BUFFERS = Min(32 << slru_buffers_size_scale, shared_buffers/256)</literal></para></listitem>
+ <listitem><para><literal>NUM_SERIAL_BUFFERS = Min(32 << slru_buffers_size_scale, shared_buffers/256)</literal></para></listitem>
+ <listitem><para><literal>NUM_CLOG_BUFFERS = Min(128 << slru_buffers_size_scale, shared_buffers/256)</literal></para></listitem>
+ <listitem><para><literal>NUM_COMMIT_TS_BUFFERS = Min(128 << slru_buffers_size_scale, shared_buffers/256)</literal></para></listitem>
+ </itemizedlist>
+ </para>
+ <para>
+ Value is in <literal>0..7</literal> bounds.
+ The default value is <literal>2</literal>.
+ This parameter can only be set at server start.
+ </para>
+ </listitem>
+ </varlistentry>
+
<varlistentry id="guc-max-stack-depth" xreflabel="max_stack_depth">
<term><varname>max_stack_depth</varname> (<type>integer</type>)
<indexterm>
Index: src/backend/access/transam/commit_ts.c
IDEA additional info:
Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP
<+>UTF-8
===================================================================
diff --git a/src/backend/access/transam/commit_ts.c b/src/backend/access/transam/commit_ts.c
--- a/src/backend/access/transam/commit_ts.c (revision 020258fbd30d37ddd03d0ec68264d1544f8d2838)
+++ b/src/backend/access/transam/commit_ts.c (date 1660677867889)
@@ -73,6 +73,8 @@
#define TransactionIdToCTsEntry(xid) \
((xid) % (TransactionId) COMMIT_TS_XACTS_PER_PAGE)
+#define NUM_COMMIT_TS_BUFFERS (128 << slru_buffers_size_scale)
+
/*
* Link to shared-memory data structures for CommitTs control
*/
@@ -508,26 +510,13 @@
PG_RETURN_DATUM(HeapTupleGetDatum(htup));
}
-/*
- * Number of shared CommitTS buffers.
- *
- * We use a very similar logic as for the number of CLOG buffers (except we
- * scale up twice as fast with shared buffers, and the maximum is twice as
- * high); see comments in CLOGShmemBuffers.
- */
-Size
-CommitTsShmemBuffers(void)
-{
- return Min(256, Max(4, NBuffers / 256));
-}
-
/*
* Shared memory sizing for CommitTs
*/
Size
CommitTsShmemSize(void)
{
- return SimpleLruShmemSize(CommitTsShmemBuffers(), 0) +
+ return SimpleLruShmemSize(NUM_COMMIT_TS_BUFFERS, 0) +
sizeof(CommitTimestampShared);
}
@@ -541,7 +530,7 @@
bool found;
CommitTsCtl->PagePrecedes = CommitTsPagePrecedes;
- SimpleLruInit(CommitTsCtl, "CommitTs", CommitTsShmemBuffers(), 0,
+ SimpleLruInit(CommitTsCtl, "CommitTs", NUM_COMMIT_TS_BUFFERS, 0,
CommitTsSLRULock, "pg_commit_ts",
LWTRANCHE_COMMITTS_BUFFER,
SYNC_HANDLER_COMMIT_TS);
^ permalink raw reply [nested|flat] 90+ messages in thread
* Re: MultiXact\SLRU buffers configuration
2020-05-08 16:36 MultiXact\SLRU buffers configuration Andrey M. Borodin <[email protected]>
2020-05-11 11:17 ` Re: MultiXact\SLRU buffers configuration Andrey M. Borodin <[email protected]>
2020-05-13 18:08 ` Re: MultiXact\SLRU buffers configuration Andrey M. Borodin <[email protected]>
2020-05-14 01:25 ` Re: MultiXact\SLRU buffers configuration Kyotaro Horiguchi <[email protected]>
2020-05-14 05:19 ` Re: MultiXact\SLRU buffers configuration Andrey M. Borodin <[email protected]>
2020-05-14 06:16 ` Re: MultiXact\SLRU buffers configuration Kyotaro Horiguchi <[email protected]>
2020-05-14 06:44 ` Re: MultiXact\SLRU buffers configuration Andrey M. Borodin <[email protected]>
2020-05-15 00:03 ` Re: MultiXact\SLRU buffers configuration Kyotaro Horiguchi <[email protected]>
2020-07-02 12:02 ` Re: MultiXact\SLRU buffers configuration Daniel Gustafsson <[email protected]>
2020-07-08 07:03 ` Re: MultiXact\SLRU buffers configuration Andrey M. Borodin <[email protected]>
2020-08-28 18:08 ` Re: MultiXact\SLRU buffers configuration Anastasia Lubennikova <[email protected]>
2020-09-28 14:41 ` Re: MultiXact\SLRU buffers configuration Andrey M. Borodin <[email protected]>
2020-10-26 01:05 ` Re: MultiXact\SLRU buffers configuration Alexander Korotkov <[email protected]>
2020-10-26 15:45 ` Re: MultiXact\SLRU buffers configuration Andrey Borodin <[email protected]>
2020-10-27 17:02 ` Re: MultiXact\SLRU buffers configuration Alexander Korotkov <[email protected]>
2020-10-27 17:23 ` Re: MultiXact\SLRU buffers configuration Alexander Korotkov <[email protected]>
2020-10-28 01:36 ` Re: MultiXact\SLRU buffers configuration Tomas Vondra <[email protected]>
2020-10-28 07:34 ` Re: MultiXact\SLRU buffers configuration Andrey Borodin <[email protected]>
2020-10-28 23:32 ` Re: MultiXact\SLRU buffers configuration Tomas Vondra <[email protected]>
2020-10-29 07:08 ` Re: MultiXact\SLRU buffers configuration Andrey Borodin <[email protected]>
2020-10-29 13:49 ` Re: MultiXact\SLRU buffers configuration Tomas Vondra <[email protected]>
2020-11-02 12:45 ` Re: MultiXact\SLRU buffers configuration Andrey Borodin <[email protected]>
2020-11-10 00:13 ` Re: MultiXact\SLRU buffers configuration Tomas Vondra <[email protected]>
2020-11-10 06:16 ` Re: MultiXact\SLRU buffers configuration Andrey Borodin <[email protected]>
2020-11-10 18:07 ` Re: MultiXact\SLRU buffers configuration Tomas Vondra <[email protected]>
2020-11-13 11:49 ` Re: MultiXact\SLRU buffers configuration Andrey Borodin <[email protected]>
2020-12-08 16:05 ` Re: MultiXact\SLRU buffers configuration Gilles Darold <[email protected]>
2020-12-08 17:52 ` Re: MultiXact\SLRU buffers configuration Andrey Borodin <[email protected]>
2020-12-10 14:45 ` Re: MultiXact\SLRU buffers configuration Gilles Darold <[email protected]>
2020-12-11 17:50 ` Re: MultiXact\SLRU buffers configuration Gilles Darold <[email protected]>
2020-12-13 09:17 ` Re: MultiXact\SLRU buffers configuration Gilles Darold <[email protected]>
2020-12-13 17:24 ` Re: MultiXact\SLRU buffers configuration Andrey Borodin <[email protected]>
2020-12-23 16:31 ` Re: MultiXact\SLRU buffers configuration Gilles Darold <[email protected]>
2021-02-15 17:17 ` Re: MultiXact\SLRU buffers configuration Andrey Borodin <[email protected]>
2021-03-11 15:50 ` Re: MultiXact\SLRU buffers configuration Gilles Darold <[email protected]>
2021-03-12 12:44 ` Re: MultiXact\SLRU buffers configuration Andrey Borodin <[email protected]>
2021-03-24 21:31 ` Re: MultiXact\SLRU buffers configuration Thomas Munro <[email protected]>
2021-03-25 01:03 ` Re: MultiXact\SLRU buffers configuration Thomas Munro <[email protected]>
2021-03-26 03:46 ` Re: MultiXact\SLRU buffers configuration Thomas Munro <[email protected]>
2021-03-26 06:00 ` Re: MultiXact\SLRU buffers configuration Andrey Borodin <[email protected]>
2021-03-26 15:52 ` Re: MultiXact\SLRU buffers configuration Andrey Borodin <[email protected]>
2021-03-26 20:26 ` Re: MultiXact\SLRU buffers configuration Thomas Munro <[email protected]>
2021-03-27 05:31 ` Re: MultiXact\SLRU buffers configuration Andrey Borodin <[email protected]>
2021-03-28 21:15 ` Re: MultiXact\SLRU buffers configuration Thomas Munro <[email protected]>
2021-03-29 08:26 ` Re: MultiXact\SLRU buffers configuration Andrey Borodin <[email protected]>
2021-03-31 21:09 ` Re: MultiXact\SLRU buffers configuration Andrey Borodin <[email protected]>
2021-04-01 03:40 ` Re: MultiXact\SLRU buffers configuration Thomas Munro <[email protected]>
2021-04-03 19:57 ` Re: MultiXact\SLRU buffers configuration Andrey Borodin <[email protected]>
2021-04-07 05:59 ` Re: MultiXact\SLRU buffers configuration Thomas Munro <[email protected]>
2021-04-07 11:44 ` Re: MultiXact\SLRU buffers configuration Andrey Borodin <[email protected]>
2021-04-07 12:13 ` Re: MultiXact\SLRU buffers configuration Andrey Borodin <[email protected]>
2021-04-08 00:30 ` Re: MultiXact\SLRU buffers configuration Thomas Munro <[email protected]>
2021-04-08 07:24 ` Re: MultiXact\SLRU buffers configuration Andrey Borodin <[email protected]>
2021-04-08 12:22 ` Re: MultiXact\SLRU buffers configuration Thomas Munro <[email protected]>
2022-07-21 13:00 ` Re: MultiXact\SLRU buffers configuration Yura Sokolov <[email protected]>
2022-07-23 08:39 ` Re: MultiXact\SLRU buffers configuration Andrey Borodin <[email protected]>
2022-08-16 19:36 ` Re: MultiXact\SLRU buffers configuration [email protected]
2022-08-18 03:35 ` Re: MultiXact\SLRU buffers configuration Andrey Borodin <[email protected]>
2022-08-19 15:48 ` Re: MultiXact\SLRU buffers configuration [email protected]
@ 2024-01-20 03:31 ` vignesh C <[email protected]>
2024-01-27 04:58 ` Re: MultiXact\SLRU buffers configuration Andrey Borodin <[email protected]>
0 siblings, 1 reply; 90+ messages in thread
From: vignesh C @ 2024-01-20 03:31 UTC (permalink / raw)
To: Andrey Borodin <[email protected]>; +Cc: [email protected]; Andrey Borodin <[email protected]>; Yura Sokolov <[email protected]>; Andres Freund <[email protected]>; Thomas Munro <[email protected]>; Gilles Darold <[email protected]>; Tomas Vondra <[email protected]>; Tomas Vondra <[email protected]>; Alexander Korotkov <[email protected]>; Anastasia Lubennikova <[email protected]>; Daniel Gustafsson <[email protected]>; Kyotaro Horiguchi <[email protected]>; pgsql-hackers
On Mon, 9 Jan 2023 at 09:49, Andrey Borodin <[email protected]> wrote:
>
> On Tue, Jan 3, 2023 at 5:02 AM vignesh C <[email protected]> wrote:
> > does not apply on top of HEAD as in [1], please post a rebased patch:
> >
> Thanks! Here's the rebase.
I'm seeing that there has been no activity in this thread for more
than 1 year now, I'm planning to close this in the current commitfest
unless someone is planning to take it forward.
Regards,
Vignesh
^ permalink raw reply [nested|flat] 90+ messages in thread
* Re: MultiXact\SLRU buffers configuration
2020-05-08 16:36 MultiXact\SLRU buffers configuration Andrey M. Borodin <[email protected]>
2020-05-11 11:17 ` Re: MultiXact\SLRU buffers configuration Andrey M. Borodin <[email protected]>
2020-05-13 18:08 ` Re: MultiXact\SLRU buffers configuration Andrey M. Borodin <[email protected]>
2020-05-14 01:25 ` Re: MultiXact\SLRU buffers configuration Kyotaro Horiguchi <[email protected]>
2020-05-14 05:19 ` Re: MultiXact\SLRU buffers configuration Andrey M. Borodin <[email protected]>
2020-05-14 06:16 ` Re: MultiXact\SLRU buffers configuration Kyotaro Horiguchi <[email protected]>
2020-05-14 06:44 ` Re: MultiXact\SLRU buffers configuration Andrey M. Borodin <[email protected]>
2020-05-15 00:03 ` Re: MultiXact\SLRU buffers configuration Kyotaro Horiguchi <[email protected]>
2020-07-02 12:02 ` Re: MultiXact\SLRU buffers configuration Daniel Gustafsson <[email protected]>
2020-07-08 07:03 ` Re: MultiXact\SLRU buffers configuration Andrey M. Borodin <[email protected]>
2020-08-28 18:08 ` Re: MultiXact\SLRU buffers configuration Anastasia Lubennikova <[email protected]>
2020-09-28 14:41 ` Re: MultiXact\SLRU buffers configuration Andrey M. Borodin <[email protected]>
2020-10-26 01:05 ` Re: MultiXact\SLRU buffers configuration Alexander Korotkov <[email protected]>
2020-10-26 15:45 ` Re: MultiXact\SLRU buffers configuration Andrey Borodin <[email protected]>
2020-10-27 17:02 ` Re: MultiXact\SLRU buffers configuration Alexander Korotkov <[email protected]>
2020-10-27 17:23 ` Re: MultiXact\SLRU buffers configuration Alexander Korotkov <[email protected]>
2020-10-28 01:36 ` Re: MultiXact\SLRU buffers configuration Tomas Vondra <[email protected]>
2020-10-28 07:34 ` Re: MultiXact\SLRU buffers configuration Andrey Borodin <[email protected]>
2020-10-28 23:32 ` Re: MultiXact\SLRU buffers configuration Tomas Vondra <[email protected]>
2020-10-29 07:08 ` Re: MultiXact\SLRU buffers configuration Andrey Borodin <[email protected]>
2020-10-29 13:49 ` Re: MultiXact\SLRU buffers configuration Tomas Vondra <[email protected]>
2020-11-02 12:45 ` Re: MultiXact\SLRU buffers configuration Andrey Borodin <[email protected]>
2020-11-10 00:13 ` Re: MultiXact\SLRU buffers configuration Tomas Vondra <[email protected]>
2020-11-10 06:16 ` Re: MultiXact\SLRU buffers configuration Andrey Borodin <[email protected]>
2020-11-10 18:07 ` Re: MultiXact\SLRU buffers configuration Tomas Vondra <[email protected]>
2020-11-13 11:49 ` Re: MultiXact\SLRU buffers configuration Andrey Borodin <[email protected]>
2020-12-08 16:05 ` Re: MultiXact\SLRU buffers configuration Gilles Darold <[email protected]>
2020-12-08 17:52 ` Re: MultiXact\SLRU buffers configuration Andrey Borodin <[email protected]>
2020-12-10 14:45 ` Re: MultiXact\SLRU buffers configuration Gilles Darold <[email protected]>
2020-12-11 17:50 ` Re: MultiXact\SLRU buffers configuration Gilles Darold <[email protected]>
2020-12-13 09:17 ` Re: MultiXact\SLRU buffers configuration Gilles Darold <[email protected]>
2020-12-13 17:24 ` Re: MultiXact\SLRU buffers configuration Andrey Borodin <[email protected]>
2020-12-23 16:31 ` Re: MultiXact\SLRU buffers configuration Gilles Darold <[email protected]>
2021-02-15 17:17 ` Re: MultiXact\SLRU buffers configuration Andrey Borodin <[email protected]>
2021-03-11 15:50 ` Re: MultiXact\SLRU buffers configuration Gilles Darold <[email protected]>
2021-03-12 12:44 ` Re: MultiXact\SLRU buffers configuration Andrey Borodin <[email protected]>
2021-03-24 21:31 ` Re: MultiXact\SLRU buffers configuration Thomas Munro <[email protected]>
2021-03-25 01:03 ` Re: MultiXact\SLRU buffers configuration Thomas Munro <[email protected]>
2021-03-26 03:46 ` Re: MultiXact\SLRU buffers configuration Thomas Munro <[email protected]>
2021-03-26 06:00 ` Re: MultiXact\SLRU buffers configuration Andrey Borodin <[email protected]>
2021-03-26 15:52 ` Re: MultiXact\SLRU buffers configuration Andrey Borodin <[email protected]>
2021-03-26 20:26 ` Re: MultiXact\SLRU buffers configuration Thomas Munro <[email protected]>
2021-03-27 05:31 ` Re: MultiXact\SLRU buffers configuration Andrey Borodin <[email protected]>
2021-03-28 21:15 ` Re: MultiXact\SLRU buffers configuration Thomas Munro <[email protected]>
2021-03-29 08:26 ` Re: MultiXact\SLRU buffers configuration Andrey Borodin <[email protected]>
2021-03-31 21:09 ` Re: MultiXact\SLRU buffers configuration Andrey Borodin <[email protected]>
2021-04-01 03:40 ` Re: MultiXact\SLRU buffers configuration Thomas Munro <[email protected]>
2021-04-03 19:57 ` Re: MultiXact\SLRU buffers configuration Andrey Borodin <[email protected]>
2021-04-07 05:59 ` Re: MultiXact\SLRU buffers configuration Thomas Munro <[email protected]>
2021-04-07 11:44 ` Re: MultiXact\SLRU buffers configuration Andrey Borodin <[email protected]>
2021-04-07 12:13 ` Re: MultiXact\SLRU buffers configuration Andrey Borodin <[email protected]>
2021-04-08 00:30 ` Re: MultiXact\SLRU buffers configuration Thomas Munro <[email protected]>
2021-04-08 07:24 ` Re: MultiXact\SLRU buffers configuration Andrey Borodin <[email protected]>
2021-04-08 12:22 ` Re: MultiXact\SLRU buffers configuration Thomas Munro <[email protected]>
2022-07-21 13:00 ` Re: MultiXact\SLRU buffers configuration Yura Sokolov <[email protected]>
2022-07-23 08:39 ` Re: MultiXact\SLRU buffers configuration Andrey Borodin <[email protected]>
2022-08-16 19:36 ` Re: MultiXact\SLRU buffers configuration [email protected]
2022-08-18 03:35 ` Re: MultiXact\SLRU buffers configuration Andrey Borodin <[email protected]>
2022-08-19 15:48 ` Re: MultiXact\SLRU buffers configuration [email protected]
2024-01-20 03:31 ` Re: MultiXact\SLRU buffers configuration vignesh C <[email protected]>
@ 2024-01-27 04:58 ` Andrey Borodin <[email protected]>
2024-01-28 12:49 ` Re: MultiXact\SLRU buffers configuration Alvaro Herrera <[email protected]>
0 siblings, 1 reply; 90+ messages in thread
From: Andrey Borodin @ 2024-01-27 04:58 UTC (permalink / raw)
To: vignesh C <[email protected]>; +Cc: Andrew Borodin <[email protected]>; [email protected]; Yura Sokolov <[email protected]>; Andres Freund <[email protected]>; Thomas Munro <[email protected]>; Gilles Darold <[email protected]>; Tomas Vondra <[email protected]>; Tomas Vondra <[email protected]>; Alexander Korotkov <[email protected]>; Anastasia Lubennikova <[email protected]>; Daniel Gustafsson <[email protected]>; Kyotaro Horiguchi <[email protected]>; pgsql-hackers
> On 20 Jan 2024, at 08:31, vignesh C <[email protected]> wrote:
>
> On Mon, 9 Jan 2023 at 09:49, Andrey Borodin <[email protected]> wrote:
>>
>> On Tue, Jan 3, 2023 at 5:02 AM vignesh C <[email protected]> wrote:
>>> does not apply on top of HEAD as in [1], please post a rebased patch:
>>>
>> Thanks! Here's the rebase.
>
> I'm seeing that there has been no activity in this thread for more
> than 1 year now, I'm planning to close this in the current commitfest
> unless someone is planning to take it forward.
Hi Vignesh,
thanks for the ping! Most important parts of this patch set are discussed in [0]. If that patchset will be committed, I'll withdraw entry for this thread from commitfest.
There's a version of Multixact-specific optimizations [1], but I hope they will not be necessary with effective caches developed in [0]. It seems to me that most important part of those optimization is removing sleeps under SLRU lock on standby [2] by Kyotaro Horiguchi. But given that cache optimizations took 4 years to get closer to commit, I'm not sure we will get this optimization any time soon...
Thanks!
Best regards, Andrey Borodin.
[0] https://www.postgresql.org/message-id/flat/CAFiTN-vzDvNz%3DExGXz6gdyjtzGixKSqs0mKHMmaQ8sOSEFZ33A%40m...
[1] https://www.postgresql.org/message-id/flat/2ECE132B-C042-4489-930E-DBC5D0DAB84A%40yandex-team.ru#5f7...
[2] https://www.postgresql.org/message-id/flat/20200515.090333.24867479329066911.horikyota.ntt%40gmail.c...
^ permalink raw reply [nested|flat] 90+ messages in thread
* Re: MultiXact\SLRU buffers configuration
2020-05-08 16:36 MultiXact\SLRU buffers configuration Andrey M. Borodin <[email protected]>
2020-05-11 11:17 ` Re: MultiXact\SLRU buffers configuration Andrey M. Borodin <[email protected]>
2020-05-13 18:08 ` Re: MultiXact\SLRU buffers configuration Andrey M. Borodin <[email protected]>
2020-05-14 01:25 ` Re: MultiXact\SLRU buffers configuration Kyotaro Horiguchi <[email protected]>
2020-05-14 05:19 ` Re: MultiXact\SLRU buffers configuration Andrey M. Borodin <[email protected]>
2020-05-14 06:16 ` Re: MultiXact\SLRU buffers configuration Kyotaro Horiguchi <[email protected]>
2020-05-14 06:44 ` Re: MultiXact\SLRU buffers configuration Andrey M. Borodin <[email protected]>
2020-05-15 00:03 ` Re: MultiXact\SLRU buffers configuration Kyotaro Horiguchi <[email protected]>
2020-07-02 12:02 ` Re: MultiXact\SLRU buffers configuration Daniel Gustafsson <[email protected]>
2020-07-08 07:03 ` Re: MultiXact\SLRU buffers configuration Andrey M. Borodin <[email protected]>
2020-08-28 18:08 ` Re: MultiXact\SLRU buffers configuration Anastasia Lubennikova <[email protected]>
2020-09-28 14:41 ` Re: MultiXact\SLRU buffers configuration Andrey M. Borodin <[email protected]>
2020-10-26 01:05 ` Re: MultiXact\SLRU buffers configuration Alexander Korotkov <[email protected]>
2020-10-26 15:45 ` Re: MultiXact\SLRU buffers configuration Andrey Borodin <[email protected]>
2020-10-27 17:02 ` Re: MultiXact\SLRU buffers configuration Alexander Korotkov <[email protected]>
2020-10-27 17:23 ` Re: MultiXact\SLRU buffers configuration Alexander Korotkov <[email protected]>
2020-10-28 01:36 ` Re: MultiXact\SLRU buffers configuration Tomas Vondra <[email protected]>
2020-10-28 07:34 ` Re: MultiXact\SLRU buffers configuration Andrey Borodin <[email protected]>
2020-10-28 23:32 ` Re: MultiXact\SLRU buffers configuration Tomas Vondra <[email protected]>
2020-10-29 07:08 ` Re: MultiXact\SLRU buffers configuration Andrey Borodin <[email protected]>
2020-10-29 13:49 ` Re: MultiXact\SLRU buffers configuration Tomas Vondra <[email protected]>
2020-11-02 12:45 ` Re: MultiXact\SLRU buffers configuration Andrey Borodin <[email protected]>
2020-11-10 00:13 ` Re: MultiXact\SLRU buffers configuration Tomas Vondra <[email protected]>
2020-11-10 06:16 ` Re: MultiXact\SLRU buffers configuration Andrey Borodin <[email protected]>
2020-11-10 18:07 ` Re: MultiXact\SLRU buffers configuration Tomas Vondra <[email protected]>
2020-11-13 11:49 ` Re: MultiXact\SLRU buffers configuration Andrey Borodin <[email protected]>
2020-12-08 16:05 ` Re: MultiXact\SLRU buffers configuration Gilles Darold <[email protected]>
2020-12-08 17:52 ` Re: MultiXact\SLRU buffers configuration Andrey Borodin <[email protected]>
2020-12-10 14:45 ` Re: MultiXact\SLRU buffers configuration Gilles Darold <[email protected]>
2020-12-11 17:50 ` Re: MultiXact\SLRU buffers configuration Gilles Darold <[email protected]>
2020-12-13 09:17 ` Re: MultiXact\SLRU buffers configuration Gilles Darold <[email protected]>
2020-12-13 17:24 ` Re: MultiXact\SLRU buffers configuration Andrey Borodin <[email protected]>
2020-12-23 16:31 ` Re: MultiXact\SLRU buffers configuration Gilles Darold <[email protected]>
2021-02-15 17:17 ` Re: MultiXact\SLRU buffers configuration Andrey Borodin <[email protected]>
2021-03-11 15:50 ` Re: MultiXact\SLRU buffers configuration Gilles Darold <[email protected]>
2021-03-12 12:44 ` Re: MultiXact\SLRU buffers configuration Andrey Borodin <[email protected]>
2021-03-24 21:31 ` Re: MultiXact\SLRU buffers configuration Thomas Munro <[email protected]>
2021-03-25 01:03 ` Re: MultiXact\SLRU buffers configuration Thomas Munro <[email protected]>
2021-03-26 03:46 ` Re: MultiXact\SLRU buffers configuration Thomas Munro <[email protected]>
2021-03-26 06:00 ` Re: MultiXact\SLRU buffers configuration Andrey Borodin <[email protected]>
2021-03-26 15:52 ` Re: MultiXact\SLRU buffers configuration Andrey Borodin <[email protected]>
2021-03-26 20:26 ` Re: MultiXact\SLRU buffers configuration Thomas Munro <[email protected]>
2021-03-27 05:31 ` Re: MultiXact\SLRU buffers configuration Andrey Borodin <[email protected]>
2021-03-28 21:15 ` Re: MultiXact\SLRU buffers configuration Thomas Munro <[email protected]>
2021-03-29 08:26 ` Re: MultiXact\SLRU buffers configuration Andrey Borodin <[email protected]>
2021-03-31 21:09 ` Re: MultiXact\SLRU buffers configuration Andrey Borodin <[email protected]>
2021-04-01 03:40 ` Re: MultiXact\SLRU buffers configuration Thomas Munro <[email protected]>
2021-04-03 19:57 ` Re: MultiXact\SLRU buffers configuration Andrey Borodin <[email protected]>
2021-04-07 05:59 ` Re: MultiXact\SLRU buffers configuration Thomas Munro <[email protected]>
2021-04-07 11:44 ` Re: MultiXact\SLRU buffers configuration Andrey Borodin <[email protected]>
2021-04-07 12:13 ` Re: MultiXact\SLRU buffers configuration Andrey Borodin <[email protected]>
2021-04-08 00:30 ` Re: MultiXact\SLRU buffers configuration Thomas Munro <[email protected]>
2021-04-08 07:24 ` Re: MultiXact\SLRU buffers configuration Andrey Borodin <[email protected]>
2021-04-08 12:22 ` Re: MultiXact\SLRU buffers configuration Thomas Munro <[email protected]>
2022-07-21 13:00 ` Re: MultiXact\SLRU buffers configuration Yura Sokolov <[email protected]>
2022-07-23 08:39 ` Re: MultiXact\SLRU buffers configuration Andrey Borodin <[email protected]>
2022-08-16 19:36 ` Re: MultiXact\SLRU buffers configuration [email protected]
2022-08-18 03:35 ` Re: MultiXact\SLRU buffers configuration Andrey Borodin <[email protected]>
2022-08-19 15:48 ` Re: MultiXact\SLRU buffers configuration [email protected]
2024-01-20 03:31 ` Re: MultiXact\SLRU buffers configuration vignesh C <[email protected]>
2024-01-27 04:58 ` Re: MultiXact\SLRU buffers configuration Andrey Borodin <[email protected]>
@ 2024-01-28 12:49 ` Alvaro Herrera <[email protected]>
2024-01-28 18:17 ` Re: MultiXact\SLRU buffers configuration Andrey M. Borodin <[email protected]>
0 siblings, 1 reply; 90+ messages in thread
From: Alvaro Herrera @ 2024-01-28 12:49 UTC (permalink / raw)
To: Andrey Borodin <[email protected]>; +Cc: vignesh C <[email protected]>; Andrew Borodin <[email protected]>; [email protected]; Yura Sokolov <[email protected]>; Andres Freund <[email protected]>; Thomas Munro <[email protected]>; Gilles Darold <[email protected]>; Tomas Vondra <[email protected]>; Tomas Vondra <[email protected]>; Alexander Korotkov <[email protected]>; Anastasia Lubennikova <[email protected]>; Daniel Gustafsson <[email protected]>; Kyotaro Horiguchi <[email protected]>; pgsql-hackers
On 2024-Jan-27, Andrey Borodin wrote:
> thanks for the ping! Most important parts of this patch set are discussed in [0]. If that patchset will be committed, I'll withdraw entry for this thread from commitfest.
> There's a version of Multixact-specific optimizations [1], but I hope they will not be necessary with effective caches developed in [0]. It seems to me that most important part of those optimization is removing sleeps under SLRU lock on standby [2] by Kyotaro Horiguchi. But given that cache optimizations took 4 years to get closer to commit, I'm not sure we will get this optimization any time soon...
I'd appreciate it if you or Horiguchi-san can update his patch to remove
use of usleep in favor of a CV in multixact, and keep this CF entry to
cover it.
Perhaps a test to make the code reach the usleep(1000) can be written
using injection points (49cd2b93d7db)?
--
Álvaro Herrera PostgreSQL Developer — https://www.EnterpriseDB.com/
"La experiencia nos dice que el hombre peló millones de veces las patatas,
pero era forzoso admitir la posibilidad de que en un caso entre millones,
las patatas pelarían al hombre" (Ijon Tichy)
^ permalink raw reply [nested|flat] 90+ messages in thread
* Re: MultiXact\SLRU buffers configuration
2020-05-08 16:36 MultiXact\SLRU buffers configuration Andrey M. Borodin <[email protected]>
2020-05-11 11:17 ` Re: MultiXact\SLRU buffers configuration Andrey M. Borodin <[email protected]>
2020-05-13 18:08 ` Re: MultiXact\SLRU buffers configuration Andrey M. Borodin <[email protected]>
2020-05-14 01:25 ` Re: MultiXact\SLRU buffers configuration Kyotaro Horiguchi <[email protected]>
2020-05-14 05:19 ` Re: MultiXact\SLRU buffers configuration Andrey M. Borodin <[email protected]>
2020-05-14 06:16 ` Re: MultiXact\SLRU buffers configuration Kyotaro Horiguchi <[email protected]>
2020-05-14 06:44 ` Re: MultiXact\SLRU buffers configuration Andrey M. Borodin <[email protected]>
2020-05-15 00:03 ` Re: MultiXact\SLRU buffers configuration Kyotaro Horiguchi <[email protected]>
2020-07-02 12:02 ` Re: MultiXact\SLRU buffers configuration Daniel Gustafsson <[email protected]>
2020-07-08 07:03 ` Re: MultiXact\SLRU buffers configuration Andrey M. Borodin <[email protected]>
2020-08-28 18:08 ` Re: MultiXact\SLRU buffers configuration Anastasia Lubennikova <[email protected]>
2020-09-28 14:41 ` Re: MultiXact\SLRU buffers configuration Andrey M. Borodin <[email protected]>
2020-10-26 01:05 ` Re: MultiXact\SLRU buffers configuration Alexander Korotkov <[email protected]>
2020-10-26 15:45 ` Re: MultiXact\SLRU buffers configuration Andrey Borodin <[email protected]>
2020-10-27 17:02 ` Re: MultiXact\SLRU buffers configuration Alexander Korotkov <[email protected]>
2020-10-27 17:23 ` Re: MultiXact\SLRU buffers configuration Alexander Korotkov <[email protected]>
2020-10-28 01:36 ` Re: MultiXact\SLRU buffers configuration Tomas Vondra <[email protected]>
2020-10-28 07:34 ` Re: MultiXact\SLRU buffers configuration Andrey Borodin <[email protected]>
2020-10-28 23:32 ` Re: MultiXact\SLRU buffers configuration Tomas Vondra <[email protected]>
2020-10-29 07:08 ` Re: MultiXact\SLRU buffers configuration Andrey Borodin <[email protected]>
2020-10-29 13:49 ` Re: MultiXact\SLRU buffers configuration Tomas Vondra <[email protected]>
2020-11-02 12:45 ` Re: MultiXact\SLRU buffers configuration Andrey Borodin <[email protected]>
2020-11-10 00:13 ` Re: MultiXact\SLRU buffers configuration Tomas Vondra <[email protected]>
2020-11-10 06:16 ` Re: MultiXact\SLRU buffers configuration Andrey Borodin <[email protected]>
2020-11-10 18:07 ` Re: MultiXact\SLRU buffers configuration Tomas Vondra <[email protected]>
2020-11-13 11:49 ` Re: MultiXact\SLRU buffers configuration Andrey Borodin <[email protected]>
2020-12-08 16:05 ` Re: MultiXact\SLRU buffers configuration Gilles Darold <[email protected]>
2020-12-08 17:52 ` Re: MultiXact\SLRU buffers configuration Andrey Borodin <[email protected]>
2020-12-10 14:45 ` Re: MultiXact\SLRU buffers configuration Gilles Darold <[email protected]>
2020-12-11 17:50 ` Re: MultiXact\SLRU buffers configuration Gilles Darold <[email protected]>
2020-12-13 09:17 ` Re: MultiXact\SLRU buffers configuration Gilles Darold <[email protected]>
2020-12-13 17:24 ` Re: MultiXact\SLRU buffers configuration Andrey Borodin <[email protected]>
2020-12-23 16:31 ` Re: MultiXact\SLRU buffers configuration Gilles Darold <[email protected]>
2021-02-15 17:17 ` Re: MultiXact\SLRU buffers configuration Andrey Borodin <[email protected]>
2021-03-11 15:50 ` Re: MultiXact\SLRU buffers configuration Gilles Darold <[email protected]>
2021-03-12 12:44 ` Re: MultiXact\SLRU buffers configuration Andrey Borodin <[email protected]>
2021-03-24 21:31 ` Re: MultiXact\SLRU buffers configuration Thomas Munro <[email protected]>
2021-03-25 01:03 ` Re: MultiXact\SLRU buffers configuration Thomas Munro <[email protected]>
2021-03-26 03:46 ` Re: MultiXact\SLRU buffers configuration Thomas Munro <[email protected]>
2021-03-26 06:00 ` Re: MultiXact\SLRU buffers configuration Andrey Borodin <[email protected]>
2021-03-26 15:52 ` Re: MultiXact\SLRU buffers configuration Andrey Borodin <[email protected]>
2021-03-26 20:26 ` Re: MultiXact\SLRU buffers configuration Thomas Munro <[email protected]>
2021-03-27 05:31 ` Re: MultiXact\SLRU buffers configuration Andrey Borodin <[email protected]>
2021-03-28 21:15 ` Re: MultiXact\SLRU buffers configuration Thomas Munro <[email protected]>
2021-03-29 08:26 ` Re: MultiXact\SLRU buffers configuration Andrey Borodin <[email protected]>
2021-03-31 21:09 ` Re: MultiXact\SLRU buffers configuration Andrey Borodin <[email protected]>
2021-04-01 03:40 ` Re: MultiXact\SLRU buffers configuration Thomas Munro <[email protected]>
2021-04-03 19:57 ` Re: MultiXact\SLRU buffers configuration Andrey Borodin <[email protected]>
2021-04-07 05:59 ` Re: MultiXact\SLRU buffers configuration Thomas Munro <[email protected]>
2021-04-07 11:44 ` Re: MultiXact\SLRU buffers configuration Andrey Borodin <[email protected]>
2021-04-07 12:13 ` Re: MultiXact\SLRU buffers configuration Andrey Borodin <[email protected]>
2021-04-08 00:30 ` Re: MultiXact\SLRU buffers configuration Thomas Munro <[email protected]>
2021-04-08 07:24 ` Re: MultiXact\SLRU buffers configuration Andrey Borodin <[email protected]>
2021-04-08 12:22 ` Re: MultiXact\SLRU buffers configuration Thomas Munro <[email protected]>
2022-07-21 13:00 ` Re: MultiXact\SLRU buffers configuration Yura Sokolov <[email protected]>
2022-07-23 08:39 ` Re: MultiXact\SLRU buffers configuration Andrey Borodin <[email protected]>
2022-08-16 19:36 ` Re: MultiXact\SLRU buffers configuration [email protected]
2022-08-18 03:35 ` Re: MultiXact\SLRU buffers configuration Andrey Borodin <[email protected]>
2022-08-19 15:48 ` Re: MultiXact\SLRU buffers configuration [email protected]
2024-01-20 03:31 ` Re: MultiXact\SLRU buffers configuration vignesh C <[email protected]>
2024-01-27 04:58 ` Re: MultiXact\SLRU buffers configuration Andrey Borodin <[email protected]>
2024-01-28 12:49 ` Re: MultiXact\SLRU buffers configuration Alvaro Herrera <[email protected]>
@ 2024-01-28 18:17 ` Andrey M. Borodin <[email protected]>
0 siblings, 0 replies; 90+ messages in thread
From: Andrey M. Borodin @ 2024-01-28 18:17 UTC (permalink / raw)
To: Alvaro Herrera <[email protected]>; +Cc: vignesh C <[email protected]>; Andrew Borodin <[email protected]>; [email protected]; Yura Sokolov <[email protected]>; Andres Freund <[email protected]>; Thomas Munro <[email protected]>; Gilles Darold <[email protected]>; Tomas Vondra <[email protected]>; Tomas Vondra <[email protected]>; Alexander Korotkov <[email protected]>; Anastasia Lubennikova <[email protected]>; Daniel Gustafsson <[email protected]>; Kyotaro Horiguchi <[email protected]>; pgsql-hackers
> On 28 Jan 2024, at 17:49, Alvaro Herrera <[email protected]> wrote:
>
> I'd appreciate it if you or Horiguchi-san can update his patch to remove
> use of usleep in favor of a CV in multixact, and keep this CF entry to
> cover it.
Sure! Sounds great!
> Perhaps a test to make the code reach the usleep(1000) can be written
> using injection points (49cd2b93d7db)?
I've tried to prototype something like that. But interesting point between GetNewMultiXactId() and RecordNewMultiXact() is a critical section, and we cannot have injection points in critical sections...
Also, to implement such a test we need "wait" type of injection points, see step 2 in attachment. With this type of injection points I can stop a backend amidst entering information about new MultiXact.
Best regards, Andrey Borodin.
Attachments:
[application/octet-stream] 0001-Add-conditional-variable-to-wait-for-next-MultXact-o.patch (3.3K, ../../[email protected]/2-0001-Add-conditional-variable-to-wait-for-next-MultXact-o.patch)
download | inline diff:
From 975eb3448acbec97c14d48f21261e44aca7b3acc Mon Sep 17 00:00:00 2001
From: Andrey Borodin <[email protected]>
Date: Fri, 22 May 2020 14:13:33 +0500
Subject: [PATCH 1/3] Add conditional variable to wait for next MultXact offset
in edge case
---
src/backend/access/transam/multixact.c | 23 ++++++++++++++++++-
.../utils/activity/wait_event_names.txt | 1 +
2 files changed, 23 insertions(+), 1 deletion(-)
diff --git a/src/backend/access/transam/multixact.c b/src/backend/access/transam/multixact.c
index 59523be901..03fcd25d4c 100644
--- a/src/backend/access/transam/multixact.c
+++ b/src/backend/access/transam/multixact.c
@@ -82,6 +82,7 @@
#include "lib/ilist.h"
#include "miscadmin.h"
#include "pg_trace.h"
+#include "pgstat.h"
#include "postmaster/autovacuum.h"
#include "storage/lmgr.h"
#include "storage/pmsignal.h"
@@ -233,6 +234,7 @@ typedef struct MultiXactStateData
/* support for members anti-wraparound measures */
MultiXactOffset offsetStopLimit; /* known if oldestOffsetKnown */
+ ConditionVariable nextoff_cv;
/*
* Per-backend data starts here. We have two arrays stored in the area
* immediately following the MultiXactStateData struct. Each is indexed by
@@ -894,6 +896,14 @@ RecordNewMultiXact(MultiXactId multi, MultiXactOffset offset,
/* Exchange our lock */
LWLockRelease(MultiXactOffsetSLRULock);
+ /*
+ * Let everybody know the offset of this mxid is recorded now. The waiters
+ * are waiting for the offset of the mxid next of the target to know the
+ * number of members of the target mxid, so we don't need to wait for
+ * members of this mxid are recorded.
+ */
+ ConditionVariableBroadcast(&MultiXactState->nextoff_cv);
+
LWLockAcquire(MultiXactMemberSLRULock, LW_EXCLUSIVE);
prev_pageno = -1;
@@ -1388,9 +1398,19 @@ retry:
if (nextMXOffset == 0)
{
/* Corner case 2: next multixact is still being filled in */
+
+ /*
+ * The recorder of the next mxid is just before writing the offset.
+ * Wait for the offset to be written.
+ */
+ ConditionVariablePrepareToSleep(&MultiXactState->nextoff_cv);
+
LWLockRelease(MultiXactOffsetSLRULock);
CHECK_FOR_INTERRUPTS();
- pg_usleep(1000L);
+
+ ConditionVariableSleep(&MultiXactState->nextoff_cv,
+ WAIT_EVENT_NEXT_MXMEMBERS);
+ ConditionVariableCancelSleep();
goto retry;
}
@@ -1875,6 +1895,7 @@ MultiXactShmemInit(void)
/* Make sure we zero out the per-backend state */
MemSet(MultiXactState, 0, SHARED_MULTIXACT_STATE_SIZE);
+ ConditionVariableInit(&MultiXactState->nextoff_cv);
}
else
Assert(found);
diff --git a/src/backend/utils/activity/wait_event_names.txt b/src/backend/utils/activity/wait_event_names.txt
index a5df835dd4..1bb78d5aad 100644
--- a/src/backend/utils/activity/wait_event_names.txt
+++ b/src/backend/utils/activity/wait_event_names.txt
@@ -144,6 +144,7 @@ SYNC_REP "Waiting for confirmation from a remote server during synchronous repli
WAL_RECEIVER_EXIT "Waiting for the WAL receiver to exit."
WAL_RECEIVER_WAIT_START "Waiting for startup process to send initial data for streaming replication."
WAL_SUMMARY_READY "Waiting for a new WAL summary to be generated."
+NEXT_MXMEMBERS "Waiting for a next multixact member to be filled."
XACT_GROUP_UPDATE "Waiting for the group leader to update transaction status at end of a parallel operation."
--
2.37.1 (Apple Git-137.1)
[application/octet-stream] 0002-Add-wait-type-for-injection-points.patch (3.7K, ../../[email protected]/3-0002-Add-wait-type-for-injection-points.patch)
download | inline diff:
From 93b4c7dac290d6d2d212522b1a10fef03372315e Mon Sep 17 00:00:00 2001
From: "Andrey M. Borodin" <[email protected]>
Date: Sun, 28 Jan 2024 22:22:22 +0500
Subject: [PATCH 2/3] Add wait type for injection points
---
src/backend/utils/misc/injection_point.c | 20 +++++++++++++++++++
src/include/utils/injection_point.h | 1 +
src/test/modules/injection_points/Makefile | 1 +
.../injection_points/injection_points.c | 16 +++++++++++++++
4 files changed, 38 insertions(+)
diff --git a/src/backend/utils/misc/injection_point.c b/src/backend/utils/misc/injection_point.c
index 0cf4d51cac..398ef2cf30 100644
--- a/src/backend/utils/misc/injection_point.c
+++ b/src/backend/utils/misc/injection_point.c
@@ -252,6 +252,26 @@ InjectionPointDetach(const char *name)
#endif
}
+/*
+ * Test if injection point is attached.
+ */
+bool
+InjectionPointIsAttach(const char *name)
+{
+#ifdef USE_INJECTION_POINTS
+ bool found;
+
+ LWLockAcquire(InjectionPointLock, LW_EXCLUSIVE);
+ hash_search(InjectionPointHash, name, HASH_FIND, &found);
+ LWLockRelease(InjectionPointLock);
+
+ return found;
+
+#else
+ elog(ERROR, "Injection points are not supported by this build");
+#endif
+}
+
/*
* Execute an injection point, if defined.
*
diff --git a/src/include/utils/injection_point.h b/src/include/utils/injection_point.h
index 55524b568f..e07f6b7024 100644
--- a/src/include/utils/injection_point.h
+++ b/src/include/utils/injection_point.h
@@ -33,5 +33,6 @@ extern void InjectionPointAttach(const char *name,
const char *function);
extern void InjectionPointRun(const char *name);
extern void InjectionPointDetach(const char *name);
+extern bool InjectionPointIsAttach(const char *name);
#endif /* INJECTION_POINT_H */
diff --git a/src/test/modules/injection_points/Makefile b/src/test/modules/injection_points/Makefile
index 2cbbae4e0a..543d2ab927 100644
--- a/src/test/modules/injection_points/Makefile
+++ b/src/test/modules/injection_points/Makefile
@@ -7,6 +7,7 @@ DATA = injection_points--1.0.sql
PGFILEDESC = "injection_points - facility for injection points"
REGRESS = injection_points
+TAP_TESTS = 1
ifdef USE_PGXS
PG_CONFIG = pg_config
diff --git a/src/test/modules/injection_points/injection_points.c b/src/test/modules/injection_points/injection_points.c
index e843e6594f..fbb30b15ad 100644
--- a/src/test/modules/injection_points/injection_points.c
+++ b/src/test/modules/injection_points/injection_points.c
@@ -18,6 +18,7 @@
#include "postgres.h"
#include "fmgr.h"
+#include "miscadmin.h"
#include "storage/lwlock.h"
#include "storage/shmem.h"
#include "utils/builtins.h"
@@ -28,6 +29,7 @@ PG_MODULE_MAGIC;
extern PGDLLEXPORT void injection_error(const char *name);
extern PGDLLEXPORT void injection_notice(const char *name);
+extern PGDLLEXPORT void injection_wait(const char *name);
/* Set of callbacks available to be attached to an injection point. */
@@ -43,6 +45,18 @@ injection_notice(const char *name)
elog(NOTICE, "notice triggered for injection point %s", name);
}
+void
+injection_wait(const char *name)
+{
+ elog(NOTICE, "waiting triggered for injection point %s", name);
+ do
+ {
+ CHECK_FOR_INTERRUPTS();
+ pg_usleep(1000L);
+ } while (InjectionPointIsAttach(name));
+ elog(NOTICE, "waiting done for injection point %s", name);
+}
+
/*
* SQL function for creating an injection point.
*/
@@ -58,6 +72,8 @@ injection_points_attach(PG_FUNCTION_ARGS)
function = "injection_error";
else if (strcmp(action, "notice") == 0)
function = "injection_notice";
+ else if (strcmp(action, "wait") == 0)
+ function = "injection_wait";
else
elog(ERROR, "incorrect action \"%s\" for injection point creation", action);
--
2.37.1 (Apple Git-137.1)
[application/octet-stream] 0003-Try-to-test-multixact-CV-sleep.patch (5.3K, ../../[email protected]/4-0003-Try-to-test-multixact-CV-sleep.patch)
download | inline diff:
From a61958407770b6cb864e0b245a4341e033824f46 Mon Sep 17 00:00:00 2001
From: "Andrey M. Borodin" <[email protected]>
Date: Sun, 28 Jan 2024 23:10:55 +0500
Subject: [PATCH 3/3] Try to test multixact CV sleep
---
src/backend/access/transam/multixact.c | 5 ++
.../injection_points--1.0.sql | 11 ++++
.../injection_points/injection_points.c | 26 ++++++++
.../modules/injection_points/t/001_wait.pl | 64 +++++++++++++++++++
4 files changed, 106 insertions(+)
create mode 100644 src/test/modules/injection_points/t/001_wait.pl
diff --git a/src/backend/access/transam/multixact.c b/src/backend/access/transam/multixact.c
index 03fcd25d4c..15b2a0010a 100644
--- a/src/backend/access/transam/multixact.c
+++ b/src/backend/access/transam/multixact.c
@@ -89,6 +89,7 @@
#include "storage/proc.h"
#include "storage/procarray.h"
#include "utils/builtins.h"
+#include "utils/injection_point.h"
#include "utils/memutils.h"
#include "utils/snapmgr.h"
@@ -1200,6 +1201,8 @@ GetNewMultiXactId(int nmembers, MultiXactOffset *offset)
LWLockRelease(MultiXactGenLock);
+ INJECTION_POINT("GetNewMultiXactId-done");
+
debug_elog4(DEBUG2, "GetNew: returning %u offset %u", result, *offset);
return result;
}
@@ -1408,6 +1411,8 @@ retry:
LWLockRelease(MultiXactOffsetSLRULock);
CHECK_FOR_INTERRUPTS();
+ INJECTION_POINT("GetMultiXactIdMembers-CV-sleep");
+
ConditionVariableSleep(&MultiXactState->nextoff_cv,
WAIT_EVENT_NEXT_MXMEMBERS);
ConditionVariableCancelSleep();
diff --git a/src/test/modules/injection_points/injection_points--1.0.sql b/src/test/modules/injection_points/injection_points--1.0.sql
index 5944c41716..d3ebda5964 100644
--- a/src/test/modules/injection_points/injection_points--1.0.sql
+++ b/src/test/modules/injection_points/injection_points--1.0.sql
@@ -33,3 +33,14 @@ CREATE FUNCTION injection_points_detach(IN point_name TEXT)
RETURNS void
AS 'MODULE_PATHNAME', 'injection_points_detach'
LANGUAGE C STRICT PARALLEL UNSAFE;
+
+
+CREATE FUNCTION create_test_multixact()
+RETURNS xid
+AS 'MODULE_PATHNAME', 'create_test_multixact'
+LANGUAGE C STRICT PARALLEL UNSAFE;
+
+CREATE FUNCTION read_test_multixact(xid)
+RETURNS void
+AS 'MODULE_PATHNAME', 'read_test_multixact'
+LANGUAGE C STRICT PARALLEL UNSAFE;
\ No newline at end of file
diff --git a/src/test/modules/injection_points/injection_points.c b/src/test/modules/injection_points/injection_points.c
index fbb30b15ad..d3d5faaa25 100644
--- a/src/test/modules/injection_points/injection_points.c
+++ b/src/test/modules/injection_points/injection_points.c
@@ -109,3 +109,29 @@ injection_points_detach(PG_FUNCTION_ARGS)
PG_RETURN_VOID();
}
+
+#include "access/multixact.h"
+#include "access/xact.h"
+
+PG_FUNCTION_INFO_V1(create_test_multixact);
+Datum
+create_test_multixact(PG_FUNCTION_ARGS)
+{
+ MultiXactId id;
+ MultiXactIdSetOldestMember();
+ id = MultiXactIdCreate(GetCurrentTransactionId(), MultiXactStatusUpdate,
+ GetCurrentTransactionId(), MultiXactStatusForShare);
+ PG_RETURN_TRANSACTIONID(id);
+}
+
+PG_FUNCTION_INFO_V1(read_test_multixact);
+Datum
+read_test_multixact(PG_FUNCTION_ARGS)
+{
+ MultiXactId id = PG_GETARG_TRANSACTIONID(0);
+ MultiXactMember *members;
+ INJECTION_POINT("read_test_multixact");
+ if (GetMultiXactIdMembers(id,&members,false, false) == -1)
+ elog(ERROR, "MultiXactId not found");
+ PG_RETURN_VOID();
+}
\ No newline at end of file
diff --git a/src/test/modules/injection_points/t/001_wait.pl b/src/test/modules/injection_points/t/001_wait.pl
new file mode 100644
index 0000000000..6076ffc6ea
--- /dev/null
+++ b/src/test/modules/injection_points/t/001_wait.pl
@@ -0,0 +1,64 @@
+
+# Copyright (c) 2024, PostgreSQL Global Development Group
+
+use strict;
+use warnings FATAL => 'all';
+
+use PostgreSQL::Test::Cluster;
+use PostgreSQL::Test::Utils;
+
+use Test::More;
+
+my ($node, $result);
+
+$node = PostgreSQL::Test::Cluster->new('injection_points');
+$node->init;
+$node->start;
+$node->safe_psql('postgres', q(CREATE EXTENSION injection_points));
+
+$result = $node->psql('postgres', q(select injection_points_attach('FIRST','wait')));
+is($result, '0', 'wait injection point set');
+
+my $bg = $node->background_psql('postgres');
+
+$bg->query_until(
+ qr/start/, q(
+\echo start
+select injection_points_run('FIRST');
+select injection_points_attach('SECOND','wait');
+));
+
+$result = $node->psql('postgres', q(
+select injection_points_run('SECOND');
+select injection_points_detach('FIRST');
+));
+is($result, '0', 'wait injection point set');
+
+$bg->quit;
+
+$node->safe_psql('postgres', q(select injection_points_attach('read_test_multixact','wait')));
+$node->safe_psql('postgres', q(select injection_points_attach('GetMultiXactIdMembers-CV-sleep','notice')));
+
+my $observer = $node->background_psql('postgres');
+
+$observer->query_safe(
+ q(
+select read_test_multixact(create_test_multixact());
+));
+
+$node->safe_psql('postgres', q(select injection_points_attach('GetNewMultiXactId-done','wait')));
+
+my $creator = $node->background_psql('postgres');
+
+$creator->query_safe( q(select create_test_multixact();));
+
+$node->safe_psql('postgres', q(select injection_points_detach('read_test_multixact')));
+
+$node->safe_psql('postgres', q(select injection_points_detach('GetNewMultiXactId-done')));
+
+$observer->quit;
+
+$creator->quit;
+
+$node->stop;
+done_testing();
--
2.37.1 (Apple Git-137.1)
^ permalink raw reply [nested|flat] 90+ messages in thread
* Re: MultiXact\SLRU buffers configuration
2020-05-08 16:36 MultiXact\SLRU buffers configuration Andrey M. Borodin <[email protected]>
2020-05-11 11:17 ` Re: MultiXact\SLRU buffers configuration Andrey M. Borodin <[email protected]>
2020-05-13 18:08 ` Re: MultiXact\SLRU buffers configuration Andrey M. Borodin <[email protected]>
2020-05-14 01:25 ` Re: MultiXact\SLRU buffers configuration Kyotaro Horiguchi <[email protected]>
2020-05-14 05:19 ` Re: MultiXact\SLRU buffers configuration Andrey M. Borodin <[email protected]>
2020-05-14 06:16 ` Re: MultiXact\SLRU buffers configuration Kyotaro Horiguchi <[email protected]>
2020-05-14 06:44 ` Re: MultiXact\SLRU buffers configuration Andrey M. Borodin <[email protected]>
2020-05-15 00:03 ` Re: MultiXact\SLRU buffers configuration Kyotaro Horiguchi <[email protected]>
2020-07-02 12:02 ` Re: MultiXact\SLRU buffers configuration Daniel Gustafsson <[email protected]>
2020-07-08 07:03 ` Re: MultiXact\SLRU buffers configuration Andrey M. Borodin <[email protected]>
2020-08-28 18:08 ` Re: MultiXact\SLRU buffers configuration Anastasia Lubennikova <[email protected]>
2020-09-28 14:41 ` Re: MultiXact\SLRU buffers configuration Andrey M. Borodin <[email protected]>
2020-10-26 01:05 ` Re: MultiXact\SLRU buffers configuration Alexander Korotkov <[email protected]>
2020-10-26 15:45 ` Re: MultiXact\SLRU buffers configuration Andrey Borodin <[email protected]>
2020-10-27 17:02 ` Re: MultiXact\SLRU buffers configuration Alexander Korotkov <[email protected]>
2020-10-27 17:23 ` Re: MultiXact\SLRU buffers configuration Alexander Korotkov <[email protected]>
2020-10-28 01:36 ` Re: MultiXact\SLRU buffers configuration Tomas Vondra <[email protected]>
@ 2020-10-28 19:36 ` Alexander Korotkov <[email protected]>
2020-10-28 23:21 ` Re: MultiXact\SLRU buffers configuration Tomas Vondra <[email protected]>
1 sibling, 1 reply; 90+ messages in thread
From: Alexander Korotkov @ 2020-10-28 19:36 UTC (permalink / raw)
To: Tomas Vondra <[email protected]>; +Cc: Andrey Borodin <[email protected]>; Anastasia Lubennikova <[email protected]>; Daniel Gustafsson <[email protected]>; Kyotaro Horiguchi <[email protected]>; pgsql-hackers
Hi, Tomas!
Thank you for your review.
On Wed, Oct 28, 2020 at 4:36 AM Tomas Vondra
<[email protected]> wrote:
> I did a quick review on this patch series. A couple comments:
>
>
> 0001
> ----
>
> This looks quite suspicious to me - SimpleLruReadPage_ReadOnly is
> changed to return information about what lock was used, merely to allow
> the callers to do an Assert() that the value is not LW_NONE.
Yes, but this is not merely to allow callers to do an Assert().
Sometimes in multixacts it could save us some relocks. So, we can
skip relocking lock to exclusive mode if it's in exclusive already.
Adding Assert() to every caller is probably overkill.
> IMO we could achieve exactly the same thing by passing a simple flag
> that would say 'make sure we got a lock' or something like that. In
> fact, aren't all callers doing the assert? That'd mean we can just do
> the check always, without the flag. (I see GetMultiXactIdMembers does
> two calls and only checks the second result, but I wonder if that's
> intended or omission.)
Having just the flag is exactly what the original version by Andrey
did. But if we have to read two multixact offsets pages or multiple
members page in one GetMultiXactIdMembers()), then it does relocks
from exclusive mode to exclusive mode. I decide that once we decide
to optimize this locks, this situation is nice to evade.
> In any case, it'd make the lwlock.c changes unnecessary, I think.
I agree that it would be better to not touch lwlock.c. But I didn't
find a way to evade relocking exclusive mode to exclusive mode without
touching lwlock.c or making code cumbersome in other places.
> 0002
> ----
>
> Specifies the number cached MultiXact by backend. Any SLRU lookup ...
>
> should be 'number of cached ...'
Sounds reasonable.
> 0003
> ----
>
> * Conditional variable for waiting till the filling of the next multixact
> * will be finished. See GetMultiXactIdMembers() and RecordNewMultiXact()
> * for details.
>
> Perhaps 'till the next multixact is filled' or 'gets full' would be
> better. Not sure.
Sounds reasonable as well.
------
Regards,
Alexander Korotkov
^ permalink raw reply [nested|flat] 90+ messages in thread
* Re: MultiXact\SLRU buffers configuration
2020-05-08 16:36 MultiXact\SLRU buffers configuration Andrey M. Borodin <[email protected]>
2020-05-11 11:17 ` Re: MultiXact\SLRU buffers configuration Andrey M. Borodin <[email protected]>
2020-05-13 18:08 ` Re: MultiXact\SLRU buffers configuration Andrey M. Borodin <[email protected]>
2020-05-14 01:25 ` Re: MultiXact\SLRU buffers configuration Kyotaro Horiguchi <[email protected]>
2020-05-14 05:19 ` Re: MultiXact\SLRU buffers configuration Andrey M. Borodin <[email protected]>
2020-05-14 06:16 ` Re: MultiXact\SLRU buffers configuration Kyotaro Horiguchi <[email protected]>
2020-05-14 06:44 ` Re: MultiXact\SLRU buffers configuration Andrey M. Borodin <[email protected]>
2020-05-15 00:03 ` Re: MultiXact\SLRU buffers configuration Kyotaro Horiguchi <[email protected]>
2020-07-02 12:02 ` Re: MultiXact\SLRU buffers configuration Daniel Gustafsson <[email protected]>
2020-07-08 07:03 ` Re: MultiXact\SLRU buffers configuration Andrey M. Borodin <[email protected]>
2020-08-28 18:08 ` Re: MultiXact\SLRU buffers configuration Anastasia Lubennikova <[email protected]>
2020-09-28 14:41 ` Re: MultiXact\SLRU buffers configuration Andrey M. Borodin <[email protected]>
2020-10-26 01:05 ` Re: MultiXact\SLRU buffers configuration Alexander Korotkov <[email protected]>
2020-10-26 15:45 ` Re: MultiXact\SLRU buffers configuration Andrey Borodin <[email protected]>
2020-10-27 17:02 ` Re: MultiXact\SLRU buffers configuration Alexander Korotkov <[email protected]>
2020-10-27 17:23 ` Re: MultiXact\SLRU buffers configuration Alexander Korotkov <[email protected]>
2020-10-28 01:36 ` Re: MultiXact\SLRU buffers configuration Tomas Vondra <[email protected]>
2020-10-28 19:36 ` Re: MultiXact\SLRU buffers configuration Alexander Korotkov <[email protected]>
@ 2020-10-28 23:21 ` Tomas Vondra <[email protected]>
0 siblings, 0 replies; 90+ messages in thread
From: Tomas Vondra @ 2020-10-28 23:21 UTC (permalink / raw)
To: Alexander Korotkov <[email protected]>; +Cc: Andrey Borodin <[email protected]>; Anastasia Lubennikova <[email protected]>; Daniel Gustafsson <[email protected]>; Kyotaro Horiguchi <[email protected]>; pgsql-hackers
On Wed, Oct 28, 2020 at 10:36:39PM +0300, Alexander Korotkov wrote:
>Hi, Tomas!
>
>Thank you for your review.
>
>On Wed, Oct 28, 2020 at 4:36 AM Tomas Vondra
><[email protected]> wrote:
>> I did a quick review on this patch series. A couple comments:
>>
>>
>> 0001
>> ----
>>
>> This looks quite suspicious to me - SimpleLruReadPage_ReadOnly is
>> changed to return information about what lock was used, merely to allow
>> the callers to do an Assert() that the value is not LW_NONE.
>
>Yes, but this is not merely to allow callers to do an Assert().
>Sometimes in multixacts it could save us some relocks. So, we can
>skip relocking lock to exclusive mode if it's in exclusive already.
>Adding Assert() to every caller is probably overkill.
>
Hmm, OK. That can only happen in GetMultiXactIdMembers, which is the
only place where we do retry, right? Do we actually know this makes any
measurable difference? It seems we're mostly imagining that it might
help, but we don't have any actual proof of that (e.g. a workload which
we might benchmark). Or am I missing something?
For me, the extra conditions make it way harder to reason about the
behavior of the code, and I can't convince myself it's worth it.
>> IMO we could achieve exactly the same thing by passing a simple flag
>> that would say 'make sure we got a lock' or something like that. In
>> fact, aren't all callers doing the assert? That'd mean we can just do
>> the check always, without the flag. (I see GetMultiXactIdMembers does
>> two calls and only checks the second result, but I wonder if that's
>> intended or omission.)
>
>Having just the flag is exactly what the original version by Andrey
>did. But if we have to read two multixact offsets pages or multiple
>members page in one GetMultiXactIdMembers()), then it does relocks
>from exclusive mode to exclusive mode. I decide that once we decide
>to optimize this locks, this situation is nice to evade.
>
>> In any case, it'd make the lwlock.c changes unnecessary, I think.
>
>I agree that it would be better to not touch lwlock.c. But I didn't
>find a way to evade relocking exclusive mode to exclusive mode without
>touching lwlock.c or making code cumbersome in other places.
>
Hmm. OK.
regards
--
Tomas Vondra http://www.2ndQuadrant.com
PostgreSQL Development, 24x7 Support, Remote DBA, Training & Services
^ permalink raw reply [nested|flat] 90+ messages in thread
* Re: MultiXact\SLRU buffers configuration
@ 2024-08-23 00:29 Michael Paquier <[email protected]>
2024-10-29 16:38 ` Re: MultiXact\SLRU buffers configuration Thom Brown <[email protected]>
0 siblings, 1 reply; 90+ messages in thread
From: Michael Paquier @ 2024-08-23 00:29 UTC (permalink / raw)
To: Alvaro Herrera <[email protected]>; +Cc: Andrey M. Borodin <[email protected]>; vignesh C <[email protected]>; Andrew Borodin <[email protected]>; Yura Sokolov <[email protected]>; Andres Freund <[email protected]>; Thomas Munro <[email protected]>; Gilles Darold <[email protected]>; Alexander Korotkov <[email protected]>; Daniel Gustafsson <[email protected]>; Kyotaro Horiguchi <[email protected]>; pgsql-hackers
On Thu, Aug 22, 2024 at 10:36:38AM -0400, Alvaro Herrera wrote:
> On 2024-Aug-22, Michael Paquier wrote:
>> I'm not sure that we need to get down to that until somebody has a
>> case where they want to rely on stats of injection points for their
>> stuff. At this stage, I only want the stats to be enabled to provide
>> automated checks for the custom pgstats APIs, so disabling it by
>> default and enabling it only in the stats test of the module
>> injection_points sounds kind of enough to me for now.
>
> Oh! I thought the stats were useful by themselves.
Yep, currently they're not, but I don't want to discard that they'll
never be, either. Perhaps there would be a case where somebody would
like to run a callback N times and trigger a condition? That's
something where the stats could be useful, but I don't have a specific
case for that now. I'm just imagining possibilities.
> That not being the case, I agree with simplifying; and the other
> ways to enhance this point might not be necessary for now.
Okay.
>> Sticking some knowledge about the stats in the backend part of
>> injection points does not sound like a good idea to me.
>
> You could flip this around: have the bool be for "this injection point
> is going to be invoked inside a critical section". Then core code just
> needs to tell the injection points module what core code does, and it's
> injection_points that decides what to do with that information.
Hmm. We could do that, but I'm not really on board with anything that
adds more code footprint into the backend. For this one, this is even
information specific to the code path where the injection point is
added.
--
Michael
Attachments:
[application/pgp-signature] signature.asc (833B, ../../[email protected]/2-signature.asc)
download
^ permalink raw reply [nested|flat] 90+ messages in thread
* Re: MultiXact\SLRU buffers configuration
2024-08-23 00:29 Re: MultiXact\SLRU buffers configuration Michael Paquier <[email protected]>
@ 2024-10-29 16:38 ` Thom Brown <[email protected]>
2024-10-29 17:45 ` Re: MultiXact\SLRU buffers configuration Thom Brown <[email protected]>
0 siblings, 1 reply; 90+ messages in thread
From: Thom Brown @ 2024-10-29 16:38 UTC (permalink / raw)
To: Michael Paquier <[email protected]>; +Cc: Alvaro Herrera <[email protected]>; Andrey M. Borodin <[email protected]>; vignesh C <[email protected]>; Andrew Borodin <[email protected]>; Yura Sokolov <[email protected]>; Andres Freund <[email protected]>; Thomas Munro <[email protected]>; Gilles Darold <[email protected]>; Alexander Korotkov <[email protected]>; Daniel Gustafsson <[email protected]>; Kyotaro Horiguchi <[email protected]>; pgsql-hackers
On Fri, 23 Aug 2024 at 01:29, Michael Paquier <[email protected]> wrote:
> On Thu, Aug 22, 2024 at 10:36:38AM -0400, Alvaro Herrera wrote:
> > On 2024-Aug-22, Michael Paquier wrote:
> >> I'm not sure that we need to get down to that until somebody has a
> >> case where they want to rely on stats of injection points for their
> >> stuff. At this stage, I only want the stats to be enabled to provide
> >> automated checks for the custom pgstats APIs, so disabling it by
> >> default and enabling it only in the stats test of the module
> >> injection_points sounds kind of enough to me for now.
> >
> > Oh! I thought the stats were useful by themselves.
>
> Yep, currently they're not, but I don't want to discard that they'll
> never be, either. Perhaps there would be a case where somebody would
> like to run a callback N times and trigger a condition? That's
> something where the stats could be useful, but I don't have a specific
> case for that now. I'm just imagining possibilities.
>
I believe I am seeing the problem being discussed occuring on a production
system running 15.6, causing ever-increasing replay lag on the standby,
until I cancel the offending process on the standby and force it to process
its interrupts.
Here's the backtrace before I do that:
#0 0x00007f4503b81876 in select () from /lib64/libc.so.6
#1 0x0000558b0956891a in pg_usleep (microsec=microsec@entry=1000) at
pgsleep.c:56
#2 0x0000558b0917e01a in GetMultiXactIdMembers (from_pgupgrade=false,
onlyLock=<optimized out>, members=0x7ffcd2a9f1e0, multi=109187502) at
multixact.c:1392
#3 GetMultiXactIdMembers (multi=109187502,
members=members@entry=0x7ffcd2a9f1e0,
from_pgupgrade=from_pgupgrade@entry=false, onlyLock=onlyLock@entry=false)
at multixact.c:1224
#4 0x0000558b0913de15 in MultiXactIdGetUpdateXid (xmax=<optimized out>,
t_infomask=<optimized out>) at heapam.c:6924
#5 0x0000558b09146028 in HeapTupleGetUpdateXid
(tuple=tuple@entry=0x7f440d428308)
at heapam.c:6965
#6 0x0000558b0914c02f in HeapTupleSatisfiesMVCC (htup=0x558b0b7cbf20,
htup=0x558b0b7cbf20, buffer=8053429, snapshot=0x558b0b63a2d8) at
heapam_visibility.c:1089
#7 HeapTupleSatisfiesVisibility (tup=tup@entry=0x7ffcd2a9f2b0,
snapshot=snapshot@entry=0x558b0b63a2d8, buffer=buffer@entry=8053429) at
heapam_visibility.c:1771
#8 0x0000558b0913e819 in heapgetpage (sscan=sscan@entry=0x558b0b7ccfa0,
page=page@entry=115) at heapam.c:468
#9 0x0000558b0913eb7e in heapgettup_pagemode (scan=scan@entry=0x558b0b7ccfa0,
dir=ForwardScanDirection, nkeys=0, key=0x0) at heapam.c:1120
#10 0x0000558b0913fb5e in heap_getnextslot (sscan=0x558b0b7ccfa0,
direction=<optimized out>, slot=0x558b0b7cc000) at heapam.c:1352
#11 0x0000558b092c0e7a in table_scan_getnextslot (slot=0x558b0b7cc000,
direction=ForwardScanDirection, sscan=<optimized out>) at
../../../src/include/access/tableam.h:1046
#12 SeqNext (node=0x558b0b7cbe10) at nodeSeqscan.c:80
#13 0x0000558b0929b9bf in ExecScan (node=0x558b0b7cbe10,
accessMtd=0x558b092c0df0 <SeqNext>, recheckMtd=0x558b092c0dc0 <SeqRecheck>)
at execScan.c:198
#14 0x0000558b09292cb2 in ExecProcNode (node=0x558b0b7cbe10) at
../../../src/include/executor/executor.h:262
#15 ExecutePlan (execute_once=<optimized out>, dest=0x558b0bca1350,
direction=<optimized out>, numberTuples=0, sendTuples=<optimized out>,
operation=CMD_SELECT, use_parallel_mode=<optimized out>,
planstate=0x558b0b7cbe10, estate=0x558b0b7cbbe8)
at execMain.c:1636
#16 standard_ExecutorRun (queryDesc=0x558b0b8c9798, direction=<optimized
out>, count=0, execute_once=<optimized out>) at execMain.c:363
#17 0x00007f44f64d43c5 in pgss_ExecutorRun (queryDesc=0x558b0b8c9798,
direction=ForwardScanDirection, count=0, execute_once=<optimized out>) at
pg_stat_statements.c:1010
#18 0x0000558b093fda0f in PortalRunSelect (portal=portal@entry=0x558b0b6ba458,
forward=forward@entry=true, count=0, count@entry=9223372036854775807,
dest=dest@entry=0x558b0bca1350) at pquery.c:924
#19 0x0000558b093fedb8 in PortalRun (portal=portal@entry=0x558b0b6ba458,
count=count@entry=9223372036854775807, isTopLevel=isTopLevel@entry=true,
run_once=run_once@entry=true, dest=dest@entry=0x558b0bca1350,
altdest=altdest@entry=0x558b0bca1350, qc=0x7ffcd2a9f7a0) at pquery.c:768
#20 0x0000558b093fb243 in exec_simple_query (
query_string=0x558b0b6170c8 "<redacted>")
at postgres.c:1250
#21 0x0000558b093fd412 in PostgresMain (dbname=<optimized out>,
username=<optimized out>) at postgres.c:4598
#22 0x0000558b0937e170 in BackendRun (port=<optimized out>, port=<optimized
out>) at postmaster.c:4514
#23 BackendStartup (port=<optimized out>) at postmaster.c:4242
#24 ServerLoop () at postmaster.c:1809
#25 0x0000558b0937f147 in PostmasterMain (argc=argc@entry=5,
argv=argv@entry=0x558b0b5d0a30)
at postmaster.c:1481
#26 0x0000558b09100a2c in main (argc=5, argv=0x558b0b5d0a30) at main.c:202
This occurred twice, meaning 2 processes needed terminating.
Thom
^ permalink raw reply [nested|flat] 90+ messages in thread
* Re: MultiXact\SLRU buffers configuration
2024-08-23 00:29 Re: MultiXact\SLRU buffers configuration Michael Paquier <[email protected]>
2024-10-29 16:38 ` Re: MultiXact\SLRU buffers configuration Thom Brown <[email protected]>
@ 2024-10-29 17:45 ` Thom Brown <[email protected]>
2024-10-31 10:46 ` Re: MultiXact\SLRU buffers configuration Andrey M. Borodin <[email protected]>
0 siblings, 1 reply; 90+ messages in thread
From: Thom Brown @ 2024-10-29 17:45 UTC (permalink / raw)
To: Michael Paquier <[email protected]>; +Cc: Alvaro Herrera <[email protected]>; Andrey M. Borodin <[email protected]>; vignesh C <[email protected]>; Andrew Borodin <[email protected]>; Yura Sokolov <[email protected]>; Andres Freund <[email protected]>; Thomas Munro <[email protected]>; Gilles Darold <[email protected]>; Alexander Korotkov <[email protected]>; Daniel Gustafsson <[email protected]>; Kyotaro Horiguchi <[email protected]>; pgsql-hackers
On Tue, 29 Oct 2024 at 16:38, Thom Brown <[email protected]> wrote:
>
> On Fri, 23 Aug 2024 at 01:29, Michael Paquier <[email protected]> wrote:
>>
>> On Thu, Aug 22, 2024 at 10:36:38AM -0400, Alvaro Herrera wrote:
>> > On 2024-Aug-22, Michael Paquier wrote:
>> >> I'm not sure that we need to get down to that until somebody has a
>> >> case where they want to rely on stats of injection points for their
>> >> stuff. At this stage, I only want the stats to be enabled to provide
>> >> automated checks for the custom pgstats APIs, so disabling it by
>> >> default and enabling it only in the stats test of the module
>> >> injection_points sounds kind of enough to me for now.
>> >
>> > Oh! I thought the stats were useful by themselves.
>>
>> Yep, currently they're not, but I don't want to discard that they'll
>> never be, either. Perhaps there would be a case where somebody would
>> like to run a callback N times and trigger a condition? That's
>> something where the stats could be useful, but I don't have a specific
>> case for that now. I'm just imagining possibilities.
>
>
> I believe I am seeing the problem being discussed occuring on a production system running 15.6, causing ever-increasing replay lag on the standby, until I cancel the offending process on the standby and force it to process its interrupts.
>
> Here's the backtrace before I do that:
>
> #0 0x00007f4503b81876 in select () from /lib64/libc.so.6
> #1 0x0000558b0956891a in pg_usleep (microsec=microsec@entry=1000) at pgsleep.c:56
> #2 0x0000558b0917e01a in GetMultiXactIdMembers (from_pgupgrade=false, onlyLock=<optimized out>, members=0x7ffcd2a9f1e0, multi=109187502) at multixact.c:1392
> #3 GetMultiXactIdMembers (multi=109187502, members=members@entry=0x7ffcd2a9f1e0, from_pgupgrade=from_pgupgrade@entry=false, onlyLock=onlyLock@entry=false) at multixact.c:1224
> #4 0x0000558b0913de15 in MultiXactIdGetUpdateXid (xmax=<optimized out>, t_infomask=<optimized out>) at heapam.c:6924
> #5 0x0000558b09146028 in HeapTupleGetUpdateXid (tuple=tuple@entry=0x7f440d428308) at heapam.c:6965
> #6 0x0000558b0914c02f in HeapTupleSatisfiesMVCC (htup=0x558b0b7cbf20, htup=0x558b0b7cbf20, buffer=8053429, snapshot=0x558b0b63a2d8) at heapam_visibility.c:1089
> #7 HeapTupleSatisfiesVisibility (tup=tup@entry=0x7ffcd2a9f2b0, snapshot=snapshot@entry=0x558b0b63a2d8, buffer=buffer@entry=8053429) at heapam_visibility.c:1771
> #8 0x0000558b0913e819 in heapgetpage (sscan=sscan@entry=0x558b0b7ccfa0, page=page@entry=115) at heapam.c:468
> #9 0x0000558b0913eb7e in heapgettup_pagemode (scan=scan@entry=0x558b0b7ccfa0, dir=ForwardScanDirection, nkeys=0, key=0x0) at heapam.c:1120
> #10 0x0000558b0913fb5e in heap_getnextslot (sscan=0x558b0b7ccfa0, direction=<optimized out>, slot=0x558b0b7cc000) at heapam.c:1352
> #11 0x0000558b092c0e7a in table_scan_getnextslot (slot=0x558b0b7cc000, direction=ForwardScanDirection, sscan=<optimized out>) at ../../../src/include/access/tableam.h:1046
> #12 SeqNext (node=0x558b0b7cbe10) at nodeSeqscan.c:80
> #13 0x0000558b0929b9bf in ExecScan (node=0x558b0b7cbe10, accessMtd=0x558b092c0df0 <SeqNext>, recheckMtd=0x558b092c0dc0 <SeqRecheck>) at execScan.c:198
> #14 0x0000558b09292cb2 in ExecProcNode (node=0x558b0b7cbe10) at ../../../src/include/executor/executor.h:262
> #15 ExecutePlan (execute_once=<optimized out>, dest=0x558b0bca1350, direction=<optimized out>, numberTuples=0, sendTuples=<optimized out>, operation=CMD_SELECT, use_parallel_mode=<optimized out>, planstate=0x558b0b7cbe10, estate=0x558b0b7cbbe8)
> at execMain.c:1636
> #16 standard_ExecutorRun (queryDesc=0x558b0b8c9798, direction=<optimized out>, count=0, execute_once=<optimized out>) at execMain.c:363
> #17 0x00007f44f64d43c5 in pgss_ExecutorRun (queryDesc=0x558b0b8c9798, direction=ForwardScanDirection, count=0, execute_once=<optimized out>) at pg_stat_statements.c:1010
> #18 0x0000558b093fda0f in PortalRunSelect (portal=portal@entry=0x558b0b6ba458, forward=forward@entry=true, count=0, count@entry=9223372036854775807, dest=dest@entry=0x558b0bca1350) at pquery.c:924
> #19 0x0000558b093fedb8 in PortalRun (portal=portal@entry=0x558b0b6ba458, count=count@entry=9223372036854775807, isTopLevel=isTopLevel@entry=true, run_once=run_once@entry=true, dest=dest@entry=0x558b0bca1350,
> altdest=altdest@entry=0x558b0bca1350, qc=0x7ffcd2a9f7a0) at pquery.c:768
> #20 0x0000558b093fb243 in exec_simple_query (
> query_string=0x558b0b6170c8 "<redacted>")
> at postgres.c:1250
> #21 0x0000558b093fd412 in PostgresMain (dbname=<optimized out>, username=<optimized out>) at postgres.c:4598
> #22 0x0000558b0937e170 in BackendRun (port=<optimized out>, port=<optimized out>) at postmaster.c:4514
> #23 BackendStartup (port=<optimized out>) at postmaster.c:4242
> #24 ServerLoop () at postmaster.c:1809
> #25 0x0000558b0937f147 in PostmasterMain (argc=argc@entry=5, argv=argv@entry=0x558b0b5d0a30) at postmaster.c:1481
> #26 0x0000558b09100a2c in main (argc=5, argv=0x558b0b5d0a30) at main.c:202
>
> This occurred twice, meaning 2 processes needed terminating.
Taking a look at what's happening under the hood, it seems to be
getting stuck here:
if (nextMXOffset == 0)
{
/* Corner case 2: next multixact is still
being filled in */
LWLockRelease(MultiXactOffsetSLRULock);
CHECK_FOR_INTERRUPTS();
pg_usleep(1000L);
goto retry;
}
It clearly checks for interrupts, but when I saw this issue happen, it
wasn't interruptible.
I looked around for similar reports, and I found a fork of Postgres
reporting the same issue, but with more info than I thought to get at
the time. They determined that the root cause involved a deadlock
where the replay thread is stuck due to an out-of-order multixact
playback sequence. The standby process waits indefinitely for a page
pin to release before proceeding, but the required multixact ID hasn't
yet been replayed due to log ordering. What they did to "fix" the
issue in their version was to add an error when the reading thread
cannot retrieve the next multixact ID, allowing it to exit instead of
becoming indefinitely stuck. This took the form of only allowing it to
loop 100 times before exiting.
Thom
^ permalink raw reply [nested|flat] 90+ messages in thread
* Re: MultiXact\SLRU buffers configuration
2024-08-23 00:29 Re: MultiXact\SLRU buffers configuration Michael Paquier <[email protected]>
2024-10-29 16:38 ` Re: MultiXact\SLRU buffers configuration Thom Brown <[email protected]>
2024-10-29 17:45 ` Re: MultiXact\SLRU buffers configuration Thom Brown <[email protected]>
@ 2024-10-31 10:46 ` Andrey M. Borodin <[email protected]>
2024-10-31 13:29 ` Re: MultiXact\SLRU buffers configuration Thom Brown <[email protected]>
0 siblings, 1 reply; 90+ messages in thread
From: Andrey M. Borodin @ 2024-10-31 10:46 UTC (permalink / raw)
To: Thom Brown <[email protected]>; +Cc: Michael Paquier <[email protected]>; Alvaro Herrera <[email protected]>; vignesh C <[email protected]>; Andrew Borodin <[email protected]>; Yura Sokolov <[email protected]>; Andres Freund <[email protected]>; Thomas Munro <[email protected]>; Gilles Darold <[email protected]>; Alexander Korotkov <[email protected]>; Daniel Gustafsson <[email protected]>; Kyotaro Horiguchi <[email protected]>; pgsql-hackers
> On 29 Oct 2024, at 21:45, Thom Brown <[email protected]> wrote:
>
> It clearly checks for interrupts, but when I saw this issue happen, it
> wasn't interruptible.
Perhaps, that was different multixacts?
When I was observing this pathology on Standby, it was a stream of different reads encountering different multis.
Either way startup can cancel locking process on it's own. Or is it the case that cancel was not enough, did you actually need termination, not cancel?
Thanks!
Best regards, Andrey Borodin.
^ permalink raw reply [nested|flat] 90+ messages in thread
* Re: MultiXact\SLRU buffers configuration
2024-08-23 00:29 Re: MultiXact\SLRU buffers configuration Michael Paquier <[email protected]>
2024-10-29 16:38 ` Re: MultiXact\SLRU buffers configuration Thom Brown <[email protected]>
2024-10-29 17:45 ` Re: MultiXact\SLRU buffers configuration Thom Brown <[email protected]>
2024-10-31 10:46 ` Re: MultiXact\SLRU buffers configuration Andrey M. Borodin <[email protected]>
@ 2024-10-31 13:29 ` Thom Brown <[email protected]>
2024-10-31 17:32 ` Re: MultiXact\SLRU buffers configuration Andrey M. Borodin <[email protected]>
0 siblings, 1 reply; 90+ messages in thread
From: Thom Brown @ 2024-10-31 13:29 UTC (permalink / raw)
To: Andrey M. Borodin <[email protected]>; +Cc: Michael Paquier <[email protected]>; Alvaro Herrera <[email protected]>; vignesh C <[email protected]>; Andrew Borodin <[email protected]>; Yura Sokolov <[email protected]>; Andres Freund <[email protected]>; Thomas Munro <[email protected]>; Gilles Darold <[email protected]>; Alexander Korotkov <[email protected]>; Daniel Gustafsson <[email protected]>; Kyotaro Horiguchi <[email protected]>; pgsql-hackers
On Thu, 31 Oct 2024 at 10:47, Andrey M. Borodin <[email protected]> wrote:
>
>
>
> > On 29 Oct 2024, at 21:45, Thom Brown <[email protected]> wrote:
> >
> > It clearly checks for interrupts, but when I saw this issue happen, it
> > wasn't interruptible.
>
> Perhaps, that was different multixacts?
> When I was observing this pathology on Standby, it was a stream of different reads encountering different multis.
>
> Either way startup can cancel locking process on it's own. Or is it the case that cancel was not enough, did you actually need termination, not cancel?
Termination didn't work on either of the processes.
Thom
^ permalink raw reply [nested|flat] 90+ messages in thread
* Re: MultiXact\SLRU buffers configuration
2024-08-23 00:29 Re: MultiXact\SLRU buffers configuration Michael Paquier <[email protected]>
2024-10-29 16:38 ` Re: MultiXact\SLRU buffers configuration Thom Brown <[email protected]>
2024-10-29 17:45 ` Re: MultiXact\SLRU buffers configuration Thom Brown <[email protected]>
2024-10-31 10:46 ` Re: MultiXact\SLRU buffers configuration Andrey M. Borodin <[email protected]>
2024-10-31 13:29 ` Re: MultiXact\SLRU buffers configuration Thom Brown <[email protected]>
@ 2024-10-31 17:32 ` Andrey M. Borodin <[email protected]>
2024-10-31 19:25 ` Re: MultiXact\SLRU buffers configuration Thom Brown <[email protected]>
0 siblings, 1 reply; 90+ messages in thread
From: Andrey M. Borodin @ 2024-10-31 17:32 UTC (permalink / raw)
To: Thom Brown <[email protected]>; +Cc: Michael Paquier <[email protected]>; Alvaro Herrera <[email protected]>; vignesh C <[email protected]>; Andrew Borodin <[email protected]>; Yura Sokolov <[email protected]>; Andres Freund <[email protected]>; Thomas Munro <[email protected]>; Gilles Darold <[email protected]>; Alexander Korotkov <[email protected]>; Daniel Gustafsson <[email protected]>; Kyotaro Horiguchi <[email protected]>; pgsql-hackers
> On 31 Oct 2024, at 17:29, Thom Brown <[email protected]> wrote:
>
> On Thu, 31 Oct 2024 at 10:47, Andrey M. Borodin <[email protected]> wrote:
>>
>>
>>
>>> On 29 Oct 2024, at 21:45, Thom Brown <[email protected]> wrote:
>>>
>>> It clearly checks for interrupts, but when I saw this issue happen, it
>>> wasn't interruptible.
>>
>> Perhaps, that was different multixacts?
>> When I was observing this pathology on Standby, it was a stream of different reads encountering different multis.
>>
>> Either way startup can cancel locking process on it's own. Or is it the case that cancel was not enough, did you actually need termination, not cancel?
>
> Termination didn't work on either of the processes.
How did you force the process to actually terminate?
Did you observe repeated read of the same multixact?
Was offending process holding any locks while waiting?
Best regards, Andrey Borodin.
^ permalink raw reply [nested|flat] 90+ messages in thread
* Re: MultiXact\SLRU buffers configuration
2024-08-23 00:29 Re: MultiXact\SLRU buffers configuration Michael Paquier <[email protected]>
2024-10-29 16:38 ` Re: MultiXact\SLRU buffers configuration Thom Brown <[email protected]>
2024-10-29 17:45 ` Re: MultiXact\SLRU buffers configuration Thom Brown <[email protected]>
2024-10-31 10:46 ` Re: MultiXact\SLRU buffers configuration Andrey M. Borodin <[email protected]>
2024-10-31 13:29 ` Re: MultiXact\SLRU buffers configuration Thom Brown <[email protected]>
2024-10-31 17:32 ` Re: MultiXact\SLRU buffers configuration Andrey M. Borodin <[email protected]>
@ 2024-10-31 19:25 ` Thom Brown <[email protected]>
2024-11-05 14:11 ` Re: MultiXact\SLRU buffers configuration Andrey M. Borodin <[email protected]>
2025-07-28 17:23 ` Re: MultiXact\SLRU buffers configuration Andrey Borodin <[email protected]>
0 siblings, 2 replies; 90+ messages in thread
From: Thom Brown @ 2024-10-31 19:25 UTC (permalink / raw)
To: Andrey M. Borodin <[email protected]>; +Cc: Michael Paquier <[email protected]>; Alvaro Herrera <[email protected]>; vignesh C <[email protected]>; Andrew Borodin <[email protected]>; Yura Sokolov <[email protected]>; Andres Freund <[email protected]>; Thomas Munro <[email protected]>; Gilles Darold <[email protected]>; Alexander Korotkov <[email protected]>; Daniel Gustafsson <[email protected]>; Kyotaro Horiguchi <[email protected]>; pgsql-hackers
On Thu, 31 Oct 2024, 17:33 Andrey M. Borodin, <[email protected]> wrote:
>
>
> > On 31 Oct 2024, at 17:29, Thom Brown <[email protected]> wrote:
> >
> > On Thu, 31 Oct 2024 at 10:47, Andrey M. Borodin <[email protected]>
> wrote:
> >>
> >>
> >>
> >>> On 29 Oct 2024, at 21:45, Thom Brown <[email protected]> wrote:
> >>>
> >>> It clearly checks for interrupts, but when I saw this issue happen, it
> >>> wasn't interruptible.
> >>
> >> Perhaps, that was different multixacts?
> >> When I was observing this pathology on Standby, it was a stream of
> different reads encountering different multis.
> >>
> >> Either way startup can cancel locking process on it's own. Or is it the
> case that cancel was not enough, did you actually need termination, not
> cancel?
> >
> > Termination didn't work on either of the processes.
>
> How did you force the process to actually terminate?
> Did you observe repeated read of the same multixact?
> Was offending process holding any locks while waiting?
>
Unfortunately I didn't gather much information when it was occuring, and
prioritised getting rid of the process blocking replay. I just attached gdb
to it, got a backtrace and then "print ProcessInterrupts()".
Thom
>
^ permalink raw reply [nested|flat] 90+ messages in thread
* Re: MultiXact\SLRU buffers configuration
2024-08-23 00:29 Re: MultiXact\SLRU buffers configuration Michael Paquier <[email protected]>
2024-10-29 16:38 ` Re: MultiXact\SLRU buffers configuration Thom Brown <[email protected]>
2024-10-29 17:45 ` Re: MultiXact\SLRU buffers configuration Thom Brown <[email protected]>
2024-10-31 10:46 ` Re: MultiXact\SLRU buffers configuration Andrey M. Borodin <[email protected]>
2024-10-31 13:29 ` Re: MultiXact\SLRU buffers configuration Thom Brown <[email protected]>
2024-10-31 17:32 ` Re: MultiXact\SLRU buffers configuration Andrey M. Borodin <[email protected]>
2024-10-31 19:25 ` Re: MultiXact\SLRU buffers configuration Thom Brown <[email protected]>
@ 2024-11-05 14:11 ` Andrey M. Borodin <[email protected]>
1 sibling, 0 replies; 90+ messages in thread
From: Andrey M. Borodin @ 2024-11-05 14:11 UTC (permalink / raw)
To: Thom Brown <[email protected]>; +Cc: Michael Paquier <[email protected]>; Alvaro Herrera <[email protected]>; vignesh C <[email protected]>; Andrew Borodin <[email protected]>; Yura Sokolov <[email protected]>; Andres Freund <[email protected]>; Thomas Munro <[email protected]>; Gilles Darold <[email protected]>; Alexander Korotkov <[email protected]>; Daniel Gustafsson <[email protected]>; Kyotaro Horiguchi <[email protected]>; pgsql-hackers
> On 1 Nov 2024, at 00:25, Thom Brown <[email protected]> wrote:
>
> Unfortunately I didn't gather much information when it was occuring, and prioritised getting rid of the process blocking replay. I just attached gdb to it, got a backtrace and then "print ProcessInterrupts()".
>
Currently I do not see how this wait can result in a deadlock.
But I did observe standby in a pathological sequential scan encountering recent multixact again and again (new each time).
I hope this situation will be alleviated by recent cahnges - now there is not a millisecond wait, but hopefully smaller amount of time.
In v17 we also added injection point test which reproduces reading very recent multixact. If there is a deadlock I hope buildfarm will show it to us.
Best regards, Andrey Borodin.
^ permalink raw reply [nested|flat] 90+ messages in thread
* Re: MultiXact\SLRU buffers configuration
2024-08-23 00:29 Re: MultiXact\SLRU buffers configuration Michael Paquier <[email protected]>
2024-10-29 16:38 ` Re: MultiXact\SLRU buffers configuration Thom Brown <[email protected]>
2024-10-29 17:45 ` Re: MultiXact\SLRU buffers configuration Thom Brown <[email protected]>
2024-10-31 10:46 ` Re: MultiXact\SLRU buffers configuration Andrey M. Borodin <[email protected]>
2024-10-31 13:29 ` Re: MultiXact\SLRU buffers configuration Thom Brown <[email protected]>
2024-10-31 17:32 ` Re: MultiXact\SLRU buffers configuration Andrey M. Borodin <[email protected]>
2024-10-31 19:25 ` Re: MultiXact\SLRU buffers configuration Thom Brown <[email protected]>
@ 2025-07-28 17:23 ` Andrey Borodin <[email protected]>
1 sibling, 0 replies; 90+ messages in thread
From: Andrey Borodin @ 2025-07-28 17:23 UTC (permalink / raw)
To: Thom Brown <[email protected]>; +Cc: Michael Paquier <[email protected]>; Alvaro Herrera <[email protected]>; vignesh C <[email protected]>; Andrew Borodin <[email protected]>; Yura Sokolov <[email protected]>; Andres Freund <[email protected]>; Thomas Munro <[email protected]>; Gilles Darold <[email protected]>; Alexander Korotkov <[email protected]>; Daniel Gustafsson <[email protected]>; Kyotaro Horiguchi <[email protected]>; pgsql-hackers
Hi Thom!
> On 1 Nov 2024, at 00:25, Thom Brown <[email protected]> wrote:
>
> Unfortunately I didn't gather much information when it was occuring, and prioritised getting rid of the process blocking replay. I just attached gdb to it, got a backtrace and then "print ProcessInterrupts()".
FWIW we diagnosed that problem in the recent thread "IPC/MultixactCreation on the Standby server" [0].
Proposed fix is non-trivial. I'm trying to asses how many reports we had about this problem. Did you ever observe this problem again?
Thanks!
Best regards, Andrey Borodin.
[0] https://www.postgresql.org/message-id/[email protected]
^ permalink raw reply [nested|flat] 90+ messages in thread
* [PATCH v33 4/5] Add CONCURRENTLY option to REPACK command.
@ 2026-01-27 10:48 Antonin Houska <[email protected]>
0 siblings, 0 replies; 90+ messages in thread
From: Antonin Houska @ 2026-01-27 10:48 UTC (permalink / raw)
The REPACK command copies the relation data into a new file, creates new
indexes and eventually swaps the files. To make sure that the old file does
not change during the copying, the relation is locked in an exclusive mode,
which prevents applications from both reading and writing. (To keep the data
consistent, we'd only need to prevent the applications from writing, but even
reading needs to be blocked before we can swap the files - otherwise some
applications could continue using the old file. Since we should not request a
stronger lock without releasing the weaker one first, we acquire the exclusive
lock in the beginning and keep it till the end of the processing.)
This patch introduces an alternative workflow, which only requires the
exclusive lock when the relation (and index) files are being swapped.
(Supposedly, the swapping should be pretty fast.) On the other hand, when we
copy the data to the new file, we allow applications to read from the relation
and even to write to it.
First, we scan the relation using a "historic snapshot", and insert all the
tuples satisfying this snapshot into the new file.
Second, logical decoding is used to capture the data changes done by
applications during the copying (i.e. changes that do not satisfy the historic
snapshot mentioned above), and those are applied to the new file before we
acquire the exclusive lock that we need to swap the files. (Of course, more
data changes can take place while we are waiting for the lock - these will be
applied to the new file after we have acquired the lock, before we swap the
files.)
Since the logical decoding system, during its startup, waits until all the
transactions which already have XID assigned have finished, there is a risk of
deadlock if a transaction that already changed anything in the database tries
to acquire a conflicting lock on the table REPACK CONCURRENTLY is working
on. As an example, consider transaction running CREATE INDEX command on the
table that is being REPACKed CONCURRENTLY. On the other hand, DML commands
(INSERT, UPDATE, DELETE) are not a problem as their lock does not conflict
with REPACK CONCURRENTLY.
The current approach is that we accept the risk. If we tried to avoid it, it'd
be necessary to unlock the table before the logical decoding is setup and lock
it again afterwards. Such temporary unlocking would imply re-checking if the
table still meets all the requirements for REPACK CONCURRENTLY.
Like the existing implementation of REPACK, the variant with the CONCURRENTLY
option also requires an extra space for the new relation and index files
(which coexist with the old files for some time). In addition, the
CONCURRENTLY option might introduce a lag in releasing WAL segments for
archiving / recycling. This is due to the decoding of the data changes done by
applications concurrently. When copying the table contents into the new file,
we check the lag periodically. If it exceeds the size of a WAL segment, we
decode all the available WAL before resuming the copying. (Of course, the
changes are not applied until the whole table contents is copied.) A
background worker might be a better approach for the decoding - let's consider
implementing it in the future.
The WAL records produced by running DML commands on the new relation do not
contain enough information to be processed by the logical decoding system. All
we need from the new relation is the file (relfilenode), while the actual
relation is eventually dropped. Thus there is no point in replaying the DMLs
anywhere.
---
doc/src/sgml/monitoring.sgml | 37 +-
doc/src/sgml/mvcc.sgml | 12 +-
doc/src/sgml/ref/repack.sgml | 129 +-
src/Makefile | 1 +
src/backend/access/heap/heapam.c | 34 +-
src/backend/access/heap/heapam_handler.c | 259 ++-
src/backend/access/heap/rewriteheap.c | 6 +-
src/backend/catalog/system_views.sql | 19 +-
src/backend/commands/cluster.c | 1641 +++++++++++++++--
src/backend/commands/matview.c | 2 +-
src/backend/commands/tablecmds.c | 1 +
src/backend/commands/vacuum.c | 12 +-
src/backend/meson.build | 1 +
src/backend/replication/logical/decode.c | 37 +-
src/backend/replication/logical/snapbuild.c | 21 +
.../replication/pgoutput_repack/Makefile | 32 +
.../replication/pgoutput_repack/meson.build | 18 +
.../pgoutput_repack/pgoutput_repack.c | 239 +++
.../storage/lmgr/generate-lwlocknames.pl | 2 +-
src/backend/utils/time/snapmgr.c | 3 +-
src/bin/psql/tab-complete.in.c | 4 +-
src/include/access/heapam.h | 5 +-
src/include/access/heapam_xlog.h | 2 +
src/include/access/tableam.h | 10 +
src/include/commands/cluster.h | 88 +-
src/include/commands/progress.h | 17 +-
src/include/replication/snapbuild.h | 1 +
src/include/storage/lockdefs.h | 4 +-
src/include/utils/snapmgr.h | 2 +
src/test/modules/injection_points/Makefile | 2 +
.../injection_points/expected/repack.out | 113 ++
.../expected/repack_toast.out | 64 +
src/test/modules/injection_points/meson.build | 2 +
.../injection_points/specs/repack.spec | 142 ++
.../injection_points/specs/repack_toast.spec | 105 ++
src/test/regress/expected/rules.out | 19 +-
src/tools/pgindent/typedefs.list | 5 +
37 files changed, 2829 insertions(+), 262 deletions(-)
create mode 100644 src/backend/replication/pgoutput_repack/Makefile
create mode 100644 src/backend/replication/pgoutput_repack/meson.build
create mode 100644 src/backend/replication/pgoutput_repack/pgoutput_repack.c
create mode 100644 src/test/modules/injection_points/expected/repack.out
create mode 100644 src/test/modules/injection_points/expected/repack_toast.out
create mode 100644 src/test/modules/injection_points/specs/repack.spec
create mode 100644 src/test/modules/injection_points/specs/repack_toast.spec
diff --git a/doc/src/sgml/monitoring.sgml b/doc/src/sgml/monitoring.sgml
index 71c92ed53ef..ec97197461a 100644
--- a/doc/src/sgml/monitoring.sgml
+++ b/doc/src/sgml/monitoring.sgml
@@ -6239,14 +6239,35 @@ FROM pg_stat_get_backend_idset() AS backendid;
<row>
<entry role="catalog_table_entry"><para role="column_definition">
- <structfield>heap_tuples_written</structfield> <type>bigint</type>
+ <structfield>heap_tuples_inserted</structfield> <type>bigint</type>
</para>
<para>
- Number of heap tuples written.
+ Number of heap tuples inserted.
This counter only advances when the phase is
<literal>seq scanning heap</literal>,
- <literal>index scanning heap</literal>
- or <literal>writing new heap</literal>.
+ <literal>index scanning heap</literal>,
+ <literal>writing new heap</literal>
+ or <literal>catch-up</literal>.
+ </para></entry>
+ </row>
+
+ <row>
+ <entry role="catalog_table_entry"><para role="column_definition">
+ <structfield>heap_tuples_updated</structfield> <type>bigint</type>
+ </para>
+ <para>
+ Number of heap tuples updated.
+ This counter only advances when the phase is <literal>catch-up</literal>.
+ </para></entry>
+ </row>
+
+ <row>
+ <entry role="catalog_table_entry"><para role="column_definition">
+ <structfield>heap_tuples_deleted</structfield> <type>bigint</type>
+ </para>
+ <para>
+ Number of heap tuples deleted.
+ This counter only advances when the phase is <literal>catch-up</literal>.
</para></entry>
</row>
@@ -6327,6 +6348,14 @@ FROM pg_stat_get_backend_idset() AS backendid;
<command>REPACK</command> is currently writing the new heap.
</entry>
</row>
+ <row>
+ <entry><literal>catch-up</literal></entry>
+ <entry>
+ <command>REPACK CONCURRENTLY</command> is currently processing the DML
+ commands that other transactions executed during any of the preceding
+ phases.
+ </entry>
+ </row>
<row>
<entry><literal>swapping relation files</literal></entry>
<entry>
diff --git a/doc/src/sgml/mvcc.sgml b/doc/src/sgml/mvcc.sgml
index 049ee75a4ba..0f5c34af542 100644
--- a/doc/src/sgml/mvcc.sgml
+++ b/doc/src/sgml/mvcc.sgml
@@ -1833,15 +1833,17 @@ SELECT pg_advisory_lock(q.id) FROM
<title>Caveats</title>
<para>
- Some DDL commands, currently only <link linkend="sql-truncate"><command>TRUNCATE</command></link> and the
- table-rewriting forms of <link linkend="sql-altertable"><command>ALTER TABLE</command></link>, are not
+ Some commands, currently only <link linkend="sql-truncate"><command>TRUNCATE</command></link>, the
+ table-rewriting forms of <link linkend="sql-altertable"><command>ALTER
+ TABLE</command></link> and <command>REPACK</command> with
+ the <literal>CONCURRENTLY</literal> option, are not
MVCC-safe. This means that after the truncation or rewrite commits, the
table will appear empty to concurrent transactions, if they are using a
- snapshot taken before the DDL command committed. This will only be an
+ snapshot taken before the command committed. This will only be an
issue for a transaction that did not access the table in question
- before the DDL command started — any transaction that has done so
+ before the command started — any transaction that has done so
would hold at least an <literal>ACCESS SHARE</literal> table lock,
- which would block the DDL command until that transaction completes.
+ which would block the truncating or rewriting command until that transaction completes.
So these commands will not cause any apparent inconsistency in the
table contents for successive queries on the target table, but they
could cause visible inconsistency between the contents of the target
diff --git a/doc/src/sgml/ref/repack.sgml b/doc/src/sgml/ref/repack.sgml
index 61d5c2cdef1..30c43c49069 100644
--- a/doc/src/sgml/ref/repack.sgml
+++ b/doc/src/sgml/ref/repack.sgml
@@ -28,6 +28,7 @@ REPACK [ ( <replaceable class="parameter">option</replaceable> [, ...] ) ] USING
VERBOSE [ <replaceable class="parameter">boolean</replaceable> ]
ANALYZE [ <replaceable class="parameter">boolean</replaceable> ]
+ CONCURRENTLY [ <replaceable class="parameter">boolean</replaceable> ]
<phrase>and <replaceable class="parameter">table_and_columns</replaceable> is:</phrase>
@@ -54,7 +55,8 @@ REPACK [ ( <replaceable class="parameter">option</replaceable> [, ...] ) ] USING
processes every table and materialized view in the current database that
the current user has the <literal>MAINTAIN</literal> privilege on. This
form of <command>REPACK</command> cannot be executed inside a transaction
- block.
+ block. Also, this form is not allowed if
+ the <literal>CONCURRENTLY</literal> option is used.
</para>
<para>
@@ -67,7 +69,8 @@ REPACK [ ( <replaceable class="parameter">option</replaceable> [, ...] ) ] USING
When a table is being repacked, an <literal>ACCESS EXCLUSIVE</literal> lock
is acquired on it. This prevents any other database operations (both reads
and writes) from operating on the table until the <command>REPACK</command>
- is finished.
+ is finished. If you want to keep the table accessible during the repacking,
+ consider using the <literal>CONCURRENTLY</literal> option.
</para>
<refsect2 id="sql-repack-notes-on-clustering" xreflabel="Notes on Clustering">
@@ -195,6 +198,128 @@ REPACK [ ( <replaceable class="parameter">option</replaceable> [, ...] ) ] USING
</listitem>
</varlistentry>
+ <varlistentry>
+ <term><literal>CONCURRENTLY</literal></term>
+ <listitem>
+ <para>
+ Allow other transactions to use the table while it is being repacked.
+ </para>
+
+ <para>
+ Internally, <command>REPACK</command> copies the contents of the table
+ (ignoring dead tuples) into a new file, sorted by the specified index,
+ and also creates a new file for each index. Then it swaps the old and
+ new files for the table and all the indexes, and deletes the old
+ files. The <literal>ACCESS EXCLUSIVE</literal> lock is needed to make
+ sure that the old files do not change during the processing because the
+ changes would get lost due to the swap.
+ </para>
+
+ <para>
+ With the <literal>CONCURRENTLY</literal> option, the <literal>ACCESS
+ EXCLUSIVE</literal> lock is only acquired to swap the table and index
+ files. The data changes that took place during the creation of the new
+ table and index files are captured using logical decoding
+ (<xref linkend="logicaldecoding"/>) and applied before
+ the <literal>ACCESS EXCLUSIVE</literal> lock is requested. Thus the lock
+ is typically held only for the time needed to swap the files, which
+ should be pretty short. However, the time might still be noticeable if
+ too many data changes have been done to the table while
+ <command>REPACK</command> was waiting for the lock: those changes must
+ be processed just before the files are swapped, while the
+ <literal>ACCESS EXCLUSIVE</literal> lock is being held.
+ </para>
+
+ <para>
+ Note that <command>REPACK</command> with the
+ <literal>CONCURRENTLY</literal> option does not try to order the rows
+ inserted into the table after the repacking started. Also
+ note <command>REPACK</command> might fail to complete due to DDL
+ commands executed on the table by other transactions during the
+ repacking.
+ </para>
+
+ <note>
+ <para>
+ In addition to the temporary space requirements explained in
+ <xref linkend="sql-repack-notes-on-resources"/>,
+ the <literal>CONCURRENTLY</literal> option can add to the usage of
+ temporary space a bit more. The reason is that other transactions can
+ perform DML operations which cannot be applied to the new file until
+ <command>REPACK</command> has copied all the tuples from the old
+ file. Thus the tuples inserted into the old file during the copying are
+ also stored separately in a temporary file, so they can eventually be
+ applied to the new file.
+ </para>
+
+ <para>
+ Furthermore, the data changes performed during the copying are
+ extracted from <link linkend="wal">write-ahead log</link> (WAL), and
+ this extraction (decoding) only takes place when certain amount of WAL
+ has been written. Therefore, WAL removal can be delayed by this
+ threshold. Currently the threshold is equal to the value of
+ the <link linkend="guc-wal-segment-size"><varname>wal_segment_size</varname></link>
+ configuration parameter.
+ </para>
+ </note>
+
+ <para>
+ The <literal>CONCURRENTLY</literal> option cannot be used in the
+ following cases:
+
+ <itemizedlist>
+ <listitem>
+ <para>
+ The table is <literal>UNLOGGED</literal>.
+ </para>
+ </listitem>
+
+ <listitem>
+ <para>
+ The table is partitioned.
+ </para>
+ </listitem>
+
+ <listitem>
+ <para>
+ The table is a system catalog or a <acronym>TOAST</acronym> table.
+ </para>
+ </listitem>
+
+ <listitem>
+ <para>
+ <command>REPACK</command> is executed inside a transaction block.
+ </para>
+ </listitem>
+
+ <listitem>
+ <para>
+ The <link linkend="guc-wal-level"><varname>wal_level</varname></link>
+ configuration parameter is less than <literal>logical</literal>.
+ </para>
+ </listitem>
+
+ <listitem>
+ <para>
+ The <link linkend="guc-max-replication-slots"><varname>max_replication_slots</varname></link>
+ configuration parameter does not allow for creation of an additional
+ replication slot.
+ </para>
+ </listitem>
+ </itemizedlist>
+ </para>
+
+ <warning>
+ <para>
+ <command>REPACK</command> with the <literal>CONCURRENTLY</literal>
+ option is not MVCC-safe, see <xref linkend="mvcc-caveats"/> for
+ details.
+ </para>
+ </warning>
+
+ </listitem>
+ </varlistentry>
+
<varlistentry>
<term><literal>VERBOSE</literal></term>
<listitem>
diff --git a/src/Makefile b/src/Makefile
index 2f31a2f20a7..b18c9a14ffa 100644
--- a/src/Makefile
+++ b/src/Makefile
@@ -23,6 +23,7 @@ SUBDIRS = \
interfaces \
backend/replication/libpqwalreceiver \
backend/replication/pgoutput \
+ backend/replication/pgoutput_repack \
fe_utils \
bin \
pl \
diff --git a/src/backend/access/heap/heapam.c b/src/backend/access/heap/heapam.c
index 3004964ab7f..a89a456135d 100644
--- a/src/backend/access/heap/heapam.c
+++ b/src/backend/access/heap/heapam.c
@@ -60,7 +60,8 @@ static HeapTuple heap_prepare_insert(Relation relation, HeapTuple tup,
static XLogRecPtr log_heap_update(Relation reln, Buffer oldbuf,
Buffer newbuf, HeapTuple oldtup,
HeapTuple newtup, HeapTuple old_key_tuple,
- bool all_visible_cleared, bool new_all_visible_cleared);
+ bool all_visible_cleared, bool new_all_visible_cleared,
+ bool walLogical);
#ifdef USE_ASSERT_CHECKING
static void check_lock_if_inplace_updateable_rel(Relation relation,
const ItemPointerData *otid,
@@ -2841,7 +2842,7 @@ xmax_infomask_changed(uint16 new_infomask, uint16 old_infomask)
TM_Result
heap_delete(Relation relation, const ItemPointerData *tid,
CommandId cid, Snapshot crosscheck, bool wait,
- TM_FailureData *tmfd, bool changingPart)
+ TM_FailureData *tmfd, bool changingPart, bool walLogical)
{
TM_Result result;
TransactionId xid = GetCurrentTransactionId();
@@ -3088,7 +3089,8 @@ l1:
* Compute replica identity tuple before entering the critical section so
* we don't PANIC upon a memory allocation failure.
*/
- old_key_tuple = ExtractReplicaIdentity(relation, &tp, true, &old_key_copied);
+ old_key_tuple = walLogical ?
+ ExtractReplicaIdentity(relation, &tp, true, &old_key_copied) : NULL;
/*
* If this is the first possibly-multixact-able operation in the current
@@ -3178,6 +3180,15 @@ l1:
xlrec.flags |= XLH_DELETE_CONTAINS_OLD_KEY;
}
+ /*
+ * Unlike UPDATE, DELETE is decoded even if there is no old key, so it
+ * does not help to clear both XLH_DELETE_CONTAINS_OLD_TUPLE and
+ * XLH_DELETE_CONTAINS_OLD_KEY. Thus we need an extra flag. TODO
+ * Consider not decoding tuples w/o the old tuple/key instead.
+ */
+ if (!walLogical)
+ xlrec.flags |= XLH_DELETE_NO_LOGICAL;
+
XLogBeginInsert();
XLogRegisterData(&xlrec, SizeOfHeapDelete);
@@ -3270,7 +3281,8 @@ simple_heap_delete(Relation relation, const ItemPointerData *tid)
result = heap_delete(relation, tid,
GetCurrentCommandId(true), InvalidSnapshot,
true /* wait for commit */ ,
- &tmfd, false /* changingPart */ );
+ &tmfd, false, /* changingPart */
+ true /* walLogical */ );
switch (result)
{
case TM_SelfModified:
@@ -3311,7 +3323,7 @@ TM_Result
heap_update(Relation relation, const ItemPointerData *otid, HeapTuple newtup,
CommandId cid, Snapshot crosscheck, bool wait,
TM_FailureData *tmfd, LockTupleMode *lockmode,
- TU_UpdateIndexes *update_indexes)
+ TU_UpdateIndexes *update_indexes, bool walLogical)
{
TM_Result result;
TransactionId xid = GetCurrentTransactionId();
@@ -4204,7 +4216,8 @@ l2:
newbuf, &oldtup, heaptup,
old_key_tuple,
all_visible_cleared,
- all_visible_cleared_new);
+ all_visible_cleared_new,
+ walLogical);
if (newbuf != buffer)
{
PageSetLSN(BufferGetPage(newbuf), recptr);
@@ -4562,7 +4575,8 @@ simple_heap_update(Relation relation, const ItemPointerData *otid, HeapTuple tup
result = heap_update(relation, otid, tup,
GetCurrentCommandId(true), InvalidSnapshot,
true /* wait for commit */ ,
- &tmfd, &lockmode, update_indexes);
+ &tmfd, &lockmode, update_indexes,
+ true /* walLogical */ );
switch (result)
{
case TM_SelfModified:
@@ -8918,7 +8932,8 @@ static XLogRecPtr
log_heap_update(Relation reln, Buffer oldbuf,
Buffer newbuf, HeapTuple oldtup, HeapTuple newtup,
HeapTuple old_key_tuple,
- bool all_visible_cleared, bool new_all_visible_cleared)
+ bool all_visible_cleared, bool new_all_visible_cleared,
+ bool walLogical)
{
xl_heap_update xlrec;
xl_heap_header xlhdr;
@@ -8929,7 +8944,8 @@ log_heap_update(Relation reln, Buffer oldbuf,
suffixlen = 0;
XLogRecPtr recptr;
Page page = BufferGetPage(newbuf);
- bool need_tuple_data = RelationIsLogicallyLogged(reln);
+ bool need_tuple_data = RelationIsLogicallyLogged(reln) &&
+ walLogical;
bool init;
int bufflags;
diff --git a/src/backend/access/heap/heapam_handler.c b/src/backend/access/heap/heapam_handler.c
index 7d4b48e5a97..908f1ef66c6 100644
--- a/src/backend/access/heap/heapam_handler.c
+++ b/src/backend/access/heap/heapam_handler.c
@@ -33,6 +33,7 @@
#include "catalog/index.h"
#include "catalog/storage.h"
#include "catalog/storage_xlog.h"
+#include "commands/cluster.h"
#include "commands/progress.h"
#include "executor/executor.h"
#include "miscadmin.h"
@@ -309,7 +310,8 @@ heapam_tuple_delete(Relation relation, ItemPointer tid, CommandId cid,
* the storage itself is cleaning the dead tuples by itself, it is the
* time to call the index tuple deletion also.
*/
- return heap_delete(relation, tid, cid, crosscheck, wait, tmfd, changingPart);
+ return heap_delete(relation, tid, cid, crosscheck, wait, tmfd, changingPart,
+ true);
}
@@ -328,7 +330,7 @@ heapam_tuple_update(Relation relation, ItemPointer otid, TupleTableSlot *slot,
tuple->t_tableOid = slot->tts_tableOid;
result = heap_update(relation, otid, tuple, cid, crosscheck, wait,
- tmfd, lockmode, update_indexes);
+ tmfd, lockmode, update_indexes, true);
ItemPointerCopy(&tuple->t_self, &slot->tts_tid);
/*
@@ -685,13 +687,15 @@ static void
heapam_relation_copy_for_cluster(Relation OldHeap, Relation NewHeap,
Relation OldIndex, bool use_sort,
TransactionId OldestXmin,
+ Snapshot snapshot,
+ LogicalDecodingContext *decoding_ctx,
TransactionId *xid_cutoff,
MultiXactId *multi_cutoff,
double *num_tuples,
double *tups_vacuumed,
double *tups_recently_dead)
{
- RewriteState rwstate;
+ RewriteState rwstate = NULL;
IndexScanDesc indexScan;
TableScanDesc tableScan;
HeapScanDesc heapScan;
@@ -705,6 +709,8 @@ heapam_relation_copy_for_cluster(Relation OldHeap, Relation NewHeap,
bool *isnull;
BufferHeapTupleTableSlot *hslot;
BlockNumber prev_cblock = InvalidBlockNumber;
+ bool concurrent = snapshot != NULL;
+ XLogRecPtr end_of_wal_prev = GetFlushRecPtr(NULL);
/* Remember if it's a system catalog */
is_system_catalog = IsSystemRelation(OldHeap);
@@ -720,9 +726,12 @@ heapam_relation_copy_for_cluster(Relation OldHeap, Relation NewHeap,
values = palloc_array(Datum, natts);
isnull = palloc_array(bool, natts);
- /* Initialize the rewrite operation */
- rwstate = begin_heap_rewrite(OldHeap, NewHeap, OldestXmin, *xid_cutoff,
- *multi_cutoff);
+ /*
+ * Initialize the rewrite operation.
+ */
+ if (!concurrent)
+ rwstate = begin_heap_rewrite(OldHeap, NewHeap, OldestXmin,
+ *xid_cutoff, *multi_cutoff);
/* Set up sorting if wanted */
@@ -737,6 +746,9 @@ heapam_relation_copy_for_cluster(Relation OldHeap, Relation NewHeap,
* Prepare to scan the OldHeap. To ensure we see recently-dead tuples
* that still need to be copied, we scan with SnapshotAny and use
* HeapTupleSatisfiesVacuum for the visibility test.
+ *
+ * In the CONCURRENTLY case, we do regular MVCC visibility tests, using
+ * the snapshot passed by the caller.
*/
if (OldIndex != NULL && !use_sort)
{
@@ -753,7 +765,9 @@ heapam_relation_copy_for_cluster(Relation OldHeap, Relation NewHeap,
tableScan = NULL;
heapScan = NULL;
- indexScan = index_beginscan(OldHeap, OldIndex, SnapshotAny, NULL, 0, 0);
+ indexScan = index_beginscan(OldHeap, OldIndex,
+ snapshot ? snapshot : SnapshotAny,
+ NULL, 0, 0);
index_rescan(indexScan, NULL, 0, NULL, 0);
}
else
@@ -762,7 +776,9 @@ heapam_relation_copy_for_cluster(Relation OldHeap, Relation NewHeap,
pgstat_progress_update_param(PROGRESS_REPACK_PHASE,
PROGRESS_REPACK_PHASE_SEQ_SCAN_HEAP);
- tableScan = table_beginscan(OldHeap, SnapshotAny, 0, (ScanKey) NULL);
+ tableScan = table_beginscan(OldHeap,
+ snapshot ? snapshot : SnapshotAny,
+ 0, (ScanKey) NULL);
heapScan = (HeapScanDesc) tableScan;
indexScan = NULL;
@@ -838,83 +854,90 @@ heapam_relation_copy_for_cluster(Relation OldHeap, Relation NewHeap,
buf = hslot->buffer;
/*
- * To be able to guarantee that we can set the hint bit, acquire an
- * exclusive lock on the old buffer. We need the hint bits, set in
- * heapam_relation_copy_for_cluster() -> HeapTupleSatisfiesVacuum(),
- * to be set, as otherwise reform_and_rewrite_tuple() ->
- * rewrite_heap_tuple() will get confused. Specifically,
- * rewrite_heap_tuple() checks for HEAP_XMAX_INVALID in the old tuple
- * to determine whether to check the old-to-new mapping hash table.
- *
- * It'd be better if we somehow could avoid setting hint bits on the
- * old page. One reason to use VACUUM FULL are very bloated tables -
- * rewriting most of the old table during VACUUM FULL doesn't exactly
- * help...
+ * Regarding CONCURRENTLY, see the comments on MVCC snapshot above.
*/
- LockBuffer(buf, BUFFER_LOCK_EXCLUSIVE);
-
- switch (HeapTupleSatisfiesVacuum(tuple, OldestXmin, buf))
+ if (!concurrent)
{
- case HEAPTUPLE_DEAD:
- /* Definitely dead */
- isdead = true;
- break;
- case HEAPTUPLE_RECENTLY_DEAD:
- *tups_recently_dead += 1;
- /* fall through */
- case HEAPTUPLE_LIVE:
- /* Live or recently dead, must copy it */
- isdead = false;
- break;
- case HEAPTUPLE_INSERT_IN_PROGRESS:
+ /*
+ * To be able to guarantee that we can set the hint bit, acquire an
+ * exclusive lock on the old buffer. We need the hint bits, set in
+ * heapam_relation_copy_for_cluster() -> HeapTupleSatisfiesVacuum(),
+ * to be set, as otherwise reform_and_rewrite_tuple() ->
+ * rewrite_heap_tuple() will get confused. Specifically,
+ * rewrite_heap_tuple() checks for HEAP_XMAX_INVALID in the old tuple
+ * to determine whether to check the old-to-new mapping hash table.
+ *
+ * It'd be better if we somehow could avoid setting hint bits on the
+ * old page. One reason to use VACUUM FULL are very bloated tables -
+ * rewriting most of the old table during VACUUM FULL doesn't exactly
+ * help...
+ */
+ LockBuffer(buf, BUFFER_LOCK_EXCLUSIVE);
- /*
- * Since we hold exclusive lock on the relation, normally the
- * only way to see this is if it was inserted earlier in our
- * own transaction. However, it can happen in system
- * catalogs, since we tend to release write lock before commit
- * there. Give a warning if neither case applies; but in any
- * case we had better copy it.
- */
- if (!is_system_catalog &&
- !TransactionIdIsCurrentTransactionId(HeapTupleHeaderGetXmin(tuple->t_data)))
- elog(WARNING, "concurrent insert in progress within table \"%s\"",
- RelationGetRelationName(OldHeap));
- /* treat as live */
- isdead = false;
- break;
- case HEAPTUPLE_DELETE_IN_PROGRESS:
-
- /*
- * Similar situation to INSERT_IN_PROGRESS case.
- */
- if (!is_system_catalog &&
- !TransactionIdIsCurrentTransactionId(HeapTupleHeaderGetUpdateXid(tuple->t_data)))
- elog(WARNING, "concurrent delete in progress within table \"%s\"",
- RelationGetRelationName(OldHeap));
- /* treat as recently dead */
- *tups_recently_dead += 1;
- isdead = false;
- break;
- default:
- elog(ERROR, "unexpected HeapTupleSatisfiesVacuum result");
- isdead = false; /* keep compiler quiet */
- break;
- }
-
- LockBuffer(buf, BUFFER_LOCK_UNLOCK);
-
- if (isdead)
- {
- *tups_vacuumed += 1;
- /* heap rewrite module still needs to see it... */
- if (rewrite_heap_dead_tuple(rwstate, tuple))
+ switch (HeapTupleSatisfiesVacuum(tuple, OldestXmin, buf))
{
- /* A previous recently-dead tuple is now known dead */
- *tups_vacuumed += 1;
- *tups_recently_dead -= 1;
+ case HEAPTUPLE_DEAD:
+ /* Definitely dead */
+ isdead = true;
+ break;
+ case HEAPTUPLE_RECENTLY_DEAD:
+ *tups_recently_dead += 1;
+ /* fall through */
+ case HEAPTUPLE_LIVE:
+ /* Live or recently dead, must copy it */
+ isdead = false;
+ break;
+ case HEAPTUPLE_INSERT_IN_PROGRESS:
+
+ /*
+ * As long as we hold exclusive lock on the relation,
+ * normally the only way to see this is if it was inserted
+ * earlier in our own transaction. However, it can happen
+ * in system catalogs, since we tend to release write lock
+ * before commit there. Give a warning if neither case
+ * applies; but in any case we had better copy it.
+ */
+ if (!is_system_catalog &&
+ !TransactionIdIsCurrentTransactionId(HeapTupleHeaderGetXmin(tuple->t_data)))
+ elog(WARNING, "concurrent insert in progress within table \"%s\"",
+ RelationGetRelationName(OldHeap));
+ /* treat as live */
+ isdead = false;
+ break;
+ case HEAPTUPLE_DELETE_IN_PROGRESS:
+
+ /*
+ * Similar situation to INSERT_IN_PROGRESS case.
+ */
+ if (!is_system_catalog &&
+ !TransactionIdIsCurrentTransactionId(HeapTupleHeaderGetUpdateXid(tuple->t_data)))
+ elog(WARNING, "concurrent delete in progress within table \"%s\"",
+ RelationGetRelationName(OldHeap));
+ /* treat as recently dead */
+ *tups_recently_dead += 1;
+ isdead = false;
+ break;
+ default:
+ elog(ERROR, "unexpected HeapTupleSatisfiesVacuum result");
+ isdead = false; /* keep compiler quiet */
+ break;
+ }
+
+ LockBuffer(buf, BUFFER_LOCK_UNLOCK);
+
+ if (isdead)
+ {
+ *tups_vacuumed += 1;
+ /* heap rewrite module still needs to see it... */
+ if (rewrite_heap_dead_tuple(rwstate, tuple))
+ {
+ /* A previous recently-dead tuple is now known dead */
+ *tups_vacuumed += 1;
+ *tups_recently_dead -= 1;
+ }
+
+ continue;
}
- continue;
}
*num_tuples += 1;
@@ -933,7 +956,7 @@ heapam_relation_copy_for_cluster(Relation OldHeap, Relation NewHeap,
{
const int ct_index[] = {
PROGRESS_REPACK_HEAP_TUPLES_SCANNED,
- PROGRESS_REPACK_HEAP_TUPLES_WRITTEN
+ PROGRESS_REPACK_HEAP_TUPLES_INSERTED
};
int64 ct_val[2];
@@ -948,6 +971,31 @@ heapam_relation_copy_for_cluster(Relation OldHeap, Relation NewHeap,
ct_val[1] = *num_tuples;
pgstat_progress_update_multi_param(2, ct_index, ct_val);
}
+
+ /*
+ * Process the WAL produced by the load, as well as by other
+ * transactions, so that the replication slot can advance and WAL does
+ * not pile up. Use wal_segment_size as a threshold so that we do not
+ * introduce the decoding overhead too often.
+ *
+ * Of course, we must not apply the changes until the initial load has
+ * completed.
+ *
+ * Note that our insertions into the new table should not be decoded
+ * as we (intentionally) do not write the logical decoding specific
+ * information to WAL.
+ */
+ if (concurrent)
+ {
+ XLogRecPtr end_of_wal;
+
+ end_of_wal = GetFlushRecPtr(NULL);
+ if ((end_of_wal - end_of_wal_prev) > wal_segment_size)
+ {
+ repack_decode_concurrent_changes(decoding_ctx, end_of_wal);
+ end_of_wal_prev = end_of_wal;
+ }
+ }
}
if (indexScan != NULL)
@@ -991,15 +1039,32 @@ heapam_relation_copy_for_cluster(Relation OldHeap, Relation NewHeap,
values, isnull,
rwstate);
/* Report n_tuples */
- pgstat_progress_update_param(PROGRESS_REPACK_HEAP_TUPLES_WRITTEN,
+ pgstat_progress_update_param(PROGRESS_REPACK_HEAP_TUPLES_INSERTED,
n_tuples);
+
+ /*
+ * Try to keep the amount of not-yet-decoded WAL small, like
+ * above.
+ */
+ if (concurrent)
+ {
+ XLogRecPtr end_of_wal;
+
+ end_of_wal = GetFlushRecPtr(NULL);
+ if ((end_of_wal - end_of_wal_prev) > wal_segment_size)
+ {
+ repack_decode_concurrent_changes(decoding_ctx, end_of_wal);
+ end_of_wal_prev = end_of_wal;
+ }
+ }
}
tuplesort_end(tuplesort);
}
/* Write out any remaining tuples, and fsync if needed */
- end_heap_rewrite(rwstate);
+ if (rwstate)
+ end_heap_rewrite(rwstate);
/* Clean up */
pfree(values);
@@ -2390,6 +2455,10 @@ heapam_scan_sample_next_tuple(TableScanDesc scan, SampleScanState *scanstate,
* SET WITHOUT OIDS.
*
* So, we must reconstruct the tuple from component Datums.
+ *
+ * If rwstate=NULL, use simple_heap_insert() instead of rewriting - in that
+ * case we still need to deform/form the tuple. TODO Shouldn't we rename the
+ * function, as might not do any rewrite?
*/
static void
reform_and_rewrite_tuple(HeapTuple tuple,
@@ -2412,8 +2481,28 @@ reform_and_rewrite_tuple(HeapTuple tuple,
copiedTuple = heap_form_tuple(newTupDesc, values, isnull);
- /* The heap rewrite module does the rest */
- rewrite_heap_tuple(rwstate, tuple, copiedTuple);
+ if (rwstate)
+ /* The heap rewrite module does the rest */
+ rewrite_heap_tuple(rwstate, tuple, copiedTuple);
+ else
+ {
+ /*
+ * Insert tuple when processing REPACK CONCURRENTLY.
+ *
+ * rewriteheap.c is not used in the CONCURRENTLY case because it'd be
+ * difficult to do the same in the catch-up phase (as the logical
+ * decoding does not provide us with sufficient visibility
+ * information). Thus we must use heap_insert() both during the
+ * catch-up and here.
+ *
+ * The following is like simple_heap_insert() except that we pass the
+ * flag to skip logical decoding: as soon as REPACK CONCURRENTLY swaps
+ * the relation files, it drops this relation, so no logical
+ * replication subscription should need the data.
+ */
+ heap_insert(NewHeap, copiedTuple, GetCurrentCommandId(true),
+ HEAP_INSERT_NO_LOGICAL, NULL);
+ }
heap_freetuple(copiedTuple);
}
diff --git a/src/backend/access/heap/rewriteheap.c b/src/backend/access/heap/rewriteheap.c
index 77fd48eb59e..96be7684660 100644
--- a/src/backend/access/heap/rewriteheap.c
+++ b/src/backend/access/heap/rewriteheap.c
@@ -620,9 +620,9 @@ raw_heap_insert(RewriteState state, HeapTuple tup)
int options = HEAP_INSERT_SKIP_FSM;
/*
- * While rewriting the heap for VACUUM FULL / CLUSTER, make sure data
- * for the TOAST table are not logically decoded. The main heap is
- * WAL-logged as XLOG FPI records, which are not logically decoded.
+ * While rewriting the heap for REPACK, make sure data for the TOAST
+ * table are not logically decoded. The main heap is WAL-logged as
+ * XLOG FPI records, which are not logically decoded.
*/
options |= HEAP_INSERT_NO_LOGICAL;
diff --git a/src/backend/catalog/system_views.sql b/src/backend/catalog/system_views.sql
index 3f05ba3083a..d79eab5670c 100644
--- a/src/backend/catalog/system_views.sql
+++ b/src/backend/catalog/system_views.sql
@@ -1298,16 +1298,19 @@ CREATE VIEW pg_stat_progress_repack AS
WHEN 2 THEN 'index scanning heap'
WHEN 3 THEN 'sorting tuples'
WHEN 4 THEN 'writing new heap'
- WHEN 5 THEN 'swapping relation files'
- WHEN 6 THEN 'rebuilding index'
- WHEN 7 THEN 'performing final cleanup'
+ WHEN 5 THEN 'catch-up'
+ WHEN 6 THEN 'swapping relation files'
+ WHEN 7 THEN 'rebuilding index'
+ WHEN 8 THEN 'performing final cleanup'
END AS phase,
CAST(S.param3 AS oid) AS repack_index_relid,
S.param4 AS heap_tuples_scanned,
- S.param5 AS heap_tuples_written,
- S.param6 AS heap_blks_total,
- S.param7 AS heap_blks_scanned,
- S.param8 AS index_rebuild_count
+ S.param5 AS heap_tuples_inserted,
+ S.param6 AS heap_tuples_updated,
+ S.param7 AS heap_tuples_deleted,
+ S.param8 AS heap_blks_total,
+ S.param9 AS heap_blks_scanned,
+ S.param10 AS index_rebuild_count
FROM pg_stat_get_progress_info('REPACK') AS S
LEFT JOIN pg_database D ON S.datid = D.oid;
@@ -1325,7 +1328,7 @@ CREATE VIEW pg_stat_progress_cluster AS
phase,
repack_index_relid AS cluster_index_relid,
heap_tuples_scanned,
- heap_tuples_written,
+ heap_tuples_inserted + heap_tuples_updated AS heap_tuples_written,
heap_blks_total,
heap_blks_scanned,
index_rebuild_count
diff --git a/src/backend/commands/cluster.c b/src/backend/commands/cluster.c
index e19675a6d05..03ccf10b782 100644
--- a/src/backend/commands/cluster.c
+++ b/src/backend/commands/cluster.c
@@ -1,8 +1,23 @@
/*-------------------------------------------------------------------------
*
* cluster.c
- * CLUSTER a table on an index. This is now also used for VACUUM FULL and
- * REPACK.
+ * Implementation of REPACK [CONCURRENTLY], also known as CLUSTER and
+ * VACUUM FULL.
+ *
+ * There are two somewhat different ways to rewrite a table. In non-
+ * concurrent mode, it's easy: take AccessExclusiveLock, create a new
+ * transient relation, copy the tuples over to the relfilenode of the new
+ * relation, swap the relfilenodes, then drop the old relation.
+ *
+ * In concurrent mode, we lock the table with only ShareUpdateExclusiveLock,
+ * then do an initial copy as above. However, while the tuples are being
+ * copied, concurrent transactions could modify the table. To cope with those
+ * changes, we rely on logical decoding to obtain them from WAL. The changes
+ * are accumulated in a tuplestore. Once the initial copy is complete, we
+ * read the changes from the tuplestore and re-apply them on the new heap.
+ * Then we upgrade our ShareUpdateExclusiveLock to AccessExclusiveLock and
+ * swap the relfilenodes. This way, the time we hold a strong lock on the
+ * table is much reduced, and the bloat is eliminated.
*
* There is hardly anything left of Paul Brown's original implementation...
*
@@ -26,6 +41,10 @@
#include "access/toast_internals.h"
#include "access/transam.h"
#include "access/xact.h"
+#include "access/xlog.h"
+#include "access/xlog_internal.h"
+#include "access/xloginsert.h"
+#include "access/xlogutils.h"
#include "catalog/catalog.h"
#include "catalog/dependency.h"
#include "catalog/heap.h"
@@ -33,6 +52,7 @@
#include "catalog/namespace.h"
#include "catalog/objectaccess.h"
#include "catalog/pg_am.h"
+#include "catalog/pg_control.h"
#include "catalog/pg_inherits.h"
#include "catalog/toasting.h"
#include "commands/cluster.h"
@@ -40,15 +60,21 @@
#include "commands/progress.h"
#include "commands/tablecmds.h"
#include "commands/vacuum.h"
+#include "executor/executor.h"
#include "miscadmin.h"
#include "optimizer/optimizer.h"
#include "pgstat.h"
+#include "replication/decode.h"
+#include "replication/logical.h"
+#include "replication/snapbuild.h"
#include "storage/bufmgr.h"
+#include "storage/ipc.h"
#include "storage/lmgr.h"
#include "storage/predicate.h"
#include "utils/acl.h"
#include "utils/fmgroids.h"
#include "utils/guc.h"
+#include "utils/injection_point.h"
#include "utils/inval.h"
#include "utils/lsyscache.h"
#include "utils/memutils.h"
@@ -68,12 +94,62 @@ typedef struct
Oid indexOid;
} RelToCluster;
+/*
+ * The following definitions are used for concurrent processing.
+ */
+
+/*
+ * The locators are used to avoid logical decoding of data that we do not need
+ * for our table.
+ */
+static RelFileLocator repacked_rel_locator = {.relNumber = InvalidOid};
+static RelFileLocator repacked_rel_toast_locator = {.relNumber = InvalidOid};
+
+/*
+ * Everything we need to call ExecInsertIndexTuples().
+ */
+typedef struct IndexInsertState
+{
+ ResultRelInfo *rri;
+ EState *estate;
+} IndexInsertState;
+
+/* The WAL segment being decoded. */
+static XLogSegNo repack_current_segment = 0;
+
+/*
+ * Information needed to apply concurrent data changes.
+ */
+typedef struct ChangeDest
+{
+ /* The relation the changes are applied to. */
+ Relation rel;
+
+ /*
+ * The following is needed to find the existing tuple if the change is
+ * UPDATE or DELETE. 'ident_key' should have all the fields except for
+ * 'sk_argument' initialized.
+ */
+ Relation ident_index;
+ ScanKey ident_key;
+ int ident_key_nentries;
+
+ /* Needed to update indexes of rel_dst. */
+ IndexInsertState *iistate;
+} ChangeDest;
+
static bool cluster_rel_recheck(RepackCommand cmd, Relation OldHeap,
- Oid indexOid, Oid userid, int options);
-static void rebuild_relation(Relation OldHeap, Relation index, bool verbose);
+ Oid indexOid, Oid userid, LOCKMODE lmode,
+ int options);
+static void check_repack_concurrently_requirements(Relation rel);
+static void rebuild_relation(Relation OldHeap, Relation index, bool verbose,
+ bool concurrent);
static void copy_table_data(Relation NewHeap, Relation OldHeap, Relation OldIndex,
- bool verbose, bool *pSwapToastByContent,
- TransactionId *pFreezeXid, MultiXactId *pCutoffMulti);
+ Snapshot snapshot, LogicalDecodingContext *decoding_ctx,
+ bool verbose,
+ bool *pSwapToastByContent,
+ TransactionId *pFreezeXid,
+ MultiXactId *pCutoffMulti);
static List *get_tables_to_repack(RepackCommand cmd, bool usingindex,
MemoryContext permcxt);
static List *get_tables_to_repack_partitioned(RepackCommand cmd,
@@ -81,13 +157,50 @@ static List *get_tables_to_repack_partitioned(RepackCommand cmd,
MemoryContext permcxt);
static bool cluster_is_permitted_for_relation(RepackCommand cmd,
Oid relid, Oid userid);
+
+static void begin_concurrent_repack(Relation rel);
+static void end_concurrent_repack(void);
+static LogicalDecodingContext *setup_logical_decoding(Oid relid);
+static HeapTuple get_changed_tuple(char *change);
+static void apply_concurrent_changes(RepackDecodingState *dstate,
+ ChangeDest *dest);
+static void apply_concurrent_insert(Relation rel, HeapTuple tup,
+ IndexInsertState *iistate,
+ TupleTableSlot *index_slot);
+static void apply_concurrent_update(Relation rel, HeapTuple tup,
+ HeapTuple tup_target,
+ IndexInsertState *iistate,
+ TupleTableSlot *index_slot);
+static void apply_concurrent_delete(Relation rel, HeapTuple tup_target);
+static HeapTuple find_target_tuple(Relation rel, ChangeDest *dest,
+ HeapTuple tup_key,
+ TupleTableSlot *ident_slot);
+static void process_concurrent_changes(LogicalDecodingContext *decoding_ctx,
+ XLogRecPtr end_of_wal,
+ ChangeDest *dest);
+static IndexInsertState *get_index_insert_state(Relation relation,
+ Oid ident_index_id,
+ Relation *ident_index_p);
+static ScanKey build_identity_key(Oid ident_idx_oid, Relation rel_src,
+ int *nentries);
+static void free_index_insert_state(IndexInsertState *iistate);
+static void cleanup_logical_decoding(LogicalDecodingContext *ctx);
+static void rebuild_relation_finish_concurrent(Relation NewHeap, Relation OldHeap,
+ LogicalDecodingContext *decoding_ctx,
+ TransactionId frozenXid,
+ MultiXactId cutoffMulti);
+static List *build_new_indexes(Relation NewHeap, Relation OldHeap, List *OldIndexes);
static Relation process_single_relation(RepackStmt *stmt,
+ LOCKMODE lockmode,
+ bool isTopLevel,
ClusterParams *params);
static Oid determine_clustered_index(Relation rel, bool usingindex,
const char *indexname);
static const char *RepackCommandAsString(RepackCommand cmd);
+#define REPL_PLUGIN_NAME "pgoutput_repack"
+
/*
* The repack code allows for processing multiple tables at once. Because
* of this, we cannot just run everything on a single transaction, or we
@@ -117,6 +230,7 @@ ExecRepack(ParseState *pstate, RepackStmt *stmt, bool isTopLevel)
ClusterParams params = {0};
Relation rel = NULL;
MemoryContext repack_context;
+ LOCKMODE lockmode;
List *rtcs;
/* Parse option list */
@@ -127,6 +241,16 @@ ExecRepack(ParseState *pstate, RepackStmt *stmt, bool isTopLevel)
else if (strcmp(opt->defname, "analyze") == 0 ||
strcmp(opt->defname, "analyse") == 0)
params.options |= defGetBoolean(opt) ? CLUOPT_ANALYZE : 0;
+ else if (strcmp(opt->defname, "concurrently") == 0 &&
+ defGetBoolean(opt))
+ {
+ if (stmt->command != REPACK_COMMAND_REPACK)
+ ereport(ERROR,
+ errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
+ errmsg("CONCURRENTLY option not supported for %s",
+ RepackCommandAsString(stmt->command)));
+ params.options |= CLUOPT_CONCURRENT;
+ }
else
ereport(ERROR,
errcode(ERRCODE_SYNTAX_ERROR),
@@ -136,13 +260,25 @@ ExecRepack(ParseState *pstate, RepackStmt *stmt, bool isTopLevel)
parser_errposition(pstate, opt->location));
}
+ /*
+ * Determine the lock mode expected by cluster_rel().
+ *
+ * In the exclusive case, we obtain AccessExclusiveLock right away to
+ * avoid lock-upgrade hazard in the single-transaction case. In the
+ * CONCURRENTLY case, the AccessExclusiveLock will only be used at the end
+ * of processing, supposedly for very short time. Until then, we'll have
+ * to unlock the relation temporarily, so there's no lock-upgrade hazard.
+ */
+ lockmode = (params.options & CLUOPT_CONCURRENT) == 0 ?
+ AccessExclusiveLock : ShareUpdateExclusiveLock;
+
/*
* If a single relation is specified, process it and we're done ... unless
* the relation is a partitioned table, in which case we fall through.
*/
if (stmt->relation != NULL)
{
- rel = process_single_relation(stmt, ¶ms);
+ rel = process_single_relation(stmt, lockmode, isTopLevel, ¶ms);
if (rel == NULL)
return; /* all done */
}
@@ -157,10 +293,29 @@ ExecRepack(ParseState *pstate, RepackStmt *stmt, bool isTopLevel)
errmsg("cannot %s multiple tables", "REPACK (ANALYZE)"));
/*
- * By here, we know we are in a multi-table situation. In order to avoid
- * holding locks for too long, we want to process each table in its own
- * transaction. This forces us to disallow running inside a user
- * transaction block.
+ * By here, we know we are in a multi-table situation.
+ *
+ * Concurrent processing is currently considered rather special (e.g. in
+ * terms of resources consumed) so it is not performed in bulk.
+ */
+ if (params.options & CLUOPT_CONCURRENT)
+ {
+ if (rel != NULL)
+ {
+ Assert(rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE);
+ ereport(ERROR,
+ errmsg("REPACK CONCURRENTLY not supported for partitioned tables"),
+ errhint("Consider running the command for individual partitions."));
+ }
+ else
+ ereport(ERROR,
+ errmsg("REPACK CONCURRENTLY requires explicit table name"));
+ }
+
+ /*
+ * In order to avoid holding locks for too long, we want to process each
+ * table in its own transaction. This forces us to disallow running
+ * inside a user transaction block.
*/
PreventInTransactionBlock(isTopLevel, RepackCommandAsString(stmt->command));
@@ -244,7 +399,7 @@ ExecRepack(ParseState *pstate, RepackStmt *stmt, bool isTopLevel)
* Open the target table, coping with the case where it has been
* dropped.
*/
- rel = try_table_open(rtc->tableOid, AccessExclusiveLock);
+ rel = try_table_open(rtc->tableOid, lockmode);
if (rel == NULL)
{
CommitTransactionCommand();
@@ -255,7 +410,7 @@ ExecRepack(ParseState *pstate, RepackStmt *stmt, bool isTopLevel)
PushActiveSnapshot(GetTransactionSnapshot());
/* Process this table */
- cluster_rel(stmt->command, rel, rtc->indexOid, ¶ms);
+ cluster_rel(stmt->command, rel, rtc->indexOid, ¶ms, isTopLevel);
/* cluster_rel closes the relation, but keeps lock */
PopActiveSnapshot();
@@ -284,22 +439,53 @@ ExecRepack(ParseState *pstate, RepackStmt *stmt, bool isTopLevel)
* If indexOid is InvalidOid, the table will be rewritten in physical order
* instead of index order.
*
+ * Note that, in the concurrent case, the function releases the lock at some
+ * point, in order to get AccessExclusiveLock for the final steps (i.e. to
+ * swap the relation files). To make things simpler, the caller should expect
+ * OldHeap to be closed on return, regardless CLUOPT_CONCURRENT. (The
+ * AccessExclusiveLock is kept till the end of the transaction.)
+ *
* 'cmd' indicates which command is being executed, to be used for error
* messages.
*/
void
cluster_rel(RepackCommand cmd, Relation OldHeap, Oid indexOid,
- ClusterParams *params)
+ ClusterParams *params, bool isTopLevel)
{
Oid tableOid = RelationGetRelid(OldHeap);
+ Relation index;
+ LOCKMODE lmode;
Oid save_userid;
int save_sec_context;
int save_nestlevel;
bool verbose = ((params->options & CLUOPT_VERBOSE) != 0);
bool recheck = ((params->options & CLUOPT_RECHECK) != 0);
- Relation index;
+ bool concurrent = ((params->options & CLUOPT_CONCURRENT) != 0);
- Assert(CheckRelationLockedByMe(OldHeap, AccessExclusiveLock, false));
+ /*
+ * The lock mode is AccessExclusiveLock for normal processing and
+ * ShareUpdateExclusiveLock for concurrent processing (so that SELECT,
+ * INSERT, UPDATE and DELETE commands work, but cluster_rel() cannot be
+ * called concurrently for the same relation).
+ */
+ lmode = !concurrent ? AccessExclusiveLock : ShareUpdateExclusiveLock;
+
+ /* There are specific requirements on concurrent processing. */
+ if (concurrent)
+ {
+ /*
+ * Make sure we have no XID assigned, otherwise call of
+ * setup_logical_decoding() can cause a deadlock.
+ *
+ * The existence of transaction block actually does not imply that XID
+ * was already assigned, but it very likely is. We might want to check
+ * the result of GetCurrentTransactionIdIfAny() instead, but that
+ * would be less clear from user's perspective.
+ */
+ PreventInTransactionBlock(isTopLevel, "REPACK (CONCURRENTLY)");
+
+ check_repack_concurrently_requirements(OldHeap);
+ }
/* Check for user-requested abort. */
CHECK_FOR_INTERRUPTS();
@@ -325,10 +511,13 @@ cluster_rel(RepackCommand cmd, Relation OldHeap, Oid indexOid,
* If this is a single-transaction CLUSTER, we can skip these tests. We
* *must* skip the one on indisclustered since it would reject an attempt
* to cluster a not-previously-clustered index.
+ *
+ * XXX move [some of] these comments to where the RECHECK flag is
+ * determined?
*/
if (recheck &&
!cluster_rel_recheck(cmd, OldHeap, indexOid, save_userid,
- params->options))
+ lmode, params->options))
goto out;
/*
@@ -343,6 +532,12 @@ cluster_rel(RepackCommand cmd, Relation OldHeap, Oid indexOid,
errmsg("cannot run %s on a shared catalog",
RepackCommandAsString(cmd)));
+ /*
+ * The CONCURRENTLY case should have been rejected earlier because it does
+ * not support system catalogs.
+ */
+ Assert(!(OldHeap->rd_rel->relisshared && concurrent));
+
/*
* Don't process temp tables of other backends ... their local buffer
* manager is not going to cope.
@@ -363,7 +558,7 @@ cluster_rel(RepackCommand cmd, Relation OldHeap, Oid indexOid,
if (OidIsValid(indexOid))
{
/* verify the index is good and lock it */
- check_index_is_clusterable(OldHeap, indexOid, AccessExclusiveLock);
+ check_index_is_clusterable(OldHeap, indexOid, lmode);
/* also open it */
index = index_open(indexOid, NoLock);
}
@@ -398,7 +593,9 @@ cluster_rel(RepackCommand cmd, Relation OldHeap, Oid indexOid,
if (OldHeap->rd_rel->relkind == RELKIND_MATVIEW &&
!RelationIsPopulated(OldHeap))
{
- relation_close(OldHeap, AccessExclusiveLock);
+ if (index)
+ index_close(index, lmode);
+ relation_close(OldHeap, lmode);
goto out;
}
@@ -411,11 +608,34 @@ cluster_rel(RepackCommand cmd, Relation OldHeap, Oid indexOid,
* invalid, because we move tuples around. Promote them to relation
* locks. Predicate locks on indexes will be promoted when they are
* reindexed.
+ *
+ * During concurrent processing, the heap as well as its indexes stay in
+ * operation, so we postpone this step until they are locked using
+ * AccessExclusiveLock near the end of the processing.
*/
- TransferPredicateLocksToHeapRelation(OldHeap);
+ if (!concurrent)
+ TransferPredicateLocksToHeapRelation(OldHeap);
/* rebuild_relation does all the dirty work */
- rebuild_relation(OldHeap, index, verbose);
+ PG_TRY();
+ {
+ /*
+ * For concurrent processing, make sure that our logical decoding
+ * ignores data changes of other tables than the one we are
+ * processing.
+ */
+ if (concurrent)
+ begin_concurrent_repack(OldHeap);
+
+ rebuild_relation(OldHeap, index, verbose, concurrent);
+ }
+ PG_FINALLY();
+ {
+ if (concurrent)
+ end_concurrent_repack();
+ }
+ PG_END_TRY();
+
/* rebuild_relation closes OldHeap, and index if valid */
out:
@@ -434,14 +654,14 @@ out:
*/
static bool
cluster_rel_recheck(RepackCommand cmd, Relation OldHeap, Oid indexOid,
- Oid userid, int options)
+ Oid userid, LOCKMODE lmode, int options)
{
Oid tableOid = RelationGetRelid(OldHeap);
/* Check that the user still has privileges for the relation */
if (!cluster_is_permitted_for_relation(cmd, tableOid, userid))
{
- relation_close(OldHeap, AccessExclusiveLock);
+ relation_close(OldHeap, lmode);
return false;
}
@@ -455,7 +675,7 @@ cluster_rel_recheck(RepackCommand cmd, Relation OldHeap, Oid indexOid,
*/
if (RELATION_IS_OTHER_TEMP(OldHeap))
{
- relation_close(OldHeap, AccessExclusiveLock);
+ relation_close(OldHeap, lmode);
return false;
}
@@ -466,7 +686,7 @@ cluster_rel_recheck(RepackCommand cmd, Relation OldHeap, Oid indexOid,
*/
if (!SearchSysCacheExists1(RELOID, ObjectIdGetDatum(indexOid)))
{
- relation_close(OldHeap, AccessExclusiveLock);
+ relation_close(OldHeap, lmode);
return false;
}
@@ -477,7 +697,7 @@ cluster_rel_recheck(RepackCommand cmd, Relation OldHeap, Oid indexOid,
if ((options & CLUOPT_RECHECK_ISCLUSTERED) != 0 &&
!get_index_isclustered(indexOid))
{
- relation_close(OldHeap, AccessExclusiveLock);
+ relation_close(OldHeap, lmode);
return false;
}
}
@@ -489,7 +709,7 @@ cluster_rel_recheck(RepackCommand cmd, Relation OldHeap, Oid indexOid,
* Verify that the specified heap and index are valid to cluster on
*
* Side effect: obtains lock on the index. The caller may
- * in some cases already have AccessExclusiveLock on the table, but
+ * in some cases already have a lock of the same strength on the table, but
* not in all cases so we can't rely on the table-level lock for
* protection here.
*/
@@ -619,17 +839,86 @@ mark_index_clustered(Relation rel, Oid indexOid, bool is_internal)
}
/*
- * rebuild_relation: rebuild an existing relation in index or physical order
- *
- * OldHeap: table to rebuild.
- * index: index to cluster by, or NULL to rewrite in physical order.
- *
- * On entry, heap and index (if one is given) must be open, and
- * AccessExclusiveLock held on them.
- * On exit, they are closed, but locks on them are not released.
+ * Check if the CONCURRENTLY option is legal for the relation.
*/
static void
-rebuild_relation(Relation OldHeap, Relation index, bool verbose)
+check_repack_concurrently_requirements(Relation rel)
+{
+ char relpersistence,
+ replident;
+ Oid ident_idx;
+
+ /* Data changes in system relations are not logically decoded. */
+ if (IsCatalogRelation(rel))
+ ereport(ERROR,
+ (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
+ errmsg("cannot repack relation \"%s\"",
+ RelationGetRelationName(rel)),
+ errhint("REPACK CONCURRENTLY is not supported for catalog relations.")));
+
+ /*
+ * reorderbuffer.c does not seem to handle processing of TOAST relation
+ * alone.
+ */
+ if (IsToastRelation(rel))
+ ereport(ERROR,
+ (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
+ errmsg("cannot repack relation \"%s\"",
+ RelationGetRelationName(rel)),
+ errhint("REPACK CONCURRENTLY is not supported for TOAST relations, unless the main relation is repacked too.")));
+
+ relpersistence = rel->rd_rel->relpersistence;
+ if (relpersistence != RELPERSISTENCE_PERMANENT)
+ ereport(ERROR,
+ (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
+ errmsg("cannot repack relation \"%s\"",
+ RelationGetRelationName(rel)),
+ errhint("REPACK CONCURRENTLY is only allowed for permanent relations.")));
+
+ /* With NOTHING, WAL does not contain the old tuple. */
+ replident = rel->rd_rel->relreplident;
+ if (replident == REPLICA_IDENTITY_NOTHING)
+ ereport(ERROR,
+ (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
+ errmsg("cannot repack relation \"%s\"",
+ RelationGetRelationName(rel)),
+ errhint("Relation \"%s\" has insufficient replication identity.",
+ RelationGetRelationName(rel))));
+
+ /*
+ * Identity index is not set if the replica identity is FULL, but PK might
+ * exist in such a case.
+ */
+ ident_idx = RelationGetReplicaIndex(rel);
+ if (!OidIsValid(ident_idx) && OidIsValid(rel->rd_pkindex))
+ ident_idx = rel->rd_pkindex;
+ if (!OidIsValid(ident_idx))
+ ereport(ERROR,
+ (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
+ errmsg("cannot process relation \"%s\"",
+ RelationGetRelationName(rel)),
+ errhint("Relation \"%s\" has no identity index.",
+ RelationGetRelationName(rel))));
+}
+
+
+/*
+ * rebuild_relation: rebuild an existing relation in index or physical order
+ *
+ * OldHeap: table to rebuild. See cluster_rel() for comments on the required
+ * lock strength.
+ *
+ * index: index to cluster by, or NULL to rewrite in physical order.
+ *
+ * On entry, heap and index (if one is given) must be open, and the
+ * appropriate lock held on them -- AccessExclusiveLock for exclusive
+ * processing and ShareUpdateExclusiveLock for concurrent processing.
+ *
+ * On exit, they are closed, but still locked with AccessExclusiveLock.
+ * (The function handles the lock upgrade if 'concurrent' is true.)
+ */
+static void
+rebuild_relation(Relation OldHeap, Relation index, bool verbose, bool concurrent)
{
Oid tableOid = RelationGetRelid(OldHeap);
Oid accessMethod = OldHeap->rd_rel->relam;
@@ -637,13 +926,38 @@ rebuild_relation(Relation OldHeap, Relation index, bool verbose)
Oid OIDNewHeap;
Relation NewHeap;
char relpersistence;
- bool is_system_catalog;
bool swap_toast_by_content;
TransactionId frozenXid;
MultiXactId cutoffMulti;
+ LogicalDecodingContext *decoding_ctx = NULL;
+ Snapshot snapshot = NULL;
+#if USE_ASSERT_CHECKING
+ LOCKMODE lmode;
- Assert(CheckRelationLockedByMe(OldHeap, AccessExclusiveLock, false) &&
- (index == NULL || CheckRelationLockedByMe(index, AccessExclusiveLock, false)));
+ lmode = concurrent ? ShareUpdateExclusiveLock : AccessExclusiveLock;
+
+ Assert(CheckRelationLockedByMe(OldHeap, lmode, false));
+ Assert(index == NULL || CheckRelationLockedByMe(index, lmode, false));
+#endif
+
+ if (concurrent)
+ {
+ /*
+ * Prepare to capture the concurrent data changes.
+ *
+ * Note that this call waits for all transactions with XID already
+ * assigned to finish. If some of those transactions is waiting for a
+ * lock conflicting with ShareUpdateExclusiveLock on our table (e.g.
+ * it runs CREATE INDEX), we can end up in a deadlock. Not sure this
+ * risk is worth unlocking/locking the table (and its clustering
+ * index) and checking again if its still eligible for REPACK
+ * CONCURRENTLY.
+ */
+ decoding_ctx = setup_logical_decoding(tableOid);
+
+ snapshot = SnapBuildInitialSnapshotForRepack(decoding_ctx->snapshot_builder);
+ PushActiveSnapshot(snapshot);
+ }
/* for CLUSTER or REPACK USING INDEX, mark the index as the one to use */
if (index != NULL)
@@ -651,7 +965,6 @@ rebuild_relation(Relation OldHeap, Relation index, bool verbose)
/* Remember info about rel before closing OldHeap */
relpersistence = OldHeap->rd_rel->relpersistence;
- is_system_catalog = IsSystemRelation(OldHeap);
/*
* Create the transient table that will receive the re-ordered data.
@@ -667,30 +980,61 @@ rebuild_relation(Relation OldHeap, Relation index, bool verbose)
NewHeap = table_open(OIDNewHeap, NoLock);
/* Copy the heap data into the new table in the desired order */
- copy_table_data(NewHeap, OldHeap, index, verbose,
+ copy_table_data(NewHeap, OldHeap, index, snapshot, decoding_ctx, verbose,
&swap_toast_by_content, &frozenXid, &cutoffMulti);
+ /* The historic snapshot won't be needed anymore. */
+ if (snapshot)
+ {
+ PopActiveSnapshot();
+ UpdateActiveSnapshotCommandId();
+ }
- /* Close relcache entries, but keep lock until transaction commit */
- table_close(OldHeap, NoLock);
- if (index)
- index_close(index, NoLock);
+ if (concurrent)
+ {
+ Assert(!swap_toast_by_content);
- /*
- * Close the new relation so it can be dropped as soon as the storage is
- * swapped. The relation is not visible to others, so no need to unlock it
- * explicitly.
- */
- table_close(NewHeap, NoLock);
+ /*
+ * Close the index, but keep the lock. Both heaps will be closed by
+ * the following call.
+ */
+ if (index)
+ index_close(index, NoLock);
- /*
- * Swap the physical files of the target and transient tables, then
- * rebuild the target's indexes and throw away the transient table.
- */
- finish_heap_swap(tableOid, OIDNewHeap, is_system_catalog,
- swap_toast_by_content, false, true,
- frozenXid, cutoffMulti,
- relpersistence);
+ rebuild_relation_finish_concurrent(NewHeap, OldHeap, decoding_ctx,
+ frozenXid, cutoffMulti);
+
+ pgstat_progress_update_param(PROGRESS_REPACK_PHASE,
+ PROGRESS_REPACK_PHASE_FINAL_CLEANUP);
+
+ /* Done with decoding. */
+ cleanup_logical_decoding(decoding_ctx);
+ }
+ else
+ {
+ bool is_system_catalog = IsSystemRelation(OldHeap);
+
+ /* Close relcache entries, but keep lock until transaction commit */
+ table_close(OldHeap, NoLock);
+ if (index)
+ index_close(index, NoLock);
+
+ /*
+ * Close the new relation so it can be dropped as soon as the storage
+ * is swapped. The relation is not visible to others, so no need to
+ * unlock it explicitly.
+ */
+ table_close(NewHeap, NoLock);
+
+ /*
+ * Swap the physical files of the target and transient tables, then
+ * rebuild the target's indexes and throw away the transient table.
+ */
+ finish_heap_swap(tableOid, OIDNewHeap, is_system_catalog,
+ swap_toast_by_content, false, true, true,
+ frozenXid, cutoffMulti,
+ relpersistence);
+ }
}
@@ -825,15 +1169,19 @@ make_new_heap(Oid OIDOldHeap, Oid NewTableSpace, Oid NewAccessMethod,
/*
* Do the physical copying of table data.
*
+ * 'snapshot' and 'decoding_ctx': see table_relation_copy_for_cluster(). Pass
+ * iff concurrent processing is required.
+ *
* There are three output parameters:
* *pSwapToastByContent is set true if toast tables must be swapped by content.
* *pFreezeXid receives the TransactionId used as freeze cutoff point.
* *pCutoffMulti receives the MultiXactId used as a cutoff point.
*/
static void
-copy_table_data(Relation NewHeap, Relation OldHeap, Relation OldIndex, bool verbose,
- bool *pSwapToastByContent, TransactionId *pFreezeXid,
- MultiXactId *pCutoffMulti)
+copy_table_data(Relation NewHeap, Relation OldHeap, Relation OldIndex,
+ Snapshot snapshot, LogicalDecodingContext *decoding_ctx,
+ bool verbose, bool *pSwapToastByContent,
+ TransactionId *pFreezeXid, MultiXactId *pCutoffMulti)
{
Relation relRelation;
HeapTuple reltup;
@@ -850,6 +1198,10 @@ copy_table_data(Relation NewHeap, Relation OldHeap, Relation OldIndex, bool verb
int elevel = verbose ? INFO : DEBUG2;
PGRUsage ru0;
char *nspname;
+ bool concurrent = snapshot != NULL;
+ LOCKMODE lmode;
+
+ lmode = concurrent ? ShareUpdateExclusiveLock : AccessExclusiveLock;
pg_rusage_init(&ru0);
@@ -878,7 +1230,7 @@ copy_table_data(Relation NewHeap, Relation OldHeap, Relation OldIndex, bool verb
* will be held till end of transaction.
*/
if (OldHeap->rd_rel->reltoastrelid)
- LockRelationOid(OldHeap->rd_rel->reltoastrelid, AccessExclusiveLock);
+ LockRelationOid(OldHeap->rd_rel->reltoastrelid, lmode);
/*
* If both tables have TOAST tables, perform toast swap by content. It is
@@ -887,7 +1239,8 @@ copy_table_data(Relation NewHeap, Relation OldHeap, Relation OldIndex, bool verb
* swap by links. This is okay because swap by content is only essential
* for system catalogs, and we don't support schema changes for them.
*/
- if (OldHeap->rd_rel->reltoastrelid && NewHeap->rd_rel->reltoastrelid)
+ if (OldHeap->rd_rel->reltoastrelid && NewHeap->rd_rel->reltoastrelid &&
+ !concurrent)
{
*pSwapToastByContent = true;
@@ -908,6 +1261,10 @@ copy_table_data(Relation NewHeap, Relation OldHeap, Relation OldIndex, bool verb
* follow the toast pointers to the wrong place. (It would actually
* work for values copied over from the old toast table, but not for
* any values that we toast which were previously not toasted.)
+ *
+ * This would not work with CONCURRENTLY because we may need to delete
+ * TOASTed tuples from the new heap. With this hack, we'd delete them
+ * from the old heap.
*/
NewHeap->rd_toastoid = OldHeap->rd_rel->reltoastrelid;
}
@@ -983,7 +1340,9 @@ copy_table_data(Relation NewHeap, Relation OldHeap, Relation OldIndex, bool verb
* values (e.g. because the AM doesn't use freezing).
*/
table_relation_copy_for_cluster(OldHeap, NewHeap, OldIndex, use_sort,
- cutoffs.OldestXmin, &cutoffs.FreezeLimit,
+ cutoffs.OldestXmin, snapshot,
+ decoding_ctx,
+ &cutoffs.FreezeLimit,
&cutoffs.MultiXactCutoff,
&num_tuples, &tups_vacuumed,
&tups_recently_dead);
@@ -992,7 +1351,11 @@ copy_table_data(Relation NewHeap, Relation OldHeap, Relation OldIndex, bool verb
*pFreezeXid = cutoffs.FreezeLimit;
*pCutoffMulti = cutoffs.MultiXactCutoff;
- /* Reset rd_toastoid just to be tidy --- it shouldn't be looked at again */
+ /*
+ * Reset rd_toastoid just to be tidy --- it shouldn't be looked at again.
+ * In the CONCURRENTLY case, we need to set it again before applying the
+ * concurrent changes.
+ */
NewHeap->rd_toastoid = InvalidOid;
num_pages = RelationGetNumberOfBlocks(NewHeap);
@@ -1450,14 +1813,13 @@ finish_heap_swap(Oid OIDOldHeap, Oid OIDNewHeap,
bool swap_toast_by_content,
bool check_constraints,
bool is_internal,
+ bool reindex,
TransactionId frozenXid,
MultiXactId cutoffMulti,
char newrelpersistence)
{
ObjectAddress object;
Oid mapped_tables[4];
- int reindex_flags;
- ReindexParams reindex_params = {0};
int i;
/* Report that we are now swapping relation files */
@@ -1483,39 +1845,47 @@ finish_heap_swap(Oid OIDOldHeap, Oid OIDNewHeap,
if (is_system_catalog)
CacheInvalidateCatalog(OIDOldHeap);
- /*
- * Rebuild each index on the relation (but not the toast table, which is
- * all-new at this point). It is important to do this before the DROP
- * step because if we are processing a system catalog that will be used
- * during DROP, we want to have its indexes available. There is no
- * advantage to the other order anyway because this is all transactional,
- * so no chance to reclaim disk space before commit. We do not need a
- * final CommandCounterIncrement() because reindex_relation does it.
- *
- * Note: because index_build is called via reindex_relation, it will never
- * set indcheckxmin true for the indexes. This is OK even though in some
- * sense we are building new indexes rather than rebuilding existing ones,
- * because the new heap won't contain any HOT chains at all, let alone
- * broken ones, so it can't be necessary to set indcheckxmin.
- */
- reindex_flags = REINDEX_REL_SUPPRESS_INDEX_USE;
- if (check_constraints)
- reindex_flags |= REINDEX_REL_CHECK_CONSTRAINTS;
+ if (reindex)
+ {
+ int reindex_flags;
+ ReindexParams reindex_params = {0};
- /*
- * Ensure that the indexes have the same persistence as the parent
- * relation.
- */
- if (newrelpersistence == RELPERSISTENCE_UNLOGGED)
- reindex_flags |= REINDEX_REL_FORCE_INDEXES_UNLOGGED;
- else if (newrelpersistence == RELPERSISTENCE_PERMANENT)
- reindex_flags |= REINDEX_REL_FORCE_INDEXES_PERMANENT;
+ /*
+ * Rebuild each index on the relation (but not the toast table, which
+ * is all-new at this point). It is important to do this before the
+ * DROP step because if we are processing a system catalog that will
+ * be used during DROP, we want to have its indexes available. There
+ * is no advantage to the other order anyway because this is all
+ * transactional, so no chance to reclaim disk space before commit. We
+ * do not need a final CommandCounterIncrement() because
+ * reindex_relation does it.
+ *
+ * Note: because index_build is called via reindex_relation, it will
+ * never set indcheckxmin true for the indexes. This is OK even
+ * though in some sense we are building new indexes rather than
+ * rebuilding existing ones, because the new heap won't contain any
+ * HOT chains at all, let alone broken ones, so it can't be necessary
+ * to set indcheckxmin.
+ */
+ reindex_flags = REINDEX_REL_SUPPRESS_INDEX_USE;
+ if (check_constraints)
+ reindex_flags |= REINDEX_REL_CHECK_CONSTRAINTS;
- /* Report that we are now reindexing relations */
- pgstat_progress_update_param(PROGRESS_REPACK_PHASE,
- PROGRESS_REPACK_PHASE_REBUILD_INDEX);
+ /*
+ * Ensure that the indexes have the same persistence as the parent
+ * relation.
+ */
+ if (newrelpersistence == RELPERSISTENCE_UNLOGGED)
+ reindex_flags |= REINDEX_REL_FORCE_INDEXES_UNLOGGED;
+ else if (newrelpersistence == RELPERSISTENCE_PERMANENT)
+ reindex_flags |= REINDEX_REL_FORCE_INDEXES_PERMANENT;
- reindex_relation(NULL, OIDOldHeap, reindex_flags, &reindex_params);
+ /* Report that we are now reindexing relations */
+ pgstat_progress_update_param(PROGRESS_REPACK_PHASE,
+ PROGRESS_REPACK_PHASE_REBUILD_INDEX);
+
+ reindex_relation(NULL, OIDOldHeap, reindex_flags, &reindex_params);
+ }
/* Report that we are now doing clean up */
pgstat_progress_update_param(PROGRESS_REPACK_PHASE,
@@ -1559,6 +1929,17 @@ finish_heap_swap(Oid OIDOldHeap, Oid OIDNewHeap,
object.objectId = OIDNewHeap;
object.objectSubId = 0;
+ if (!reindex)
+ {
+ /*
+ * Make sure the changes in pg_class are visible. This is especially
+ * important if !swap_toast_by_content, so that the correct TOAST
+ * relation is dropped. (reindex_relation() above did not help in this
+ * case))
+ */
+ CommandCounterIncrement();
+ }
+
/*
* The new relation is local to our transaction and we know nothing
* depends on it, so DROP_RESTRICT should be OK.
@@ -1598,7 +1979,7 @@ finish_heap_swap(Oid OIDOldHeap, Oid OIDNewHeap,
/* Get the associated valid index to be renamed */
toastidx = toast_get_valid_index(newrel->rd_rel->reltoastrelid,
- NoLock);
+ AccessExclusiveLock);
/* rename the toast table ... */
snprintf(NewToastName, NAMEDATALEN, "pg_toast_%u",
@@ -1858,7 +2239,8 @@ cluster_is_permitted_for_relation(RepackCommand cmd, Oid relid, Oid userid)
* case, if an index name is given, it's up to the caller to resolve it.
*/
static Relation
-process_single_relation(RepackStmt *stmt, ClusterParams *params)
+process_single_relation(RepackStmt *stmt, LOCKMODE lockmode, bool isTopLevel,
+ ClusterParams *params)
{
Relation rel;
Oid tableOid;
@@ -1867,13 +2249,9 @@ process_single_relation(RepackStmt *stmt, ClusterParams *params)
Assert(stmt->command == REPACK_COMMAND_CLUSTER ||
stmt->command == REPACK_COMMAND_REPACK);
- /*
- * Find, lock, and check permissions on the table. We obtain
- * AccessExclusiveLock right away to avoid lock-upgrade hazard in the
- * single-transaction case.
- */
+ /* Find, lock, and check permissions on the table. */
tableOid = RangeVarGetRelidExtended(stmt->relation->relation,
- AccessExclusiveLock,
+ lockmode,
0,
RangeVarCallbackMaintainsTable,
NULL);
@@ -1905,13 +2283,14 @@ process_single_relation(RepackStmt *stmt, ClusterParams *params)
return rel;
else
{
- Oid indexOid;
+ Oid indexOid = InvalidOid;
indexOid = determine_clustered_index(rel, stmt->usingindex,
stmt->indexname);
if (OidIsValid(indexOid))
- check_index_is_clusterable(rel, indexOid, AccessExclusiveLock);
- cluster_rel(stmt->command, rel, indexOid, params);
+ check_index_is_clusterable(rel, indexOid, lockmode);
+
+ cluster_rel(stmt->command, rel, indexOid, params, isTopLevel);
/* Do an analyze, if requested */
if (params->options & CLUOPT_ANALYZE)
@@ -1994,3 +2373,1047 @@ RepackCommandAsString(RepackCommand cmd)
}
return "???"; /* keep compiler quiet */
}
+
+
+/*
+ * Call this function before REPACK CONCURRENTLY starts to setup logical
+ * decoding. It makes sure that other users of the table put enough
+ * information into WAL.
+ *
+ * The point is that at various places we expect that the table we're
+ * processing is treated like a system catalog. For example, we need to be
+ * able to scan it using a "historic snapshot" anytime during the processing
+ * (as opposed to scanning only at the start point of the decoding, as logical
+ * replication does during initial table synchronization), in order to apply
+ * concurrent UPDATE / DELETE commands.
+ *
+ * Note that TOAST table needs no attention here as it's not scanned using
+ * historic snapshot.
+ */
+static void
+begin_concurrent_repack(Relation rel)
+{
+ Oid toastrelid;
+
+ /*
+ * Avoid logical decoding of other relations by this backend. The lock we
+ * have guarantees that the actual locator cannot be changed concurrently:
+ * TRUNCATE needs AccessExclusiveLock.
+ */
+ Assert(CheckRelationLockedByMe(rel, ShareUpdateExclusiveLock, false));
+ repacked_rel_locator = rel->rd_locator;
+ toastrelid = rel->rd_rel->reltoastrelid;
+ if (OidIsValid(toastrelid))
+ {
+ Relation toastrel;
+
+ /* Avoid logical decoding of other TOAST relations. */
+ toastrel = table_open(toastrelid, AccessShareLock);
+ repacked_rel_toast_locator = toastrel->rd_locator;
+ table_close(toastrel, AccessShareLock);
+ }
+}
+
+/*
+ * Call this when done with REPACK CONCURRENTLY.
+ */
+static void
+end_concurrent_repack(void)
+{
+ /*
+ * Restore normal function of (future) logical decoding for this backend.
+ */
+ repacked_rel_locator.relNumber = InvalidOid;
+ repacked_rel_toast_locator.relNumber = InvalidOid;
+}
+
+/*
+ * Is this backend performing logical decoding on behalf of REPACK
+ * (CONCURRENTLY) ?
+ */
+bool
+am_decoding_for_repack(void)
+{
+ return OidIsValid(repacked_rel_locator.relNumber);
+}
+
+/*
+ * Does the WAL record contain a data change that this backend does not need
+ * to decode on behalf of REPACK (CONCURRENTLY)?
+ */
+bool
+change_useless_for_repack(XLogRecordBuffer *buf)
+{
+ XLogReaderState *r = buf->record;
+ RelFileLocator locator;
+
+ /* TOAST locator should not be set unless the main is. */
+ Assert(!OidIsValid(repacked_rel_toast_locator.relNumber) ||
+ OidIsValid(repacked_rel_locator.relNumber));
+
+ /*
+ * Backends not involved in REPACK (CONCURRENTLY) should not do the
+ * filtering.
+ */
+ if (!am_decoding_for_repack())
+ return false;
+
+ /*
+ * If the record does not contain the block 0, it's probably not INSERT /
+ * UPDATE / DELETE. In any case, we do not have enough information to
+ * filter the change out.
+ */
+ if (!XLogRecGetBlockTagExtended(r, 0, &locator, NULL, NULL, NULL))
+ return false;
+
+ /*
+ * Decode the change if it belongs to the table we are repacking, or if it
+ * belongs to its TOAST relation.
+ */
+ if (RelFileLocatorEquals(locator, repacked_rel_locator))
+ return false;
+ if (OidIsValid(repacked_rel_toast_locator.relNumber) &&
+ RelFileLocatorEquals(locator, repacked_rel_toast_locator))
+ return false;
+
+ /* Filter out changes of other tables. */
+ return true;
+}
+
+/*
+ * This function is much like pg_create_logical_replication_slot() except that
+ * the new slot is neither released (if anyone else could read changes from
+ * our slot, we could miss changes other backends do while we copy the
+ * existing data into temporary table), nor persisted (it's easier to handle
+ * crash by restarting all the work from scratch).
+ */
+static LogicalDecodingContext *
+setup_logical_decoding(Oid relid)
+{
+ Relation rel;
+ TupleDesc tupdesc;
+ LogicalDecodingContext *ctx;
+ RepackDecodingState *dstate = palloc0_object(RepackDecodingState);
+
+ /*
+ * REPACK CONCURRENTLY is not allowed in a transaction block, so this
+ * should never fire.
+ */
+ Assert(!TransactionIdIsValid(GetTopTransactionIdIfAny()));
+
+ /*
+ * A single backend should not execute multiple REPACK commands at a time,
+ * so use PID to make the slot unique.
+ */
+ snprintf(NameStr(dstate->slotname), NAMEDATALEN, "repack_%d", MyProcPid);
+
+ /*
+ * Make sure we can use logical decoding.
+ */
+ CheckSlotPermissions();
+ CheckLogicalDecodingRequirements();
+ /* RS_TEMPORARY so that the slot gets cleaned up on ERROR. */
+ ReplicationSlotCreate(NameStr(dstate->slotname), true, RS_TEMPORARY,
+ false, false, false);
+ EnsureLogicalDecodingEnabled();
+
+ /*
+ * Neither prepare_write nor do_write callback nor update_progress is
+ * useful for us.
+ */
+ ctx = CreateInitDecodingContext(REPL_PLUGIN_NAME,
+ NIL,
+ true,
+ InvalidXLogRecPtr,
+ XL_ROUTINE(.page_read = read_local_xlog_page,
+ .segment_open = wal_segment_open,
+ .segment_close = wal_segment_close),
+ NULL, NULL, NULL);
+
+ /*
+ * We don't have control on setting fast_forward, so at least check it.
+ */
+ Assert(!ctx->fast_forward);
+
+ DecodingContextFindStartpoint(ctx);
+
+ /* Some WAL records should have been read. */
+ Assert(ctx->reader->EndRecPtr != InvalidXLogRecPtr);
+
+ XLByteToSeg(ctx->reader->EndRecPtr, repack_current_segment,
+ wal_segment_size);
+
+ /*
+ * Setup structures to store decoded changes.
+ */
+ dstate->relid = relid;
+ dstate->tstore = tuplestore_begin_heap(false, false,
+ maintenance_work_mem);
+
+ /* Caller should already have the table locked. */
+ rel = table_open(relid, NoLock);
+ tupdesc = CreateTupleDescCopy(RelationGetDescr(rel));
+ dstate->tupdesc = tupdesc;
+ table_close(rel, NoLock);
+
+ /* Initialize the descriptor to store the changes ... */
+ dstate->tupdesc_change = CreateTemplateTupleDesc(1);
+
+ TupleDescInitEntry(dstate->tupdesc_change, 1, NULL, BYTEAOID, -1, 0);
+ /* ... as well as the corresponding slot. */
+ dstate->tsslot = MakeSingleTupleTableSlot(dstate->tupdesc_change,
+ &TTSOpsMinimalTuple);
+
+ dstate->resowner = ResourceOwnerCreate(CurrentResourceOwner,
+ "logical decoding");
+
+ ctx->output_writer_private = dstate;
+ return ctx;
+}
+
+/*
+ * Retrieve tuple from ConcurrentChange structure.
+ *
+ * The input data starts with the structure but it might not be appropriately
+ * aligned.
+ */
+static HeapTuple
+get_changed_tuple(char *change)
+{
+ HeapTupleData tup_data;
+ HeapTuple result;
+ char *src;
+
+ /*
+ * Ensure alignment before accessing the fields. (This is why we can't use
+ * heap_copytuple() instead of this function.)
+ */
+ src = change + offsetof(ConcurrentChange, tup_data);
+ memcpy(&tup_data, src, sizeof(HeapTupleData));
+
+ result = (HeapTuple) palloc(HEAPTUPLESIZE + tup_data.t_len);
+ memcpy(result, &tup_data, sizeof(HeapTupleData));
+ result->t_data = (HeapTupleHeader) ((char *) result + HEAPTUPLESIZE);
+ src = change + SizeOfConcurrentChange;
+ memcpy(result->t_data, src, result->t_len);
+
+ return result;
+}
+
+/*
+ * Decode logical changes from the WAL sequence up to end_of_wal.
+ */
+void
+repack_decode_concurrent_changes(LogicalDecodingContext *ctx,
+ XLogRecPtr end_of_wal)
+{
+ RepackDecodingState *dstate;
+ ResourceOwner resowner_old;
+
+ dstate = (RepackDecodingState *) ctx->output_writer_private;
+ resowner_old = CurrentResourceOwner;
+ CurrentResourceOwner = dstate->resowner;
+
+ PG_TRY();
+ {
+ while (ctx->reader->EndRecPtr < end_of_wal)
+ {
+ XLogRecord *record;
+ XLogSegNo segno_new;
+ char *errm = NULL;
+ XLogRecPtr end_lsn;
+
+ record = XLogReadRecord(ctx->reader, &errm);
+ if (errm)
+ elog(ERROR, "%s", errm);
+
+ if (record != NULL)
+ LogicalDecodingProcessRecord(ctx, ctx->reader);
+
+ /*
+ * If WAL segment boundary has been crossed, inform the decoding
+ * system that the catalog_xmin can advance. (We can confirm more
+ * often, but a filling a single WAL segment should not take much
+ * time.)
+ */
+ end_lsn = ctx->reader->EndRecPtr;
+ XLByteToSeg(end_lsn, segno_new, wal_segment_size);
+ if (segno_new != repack_current_segment)
+ {
+ LogicalConfirmReceivedLocation(end_lsn);
+ elog(DEBUG1, "REPACK: confirmed receive location %X/%X",
+ (uint32) (end_lsn >> 32), (uint32) end_lsn);
+ repack_current_segment = segno_new;
+ }
+
+ CHECK_FOR_INTERRUPTS();
+ }
+ InvalidateSystemCaches();
+ CurrentResourceOwner = resowner_old;
+ }
+ PG_CATCH();
+ {
+ /* clear all timetravel entries */
+ InvalidateSystemCaches();
+ CurrentResourceOwner = resowner_old;
+ PG_RE_THROW();
+ }
+ PG_END_TRY();
+}
+
+/*
+ * Apply changes stored in 'file'.
+ */
+static void
+apply_concurrent_changes(RepackDecodingState *dstate, ChangeDest *dest)
+{
+ Relation rel = dest->rel;
+ TupleTableSlot *index_slot,
+ *ident_slot;
+ HeapTuple tup_old = NULL;
+
+ if (dstate->nchanges == 0)
+ return;
+
+ /* TupleTableSlot is needed to pass the tuple to ExecInsertIndexTuples(). */
+ index_slot = MakeSingleTupleTableSlot(dstate->tupdesc, &TTSOpsHeapTuple);
+
+ /* A slot to fetch tuples from identity index. */
+ ident_slot = table_slot_create(rel, NULL);
+
+ while (tuplestore_gettupleslot(dstate->tstore, true, false,
+ dstate->tsslot))
+ {
+ bool shouldFree;
+ HeapTuple tup_change,
+ tup,
+ tup_exist;
+ char *change_raw,
+ *src;
+ ConcurrentChange change;
+ bool isnull[1];
+ Datum values[1];
+
+ CHECK_FOR_INTERRUPTS();
+
+ /* Get the change from the single-column tuple. */
+ tup_change = ExecFetchSlotHeapTuple(dstate->tsslot, false, &shouldFree);
+ heap_deform_tuple(tup_change, dstate->tupdesc_change, values, isnull);
+ Assert(!isnull[0]);
+
+ /* Make sure we access aligned data. */
+ change_raw = (char *) DatumGetByteaP(values[0]);
+ src = (char *) VARDATA(change_raw);
+ memcpy(&change, src, SizeOfConcurrentChange);
+
+ /*
+ * Extract the tuple from the change. The tuple is copied here because
+ * it might be assigned to 'tup_old', in which case it needs to
+ * survive into the next iteration.
+ */
+ tup = get_changed_tuple(src);
+
+ if (change.kind == CHANGE_UPDATE_OLD)
+ {
+ Assert(tup_old == NULL);
+ tup_old = tup;
+ }
+ else if (change.kind == CHANGE_INSERT)
+ {
+ Assert(tup_old == NULL);
+
+ apply_concurrent_insert(rel, tup, dest->iistate, index_slot);
+
+ pfree(tup);
+ }
+ else if (change.kind == CHANGE_UPDATE_NEW ||
+ change.kind == CHANGE_DELETE)
+ {
+ HeapTuple tup_key;
+
+ if (change.kind == CHANGE_UPDATE_NEW)
+ {
+ tup_key = tup_old != NULL ? tup_old : tup;
+ }
+ else
+ {
+ Assert(tup_old == NULL);
+ tup_key = tup;
+ }
+
+ /*
+ * Find the tuple to be updated or deleted.
+ */
+ tup_exist = find_target_tuple(rel, dest, tup_key, ident_slot);
+ if (tup_exist == NULL)
+ elog(ERROR, "failed to find target tuple");
+
+ if (change.kind == CHANGE_UPDATE_NEW)
+ apply_concurrent_update(rel, tup, tup_exist, dest->iistate,
+ index_slot);
+ else
+ apply_concurrent_delete(rel, tup_exist);
+
+ if (tup_old != NULL)
+ {
+ pfree(tup_old);
+ tup_old = NULL;
+ }
+
+ pfree(tup);
+ }
+ else
+ elog(ERROR, "unrecognized kind of change: %d", change.kind);
+
+ /*
+ * If a change was applied now, increment CID for next writes and
+ * update the snapshot so it sees the changes we've applied so far.
+ */
+ if (change.kind != CHANGE_UPDATE_OLD)
+ {
+ CommandCounterIncrement();
+ UpdateActiveSnapshotCommandId();
+ }
+
+ /* TTSOpsMinimalTuple has .get_heap_tuple==NULL. */
+ Assert(shouldFree);
+ pfree(tup_change);
+ }
+
+ tuplestore_clear(dstate->tstore);
+ dstate->nchanges = 0;
+
+ /* Cleanup. */
+ ExecDropSingleTupleTableSlot(index_slot);
+ ExecDropSingleTupleTableSlot(ident_slot);
+}
+
+static void
+apply_concurrent_insert(Relation rel, HeapTuple tup, IndexInsertState *iistate,
+ TupleTableSlot *index_slot)
+{
+ List *recheck;
+
+ /*
+ * Like simple_heap_insert(), but make sure that the INSERT is not
+ * logically decoded - see reform_and_rewrite_tuple() for more
+ * information.
+ */
+ heap_insert(rel, tup, GetCurrentCommandId(true), HEAP_INSERT_NO_LOGICAL,
+ NULL);
+
+ /*
+ * Update indexes.
+ *
+ * In case functions in the index need the active snapshot and caller
+ * hasn't set one.
+ */
+ ExecStoreHeapTuple(tup, index_slot, false);
+ recheck = ExecInsertIndexTuples(iistate->rri,
+ index_slot,
+ iistate->estate,
+ false, /* update */
+ false, /* noDupErr */
+ NULL, /* specConflict */
+ NIL, /* arbiterIndexes */
+ false /* onlySummarizing */
+ );
+
+ /*
+ * If recheck is required, it must have been performed on the source
+ * relation by now. (All the logical changes we process here are already
+ * committed.)
+ */
+ list_free(recheck);
+
+ pgstat_progress_incr_param(PROGRESS_REPACK_HEAP_TUPLES_INSERTED, 1);
+}
+
+static void
+apply_concurrent_update(Relation rel, HeapTuple tup, HeapTuple tup_target,
+ IndexInsertState *iistate, TupleTableSlot *index_slot)
+{
+ LockTupleMode lockmode;
+ TM_FailureData tmfd;
+ TU_UpdateIndexes update_indexes;
+ TM_Result res;
+ List *recheck;
+
+ /*
+ * Write the new tuple into the new heap. ('tup' gets the TID assigned
+ * here.)
+ *
+ * Do it like in simple_heap_update(), except for 'wal_logical' (and
+ * except for 'wait').
+ */
+ res = heap_update(rel, &tup_target->t_self, tup,
+ GetCurrentCommandId(true),
+ InvalidSnapshot,
+ false, /* no wait - only we are doing changes */
+ &tmfd, &lockmode, &update_indexes,
+ false /* wal_logical */ );
+ if (res != TM_Ok)
+ ereport(ERROR, (errmsg("failed to apply concurrent UPDATE")));
+
+ ExecStoreHeapTuple(tup, index_slot, false);
+
+ if (update_indexes != TU_None)
+ {
+ recheck = ExecInsertIndexTuples(iistate->rri,
+ index_slot,
+ iistate->estate,
+ true, /* update */
+ false, /* noDupErr */
+ NULL, /* specConflict */
+ NIL, /* arbiterIndexes */
+ /* onlySummarizing */
+ update_indexes == TU_Summarizing);
+ list_free(recheck);
+ }
+
+ pgstat_progress_incr_param(PROGRESS_REPACK_HEAP_TUPLES_UPDATED, 1);
+}
+
+static void
+apply_concurrent_delete(Relation rel, HeapTuple tup_target)
+{
+ TM_Result res;
+ TM_FailureData tmfd;
+
+ /*
+ * Delete tuple from the new heap.
+ *
+ * Do it like in simple_heap_delete(), except for 'wal_logical' (and
+ * except for 'wait').
+ */
+ res = heap_delete(rel, &tup_target->t_self, GetCurrentCommandId(true),
+ InvalidSnapshot, false,
+ &tmfd,
+ false, /* no wait - only we are doing changes */
+ false /* wal_logical */ );
+
+ if (res != TM_Ok)
+ ereport(ERROR, (errmsg("failed to apply concurrent DELETE")));
+
+ pgstat_progress_incr_param(PROGRESS_REPACK_HEAP_TUPLES_DELETED, 1);
+}
+
+/*
+ * Find the tuple to be updated or deleted.
+ *
+ * 'tup_key' is a tuple containing the key values for the scan.
+ */
+static HeapTuple
+find_target_tuple(Relation rel, ChangeDest *dest, HeapTuple tup_key,
+ TupleTableSlot *ident_slot)
+{
+ Relation ident_index = dest->ident_index;
+ IndexScanDesc scan;
+ Form_pg_index ident_form;
+ int2vector *ident_indkey;
+ HeapTuple result = NULL;
+
+ /* XXX no instrumentation for now */
+ scan = index_beginscan(rel, ident_index, GetActiveSnapshot(),
+ NULL, dest->ident_key_nentries, 0);
+
+ /*
+ * Scan key is passed by caller, so it does not have to be constructed
+ * multiple times. Key entries have all fields initialized, except for
+ * sk_argument.
+ */
+ index_rescan(scan, dest->ident_key, dest->ident_key_nentries, NULL, 0);
+
+ /* Info needed to retrieve key values from heap tuple. */
+ ident_form = ident_index->rd_index;
+ ident_indkey = &ident_form->indkey;
+
+ /* Use the incoming tuple to finalize the scan key. */
+ for (int i = 0; i < scan->numberOfKeys; i++)
+ {
+ ScanKey entry;
+ bool isnull;
+ int16 attno_heap;
+
+ entry = &scan->keyData[i];
+ attno_heap = ident_indkey->values[i];
+ entry->sk_argument = heap_getattr(tup_key,
+ attno_heap,
+ rel->rd_att,
+ &isnull);
+ Assert(!isnull);
+ }
+ if (index_getnext_slot(scan, ForwardScanDirection, ident_slot))
+ {
+ bool shouldFree;
+
+ result = ExecFetchSlotHeapTuple(ident_slot, false, &shouldFree);
+ /* TTSOpsBufferHeapTuple has .get_heap_tuple != NULL. */
+ Assert(!shouldFree);
+ }
+ index_endscan(scan);
+
+ return result;
+}
+
+/*
+ * Decode and apply concurrent changes.
+ */
+static void
+process_concurrent_changes(LogicalDecodingContext *decoding_ctx,
+ XLogRecPtr end_of_wal, ChangeDest *dest)
+{
+ RepackDecodingState *dstate;
+
+ pgstat_progress_update_param(PROGRESS_REPACK_PHASE,
+ PROGRESS_REPACK_PHASE_CATCH_UP);
+
+ dstate = (RepackDecodingState *) decoding_ctx->output_writer_private;
+
+ repack_decode_concurrent_changes(decoding_ctx, end_of_wal);
+
+ if (dstate->nchanges == 0)
+ return;
+
+ apply_concurrent_changes(dstate, dest);
+}
+
+/*
+ * Initialize IndexInsertState for index specified by ident_index_id.
+ *
+ * While doing that, also return the identity index in *ident_index_p.
+ */
+static IndexInsertState *
+get_index_insert_state(Relation relation, Oid ident_index_id,
+ Relation *ident_index_p)
+{
+ EState *estate;
+ int i;
+ IndexInsertState *result;
+ Relation ident_index = NULL;
+
+ result = (IndexInsertState *) palloc0(sizeof(IndexInsertState));
+ estate = CreateExecutorState();
+
+ result->rri = (ResultRelInfo *) palloc(sizeof(ResultRelInfo));
+ InitResultRelInfo(result->rri, relation, 0, 0, 0);
+ ExecOpenIndices(result->rri, false);
+
+ /*
+ * Find the relcache entry of the identity index so that we spend no extra
+ * effort to open / close it.
+ */
+ for (i = 0; i < result->rri->ri_NumIndices; i++)
+ {
+ Relation ind_rel;
+
+ ind_rel = result->rri->ri_IndexRelationDescs[i];
+ if (ind_rel->rd_id == ident_index_id)
+ ident_index = ind_rel;
+ }
+ if (ident_index == NULL)
+ elog(ERROR, "failed to open identity index");
+
+ /* Only initialize fields needed by ExecInsertIndexTuples(). */
+ result->estate = estate;
+
+ *ident_index_p = ident_index;
+ return result;
+}
+
+/*
+ * Build scan key to process logical changes.
+ */
+static ScanKey
+build_identity_key(Oid ident_idx_oid, Relation rel_src, int *nentries)
+{
+ Relation ident_idx_rel;
+ Form_pg_index ident_idx;
+ int n,
+ i;
+ ScanKey result;
+
+ Assert(OidIsValid(ident_idx_oid));
+ ident_idx_rel = index_open(ident_idx_oid, AccessShareLock);
+ ident_idx = ident_idx_rel->rd_index;
+ n = ident_idx->indnatts;
+ result = (ScanKey) palloc(sizeof(ScanKeyData) * n);
+ for (i = 0; i < n; i++)
+ {
+ ScanKey entry;
+ int16 relattno;
+ Form_pg_attribute att;
+ Oid opfamily,
+ opcintype,
+ opno,
+ opcode;
+
+ entry = &result[i];
+ relattno = ident_idx->indkey.values[i];
+ if (relattno >= 1)
+ {
+ TupleDesc desc;
+
+ desc = rel_src->rd_att;
+ att = TupleDescAttr(desc, relattno - 1);
+ }
+ else
+ elog(ERROR, "unexpected attribute number %d in index", relattno);
+
+ opfamily = ident_idx_rel->rd_opfamily[i];
+ opcintype = ident_idx_rel->rd_opcintype[i];
+ opno = get_opfamily_member(opfamily, opcintype, opcintype,
+ BTEqualStrategyNumber);
+
+ if (!OidIsValid(opno))
+ elog(ERROR, "failed to find = operator for type %u", opcintype);
+
+ opcode = get_opcode(opno);
+ if (!OidIsValid(opcode))
+ elog(ERROR, "failed to find = operator for operator %u", opno);
+
+ /* Initialize everything but argument. */
+ ScanKeyInit(entry,
+ i + 1,
+ BTEqualStrategyNumber, opcode,
+ (Datum) NULL);
+ entry->sk_collation = att->attcollation;
+ }
+ index_close(ident_idx_rel, AccessShareLock);
+
+ *nentries = n;
+ return result;
+}
+
+static void
+free_index_insert_state(IndexInsertState *iistate)
+{
+ ExecCloseIndices(iistate->rri);
+ FreeExecutorState(iistate->estate);
+ pfree(iistate->rri);
+ pfree(iistate);
+}
+
+static void
+cleanup_logical_decoding(LogicalDecodingContext *ctx)
+{
+ RepackDecodingState *dstate;
+
+ dstate = (RepackDecodingState *) ctx->output_writer_private;
+
+ ExecDropSingleTupleTableSlot(dstate->tsslot);
+ FreeTupleDesc(dstate->tupdesc_change);
+ FreeTupleDesc(dstate->tupdesc);
+ tuplestore_end(dstate->tstore);
+
+ FreeDecodingContext(ctx);
+
+ ReplicationSlotRelease();
+ ReplicationSlotDrop(NameStr(dstate->slotname), false);
+ pfree(dstate);
+}
+
+/*
+ * The final steps of rebuild_relation() for concurrent processing.
+ *
+ * On entry, NewHeap is locked in AccessExclusiveLock mode. OldHeap and its
+ * clustering index (if one is passed) are still locked in a mode that allows
+ * concurrent data changes. On exit, both tables and their indexes are closed,
+ * but locked in AccessExclusiveLock mode.
+ */
+static void
+rebuild_relation_finish_concurrent(Relation NewHeap, Relation OldHeap,
+ LogicalDecodingContext *decoding_ctx,
+ TransactionId frozenXid,
+ MultiXactId cutoffMulti)
+{
+ LOCKMODE lockmode_old PG_USED_FOR_ASSERTS_ONLY;
+ List *ind_oids_new;
+ Oid old_table_oid = RelationGetRelid(OldHeap);
+ Oid new_table_oid = RelationGetRelid(NewHeap);
+ List *ind_oids_old = RelationGetIndexList(OldHeap);
+ ListCell *lc,
+ *lc2;
+ char relpersistence;
+ bool is_system_catalog;
+ Oid ident_idx_old,
+ ident_idx_new;
+ XLogRecPtr wal_insert_ptr,
+ end_of_wal;
+ char dummy_rec_data = '\0';
+ Relation *ind_refs,
+ *ind_refs_p;
+ int nind;
+ ChangeDest chgdst;
+
+ /* Like in cluster_rel(). */
+ lockmode_old = ShareUpdateExclusiveLock;
+ Assert(CheckRelationLockedByMe(OldHeap, lockmode_old, false));
+ /* This is expected from the caller. */
+ Assert(CheckRelationLockedByMe(NewHeap, AccessExclusiveLock, false));
+
+ ident_idx_old = RelationGetReplicaIndex(OldHeap);
+
+ /*
+ * Unlike the exclusive case, we build new indexes for the new relation
+ * rather than swapping the storage and reindexing the old relation. The
+ * point is that the index build can take some time, so we do it before we
+ * get AccessExclusiveLock on the old heap and therefore we cannot swap
+ * the heap storage yet.
+ *
+ * index_create() will lock the new indexes using AccessExclusiveLock - no
+ * need to change that. At the same time, we use ShareUpdateExclusiveLock
+ * to lock the existing indexes - that should be enough to prevent others
+ * from changing them while we're repacking the relation. The lock on
+ * table should prevent others from changing the index column list, but
+ * might not be enough for commands like ALTER INDEX ... SET ... (Those
+ * are not necessarily dangerous, but can make user confused if the
+ * changes they do get lost due to REPACK.)
+ */
+ ind_oids_new = build_new_indexes(NewHeap, OldHeap, ind_oids_old);
+
+ /*
+ * Processing shouldn't start w/o valid identity index.
+ */
+ Assert(OidIsValid(ident_idx_old));
+
+ /* Find "identity index" on the new relation. */
+ ident_idx_new = InvalidOid;
+ forboth(lc, ind_oids_old, lc2, ind_oids_new)
+ {
+ Oid ind_old = lfirst_oid(lc);
+ Oid ind_new = lfirst_oid(lc2);
+
+ if (ident_idx_old == ind_old)
+ {
+ ident_idx_new = ind_new;
+ break;
+ }
+ }
+ if (!OidIsValid(ident_idx_new))
+
+ /*
+ * Should not happen, given our lock on the old relation.
+ */
+ ereport(ERROR,
+ (errmsg("identity index missing on the new relation")));
+
+ /* Gather information to apply concurrent changes. */
+ chgdst.rel = NewHeap;
+ chgdst.iistate = get_index_insert_state(NewHeap, ident_idx_new,
+ &chgdst.ident_index);
+ chgdst.ident_key = build_identity_key(ident_idx_new, OldHeap,
+ &chgdst.ident_key_nentries);
+
+ /*
+ * During testing, wait for another backend to perform concurrent data
+ * changes which we will process below.
+ */
+ INJECTION_POINT("repack-concurrently-before-lock", NULL);
+
+ /*
+ * Flush all WAL records inserted so far (possibly except for the last
+ * incomplete page, see GetInsertRecPtr), to minimize the amount of data
+ * we need to flush while holding exclusive lock on the source table.
+ */
+ wal_insert_ptr = GetInsertRecPtr();
+ XLogFlush(wal_insert_ptr);
+ end_of_wal = GetFlushRecPtr(NULL);
+
+ /*
+ * Apply concurrent changes first time, to minimize the time we need to
+ * hold AccessExclusiveLock. (Quite some amount of WAL could have been
+ * written during the data copying and index creation.)
+ */
+ process_concurrent_changes(decoding_ctx, end_of_wal, &chgdst);
+
+ /*
+ * Acquire AccessExclusiveLock on the table, its TOAST relation (if there
+ * is one), all its indexes, so that we can swap the files.
+ */
+ LockRelationOid(old_table_oid, AccessExclusiveLock);
+
+ /*
+ * Lock all indexes now, not only the clustering one: all indexes need to
+ * have their files swapped. While doing that, store their relation
+ * references in an array, to handle predicate locks below.
+ */
+ ind_refs_p = ind_refs = palloc_array(Relation, list_length(ind_oids_old));
+ nind = 0;
+ foreach_oid(ind_oid, ind_oids_old)
+ {
+ Relation index;
+
+ index = index_open(ind_oid, AccessExclusiveLock);
+
+ /*
+ * TODO 1) Do we need to check if ALTER INDEX was executed since the
+ * new index was created in build_new_indexes()? 2) Specifically for
+ * the clustering index, should check_index_is_clusterable() be called
+ * here? (Not sure about the latter: ShareUpdateExclusiveLock on the
+ * table probably blocks all commands that affect the result of
+ * check_index_is_clusterable().)
+ */
+ *ind_refs_p = index;
+ ind_refs_p++;
+ nind++;
+ }
+
+ /*
+ * Lock the OldHeap's TOAST relation exclusively - again, the lock is
+ * needed to swap the files.
+ */
+ if (OidIsValid(OldHeap->rd_rel->reltoastrelid))
+ LockRelationOid(OldHeap->rd_rel->reltoastrelid, AccessExclusiveLock);
+
+ /*
+ * Tuples and pages of the old heap will be gone, but the heap will stay.
+ */
+ TransferPredicateLocksToHeapRelation(OldHeap);
+ /* The same for indexes. */
+ for (int i = 0; i < nind; i++)
+ {
+ Relation index = ind_refs[i];
+
+ TransferPredicateLocksToHeapRelation(index);
+
+ /*
+ * References to indexes on the old relation are not needed anymore,
+ * however locks stay till the end of the transaction.
+ */
+ index_close(index, NoLock);
+ }
+ pfree(ind_refs);
+
+ /*
+ * Flush anything we see in WAL, to make sure that all changes committed
+ * while we were waiting for the exclusive lock are available for
+ * decoding. This should not be necessary if all backends had
+ * synchronous_commit set, but we can't rely on this setting.
+ *
+ * Unfortunately, GetInsertRecPtr() may lag behind the actual insert
+ * position, and GetLastImportantRecPtr() points at the start of the last
+ * record rather than at the end. Thus the simplest way to determine the
+ * insert position is to insert a dummy record and use its LSN.
+ *
+ * XXX Consider using GetLastImportantRecPtr() and adding the size of the
+ * last record (plus the total size of all the page headers the record
+ * spans)?
+ */
+ XLogBeginInsert();
+ XLogRegisterData(&dummy_rec_data, 1);
+ wal_insert_ptr = XLogInsert(RM_XLOG_ID, XLOG_NOOP);
+ XLogFlush(wal_insert_ptr);
+ end_of_wal = GetFlushRecPtr(NULL);
+
+ /* Apply the concurrent changes again. */
+ process_concurrent_changes(decoding_ctx, end_of_wal, &chgdst);
+
+ /* Remember info about rel before closing OldHeap */
+ relpersistence = OldHeap->rd_rel->relpersistence;
+ is_system_catalog = IsSystemRelation(OldHeap);
+
+ pgstat_progress_update_param(PROGRESS_REPACK_PHASE,
+ PROGRESS_REPACK_PHASE_SWAP_REL_FILES);
+
+ /*
+ * Even ShareUpdateExclusiveLock should have prevented others from
+ * creating / dropping indexes (even using the CONCURRENTLY option), so we
+ * do not need to check whether the lists match.
+ */
+ forboth(lc, ind_oids_old, lc2, ind_oids_new)
+ {
+ Oid ind_old = lfirst_oid(lc);
+ Oid ind_new = lfirst_oid(lc2);
+ Oid mapped_tables[4];
+
+ /* Zero out possible results from swapped_relation_files */
+ memset(mapped_tables, 0, sizeof(mapped_tables));
+
+ swap_relation_files(ind_old, ind_new,
+ (old_table_oid == RelationRelationId),
+ false, /* swap_toast_by_content */
+ true,
+ InvalidTransactionId,
+ InvalidMultiXactId,
+ mapped_tables);
+
+#ifdef USE_ASSERT_CHECKING
+
+ /*
+ * Concurrent processing is not supported for system relations, so
+ * there should be no mapped tables.
+ */
+ for (int i = 0; i < 4; i++)
+ Assert(mapped_tables[i] == 0);
+#endif
+ }
+
+ /* The new indexes must be visible for deletion. */
+ CommandCounterIncrement();
+
+ /* Close the old heap but keep lock until transaction commit. */
+ table_close(OldHeap, NoLock);
+ /* Close the new heap. (We didn't have to open its indexes). */
+ table_close(NewHeap, NoLock);
+
+ /* Cleanup what we don't need anymore. (And close the identity index.) */
+ pfree(chgdst.ident_key);
+ free_index_insert_state(chgdst.iistate);
+
+ /*
+ * Swap the relations and their TOAST relations and TOAST indexes. This
+ * also drops the new relation and its indexes.
+ *
+ * (System catalogs are currently not supported.)
+ */
+ Assert(!is_system_catalog);
+ finish_heap_swap(old_table_oid, new_table_oid,
+ is_system_catalog,
+ false, /* swap_toast_by_content */
+ false, true, false,
+ frozenXid, cutoffMulti,
+ relpersistence);
+}
+
+/*
+ * Build indexes on NewHeap according to those on OldHeap.
+ *
+ * OldIndexes is the list of index OIDs on OldHeap. The contained indexes end
+ * up locked using ShareUpdateExclusiveLock.
+ *
+ * A list of OIDs of the corresponding indexes created on NewHeap is
+ * returned. The order of items does match, so we can use these arrays to swap
+ * index storage.
+ */
+static List *
+build_new_indexes(Relation NewHeap, Relation OldHeap, List *OldIndexes)
+{
+ List *result = NIL;
+
+ pgstat_progress_update_param(PROGRESS_REPACK_PHASE,
+ PROGRESS_REPACK_PHASE_REBUILD_INDEX);
+
+ foreach_oid(ind_oid, OldIndexes)
+ {
+ Oid ind_oid_new;
+ char *newName;
+ Relation ind;
+
+ ind = index_open(ind_oid, ShareUpdateExclusiveLock);
+
+ newName = ChooseRelationName(get_rel_name(ind_oid),
+ NULL,
+ "repacknew",
+ get_rel_namespace(ind->rd_index->indrelid),
+ false);
+ ind_oid_new = index_create_copy(NewHeap, ind_oid,
+ ind->rd_rel->reltablespace, newName,
+ false);
+ result = lappend_oid(result, ind_oid_new);
+
+ index_close(ind, NoLock);
+ }
+
+ return result;
+}
diff --git a/src/backend/commands/matview.c b/src/backend/commands/matview.c
index 81a55a33ef2..ebc70f5bead 100644
--- a/src/backend/commands/matview.c
+++ b/src/backend/commands/matview.c
@@ -892,7 +892,7 @@ refresh_by_match_merge(Oid matviewOid, Oid tempOid, Oid relowner,
static void
refresh_by_heap_swap(Oid matviewOid, Oid OIDNewHeap, char relpersistence)
{
- finish_heap_swap(matviewOid, OIDNewHeap, false, false, true, true,
+ finish_heap_swap(matviewOid, OIDNewHeap, false, false, true, true, true,
RecentXmin, ReadNextMultiXactId(), relpersistence);
}
diff --git a/src/backend/commands/tablecmds.c b/src/backend/commands/tablecmds.c
index f976c0e5c7e..296387c7889 100644
--- a/src/backend/commands/tablecmds.c
+++ b/src/backend/commands/tablecmds.c
@@ -6025,6 +6025,7 @@ ATRewriteTables(AlterTableStmt *parsetree, List **wqueue, LOCKMODE lockmode,
finish_heap_swap(tab->relid, OIDNewHeap,
false, false, true,
!OidIsValid(tab->newTableSpace),
+ true,
RecentXmin,
ReadNextMultiXactId(),
persistence);
diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c
index aea998260e1..bce24d0f804 100644
--- a/src/backend/commands/vacuum.c
+++ b/src/backend/commands/vacuum.c
@@ -126,7 +126,7 @@ static void vac_truncate_clog(TransactionId frozenXID,
TransactionId lastSaneFrozenXid,
MultiXactId lastSaneMinMulti);
static bool vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params,
- BufferAccessStrategy bstrategy);
+ BufferAccessStrategy bstrategy, bool isTopLevel);
static double compute_parallel_delay(void);
static VacOptValue get_vacoptval_from_boolean(DefElem *def);
static bool vac_tid_reaped(ItemPointer itemptr, void *state);
@@ -629,7 +629,8 @@ vacuum(List *relations, const VacuumParams params, BufferAccessStrategy bstrateg
if (params.options & VACOPT_VACUUM)
{
- if (!vacuum_rel(vrel->oid, vrel->relation, params, bstrategy))
+ if (!vacuum_rel(vrel->oid, vrel->relation, params, bstrategy,
+ isTopLevel))
continue;
}
@@ -1999,7 +2000,7 @@ vac_truncate_clog(TransactionId frozenXID,
*/
static bool
vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params,
- BufferAccessStrategy bstrategy)
+ BufferAccessStrategy bstrategy, bool isTopLevel)
{
LOCKMODE lmode;
Relation rel;
@@ -2290,7 +2291,7 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params,
/* VACUUM FULL is a variant of REPACK; see cluster.c */
cluster_rel(REPACK_COMMAND_VACUUMFULL, rel, InvalidOid,
- &cluster_params);
+ &cluster_params, isTopLevel);
/* cluster_rel closes the relation, but keeps lock */
rel = NULL;
@@ -2333,7 +2334,8 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params,
toast_vacuum_params.options |= VACOPT_PROCESS_MAIN;
toast_vacuum_params.toast_parent = relid;
- vacuum_rel(toast_relid, NULL, toast_vacuum_params, bstrategy);
+ vacuum_rel(toast_relid, NULL, toast_vacuum_params, bstrategy,
+ isTopLevel);
}
/*
diff --git a/src/backend/meson.build b/src/backend/meson.build
index 712a857cdb4..3e43edf48a0 100644
--- a/src/backend/meson.build
+++ b/src/backend/meson.build
@@ -194,5 +194,6 @@ pg_test_mod_args = pg_mod_args + {
subdir('jit/llvm')
subdir('replication/libpqwalreceiver')
subdir('replication/pgoutput')
+subdir('replication/pgoutput_repack')
subdir('snowball')
subdir('utils/mb/conversion_procs')
diff --git a/src/backend/replication/logical/decode.c b/src/backend/replication/logical/decode.c
index 32af1249610..887873c93ac 100644
--- a/src/backend/replication/logical/decode.c
+++ b/src/backend/replication/logical/decode.c
@@ -33,6 +33,7 @@
#include "access/xlogreader.h"
#include "access/xlogrecord.h"
#include "catalog/pg_control.h"
+#include "commands/cluster.h"
#include "replication/decode.h"
#include "replication/logical.h"
#include "replication/message.h"
@@ -420,7 +421,8 @@ heap2_decode(LogicalDecodingContext *ctx, XLogRecordBuffer *buf)
{
case XLOG_HEAP2_MULTI_INSERT:
if (SnapBuildProcessChange(builder, xid, buf->origptr) &&
- !ctx->fast_forward)
+ !ctx->fast_forward &&
+ !change_useless_for_repack(buf))
DecodeMultiInsert(ctx, buf);
break;
case XLOG_HEAP2_NEW_CID:
@@ -467,6 +469,15 @@ heap_decode(LogicalDecodingContext *ctx, XLogRecordBuffer *buf)
TransactionId xid = XLogRecGetXid(buf->record);
SnapBuild *builder = ctx->snapshot_builder;
+ /*
+ * XXX Should we return here if change_useless_for_repack() returns true,
+ * instead of calling the function below? Unlike the fast-forward case, we
+ * shouldn't need the base snapshot for the containing transaction until
+ * we receive a change that belongs to the table being REPACKed. Thus it
+ * should be fine to skip SnapBuildProcessChange(), and therefore
+ * reorderbuffer.c can create the transaction later.
+ */
+
ReorderBufferProcessXid(ctx->reorder, xid, buf->origptr);
/*
@@ -484,7 +495,8 @@ heap_decode(LogicalDecodingContext *ctx, XLogRecordBuffer *buf)
{
case XLOG_HEAP_INSERT:
if (SnapBuildProcessChange(builder, xid, buf->origptr) &&
- !ctx->fast_forward)
+ !ctx->fast_forward &&
+ !change_useless_for_repack(buf))
DecodeInsert(ctx, buf);
break;
@@ -496,19 +508,22 @@ heap_decode(LogicalDecodingContext *ctx, XLogRecordBuffer *buf)
case XLOG_HEAP_HOT_UPDATE:
case XLOG_HEAP_UPDATE:
if (SnapBuildProcessChange(builder, xid, buf->origptr) &&
- !ctx->fast_forward)
+ !ctx->fast_forward &&
+ !change_useless_for_repack(buf))
DecodeUpdate(ctx, buf);
break;
case XLOG_HEAP_DELETE:
if (SnapBuildProcessChange(builder, xid, buf->origptr) &&
- !ctx->fast_forward)
+ !ctx->fast_forward &&
+ !change_useless_for_repack(buf))
DecodeDelete(ctx, buf);
break;
case XLOG_HEAP_TRUNCATE:
if (SnapBuildProcessChange(builder, xid, buf->origptr) &&
- !ctx->fast_forward)
+ !ctx->fast_forward &&
+ !change_useless_for_repack(buf))
DecodeTruncate(ctx, buf);
break;
@@ -524,7 +539,8 @@ heap_decode(LogicalDecodingContext *ctx, XLogRecordBuffer *buf)
case XLOG_HEAP_CONFIRM:
if (SnapBuildProcessChange(builder, xid, buf->origptr) &&
- !ctx->fast_forward)
+ !ctx->fast_forward &&
+ !change_useless_for_repack(buf))
DecodeSpecConfirm(ctx, buf);
break;
@@ -1021,6 +1037,15 @@ DecodeDelete(LogicalDecodingContext *ctx, XLogRecordBuffer *buf)
xlrec = (xl_heap_delete *) XLogRecGetData(r);
+ /*
+ * Ignore changes which are considered useless for logical
+ * decoding. Currently such changes are created by REPACK (CONCURRENTLY)
+ * when replays DELETE commands on the new table (which is not yet visible
+ * to other transactions).
+ */
+ if (xlrec->flags & XLH_DELETE_NO_LOGICAL)
+ return;
+
/* only interested in our database */
XLogRecGetBlockTag(r, 0, &target_locator, NULL, NULL);
if (target_locator.dbOid != ctx->slot->data.database)
diff --git a/src/backend/replication/logical/snapbuild.c b/src/backend/replication/logical/snapbuild.c
index a738ad8a864..ffe6aa7f7bb 100644
--- a/src/backend/replication/logical/snapbuild.c
+++ b/src/backend/replication/logical/snapbuild.c
@@ -486,6 +486,27 @@ SnapBuildInitialSnapshot(SnapBuild *builder)
return SnapBuildMVCCFromHistoric(snap, true);
}
+/*
+ * Build an MVCC snapshot for the initial data load performed by REPACK
+ * CONCURRENTLY command.
+ *
+ * The snapshot will only be used to scan one particular relation, which is
+ * treated like a catalog (therefore ->building_full_snapshot is not
+ * important), and the caller should already have a replication slot setup (so
+ * we do not set MyProc->xmin). XXX Do we yet need to add some restrictions?
+ */
+Snapshot
+SnapBuildInitialSnapshotForRepack(SnapBuild *builder)
+{
+ Snapshot snap;
+
+ Assert(builder->state == SNAPBUILD_CONSISTENT);
+ Assert(builder->building_full_snapshot);
+
+ snap = SnapBuildBuildSnapshot(builder);
+ return SnapBuildMVCCFromHistoric(snap, false);
+}
+
/*
* Turn a historic MVCC snapshot into an ordinary MVCC snapshot.
*
diff --git a/src/backend/replication/pgoutput_repack/Makefile b/src/backend/replication/pgoutput_repack/Makefile
new file mode 100644
index 00000000000..4efeb713b70
--- /dev/null
+++ b/src/backend/replication/pgoutput_repack/Makefile
@@ -0,0 +1,32 @@
+#-------------------------------------------------------------------------
+#
+# Makefile--
+# Makefile for src/backend/replication/pgoutput_repack
+#
+# IDENTIFICATION
+# src/backend/replication/pgoutput_repack
+#
+#-------------------------------------------------------------------------
+
+subdir = src/backend/replication/pgoutput_repack
+top_builddir = ../../../..
+include $(top_builddir)/src/Makefile.global
+
+OBJS = \
+ $(WIN32RES) \
+ pgoutput_repack.o
+PGFILEDESC = "pgoutput_repack - logical replication output plugin for REPACK command"
+NAME = pgoutput_repack
+
+all: all-shared-lib
+
+include $(top_srcdir)/src/Makefile.shlib
+
+install: all installdirs install-lib
+
+installdirs: installdirs-lib
+
+uninstall: uninstall-lib
+
+clean distclean: clean-lib
+ rm -f $(OBJS)
diff --git a/src/backend/replication/pgoutput_repack/meson.build b/src/backend/replication/pgoutput_repack/meson.build
new file mode 100644
index 00000000000..133e865a4a0
--- /dev/null
+++ b/src/backend/replication/pgoutput_repack/meson.build
@@ -0,0 +1,18 @@
+# Copyright (c) 2022-2024, PostgreSQL Global Development Group
+
+pgoutput_repack_sources = files(
+ 'pgoutput_repack.c',
+)
+
+if host_system == 'windows'
+ pgoutput_repack_sources += rc_lib_gen.process(win32ver_rc, extra_args: [
+ '--NAME', 'pgoutput_repack',
+ '--FILEDESC', 'pgoutput_repack - logical replication output plugin for REPACK command',])
+endif
+
+pgoutput_repack = shared_module('pgoutput_repack',
+ pgoutput_repack_sources,
+ kwargs: pg_mod_args,
+)
+
+backend_targets += pgoutput_repack
diff --git a/src/backend/replication/pgoutput_repack/pgoutput_repack.c b/src/backend/replication/pgoutput_repack/pgoutput_repack.c
new file mode 100644
index 00000000000..6b54ea040ac
--- /dev/null
+++ b/src/backend/replication/pgoutput_repack/pgoutput_repack.c
@@ -0,0 +1,239 @@
+/*-------------------------------------------------------------------------
+ *
+ * pgoutput_repack.c
+ * Logical Replication output plugin for REPACK command
+ *
+ * Copyright (c) 2012-2026, PostgreSQL Global Development Group
+ *
+ * IDENTIFICATION
+ * src/backend/replication/pgoutput_repack/pgoutput_repack.c
+ *
+ *-------------------------------------------------------------------------
+ */
+#include "postgres.h"
+
+#include "access/heaptoast.h"
+#include "commands/cluster.h"
+#include "replication/snapbuild.h"
+#include "utils/memutils.h"
+
+PG_MODULE_MAGIC;
+
+static void plugin_startup(LogicalDecodingContext *ctx,
+ OutputPluginOptions *opt, bool is_init);
+static void plugin_shutdown(LogicalDecodingContext *ctx);
+static void plugin_begin_txn(LogicalDecodingContext *ctx,
+ ReorderBufferTXN *txn);
+static void plugin_commit_txn(LogicalDecodingContext *ctx,
+ ReorderBufferTXN *txn, XLogRecPtr commit_lsn);
+static void plugin_change(LogicalDecodingContext *ctx, ReorderBufferTXN *txn,
+ Relation rel, ReorderBufferChange *change);
+static void store_change(LogicalDecodingContext *ctx,
+ ConcurrentChangeKind kind, HeapTuple tuple);
+
+void
+_PG_output_plugin_init(OutputPluginCallbacks *cb)
+{
+ cb->startup_cb = plugin_startup;
+ cb->begin_cb = plugin_begin_txn;
+ cb->change_cb = plugin_change;
+ cb->commit_cb = plugin_commit_txn;
+ cb->shutdown_cb = plugin_shutdown;
+}
+
+
+/* initialize this plugin */
+static void
+plugin_startup(LogicalDecodingContext *ctx, OutputPluginOptions *opt,
+ bool is_init)
+{
+ ctx->output_plugin_private = NULL;
+
+ /* Probably unnecessary, as we don't use the SQL interface ... */
+ opt->output_type = OUTPUT_PLUGIN_BINARY_OUTPUT;
+
+ if (ctx->output_plugin_options != NIL)
+ {
+ ereport(ERROR,
+ (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
+ errmsg("This plugin does not expect any options")));
+ }
+}
+
+static void
+plugin_shutdown(LogicalDecodingContext *ctx)
+{
+}
+
+/*
+ * As we don't release the slot during processing of particular table, there's
+ * no room for SQL interface, even for debugging purposes. Therefore we need
+ * neither OutputPluginPrepareWrite() nor OutputPluginWrite() in the plugin
+ * callbacks. (Although we might want to write custom callbacks, this API
+ * seems to be unnecessarily generic for our purposes.)
+ */
+
+/* BEGIN callback */
+static void
+plugin_begin_txn(LogicalDecodingContext *ctx, ReorderBufferTXN *txn)
+{
+}
+
+/* COMMIT callback */
+static void
+plugin_commit_txn(LogicalDecodingContext *ctx, ReorderBufferTXN *txn,
+ XLogRecPtr commit_lsn)
+{
+}
+
+/*
+ * Callback for individual changed tuples
+ */
+static void
+plugin_change(LogicalDecodingContext *ctx, ReorderBufferTXN *txn,
+ Relation relation, ReorderBufferChange *change)
+{
+ RepackDecodingState *dstate;
+
+ dstate = (RepackDecodingState *) ctx->output_writer_private;
+
+ /* Only interested in one particular relation. */
+ if (relation->rd_id != dstate->relid)
+ return;
+
+ /* Decode entry depending on its type */
+ switch (change->action)
+ {
+ case REORDER_BUFFER_CHANGE_INSERT:
+ {
+ HeapTuple newtuple;
+
+ newtuple = change->data.tp.newtuple;
+
+ /*
+ * Identity checks in the main function should have made this
+ * impossible.
+ */
+ if (newtuple == NULL)
+ elog(ERROR, "Incomplete insert info.");
+
+ store_change(ctx, CHANGE_INSERT, newtuple);
+ }
+ break;
+ case REORDER_BUFFER_CHANGE_UPDATE:
+ {
+ HeapTuple oldtuple,
+ newtuple;
+
+ oldtuple = change->data.tp.oldtuple;
+ newtuple = change->data.tp.newtuple;
+
+ if (newtuple == NULL)
+ elog(ERROR, "Incomplete update info.");
+
+ if (oldtuple != NULL)
+ store_change(ctx, CHANGE_UPDATE_OLD, oldtuple);
+
+ store_change(ctx, CHANGE_UPDATE_NEW, newtuple);
+ }
+ break;
+ case REORDER_BUFFER_CHANGE_DELETE:
+ {
+ HeapTuple oldtuple;
+
+ oldtuple = change->data.tp.oldtuple;
+
+ if (oldtuple == NULL)
+ elog(ERROR, "Incomplete delete info.");
+
+ store_change(ctx, CHANGE_DELETE, oldtuple);
+ }
+ break;
+ default:
+ /*
+ * Should not come here. This includes TRUNCATE of the table being
+ * processed. heap_decode() cannot check the file locator easily,
+ * but we assume that TRUNCATE uses AccessExclusiveLock on the
+ * table so it should not occur during REPACK (CONCURRENTLY).
+ */
+ Assert(false);
+ break;
+ }
+}
+
+/* Store concurrent data change. */
+static void
+store_change(LogicalDecodingContext *ctx, ConcurrentChangeKind kind,
+ HeapTuple tuple)
+{
+ RepackDecodingState *dstate;
+ char *change_raw;
+ ConcurrentChange change;
+ bool flattened = false;
+ Size size;
+ Datum values[1];
+ bool isnull[1];
+ char *dst;
+
+ dstate = (RepackDecodingState *) ctx->output_writer_private;
+
+ size = VARHDRSZ + SizeOfConcurrentChange;
+
+ /*
+ * ReorderBufferCommit() stores the TOAST chunks in its private memory
+ * context and frees them after having called apply_change(). Therefore
+ * we need flat copy (including TOAST) that we eventually copy into the
+ * memory context which is available to decode_concurrent_changes().
+ */
+ if (HeapTupleHasExternal(tuple))
+ {
+ /*
+ * toast_flatten_tuple_to_datum() might be more convenient but we
+ * don't want the decompression it does.
+ */
+ tuple = toast_flatten_tuple(tuple, dstate->tupdesc);
+ flattened = true;
+ }
+
+ size += tuple->t_len;
+ if (size >= MaxAllocSize)
+ elog(ERROR, "Change is too big.");
+
+ /* Construct the change. */
+ change_raw = (char *) palloc0(size);
+ SET_VARSIZE(change_raw, size);
+
+ /*
+ * Since the varlena alignment might not be sufficient for the structure,
+ * set the fields in a local instance and remember where it should
+ * eventually be copied.
+ */
+ change.kind = kind;
+ dst = (char *) VARDATA(change_raw);
+
+ /*
+ * Copy the tuple.
+ *
+ * Note: change->tup_data.t_data must be fixed on retrieval!
+ */
+ memcpy(&change.tup_data, tuple, sizeof(HeapTupleData));
+ memcpy(dst, &change, SizeOfConcurrentChange);
+ dst += SizeOfConcurrentChange;
+ memcpy(dst, tuple->t_data, tuple->t_len);
+
+ /* The data has been copied. */
+ if (flattened)
+ pfree(tuple);
+
+ /* Store as tuple of 1 bytea column. */
+ values[0] = PointerGetDatum(change_raw);
+ isnull[0] = false;
+ tuplestore_putvalues(dstate->tstore, dstate->tupdesc_change,
+ values, isnull);
+
+ /* Accounting. */
+ dstate->nchanges++;
+
+ /* Cleanup. */
+ pfree(change_raw);
+}
diff --git a/src/backend/storage/lmgr/generate-lwlocknames.pl b/src/backend/storage/lmgr/generate-lwlocknames.pl
index b49007167b0..2e7f1054e62 100644
--- a/src/backend/storage/lmgr/generate-lwlocknames.pl
+++ b/src/backend/storage/lmgr/generate-lwlocknames.pl
@@ -162,7 +162,7 @@ while (<$lwlocklist>)
die
"$wait_event_lwlocks[$lwlock_count] defined in wait_event_names.txt but "
- . " missing from lwlocklist.h"
+ . "missing from lwlocklist.h"
if $lwlock_count < scalar @wait_event_lwlocks;
die
diff --git a/src/backend/utils/time/snapmgr.c b/src/backend/utils/time/snapmgr.c
index 3af1b366adf..fdf3427b43f 100644
--- a/src/backend/utils/time/snapmgr.c
+++ b/src/backend/utils/time/snapmgr.c
@@ -214,7 +214,6 @@ static List *exportedSnapshots = NIL;
/* Prototypes for local functions */
static void UnregisterSnapshotNoOwner(Snapshot snapshot);
-static void FreeSnapshot(Snapshot snapshot);
static void SnapshotResetXmin(void);
/* ResourceOwner callbacks to track snapshot references */
@@ -659,7 +658,7 @@ CopySnapshot(Snapshot snapshot)
* FreeSnapshot
* Free the memory associated with a snapshot.
*/
-static void
+void
FreeSnapshot(Snapshot snapshot)
{
Assert(snapshot->regd_count == 0);
diff --git a/src/bin/psql/tab-complete.in.c b/src/bin/psql/tab-complete.in.c
index 2a1bb47ff03..0ec0f4c4790 100644
--- a/src/bin/psql/tab-complete.in.c
+++ b/src/bin/psql/tab-complete.in.c
@@ -5121,8 +5121,8 @@ match_previous_words(int pattern_id,
* one word, so the above test is correct.
*/
if (ends_with(prev_wd, '(') || ends_with(prev_wd, ','))
- COMPLETE_WITH("ANALYZE", "VERBOSE");
- else if (TailMatches("ANALYZE", "VERBOSE"))
+ COMPLETE_WITH("ANALYZE", "CONCURRENTLY", "VERBOSE");
+ else if (TailMatches("ANALYZE", "CONCURRENTLY", "VERBOSE"))
COMPLETE_WITH("ON", "OFF");
}
diff --git a/src/include/access/heapam.h b/src/include/access/heapam.h
index 3c0961ab36b..f3cf4e1f487 100644
--- a/src/include/access/heapam.h
+++ b/src/include/access/heapam.h
@@ -361,14 +361,15 @@ extern void heap_multi_insert(Relation relation, TupleTableSlot **slots,
BulkInsertState bistate);
extern TM_Result heap_delete(Relation relation, const ItemPointerData *tid,
CommandId cid, Snapshot crosscheck, bool wait,
- TM_FailureData *tmfd, bool changingPart);
+ TM_FailureData *tmfd, bool changingPart,
+ bool wal_logical);
extern void heap_finish_speculative(Relation relation, const ItemPointerData *tid);
extern void heap_abort_speculative(Relation relation, const ItemPointerData *tid);
extern TM_Result heap_update(Relation relation, const ItemPointerData *otid,
HeapTuple newtup,
CommandId cid, Snapshot crosscheck, bool wait,
TM_FailureData *tmfd, LockTupleMode *lockmode,
- TU_UpdateIndexes *update_indexes);
+ TU_UpdateIndexes *update_indexes, bool wal_logical);
extern TM_Result heap_lock_tuple(Relation relation, HeapTuple tuple,
CommandId cid, LockTupleMode mode, LockWaitPolicy wait_policy,
bool follow_updates,
diff --git a/src/include/access/heapam_xlog.h b/src/include/access/heapam_xlog.h
index ce3566ba949..f1f5495556b 100644
--- a/src/include/access/heapam_xlog.h
+++ b/src/include/access/heapam_xlog.h
@@ -104,6 +104,8 @@
#define XLH_DELETE_CONTAINS_OLD_KEY (1<<2)
#define XLH_DELETE_IS_SUPER (1<<3)
#define XLH_DELETE_IS_PARTITION_MOVE (1<<4)
+/* See heap_delete() */
+#define XLH_DELETE_NO_LOGICAL (1<<5)
/* convenience macro for checking whether any form of old tuple was logged */
#define XLH_DELETE_CONTAINS_OLD \
diff --git a/src/include/access/tableam.h b/src/include/access/tableam.h
index 7260b7b3d52..14928cd04a1 100644
--- a/src/include/access/tableam.h
+++ b/src/include/access/tableam.h
@@ -22,6 +22,7 @@
#include "access/xact.h"
#include "commands/vacuum.h"
#include "executor/tuptable.h"
+#include "replication/logical.h"
#include "storage/read_stream.h"
#include "utils/rel.h"
#include "utils/snapshot.h"
@@ -629,6 +630,8 @@ typedef struct TableAmRoutine
Relation OldIndex,
bool use_sort,
TransactionId OldestXmin,
+ Snapshot snapshot,
+ LogicalDecodingContext *decoding_ctx,
TransactionId *xid_cutoff,
MultiXactId *multi_cutoff,
double *num_tuples,
@@ -1658,6 +1661,10 @@ table_relation_copy_data(Relation rel, const RelFileLocator *newrlocator)
* not needed for the relation's AM
* - *xid_cutoff - ditto
* - *multi_cutoff - ditto
+ * - snapshot - if != NULL, ignore data changes done by transactions that this
+ * (MVCC) snapshot considers still in-progress or in the future.
+ * - decoding_ctx - logical decoding context, to capture concurrent data
+ * changes.
*
* Output parameters:
* - *xid_cutoff - rel's new relfrozenxid value, may be invalid
@@ -1670,6 +1677,8 @@ table_relation_copy_for_cluster(Relation OldTable, Relation NewTable,
Relation OldIndex,
bool use_sort,
TransactionId OldestXmin,
+ Snapshot snapshot,
+ LogicalDecodingContext *decoding_ctx,
TransactionId *xid_cutoff,
MultiXactId *multi_cutoff,
double *num_tuples,
@@ -1678,6 +1687,7 @@ table_relation_copy_for_cluster(Relation OldTable, Relation NewTable,
{
OldTable->rd_tableam->relation_copy_for_cluster(OldTable, NewTable, OldIndex,
use_sort, OldestXmin,
+ snapshot, decoding_ctx,
xid_cutoff, multi_cutoff,
num_tuples, tups_vacuumed,
tups_recently_dead);
diff --git a/src/include/commands/cluster.h b/src/include/commands/cluster.h
index 28741988478..6a5c476294a 100644
--- a/src/include/commands/cluster.h
+++ b/src/include/commands/cluster.h
@@ -13,10 +13,15 @@
#ifndef CLUSTER_H
#define CLUSTER_H
+#include "nodes/execnodes.h"
#include "nodes/parsenodes.h"
#include "parser/parse_node.h"
+#include "replication/decode.h"
+#include "replication/logical.h"
#include "storage/lock.h"
#include "utils/relcache.h"
+#include "utils/resowner.h"
+#include "utils/tuplestore.h"
/* flag bits for ClusterParams->options */
@@ -25,6 +30,8 @@
#define CLUOPT_RECHECK_ISCLUSTERED 0x04 /* recheck relation state for
* indisclustered */
#define CLUOPT_ANALYZE 0x08 /* do an ANALYZE */
+#define CLUOPT_CONCURRENT 0x10 /* allow concurrent data changes */
+
/* options for CLUSTER */
typedef struct ClusterParams
@@ -33,10 +40,84 @@ typedef struct ClusterParams
} ClusterParams;
+/*
+ * The following definitions are used by REPACK CONCURRENTLY.
+ */
+
+typedef enum
+{
+ CHANGE_INSERT,
+ CHANGE_UPDATE_OLD,
+ CHANGE_UPDATE_NEW,
+ CHANGE_DELETE
+} ConcurrentChangeKind;
+
+typedef struct ConcurrentChange
+{
+ /* See the enum above. */
+ ConcurrentChangeKind kind;
+
+ /*
+ * The actual tuple.
+ *
+ * The tuple data follows the ConcurrentChange structure. Before use make
+ * sure the tuple is correctly aligned (ConcurrentChange can be stored as
+ * bytea) and that tuple->t_data is fixed.
+ */
+ HeapTupleData tup_data;
+} ConcurrentChange;
+
+#define SizeOfConcurrentChange (offsetof(ConcurrentChange, tup_data) + \
+ sizeof(HeapTupleData))
+
+/*
+ * Logical decoding state.
+ *
+ * Here we store the data changes that we decode from WAL while the table
+ * contents is being copied to a new storage. Also the necessary metadata
+ * needed to apply these changes to the table is stored here.
+ */
+typedef struct RepackDecodingState
+{
+ /* The relation whose changes we're decoding. */
+ Oid relid;
+
+ /* Replication slot name. */
+ NameData slotname;
+
+ /*
+ * Decoded changes are stored here. Although we try to avoid excessive
+ * batches, it can happen that the changes need to be stored to disk. The
+ * tuplestore does this transparently.
+ */
+ Tuplestorestate *tstore;
+
+ /* The current number of changes in tstore. */
+ double nchanges;
+
+ /*
+ * Descriptor to store the ConcurrentChange structure serialized (bytea).
+ * We can't store the tuple directly because tuplestore only supports
+ * minimum tuple and we may need to transfer OID system column from the
+ * output plugin. Also we need to transfer the change kind, so it's better
+ * to put everything in the structure than to use 2 tuplestores "in
+ * parallel".
+ */
+ TupleDesc tupdesc_change;
+
+ /* Tuple descriptor needed to update indexes. */
+ TupleDesc tupdesc;
+
+ /* Slot to retrieve data from tstore. */
+ TupleTableSlot *tsslot;
+
+ ResourceOwner resowner;
+} RepackDecodingState;
+
extern void ExecRepack(ParseState *pstate, RepackStmt *stmt, bool isTopLevel);
extern void cluster_rel(RepackCommand command, Relation OldHeap, Oid indexOid,
- ClusterParams *params);
+ ClusterParams *params, bool isTopLevel);
extern void check_index_is_clusterable(Relation OldHeap, Oid indexOid,
LOCKMODE lockmode);
extern void mark_index_clustered(Relation rel, Oid indexOid, bool is_internal);
@@ -48,8 +129,13 @@ extern void finish_heap_swap(Oid OIDOldHeap, Oid OIDNewHeap,
bool swap_toast_by_content,
bool check_constraints,
bool is_internal,
+ bool reindex,
TransactionId frozenXid,
MultiXactId cutoffMulti,
char newrelpersistence);
+extern bool am_decoding_for_repack(void);
+extern bool change_useless_for_repack(XLogRecordBuffer *buf);
+extern void repack_decode_concurrent_changes(LogicalDecodingContext *ctx,
+ XLogRecPtr end_of_wal);
#endif /* CLUSTER_H */
diff --git a/src/include/commands/progress.h b/src/include/commands/progress.h
index f00e39b937d..4445724a463 100644
--- a/src/include/commands/progress.h
+++ b/src/include/commands/progress.h
@@ -86,10 +86,12 @@
#define PROGRESS_REPACK_PHASE 1
#define PROGRESS_REPACK_INDEX_RELID 2
#define PROGRESS_REPACK_HEAP_TUPLES_SCANNED 3
-#define PROGRESS_REPACK_HEAP_TUPLES_WRITTEN 4
-#define PROGRESS_REPACK_TOTAL_HEAP_BLKS 5
-#define PROGRESS_REPACK_HEAP_BLKS_SCANNED 6
-#define PROGRESS_REPACK_INDEX_REBUILD_COUNT 7
+#define PROGRESS_REPACK_HEAP_TUPLES_INSERTED 4
+#define PROGRESS_REPACK_HEAP_TUPLES_UPDATED 5
+#define PROGRESS_REPACK_HEAP_TUPLES_DELETED 6
+#define PROGRESS_REPACK_TOTAL_HEAP_BLKS 7
+#define PROGRESS_REPACK_HEAP_BLKS_SCANNED 8
+#define PROGRESS_REPACK_INDEX_REBUILD_COUNT 9
/*
* Phases of repack (as advertised via PROGRESS_REPACK_PHASE).
@@ -98,9 +100,10 @@
#define PROGRESS_REPACK_PHASE_INDEX_SCAN_HEAP 2
#define PROGRESS_REPACK_PHASE_SORT_TUPLES 3
#define PROGRESS_REPACK_PHASE_WRITE_NEW_HEAP 4
-#define PROGRESS_REPACK_PHASE_SWAP_REL_FILES 5
-#define PROGRESS_REPACK_PHASE_REBUILD_INDEX 6
-#define PROGRESS_REPACK_PHASE_FINAL_CLEANUP 7
+#define PROGRESS_REPACK_PHASE_CATCH_UP 5
+#define PROGRESS_REPACK_PHASE_SWAP_REL_FILES 6
+#define PROGRESS_REPACK_PHASE_REBUILD_INDEX 7
+#define PROGRESS_REPACK_PHASE_FINAL_CLEANUP 8
/* Progress parameters for CREATE INDEX */
/* 3, 4 and 5 reserved for "waitfor" metrics */
diff --git a/src/include/replication/snapbuild.h b/src/include/replication/snapbuild.h
index 34383dea776..5ee267d1c90 100644
--- a/src/include/replication/snapbuild.h
+++ b/src/include/replication/snapbuild.h
@@ -73,6 +73,7 @@ extern void FreeSnapshotBuilder(SnapBuild *builder);
extern void SnapBuildSnapDecRefcount(Snapshot snap);
extern Snapshot SnapBuildInitialSnapshot(SnapBuild *builder);
+extern Snapshot SnapBuildInitialSnapshotForRepack(SnapBuild *builder);
extern Snapshot SnapBuildMVCCFromHistoric(Snapshot snapshot, bool in_place);
extern const char *SnapBuildExportSnapshot(SnapBuild *builder);
extern void SnapBuildClearExportedSnapshot(void);
diff --git a/src/include/storage/lockdefs.h b/src/include/storage/lockdefs.h
index b73bb5618e6..3785b009808 100644
--- a/src/include/storage/lockdefs.h
+++ b/src/include/storage/lockdefs.h
@@ -36,8 +36,8 @@ typedef int LOCKMODE;
#define AccessShareLock 1 /* SELECT */
#define RowShareLock 2 /* SELECT FOR UPDATE/FOR SHARE */
#define RowExclusiveLock 3 /* INSERT, UPDATE, DELETE */
-#define ShareUpdateExclusiveLock 4 /* VACUUM (non-FULL), ANALYZE, CREATE
- * INDEX CONCURRENTLY */
+#define ShareUpdateExclusiveLock 4 /* VACUUM (non-exclusive), ANALYZE, CREATE
+ * INDEX CONCURRENTLY, REPACK CONCURRENTLY */
#define ShareLock 5 /* CREATE INDEX (WITHOUT CONCURRENTLY) */
#define ShareRowExclusiveLock 6 /* like EXCLUSIVE MODE, but allows ROW
* SHARE */
diff --git a/src/include/utils/snapmgr.h b/src/include/utils/snapmgr.h
index de824945f0b..0eb8ced76d3 100644
--- a/src/include/utils/snapmgr.h
+++ b/src/include/utils/snapmgr.h
@@ -64,6 +64,8 @@ extern Snapshot GetLatestSnapshot(void);
extern void SnapshotSetCommandId(CommandId curcid);
extern Snapshot CopySnapshot(Snapshot snapshot);
+extern void FreeSnapshot(Snapshot snapshot);
+
extern Snapshot GetCatalogSnapshot(Oid relid);
extern Snapshot GetNonHistoricCatalogSnapshot(Oid relid);
extern void InvalidateCatalogSnapshot(void);
diff --git a/src/test/modules/injection_points/Makefile b/src/test/modules/injection_points/Makefile
index a41d781f8c9..2cd7d87c533 100644
--- a/src/test/modules/injection_points/Makefile
+++ b/src/test/modules/injection_points/Makefile
@@ -14,6 +14,8 @@ REGRESS_OPTS = --dlpath=$(top_builddir)/src/test/regress
ISOLATION = basic \
inplace \
+ repack \
+ repack_toast \
syscache-update-pruned \
heap_lock_update
diff --git a/src/test/modules/injection_points/expected/repack.out b/src/test/modules/injection_points/expected/repack.out
new file mode 100644
index 00000000000..b575e9052ee
--- /dev/null
+++ b/src/test/modules/injection_points/expected/repack.out
@@ -0,0 +1,113 @@
+Parsed test spec with 2 sessions
+
+starting permutation: wait_before_lock change_existing change_new change_subxact1 change_subxact2 check2 wakeup_before_lock check1
+injection_points_attach
+-----------------------
+
+(1 row)
+
+step wait_before_lock:
+ REPACK (CONCURRENTLY) repack_test USING INDEX repack_test_pkey;
+ <waiting ...>
+step change_existing:
+ UPDATE repack_test SET i=10 where i=1;
+ UPDATE repack_test SET j=20 where i=2;
+ UPDATE repack_test SET i=30 where i=3;
+ UPDATE repack_test SET i=40 where i=30;
+ DELETE FROM repack_test WHERE i=4;
+
+step change_new:
+ INSERT INTO repack_test(i, j) VALUES (5, 5), (6, 6), (7, 7), (8, 8);
+ UPDATE repack_test SET i=50 where i=5;
+ UPDATE repack_test SET j=60 where i=6;
+ DELETE FROM repack_test WHERE i=7;
+
+step change_subxact1:
+ BEGIN;
+ INSERT INTO repack_test(i, j) VALUES (100, 100);
+ SAVEPOINT s1;
+ UPDATE repack_test SET i=101 where i=100;
+ SAVEPOINT s2;
+ UPDATE repack_test SET i=102 where i=101;
+ COMMIT;
+
+step change_subxact2:
+ BEGIN;
+ SAVEPOINT s1;
+ INSERT INTO repack_test(i, j) VALUES (110, 110);
+ ROLLBACK TO SAVEPOINT s1;
+ INSERT INTO repack_test(i, j) VALUES (110, 111);
+ COMMIT;
+
+step check2:
+ INSERT INTO relfilenodes(node)
+ SELECT relfilenode FROM pg_class WHERE relname='repack_test';
+
+ SELECT i, j FROM repack_test ORDER BY i, j;
+
+ INSERT INTO data_s2(i, j)
+ SELECT i, j FROM repack_test;
+
+ i| j
+---+---
+ 2| 20
+ 6| 60
+ 8| 8
+ 10| 1
+ 40| 3
+ 50| 5
+102|100
+110|111
+(8 rows)
+
+step wakeup_before_lock:
+ SELECT injection_points_wakeup('repack-concurrently-before-lock');
+
+injection_points_wakeup
+-----------------------
+
+(1 row)
+
+step wait_before_lock: <... completed>
+step check1:
+ INSERT INTO relfilenodes(node)
+ SELECT relfilenode FROM pg_class WHERE relname='repack_test';
+
+ SELECT count(DISTINCT node) FROM relfilenodes;
+
+ SELECT i, j FROM repack_test ORDER BY i, j;
+
+ INSERT INTO data_s1(i, j)
+ SELECT i, j FROM repack_test;
+
+ SELECT count(*)
+ FROM data_s1 d1 FULL JOIN data_s2 d2 USING (i, j)
+ WHERE d1.i ISNULL OR d2.i ISNULL;
+
+count
+-----
+ 2
+(1 row)
+
+ i| j
+---+---
+ 2| 20
+ 6| 60
+ 8| 8
+ 10| 1
+ 40| 3
+ 50| 5
+102|100
+110|111
+(8 rows)
+
+count
+-----
+ 0
+(1 row)
+
+injection_points_detach
+-----------------------
+
+(1 row)
+
diff --git a/src/test/modules/injection_points/expected/repack_toast.out b/src/test/modules/injection_points/expected/repack_toast.out
new file mode 100644
index 00000000000..4f866a74e32
--- /dev/null
+++ b/src/test/modules/injection_points/expected/repack_toast.out
@@ -0,0 +1,64 @@
+Parsed test spec with 2 sessions
+
+starting permutation: wait_before_lock change check2 wakeup_before_lock check1
+injection_points_attach
+-----------------------
+
+(1 row)
+
+step wait_before_lock:
+ REPACK (CONCURRENTLY) repack_test;
+ <waiting ...>
+step change:
+ UPDATE repack_test SET j=get_long_string() where i=2;
+ DELETE FROM repack_test WHERE i=3;
+ INSERT INTO repack_test(i, j) VALUES (4, get_long_string());
+
+step check2:
+ INSERT INTO relfilenodes(node)
+ SELECT c2.relfilenode
+ FROM pg_class c1 JOIN pg_class c2 ON c2.oid = c1.oid OR c2.oid = c1.reltoastrelid
+ WHERE c1.relname='repack_test';
+
+ INSERT INTO data_s2(i, j)
+ SELECT i, j FROM repack_test;
+
+step wakeup_before_lock:
+ SELECT injection_points_wakeup('repack-concurrently-before-lock');
+
+injection_points_wakeup
+-----------------------
+
+(1 row)
+
+step wait_before_lock: <... completed>
+step check1:
+ INSERT INTO relfilenodes(node)
+ SELECT c2.relfilenode
+ FROM pg_class c1 JOIN pg_class c2 ON c2.oid = c1.oid OR c2.oid = c1.reltoastrelid
+ WHERE c1.relname='repack_test';
+
+ SELECT count(DISTINCT node) FROM relfilenodes;
+
+ INSERT INTO data_s1(i, j)
+ SELECT i, j FROM repack_test;
+
+ SELECT count(*)
+ FROM data_s1 d1 FULL JOIN data_s2 d2 USING (i, j)
+ WHERE d1.i ISNULL OR d2.i ISNULL;
+
+count
+-----
+ 4
+(1 row)
+
+count
+-----
+ 0
+(1 row)
+
+injection_points_detach
+-----------------------
+
+(1 row)
+
diff --git a/src/test/modules/injection_points/meson.build b/src/test/modules/injection_points/meson.build
index fcc85414515..a414abb924b 100644
--- a/src/test/modules/injection_points/meson.build
+++ b/src/test/modules/injection_points/meson.build
@@ -45,6 +45,8 @@ tests += {
'specs': [
'basic',
'inplace',
+ 'repack',
+ 'repack_toast',
'syscache-update-pruned',
'heap_lock_update',
],
diff --git a/src/test/modules/injection_points/specs/repack.spec b/src/test/modules/injection_points/specs/repack.spec
new file mode 100644
index 00000000000..d727a9b056b
--- /dev/null
+++ b/src/test/modules/injection_points/specs/repack.spec
@@ -0,0 +1,142 @@
+# REPACK (CONCURRENTLY) ... USING INDEX ...;
+setup
+{
+ CREATE EXTENSION injection_points;
+
+ CREATE TABLE repack_test(i int PRIMARY KEY, j int);
+ INSERT INTO repack_test(i, j) VALUES (1, 1), (2, 2), (3, 3), (4, 4);
+
+ CREATE TABLE relfilenodes(node oid);
+
+ CREATE TABLE data_s1(i int, j int);
+ CREATE TABLE data_s2(i int, j int);
+}
+
+teardown
+{
+ DROP TABLE repack_test;
+ DROP EXTENSION injection_points;
+
+ DROP TABLE relfilenodes;
+ DROP TABLE data_s1;
+ DROP TABLE data_s2;
+}
+
+session s1
+setup
+{
+ SELECT injection_points_set_local();
+ SELECT injection_points_attach('repack-concurrently-before-lock', 'wait');
+}
+# Perform the initial load and wait for s2 to do some data changes.
+step wait_before_lock
+{
+ REPACK (CONCURRENTLY) repack_test USING INDEX repack_test_pkey;
+}
+# Check the table from the perspective of s1.
+#
+# Besides the contents, we also check that relfilenode has changed.
+
+# Have each session write the contents into a table and use FULL JOIN to check
+# if the outputs are identical.
+step check1
+{
+ INSERT INTO relfilenodes(node)
+ SELECT relfilenode FROM pg_class WHERE relname='repack_test';
+
+ SELECT count(DISTINCT node) FROM relfilenodes;
+
+ SELECT i, j FROM repack_test ORDER BY i, j;
+
+ INSERT INTO data_s1(i, j)
+ SELECT i, j FROM repack_test;
+
+ SELECT count(*)
+ FROM data_s1 d1 FULL JOIN data_s2 d2 USING (i, j)
+ WHERE d1.i ISNULL OR d2.i ISNULL;
+}
+teardown
+{
+ SELECT injection_points_detach('repack-concurrently-before-lock');
+}
+
+session s2
+# Change the existing data. UPDATE changes both key and non-key columns. Also
+# update one row twice to test whether tuple version generated by this session
+# can be found.
+step change_existing
+{
+ UPDATE repack_test SET i=10 where i=1;
+ UPDATE repack_test SET j=20 where i=2;
+ UPDATE repack_test SET i=30 where i=3;
+ UPDATE repack_test SET i=40 where i=30;
+ DELETE FROM repack_test WHERE i=4;
+}
+# Insert new rows and UPDATE / DELETE some of them. Again, update both key and
+# non-key column.
+step change_new
+{
+ INSERT INTO repack_test(i, j) VALUES (5, 5), (6, 6), (7, 7), (8, 8);
+ UPDATE repack_test SET i=50 where i=5;
+ UPDATE repack_test SET j=60 where i=6;
+ DELETE FROM repack_test WHERE i=7;
+}
+
+# When applying concurrent data changes, we should see the effects of an
+# in-progress subtransaction.
+#
+# XXX Not sure this test is useful now - it was designed for the patch that
+# preserves tuple visibility and which therefore modifies
+# TransactionIdIsCurrentTransactionId().
+step change_subxact1
+{
+ BEGIN;
+ INSERT INTO repack_test(i, j) VALUES (100, 100);
+ SAVEPOINT s1;
+ UPDATE repack_test SET i=101 where i=100;
+ SAVEPOINT s2;
+ UPDATE repack_test SET i=102 where i=101;
+ COMMIT;
+}
+
+# When applying concurrent data changes, we should not see the effects of a
+# rolled back subtransaction.
+#
+# XXX Is this test useful? See above.
+step change_subxact2
+{
+ BEGIN;
+ SAVEPOINT s1;
+ INSERT INTO repack_test(i, j) VALUES (110, 110);
+ ROLLBACK TO SAVEPOINT s1;
+ INSERT INTO repack_test(i, j) VALUES (110, 111);
+ COMMIT;
+}
+
+# Check the table from the perspective of s2.
+step check2
+{
+ INSERT INTO relfilenodes(node)
+ SELECT relfilenode FROM pg_class WHERE relname='repack_test';
+
+ SELECT i, j FROM repack_test ORDER BY i, j;
+
+ INSERT INTO data_s2(i, j)
+ SELECT i, j FROM repack_test;
+}
+step wakeup_before_lock
+{
+ SELECT injection_points_wakeup('repack-concurrently-before-lock');
+}
+
+# Test if data changes introduced while one session is performing REPACK
+# CONCURRENTLY find their way into the table.
+permutation
+ wait_before_lock
+ change_existing
+ change_new
+ change_subxact1
+ change_subxact2
+ check2
+ wakeup_before_lock
+ check1
diff --git a/src/test/modules/injection_points/specs/repack_toast.spec b/src/test/modules/injection_points/specs/repack_toast.spec
new file mode 100644
index 00000000000..b48abf21450
--- /dev/null
+++ b/src/test/modules/injection_points/specs/repack_toast.spec
@@ -0,0 +1,105 @@
+# REPACK (CONCURRENTLY);
+#
+# Test handling of TOAST. At the same time, no tuplesort.
+setup
+{
+ CREATE EXTENSION injection_points;
+
+ -- Return a string that needs to be TOASTed.
+ CREATE FUNCTION get_long_string()
+ RETURNS text
+ LANGUAGE sql as $$
+ SELECT string_agg(chr(65 + trunc(25 * random())::int), '')
+ FROM generate_series(1, 2048) s(x);
+ $$;
+
+ CREATE TABLE repack_test(i int PRIMARY KEY, j text);
+ INSERT INTO repack_test(i, j) VALUES (1, get_long_string()),
+ (2, get_long_string()), (3, get_long_string());
+
+ CREATE TABLE relfilenodes(node oid);
+
+ CREATE TABLE data_s1(i int, j text);
+ CREATE TABLE data_s2(i int, j text);
+}
+
+teardown
+{
+ DROP TABLE repack_test;
+ DROP EXTENSION injection_points;
+ DROP FUNCTION get_long_string();
+
+ DROP TABLE relfilenodes;
+ DROP TABLE data_s1;
+ DROP TABLE data_s2;
+}
+
+session s1
+setup
+{
+ SELECT injection_points_set_local();
+ SELECT injection_points_attach('repack-concurrently-before-lock', 'wait');
+}
+# Perform the initial load and wait for s2 to do some data changes.
+step wait_before_lock
+{
+ REPACK (CONCURRENTLY) repack_test;
+}
+# Check the table from the perspective of s1.
+#
+# Besides the contents, we also check that relfilenode has changed.
+
+# Have each session write the contents into a table and use FULL JOIN to check
+# if the outputs are identical.
+step check1
+{
+ INSERT INTO relfilenodes(node)
+ SELECT c2.relfilenode
+ FROM pg_class c1 JOIN pg_class c2 ON c2.oid = c1.oid OR c2.oid = c1.reltoastrelid
+ WHERE c1.relname='repack_test';
+
+ SELECT count(DISTINCT node) FROM relfilenodes;
+
+ INSERT INTO data_s1(i, j)
+ SELECT i, j FROM repack_test;
+
+ SELECT count(*)
+ FROM data_s1 d1 FULL JOIN data_s2 d2 USING (i, j)
+ WHERE d1.i ISNULL OR d2.i ISNULL;
+}
+teardown
+{
+ SELECT injection_points_detach('repack-concurrently-before-lock');
+}
+
+session s2
+step change
+{
+ UPDATE repack_test SET j=get_long_string() where i=2;
+ DELETE FROM repack_test WHERE i=3;
+ INSERT INTO repack_test(i, j) VALUES (4, get_long_string());
+}
+# Check the table from the perspective of s2.
+step check2
+{
+ INSERT INTO relfilenodes(node)
+ SELECT c2.relfilenode
+ FROM pg_class c1 JOIN pg_class c2 ON c2.oid = c1.oid OR c2.oid = c1.reltoastrelid
+ WHERE c1.relname='repack_test';
+
+ INSERT INTO data_s2(i, j)
+ SELECT i, j FROM repack_test;
+}
+step wakeup_before_lock
+{
+ SELECT injection_points_wakeup('repack-concurrently-before-lock');
+}
+
+# Test if data changes introduced while one session is performing REPACK
+# CONCURRENTLY find their way into the table.
+permutation
+ wait_before_lock
+ change
+ check2
+ wakeup_before_lock
+ check1
diff --git a/src/test/regress/expected/rules.out b/src/test/regress/expected/rules.out
index 48461550636..470920f0d16 100644
--- a/src/test/regress/expected/rules.out
+++ b/src/test/regress/expected/rules.out
@@ -2014,7 +2014,7 @@ pg_stat_progress_cluster| SELECT pid,
phase,
repack_index_relid AS cluster_index_relid,
heap_tuples_scanned,
- heap_tuples_written,
+ (heap_tuples_inserted + heap_tuples_updated) AS heap_tuples_written,
heap_blks_total,
heap_blks_scanned,
index_rebuild_count
@@ -2094,17 +2094,20 @@ pg_stat_progress_repack| SELECT s.pid,
WHEN 2 THEN 'index scanning heap'::text
WHEN 3 THEN 'sorting tuples'::text
WHEN 4 THEN 'writing new heap'::text
- WHEN 5 THEN 'swapping relation files'::text
- WHEN 6 THEN 'rebuilding index'::text
- WHEN 7 THEN 'performing final cleanup'::text
+ WHEN 5 THEN 'catch-up'::text
+ WHEN 6 THEN 'swapping relation files'::text
+ WHEN 7 THEN 'rebuilding index'::text
+ WHEN 8 THEN 'performing final cleanup'::text
ELSE NULL::text
END AS phase,
(s.param3)::oid AS repack_index_relid,
s.param4 AS heap_tuples_scanned,
- s.param5 AS heap_tuples_written,
- s.param6 AS heap_blks_total,
- s.param7 AS heap_blks_scanned,
- s.param8 AS index_rebuild_count
+ s.param5 AS heap_tuples_inserted,
+ s.param6 AS heap_tuples_updated,
+ s.param7 AS heap_tuples_deleted,
+ s.param8 AS heap_blks_total,
+ s.param9 AS heap_blks_scanned,
+ s.param10 AS index_rebuild_count
FROM (pg_stat_get_progress_info('REPACK'::text) s(pid, datid, relid, param1, param2, param3, param4, param5, param6, param7, param8, param9, param10, param11, param12, param13, param14, param15, param16, param17, param18, param19, param20)
LEFT JOIN pg_database d ON ((s.datid = d.oid)));
pg_stat_progress_vacuum| SELECT s.pid,
diff --git a/src/tools/pgindent/typedefs.list b/src/tools/pgindent/typedefs.list
index 6c4af1c210d..2676823d2a7 100644
--- a/src/tools/pgindent/typedefs.list
+++ b/src/tools/pgindent/typedefs.list
@@ -420,6 +420,7 @@ CatCacheHeader
CatalogId
CatalogIdMapEntry
CatalogIndexState
+ChangeDest
ChangeVarNodes_callback
ChangeVarNodes_context
ChannelName
@@ -497,6 +498,8 @@ CompressFileHandle
CompressionLocation
CompressorState
ComputeXidHorizonsResult
+ConcurrentChange
+ConcurrentChangeKind
ConditionVariable
ConditionVariableMinimallyPadded
ConditionalStack
@@ -1278,6 +1281,7 @@ IndexElem
IndexFetchHeapData
IndexFetchTableData
IndexInfo
+IndexInsertState
IndexList
IndexOnlyScan
IndexOnlyScanState
@@ -2576,6 +2580,7 @@ ReorderBufferTupleCidKey
ReorderBufferUpdateProgressTxnCB
ReorderTuple
RepackCommand
+RepackDecodingState
RepackStmt
ReparameterizeForeignPathByChild_function
ReplOriginId
--
2.47.3
--r7amdyq3rmktb267
Content-Type: text/x-diff; charset=utf-8
Content-Disposition: attachment;
filename="v33-0005-Use-background-worker-to-do-logical-decoding.patch"
^ permalink raw reply [nested|flat] 90+ messages in thread
end of thread, other threads:[~2026-01-27 10:48 UTC | newest]
Thread overview: 90+ messages (download: mbox mbox.gz follow: Atom feed)
-- links below jump to the message on this page --
2019-03-08 00:31 [PATCH v18 08/18] tableam: finish_bulk_insert(). Andres Freund <[email protected]>
2020-05-08 16:36 MultiXact\SLRU buffers configuration Andrey M. Borodin <[email protected]>
2020-05-11 11:17 ` Re: MultiXact\SLRU buffers configuration Andrey M. Borodin <[email protected]>
2020-05-13 18:08 ` Re: MultiXact\SLRU buffers configuration Andrey M. Borodin <[email protected]>
2020-05-14 01:25 ` Re: MultiXact\SLRU buffers configuration Kyotaro Horiguchi <[email protected]>
2020-05-14 05:19 ` Re: MultiXact\SLRU buffers configuration Andrey M. Borodin <[email protected]>
2020-05-14 06:16 ` Re: MultiXact\SLRU buffers configuration Kyotaro Horiguchi <[email protected]>
2020-05-14 06:44 ` Re: MultiXact\SLRU buffers configuration Andrey M. Borodin <[email protected]>
2020-05-15 00:03 ` Re: MultiXact\SLRU buffers configuration Kyotaro Horiguchi <[email protected]>
2020-05-15 09:01 ` Re: MultiXact\SLRU buffers configuration Andrey M. Borodin <[email protected]>
2020-05-20 04:54 ` Re: MultiXact\SLRU buffers configuration Kyotaro Horiguchi <[email protected]>
2020-07-02 12:02 ` Re: MultiXact\SLRU buffers configuration Daniel Gustafsson <[email protected]>
2020-07-08 07:03 ` Re: MultiXact\SLRU buffers configuration Andrey M. Borodin <[email protected]>
2020-08-02 21:30 ` Re: MultiXact\SLRU buffers configuration Daniel Gustafsson <[email protected]>
2020-08-28 18:08 ` Re: MultiXact\SLRU buffers configuration Anastasia Lubennikova <[email protected]>
2020-09-28 14:41 ` Re: MultiXact\SLRU buffers configuration Andrey M. Borodin <[email protected]>
2020-10-07 14:23 ` Re: MultiXact\SLRU buffers configuration Anastasia Lubennikova <[email protected]>
2020-10-26 01:05 ` Re: MultiXact\SLRU buffers configuration Alexander Korotkov <[email protected]>
2020-10-26 15:45 ` Re: MultiXact\SLRU buffers configuration Andrey Borodin <[email protected]>
2020-10-27 17:02 ` Re: MultiXact\SLRU buffers configuration Alexander Korotkov <[email protected]>
2020-10-27 17:23 ` Re: MultiXact\SLRU buffers configuration Alexander Korotkov <[email protected]>
2020-10-28 01:36 ` Re: MultiXact\SLRU buffers configuration Tomas Vondra <[email protected]>
2020-10-28 07:34 ` Re: MultiXact\SLRU buffers configuration Andrey Borodin <[email protected]>
2020-10-28 23:32 ` Re: MultiXact\SLRU buffers configuration Tomas Vondra <[email protected]>
2020-10-29 07:08 ` Re: MultiXact\SLRU buffers configuration Andrey Borodin <[email protected]>
2020-10-29 13:49 ` Re: MultiXact\SLRU buffers configuration Tomas Vondra <[email protected]>
2020-11-02 12:45 ` Re: MultiXact\SLRU buffers configuration Andrey Borodin <[email protected]>
2020-11-10 00:13 ` Re: MultiXact\SLRU buffers configuration Tomas Vondra <[email protected]>
2020-11-10 06:16 ` Re: MultiXact\SLRU buffers configuration Andrey Borodin <[email protected]>
2020-11-10 18:07 ` Re: MultiXact\SLRU buffers configuration Tomas Vondra <[email protected]>
2020-11-10 18:41 ` Re: MultiXact\SLRU buffers configuration Thomas Munro <[email protected]>
2020-11-13 11:49 ` Re: MultiXact\SLRU buffers configuration Andrey Borodin <[email protected]>
2020-12-08 16:05 ` Re: MultiXact\SLRU buffers configuration Gilles Darold <[email protected]>
2020-12-08 17:52 ` Re: MultiXact\SLRU buffers configuration Andrey Borodin <[email protected]>
2020-12-09 10:51 ` Re: MultiXact\SLRU buffers configuration Gilles Darold <[email protected]>
2020-12-09 11:06 ` Re: MultiXact\SLRU buffers configuration Gilles Darold <[email protected]>
2020-12-10 14:45 ` Re: MultiXact\SLRU buffers configuration Gilles Darold <[email protected]>
2020-12-11 17:50 ` Re: MultiXact\SLRU buffers configuration Gilles Darold <[email protected]>
2020-12-13 09:17 ` Re: MultiXact\SLRU buffers configuration Gilles Darold <[email protected]>
2020-12-13 17:24 ` Re: MultiXact\SLRU buffers configuration Andrey Borodin <[email protected]>
2020-12-14 06:31 ` Re: MultiXact\SLRU buffers configuration Andrey Borodin <[email protected]>
2020-12-23 16:31 ` Re: MultiXact\SLRU buffers configuration Gilles Darold <[email protected]>
2021-02-15 17:17 ` Re: MultiXact\SLRU buffers configuration Andrey Borodin <[email protected]>
2021-03-11 15:50 ` Re: MultiXact\SLRU buffers configuration Gilles Darold <[email protected]>
2021-03-12 12:44 ` Re: MultiXact\SLRU buffers configuration Andrey Borodin <[email protected]>
2021-03-15 15:41 ` Re: MultiXact\SLRU buffers configuration Gilles Darold <[email protected]>
2021-03-24 21:31 ` Re: MultiXact\SLRU buffers configuration Thomas Munro <[email protected]>
2021-03-25 01:03 ` Re: MultiXact\SLRU buffers configuration Thomas Munro <[email protected]>
2021-03-26 03:46 ` Re: MultiXact\SLRU buffers configuration Thomas Munro <[email protected]>
2021-03-26 06:00 ` Re: MultiXact\SLRU buffers configuration Andrey Borodin <[email protected]>
2021-03-26 15:52 ` Re: MultiXact\SLRU buffers configuration Andrey Borodin <[email protected]>
2021-03-26 20:26 ` Re: MultiXact\SLRU buffers configuration Thomas Munro <[email protected]>
2021-03-27 05:31 ` Re: MultiXact\SLRU buffers configuration Andrey Borodin <[email protected]>
2021-03-28 21:15 ` Re: MultiXact\SLRU buffers configuration Thomas Munro <[email protected]>
2021-03-29 08:26 ` Re: MultiXact\SLRU buffers configuration Andrey Borodin <[email protected]>
2021-03-31 21:09 ` Re: MultiXact\SLRU buffers configuration Andrey Borodin <[email protected]>
2021-04-01 03:40 ` Re: MultiXact\SLRU buffers configuration Thomas Munro <[email protected]>
2021-04-03 19:57 ` Re: MultiXact\SLRU buffers configuration Andrey Borodin <[email protected]>
2021-04-07 05:59 ` Re: MultiXact\SLRU buffers configuration Thomas Munro <[email protected]>
2021-04-07 11:44 ` Re: MultiXact\SLRU buffers configuration Andrey Borodin <[email protected]>
2021-04-07 12:13 ` Re: MultiXact\SLRU buffers configuration Andrey Borodin <[email protected]>
2021-04-08 00:30 ` Re: MultiXact\SLRU buffers configuration Thomas Munro <[email protected]>
2021-04-08 07:24 ` Re: MultiXact\SLRU buffers configuration Andrey Borodin <[email protected]>
2021-04-08 12:22 ` Re: MultiXact\SLRU buffers configuration Thomas Munro <[email protected]>
2021-04-11 18:37 ` Re: MultiXact\SLRU buffers configuration Andrey Borodin <[email protected]>
2021-06-14 17:40 ` Re: MultiXact\SLRU buffers configuration Васильев Дмитрий <[email protected]>
2021-12-26 10:09 ` Re: MultiXact\SLRU buffers configuration Andrey Borodin <[email protected]>
2022-07-21 13:00 ` Re: MultiXact\SLRU buffers configuration Yura Sokolov <[email protected]>
2022-07-23 08:39 ` Re: MultiXact\SLRU buffers configuration Andrey Borodin <[email protected]>
2022-07-23 08:47 ` Re: MultiXact\SLRU buffers configuration Thomas Munro <[email protected]>
2022-12-20 18:39 ` Re: MultiXact\SLRU buffers configuration Andrey Borodin <[email protected]>
2022-08-16 19:36 ` Re: MultiXact\SLRU buffers configuration [email protected]
2022-08-18 03:35 ` Re: MultiXact\SLRU buffers configuration Andrey Borodin <[email protected]>
2022-08-19 15:48 ` Re: MultiXact\SLRU buffers configuration [email protected]
2024-01-20 03:31 ` Re: MultiXact\SLRU buffers configuration vignesh C <[email protected]>
2024-01-27 04:58 ` Re: MultiXact\SLRU buffers configuration Andrey Borodin <[email protected]>
2024-01-28 12:49 ` Re: MultiXact\SLRU buffers configuration Alvaro Herrera <[email protected]>
2024-01-28 18:17 ` Re: MultiXact\SLRU buffers configuration Andrey M. Borodin <[email protected]>
2020-10-28 19:36 ` Re: MultiXact\SLRU buffers configuration Alexander Korotkov <[email protected]>
2020-10-28 23:21 ` Re: MultiXact\SLRU buffers configuration Tomas Vondra <[email protected]>
2024-08-23 00:29 Re: MultiXact\SLRU buffers configuration Michael Paquier <[email protected]>
2024-10-29 16:38 ` Re: MultiXact\SLRU buffers configuration Thom Brown <[email protected]>
2024-10-29 17:45 ` Re: MultiXact\SLRU buffers configuration Thom Brown <[email protected]>
2024-10-31 10:46 ` Re: MultiXact\SLRU buffers configuration Andrey M. Borodin <[email protected]>
2024-10-31 13:29 ` Re: MultiXact\SLRU buffers configuration Thom Brown <[email protected]>
2024-10-31 17:32 ` Re: MultiXact\SLRU buffers configuration Andrey M. Borodin <[email protected]>
2024-10-31 19:25 ` Re: MultiXact\SLRU buffers configuration Thom Brown <[email protected]>
2024-11-05 14:11 ` Re: MultiXact\SLRU buffers configuration Andrey M. Borodin <[email protected]>
2025-07-28 17:23 ` Re: MultiXact\SLRU buffers configuration Andrey Borodin <[email protected]>
2026-01-27 10:48 [PATCH v33 4/5] Add CONCURRENTLY option to REPACK command. Antonin Houska <[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