postgres.git / summary / log / commit / refs

commit    864e8080e19007ed3377d679447d2fc06f148bc8
Author:   Tom Lane <tgl@sss.pgh.pa.us>
Date:     Sun Nov 24 20:57:32 2019 +0000
First released in: 13.0, 9.4.26, 9.5.21, 9.6.17, 10.12, 11.7, 12.2

    Avoid assertion failure with LISTEN in a serializable transaction.
    
    If LISTEN is the only action in a serializable-mode transaction,
    and the session was not previously listening, and the notify queue
    is not empty, predicate.c reported an assertion failure.  That
    happened because we'd acquire the transaction's initial snapshot
    during PreCommit_Notify, which was called *after* predicate.c
    expects any such snapshot to have been established.
    
    To fix, just swap the order of the PreCommit_Notify and
    PreCommit_CheckForSerializationFailure calls during CommitTransaction.
    This will imply holding the notify-insertion lock slightly longer,
    but the difference could only be meaningful in serializable mode,
    which is an expensive option anyway.
    
    It appears that this is just an assertion failure, with no
    consequences in non-assert builds.  A snapshot used only to scan
    the notify queue could not have been involved in any serialization
    conflicts, so there would be nothing for
    PreCommit_CheckForSerializationFailure to do except assign it a
    prepareSeqNo and set the SXACT_FLAG_PREPARED flag.  And given no
    conflicts, neither of those omissions affect the behavior of
    ReleasePredicateLocks.  This admittedly once-over-lightly analysis
    is backed up by the lack of field reports of trouble.
    
    Per report from Mark Dilger.  The bug is old, so back-patch to all
    supported branches; but the new test case only goes back to 9.6,
    for lack of adequate isolationtester infrastructure before that.
    
    Discussion: https://postgr.es/m/3ac7f397-4d5f-be8e-f354-440020675694@gmail.com
    Discussion: https://postgr.es/m/13881.1574557302@sss.pgh.pa.us


src/backend/access/transam/xact.c | 19 ++++++++++--------- 1 file changed, 10 insertions(+), 9 deletions(-) diff --git a/src/backend/access/transam/xact.c b/src/backend/access/transam/xact.c index 9effa1a7cd9..03cadb018f4 100644 --- a/src/backend/access/transam/xact.c +++ b/src/backend/access/transam/xact.c @@ -2021,6 +2021,14 @@ CommitTransaction(void) /* close large objects before lower-level cleanup */ AtEOXact_LargeObject(true); + /* + * Insert notifications sent by NOTIFY commands into the queue. This + * should be late in the pre-commit sequence to minimize time spent + * holding the notify-insertion lock. However, this could result in + * creating a snapshot, so we must do it before serializable cleanup. + */ + PreCommit_Notify(); + /* * Mark serializable transaction as complete for predicate locking * purposes. This should be done as late as we can put it and still allow @@ -2028,13 +2036,6 @@ CommitTransaction(void) */ PreCommit_CheckForSerializationFailure(); - /* - * Insert notifications sent by NOTIFY commands into the queue. This - * should be late in the pre-commit sequence to minimize time spent - * holding the notify-insertion lock. - */ - PreCommit_Notify(); - /* Prevent cancel/die interrupt while cleaning up */ HOLD_INTERRUPTS(); @@ -2248,6 +2249,8 @@ PrepareTransaction(void) /* close large objects before lower-level cleanup */ AtEOXact_LargeObject(true); + /* NOTIFY requires no work at this point */ + /* * Mark serializable transaction as complete for predicate locking * purposes. This should be done as late as we can put it and still allow @@ -2255,8 +2258,6 @@ PrepareTransaction(void) */ PreCommit_CheckForSerializationFailure(); - /* NOTIFY will be handled below */ - /* * Don't allow PREPARE TRANSACTION if we've accessed a temporary table in * this transaction. Having the prepared xact hold locks on another [parent: bcd541897fcf]