Commit 953477ca authored by Robert Haas's avatar Robert Haas

Fixes for single-page hash index vacuum.

Clear LH_PAGE_HAS_DEAD_TUPLES during replay, similar to what gets done
for btree.  Update hashdesc.c for xl_hash_vacuum_one_page.

Oversights in commit 6977b8b7 spotted
by Amit Kapila.  Patch by Ashutosh Sharma.

Bump WAL version.  The original patch to make hash indexes write-ahead
logged probably should have done this, and the single page vacuuming
patch probably should have done it again, but better late than never.

Discussion: http://postgr.es/m/CAA4eK1Kd=mJ9xreovcsh0qMiAj-QqCphHVQ_Lfau1DR9oVjASQ@mail.gmail.com
parent bc18126a
...@@ -790,6 +790,7 @@ hashbucketcleanup(Relation rel, Bucket cur_bucket, Buffer bucket_buf, ...@@ -790,6 +790,7 @@ hashbucketcleanup(Relation rel, Bucket cur_bucket, Buffer bucket_buf,
OffsetNumber deletable[MaxOffsetNumber]; OffsetNumber deletable[MaxOffsetNumber];
int ndeletable = 0; int ndeletable = 0;
bool retain_pin = false; bool retain_pin = false;
bool clear_dead_marking = false;
vacuum_delay_point(); vacuum_delay_point();
...@@ -877,11 +878,14 @@ hashbucketcleanup(Relation rel, Bucket cur_bucket, Buffer bucket_buf, ...@@ -877,11 +878,14 @@ hashbucketcleanup(Relation rel, Bucket cur_bucket, Buffer bucket_buf,
/* /*
* Let us mark the page as clean if vacuum removes the DEAD tuples * Let us mark the page as clean if vacuum removes the DEAD tuples
* from an index page. We do this by clearing LH_PAGE_HAS_DEAD_TUPLES * from an index page. We do this by clearing LH_PAGE_HAS_DEAD_TUPLES
* flag. Clearing this flag is just a hint; replay won't redo this. * flag.
*/ */
if (tuples_removed && *tuples_removed > 0 && if (tuples_removed && *tuples_removed > 0 &&
opaque->hasho_flag & LH_PAGE_HAS_DEAD_TUPLES) opaque->hasho_flag & LH_PAGE_HAS_DEAD_TUPLES)
{
opaque->hasho_flag &= ~LH_PAGE_HAS_DEAD_TUPLES; opaque->hasho_flag &= ~LH_PAGE_HAS_DEAD_TUPLES;
clear_dead_marking = true;
}
MarkBufferDirty(buf); MarkBufferDirty(buf);
...@@ -891,6 +895,7 @@ hashbucketcleanup(Relation rel, Bucket cur_bucket, Buffer bucket_buf, ...@@ -891,6 +895,7 @@ hashbucketcleanup(Relation rel, Bucket cur_bucket, Buffer bucket_buf,
xl_hash_delete xlrec; xl_hash_delete xlrec;
XLogRecPtr recptr; XLogRecPtr recptr;
xlrec.clear_dead_marking = clear_dead_marking;
xlrec.is_primary_bucket_page = (buf == bucket_buf) ? true : false; xlrec.is_primary_bucket_page = (buf == bucket_buf) ? true : false;
XLogBeginInsert(); XLogBeginInsert();
......
...@@ -859,6 +859,19 @@ hash_xlog_delete(XLogReaderState *record) ...@@ -859,6 +859,19 @@ hash_xlog_delete(XLogReaderState *record)
PageIndexMultiDelete(page, unused, unend - unused); PageIndexMultiDelete(page, unused, unend - unused);
} }
/*
* Mark the page as not containing any LP_DEAD items only if
* clear_dead_marking flag is set to true. See comments in
* hashbucketcleanup() for details.
*/
if (xldata->clear_dead_marking)
{
HashPageOpaque pageopaque;
pageopaque = (HashPageOpaque) PageGetSpecialPointer(page);
pageopaque->hasho_flag &= ~LH_PAGE_HAS_DEAD_TUPLES;
}
PageSetLSN(page, lsn); PageSetLSN(page, lsn);
MarkBufferDirty(deletebuf); MarkBufferDirty(deletebuf);
} }
...@@ -1078,6 +1091,7 @@ hash_xlog_vacuum_one_page(XLogReaderState *record) ...@@ -1078,6 +1091,7 @@ hash_xlog_vacuum_one_page(XLogReaderState *record)
Buffer metabuf; Buffer metabuf;
Page page; Page page;
XLogRedoAction action; XLogRedoAction action;
HashPageOpaque pageopaque;
xldata = (xl_hash_vacuum_one_page *) XLogRecGetData(record); xldata = (xl_hash_vacuum_one_page *) XLogRecGetData(record);
...@@ -1126,6 +1140,13 @@ hash_xlog_vacuum_one_page(XLogReaderState *record) ...@@ -1126,6 +1140,13 @@ hash_xlog_vacuum_one_page(XLogReaderState *record)
PageIndexMultiDelete(page, unused, unend - unused); PageIndexMultiDelete(page, unused, unend - unused);
} }
/*
* Mark the page as not containing any LP_DEAD items. See comments
* in _hash_vacuum_one_page() for details.
*/
pageopaque = (HashPageOpaque) PageGetSpecialPointer(page);
pageopaque->hasho_flag &= ~LH_PAGE_HAS_DEAD_TUPLES;
PageSetLSN(page, lsn); PageSetLSN(page, lsn);
MarkBufferDirty(buffer); MarkBufferDirty(buffer);
} }
......
...@@ -374,6 +374,14 @@ _hash_vacuum_one_page(Relation rel, Buffer metabuf, Buffer buf, ...@@ -374,6 +374,14 @@ _hash_vacuum_one_page(Relation rel, Buffer metabuf, Buffer buf,
PageIndexMultiDelete(page, deletable, ndeletable); PageIndexMultiDelete(page, deletable, ndeletable);
/*
* Mark the page as not containing any LP_DEAD items. This is not
* certainly true (there might be some that have recently been marked,
* but weren't included in our target-item list), but it will almost
* always be true and it doesn't seem worth an additional page scan
* to check it. Remember that LH_PAGE_HAS_DEAD_TUPLES is only a hint
* anyway.
*/
pageopaque = (HashPageOpaque) PageGetSpecialPointer(page); pageopaque = (HashPageOpaque) PageGetSpecialPointer(page);
pageopaque->hasho_flag &= ~LH_PAGE_HAS_DEAD_TUPLES; pageopaque->hasho_flag &= ~LH_PAGE_HAS_DEAD_TUPLES;
......
...@@ -96,7 +96,8 @@ hash_desc(StringInfo buf, XLogReaderState *record) ...@@ -96,7 +96,8 @@ hash_desc(StringInfo buf, XLogReaderState *record)
{ {
xl_hash_delete *xlrec = (xl_hash_delete *) rec; xl_hash_delete *xlrec = (xl_hash_delete *) rec;
appendStringInfo(buf, "is_primary %c", appendStringInfo(buf, "clear_dead_marking %c, is_primary %c",
xlrec->clear_dead_marking ? 'T' : 'F',
xlrec->is_primary_bucket_page ? 'T' : 'F'); xlrec->is_primary_bucket_page ? 'T' : 'F');
break; break;
} }
...@@ -104,6 +105,14 @@ hash_desc(StringInfo buf, XLogReaderState *record) ...@@ -104,6 +105,14 @@ hash_desc(StringInfo buf, XLogReaderState *record)
{ {
xl_hash_update_meta_page *xlrec = (xl_hash_update_meta_page *) rec; xl_hash_update_meta_page *xlrec = (xl_hash_update_meta_page *) rec;
appendStringInfo(buf, "ntuples %g",
xlrec->ntuples);
break;
}
case XLOG_HASH_VACUUM_ONE_PAGE:
{
xl_hash_vacuum_one_page *xlrec = (xl_hash_vacuum_one_page *) rec;
appendStringInfo(buf, "ntuples %g", appendStringInfo(buf, "ntuples %g",
xlrec->ntuples); xlrec->ntuples);
break; break;
......
...@@ -197,6 +197,8 @@ typedef struct xl_hash_squeeze_page ...@@ -197,6 +197,8 @@ typedef struct xl_hash_squeeze_page
*/ */
typedef struct xl_hash_delete typedef struct xl_hash_delete
{ {
bool clear_dead_marking; /* TRUE if this operation clears
* LH_PAGE_HAS_DEAD_TUPLES flag */
bool is_primary_bucket_page; /* TRUE if the operation is for bool is_primary_bucket_page; /* TRUE if the operation is for
* primary bucket page */ * primary bucket page */
} xl_hash_delete; } xl_hash_delete;
......
...@@ -31,7 +31,7 @@ ...@@ -31,7 +31,7 @@
/* /*
* Each page of XLOG file has a header like this: * Each page of XLOG file has a header like this:
*/ */
#define XLOG_PAGE_MAGIC 0xD095 /* can be used as WAL version indicator */ #define XLOG_PAGE_MAGIC 0xD096 /* can be used as WAL version indicator */
typedef struct XLogPageHeaderData typedef struct XLogPageHeaderData
{ {
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment