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 6977b8b7f4dfb40896ff5e2175cad7fdbda862eb 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
This commit is contained in:
parent
bc18126a6b
commit
953477ca35
@ -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,
|
|||||||
/*
|
/*
|
||||||
* 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,
|
|||||||
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)
|
|||||||
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)
|
|||||||
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)
|
|||||||
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,
|
|||||||
|
|
||||||
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)
|
|||||||
{
|
{
|
||||||
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)
|
|||||||
{
|
{
|
||||||
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
|
|||||||
*/
|
*/
|
||||||
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 @@
|
|||||||
/*
|
/*
|
||||||
* 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
|
||||||
{
|
{
|
||||||
|
Loading…
x
Reference in New Issue
Block a user