Movatterモバイル変換


[0]ホーム

URL:


Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Commit7cdfeee

Browse files
Add contrib/pg_logicalinspect.
This module provides SQL functions that allow to inspect logicaldecoding components.It currently allows to inspect the contents of serialized logicalsnapshots of a running database cluster, which is useful for debuggingor educational purposes.Author: Bertrand DrouvotReviewed-by: Amit Kapila, Shveta Malik, Peter Smith, Peter EisentrautReviewed-by: David G. JohnstonDiscussion:https://postgr.es/m/ZscuZ92uGh3wm4tW%40ip-10-97-1-34.eu-west-3.compute.internal
1 parente2fd615 commit7cdfeee

File tree

18 files changed

+598
-39
lines changed

18 files changed

+598
-39
lines changed

‎contrib/Makefile

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@ SUBDIRS = \
3232
passwordcheck\
3333
pg_buffercache\
3434
pg_freespacemap\
35+
pg_logicalinspect\
3536
pg_prewarm\
3637
pg_stat_statements\
3738
pg_surgery\

‎contrib/meson.build

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,7 @@ subdir('passwordcheck')
4646
subdir('pg_buffercache')
4747
subdir('pgcrypto')
4848
subdir('pg_freespacemap')
49+
subdir('pg_logicalinspect')
4950
subdir('pg_prewarm')
5051
subdir('pgrowlocks')
5152
subdir('pg_stat_statements')

‎contrib/pg_logicalinspect/.gitignore

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
# Generated subdirectories
2+
/log/
3+
/results/
4+
/output_iso/
5+
/tmp_check/
6+
/tmp_check_iso/

‎contrib/pg_logicalinspect/Makefile

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
# contrib/pg_logicalinspect/Makefile
2+
3+
MODULE_big = pg_logicalinspect
4+
OBJS =\
5+
$(WIN32RES)\
6+
pg_logicalinspect.o
7+
PGFILEDESC = "pg_logicalinspect - functions to inspect logical decoding components"
8+
9+
EXTENSION = pg_logicalinspect
10+
DATA = pg_logicalinspect--1.0.sql
11+
12+
EXTRA_INSTALL = contrib/test_decoding
13+
14+
ISOLATION = logical_inspect
15+
16+
ISOLATION_OPTS = --temp-config$(top_srcdir)/contrib/pg_logicalinspect/logicalinspect.conf
17+
18+
# Disabled because these tests require "wal_level=logical", which
19+
# some installcheck users do not have (e.g. buildfarm clients).
20+
NO_INSTALLCHECK = 1
21+
22+
ifdefUSE_PGXS
23+
PG_CONFIG = pg_config
24+
PGXS :=$(shell$(PG_CONFIG) --pgxs)
25+
include$(PGXS)
26+
else
27+
subdir = contrib/pg_logicalinspect
28+
top_builddir = ../..
29+
include$(top_builddir)/src/Makefile.global
30+
include$(top_srcdir)/contrib/contrib-global.mk
31+
endif
Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
Parsed test spec with 2 sessions
2+
3+
starting permutation: s0_init s0_begin s0_savepoint s0_truncate s1_checkpoint s1_get_changes s0_commit s0_begin s0_insert s1_checkpoint s1_get_changes s0_commit s1_get_changes s1_get_logical_snapshot_info s1_get_logical_snapshot_meta
4+
step s0_init: SELECT 'init' FROM pg_create_logical_replication_slot('isolation_slot', 'test_decoding');
5+
?column?
6+
--------
7+
init
8+
(1 row)
9+
10+
step s0_begin: BEGIN;
11+
step s0_savepoint: SAVEPOINT sp1;
12+
step s0_truncate: TRUNCATE tbl1;
13+
step s1_checkpoint: CHECKPOINT;
14+
step s1_get_changes: SELECT data FROM pg_logical_slot_get_changes('isolation_slot', NULL, NULL, 'skip-empty-xacts', '1', 'include-xids', '0');
15+
data
16+
----
17+
(0 rows)
18+
19+
step s0_commit: COMMIT;
20+
step s0_begin: BEGIN;
21+
step s0_insert: INSERT INTO tbl1 VALUES (1);
22+
step s1_checkpoint: CHECKPOINT;
23+
step s1_get_changes: SELECT data FROM pg_logical_slot_get_changes('isolation_slot', NULL, NULL, 'skip-empty-xacts', '1', 'include-xids', '0');
24+
data
25+
---------------------------------------
26+
BEGIN
27+
table public.tbl1: TRUNCATE: (no-flags)
28+
COMMIT
29+
(3 rows)
30+
31+
step s0_commit: COMMIT;
32+
step s1_get_changes: SELECT data FROM pg_logical_slot_get_changes('isolation_slot', NULL, NULL, 'skip-empty-xacts', '1', 'include-xids', '0');
33+
data
34+
-------------------------------------------------------------
35+
BEGIN
36+
table public.tbl1: INSERT: val1[integer]:1 val2[integer]:null
37+
COMMIT
38+
(3 rows)
39+
40+
step s1_get_logical_snapshot_info: SELECT info.state, info.catchange_count, array_length(info.catchange_xip,1) AS catchange_array_length, info.committed_count, array_length(info.committed_xip,1) AS committed_array_length FROM pg_ls_logicalsnapdir(), pg_get_logical_snapshot_info(name) AS info ORDER BY 2;
41+
state |catchange_count|catchange_array_length|committed_count|committed_array_length
42+
----------+---------------+----------------------+---------------+----------------------
43+
consistent| 0| | 2| 2
44+
consistent| 2| 2| 0|
45+
(2 rows)
46+
47+
step s1_get_logical_snapshot_meta: SELECT COUNT(meta.*) from pg_ls_logicalsnapdir(), pg_get_logical_snapshot_meta(name) as meta;
48+
count
49+
-----
50+
2
51+
(1 row)
52+
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
wal_level = logical

‎contrib/pg_logicalinspect/meson.build

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
# Copyright (c) 2024, PostgreSQL Global Development Group
2+
3+
pg_logicalinspect_sources=files('pg_logicalinspect.c')
4+
5+
if host_system=='windows'
6+
pg_logicalinspect_sources+= rc_lib_gen.process(win32ver_rc,extra_args: [
7+
'--NAME','pg_logicalinspect',
8+
'--FILEDESC','pg_logicalinspect - functions to inspect logical decoding components',])
9+
endif
10+
11+
pg_logicalinspect=shared_module('pg_logicalinspect',
12+
pg_logicalinspect_sources,
13+
kwargs: contrib_mod_args+ {
14+
'dependencies': contrib_mod_args['dependencies'],
15+
},
16+
)
17+
contrib_targets+= pg_logicalinspect
18+
19+
install_data(
20+
'pg_logicalinspect.control',
21+
'pg_logicalinspect--1.0.sql',
22+
kwargs: contrib_data_args,
23+
)
24+
25+
tests+= {
26+
'name':'pg_logicalinspect',
27+
'sd':meson.current_source_dir(),
28+
'bd':meson.current_build_dir(),
29+
'isolation': {
30+
'specs': [
31+
'logical_inspect',
32+
],
33+
'regress_args': [
34+
'--temp-config',files('logicalinspect.conf'),
35+
],
36+
# see above
37+
'runningcheck':false,
38+
},
39+
}
Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
/* contrib/pg_logicalinspect/pg_logicalinspect--1.0.sql*/
2+
3+
-- complain if script is sourced in psql, rather than via CREATE EXTENSION
4+
\echo Use"CREATE EXTENSION pg_logicalinspect" to load this file. \quit
5+
6+
--
7+
-- pg_get_logical_snapshot_meta()
8+
--
9+
CREATEFUNCTIONpg_get_logical_snapshot_meta(IN filenametext,
10+
OUT magic int4,
11+
OUT checksum int8,
12+
OUT version int4
13+
)
14+
AS'MODULE_PATHNAME','pg_get_logical_snapshot_meta'
15+
LANGUAGE C STRICT PARALLEL SAFE;
16+
17+
REVOKE EXECUTEON FUNCTION pg_get_logical_snapshot_meta(text)FROM PUBLIC;
18+
GRANT EXECUTEON FUNCTION pg_get_logical_snapshot_meta(text) TO pg_read_server_files;
19+
20+
--
21+
-- pg_get_logical_snapshot_info()
22+
--
23+
CREATEFUNCTIONpg_get_logical_snapshot_info(IN filenametext,
24+
OUT statetext,
25+
OUT xmin xid,
26+
OUT xmax xid,
27+
OUT start_decoding_at pg_lsn,
28+
OUT two_phase_at pg_lsn,
29+
OUT initial_xmin_horizon xid,
30+
OUT building_full_snapshotboolean,
31+
OUT in_slot_creationboolean,
32+
OUT last_serialized_snapshot pg_lsn,
33+
OUT next_phase_at xid,
34+
OUT committed_count int4,
35+
OUT committed_xip xid[],
36+
OUT catchange_count int4,
37+
OUT catchange_xip xid[]
38+
)
39+
AS'MODULE_PATHNAME','pg_get_logical_snapshot_info'
40+
LANGUAGE C STRICT PARALLEL SAFE;
41+
42+
REVOKE EXECUTEON FUNCTION pg_get_logical_snapshot_info(text)FROM PUBLIC;
43+
GRANT EXECUTEON FUNCTION pg_get_logical_snapshot_info(text) TO pg_read_server_files;
Lines changed: 167 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,167 @@
1+
/*-------------------------------------------------------------------------
2+
*
3+
* pg_logicalinspect.c
4+
* Functions to inspect contents of PostgreSQL logical snapshots
5+
*
6+
* Copyright (c) 2024, PostgreSQL Global Development Group
7+
*
8+
* IDENTIFICATION
9+
* contrib/pg_logicalinspect/pg_logicalinspect.c
10+
*
11+
*-------------------------------------------------------------------------
12+
*/
13+
#include"postgres.h"
14+
15+
#include"funcapi.h"
16+
#include"replication/snapbuild_internal.h"
17+
#include"utils/array.h"
18+
#include"utils/builtins.h"
19+
#include"utils/pg_lsn.h"
20+
21+
PG_MODULE_MAGIC;
22+
23+
PG_FUNCTION_INFO_V1(pg_get_logical_snapshot_meta);
24+
PG_FUNCTION_INFO_V1(pg_get_logical_snapshot_info);
25+
26+
/* Return the description of SnapBuildState */
27+
staticconstchar*
28+
get_snapbuild_state_desc(SnapBuildStatestate)
29+
{
30+
constchar*stateDesc="unknown state";
31+
32+
switch (state)
33+
{
34+
caseSNAPBUILD_START:
35+
stateDesc="start";
36+
break;
37+
caseSNAPBUILD_BUILDING_SNAPSHOT:
38+
stateDesc="building";
39+
break;
40+
caseSNAPBUILD_FULL_SNAPSHOT:
41+
stateDesc="full";
42+
break;
43+
caseSNAPBUILD_CONSISTENT:
44+
stateDesc="consistent";
45+
break;
46+
}
47+
48+
returnstateDesc;
49+
}
50+
51+
/*
52+
* Retrieve the logical snapshot file metadata.
53+
*/
54+
Datum
55+
pg_get_logical_snapshot_meta(PG_FUNCTION_ARGS)
56+
{
57+
#definePG_GET_LOGICAL_SNAPSHOT_META_COLS 3
58+
SnapBuildOnDiskondisk;
59+
HeapTupletuple;
60+
Datumvalues[PG_GET_LOGICAL_SNAPSHOT_META_COLS]= {0};
61+
boolnulls[PG_GET_LOGICAL_SNAPSHOT_META_COLS]= {0};
62+
TupleDesctupdesc;
63+
charpath[MAXPGPATH];
64+
inti=0;
65+
text*filename_t=PG_GETARG_TEXT_PP(0);
66+
67+
/* Build a tuple descriptor for our result type */
68+
if (get_call_result_type(fcinfo,NULL,&tupdesc)!=TYPEFUNC_COMPOSITE)
69+
elog(ERROR,"return type must be a row type");
70+
71+
sprintf(path,"%s/%s",
72+
PG_LOGICAL_SNAPSHOTS_DIR,
73+
text_to_cstring(filename_t));
74+
75+
/* Validate and restore the snapshot to 'ondisk' */
76+
SnapBuildRestoreSnapshot(&ondisk,path,CurrentMemoryContext, false);
77+
78+
values[i++]=UInt32GetDatum(ondisk.magic);
79+
values[i++]=Int64GetDatum((int64)ondisk.checksum);
80+
values[i++]=UInt32GetDatum(ondisk.version);
81+
82+
Assert(i==PG_GET_LOGICAL_SNAPSHOT_META_COLS);
83+
84+
tuple=heap_form_tuple(tupdesc,values,nulls);
85+
86+
PG_RETURN_DATUM(HeapTupleGetDatum(tuple));
87+
88+
#undef PG_GET_LOGICAL_SNAPSHOT_META_COLS
89+
}
90+
91+
Datum
92+
pg_get_logical_snapshot_info(PG_FUNCTION_ARGS)
93+
{
94+
#definePG_GET_LOGICAL_SNAPSHOT_INFO_COLS 14
95+
SnapBuildOnDiskondisk;
96+
HeapTupletuple;
97+
Datumvalues[PG_GET_LOGICAL_SNAPSHOT_INFO_COLS]= {0};
98+
boolnulls[PG_GET_LOGICAL_SNAPSHOT_INFO_COLS]= {0};
99+
TupleDesctupdesc;
100+
charpath[MAXPGPATH];
101+
inti=0;
102+
text*filename_t=PG_GETARG_TEXT_PP(0);
103+
104+
/* Build a tuple descriptor for our result type */
105+
if (get_call_result_type(fcinfo,NULL,&tupdesc)!=TYPEFUNC_COMPOSITE)
106+
elog(ERROR,"return type must be a row type");
107+
108+
sprintf(path,"%s/%s",
109+
PG_LOGICAL_SNAPSHOTS_DIR,
110+
text_to_cstring(filename_t));
111+
112+
/* Validate and restore the snapshot to 'ondisk' */
113+
SnapBuildRestoreSnapshot(&ondisk,path,CurrentMemoryContext, false);
114+
115+
values[i++]=CStringGetTextDatum(get_snapbuild_state_desc(ondisk.builder.state));
116+
values[i++]=TransactionIdGetDatum(ondisk.builder.xmin);
117+
values[i++]=TransactionIdGetDatum(ondisk.builder.xmax);
118+
values[i++]=LSNGetDatum(ondisk.builder.start_decoding_at);
119+
values[i++]=LSNGetDatum(ondisk.builder.two_phase_at);
120+
values[i++]=TransactionIdGetDatum(ondisk.builder.initial_xmin_horizon);
121+
values[i++]=BoolGetDatum(ondisk.builder.building_full_snapshot);
122+
values[i++]=BoolGetDatum(ondisk.builder.in_slot_creation);
123+
values[i++]=LSNGetDatum(ondisk.builder.last_serialized_snapshot);
124+
values[i++]=TransactionIdGetDatum(ondisk.builder.next_phase_at);
125+
126+
values[i++]=UInt32GetDatum(ondisk.builder.committed.xcnt);
127+
if (ondisk.builder.committed.xcnt>0)
128+
{
129+
Datum*arrayelems;
130+
131+
arrayelems= (Datum*)palloc(ondisk.builder.committed.xcnt*sizeof(Datum));
132+
133+
for (intj=0;j<ondisk.builder.committed.xcnt;j++)
134+
arrayelems[j]=TransactionIdGetDatum(ondisk.builder.committed.xip[j]);
135+
136+
values[i++]=PointerGetDatum(construct_array_builtin(arrayelems,
137+
ondisk.builder.committed.xcnt,
138+
XIDOID));
139+
}
140+
else
141+
nulls[i++]= true;
142+
143+
values[i++]=UInt32GetDatum(ondisk.builder.catchange.xcnt);
144+
if (ondisk.builder.catchange.xcnt>0)
145+
{
146+
Datum*arrayelems;
147+
148+
arrayelems= (Datum*)palloc(ondisk.builder.catchange.xcnt*sizeof(Datum));
149+
150+
for (intj=0;j<ondisk.builder.catchange.xcnt;j++)
151+
arrayelems[j]=TransactionIdGetDatum(ondisk.builder.catchange.xip[j]);
152+
153+
values[i++]=PointerGetDatum(construct_array_builtin(arrayelems,
154+
ondisk.builder.catchange.xcnt,
155+
XIDOID));
156+
}
157+
else
158+
nulls[i++]= true;
159+
160+
Assert(i==PG_GET_LOGICAL_SNAPSHOT_INFO_COLS);
161+
162+
tuple=heap_form_tuple(tupdesc,values,nulls);
163+
164+
PG_RETURN_DATUM(HeapTupleGetDatum(tuple));
165+
166+
#undef PG_GET_LOGICAL_SNAPSHOT_INFO_COLS
167+
}
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
# pg_logicalinspect extension
2+
comment = 'functions to inspect logical decoding components'
3+
default_version = '1.0'
4+
module_pathname = '$libdir/pg_logicalinspect'
5+
relocatable = true

0 commit comments

Comments
 (0)

[8]ページ先頭

©2009-2025 Movatter.jp