Skip to content

Commit

Permalink
Merge pull request #6 from cpaelzer/fix-pg-11.2-test-error
Browse files Browse the repository at this point in the history
Fix test issue with postgresql 11.2
  • Loading branch information
jfinzel authored Sep 10, 2019
2 parents 7b5a9c3 + b518c7f commit 2570779
Show file tree
Hide file tree
Showing 3 changed files with 247 additions and 0 deletions.
84 changes: 84 additions & 0 deletions expected/07_handlers_1.out
Original file line number Diff line number Diff line change
@@ -0,0 +1,84 @@
/***
There may be a race condition in WaitForBackgroundWorkerStartup that
leads to indeterminate behavior on a bad launch.

For this reason, we set log_min_messages to FATAL. These tests then
really only ensure that the server lives OK during a bad launch.
***/
SET client_min_messages TO FATAL;
--The _launch function is not supposed to be used directly
--This tests that stupid things don't do something really bad
DROP TABLE IF EXISTS bad_pid;
CREATE TEMP TABLE bad_pid AS
SELECT pglogical_ticker._launch(9999999::OID) AS pid;
ERROR: could not start background process
HINT: More details may be available in the server log.
--Verify that it exits cleanly if the SQL within the worker errors out
--In this case, renaming the function will do it
ALTER FUNCTION pglogical_ticker.tick() RENAME TO tick_oops;
DROP TABLE IF EXISTS bad_pid_2;
CREATE TEMP TABLE bad_pid_2 AS
SELECT pglogical_ticker.launch() AS pid;
ERROR: could not start background process
HINT: More details may be available in the server log.
CONTEXT: SQL function "launch" statement 1
-- Give it time to die asynchronously
SELECT pg_sleep(2);
pg_sleep
----------

(1 row)

-- Fix it
ALTER FUNCTION pglogical_ticker.tick_oops() RENAME TO tick;
--Verify we can't start multiple workers - the second attempt should return NULL
--We know this is imperfect but so long as pglogical_ticker.launch is not executed
--at the same exact moment this is good enough insurance for now.
--Also, multiple workers still could be running without any bad side effects.
--Should be false because the process should start OK
SELECT pglogical_ticker.launch() IS NULL AS pid;
pid
-----
f
(1 row)

SELECT pg_sleep(1);
pg_sleep
----------

(1 row)

--Should be true because we already have one running
SELECT pglogical_ticker.launch() IS NULL AS next_attempt_no_pid;
next_attempt_no_pid
---------------------
t
(1 row)

-- We do this because of race condition above. We may be killing more than one pid
WITH canceled AS (
SELECT pg_cancel_backend(pid)
FROM pg_stat_activity
WHERE NOT pid = pg_backend_pid()
AND query LIKE '%pglogical_ticker%')
SELECT (SELECT COUNT(1) FROM canceled) > 0 AS at_least_one_canceled;
at_least_one_canceled
-----------------------
t
(1 row)

SELECT pg_sleep(1);
pg_sleep
----------

(1 row)

SELECT COUNT(1) AS ticker_still_running
FROM pg_stat_activity
WHERE NOT pid = pg_backend_pid()
AND query LIKE '%pglogical_ticker%';
ticker_still_running
----------------------
0
(1 row)

82 changes: 82 additions & 0 deletions expected/07_handlers_2.out
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
/***
There may be a race condition in WaitForBackgroundWorkerStartup that
leads to indeterminate behavior on a bad launch.

For this reason, we set log_min_messages to FATAL. These tests then
really only ensure that the server lives OK during a bad launch.
***/
SET client_min_messages TO FATAL;
--The _launch function is not supposed to be used directly
--This tests that stupid things don't do something really bad
DROP TABLE IF EXISTS bad_pid;
CREATE TEMP TABLE bad_pid AS
SELECT pglogical_ticker._launch(9999999::OID) AS pid;
--Verify that it exits cleanly if the SQL within the worker errors out
--In this case, renaming the function will do it
ALTER FUNCTION pglogical_ticker.tick() RENAME TO tick_oops;
DROP TABLE IF EXISTS bad_pid_2;
CREATE TEMP TABLE bad_pid_2 AS
SELECT pglogical_ticker.launch() AS pid;
ERROR: could not start background process
HINT: More details may be available in the server log.
CONTEXT: SQL function "launch" statement 1
-- Give it time to die asynchronously
SELECT pg_sleep(2);
pg_sleep
----------

(1 row)

-- Fix it
ALTER FUNCTION pglogical_ticker.tick_oops() RENAME TO tick;
--Verify we can't start multiple workers - the second attempt should return NULL
--We know this is imperfect but so long as pglogical_ticker.launch is not executed
--at the same exact moment this is good enough insurance for now.
--Also, multiple workers still could be running without any bad side effects.
--Should be false because the process should start OK
SELECT pglogical_ticker.launch() IS NULL AS pid;
pid
-----
f
(1 row)

SELECT pg_sleep(1);
pg_sleep
----------

(1 row)

--Should be true because we already have one running
SELECT pglogical_ticker.launch() IS NULL AS next_attempt_no_pid;
next_attempt_no_pid
---------------------
t
(1 row)

-- We do this because of race condition above. We may be killing more than one pid
WITH canceled AS (
SELECT pg_cancel_backend(pid)
FROM pg_stat_activity
WHERE NOT pid = pg_backend_pid()
AND query LIKE '%pglogical_ticker%')
SELECT (SELECT COUNT(1) FROM canceled) > 0 AS at_least_one_canceled;
at_least_one_canceled
-----------------------
t
(1 row)

SELECT pg_sleep(1);
pg_sleep
----------

(1 row)

SELECT COUNT(1) AS ticker_still_running
FROM pg_stat_activity
WHERE NOT pid = pg_backend_pid()
AND query LIKE '%pglogical_ticker%';
ticker_still_running
----------------------
0
(1 row)

81 changes: 81 additions & 0 deletions expected/07_handlers_3.out
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
/***
There may be a race condition in WaitForBackgroundWorkerStartup that
leads to indeterminate behavior on a bad launch.

For this reason, we set log_min_messages to FATAL. These tests then
really only ensure that the server lives OK during a bad launch.
***/
SET client_min_messages TO FATAL;
--The _launch function is not supposed to be used directly
--This tests that stupid things don't do something really bad
DROP TABLE IF EXISTS bad_pid;
CREATE TEMP TABLE bad_pid AS
SELECT pglogical_ticker._launch(9999999::OID) AS pid;
ERROR: could not start background process
HINT: More details may be available in the server log.
--Verify that it exits cleanly if the SQL within the worker errors out
--In this case, renaming the function will do it
ALTER FUNCTION pglogical_ticker.tick() RENAME TO tick_oops;
DROP TABLE IF EXISTS bad_pid_2;
CREATE TEMP TABLE bad_pid_2 AS
SELECT pglogical_ticker.launch() AS pid;
-- Give it time to die asynchronously
SELECT pg_sleep(2);
pg_sleep
----------

(1 row)

-- Fix it
ALTER FUNCTION pglogical_ticker.tick_oops() RENAME TO tick;
--Verify we can't start multiple workers - the second attempt should return NULL
--We know this is imperfect but so long as pglogical_ticker.launch is not executed
--at the same exact moment this is good enough insurance for now.
--Also, multiple workers still could be running without any bad side effects.
--Should be false because the process should start OK
SELECT pglogical_ticker.launch() IS NULL AS pid;
pid
-----
f
(1 row)

SELECT pg_sleep(1);
pg_sleep
----------

(1 row)

--Should be true because we already have one running
SELECT pglogical_ticker.launch() IS NULL AS next_attempt_no_pid;
next_attempt_no_pid
---------------------
t
(1 row)

-- We do this because of race condition above. We may be killing more than one pid
WITH canceled AS (
SELECT pg_cancel_backend(pid)
FROM pg_stat_activity
WHERE NOT pid = pg_backend_pid()
AND query LIKE '%pglogical_ticker%')
SELECT (SELECT COUNT(1) FROM canceled) > 0 AS at_least_one_canceled;
at_least_one_canceled
-----------------------
t
(1 row)

SELECT pg_sleep(1);
pg_sleep
----------

(1 row)

SELECT COUNT(1) AS ticker_still_running
FROM pg_stat_activity
WHERE NOT pid = pg_backend_pid()
AND query LIKE '%pglogical_ticker%';
ticker_still_running
----------------------
0
(1 row)

0 comments on commit 2570779

Please sign in to comment.