aboutsummaryrefslogtreecommitdiff
path: root/src/test/recovery/t/018_wal_optimize.pl
diff options
context:
space:
mode:
Diffstat (limited to 'src/test/recovery/t/018_wal_optimize.pl')
-rw-r--r--src/test/recovery/t/018_wal_optimize.pl372
1 files changed, 0 insertions, 372 deletions
diff --git a/src/test/recovery/t/018_wal_optimize.pl b/src/test/recovery/t/018_wal_optimize.pl
deleted file mode 100644
index 50bb2fef611..00000000000
--- a/src/test/recovery/t/018_wal_optimize.pl
+++ /dev/null
@@ -1,372 +0,0 @@
-# Test WAL replay when some operation has skipped WAL.
-#
-# These tests exercise code that once violated the mandate described in
-# src/backend/access/transam/README section "Skipping WAL for New
-# RelFileNode". The tests work by committing some transactions, initiating an
-# immediate shutdown, and confirming that the expected data survives recovery.
-# For many years, individual commands made the decision to skip WAL, hence the
-# frequent appearance of COPY in these tests.
-use strict;
-use warnings;
-
-use PostgresNode;
-use TestLib;
-use Test::More tests => 34;
-
-sub check_orphan_relfilenodes
-{
- my ($node, $test_name) = @_;
-
- my $db_oid = $node->safe_psql('postgres',
- "SELECT oid FROM pg_database WHERE datname = 'postgres'");
- my $prefix = "base/$db_oid/";
- my $filepaths_referenced = $node->safe_psql(
- 'postgres', "
- SELECT pg_relation_filepath(oid) FROM pg_class
- WHERE reltablespace = 0 AND relpersistence <> 't' AND
- pg_relation_filepath(oid) IS NOT NULL;");
- is_deeply(
- [
- sort(map { "$prefix$_" }
- grep(/^[0-9]+$/, slurp_dir($node->data_dir . "/$prefix")))
- ],
- [ sort split /\n/, $filepaths_referenced ],
- $test_name);
- return;
-}
-
-# We run this same test suite for both wal_level=minimal and replica.
-sub run_wal_optimize
-{
- my $wal_level = shift;
-
- my $node = get_new_node("node_$wal_level");
- $node->init;
- $node->append_conf(
- 'postgresql.conf', qq(
-wal_level = $wal_level
-max_prepared_transactions = 1
-wal_log_hints = on
-wal_skip_threshold = 0
-#wal_debug = on
-));
- $node->start;
-
- # Setup
- my $tablespace_dir = $node->basedir . '/tablespace_other';
- mkdir($tablespace_dir);
- $tablespace_dir = TestLib::perl2host($tablespace_dir);
- $node->safe_psql('postgres',
- "CREATE TABLESPACE other LOCATION '$tablespace_dir';");
-
- # Test direct truncation optimization. No tuples.
- $node->safe_psql(
- 'postgres', "
- BEGIN;
- CREATE TABLE trunc (id serial PRIMARY KEY);
- TRUNCATE trunc;
- COMMIT;");
- $node->stop('immediate');
- $node->start;
- my $result = $node->safe_psql('postgres', "SELECT count(*) FROM trunc;");
- is($result, qq(0), "wal_level = $wal_level, TRUNCATE with empty table");
-
- # Test truncation with inserted tuples within the same transaction.
- # Tuples inserted after the truncation should be seen.
- $node->safe_psql(
- 'postgres', "
- BEGIN;
- CREATE TABLE trunc_ins (id serial PRIMARY KEY);
- INSERT INTO trunc_ins VALUES (DEFAULT);
- TRUNCATE trunc_ins;
- INSERT INTO trunc_ins VALUES (DEFAULT);
- COMMIT;");
- $node->stop('immediate');
- $node->start;
- $result = $node->safe_psql('postgres',
- "SELECT count(*), min(id) FROM trunc_ins;");
- is($result, qq(1|2), "wal_level = $wal_level, TRUNCATE INSERT");
-
- # Same for prepared transaction.
- # Tuples inserted after the truncation should be seen.
- $node->safe_psql(
- 'postgres', "
- BEGIN;
- CREATE TABLE twophase (id serial PRIMARY KEY);
- INSERT INTO twophase VALUES (DEFAULT);
- TRUNCATE twophase;
- INSERT INTO twophase VALUES (DEFAULT);
- PREPARE TRANSACTION 't';
- COMMIT PREPARED 't';");
- $node->stop('immediate');
- $node->start;
- $result = $node->safe_psql('postgres',
- "SELECT count(*), min(id) FROM trunc_ins;");
- is($result, qq(1|2), "wal_level = $wal_level, TRUNCATE INSERT PREPARE");
-
- # Writing WAL at end of xact, instead of syncing.
- $node->safe_psql(
- 'postgres', "
- SET wal_skip_threshold = '1TB';
- BEGIN;
- CREATE TABLE noskip (id serial PRIMARY KEY);
- INSERT INTO noskip (SELECT FROM generate_series(1, 20000) a) ;
- COMMIT;");
- $node->stop('immediate');
- $node->start;
- $result = $node->safe_psql('postgres', "SELECT count(*) FROM noskip;");
- is($result, qq(20000), "wal_level = $wal_level, end-of-xact WAL");
-
- # Data file for COPY query in subsequent tests
- my $basedir = $node->basedir;
- my $copy_file = "$basedir/copy_data.txt";
- TestLib::append_to_file(
- $copy_file, qq(20000,30000
-20001,30001
-20002,30002));
-
- # Test truncation with inserted tuples using both INSERT and COPY. Tuples
- # inserted after the truncation should be seen.
- $node->safe_psql(
- 'postgres', "
- BEGIN;
- CREATE TABLE ins_trunc (id serial PRIMARY KEY, id2 int);
- INSERT INTO ins_trunc VALUES (DEFAULT, generate_series(1,10000));
- TRUNCATE ins_trunc;
- INSERT INTO ins_trunc (id, id2) VALUES (DEFAULT, 10000);
- COPY ins_trunc FROM '$copy_file' DELIMITER ',';
- INSERT INTO ins_trunc (id, id2) VALUES (DEFAULT, 10000);
- COMMIT;");
- $node->stop('immediate');
- $node->start;
- $result = $node->safe_psql('postgres', "SELECT count(*) FROM ins_trunc;");
- is($result, qq(5), "wal_level = $wal_level, TRUNCATE COPY INSERT");
-
- # Test truncation with inserted tuples using COPY. Tuples copied after
- # the truncation should be seen.
- $node->safe_psql(
- 'postgres', "
- BEGIN;
- CREATE TABLE trunc_copy (id serial PRIMARY KEY, id2 int);
- INSERT INTO trunc_copy VALUES (DEFAULT, generate_series(1,3000));
- TRUNCATE trunc_copy;
- COPY trunc_copy FROM '$copy_file' DELIMITER ',';
- COMMIT;");
- $node->stop('immediate');
- $node->start;
- $result =
- $node->safe_psql('postgres', "SELECT count(*) FROM trunc_copy;");
- is($result, qq(3), "wal_level = $wal_level, TRUNCATE COPY");
-
- # Like previous test, but rollback SET TABLESPACE in a subtransaction.
- $node->safe_psql(
- 'postgres', "
- BEGIN;
- CREATE TABLE spc_abort (id serial PRIMARY KEY, id2 int);
- INSERT INTO spc_abort VALUES (DEFAULT, generate_series(1,3000));
- TRUNCATE spc_abort;
- SAVEPOINT s;
- ALTER TABLE spc_abort SET TABLESPACE other; ROLLBACK TO s;
- COPY spc_abort FROM '$copy_file' DELIMITER ',';
- COMMIT;");
- $node->stop('immediate');
- $node->start;
- $result = $node->safe_psql('postgres', "SELECT count(*) FROM spc_abort;");
- is($result, qq(3),
- "wal_level = $wal_level, SET TABLESPACE abort subtransaction");
-
- # in different subtransaction patterns
- $node->safe_psql(
- 'postgres', "
- BEGIN;
- CREATE TABLE spc_commit (id serial PRIMARY KEY, id2 int);
- INSERT INTO spc_commit VALUES (DEFAULT, generate_series(1,3000));
- TRUNCATE spc_commit;
- SAVEPOINT s; ALTER TABLE spc_commit SET TABLESPACE other; RELEASE s;
- COPY spc_commit FROM '$copy_file' DELIMITER ',';
- COMMIT;");
- $node->stop('immediate');
- $node->start;
- $result =
- $node->safe_psql('postgres', "SELECT count(*) FROM spc_commit;");
- is($result, qq(3),
- "wal_level = $wal_level, SET TABLESPACE commit subtransaction");
-
- $node->safe_psql(
- 'postgres', "
- BEGIN;
- CREATE TABLE spc_nest (id serial PRIMARY KEY, id2 int);
- INSERT INTO spc_nest VALUES (DEFAULT, generate_series(1,3000));
- TRUNCATE spc_nest;
- SAVEPOINT s;
- ALTER TABLE spc_nest SET TABLESPACE other;
- SAVEPOINT s2;
- ALTER TABLE spc_nest SET TABLESPACE pg_default;
- ROLLBACK TO s2;
- SAVEPOINT s2;
- ALTER TABLE spc_nest SET TABLESPACE pg_default;
- RELEASE s2;
- ROLLBACK TO s;
- COPY spc_nest FROM '$copy_file' DELIMITER ',';
- COMMIT;");
- $node->stop('immediate');
- $node->start;
- $result = $node->safe_psql('postgres', "SELECT count(*) FROM spc_nest;");
- is($result, qq(3),
- "wal_level = $wal_level, SET TABLESPACE nested subtransaction");
-
- $node->safe_psql(
- 'postgres', "
- CREATE TABLE spc_hint (id int);
- INSERT INTO spc_hint VALUES (1);
- BEGIN;
- ALTER TABLE spc_hint SET TABLESPACE other;
- CHECKPOINT;
- SELECT * FROM spc_hint; -- set hint bit
- INSERT INTO spc_hint VALUES (2);
- COMMIT;");
- $node->stop('immediate');
- $node->start;
- $result = $node->safe_psql('postgres', "SELECT count(*) FROM spc_hint;");
- is($result, qq(2), "wal_level = $wal_level, SET TABLESPACE, hint bit");
-
- $node->safe_psql(
- 'postgres', "
- BEGIN;
- CREATE TABLE idx_hint (c int PRIMARY KEY);
- SAVEPOINT q; INSERT INTO idx_hint VALUES (1); ROLLBACK TO q;
- CHECKPOINT;
- INSERT INTO idx_hint VALUES (1); -- set index hint bit
- INSERT INTO idx_hint VALUES (2);
- COMMIT;");
- $node->stop('immediate');
- $node->start;
- $result = $node->psql('postgres',);
- my ($ret, $stdout, $stderr) =
- $node->psql('postgres', "INSERT INTO idx_hint VALUES (2);");
- is($ret, qq(3), "wal_level = $wal_level, unique index LP_DEAD");
- like(
- $stderr,
- qr/violates unique/,
- "wal_level = $wal_level, unique index LP_DEAD message");
-
- # UPDATE touches two buffers for one row.
- $node->safe_psql(
- 'postgres', "
- BEGIN;
- CREATE TABLE upd (id serial PRIMARY KEY, id2 int);
- INSERT INTO upd (id, id2) VALUES (DEFAULT, generate_series(1,10000));
- COPY upd FROM '$copy_file' DELIMITER ',';
- UPDATE upd SET id2 = id2 + 1;
- DELETE FROM upd;
- COMMIT;");
- $node->stop('immediate');
- $node->start;
- $result = $node->safe_psql('postgres', "SELECT count(*) FROM upd;");
- is($result, qq(0),
- "wal_level = $wal_level, UPDATE touches two buffers for one row");
-
- # Test consistency of COPY with INSERT for table created in the same
- # transaction.
- $node->safe_psql(
- 'postgres', "
- BEGIN;
- CREATE TABLE ins_copy (id serial PRIMARY KEY, id2 int);
- INSERT INTO ins_copy VALUES (DEFAULT, 1);
- COPY ins_copy FROM '$copy_file' DELIMITER ',';
- COMMIT;");
- $node->stop('immediate');
- $node->start;
- $result = $node->safe_psql('postgres', "SELECT count(*) FROM ins_copy;");
- is($result, qq(4), "wal_level = $wal_level, INSERT COPY");
-
- # Test consistency of COPY that inserts more to the same table using
- # triggers. If the INSERTS from the trigger go to the same block data
- # is copied to, and the INSERTs are WAL-logged, WAL replay will fail when
- # it tries to replay the WAL record but the "before" image doesn't match,
- # because not all changes were WAL-logged.
- $node->safe_psql(
- 'postgres', "
- BEGIN;
- CREATE TABLE ins_trig (id serial PRIMARY KEY, id2 text);
- CREATE FUNCTION ins_trig_before_row_trig() RETURNS trigger
- LANGUAGE plpgsql as \$\$
- BEGIN
- IF new.id2 NOT LIKE 'triggered%' THEN
- INSERT INTO ins_trig
- VALUES (DEFAULT, 'triggered row before' || NEW.id2);
- END IF;
- RETURN NEW;
- END; \$\$;
- CREATE FUNCTION ins_trig_after_row_trig() RETURNS trigger
- LANGUAGE plpgsql as \$\$
- BEGIN
- IF new.id2 NOT LIKE 'triggered%' THEN
- INSERT INTO ins_trig
- VALUES (DEFAULT, 'triggered row after' || NEW.id2);
- END IF;
- RETURN NEW;
- END; \$\$;
- CREATE TRIGGER ins_trig_before_row_insert
- BEFORE INSERT ON ins_trig
- FOR EACH ROW EXECUTE PROCEDURE ins_trig_before_row_trig();
- CREATE TRIGGER ins_trig_after_row_insert
- AFTER INSERT ON ins_trig
- FOR EACH ROW EXECUTE PROCEDURE ins_trig_after_row_trig();
- COPY ins_trig FROM '$copy_file' DELIMITER ',';
- COMMIT;");
- $node->stop('immediate');
- $node->start;
- $result = $node->safe_psql('postgres', "SELECT count(*) FROM ins_trig;");
- is($result, qq(9), "wal_level = $wal_level, COPY with INSERT triggers");
-
- # Test consistency of INSERT, COPY and TRUNCATE in same transaction block
- # with TRUNCATE triggers.
- $node->safe_psql(
- 'postgres', "
- BEGIN;
- CREATE TABLE trunc_trig (id serial PRIMARY KEY, id2 text);
- CREATE FUNCTION trunc_trig_before_stat_trig() RETURNS trigger
- LANGUAGE plpgsql as \$\$
- BEGIN
- INSERT INTO trunc_trig VALUES (DEFAULT, 'triggered stat before');
- RETURN NULL;
- END; \$\$;
- CREATE FUNCTION trunc_trig_after_stat_trig() RETURNS trigger
- LANGUAGE plpgsql as \$\$
- BEGIN
- INSERT INTO trunc_trig VALUES (DEFAULT, 'triggered stat before');
- RETURN NULL;
- END; \$\$;
- CREATE TRIGGER trunc_trig_before_stat_truncate
- BEFORE TRUNCATE ON trunc_trig
- FOR EACH STATEMENT EXECUTE PROCEDURE trunc_trig_before_stat_trig();
- CREATE TRIGGER trunc_trig_after_stat_truncate
- AFTER TRUNCATE ON trunc_trig
- FOR EACH STATEMENT EXECUTE PROCEDURE trunc_trig_after_stat_trig();
- INSERT INTO trunc_trig VALUES (DEFAULT, 1);
- TRUNCATE trunc_trig;
- COPY trunc_trig FROM '$copy_file' DELIMITER ',';
- COMMIT;");
- $node->stop('immediate');
- $node->start;
- $result =
- $node->safe_psql('postgres', "SELECT count(*) FROM trunc_trig;");
- is($result, qq(4),
- "wal_level = $wal_level, TRUNCATE COPY with TRUNCATE triggers");
-
- # Test redo of temp table creation.
- $node->safe_psql(
- 'postgres', "
- CREATE TEMP TABLE temp (id serial PRIMARY KEY, id2 text);");
- $node->stop('immediate');
- $node->start;
- check_orphan_relfilenodes($node,
- "wal_level = $wal_level, no orphan relfilenode remains");
-
- return;
-}
-
-# Run same test suite for multiple wal_level values.
-run_wal_optimize("minimal");
-run_wal_optimize("replica");