Hi,

On 2021-06-10 16:42:01 +0300, Anastasia Lubennikova wrote:
> Cool. Thank you for working on that!
> Could you please share a WIP patch for the $subj? I'd be happy to help with
> it.

I've attached the current WIP state, which hasn't evolved much since
this message... I put the test in 
src/backend/access/heap/t/001_emergency_vacuum.pl
but I'm not sure that's the best place. But I didn't think
src/test/recovery is great either.

Regards,

Andres
use strict;
use warnings;
use PostgresNode;
use TestLib;
use Test::More tests => 4;

# Initialize primary node
my $node_primary = get_new_node('primary');

$node_primary->init(allows_streaming => 1);
$node_primary->append_conf('postgresql.conf', qq/
max_prepared_transactions=10
autovacuum_naptime = 1s
# So it's easier to verify the order of operations
autovacuum_max_workers=1
autovacuum_vacuum_cost_delay=0
log_autovacuum_min_duration=0
/);
$node_primary->start;

#
# Create tables for a few different test scenarios
#

$node_primary->safe_psql('postgres', qq/
	CREATE TABLE large(id serial primary key, data text, filler text default repeat(random()::text, 10));
    INSERT INTO large(data) SELECT generate_series(1,30000);

	CREATE TABLE large_trunc(id serial primary key, data text, filler text default repeat(random()::text, 10));
    INSERT INTO large_trunc(data) SELECT generate_series(1,30000);

	CREATE TABLE small(id serial primary key, data text, filler text default repeat(random()::text, 10));
    INSERT INTO small(data) SELECT generate_series(1,15000);

	CREATE TABLE small_trunc(id serial primary key, data text, filler text default repeat(random()::text, 10));
    INSERT INTO small_trunc(data) SELECT generate_series(1,15000);

    CREATE TABLE autovacuum_disabled(id serial primary key, data text) WITH (autovacuum_enabled=false);
    INSERT INTO autovacuum_disabled(data) SELECT generate_series(1,1000);
/);


# To prevent autovacuum from handling the tables immediately after
# restart, acquire locks in a 2PC transaction. That allows us to test
# interactions with running commands.

$node_primary->safe_psql('postgres', qq(
    BEGIN;
    LOCK TABLE large IN SHARE UPDATE EXCLUSIVE MODE;
    LOCK TABLE large_trunc IN SHARE UPDATE EXCLUSIVE MODE;
    LOCK TABLE small IN SHARE UPDATE EXCLUSIVE MODE;
    LOCK TABLE small_trunc IN SHARE UPDATE EXCLUSIVE MODE;
    LOCK TABLE autovacuum_disabled IN SHARE UPDATE EXCLUSIVE MODE;
	PREPARE TRANSACTION 'prevent_vacuum';
));


# Delete a few rows to ensure that vacuum has work to do.
$node_primary->safe_psql('postgres', qq/
    DELETE FROM large WHERE id % 2 = 0;
    DELETE FROM large_trunc WHERE id > 10000;
    DELETE FROM small WHERE id % 2 = 0;
    DELETE FROM small_trunc WHERE id > 1000;
    DELETE FROM autovacuum_disabled WHERE id % 2 = 0;
/);


$node_primary->stop;

$node_primary->append_conf('postgresql.conf', qq/
wal_debug=0
log_min_messages=debug2
/);

# Need to reset to a clog page boundary, otherwise we'll get errors
# about the file not existing. With default compilation settings
# CLOG_XACTS_PER_PAGE is 32768. The value below is 32768 *
# (2000000000/32768 + 1), with 2000000000 being the max value for
# autovacuum_freeze_max_age.

command_like([ 'pg_resetwal', '-x2000027648', $node_primary->data_dir ],
	qr/Write-ahead log reset/, 'pg_resetwal -x to');

#
# Now test autovacuum behaviour. Because of the 2PC transaction
# acquiring locks we can perform setup without autovacuum racing
# ahead.
#
$node_primary->start;

diag($node_primary->safe_psql('postgres',
							   qq/SELECT datname, datfrozenxid, age(datfrozenxid) FROM pg_database ORDER BY datname/));

$node_primary->safe_psql('postgres', qq/
    COMMIT PREPARED 'prevent_vacuum';
/);

ok($node_primary->poll_query_until('postgres', qq/
    SELECT NOT EXISTS (
        SELECT *
        FROM pg_database
        WHERE age(datfrozenxid) > current_setting('autovacuum_freeze_max_age')::int)
/),
   "xid horizon increased");

diag($node_primary->safe_psql('postgres',
							   qq/SELECT datname, datfrozenxid, age(datfrozenxid) FROM pg_database ORDER BY datname/));

diag($node_primary->safe_psql('postgres', qq/
    SELECT oid::regclass, relfrozenxid
    FROM pg_class
    WHERE oid = ANY(ARRAY['large'::regclass, 'large_trunc', 'autovacuum_disabled'])
/));

$node_primary->stop;

Reply via email to