Re: [HACKERS] Hot Standby and query cancel
On Wed, 2010-01-13 at 19:23 +, Simon Riggs wrote: On Wed, 2010-01-13 at 19:58 +0100, Andres Freund wrote: I am still testing patch, so should be confident to commit tomorrow barring issues. I have only looked at briefly because right now I dont have the time (going to eat at a friends place...) but I think I spotted an issue: The IsAbortedTransactionBlockState() check in RecoveryConflictInterrupt is not correct right now because that returns true for TBLOCK_SUBABORT as well. Wouldnt that mess with the case where were in a failed subxact and then rollback only that subxact? Well spotted, yes. Latest version of same patch, but uses conflict reasons passed-thru directly from recovery to backend. Please review, no commit before tomorrow. -- Simon Riggs www.2ndQuadrant.com *** a/src/backend/access/transam/xact.c --- b/src/backend/access/transam/xact.c *** *** 313,320 IsTransactionState(void) /* * IsAbortedTransactionBlockState * ! * This returns true if we are currently running a query ! * within an aborted transaction block. */ bool IsAbortedTransactionBlockState(void) --- 313,319 /* * IsAbortedTransactionBlockState * ! * This returns true if we are within an aborted transaction block. */ bool IsAbortedTransactionBlockState(void) *** a/src/backend/storage/ipc/procarray.c --- b/src/backend/storage/ipc/procarray.c *** *** 324,329 ProcArrayEndTransaction(PGPROC *proc, TransactionId latestXid) --- 324,330 /* must be cleared with xid/xmin: */ proc-vacuumFlags = ~PROC_VACUUM_STATE_MASK; proc-inCommit = false; /* be sure this is cleared in abort */ + proc-recoveryConflictPending = false; /* Clear the subtransaction-XID cache too while holding the lock */ proc-subxids.nxids = 0; *** *** 350,355 ProcArrayEndTransaction(PGPROC *proc, TransactionId latestXid) --- 351,357 /* must be cleared with xid/xmin: */ proc-vacuumFlags = ~PROC_VACUUM_STATE_MASK; proc-inCommit = false; /* be sure this is cleared in abort */ + proc-recoveryConflictPending = false; Assert(proc-subxids.nxids == 0); Assert(proc-subxids.overflowed == false); *** *** 377,383 ProcArrayClearTransaction(PGPROC *proc) proc-xid = InvalidTransactionId; proc-lxid = InvalidLocalTransactionId; proc-xmin = InvalidTransactionId; ! proc-recoveryConflictMode = 0; /* redundant, but just in case */ proc-vacuumFlags = ~PROC_VACUUM_STATE_MASK; --- 379,385 proc-xid = InvalidTransactionId; proc-lxid = InvalidLocalTransactionId; proc-xmin = InvalidTransactionId; ! proc-recoveryConflictPending = false; /* redundant, but just in case */ proc-vacuumFlags = ~PROC_VACUUM_STATE_MASK; *** *** 1665,1671 GetConflictingVirtualXIDs(TransactionId limitXmin, Oid dbOid, if (proc-pid == 0) continue; ! if (skipExistingConflicts proc-recoveryConflictMode 0) continue; if (!OidIsValid(dbOid) || --- 1667,1673 if (proc-pid == 0) continue; ! if (skipExistingConflicts proc-recoveryConflictPending) continue; if (!OidIsValid(dbOid) || *** *** 1704,1710 GetConflictingVirtualXIDs(TransactionId limitXmin, Oid dbOid, * Returns pid of the process signaled, or 0 if not found. */ pid_t ! CancelVirtualTransaction(VirtualTransactionId vxid, int cancel_mode) { ProcArrayStruct *arrayP = procArray; int index; --- 1706,1712 * Returns pid of the process signaled, or 0 if not found. */ pid_t ! CancelVirtualTransaction(VirtualTransactionId vxid, ProcSignalReason sigmode) { ProcArrayStruct *arrayP = procArray; int index; *** *** 1722,1749 CancelVirtualTransaction(VirtualTransactionId vxid, int cancel_mode) if (procvxid.backendId == vxid.backendId procvxid.localTransactionId == vxid.localTransactionId) { ! /* ! * Issue orders for the proc to read next time it receives SIGINT ! */ ! if (proc-recoveryConflictMode cancel_mode) ! proc-recoveryConflictMode = cancel_mode; ! pid = proc-pid; break; } } LWLockRelease(ProcArrayLock); - if (pid != 0) - { - /* - * Kill the pid if it's still here. If not, that's what we wanted - * so ignore any errors. - */ - kill(pid, SIGINT); - } - return pid; } --- 1724,1745 if (procvxid.backendId == vxid.backendId procvxid.localTransactionId == vxid.localTransactionId) { ! proc-recoveryConflictPending = true; pid = proc-pid; + if (pid != 0) + { + /* + * Kill the pid if it's still here. If not, that's what we wanted + * so ignore any errors. + */ + (void) SendProcSignal(pid, sigmode, vxid.backendId); + } break; } } LWLockRelease(ProcArrayLock); return pid; } *** *** 1834,1839 CancelDBBackends(Oid
Re: [HACKERS] Hot Standby and query cancel
On Thursday 14 January 2010 13:21:07 Simon Riggs wrote: On Wed, 2010-01-13 at 19:23 +, Simon Riggs wrote: On Wed, 2010-01-13 at 19:58 +0100, Andres Freund wrote: I am still testing patch, so should be confident to commit tomorrow barring issues. I have only looked at briefly because right now I dont have the time (going to eat at a friends place...) but I think I spotted an issue: The IsAbortedTransactionBlockState() check in RecoveryConflictInterrupt is not correct right now because that returns true for TBLOCK_SUBABORT as well. Wouldnt that mess with the case where were in a failed subxact and then rollback only that subxact? Well spotted, yes. Latest version of same patch, but uses conflict reasons passed-thru directly from recovery to backend. Please review, no commit before tomorrow. I only noted a tiny thing (which was present earlier on): snprintf(waitactivitymsg, sizeof(waitactivitymsg), waiting for max_standby_delay (%u ms), MaxStandbyDelay); in ResolveRecoveryConflictWithVirtualXIDs. Shouldnt that be seconds? Otherwise the check in WaitExceedsMaxStandbyDelay is wrong... Andres -- Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org) To make changes to your subscription: http://www.postgresql.org/mailpref/pgsql-hackers
Re: [HACKERS] Hot Standby and query cancel
Hi Simon, On Wednesday 13 January 2010 19:24:22 Simon Riggs wrote: We've been chewing around query cancel on Hot Standby and I think things have got fairly confusing, hence a new thread. Good idea. I enclose a patch that includes all the things that we all agree on so far, in my understanding cool. * Recovery conflict processing uses SIGUSR1 rather than shmem per Tom, while holding ProcArrayLock per Andres * CONFLICT_MODE_ERROR throws ERROR when in a transaction, not idle and not in subtransaction, otherwise becomes CONFLICT_MODE_FATAL per Tom and other discussion * Recovery abort message has additional detail, per Heikki It doesn't include anything still under discussion, though is intended as a base upon which further patches can progress independently. I am still testing patch, so should be confident to commit tomorrow barring issues. I have only looked at briefly because right now I dont have the time (going to eat at a friends place...) but I think I spotted an issue: The IsAbortedTransactionBlockState() check in RecoveryConflictInterrupt is not correct right now because that returns true for TBLOCK_SUBABORT as well. Wouldnt that mess with the case where were in a failed subxact and then rollback only that subxact? Andres -- Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org) To make changes to your subscription: http://www.postgresql.org/mailpref/pgsql-hackers
Re: [HACKERS] Hot Standby and query cancel
On Wed, 2010-01-13 at 19:58 +0100, Andres Freund wrote: I am still testing patch, so should be confident to commit tomorrow barring issues. I have only looked at briefly because right now I dont have the time (going to eat at a friends place...) but I think I spotted an issue: The IsAbortedTransactionBlockState() check in RecoveryConflictInterrupt is not correct right now because that returns true for TBLOCK_SUBABORT as well. Wouldnt that mess with the case where were in a failed subxact and then rollback only that subxact? Well spotted, yes. -- Simon Riggs www.2ndQuadrant.com *** a/src/backend/access/transam/xact.c --- b/src/backend/access/transam/xact.c *** *** 313,320 IsTransactionState(void) /* * IsAbortedTransactionBlockState * ! * This returns true if we are currently running a query ! * within an aborted transaction block. */ bool IsAbortedTransactionBlockState(void) --- 313,319 /* * IsAbortedTransactionBlockState * ! * This returns true if we are within an aborted transaction block. */ bool IsAbortedTransactionBlockState(void) *** a/src/backend/storage/ipc/procarray.c --- b/src/backend/storage/ipc/procarray.c *** *** 324,329 ProcArrayEndTransaction(PGPROC *proc, TransactionId latestXid) --- 324,330 /* must be cleared with xid/xmin: */ proc-vacuumFlags = ~PROC_VACUUM_STATE_MASK; proc-inCommit = false; /* be sure this is cleared in abort */ + proc-recoveryConflictPending = false; /* Clear the subtransaction-XID cache too while holding the lock */ proc-subxids.nxids = 0; *** *** 350,355 ProcArrayEndTransaction(PGPROC *proc, TransactionId latestXid) --- 351,357 /* must be cleared with xid/xmin: */ proc-vacuumFlags = ~PROC_VACUUM_STATE_MASK; proc-inCommit = false; /* be sure this is cleared in abort */ + proc-recoveryConflictPending = false; Assert(proc-subxids.nxids == 0); Assert(proc-subxids.overflowed == false); *** *** 377,383 ProcArrayClearTransaction(PGPROC *proc) proc-xid = InvalidTransactionId; proc-lxid = InvalidLocalTransactionId; proc-xmin = InvalidTransactionId; ! proc-recoveryConflictMode = 0; /* redundant, but just in case */ proc-vacuumFlags = ~PROC_VACUUM_STATE_MASK; --- 379,385 proc-xid = InvalidTransactionId; proc-lxid = InvalidLocalTransactionId; proc-xmin = InvalidTransactionId; ! proc-recoveryConflictPending = false; /* redundant, but just in case */ proc-vacuumFlags = ~PROC_VACUUM_STATE_MASK; *** *** 1665,1671 GetConflictingVirtualXIDs(TransactionId limitXmin, Oid dbOid, if (proc-pid == 0) continue; ! if (skipExistingConflicts proc-recoveryConflictMode 0) continue; if (!OidIsValid(dbOid) || --- 1667,1673 if (proc-pid == 0) continue; ! if (skipExistingConflicts proc-recoveryConflictPending) continue; if (!OidIsValid(dbOid) || *** *** 1704,1710 GetConflictingVirtualXIDs(TransactionId limitXmin, Oid dbOid, * Returns pid of the process signaled, or 0 if not found. */ pid_t ! CancelVirtualTransaction(VirtualTransactionId vxid, int cancel_mode) { ProcArrayStruct *arrayP = procArray; int index; --- 1706,1712 * Returns pid of the process signaled, or 0 if not found. */ pid_t ! CancelVirtualTransaction(VirtualTransactionId vxid, ProcSignalReason sigmode) { ProcArrayStruct *arrayP = procArray; int index; *** *** 1722,1749 CancelVirtualTransaction(VirtualTransactionId vxid, int cancel_mode) if (procvxid.backendId == vxid.backendId procvxid.localTransactionId == vxid.localTransactionId) { ! /* ! * Issue orders for the proc to read next time it receives SIGINT ! */ ! if (proc-recoveryConflictMode cancel_mode) ! proc-recoveryConflictMode = cancel_mode; ! pid = proc-pid; break; } } LWLockRelease(ProcArrayLock); - if (pid != 0) - { - /* - * Kill the pid if it's still here. If not, that's what we wanted - * so ignore any errors. - */ - kill(pid, SIGINT); - } - return pid; } --- 1724,1745 if (procvxid.backendId == vxid.backendId procvxid.localTransactionId == vxid.localTransactionId) { ! proc-recoveryConflictPending = true; pid = proc-pid; + if (pid != 0) + { + /* + * Kill the pid if it's still here. If not, that's what we wanted + * so ignore any errors. + */ + (void) SendProcSignal(pid, sigmode, vxid.backendId); + } break; } } LWLockRelease(ProcArrayLock); return pid; } *** *** 1834,1839 CancelDBBackends(Oid databaseid) --- 1830,1836 { ProcArrayStruct *arrayP = procArray; int index; + pid_t pid = 0; /* tell all backends to die */ LWLockAcquire(ProcArrayLock, LW_EXCLUSIVE); *** ***