Still more code review for single-page hash vacuuming.
Most seriously, fix use of incorrect block ID, per a report from Jeff Janes that it causes a crash and a diagnosis from Amit Kapila. Improve consistency between the hash and btree versions of this code by adding back a PANIC that btree has, and by registering data in the xlog record in the same way, per complaints from Jeff Janes and Amit Kapila. Tidy up some minor cosmetic points, per complaints from Amit Kapila. Patch by Ashutosh Sharma, reviewed by Amit Kapila, and tested by Jeff Janes. Discussion: http://postgr.es/m/CAMkU=1w-9Qe=Ff1o6bSaXpNO9wqpo7_9GL8_CVhw4BoVVHasqg@mail.gmail.com
This commit is contained in:
parent
1b02be21f2
commit
c4c51541e2
@ -957,8 +957,6 @@ hash_xlog_vacuum_get_latestRemovedXid(XLogReaderState *record)
|
|||||||
OffsetNumber hoffnum;
|
OffsetNumber hoffnum;
|
||||||
TransactionId latestRemovedXid = InvalidTransactionId;
|
TransactionId latestRemovedXid = InvalidTransactionId;
|
||||||
int i;
|
int i;
|
||||||
char *ptr;
|
|
||||||
Size len;
|
|
||||||
|
|
||||||
xlrec = (xl_hash_vacuum_one_page *) XLogRecGetData(record);
|
xlrec = (xl_hash_vacuum_one_page *) XLogRecGetData(record);
|
||||||
|
|
||||||
@ -976,13 +974,21 @@ hash_xlog_vacuum_get_latestRemovedXid(XLogReaderState *record)
|
|||||||
if (CountDBBackends(InvalidOid) == 0)
|
if (CountDBBackends(InvalidOid) == 0)
|
||||||
return latestRemovedXid;
|
return latestRemovedXid;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Check if WAL replay has reached a consistent database state. If not,
|
||||||
|
* we must PANIC. See the definition of btree_xlog_delete_get_latestRemovedXid
|
||||||
|
* for more details.
|
||||||
|
*/
|
||||||
|
if (!reachedConsistency)
|
||||||
|
elog(PANIC, "hash_xlog_vacuum_get_latestRemovedXid: cannot operate with inconsistent data");
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Get index page. If the DB is consistent, this should not fail, nor
|
* Get index page. If the DB is consistent, this should not fail, nor
|
||||||
* should any of the heap page fetches below. If one does, we return
|
* should any of the heap page fetches below. If one does, we return
|
||||||
* InvalidTransactionId to cancel all HS transactions. That's probably
|
* InvalidTransactionId to cancel all HS transactions. That's probably
|
||||||
* overkill, but it's safe, and certainly better than panicking here.
|
* overkill, but it's safe, and certainly better than panicking here.
|
||||||
*/
|
*/
|
||||||
XLogRecGetBlockTag(record, 1, &rnode, NULL, &blkno);
|
XLogRecGetBlockTag(record, 0, &rnode, NULL, &blkno);
|
||||||
ibuffer = XLogReadBufferExtended(rnode, MAIN_FORKNUM, blkno, RBM_NORMAL);
|
ibuffer = XLogReadBufferExtended(rnode, MAIN_FORKNUM, blkno, RBM_NORMAL);
|
||||||
|
|
||||||
if (!BufferIsValid(ibuffer))
|
if (!BufferIsValid(ibuffer))
|
||||||
@ -994,9 +1000,7 @@ hash_xlog_vacuum_get_latestRemovedXid(XLogReaderState *record)
|
|||||||
* Loop through the deleted index items to obtain the TransactionId from
|
* Loop through the deleted index items to obtain the TransactionId from
|
||||||
* the heap items they point to.
|
* the heap items they point to.
|
||||||
*/
|
*/
|
||||||
ptr = XLogRecGetBlockData(record, 1, &len);
|
unused = (OffsetNumber *) ((char *) xlrec + SizeOfHashVacuumOnePage);
|
||||||
|
|
||||||
unused = (OffsetNumber *) ptr;
|
|
||||||
|
|
||||||
for (i = 0; i < xlrec->ntuples; i++)
|
for (i = 0; i < xlrec->ntuples; i++)
|
||||||
{
|
{
|
||||||
@ -1121,23 +1125,15 @@ hash_xlog_vacuum_one_page(XLogReaderState *record)
|
|||||||
|
|
||||||
if (action == BLK_NEEDS_REDO)
|
if (action == BLK_NEEDS_REDO)
|
||||||
{
|
{
|
||||||
char *ptr;
|
|
||||||
Size len;
|
|
||||||
|
|
||||||
ptr = XLogRecGetBlockData(record, 0, &len);
|
|
||||||
|
|
||||||
page = (Page) BufferGetPage(buffer);
|
page = (Page) BufferGetPage(buffer);
|
||||||
|
|
||||||
if (len > 0)
|
if (XLogRecGetDataLen(record) > SizeOfHashVacuumOnePage)
|
||||||
{
|
{
|
||||||
OffsetNumber *unused;
|
OffsetNumber *unused;
|
||||||
OffsetNumber *unend;
|
|
||||||
|
|
||||||
unused = (OffsetNumber *) ptr;
|
unused = (OffsetNumber *) ((char *) xldata + SizeOfHashVacuumOnePage);
|
||||||
unend = (OffsetNumber *) ((char *) ptr + len);
|
|
||||||
|
|
||||||
if ((unend - unused) > 0)
|
PageIndexMultiDelete(page, unused, xldata->ntuples);
|
||||||
PageIndexMultiDelete(page, unused, unend - unused);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -344,7 +344,6 @@ _hash_vacuum_one_page(Relation rel, Buffer metabuf, Buffer buf,
|
|||||||
Page page = BufferGetPage(buf);
|
Page page = BufferGetPage(buf);
|
||||||
HashPageOpaque pageopaque;
|
HashPageOpaque pageopaque;
|
||||||
HashMetaPage metap;
|
HashMetaPage metap;
|
||||||
double tuples_removed = 0;
|
|
||||||
|
|
||||||
/* Scan each tuple in page to see if it is marked as LP_DEAD */
|
/* Scan each tuple in page to see if it is marked as LP_DEAD */
|
||||||
maxoff = PageGetMaxOffsetNumber(page);
|
maxoff = PageGetMaxOffsetNumber(page);
|
||||||
@ -355,10 +354,7 @@ _hash_vacuum_one_page(Relation rel, Buffer metabuf, Buffer buf,
|
|||||||
ItemId itemId = PageGetItemId(page, offnum);
|
ItemId itemId = PageGetItemId(page, offnum);
|
||||||
|
|
||||||
if (ItemIdIsDead(itemId))
|
if (ItemIdIsDead(itemId))
|
||||||
{
|
|
||||||
deletable[ndeletable++] = offnum;
|
deletable[ndeletable++] = offnum;
|
||||||
tuples_removed += 1;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (ndeletable > 0)
|
if (ndeletable > 0)
|
||||||
@ -386,7 +382,7 @@ _hash_vacuum_one_page(Relation rel, Buffer metabuf, Buffer buf,
|
|||||||
pageopaque->hasho_flag &= ~LH_PAGE_HAS_DEAD_TUPLES;
|
pageopaque->hasho_flag &= ~LH_PAGE_HAS_DEAD_TUPLES;
|
||||||
|
|
||||||
metap = HashPageGetMeta(BufferGetPage(metabuf));
|
metap = HashPageGetMeta(BufferGetPage(metabuf));
|
||||||
metap->hashm_ntuples -= tuples_removed;
|
metap->hashm_ntuples -= ndeletable;
|
||||||
|
|
||||||
MarkBufferDirty(buf);
|
MarkBufferDirty(buf);
|
||||||
MarkBufferDirty(metabuf);
|
MarkBufferDirty(metabuf);
|
||||||
@ -398,13 +394,18 @@ _hash_vacuum_one_page(Relation rel, Buffer metabuf, Buffer buf,
|
|||||||
XLogRecPtr recptr;
|
XLogRecPtr recptr;
|
||||||
|
|
||||||
xlrec.hnode = hnode;
|
xlrec.hnode = hnode;
|
||||||
xlrec.ntuples = tuples_removed;
|
xlrec.ntuples = ndeletable;
|
||||||
|
|
||||||
XLogBeginInsert();
|
XLogBeginInsert();
|
||||||
|
XLogRegisterBuffer(0, buf, REGBUF_STANDARD);
|
||||||
XLogRegisterData((char *) &xlrec, SizeOfHashVacuumOnePage);
|
XLogRegisterData((char *) &xlrec, SizeOfHashVacuumOnePage);
|
||||||
|
|
||||||
XLogRegisterBuffer(0, buf, REGBUF_STANDARD);
|
/*
|
||||||
XLogRegisterBufData(0, (char *) deletable,
|
* We need the target-offsets array whether or not we store the whole
|
||||||
|
* buffer, to allow us to find the latestRemovedXid on a standby
|
||||||
|
* server.
|
||||||
|
*/
|
||||||
|
XLogRegisterData((char *) deletable,
|
||||||
ndeletable * sizeof(OffsetNumber));
|
ndeletable * sizeof(OffsetNumber));
|
||||||
|
|
||||||
XLogRegisterBuffer(1, metabuf, REGBUF_STANDARD);
|
XLogRegisterBuffer(1, metabuf, REGBUF_STANDARD);
|
||||||
|
@ -113,7 +113,7 @@ hash_desc(StringInfo buf, XLogReaderState *record)
|
|||||||
{
|
{
|
||||||
xl_hash_vacuum_one_page *xlrec = (xl_hash_vacuum_one_page *) rec;
|
xl_hash_vacuum_one_page *xlrec = (xl_hash_vacuum_one_page *) rec;
|
||||||
|
|
||||||
appendStringInfo(buf, "ntuples %g",
|
appendStringInfo(buf, "ntuples %d",
|
||||||
xlrec->ntuples);
|
xlrec->ntuples);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@ -265,11 +265,13 @@ typedef struct xl_hash_init_bitmap_page
|
|||||||
typedef struct xl_hash_vacuum_one_page
|
typedef struct xl_hash_vacuum_one_page
|
||||||
{
|
{
|
||||||
RelFileNode hnode;
|
RelFileNode hnode;
|
||||||
double ntuples;
|
int ntuples;
|
||||||
|
|
||||||
|
/* TARGET OFFSET NUMBERS FOLLOW AT THE END */
|
||||||
} xl_hash_vacuum_one_page;
|
} xl_hash_vacuum_one_page;
|
||||||
|
|
||||||
#define SizeOfHashVacuumOnePage \
|
#define SizeOfHashVacuumOnePage \
|
||||||
(offsetof(xl_hash_vacuum_one_page, ntuples) + sizeof(double))
|
(offsetof(xl_hash_vacuum_one_page, ntuples) + sizeof(int))
|
||||||
|
|
||||||
extern void hash_redo(XLogReaderState *record);
|
extern void hash_redo(XLogReaderState *record);
|
||||||
extern void hash_desc(StringInfo buf, XLogReaderState *record);
|
extern void hash_desc(StringInfo buf, XLogReaderState *record);
|
||||||
|
Loading…
x
Reference in New Issue
Block a user