On 01/04/2025 21:25, Heikki Linnakangas wrote:
On 07/03/2025 13:30, Maxim Orlov wrote:
Here is a rebase, v14.
Thanks! I did some manual testing of this. I created a little helper
function to consume multixids, to test the autovacuum behavior, and
found one issue:
Forgot to attach the test function I used, here it is.
--
Heikki Linnakangas
Neon (https://neon.tech)
From b2f156bfdd15df21ae25b3369d090cf9899e80aa Mon Sep 17 00:00:00 2001
From: Heikki Linnakangas <heikki.linnakan...@iki.fi>
Date: Tue, 1 Apr 2025 21:01:07 +0300
Subject: [PATCH 1/1] TEST: add consume_multixids function
---
src/test/modules/xid_wraparound/Makefile | 1 +
src/test/modules/xid_wraparound/meson.build | 1 +
.../xid_wraparound/multixid_wraparound.c | 96 +++++++++++++++++++
.../xid_wraparound/xid_wraparound--1.0.sql | 4 +
4 files changed, 102 insertions(+)
create mode 100644 src/test/modules/xid_wraparound/multixid_wraparound.c
diff --git a/src/test/modules/xid_wraparound/Makefile b/src/test/modules/xid_wraparound/Makefile
index 7a6e0f66762..ebb3d8fcb3e 100644
--- a/src/test/modules/xid_wraparound/Makefile
+++ b/src/test/modules/xid_wraparound/Makefile
@@ -3,6 +3,7 @@
MODULE_big = xid_wraparound
OBJS = \
$(WIN32RES) \
+ multixid_wraparound.o \
xid_wraparound.o
PGFILEDESC = "xid_wraparound - tests for XID wraparound"
diff --git a/src/test/modules/xid_wraparound/meson.build b/src/test/modules/xid_wraparound/meson.build
index f7dada67f67..98ad381614c 100644
--- a/src/test/modules/xid_wraparound/meson.build
+++ b/src/test/modules/xid_wraparound/meson.build
@@ -1,6 +1,7 @@
# Copyright (c) 2023-2025, PostgreSQL Global Development Group
xid_wraparound_sources = files(
+ 'multixid_wraparound.c',
'xid_wraparound.c',
)
diff --git a/src/test/modules/xid_wraparound/multixid_wraparound.c b/src/test/modules/xid_wraparound/multixid_wraparound.c
new file mode 100644
index 00000000000..af567c6e541
--- /dev/null
+++ b/src/test/modules/xid_wraparound/multixid_wraparound.c
@@ -0,0 +1,96 @@
+/*--------------------------------------------------------------------------
+ *
+ * multixid_wraparound.c
+ * Utilities for testing multixids
+ *
+ *
+ * Portions Copyright (c) 1996-2025, PostgreSQL Global Development Group
+ * Portions Copyright (c) 1994, Regents of the University of California
+ *
+ * IDENTIFICATION
+ * src/test/modules/xid_wraparound/multixid_wraparound.c
+ *
+ * -------------------------------------------------------------------------
+ */
+#include "postgres.h"
+
+#include "access/multixact.h"
+#include "access/xact.h"
+#include "miscadmin.h"
+#include "storage/proc.h"
+#include "utils/xid8.h"
+
+static int mxactMemberComparator(const void *arg1, const void *arg2);
+
+/*
+ * Consume the specified number of multi-XIDs, with specified number of
+ * members each.
+ */
+PG_FUNCTION_INFO_V1(consume_multixids);
+Datum
+consume_multixids(PG_FUNCTION_ARGS)
+{
+ int64 nmultis = PG_GETARG_INT64(0);
+ int32 nmembers = PG_GETARG_INT32(1);
+ MultiXactMember *members;
+ MultiXactId lastmxid = InvalidMultiXactId;
+
+ if (nmultis < 0)
+ elog(ERROR, "invalid nxids argument: %" PRId64, nmultis);
+ if (nmembers < 1)
+ elog(ERROR, "invalid nmembers argument: %d", nmembers);
+
+ /*
+ * We consume XIDs by calling GetNewTransactionId(true), which marks the
+ * consumed XIDs as subtransactions of the current top-level transaction.
+ * For that to work, this transaction must have a top-level XID.
+ *
+ * GetNewTransactionId registers them in the subxid cache in PGPROC, until
+ * the cache overflows, but beyond that, we don't keep track of the
+ * consumed XIDs.
+ */
+ (void) GetTopTransactionId();
+
+ members = palloc((nmultis + nmembers) * sizeof(MultiXactMember));
+ for (int32 i = 0; i < nmultis + nmembers; i++)
+ {
+ FullTransactionId xid;
+
+ xid = GetNewTransactionId(true);
+ members[i].xid = XidFromFullTransactionId(xid);
+ members[i].status = MultiXactStatusForKeyShare;
+ }
+ /*
+ * pre-sort the array like mXactCacheGetBySet does, so that the qsort call
+ * in mXactCacheGetBySet() is cheaper.
+ */
+ qsort(members, nmultis + nmembers, sizeof(MultiXactMember), mxactMemberComparator);
+
+ for (int64 i = 0; i < nmultis; i++)
+ {
+ lastmxid = MultiXactIdCreateFromMembers(nmembers, &members[i]);
+ CHECK_FOR_INTERRUPTS();
+ }
+
+ pfree(members);
+
+ PG_RETURN_TRANSACTIONID(lastmxid);
+}
+
+/* copied from multixact.c */
+static int
+mxactMemberComparator(const void *arg1, const void *arg2)
+{
+ MultiXactMember member1 = *(const MultiXactMember *) arg1;
+ MultiXactMember member2 = *(const MultiXactMember *) arg2;
+
+ if (member1.xid > member2.xid)
+ return 1;
+ if (member1.xid < member2.xid)
+ return -1;
+ if (member1.status > member2.status)
+ return 1;
+ if (member1.status < member2.status)
+ return -1;
+ return 0;
+}
diff --git a/src/test/modules/xid_wraparound/xid_wraparound--1.0.sql b/src/test/modules/xid_wraparound/xid_wraparound--1.0.sql
index 96356b4b974..ed7520c3d86 100644
--- a/src/test/modules/xid_wraparound/xid_wraparound--1.0.sql
+++ b/src/test/modules/xid_wraparound/xid_wraparound--1.0.sql
@@ -10,3 +10,7 @@ AS 'MODULE_PATHNAME' LANGUAGE C;
CREATE FUNCTION consume_xids_until(targetxid xid8)
RETURNS xid8 VOLATILE PARALLEL UNSAFE STRICT
AS 'MODULE_PATHNAME' LANGUAGE C;
+
+CREATE FUNCTION consume_multixids(nmultis bigint, nmembers int4)
+RETURNS bigint VOLATILE PARALLEL UNSAFE STRICT
+AS 'MODULE_PATHNAME' LANGUAGE C;
--
2.39.5