Location via proxy:   [ UP ]  
[Report a bug]   [Manage cookies]                
Skip to content

Commit a892234

Browse files
committed
Change the format of the VM fork to add a second bit per page.
The new bit indicates whether every tuple on the page is already frozen. It is cleared only when the all-visible bit is cleared, and it can be set only when we vacuum a page and find that every tuple on that page is both visible to every transaction and in no need of any future vacuuming. A future commit will use this new bit to optimize away full-table scans that would otherwise be triggered by XID wraparound considerations. A page which is merely all-visible must still be scanned in that case, but a page which is all-frozen need not be. This commit does not attempt that optimization, although that optimization is the goal here. It seems better to get the basic infrastructure in place first. Per discussion, it's very desirable for pg_upgrade to automatically migrate existing VM forks from the old format to the new format. That, too, will be handled in a follow-on patch. Masahiko Sawada, reviewed by Kyotaro Horiguchi, Fujii Masao, Amit Kapila, Simon Riggs, Andres Freund, and others, and substantially revised by me.
1 parent 68c521e commit a892234

File tree

14 files changed

+309
-126
lines changed

14 files changed

+309
-126
lines changed

contrib/pgstattuple/pgstatapprox.c

+1-1
Original file line numberDiff line numberDiff line change
@@ -87,7 +87,7 @@ statapprox_heap(Relation rel, output_type *stat)
8787
* If the page has only visible tuples, then we can find out the free
8888
* space from the FSM and move on.
8989
*/
90-
if (visibilitymap_test(rel, blkno, &vmbuffer))
90+
if (VM_ALL_VISIBLE(rel, blkno, &vmbuffer))
9191
{
9292
freespace = GetRecordedFreeSpace(rel, blkno);
9393
stat->tuple_len += BLCKSZ - freespace;

doc/src/sgml/storage.sgml

+6-4
Original file line numberDiff line numberDiff line change
@@ -623,7 +623,8 @@ can be used to examine the information stored in free space maps.
623623
<para>
624624
Each heap relation has a Visibility Map
625625
(VM) to keep track of which pages contain only tuples that are known to be
626-
visible to all active transactions. It's stored
626+
visible to all active transactions; it also keeps track of which pages contain
627+
only unfrozen tuples. It's stored
627628
alongside the main relation data in a separate relation fork, named after the
628629
filenode number of the relation, plus a <literal>_vm</> suffix. For example,
629630
if the filenode of a relation is 12345, the VM is stored in a file called
@@ -632,11 +633,12 @@ Note that indexes do not have VMs.
632633
</para>
633634

634635
<para>
635-
The visibility map simply stores one bit per heap page. A set bit means
636-
that all tuples on the page are known to be visible to all transactions.
637-
This means that the page does not contain any tuples that need to be vacuumed.
636+
The visibility map stores two bits per heap page. The first bit, if set,
637+
indicates that the page is all-visible, or in other words that the page does
638+
not contain any tuples that need to be vacuumed.
638639
This information can also be used by <firstterm>index-only scans</> to answer
639640
queries using only the index tuple.
641+
The second bit, if set, means that all tuples on the page have been frozen.
640642
</para>
641643

642644
<para>

src/backend/access/heap/heapam.c

+58-3
Original file line numberDiff line numberDiff line change
@@ -6951,6 +6951,55 @@ ConditionalMultiXactIdWait(MultiXactId multi, MultiXactStatus status,
69516951
rel, NULL, XLTW_None, remaining);
69526952
}
69536953

6954+
/*
6955+
* heap_tuple_needs_eventual_freeze
6956+
*
6957+
* Check to see whether any of the XID fields of a tuple (xmin, xmax, xvac)
6958+
* will eventually require freezing. Similar to heap_tuple_needs_freeze,
6959+
* but there's no cutoff, since we're trying to figure out whether freezing
6960+
* will ever be needed, not whether it's needed now.
6961+
*/
6962+
bool
6963+
heap_tuple_needs_eventual_freeze(HeapTupleHeader tuple)
6964+
{
6965+
TransactionId xid;
6966+
6967+
/*
6968+
* If xmin is a normal transaction ID, this tuple is definitely not
6969+
* frozen.
6970+
*/
6971+
xid = HeapTupleHeaderGetXmin(tuple);
6972+
if (TransactionIdIsNormal(xid))
6973+
return true;
6974+
6975+
/*
6976+
* If xmax is a valid xact or multixact, this tuple is also not frozen.
6977+
*/
6978+
if (tuple->t_infomask & HEAP_XMAX_IS_MULTI)
6979+
{
6980+
MultiXactId multi;
6981+
6982+
multi = HeapTupleHeaderGetRawXmax(tuple);
6983+
if (MultiXactIdIsValid(multi))
6984+
return true;
6985+
}
6986+
else
6987+
{
6988+
xid = HeapTupleHeaderGetRawXmax(tuple);
6989+
if (TransactionIdIsNormal(xid))
6990+
return true;
6991+
}
6992+
6993+
if (tuple->t_infomask & HEAP_MOVED)
6994+
{
6995+
xid = HeapTupleHeaderGetXvac(tuple);
6996+
if (TransactionIdIsNormal(xid))
6997+
return true;
6998+
}
6999+
7000+
return false;
7001+
}
7002+
69547003
/*
69557004
* heap_tuple_needs_freeze
69567005
*
@@ -7205,7 +7254,7 @@ log_heap_freeze(Relation reln, Buffer buffer, TransactionId cutoff_xid,
72057254
*/
72067255
XLogRecPtr
72077256
log_heap_visible(RelFileNode rnode, Buffer heap_buffer, Buffer vm_buffer,
7208-
TransactionId cutoff_xid)
7257+
TransactionId cutoff_xid, uint8 vmflags)
72097258
{
72107259
xl_heap_visible xlrec;
72117260
XLogRecPtr recptr;
@@ -7215,6 +7264,7 @@ log_heap_visible(RelFileNode rnode, Buffer heap_buffer, Buffer vm_buffer,
72157264
Assert(BufferIsValid(vm_buffer));
72167265

72177266
xlrec.cutoff_xid = cutoff_xid;
7267+
xlrec.flags = vmflags;
72187268
XLogBeginInsert();
72197269
XLogRegisterData((char *) &xlrec, SizeOfHeapVisible);
72207270

@@ -7804,7 +7854,12 @@ heap_xlog_visible(XLogReaderState *record)
78047854
* the subsequent update won't be replayed to clear the flag.
78057855
*/
78067856
page = BufferGetPage(buffer);
7807-
PageSetAllVisible(page);
7857+
7858+
if (xlrec->flags & VISIBILITYMAP_ALL_VISIBLE)
7859+
PageSetAllVisible(page);
7860+
if (xlrec->flags & VISIBILITYMAP_ALL_FROZEN)
7861+
PageSetAllFrozen(page);
7862+
78087863
MarkBufferDirty(buffer);
78097864
}
78107865
else if (action == BLK_RESTORED)
@@ -7856,7 +7911,7 @@ heap_xlog_visible(XLogReaderState *record)
78567911
*/
78577912
if (lsn > PageGetLSN(vmpage))
78587913
visibilitymap_set(reln, blkno, InvalidBuffer, lsn, vmbuffer,
7859-
xlrec->cutoff_xid);
7914+
xlrec->cutoff_xid, xlrec->flags);
78607915

78617916
ReleaseBuffer(vmbuffer);
78627917
FreeFakeRelcacheEntry(reln);

0 commit comments

Comments
 (0)