On Sun, Dec 6, 2009 at 4:23 PM, Tom Lane <t...@sss.pgh.pa.us> wrote:
> We are using NOTICE, not NOTIFY, assuming that we use anything at all
> (which I still regard as unnecessary).  Please stop injecting confusion
> into the discussion.

Attached is a minimal POC patch that allows to cancel an idle
transaction with SIGINT. The HS patch also allows this in its current
form but as Simon points out the client gets out of sync with it.

The proposal is to send an additional NOTICE to the client and abort
all open transactions and subtransactions (this is what I got from the
previous discussion).

I had to write an additional function AbortAnyTransaction() which
aborts all transactions and subtransactions and leaves the transaction
in the aborted state, is there an existing function to do this?

We'd probably want to add a timeout for idle transactions also (which
is a wishlist item since quite some time) and could also offer user
functions like pg_cancel_idle_transaction(). Along this we might need
to add internal reasons like we do for SIGUSR1 because we are now
multiplexing different functionality onto the SIGINT signal. One might
want to cancel an idle transaction only and not a running query,
without keeping track of internal reasons one risks to cancel a
legitimate query if that backend has started to work on a query again.

Comments?


Joachim
diff -cr cvs/src/backend/access/transam/xact.c cvs.build/src/backend/access/transam/xact.c
*** cvs/src/backend/access/transam/xact.c	2009-12-24 13:55:12.000000000 +0100
--- cvs.build/src/backend/access/transam/xact.c	2009-12-24 20:55:17.000000000 +0100
***************
*** 2692,2697 ****
--- 2692,2735 ----
  }
  
  /*
+  *	AbortAnyTransaction
+  */
+ void
+ AbortAnyTransaction(void)
+ {
+ 	TransactionState s = CurrentTransactionState;
+ 
+ 	switch (s->blockState)
+ 	{
+ 		case TBLOCK_DEFAULT:
+ 		case TBLOCK_STARTED:
+ 		case TBLOCK_BEGIN:
+ 		case TBLOCK_INPROGRESS:
+ 		case TBLOCK_END:
+ 		case TBLOCK_ABORT:
+ 		case TBLOCK_SUBABORT:
+ 		case TBLOCK_ABORT_END:
+ 		case TBLOCK_ABORT_PENDING:
+ 		case TBLOCK_PREPARE:
+ 		case TBLOCK_SUBABORT_END:
+ 		case TBLOCK_SUBABORT_RESTART:
+ 			AbortCurrentTransaction();
+ 			break;
+ 
+ 		case TBLOCK_SUBINPROGRESS:
+ 		case TBLOCK_SUBBEGIN:
+ 		case TBLOCK_SUBEND:
+ 		case TBLOCK_SUBABORT_PENDING:
+ 		case TBLOCK_SUBRESTART:
+ 			AbortSubTransaction();
+ 			CleanupSubTransaction();
+ 			AbortAnyTransaction();
+ 			break;
+ 	}
+ }
+ 
+ 
+ /*
   *	PreventTransactionChain
   *
   *	This routine is to be called by statements that must not run inside
diff -cr cvs/src/backend/tcop/postgres.c cvs.build/src/backend/tcop/postgres.c
*** cvs/src/backend/tcop/postgres.c	2009-12-24 13:55:18.000000000 +0100
--- cvs.build/src/backend/tcop/postgres.c	2009-12-24 20:55:17.000000000 +0100
***************
*** 2637,2643 ****
  	if (!proc_exit_inprogress)
  	{
  		InterruptPending = true;
! 		QueryCancelPending = true;
  
  		/*
  		 * If it's safe to interrupt, and we're waiting for a lock, service
--- 2637,2647 ----
  	if (!proc_exit_inprogress)
  	{
  		InterruptPending = true;
! 
! 		if (DoingCommandRead)
! 			TransactionCancelPending = true;
! 		else
! 			QueryCancelPending = true;
  
  		/*
  		 * If it's safe to interrupt, and we're waiting for a lock, service
***************
*** 2789,2794 ****
--- 2793,2821 ----
  					 errmsg("canceling statement due to user request")));
  		}
  	}
+ 	if (TransactionCancelPending)
+ 	{
+ 		QueryCancelPending = false;
+ 		ImmediateInterruptOK = false;	/* not idle anymore */
+ 
+ 		if (!IsTransactionOrTransactionBlock())
+ 			return;
+ 
+ 		if (IsAbortedTransactionBlockState())
+ 			return;
+ 
+ 		DisableNotifyInterrupt();
+ 		DisableCatchupInterrupt();
+ 
+ 		ereport(NOTICE,
+ 				(errcode(ERRCODE_QUERY_CANCELED),
+ 				 errmsg("canceling transaction due to user request")));
+ 
+ 		AbortAnyTransaction();
+ 
+ 		set_ps_display("idle in transaction (aborted)", false);
+ 		pgstat_report_activity("<IDLE> in transaction (aborted)");
+ 	}
  	/* If we get here, do nothing (probably, QueryCancelPending was reset) */
  }
  
diff -cr cvs/src/backend/utils/init/globals.c cvs.build/src/backend/utils/init/globals.c
*** cvs/src/backend/utils/init/globals.c	2009-12-09 11:24:42.000000000 +0100
--- cvs.build/src/backend/utils/init/globals.c	2009-12-24 20:55:17.000000000 +0100
***************
*** 27,32 ****
--- 27,33 ----
  
  volatile bool InterruptPending = false;
  volatile bool QueryCancelPending = false;
+ volatile bool TransactionCancelPending = false;
  volatile bool ProcDiePending = false;
  volatile bool ImmediateInterruptOK = false;
  volatile uint32 InterruptHoldoffCount = 0;
diff -cr cvs/src/include/access/xact.h cvs.build/src/include/access/xact.h
*** cvs/src/include/access/xact.h	2009-12-24 13:55:28.000000000 +0100
--- cvs.build/src/include/access/xact.h	2009-12-24 20:55:17.000000000 +0100
***************
*** 204,209 ****
--- 204,210 ----
  extern bool IsTransactionOrTransactionBlock(void);
  extern char TransactionBlockStatusCode(void);
  extern void AbortOutOfAnyTransaction(void);
+ extern void AbortAnyTransaction(void);
  extern void PreventTransactionChain(bool isTopLevel, const char *stmtType);
  extern void RequireTransactionChain(bool isTopLevel, const char *stmtType);
  extern bool IsInTransactionChain(bool isTopLevel);
diff -cr cvs/src/include/miscadmin.h cvs.build/src/include/miscadmin.h
*** cvs/src/include/miscadmin.h	2009-12-24 13:55:28.000000000 +0100
--- cvs.build/src/include/miscadmin.h	2009-12-24 20:55:37.000000000 +0100
***************
*** 68,73 ****
--- 68,74 ----
  /* these are marked volatile because they are set by signal handlers: */
  extern PGDLLIMPORT volatile bool InterruptPending;
  extern volatile bool QueryCancelPending;
+ extern volatile bool TransactionCancelPending;
  extern volatile bool ProcDiePending;
  
  /* these are marked volatile because they are examined by signal handlers: */
-- 
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers

Reply via email to