mirror of https://github.com/postgres/postgres
This new function exposes at SQL level some information related to
multixacts, not available until now. This data is useful for monitoring
purposes, especially for workloads that make a heavy use of multixacts:
- num_mxids, number of MultiXact IDs in use.
- num_members, number of member entries in use.
- members_size, bytes used by num_members in pg_multixact/members/.
- oldest_multixact: oldest MultiXact still needed.
This patch has been originally proposed when MultiXactOffset was still
32 bits, to monitor wraparound. This part is not relevant anymore since
bd8d9c9bdf that has widen MultiXactOffset to 64 bits. The monitoring
of disk space usage for the members is still relevant.
Some tests are added to check this function, in the shape of one
isolation test with concurrent transactions that take a ROW SHARE lock,
and some SQL tests for pg_read_all_stats. Some documentation is added
to explain some patterns that can come from the information provided by
the function.
Bump catalog version.
Author: Naga Appani <nagnrik@gmail.com>
Reviewed-by: Ashutosh Bapat <ashutosh.bapat.oss@gmail.com>
Reviewed-by: Michael Paquier <michael@paquier.xyz>
Reviewed-by: Atsushi Torikoshi <torikoshia@oss.nttdata.com>
Discussion: https://postgr.es/m/CA+QeY+AAsYK6WvBW4qYzHz4bahHycDAY_q5ECmHkEV_eB9ckzg@mail.gmail.com
pull/269/head
parent
0e3ad4b96a
commit
97b101776c
@ -0,0 +1,89 @@ |
||||
Parsed test spec with 2 sessions |
||||
|
||||
starting permutation: snap0 s1_begin s1_lock snap1 s2_begin s2_lock snap2 check_while_pinned s1_commit s2_commit |
||||
step snap0: |
||||
CREATE TEMP TABLE snap0 AS |
||||
SELECT num_mxids, num_members, oldest_multixact |
||||
FROM pg_get_multixact_stats(); |
||||
|
||||
step s1_begin: BEGIN; |
||||
step s1_lock: SELECT 1 FROM mxq WHERE id=1 FOR KEY SHARE; |
||||
?column? |
||||
-------- |
||||
1 |
||||
(1 row) |
||||
|
||||
step snap1: |
||||
CREATE TEMP TABLE snap1 AS |
||||
SELECT num_mxids, num_members, oldest_multixact |
||||
FROM pg_get_multixact_stats(); |
||||
|
||||
step s2_begin: BEGIN; |
||||
step s2_lock: SELECT 1 FROM mxq WHERE id=1 FOR KEY SHARE; |
||||
?column? |
||||
-------- |
||||
1 |
||||
(1 row) |
||||
|
||||
step snap2: |
||||
CREATE TEMP TABLE snap2 AS |
||||
SELECT num_mxids, num_members, oldest_multixact |
||||
FROM pg_get_multixact_stats(); |
||||
|
||||
step check_while_pinned: |
||||
SELECT r.assertion, r.ok |
||||
FROM snap0 s0 |
||||
JOIN snap1 s1 ON TRUE |
||||
JOIN snap2 s2 ON TRUE, |
||||
LATERAL unnest( |
||||
ARRAY[ |
||||
'is_init_mxids', |
||||
'is_init_members', |
||||
'is_init_oldest_mxid', |
||||
'is_init_oldest_off', |
||||
'is_oldest_mxid_nondec_01', |
||||
'is_oldest_mxid_nondec_12', |
||||
'is_oldest_off_nondec_01', |
||||
'is_oldest_off_nondec_12', |
||||
'is_members_increased_ge1', |
||||
'is_mxids_nondec_01', |
||||
'is_mxids_nondec_12', |
||||
'is_members_nondec_01', |
||||
'is_members_nondec_12' |
||||
], |
||||
ARRAY[ |
||||
(s2.num_mxids IS NOT NULL), |
||||
(s2.num_members IS NOT NULL), |
||||
(s2.oldest_multixact IS NOT NULL), |
||||
|
||||
(s1.oldest_multixact::text::bigint >= COALESCE(s0.oldest_multixact::text::bigint, 0)), |
||||
(s2.oldest_multixact::text::bigint >= COALESCE(s1.oldest_multixact::text::bigint, 0)), |
||||
|
||||
(s2.num_members >= COALESCE(s1.num_members, 0) + 1), |
||||
|
||||
(s1.num_mxids >= COALESCE(s0.num_mxids, 0)), |
||||
(s2.num_mxids >= COALESCE(s1.num_mxids, 0)), |
||||
(s1.num_members >= COALESCE(s0.num_members, 0)), |
||||
(s2.num_members >= COALESCE(s1.num_members, 0)) |
||||
] |
||||
) AS r(assertion, ok); |
||||
|
||||
assertion |ok |
||||
------------------------+-- |
||||
is_init_mxids |t |
||||
is_init_members |t |
||||
is_init_oldest_mxid |t |
||||
is_init_oldest_off |t |
||||
is_oldest_mxid_nondec_01|t |
||||
is_oldest_mxid_nondec_12|t |
||||
is_oldest_off_nondec_01 |t |
||||
is_oldest_off_nondec_12 |t |
||||
is_members_increased_ge1|t |
||||
is_mxids_nondec_01 |t |
||||
is_mxids_nondec_12 | |
||||
is_members_nondec_01 | |
||||
is_members_nondec_12 | |
||||
(13 rows) |
||||
|
||||
step s1_commit: COMMIT; |
||||
step s2_commit: COMMIT; |
||||
@ -0,0 +1,111 @@ |
||||
# Test for pg_get_multixact_stats() |
||||
# |
||||
# This test creates one multixact on a brand-new table. While the multixact |
||||
# is pinned by two open transactions, we check some patterns that VACUUM and |
||||
# FREEZE cannot violate: |
||||
# 1) "members" increased by at least 1 when the second session locked the row. |
||||
# 2) (num_mxids / num_members) not decreased compared to earlier snapshots. |
||||
# 3) "oldest_*" fields never decreased. |
||||
# |
||||
# This test does not run checks after releasing locks, as freezing and/or |
||||
# truncation may shrink the multixact ranges calculated. |
||||
|
||||
setup |
||||
{ |
||||
CREATE TABLE mxq(id int PRIMARY KEY, v int); |
||||
INSERT INTO mxq VALUES (1, 42); |
||||
} |
||||
|
||||
teardown |
||||
{ |
||||
DROP TABLE mxq; |
||||
} |
||||
|
||||
# Two sessions that lock the same tuple, leading to one multixact with |
||||
# at least 2 members. |
||||
session "s1" |
||||
setup { SET client_min_messages = warning; SET lock_timeout = '5s'; } |
||||
step s1_begin { BEGIN; } |
||||
step s1_lock { SELECT 1 FROM mxq WHERE id=1 FOR KEY SHARE; } |
||||
step s1_commit { COMMIT; } |
||||
|
||||
session "s2" |
||||
setup { SET client_min_messages = warning; SET lock_timeout = '5s'; } |
||||
step s2_begin { BEGIN; } |
||||
step s2_lock { SELECT 1 FROM mxq WHERE id=1 FOR KEY SHARE; } |
||||
step s2_commit { COMMIT; } |
||||
|
||||
# Save multixact state *BEFORE* any locking; some of these may be NULLs if |
||||
# multixacts have not initialized yet. |
||||
step snap0 { |
||||
CREATE TEMP TABLE snap0 AS |
||||
SELECT num_mxids, num_members, oldest_multixact |
||||
FROM pg_get_multixact_stats(); |
||||
} |
||||
|
||||
# Save multixact state after s1 has locked the row. |
||||
step snap1 { |
||||
CREATE TEMP TABLE snap1 AS |
||||
SELECT num_mxids, num_members, oldest_multixact |
||||
FROM pg_get_multixact_stats(); |
||||
} |
||||
|
||||
# Save multixact state after s2 joins to lock the same row, leading to |
||||
# a multixact with at least 2 members. |
||||
step snap2 { |
||||
CREATE TEMP TABLE snap2 AS |
||||
SELECT num_mxids, num_members, oldest_multixact |
||||
FROM pg_get_multixact_stats(); |
||||
} |
||||
|
||||
# Pretty, deterministic key/value outputs based of boolean checks: |
||||
# is_init_mxids : num_mxids not NULL |
||||
# is_init_members : num_members not NULL |
||||
# is_init_oldest_mxid : oldest_multixact not NULL |
||||
# is_oldest_mxid_nondec_01 : oldest_multixact not decreased (snap0->snap1) |
||||
# is_oldest_mxid_nondec_12 : oldest_multixact did not decreased (snap1->snap2) |
||||
# is_members_increased_ge1 : members increased by at least 1 when s2 joined |
||||
# is_mxids_nondec_01 : num_mxids not decreased (snap0->snap1) |
||||
# is_mxids_nondec_12 : num_mxids not decreased (snap1->snap2) |
||||
# is_members_nondec_01 : num_members not decreased (snap0->snap1) |
||||
# is_members_nondec_12 : num_members not decreased (snap1->snap2) |
||||
step check_while_pinned { |
||||
SELECT r.assertion, r.ok |
||||
FROM snap0 s0 |
||||
JOIN snap1 s1 ON TRUE |
||||
JOIN snap2 s2 ON TRUE, |
||||
LATERAL unnest( |
||||
ARRAY[ |
||||
'is_init_mxids', |
||||
'is_init_members', |
||||
'is_init_oldest_mxid', |
||||
'is_init_oldest_off', |
||||
'is_oldest_mxid_nondec_01', |
||||
'is_oldest_mxid_nondec_12', |
||||
'is_oldest_off_nondec_01', |
||||
'is_oldest_off_nondec_12', |
||||
'is_members_increased_ge1', |
||||
'is_mxids_nondec_01', |
||||
'is_mxids_nondec_12', |
||||
'is_members_nondec_01', |
||||
'is_members_nondec_12' |
||||
], |
||||
ARRAY[ |
||||
(s2.num_mxids IS NOT NULL), |
||||
(s2.num_members IS NOT NULL), |
||||
(s2.oldest_multixact IS NOT NULL), |
||||
|
||||
(s1.oldest_multixact::text::bigint >= COALESCE(s0.oldest_multixact::text::bigint, 0)), |
||||
(s2.oldest_multixact::text::bigint >= COALESCE(s1.oldest_multixact::text::bigint, 0)), |
||||
|
||||
(s2.num_members >= COALESCE(s1.num_members, 0) + 1), |
||||
|
||||
(s1.num_mxids >= COALESCE(s0.num_mxids, 0)), |
||||
(s2.num_mxids >= COALESCE(s1.num_mxids, 0)), |
||||
(s1.num_members >= COALESCE(s0.num_members, 0)), |
||||
(s2.num_members >= COALESCE(s1.num_members, 0)) |
||||
] |
||||
) AS r(assertion, ok); |
||||
} |
||||
|
||||
permutation snap0 s1_begin s1_lock snap1 s2_begin s2_lock snap2 check_while_pinned s1_commit s2_commit |
||||
Loading…
Reference in new issue