#!/bin/bash # usage: catchk_run.sh # # Needs a build with nocfbot-catchk-instrumentation.diff applied. # # 1. Creates a logical slot, runs "make installcheck-parallel" from the build # dir against a throwaway cluster, decodes everything, and counts, per # committed xid, whether the reorder buffer had it as catalog-changing and # whether its commit had XACT_XINFO_HAS_INVALS. # 2. For the xacts with catalog changes but no invals, lists the catalogs # their NEW_CID records were for, and whether the xids that touched them # committed (they appear as committed subxids) or were rolled back. # 3. The same check for INSERT/UPDATE/DELETE on a user catalog table. P=$1; B=$2; PORT=$3 D=/tmp/catchk_$PORT rm -rf $D $P/bin/initdb -D $D -U postgres --no-sync >/dev/null 2>&1 cat >> $D/postgresql.conf </dev/null trap '$P/bin/pg_ctl -D $D -m immediate -w stop >/dev/null 2>&1; rm -rf $D' EXIT PSQL="$P/bin/psql -h /tmp -p $PORT -U postgres -X -q -At postgres" $PSQL -c "SELECT 'slot' FROM pg_create_logical_replication_slot('catchk', 'test_decoding')" >/dev/null make -C $B/src/test/regress installcheck-parallel PGHOST=/tmp PGPORT=$PORT PGUSER=postgres \ > $D/installcheck.log 2>&1 grep -E '# All|failed' $D/installcheck.log $PSQL -c "SELECT count(*) FROM pg_logical_slot_get_changes('catchk', NULL, NULL)" >/dev/null echo "== committed top-level xacts: catalog changes (rb) vs invals in commit" grep -oE 'CATCHK state=2 xid=[0-9]+ sub=0 rb=[01] invals=[01]' $D/log | awk '{print $5, $6}' | sort | uniq -c echo "== the ones with rb=1 invals=0, by catalog touched" $PSQL -c "SELECT pg_relation_filenode(oid) || '|' || relname FROM pg_class WHERE relnamespace = 'pg_catalog'::regnamespace" > $D/filenodes perl -e ' open F, "$ARGV[0]"; while () { chomp; my ($n, $r) = split /\|/; $fn{$n} = $r } open L, "$ARGV[1]"; while () { $bad{$1} = 1 if /CATCHK state=2 xid=(\d+) sub=0 rb=1 invals=0/; $committed{$1} = 1 if /CATCHK state=2 xid=(\d+) sub=1 /; push @{ $nc{$2} }, [$1, $3] if /NEWCID xid=(\d+) top=(\d+) rel=(\d+)/; } for my $x (keys %bad) { my (%cat, $aborted); for my $e (@{ $nc{$x} || [] }) { $cat{ $fn{$e->[1]} // "relfilenode $e->[1]" } = 1; $aborted = 1 if $e->[0] != $x && !$committed{ $e->[0] }; } my $k = join(", ", sort keys %cat) . ($aborted ? " (in rolled back subxacts)" : ""); $g{$k}++; } printf "%5d %s\n", $g{$_}, $_ for sort { $g{$b} <=> $g{$a} } keys %g; ' $D/filenodes $D/log echo "== user catalog table" $PSQL -c "CREATE TABLE uc (k int PRIMARY KEY, v text) WITH (user_catalog_table = true)" \ -c "SELECT 'slot' FROM pg_create_logical_replication_slot('uc', 'test_decoding')" >/dev/null for q in "INSERT INTO uc VALUES (1, 'a')" "UPDATE uc SET v = 'b' WHERE k = 1" \ "DELETE FROM uc WHERE k = 1" "ALTER TABLE uc ADD COLUMN w int"; do x=$($PSQL -c "BEGIN" -c "$q" -c "SELECT txid_current()" -c "COMMIT" | tail -1) echo "$x|$q" done > $D/uc $PSQL -c "SELECT count(*) FROM pg_logical_slot_get_changes('uc', NULL, NULL)" >/dev/null while IFS='|' read -r x q; do printf " %-36s %s\n" "$q" \ "$(grep -oE "CATCHK state=2 xid=$x sub=0 rb=[01] invals=[01]" $D/log | tail -1 | grep -oE 'rb=[01] invals=[01]')" done < $D/uc