digoal
2023-11-30
PostgreSQL , PolarDB , duckdb , xid , wraparound
《Use pg_resetxlog simulate tuple disappear within PostgreSQL》
使用pg_resetxlog可以模拟xid的耗尽, 从而模拟tuple不可见的情况.
现在PostgreSQL 17直接提供了一个测试插件, 用于模拟快速消耗xid.
CREATE EXTENSION xid_wraparound;
两个接口函数如下:
consume_xids(nxids bigint)
consume_xids_until(targetxid xid8)
Add tests for XID wraparound. master github/master
author Masahiko Sawada <msawada@postgresql.org>
Thu, 30 Nov 2023 05:29:48 +0000 (14:29 +0900)
committer Masahiko Sawada <msawada@postgresql.org>
Thu, 30 Nov 2023 05:29:48 +0000 (14:29 +0900)
commit e255b646a16b45823c338dadf787813fc9e191dc
tree 7fd87cf5d0e8caf51d8ba886904757e0569b8469 tree
parent a243569bf65c5664436e8f63d870b7ee9c014dcb commit | diff
Add tests for XID wraparound.
The test module includes helper functions to quickly burn through lots
of XIDs. They are used in the tests, and are also handy for manually
testing XID wraparound.
Since these tests are very expensive the entire suite is disabled by
default. It requires to set PG_TEST_EXTRA to run it.
Reviewed-by: Daniel Gustafsson, John Naylor, Michael Paquier
Reviewed-by: vignesh C
Author: Heikki Linnakangas, Masahiko Sawada, Andres Freund
Discussion: https://www.postgresql.org/message-id/CAD21AoDVhkXp8HjpFO-gp3TgL6tCKcZQNxn04m01VAtcSi-5sA%40mail.gmail.com
1 /* src/test/modules/xid_wraparound/xid_wraparound--1.0.sql */
2
3 -- complain if script is sourced in psql, rather than via CREATE EXTENSION
4 \echo Use "CREATE EXTENSION xid_wraparound" to load this file. \quit
5
6 CREATE FUNCTION consume_xids(nxids bigint)
7 RETURNS xid8 IMMUTABLE PARALLEL SAFE STRICT
8 AS 'MODULE_PATHNAME' LANGUAGE C;
9
10 CREATE FUNCTION consume_xids_until(targetxid xid8)
11 RETURNS xid8 IMMUTABLE PARALLEL SAFE STRICT
12 AS 'MODULE_PATHNAME' LANGUAGE C;
/*
68 * Common functionality between the two public functions.
69 */
70 static FullTransactionId
71 consume_xids_common(FullTransactionId untilxid, uint64 nxids)
72 {
73 FullTransactionId lastxid;
74 uint64 last_reported_at = 0;
75 uint64 consumed = 0;
76
77 /* Print a NOTICE every REPORT_INTERVAL xids */
78 #define REPORT_INTERVAL (10 * 1000000)
79
80 /* initialize 'lastxid' with the system's current next XID */
81 lastxid = ReadNextFullTransactionId();
82
83 /*
84 * We consume XIDs by calling GetNewTransactionId(true), which marks the
85 * consumed XIDs as subtransactions of the current top-level transaction.
86 * For that to work, this transaction must have a top-level XID.
87 *
88 * GetNewTransactionId registers them in the subxid cache in PGPROC, until
89 * the cache overflows, but beyond that, we don't keep track of the
90 * consumed XIDs.
91 */
92 (void) GetTopTransactionId();
93
94 for (;;)
95 {
96 uint64 xids_left;
97
98 CHECK_FOR_INTERRUPTS();
99
100 /* How many XIDs do we have left to consume? */
101 if (nxids > 0)
102 {
103 if (consumed >= nxids)
104 break;
105 xids_left = nxids - consumed;
106 }
107 else
108 {
109 if (FullTransactionIdFollowsOrEquals(lastxid, untilxid))
110 break;
111 xids_left = U64FromFullTransactionId(untilxid) - U64FromFullTransactionId(lastxid);
112 }
113
114 /*
115 * If we still have plenty of XIDs to consume, try to take a shortcut
116 * and bump up the nextXid counter directly.
117 */
118 if (xids_left > 2000 &&
119 consumed - last_reported_at < REPORT_INTERVAL &&
120 MyProc->subxidStatus.overflowed)
121 {
122 int64 consumed_by_shortcut = consume_xids_shortcut();
123
124 if (consumed_by_shortcut > 0)
125 {
126 consumed += consumed_by_shortcut;
127 continue;
128 }
129 }
130
131 /* Slow path: Call GetNewTransactionId to allocate a new XID. */
132 lastxid = GetNewTransactionId(true);
133 consumed++;
134
135 /* Report progress */
136 if (consumed - last_reported_at >= REPORT_INTERVAL)
137 {
138 if (nxids > 0)
139 elog(NOTICE, "consumed %llu / %llu XIDs, latest %u:%u",
140 (unsigned long long) consumed, (unsigned long long) nxids,
141 EpochFromFullTransactionId(lastxid),
142 XidFromFullTransactionId(lastxid));
143 else
144 elog(NOTICE, "consumed up to %u:%u / %u:%u",
145 EpochFromFullTransactionId(lastxid),
146 XidFromFullTransactionId(lastxid),
147 EpochFromFullTransactionId(untilxid),
148 XidFromFullTransactionId(untilxid));
149 last_reported_at = consumed;
150 }
151 }
152
153 return lastxid;
154 }