1
0
mirror of https://github.com/postgres/postgres.git synced 2025-07-21 16:02:15 +03:00

Improve handling of prune/no-prune decisions by storing a page's oldest

unpruned XMAX in its header.  At the cost of 4 bytes per page, this keeps us
from performing heap_page_prune when there's no chance of pruning anything.
Seems to be necessary per Heikki's preliminary performance testing.
This commit is contained in:
Tom Lane
2007-09-21 21:25:42 +00:00
parent 386a5d4268
commit cc59049daf
10 changed files with 92 additions and 59 deletions

View File

@ -1,4 +1,4 @@
$PostgreSQL: pgsql/src/backend/access/heap/README.HOT,v 1.1 2007/09/20 17:56:30 tgl Exp $
$PostgreSQL: pgsql/src/backend/access/heap/README.HOT,v 1.2 2007/09/21 21:25:42 tgl Exp $
Heap Only Tuples (HOT)
@ -233,8 +233,8 @@ subsequent index searches. However it is unclear that this gain is
large enough to accept any extra maintenance burden for.
The currently planned heuristic is to prune and defrag when first accessing
a page that potentially has prunable tuples (flagged by the PD_PRUNABLE
page hint bit) and that either has free space less than MAX(fillfactor
a page that potentially has prunable tuples (as flagged by the pd_prune_xid
page hint field) and that either has free space less than MAX(fillfactor
target free space, BLCKSZ/10) *or* has recently had an UPDATE fail to
find enough free space to store an updated tuple version. (These rules
are subject to change.)

View File

@ -8,7 +8,7 @@
*
*
* IDENTIFICATION
* $PostgreSQL: pgsql/src/backend/access/heap/heapam.c,v 1.241 2007/09/20 17:56:30 tgl Exp $
* $PostgreSQL: pgsql/src/backend/access/heap/heapam.c,v 1.242 2007/09/21 21:25:42 tgl Exp $
*
*
* INTERFACE ROUTINES
@ -2068,11 +2068,12 @@ l1:
/*
* If this transaction commits, the tuple will become DEAD sooner or
* later. Set hint bit that this page is a candidate for pruning. If
* the transaction finally aborts, the subsequent page pruning will be
* a no-op and the hint will be cleared.
* later. Set flag that this page is a candidate for pruning once our xid
* falls below the OldestXmin horizon. If the transaction finally aborts,
* the subsequent page pruning will be a no-op and the hint will be
* cleared.
*/
PageSetPrunable((Page) dp);
PageSetPrunable(dp, xid);
/* store transaction information of xact deleting the tuple */
tp.t_data->t_infomask &= ~(HEAP_XMAX_COMMITTED |
@ -2571,16 +2572,17 @@ l2:
/*
* If this transaction commits, the old tuple will become DEAD sooner or
* later. Set hint bit that this page is a candidate for pruning. If
* the transaction finally aborts, the subsequent page pruning will be
* a no-op and the hint will be cleared.
* later. Set flag that this page is a candidate for pruning once our xid
* falls below the OldestXmin horizon. If the transaction finally aborts,
* the subsequent page pruning will be a no-op and the hint will be
* cleared.
*
* XXX Should we set hint on newbuf as well? If the transaction
* aborts, there would be a prunable tuple in the newbuf; but for now
* we choose not to optimize for aborts. Note that heap_xlog_update
* must be kept in sync if this changes.
* must be kept in sync if this decision changes.
*/
PageSetPrunable(dp);
PageSetPrunable(dp, xid);
if (use_hot_update)
{
@ -4108,7 +4110,7 @@ heap_xlog_delete(XLogRecPtr lsn, XLogRecord *record)
HeapTupleHeaderSetCmax(htup, FirstCommandId, false);
/* Mark the page as a candidate for pruning */
PageSetPrunable(page);
PageSetPrunable(page, record->xl_xid);
/* Make sure there is no forward chain link in t_ctid */
htup->t_ctid = xlrec->target.tid;
@ -4284,7 +4286,7 @@ heap_xlog_update(XLogRecPtr lsn, XLogRecord *record, bool move, bool hot_update)
}
/* Mark the page as a candidate for pruning */
PageSetPrunable(page);
PageSetPrunable(page, record->xl_xid);
/*
* this test is ugly, but necessary to avoid thinking that insert change

View File

@ -8,7 +8,7 @@
*
*
* IDENTIFICATION
* $PostgreSQL: pgsql/src/backend/access/heap/pruneheap.c,v 1.1 2007/09/20 17:56:30 tgl Exp $
* $PostgreSQL: pgsql/src/backend/access/heap/pruneheap.c,v 1.2 2007/09/21 21:25:42 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@ -63,9 +63,10 @@ heap_page_prune_opt(Relation relation, Buffer buffer, TransactionId OldestXmin)
/*
* Let's see if we really need pruning.
*
* Forget it if page is not hinted to contain something prunable
* Forget it if page is not hinted to contain something prunable that's
* older than OldestXmin.
*/
if (!PageIsPrunable(dp))
if (!PageIsPrunable(dp, OldestXmin))
return;
/*
@ -93,6 +94,8 @@ heap_page_prune_opt(Relation relation, Buffer buffer, TransactionId OldestXmin)
/*
* Now that we have buffer lock, get accurate information about the
* page's free space, and recheck the heuristic about whether to prune.
* (We needn't recheck PageIsPrunable, since no one else could have
* pruned while we hold pin.)
*/
if (PageIsFull(dp) || PageGetHeapFreeSpace((Page) dp) < minfree)
{
@ -147,7 +150,7 @@ heap_page_prune(Relation relation, Buffer buffer, TransactionId OldestXmin,
START_CRIT_SECTION();
/*
* Mark the page as clear of prunable tuples. If we find a tuple which
* Mark the page as clear of prunable tuples. If we find a tuple which
* may soon become prunable, we shall set the hint again. Also clear
* the "page is full" flag, since there's no point in repeating the
* prune/defrag process until something else happens to the page.
@ -203,6 +206,14 @@ heap_page_prune(Relation relation, Buffer buffer, TransactionId OldestXmin,
PageSetLSN(BufferGetPage(buffer), recptr);
}
}
else
{
/*
* If we didn't prune anything, we have nonetheless updated the
* pd_prune_xid field; treat this as a non-WAL-logged hint.
*/
SetBufferCommitInfoNeedsSave(buffer);
}
END_CRIT_SECTION();
@ -392,18 +403,18 @@ heap_prune_chain(Relation relation, Buffer buffer, OffsetNumber rootoffnum,
case HEAPTUPLE_RECENTLY_DEAD:
recent_dead = true;
/*
* This tuple may soon become DEAD. Re-set the hint bit so
* This tuple may soon become DEAD. Update the hint field so
* that the page is reconsidered for pruning in future.
*/
PageSetPrunable(dp);
PageSetPrunable(dp, HeapTupleHeaderGetXmax(htup));
break;
case HEAPTUPLE_DELETE_IN_PROGRESS:
/*
* This tuple may soon become DEAD. Re-set the hint bit so
* This tuple may soon become DEAD. Update the hint field so
* that the page is reconsidered for pruning in future.
*/
PageSetPrunable(dp);
PageSetPrunable(dp, HeapTupleHeaderGetXmax(htup));
break;
case HEAPTUPLE_LIVE: