Re: [HACKERS] Commits 8de72b and 5457a1 (COPY FREEZE) - Mailing list pgsql-hackers

From Noah Misch
Subject Re: [HACKERS] Commits 8de72b and 5457a1 (COPY FREEZE)
Date
Msg-id 20190504202442.GD852556@rfd.leadboat.com
Whole thread Raw
In response to Re: [HACKERS] Commits 8de72b and 5457a1 (COPY FREEZE)  (Tom Lane <tgl@sss.pgh.pa.us>)
Responses Re: [HACKERS] Commits 8de72b and 5457a1 (COPY FREEZE)
List pgsql-hackers
On Wed, May 01, 2019 at 07:01:23PM -0400, Tom Lane wrote:
> > On 2019-05-01 14:44:12 -0400, Tom Lane wrote:
> >> I'm busy looking into the REINDEX-on-pg_class mess, and one thing I found
> >> while testing HEAD is that with CLOBBER_CACHE_ALWAYS on, once you've
> >> gotten a failure, your session is hosed:
> >> 
> >> regression=# select 1;
> >> ?column? 
> >> ----------
> >> 1
> >> (1 row)
> >> 
> >> regression=# reindex index pg_class_oid_index;
> >> psql: ERROR:  could not read block 0 in file "base/16384/35344": read only 0 of 8192 bytes
> >> regression=# select 1;
> >> psql: ERROR:  could not open file "base/16384/35344": No such file or directory

> It seems that the reason we fail to recover is that we detect the error
> during CommandEndInvalidationMessages, after we've updated the relcache
> entry for pg_class_oid_index; of course at that point, any additional
> pg_class access is going to fail because it'll try to use the
> not-yet-existent index.  However, when we then abort the transaction,
> we fail to revert pg_class_oid_index's relcache entry because *there is
> not yet an invalidation queue entry telling us to do so*.
> 
> This is, therefore, an order-of-operations bug in
> CommandEndInvalidationMessages.  It should attach the "current command"
> queue entries to PriorCmdInvalidMsgs *before* it processes them, not
> after.  In this way they'll be available to be reprocessed by 
> AtEOXact_Inval or AtEOSubXact_Inval if we fail during CCI.

That makes sense.

> The attached quick-hack patch changes that around, and seems to survive
> testing (though I've not completed a CCA run with it).  The basic change
> I had to make to make this work is to make AppendInvalidationMessageList
> actually append the current-commands list to the prior-cmds list, not
> prepend as it's really always done.  (In that way, we can still scan the
> current-commands list just by starting at its head.)  The comments for
> struct InvalidationChunk explicitly disclaim any significance to the order
> of the entries, so this should be okay, and I'm not seeing any problem
> in testing.  It's been a long time since I wrote that code, but I think
> the reason I did it like that was the thought that in a long transaction,
> the prior-cmds list might be much longer than the current-commands list,
> so iterating down the prior-cmds list could add an O(N^2) cost.  The
> easy answer to that, of course, is to make the lists doubly-linked,
> and I'd do that before committing; this version is just for testing.
> (It's short on comments, too.)

Looks reasonable so far.

> The thing I was worried about in RelationCacheInvalidate does seem
> to be a red herring, at least fixing it is not necessary to make
> the broken-session-state problem go away.

Your earlier proposal would have made RelationCacheInvalidate() work more like
RelationFlushRelation() when rd_newRelfilenodeSubid is set.  That's a good
direction, all else being equal, though I'm not aware of a specific bug
reachable today.  I think RelationCacheInvalidate() would then need the
reference count bits that RelationFlushRelation() has.

> *************** xactGetCommittedInvalidationMessages(Sha
> *** 858,867 ****
>        */
>       oldcontext = MemoryContextSwitchTo(CurTransactionContext);
>   
> -     ProcessInvalidationMessagesMulti(&transInvalInfo->CurrentCmdInvalidMsgs,
> -                                      MakeSharedInvalidMessagesArray);
>       ProcessInvalidationMessagesMulti(&transInvalInfo->PriorCmdInvalidMsgs,
>                                        MakeSharedInvalidMessagesArray);
>       MemoryContextSwitchTo(oldcontext);
>   
>       Assert(!(numSharedInvalidMessagesArray > 0 &&
> --- 865,874 ----
>        */
>       oldcontext = MemoryContextSwitchTo(CurTransactionContext);
>   
>       ProcessInvalidationMessagesMulti(&transInvalInfo->PriorCmdInvalidMsgs,
>                                        MakeSharedInvalidMessagesArray);
> +     ProcessInvalidationMessagesMulti(&transInvalInfo->CurrentCmdInvalidMsgs,
> +                                      MakeSharedInvalidMessagesArray);

Why this order change?



pgsql-hackers by date:

Previous
From: Tom Lane
Date:
Subject: Re: First-draft release notes for back branches are up
Next
From: Tom Lane
Date:
Subject: Re: [HACKERS] Commits 8de72b and 5457a1 (COPY FREEZE)