aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/backend/access/heap/heapam.c207
-rw-r--r--src/backend/access/heap/visibilitymap.c18
-rw-r--r--src/backend/access/rmgrdesc/heapdesc.c6
-rw-r--r--src/backend/commands/vacuumlazy.c6
-rw-r--r--src/include/access/heapam_xlog.h9
-rw-r--r--src/include/access/visibilitymap.h4
-rw-r--r--src/include/access/xlog_internal.h2
7 files changed, 194 insertions, 58 deletions
diff --git a/src/backend/access/heap/heapam.c b/src/backend/access/heap/heapam.c
index 2815d916f3d..38bba162997 100644
--- a/src/backend/access/heap/heapam.c
+++ b/src/backend/access/heap/heapam.c
@@ -2423,7 +2423,7 @@ heap_insert(Relation relation, HeapTuple tup, CommandId cid,
PageClearAllVisible(BufferGetPage(buffer));
visibilitymap_clear(relation,
ItemPointerGetBlockNumber(&(heaptup->t_self)),
- vmbuffer);
+ vmbuffer, VISIBILITYMAP_VALID_BITS);
}
/*
@@ -2737,7 +2737,7 @@ heap_multi_insert(Relation relation, HeapTuple *tuples, int ntuples,
PageClearAllVisible(page);
visibilitymap_clear(relation,
BufferGetBlockNumber(buffer),
- vmbuffer);
+ vmbuffer, VISIBILITYMAP_VALID_BITS);
}
/*
@@ -3239,7 +3239,7 @@ l1:
all_visible_cleared = true;
PageClearAllVisible(page);
visibilitymap_clear(relation, BufferGetBlockNumber(buffer),
- vmbuffer);
+ vmbuffer, VISIBILITYMAP_VALID_BITS);
}
/* store transaction information of xact deleting the tuple */
@@ -3925,6 +3925,7 @@ l2:
TransactionId xmax_lock_old_tuple;
uint16 infomask_lock_old_tuple,
infomask2_lock_old_tuple;
+ bool cleared_all_frozen = false;
/*
* To prevent concurrent sessions from updating the tuple, we have to
@@ -3968,6 +3969,17 @@ l2:
/* temporarily make it look not-updated, but locked */
oldtup.t_data->t_ctid = oldtup.t_self;
+ /*
+ * Clear all-frozen bit on visibility map if needed. We could
+ * immediately reset ALL_VISIBLE, but given that the WAL logging
+ * overhead would be unchanged, that doesn't seem necessarily
+ * worthwhile.
+ */
+ if (PageIsAllVisible(BufferGetPage(buffer)) &&
+ visibilitymap_clear(relation, block, vmbuffer,
+ VISIBILITYMAP_ALL_FROZEN))
+ cleared_all_frozen = true;
+
MarkBufferDirty(buffer);
if (RelationNeedsWAL(relation))
@@ -3982,6 +3994,8 @@ l2:
xlrec.locking_xid = xmax_lock_old_tuple;
xlrec.infobits_set = compute_infobits(oldtup.t_data->t_infomask,
oldtup.t_data->t_infomask2);
+ xlrec.flags =
+ cleared_all_frozen ? XLH_LOCK_ALL_FROZEN_CLEARED : 0;
XLogRegisterData((char *) &xlrec, SizeOfHeapLock);
recptr = XLogInsert(RM_HEAP_ID, XLOG_HEAP_LOCK);
PageSetLSN(page, recptr);
@@ -4159,20 +4173,20 @@ l2:
/* record address of new tuple in t_ctid of old one */
oldtup.t_data->t_ctid = heaptup->t_self;
- /* clear PD_ALL_VISIBLE flags */
+ /* clear PD_ALL_VISIBLE flags, reset all visibilitymap bits */
if (PageIsAllVisible(BufferGetPage(buffer)))
{
all_visible_cleared = true;
PageClearAllVisible(BufferGetPage(buffer));
visibilitymap_clear(relation, BufferGetBlockNumber(buffer),
- vmbuffer);
+ vmbuffer, VISIBILITYMAP_VALID_BITS);
}
if (newbuf != buffer && PageIsAllVisible(BufferGetPage(newbuf)))
{
all_visible_cleared_new = true;
PageClearAllVisible(BufferGetPage(newbuf));
visibilitymap_clear(relation, BufferGetBlockNumber(newbuf),
- vmbuffer_new);
+ vmbuffer_new, VISIBILITYMAP_VALID_BITS);
}
if (newbuf != buffer)
@@ -4556,6 +4570,8 @@ heap_lock_tuple(Relation relation, HeapTuple tuple,
ItemPointer tid = &(tuple->t_self);
ItemId lp;
Page page;
+ Buffer vmbuffer = InvalidBuffer;
+ BlockNumber block;
TransactionId xid,
xmax;
uint16 old_infomask,
@@ -4563,8 +4579,19 @@ heap_lock_tuple(Relation relation, HeapTuple tuple,
new_infomask2;
bool first_time = true;
bool have_tuple_lock = false;
+ bool cleared_all_frozen = false;
*buffer = ReadBuffer(relation, ItemPointerGetBlockNumber(tid));
+ block = ItemPointerGetBlockNumber(tid);
+
+ /*
+ * Before locking the buffer, pin the visibility map page if it may be
+ * necessary. XXX: It might be possible for this to change after acquiring
+ * the lock below. We don't yet deal with that case.
+ */
+ if (PageIsAllVisible(BufferGetPage(*buffer)))
+ visibilitymap_pin(relation, block, &vmbuffer);
+
LockBuffer(*buffer, BUFFER_LOCK_EXCLUSIVE);
page = BufferGetPage(*buffer);
@@ -4580,15 +4607,14 @@ l3:
if (result == HeapTupleInvisible)
{
- LockBuffer(*buffer, BUFFER_LOCK_UNLOCK);
-
/*
* This is possible, but only when locking a tuple for ON CONFLICT
* UPDATE. We return this value here rather than throwing an error in
* order to give that case the opportunity to throw a more specific
* error.
*/
- return HeapTupleInvisible;
+ result = HeapTupleInvisible;
+ goto out_locked;
}
else if (result == HeapTupleBeingUpdated || result == HeapTupleUpdated)
{
@@ -4646,7 +4672,8 @@ l3:
if (TUPLOCK_from_mxstatus(members[i].status) >= mode)
{
pfree(members);
- return HeapTupleMayBeUpdated;
+ result = HeapTupleMayBeUpdated;
+ goto out_unlocked;
}
}
@@ -4661,21 +4688,30 @@ l3:
Assert(HEAP_XMAX_IS_KEYSHR_LOCKED(infomask) ||
HEAP_XMAX_IS_SHR_LOCKED(infomask) ||
HEAP_XMAX_IS_EXCL_LOCKED(infomask));
- return HeapTupleMayBeUpdated;
- break;
+ result = HeapTupleMayBeUpdated;
+ goto out_unlocked;
case LockTupleShare:
if (HEAP_XMAX_IS_SHR_LOCKED(infomask) ||
HEAP_XMAX_IS_EXCL_LOCKED(infomask))
- return HeapTupleMayBeUpdated;
+ {
+ result = HeapTupleMayBeUpdated;
+ goto out_unlocked;
+ }
break;
case LockTupleNoKeyExclusive:
if (HEAP_XMAX_IS_EXCL_LOCKED(infomask))
- return HeapTupleMayBeUpdated;
+ {
+ result = HeapTupleMayBeUpdated;
+ goto out_unlocked;
+ }
break;
case LockTupleExclusive:
if (HEAP_XMAX_IS_EXCL_LOCKED(infomask) &&
infomask2 & HEAP_KEYS_UPDATED)
- return HeapTupleMayBeUpdated;
+ {
+ result = HeapTupleMayBeUpdated;
+ goto out_unlocked;
+ }
break;
}
}
@@ -5036,10 +5072,7 @@ failed:
hufd->cmax = HeapTupleHeaderGetCmax(tuple->t_data);
else
hufd->cmax = InvalidCommandId;
- LockBuffer(*buffer, BUFFER_LOCK_UNLOCK);
- if (have_tuple_lock)
- UnlockTupleTuplock(relation, tid, mode);
- return result;
+ goto out_locked;
}
xmax = HeapTupleHeaderGetRawXmax(tuple->t_data);
@@ -5094,6 +5127,13 @@ failed:
if (HEAP_XMAX_IS_LOCKED_ONLY(new_infomask))
tuple->t_data->t_ctid = *tid;
+ /* Clear only the all-frozen bit on visibility map if needed */
+ if (PageIsAllVisible(page) &&
+ visibilitymap_clear(relation, block, vmbuffer,
+ VISIBILITYMAP_ALL_FROZEN))
+ cleared_all_frozen = true;
+
+
MarkBufferDirty(*buffer);
/*
@@ -5120,6 +5160,7 @@ failed:
xlrec.locking_xid = xid;
xlrec.infobits_set = compute_infobits(new_infomask,
tuple->t_data->t_infomask2);
+ xlrec.flags = cleared_all_frozen ? XLH_LOCK_ALL_FROZEN_CLEARED : 0;
XLogRegisterData((char *) &xlrec, SizeOfHeapLock);
/* we don't decode row locks atm, so no need to log the origin */
@@ -5131,8 +5172,15 @@ failed:
END_CRIT_SECTION();
+ result = HeapTupleMayBeUpdated;
+
+out_locked:
LockBuffer(*buffer, BUFFER_LOCK_UNLOCK);
+out_unlocked:
+ if (BufferIsValid(vmbuffer))
+ ReleaseBuffer(vmbuffer);
+
/*
* Don't update the visibility map here. Locking a tuple doesn't change
* visibility info.
@@ -5145,7 +5193,7 @@ failed:
if (have_tuple_lock)
UnlockTupleTuplock(relation, tid, mode);
- return HeapTupleMayBeUpdated;
+ return result;
}
/*
@@ -5577,6 +5625,7 @@ static HTSU_Result
heap_lock_updated_tuple_rec(Relation rel, ItemPointer tid, TransactionId xid,
LockTupleMode mode)
{
+ HTSU_Result result;
ItemPointerData tupid;
HeapTupleData mytup;
Buffer buf;
@@ -5587,6 +5636,9 @@ heap_lock_updated_tuple_rec(Relation rel, ItemPointer tid, TransactionId xid,
TransactionId xmax,
new_xmax;
TransactionId priorXmax = InvalidTransactionId;
+ bool cleared_all_frozen = false;
+ Buffer vmbuffer = InvalidBuffer;
+ BlockNumber block;
ItemPointerCopy(tid, &tupid);
@@ -5594,6 +5646,7 @@ heap_lock_updated_tuple_rec(Relation rel, ItemPointer tid, TransactionId xid,
{
new_infomask = 0;
new_xmax = InvalidTransactionId;
+ block = ItemPointerGetBlockNumber(&tupid);
ItemPointerCopy(&tupid, &(mytup.t_self));
if (!heap_fetch(rel, SnapshotAny, &mytup, &buf, false, NULL))
@@ -5610,6 +5663,17 @@ heap_lock_updated_tuple_rec(Relation rel, ItemPointer tid, TransactionId xid,
l4:
CHECK_FOR_INTERRUPTS();
+
+ /*
+ * Before locking the buffer, pin the visibility map page if it may be
+ * necessary. XXX: It might be possible for this to change after
+ * acquiring the lock below. We don't yet deal with that case.
+ */
+ if (PageIsAllVisible(BufferGetPage(buf)))
+ visibilitymap_pin(rel, block, &vmbuffer);
+ else
+ vmbuffer = InvalidBuffer;
+
LockBuffer(buf, BUFFER_LOCK_EXCLUSIVE);
/*
@@ -5620,8 +5684,8 @@ l4:
!TransactionIdEquals(HeapTupleHeaderGetXmin(mytup.t_data),
priorXmax))
{
- UnlockReleaseBuffer(buf);
- return HeapTupleMayBeUpdated;
+ result = HeapTupleMayBeUpdated;
+ goto out_locked;
}
old_infomask = mytup.t_data->t_infomask;
@@ -5661,11 +5725,9 @@ l4:
HEAP_XMAX_IS_LOCKED_ONLY(old_infomask));
for (i = 0; i < nmembers; i++)
{
- HTSU_Result res;
-
- res = test_lockmode_for_conflict(members[i].status,
- members[i].xid,
- mode, &needwait);
+ result = test_lockmode_for_conflict(members[i].status,
+ members[i].xid,
+ mode, &needwait);
if (needwait)
{
@@ -5676,11 +5738,10 @@ l4:
pfree(members);
goto l4;
}
- if (res != HeapTupleMayBeUpdated)
+ if (result != HeapTupleMayBeUpdated)
{
- UnlockReleaseBuffer(buf);
pfree(members);
- return res;
+ goto out_locked;
}
}
if (members)
@@ -5688,7 +5749,6 @@ l4:
}
else
{
- HTSU_Result res;
MultiXactStatus status;
/*
@@ -5727,8 +5787,8 @@ l4:
status = MultiXactStatusNoKeyUpdate;
}
- res = test_lockmode_for_conflict(status, rawxmax, mode,
- &needwait);
+ result = test_lockmode_for_conflict(status, rawxmax, mode,
+ &needwait);
if (needwait)
{
LockBuffer(buf, BUFFER_LOCK_UNLOCK);
@@ -5736,10 +5796,9 @@ l4:
XLTW_LockUpdated);
goto l4;
}
- if (res != HeapTupleMayBeUpdated)
+ if (result != HeapTupleMayBeUpdated)
{
- UnlockReleaseBuffer(buf);
- return res;
+ goto out_locked;
}
}
}
@@ -5749,6 +5808,11 @@ l4:
xid, mode, false,
&new_xmax, &new_infomask, &new_infomask2);
+ if (PageIsAllVisible(BufferGetPage(buf)) &&
+ visibilitymap_clear(rel, block, vmbuffer,
+ VISIBILITYMAP_ALL_FROZEN))
+ cleared_all_frozen = true;
+
START_CRIT_SECTION();
/* ... and set them */
@@ -5773,6 +5837,8 @@ l4:
xlrec.offnum = ItemPointerGetOffsetNumber(&mytup.t_self);
xlrec.xmax = new_xmax;
xlrec.infobits_set = compute_infobits(new_infomask, new_infomask2);
+ xlrec.flags =
+ cleared_all_frozen ? XLH_LOCK_ALL_FROZEN_CLEARED : 0;
XLogRegisterData((char *) &xlrec, SizeOfHeapLockUpdated);
@@ -5788,15 +5854,28 @@ l4:
ItemPointerEquals(&mytup.t_self, &mytup.t_data->t_ctid) ||
HeapTupleHeaderIsOnlyLocked(mytup.t_data))
{
- UnlockReleaseBuffer(buf);
- return HeapTupleMayBeUpdated;
+ result = HeapTupleMayBeUpdated;
+ goto out_locked;
}
/* tail recursion */
priorXmax = HeapTupleHeaderGetUpdateXid(mytup.t_data);
ItemPointerCopy(&(mytup.t_data->t_ctid), &tupid);
UnlockReleaseBuffer(buf);
+ if (vmbuffer != InvalidBuffer)
+ ReleaseBuffer(vmbuffer);
}
+
+ result = HeapTupleMayBeUpdated;
+
+out_locked:
+ UnlockReleaseBuffer(buf);
+
+ if (vmbuffer != InvalidBuffer)
+ ReleaseBuffer(vmbuffer);
+
+ return result;
+
}
/*
@@ -8107,7 +8186,7 @@ heap_xlog_delete(XLogReaderState *record)
Buffer vmbuffer = InvalidBuffer;
visibilitymap_pin(reln, blkno, &vmbuffer);
- visibilitymap_clear(reln, blkno, vmbuffer);
+ visibilitymap_clear(reln, blkno, vmbuffer, VISIBILITYMAP_VALID_BITS);
ReleaseBuffer(vmbuffer);
FreeFakeRelcacheEntry(reln);
}
@@ -8185,7 +8264,7 @@ heap_xlog_insert(XLogReaderState *record)
Buffer vmbuffer = InvalidBuffer;
visibilitymap_pin(reln, blkno, &vmbuffer);
- visibilitymap_clear(reln, blkno, vmbuffer);
+ visibilitymap_clear(reln, blkno, vmbuffer, VISIBILITYMAP_VALID_BITS);
ReleaseBuffer(vmbuffer);
FreeFakeRelcacheEntry(reln);
}
@@ -8305,7 +8384,7 @@ heap_xlog_multi_insert(XLogReaderState *record)
Buffer vmbuffer = InvalidBuffer;
visibilitymap_pin(reln, blkno, &vmbuffer);
- visibilitymap_clear(reln, blkno, vmbuffer);
+ visibilitymap_clear(reln, blkno, vmbuffer, VISIBILITYMAP_VALID_BITS);
ReleaseBuffer(vmbuffer);
FreeFakeRelcacheEntry(reln);
}
@@ -8460,7 +8539,7 @@ heap_xlog_update(XLogReaderState *record, bool hot_update)
Buffer vmbuffer = InvalidBuffer;
visibilitymap_pin(reln, oldblk, &vmbuffer);
- visibilitymap_clear(reln, oldblk, vmbuffer);
+ visibilitymap_clear(reln, oldblk, vmbuffer, VISIBILITYMAP_VALID_BITS);
ReleaseBuffer(vmbuffer);
FreeFakeRelcacheEntry(reln);
}
@@ -8544,7 +8623,7 @@ heap_xlog_update(XLogReaderState *record, bool hot_update)
Buffer vmbuffer = InvalidBuffer;
visibilitymap_pin(reln, newblk, &vmbuffer);
- visibilitymap_clear(reln, newblk, vmbuffer);
+ visibilitymap_clear(reln, newblk, vmbuffer, VISIBILITYMAP_VALID_BITS);
ReleaseBuffer(vmbuffer);
FreeFakeRelcacheEntry(reln);
}
@@ -8724,6 +8803,27 @@ heap_xlog_lock(XLogReaderState *record)
ItemId lp = NULL;
HeapTupleHeader htup;
+ /*
+ * The visibility map may need to be fixed even if the heap page is
+ * already up-to-date.
+ */
+ if (xlrec->flags & XLH_LOCK_ALL_FROZEN_CLEARED)
+ {
+ RelFileNode rnode;
+ Buffer vmbuffer = InvalidBuffer;
+ BlockNumber block;
+ Relation reln;
+
+ XLogRecGetBlockTag(record, 0, &rnode, NULL, &block);
+ reln = CreateFakeRelcacheEntry(rnode);
+
+ visibilitymap_pin(reln, block, &vmbuffer);
+ visibilitymap_clear(reln, block, vmbuffer, VISIBILITYMAP_ALL_FROZEN);
+
+ ReleaseBuffer(vmbuffer);
+ FreeFakeRelcacheEntry(reln);
+ }
+
if (XLogReadBufferForRedo(record, 0, &buffer) == BLK_NEEDS_REDO)
{
page = (Page) BufferGetPage(buffer);
@@ -8776,6 +8876,27 @@ heap_xlog_lock_updated(XLogReaderState *record)
xlrec = (xl_heap_lock_updated *) XLogRecGetData(record);
+ /*
+ * The visibility map may need to be fixed even if the heap page is
+ * already up-to-date.
+ */
+ if (xlrec->flags & XLH_LOCK_ALL_FROZEN_CLEARED)
+ {
+ RelFileNode rnode;
+ Buffer vmbuffer = InvalidBuffer;
+ BlockNumber block;
+ Relation reln;
+
+ XLogRecGetBlockTag(record, 0, &rnode, NULL, &block);
+ reln = CreateFakeRelcacheEntry(rnode);
+
+ visibilitymap_pin(reln, block, &vmbuffer);
+ visibilitymap_clear(reln, block, vmbuffer, VISIBILITYMAP_ALL_FROZEN);
+
+ ReleaseBuffer(vmbuffer);
+ FreeFakeRelcacheEntry(reln);
+ }
+
if (XLogReadBufferForRedo(record, 0, &buffer) == BLK_NEEDS_REDO)
{
page = BufferGetPage(buffer);
diff --git a/src/backend/access/heap/visibilitymap.c b/src/backend/access/heap/visibilitymap.c
index b472d31a03c..3ad4a9f5870 100644
--- a/src/backend/access/heap/visibilitymap.c
+++ b/src/backend/access/heap/visibilitymap.c
@@ -11,7 +11,7 @@
* src/backend/access/heap/visibilitymap.c
*
* INTERFACE ROUTINES
- * visibilitymap_clear - clear a bit in the visibility map
+ * visibilitymap_clear - clear bits for one page in the visibility map
* visibilitymap_pin - pin a map page for setting a bit
* visibilitymap_pin_ok - check whether correct map page is already pinned
* visibilitymap_set - set a bit in a previously pinned page
@@ -159,20 +159,23 @@ static void vm_extend(Relation rel, BlockNumber nvmblocks);
/*
- * visibilitymap_clear - clear all bits for one page in visibility map
+ * visibilitymap_clear - clear specified bits for one page in visibility map
*
* You must pass a buffer containing the correct map page to this function.
* Call visibilitymap_pin first to pin the right one. This function doesn't do
- * any I/O.
+ * any I/O. Returns true if any bits have been cleared and false otherwise.
*/
-void
-visibilitymap_clear(Relation rel, BlockNumber heapBlk, Buffer buf)
+bool
+visibilitymap_clear(Relation rel, BlockNumber heapBlk, Buffer buf, uint8 flags)
{
BlockNumber mapBlock = HEAPBLK_TO_MAPBLOCK(heapBlk);
int mapByte = HEAPBLK_TO_MAPBYTE(heapBlk);
int mapOffset = HEAPBLK_TO_OFFSET(heapBlk);
- uint8 mask = VISIBILITYMAP_VALID_BITS << mapOffset;
+ uint8 mask = flags << mapOffset;
char *map;
+ bool cleared = false;
+
+ Assert(flags & VISIBILITYMAP_VALID_BITS);
#ifdef TRACE_VISIBILITYMAP
elog(DEBUG1, "vm_clear %s %d", RelationGetRelationName(rel), heapBlk);
@@ -189,9 +192,12 @@ visibilitymap_clear(Relation rel, BlockNumber heapBlk, Buffer buf)
map[mapByte] &= ~mask;
MarkBufferDirty(buf);
+ cleared = true;
}
LockBuffer(buf, BUFFER_LOCK_UNLOCK);
+
+ return cleared;
}
/*
diff --git a/src/backend/access/rmgrdesc/heapdesc.c b/src/backend/access/rmgrdesc/heapdesc.c
index 2b31ea413c3..7c763b6b0ef 100644
--- a/src/backend/access/rmgrdesc/heapdesc.c
+++ b/src/backend/access/rmgrdesc/heapdesc.c
@@ -85,7 +85,8 @@ heap_desc(StringInfo buf, XLogReaderState *record)
{
xl_heap_lock *xlrec = (xl_heap_lock *) rec;
- appendStringInfo(buf, "off %u: xid %u ", xlrec->offnum, xlrec->locking_xid);
+ appendStringInfo(buf, "off %u: xid %u: flags %u ",
+ xlrec->offnum, xlrec->locking_xid, xlrec->flags);
out_infobits(buf, xlrec->infobits_set);
}
else if (info == XLOG_HEAP_INPLACE)
@@ -138,7 +139,8 @@ heap2_desc(StringInfo buf, XLogReaderState *record)
{
xl_heap_lock_updated *xlrec = (xl_heap_lock_updated *) rec;
- appendStringInfo(buf, "off %u: xmax %u ", xlrec->offnum, xlrec->xmax);
+ appendStringInfo(buf, "off %u: xmax %u: flags %u ",
+ xlrec->offnum, xlrec->xmax, xlrec->flags);
out_infobits(buf, xlrec->infobits_set);
}
else if (info == XLOG_HEAP2_NEW_CID)
diff --git a/src/backend/commands/vacuumlazy.c b/src/backend/commands/vacuumlazy.c
index 32b6fddc622..4075f4d1c92 100644
--- a/src/backend/commands/vacuumlazy.c
+++ b/src/backend/commands/vacuumlazy.c
@@ -1179,7 +1179,8 @@ lazy_scan_heap(Relation onerel, int options, LVRelStats *vacrelstats,
{
elog(WARNING, "page is not marked all-visible but visibility map bit is set in relation \"%s\" page %u",
relname, blkno);
- visibilitymap_clear(onerel, blkno, vmbuffer);
+ visibilitymap_clear(onerel, blkno, vmbuffer,
+ VISIBILITYMAP_VALID_BITS);
}
/*
@@ -1201,7 +1202,8 @@ lazy_scan_heap(Relation onerel, int options, LVRelStats *vacrelstats,
relname, blkno);
PageClearAllVisible(page);
MarkBufferDirty(buf);
- visibilitymap_clear(onerel, blkno, vmbuffer);
+ visibilitymap_clear(onerel, blkno, vmbuffer,
+ VISIBILITYMAP_VALID_BITS);
}
/*
diff --git a/src/include/access/heapam_xlog.h b/src/include/access/heapam_xlog.h
index a822d0b82dc..06a82426bb5 100644
--- a/src/include/access/heapam_xlog.h
+++ b/src/include/access/heapam_xlog.h
@@ -243,15 +243,19 @@ typedef struct xl_heap_cleanup_info
#define XLHL_XMAX_KEYSHR_LOCK 0x08
#define XLHL_KEYS_UPDATED 0x10
+/* flag bits for xl_heap_lock / xl_heap_lock_updated's flag field */
+#define XLH_LOCK_ALL_FROZEN_CLEARED 0x01
+
/* This is what we need to know about lock */
typedef struct xl_heap_lock
{
TransactionId locking_xid; /* might be a MultiXactId not xid */
OffsetNumber offnum; /* locked tuple's offset on page */
int8 infobits_set; /* infomask and infomask2 bits to set */
+ uint8 flags; /* XLH_LOCK_* flag bits */
} xl_heap_lock;
-#define SizeOfHeapLock (offsetof(xl_heap_lock, infobits_set) + sizeof(int8))
+#define SizeOfHeapLock (offsetof(xl_heap_lock, flags) + sizeof(int8))
/* This is what we need to know about locking an updated version of a row */
typedef struct xl_heap_lock_updated
@@ -259,9 +263,10 @@ typedef struct xl_heap_lock_updated
TransactionId xmax;
OffsetNumber offnum;
uint8 infobits_set;
+ uint8 flags;
} xl_heap_lock_updated;
-#define SizeOfHeapLockUpdated (offsetof(xl_heap_lock_updated, infobits_set) + sizeof(uint8))
+#define SizeOfHeapLockUpdated (offsetof(xl_heap_lock_updated, flags) + sizeof(uint8))
/* This is what we need to know about confirmation of speculative insertion */
typedef struct xl_heap_confirm
diff --git a/src/include/access/visibilitymap.h b/src/include/access/visibilitymap.h
index fca99ca318d..00bbd4c2d94 100644
--- a/src/include/access/visibilitymap.h
+++ b/src/include/access/visibilitymap.h
@@ -34,8 +34,8 @@
#define VM_ALL_FROZEN(r, b, v) \
((visibilitymap_get_status((r), (b), (v)) & VISIBILITYMAP_ALL_FROZEN) != 0)
-extern void visibilitymap_clear(Relation rel, BlockNumber heapBlk,
- Buffer vmbuf);
+extern bool visibilitymap_clear(Relation rel, BlockNumber heapBlk,
+ Buffer vmbuf, uint8 flags);
extern void visibilitymap_pin(Relation rel, BlockNumber heapBlk,
Buffer *vmbuf);
extern bool visibilitymap_pin_ok(BlockNumber heapBlk, Buffer vmbuf);
diff --git a/src/include/access/xlog_internal.h b/src/include/access/xlog_internal.h
index 2627519ba08..0a595ccc481 100644
--- a/src/include/access/xlog_internal.h
+++ b/src/include/access/xlog_internal.h
@@ -31,7 +31,7 @@
/*
* Each page of XLOG file has a header like this:
*/
-#define XLOG_PAGE_MAGIC 0xD092 /* can be used as WAL version indicator */
+#define XLOG_PAGE_MAGIC 0xD093 /* can be used as WAL version indicator */
typedef struct XLogPageHeaderData
{