@ -5,7 +5,6 @@ use PostgresNode;
use TestLib ;
use TestLib ;
use Test::More ;
use Test::More ;
use Config ;
use Config ;
use Time::HiRes qw( usleep ) ;
plan tests = > 9 ;
plan tests = > 9 ;
@ -33,8 +32,7 @@ $node->safe_psql(
# create table, insert rows
# create table, insert rows
$ node - > safe_psql (
$ node - > safe_psql (
'postgres' ,
'postgres' ,
q[ CREATE TABLE tab_crash (a text);
q[ CREATE TABLE tab_crash (a integer UNIQUE); ] ) ;
INSERT INTO tab_crash ( a ) SELECT gen_random_uuid ( ) FROM generate_series ( 1 , 500 ) ; ] ) ;
# Run psql, keeping session alive, so we have an alive backend to kill.
# Run psql, keeping session alive, so we have an alive backend to kill.
my ( $ killme_stdin , $ killme_stdout , $ killme_stderr ) = ( '' , '' , '' ) ;
my ( $ killme_stdin , $ killme_stdout , $ killme_stderr ) = ( '' , '' , '' ) ;
@ -62,6 +60,32 @@ chomp($pid);
$ killme_stdout = '' ;
$ killme_stdout = '' ;
$ killme_stderr = '' ;
$ killme_stderr = '' ;
# Open a 2nd session that will block the 1st one, using the UNIQUE constraint.
# This will prevent removal of the temporary file created by the 1st session.
my ( $ killme_stdin2 , $ killme_stdout2 , $ killme_stderr2 ) = ( '' , '' , '' ) ;
my $ killme2 = IPC::Run:: start (
[
'psql' , '-X' , '-qAt' , '-v' , 'ON_ERROR_STOP=1' , '-f' , '-' , '-d' ,
$ node - > connstr ( 'postgres' )
] ,
'<' ,
\ $ killme_stdin2 ,
'>' ,
\ $ killme_stdout2 ,
'2>' ,
\ $ killme_stderr2 ,
$ psql_timeout ) ;
# Insert one tuple and leave the transaction open
$ killme_stdin2 . = q[
BEGIN ;
SELECT $$ insert - tuple - to - lock - next - insert $$ ;
INSERT INTO tab_crash ( a ) VALUES ( 1 ) ;
] ;
pump_until ( $ killme2 , \ $ killme_stdout2 , qr/insert-tuple-to-lock-next-insert/ m ) ;
$ killme_stdout2 = '' ;
$ killme_stderr2 = '' ;
# Run the query that generates a temporary file and that will be killed before
# Run the query that generates a temporary file and that will be killed before
# it finishes. Since the query that generates the temporary file does not
# it finishes. Since the query that generates the temporary file does not
# return before the connection is killed, use a SELECT before to trigger
# return before the connection is killed, use a SELECT before to trigger
@ -69,22 +93,20 @@ $killme_stderr = '';
$ killme_stdin . = q[
$ killme_stdin . = q[
BEGIN ;
BEGIN ;
SELECT $$ in - progress - before - sigkill $$ ;
SELECT $$ in - progress - before - sigkill $$ ;
WITH foo AS ( SELECT a FROM tab_crash ORDER BY a ) SELECT a , pg_sleep ( 1 ) FROM foo ;
INSERT INTO tab_crash ( a ) SELECT i FROM generate_series ( 1 , 5000 ) s(i) ;
] ;
] ;
ok ( pump_until ( $ killme , \ $ killme_stdout , qr/in-progress-before-sigkill/ m ) ,
ok ( pump_until ( $ killme , \ $ killme_stdout , qr/in-progress-before-sigkill/ m ) ,
'selec t in-progress-before-sigkill' ) ;
'inser t in-progress-before-sigkill' ) ;
$ killme_stdout = '' ;
$ killme_stdout = '' ;
$ killme_stderr = '' ;
$ killme_stderr = '' ;
# Wait some time so the temporary file is generated by SELECT
usleep ( 10_000 ) ;
# Kill with SIGKILL
# Kill with SIGKILL
my $ ret = TestLib:: system_log ( 'pg_ctl' , 'kill' , 'KILL' , $ pid ) ;
my $ ret = TestLib:: system_log ( 'pg_ctl' , 'kill' , 'KILL' , $ pid ) ;
is ( $ ret , 0 , 'killed process with KILL' ) ;
is ( $ ret , 0 , 'killed process with KILL' ) ;
# Close psql session
# Close psql session
$ killme - > finish ;
$ killme - > finish ;
$ killme2 - > finish ;
# Wait till server restarts
# Wait till server restarts
$ node - > poll_query_until ( 'postgres' , 'SELECT 1' , '1' ) ;
$ node - > poll_query_until ( 'postgres' , 'SELECT 1' , '1' ) ;
@ -118,6 +140,20 @@ chomp($pid);
$ killme_stdout = '' ;
$ killme_stdout = '' ;
$ killme_stderr = '' ;
$ killme_stderr = '' ;
# Restart the 2nd psql session
( $ killme_stdin2 , $ killme_stdout2 , $ killme_stderr2 ) = ( '' , '' , '' ) ;
$ killme2 - > run ( ) ;
# Insert one tuple and leave the transaction open
$ killme_stdin2 . = q[
BEGIN ;
SELECT $$ insert - tuple - to - lock - next - insert $$ ;
INSERT INTO tab_crash ( a ) VALUES ( 1 ) ;
] ;
pump_until ( $ killme2 , \ $ killme_stdout2 , qr/insert-tuple-to-lock-next-insert/ m ) ;
$ killme_stdout2 = '' ;
$ killme_stderr2 = '' ;
# Run the query that generates a temporary file and that will be killed before
# Run the query that generates a temporary file and that will be killed before
# it finishes. Since the query that generates the temporary file does not
# it finishes. Since the query that generates the temporary file does not
# return before the connection is killed, use a SELECT before to trigger
# return before the connection is killed, use a SELECT before to trigger
@ -125,22 +161,20 @@ $killme_stderr = '';
$ killme_stdin . = q[
$ killme_stdin . = q[
BEGIN ;
BEGIN ;
SELECT $$ in - progress - before - sigkill $$ ;
SELECT $$ in - progress - before - sigkill $$ ;
WITH foo AS ( SELECT a FROM tab_crash ORDER BY a ) SELECT a , pg_sleep ( 1 ) FROM foo ;
INSERT INTO tab_crash ( a ) SELECT i FROM generate_series ( 1 , 5000 ) s(i) ;
] ;
] ;
ok ( pump_until ( $ killme , \ $ killme_stdout , qr/in-progress-before-sigkill/ m ) ,
ok ( pump_until ( $ killme , \ $ killme_stdout , qr/in-progress-before-sigkill/ m ) ,
'selec t in-progress-before-sigkill' ) ;
'inser t in-progress-before-sigkill' ) ;
$ killme_stdout = '' ;
$ killme_stdout = '' ;
$ killme_stderr = '' ;
$ killme_stderr = '' ;
# Wait some time so the temporary file is generated by SELECT
usleep ( 10_000 ) ;
# Kill with SIGKILL
# Kill with SIGKILL
$ ret = TestLib:: system_log ( 'pg_ctl' , 'kill' , 'KILL' , $ pid ) ;
$ ret = TestLib:: system_log ( 'pg_ctl' , 'kill' , 'KILL' , $ pid ) ;
is ( $ ret , 0 , 'killed process with KILL' ) ;
is ( $ ret , 0 , 'killed process with KILL' ) ;
# Close psql session
# Close psql session
$ killme - > finish ;
$ killme - > finish ;
$ killme2 - > finish ;
# Wait till server restarts
# Wait till server restarts
$ node - > poll_query_until ( 'postgres' , 'SELECT 1' , '1' ) ;
$ node - > poll_query_until ( 'postgres' , 'SELECT 1' , '1' ) ;