-- Tests for running transaction recovery from a worker node SET citus.shard_count TO 4; SET citus.shard_replication_factor TO 1; SET citus.replication_model TO streaming; CREATE TABLE test_recovery (x text); SELECT create_distributed_table('test_recovery', 'x'); create_distributed_table -------------------------- (1 row) \c - - - :worker_1_port -- Disable auto-recovery for the initial tests ALTER SYSTEM SET citus.recover_2pc_interval TO -1; SELECT pg_reload_conf(); pg_reload_conf ---------------- t (1 row) SET citus.multi_shard_commit_protocol TO '2pc'; -- Ensure pg_dist_transaction is empty for test SELECT recover_prepared_transactions(); recover_prepared_transactions ------------------------------- 0 (1 row) SELECT count(*) FROM pg_dist_transaction; count ------- 0 (1 row) -- If the groupid of the worker changes this query will produce a -- different result and the prepared statement names should be adapted -- accordingly. SELECT * FROM pg_dist_local_group; groupid --------- 14 (1 row) BEGIN; CREATE TABLE table_should_abort (value int); PREPARE TRANSACTION 'citus_14_should_abort'; BEGIN; CREATE TABLE table_should_commit (value int); PREPARE TRANSACTION 'citus_14_should_commit'; BEGIN; CREATE TABLE should_be_sorted_into_middle (value int); PREPARE TRANSACTION 'citus_14_should_be_sorted_into_middle'; -- this node (e.g., node id 14) should not touch -- transactions with different nodeIds in the gid BEGIN; CREATE TABLE table_should_do_nothing (value int); PREPARE TRANSACTION 'citus_122_should_do_nothing'; -- Add "fake" pg_dist_transaction records and run recovery INSERT INTO pg_dist_transaction VALUES (14, 'citus_14_should_commit'); INSERT INTO pg_dist_transaction VALUES (14, 'citus_14_should_be_forgotten'); INSERT INTO pg_dist_transaction VALUES (122, 'citus_122_should_do_nothing'); SELECT recover_prepared_transactions(); recover_prepared_transactions ------------------------------- 3 (1 row) -- delete the citus_122_should_do_nothing transaction DELETE FROM pg_dist_transaction WHERE gid = 'citus_122_should_do_nothing' RETURNING *; groupid | gid ---------+----------------------------- 122 | citus_122_should_do_nothing (1 row) ROLLBACK PREPARED 'citus_122_should_do_nothing'; SELECT count(*) FROM pg_dist_transaction; count ------- 0 (1 row) SELECT count(*) FROM pg_tables WHERE tablename = 'table_should_abort'; count ------- 0 (1 row) SELECT count(*) FROM pg_tables WHERE tablename = 'table_should_commit'; count ------- 1 (1 row) -- plain INSERT does not use 2PC INSERT INTO test_recovery VALUES ('hello'); SELECT count(*) FROM pg_dist_transaction; count ------- 0 (1 row) -- Multi-statement transactions should write 2 transaction recovery records BEGIN; SET LOCAL citus.enable_local_execution TO false; INSERT INTO test_recovery VALUES ('hello'); INSERT INTO test_recovery VALUES ('world'); COMMIT; SELECT count(*) FROM pg_dist_transaction; count ------- 2 (1 row) SELECT recover_prepared_transactions(); recover_prepared_transactions ------------------------------- 0 (1 row) -- the same transaction block, but this time -- enable local execution as well. The first -- command is locally executed, the second -- is remote, so 1 entry is expected BEGIN; INSERT INTO test_recovery VALUES ('hello'); INSERT INTO test_recovery VALUES ('world'); COMMIT; SELECT count(*) FROM pg_dist_transaction; count ------- 1 (1 row) SELECT recover_prepared_transactions(); recover_prepared_transactions ------------------------------- 0 (1 row) -- Committed INSERT..SELECT via coordinator should write 4 transaction recovery records INSERT INTO test_recovery (x) SELECT 'hello-'||s FROM generate_series(1,100) s; SELECT count(*) FROM pg_dist_transaction; count ------- 4 (1 row) SELECT recover_prepared_transactions(); recover_prepared_transactions ------------------------------- 0 (1 row) -- Committed COPY should write 3 transaction records (2 fall into the same shard) COPY test_recovery (x) FROM STDIN CSV; SELECT count(*) FROM pg_dist_transaction; count ------- 3 (1 row) -- Test whether auto-recovery runs ALTER SYSTEM SET citus.recover_2pc_interval TO 10; SELECT pg_reload_conf(); pg_reload_conf ---------------- t (1 row) -- Sleep 1 second to give Valgrind enough time to clear transactions SELECT pg_sleep(1); pg_sleep ---------- (1 row) SELECT count(*) FROM pg_dist_transaction; count ------- 0 (1 row) ALTER SYSTEM RESET citus.recover_2pc_interval; SELECT pg_reload_conf(); pg_reload_conf ---------------- t (1 row) DROP TABLE table_should_commit; \c - - - :master_port DROP TABLE test_recovery_ref; ERROR: table "test_recovery_ref" does not exist DROP TABLE test_recovery;