summaryrefslogtreecommitdiff
path: root/src/backend/utils/time/tqual.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/backend/utils/time/tqual.c')
-rw-r--r--src/backend/utils/time/tqual.c466
1 files changed, 379 insertions, 87 deletions
diff --git a/src/backend/utils/time/tqual.c b/src/backend/utils/time/tqual.c
index 51f0afded98..f2c9ff2e1c1 100644
--- a/src/backend/utils/time/tqual.c
+++ b/src/backend/utils/time/tqual.c
@@ -214,12 +214,25 @@ HeapTupleSatisfiesSelf(HeapTupleHeader tuple, Snapshot snapshot, Buffer buffer)
if (tuple->t_infomask & HEAP_XMAX_INVALID) /* xid invalid */
return true;
- if (tuple->t_infomask & HEAP_IS_LOCKED) /* not deleter */
+ if (HEAP_XMAX_IS_LOCKED_ONLY(tuple->t_infomask)) /* not deleter */
return true;
- Assert(!(tuple->t_infomask & HEAP_XMAX_IS_MULTI));
+ if (tuple->t_infomask & HEAP_XMAX_IS_MULTI)
+ {
+ TransactionId xmax;
+
+ xmax = HeapTupleGetUpdateXid(tuple);
+ if (!TransactionIdIsValid(xmax))
+ return true;
+
+ /* updating subtransaction must have aborted */
+ if (!TransactionIdIsCurrentTransactionId(xmax))
+ return true;
+ else
+ return false;
+ }
- if (!TransactionIdIsCurrentTransactionId(HeapTupleHeaderGetXmax(tuple)))
+ if (!TransactionIdIsCurrentTransactionId(HeapTupleHeaderGetRawXmax(tuple)))
{
/* deleting subtransaction must have aborted */
SetHintBits(tuple, buffer, HEAP_XMAX_INVALID,
@@ -250,29 +263,41 @@ HeapTupleSatisfiesSelf(HeapTupleHeader tuple, Snapshot snapshot, Buffer buffer)
if (tuple->t_infomask & HEAP_XMAX_COMMITTED)
{
- if (tuple->t_infomask & HEAP_IS_LOCKED)
+ if (HEAP_XMAX_IS_LOCKED_ONLY(tuple->t_infomask))
return true;
return false; /* updated by other */
}
if (tuple->t_infomask & HEAP_XMAX_IS_MULTI)
{
- /* MultiXacts are currently only allowed to lock tuples */
- Assert(tuple->t_infomask & HEAP_IS_LOCKED);
+ TransactionId xmax;
+
+ if (HEAP_XMAX_IS_LOCKED_ONLY(tuple->t_infomask))
+ return true;
+
+ xmax = HeapTupleGetUpdateXid(tuple);
+ if (!TransactionIdIsValid(xmax))
+ return true;
+ if (TransactionIdIsCurrentTransactionId(xmax))
+ return false;
+ if (TransactionIdIsInProgress(xmax))
+ return true;
+ if (TransactionIdDidCommit(xmax))
+ return false;
return true;
}
- if (TransactionIdIsCurrentTransactionId(HeapTupleHeaderGetXmax(tuple)))
+ if (TransactionIdIsCurrentTransactionId(HeapTupleHeaderGetRawXmax(tuple)))
{
- if (tuple->t_infomask & HEAP_IS_LOCKED)
+ if (HEAP_XMAX_IS_LOCKED_ONLY(tuple->t_infomask))
return true;
return false;
}
- if (TransactionIdIsInProgress(HeapTupleHeaderGetXmax(tuple)))
+ if (TransactionIdIsInProgress(HeapTupleHeaderGetRawXmax(tuple)))
return true;
- if (!TransactionIdDidCommit(HeapTupleHeaderGetXmax(tuple)))
+ if (!TransactionIdDidCommit(HeapTupleHeaderGetRawXmax(tuple)))
{
/* it must have aborted or crashed */
SetHintBits(tuple, buffer, HEAP_XMAX_INVALID,
@@ -282,7 +307,7 @@ HeapTupleSatisfiesSelf(HeapTupleHeader tuple, Snapshot snapshot, Buffer buffer)
/* xmax transaction committed */
- if (tuple->t_infomask & HEAP_IS_LOCKED)
+ if (HEAP_XMAX_IS_LOCKED_ONLY(tuple->t_infomask))
{
SetHintBits(tuple, buffer, HEAP_XMAX_INVALID,
InvalidTransactionId);
@@ -290,7 +315,7 @@ HeapTupleSatisfiesSelf(HeapTupleHeader tuple, Snapshot snapshot, Buffer buffer)
}
SetHintBits(tuple, buffer, HEAP_XMAX_COMMITTED,
- HeapTupleHeaderGetXmax(tuple));
+ HeapTupleHeaderGetRawXmax(tuple));
return false;
}
@@ -380,12 +405,25 @@ HeapTupleSatisfiesNow(HeapTupleHeader tuple, Snapshot snapshot, Buffer buffer)
if (tuple->t_infomask & HEAP_XMAX_INVALID) /* xid invalid */
return true;
- if (tuple->t_infomask & HEAP_IS_LOCKED) /* not deleter */
+ if (HEAP_XMAX_IS_LOCKED_ONLY(tuple->t_infomask)) /* not deleter */
return true;
- Assert(!(tuple->t_infomask & HEAP_XMAX_IS_MULTI));
+ if (tuple->t_infomask & HEAP_XMAX_IS_MULTI)
+ {
+ TransactionId xmax;
- if (!TransactionIdIsCurrentTransactionId(HeapTupleHeaderGetXmax(tuple)))
+ xmax = HeapTupleGetUpdateXid(tuple);
+ if (!TransactionIdIsValid(xmax))
+ return true;
+
+ /* updating subtransaction must have aborted */
+ if (!TransactionIdIsCurrentTransactionId(xmax))
+ return true;
+ else
+ return false;
+ }
+
+ if (!TransactionIdIsCurrentTransactionId(HeapTupleHeaderGetRawXmax(tuple)))
{
/* deleting subtransaction must have aborted */
SetHintBits(tuple, buffer, HEAP_XMAX_INVALID,
@@ -419,21 +457,38 @@ HeapTupleSatisfiesNow(HeapTupleHeader tuple, Snapshot snapshot, Buffer buffer)
if (tuple->t_infomask & HEAP_XMAX_COMMITTED)
{
- if (tuple->t_infomask & HEAP_IS_LOCKED)
+ if (HEAP_XMAX_IS_LOCKED_ONLY(tuple->t_infomask))
return true;
return false;
}
if (tuple->t_infomask & HEAP_XMAX_IS_MULTI)
{
- /* MultiXacts are currently only allowed to lock tuples */
- Assert(tuple->t_infomask & HEAP_IS_LOCKED);
+ TransactionId xmax;
+
+ if (HEAP_XMAX_IS_LOCKED_ONLY(tuple->t_infomask))
+ return true;
+
+ xmax = HeapTupleGetUpdateXid(tuple);
+ if (!TransactionIdIsValid(xmax))
+ return true;
+ if (TransactionIdIsCurrentTransactionId(xmax))
+ {
+ if (HeapTupleHeaderGetCmax(tuple) >= GetCurrentCommandId(false))
+ return true; /* deleted after scan started */
+ else
+ return false; /* deleted before scan started */
+ }
+ if (TransactionIdIsInProgress(xmax))
+ return true;
+ if (TransactionIdDidCommit(xmax))
+ return false;
return true;
}
- if (TransactionIdIsCurrentTransactionId(HeapTupleHeaderGetXmax(tuple)))
+ if (TransactionIdIsCurrentTransactionId(HeapTupleHeaderGetRawXmax(tuple)))
{
- if (tuple->t_infomask & HEAP_IS_LOCKED)
+ if (HEAP_XMAX_IS_LOCKED_ONLY(tuple->t_infomask))
return true;
if (HeapTupleHeaderGetCmax(tuple) >= GetCurrentCommandId(false))
return true; /* deleted after scan started */
@@ -441,10 +496,10 @@ HeapTupleSatisfiesNow(HeapTupleHeader tuple, Snapshot snapshot, Buffer buffer)
return false; /* deleted before scan started */
}
- if (TransactionIdIsInProgress(HeapTupleHeaderGetXmax(tuple)))
+ if (TransactionIdIsInProgress(HeapTupleHeaderGetRawXmax(tuple)))
return true;
- if (!TransactionIdDidCommit(HeapTupleHeaderGetXmax(tuple)))
+ if (!TransactionIdDidCommit(HeapTupleHeaderGetRawXmax(tuple)))
{
/* it must have aborted or crashed */
SetHintBits(tuple, buffer, HEAP_XMAX_INVALID,
@@ -454,7 +509,7 @@ HeapTupleSatisfiesNow(HeapTupleHeader tuple, Snapshot snapshot, Buffer buffer)
/* xmax transaction committed */
- if (tuple->t_infomask & HEAP_IS_LOCKED)
+ if (HEAP_XMAX_IS_LOCKED_ONLY(tuple->t_infomask))
{
SetHintBits(tuple, buffer, HEAP_XMAX_INVALID,
InvalidTransactionId);
@@ -462,7 +517,7 @@ HeapTupleSatisfiesNow(HeapTupleHeader tuple, Snapshot snapshot, Buffer buffer)
}
SetHintBits(tuple, buffer, HEAP_XMAX_COMMITTED,
- HeapTupleHeaderGetXmax(tuple));
+ HeapTupleHeaderGetRawXmax(tuple));
return false;
}
@@ -627,12 +682,30 @@ HeapTupleSatisfiesUpdate(HeapTupleHeader tuple, CommandId curcid,
if (tuple->t_infomask & HEAP_XMAX_INVALID) /* xid invalid */
return HeapTupleMayBeUpdated;
- if (tuple->t_infomask & HEAP_IS_LOCKED) /* not deleter */
+ if (HEAP_XMAX_IS_LOCKED_ONLY(tuple->t_infomask)) /* not deleter */
return HeapTupleMayBeUpdated;
- Assert(!(tuple->t_infomask & HEAP_XMAX_IS_MULTI));
+ if (tuple->t_infomask & HEAP_XMAX_IS_MULTI)
+ {
+ TransactionId xmax;
+
+ xmax = HeapTupleGetUpdateXid(tuple);
+ if (!TransactionIdIsValid(xmax))
+ return HeapTupleMayBeUpdated;
+
+ /* updating subtransaction must have aborted */
+ if (!TransactionIdIsCurrentTransactionId(xmax))
+ return HeapTupleMayBeUpdated;
+ else
+ {
+ if (HeapTupleHeaderGetCmax(tuple) >= curcid)
+ return HeapTupleSelfUpdated; /* updated after scan started */
+ else
+ return HeapTupleInvisible; /* updated before scan started */
+ }
+ }
- if (!TransactionIdIsCurrentTransactionId(HeapTupleHeaderGetXmax(tuple)))
+ if (!TransactionIdIsCurrentTransactionId(HeapTupleHeaderGetRawXmax(tuple)))
{
/* deleting subtransaction must have aborted */
SetHintBits(tuple, buffer, HEAP_XMAX_INVALID,
@@ -666,26 +739,62 @@ HeapTupleSatisfiesUpdate(HeapTupleHeader tuple, CommandId curcid,
if (tuple->t_infomask & HEAP_XMAX_COMMITTED)
{
- if (tuple->t_infomask & HEAP_IS_LOCKED)
+ if (HEAP_XMAX_IS_LOCKED_ONLY(tuple->t_infomask))
return HeapTupleMayBeUpdated;
return HeapTupleUpdated; /* updated by other */
}
if (tuple->t_infomask & HEAP_XMAX_IS_MULTI)
{
- /* MultiXacts are currently only allowed to lock tuples */
- Assert(tuple->t_infomask & HEAP_IS_LOCKED);
+ TransactionId xmax;
- if (MultiXactIdIsRunning(HeapTupleHeaderGetXmax(tuple)))
+ if (HEAP_XMAX_IS_LOCKED_ONLY(tuple->t_infomask))
+ {
+ /*
+ * If it's only locked but neither EXCL_LOCK nor KEYSHR_LOCK
+ * is set, it cannot possibly be running. Otherwise need to
+ * check.
+ */
+ if ((tuple->t_infomask & (HEAP_XMAX_EXCL_LOCK |
+ HEAP_XMAX_KEYSHR_LOCK)) &&
+ MultiXactIdIsRunning(HeapTupleHeaderGetRawXmax(tuple)))
+ return HeapTupleBeingUpdated;
+
+ SetHintBits(tuple, buffer, HEAP_XMAX_INVALID, InvalidTransactionId);
+ return HeapTupleMayBeUpdated;
+ }
+
+ xmax = HeapTupleGetUpdateXid(tuple);
+ if (!TransactionIdIsValid(xmax))
+ {
+ if (MultiXactIdIsRunning(HeapTupleHeaderGetRawXmax(tuple)))
+ return HeapTupleBeingUpdated;
+
+ SetHintBits(tuple, buffer, HEAP_XMAX_INVALID, InvalidTransactionId);
+ return HeapTupleMayBeUpdated;
+ }
+
+ if (TransactionIdIsCurrentTransactionId(xmax))
+ {
+ if (HeapTupleHeaderGetCmax(tuple) >= curcid)
+ return HeapTupleSelfUpdated; /* updated after scan started */
+ else
+ return HeapTupleInvisible; /* updated before scan started */
+ }
+
+ if (MultiXactIdIsRunning(HeapTupleHeaderGetRawXmax(tuple)))
return HeapTupleBeingUpdated;
- SetHintBits(tuple, buffer, HEAP_XMAX_INVALID,
- InvalidTransactionId);
+
+ if (TransactionIdDidCommit(xmax))
+ return HeapTupleUpdated;
+ /* it must have aborted or crashed */
+ SetHintBits(tuple, buffer, HEAP_XMAX_INVALID, InvalidTransactionId);
return HeapTupleMayBeUpdated;
}
- if (TransactionIdIsCurrentTransactionId(HeapTupleHeaderGetXmax(tuple)))
+ if (TransactionIdIsCurrentTransactionId(HeapTupleHeaderGetRawXmax(tuple)))
{
- if (tuple->t_infomask & HEAP_IS_LOCKED)
+ if (HEAP_XMAX_IS_LOCKED_ONLY(tuple->t_infomask))
return HeapTupleMayBeUpdated;
if (HeapTupleHeaderGetCmax(tuple) >= curcid)
return HeapTupleSelfUpdated; /* updated after scan started */
@@ -693,10 +802,10 @@ HeapTupleSatisfiesUpdate(HeapTupleHeader tuple, CommandId curcid,
return HeapTupleInvisible; /* updated before scan started */
}
- if (TransactionIdIsInProgress(HeapTupleHeaderGetXmax(tuple)))
+ if (TransactionIdIsInProgress(HeapTupleHeaderGetRawXmax(tuple)))
return HeapTupleBeingUpdated;
- if (!TransactionIdDidCommit(HeapTupleHeaderGetXmax(tuple)))
+ if (!TransactionIdDidCommit(HeapTupleHeaderGetRawXmax(tuple)))
{
/* it must have aborted or crashed */
SetHintBits(tuple, buffer, HEAP_XMAX_INVALID,
@@ -706,7 +815,7 @@ HeapTupleSatisfiesUpdate(HeapTupleHeader tuple, CommandId curcid,
/* xmax transaction committed */
- if (tuple->t_infomask & HEAP_IS_LOCKED)
+ if (HEAP_XMAX_IS_LOCKED_ONLY(tuple->t_infomask))
{
SetHintBits(tuple, buffer, HEAP_XMAX_INVALID,
InvalidTransactionId);
@@ -714,7 +823,7 @@ HeapTupleSatisfiesUpdate(HeapTupleHeader tuple, CommandId curcid,
}
SetHintBits(tuple, buffer, HEAP_XMAX_COMMITTED,
- HeapTupleHeaderGetXmax(tuple));
+ HeapTupleHeaderGetRawXmax(tuple));
return HeapTupleUpdated; /* updated by other */
}
@@ -793,12 +902,25 @@ HeapTupleSatisfiesDirty(HeapTupleHeader tuple, Snapshot snapshot,
if (tuple->t_infomask & HEAP_XMAX_INVALID) /* xid invalid */
return true;
- if (tuple->t_infomask & HEAP_IS_LOCKED) /* not deleter */
+ if (HEAP_XMAX_IS_LOCKED_ONLY(tuple->t_infomask)) /* not deleter */
return true;
- Assert(!(tuple->t_infomask & HEAP_XMAX_IS_MULTI));
+ if (tuple->t_infomask & HEAP_XMAX_IS_MULTI)
+ {
+ TransactionId xmax;
- if (!TransactionIdIsCurrentTransactionId(HeapTupleHeaderGetXmax(tuple)))
+ xmax = HeapTupleGetUpdateXid(tuple);
+ if (!TransactionIdIsValid(xmax))
+ return true;
+
+ /* updating subtransaction must have aborted */
+ if (!TransactionIdIsCurrentTransactionId(xmax))
+ return true;
+ else
+ return false;
+ }
+
+ if (!TransactionIdIsCurrentTransactionId(HeapTupleHeaderGetRawXmax(tuple)))
{
/* deleting subtransaction must have aborted */
SetHintBits(tuple, buffer, HEAP_XMAX_INVALID,
@@ -833,32 +955,47 @@ HeapTupleSatisfiesDirty(HeapTupleHeader tuple, Snapshot snapshot,
if (tuple->t_infomask & HEAP_XMAX_COMMITTED)
{
- if (tuple->t_infomask & HEAP_IS_LOCKED)
+ if (HEAP_XMAX_IS_LOCKED_ONLY(tuple->t_infomask))
return true;
return false; /* updated by other */
}
if (tuple->t_infomask & HEAP_XMAX_IS_MULTI)
{
- /* MultiXacts are currently only allowed to lock tuples */
- Assert(tuple->t_infomask & HEAP_IS_LOCKED);
+ TransactionId xmax;
+
+ if (HEAP_XMAX_IS_LOCKED_ONLY(tuple->t_infomask))
+ return true;
+
+ xmax = HeapTupleGetUpdateXid(tuple);
+ if (!TransactionIdIsValid(xmax))
+ return true;
+ if (TransactionIdIsCurrentTransactionId(xmax))
+ return false;
+ if (TransactionIdIsInProgress(xmax))
+ {
+ snapshot->xmax = xmax;
+ return true;
+ }
+ if (TransactionIdDidCommit(xmax))
+ return false;
return true;
}
- if (TransactionIdIsCurrentTransactionId(HeapTupleHeaderGetXmax(tuple)))
+ if (TransactionIdIsCurrentTransactionId(HeapTupleHeaderGetRawXmax(tuple)))
{
- if (tuple->t_infomask & HEAP_IS_LOCKED)
+ if (HEAP_XMAX_IS_LOCKED_ONLY(tuple->t_infomask))
return true;
return false;
}
- if (TransactionIdIsInProgress(HeapTupleHeaderGetXmax(tuple)))
+ if (TransactionIdIsInProgress(HeapTupleHeaderGetRawXmax(tuple)))
{
- snapshot->xmax = HeapTupleHeaderGetXmax(tuple);
+ snapshot->xmax = HeapTupleHeaderGetRawXmax(tuple);
return true;
}
- if (!TransactionIdDidCommit(HeapTupleHeaderGetXmax(tuple)))
+ if (!TransactionIdDidCommit(HeapTupleHeaderGetRawXmax(tuple)))
{
/* it must have aborted or crashed */
SetHintBits(tuple, buffer, HEAP_XMAX_INVALID,
@@ -868,7 +1005,7 @@ HeapTupleSatisfiesDirty(HeapTupleHeader tuple, Snapshot snapshot,
/* xmax transaction committed */
- if (tuple->t_infomask & HEAP_IS_LOCKED)
+ if (HEAP_XMAX_IS_LOCKED_ONLY(tuple->t_infomask))
{
SetHintBits(tuple, buffer, HEAP_XMAX_INVALID,
InvalidTransactionId);
@@ -876,7 +1013,7 @@ HeapTupleSatisfiesDirty(HeapTupleHeader tuple, Snapshot snapshot,
}
SetHintBits(tuple, buffer, HEAP_XMAX_COMMITTED,
- HeapTupleHeaderGetXmax(tuple));
+ HeapTupleHeaderGetRawXmax(tuple));
return false; /* updated by other */
}
@@ -957,12 +1094,27 @@ HeapTupleSatisfiesMVCC(HeapTupleHeader tuple, Snapshot snapshot,
if (tuple->t_infomask & HEAP_XMAX_INVALID) /* xid invalid */
return true;
- if (tuple->t_infomask & HEAP_IS_LOCKED) /* not deleter */
+ if (HEAP_XMAX_IS_LOCKED_ONLY(tuple->t_infomask)) /* not deleter */
return true;
- Assert(!(tuple->t_infomask & HEAP_XMAX_IS_MULTI));
+ if (tuple->t_infomask & HEAP_XMAX_IS_MULTI)
+ {
+ TransactionId xmax;
+
+ xmax = HeapTupleGetUpdateXid(tuple);
+ if (!TransactionIdIsValid(xmax))
+ return true;
+
+ /* updating subtransaction must have aborted */
+ if (!TransactionIdIsCurrentTransactionId(xmax))
+ return true;
+ else if (HeapTupleHeaderGetCmax(tuple) >= snapshot->curcid)
+ return true; /* updated after scan started */
+ else
+ return false; /* updated before scan started */
+ }
- if (!TransactionIdIsCurrentTransactionId(HeapTupleHeaderGetXmax(tuple)))
+ if (!TransactionIdIsCurrentTransactionId(HeapTupleHeaderGetRawXmax(tuple)))
{
/* deleting subtransaction must have aborted */
SetHintBits(tuple, buffer, HEAP_XMAX_INVALID,
@@ -999,19 +1151,41 @@ HeapTupleSatisfiesMVCC(HeapTupleHeader tuple, Snapshot snapshot,
if (tuple->t_infomask & HEAP_XMAX_INVALID) /* xid invalid or aborted */
return true;
- if (tuple->t_infomask & HEAP_IS_LOCKED)
+ if (HEAP_XMAX_IS_LOCKED_ONLY(tuple->t_infomask))
return true;
if (tuple->t_infomask & HEAP_XMAX_IS_MULTI)
{
- /* MultiXacts are currently only allowed to lock tuples */
- Assert(tuple->t_infomask & HEAP_IS_LOCKED);
+ TransactionId xmax;
+
+ /* already checked above */
+ Assert(!HEAP_XMAX_IS_LOCKED_ONLY(tuple->t_infomask));
+
+ xmax = HeapTupleGetUpdateXid(tuple);
+ if (!TransactionIdIsValid(xmax))
+ return true;
+ if (TransactionIdIsCurrentTransactionId(xmax))
+ {
+ if (HeapTupleHeaderGetCmax(tuple) >= snapshot->curcid)
+ return true; /* deleted after scan started */
+ else
+ return false; /* deleted before scan started */
+ }
+ if (TransactionIdIsInProgress(xmax))
+ return true;
+ if (TransactionIdDidCommit(xmax))
+ {
+ /* updating transaction committed, but when? */
+ if (XidInMVCCSnapshot(xmax, snapshot))
+ return true; /* treat as still in progress */
+ return false;
+ }
return true;
}
if (!(tuple->t_infomask & HEAP_XMAX_COMMITTED))
{
- if (TransactionIdIsCurrentTransactionId(HeapTupleHeaderGetXmax(tuple)))
+ if (TransactionIdIsCurrentTransactionId(HeapTupleHeaderGetRawXmax(tuple)))
{
if (HeapTupleHeaderGetCmax(tuple) >= snapshot->curcid)
return true; /* deleted after scan started */
@@ -1019,10 +1193,10 @@ HeapTupleSatisfiesMVCC(HeapTupleHeader tuple, Snapshot snapshot,
return false; /* deleted before scan started */
}
- if (TransactionIdIsInProgress(HeapTupleHeaderGetXmax(tuple)))
+ if (TransactionIdIsInProgress(HeapTupleHeaderGetRawXmax(tuple)))
return true;
- if (!TransactionIdDidCommit(HeapTupleHeaderGetXmax(tuple)))
+ if (!TransactionIdDidCommit(HeapTupleHeaderGetRawXmax(tuple)))
{
/* it must have aborted or crashed */
SetHintBits(tuple, buffer, HEAP_XMAX_INVALID,
@@ -1032,13 +1206,13 @@ HeapTupleSatisfiesMVCC(HeapTupleHeader tuple, Snapshot snapshot,
/* xmax transaction committed */
SetHintBits(tuple, buffer, HEAP_XMAX_COMMITTED,
- HeapTupleHeaderGetXmax(tuple));
+ HeapTupleHeaderGetRawXmax(tuple));
}
/*
* OK, the deleting transaction committed too ... but when?
*/
- if (XidInMVCCSnapshot(HeapTupleHeaderGetXmax(tuple), snapshot))
+ if (XidInMVCCSnapshot(HeapTupleHeaderGetRawXmax(tuple), snapshot))
return true; /* treat as still in progress */
return false;
@@ -1112,7 +1286,7 @@ HeapTupleSatisfiesVacuum(HeapTupleHeader tuple, TransactionId OldestXmin,
{
if (tuple->t_infomask & HEAP_XMAX_INVALID) /* xid invalid */
return HEAPTUPLE_INSERT_IN_PROGRESS;
- if (tuple->t_infomask & HEAP_IS_LOCKED)
+ if (HEAP_XMAX_IS_LOCKED_ONLY(tuple->t_infomask))
return HEAPTUPLE_INSERT_IN_PROGRESS;
/* inserted and then deleted by same xact */
return HEAPTUPLE_DELETE_IN_PROGRESS;
@@ -1144,7 +1318,7 @@ HeapTupleSatisfiesVacuum(HeapTupleHeader tuple, TransactionId OldestXmin,
if (tuple->t_infomask & HEAP_XMAX_INVALID)
return HEAPTUPLE_LIVE;
- if (tuple->t_infomask & HEAP_IS_LOCKED)
+ if (HEAP_XMAX_IS_LOCKED_ONLY(tuple->t_infomask))
{
/*
* "Deleting" xact really only locked it, so the tuple is live in any
@@ -1158,40 +1332,96 @@ HeapTupleSatisfiesVacuum(HeapTupleHeader tuple, TransactionId OldestXmin,
{
if (tuple->t_infomask & HEAP_XMAX_IS_MULTI)
{
- if (MultiXactIdIsRunning(HeapTupleHeaderGetXmax(tuple)))
+ /*
+ * If it's only locked but neither EXCL_LOCK nor KEYSHR_LOCK
+ * are set, it cannot possibly be running; otherwise have to
+ * check.
+ */
+ if ((tuple->t_infomask & (HEAP_XMAX_EXCL_LOCK |
+ HEAP_XMAX_KEYSHR_LOCK)) &&
+ MultiXactIdIsRunning(HeapTupleHeaderGetRawXmax(tuple)))
return HEAPTUPLE_LIVE;
+ SetHintBits(tuple, buffer, HEAP_XMAX_INVALID, InvalidTransactionId);
+
}
else
{
- if (TransactionIdIsInProgress(HeapTupleHeaderGetXmax(tuple)))
+ if (TransactionIdIsInProgress(HeapTupleHeaderGetRawXmax(tuple)))
return HEAPTUPLE_LIVE;
+ SetHintBits(tuple, buffer, HEAP_XMAX_INVALID,
+ InvalidTransactionId);
}
-
- /*
- * We don't really care whether xmax did commit, abort or crash.
- * We know that xmax did lock the tuple, but it did not and will
- * never actually update it.
- */
- SetHintBits(tuple, buffer, HEAP_XMAX_INVALID,
- InvalidTransactionId);
}
+
+ /*
+ * We don't really care whether xmax did commit, abort or crash.
+ * We know that xmax did lock the tuple, but it did not and will
+ * never actually update it.
+ */
+
return HEAPTUPLE_LIVE;
}
if (tuple->t_infomask & HEAP_XMAX_IS_MULTI)
{
- /* MultiXacts are currently only allowed to lock tuples */
- Assert(tuple->t_infomask & HEAP_IS_LOCKED);
- return HEAPTUPLE_LIVE;
+ TransactionId xmax;
+
+ if (MultiXactIdIsRunning(HeapTupleHeaderGetRawXmax(tuple)))
+ {
+ /* already checked above */
+ Assert(!HEAP_XMAX_IS_LOCKED_ONLY(tuple->t_infomask));
+
+ xmax = HeapTupleGetUpdateXid(tuple);
+ if (!TransactionIdIsValid(xmax))
+ return HEAPTUPLE_LIVE;
+ if (TransactionIdIsInProgress(xmax))
+ return HEAPTUPLE_DELETE_IN_PROGRESS;
+ else if (TransactionIdDidCommit(xmax))
+ /* there are still lockers around -- can't return DEAD here */
+ return HEAPTUPLE_RECENTLY_DEAD;
+ /* updating transaction aborted */
+ return HEAPTUPLE_LIVE;
+ }
+
+ Assert(!(tuple->t_infomask & HEAP_XMAX_COMMITTED));
+
+ xmax = HeapTupleGetUpdateXid(tuple);
+ if (!TransactionIdIsValid(xmax))
+ return HEAPTUPLE_LIVE;
+ /* multi is not running -- updating xact cannot be */
+ Assert(!TransactionIdIsInProgress(xmax));
+ if (TransactionIdDidCommit(xmax))
+ {
+ if (!TransactionIdPrecedes(xmax, OldestXmin))
+ return HEAPTUPLE_RECENTLY_DEAD;
+ else
+ return HEAPTUPLE_DEAD;
+ }
+ else
+ {
+ /*
+ * Not in Progress, Not Committed, so either Aborted or crashed.
+ */
+ SetHintBits(tuple, buffer, HEAP_XMAX_INVALID, InvalidTransactionId);
+ return HEAPTUPLE_LIVE;
+ }
+
+ /*
+ * Deleter committed, but perhaps it was recent enough that some open
+ * transactions could still see the tuple.
+ */
+
+ /* Otherwise, it's dead and removable */
+ return HEAPTUPLE_DEAD;
}
if (!(tuple->t_infomask & HEAP_XMAX_COMMITTED))
{
- if (TransactionIdIsInProgress(HeapTupleHeaderGetXmax(tuple)))
+ if (TransactionIdIsInProgress(HeapTupleHeaderGetRawXmax(tuple)))
return HEAPTUPLE_DELETE_IN_PROGRESS;
- else if (TransactionIdDidCommit(HeapTupleHeaderGetXmax(tuple)))
+ else if (TransactionIdDidCommit(HeapTupleHeaderGetRawXmax(tuple)))
SetHintBits(tuple, buffer, HEAP_XMAX_COMMITTED,
- HeapTupleHeaderGetXmax(tuple));
+ HeapTupleHeaderGetRawXmax(tuple));
else
{
/*
@@ -1213,7 +1443,7 @@ HeapTupleSatisfiesVacuum(HeapTupleHeader tuple, TransactionId OldestXmin,
* Deleter committed, but perhaps it was recent enough that some open
* transactions could still see the tuple.
*/
- if (!TransactionIdPrecedes(HeapTupleHeaderGetXmax(tuple), OldestXmin))
+ if (!TransactionIdPrecedes(HeapTupleHeaderGetRawXmax(tuple), OldestXmin))
return HEAPTUPLE_RECENTLY_DEAD;
/* Otherwise, it's dead and removable */
@@ -1246,11 +1476,22 @@ HeapTupleIsSurelyDead(HeapTupleHeader tuple, TransactionId OldestXmin)
/*
* If the inserting transaction committed, but any deleting transaction
- * aborted, the tuple is still alive. Likewise, if XMAX is a lock rather
- * than a delete, the tuple is still alive.
+ * aborted, the tuple is still alive.
*/
- if (tuple->t_infomask &
- (HEAP_XMAX_INVALID | HEAP_IS_LOCKED | HEAP_XMAX_IS_MULTI))
+ if (tuple->t_infomask & HEAP_XMAX_INVALID)
+ return false;
+
+ /*
+ * If the XMAX is just a lock, the tuple is still alive.
+ */
+ if (HEAP_XMAX_IS_LOCKED_ONLY(tuple->t_infomask))
+ return false;
+
+ /*
+ * If the Xmax is a MultiXact, it might be dead or alive, but we cannot
+ * know without checking pg_multixact.
+ */
+ if (tuple->t_infomask & HEAP_XMAX_IS_MULTI)
return false;
/* If deleter isn't known to have committed, assume it's still running. */
@@ -1258,7 +1499,7 @@ HeapTupleIsSurelyDead(HeapTupleHeader tuple, TransactionId OldestXmin)
return false;
/* Deleter committed, so tuple is dead if the XID is old enough. */
- return TransactionIdPrecedes(HeapTupleHeaderGetXmax(tuple), OldestXmin);
+ return TransactionIdPrecedes(HeapTupleHeaderGetRawXmax(tuple), OldestXmin);
}
/*
@@ -1375,3 +1616,54 @@ XidInMVCCSnapshot(TransactionId xid, Snapshot snapshot)
return false;
}
+
+/*
+ * Is the tuple really only locked? That is, is it not updated?
+ *
+ * It's easy to check just infomask bits if the locker is not a multi; but
+ * otherwise we need to verify that the updating transaction has not aborted.
+ *
+ * This function is here because it follows the same time qualification rules
+ * laid out at the top of this file.
+ */
+bool
+HeapTupleHeaderIsOnlyLocked(HeapTupleHeader tuple)
+{
+ TransactionId xmax;
+
+ /* if there's no valid Xmax, then there's obviously no update either */
+ if (tuple->t_infomask & HEAP_XMAX_INVALID)
+ return true;
+
+ if (tuple->t_infomask & HEAP_XMAX_LOCK_ONLY)
+ return true;
+
+ /* invalid xmax means no update */
+ if (!TransactionIdIsValid(HeapTupleHeaderGetRawXmax(tuple)))
+ return true;
+
+ /*
+ * if HEAP_XMAX_LOCK_ONLY is not set and not a multi, then this
+ * must necessarily have been updated
+ */
+ if (!(tuple->t_infomask & HEAP_XMAX_IS_MULTI))
+ return false;
+
+ /* ... but if it's a multi, then perhaps the updating Xid aborted. */
+ xmax = HeapTupleGetUpdateXid(tuple);
+ if (!TransactionIdIsValid(xmax)) /* shouldn't happen .. */
+ return true;
+
+ if (TransactionIdIsCurrentTransactionId(xmax))
+ return false;
+ if (TransactionIdIsInProgress(xmax))
+ return false;
+ if (TransactionIdDidCommit(xmax))
+ return false;
+
+ /*
+ * not current, not in progress, not committed -- must have aborted or
+ * crashed
+ */
+ return true;
+}