[ Having now read the whole thread, I'm prepared to weigh in ... ]
Pavan Deolasee <[email protected]> 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 ([email protected])
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers