diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/Makefile.global.in | 2 | ||||
-rw-r--r-- | src/Makefile.shlib | 2 | ||||
-rw-r--r-- | src/backend/access/heap/heapam.c | 23 | ||||
-rw-r--r-- | src/backend/access/index/indexam.c | 15 | ||||
-rw-r--r-- | src/backend/access/nbtree/nbtsearch.c | 33 | ||||
-rw-r--r-- | src/backend/catalog/information_schema.sql | 2 | ||||
-rw-r--r-- | src/backend/executor/nodeSeqscan.c | 3 | ||||
-rw-r--r-- | src/backend/parser/parse_utilcmd.c | 2 | ||||
-rw-r--r-- | src/backend/storage/lmgr/predicate.c | 220 | ||||
-rw-r--r-- | src/bin/psql/tab-complete.c | 6 | ||||
-rw-r--r-- | src/include/storage/predicate.h | 9 | ||||
-rw-r--r-- | src/include/storage/predicate_internals.h | 11 | ||||
-rw-r--r-- | src/interfaces/ecpg/test/Makefile | 2 | ||||
-rw-r--r-- | src/test/isolation/Makefile | 2 |
14 files changed, 188 insertions, 144 deletions
diff --git a/src/Makefile.global.in b/src/Makefile.global.in index 56f282712d..e2e7e725a9 100644 --- a/src/Makefile.global.in +++ b/src/Makefile.global.in @@ -437,7 +437,7 @@ endif pg_regress_locale_flags = $(if $(ENCODING),--encoding=$(ENCODING)) $(NOLOCALE) pg_regress_check = $(top_builddir)/src/test/regress/pg_regress --inputdir=$(srcdir) --temp-install=./tmp_check --top-builddir=$(top_builddir) $(pg_regress_locale_flags) -pg_regress_installcheck = $(top_builddir)/src/test/regress/pg_regress --inputdir=$(srcdir) --psqldir=$(PSQLDIR) $(pg_regress_locale_flags) +pg_regress_installcheck = $(top_builddir)/src/test/regress/pg_regress --inputdir=$(srcdir) --psqldir="$(PSQLDIR)" $(pg_regress_locale_flags) pg_regress_clean_files = results/ regression.diffs regression.out tmp_check/ log/ diff --git a/src/Makefile.shlib b/src/Makefile.shlib index a5cf6c6c16..53b527bcab 100644 --- a/src/Makefile.shlib +++ b/src/Makefile.shlib @@ -130,7 +130,7 @@ ifeq ($(PORTNAME), darwin) ifneq ($(SO_MAJOR_VERSION), 0) version_link = -compatibility_version $(SO_MAJOR_VERSION) -current_version $(SO_MAJOR_VERSION).$(SO_MINOR_VERSION) endif - LINK.shared = $(COMPILER) -dynamiclib -install_name $(libdir)/lib$(NAME).$(SO_MAJOR_VERSION)$(DLSUFFIX) $(version_link) $(exported_symbols_list) -multiply_defined suppress + LINK.shared = $(COMPILER) -dynamiclib -install_name "$(libdir)/lib$(NAME).$(SO_MAJOR_VERSION)$(DLSUFFIX)" $(version_link) $(exported_symbols_list) -multiply_defined suppress shlib = lib$(NAME).$(SO_MAJOR_VERSION).$(SO_MINOR_VERSION)$(DLSUFFIX) shlib_major = lib$(NAME).$(SO_MAJOR_VERSION)$(DLSUFFIX) else diff --git a/src/backend/access/heap/heapam.c b/src/backend/access/heap/heapam.c index 01a492e496..b947c11f7d 100644 --- a/src/backend/access/heap/heapam.c +++ b/src/backend/access/heap/heapam.c @@ -274,7 +274,8 @@ heapgetpage(HeapScanDesc scan, BlockNumber page) else valid = HeapTupleSatisfiesVisibility(&loctup, snapshot, buffer); - CheckForSerializableConflictOut(valid, scan->rs_rd, &loctup, buffer); + CheckForSerializableConflictOut(valid, scan->rs_rd, &loctup, + buffer, snapshot); if (valid) scan->rs_vistuples[ntup++] = lineoff; @@ -469,7 +470,8 @@ heapgettup(HeapScanDesc scan, snapshot, scan->rs_cbuf); - CheckForSerializableConflictOut(valid, scan->rs_rd, tuple, scan->rs_cbuf); + CheckForSerializableConflictOut(valid, scan->rs_rd, tuple, + scan->rs_cbuf, snapshot); if (valid && key != NULL) HeapKeyTest(tuple, RelationGetDescr(scan->rs_rd), @@ -478,7 +480,7 @@ heapgettup(HeapScanDesc scan, if (valid) { if (!scan->rs_relpredicatelocked) - PredicateLockTuple(scan->rs_rd, tuple); + PredicateLockTuple(scan->rs_rd, tuple, snapshot); LockBuffer(scan->rs_cbuf, BUFFER_LOCK_UNLOCK); return; } @@ -747,7 +749,7 @@ heapgettup_pagemode(HeapScanDesc scan, if (valid) { if (!scan->rs_relpredicatelocked) - PredicateLockTuple(scan->rs_rd, tuple); + PredicateLockTuple(scan->rs_rd, tuple, scan->rs_snapshot); scan->rs_cindex = lineindex; return; } @@ -755,7 +757,7 @@ heapgettup_pagemode(HeapScanDesc scan, else { if (!scan->rs_relpredicatelocked) - PredicateLockTuple(scan->rs_rd, tuple); + PredicateLockTuple(scan->rs_rd, tuple, scan->rs_snapshot); scan->rs_cindex = lineindex; return; } @@ -1470,9 +1472,9 @@ heap_fetch(Relation relation, valid = HeapTupleSatisfiesVisibility(tuple, snapshot, buffer); if (valid) - PredicateLockTuple(relation, tuple); + PredicateLockTuple(relation, tuple, snapshot); - CheckForSerializableConflictOut(valid, relation, tuple, buffer); + CheckForSerializableConflictOut(valid, relation, tuple, buffer, snapshot); LockBuffer(buffer, BUFFER_LOCK_UNLOCK); @@ -1588,11 +1590,12 @@ heap_hot_search_buffer(ItemPointer tid, Relation relation, Buffer buffer, /* If it's visible per the snapshot, we must return it */ valid = HeapTupleSatisfiesVisibility(&heapTuple, snapshot, buffer); - CheckForSerializableConflictOut(valid, relation, &heapTuple, buffer); + CheckForSerializableConflictOut(valid, relation, &heapTuple, buffer, + snapshot); if (valid) { ItemPointerSetOffsetNumber(tid, offnum); - PredicateLockTuple(relation, &heapTuple); + PredicateLockTuple(relation, &heapTuple, snapshot); if (all_dead) *all_dead = false; return true; @@ -1750,7 +1753,7 @@ heap_get_latest_tid(Relation relation, * result candidate. */ valid = HeapTupleSatisfiesVisibility(&tp, snapshot, buffer); - CheckForSerializableConflictOut(valid, relation, &tp, buffer); + CheckForSerializableConflictOut(valid, relation, &tp, buffer, snapshot); if (valid) *tid = ctid; diff --git a/src/backend/access/index/indexam.c b/src/backend/access/index/indexam.c index 0208765964..31d705c056 100644 --- a/src/backend/access/index/indexam.c +++ b/src/backend/access/index/indexam.c @@ -126,7 +126,7 @@ do { \ } while(0) static IndexScanDesc index_beginscan_internal(Relation indexRelation, - int nkeys, int norderbys); + int nkeys, int norderbys, Snapshot snapshot); /* ---------------------------------------------------------------- @@ -234,7 +234,7 @@ index_beginscan(Relation heapRelation, { IndexScanDesc scan; - scan = index_beginscan_internal(indexRelation, nkeys, norderbys); + scan = index_beginscan_internal(indexRelation, nkeys, norderbys, snapshot); /* * Save additional parameters into the scandesc. Everything else was set @@ -259,7 +259,7 @@ index_beginscan_bitmap(Relation indexRelation, { IndexScanDesc scan; - scan = index_beginscan_internal(indexRelation, nkeys, 0); + scan = index_beginscan_internal(indexRelation, nkeys, 0, snapshot); /* * Save additional parameters into the scandesc. Everything else was set @@ -275,7 +275,7 @@ index_beginscan_bitmap(Relation indexRelation, */ static IndexScanDesc index_beginscan_internal(Relation indexRelation, - int nkeys, int norderbys) + int nkeys, int norderbys, Snapshot snapshot) { IndexScanDesc scan; FmgrInfo *procedure; @@ -284,7 +284,7 @@ index_beginscan_internal(Relation indexRelation, GET_REL_PROCEDURE(ambeginscan); if (!(indexRelation->rd_am->ampredlocks)) - PredicateLockRelation(indexRelation); + PredicateLockRelation(indexRelation, snapshot); /* * We hold a reference count to the relcache entry throughout the scan. @@ -602,7 +602,8 @@ index_getnext(IndexScanDesc scan, ScanDirection direction) scan->xs_cbuf); CheckForSerializableConflictOut(valid, scan->heapRelation, - heapTuple, scan->xs_cbuf); + heapTuple, scan->xs_cbuf, + scan->xs_snapshot); if (valid) { @@ -624,7 +625,7 @@ index_getnext(IndexScanDesc scan, ScanDirection direction) else scan->xs_next_hot = InvalidOffsetNumber; - PredicateLockTuple(scan->heapRelation, heapTuple); + PredicateLockTuple(scan->heapRelation, heapTuple, scan->xs_snapshot); LockBuffer(scan->xs_cbuf, BUFFER_LOCK_UNLOCK); diff --git a/src/backend/access/nbtree/nbtsearch.c b/src/backend/access/nbtree/nbtsearch.c index 2ce2bc2f00..0771d19463 100644 --- a/src/backend/access/nbtree/nbtsearch.c +++ b/src/backend/access/nbtree/nbtsearch.c @@ -64,10 +64,7 @@ _bt_search(Relation rel, int keysz, ScanKey scankey, bool nextkey, /* If index is empty and access = BT_READ, no root page is created. */ if (!BufferIsValid(*bufP)) - { - PredicateLockRelation(rel); /* Nothing finer to lock exists. */ return (BTStack) NULL; - } /* Loop iterates once per level descended in the tree */ for (;;) @@ -92,11 +89,7 @@ _bt_search(Relation rel, int keysz, ScanKey scankey, bool nextkey, page = BufferGetPage(*bufP); opaque = (BTPageOpaque) PageGetSpecialPointer(page); if (P_ISLEAF(opaque)) - { - if (access == BT_READ) - PredicateLockPage(rel, BufferGetBlockNumber(*bufP)); break; - } /* * Find the appropriate item on the internal page, and get the child @@ -855,9 +848,16 @@ _bt_first(IndexScanDesc scan, ScanDirection dir) if (!BufferIsValid(buf)) { - /* Only get here if index is completely empty */ + /* + * We only get here if the index is completely empty. + * Lock relation because nothing finer to lock exists. + */ + PredicateLockRelation(rel, scan->xs_snapshot); return false; } + else + PredicateLockPage(rel, BufferGetBlockNumber(buf), + scan->xs_snapshot); /* initialize moreLeft/moreRight appropriately for scan direction */ if (ScanDirectionIsForward(dir)) @@ -1153,7 +1153,7 @@ _bt_steppage(IndexScanDesc scan, ScanDirection dir) opaque = (BTPageOpaque) PageGetSpecialPointer(page); if (!P_IGNORE(opaque)) { - PredicateLockPage(rel, blkno); + PredicateLockPage(rel, blkno, scan->xs_snapshot); /* see if there are any matches on this page */ /* note that this will clear moreRight if we can stop */ if (_bt_readpage(scan, dir, P_FIRSTDATAKEY(opaque))) @@ -1201,7 +1201,7 @@ _bt_steppage(IndexScanDesc scan, ScanDirection dir) opaque = (BTPageOpaque) PageGetSpecialPointer(page); if (!P_IGNORE(opaque)) { - PredicateLockPage(rel, BufferGetBlockNumber(so->currPos.buf)); + PredicateLockPage(rel, BufferGetBlockNumber(so->currPos.buf), scan->xs_snapshot); /* see if there are any matches on this page */ /* note that this will clear moreLeft if we can stop */ if (_bt_readpage(scan, dir, PageGetMaxOffsetNumber(page))) @@ -1363,11 +1363,7 @@ _bt_get_endpoint(Relation rel, uint32 level, bool rightmost) buf = _bt_gettrueroot(rel); if (!BufferIsValid(buf)) - { - /* empty index... */ - PredicateLockRelation(rel); /* Nothing finer to lock exists. */ return InvalidBuffer; - } page = BufferGetPage(buf); opaque = (BTPageOpaque) PageGetSpecialPointer(page); @@ -1444,13 +1440,16 @@ _bt_endpoint(IndexScanDesc scan, ScanDirection dir) if (!BufferIsValid(buf)) { - /* empty index... */ - PredicateLockRelation(rel); /* Nothing finer to lock exists. */ + /* + * Empty index. Lock the whole relation, as nothing finer to lock + * exists. + */ + PredicateLockRelation(rel, scan->xs_snapshot); so->currPos.buf = InvalidBuffer; return false; } - PredicateLockPage(rel, BufferGetBlockNumber(buf)); + PredicateLockPage(rel, BufferGetBlockNumber(buf), scan->xs_snapshot); page = BufferGetPage(buf); opaque = (BTPageOpaque) PageGetSpecialPointer(page); Assert(P_ISLEAF(opaque)); diff --git a/src/backend/catalog/information_schema.sql b/src/backend/catalog/information_schema.sql index 452a0ead44..81407a3a5e 100644 --- a/src/backend/catalog/information_schema.sql +++ b/src/backend/catalog/information_schema.sql @@ -274,7 +274,7 @@ CREATE VIEW attributes AS CAST(pg_get_expr(ad.adbin, ad.adrelid) AS character_data) AS attribute_default, CAST(CASE WHEN a.attnotnull OR (t.typtype = 'd' AND t.typnotnull) THEN 'NO' ELSE 'YES' END AS yes_or_no) - AS is_nullable, + AS is_nullable, -- This column was apparently removed between SQL:2003 and SQL:2008. CAST( CASE WHEN t.typelem <> 0 AND t.typlen = -1 THEN 'ARRAY' diff --git a/src/backend/executor/nodeSeqscan.c b/src/backend/executor/nodeSeqscan.c index 1e566b2d50..f356874b44 100644 --- a/src/backend/executor/nodeSeqscan.c +++ b/src/backend/executor/nodeSeqscan.c @@ -113,7 +113,8 @@ SeqRecheck(SeqScanState *node, TupleTableSlot *slot) TupleTableSlot * ExecSeqScan(SeqScanState *node) { - PredicateLockRelation(node->ss_currentRelation); + PredicateLockRelation(node->ss_currentRelation, + node->ss_currentScanDesc->rs_snapshot); node->ss_currentScanDesc->rs_relpredicatelocked = true; return ExecScan((ScanState *) node, (ExecScanAccessMtd) SeqNext, diff --git a/src/backend/parser/parse_utilcmd.c b/src/backend/parser/parse_utilcmd.c index 25ce6a76a5..a6a626f576 100644 --- a/src/backend/parser/parse_utilcmd.c +++ b/src/backend/parser/parse_utilcmd.c @@ -849,7 +849,6 @@ static void transformOfType(CreateStmtContext *cxt, TypeName *ofTypename) { HeapTuple tuple; - Form_pg_type typ; TupleDesc tupdesc; int i; Oid ofTypeId; @@ -858,7 +857,6 @@ transformOfType(CreateStmtContext *cxt, TypeName *ofTypename) tuple = typenameType(NULL, ofTypename, NULL); check_of_type(tuple); - typ = (Form_pg_type) GETSTRUCT(tuple); ofTypeId = HeapTupleGetOid(tuple); ofTypename->typeOid = ofTypeId; /* cached for later */ diff --git a/src/backend/storage/lmgr/predicate.c b/src/backend/storage/lmgr/predicate.c index 02f5d033b2..a12f52ecc9 100644 --- a/src/backend/storage/lmgr/predicate.c +++ b/src/backend/storage/lmgr/predicate.c @@ -148,9 +148,11 @@ * predicate lock maintenance * RegisterSerializableTransaction(Snapshot snapshot) * RegisterPredicateLockingXid(void) - * PredicateLockRelation(Relation relation) - * PredicateLockPage(Relation relation, BlockNumber blkno) - * PredicateLockTuple(Relation relation, HeapTuple tuple) + * PredicateLockRelation(Relation relation, Snapshot snapshot) + * PredicateLockPage(Relation relation, BlockNumber blkno, + * Snapshot snapshot) + * PredicateLockTuple(Relation relation, HeapTuple tuple, + * Snapshot snapshot) * PredicateLockPageSplit(Relation relation, BlockNumber oldblkno, * BlockNumber newblkno); * PredicateLockPageCombine(Relation relation, BlockNumber oldblkno, @@ -160,7 +162,8 @@ * * conflict detection (may also trigger rollback) * CheckForSerializableConflictOut(bool visible, Relation relation, - * HeapTupleData *tup, Buffer buffer) + * HeapTupleData *tup, Buffer buffer, + * Snapshot snapshot) * CheckForSerializableConflictIn(Relation relation, HeapTupleData *tup, * Buffer buffer) * CheckTableForSerializableConflictIn(Relation relation) @@ -241,9 +244,9 @@ #define SxactIsOnFinishedList(sxact) (!SHMQueueIsDetached(&((sxact)->finishedLink))) -#define SxactIsPrepared(sxact) (((sxact)->flags & SXACT_FLAG_PREPARED) != 0) #define SxactIsCommitted(sxact) (((sxact)->flags & SXACT_FLAG_COMMITTED) != 0) -#define SxactIsRolledBack(sxact) (((sxact)->flags & SXACT_FLAG_ROLLED_BACK) != 0) +#define SxactIsPrepared(sxact) (((sxact)->flags & SXACT_FLAG_PREPARED) != 0) +#define SxactIsDoomed(sxact) (((sxact)->flags & SXACT_FLAG_DOOMED) != 0) #define SxactIsReadOnly(sxact) (((sxact)->flags & SXACT_FLAG_READ_ONLY) != 0) #define SxactHasSummaryConflictIn(sxact) (((sxact)->flags & SXACT_FLAG_SUMMARY_CONFLICT_IN) != 0) #define SxactHasSummaryConflictOut(sxact) (((sxact)->flags & SXACT_FLAG_SUMMARY_CONFLICT_OUT) != 0) @@ -256,27 +259,6 @@ #define SxactIsDeferrableWaiting(sxact) (((sxact)->flags & SXACT_FLAG_DEFERRABLE_WAITING) != 0) #define SxactIsROSafe(sxact) (((sxact)->flags & SXACT_FLAG_RO_SAFE) != 0) #define SxactIsROUnsafe(sxact) (((sxact)->flags & SXACT_FLAG_RO_UNSAFE) != 0) -#define SxactIsMarkedForDeath(sxact) (((sxact)->flags & SXACT_FLAG_MARKED_FOR_DEATH) != 0) - -/* - * Is this relation exempt from predicate locking? We don't do predicate - * locking on system or temporary relations. - */ -#define SkipPredicateLocksForRelation(relation) \ - (((relation)->rd_id < FirstBootstrapObjectId) \ - || RelationUsesLocalBuffers(relation)) - -/* - * When a public interface method is called for serializing a relation within - * the current transaction, this is the test to see if we should do a quick - * return. - */ -#define SkipSerialization(relation) \ - ((!IsolationIsSerializable()) \ - || ((MySerializableXact == InvalidSerializableXact)) \ - || ReleasePredicateLocksIfROSafe() \ - || SkipPredicateLocksForRelation(relation)) - /* * Compute the hash code associated with a PREDICATELOCKTARGETTAG. @@ -444,7 +426,6 @@ static void PredicateLockAcquire(const PREDICATELOCKTARGETTAG *targettag); static void DropAllPredicateLocksFromTable(const Relation relation, bool transfer); static void SetNewSxactGlobalXmin(void); -static bool ReleasePredicateLocksIfROSafe(void); static void ClearOldPredicateLocks(void); static void ReleaseOneSerializableXact(SERIALIZABLEXACT *sxact, bool partial, bool summarize); @@ -454,6 +435,91 @@ static void FlagRWConflict(SERIALIZABLEXACT *reader, SERIALIZABLEXACT *writer); static void OnConflict_CheckForSerializationFailure(const SERIALIZABLEXACT *reader, SERIALIZABLEXACT *writer); + +/*------------------------------------------------------------------------*/ + +/* + * Does this relation participate in predicate locking? Temporary and system + * relations are exempt. + */ +static inline bool +PredicateLockingNeededForRelation(Relation relation) +{ + return !(relation->rd_id < FirstBootstrapObjectId || + RelationUsesLocalBuffers(relation)); +} + +/* + * When a public interface method is called for a read, this is the test to + * see if we should do a quick return. + * + * Note: this function has side-effects! If this transaction has been flagged + * as RO-safe since the last call, we release all predicate locks and reset + * MySerializableXact. That makes subsequent calls to return quickly. + * + * This is marked as 'inline' to make to eliminate the function call overhead + * in the common case that serialization is not needed. + */ +static inline bool +SerializationNeededForRead(Relation relation, Snapshot snapshot) +{ + /* Nothing to do if this is not a serializable transaction */ + if (MySerializableXact == InvalidSerializableXact) + return false; + + /* + * Don't acquire locks or conflict when scanning with a special snapshot. + * This excludes things like CLUSTER and REINDEX. They use the wholesale + * functions TransferPredicateLocksToHeapRelation() and + * CheckTableForSerializableConflictIn() to participate serialization, but + * the scans involved don't need serialization. + */ + if (!IsMVCCSnapshot(snapshot)) + return false; + + /* + * Check if we have just become "RO-safe". If we have, immediately release + * all locks as they're not needed anymore. This also resets + * MySerializableXact, so that subsequent calls to this function can exit + * quickly. + * + * A transaction is flagged as RO_SAFE if all concurrent R/W + * transactions commit without having conflicts out to an earlier + * snapshot, thus ensuring that no conflicts are possible for this + * transaction. + */ + if (SxactIsROSafe(MySerializableXact)) + { + ReleasePredicateLocks(false); + return false; + } + + /* Check if the relation doesn't participate in predicate locking */ + if (!PredicateLockingNeededForRelation(relation)) + return false; + + return true; /* no excuse to skip predicate locking */ +} + +/* + * Like SerializationNeededForRead(), but called on writes. + * The logic is the same, but there is no snapshot and we can't be RO-safe. + */ +static inline bool +SerializationNeededForWrite(Relation relation) +{ + /* Nothing to do if this is not a serializable transaction */ + if (MySerializableXact == InvalidSerializableXact) + return false; + + /* Check if the relation doesn't participate in predicate locking */ + if (!PredicateLockingNeededForRelation(relation)) + return false; + + return true; /* no excuse to skip predicate locking */ +} + + /*------------------------------------------------------------------------*/ /* @@ -542,8 +608,8 @@ RWConflictExists(const SERIALIZABLEXACT *reader, const SERIALIZABLEXACT *writer) Assert(reader != writer); /* Check the ends of the purported conflict first. */ - if (SxactIsRolledBack(reader) - || SxactIsRolledBack(writer) + if (SxactIsDoomed(reader) + || SxactIsDoomed(writer) || SHMQueueEmpty(&reader->outConflicts) || SHMQueueEmpty(&writer->inConflicts)) return false; @@ -2244,11 +2310,11 @@ PredicateLockAcquire(const PREDICATELOCKTARGETTAG *targettag) * Clear any finer-grained predicate locks this session has on the relation. */ void -PredicateLockRelation(const Relation relation) +PredicateLockRelation(const Relation relation, const Snapshot snapshot) { PREDICATELOCKTARGETTAG tag; - if (SkipSerialization(relation)) + if (!SerializationNeededForRead(relation, snapshot)) return; SET_PREDICATELOCKTARGETTAG_RELATION(tag, @@ -2267,11 +2333,12 @@ PredicateLockRelation(const Relation relation) * Clear any finer-grained predicate locks this session has on the relation. */ void -PredicateLockPage(const Relation relation, const BlockNumber blkno) +PredicateLockPage(const Relation relation, const BlockNumber blkno, + const Snapshot snapshot) { PREDICATELOCKTARGETTAG tag; - if (SkipSerialization(relation)) + if (!SerializationNeededForRead(relation, snapshot)) return; SET_PREDICATELOCKTARGETTAG_PAGE(tag, @@ -2289,13 +2356,14 @@ PredicateLockPage(const Relation relation, const BlockNumber blkno) * Skip if this is a temporary table. */ void -PredicateLockTuple(const Relation relation, const HeapTuple tuple) +PredicateLockTuple(const Relation relation, const HeapTuple tuple, + const Snapshot snapshot) { PREDICATELOCKTARGETTAG tag; ItemPointer tid; TransactionId targetxmin; - if (SkipSerialization(relation)) + if (!SerializationNeededForRead(relation, snapshot)) return; /* @@ -2666,7 +2734,7 @@ DropAllPredicateLocksFromTable(const Relation relation, bool transfer) if (!TransactionIdIsValid(PredXact->SxactGlobalXmin)) return; - if (SkipPredicateLocksForRelation(relation)) + if (!PredicateLockingNeededForRelation(relation)) return; dbId = relation->rd_node.dbNode; @@ -2881,7 +2949,7 @@ PredicateLockPageSplit(const Relation relation, const BlockNumber oldblkno, if (!TransactionIdIsValid(PredXact->SxactGlobalXmin)) return; - if (SkipPredicateLocksForRelation(relation)) + if (!PredicateLockingNeededForRelation(relation)) return; Assert(oldblkno != newblkno); @@ -2979,7 +3047,7 @@ SetNewSxactGlobalXmin(void) for (sxact = FirstPredXact(); sxact != NULL; sxact = NextPredXact(sxact)) { - if (!SxactIsRolledBack(sxact) + if (!SxactIsDoomed(sxact) && !SxactIsCommitted(sxact) && sxact != OldCommittedSxact) { @@ -3044,7 +3112,7 @@ ReleasePredicateLocks(const bool isCommit) } Assert(!isCommit || SxactIsPrepared(MySerializableXact)); - Assert(!SxactIsRolledBack(MySerializableXact)); + Assert(!isCommit || !SxactIsDoomed(MySerializableXact)); Assert(!SxactIsCommitted(MySerializableXact)); /* may not be serializable during COMMIT/ROLLBACK PREPARED */ @@ -3084,9 +3152,7 @@ ReleasePredicateLocks(const bool isCommit) MySerializableXact->flags |= SXACT_FLAG_READ_ONLY; } else - { - MySerializableXact->flags |= SXACT_FLAG_ROLLED_BACK; - } + MySerializableXact->flags |= SXACT_FLAG_DOOMED; if (!topLevelIsDeclaredReadOnly) { @@ -3311,30 +3377,6 @@ ReleasePredicateLocks(const bool isCommit) } /* - * ReleasePredicateLocksIfROSafe - * Check if the current transaction is read only and operating on - * a safe snapshot. If so, release predicate locks and return - * true. - * - * A transaction is flagged as RO_SAFE if all concurrent R/W - * transactions commit without having conflicts out to an earlier - * snapshot, thus ensuring that no conflicts are possible for this - * transaction. Thus, we call this function as part of the - * SkipSerialization check on all public interface methods. - */ -static bool -ReleasePredicateLocksIfROSafe(void) -{ - if (SxactIsROSafe(MySerializableXact)) - { - ReleasePredicateLocks(false); - return true; - } - else - return false; -} - -/* * Clear old predicate locks, belonging to committed transactions that are no * longer interesting to any in-progress transaction. */ @@ -3486,7 +3528,7 @@ ReleaseOneSerializableXact(SERIALIZABLEXACT *sxact, bool partial, nextConflict; Assert(sxact != NULL); - Assert(SxactIsRolledBack(sxact) || SxactIsCommitted(sxact)); + Assert(SxactIsDoomed(sxact) || SxactIsCommitted(sxact)); Assert(LWLockHeldByMe(SerializableFinishedListLock)); /* @@ -3679,7 +3721,8 @@ XidIsConcurrent(TransactionId xid) */ void CheckForSerializableConflictOut(const bool visible, const Relation relation, - const HeapTuple tuple, const Buffer buffer) + const HeapTuple tuple, const Buffer buffer, + const Snapshot snapshot) { TransactionId xid; SERIALIZABLEXIDTAG sxidtag; @@ -3687,10 +3730,11 @@ CheckForSerializableConflictOut(const bool visible, const Relation relation, SERIALIZABLEXACT *sxact; HTSV_Result htsvResult; - if (SkipSerialization(relation)) + if (!SerializationNeededForRead(relation, snapshot)) return; - if (SxactIsMarkedForDeath(MySerializableXact)) + /* Check if someone else has already decided that we need to die */ + if (SxactIsDoomed(MySerializableXact)) { ereport(ERROR, (errcode(ERRCODE_T_R_SERIALIZATION_FAILURE), @@ -3804,11 +3848,9 @@ CheckForSerializableConflictOut(const bool visible, const Relation relation, } sxact = sxid->myXact; Assert(TransactionIdEquals(sxact->topXid, xid)); - if (sxact == MySerializableXact - || SxactIsRolledBack(sxact) - || SxactIsMarkedForDeath(sxact)) + if (sxact == MySerializableXact || SxactIsDoomed(sxact)) { - /* We can't conflict with our own transaction or one rolled back. */ + /* Can't conflict with ourself or a transaction that will roll back. */ LWLockRelease(SerializableXactHashLock); return; } @@ -3823,7 +3865,7 @@ CheckForSerializableConflictOut(const bool visible, const Relation relation, { if (!SxactIsPrepared(sxact)) { - sxact->flags |= SXACT_FLAG_MARKED_FOR_DEATH; + sxact->flags |= SXACT_FLAG_DOOMED; LWLockRelease(SerializableXactHashLock); return; } @@ -3950,7 +3992,7 @@ CheckTargetForConflictsIn(PREDICATELOCKTARGETTAG *targettag) mypredlocktag = predlock->tag; } } - else if (!SxactIsRolledBack(sxact) + else if (!SxactIsDoomed(sxact) && (!SxactIsCommitted(sxact) || TransactionIdPrecedes(GetTransactionSnapshot()->xmin, sxact->finishedBefore)) @@ -3963,7 +4005,7 @@ CheckTargetForConflictsIn(PREDICATELOCKTARGETTAG *targettag) * Re-check after getting exclusive lock because the other * transaction may have flagged a conflict. */ - if (!SxactIsRolledBack(sxact) + if (!SxactIsDoomed(sxact) && (!SxactIsCommitted(sxact) || TransactionIdPrecedes(GetTransactionSnapshot()->xmin, sxact->finishedBefore)) @@ -4064,10 +4106,11 @@ CheckForSerializableConflictIn(const Relation relation, const HeapTuple tuple, { PREDICATELOCKTARGETTAG targettag; - if (SkipSerialization(relation)) + if (!SerializationNeededForWrite(relation)) return; - if (SxactIsMarkedForDeath(MySerializableXact)) + /* Check if someone else has already decided that we need to die */ + if (SxactIsDoomed(MySerializableXact)) ereport(ERROR, (errcode(ERRCODE_T_R_SERIALIZATION_FAILURE), errmsg("could not serialize access due to read/write dependencies among transactions"), @@ -4160,7 +4203,7 @@ CheckTableForSerializableConflictIn(const Relation relation) if (!TransactionIdIsValid(PredXact->SxactGlobalXmin)) return; - if (SkipSerialization(relation)) + if (!SerializationNeededForWrite(relation)) return; /* @@ -4371,7 +4414,7 @@ OnConflict_CheckForSerializationFailure(const SERIALIZABLEXACT *reader, { SERIALIZABLEXACT *t0 = conflict->sxactOut; - if (!SxactIsRolledBack(t0) + if (!SxactIsDoomed(t0) && (!SxactIsCommitted(t0) || t0->commitSeqNo >= writer->commitSeqNo) && (!SxactIsReadOnly(t0) @@ -4418,7 +4461,7 @@ OnConflict_CheckForSerializationFailure(const SERIALIZABLEXACT *reader, errdetail("Cancelled on conflict out to pivot %u, during read.", writer->topXid), errhint("The transaction might succeed if retried."))); } - writer->flags |= SXACT_FLAG_MARKED_FOR_DEATH; + writer->flags |= SXACT_FLAG_DOOMED; } } @@ -4450,7 +4493,8 @@ PreCommit_CheckForSerializationFailure(void) LWLockAcquire(SerializableXactHashLock, LW_EXCLUSIVE); - if (SxactIsMarkedForDeath(MySerializableXact)) + /* Check if someone else has already decided that we need to die */ + if (SxactIsDoomed(MySerializableXact)) { LWLockRelease(SerializableXactHashLock); ereport(ERROR, @@ -4467,8 +4511,7 @@ PreCommit_CheckForSerializationFailure(void) while (nearConflict) { if (!SxactIsCommitted(nearConflict->sxactOut) - && !SxactIsRolledBack(nearConflict->sxactOut) - && !SxactIsMarkedForDeath(nearConflict->sxactOut)) + && !SxactIsDoomed(nearConflict->sxactOut)) { RWConflict farConflict; @@ -4481,10 +4524,9 @@ PreCommit_CheckForSerializationFailure(void) if (farConflict->sxactOut == MySerializableXact || (!SxactIsCommitted(farConflict->sxactOut) && !SxactIsReadOnly(farConflict->sxactOut) - && !SxactIsRolledBack(farConflict->sxactOut) - && !SxactIsMarkedForDeath(farConflict->sxactOut))) + && !SxactIsDoomed(farConflict->sxactOut))) { - nearConflict->sxactOut->flags |= SXACT_FLAG_MARKED_FOR_DEATH; + nearConflict->sxactOut->flags |= SXACT_FLAG_DOOMED; break; } farConflict = (RWConflict) diff --git a/src/bin/psql/tab-complete.c b/src/bin/psql/tab-complete.c index a43d6e3159..32f418306c 100644 --- a/src/bin/psql/tab-complete.c +++ b/src/bin/psql/tab-complete.c @@ -369,11 +369,11 @@ static const SchemaQuery Query_for_list_of_updatables = { NULL }; -static const SchemaQuery Query_for_list_of_tisvf = { +static const SchemaQuery Query_for_list_of_relations = { /* catname */ "pg_catalog.pg_class c", /* selcondition */ - "c.relkind IN ('r', 'i', 'S', 'v', 'f')", + NULL, /* viscondition */ "pg_catalog.pg_table_is_visible(c.oid)", /* namespace */ @@ -2826,7 +2826,7 @@ psql_completion(char *text, int start, int end) /* must be at end of \d list */ else if (strncmp(prev_wd, "\\d", strlen("\\d")) == 0) - COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_tisvf, NULL); + COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_relations, NULL); else if (strcmp(prev_wd, "\\ef") == 0) COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_functions, NULL); diff --git a/src/include/storage/predicate.h b/src/include/storage/predicate.h index 760c76cff0..aae5326fd8 100644 --- a/src/include/storage/predicate.h +++ b/src/include/storage/predicate.h @@ -44,16 +44,17 @@ extern bool PageIsPredicateLocked(const Relation relation, const BlockNumber blk /* predicate lock maintenance */ extern Snapshot RegisterSerializableTransaction(Snapshot snapshot); extern void RegisterPredicateLockingXid(const TransactionId xid); -extern void PredicateLockRelation(const Relation relation); -extern void PredicateLockPage(const Relation relation, const BlockNumber blkno); -extern void PredicateLockTuple(const Relation relation, const HeapTuple tuple); +extern void PredicateLockRelation(const Relation relation, const Snapshot snapshot); +extern void PredicateLockPage(const Relation relation, const BlockNumber blkno, const Snapshot snapshot); +extern void PredicateLockTuple(const Relation relation, const HeapTuple tuple, const Snapshot snapshot); 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) */ -extern void CheckForSerializableConflictOut(const bool valid, const Relation relation, const HeapTuple tuple, const Buffer buffer); +extern void CheckForSerializableConflictOut(const bool valid, const Relation relation, const HeapTuple tuple, + const Buffer buffer, const Snapshot snapshot); extern void CheckForSerializableConflictIn(const Relation relation, const HeapTuple tuple, const Buffer buffer); extern void CheckTableForSerializableConflictIn(const Relation relation); diff --git a/src/include/storage/predicate_internals.h b/src/include/storage/predicate_internals.h index da6e641f4e..b305c6a4c7 100644 --- a/src/include/storage/predicate_internals.h +++ b/src/include/storage/predicate_internals.h @@ -90,22 +90,21 @@ typedef struct SERIALIZABLEXACT int pid; /* pid of associated process */ } SERIALIZABLEXACT; -#define SXACT_FLAG_ROLLED_BACK 0x00000001 -#define SXACT_FLAG_COMMITTED 0x00000002 +#define SXACT_FLAG_COMMITTED 0x00000001 /* already committed */ +#define SXACT_FLAG_PREPARED 0x00000002 /* about to commit */ +#define SXACT_FLAG_DOOMED 0x00000004 /* will roll back */ /* * The following flag actually means that the flagged transaction has a * conflict out *to a transaction which committed ahead of it*. It's hard * to get that into a name of a reasonable length. */ -#define SXACT_FLAG_CONFLICT_OUT 0x00000004 -#define SXACT_FLAG_READ_ONLY 0x00000008 -#define SXACT_FLAG_MARKED_FOR_DEATH 0x00000010 +#define SXACT_FLAG_CONFLICT_OUT 0x00000008 +#define SXACT_FLAG_READ_ONLY 0x00000010 #define SXACT_FLAG_DEFERRABLE_WAITING 0x00000020 #define SXACT_FLAG_RO_SAFE 0x00000040 #define SXACT_FLAG_RO_UNSAFE 0x00000080 #define SXACT_FLAG_SUMMARY_CONFLICT_IN 0x00000100 #define SXACT_FLAG_SUMMARY_CONFLICT_OUT 0x00000200 -#define SXACT_FLAG_PREPARED 0x00000400 /* * The following types are used to provide an ad hoc list for holding diff --git a/src/interfaces/ecpg/test/Makefile b/src/interfaces/ecpg/test/Makefile index 7ee8287cab..2f954c63ce 100644 --- a/src/interfaces/ecpg/test/Makefile +++ b/src/interfaces/ecpg/test/Makefile @@ -84,4 +84,4 @@ checktcp: all ./pg_regress --dbname=regress1,connectdb --top-builddir=$(top_builddir) --temp-install=./tmp_check $(pg_regress_locale_flags) $(THREAD) --schedule=$(srcdir)/ecpg_schedule_tcp --create-role=connectuser,connectdb --host=localhost installcheck: all - ./pg_regress --psqldir=$(PSQLDIR) --dbname=regress1,connectdb --top-builddir=$(top_builddir) $(pg_regress_locale_flags) $(THREAD) --schedule=$(srcdir)/ecpg_schedule --create-role=connectuser,connectdb + ./pg_regress --psqldir="$(PSQLDIR)" --dbname=regress1,connectdb --top-builddir=$(top_builddir) $(pg_regress_locale_flags) $(THREAD) --schedule=$(srcdir)/ecpg_schedule --create-role=connectuser,connectdb diff --git a/src/test/isolation/Makefile b/src/test/isolation/Makefile index 7cbcd4b403..0fe8d608cc 100644 --- a/src/test/isolation/Makefile +++ b/src/test/isolation/Makefile @@ -73,7 +73,7 @@ maintainer-clean: distclean rm -f specparse.c specscanner.c installcheck: all - ./pg_isolation_regress --psqldir=$(PSQLDIR) --inputdir=$(srcdir) --schedule=$(srcdir)/isolation_schedule + ./pg_isolation_regress --psqldir="$(PSQLDIR)" --inputdir=$(srcdir) --schedule=$(srcdir)/isolation_schedule # We can't support "make check" because isolationtester requires libpq, and # in fact (on typical platforms using shared libraries) requires libpq to |