ssi-ddl-1.patch
text/plain
Filename: ssi-ddl-1.patch
Type: text/plain
Part: 0
Patch
Same data as JSON:
GET /api/v1/attachments/:id/patch
the parsed metadata as JSON — format, series position, per-file stats; never the diff bytes.
API reference →
Format: context
| File | + | − |
|---|---|---|
| src/backend/catalog/index.c | 8 | 0 |
| src/backend/storage/lmgr/predicate.c | 225 | 0 |
| src/include/catalog/index.h | 2 | 0 |
| src/include/storage/predicate.h | 1 | 0 |
*** a/src/backend/catalog/index.c
--- b/src/backend/catalog/index.c
***************
*** 54,59 ****
--- 54,60 ----
#include "parser/parser.h"
#include "storage/bufmgr.h"
#include "storage/lmgr.h"
+ #include "storage/predicate.h"
#include "storage/procarray.h"
#include "storage/smgr.h"
#include "utils/builtins.h"
***************
*** 114,120 **** static void validate_index_heapscan(Relation heapRelation,
IndexInfo *indexInfo,
Snapshot snapshot,
v_i_state *state);
- static Oid IndexGetRelation(Oid indexId);
static void SetReindexProcessing(Oid heapOid, Oid indexOid);
static void ResetReindexProcessing(void);
static void SetReindexPending(List *indexes);
--- 115,120 ----
***************
*** 2721,2727 **** validate_index_heapscan(Relation heapRelation,
* IndexGetRelation: given an index's relation OID, get the OID of the
* relation it is an index on. Uses the system cache.
*/
! static Oid
IndexGetRelation(Oid indexId)
{
HeapTuple tuple;
--- 2721,2727 ----
* IndexGetRelation: given an index's relation OID, get the OID of the
* relation it is an index on. Uses the system cache.
*/
! Oid
IndexGetRelation(Oid indexId)
{
HeapTuple tuple;
***************
*** 2782,2787 **** reindex_index(Oid indexId, bool skip_constraint_checks)
--- 2782,2793 ----
*/
CheckTableNotInUse(iRel, "REINDEX INDEX");
+ /*
+ * All predicate locks on the index are about to be made invalid.
+ * Promote them to relation locks on the heap.
+ */
+ TransferPredicateLocksToHeapRelation(iRel);
+
PG_TRY();
{
/* Suppress use of the target index while rebuilding it */
*** a/src/backend/storage/lmgr/predicate.c
--- b/src/backend/storage/lmgr/predicate.c
***************
*** 185,190 ****
--- 185,191 ----
#include "access/twophase.h"
#include "access/twophase_rmgr.h"
#include "access/xact.h"
+ #include "catalog/index.h"
#include "miscadmin.h"
#include "storage/bufmgr.h"
#include "storage/predicate.h"
***************
*** 975,982 **** InitPredicateLocks(void)
bool found;
/*
! * Compute size of predicate lock target hashtable.
! * Note these calculations must agree with PredicateLockShmemSize!
*/
max_table_size = NPREDICATELOCKTARGETENTS();
--- 976,983 ----
bool found;
/*
! * Compute size of predicate lock target hashtable. Note these
! * calculations must agree with PredicateLockShmemSize!
*/
max_table_size = NPREDICATELOCKTARGETENTS();
***************
*** 1028,1035 **** InitPredicateLocks(void)
hash_flags);
/*
! * Compute size for serializable transaction hashtable.
! * Note these calculations must agree with PredicateLockShmemSize!
*/
max_table_size = (MaxBackends + max_prepared_xacts);
--- 1029,1036 ----
hash_flags);
/*
! * Compute size for serializable transaction hashtable. Note these
! * calculations must agree with PredicateLockShmemSize!
*/
max_table_size = (MaxBackends + max_prepared_xacts);
***************
*** 2276,2288 **** PredicateLockTupleRowVersionLink(const Relation relation,
newxmin;
/*
! * Bail out quickly if there are no serializable transactions
! * running.
*
! * It's safe to do this check without taking any additional
! * locks. Even if a serializable transaction starts concurrently,
! * we know it can't take any SIREAD locks on the modified tuple
! * because the caller is holding the associated buffer page lock.
*/
if (!TransactionIdIsValid(PredXact->SxactGlobalXmin))
return;
--- 2277,2288 ----
newxmin;
/*
! * Bail out quickly if there are no serializable transactions running.
*
! * It's safe to do this check without taking any additional locks. Even if
! * a serializable transaction starts concurrently, we know it can't take
! * any SIREAD locks on the modified tuple because the caller is holding
! * the associated buffer page lock.
*/
if (!TransactionIdIsValid(PredXact->SxactGlobalXmin))
return;
***************
*** 2622,2627 **** exit:
--- 2622,2839 ----
return !outOfShmem;
}
+ /*
+ * For all connections, transfer all predicate locks for the given relation
+ * to a single relation lock on the heap. For a heap relation that includes
+ * all locks on indexes; for an index it is just the locks on that one
+ * index.
+ *
+ * This requires grabbing a lot of LW locks and scanning the entire lock
+ * target table for matches. That makes this more expensive than most
+ * functions, but it will only be called for DDL type commands and there are
+ * fast returns when no serializable transactions are active or the relation
+ * is temporary.
+ *
+ * We are not using the existing TransferPredicateLocksToNewTarget because
+ * it acquires its own locks on the partitions of the two targets invovled,
+ * and we'll already be holding all partition locks.
+ *
+ * We can't throw an error from here, because the call could be from a
+ * transaction which is not serializable.
+ */
+ void
+ TransferPredicateLocksToHeapRelation(const Relation relation)
+ {
+ HASH_SEQ_STATUS seqstat;
+ PREDICATELOCKTARGET *oldtarget;
+ PREDICATELOCKTARGET *heaptarget;
+ PREDICATELOCKTARGETTAG heaptargettag;
+ PREDICATELOCKTAG newpredlocktag;
+ Oid dbId;
+ Oid indexId;
+ Oid heapId;
+ int i;
+ bool isSingleIndex;
+ bool found;
+ uint32 reservedtargettaghash;
+ uint32 heaptargettaghash;
+
+ /*
+ * Bail out quickly if there are no serializable transactions running. As
+ * with PredicateLockTupleRowVersionLink, it's safe to check this without
+ * taking locks because the caller is holding the buffer page lock.
+ */
+ if (!TransactionIdIsValid(PredXact->SxactGlobalXmin))
+ return;
+
+ if (SkipSplitTracking(relation))
+ return;
+
+ dbId = relation->rd_node.dbNode;
+ if (relation->rd_index == NULL)
+ {
+ isSingleIndex = false;
+ indexId = InvalidOid; /* quiet compiler warning */
+ heapId = relation->rd_id;
+ }
+ else
+ {
+ isSingleIndex = true;
+ indexId = relation->rd_id;
+ heapId = relation->rd_index->indrelid;
+ }
+ Assert(heapId != InvalidOid);
+ SET_PREDICATELOCKTARGETTAG_RELATION(heaptargettag,
+ dbId,
+ heapId);
+ heaptargettaghash = PredicateLockTargetTagHashCode(&heaptargettag);
+ heaptarget = NULL; /* Retrieve first time needed, then keep. */
+
+ LWLockAcquire(SerializablePredicateLockListLock, LW_EXCLUSIVE);
+ for (i = 0; i < NUM_PREDICATELOCK_PARTITIONS; i++)
+ LWLockAcquire(FirstPredicateLockMgrLock + i, LW_EXCLUSIVE);
+ LWLockAcquire(SerializableXactHashLock, LW_EXCLUSIVE);
+
+ /*
+ * Remove the reserved entry to give us scratch space, so we know we'll be
+ * able to create the new lock target.
+ */
+ reservedtargettaghash = PredicateLockTargetTagHashCode(&ReservedTargetTag);
+ hash_search_with_hash_value(PredicateLockTargetHash,
+ &ReservedTargetTag,
+ reservedtargettaghash,
+ HASH_REMOVE, &found);
+ Assert(found);
+
+ /* Scan through PredicateLockHash and copy contents */
+ hash_seq_init(&seqstat, PredicateLockTargetHash);
+
+ while ((oldtarget = (PREDICATELOCKTARGET *) hash_seq_search(&seqstat)))
+ {
+ PREDICATELOCK *oldpredlock;
+
+ /*
+ * Check whether this is a target which needs attention.
+ */
+ if (GET_PREDICATELOCKTARGETTAG_DB(oldtarget->tag) != dbId)
+ continue; /* wrong database */
+ if (isSingleIndex)
+ {
+ if (GET_PREDICATELOCKTARGETTAG_RELATION(oldtarget->tag) != indexId)
+ continue; /* not the index we're looking for */
+ }
+ else
+ {
+ if (GET_PREDICATELOCKTARGETTAG_RELATION(oldtarget->tag) == heapId)
+ {
+ if (GET_PREDICATELOCKTARGETTAG_TYPE(oldtarget->tag) == PREDLOCKTAG_RELATION)
+ continue; /* already the right lock */
+ }
+ else
+ {
+ /* This is an index. Is it for the right heap? */
+ if (IndexGetRelation(GET_PREDICATELOCKTARGETTAG_RELATION(oldtarget->tag))
+ != heapId)
+ continue; /* index on wrong heap relation */
+ }
+ }
+
+ /*
+ * If we made it here, we have work to do. We make sure the heap
+ * relation lock exists, then we walk the list of predicate locks for
+ * the old target we found, moving all locks to the heap relation lock
+ * -- unless they already hold that.
+ */
+
+ /*
+ * First make sure we have the heap relation target. We only need to
+ * do this once.
+ */
+ if (heaptarget == NULL)
+ {
+ heaptarget = hash_search_with_hash_value(PredicateLockTargetHash,
+ &heaptargettag,
+ heaptargettaghash,
+ HASH_ENTER, &found);
+ Assert(heaptarget != NULL);
+ if (!found)
+ SHMQueueInit(&heaptarget->predicateLocks);
+ newpredlocktag.myTarget = heaptarget;
+ }
+
+ /*
+ * Loop through moving locks from this target to the relation target.
+ */
+ oldpredlock = (PREDICATELOCK *)
+ SHMQueueNext(&(oldtarget->predicateLocks),
+ &(oldtarget->predicateLocks),
+ offsetof(PREDICATELOCK, targetLink));
+ while (oldpredlock)
+ {
+ PREDICATELOCK *nextpredlock;
+ PREDICATELOCK *newpredlock;
+ SerCommitSeqNo oldCommitSeqNo = oldpredlock->commitSeqNo;
+
+ nextpredlock = (PREDICATELOCK *)
+ SHMQueueNext(&(oldtarget->predicateLocks),
+ &(oldpredlock->targetLink),
+ offsetof(PREDICATELOCK, targetLink));
+ newpredlocktag.myXact = oldpredlock->tag.myXact;
+
+ SHMQueueDelete(&(oldpredlock->xactLink));
+ /* No need for retail delete from oldtarget list. */
+ hash_search(PredicateLockHash,
+ &oldpredlock->tag,
+ HASH_REMOVE, &found);
+ Assert(found);
+
+ newpredlock = (PREDICATELOCK *)
+ hash_search_with_hash_value
+ (PredicateLockHash,
+ &newpredlocktag,
+ PredicateLockHashCodeFromTargetHashCode(&newpredlocktag,
+ heaptargettaghash),
+ HASH_ENTER_NULL, &found);
+ Assert(newpredlock != NULL);
+ if (!found)
+ {
+ SHMQueueInsertBefore(&(heaptarget->predicateLocks),
+ &(newpredlock->targetLink));
+ SHMQueueInsertBefore(&(newpredlocktag.myXact->predicateLocks),
+ &(newpredlock->xactLink));
+ newpredlock->commitSeqNo = oldCommitSeqNo;
+ }
+ else
+ {
+ if (newpredlock->commitSeqNo < oldCommitSeqNo)
+ newpredlock->commitSeqNo = oldCommitSeqNo;
+ }
+
+ Assert(newpredlock->commitSeqNo != 0);
+ Assert((newpredlock->commitSeqNo == InvalidSerCommitSeqNo)
+ || (newpredlock->tag.myXact == OldCommittedSxact));
+
+ oldpredlock = nextpredlock;
+ }
+
+ hash_search(PredicateLockTargetHash, &oldtarget->tag, HASH_REMOVE, &found);
+ Assert(found);
+ }
+
+ /* Put the reserved entry back */
+ hash_search_with_hash_value(PredicateLockTargetHash,
+ &ReservedTargetTag,
+ reservedtargettaghash,
+ HASH_ENTER, &found);
+ Assert(!found);
+
+ /* Release locks in reverse order */
+ LWLockRelease(SerializableXactHashLock);
+ for (i = NUM_PREDICATELOCK_PARTITIONS - 1; i >= 0; i--)
+ LWLockRelease(FirstPredicateLockMgrLock + i);
+ LWLockRelease(SerializablePredicateLockListLock);
+ }
+
/*
* PredicateLockPageSplit
***************
*** 2646,2655 **** PredicateLockPageSplit(const Relation relation, const BlockNumber oldblkno,
bool success;
/*
! * Bail out quickly if there are no serializable transactions
! * running. As with PredicateLockTupleRowVersionLink, it's safe to
! * check this without taking locks because the caller is holding
! * the buffer page lock.
*/
if (!TransactionIdIsValid(PredXact->SxactGlobalXmin))
return;
--- 2858,2866 ----
bool success;
/*
! * Bail out quickly if there are no serializable transactions running. As
! * with PredicateLockTupleRowVersionLink, it's safe to check this without
! * taking locks because the caller is holding the buffer page lock.
*/
if (!TransactionIdIsValid(PredXact->SxactGlobalXmin))
return;
*** a/src/include/catalog/index.h
--- b/src/include/catalog/index.h
***************
*** 66,71 **** extern void index_drop(Oid indexId);
--- 66,73 ----
extern IndexInfo *BuildIndexInfo(Relation index);
+ extern Oid IndexGetRelation(Oid indexId);
+
extern void FormIndexDatum(IndexInfo *indexInfo,
TupleTableSlot *slot,
EState *estate,
*** a/src/include/storage/predicate.h
--- b/src/include/storage/predicate.h
***************
*** 50,55 **** extern void PredicateLockTuple(const Relation relation, const HeapTuple tuple);
--- 50,56 ----
extern void PredicateLockTupleRowVersionLink(const Relation relation, const HeapTuple oldTuple, const HeapTuple newTuple);
extern void PredicateLockPageSplit(const Relation relation, const BlockNumber oldblkno, const BlockNumber newblkno);
extern void PredicateLockPageCombine(const Relation relation, const BlockNumber oldblkno, const BlockNumber newblkno);
+ extern void TransferPredicateLocksToHeapRelation(const Relation relation);
extern void ReleasePredicateLocks(const bool isCommit);
/* conflict detection (may also trigger rollback) */