fix pushstandby can't clean buffer when redo truncate wal

Signed-off-by: shipixian <shipixian_yewu@cmss.chinamobile.com>
This commit is contained in:
shipixian 2023-06-19 14:15:00 +08:00
parent 6e00046003
commit 7dc5fd0303
4 changed files with 94 additions and 31 deletions

View File

@ -22,6 +22,7 @@
#include "storage/smgr.h"
#include "utils/rel.h"
#include "utils/snapmgr.h"
#include "postmaster/bgwriter.h"
PG_MODULE_MAGIC;
@ -385,6 +386,7 @@ pg_truncate_visibility_map(PG_FUNCTION_ARGS)
Relation rel;
ForkNumber fork;
BlockNumber block;
XLogRecPtr lsn = InvalidXLogRecPtr;
rel = relation_open(relid, AccessExclusiveLock);
@ -394,13 +396,6 @@ pg_truncate_visibility_map(PG_FUNCTION_ARGS)
RelationOpenSmgr(rel);
rel->rd_smgr->smgr_cached_nblocks[VISIBILITYMAP_FORKNUM] = InvalidBlockNumber;
block = visibilitymap_prepare_truncate(rel, 0);
if (BlockNumberIsValid(block))
{
fork = VISIBILITYMAP_FORKNUM;
smgrtruncatelsn(rel->rd_smgr, &fork, 1, &block);
}
if (RelationNeedsWAL(rel))
{
xl_smgr_truncate xlrec;
@ -411,11 +406,36 @@ pg_truncate_visibility_map(PG_FUNCTION_ARGS)
XLogBeginInsert();
XLogRegisterData((char *) &xlrec, sizeof(xlrec));
lsn = XLogInsert(RM_SMGR_ID, XLOG_SMGR_TRUNCATE | XLR_SPECIAL_REL_UPDATE);
XLogFlush(lsn);
if (IsBootstrapProcessingMode() != true && InitdbSingle != true) {
RequestCheckpoint(CHECKPOINT_IMMEDIATE | CHECKPOINT_FORCE | CHECKPOINT_WAIT
| CHECKPOINT_FLUSH_ALL);
}
XLogInsert(RM_SMGR_ID, XLOG_SMGR_TRUNCATE | XLR_SPECIAL_REL_UPDATE);
}
block = visibilitymap_prepare_truncate(rel, 0);
if (BlockNumberIsValid(block))
{
fork = VISIBILITYMAP_FORKNUM;
/*
* Get rid of any buffers for the about-to-be-deleted blocks. bufmgr will
* just drop them without bothering to write the contents.
*/
DropRelFileNodeBuffers(rel->rd_smgr, &fork, 1, &block);
/*
* Send a shared-inval message to force other backends to close any smgr
* references they may have for this rel. This is useful because they
* might have open file pointers to segments that got removed, and/or
* smgr_targblock variables pointing past the new rel end. (The inval
* message will come back to our backend, too, causing a
* probably-unnecessary local smgr flush. But we don't expect that this
* is a performance-critical path.) As in the unlink code, we want to be
* sure the message is sent before we start changing things on-disk.
*/
CacheInvalidateSmgr(rel->rd_smgr->smgr_rnode);
smgrtruncatelsn(rel->rd_smgr, &fork, 1, &block, lsn);
}
/*

View File

@ -34,6 +34,8 @@
#include "utils/memutils.h"
#include "utils/rel.h"
#include "utils/guc.h"
#include "utils/inval.h"
#include "postmaster/bgwriter.h"
/* GUC variables */
int wal_skip_threshold = 2048; /* in kilobytes */
@ -283,6 +285,7 @@ RelationTruncate(Relation rel, BlockNumber nblocks)
ForkNumber forks[MAX_FORKNUM];
BlockNumber blocks[MAX_FORKNUM];
int nforks = 0;
bool disable_cancel_query = false;
/* Open it at the smgr level if not already done */
RelationOpenSmgr(rel);
@ -344,16 +347,20 @@ RelationTruncate(Relation rel, BlockNumber nblocks)
xl_smgr_truncate xlrec;
/*
* He3DB: Disable cancel query during writing truacte XLOG and truncating.
* If standby receive truncate log but master failed to trucate file,
* standby will crash when master write to these blocks which truncated in standby node.
*/
HOLD_INTERRUPTS();
disable_cancel_query = true;
xlrec.blkno = nblocks;
xlrec.rnode = rel->rd_node;
xlrec.flags = SMGR_TRUNCATE_ALL;
XLogBeginInsert();
XLogRegisterData((char *) &xlrec, sizeof(xlrec));
if (IsBootstrapProcessingMode() != true && InitdbSingle != true) {
RequestCheckpoint(CHECKPOINT_IMMEDIATE | CHECKPOINT_FORCE | CHECKPOINT_WAIT
| CHECKPOINT_FLUSH_ALL);
}
lsn = XLogInsert(RM_SMGR_ID,
XLOG_SMGR_TRUNCATE | XLR_SPECIAL_REL_UPDATE);
@ -366,10 +373,32 @@ RelationTruncate(Relation rel, BlockNumber nblocks)
*/
if (fsm || vm)
XLogFlush(lsn);
if (IsBootstrapProcessingMode() != true && InitdbSingle != true) {
RequestCheckpoint(CHECKPOINT_IMMEDIATE | CHECKPOINT_FORCE | CHECKPOINT_WAIT
| CHECKPOINT_FLUSH_ALL);
}
}
/* Do the real work to truncate relation forks */
if (IsBootstrapProcessingMode()!=true && InitdbSingle!=true) {
/*
* Get rid of any buffers for the about-to-be-deleted blocks. bufmgr will
* just drop them without bothering to write the contents.
*/
DropRelFileNodeBuffers(rel->rd_smgr, &forks, nforks, &blocks);
/*
* Send a shared-inval message to force other backends to close any smgr
* references they may have for this rel. This is useful because they
* might have open file pointers to segments that got removed, and/or
* smgr_targblock variables pointing past the new rel end. (The inval
* message will come back to our backend, too, causing a
* probably-unnecessary local smgr flush. But we don't expect that this
* is a performance-critical path.) As in the unlink code, we want to be
* sure the message is sent before we start changing things on-disk.
*/
CacheInvalidateSmgr(rel->rd_smgr->smgr_rnode);
smgrtruncatelsn(rel->rd_smgr, forks, nforks, blocks,lsn);
} else {
smgrtruncate(rel->rd_smgr, forks, nforks, blocks);
@ -383,6 +412,13 @@ RelationTruncate(Relation rel, BlockNumber nblocks)
*/
if (need_fsm_vacuum)
FreeSpaceMapVacuumRange(rel, nblocks, InvalidBlockNumber);
/* He3DB: Resume to enable cancel query */
if (disable_cancel_query)
{
RESUME_INTERRUPTS();
CHECK_FOR_INTERRUPTS();
}
}
/*
@ -1010,6 +1046,24 @@ smgr_redo(XLogReaderState *record)
}
}
/*
* Get rid of any buffers for the about-to-be-deleted blocks. bufmgr will
* just drop them without bothering to write the contents.
*/
DropRelFileNodeBuffers(reln, &forks, nforks, &blocks);
/*
* Send a shared-inval message to force other backends to close any smgr
* references they may have for this rel. This is useful because they
* might have open file pointers to segments that got removed, and/or
* smgr_targblock variables pointing past the new rel end. (The inval
* message will come back to our backend, too, causing a
* probably-unnecessary local smgr flush. But we don't expect that this
* is a performance-critical path.) As in the unlink code, we want to be
* sure the message is sent before we start changing things on-disk.
*/
CacheInvalidateSmgr(reln->smgr_rnode);
/* Do the real work to truncate relation forks */
if (nforks > 0 && (!EnableHotStandby || *isPromoteIsTriggered || !he3share))
smgrtruncatelsn(reln, forks, nforks, blocks, record->ReadRecPtr);

View File

@ -1122,7 +1122,8 @@ ReadBuffer_common(SMgrRelation smgr, char relpersistence, ForkNumber forkNum,
pageTag.rnode = smgr->smgr_rnode.node;
pageTag.forkNum = forkNum;
pageTag.blockNum = blockNum;
XLogRecPtr pageLsn = BufferGetLSN(bufHdr);
// XLogRecPtr pageLsn = BufferGetLSN(bufHdr);
XLogRecPtr pageLsn = Max(GetXLogPushToDisk(), BufferGetLSN(bufHdr));
head = GetLogIndexByPage(&pageTag,pageLsn,replayLsn);
if ((EnableHotStandby == true && *isPromoteIsTriggered == false) && push_standby == false) {
if (head->next != NULL) {
@ -1153,7 +1154,8 @@ ReadBuffer_common(SMgrRelation smgr, char relpersistence, ForkNumber forkNum,
pageTag.rnode = smgr->smgr_rnode.node;
pageTag.forkNum = forkNum;
pageTag.blockNum = blockNum;
XLogRecPtr pageLsn = BufferGetLSN(bufHdr);
// XLogRecPtr pageLsn = BufferGetLSN(bufHdr);
XLogRecPtr pageLsn = Max(GetXLogPushToDisk(), BufferGetLSN(bufHdr));
head = GetLogIndexByPage(&pageTag,pageLsn,replayLsn);
if (head->next!=NULL) {
LsnNode* next = head->next;

View File

@ -772,23 +772,7 @@ smgrtruncatelsn(SMgrRelation reln, ForkNumber *forknum, int nforks, BlockNumber
int i;
PageKey pk;
OriginDPageKey odpk;
/*
* Get rid of any buffers for the about-to-be-deleted blocks. bufmgr will
* just drop them without bothering to write the contents.
*/
DropRelFileNodeBuffers(reln, forknum, nforks, nblocks);
/*
* Send a shared-inval message to force other backends to close any smgr
* references they may have for this rel. This is useful because they
* might have open file pointers to segments that got removed, and/or
* smgr_targblock variables pointing past the new rel end. (The inval
* message will come back to our backend, too, causing a
* probably-unnecessary local smgr flush. But we don't expect that this
* is a performance-critical path.) As in the unlink code, we want to be
* sure the message is sent before we start changing things on-disk.
*/
CacheInvalidateSmgr(reln->smgr_rnode);
//push to truncate
bool flag = false;
/* Do the truncation */
@ -801,6 +785,9 @@ smgrtruncatelsn(SMgrRelation reln, ForkNumber *forknum, int nforks, BlockNumber
XLogRecPtr minApplyLsn;
do {
sleep(1);
if (!EnableHotStandby || *isPromoteIsTriggered)
minApplyLsn = QueryPushChkpointLsn();
else
minApplyLsn = He3DBQueryMinLsnFromAllStanby();
elog(LOG,"====pushlsn=%lx==lsn==%lx==\n",minApplyLsn,lsn);
CHECK_FOR_INTERRUPTS();