*** a/src/backend/access/gist/gist.c --- b/src/backend/access/gist/gist.c *************** *** 20,25 **** --- 20,26 ---- #include "miscadmin.h" #include "storage/bufmgr.h" #include "storage/indexfsm.h" + #include "storage/predicate.h" #include "utils/memutils.h" const XLogRecPtr XLogRecPtrForTemp = {1, 1}; *************** *** 286,291 **** gistplacetopage(GISTInsertState *state, GISTSTATE *giststate) --- 287,294 ---- bool is_splitted = false; bool is_leaf = (GistPageIsLeaf(state->stack->page)) ? true : false; + CheckForSerializableConflictIn(state->r, NULL, state->stack->buffer); + /* * if (!is_leaf) remove old key: This node's key has been modified, either * because a child split occurred or because we needed to adjust our key *** a/src/backend/access/gist/gistget.c --- b/src/backend/access/gist/gistget.c *************** *** 20,25 **** --- 20,26 ---- #include "miscadmin.h" #include "pgstat.h" #include "storage/bufmgr.h" + #include "storage/predicate.h" #include "utils/memutils.h" *************** *** 217,222 **** gistnext(IndexScanDesc scan, TIDBitmap *tbm) --- 218,224 ---- Assert(so->curbuf != InvalidBuffer); LockBuffer(so->curbuf, GIST_SHARE); gistcheckpage(scan->indexRelation, so->curbuf); + PredicateLockPage(scan->indexRelation, BufferGetBlockNumber(so->curbuf)); p = BufferGetPage(so->curbuf); opaque = GistPageGetOpaque(p); *** a/src/backend/access/gist/gistvacuum.c --- b/src/backend/access/gist/gistvacuum.c *************** *** 23,28 **** --- 23,29 ---- #include "storage/freespace.h" #include "storage/indexfsm.h" #include "storage/lmgr.h" + #include "storage/predicate.h" #include "utils/memutils.h" *************** *** 99,106 **** gistvacuumcleanup(PG_FUNCTION_ARGS) if (PageIsNew(page) || GistPageIsDeleted(page)) { ! totFreePages++; ! RecordFreeIndexPage(rel, blkno); } else lastFilledBlock = blkno; --- 100,110 ---- if (PageIsNew(page) || GistPageIsDeleted(page)) { ! if (!PageIsPredicateLocked(rel, blkno)) ! { ! totFreePages++; ! RecordFreeIndexPage(rel, blkno); ! } } else lastFilledBlock = blkno; *** a/src/backend/storage/lmgr/predicate.c --- b/src/backend/storage/lmgr/predicate.c *************** *** 87,93 **** * PredicateLockShmemSize(void) * * predicate lock reporting ! * PredicateLockData *GetPredicateLockStatusData(void) * * predicate lock maintenance * RegisterSerializableTransaction(Snapshot snapshot) --- 87,94 ---- * PredicateLockShmemSize(void) * * predicate lock reporting ! * GetPredicateLockStatusData(void) ! * PageIsPredicateLocked(Relation relation, BlockNumber blkno) * * predicate lock maintenance * RegisterSerializableTransaction(Snapshot snapshot) *************** *** 727,732 **** EnsureMySerializableXidExists(void) --- 728,771 ---- } } + /* + * Check whether there are any predicate locks held by any transaction + * for the page at the given block number. + * + * Note that the transaction may be completed but not yet subject to + * cleanup due to overlapping serializable transactions. This must + * return valid information regardless of transaction isolation level. + * + * Also note that this doesn't check for a conflicting relation lock, + * just a lock specifically on the given page. + * + * One use is to support proper behavior during GiST index vacuum. + */ + bool + PageIsPredicateLocked(const Relation relation, const BlockNumber blkno) + { + PREDICATELOCKTARGETTAG targettag; + uint32 targettaghash; + LWLockId partitionLock; + PREDICATELOCKTARGET *target; + + SET_PREDICATELOCKTARGETTAG_PAGE(targettag, + relation->rd_node.dbNode, + relation->rd_id, + blkno); + + targettaghash = PredicateLockTargetTagHashCode(&targettag); + partitionLock = PredicateLockHashPartitionLock(targettaghash); + LWLockAcquire(partitionLock, LW_SHARED); + target = (PREDICATELOCKTARGET *) + hash_search_with_hash_value(PredicateLockTargetHash, + &targettag, targettaghash, + HASH_FIND, NULL); + LWLockRelease(partitionLock); + + return (target != NULL); + } + /* * Check whether a particular lock is held by this transaction. *** a/src/include/catalog/pg_am.h --- b/src/include/catalog/pg_am.h *************** *** 117,123 **** DESCR("b-tree index access method"); DATA(insert OID = 405 ( hash 1 1 f t f f f f f f f f 23 hashinsert hashbeginscan hashgettuple hashgetbitmap hashrescan hashendscan hashmarkpos hashrestrpos hashbuild hashbulkdelete hashvacuumcleanup hashcostestimate hashoptions )); DESCR("hash index access method"); #define HASH_AM_OID 405 ! DATA(insert OID = 783 ( gist 0 7 f f f t t t t t t f 0 gistinsert gistbeginscan gistgettuple gistgetbitmap gistrescan gistendscan gistmarkpos gistrestrpos gistbuild gistbulkdelete gistvacuumcleanup gistcostestimate gistoptions )); DESCR("GiST index access method"); #define GIST_AM_OID 783 DATA(insert OID = 2742 ( gin 0 5 f f f t t f f t f f 0 gininsert ginbeginscan - gingetbitmap ginrescan ginendscan ginmarkpos ginrestrpos ginbuild ginbulkdelete ginvacuumcleanup gincostestimate ginoptions )); --- 117,123 ---- DATA(insert OID = 405 ( hash 1 1 f t f f f f f f f f 23 hashinsert hashbeginscan hashgettuple hashgetbitmap hashrescan hashendscan hashmarkpos hashrestrpos hashbuild hashbulkdelete hashvacuumcleanup hashcostestimate hashoptions )); DESCR("hash index access method"); #define HASH_AM_OID 405 ! DATA(insert OID = 783 ( gist 0 7 f f f t t t t t t t 0 gistinsert gistbeginscan gistgettuple gistgetbitmap gistrescan gistendscan gistmarkpos gistrestrpos gistbuild gistbulkdelete gistvacuumcleanup gistcostestimate gistoptions )); DESCR("GiST index access method"); #define GIST_AM_OID 783 DATA(insert OID = 2742 ( gin 0 5 f f f t t f f t f f 0 gininsert ginbeginscan - gingetbitmap ginrescan ginendscan ginmarkpos ginrestrpos ginbuild ginbulkdelete ginvacuumcleanup gincostestimate ginoptions )); *** a/src/include/storage/predicate.h --- b/src/include/storage/predicate.h *************** *** 156,161 **** extern Size PredicateLockShmemSize(void); --- 156,162 ---- /* predicate lock reporting */ extern PredicateLockData *GetPredicateLockStatusData(void); + extern bool PageIsPredicateLocked(const Relation relation, const BlockNumber blkno); /* predicate lock maintenance */ extern void RegisterSerializableTransaction(const Snapshot snapshot);