!265 极致RTO bugfix

Merge pull request !265 from meimeidtt/master
This commit is contained in:
opengauss-bot 2020-09-28 17:29:31 +08:00 committed by Gitee
commit 1bc0eaedd6
43 changed files with 1861 additions and 1524 deletions

View File

@ -875,6 +875,7 @@ void smgr_redo_create(RelFileNode rnode, ForkNumber forkNum)
CFileNode cFileNode(rnode, ColForkNum2ColumnId(forkNum), MAIN_FORKNUM);
CUStorage* cuStorage = New(CurrentMemoryContext) CUStorage(cFileNode);
Assert(cuStorage);
TablespaceCreateDbspace(rnode.spcNode, rnode.dbNode, true);
cuStorage->CreateStorage(0, true);
DELETE_EX(cuStorage);
}

View File

@ -204,7 +204,7 @@ void TablespaceCreateDbspace(Oid spcNode, Oid dbNode, bool isRedo)
pfree_ext(parentdir);
/* Create database directory */
if (mkdir(dir, S_IRWXU) < 0)
if (mkdir(dir, S_IRWXU) < 0 && errno != EEXIST)
ereport(
ERROR, (errcode_for_file_access(), errmsg("could not create directory \"%s\": %m", dir)));
}
@ -2608,6 +2608,41 @@ void xlog_create_tblspc(Oid ts_id, char* ts_path, bool isRelativePath)
pfree_ext(location);
}
}
void xlog_drop_tblspc(Oid tsId)
{
/*
* If we issued a WAL record for a drop tablespace it implies that
* there were no files in it at all when the DROP was done. That means
* that no permanent objects can exist in it at this point.
*
* It is possible for standby users to be using this tablespace as a
* location for their temporary files, so if we fail to remove all
* files then do conflict processing and try again, if currently
* enabled.
*
* Other possible reasons for failure include bollixed file
* permissions on a standby server when they were okay on the primary,
* etc etc. There's not much we can do about that, so just remove what
* we can and press on.
*/
if (!destroy_tablespace_directories(tsId, true)) {
ResolveRecoveryConflictWithTablespace(tsId);
/*
* If we did recovery processing then hopefully the backends who
* wrote temp files should have cleaned up and exited by now. So
* retry before complaining. If we fail again, this is just a LOG
* condition, because it's not worth throwing an ERROR for (as
* that would crash the database and require manual intervention
* before we could get past this WAL record on restart).
*/
if (!destroy_tablespace_directories(tsId, true))
ereport(LOG,
(errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
errmsg("directories for tablespace %u could not be removed", tsId),
errhint("You can remove the directories manually if necessary.")));
}
}
/*
* TABLESPACE resource manager's routines

View File

@ -213,6 +213,7 @@ int bbox_handler_exit = 0;
extern int S3_init();
extern void TermMOT();
static const int RECOVERY_PARALLELISM_DEFAULT = 1;
/* flag to get logic cluster name for dn alarm */
static bool isNeedGetLCName = true;
@ -2447,19 +2448,36 @@ static void checkDataDir(void)
static void CheckExtremeRtoGUCConflicts(void)
{
const int minReceiverBufSize = 32 * 1024;
if ((g_instance.attr.attr_storage.recovery_parse_workers > 1) && IS_DN_DUMMY_STANDYS_MODE()) {
ereport(ERROR,
(errcode(ERRCODE_SYSTEM_ERROR),
errmsg("when starting as dummy_standby mode, we couldn't support extreme rto."),
errhint("Either turn off extreme rto, or set \"replication_type\" to 1.")));
}
if ((g_instance.attr.attr_storage.recovery_parse_workers > 1) && g_instance.attr.attr_storage.EnableHotStandby) {
ereport(ERROR,
(errcode(ERRCODE_SYSTEM_ERROR),
errmsg("extreme rto could not support hot standby."),
errhint("Either turn off extreme rto, or turn off hot_standby.")));
}
if ((g_instance.attr.attr_storage.recovery_parse_workers > 1) &&
g_instance.attr.attr_storage.WalReceiverBufSize < minReceiverBufSize) {
ereport(ERROR,
(errcode(ERRCODE_SYSTEM_ERROR),
errmsg("when starting extreme rto, wal receiver buf should not smaller than %dMB",
minReceiverBufSize / 1024),
errhint("recommend config \"wal_receiver_buffer_size=64MB\"")));
}
}
static void CheckRecoveryParaConflict()
{
if (g_instance.attr.attr_storage.max_recovery_parallelism > RECOVERY_PARALLELISM_DEFAULT
&& IS_DN_DUMMY_STANDYS_MODE()) {
ereport(WARNING,
(errmsg("when starting as dummy_standby mode, we couldn't support parallel redo, down it")));
g_instance.attr.attr_storage.max_recovery_parallelism = RECOVERY_PARALLELISM_DEFAULT;
}
}
/*
@ -2515,7 +2533,7 @@ static void CheckGUCConflicts(void)
ereport(LOG, (errmsg("when starting as multi_standby mode, we couldn't support data replicaton.")));
u_sess->attr.attr_storage.enable_data_replicate = false;
}
CheckRecoveryParaConflict();
if (g_instance.attr.attr_storage.enable_mix_replication &&
g_instance.attr.attr_storage.MaxSendSize >= g_instance.attr.attr_storage.DataQueueBufSize) {
write_stderr("%s: the data queue buffer size must be larger than the wal sender max send size for the "
@ -7024,6 +7042,7 @@ static void handle_promote_signal()
}
t_thrd.postmaster_cxt.audit_primary_failover = true;
/* Tell startup process to finish recovery */
ereport(LOG, (errmsg("Instance to do failover.")));
SendNotifySignal(NOTIFY_FAILOVER, g_instance.pid_cxt.StartupPID);
}
}
@ -10767,6 +10786,7 @@ Datum disable_conn(PG_FUNCTION_ARGS)
*/
if (disconn_node.conn_mode == PROHIBIT_CONNECTION) {
if(!knl_g_get_is_local_redo()) {
g_instance.comm_cxt.localinfo_cxt.need_disable_connection_node = true;
ereport(ERROR, (errcode_for_file_access(),
errmsg("could not add lock when DN is not redo all xlog, redo done flag is false")));
}

View File

@ -291,7 +291,7 @@ bool IsFailoverTriggered(void)
else
{
/* check for primary */
uint32 tgigger = pg_atomic_read_u32(&(extreme_rto::g_triggeredstate));
uint32 tgigger = pg_atomic_read_u32(&(extreme_rto::g_startupTriggerState));
if (tgigger == (uint32)extreme_rto::TRIGGER_FAILOVER)
return true;
}
@ -306,7 +306,7 @@ bool IsSwitchoverTriggered(void)
else
{
/* check for primary */
uint32 tgigger = pg_atomic_read_u32(&(extreme_rto::g_triggeredstate));
uint32 tgigger = pg_atomic_read_u32(&(extreme_rto::g_startupTriggerState));
if (tgigger == (uint32)extreme_rto::TRIGGER_SWITCHOVER)
return true;
}
@ -320,7 +320,7 @@ bool IsPrimaryTriggered(void)
else
{
/* check for primary */
uint32 tgigger = pg_atomic_read_u32(&(extreme_rto::g_triggeredstate));
uint32 tgigger = pg_atomic_read_u32(&(extreme_rto::g_startupTriggerState));
if (tgigger == (uint32)extreme_rto::TRIGGER_PRIMARY)
return true;
}
@ -334,7 +334,7 @@ bool IsStandbyTriggered(void)
else
{
/* check for primary */
uint32 tgigger = pg_atomic_read_u32(&(extreme_rto::g_triggeredstate));
uint32 tgigger = pg_atomic_read_u32(&(extreme_rto::g_startupTriggerState));
if (tgigger == (uint32)extreme_rto::TRIGGER_STADNBY)
return true;
}

View File

@ -174,6 +174,7 @@ static void knl_g_parallel_redo_init(knl_g_parallel_redo_context* predo_cxt)
predo_cxt->redoPf.local_max_lsn = 0;
knl_g_set_is_local_redo_finish(false);
predo_cxt->redoType = DEFAULT_REDO;
SpinLockInit(&(predo_cxt->destroy_lock));
}
static void knl_g_cache_init(knl_g_cache_context* cache_cxt)

View File

@ -393,8 +393,10 @@ static void initialize_reloptions(void)
j++;
j += t_thrd.relopt_cxt.num_custom_options;
if (t_thrd.relopt_cxt.relOpts)
if (t_thrd.relopt_cxt.relOpts) {
pfree(t_thrd.relopt_cxt.relOpts);
t_thrd.relopt_cxt.relOpts = NULL;
}
t_thrd.relopt_cxt.relOpts = (relopt_gen**)MemoryContextAlloc(t_thrd.top_mem_cxt, (j + 1) * sizeof(relopt_gen*));
j = 0;

View File

@ -45,7 +45,7 @@ XLogRecParseState* clog_xlog_ddl_parse_to_block(XLogReaderState* record, uint32*
{
uint8 info = XLogRecGetInfo(record) & ~XLR_INFO_MASK;
errno_t rc = EOK;
int64 pageno;
int64 pageno = 0;
ForkNumber forknum = MAIN_FORKNUM;
BlockNumber lowblknum = InvalidBlockNumber;
XLogRecParseState* recordstatehead = NULL;

View File

@ -489,6 +489,7 @@ void GinRedoCreateIndexBlock(XLogBlockHead* blockhead, XLogBlockDataParse* block
} else {
ginRedoCreateIndexOperatorRootPage(bufferinfo);
}
MakeRedoBufferDirty(bufferinfo);
}
void GinRedoCreatePTreeBlock(XLogBlockHead* blockhead, XLogBlockDataParse* blockdatarec, RedoBufferInfo* bufferinfo)
@ -497,6 +498,7 @@ void GinRedoCreatePTreeBlock(XLogBlockHead* blockhead, XLogBlockDataParse* block
if (XLogBlockDataGetBlockId(datadecode) == GIN_CREATE_P_TREE_BLOCK_NUM) {
char* maindata = XLogBlockDataGetMainData(datadecode, NULL);
ginRedoCreatePTreeOperatorPage(bufferinfo, maindata);
MakeRedoBufferDirty(bufferinfo);
}
}

View File

@ -172,26 +172,30 @@ void gistRedoCreateIndexOperatorPage(RedoBufferInfo* buffer)
static XLogRecParseState* GistXlogUpdateParseBlock(XLogReaderState* record, uint32* blocknum)
{
XLogRecParseState* recordstatehead = NULL;
*blocknum = 1;
XLogParseBufferAllocListFunc(record, &recordstatehead, NULL);
XLogRecSetBlockDataState(record, GIST_UPDATE_ORIG_BLOCK_NUM, recordstatehead);
XLogRecParseState* blockstate = NULL;
XLogParseBufferAllocListFunc(record, &blockstate, recordstatehead);
XLogRecSetBlockDataState(record, GIST_UPDATE_LEFT_CHILD_BOCK_NUM, blockstate);
*blocknum = 2;
if (XLogRecHasBlockRef(record, GIST_UPDATE_LEFT_CHILD_BOCK_NUM)) {
XLogRecParseState *blockstate = NULL;
XLogParseBufferAllocListFunc(record, &blockstate, recordstatehead);
XLogRecSetBlockDataState(record, GIST_UPDATE_LEFT_CHILD_BOCK_NUM, blockstate);
*blocknum += 1;
}
return recordstatehead;
}
static XLogRecParseState* GistXlogPageSplitParse(XLogReaderState* record, uint32* blocknum)
static XLogRecParseState *GistXlogPageSplitParseBlock(XLogReaderState *record, uint32 *blocknum)
{
XLogRecParseState* recordstatehead = NULL;
XLogRecParseState* blockstate = NULL;
gistxlogPageSplit* xldata = (gistxlogPageSplit*)XLogRecGetData(record);
*blocknum = xldata->npage;
bool isrootsplit = false;
for (uint16 i = 0; i < xldata->npage; i++) {
XLogParseBufferAllocListFunc(record, &blockstate, recordstatehead);
if (recordstatehead == NULL) {
@ -201,13 +205,15 @@ static XLogRecParseState* GistXlogPageSplitParse(XLogReaderState* record, uint32
BlockNumber blkno;
XLogRecGetBlockTag(record, i + 1, NULL, NULL, &blkno);
if (blkno == GIST_ROOT_BLKNO)
if (blkno == GIST_ROOT_BLKNO) {
XLogRecSetAuxiBlkNumState(
&blockstate->blockparse.extra_rec.blockdatarec, InvalidForkNumber, InvalidForkNumber);
else {
isrootsplit = true;
}
if (blkno != GIST_ROOT_BLKNO) {
uint32 flag;
if ((i < xldata->npage - 1) && xldata->markfollowright)
flag = F_FOLLOW_RIGHT;
if ((i < xldata->npage - 1) && !isrootsplit && xldata->markfollowright)
flag = 1;
else
flag = 0;
@ -220,8 +226,7 @@ static XLogRecParseState* GistXlogPageSplitParse(XLogReaderState* record, uint32
}
}
*blocknum = xldata->npage;
if (XLogRecHasBlockRef(record, 0)) {
if (XLogRecHasBlockRef(record, GIST_SPLIT_FOLLOW_WRITE_BLOCK_NUM)) {
XLogParseBufferAllocListFunc(record, &blockstate, recordstatehead);
XLogRecSetBlockDataState(record, GIST_SPLIT_FOLLOW_WRITE_BLOCK_NUM, blockstate);
++(*blocknum);
@ -229,7 +234,7 @@ static XLogRecParseState* GistXlogPageSplitParse(XLogReaderState* record, uint32
return recordstatehead;
}
static XLogRecParseState* GistXlogCreateIndex(XLogReaderState* record, uint32* blocknum)
static XLogRecParseState *GistXlogCreateIndexParseBlock(XLogReaderState *record, uint32 *blocknum)
{
XLogRecParseState* recordstatehead = NULL;
@ -251,14 +256,83 @@ XLogRecParseState* GistRedoParseToBlock(XLogReaderState* record, uint32* blocknu
recordblockstate = GistXlogUpdateParseBlock(record, blocknum);
break;
case XLOG_GIST_PAGE_SPLIT:
recordblockstate = GistXlogPageSplitParse(record, blocknum);
recordblockstate = GistXlogPageSplitParseBlock(record, blocknum);
break;
case XLOG_GIST_CREATE_INDEX:
recordblockstate = GistXlogCreateIndex(record, blocknum);
recordblockstate = GistXlogCreateIndexParseBlock(record, blocknum);
break;
default:
ereport(PANIC, (errcode(ERRCODE_INDEX_CORRUPTED), errmsg("gist_redo: unknown op code %u", info)));
ereport(PANIC, (errcode(ERRCODE_INDEX_CORRUPTED), errmsg("gist parse: unknown op code %u", info)));
}
return recordblockstate;
}
void GistPageUpdateRedoBlock(XLogBlockHead *blockhead, XLogBlockDataParse *blockdatarec, RedoBufferInfo *bufferinfo)
{
XLogBlockDataParse *datadecode = blockdatarec;
if (XLogBlockDataGetBlockId(datadecode) == GIST_UPDATE_ORIG_BLOCK_NUM) {
XLogRedoAction action = XLogCheckBlockDataRedoAction(datadecode, bufferinfo);
if (action == BLK_NEEDS_REDO) {
Size blkdatalen = 0;
char *blkdata = XLogBlockDataGetBlockData(datadecode, &blkdatalen);
gistRedoPageUpdateOperatorPage(bufferinfo, datadecode->main_data, blkdata, blkdatalen);
MakeRedoBufferDirty(bufferinfo);
}
} else {
XLogRedoAction action = XLogCheckBlockDataRedoAction(datadecode, bufferinfo);
if (action == BLK_NEEDS_REDO || action == BLK_RESTORED) {
gistRedoClearFollowRightOperatorPage(bufferinfo);
MakeRedoBufferDirty(bufferinfo);
}
}
}
void GistPageSplitRedoBlock(XLogBlockHead *blockhead, XLogBlockDataParse *blockdatarec, RedoBufferInfo *bufferinfo)
{
XLogBlockDataParse *datadecode = blockdatarec;
if (XLogBlockDataGetBlockId(datadecode) == GIST_SPLIT_FOLLOW_WRITE_BLOCK_NUM) {
XLogRedoAction action = XLogCheckBlockDataRedoAction(datadecode, bufferinfo);
if (action == BLK_NEEDS_REDO || action == BLK_RESTORED) {
gistRedoClearFollowRightOperatorPage(bufferinfo);
MakeRedoBufferDirty(bufferinfo);
}
} else {
Size blkdatalen = 0;
char *blkdata = XLogBlockDataGetBlockData(datadecode, &blkdatalen);
BlockNumber nextblkno = XLogBlockDataGetAuxiBlock1(datadecode);
bool markflag = (XLogBlockDataGetAuxiBlock2(datadecode) > 0);
char *maindata = XLogBlockDataGetMainData(datadecode, NULL);
gistRedoPageSplitOperatorPage(bufferinfo, (void *)maindata, blkdata, blkdatalen, markflag, nextblkno);
MakeRedoBufferDirty(bufferinfo);
}
}
void GistCreateIndexRedoBlock(XLogBlockHead *blockhead, XLogBlockDataParse *blockdatarec, RedoBufferInfo *bufferinfo)
{
gistRedoCreateIndexOperatorPage(bufferinfo);
MakeRedoBufferDirty(bufferinfo);
}
void GistRedoDataBlock(XLogBlockHead *blockhead, XLogBlockDataParse *blockdatarec, RedoBufferInfo *bufferinfo)
{
uint8 info = XLogBlockHeadGetInfo(blockhead) & ~XLR_INFO_MASK;
switch (info) {
case XLOG_GIST_PAGE_UPDATE:
GistPageUpdateRedoBlock(blockhead, blockdatarec, bufferinfo);
break;
case XLOG_GIST_PAGE_SPLIT:
GistPageSplitRedoBlock(blockhead, blockdatarec, bufferinfo);
break;
case XLOG_GIST_CREATE_INDEX:
GistCreateIndexRedoBlock(blockhead, blockdatarec, bufferinfo);
break;
default:
ereport(PANIC, (errcode(ERRCODE_INDEX_CORRUPTED), errmsg("gist redo: unknown op code %u", info)));
}
}

View File

@ -938,16 +938,18 @@ static void btree_xlog_newroot_block(
if (XLogBlockDataGetBlockId(datadecode) == BTREE_NEWROOT_ORIG_BLOCK_NUM) {
char* maindata = XLogBlockDataGetMainData(datadecode, NULL);
btree_xlog_newroot_operator_page(bufferinfo, (void*)maindata, (void*)blkdata, blkdatalen, &downlink);
MakeRedoBufferDirty(bufferinfo);
} else if (XLogBlockDataGetBlockId(datadecode) == BTREE_NEWROOT_LEFT_BLOCK_NUM) {
XLogRedoAction action;
action = XLogCheckBlockDataRedoAction(datadecode, bufferinfo);
if (action == BLK_NEEDS_REDO) {
btree_xlog_clear_incomplete_split(bufferinfo);
MakeRedoBufferDirty(bufferinfo);
}
} else {
btree_restore_meta_operator_page(bufferinfo, (void*)blkdata, blkdatalen);
MakeRedoBufferDirty(bufferinfo);
}
MakeRedoBufferDirty(bufferinfo);
}
void btree_redo_data_block(XLogBlockHead* blockhead, XLogBlockDataParse* blockdatarec, RedoBufferInfo* bufferinfo)

View File

@ -43,7 +43,7 @@
#include "storage/smgr.h"
#include "storage/buf_internals.h"
#include "storage/freespace.h"
#include "storage/ipc.h"
#include "utils/guc.h"
#include "utils/hsearch.h"
#include "utils/rel.h"
@ -53,8 +53,8 @@
#include "access/twophase.h"
#include "access/redo_common.h"
THR_LOCAL RedoParseManager g_parseManager;
THR_LOCAL RedoBufferManager g_bufferManager;
THR_LOCAL RedoParseManager *g_parseManager = NULL;
THR_LOCAL RedoBufferManager *g_bufferManager = NULL;
#ifdef BUILD_ALONE
THR_LOCAL bool assert_enabled = true;
@ -590,6 +590,11 @@ RedoMemSlot* XLogMemAlloc(RedoMemManager* memctl)
memctl->usedblknum++;
nextfreeslot->freeNext = InvalidBuffer;
}
if (memctl->doInterrupt != NULL) {
memctl->doInterrupt();
}
} while (nextfreeslot == NULL);
return nextfreeslot;
@ -613,18 +618,26 @@ void XLogMemRelease(RedoMemManager* memctl, Buffer bufferid)
} while (!AtomicCompareExchangeBuffer(&memctl->firstreleaseslot, &oldFirst, bufferid));
}
void XLogRedoBufferInit(RedoBufferManager* buffermanager, int buffernum, RefOperate* refOperate)
void XLogRedoBufferInit(RedoBufferManager *buffermanager, int buffernum, RefOperate *refOperate,
InterruptFunc interruptOperte)
{
void* allocdata = NULL;
allocdata = XLogMemCtlInit(&(buffermanager->memctl), (BLCKSZ + sizeof(RedoBufferDesc)), buffernum);
void *allocdata = XLogMemCtlInit(&(buffermanager->memctl), (BLCKSZ + sizeof(RedoBufferDesc)), buffernum);
buffermanager->BufferBlockPointers = allocdata;
buffermanager->refOperate = refOperate;
buffermanager->memctl.doInterrupt = interruptOperte;
buffermanager->memctl.isInit = true;
g_bufferManager = buffermanager;
return;
}
void XLogRedoBufferDestory(RedoBufferManager* buffermanager)
{
pfree(buffermanager->BufferBlockPointers);
g_bufferManager = NULL;
buffermanager->memctl.isInit = false;
if (buffermanager->BufferBlockPointers != NULL) {
pfree(buffermanager->BufferBlockPointers);
buffermanager->BufferBlockPointers = NULL;
}
}
RedoMemSlot* XLogRedoBufferAlloc(
@ -763,20 +776,28 @@ void XLogRedoBufferSetState(RedoBufferManager* buffermanager, RedoMemSlot* buffe
bufferdesc->state |= state;
}
void XLogParseBufferInit(RedoParseManager* parsemanager, int buffernum, RefOperate* refOperate)
void XLogParseBufferInit(RedoParseManager *parsemanager, int buffernum, RefOperate *refOperate,
InterruptFunc interruptOperte)
{
void* allocdata = NULL;
allocdata =
XLogMemCtlInit(&(parsemanager->memctl), (sizeof(XLogRecParseState) + sizeof(ParseBufferDesc)), buffernum);
void *allocdata = NULL;
allocdata = XLogMemCtlInit(&(parsemanager->memctl), (sizeof(XLogRecParseState) + sizeof(ParseBufferDesc)),
buffernum);
parsemanager->parsebuffers = allocdata;
parsemanager->refOperate = refOperate;
parsemanager->memctl.doInterrupt = interruptOperte;
parsemanager->memctl.isInit = true;
parsemanager->refOperate = refOperate;
g_parseManager = parsemanager;
return;
}
void XLogParseBufferDestory(RedoParseManager* parsemanager)
{
pfree(parsemanager->parsebuffers);
g_parseManager = NULL;
if (parsemanager->parsebuffers != NULL) {
pfree(parsemanager->parsebuffers);
parsemanager->parsebuffers = NULL;
}
parsemanager->memctl.isInit = false;
}
@ -881,6 +902,7 @@ void XLogBlockDataCommonRedo(XLogBlockHead* blockhead, void* blockrecbody, RedoB
GinRedoDataBlock(blockhead, blockdatarec, bufferinfo);
break;
case RM_GIST_ID:
GistRedoDataBlock(blockhead, blockdatarec, bufferinfo);
break;
case RM_SPGIST_ID:
break;
@ -993,6 +1015,12 @@ void XLogBlockDdlDoRealAction(XLogBlockHead* blockhead, void* blockrecbody, Redo
case BLOCK_DDL_TRUNCATE_RELNODE:
XLogBlockSmgrRedoTruncate(rnode, blockhead->blkno, blockhead->end_ptr);
break;
case BLOCK_DDL_DROP_RELNODE: {
SMgrRelation reln =
smgropen(bufferinfo->blockinfo.rnode, InvalidBackendId, GetColumnNum(bufferinfo->blockinfo.forknum));
smgrclose(reln);
break;
}
default:
break;
}
@ -1094,11 +1122,11 @@ void UpdateFsm(RedoBufferTag* blockInfo, Size freespace)
}
}
void ExtremeRtoFlushBuffer(RedoBufferInfo* bufferinfo, bool updateFsm)
void ExtremeRtoFlushBuffer(RedoBufferInfo *bufferinfo, bool updateFsm)
{
Size freespace;
if (updateFsm) {
Size freespace = PageGetHeapFreeSpace(bufferinfo->pageinfo.page);
UpdateFsm(&bufferinfo->blockinfo, freespace);
freespace = PageGetHeapFreeSpace(bufferinfo->pageinfo.page);
}
if (ParseStateWithoutCache()) {
@ -1116,6 +1144,10 @@ void ExtremeRtoFlushBuffer(RedoBufferInfo* bufferinfo, bool updateFsm)
UnlockReleaseBuffer(bufferinfo->buf); /* release buffer */
}
}
if (updateFsm) {
UpdateFsm(&bufferinfo->blockinfo, freespace);
}
}
void XLogSynAllBuffer()

View File

@ -38,6 +38,7 @@ void gist_desc(StringInfo buf, XLogReaderState* record)
out_gistxlogPageSplit(buf, (gistxlogPageSplit*)rec);
break;
case XLOG_GIST_CREATE_INDEX:
appendStringInfo(buf, "create_index: ");
break;
default:
appendStringInfo(buf, "unknown gist op code %hhu", info);

View File

@ -70,6 +70,7 @@
#include "commands/sequence.h"
#include "replication/slot.h"
#include "replication/walreceiver.h"
#include "gssignal/gs_signal.h"
#include "utils/atomic.h"
#include "pgstat.h"
@ -90,7 +91,8 @@ static const int32 MAX_PENDING_STANDBY = 1;
static const int32 ITEM_QUQUE_SIZE_RATIO = 10;
static const uint32 EXIT_WAIT_DELAY = 100; /* 100 us */
uint32 g_triggeredstate = TRIGGER_NORMAL;
uint32 g_startupTriggerState = TRIGGER_NORMAL;
uint32 g_readManagerTriggerFlag = TRIGGER_NORMAL;
typedef void* (*GetStateFunc)(PageRedoWorker* worker);
@ -140,28 +142,28 @@ void CopyDataFromOldReader(XLogReaderState* newReaderState, const XLogReaderStat
/* dispatchTable must consistent with RmgrTable */
static const RmgrDispatchData g_dispatchTable[RM_MAX_ID + 1] = {
{DispatchXLogRecord, RmgrRecordInfoValid, RM_XLOG_ID, XLOG_CHECKPOINT_SHUTDOWN, XLOG_FPI},
{DispatchXactRecord, RmgrRecordInfoValid, RM_XACT_ID, XLOG_XACT_COMMIT, XLOG_XACT_COMMIT_COMPACT},
{DispatchSmgrRecord, RmgrRecordInfoValid, RM_SMGR_ID, XLOG_SMGR_CREATE, XLOG_SMGR_TRUNCATE},
{DispatchCLogRecord, RmgrRecordInfoValid, RM_CLOG_ID, CLOG_ZEROPAGE, CLOG_TRUNCATE},
{DispatchDataBaseRecord, RmgrRecordInfoValid, RM_DBASE_ID, XLOG_DBASE_CREATE, XLOG_DBASE_DROP},
{DispatchTableSpaceRecord, RmgrRecordInfoValid, RM_TBLSPC_ID, XLOG_TBLSPC_CREATE, XLOG_TBLSPC_RELATIVE_CREATE},
{DispatchMultiXactRecord,
RmgrRecordInfoValid,
RM_MULTIXACT_ID,
XLOG_MULTIXACT_ZERO_OFF_PAGE,
XLOG_MULTIXACT_CREATE_ID},
{DispatchRelMapRecord, RmgrRecordInfoValid, RM_RELMAP_ID, XLOG_RELMAP_UPDATE, XLOG_RELMAP_UPDATE},
{ DispatchXLogRecord, RmgrRecordInfoValid, RM_XLOG_ID, XLOG_CHECKPOINT_SHUTDOWN, XLOG_FPI },
{ DispatchXactRecord, RmgrRecordInfoValid, RM_XACT_ID, XLOG_XACT_COMMIT, XLOG_XACT_COMMIT_COMPACT },
{ DispatchSmgrRecord, RmgrRecordInfoValid, RM_SMGR_ID, XLOG_SMGR_CREATE, XLOG_SMGR_TRUNCATE },
{ DispatchCLogRecord, RmgrRecordInfoValid, RM_CLOG_ID, CLOG_ZEROPAGE, CLOG_TRUNCATE },
{ DispatchDataBaseRecord, RmgrRecordInfoValid, RM_DBASE_ID, XLOG_DBASE_CREATE, XLOG_DBASE_DROP },
{ DispatchTableSpaceRecord, RmgrRecordInfoValid, RM_TBLSPC_ID, XLOG_TBLSPC_CREATE, XLOG_TBLSPC_RELATIVE_CREATE },
{ DispatchMultiXactRecord,
RmgrRecordInfoValid,
RM_MULTIXACT_ID,
XLOG_MULTIXACT_ZERO_OFF_PAGE,
XLOG_MULTIXACT_CREATE_ID},
{ DispatchRelMapRecord, RmgrRecordInfoValid, RM_RELMAP_ID, XLOG_RELMAP_UPDATE, XLOG_RELMAP_UPDATE },
#ifndef ENABLE_MULTIPLE_NODES
{DispatchStandbyRecord, RmgrRecordInfoValid, RM_STANDBY_ID, XLOG_STANDBY_LOCK, XLOG_STANDBY_CSN_ABORTED},
#else
{DispatchStandbyRecord, RmgrRecordInfoValid, RM_STANDBY_ID, XLOG_STANDBY_LOCK, XLOG_STANDBY_CSN},
#endif
{DispatchHeap2Record, RmgrRecordInfoValid, RM_HEAP2_ID, XLOG_HEAP2_FREEZE, XLOG_HEAP2_LOGICAL_NEWPAGE},
{DispatchHeapRecord, RmgrRecordInfoValid, RM_HEAP_ID, XLOG_HEAP_INSERT, XLOG_HEAP_INPLACE},
{DispatchBtreeRecord, RmgrRecordInfoValid, RM_BTREE_ID, XLOG_BTREE_INSERT_LEAF, XLOG_BTREE_REUSE_PAGE},
{DispatchHashRecord, NULL, RM_HASH_ID, 0, 0},
{DispatchGinRecord, RmgrRecordInfoValid, RM_GIN_ID, XLOG_GIN_CREATE_INDEX, XLOG_GIN_VACUUM_DATA_LEAF_PAGE},
{ DispatchHeap2Record, RmgrRecordInfoValid, RM_HEAP2_ID, XLOG_HEAP2_FREEZE, XLOG_HEAP2_LOGICAL_NEWPAGE },
{ DispatchHeapRecord, RmgrRecordInfoValid, RM_HEAP_ID, XLOG_HEAP_INSERT, XLOG_HEAP_INPLACE },
{ DispatchBtreeRecord, RmgrRecordInfoValid, RM_BTREE_ID, XLOG_BTREE_INSERT_LEAF, XLOG_BTREE_REUSE_PAGE },
{ DispatchHashRecord, NULL, RM_HASH_ID, 0, 0 },
{ DispatchGinRecord, RmgrRecordInfoValid, RM_GIN_ID, XLOG_GIN_CREATE_INDEX, XLOG_GIN_VACUUM_DATA_LEAF_PAGE },
/* XLOG_GIST_PAGE_DELETE is not used and info isn't continus */
{DispatchGistRecord, RmgrGistRecordInfoValid, RM_GIST_ID, 0, 0},
{DispatchSeqRecord, RmgrRecordInfoValid, RM_SEQ_ID, XLOG_SEQ_LOG, XLOG_SEQ_LOG},
@ -211,12 +213,9 @@ void WaitWorkerReady()
for (waitLoop = 0; waitLoop < MAX_REDO_WAIT_LOOP; ++waitLoop) {
readyWorkerCnt = GetReadyWorker();
if (readyWorkerCnt == g_instance.comm_cxt.predo_cxt.totalNum) {
ereport(LOG,
(errmodule(MOD_REDO),
errcode(ERRCODE_LOG),
errmsg("WaitWorkerReady total worker count:%u, readyWorkerCnt:%u",
g_dispatcher->allWorkersCnt,
readyWorkerCnt)));
ereport(LOG, (errmodule(MOD_REDO), errcode(ERRCODE_LOG),
errmsg("WaitWorkerReady total worker count:%u, readyWorkerCnt:%u",
g_dispatcher->allWorkersCnt, readyWorkerCnt)));
break;
}
pg_usleep(REDO_WAIT_SLEEP_TIME);
@ -226,21 +225,16 @@ void WaitWorkerReady()
SpinLockRelease(&(g_instance.comm_cxt.predo_cxt.rwlock));
readyWorkerCnt = GetReadyWorker();
if (waitLoop == MAX_REDO_WAIT_LOOP && readyWorkerCnt == 0) {
ereport(PANIC,
(errmodule(MOD_REDO),
errcode(ERRCODE_LOG),
errmsg("WaitWorkerReady failed, no worker is ready for work. totalWorkerCount :%u",
g_dispatcher->allWorkersCnt)));
ereport(PANIC, (errmodule(MOD_REDO), errcode(ERRCODE_LOG),
errmsg("WaitWorkerReady failed, no worker is ready for work. totalWorkerCount :%u",
g_dispatcher->allWorkersCnt)));
}
/* RTO_DEMO */
if (readyWorkerCnt != g_dispatcher->allWorkersCnt) {
ereport(PANIC,
(errmodule(MOD_REDO),
errcode(ERRCODE_LOG),
errmsg("WaitWorkerReady total thread count:%u, readyWorkerCnt:%u, not all thread ready",
g_dispatcher->allWorkersCnt,
readyWorkerCnt)));
ereport(PANIC, (errmodule(MOD_REDO), errcode(ERRCODE_LOG),
errmsg("WaitWorkerReady total thread count:%u, readyWorkerCnt:%u, not all thread ready",
g_dispatcher->allWorkersCnt, readyWorkerCnt)));
}
}
@ -248,11 +242,9 @@ void CheckAlivePageWorkers()
{
for (uint32 i = 0; i < MAX_RECOVERY_THREAD_NUM; ++i) {
if (g_instance.comm_cxt.predo_cxt.pageRedoThreadStatusList[i].threadState != PAGE_REDO_WORKER_INVALID) {
ereport(PANIC,
(errmodule(MOD_REDO),
errcode(ERRCODE_LOG),
errmsg("CheckAlivePageWorkers: thread %lu is still alive",
g_instance.comm_cxt.predo_cxt.pageRedoThreadStatusList[i].threadId)));
ereport(PANIC, (errmodule(MOD_REDO), errcode(ERRCODE_LOG),
errmsg("CheckAlivePageWorkers: thread %lu is still alive",
g_instance.comm_cxt.predo_cxt.pageRedoThreadStatusList[i].threadId)));
}
g_instance.comm_cxt.predo_cxt.pageRedoThreadStatusList[i].threadId = 0;
}
@ -266,7 +258,14 @@ void AllocRecordReadBuffer(XLogReaderState* xlogreader, uint32 privateLen)
initreader = GetXlogReader(xlogreader);
initreader->isPRProcess = true;
g_dispatcher->recordstate.startreadworker = READ_WORKER_STOP;
g_dispatcher->recordstate.readWorkerState = WORKER_STATE_STOP;
g_dispatcher->recordstate.readPageWorkerState = WORKER_STATE_STOP;
g_dispatcher->recordstate.readSource = 0;
g_dispatcher->recordstate.failSource = 0;
g_dispatcher->recordstate.xlogReadManagerState = READ_MANAGER_RUN;
g_dispatcher->recordstate.latestValidRecord = InvalidXLogRecPtr;
g_dispatcher->recordstate.targetRecPtr = InvalidXLogRecPtr;
g_dispatcher->recordstate.expectLsn = InvalidXLogRecPtr;
g_dispatcher->recordstate.readsegbuf = (char*)palloc0(XLOG_SEG_SIZE * MAX_ALLOC_SEGNUM);
g_dispatcher->recordstate.readprivate = (void*)palloc0(MAXALIGN(privateLen));
errorno = memset_s(g_dispatcher->recordstate.readprivate, MAXALIGN(privateLen), 0, MAXALIGN(privateLen));
@ -289,8 +288,8 @@ void AllocRecordReadBuffer(XLogReaderState* xlogreader, uint32 privateLen)
g_dispatcher->recordstate.xlogsegarray[0].segoffset = xlogreader->readOff;
g_dispatcher->recordstate.xlogsegarray[0].readlen = xlogreader->readOff + xlogreader->readLen;
initreader->readBuf =
g_dispatcher->recordstate.xlogsegarray[0].readsegbuf + g_dispatcher->recordstate.xlogsegarray[0].segoffset;
initreader->readBuf = g_dispatcher->recordstate.xlogsegarray[0].readsegbuf +
g_dispatcher->recordstate.xlogsegarray[0].segoffset;
errorno = memcpy_s(initreader->readBuf, XLOG_BLCKSZ, xlogreader->readBuf, xlogreader->readLen);
securec_check(errorno, "", "");
@ -300,6 +299,8 @@ void AllocRecordReadBuffer(XLogReaderState* xlogreader, uint32 privateLen)
g_dispatcher->recordstate.initreader = initreader;
g_recordbuffer = &g_dispatcher->recordstate;
g_startupTriggerState = TRIGGER_NORMAL;
g_readManagerTriggerFlag = TRIGGER_NORMAL;
}
/* Run from the dispatcher thread. */
@ -312,17 +313,15 @@ void StartRecoveryWorkers(XLogReaderState* xlogreader, uint32 privateLen)
CheckAlivePageWorkers();
g_dispatcher = CreateDispatcher();
g_dispatcher->oldCtx = MemoryContextSwitchTo(g_instance.comm_cxt.predo_cxt.parallelRedoCtx);
g_dispatcher->maxItemNum = (get_real_recovery_parallelism() + 1) * PAGE_WORK_QUEUE_SIZE * ITEM_QUQUE_SIZE_RATIO;
g_dispatcher->maxItemNum = (get_batch_redo_num() + 4) * PAGE_WORK_QUEUE_SIZE *
ITEM_QUQUE_SIZE_RATIO; // 4: a startup, readmanager, txnmanager, txnworker
/* alloc for record readbuf */
AllocRecordReadBuffer(xlogreader, privateLen);
StartPageRedoWorkers(get_real_recovery_parallelism());
ereport(LOG,
(errmodule(MOD_REDO),
errcode(ERRCODE_LOG),
errmsg("[PR]: max=%d, thrd=%d",
g_instance.attr.attr_storage.max_recovery_parallelism,
get_real_recovery_parallelism())));
ereport(LOG, (errmodule(MOD_REDO), errcode(ERRCODE_LOG),
errmsg("[PR]: max=%d, thrd=%d", g_instance.attr.attr_storage.max_recovery_parallelism,
get_real_recovery_parallelism())));
WaitWorkerReady();
SpinLockAcquire(&(g_instance.comm_cxt.predo_cxt.rwlock));
g_instance.comm_cxt.predo_cxt.state = REDO_IN_PROGRESS;
@ -337,14 +336,10 @@ void DumpDispatcher()
PageRedoPipeline* pl = NULL;
state = g_instance.comm_cxt.predo_cxt.state;
if ((get_real_recovery_parallelism() > 1) && (GetBatchCount() > 0)) {
ereport(LOG,
(errmodule(MOD_REDO),
errcode(ERRCODE_LOG),
errmsg("[REDO_LOG_TRACE]dispatcher : totalWorkerCount %d, state %u, curItemNum %u, maxItemNum %u",
get_real_recovery_parallelism(),
(uint32)state,
g_dispatcher->curItemNum,
g_dispatcher->maxItemNum)));
ereport(LOG, (errmodule(MOD_REDO), errcode(ERRCODE_LOG),
errmsg("[REDO_LOG_TRACE]dispatcher : totalWorkerCount %d, state %u, curItemNum %u, maxItemNum %u",
get_real_recovery_parallelism(), (uint32)state, g_dispatcher->curItemNum,
g_dispatcher->maxItemNum)));
for (uint32 i = 0; i < g_dispatcher->pageLineNum; ++i) {
pl = &(g_dispatcher->pageLines[i]);
@ -360,21 +355,13 @@ void DumpDispatcher()
}
}
List* CheckImcompleteAction(List* imcompleteActionList)
{
/* RTO_DEMO test */
return NULL;
}
/* Run from the dispatcher thread. */
static LogDispatcher* CreateDispatcher()
{
MemoryContext ctx = AllocSetContextCreate(t_thrd.top_mem_cxt,
"ParallelRecoveryDispatcher",
ALLOCSET_DEFAULT_MINSIZE,
ALLOCSET_DEFAULT_INITSIZE,
ALLOCSET_DEFAULT_MAXSIZE,
SHARED_CONTEXT);
MemoryContext ctx = AllocSetContextCreate(g_instance.instance_context, "ParallelRecoveryDispatcher",
ALLOCSET_DEFAULT_MINSIZE, ALLOCSET_DEFAULT_INITSIZE,
ALLOCSET_DEFAULT_MAXSIZE, SHARED_CONTEXT);
LogDispatcher* newDispatcher = (LogDispatcher*)MemoryContextAllocZero(ctx, sizeof(LogDispatcher));
@ -382,10 +369,6 @@ static LogDispatcher* CreateDispatcher()
SpinLockAcquire(&(g_instance.comm_cxt.predo_cxt.rwlock));
g_instance.comm_cxt.predo_cxt.state = REDO_STARTING_BEGIN;
SpinLockRelease(&(g_instance.comm_cxt.predo_cxt.rwlock));
if (OnHotStandBy())
newDispatcher->pendingMax = MAX_PENDING_STANDBY;
else
newDispatcher->pendingMax = MAX_PENDING; /* one batch, one recorder */
newDispatcher->totalCostTime = 0;
newDispatcher->txnCostTime = 0;
newDispatcher->pprCostTime = 0;
@ -393,6 +376,9 @@ static LogDispatcher* CreateDispatcher()
newDispatcher->syncExitCount = 0;
pg_atomic_init_u32(&(newDispatcher->standbyState), STANDBY_INITIALIZED);
newDispatcher->needImmediateCheckpoint = false;
newDispatcher->needFullSyncCheckpoint =false;
newDispatcher->smartShutdown = false;
return newDispatcher;
}
@ -415,24 +401,19 @@ static void StartPageRedoWorkers(uint32 totalThrdNum)
uint32 workerCnt = 0;
PageRedoWorker** tmpWorkers;
uint32 started;
ereport(LOG,
(errmsg("StartPageRedoWorkers, totalThrdNum:%u, "
"batchNum:%u, batchWorkerPerMng is %u",
totalThrdNum,
batchNum,
batchWorkerPerMng)));
ereport(LOG, (errmsg("StartPageRedoWorkers, totalThrdNum:%u, "
"batchNum:%u, batchWorkerPerMng is %u",
totalThrdNum, batchNum, batchWorkerPerMng)));
g_dispatcher->allWorkers = (PageRedoWorker**)palloc(sizeof(PageRedoWorker*) * totalThrdNum);
g_dispatcher->allWorkers = (PageRedoWorker **)palloc0(sizeof(PageRedoWorker *) * totalThrdNum);
g_dispatcher->allWorkersCnt = totalThrdNum;
g_dispatcher->pageLines = (PageRedoPipeline*)palloc(sizeof(PageRedoPipeline) * batchNum);
for (started = 0; started < totalThrdNum; started++) {
g_dispatcher->allWorkers[started] = CreateWorker(started);
if (g_dispatcher->allWorkers[started] == NULL) {
ereport(PANIC,
(errmodule(MOD_REDO),
errcode(ERRCODE_LOG),
errmsg("[REDO_LOG_TRACE]StartPageRedoWorkers CreateWorker failed, started:%u", started)));
ereport(PANIC, (errmodule(MOD_REDO), errcode(ERRCODE_LOG),
errmsg("[REDO_LOG_TRACE]StartPageRedoWorkers CreateWorker failed, started:%u", started)));
}
}
tmpWorkers = g_dispatcher->allWorkers;
@ -452,14 +433,14 @@ static void StartPageRedoWorkers(uint32 totalThrdNum)
RedoRoleInit(&(g_dispatcher->trxnLine.redoThd), tmpWorkers[workerCnt++], REDO_TRXN_WORKER, 0);
RedoRoleInit(&(g_dispatcher->readLine.managerThd), tmpWorkers[workerCnt++], REDO_READ_MNG, 0);
RedoRoleInit(&(g_dispatcher->readLine.readPageThd), tmpWorkers[workerCnt++], REDO_READ_PAGE_WORKER, 0);
RedoRoleInit(&(g_dispatcher->readLine.readThd), tmpWorkers[workerCnt++], REDO_READ_WORKER, 0);
for (started = 0; started < totalThrdNum; started++) {
if (StartPageRedoWorker(g_dispatcher->allWorkers[started]) == NULL) {
ereport(PANIC,
(errmodule(MOD_REDO),
errcode(ERRCODE_LOG),
errmsg("[REDO_LOG_TRACE]StartPageRedoWorkers StartPageRedoWorker failed, started:%u", started)));
(errmodule(MOD_REDO), errcode(ERRCODE_LOG),
errmsg("[REDO_LOG_TRACE]StartPageRedoWorkers StartPageRedoWorker failed, started:%u", started)));
}
}
@ -509,11 +490,9 @@ void SendSingalToPageWorker(int signal)
if (state == PAGE_REDO_WORKER_READY) {
int err = gs_signal_send(g_instance.comm_cxt.predo_cxt.pageRedoThreadStatusList[i].threadId, signal);
if (0 != err) {
ereport(WARNING,
(errmsg("Dispatch kill(pid %lu, signal %d) failed: \"%s\",",
g_instance.comm_cxt.predo_cxt.pageRedoThreadStatusList[i].threadId,
signal,
gs_strerror(err))));
ereport(WARNING, (errmsg("Dispatch kill(pid %lu, signal %d) failed: \"%s\",",
g_instance.comm_cxt.predo_cxt.pageRedoThreadStatusList[i].threadId, signal,
gs_strerror(err))));
}
}
}
@ -522,13 +501,10 @@ void SendSingalToPageWorker(int signal)
/* Run from the dispatcher thread. */
static void StopRecoveryWorkers(int code, Datum arg)
{
ereport(LOG,
(errmodule(MOD_REDO),
errcode(ERRCODE_LOG),
errmsg("parallel redo workers are going to stop, "
"code:%d, arg:%lu",
code,
DatumGetUInt64(arg))));
ereport(LOG, (errmodule(MOD_REDO), errcode(ERRCODE_LOG),
errmsg("parallel redo workers are going to stop, "
"code:%d, arg:%lu",
code, DatumGetUInt64(arg))));
SendSingalToPageWorker(SIGTERM);
uint64 count = 0;
@ -539,15 +515,19 @@ static void StopRecoveryWorkers(int code, Datum arg)
(errmodule(MOD_REDO), errcode(ERRCODE_LOG), errmsg("StopRecoveryWorkers wait page work exit")));
if ((count & PRINT_ALL_WAIT_COUNT) == PRINT_ALL_WAIT_COUNT) {
DumpDispatcher();
ereport(
PANIC, (errmodule(MOD_REDO), errcode(ERRCODE_LOG), errmsg("StopRecoveryWorkers wait too long!!!")));
ereport(PANIC,
(errmodule(MOD_REDO), errcode(ERRCODE_LOG), errmsg("StopRecoveryWorkers wait too long!!!")));
}
pg_usleep(EXIT_WAIT_DELAY);
}
}
pg_atomic_write_u32(&g_dispatcher->recordstate.readWorkerState, WORKER_STATE_EXIT);
ShutdownWalRcv();
FreeAllocatedRedoItem();
DestroyRecoveryWorkers();
g_startupTriggerState = TRIGGER_NORMAL;
g_readManagerTriggerFlag = TRIGGER_NORMAL;
ereport(LOG, (errmodule(MOD_REDO), errcode(ERRCODE_LOG), errmsg("parallel redo(startup) thread exit")));
}
@ -555,6 +535,7 @@ static void StopRecoveryWorkers(int code, Datum arg)
static void DestroyRecoveryWorkers()
{
if (g_dispatcher != NULL) {
SpinLockAcquire(&(g_instance.comm_cxt.predo_cxt.destroy_lock));
for (uint32 i = 0; i < g_dispatcher->pageLineNum; i++) {
DestroyPageRedoWorker(g_dispatcher->pageLines[i].batchThd);
DestroyPageRedoWorker(g_dispatcher->pageLines[i].managerThd);
@ -580,6 +561,7 @@ static void DestroyRecoveryWorkers()
g_instance.comm_cxt.predo_cxt.parallelRedoCtx = NULL;
}
g_dispatcher = NULL;
SpinLockRelease(&(g_instance.comm_cxt.predo_cxt.destroy_lock));
}
}
@ -631,8 +613,8 @@ void DispatchRedoRecordToFile(XLogReaderState* record, List* expectedTLIs, Times
indexid = g_dispatchTable[rmid].rm_id;
if ((indexid != rmid) ||
((g_dispatchTable[rmid].rm_loginfovalid != NULL) &&
(g_dispatchTable[rmid].rm_loginfovalid(
record, g_dispatchTable[rmid].rm_mininfo, g_dispatchTable[rmid].rm_maxinfo) == false))) {
(g_dispatchTable[rmid].rm_loginfovalid(record, g_dispatchTable[rmid].rm_mininfo,
g_dispatchTable[rmid].rm_maxinfo) == false))) {
/* it's invalid info */
fatalerror = true;
}
@ -641,20 +623,27 @@ void DispatchRedoRecordToFile(XLogReaderState* record, List* expectedTLIs, Times
}
ResetChosedPageLineList();
pg_atomic_write_u64(&(g_instance.comm_cxt.predo_cxt.endRecPtr), record->EndRecPtr);
/* RTO_DEMO */
if (fatalerror != true) {
g_dispatchTable[rmid].rm_dispatch(record, expectedTLIs, recordXTime);
} else {
DispatchDefaultRecord(record, expectedTLIs, recordXTime);
}
if (fatalerror == true) {
/* output panic error info */
DumpDispatcher();
ereport(PANIC,
(errmodule(MOD_REDO),
errcode(ERRCODE_LOG),
errmsg("[REDO_LOG_TRACE]DispatchRedoRecord encounter fatal error:rmgrID:%u, info:%u, indexid:%u",
rmid,
(uint32)XLogRecGetInfo(record),
indexid)));
}
} else {
ereport(PANIC,
(errmodule(MOD_REDO),
errcode(ERRCODE_LOG),
errmsg("[REDO_LOG_TRACE]DispatchRedoRecord could not be here config recovery num %d, work num %u",
get_real_recovery_parallelism(),
GetBatchCount())));
(errmodule(MOD_REDO), errcode(ERRCODE_LOG),
errmsg("[REDO_LOG_TRACE]DispatchRedoRecord could not be here config recovery num %d, work num %u",
get_real_recovery_parallelism(), GetBatchCount())));
}
}
@ -663,22 +652,17 @@ void DispatchRedoRecordToFile(XLogReaderState* record, List* expectedTLIs, Times
* trxnthreadexe is true when the record need execute on trxn thread
* pagethredexe is true when the record need execute on pageworker thread
*/
static void DispatchSyncTxnRecord(
XLogReaderState* record, List* expectedTLIs, TimestampTz recordXTime, uint32 designatedWorker)
static void DispatchSyncTxnRecord(XLogReaderState *record, List *expectedTLIs, TimestampTz recordXTime,
uint32 designatedWorker)
{
RedoItem* item = GetRedoItemPtr(record);
RedoItem *item = GetRedoItemPtr(record);
ReferenceRedoItem(item);
item->sharewithtrxn = true;
item->blockbytrxn = false;
if ((g_dispatcher->chosedPLCnt != 1) && (XLogRecGetRmid(&item->record) != RM_XACT_ID)) {
ereport(WARNING,
(errmodule(MOD_REDO),
errcode(ERRCODE_LOG),
errmsg("[REDO_LOG_TRACE]DispatchSyncTxnRecord maybe some error:rmgrID:%u, info:%u, workerCount:%u",
XLogRecGetRmid(&item->record),
XLogRecGetInfo(&item->record),
g_dispatcher->chosedPLCnt)));
(errmodule(MOD_REDO), errcode(ERRCODE_LOG),
errmsg("[REDO_LOG_TRACE]DispatchSyncTxnRecord maybe some error:rmgrID:%u, info:%u, workerCount:%u",
XLogRecGetRmid(&item->record), XLogRecGetInfo(&item->record), g_dispatcher->chosedPLCnt)));
}
for (uint32 i = 0; i < g_dispatcher->pageLineNum; ++i) {
@ -716,12 +700,11 @@ static void DispatchToOnePageWorker(XLogReaderState* record, const RelFileNode r
* trxn record's recordtime must set , see SetLatestXTime
*/
static void DispatchTxnRecord(
XLogReaderState* record, List* expectedTLIs, TimestampTz recordXTime, bool imcheckpoint, bool isForceAll = false)
static void DispatchTxnRecord(XLogReaderState *record, List *expectedTLIs, TimestampTz recordXTime, bool imcheckpoint,
bool isForceAll = false)
{
RedoItem* trxnItem = GetRedoItemPtr(record);
RedoItem *trxnItem = GetRedoItemPtr(record);
ReferenceRedoItem(trxnItem);
trxnItem->imcheckpoint = imcheckpoint; /* immdiate checkpoint set imcheckpoint */
AddTxnRedoItem(g_dispatcher->trxnLine.managerThd, trxnItem);
}
@ -769,7 +752,11 @@ static bool DispatchXLogRecord(XLogReaderState* record, List* expectedTLIs, Time
if (IsCheckPoint(record)) {
isNeedFullSync = XLogWillChangeStandbyState(record);
RedoItem* item = GetRedoItemPtr(record);
RedoItem *item = GetRedoItemPtr(record);
item->needImmediateCheckpoint = g_dispatcher->needImmediateCheckpoint;
item->record.isFullSyncCheckpoint = g_dispatcher->needFullSyncCheckpoint;
g_dispatcher->needImmediateCheckpoint = false;
g_dispatcher->needFullSyncCheckpoint = false;
ReferenceRedoItem(item);
for (uint32 i = 0; i < g_dispatcher->pageLineNum; ++i) {
/*
@ -915,7 +902,6 @@ static bool DispatchDataBaseRecord(XLogReaderState* record, List* expectedTLIs,
isNeedFullSync = true;
RedoItem* item = GetRedoItemPtr(record);
ReferenceRedoItem(item);
item->imcheckpoint = true;
for (uint32 i = 0; i < g_dispatcher->pageLineNum; i++) {
ReferenceRedoItem(item);
AddPageRedoItem(g_dispatcher->pageLines[i].batchThd, item);
@ -924,24 +910,18 @@ static bool DispatchDataBaseRecord(XLogReaderState* record, List* expectedTLIs,
} else {
/* database dir may impact many rel so need to sync to all pageworks */
DispatchRecordWithoutPage(record, expectedTLIs);
g_dispatcher->needFullSyncCheckpoint = true;
}
g_dispatcher->needImmediateCheckpoint = true;
return isNeedFullSync;
}
static bool DispatchTableSpaceRecord(XLogReaderState* record, List* expectedTLIs, TimestampTz recordXTime)
{
bool isNeedFullSync = false;
uint8 info = (XLogRecGetInfo(record) & (~XLR_INFO_MASK));
if (info == XLOG_TBLSPC_DROP) {
isNeedFullSync = true;
DispatchTxnRecord(record, expectedTLIs, recordXTime, true, isNeedFullSync);
} else {
/* tablespace dir may impact many rel so need to sync to all pageworks */
DispatchRecordWithoutPage(record, expectedTLIs);
}
DispatchRecordWithoutPage(record, expectedTLIs);
g_dispatcher->needImmediateCheckpoint = true;
return isNeedFullSync;
}
@ -1070,21 +1050,18 @@ static bool DispatchBtreeRecord(XLogReaderState* record, List* expectedTLIs, Tim
}
/* Run from the dispatcher thread. */
static bool DispatchGinRecord(XLogReaderState* record, List* expectedTLIs, TimestampTz recordXTime)
static bool DispatchGinRecord(XLogReaderState *record, List *expectedTLIs, TimestampTz recordXTime)
{
bool isNeedFullSync = false;
uint8 info = (XLogRecGetInfo(record) & (~XLR_INFO_MASK));
if (info == XLOG_GIN_DELETE_LISTPAGE) {
ginxlogDeleteListPages* data = (ginxlogDeleteListPages*)XLogRecGetData(record);
ginxlogDeleteListPages *data = (ginxlogDeleteListPages *)XLogRecGetData(record);
/* output warning */
if (data->ndeleted != record->max_block_id) {
ereport(WARNING,
(errmodule(MOD_REDO),
errcode(ERRCODE_LOG),
errmsg("[REDO_LOG_TRACE]DispatchGinRecord warnninginfo:ndeleted:%d, max_block_id:%d",
data->ndeleted,
record->max_block_id)));
ereport(WARNING, (errmodule(MOD_REDO), errcode(ERRCODE_LOG),
errmsg("[REDO_LOG_TRACE]DispatchGinRecord warnninginfo:ndeleted:%d, max_block_id:%d",
data->ndeleted, record->max_block_id)));
}
}
@ -1109,15 +1086,12 @@ static bool DispatchGistRecord(XLogReaderState* record, List* expectedTLIs, Time
bool isNeedFullSync = false;
if (info == XLOG_GIST_PAGE_SPLIT) {
gistxlogPageSplit* xldata = (gistxlogPageSplit*)XLogRecGetData(record);
gistxlogPageSplit *xldata = (gistxlogPageSplit *)XLogRecGetData(record);
/* output warning */
if (xldata->npage != record->max_block_id) {
ereport(WARNING,
(errmodule(MOD_REDO),
errcode(ERRCODE_LOG),
errmsg("[REDO_LOG_TRACE]DispatchGistRecord warnninginfo:npage:%u, max_block_id:%d",
xldata->npage,
record->max_block_id)));
ereport(WARNING, (errmodule(MOD_REDO), errcode(ERRCODE_LOG),
errmsg("[REDO_LOG_TRACE]DispatchGistRecord warnninginfo:npage:%u, max_block_id:%d",
xldata->npage, record->max_block_id)));
}
}
@ -1164,21 +1138,16 @@ static bool DispatchSpgistRecord(XLogReaderState* record, List* expectedTLIs, Ti
/**
* dispatch record to a specified thread
*/
static void DispatchToSpecPageWorker(XLogReaderState* record, List* expectedTLIs, bool waittrxnsync)
static void DispatchToSpecPageWorker(XLogReaderState *record, List *expectedTLIs, bool waittrxnsync)
{
RedoItem* item = GetRedoItemPtr(record);
RedoItem *item = GetRedoItemPtr(record);
ReferenceRedoItem(item);
item->sharewithtrxn = false;
item->blockbytrxn = waittrxnsync;
if (g_dispatcher->chosedPLCnt != 1) {
ereport(WARNING,
(errmodule(MOD_REDO),
errcode(ERRCODE_LOG),
errmsg("[REDO_LOG_TRACE]DispatchToSpecPageWorker maybe some error:rmgrID:%u, info:%u, workerCount:%u",
XLogRecGetRmid(&item->record),
XLogRecGetInfo(&item->record),
g_dispatcher->chosedPLCnt)));
(errmodule(MOD_REDO), errcode(ERRCODE_LOG),
errmsg("[REDO_LOG_TRACE]DispatchToSpecPageWorker maybe some error:rmgrID:%u, info:%u, workerCount:%u",
XLogRecGetRmid(&item->record), XLogRecGetInfo(&item->record), g_dispatcher->chosedPLCnt)));
}
for (uint32 i = 0; i < g_dispatcher->pageLineNum; i++) {
@ -1191,7 +1160,7 @@ static void DispatchToSpecPageWorker(XLogReaderState* record, List* expectedTLIs
DereferenceRedoItem(item);
}
static bool DispatchHeap2VacuumRecord(XLogReaderState* record, List* expectedTLIs, TimestampTz recordXTime)
static bool DispatchHeap2VacuumRecord(XLogReaderState *record, List *expectedTLIs, TimestampTz recordXTime)
{
/*
* don't support consistency view
@ -1208,7 +1177,7 @@ static bool DispatchHeap2VacuumRecord(XLogReaderState* record, List* expectedTLI
return isNeedFullSync;
}
static bool DispatchHeap2VacuumHotStandby(XLogReaderState* record, List* expectedTLIs, TimestampTz recordXTime)
static bool DispatchHeap2VacuumHotStandby(XLogReaderState *record, List *expectedTLIs, TimestampTz recordXTime)
{
/*
* base on mvcc , except vacumm action the record is always exist
@ -1224,7 +1193,7 @@ static bool DispatchHeap2VacuumHotStandby(XLogReaderState* record, List* expecte
/* for parallel redo performance */
if (SUPPORT_FPAGE_DISPATCH) {
uint32 id;
xl_heap_cleanup_info* xlrec = (xl_heap_cleanup_info*)XLogRecGetData(record);
xl_heap_cleanup_info *xlrec = (xl_heap_cleanup_info *)XLogRecGetData(record);
RelFileNode tmp_node;
RelFileNodeCopy(tmp_node, xlrec->node, XLogRecGetBucketId(record));
id = GetSlotId(tmp_node, 0, 0, GetBatchCount());
@ -1241,7 +1210,7 @@ static bool DispatchHeap2VacuumHotStandby(XLogReaderState* record, List* expecte
GetSlotIds(record, ANY_WORKER, SUPPORT_FPAGE_DISPATCH);
if (info == XLOG_HEAP2_CLEAN) {
xl_heap_clean* xlrec = (xl_heap_clean*)XLogRecGetData(record);
xl_heap_clean *xlrec = (xl_heap_clean *)XLogRecGetData(record);
if (InHotStandby && TransactionIdIsValid(xlrec->latestRemovedXid))
isSyncWithTrxn = true;
} else {
@ -1263,7 +1232,7 @@ static bool DispatchHeap2VacuumHotStandby(XLogReaderState* record, List* expecte
}
/* Run from the dispatcher thread. */
static bool DispatchHeap2Record(XLogReaderState* record, List* expectedTLIs, TimestampTz recordXTime)
static bool DispatchHeap2Record(XLogReaderState *record, List *expectedTLIs, TimestampTz recordXTime)
{
bool isNeedFullSync = false;
@ -1296,11 +1265,17 @@ static bool DispatchHeap2Record(XLogReaderState* record, List* expectedTLIs, Tim
DispatchToOnePageWorker(record, tmp_node, expectedTLIs);
} else
DispatchRecordWithoutPage(record, expectedTLIs);
} else {
RedoItem *item = GetRedoItemPtr(record);
FreeRedoItem(item);
}
} else {
if (!g_instance.attr.attr_storage.enable_mix_replication) {
isNeedFullSync = true;
DispatchTxnRecord(record, expectedTLIs, recordXTime, false, isNeedFullSync);
} else {
RedoItem *item = GetRedoItemPtr(record);
FreeRedoItem(item);
}
}
} else {
@ -1355,12 +1330,9 @@ uint32 GetSlotId(const RelFileNode node, BlockNumber block, ForkNumber forkNum,
static void AddSlotToPLSet(uint32 id)
{
if (id >= g_dispatcher->pageLineNum) {
ereport(PANIC,
(errmodule(MOD_REDO),
errcode(ERRCODE_LOG),
errmsg("[REDO_LOG_TRACE]AddWorkerToSet:input work id error, id:%u, batch work num %u",
id,
g_dispatcher->pageLineNum)));
ereport(PANIC, (errmodule(MOD_REDO), errcode(ERRCODE_LOG),
errmsg("[REDO_LOG_TRACE]AddWorkerToSet:input work id error, id:%u, batch work num %u", id,
g_dispatcher->pageLineNum)));
return;
}
@ -1371,14 +1343,14 @@ static void AddSlotToPLSet(uint32 id)
}
/* Run from the dispatcher and each page worker thread. */
bool XactWillRemoveRelFiles(XLogReaderState* record)
bool XactWillRemoveRelFiles(XLogReaderState *record)
{
/*
* Relation files under tablespace folders are removed only from
* applying transaction log record.
*/
int nrels = 0;
ColFileNodeRel* xnodes = NULL;
ColFileNodeRel *xnodes = NULL;
if (XLogRecGetRmid(record) != RM_XACT_ID) {
return false;
@ -1427,17 +1399,17 @@ static bool StandbyWillChangeStandbyState(const XLogReaderState* record)
}
/* Run from each page worker thread. */
void FreeRedoItem(RedoItem* item)
void FreeRedoItem(RedoItem *item)
{
RedoItem* oldHead = (RedoItem*)pg_atomic_read_uintptr((uintptr_t*)&g_dispatcher->freeHead);
RedoItem *oldHead = (RedoItem *)pg_atomic_read_uintptr((uintptr_t *)&g_dispatcher->freeHead);
do {
item->freeNext = oldHead;
} while (!pg_atomic_compare_exchange_uintptr(
(uintptr_t*)&g_dispatcher->freeHead, (uintptr_t*)&oldHead, (uintptr_t)item));
} while (!pg_atomic_compare_exchange_uintptr((uintptr_t *)&g_dispatcher->freeHead, (uintptr_t *)&oldHead,
(uintptr_t)item));
}
void InitReaderStateByOld(XLogReaderState* newState, XLogReaderState* oldState, bool isNew)
void InitReaderStateByOld(XLogReaderState *newState, XLogReaderState *oldState, bool isNew)
{
newState->ReadRecPtr = oldState->ReadRecPtr;
newState->EndRecPtr = oldState->EndRecPtr;
@ -1470,8 +1442,10 @@ void InitReaderStateByOld(XLogReaderState* newState, XLogReaderState* oldState,
newState->blocks[i].data_len = 0;
newState->blocks[i].data_bufsz = 0;
}
newState->refcount = 0;
newState->isDecode = false;
newState->isFullSyncCheckpoint = false;
}
static XLogReaderState* GetXlogReader(XLogReaderState* readerState)
@ -1484,16 +1458,16 @@ static XLogReaderState* GetXlogReader(XLogReaderState* readerState)
retReaderState = &g_dispatcher->freeStateHead->record;
g_dispatcher->freeStateHead = g_dispatcher->freeStateHead->freeNext;
} else {
RedoItem* head =
(RedoItem*)pg_atomic_exchange_uintptr((uintptr_t*)&g_dispatcher->freeHead, (uintptr_t)NULL);
RedoItem *head = (RedoItem *)pg_atomic_exchange_uintptr((uintptr_t *)&g_dispatcher->freeHead,
(uintptr_t)NULL);
if (head != NULL) {
retReaderState = &head->record;
g_dispatcher->freeStateHead = head->freeNext;
} else if (g_dispatcher->maxItemNum > g_dispatcher->curItemNum) {
RedoItem* item =
(RedoItem*)palloc_extended(MAXALIGN(sizeof(RedoItem)) + sizeof(RedoItem*) * GetAllWorkerCount() +
sizeof(bool) * GetAllWorkerCount(),
MCXT_ALLOC_NO_OOM | MCXT_ALLOC_ZERO);
RedoItem *item = (RedoItem *)palloc_extended(MAXALIGN(sizeof(RedoItem)) +
sizeof(RedoItem *) * GetAllWorkerCount() +
sizeof(bool) * GetAllWorkerCount(),
MCXT_ALLOC_NO_OOM | MCXT_ALLOC_ZERO);
if (item != NULL) {
retReaderState = &item->record;
item->allocatedNext = g_dispatcher->allocatedRedoItem;
@ -1505,12 +1479,9 @@ static XLogReaderState* GetXlogReader(XLogReaderState* readerState)
++count;
if ((count & OUTPUT_WAIT_COUNT) == OUTPUT_WAIT_COUNT) {
ereport(WARNING,
(errmodule(MOD_REDO),
errcode(ERRCODE_LOG),
errmsg("GetXlogReader Allocated record buffer failed!, cur item:%u, max item:%u",
g_dispatcher->curItemNum,
g_dispatcher->maxItemNum)));
ereport(WARNING, (errmodule(MOD_REDO), errcode(ERRCODE_LOG),
errmsg("GetXlogReader Allocated record buffer failed!, cur item:%u, max item:%u",
g_dispatcher->curItemNum, g_dispatcher->maxItemNum)));
if ((count & PRINT_ALL_WAIT_COUNT) == PRINT_ALL_WAIT_COUNT) {
DumpDispatcher();
}
@ -1526,7 +1497,7 @@ static XLogReaderState* GetXlogReader(XLogReaderState* readerState)
return retReaderState;
}
void CopyDataFromOldReader(XLogReaderState* newReaderState, const XLogReaderState* oldReaderState)
void CopyDataFromOldReader(XLogReaderState *newReaderState, const XLogReaderState *oldReaderState)
{
errno_t rc = EOK;
if ((newReaderState->readRecordBuf == NULL) ||
@ -1546,13 +1517,13 @@ void CopyDataFromOldReader(XLogReaderState* newReaderState, const XLogReaderStat
oldReaderState->readRecordBuf,
oldReaderState->readRecordBufSize);
securec_check(rc, "\0", "\0");
newReaderState->decoded_record = (XLogRecord*)newReaderState->readRecordBuf;
newReaderState->decoded_record = (XLogRecord *)newReaderState->readRecordBuf;
for (int i = 0; i <= newReaderState->max_block_id; i++) {
if (newReaderState->blocks[i].has_image)
newReaderState->blocks[i].bkp_image =
(char*)((uintptr_t)newReaderState->decoded_record +
((uintptr_t)oldReaderState->blocks[i].bkp_image - (uintptr_t)oldReaderState->decoded_record));
(char *)((uintptr_t)newReaderState->decoded_record +
((uintptr_t)oldReaderState->blocks[i].bkp_image - (uintptr_t)oldReaderState->decoded_record));
if (newReaderState->blocks[i].has_data) {
newReaderState->blocks[i].data = oldReaderState->blocks[i].data;
newReaderState->blocks[i].data_len = oldReaderState->blocks[i].data_len;
@ -1601,10 +1572,10 @@ void FreeAllocatedRedoItem()
/* Run from the dispatcher thread. */
void SendRecoveryEndMarkToWorkersAndWaitForFinish(int code)
{
ereport(LOG,
(errmodule(MOD_REDO),
errcode(ERRCODE_LOG),
errmsg("[REDO_LOG_TRACE]SendRecoveryEndMarkToWorkersAndWaitForFinish, ready to stop redo workers, code: %d",
ereport(
LOG,
(errmodule(MOD_REDO), errcode(ERRCODE_LOG),
errmsg("[REDO_LOG_TRACE]SendRecoveryEndMarkToWorkersAndWaitForFinish, ready to stop redo workers, code: %d",
code)));
if ((get_real_recovery_parallelism() > 1) && (GetBatchCount() > 0)) {
uint32 i;
@ -1619,10 +1590,13 @@ void SendRecoveryEndMarkToWorkersAndWaitForFinish(int code)
for (i = 0; i < g_dispatcher->pageLineNum; i++) {
WaitPageRedoWorkerReachLastMark(pl[i].batchThd);
}
pg_atomic_write_u32(&(g_dispatcher->recordstate.xlogReadManagerState), READ_MANAGER_STOP);
WaitPageRedoWorkerReachLastMark(g_dispatcher->readLine.managerThd);
WaitPageRedoWorkerReachLastMark(g_dispatcher->readLine.readThd);
WaitPageRedoWorkerReachLastMark(g_dispatcher->readLine.readPageThd);
WaitPageRedoWorkerReachLastMark(g_dispatcher->trxnLine.managerThd);
LsnUpdate();
}
}
@ -1721,22 +1695,23 @@ void UpdateStandbyState(HotStandbyState newState)
UpdatePageRedoWorkerStandbyState(g_dispatcher->trxnLine.managerThd, newState);
UpdatePageRedoWorkerStandbyState(g_dispatcher->trxnLine.redoThd, newState);
UpdatePageRedoWorkerStandbyState(g_dispatcher->readLine.managerThd, newState);
UpdatePageRedoWorkerStandbyState(g_dispatcher->readLine.readPageThd, newState);
UpdatePageRedoWorkerStandbyState(g_dispatcher->readLine.readThd, newState);
pg_atomic_write_u32(&(g_dispatcher->standbyState), newState);
}
}
/* Run from the dispatcher thread. */
void** GetXLogInvalidPagesFromWorkers()
void **GetXLogInvalidPagesFromWorkers()
{
return CollectStatesFromWorkers(GetXLogInvalidPages);
}
/* Run from the dispatcher thread. */
static void** CollectStatesFromWorkers(GetStateFunc getStateFunc)
static void **CollectStatesFromWorkers(GetStateFunc getStateFunc)
{
if (g_dispatcher->allWorkersCnt > 0) {
void** stateArray = (void**)palloc(sizeof(void*) * g_dispatcher->allWorkersCnt);
void **stateArray = (void **)palloc(sizeof(void *) * g_dispatcher->allWorkersCnt);
for (uint32 i = 0; i < g_dispatcher->allWorkersCnt; i++)
stateArray[i] = getStateFunc(g_dispatcher->allWorkers[i]);
return stateArray;
@ -1744,7 +1719,7 @@ static void** CollectStatesFromWorkers(GetStateFunc getStateFunc)
return NULL;
}
void DiagLogRedoRecord(XLogReaderState* record, const char* funcName)
void DiagLogRedoRecord(XLogReaderState *record, const char *funcName)
{
uint8 info;
RelFileNode oldRn = {0};
@ -1758,8 +1733,8 @@ void DiagLogRedoRecord(XLogReaderState* record, const char* funcName)
StringInfoData buf;
/* Support redo old version xlog during upgrade (Just the runningxact log with chekpoint online ) */
uint32 rmid = redo_oldversion_xlog ? ((XLogRecordOld*)record->decoded_record)->xl_rmid : XLogRecGetRmid(record);
info = redo_oldversion_xlog ? ((((XLogRecordOld*)record->decoded_record)->xl_info) & ~XLR_INFO_MASK)
uint32 rmid = redo_oldversion_xlog ? ((XLogRecordOld *)record->decoded_record)->xl_rmid : XLogRecGetRmid(record);
info = redo_oldversion_xlog ? ((((XLogRecordOld *)record->decoded_record)->xl_info) & ~XLR_INFO_MASK)
: (XLogRecGetInfo(record) & ~XLR_INFO_MASK);
initStringInfo(&buf);
@ -1772,35 +1747,17 @@ void DiagLogRedoRecord(XLogReaderState* record, const char* funcName)
oldBlkExistFlg = true;
}
ereport(DEBUG4,
(errmodule(MOD_REDO),
errcode(ERRCODE_LOG),
errmsg("[REDO_LOG_TRACE]DiagLogRedoRecord: %s, ReadRecPtr:%lu,EndRecPtr:%lu,"
"newBlkExistFlg:%u,"
"newRn(spcNode:%u, dbNode:%u, relNode:%u),newFk:%d,newblk:%u,"
"oldBlkExistFlg:%d,"
"oldRn(spcNode:%u, dbNode:%u, relNode:%u),oldFk:%d,oldblk:%u,"
"info:%u,redo_oldversion_xlog:%u, rm_name:%s, desc:%s,"
"max_block_id:%d",
funcName,
record->ReadRecPtr,
record->EndRecPtr,
newBlkExistFlg,
newRn.spcNode,
newRn.dbNode,
newRn.relNode,
newFk,
newblk,
oldBlkExistFlg,
oldRn.spcNode,
oldRn.dbNode,
oldRn.relNode,
oldFk,
oldblk,
info,
redo_oldversion_xlog,
RmgrTable[rmid].rm_name,
buf.data,
record->max_block_id)));
(errmodule(MOD_REDO), errcode(ERRCODE_LOG),
errmsg("[REDO_LOG_TRACE]DiagLogRedoRecord: %s, ReadRecPtr:%lu,EndRecPtr:%lu,"
"newBlkExistFlg:%u,"
"newRn(spcNode:%u, dbNode:%u, relNode:%u),newFk:%d,newblk:%u,"
"oldBlkExistFlg:%d,"
"oldRn(spcNode:%u, dbNode:%u, relNode:%u),oldFk:%d,oldblk:%u,"
"info:%u,redo_oldversion_xlog:%u, rm_name:%s, desc:%s,"
"max_block_id:%d",
funcName, record->ReadRecPtr, record->EndRecPtr, newBlkExistFlg, newRn.spcNode, newRn.dbNode,
newRn.relNode, newFk, newblk, oldBlkExistFlg, oldRn.spcNode, oldRn.dbNode, oldRn.relNode, oldFk,
oldblk, info, redo_oldversion_xlog, RmgrTable[rmid].rm_name, buf.data, record->max_block_id)));
pfree_ext(buf.data);
}
@ -1838,4 +1795,32 @@ void GetReplayedRecPtr(XLogRecPtr* startPtr, XLogRecPtr* endPtr)
*endPtr = minEnd;
}
RedoWaitInfo redo_get_io_event(int32 event_id)
{
RedoWaitInfo waitInfo;
waitInfo.counter = 0;
waitInfo.total_duration = 0;
return waitInfo;
}
void redo_get_wroker_statistic(uint32 *realNum, RedoWorkerStatsData *worker, uint32 workerLen)
{
PageRedoWorker *redoWorker = NULL;
SpinLockAcquire(&(g_instance.comm_cxt.predo_cxt.destroy_lock));
if (g_dispatcher == NULL) {
SpinLockRelease(&(g_instance.comm_cxt.predo_cxt.destroy_lock));
*realNum = 0;
return;
}
*realNum = g_dispatcher->pageLineNum;
for (uint32 i = 0; i < g_dispatcher->pageLineNum; i++) {
redoWorker = (g_dispatcher->pageLines[i].batchThd);
worker[i].id = redoWorker->id;
worker[i].queue_usage = SPSCGetQueueCount(redoWorker->queue);
worker[i].queue_max_usage = (uint32)(pg_atomic_read_u32(&((redoWorker->queue)->maxUsage)));
worker[i].redo_rec_count = (uint32)(pg_atomic_read_u64(&((redoWorker->queue)->totalCnt)));
}
SpinLockRelease(&(g_instance.comm_cxt.predo_cxt.destroy_lock));
}
} // namespace extreme_rto

View File

@ -43,24 +43,6 @@
namespace extreme_rto {
extern void FreeRedoItem(RedoItem* item);
static const uint32 LSN_MARKER = 0;
inline void InitNextByWorker(RedoItem** nextByWorker)
{
for (uint32 i = 0; i < GetAllWorkerCount(); i++) {
nextByWorker[i] = NULL;
}
}
inline void InitIsInWorker(bool* isInWorker)
{
for (uint32 i = 0; i < GetAllWorkerCount(); i++) {
isInWorker[i] = false;
}
}
/* Run from the dispatcher thread. */
RedoItem* CreateRedoItem(XLogReaderState* record, uint32 shareCount, uint32 designatedWorker, List* expectedTLIs,
TimestampTz recordXTime, bool buseoriginal, bool isForceAll)
@ -85,16 +67,13 @@ RedoItem* CreateRedoItem(XLogReaderState* record, uint32 shareCount, uint32 desi
}
item->oldVersion = t_thrd.xlog_cxt.redo_oldversion_xlog;
item->sharewithtrxn = false;
item->blockbytrxn = false;
item->imcheckpoint = false;
item->needImmediateCheckpoint = false;
item->needFullSyncCheckpoint = false;
item->shareCount = shareCount;
item->rdsCnt = 0;
item->designatedWorker = designatedWorker;
item->expectedTLIs = expectedTLIs;
item->recordXTime = recordXTime;
item->freeNext = NULL;
item->contextUpdateOp.inUse = false;
item->syncXLogReceiptTime = t_thrd.xlog_cxt.XLogReceiptTime;
item->syncXLogReceiptSource = t_thrd.xlog_cxt.XLogReceiptSource;
item->RecentXmin = u_sess->utils_cxt.RecentXmin;
@ -102,61 +81,11 @@ RedoItem* CreateRedoItem(XLogReaderState* record, uint32 shareCount, uint32 desi
item->isForceAll = isForceAll;
pg_atomic_init_u32(&item->refCount, shareCount);
pg_atomic_init_u32(&item->replayed, 0);
item->nextByWorker = (RedoItem**)(((uintptr_t)item) + MAXALIGN(sizeof(RedoItem)));
pg_atomic_init_u32(&item->blkShareCount, 0);
pg_atomic_init_u32(&item->distributeCount, shareCount);
InitNextByWorker(item->nextByWorker);
item->isInWorker =
(bool*)(((uintptr_t)item) + MAXALIGN(sizeof(RedoItem)) + sizeof(RedoItem*) * GetAllWorkerCount());
InitIsInWorker(item->isInWorker);
return item;
}
/* Run from the dispatcher thread. */
RedoItem* CreateLSNMarker(XLogReaderState* record, List* expectedTLIs, bool buseoriginal)
{
RedoItem* item = NULL;
if (buseoriginal && (t_thrd.xlog_cxt.redoItemIdx == 0)) {
item = GetRedoItemPtr(record);
t_thrd.xlog_cxt.redoItemIdx++;
} else {
/* don't need to copy data, only need copy state */
item = GetRedoItemPtr(NewReaderState(record, false));
}
item->oldVersion = t_thrd.xlog_cxt.redo_oldversion_xlog;
item->sharewithtrxn = false;
item->blockbytrxn = false;
item->imcheckpoint = false;
item->shareCount = LSN_MARKER;
item->rdsCnt = 0;
item->expectedTLIs = expectedTLIs;
item->freeNext = NULL;
item->contextUpdateOp.inUse = false;
item->syncXLogReceiptTime = t_thrd.xlog_cxt.XLogReceiptTime;
item->syncXLogReceiptSource = t_thrd.xlog_cxt.XLogReceiptSource;
item->RecentXmin = u_sess->utils_cxt.RecentXmin;
item->syncServerMode = GetServerMode();
item->isForceAll = false;
pg_atomic_init_u32(&item->refCount, 1);
item->nextByWorker = (RedoItem**)(((uintptr_t)item) + MAXALIGN(sizeof(RedoItem)));
InitNextByWorker(item->nextByWorker);
item->isInWorker =
(bool*)(((uintptr_t)item) + MAXALIGN(sizeof(RedoItem)) + sizeof(RedoItem*) * GetAllWorkerCount());
InitIsInWorker(item->isInWorker);
return item;
}
/* Run from each page worker thread. */
bool IsLSNMarker(const RedoItem* item)
{
return item->shareCount == LSN_MARKER;
}
void ApplyRedoRecord(XLogReaderState* record, bool bOld)
{
t_thrd.xlog_cxt.redo_oldversion_xlog = bOld;

View File

@ -92,6 +92,7 @@ bool SPSCBlockingQueuePut(SPSCBlockingQueue* queue, void* element)
do {
tail = pg_atomic_read_u32(&queue->readTail);
cnt++;
HandlePageRedoInterrupts();
} while (SPACE(head, tail, queue->mask) == 0);
/*

View File

@ -47,248 +47,10 @@
#include "catalog/pg_control.h"
namespace extreme_rto {
struct TxnRedoWorker {
RedoItem* pendingHead; /* The head of the RedoItem list. */
RedoItem* pendingTail; /* The tail of the RedoItem list. */
RedoItem* procHead;
RedoItem* procTail;
};
TxnRedoWorker* StartTxnRedoWorker()
{
TxnRedoWorker* worker = (TxnRedoWorker*)palloc(sizeof(TxnRedoWorker));
worker->pendingHead = NULL;
worker->pendingTail = NULL;
worker->procHead = NULL;
worker->procTail = NULL;
return worker;
}
bool IsTxnWorkerIdle(TxnRedoWorker* worker)
{
return ((worker->procHead == NULL) && (worker->procTail == NULL));
}
void DestroyTxnRedoWorker(TxnRedoWorker* worker)
{
pfree(worker);
}
XLogRecPtr GetReplayedRecPtrFromWorkers()
{
XLogRecPtr minLastReplayedEndRecPtr = MAX_XLOG_REC_PTR;
for (uint32 i = 0; i < g_dispatcher->pageLineNum; i++) {
if (!RedoWorkerIsIdle(g_dispatcher->pageLines[i].batchThd)) {
XLogRecPtr lastReplayedLSN = GetCompletedRecPtr(g_dispatcher->pageLines[i].batchThd);
if (XLByteLT(lastReplayedLSN, minLastReplayedEndRecPtr)) {
minLastReplayedEndRecPtr = lastReplayedLSN;
}
}
}
return minLastReplayedEndRecPtr;
}
XLogRecPtr TrxnStageGetReplayedRecPtrFromWorkers()
{
XLogRecPtr minLastReplayedEndRecPtr = MAX_XLOG_REC_PTR;
for (uint32 i = 0; i < g_dispatcher->pageLineNum; i++) {
if (!RedoWorkerIsIdle(g_dispatcher->pageLines[i].batchThd)) {
XLogRecPtr lastReplayedLSN = GetCompletedRecPtr(g_dispatcher->pageLines[i].batchThd);
if (XLByteLT(lastReplayedLSN, minLastReplayedEndRecPtr)) {
minLastReplayedEndRecPtr = lastReplayedLSN;
}
}
}
if (!RedoWorkerIsIdle(g_dispatcher->trxnLine.redoThd)) {
XLogRecPtr lastReplayedLSN = GetCompletedRecPtr(g_dispatcher->trxnLine.redoThd);
if (XLByteLT(lastReplayedLSN, minLastReplayedEndRecPtr)) {
minLastReplayedEndRecPtr = lastReplayedLSN;
}
}
return minLastReplayedEndRecPtr;
}
XLogRecPtr TestStageGetReplayedRecPtrFromWorkers()
{
XLogRecPtr minLastReplayedEndRecPtr = MAX_XLOG_REC_PTR;
for (uint32 i = 0; i < g_dispatcher->pageLineNum; i++) {
if (!RedoWorkerIsIdle(g_dispatcher->pageLines[i].batchThd)) {
XLogRecPtr lastReplayedLSN = GetCompletedRecPtr(g_dispatcher->pageLines[i].batchThd);
if (XLByteLT(lastReplayedLSN, minLastReplayedEndRecPtr)) {
minLastReplayedEndRecPtr = lastReplayedLSN;
}
}
}
if (!RedoWorkerIsIdle(g_dispatcher->trxnLine.redoThd)) {
XLogRecPtr lastReplayedLSN = GetCompletedRecPtr(g_dispatcher->trxnLine.redoThd);
if (XLByteLT(lastReplayedLSN, minLastReplayedEndRecPtr)) {
minLastReplayedEndRecPtr = lastReplayedLSN;
}
}
return minLastReplayedEndRecPtr;
}
void TestSetLastReplayedPtr(XLogRecPtr ReadRecPtr, XLogRecPtr EndRecPtr)
{
XLogRecPtr tmpEndPtr = TestStageGetReplayedRecPtrFromWorkers();
if (XLByteLT(tmpEndPtr, EndRecPtr)) {
SetXLogReplayRecPtr(tmpEndPtr, tmpEndPtr);
} else {
SetXLogReplayRecPtr(ReadRecPtr, EndRecPtr);
}
}
void TrxnSetLastReplayedPtr(XLogRecPtr ReadRecPtr, XLogRecPtr EndRecPtr)
{
XLogRecPtr tmpEndPtr = TrxnStageGetReplayedRecPtrFromWorkers();
if (XLByteLT(tmpEndPtr, EndRecPtr)) {
SetXLogReplayRecPtr(tmpEndPtr, tmpEndPtr);
} else {
SetXLogReplayRecPtr(ReadRecPtr, EndRecPtr);
}
}
extern THR_LOCAL PageRedoWorker* g_redoWorker;
void TestSetLastReplayedPtrComm()
{
if (g_redoWorker->role != REDO_TRXN_MNG) {
return;
}
XLogRecPtr endPtr = pg_atomic_read_u64(&(g_instance.comm_cxt.predo_cxt.endRecPtr));
TestSetLastReplayedPtr(endPtr, endPtr);
}
void AddTxnRedoItem(PageRedoWorker* worker, void* item)
void AddTxnRedoItem(PageRedoWorker *worker, void *item)
{
(void)SPSCBlockingQueuePut(worker->queue, item);
}
void ApplyReadyTxnShareLogRecords(RedoItem* item)
{
if (item->shareCount <= 1) {
ereport(PANIC,
(errmodule(MOD_REDO),
errcode(ERRCODE_LOG),
errmsg("[REDO_LOG_TRACE]ApplyReadyTxnShareLogRecords encounter fatal error:rmgrID:%u, "
"info:%u, sharcount:%u",
XLogRecGetRmid(&item->record),
XLogRecGetInfo(&item->record),
item->shareCount)));
}
(void)pg_atomic_add_fetch_u32(&item->refCount, 1);
if ((item->designatedWorker == ALL_WORKER) || (item->designatedWorker == TRXN_WORKER)) {
pg_memory_barrier();
/* must be the last one */
MemoryContext oldCtx = MemoryContextSwitchTo(g_dispatcher->oldCtx);
ApplyRedoRecord(&item->record, item->oldVersion);
(void)MemoryContextSwitchTo(oldCtx);
pg_memory_barrier();
pg_atomic_write_u32(&item->replayed, 1); /* notify other pageworker continue */
} else {
/* panic error */
ereport(PANIC,
(errmodule(MOD_REDO),
errcode(ERRCODE_LOG),
errmsg("[REDO_LOG_TRACE]ApplyReadyTxnShareLogRecords encounter fatal error:rmgrID:%u, "
"info:%u, designatedWorker:%u",
XLogRecGetRmid(&item->record),
XLogRecGetInfo(&item->record),
item->designatedWorker)));
}
FreeRedoItem(item);
}
void ApplyReadyAllShareLogRecords(RedoItem* item)
{
if (item->shareCount != (GetBatchCount() + 1)) {
/* panic */
ereport(PANIC,
(errmodule(MOD_REDO),
errcode(ERRCODE_LOG),
errmsg("[REDO_LOG_TRACE]ApplyReadyAllShareLogRecords encounter fatal error:rmgrID:%u, "
"info:%u, sharcount:%u",
XLogRecGetRmid(&item->record),
XLogRecGetInfo(&item->record),
item->shareCount)));
}
uint32 refCount = pg_atomic_add_fetch_u32(&item->refCount, 1);
pg_memory_barrier();
uint64 waitCount = 0;
pgstat_report_waitevent(WAIT_EVENT_PREDO_APPLY);
/* must be the last one */
while (refCount != item->shareCount) {
++waitCount;
refCount = pg_atomic_read_u32(&item->refCount);
if ((waitCount & OUTPUT_WAIT_COUNT) == OUTPUT_WAIT_COUNT) {
ereport(PANIC,
(errmodule(MOD_REDO),
errcode(ERRCODE_LOG),
errmsg("[REDO_LOG_TRACE]ApplyReadyAllShareLogRecords encounter fatal error:rmgrID:%u, info:%u, "
"sharcount:%u, refcount:%u",
XLogRecGetRmid(&item->record),
XLogRecGetInfo(&item->record),
item->shareCount,
refCount)));
}
HandleStartupProcInterrupts();
}
pgstat_report_waitevent(WAIT_EVENT_END);
MemoryContext oldCtx = MemoryContextSwitchTo(g_dispatcher->oldCtx);
ApplyRedoRecord(&item->record, item->oldVersion);
(void)MemoryContextSwitchTo(oldCtx);
FreeRedoItem(item);
}
void ProcTxnItem(RedoItem* item)
{
XLogRecPtr EndRecPtr = item->record.EndRecPtr; /* end+1 of last record read */
TimestampTz recordXTime = item->recordXTime;
bool imcheckpoint = item->imcheckpoint;
if (!IsLSNMarker(item)) {
if (item->sharewithtrxn) {
ApplyReadyTxnShareLogRecords(item);
} else if ((item->shareCount == (GetBatchCount() + 1)) && (item->designatedWorker == ALL_WORKER)) {
/* checkpoint and drop database */
ApplyReadyAllShareLogRecords(item);
} else {
MemoryContext oldCtx = MemoryContextSwitchTo(g_dispatcher->oldCtx);
ApplyRedoRecord(&item->record, item->oldVersion);
(void)MemoryContextSwitchTo(oldCtx);
FreeRedoItem(item);
}
if (recordXTime != 0) {
SetLatestXTime(recordXTime);
}
} else {
FreeRedoItem(item);
}
pg_atomic_write_u64(&g_redoWorker->lastReplayedEndRecPtr, EndRecPtr);
/* update immediate checkpoint */
if (imcheckpoint)
t_thrd.xlog_cxt.needImmediateCkp = true;
}
void TrxnMngProc(RedoItem* item)
{
AddTxnRedoItem(g_dispatcher->trxnLine.redoThd, item);
}
void TrxnWorkerProc(RedoItem* item)
{
ProcTxnItem(item);
}
} // namespace extreme_rto

View File

@ -57,13 +57,38 @@ bool IsExtremeRtoRunning()
extreme_rto::g_dispatcher->pageLineNum > 0);
}
bool IsExtremeRtoSmartShutdown()
{
if (!IsExtremeRtoRunning()) {
return false;
}
if (extreme_rto::g_dispatcher->smartShutdown) {
extreme_rto::g_dispatcher->smartShutdown =false;
return true;
}
return false;
}
void ExtremeRtoRedoManagerSendEndToStartup()
{
if (!IsExtremeRtoRunning()) {
return;
}
extreme_rto::g_redoEndMark.record.isDecode = true;
extreme_rto::PutRecordToReadQueue((XLogReaderState *)&extreme_rto::g_redoEndMark.record);
}
bool IsExtremeRtoReadWorkerRunning()
{
if (!IsExtremeRtoRunning()) {
return false;
}
if (pg_atomic_read_u32(&extreme_rto::g_dispatcher->recordstate.startreadworker) != extreme_rto::READ_WORKER_RUN) {
uint32 readWorkerState = pg_atomic_read_u32(&extreme_rto::g_dispatcher->recordstate.readWorkerState);
if (readWorkerState == extreme_rto::WORKER_STATE_STOP || readWorkerState == extreme_rto::WORKER_STATE_EXIT) {
return false;
}
@ -311,3 +336,21 @@ void SendRecoveryEndMarkToWorkersAndWaitForFinish(int code)
return parallel_recovery::SendRecoveryEndMarkToWorkersAndWaitForFinish(code);
}
}
RedoWaitInfo GetRedoIoEvent(int32 event_id)
{
if (IsExtremeRedo()) {
return extreme_rto::redo_get_io_event(event_id);
} else {
return parallel_recovery::redo_get_io_event(event_id);
}
}
void GetRedoWrokerStatistic(uint32 *realNum, RedoWorkerStatsData *worker, uint32 workerLen)
{
if (IsExtremeRedo()) {
extreme_rto::redo_get_wroker_statistic(realNum, worker, workerLen);
} else {
parallel_recovery::redo_get_wroker_statistic(realNum, worker, workerLen);
}
}

View File

@ -2045,8 +2045,10 @@ void multixact_redo(XLogReaderState* record)
*/
if (TransactionIdFollowsOrEquals(max_xid, t_thrd.xact_cxt.ShmemVariableCache->nextXid)) {
(void)LWLockAcquire(XidGenLock, LW_EXCLUSIVE);
t_thrd.xact_cxt.ShmemVariableCache->nextXid = max_xid;
TransactionIdAdvance(t_thrd.xact_cxt.ShmemVariableCache->nextXid);
if (TransactionIdFollowsOrEquals(max_xid, t_thrd.xact_cxt.ShmemVariableCache->nextXid)) {
t_thrd.xact_cxt.ShmemVariableCache->nextXid = max_xid;
TransactionIdAdvance(t_thrd.xact_cxt.ShmemVariableCache->nextXid);
}
LWLockRelease(XidGenLock);
}
} else

View File

@ -504,12 +504,14 @@ static void StopRecoveryWorkers(int code, Datum arg)
static void DestroyRecoveryWorkers()
{
if (g_dispatcher != NULL) {
SpinLockAcquire(&(g_instance.comm_cxt.predo_cxt.destroy_lock));
for (uint32 i = 0; i < g_dispatcher->totalWorkerCount; i++)
DestroyPageRedoWorker(g_dispatcher->pageWorkers[i]);
if (g_dispatcher->txnWorker != NULL)
DestroyTxnRedoWorker(g_dispatcher->txnWorker);
if (g_dispatcher->chosedWorkerIds != NULL) {
pfree(g_dispatcher->chosedWorkerIds);
g_dispatcher->chosedWorkerIds = NULL;
}
if (get_real_recovery_parallelism() > 1) {
MemoryContextSwitchTo(g_dispatcher->oldCtx);
@ -517,6 +519,7 @@ static void DestroyRecoveryWorkers()
g_instance.comm_cxt.predo_cxt.parallelRedoCtx = NULL;
}
g_dispatcher = NULL;
SpinLockRelease(&(g_instance.comm_cxt.predo_cxt.destroy_lock));
}
}
@ -1781,7 +1784,9 @@ void redo_get_wroker_statistic(uint32* realNum, RedoWorkerStatsData* worker, uin
{
PageRedoWorker* redoWorker = NULL;
Assert(workerLen == MAX_RECOVERY_THREAD_NUM);
SpinLockAcquire(&(g_instance.comm_cxt.predo_cxt.destroy_lock));
if (g_dispatcher == NULL) {
SpinLockRelease(&(g_instance.comm_cxt.predo_cxt.destroy_lock));
*realNum = 0;
return;
}
@ -1793,6 +1798,7 @@ void redo_get_wroker_statistic(uint32* realNum, RedoWorkerStatsData* worker, uin
worker[i].queue_max_usage = (uint32)(pg_atomic_read_u32(&((redoWorker->queue)->maxUsage)));
worker[i].redo_rec_count = (uint32)(pg_atomic_read_u64(&((redoWorker->queue)->totalCnt)));
}
SpinLockRelease(&(g_instance.comm_cxt.predo_cxt.destroy_lock));
}
RedoWaitInfo redo_get_io_event(int32 event_id)
@ -1802,26 +1808,28 @@ RedoWaitInfo redo_get_io_event(int32 event_id)
PgBackendStatus* beentry = NULL;
int index = MAX_BACKEND_SLOT + StartupProcess;
if (IS_PGSTATE_TRACK_UNDEFINE || PgBackendStatusArray == NULL) {
if (IS_PGSTATE_TRACK_UNDEFINE || t_thrd.shemem_ptr_cxt.BackendStatusArray == NULL) {
return result_info;
}
beentry = &(PgBackendStatusArray[index]);
beentry = t_thrd.shemem_ptr_cxt.BackendStatusArray + index;
tmp_io = beentry->waitInfo.event_info.io_info[event_id - WAIT_EVENT_BUFFILE_READ];
result_info.total_duration = tmp_io.total_duration;
result_info.counter = tmp_io.counter;
SpinLockAcquire(&(g_instance.comm_cxt.predo_cxt.destroy_lock));
if (g_dispatcher == NULL || event_id == WAIT_EVENT_WAL_READ || event_id == WAIT_EVENT_PREDO_PROCESS_PENDING) {
SpinLockRelease(&(g_instance.comm_cxt.predo_cxt.destroy_lock));
return result_info;
}
for (uint32 i = 0; i < g_dispatcher->pageWorkerCount; i++) {
index = g_dispatcher->pageWorkers[i]->index;
beentry = &(PgBackendStatusArray[index]);
beentry = t_thrd.shemem_ptr_cxt.BackendStatusArray + index;
tmp_io = beentry->waitInfo.event_info.io_info[event_id - WAIT_EVENT_BUFFILE_READ];
result_info.total_duration += tmp_io.total_duration;
result_info.counter += tmp_io.counter;
}
SpinLockRelease(&(g_instance.comm_cxt.predo_cxt.destroy_lock));
return result_info;
}

View File

@ -6854,8 +6854,10 @@ static void xact_redo_commit_internal(TransactionId xid, XLogRecPtr lsn, Transac
*/
if (TransactionIdFollowsOrEquals(max_xid, t_thrd.xact_cxt.ShmemVariableCache->nextXid)) {
(void)LWLockAcquire(XidGenLock, LW_EXCLUSIVE);
t_thrd.xact_cxt.ShmemVariableCache->nextXid = max_xid;
TransactionIdAdvance(t_thrd.xact_cxt.ShmemVariableCache->nextXid);
if (TransactionIdFollowsOrEquals(max_xid, t_thrd.xact_cxt.ShmemVariableCache->nextXid)) {
t_thrd.xact_cxt.ShmemVariableCache->nextXid = max_xid;
TransactionIdAdvance(t_thrd.xact_cxt.ShmemVariableCache->nextXid);
}
LWLockRelease(XidGenLock);
}
@ -7145,8 +7147,10 @@ static void xact_redo_abort(xl_xact_abort* xlrec, TransactionId xid, XLogRecPtr
*/
if (TransactionIdFollowsOrEquals(max_xid, t_thrd.xact_cxt.ShmemVariableCache->nextXid)) {
(void)LWLockAcquire(XidGenLock, LW_EXCLUSIVE);
t_thrd.xact_cxt.ShmemVariableCache->nextXid = max_xid;
TransactionIdAdvance(t_thrd.xact_cxt.ShmemVariableCache->nextXid);
if (TransactionIdFollowsOrEquals(max_xid, t_thrd.xact_cxt.ShmemVariableCache->nextXid)) {
t_thrd.xact_cxt.ShmemVariableCache->nextXid = max_xid;
TransactionIdAdvance(t_thrd.xact_cxt.ShmemVariableCache->nextXid);
}
LWLockRelease(XidGenLock);
}
@ -7192,8 +7196,10 @@ static void xact_redo_prepare(TransactionId xid)
{
if (TransactionIdFollowsOrEquals(xid, t_thrd.xact_cxt.ShmemVariableCache->nextXid)) {
(void)LWLockAcquire(XidGenLock, LW_EXCLUSIVE);
t_thrd.xact_cxt.ShmemVariableCache->nextXid = xid;
TransactionIdAdvance(t_thrd.xact_cxt.ShmemVariableCache->nextXid);
if (TransactionIdFollowsOrEquals(xid, t_thrd.xact_cxt.ShmemVariableCache->nextXid)) {
t_thrd.xact_cxt.ShmemVariableCache->nextXid = xid;
TransactionIdAdvance(t_thrd.xact_cxt.ShmemVariableCache->nextXid);
}
LWLockRelease(XidGenLock);
}
}

View File

@ -185,6 +185,8 @@ struct config_enum_entry sync_method_options[] = {
};
XLogRecPtr latestValidRecord = InvalidXLogRecPtr;
pg_crc32 latestRecordCrc = InvalidXLogRecPtr;
XLogSegNo XlogRemoveSegPrimary = InvalidXLogSegPtr;
/* The nextXid and oldestXid in ShmemVariableCache when recovery done */
@ -464,7 +466,7 @@ void update_dirty_page_queue_rec_lsn(XLogRecPtr current_insert_lsn, bool need_im
#define UsableBytesInPage (XLOG_BLCKSZ - SizeOfXLogShortPHD)
#define UsableBytesInSegment \
((XLOG_SEG_SIZE / XLOG_BLCKSZ) * UsableBytesInPage - (SizeOfXLogLongPHD - SizeOfXLogShortPHD))
static const int XLOG_PARALLEL_READREC_MAXTRY = 10;
/*
* Add xlog reader private structure for page read.
*/
@ -566,6 +568,8 @@ static void WALInsertLockUpdateInsertingAt(XLogRecPtr insertingAt);
static XLogRecPtr XLogInsertRecordSingle(XLogRecData* rdata, XLogRecPtr fpw_lsn, bool isupgrade);
int ParallelXLogPageRead(XLogReaderState *xlogreader, XLogRecPtr targetPagePtr, int reqLen, XLogRecPtr targetRecPtr,
char *readBuf, TimeLineID *readTLI);
#ifdef __aarch64__
static XLogRecPtr XLogInsertRecordGroup(XLogRecData* rdata, XLogRecPtr fpw_lsn);
@ -4916,8 +4920,8 @@ inline static XLogReaderState* ReadNextRecordFromQueue(int emode)
{
char* errormsg = NULL;
bool readoldversion = false;
extreme_rto::SPSCBlockingQueue* linequeue = extreme_rto::g_dispatcher->readLine.managerThd->queue;
XLogReaderState* xlogreader = NULL;
extreme_rto::SPSCBlockingQueue *linequeue = extreme_rto::g_dispatcher->readLine.readPageThd->queue;
XLogReaderState *xlogreader = NULL;
do {
xlogreader = (XLogReaderState*)extreme_rto::SPSCBlockingQueueTake(linequeue);
if (!xlogreader->isDecode) {
@ -4925,10 +4929,8 @@ inline static XLogReaderState* ReadNextRecordFromQueue(int emode)
;
if (!DecodeXLogRecord(xlogreader, record, &errormsg, readoldversion)) {
ereport(emode,
(errmsg("ReadNextRecordFromQueue %X/%X decode error, %s",
(uint32)(xlogreader->EndRecPtr >> 32),
(uint32)(xlogreader->EndRecPtr),
errormsg)));
(errmsg("ReadNextRecordFromQueue %X/%X decode error, %s", (uint32)(xlogreader->EndRecPtr >> 32),
(uint32)(xlogreader->EndRecPtr), errormsg)));
extreme_rto::RedoItem* item = extreme_rto::GetRedoItemPtr(xlogreader);
extreme_rto::FreeRedoItem(item);
@ -4937,16 +4939,19 @@ inline static XLogReaderState* ReadNextRecordFromQueue(int emode)
}
}
if ((void*)xlogreader == (void*)&(extreme_rto::g_GlobalLsnForwarder.record)) {
extreme_rto::StartupSendLsnFowarder();
if ((void *)xlogreader == (void *)&(extreme_rto::g_GlobalLsnForwarder.record)) {
extreme_rto::StartupSendFowarder(extreme_rto::GetRedoItemPtr(xlogreader));
xlogreader = NULL;
}
/* check for primary */
uint32 triggeredstate = pg_atomic_read_u32(&(extreme_rto::g_triggeredstate));
uint32 triggeredstate = pg_atomic_read_u32(&(extreme_rto::g_startupTriggerState));
uint32 newtriggered = CheckForSatartupStatus();
if (triggeredstate != newtriggered) {
pg_atomic_write_u32(&(extreme_rto::g_triggeredstate), newtriggered);
if (newtriggered != extreme_rto::TRIGGER_NORMAL && triggeredstate != newtriggered) {
ereport(LOG, (errmodule(MOD_REDO), errcode(ERRCODE_LOG),
errmsg("ReadNextRecordFromQueue:g_startupTriggerState set from %u to %u",
triggeredstate, newtriggered)));
pg_atomic_write_u32(&(extreme_rto::g_startupTriggerState), newtriggered);
}
} while (xlogreader == NULL);
@ -4969,9 +4974,12 @@ static XLogRecord* ReadNextXLogRecord(XLogReaderState** xlogreaderptr, int emode
/* Great, got a record */
record = (XLogRecord*)xlogreader->readRecordBuf;
t_thrd.xlog_cxt.latestRecordCrc = record->xl_crc;
latestRecordCrc = record->xl_crc;
} else {
*xlogreaderptr = &extreme_rto::g_redoEndMark.record;
if (t_thrd.startup_cxt.shutdown_requested) {
proc_exit(0);
}
}
return record;
}
@ -5065,8 +5073,7 @@ static XLogRecord* ReadRecord(
if (record != NULL) {
/* Set up lastest valid record */
latestValidRecord = t_thrd.xlog_cxt.ReadRecPtr;
t_thrd.xlog_cxt.latestRecordCrc = record->xl_crc;
latestRecordCrc = record->xl_crc;
/* Great, got a record */
return record;
} else {
@ -5189,8 +5196,8 @@ int ParallelReadPageInternal(XLogReaderState* state, XLogRecPtr pageptr, int req
* First, read the requested data length, but at least a short page header
* so that we can validate it.
*/
readLen = state->read_page(
state, pageptr, Max(reqLen, (int)SizeOfXLogShortPHD), state->currRecPtr, state->readBuf, &state->readPageTLI);
readLen = ParallelXLogPageRead(state, pageptr, Max(reqLen, (int)SizeOfXLogShortPHD), state->currRecPtr,
state->readBuf, &state->readPageTLI);
if (readLen < 0) {
goto err;
}
@ -5212,8 +5219,8 @@ int ParallelReadPageInternal(XLogReaderState* state, XLogRecPtr pageptr, int req
/* still not enough */
if (readLen < (int)XLogPageHeaderSize(hdr)) {
readLen = state->read_page(
state, pageptr, XLogPageHeaderSize(hdr), state->currRecPtr, state->readBuf, &state->readPageTLI);
readLen = ParallelXLogPageRead(state, pageptr, XLogPageHeaderSize(hdr), state->currRecPtr, state->readBuf,
&state->readPageTLI);
if (readLen < 0) {
goto err;
}
@ -5545,6 +5552,34 @@ err:
return NULL;
}
static void UpdateMinrecoveryInAchive()
{
volatile XLogCtlData *xlogctl = t_thrd.shemem_ptr_cxt.XLogCtl;
XLogRecPtr newMinRecoveryPoint;
/* initialize minRecoveryPoint to this record */
LWLockAcquire(ControlFileLock, LW_EXCLUSIVE);
t_thrd.shemem_ptr_cxt.ControlFile->state = DB_IN_ARCHIVE_RECOVERY;
SpinLockAcquire(&xlogctl->info_lck);
newMinRecoveryPoint = xlogctl->lastReplayedEndRecPtr;
SpinLockRelease(&xlogctl->info_lck);
if (XLByteLT(t_thrd.shemem_ptr_cxt.ControlFile->minRecoveryPoint, newMinRecoveryPoint)) {
t_thrd.shemem_ptr_cxt.ControlFile->minRecoveryPoint = newMinRecoveryPoint;
}
/* update local copy */
t_thrd.xlog_cxt.minRecoveryPoint = t_thrd.shemem_ptr_cxt.ControlFile->minRecoveryPoint;
g_instance.comm_cxt.predo_cxt.redoPf.min_recovery_point = t_thrd.xlog_cxt.minRecoveryPoint;
UpdateControlFile();
LWLockRelease(ControlFileLock);
ereport(LOG, (errmsg("update minrecovery point to %X/%X in archive recovery",
(uint32)(t_thrd.xlog_cxt.minRecoveryPoint >> 32),
(uint32)(t_thrd.xlog_cxt.minRecoveryPoint))));
}
XLogRecord* XLogParallelReadNextRecord(XLogReaderState* xlogreader)
{
XLogRecord* record = nullptr;
@ -5561,11 +5596,6 @@ XLogRecord* XLogParallelReadNextRecord(XLogReaderState* xlogreader)
g_instance.comm_cxt.predo_cxt.redoPf.read_ptr = t_thrd.xlog_cxt.ReadRecPtr;
if (record == NULL) {
if (t_thrd.xlog_cxt.readFile >= 0) {
close(t_thrd.xlog_cxt.readFile);
t_thrd.xlog_cxt.readFile = -1;
}
/*
* We only end up here without a message when XLogPageRead() failed
* - in that case we already logged something.
@ -5590,42 +5620,33 @@ XLogRecord* XLogParallelReadNextRecord(XLogReaderState* xlogreader)
XLByteToSeg(xlogreader->latestPagePtr, targetSegNo);
offset = xlogreader->latestPagePtr % XLogSegSize;
errorno = snprintf_s(fname,
MAXFNAMELEN,
MAXFNAMELEN - 1,
"%08X%08X%08X",
xlogreader->readPageTLI,
(uint32)((targetSegNo) / XLogSegmentsPerXLogId),
(uint32)((targetSegNo) % XLogSegmentsPerXLogId));
errorno = snprintf_s(fname, MAXFNAMELEN, MAXFNAMELEN - 1, "%08X%08X%08X", xlogreader->readPageTLI,
(uint32)((targetSegNo) / XLogSegmentsPerXLogId),
(uint32)((targetSegNo) % XLogSegmentsPerXLogId));
securec_check_ss(errorno, "", "");
ereport(emode_for_corrupt_record(LOG, t_thrd.xlog_cxt.EndRecPtr),
(errmsg("unexpected timeline ID %u in log segment %s, offset %u",
xlogreader->latestPageTLI,
fname,
offset)));
(errmsg("unexpected timeline ID %u in log segment %s, offset %u", xlogreader->latestPageTLI, fname,
offset)));
record = NULL;
}
if (record != NULL) {
/* clear xlog read from XLOG_STREAM fail count when success */
if (t_thrd.xlog_cxt.readSource == XLOG_FROM_STREAM)
streamFailCount = 0;
/* Set up lastest valid record */
latestValidRecord = t_thrd.xlog_cxt.ReadRecPtr;
t_thrd.xlog_cxt.latestRecordCrc = record->xl_crc;
latestRecordCrc = record->xl_crc;
ADD_ABNORMAL_POSITION(9);
/* Great, got a record */
return record;
} else {
/* No valid record available from this source */
t_thrd.xlog_cxt.failedSources |= t_thrd.xlog_cxt.readSource;
if (t_thrd.xlog_cxt.readSource == XLOG_FROM_STREAM)
streamFailCount = 0;
pg_atomic_write_u32(&(extreme_rto::g_recordbuffer->startreadworker), extreme_rto::READ_WORKER_STOP);
if (t_thrd.xlog_cxt.readSource == XLOG_FROM_STREAM && streamFailCount < XLOG_PARALLEL_READREC_MAXTRY) {
streamFailCount++;
} else {
t_thrd.xlog_cxt.failedSources |= t_thrd.xlog_cxt.readSource;
if (t_thrd.xlog_cxt.readSource == XLOG_FROM_STREAM)
streamFailCount = 0;
}
if (t_thrd.xlog_cxt.readFile >= 0) {
close(t_thrd.xlog_cxt.readFile);
@ -5649,38 +5670,8 @@ XLogRecord* XLogParallelReadNextRecord(XLogReaderState* xlogreader)
if (t_thrd.xlog_cxt.StandbyModeRequested)
t_thrd.xlog_cxt.StandbyMode = true;
/* construct a minrecoverypoint, update LSN */
volatile XLogCtlData* xlogctl = t_thrd.shemem_ptr_cxt.XLogCtl;
XLogRecPtr newMinRecoveryPoint;
t_thrd.xlog_cxt.InArchiveRecovery = true;
if (t_thrd.xlog_cxt.StandbyModeRequested) {
t_thrd.xlog_cxt.StandbyMode = true;
}
/* initialize minRecoveryPoint to this record */
LWLockAcquire(ControlFileLock, LW_EXCLUSIVE);
t_thrd.shemem_ptr_cxt.ControlFile->state = DB_IN_ARCHIVE_RECOVERY;
SpinLockAcquire(&xlogctl->info_lck);
newMinRecoveryPoint = xlogctl->lastReplayedEndRecPtr;
SpinLockRelease(&xlogctl->info_lck);
if (XLByteLT(t_thrd.shemem_ptr_cxt.ControlFile->minRecoveryPoint, newMinRecoveryPoint)) {
t_thrd.shemem_ptr_cxt.ControlFile->minRecoveryPoint = newMinRecoveryPoint;
}
/* update local copy */
t_thrd.xlog_cxt.minRecoveryPoint = t_thrd.shemem_ptr_cxt.ControlFile->minRecoveryPoint;
g_instance.comm_cxt.predo_cxt.redoPf.min_recovery_point = t_thrd.xlog_cxt.minRecoveryPoint;
UpdateControlFile();
LWLockRelease(ControlFileLock);
UpdateMinrecoveryInAchive();
CheckRecoveryConsistency();
ereport(LOG,
(errmsg("update minrecovery point to %X/%X in archive recovery",
(uint32)(t_thrd.xlog_cxt.minRecoveryPoint >> 32),
(uint32)(t_thrd.xlog_cxt.minRecoveryPoint))));
/*
* Before we retry, reset lastSourceFailed and currentSource
* so that we will check the archive next.
@ -5690,7 +5681,7 @@ XLogRecord* XLogParallelReadNextRecord(XLogReaderState* xlogreader)
}
/* In standby mode, loop back to retry. Otherwise, give up. */
if (t_thrd.xlog_cxt.StandbyMode && !dummyStandbyMode && !t_thrd.xlog_cxt.recoveryTriggered)
if (t_thrd.xlog_cxt.StandbyMode && !t_thrd.xlog_cxt.recoveryTriggered)
continue;
else
return NULL;
@ -7757,8 +7748,6 @@ static void CheckRequiredParameterValues(bool DBStateShutdown)
void StartupDummyStandby(void)
{
TimeLineID timeline = 0;
XLogRecPtr startpos = 0;
char conninfo[MAXCONNINFO];
int replIdx = 1;
@ -7766,7 +7755,7 @@ void StartupDummyStandby(void)
ReadControlFile();
t_thrd.xlog_cxt.ThisTimeLineID = timeline = GetThisTimeID();
TimeLineID timeline = t_thrd.xlog_cxt.ThisTimeLineID = GetThisTimeID();
DummyStandbySetRecoveryTargetTLI(timeline);
sync_system_identifier = GetSystemIdentifier();
@ -7812,7 +7801,7 @@ void StartupDummyStandby(void)
/* For dummystandby, startpos is not required, Primary will choose the startpos */
ShutdownWalRcv();
startpos = 0;
XLogRecPtr startpos = 0;
RequestXLogStreaming(&startpos, conninfo, REPCONNTARGET_DEFAULT, u_sess->attr.attr_storage.PrimarySlotName);
}
@ -8726,7 +8715,7 @@ void StartupXLOG(void)
* process in addition to postmaster! Also, fsync requests are
* subsequently to be handled by the checkpointer, not locally.
*/
if ((t_thrd.xlog_cxt.ArchiveRecoveryRequested || IS_PGXC_COORDINATOR || IS_SINGLE_NODE) && IsUnderPostmaster) {
if ((t_thrd.xlog_cxt.ArchiveRecoveryRequested || IS_PGXC_COORDINATOR || IS_SINGLE_NODE || isRestoreMode) && IsUnderPostmaster) {
PublishStartupProcessInformation();
SetForwardFsyncRequests();
SendPostmasterSignal(PMSIGNAL_RECOVERY_STARTED);
@ -8877,8 +8866,10 @@ void StartupXLOG(void)
*/
if (TransactionIdFollowsOrEquals(record->xl_xid, t_thrd.xact_cxt.ShmemVariableCache->nextXid)) {
LWLockAcquire(XidGenLock, LW_EXCLUSIVE);
t_thrd.xact_cxt.ShmemVariableCache->nextXid = record->xl_xid;
TransactionIdAdvance(t_thrd.xact_cxt.ShmemVariableCache->nextXid);
if (TransactionIdFollowsOrEquals(record->xl_xid, t_thrd.xact_cxt.ShmemVariableCache->nextXid)) {
t_thrd.xact_cxt.ShmemVariableCache->nextXid = record->xl_xid;
TransactionIdAdvance(t_thrd.xact_cxt.ShmemVariableCache->nextXid);
}
LWLockRelease(XidGenLock);
}
@ -13970,17 +13961,6 @@ static bool IsRedoDonePromoting(void)
return result;
}
void UpdateWalRcvReadOffset()
{
WalRcvCtlBlock* walrcb = getCurrentWalRcvCtlBlock();
if (walrcb == NULL) {
return;
}
SpinLockAcquire(&walrcb->mutex);
walrcb->walReadOffset = walrcb->walWriteOffset;
SpinLockRelease(&walrcb->mutex);
}
bool XLogReadFromWriteBufferForFirst(XLogRecPtr targetPagePtr, int reqLen, char* readBuf)
{
@ -14005,7 +13985,7 @@ bool XLogReadFromWriteBufferForFirst(XLogRecPtr targetPagePtr, int reqLen, char*
buflen = (int64)(startptr - targetPagePtr);
walReadOffset = walwriteoffset - buflen;
if ((walReadOffset < 0) || ((walReadOffset % XLOG_BLCKSZ) != 0) || (buflen < (int64)reqLen)) {
/* panic */
return false;
}
srcbuf = walrecvbuf + walReadOffset;
@ -14022,15 +14002,14 @@ bool XLogReadFromWriteBufferForFirst(XLogRecPtr targetPagePtr, int reqLen, char*
SpinLockAcquire(&walrcb->mutex);
walrcb->lastReadPtr = targetPagePtr + reqLen;
if (walrcb->walWriteOffset == recBufferSize) {
walrcb->walWriteOffset = 0;
if (walrcb->walFreeOffset == recBufferSize)
walrcb->walFreeOffset = 0;
}
walrcb->walReadOffset = walReadOffset + reqLen;
if (walrcb->walReadOffset == recBufferSize) {
walrcb->walReadOffset = 0;
if (walrcb->walWriteOffset == recBufferSize) {
walrcb->walWriteOffset = 0;
if (walrcb->walFreeOffset == recBufferSize)
walrcb->walFreeOffset = 0;
}
}
SpinLockRelease(&walrcb->mutex);
@ -14038,7 +14017,7 @@ bool XLogReadFromWriteBufferForFirst(XLogRecPtr targetPagePtr, int reqLen, char*
return true;
}
int XLogReadFromWriteBuffer(XLogRecPtr targetStartPtr, int reqLen, char* readBuf, uint32* rereadlen)
bool XLogReadFromWriteBuffer(XLogRecPtr targetStartPtr, int reqLen, char *readBuf, uint32 *rereadlen)
{
WalRcvCtlBlock* walrcb = getCurrentWalRcvCtlBlock();
int64 recBufferSize = g_instance.attr.attr_storage.WalReceiverBufSize * 1024;
@ -14091,19 +14070,478 @@ int XLogReadFromWriteBuffer(XLogRecPtr targetStartPtr, int reqLen, char* readBuf
SpinLockAcquire(&walrcb->mutex);
walrcb->lastReadPtr = lastreadptr + realLen;
if (walrcb->walWriteOffset == recBufferSize) {
walrcb->walWriteOffset = 0;
if (walrcb->walFreeOffset == recBufferSize)
walrcb->walFreeOffset = 0;
walrcb->walReadOffset = walReadOffset + realLen;
if (walrcb->walReadOffset == recBufferSize) {
walrcb->walReadOffset = 0;
if (walrcb->walWriteOffset == recBufferSize) {
walrcb->walWriteOffset = 0;
if (walrcb->walFreeOffset == recBufferSize)
walrcb->walFreeOffset = 0;
}
}
walrcb->walReadOffset = (walReadOffset + realLen) % recBufferSize;
SpinLockRelease(&walrcb->mutex);
*rereadlen = realLen;
return true;
}
bool NewDataIsInBuf(XLogRecPtr expectedRecPtr)
{
bool havedata = false;
if (XLByteLT(expectedRecPtr, t_thrd.xlog_cxt.receivedUpto)) {
havedata = true;
} else {
XLogRecPtr latestChunkStart;
t_thrd.xlog_cxt.receivedUpto = GetWalRcvWriteRecPtr(&latestChunkStart);
if (XLByteLT(expectedRecPtr, t_thrd.xlog_cxt.receivedUpto)) {
havedata = true;
if (!XLByteLT(expectedRecPtr, latestChunkStart)) {
t_thrd.xlog_cxt.XLogReceiptTime = GetCurrentTimestamp();
SetCurrentChunkStartTime(t_thrd.xlog_cxt.XLogReceiptTime);
}
} else {
havedata = false;
}
}
return havedata;
}
void SwitchToReadXlogFromFile(XLogReaderState *state, XLogRecPtr pageptr)
{
pg_atomic_write_u32(&extreme_rto::g_dispatcher->recordstate.failSource, XLOG_FROM_STREAM);
pg_atomic_write_u32(&extreme_rto::g_dispatcher->recordstate.readSource, XLOG_FROM_PG_XLOG);
pg_atomic_write_u64(&extreme_rto::g_dispatcher->recordstate.expectLsn, InvalidXLogRecPtr);
pg_atomic_write_u32(&(extreme_rto::g_recordbuffer->readWorkerState), extreme_rto::WORKER_STATE_STOPPING);
uint32 workerState = pg_atomic_read_u32(&(extreme_rto::g_recordbuffer->readWorkerState));
while (workerState != extreme_rto::WORKER_STATE_EXIT && workerState != extreme_rto::WORKER_STATE_STOP) {
extreme_rto::HandlePageRedoInterrupts();
workerState = pg_atomic_read_u32(&(extreme_rto::g_recordbuffer->readWorkerState));
}
XLogSegNo targetSegNo;
XLByteToSeg(pageptr, targetSegNo);
uint32 targetPageOff = (pageptr % XLOG_SEG_SIZE);
uint32 applyindex = extreme_rto::g_recordbuffer->applyindex;
extreme_rto::g_recordbuffer->xlogsegarray[applyindex].segno = targetSegNo;
extreme_rto::g_recordbuffer->xlogsegarray[applyindex].segoffset = targetPageOff;
state->readBuf = extreme_rto::g_recordbuffer->xlogsegarray[applyindex].readsegbuf + targetPageOff;
}
int ParallelXLogReadWorkBufRead(XLogReaderState *xlogreader, XLogRecPtr targetPagePtr, int reqLen,
XLogRecPtr targetRecPtr, char *readBuf, TimeLineID *readTLI)
{
XLogRecPtr RecPtr = targetPagePtr;
uint32 targetPageOff = targetPagePtr % XLogSegSize;
XLByteToSeg(targetPagePtr, t_thrd.xlog_cxt.readSegNo);
XLByteAdvance(RecPtr, reqLen);
XLogRecPtr expectedRecPtr = RecPtr;
if (RecPtr % XLogSegSize == 0) {
XLByteAdvance(expectedRecPtr, SizeOfXLogLongPHD);
} else if (RecPtr % XLOG_BLCKSZ == 0) {
XLByteAdvance(expectedRecPtr, SizeOfXLogShortPHD);
}
pg_atomic_write_u64(&extreme_rto::g_dispatcher->recordstate.expectLsn, expectedRecPtr);
for (;;) {
// Check to see if the trigger file exists. If so, update the gaussdb state file.
if (CheckForStandbyTrigger()) {
SendPostmasterSignal(PMSIGNAL_UPDATE_NORMAL);
}
/*
* If we find an invalid record in the WAL streamed from
* master, something is seriously wrong. There's little
* chance that the problem will just go away, but PANIC is
* not good for availability either, especially in hot
* standby mode. Disconnect, and retry from
* archive/pg_xlog again. The WAL in the archive should be
* identical to what was streamed, so it's unlikely that
* it helps, but one can hope...
*/
if (t_thrd.xlog_cxt.failedSources & XLOG_FROM_STREAM) {
SwitchToReadXlogFromFile(xlogreader, targetPagePtr);
return -1;
}
/*
* Walreceiver is active, so see if new data has arrived.
*
* We only advance XLogReceiptTime when we obtain fresh
* WAL from walreceiver and observe that we had already
* processed everything before the most recent "chunk"
* that it flushed to disk. In steady state where we are
* keeping up with the incoming data, XLogReceiptTime will
* be updated on each cycle. When we are behind,
* XLogReceiptTime will not advance, so the grace time
* alloted to conflicting queries will decrease.
*/
bool havedata = NewDataIsInBuf(expectedRecPtr);
if (havedata) {
/* just make sure source info is correct... */
t_thrd.xlog_cxt.readSource = XLOG_FROM_STREAM;
t_thrd.xlog_cxt.XLogReceiptSource = XLOG_FROM_STREAM;
if ((targetPagePtr / XLOG_BLCKSZ) != (t_thrd.xlog_cxt.receivedUpto / XLOG_BLCKSZ)) {
t_thrd.xlog_cxt.readLen = XLOG_BLCKSZ;
} else {
t_thrd.xlog_cxt.readLen = t_thrd.xlog_cxt.receivedUpto % XLogSegSize - targetPageOff;
}
/* read from wal writer buffer */
bool readflag = extreme_rto::XLogPageReadForExtRto(targetPagePtr, t_thrd.xlog_cxt.readLen, readBuf);
if (readflag) {
*readTLI = t_thrd.xlog_cxt.curFileTLI;
return t_thrd.xlog_cxt.readLen;
}
}
uint32 trigger = pg_atomic_read_u32(&extreme_rto::g_readManagerTriggerFlag);
if (trigger > 0) {
pg_atomic_write_u32(&extreme_rto::g_dispatcher->recordstate.readSource, XLOG_FROM_PG_XLOG);
pg_atomic_write_u32(&(extreme_rto::g_recordbuffer->readWorkerState), extreme_rto::WORKER_STATE_STOPPING);
return -1;
}
/*
* Wait for more WAL to arrive, or timeout to be reached
*/
WaitLatch(&t_thrd.shemem_ptr_cxt.XLogCtl->recoveryWakeupLatch, WL_LATCH_SET | WL_TIMEOUT, 1000L);
ResetLatch(&t_thrd.shemem_ptr_cxt.XLogCtl->recoveryWakeupLatch);
/*
* This possibly-long loop needs to handle interrupts of
* startup process.
*/
extreme_rto::HandlePageRedoInterrupts();
}
return -1;
}
int ParallelXLogPageReadFile(XLogReaderState *xlogreader, XLogRecPtr targetPagePtr, int reqLen, XLogRecPtr targetRecPtr,
char *readBuf, TimeLineID *readTLI)
{
/* Load reader private data */
XLogPageReadPrivate *readprivate = (XLogPageReadPrivate *)xlogreader->private_data;
int emode = readprivate->emode;
bool randAccess = readprivate->randAccess;
uint32 targetPageOff;
volatile XLogCtlData *xlogctl = t_thrd.shemem_ptr_cxt.XLogCtl;
XLogRecPtr RecPtr = targetPagePtr;
XLogSegNo replayedSegNo;
uint32 ret;
#ifdef USE_ASSERT_CHECKING
XLogSegNo targetSegNo;
XLByteToSeg(targetPagePtr, targetSegNo);
#endif
targetPageOff = targetPagePtr % XLogSegSize;
/*
* See if we need to switch to a new segment because the requested record
* is not in the currently open one.
*/
if (t_thrd.xlog_cxt.readFile >= 0 && !XLByteInSeg(targetPagePtr, t_thrd.xlog_cxt.readSegNo)) {
/*
* Request a restartpoint if we've replayed too much xlog since the
* last one.
*/
if (t_thrd.xlog_cxt.StandbyModeRequested &&
(t_thrd.xlog_cxt.bgwriterLaunched || t_thrd.xlog_cxt.pagewriter_launched)) {
XLByteToSeg(GetXLogReplayRecPtr(NULL), replayedSegNo);
if (XLogCheckpointNeeded(replayedSegNo)) {
(void)GetRedoRecPtr();
if (XLogCheckpointNeeded(replayedSegNo)) {
RequestCheckpoint(CHECKPOINT_CAUSE_XLOG);
}
}
}
close(t_thrd.xlog_cxt.readFile);
t_thrd.xlog_cxt.readFile = -1;
t_thrd.xlog_cxt.readSource = 0;
}
XLByteToSeg(targetPagePtr, t_thrd.xlog_cxt.readSegNo);
XLByteAdvance(RecPtr, reqLen);
retry:
/* See if we need to retrieve more data */
if (t_thrd.xlog_cxt.readFile < 0) {
if (t_thrd.xlog_cxt.StandbyMode) {
/*
* In standby mode, wait for the requested record to become
* available, either via restore_command succeeding to restore the
* segment, or via walreceiver having streamed the record.
*/
for (;;) {
/*
* Until walreceiver manages to reconnect, poll the
* archive.
*/
if (t_thrd.xlog_cxt.readFile >= 0) {
close(t_thrd.xlog_cxt.readFile);
t_thrd.xlog_cxt.readFile = -1;
}
/* Reset curFileTLI if random fetch. */
if (randAccess) {
t_thrd.xlog_cxt.curFileTLI = 0;
}
/*
* Try to restore the file from archive, or read an
* existing file from pg_xlog.
*/
uint32 sources = XLOG_FROM_ARCHIVE | XLOG_FROM_PG_XLOG;
if (!(sources & ~t_thrd.xlog_cxt.failedSources)) {
/*
* We've exhausted all options for retrieving the
* file. Retry.
*/
t_thrd.xlog_cxt.failedSources = 0;
/*
* Before we sleep, re-scan for possible new timelines
* if we were requested to recover to the latest
* timeline.
*/
if (t_thrd.xlog_cxt.recoveryTargetIsLatest) {
if (rescanLatestTimeLine()) {
continue;
}
}
if (!xlogctl->IsRecoveryDone) {
g_instance.comm_cxt.predo_cxt.redoPf.redo_done_time = GetCurrentTimestamp();
g_instance.comm_cxt.predo_cxt.redoPf.recovery_done_ptr = t_thrd.xlog_cxt.ReadRecPtr;
ereport(LOG, (errmodule(MOD_REDO), errcode(ERRCODE_LOG),
errmsg("XLogPageRead IsRecoveryDone is set true,"
"ReadRecPtr:%lu, EndRecPtr:%lu",
t_thrd.xlog_cxt.ReadRecPtr, t_thrd.xlog_cxt.EndRecPtr)));
}
/*
* signal postmaster to update local redo end
* point to gaussdb state file.
*/
if (!xlogctl->IsRecoveryDone) {
SendPostmasterSignal(PMSIGNAL_LOCAL_RECOVERY_DONE);
extreme_rto::PushToWorkerLsn(true);
}
SpinLockAcquire(&xlogctl->info_lck);
xlogctl->IsRecoveryDone = true;
SpinLockRelease(&xlogctl->info_lck);
/*
* If it hasn't been long since last attempt, sleep 1s to
* avoid busy-waiting.
*/
pg_usleep(50000L);
/*
* If primary_conninfo is set, launch walreceiver to
* try to stream the missing WAL, before retrying to
* restore from archive/pg_xlog.
*
* If fetching_ckpt is TRUE, RecPtr points to the
* initial checkpoint location. In that case, we use
* RedoStartLSN as the streaming start position
* instead of RecPtr, so that when we later jump
* backwards to start redo at RedoStartLSN, we will
* have the logs streamed already.
*/
uint32 trigger = pg_atomic_read_u32(&extreme_rto::g_readManagerTriggerFlag);
if (trigger > 0) {
pg_atomic_write_u32(&extreme_rto::g_readManagerTriggerFlag, extreme_rto::TRIGGER_NORMAL);
goto triggered;
}
load_server_mode();
if (t_thrd.xlog_cxt.PrimaryConnInfo || t_thrd.xlog_cxt.server_mode == STANDBY_MODE) {
t_thrd.xlog_cxt.receivedUpto = 0;
uint32 failSouce = pg_atomic_read_u32(&extreme_rto::g_dispatcher->recordstate.failSource);
if (!(failSouce & XLOG_FROM_STREAM)) {
extreme_rto::PushToWorkerLsn(true);
volatile WalRcvData* walrcv = t_thrd.walreceiverfuncs_cxt.WalRcv;
SpinLockAcquire(&walrcv->mutex);
walrcv->receivedUpto = 0;
SpinLockRelease(&walrcv->mutex);
t_thrd.xlog_cxt.readSource = XLOG_FROM_STREAM;
t_thrd.xlog_cxt.XLogReceiptSource = XLOG_FROM_STREAM;
pg_atomic_write_u32(&extreme_rto::g_dispatcher->recordstate.readSource, XLOG_FROM_STREAM);
return -1;
}
}
}
/* Don't try to read from a source that just failed */
sources &= ~t_thrd.xlog_cxt.failedSources;
t_thrd.xlog_cxt.readFile = XLogFileReadAnyTLI(t_thrd.xlog_cxt.readSegNo, DEBUG2, sources);
if (t_thrd.xlog_cxt.readFile >= 0) {
break;
}
/*
* Nope, not found in archive and/or pg_xlog.:
*/
t_thrd.xlog_cxt.failedSources |= sources;
/*
* Check to see if the trigger file exists. Note that we
* do this only after failure, so when you create the
* trigger file, we still finish replaying as much as we
* can from archive and pg_xlog before failover.
*/
uint32 trigger = pg_atomic_read_u32(&extreme_rto::g_readManagerTriggerFlag);
if (trigger > 0) {
pg_atomic_write_u32(&extreme_rto::g_readManagerTriggerFlag, extreme_rto::TRIGGER_NORMAL);
goto triggered;
}
/*
* This possibly-long loop needs to handle interrupts of
* startup process.
*/
extreme_rto::HandlePageRedoInterrupts();
}
} else {
/* In archive or crash recovery. */
if (t_thrd.xlog_cxt.readFile < 0) {
uint32 sources;
/* Reset curFileTLI if random fetch. */
if (randAccess) {
t_thrd.xlog_cxt.curFileTLI = 0;
}
sources = XLOG_FROM_PG_XLOG;
if (t_thrd.xlog_cxt.InArchiveRecovery) {
sources |= XLOG_FROM_ARCHIVE;
}
t_thrd.xlog_cxt.readFile = XLogFileReadAnyTLI(t_thrd.xlog_cxt.readSegNo, emode, sources);
if (t_thrd.xlog_cxt.readFile < 0) {
return -1;
}
}
}
}
/*
* At this point, we have the right segment open and if we're streaming we
* know the requested record is in it.
*/
Assert(t_thrd.xlog_cxt.readFile != -1);
/*
* If the current segment is being streamed from master, calculate how
* much of the current page we have received already. We know the
* requested record has been received, but this is for the benefit of
* future calls, to allow quick exit at the top of this function.
*/
t_thrd.xlog_cxt.readLen = XLOG_BLCKSZ;
/* Read the requested page */
t_thrd.xlog_cxt.readOff = targetPageOff;
try_again:
if (lseek(t_thrd.xlog_cxt.readFile, (off_t)t_thrd.xlog_cxt.readOff, SEEK_SET) < 0) {
ereport(emode_for_corrupt_record(emode, RecPtr),
(errcode_for_file_access(),
errmsg("could not seek in log file %s to offset %u: %m",
XLogFileNameP(t_thrd.xlog_cxt.ThisTimeLineID, t_thrd.xlog_cxt.readSegNo),
t_thrd.xlog_cxt.readOff)));
if (errno == EINTR) {
errno = 0;
pg_usleep(1000);
goto try_again;
}
goto next_record_is_invalid;
}
pgstat_report_waitevent(WAIT_EVENT_WAL_READ);
ret = read(t_thrd.xlog_cxt.readFile, readBuf, XLOG_BLCKSZ);
pgstat_report_waitevent(WAIT_EVENT_END);
if (ret != XLOG_BLCKSZ) {
ereport(emode_for_corrupt_record(emode, RecPtr),
(errcode_for_file_access(),
errmsg("could not read from log file %s to offset %u: %m",
XLogFileNameP(t_thrd.xlog_cxt.ThisTimeLineID, t_thrd.xlog_cxt.readSegNo),
t_thrd.xlog_cxt.readOff)));
if (errno == EINTR) {
errno = 0;
pg_usleep(1000);
goto try_again;
}
goto next_record_is_invalid;
}
Assert(targetSegNo == t_thrd.xlog_cxt.readSegNo);
Assert(targetPageOff == t_thrd.xlog_cxt.readOff);
Assert((uint32)reqLen <= t_thrd.xlog_cxt.readLen);
*readTLI = t_thrd.xlog_cxt.curFileTLI;
return t_thrd.xlog_cxt.readLen;
next_record_is_invalid:
t_thrd.xlog_cxt.failedSources |= t_thrd.xlog_cxt.readSource;
if (t_thrd.xlog_cxt.readFile >= 0) {
close(t_thrd.xlog_cxt.readFile);
}
t_thrd.xlog_cxt.readFile = -1;
t_thrd.xlog_cxt.readLen = 0;
t_thrd.xlog_cxt.readSource = 0;
/* In standby-mode, keep trying */
if (t_thrd.xlog_cxt.StandbyMode) {
goto retry;
} else {
return -1;
}
triggered:
if (t_thrd.xlog_cxt.readFile >= 0) {
close(t_thrd.xlog_cxt.readFile);
}
t_thrd.xlog_cxt.readFile = -1;
t_thrd.xlog_cxt.readLen = 0;
t_thrd.xlog_cxt.readSource = 0;
t_thrd.xlog_cxt.recoveryTriggered = true;
return -1;
}
int ParallelXLogPageRead(XLogReaderState *xlogreader, XLogRecPtr targetPagePtr, int reqLen, XLogRecPtr targetRecPtr,
char *readBuf, TimeLineID *readTLI)
{
int readLen = -1;
pg_atomic_write_u64(&extreme_rto::g_dispatcher->recordstate.targetRecPtr, targetRecPtr);
for (;;) {
uint32 readSource = pg_atomic_read_u32(&(extreme_rto::g_recordbuffer->readSource));
if (readSource & XLOG_FROM_STREAM) {
readLen = ParallelXLogReadWorkBufRead(xlogreader, targetPagePtr, reqLen, targetRecPtr, readBuf, readTLI);
} else {
readLen = ParallelXLogPageReadFile(xlogreader, targetPagePtr, reqLen, targetRecPtr, readBuf, readTLI);
}
if (readLen > 0 || t_thrd.xlog_cxt.recoveryTriggered || !t_thrd.xlog_cxt.StandbyMode) {
return readLen;
}
extreme_rto::HandlePageRedoInterrupts();
ADD_ABNORMAL_POSITION(10);
}
return readLen;
}
/*
* Read the XLOG page containing RecPtr into readBuf (if not read already).
* Returns number of bytes read, if the page is read successfully, or -1
@ -14227,22 +14665,12 @@ retry:
*/
if (t_thrd.xlog_cxt.failedSources & XLOG_FROM_STREAM) {
ProcTxnWorkLoad(true);
ShutdownWalRcv();
if (IsExtremeRtoRunning()) {
t_thrd.xlog_cxt.readfrombuffer = false;
pg_atomic_write_u32(
&(extreme_rto::g_recordbuffer->startreadworker), extreme_rto::READ_WORKER_STOP);
extreme_rto::DumpExtremeRtoReadBuf();
ereport(LOG,
(errmsg("XLogPageRead targetPagePtr:%lu,reqLen %d,targetRecPtr %lu,Upto %lu,endptr %lu",
targetPagePtr,
reqLen,
targetRecPtr,
t_thrd.xlog_cxt.receivedUpto,
xlogreader->EndRecPtr)));
pg_atomic_write_u32(&(extreme_rto::g_recordbuffer->readWorkerState),
extreme_rto::WORKER_STATE_STOP);
}
ShutdownWalRcv();
continue;
}
@ -14313,10 +14741,6 @@ retry:
t_thrd.xlog_cxt.RedoDone = IsRedoDonePromoting();
pg_memory_barrier();
if (IsExtremeRtoRunning() && pg_atomic_read_u32(&(extreme_rto::g_recordbuffer->startreadworker)) ==
extreme_rto::READ_WORKER_STOP) {
UpdateWalRcvReadOffset();
}
/*
* The judging rules are the following:
* (1)For the One-Primary-Multi-Standbys deployment the dummy_status is set
@ -14521,8 +14945,8 @@ retry:
SpinLockRelease(&walrcv->mutex);
if (IsExtremeRtoRunning()) {
/* restart from recvbuffer */
pg_atomic_write_u32(
&(extreme_rto::g_recordbuffer->startreadworker), extreme_rto::READ_WORKER_STOP);
pg_atomic_write_u32(&(extreme_rto::g_recordbuffer->readWorkerState),
extreme_rto::WORKER_STATE_STOP);
}
RequestXLogStreaming(fetching_ckpt ? &t_thrd.xlog_cxt.RedoStartLSN : &targetRecPtr,
t_thrd.xlog_cxt.PrimaryConnInfo,
@ -14579,13 +15003,12 @@ retry:
SpinLockRelease(&walrcv->mutex);
if (IsExtremeRtoRunning()) {
/* restart from recvbuffer */
pg_atomic_write_u32(
&(extreme_rto::g_recordbuffer->startreadworker), extreme_rto::READ_WORKER_STOP);
pg_atomic_write_u32(&(extreme_rto::g_recordbuffer->readWorkerState),
extreme_rto::WORKER_STATE_STOP);
}
RequestXLogStreaming(fetching_ckpt ? &t_thrd.xlog_cxt.RedoStartLSN : &targetRecPtr,
t_thrd.xlog_cxt.PrimaryConnInfo,
REPCONNTARGET_PRIMARY,
u_sess->attr.attr_storage.PrimarySlotName);
t_thrd.xlog_cxt.PrimaryConnInfo, REPCONNTARGET_PRIMARY,
u_sess->attr.attr_storage.PrimarySlotName);
if (!g_instance.attr.attr_storage.enable_mix_replication && !IS_DN_MULTI_STANDYS_MODE()) {
StartupDataStreaming();
}
@ -14942,7 +15365,7 @@ static bool CheckForPrimaryTrigger(void)
return false;
} else {
/* check for primary */
uint32 tgigger = pg_atomic_read_u32(&(extreme_rto::g_triggeredstate));
uint32 tgigger = pg_atomic_read_u32(&(extreme_rto::g_startupTriggerState));
if (tgigger == extreme_rto::TRIGGER_PRIMARY)
return true;
}
@ -14961,7 +15384,7 @@ static bool CheckForStandbyTrigger(void)
return false;
} else {
/* check for primary */
uint32 tgigger = pg_atomic_read_u32(&(extreme_rto::g_triggeredstate));
uint32 tgigger = pg_atomic_read_u32(&(extreme_rto::g_startupTriggerState));
if (tgigger == extreme_rto::TRIGGER_STADNBY)
return true;
}
@ -15688,3 +16111,16 @@ void ReLeaseRecoveryLatch()
{
DisownLatch(&t_thrd.shemem_ptr_cxt.XLogCtl->recoveryWakeupLatch);
}
bool IsRecoveryDone()
{
volatile XLogCtlData *xlogctl = t_thrd.shemem_ptr_cxt.XLogCtl;
return xlogctl->IsRecoveryDone;
}
void ExtremRtoUpdateMinCheckpoint()
{
if (t_thrd.shemem_ptr_cxt.XLogCtl->IsRecoveryDone && t_thrd.xlog_cxt.minRecoveryPoint == InvalidXLogRecPtr) {
t_thrd.xlog_cxt.minRecoveryPoint = t_thrd.shemem_ptr_cxt.ControlFile->minRecoveryPoint;
}
}

View File

@ -793,6 +793,7 @@ Datum pg_resume_bkp_flag(PG_FUNCTION_ARGS)
resultHeapTuple = heap_form_tuple(resultTupleDesc, values, isnull);
if (0 != pg_strcasecmp(rewindTime, "")) {
pfree(rewindTime);
rewindTime = NULL;
}
result = HeapTupleGetDatum(resultHeapTuple);

View File

@ -498,10 +498,12 @@ XLogRecord* XLogReadRecord(
if (doDecode) {
if (DecodeXLogRecord(state, record, errormsg, readoldversion)) {
return record;
} else
} else {
return NULL;
} else
}
} else {
return record;
}
err:

View File

@ -4043,14 +4043,13 @@ void GetFlushBufferInfo(void* buf, RedoBufferInfo *bufferinfo, uint32 *buf_state
*/
/* To check if block content changes while flushing. - vadim 01/17/97 */
*buf_state &= ~BM_JUST_DIRTIED;
bufferinfo->lsn = (flushmethod == WITH_LOCAL_CACHE) ? LocalBufGetLSN(bufdesc) : BufferGetLSN(bufdesc);
UnlockBufHdr(bufdesc, *buf_state);
bufferinfo->lsn = (flushmethod == WITH_LOCAL_CACHE) ? LocalBufGetLSN(bufdesc) : BufferGetLSN(bufdesc);
bufferinfo->buf = BufferDescriptorGetBuffer(bufdesc);
bufferinfo->pageinfo.page = (flushmethod == WITH_LOCAL_CACHE) ? (Page)LocalBufHdrGetBlock(bufdesc) : (Page)BufHdrGetBlock(bufdesc);;
bufferinfo->pageinfo.pagesize = BufferGetPageSize(bufferinfo->buf);
}
else
{
bufferinfo->buf = BufferDescriptorGetBuffer(bufdesc);
bufferinfo->pageinfo.page = (flushmethod == WITH_LOCAL_CACHE) ? (Page)LocalBufHdrGetBlock(bufdesc)
: (Page)BufHdrGetBlock(bufdesc);
bufferinfo->pageinfo.pagesize = BufferGetPageSize(bufferinfo->buf);
} else {
*bufferinfo = *((RedoBufferInfo *)buf);
}
}

View File

@ -1059,7 +1059,9 @@ void ProcArrayApplyRecoveryInfo(RunningTransactions running)
if (TransactionIdFollows(nextXid, t_thrd.xact_cxt.ShmemVariableCache->nextXid)) {
LWLockAcquire(XidGenLock, LW_EXCLUSIVE);
t_thrd.xact_cxt.ShmemVariableCache->nextXid = nextXid;
if (TransactionIdFollows(nextXid, t_thrd.xact_cxt.ShmemVariableCache->nextXid)) {
t_thrd.xact_cxt.ShmemVariableCache->nextXid = nextXid;
}
LWLockRelease(XidGenLock);
}

View File

@ -868,6 +868,26 @@ void PublishStartupProcessInformation(void)
SpinLockRelease(&g_instance.proc_base_lock);
}
/*
* Used from bufgr to share the value of the buffer that Startup waits on,
* or to reset the value to "not waiting" (-1). This allows processing
* of recovery conflicts for buffer pins. Set is made before backends look
* at this value, so locking not required, especially since the set is
* an atomic integer set operation.
*/
void SetStartupBufferPinWaitBufId(int bufid)
{
g_instance.proc_base->startupBufferPinWaitBufId = bufid;
}
/*
* Used by backends when they receive a request to check for buffer pin waits.
*/
int GetStartupBufferPinWaitBufId(void)
{
return g_instance.proc_base->startupBufferPinWaitBufId;
}
/*
* Check whether there are at least N free PGPROC objects.
*

View File

@ -598,9 +598,10 @@ int walRcvWrite(WalRcvCtlBlock* walrcb)
SpinLockAcquire(&walrcb->mutex);
if (walrcb->walFreeOffset == walrcb->walWriteOffset) {
if ((IsExtremeRtoReadWorkerRunning()) && (walrcb->walFreeOffset != walrcb->walReadOffset))
{
nbytes = 1;
if (IsExtremeRtoReadWorkerRunning()) {
if (walrcb->walFreeOffset != walrcb->walReadOffset) {
nbytes = 1;
}
}
SpinLockRelease(&walrcb->mutex);
@ -627,14 +628,10 @@ int walRcvWrite(WalRcvCtlBlock* walrcb)
walrcb->walWriteOffset += nbytes;
walrcb->walStart = startptr;
if (IsExtremeRedo()) {
if (walrcb->walReadOffset == recBufferSize) {
walrcb->walReadOffset = 0;
}
if (walrcb->walFreeOffset == recBufferSize && walrcb->walReadOffset > 0) {
walrcb->walFreeOffset = 0;
}
if (walrcb->walWriteOffset == recBufferSize && (walrcb->walFreeOffset != recBufferSize)) {
if (walrcb->walWriteOffset == recBufferSize && (walrcb->walReadOffset > 0)) {
walrcb->walWriteOffset = 0;
if (walrcb->walFreeOffset == recBufferSize)
walrcb->walFreeOffset = 0;
}
} else {

View File

@ -1122,6 +1122,19 @@ static void WalDataRcvReceive(char* buf, Size nbytes, XLogRecPtr recptr)
wakeupWalRcvWriter();
}
void UpdateWalRcvCtl(struct WalRcvCtlBlock* walRcvCtlBlock, const XLogRecPtr recptr, const int segbytes)
{
const int64 recBufferSize = g_instance.attr.attr_storage.WalReceiverBufSize * 1024;
SpinLockAcquire(&walRcvCtlBlock->mutex);
walRcvCtlBlock->walFreeOffset += segbytes;
if (walRcvCtlBlock->walFreeOffset == recBufferSize && walRcvCtlBlock->walReadOffset > 0 &&
walRcvCtlBlock->walReadOffset > 0) {
walRcvCtlBlock->walFreeOffset = 0;
}
walRcvCtlBlock->receivePtr = recptr;
SpinLockRelease(&walRcvCtlBlock->mutex);
}
/*
* Receive XLOG data into receiver buffer.
*/
@ -1145,7 +1158,8 @@ static void XLogWalRcvReceiveInBuf(char* buf, Size nbytes, XLogRecPtr recptr)
// no data to be flushed
t_thrd.walreceiver_cxt.walRcvCtlBlock->walStart = recptr;
} else if (t_thrd.walreceiver_cxt.walRcvCtlBlock->walFreeOffset == recBufferSize &&
t_thrd.walreceiver_cxt.walRcvCtlBlock->walReadOffset > 0) {
t_thrd.walreceiver_cxt.walRcvCtlBlock->walReadOffset > 0 &&
t_thrd.walreceiver_cxt.walRcvCtlBlock->walWriteOffset > 0) {
t_thrd.walreceiver_cxt.walRcvCtlBlock->walFreeOffset = 0;
}
walfreeoffset = t_thrd.walreceiver_cxt.walRcvCtlBlock->walFreeOffset;
@ -1155,16 +1169,10 @@ static void XLogWalRcvReceiveInBuf(char* buf, Size nbytes, XLogRecPtr recptr)
startptr = t_thrd.walreceiver_cxt.walRcvCtlBlock->walStart;
SpinLockRelease(&t_thrd.walreceiver_cxt.walRcvCtlBlock->mutex);
ereport(DEBUG5,
(errmsg("XLogWalRcvReceive: recptr(%X:%X),nbytes(%d),"
"walfreeoffset(%ld),walwriteoffset(%ld),startptr(%X:%X)",
(uint32)(recptr >> 32),
(uint32)recptr,
(int)nbytes,
walfreeoffset,
walwriteoffset,
(uint32)(startptr >> 32),
(uint32)startptr)));
ereport(DEBUG5, (errmsg("XLogWalRcvReceive: recptr(%X:%X),nbytes(%d),"
"walfreeoffset(%ld),walwriteoffset(%ld),startptr(%X:%X)",
(uint32)(recptr >> 32), (uint32)recptr, (int)nbytes, walfreeoffset, walwriteoffset,
(uint32)(startptr >> 32), (uint32)startptr)));
XLogWalRcvSendReply(false, false);
@ -1177,6 +1185,127 @@ static void XLogWalRcvReceiveInBuf(char* buf, Size nbytes, XLogRecPtr recptr)
endPoint = walreadoffset - 1;
}
if (endPoint == walfreeoffset) {
if (WalRcvWriterInProgress()) {
wakeupWalRcvWriter();
/* Process any requests or signals received recently */
ProcessWalRcvInterrupts();
/* Keepalived with primary when waiting flush wal data */
XLogWalRcvSendReply(false, false);
pg_usleep(1000);
} else {
walRcvDataCleanup();
ProcessWalRcvInterrupts();
}
continue;
}
segbytes = ((walfreeoffset + (int)nbytes > endPoint) ? (endPoint - walfreeoffset) : (int)nbytes);
/* Need to seek in the buffer? */
if (walfreeoffset != walwriteoffset) {
if (walfreeoffset > walwriteoffset) {
XLByteAdvance(startptr, (uint32)(walfreeoffset - walwriteoffset));
} else {
XLByteAdvance(startptr, (uint32)(recBufferSize - walwriteoffset + walfreeoffset));
}
if (!XLByteEQ(startptr, recptr)) {
/* wait for finishing flushing all wal data */
while (true) {
SpinLockAcquire(&t_thrd.walreceiver_cxt.walRcvCtlBlock->mutex);
if (t_thrd.walreceiver_cxt.walRcvCtlBlock->walFreeOffset ==
t_thrd.walreceiver_cxt.walRcvCtlBlock->walWriteOffset) {
t_thrd.walreceiver_cxt.walRcvCtlBlock->walStart = recptr;
SpinLockRelease(&t_thrd.walreceiver_cxt.walRcvCtlBlock->mutex);
break;
}
SpinLockRelease(&t_thrd.walreceiver_cxt.walRcvCtlBlock->mutex);
if (WalRcvWriterInProgress()) {
wakeupWalRcvWriter();
/* Process any requests or signals received recently */
ProcessWalRcvInterrupts();
/* Keepalived with primary when waiting flush wal data */
XLogWalRcvSendReply(false, false);
pg_usleep(1000); /* 1ms */
} else {
walRcvDataCleanup();
ProcessWalRcvInterrupts();
}
}
ereport(FATAL,
(errmsg("Unexpected seek in the walreceiver buffer. "
"xlogrecptr is (%X:%X) but local xlogptr is (%X:%X)."
"nbyte is %lu, walfreeoffset is %ld walwriteoffset is %ld walreadoffset is %ld",
(uint32)(recptr >> 32), (uint32)recptr, (uint32)(startptr >> 32), (uint32)startptr,
nbytes, walfreeoffset, walwriteoffset, walreadoffset)));
}
}
/* OK to receive the logs */
Assert(walfreeoffset + segbytes <= recBufferSize);
errorno = memcpy_s(walrecvbuf + walfreeoffset, recBufferSize - walfreeoffset, buf, segbytes);
securec_check(errorno, "\0", "\0");
XLByteAdvance(recptr, (uint32)segbytes);
nbytes -= segbytes;
buf += segbytes;
// update shared memory
UpdateWalRcvCtl(t_thrd.walreceiver_cxt.walRcvCtlBlock, recptr, segbytes);
}
wakeupWalRcvWriter();
}
/*
* Receive XLOG data into receiver buffer.
*/
static void XLogWalRcvReceive(char *buf, Size nbytes, XLogRecPtr recptr)
{
int walfreeoffset;
int walwriteoffset;
char *walrecvbuf = NULL;
XLogRecPtr startptr;
int recBufferSize = g_instance.attr.attr_storage.WalReceiverBufSize * 1024;
while (nbytes > 0) {
int segbytes;
int endPoint = recBufferSize;
errno_t errorno = EOK;
SpinLockAcquire(&t_thrd.walreceiver_cxt.walRcvCtlBlock->mutex);
if (t_thrd.walreceiver_cxt.walRcvCtlBlock->walFreeOffset ==
t_thrd.walreceiver_cxt.walRcvCtlBlock->walWriteOffset) {
// no data to be flushed
t_thrd.walreceiver_cxt.walRcvCtlBlock->walStart = recptr;
} else if (t_thrd.walreceiver_cxt.walRcvCtlBlock->walFreeOffset == recBufferSize &&
t_thrd.walreceiver_cxt.walRcvCtlBlock->walWriteOffset > 0) {
t_thrd.walreceiver_cxt.walRcvCtlBlock->walFreeOffset = 0;
}
walfreeoffset = t_thrd.walreceiver_cxt.walRcvCtlBlock->walFreeOffset;
walwriteoffset = t_thrd.walreceiver_cxt.walRcvCtlBlock->walWriteOffset;
walrecvbuf = t_thrd.walreceiver_cxt.walRcvCtlBlock->walReceiverBuffer;
startptr = t_thrd.walreceiver_cxt.walRcvCtlBlock->walStart;
SpinLockRelease(&t_thrd.walreceiver_cxt.walRcvCtlBlock->mutex);
ereport(DEBUG5, (errmsg("XLogWalRcvReceive: recptr(%u:%X),nbytes(%d),"
"walfreeoffset(%d),walwriteoffset(%d),startptr(%u:%X)",
(uint32)(recptr >> 32), (uint32)recptr, (int)nbytes, walfreeoffset, walwriteoffset,
(uint32)(startptr >> 32), (uint32)startptr)));
XLogWalRcvSendReply(false, false);
Assert(walrecvbuf != NULL);
Assert(walfreeoffset <= recBufferSize);
Assert(walwriteoffset <= recBufferSize);
if (walfreeoffset < walwriteoffset) {
endPoint = walwriteoffset - 1;
}
if (endPoint == walfreeoffset) {
if (WalRcvWriterInProgress()) {
wakeupWalRcvWriter();
@ -1207,7 +1336,7 @@ static void XLogWalRcvReceiveInBuf(char* buf, Size nbytes, XLogRecPtr recptr)
while (true) {
SpinLockAcquire(&t_thrd.walreceiver_cxt.walRcvCtlBlock->mutex);
if (t_thrd.walreceiver_cxt.walRcvCtlBlock->walFreeOffset ==
t_thrd.walreceiver_cxt.walRcvCtlBlock->walReadOffset) {
t_thrd.walreceiver_cxt.walRcvCtlBlock->walWriteOffset) {
t_thrd.walreceiver_cxt.walRcvCtlBlock->walStart = recptr;
SpinLockRelease(&t_thrd.walreceiver_cxt.walRcvCtlBlock->mutex);
break;
@ -1226,18 +1355,15 @@ static void XLogWalRcvReceiveInBuf(char* buf, Size nbytes, XLogRecPtr recptr)
}
ereport(FATAL,
(errmsg("Unexpected seek in the walreceiver buffer. "
"xlogrecptr is (%X:%X) but local xlogptr is (%X:%X).",
(uint32)(recptr >> 32),
(uint32)recptr,
(uint32)(startptr >> 32),
(uint32)startptr)));
(errmsg("Unexpected seek in the walreceiver buffer. "
"xlogrecptr is (%X:%X) but local xlogptr is (%X:%X).",
(uint32)(recptr >> 32), (uint32)recptr, (uint32)(startptr >> 32), (uint32)startptr)));
}
}
/* OK to receive the logs */
Assert(walfreeoffset + segbytes <= recBufferSize);
errorno = memcpy_s(walrecvbuf + walfreeoffset, recBufferSize - walfreeoffset, buf, segbytes);
errorno = memcpy_s(walrecvbuf + walfreeoffset, recBufferSize, buf, segbytes);
securec_check(errorno, "\0", "\0");
XLByteAdvance(recptr, (uint32)segbytes);
@ -1249,7 +1375,7 @@ static void XLogWalRcvReceiveInBuf(char* buf, Size nbytes, XLogRecPtr recptr)
SpinLockAcquire(&t_thrd.walreceiver_cxt.walRcvCtlBlock->mutex);
t_thrd.walreceiver_cxt.walRcvCtlBlock->walFreeOffset += segbytes;
if (t_thrd.walreceiver_cxt.walRcvCtlBlock->walFreeOffset == recBufferSize &&
t_thrd.walreceiver_cxt.walRcvCtlBlock->walReadOffset > 0) {
t_thrd.walreceiver_cxt.walRcvCtlBlock->walWriteOffset > 0) {
t_thrd.walreceiver_cxt.walRcvCtlBlock->walFreeOffset = 0;
}
t_thrd.walreceiver_cxt.walRcvCtlBlock->receivePtr = recptr;
@ -1259,158 +1385,6 @@ static void XLogWalRcvReceiveInBuf(char* buf, Size nbytes, XLogRecPtr recptr)
wakeupWalRcvWriter();
}
/*
* Receive XLOG data into receiver buffer.
*/
static void
XLogWalRcvReceive(char *buf, Size nbytes, XLogRecPtr recptr)
{
int walfreeoffset;
int walwriteoffset;
char *walrecvbuf = NULL;
XLogRecPtr startptr;
int recBufferSize = g_instance.attr.attr_storage.WalReceiverBufSize * 1024;
while (nbytes > 0)
{
int segbytes;
int endPoint = recBufferSize;
errno_t errorno = EOK;
SpinLockAcquire(&t_thrd.walreceiver_cxt.walRcvCtlBlock->mutex);
if (t_thrd.walreceiver_cxt.walRcvCtlBlock->walFreeOffset == t_thrd.walreceiver_cxt.walRcvCtlBlock->walWriteOffset)
{
// no data to be flushed
t_thrd.walreceiver_cxt.walRcvCtlBlock->walStart = recptr;
}
else if (t_thrd.walreceiver_cxt.walRcvCtlBlock->walFreeOffset == recBufferSize &&
t_thrd.walreceiver_cxt.walRcvCtlBlock->walWriteOffset > 0)
{
t_thrd.walreceiver_cxt.walRcvCtlBlock->walFreeOffset = 0;
}
walfreeoffset = t_thrd.walreceiver_cxt.walRcvCtlBlock->walFreeOffset;
walwriteoffset = t_thrd.walreceiver_cxt.walRcvCtlBlock->walWriteOffset;
walrecvbuf = t_thrd.walreceiver_cxt.walRcvCtlBlock->walReceiverBuffer;
startptr = t_thrd.walreceiver_cxt.walRcvCtlBlock->walStart;
SpinLockRelease(&t_thrd.walreceiver_cxt.walRcvCtlBlock->mutex);
ereport(DEBUG5,
(errmsg("XLogWalRcvReceive: recptr(%u:%X),nbytes(%d),"
"walfreeoffset(%d),walwriteoffset(%d),startptr(%u:%X)",
(uint32) (recptr >> 32), (uint32) recptr, (int)nbytes, walfreeoffset,
walwriteoffset, (uint32) (startptr >> 32), (uint32) startptr)));
XLogWalRcvSendReply(false, false);
Assert(walrecvbuf != NULL);
Assert(walfreeoffset <= recBufferSize);
Assert(walwriteoffset <= recBufferSize);
if (walfreeoffset < walwriteoffset)
{
endPoint = walwriteoffset - 1;
}
if (endPoint == walfreeoffset)
{
if (WalRcvWriterInProgress())
{
wakeupWalRcvWriter();
/* Process any requests or signals received recently */
ProcessWalRcvInterrupts();
/* Keepalived with primary when waiting flush wal data */
XLogWalRcvSendReply(false, false);
pg_usleep(1000);
}
else
walRcvDataCleanup();
continue;
}
if (walfreeoffset + (int)nbytes > endPoint)
segbytes = endPoint - walfreeoffset;
else
segbytes = nbytes;
/* Need to seek in the buffer? */
if (walfreeoffset != walwriteoffset)
{
if (walfreeoffset > walwriteoffset)
{
XLByteAdvance(startptr, (uint32)(walfreeoffset - walwriteoffset));
}
else
{
XLByteAdvance(startptr, (uint32)(recBufferSize - walwriteoffset + walfreeoffset));
}
if (!XLByteEQ(startptr, recptr))
{
/* wait for finishing flushing all wal data */
while (true)
{
SpinLockAcquire(&t_thrd.walreceiver_cxt.walRcvCtlBlock->mutex);
if (t_thrd.walreceiver_cxt.walRcvCtlBlock->walFreeOffset == t_thrd.walreceiver_cxt.walRcvCtlBlock->walWriteOffset)
{
t_thrd.walreceiver_cxt.walRcvCtlBlock->walStart = recptr;
SpinLockRelease(&t_thrd.walreceiver_cxt.walRcvCtlBlock->mutex);
break;
}
SpinLockRelease(&t_thrd.walreceiver_cxt.walRcvCtlBlock->mutex);
if (WalRcvWriterInProgress())
{
wakeupWalRcvWriter();
/* Process any requests or signals received recently */
ProcessWalRcvInterrupts();
/* Keepalived with primary when waiting flush wal data */
XLogWalRcvSendReply(false, false);
pg_usleep(1000);
}
else
walRcvDataCleanup();
}
ereport(FATAL,
(errmsg("Unexpected seek in the walreceiver buffer. "
"xlogrecptr is (%X:%X) but local xlogptr is (%X:%X).",
(uint32) (recptr >> 32),
(uint32) recptr,
(uint32) (startptr >> 32),
(uint32) startptr)));
}
}
/* OK to receive the logs */
Assert(walfreeoffset + segbytes <= recBufferSize);
errorno = memcpy_s(walrecvbuf + walfreeoffset, recBufferSize - walfreeoffset, buf, segbytes);
securec_check(errorno, "\0", "\0");
XLByteAdvance(recptr, (uint32)segbytes);
nbytes -= segbytes;
buf += segbytes;
// update shared memory
SpinLockAcquire(&t_thrd.walreceiver_cxt.walRcvCtlBlock->mutex);
t_thrd.walreceiver_cxt.walRcvCtlBlock->walFreeOffset += segbytes;
if (t_thrd.walreceiver_cxt.walRcvCtlBlock->walFreeOffset == recBufferSize &&
t_thrd.walreceiver_cxt.walRcvCtlBlock->walWriteOffset > 0)
{
t_thrd.walreceiver_cxt.walRcvCtlBlock->walFreeOffset = 0;
}
t_thrd.walreceiver_cxt.walRcvCtlBlock->receivePtr = recptr;
SpinLockRelease(&t_thrd.walreceiver_cxt.walRcvCtlBlock->mutex);
}
wakeupWalRcvWriter();
}
/*
* Send reply message to primary, indicating our current XLOG positions, oldest
* xmin and the current time.

View File

@ -464,16 +464,13 @@ void RequestXLogStreaming(XLogRecPtr* recptr, const char* conninfo, ReplConnTarg
walrcv->receiveStart = Lcrecptr;
walrcv->latestValidRecord = latestValidRecord;
walrcv->latestRecordCrc = t_thrd.xlog_cxt.latestRecordCrc;
walrcv->latestRecordCrc = latestRecordCrc;
SpinLockRelease(&walrcv->mutex);
WalRcvSetPercentCountStartLsn(t_thrd.xlog_cxt.latestRecordCrc);
WalRcvSetPercentCountStartLsn(walrcv->latestValidRecord);
if (XLByteLT(latestValidRecord, Lcrecptr))
ereport(LOG,
(errmsg("latest valid record at %X/%X, wal receiver start point at %X/%X",
(uint32)(latestValidRecord >> 32),
(uint32)latestValidRecord,
(uint32)(Lcrecptr >> 32),
(uint32)Lcrecptr)));
ereport(LOG, (errmsg("latest valid record at %X/%X, wal receiver start point at %X/%X",
(uint32)(latestValidRecord >> 32), (uint32)latestValidRecord, (uint32)(Lcrecptr >> 32),
(uint32)Lcrecptr)));
SendPostmasterSignal(PMSIGNAL_START_WALRECEIVER);
}

View File

@ -33,7 +33,7 @@
#include "access/xlogreader.h"
#include "nodes/pg_list.h"
#include "storage/proc.h"
#include "access/redo_statistic.h"
#include "access/extreme_rto/redo_item.h"
#include "access/extreme_rto/page_redo.h"
#include "access/extreme_rto/txn_redo.h"
@ -55,8 +55,9 @@ typedef struct {
} TrxnRedoPipeline;
typedef struct ReadPipeline {
PageRedoWorker* managerThd; /* readthrd */
PageRedoWorker* readThd; /* readthrd */
PageRedoWorker *managerThd; /* readthrd */
PageRedoWorker *readPageThd; /* readthrd */
PageRedoWorker *readThd; /* readthrd */
} ReadPipeline;
#define MAX_XLOG_READ_BUFFER (0xFFFFF) /* 8k uint*/
@ -65,20 +66,22 @@ typedef struct ReadPipeline {
typedef enum {
READ_WORKER_STOP = 0,
READ_WORKER_RUN,
READ_WORKER_EXIT,
READ_NOTIFY_EXIT,
}Enum_ReadWorkerState;
WORKER_STATE_STOP = 0,
WORKER_STATE_RUN,
WORKER_STATE_STOPPING,
WORKER_STATE_EXIT,
WORKER_STATE_EXITING,
} ReadWorkersState;
typedef enum {
TRIGGER_NORMAL = 0,
TRIGGER_PRIMARY,
TRIGGER_STADNBY,
TRIGGER_FAILOVER,
TRIGGER_SWITCHOVER,
}Enum_TriggeredState;
TRIGGER_STADNBY,
TRIGGER_FAILOVER,
TRIGGER_SWITCHOVER,
TRIGGER_SMARTSHUTDOWN,
} Enum_TriggeredState;
typedef enum {
NONE,
@ -86,6 +89,10 @@ typedef enum {
APPLIED,
}ReadBufState;
typedef enum {
READ_MANAGER_STOP,
READ_MANAGER_RUN,
} XLogReadManagerState;
typedef struct RecordBufferAarray {
XLogSegNo segno;
@ -96,15 +103,23 @@ typedef struct RecordBufferAarray {
} RecordBufferAarray;
typedef struct RecordBufferState {
XLogReaderState* initreader;
uint32 startreadworker;
uint32 applyindex;
uint32 readindex;
RecordBufferAarray xlogsegarray[MAX_ALLOC_SEGNUM];
char *readsegbuf;
char *readBuf;
char *errormsg_buf;
void *readprivate;
XLogReaderState *initreader;
uint32 readWorkerState;
uint32 readPageWorkerState;
uint32 readSource;
uint32 failSource;
uint32 xlogReadManagerState;
uint32 applyindex;
uint32 readindex;
RecordBufferAarray xlogsegarray[MAX_ALLOC_SEGNUM];
char *readsegbuf;
char *readBuf;
char *errormsg_buf;
void *readprivate;
XLogRecPtr latestValidRecord;
XLogRecPtr targetRecPtr;
XLogRecPtr expectLsn;
pg_crc32 latestRecordCrc;
} RecordBufferState;
@ -115,17 +130,14 @@ typedef struct {
uint32* chosedPageLineIds; /* chosedPageLineIds */
uint32 chosedPLCnt; /* chosedPageLineCount */
TrxnRedoPipeline trxnLine;
ReadPipeline readLine;
RecordBufferState recordstate;
PageRedoWorker** allWorkers; /* Array of page redo workers. */
TxnRedoWorker* txnWorker; /* Txn redo worker. */
ReadPipeline readLine;
RecordBufferState recordstate;
PageRedoWorker **allWorkers; /* Array of page redo workers. */
uint32 allWorkersCnt;
RedoItem* freeHead; /* Head of freed-item list. */
RedoItem* freeStateHead;
RedoItem* allocatedRedoItem;
int32 pendingCount; /* Number of records pending. */
int32 pendingMax; /* The max. pending count per batch. */
int exitCode; /* Thread exit code. */
RedoItem *freeHead; /* Head of freed-item list. */
RedoItem *freeStateHead;
RedoItem *allocatedRedoItem;
int exitCode; /* Thread exit code. */
uint64 totalCostTime;
uint64 txnCostTime; /* txn cost time */
uint64 pprCostTime;
@ -136,6 +148,10 @@ typedef struct {
uint32 syncExitCount;
pg_atomic_uint32 standbyState; /* sync standbyState from trxn worker to startup */
bool needImmediateCheckpoint;
bool needFullSyncCheckpoint;
volatile sig_atomic_t smartShutdown;
} LogDispatcher;
typedef struct {
@ -157,8 +173,8 @@ const static XLogRecPtr MAX_XLOG_REC_PTR = (XLogRecPtr)0xFFFFFFFFFFFFFFFF;
const static uint64 OUTPUT_WAIT_COUNT = 0x7FFFFFF;
const static uint64 PRINT_ALL_WAIT_COUNT = 0x7FFFFFFFF;
extern RedoItem g_redoEndMark;
extern uint32 g_triggeredstate;
extern uint32 g_startupTriggerState;
extern uint32 g_readManagerTriggerFlag;
inline int get_batch_redo_num()
{
@ -200,7 +216,6 @@ PGPROC* StartupPidGetProc(ThreadId pid);
extern void SetStartupBufferPinWaitBufId(int bufid);
extern void GetStartupBufferPinWaitBufId(int *bufids, uint32 len);
extern uint32 GetStartupBufferPinWaitBufLen();
void UpdateStandbyState(HotStandbyState newState);
/* Redo end state saved by each page worker. */
@ -216,7 +231,9 @@ List* CheckImcompleteAction(List* imcompleteActionList);
void SetPageWorkStateByThreadId(uint32 threadState);
void UpdateDispatcherStandbyState(HotStandbyState* state);
void GetReplayedRecPtr(XLogRecPtr *startPtr, XLogRecPtr *endPtr);
void StartupSendLsnFowarder();
void StartupSendFowarder(RedoItem *item);
RedoWaitInfo redo_get_io_event(int32 event_id);
void redo_get_wroker_statistic(uint32 *realNum, RedoWorkerStatsData *worker, uint32 workerLen);
} // namespace extreme_rto

View File

@ -35,18 +35,12 @@
#include "access/extreme_rto/posix_semaphore.h"
#include "access/extreme_rto/spsc_blocking_queue.h"
#include "access/xlogproc.h"
namespace extreme_rto {
static const uint32 PAGE_WORK_QUEUE_SIZE = 8192;
static const uint32 MAX_REDO_DISTRUBUTE_MAP_NUM = 2;
struct SafeRestartPoint {
SafeRestartPoint* next;
XLogRecPtr restartPoint;
};
typedef enum {
REDO_BATCH,
REDO_PAGE_MNG,
@ -54,20 +48,11 @@ typedef enum {
REDO_TRXN_MNG,
REDO_TRXN_WORKER,
REDO_READ_WORKER,
REDO_READ_PAGE_WORKER,
REDO_READ_MNG,
REDO_ROLE_NUM,
} RedoRole;
typedef struct {
HTAB* redoItemHash;
slock_t rwlock;
} RedoDistributeMap;
typedef struct {
uint32 curMapNum;
RedoDistributeMap mapList[MAX_REDO_DISTRUBUTE_MAP_NUM];
} RedoItemMap;
struct PageRedoWorker {
/*
* The last successfully applied log record's end position + 1 as an
@ -121,12 +106,6 @@ struct PageRedoWorker {
* Safe restart point handling.
*/
/*
* A list of safe recovery restart point seen by this worker.
* The restart points are listed in reverse LSN order to ease the
* lock-free implementation.
*/
SafeRestartPoint* safePointHead;
/*
* The last recovery restart point seen by the txn worker. Restart
* points before this is useless and can be removed.
@ -165,9 +144,6 @@ struct PageRedoWorker {
* These values are collected by each redo worker at redo end and
* are used by the dispatcher.
*/
/* B-Tree incomplete actions. */
void* btreeIncompleteActions;
/* XLog invalid pages. */
void* xlogInvalidPages;
@ -180,23 +156,20 @@ struct PageRedoWorker {
/* Semaphore marking the completion of the current phase. */
PosixSemaphore phaseMarker;
uint32 statMulpageCnt;
uint64 statWaitReach;
uint64 statWaitReplay;
pg_atomic_uint32 readyStatus;
MemoryContext oldCtx;
HTAB * redoItemHash;
uint64 curbatchcount;
TimeLineID recoveryTargetTLI;
bool ArchiveRecoveryRequested;
HTAB *redoItemHash;
TimeLineID recoveryTargetTLI;
bool ArchiveRecoveryRequested;
bool StandbyModeRequested;
bool InArchiveRecovery;
bool ArchiveRestoreRequested;
bool InRecovery;
int bufferPinWaitBufId;
uint32 fullSyncFlag;
RedoParseManager parseManager;
RedoBufferManager bufferManager;
int bufferPinWaitBufId;
};
extern THR_LOCAL PageRedoWorker* g_redoWorker;
@ -228,16 +201,14 @@ bool ProcessPendingPageRedoItems(PageRedoWorker* worker);
/* Run-time worker states. */
uint64 GetCompletedRecPtr(PageRedoWorker* worker);
bool IsRecoveryRestartPointSafe(PageRedoWorker* worker, XLogRecPtr restartPoint);
void SetWorkerRestartPoint(PageRedoWorker* worker, XLogRecPtr restartPoint);
void UpdatePageRedoWorkerStandbyState(PageRedoWorker* worker, HotStandbyState newState);
/* Redo end states. */
void* GetBTreeIncompleteActions(PageRedoWorker* worker);
void ClearBTreeIncompleteActions(PageRedoWorker* worker);
void* GetXLogInvalidPages(PageRedoWorker* worker);
bool RedoWorkerIsIdle(PageRedoWorker* worker);
void ClearBTreeIncompleteActions(PageRedoWorker *worker);
void *GetXLogInvalidPages(PageRedoWorker *worker);
bool RedoWorkerIsIdle(PageRedoWorker *worker);
void PageRedoSetAffinity(uint32 id);
void DumpPageRedoWorker(PageRedoWorker* worker);
@ -247,13 +218,13 @@ extern void UpdateRecordGlobals(RedoItem* item, HotStandbyState standbyState);
void ReferenceRedoItem(void *item);
void DereferenceRedoItem(void *item);
void PushToWorkerLsn(bool force);
void WaitLsnUpdate(bool force);
void GetCompletedReadEndPtr(PageRedoWorker *worker, XLogRecPtr *readPtr, XLogRecPtr *endPtr);
void UpdateReadBufferForExtRto(XLogReaderState* state);
bool SetReadBufferForExtRto(XLogReaderState* state, XLogRecPtr pageptr, int reqLen);
bool XLogPageReadForExtRto(XLogRecPtr targetPagePtr, int reqLen, char* readBuf);
void DumpExtremeRtoReadBuf();
void PutRecordToReadQueue(XLogReaderState *recordreader);
bool LsnUpdate();
} // namespace extreme_rto
#endif

View File

@ -37,86 +37,22 @@
#include "replication/replicainternal.h"
namespace extreme_rto {
typedef struct {
RelFileNode node;
BlockNumber block;
bool is_root;
} BTreeIncompleteAction;
typedef struct {
RelFileNode node;
ForkNumber fork;
BlockNumber minBlock;
Oid dbid;
} XLogInvalidPage;
typedef union {
BTreeIncompleteAction btree;
XLogInvalidPage xlog;
} ContextUpdateData;
typedef enum {
BTREE_FORGET_SPLIT,
BTREE_FORGET_DELETE,
XLOG_FORGET_PAGES,
XLOG_FORGET_PAGES_DB
} ContextUpdateType;
typedef void (*ContextUpdateFunc)(const ContextUpdateData* data);
/*
* Btree's incomplete_actions and XLog's invalid_page_tab need special
* treatment. Both use log_xxx() and forget_xxx() functions to maintain
* inconsistent states during log replay. Each of the log_xxx() functions
* remembers an inconsistent condition, and each of the forget_xxx()
* functions removes some inconsistent conditions. Because the two
* variables are thread local, the key to make it work under parallel log
* replay is to make sure the log_xxx() and the forget_xxx() for matching
* conditions are called in the same thread so they can correctly cancel
* each other. A ContextUpdateOp can be used to send a request to call
* log_xxx() or forget_xxx() from one worker to another worker. The
* protocol is to set up the ContextUpdateOp during the redo function, and
* after the record has been replayed each of the other workers checks
* the ContextUpdateOp and calls the ContextUpdateFunc if it is the
* ContextUpdateOp's designatedWorker. See comments on incomplete_actions
* and invalid_page_tab for detailed descriptions.
*/
typedef struct {
/* The type of the operation. */
ContextUpdateType type;
/* The data for the operation. */
ContextUpdateData data;
/* The function that performs the operation. */
ContextUpdateFunc func;
/* The id of the worker who needs to perform the operation. */
uint32 designatedWorker;
/* If the operation is valid. */
bool inUse;
} ContextUpdateOp;
typedef struct RedoItem_s {
/* Old version. */
bool oldVersion;
bool sharewithtrxn; /* if ture when designatedWorker is trxn or all and need sync with pageworker */
bool blockbytrxn; /* if ture when designatedWorker is pagerworker and need sync with trxn */
bool imcheckpoint;
bool needImmediateCheckpoint;
bool needFullSyncCheckpoint;
/* Number of workers sharing this item. */
uint32 shareCount;
/* redo pool share count. */
uint32 rdsCnt;
/* Id of the worker designated to apply this item. */
uint32 designatedWorker;
/* The expected timelines for this record. */
List* expectedTLIs;
List *expectedTLIs;
/* The timestamp of the log record if it is a transaction record. */
TimestampTz recordXTime;
/* Next item on each worker's list. */
struct RedoItem_s** nextByWorker;
/* Next item on the free list. */
struct RedoItem_s* freeNext;
/* Operation to update thread-local variables after replay. */
ContextUpdateOp contextUpdateOp;
struct RedoItem_s *freeNext;
/* Number of workers holding a reference to this item. */
pg_atomic_uint32 refCount;
/* If this item has been replayed. */
@ -134,8 +70,6 @@ typedef struct RedoItem_s {
pg_atomic_uint32 blkShareCount;
bool isForceAll;
/* one item can not be put in the same queue twice. */
bool* isInWorker;
pg_atomic_uint32 distributeCount;
} RedoItem;
@ -149,15 +83,10 @@ static inline RedoItem* GetRedoItemPtr(XLogReaderState* record)
return (RedoItem*)(((char*)record) - offsetof(RedoItem, record));
}
RedoItem *CreateRedoItem(XLogReaderState *record, uint32 shareCount, uint32 designatedWorker, List *expectedTLIs,
TimestampTz recordXTime, bool buseoriginal, bool isForceAll = false);
RedoItem* CreateRedoItem(XLogReaderState* record, uint32 shareCount, uint32 designatedWorker, List* expectedTLIs,
TimestampTz recordXTime, bool buseoriginal, bool isForceAll = false);
RedoItem* CreateLSNMarker(XLogReaderState* record, List* expectedTLIs, bool buseoriginal = false);
bool IsLSNMarker(const RedoItem* item);
void ApplyRedoRecord(XLogReaderState* record, bool bOld);
void ApplyRedoRecord(XLogReaderState *record, bool bOld);
} // namespace extreme_rto
#endif

View File

@ -36,7 +36,7 @@ static const int MAX_REDO_WORKERS_PER_PARSE = 8;
static const int TRXN_REDO_MANAGER_NUM = 1;
static const int TRXN_REDO_WORKER_NUM = 1;
static const int XLOG_READER_NUM = 2;
static const int XLOG_READER_NUM = 3;
static const int MAX_EXTREME_THREAD_NUM = MAX_PARSE_WORKERS * MAX_REDO_WORKERS_PER_PARSE + MAX_PARSE_WORKERS +
MAX_PARSE_WORKERS + TRXN_REDO_MANAGER_NUM + TRXN_REDO_WORKER_NUM + XLOG_READER_NUM;

View File

@ -20,6 +20,7 @@
#include "datatype/timestamp.h"
#include "lib/stringinfo.h"
#include "access/parallel_recovery/redo_item.h"
#include "knl/knl_instance.h"
#include "access/htup.h"
/* Sync methods */
@ -381,6 +382,8 @@ extern void load_server_mode(void);
extern void WaitCheckpointSync(void);
void GetRecoveryLatch();
void ReLeaseRecoveryLatch();
void ExtremRtoUpdateMinCheckpoint();
bool IsRecoveryDone();
extern XLogRecPtr XlogRemoveSegPrimary;

View File

@ -313,6 +313,7 @@ struct XLogReaderState {
// For parallel recovery
bool isPRProcess;
bool isDecode;
bool isFullSyncCheckpoint;
};
#define SizeOfXLogRecord (offsetof(XLogRecord, xl_crc) + sizeof(pg_crc32c))

View File

@ -235,7 +235,7 @@ extern Datum pg_xlog_location_diff(PG_FUNCTION_ARGS);
int XLogPageRead(XLogReaderState* xlogreader, XLogRecPtr targetPagePtr, int reqLen, XLogRecPtr targetRecPtr,
char* readBuf, TimeLineID* readTLI);
bool XLogReadFromWriteBufferForFirst(XLogRecPtr targetPagePtr, int reqLen, char* readBuf);
int XLogReadFromWriteBuffer(XLogRecPtr targetStartPtr, int reqLen, char* readBuf, uint32 *rereadlen);
bool XLogReadFromWriteBuffer(XLogRecPtr targetStartPtr, int reqLen, char* readBuf, uint32 *rereadlen);
#endif /* XLOG_INTERNAL_H */

View File

@ -204,6 +204,7 @@ typedef struct {
uint32 blockddltype;
uint32 columnrel;
Oid ownerid;
char *mainData;
} XLogBlockDdlParse;
/* ********BLOCK DDL END ***************** */
@ -477,6 +478,9 @@ typedef struct
Buffer buf_id;
Buffer freeNext;
} RedoMemSlot;
typedef void (*InterruptFunc)();
typedef struct
{
int totalblknum; /* total slot */
@ -486,6 +490,7 @@ typedef struct
Buffer firstreleaseslot; /* first release slot */
RedoMemSlot *memslot; /* slot itme */
bool isInit;
InterruptFunc doInterrupt;
}RedoMemManager;
typedef void (*RefOperateFunc)(void *record);
@ -519,6 +524,7 @@ typedef struct {
RedoParseManager* manager;
void* refrecord; /* origin dataptr, for mem release */
uint64 batchcount;
bool isFullSyncCheckpoint;
} XLogRecParseState;
typedef struct XLogBlockRedoExtreRto {
@ -581,14 +587,15 @@ typedef enum {
HEAP_PAGE_UPDATE_ORIG_BLOCK_NUM = 0
} XLogHeapPageUpdateBlockEnum;
extern THR_LOCAL RedoParseManager g_parseManager;
extern THR_LOCAL RedoBufferManager g_bufferManager;
extern THR_LOCAL RedoParseManager* g_parseManager;
extern THR_LOCAL RedoBufferManager* g_bufferManager;
extern void* XLogMemCtlInit(RedoMemManager* memctl, Size itemsize, int itemnum);
extern RedoMemSlot* XLogMemAlloc(RedoMemManager* memctl);
extern void XLogMemRelease(RedoMemManager* memctl, Buffer bufferid);
extern void XLogRedoBufferInit(RedoBufferManager* buffermanager, int buffernum, RefOperate *refOperate);
extern void XLogRedoBufferInit(RedoBufferManager* buffermanager, int buffernum, RefOperate *refOperate,
InterruptFunc interruptOperte);
extern void XLogRedoBufferDestory(RedoBufferManager* buffermanager);
extern RedoMemSlot* XLogRedoBufferAlloc(
RedoBufferManager* buffermanager, RelFileNode relnode, ForkNumber forkNum, BlockNumber blockNum);
@ -599,44 +606,39 @@ extern Block XLogRedoBufferGetBlk(RedoBufferManager* buffermanager, RedoMemSlot*
extern Block XLogRedoBufferGetPage(RedoBufferManager* buffermanager, Buffer bufferid);
extern void XLogRedoBufferSetState(RedoBufferManager* buffermanager, RedoMemSlot* bufferslot, uint32 state);
#define XLogRedoBufferInitFunc(buffernum, defOperate) do { \
XLogRedoBufferInit(&(g_bufferManager), buffernum, defOperate); \
#define XLogRedoBufferInitFunc(bufferManager, buffernum, defOperate, interruptOperte) do { \
XLogRedoBufferInit(bufferManager, buffernum, defOperate, interruptOperte); \
} while (0)
#define XLogRedoBufferDestoryFunc() do { \
XLogRedoBufferDestory(&(g_bufferManager)); \
#define XLogRedoBufferDestoryFunc(bufferManager) do { \
XLogRedoBufferDestory(bufferManager); \
} while (0)
#define XLogRedoBufferAllocFunc(relnode, forkNum, blockNum, bufferslot) do { \
*bufferslot = XLogRedoBufferAlloc(&(g_bufferManager), relnode, forkNum, blockNum); \
*bufferslot = XLogRedoBufferAlloc(g_bufferManager, relnode, forkNum, blockNum); \
} while (0)
#define XLogRedoBufferIsValidFunc(bufferid, isvalid) do { \
*isvalid = XLogRedoBufferIsValid(&(g_bufferManager), bufferid); \
*isvalid = XLogRedoBufferIsValid(g_bufferManager, bufferid); \
} while (0)
#define XLogRedoBufferReleaseFunc(bufferid) do { \
XLogRedoBufferRelease(&(g_bufferManager), bufferid); \
XLogRedoBufferRelease(g_bufferManager, bufferid); \
} while (0)
#define XLogRedoBufferGetBlkNumberFunc(bufferid, blknumber) do { \
*blknumber = XLogRedoBufferGetBlkNumber(&(g_bufferManager), bufferid); \
*blknumber = XLogRedoBufferGetBlkNumber(g_bufferManager, bufferid); \
} while (0)
#define XLogRedoBufferGetBlkFunc(bufferslot, blockdata) do { \
*blockdata = XLogRedoBufferGetBlk(&(g_bufferManager), bufferslot); \
*blockdata = XLogRedoBufferGetBlk(g_bufferManager, bufferslot); \
} while (0)
#define XLogRedoBufferGetPageFunc(bufferid, blockdata) do { \
*blockdata = (Page)XLogRedoBufferGetPage(&(g_bufferManager), bufferid); \
*blockdata = (Page)XLogRedoBufferGetPage(g_bufferManager, bufferid); \
} while (0)
#define XLogRedoBufferSetStateFunc(bufferslot, state) do { \
XLogRedoBufferSetState(&(g_bufferManager), bufferslot, state); \
XLogRedoBufferSetState(g_bufferManager, bufferslot, state); \
} while (0)
#define Inc_ReaderState_RefCount(readstate) (++((readstate)->refcount))
#define DecAndGet_ReaderState_RefCount(readstate) (--(((XLogReaderState*)(readstate))->refcount))
extern void XLogParseBufferInit(RedoParseManager* parsemanager, int buffernum, RefOperate *refOperate);
extern void XLogParseBufferInit(RedoParseManager* parsemanager, int buffernum, RefOperate *refOperate,
InterruptFunc interruptOperte);
extern void XLogParseBufferDestory(RedoParseManager* parsemanager);
extern void XLogParseBufferRelease(XLogRecParseState* recordstate);
extern XLogRecParseState* XLogParseBufferAllocList(RedoParseManager* parsemanager, XLogRecParseState* blkstatehead, void *record);
@ -645,12 +647,12 @@ extern void XLogInitBufferForRedo(XLogReaderState* record, uint8 block_id, RedoB
extern XLogRedoAction XLogReadBufferForRedoExtended(XLogReaderState* record, uint8 buffer_id, ReadBufferMode mode,
bool get_cleanup_lock, RedoBufferInfo* bufferinfo, ReadBufferMethod readmethod = WITH_NORMAL_CACHE);
#define XLogParseBufferInitFunc(buffernum, defOperate) do { \
XLogParseBufferInit(&(g_parseManager), buffernum, defOperate); \
#define XLogParseBufferInitFunc(parseManager, buffernum, defOperate, interruptOperte) do { \
XLogParseBufferInit(parseManager, buffernum, defOperate, interruptOperte); \
} while (0)
#define XLogParseBufferDestoryFunc() do { \
XLogParseBufferDestory(&(g_parseManager)); \
#define XLogParseBufferDestoryFunc(parseManager) do { \
XLogParseBufferDestory(parseManager); \
} while (0)
#define XLogParseBufferReleaseFunc(recordstate) do { \
@ -658,18 +660,45 @@ extern XLogRedoAction XLogReadBufferForRedoExtended(XLogReaderState* record, uin
} while (0)
#define XLogParseBufferAllocListFunc(record, newblkstate, blkstatehead) do { \
*newblkstate = XLogParseBufferAllocList(&(g_parseManager), blkstatehead, record); \
*newblkstate = XLogParseBufferAllocList(g_parseManager, blkstatehead, record); \
} while (0)
#define XLogParseBufferAllocListStateFunc(record, newblkstate, blkstatehead) do { \
if (*blkstatehead == NULL) { \
*newblkstate = XLogParseBufferAllocList(&(g_parseManager), NULL, record); \
*newblkstate = XLogParseBufferAllocList(g_parseManager, NULL, record); \
*blkstatehead = *newblkstate; \
} else { \
*newblkstate = XLogParseBufferAllocList(&(g_parseManager), *blkstatehead, record); \
*newblkstate = XLogParseBufferAllocList(g_parseManager, *blkstatehead, record); \
} \
} while (0)
#ifdef EXTREME_RTO_DEBUG_AB
typedef void (*AbnormalProcFunc)(void);
typedef enum {
A_THREAD_EXIT,
ALLOC_FAIL,
OPEN_FILE_FAIL,
ABNORMAL_NUM,
}AbnormalType;
extern AbnormalProcFunc g_AbFunList[ABNORMAL_NUM];
#define ADD_ABNORMAL_POSITION(pos) do { \
static int __count##pos = 0; \
__count##pos++; \
if (g_instance.attr.attr_storage.extreme_rto_ab_pos == pos) { \
if (g_instance.attr.attr_storage.extreme_rto_ab_count == __count##pos) { \
ereport(LOG, (errmsg("extreme rto debug abnormal stop pos:%d, type:%d, count:%d", pos, \
g_instance.attr.attr_storage.extreme_rto_ab_type, __count##pos))); \
g_AbFunList[g_instance.attr.attr_storage.extreme_rto_ab_type % ABNORMAL_NUM](); \
} \
} \
} while(0)
#else
#define ADD_ABNORMAL_POSITION(pos)
#endif
void heap_xlog_clean_operator_page(
RedoBufferInfo* buffer, void* recorddata, void* blkdata, Size datalen, Size* freespace, bool repair_fragmentation);
void heap_xlog_freeze_operator_page(RedoBufferInfo* buffer, void* recorddata, void* blkdata, Size datalen);
@ -870,5 +899,5 @@ extern void SyncOneBufferForExtremRto(RedoBufferInfo *bufferinfo);
extern void XLogBlockInitRedoBlockInfo(XLogBlockHead* blockhead, RedoBufferTag* blockinfo);
extern void XLogBlockDdlDoRealAction(XLogBlockHead* blockhead, void* blockrecbody, RedoBufferInfo* bufferinfo);
extern void GinRedoDataBlock(XLogBlockHead* blockhead, XLogBlockDataParse* blockdatarec, RedoBufferInfo* bufferinfo);
extern void GistRedoDataBlock(XLogBlockHead *blockhead, XLogBlockDataParse *blockdatarec, RedoBufferInfo *bufferinfo);
#endif

View File

@ -135,6 +135,7 @@ extern uint64 pg_cal_tablespace_size_oid(Oid tblspcOid);
extern Oid ConvertToPgclassRelTablespaceOid(Oid tblspc);
extern Oid ConvertToRelfilenodeTblspcOid(Oid tblspc);
extern void xlog_create_tblspc(Oid ts_id, char* ts_path, bool isRelativePath);
extern void xlog_drop_tblspc(Oid tsId);
#endif /* TABLESPACE_H */

View File

@ -82,6 +82,11 @@ typedef struct knl_instance_attr_storage {
int advance_xlog_file_num;
int gtm_option;
int max_keep_log_seg;
#ifdef EXTREME_RTO_DEBUG_AB
int extreme_rto_ab_pos;
int extreme_rto_ab_type;
int extreme_rto_ab_count;
#endif
} knl_instance_attr_storage;
#endif /* SRC_INCLUDE_KNL_KNL_INSTANCE_ATTR_STORAGE_H_ */

View File

@ -250,6 +250,7 @@ typedef struct knl_g_localinfo_context {
volatile uint32 term = 1;
bool set_term = true;
knl_g_disconn_node_context disable_conn_node;
volatile bool need_disable_connection_node = false;
} knl_g_localinfo_context;
typedef struct knl_g_counters_context {
@ -396,6 +397,7 @@ typedef struct knl_g_parallel_redo_context {
volatile PageRedoWorkerStatus pageRedoThreadStatusList[MAX_RECOVERY_THREAD_NUM];
RedoPerf redoPf; /* redo Performance statistics */
pg_atomic_uint32 isLocalRedoFinish;
slock_t destroy_lock; /* redo worker destroy lock */
pg_atomic_uint64 endRecPtr;
} knl_g_parallel_redo_context;

View File

@ -185,6 +185,7 @@ typedef struct WalRcvData {
} WalRcvData;
extern XLogRecPtr latestValidRecord;
extern pg_crc32 latestRecordCrc;
extern bool ws_dummy_data_writer_use_file;
extern THR_LOCAL uint32 ws_dummy_data_read_file_num;

View File

@ -377,6 +377,8 @@ extern void InitProcessPhase2(void);
extern void InitAuxiliaryProcess(void);
extern void PublishStartupProcessInformation(void);
extern void SetStartupBufferPinWaitBufId(int bufid);
extern int GetStartupBufferPinWaitBufId(void);
extern bool HaveNFreeProcs(int n);
extern void ProcReleaseLocks(bool isCommit);
extern int GetUsedConnectionCount(void);