[ Having now read the whole thread, I'm prepared to weigh in ... ]

Pavan Deolasee <pavan.deola...@gmail.com> writes:
> This seems like a real problem to me. I don't know what the consequences
> are, but definitely having various attribute lists to have different view
> of the set of indexes doesn't seem right.

For sure.

> 2. In the second patch, we tried to recompute attribute lists if a relcache
> flush happens in between and index list is invalidated. We've seen problems
> with that, especially it getting into an infinite loop with
> CACHE_CLOBBER_ALWAYS. Not clear why it happens, but apparently relcache
> flushes keep happening.

Well, yeah: the point of CLOBBER_CACHE_ALWAYS is to make a relcache flush
happen whenever it possibly could.  The way to deal with that without
looping is to test whether the index set *actually* changed, not whether
it just might have changed.

I do not like any of the other patches proposed in this thread, because
they fail to guarantee delivering an up-to-date attribute bitmap to the
caller.  I think we need a retry loop, and I think that it needs to look
like the attached.

(Note that the tests whether rd_pkindex and rd_replidindex changed might
be redundant; but I'm not totally sure of that, and they're cheap.)

                        regards, tom lane

diff --git a/src/backend/utils/cache/relcache.c b/src/backend/utils/cache/relcache.c
index 8a7c560..b659994 100644
*** a/src/backend/utils/cache/relcache.c
--- b/src/backend/utils/cache/relcache.c
*************** RelationGetFKeyList(Relation relation)
*** 4327,4335 ****
   * it is the pg_class OID of a unique index on OID when the relation has one,
   * and InvalidOid if there is no such index.
   *
!  * In exactly the same way, we update rd_replidindex, which is the pg_class
!  * OID of an index to be used as the relation's replication identity index,
!  * or InvalidOid if there is no such index.
   */
  List *
  RelationGetIndexList(Relation relation)
--- 4327,4336 ----
   * it is the pg_class OID of a unique index on OID when the relation has one,
   * and InvalidOid if there is no such index.
   *
!  * In exactly the same way, we update rd_pkindex, which is the OID of the
!  * relation's primary key index if any, else InvalidOid; and rd_replidindex,
!  * which is the pg_class OID of an index to be used as the relation's
!  * replication identity index, or InvalidOid if there is no such index.
   */
  List *
  RelationGetIndexList(Relation relation)
*************** RelationGetIndexPredicate(Relation relat
*** 4746,4753 ****
   * we can include system attributes (e.g., OID) in the bitmap representation.
   *
   * Caller had better hold at least RowExclusiveLock on the target relation
!  * to ensure that it has a stable set of indexes.  This also makes it safe
!  * (deadlock-free) for us to take locks on the relation's indexes.
   *
   * The returned result is palloc'd in the caller's memory context and should
   * be bms_free'd when not needed anymore.
--- 4747,4756 ----
   * we can include system attributes (e.g., OID) in the bitmap representation.
   *
   * Caller had better hold at least RowExclusiveLock on the target relation
!  * to ensure it is safe (deadlock-free) for us to take locks on the relation's
!  * indexes.  Note that since the introduction of CREATE INDEX CONCURRENTLY,
!  * that lock level doesn't guarantee a stable set of indexes, so we have to
!  * be prepared to retry here in case of a change in the set of indexes.
   *
   * The returned result is palloc'd in the caller's memory context and should
   * be bms_free'd when not needed anymore.
*************** RelationGetIndexAttrBitmap(Relation rela
*** 4760,4765 ****
--- 4763,4769 ----
  	Bitmapset  *pkindexattrs;	/* columns in the primary index */
  	Bitmapset  *idindexattrs;	/* columns in the replica identity */
  	List	   *indexoidlist;
+ 	List	   *newindexoidlist;
  	Oid			relpkindex;
  	Oid			relreplindex;
  	ListCell   *l;
*************** RelationGetIndexAttrBitmap(Relation rela
*** 4788,4795 ****
  		return NULL;
  
  	/*
! 	 * Get cached list of index OIDs
  	 */
  	indexoidlist = RelationGetIndexList(relation);
  
  	/* Fall out if no indexes (but relhasindex was set) */
--- 4792,4800 ----
  		return NULL;
  
  	/*
! 	 * Get cached list of index OIDs. If we have to start over, we do so here.
  	 */
+ restart:
  	indexoidlist = RelationGetIndexList(relation);
  
  	/* Fall out if no indexes (but relhasindex was set) */
*************** RelationGetIndexAttrBitmap(Relation rela
*** 4800,4808 ****
  	 * Copy the rd_pkindex and rd_replidindex value computed by
  	 * RelationGetIndexList before proceeding.  This is needed because a
  	 * relcache flush could occur inside index_open below, resetting the
! 	 * fields managed by RelationGetIndexList. (The values we're computing
! 	 * will still be valid, assuming that caller has a sufficient lock on
! 	 * the relation.)
  	 */
  	relpkindex = relation->rd_pkindex;
  	relreplindex = relation->rd_replidindex;
--- 4805,4812 ----
  	 * Copy the rd_pkindex and rd_replidindex value computed by
  	 * RelationGetIndexList before proceeding.  This is needed because a
  	 * relcache flush could occur inside index_open below, resetting the
! 	 * fields managed by RelationGetIndexList.  We need to do the work with
! 	 * stable values of these fields.
  	 */
  	relpkindex = relation->rd_pkindex;
  	relreplindex = relation->rd_replidindex;
*************** RelationGetIndexAttrBitmap(Relation rela
*** 4880,4886 ****
  		index_close(indexDesc, AccessShareLock);
  	}
  
! 	list_free(indexoidlist);
  
  	/* Don't leak the old values of these bitmaps, if any */
  	bms_free(relation->rd_indexattr);
--- 4884,4915 ----
  		index_close(indexDesc, AccessShareLock);
  	}
  
! 	/*
! 	 * During one of the index_opens in the above loop, we might have received
! 	 * a relcache flush event on this relcache entry, which might have been
! 	 * signaling a change in the rel's index list.  If so, we'd better start
! 	 * over to ensure we deliver up-to-date attribute bitmaps.
! 	 */
! 	newindexoidlist = RelationGetIndexList(relation);
! 	if (equal(indexoidlist, newindexoidlist) &&
! 		relpkindex == relation->rd_pkindex &&
! 		relreplindex == relation->rd_replidindex)
! 	{
! 		/* Still the same index set, so proceed */
! 		list_free(newindexoidlist);
! 		list_free(indexoidlist);
! 	}
! 	else
! 	{
! 		/* Gotta do it over ... might as well not leak memory */
! 		list_free(newindexoidlist);
! 		list_free(indexoidlist);
! 		bms_free(uindexattrs);
! 		bms_free(pkindexattrs);
! 		bms_free(idindexattrs);
! 		bms_free(indexattrs);
! 		goto restart;
! 	}
  
  	/* Don't leak the old values of these bitmaps, if any */
  	bms_free(relation->rd_indexattr);
-- 
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