From 6b4954f66f8f2028eea167ead6a73a44e81c2115 Mon Sep 17 00:00:00 2001 From: victor_zhc Date: Mon, 28 Sep 2020 15:58:38 +0800 Subject: [PATCH] exetreme RTO --- src/common/backend/catalog/storage.cpp | 1 + .../optimizer/commands/tablespace.cpp | 37 +- .../process/postmaster/postmaster.cpp | 24 +- .../process/postmaster/startup.cpp | 8 +- .../process/threadpool/knl_instance.cpp | 1 + .../storage/access/common/reloptions.cpp | 4 +- src/gausskernel/storage/access/redo/clog.cpp | 2 +- .../storage/access/redo/ginxlog.cpp | 2 + .../storage/access/redo/gistxlog.cpp | 106 ++- .../storage/access/redo/nbtxlog.cpp | 4 +- .../storage/access/redo/xlogutils.cpp | 62 +- .../storage/access/rmgrdesc/gistdesc.cpp | 1 + .../access/transam/extreme_rto/dispatcher.cpp | 457 +++++----- .../access/transam/extreme_rto/page_redo.cpp | 838 +++++++++--------- .../access/transam/extreme_rto/redo_item.cpp | 75 +- .../extreme_rto/spsc_blocking_queue.cpp | 1 + .../access/transam/extreme_rto/txn_redo.cpp | 240 +---- .../storage/access/transam/multi_redo_api.cpp | 45 +- .../storage/access/transam/multixact.cpp | 6 +- .../transam/parallel_recovery/dispatcher.cpp | 16 +- .../storage/access/transam/xact.cpp | 18 +- .../storage/access/transam/xlog.cpp | 710 ++++++++++++--- .../storage/access/transam/xlogfuncs.cpp | 1 + .../storage/access/transam/xlogreader.cpp | 6 +- src/gausskernel/storage/buffer/bufmgr.cpp | 13 +- src/gausskernel/storage/ipc/procarray.cpp | 4 +- src/gausskernel/storage/lmgr/proc.cpp | 20 + .../storage/replication/walrcvwriter.cpp | 17 +- .../storage/replication/walreceiver.cpp | 318 +++---- .../storage/replication/walreceiverfuncs.cpp | 13 +- src/include/access/extreme_rto/dispatcher.h | 87 +- src/include/access/extreme_rto/page_redo.h | 57 +- src/include/access/extreme_rto/redo_item.h | 85 +- src/include/access/multi_redo_settings.h | 2 +- src/include/access/xlog.h | 3 + src/include/access/xlog_basic.h | 1 + src/include/access/xlog_internal.h | 2 +- src/include/access/xlogproc.h | 87 +- src/include/commands/tablespace.h | 1 + .../knl/knl_guc/knl_instance_attr_storage.h | 5 + src/include/knl/knl_instance.h | 2 + src/include/replication/walreceiver.h | 1 + src/include/storage/proc.h | 2 + 43 files changed, 1861 insertions(+), 1524 deletions(-) diff --git a/src/common/backend/catalog/storage.cpp b/src/common/backend/catalog/storage.cpp index 4ebaba1c6..a272e87d4 100644 --- a/src/common/backend/catalog/storage.cpp +++ b/src/common/backend/catalog/storage.cpp @@ -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); } diff --git a/src/gausskernel/optimizer/commands/tablespace.cpp b/src/gausskernel/optimizer/commands/tablespace.cpp index 0a6f9e450..c3ce82c67 100644 --- a/src/gausskernel/optimizer/commands/tablespace.cpp +++ b/src/gausskernel/optimizer/commands/tablespace.cpp @@ -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 diff --git a/src/gausskernel/process/postmaster/postmaster.cpp b/src/gausskernel/process/postmaster/postmaster.cpp index 20bc66a0f..7b9d36e5b 100755 --- a/src/gausskernel/process/postmaster/postmaster.cpp +++ b/src/gausskernel/process/postmaster/postmaster.cpp @@ -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"))); } diff --git a/src/gausskernel/process/postmaster/startup.cpp b/src/gausskernel/process/postmaster/startup.cpp index 0f1631a80..5e5a95d8a 100755 --- a/src/gausskernel/process/postmaster/startup.cpp +++ b/src/gausskernel/process/postmaster/startup.cpp @@ -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; } diff --git a/src/gausskernel/process/threadpool/knl_instance.cpp b/src/gausskernel/process/threadpool/knl_instance.cpp index dad582020..1892ff84f 100755 --- a/src/gausskernel/process/threadpool/knl_instance.cpp +++ b/src/gausskernel/process/threadpool/knl_instance.cpp @@ -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) diff --git a/src/gausskernel/storage/access/common/reloptions.cpp b/src/gausskernel/storage/access/common/reloptions.cpp index ed7de5d4f..317716517 100644 --- a/src/gausskernel/storage/access/common/reloptions.cpp +++ b/src/gausskernel/storage/access/common/reloptions.cpp @@ -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; diff --git a/src/gausskernel/storage/access/redo/clog.cpp b/src/gausskernel/storage/access/redo/clog.cpp index 4c1a9c314..3caa50434 100644 --- a/src/gausskernel/storage/access/redo/clog.cpp +++ b/src/gausskernel/storage/access/redo/clog.cpp @@ -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; diff --git a/src/gausskernel/storage/access/redo/ginxlog.cpp b/src/gausskernel/storage/access/redo/ginxlog.cpp index b24de495b..cc4933fc6 100644 --- a/src/gausskernel/storage/access/redo/ginxlog.cpp +++ b/src/gausskernel/storage/access/redo/ginxlog.cpp @@ -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); } } diff --git a/src/gausskernel/storage/access/redo/gistxlog.cpp b/src/gausskernel/storage/access/redo/gistxlog.cpp index ece782aed..d140efc2d 100644 --- a/src/gausskernel/storage/access/redo/gistxlog.cpp +++ b/src/gausskernel/storage/access/redo/gistxlog.cpp @@ -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))); + } +} + diff --git a/src/gausskernel/storage/access/redo/nbtxlog.cpp b/src/gausskernel/storage/access/redo/nbtxlog.cpp index c9627e9d3..c6f62f2a0 100644 --- a/src/gausskernel/storage/access/redo/nbtxlog.cpp +++ b/src/gausskernel/storage/access/redo/nbtxlog.cpp @@ -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) diff --git a/src/gausskernel/storage/access/redo/xlogutils.cpp b/src/gausskernel/storage/access/redo/xlogutils.cpp index d208d904d..ffec04b9d 100644 --- a/src/gausskernel/storage/access/redo/xlogutils.cpp +++ b/src/gausskernel/storage/access/redo/xlogutils.cpp @@ -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() diff --git a/src/gausskernel/storage/access/rmgrdesc/gistdesc.cpp b/src/gausskernel/storage/access/rmgrdesc/gistdesc.cpp index ef572c35c..541c3d156 100644 --- a/src/gausskernel/storage/access/rmgrdesc/gistdesc.cpp +++ b/src/gausskernel/storage/access/rmgrdesc/gistdesc.cpp @@ -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); diff --git a/src/gausskernel/storage/access/transam/extreme_rto/dispatcher.cpp b/src/gausskernel/storage/access/transam/extreme_rto/dispatcher.cpp index 3d5eb587a..5644a2e0d 100644 --- a/src/gausskernel/storage/access/transam/extreme_rto/dispatcher.cpp +++ b/src/gausskernel/storage/access/transam/extreme_rto/dispatcher.cpp @@ -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 diff --git a/src/gausskernel/storage/access/transam/extreme_rto/page_redo.cpp b/src/gausskernel/storage/access/transam/extreme_rto/page_redo.cpp index f8584b975..181fde77a 100644 --- a/src/gausskernel/storage/access/transam/extreme_rto/page_redo.cpp +++ b/src/gausskernel/storage/access/transam/extreme_rto/page_redo.cpp @@ -40,6 +40,7 @@ #include "access/xlog_internal.h" #include "access/xlogutils.h" #include "access/xlogproc.h" +#include "access/nbtree.h" #include "catalog/storage_xlog.h" #include "gssignal/gs_signal.h" #include "libpq/pqsignal.h" @@ -47,7 +48,8 @@ #include "storage/ipc.h" #include "storage/freespace.h" #include "storage/smgr.h" -#include "access/nbtree.h" +#include "storage/pmsignal.h" + #include "utils/guc.h" #include "utils/palloc.h" #include "portability/instr_time.h" @@ -65,6 +67,7 @@ #include "access/multi_redo_api.h" #include "replication/walreceiver.h" #include "storage/mot/mot_fdw.h" +#include "replication/datareceiver.h" #ifdef EXTREME_RTO_DEBUG #include @@ -77,8 +80,8 @@ #endif namespace extreme_rto { -static const int MAX_PARSE_BUFF_NUM = 8192 * 10 * 3; -static const int MAX_LOCAL_BUFF_NUM = 8192 * 10 * 3; /* 8M for each thread */ +static const int MAX_PARSE_BUFF_NUM = PAGE_WORK_QUEUE_SIZE * 10 * 3; +static const int MAX_LOCAL_BUFF_NUM = PAGE_WORK_QUEUE_SIZE * 10 * 3; static const char* const PROCESS_TYPE_CMD_ARG = "--forkpageredo"; static char g_AUXILIARY_TYPE_CMD_ARG[16] = {0}; @@ -132,10 +135,8 @@ PageRedoWorker* StartPageRedoWorker(PageRedoWorker* worker) DestroyPageRedoWorker(worker); return NULL; } else { - ereport(LOG, - (errmsg("StartPageRedoWorker successfully create page-redo-worker id: %u, threadId:%lu.", - id, - worker->tid.thid))); + ereport(LOG, (errmsg("StartPageRedoWorker successfully create page-redo-worker id: %u, threadId:%lu.", id, + worker->tid.thid))); } g_instance.comm_cxt.predo_cxt.pageRedoThreadStatusList[id].threadId = threadId; SpinLockAcquire(&(g_instance.comm_cxt.predo_cxt.rwlock)); @@ -148,11 +149,11 @@ PageRedoWorker* StartPageRedoWorker(PageRedoWorker* worker) } /* Run from the dispatcher thread. */ -PageRedoWorker* CreateWorker(uint32 id) +PageRedoWorker *CreateWorker(uint32 id) { - PageRedoWorker* tmp = (PageRedoWorker*)palloc0(sizeof(PageRedoWorker) + REDO_WORKER_ALIGN_LEN); - PageRedoWorker* worker; - worker = (PageRedoWorker*)TYPEALIGN(REDO_WORKER_ALIGN_LEN, tmp); + PageRedoWorker *tmp = (PageRedoWorker *)palloc0(sizeof(PageRedoWorker) + REDO_WORKER_ALIGN_LEN); + PageRedoWorker *worker; + worker = (PageRedoWorker *)TYPEALIGN(REDO_WORKER_ALIGN_LEN, tmp); worker->selfOrinAddr = tmp; worker->id = id; worker->index = 0; @@ -173,7 +174,6 @@ PageRedoWorker* CreateWorker(uint32 id) worker->pendingHead = NULL; worker->pendingTail = NULL; worker->queue = SPSCBlockingQueueCreate(PAGE_WORK_QUEUE_SIZE); - worker->safePointHead = NULL; worker->lastCheckedRestartPoint = InvalidXLogRecPtr; worker->lastReplayedEndRecPtr = InvalidXLogRecPtr; worker->standbyState = (HotStandbyState)t_thrd.xlog_cxt.standbyState; @@ -181,19 +181,16 @@ PageRedoWorker* CreateWorker(uint32 id) worker->latestObservedXid = t_thrd.storage_cxt.latestObservedXid; worker->DataDir = t_thrd.proc_cxt.DataDir; worker->RecentXmin = u_sess->utils_cxt.RecentXmin; - worker->btreeIncompleteActions = NULL; worker->xlogInvalidPages = NULL; PosixSemaphoreInit(&worker->phaseMarker, 0); - worker->statMulpageCnt = 0; - worker->statWaitReach = 0; - worker->statWaitReplay = 0; worker->oldCtx = NULL; - worker->curbatchcount = 0; + worker->fullSyncFlag = 0; worker->bufferPinWaitBufId = -1; - pg_atomic_write_u32(&(worker->readyStatus), PAGE_REDO_WORKER_INVALID); #if (!defined __x86_64__) && (!defined __aarch64__) SpinLockInit(&worker->ptrLck); #endif + worker->parseManager.memctl.isInit = false; + worker->parseManager.parsebuffers = NULL; return worker; } @@ -209,11 +206,13 @@ void DestroyPageRedoWorker(PageRedoWorker* worker) { PosixSemaphoreDestroy(&worker->phaseMarker); SPSCBlockingQueueDestroy(worker->queue); + XLogRedoBufferDestoryFunc(&(worker->bufferManager)); + XLogParseBufferDestoryFunc(&(worker->parseManager)); pfree(worker->selfOrinAddr); } /* automic write for lastReplayedReadRecPtr and lastReplayedEndRecPtr */ -void SetCompletedReadEndPtr(PageRedoWorker* worker, XLogRecPtr readPtr, XLogRecPtr endPtr) +void SetCompletedReadEndPtr(PageRedoWorker *worker, XLogRecPtr readPtr, XLogRecPtr endPtr) { volatile PageRedoWorker* tmpWk = worker; #if defined(__x86_64__) || defined(__aarch64__) @@ -311,10 +310,13 @@ void HandlePageRedoInterrupts() if (AmStartupProcess()) { /* check for primary */ - uint32 triggeredstate = pg_atomic_read_u32(&(g_triggeredstate)); + uint32 triggeredstate = pg_atomic_read_u32(&(g_startupTriggerState)); uint32 newtriggered = (uint32)CheckForSatartupStatus(); - if (triggeredstate != newtriggered) { - pg_atomic_write_u32(&(g_triggeredstate), newtriggered); + if (newtriggered != extreme_rto::TRIGGER_NORMAL && triggeredstate != newtriggered) { + ereport(LOG, (errmodule(MOD_REDO), errcode(ERRCODE_LOG), + errmsg("HandlePageRedoInterrupts:g_startupTriggerState set from %u to %u", + triggeredstate, newtriggered))); + pg_atomic_write_u32(&(g_startupTriggerState), newtriggered); } if (t_thrd.startup_cxt.got_SIGHUP) { @@ -325,8 +327,12 @@ void HandlePageRedoInterrupts() /* * Check if we were requested to exit without finishing recovery. */ - if (t_thrd.startup_cxt.shutdown_requested && SmartShutdown != g_instance.status) { - proc_exit(1); + if (t_thrd.startup_cxt.shutdown_requested) { + if (g_instance.status != SmartShutdown) { + proc_exit(1); + } else { + g_dispatcher->smartShutdown = true; + } } } @@ -492,10 +498,9 @@ void BatchRedoMain() { void** eleArry; uint32 eleNum; - - knl_thread_set_name("RedoBatch"); - - XLogParseBufferInitFunc(MAX_PARSE_BUFF_NUM, &recordRefOperate); + knl_thread_set_name("RedoBatch"); + XLogParseBufferInitFunc(&(g_redoWorker->parseManager), MAX_PARSE_BUFF_NUM, &recordRefOperate, + HandlePageRedoInterrupts); while (SPSCBlockingQueueGetAll(g_redoWorker->queue, &eleArry, &eleNum)) { bool isEnd = BatchRedoDistributeItems(eleArry, eleNum); SPSCBlockingQueuePopN(g_redoWorker->queue, eleNum); @@ -503,11 +508,12 @@ void BatchRedoMain() break; HandlePageRedoInterrupts(); + ADD_ABNORMAL_POSITION(1); } // need notify redo page manager BatchRedoDistributeEndMark(); RedoThrdWaitForExit(g_redoWorker); - XLogParseBufferDestoryFunc(); + XLogParseBufferDestoryFunc(&(g_redoWorker->parseManager)); } uint32 GetWorkerId(const RedoItemTag* redoItemTag, uint32 workerCount) @@ -577,6 +583,7 @@ void WaitAllRedoWorkerQueueEmpty() for (uint32 i = 0; i < WorkerNumPerMng; ++i) { while (!SPSCBlockingQueueIsEmpty(myRedoLine->redoThd[i]->queue)) { + HandlePageRedoInterrupts(); } } } @@ -601,12 +608,24 @@ void RedoPageManagerDdlAction(XLogRecParseState* parsestate) parsestate->blockparse.extra_rec.blocktblspc.isRelativePath); break; case BLOCK_DATA_CREATE_DATABASE_TYPE: - xlog_db_create(parsestate->blockparse.blockhead.dbNode, - parsestate->blockparse.blockhead.spcNode, - parsestate->blockparse.extra_rec.blockdatabase.src_db_id, - parsestate->blockparse.extra_rec.blockdatabase.src_tablespace_id); + xlog_db_create(parsestate->blockparse.blockhead.dbNode, parsestate->blockparse.blockhead.spcNode, + parsestate->blockparse.extra_rec.blockdatabase.src_db_id, + parsestate->blockparse.extra_rec.blockdatabase.src_tablespace_id); break; + case BLOCK_DATA_DROP_TBLSPC_TYPE: + xlog_drop_tblspc(parsestate->blockparse.blockhead.spcNode); + break; + default: + break; + } +} +void RedoPageManagerSmgrClose(XLogRecParseState *parsestate) +{ + switch (parsestate->blockparse.blockhead.block_valid) { + case BLOCK_DATA_DROP_DATABASE_TYPE: + smgrcloseall(); + break; default: break; } @@ -623,6 +642,7 @@ void RedoPageManagerSyncDdlAction(XLogRecParseState* parsestate) /* do actual work */ RedoPageManagerDdlAction(parsestate); } else { + RedoPageManagerSmgrClose(parsestate); do { entershareCount = pg_atomic_read_u32(&g_dispatcher->syncEnterCount); } while (entershareCount != 0); @@ -703,26 +723,24 @@ void PageManagerDistributeBcmBlock(XLogRecParseState* preState) bool PageManagerRedoDistributeItems(void** eleArry, uint32 eleNum) { - XLogRecParseState* recordblockstate = NULL; - HTAB* hashMap = g_dispatcher->pageLines[g_redoWorker->slotId].managerThd->redoItemHash; + HTAB *hashMap = g_dispatcher->pageLines[g_redoWorker->slotId].managerThd->redoItemHash; for (uint32 i = 0; i < eleNum; i++) { if (eleArry[i] == (void*)&g_redoEndMark) { RedoPageManagerDistributeBlockRecord(hashMap, NULL); return true; } else if (eleArry[i] == (void*)&g_GlobalLsnForwarder) { + RedoPageManagerDistributeBlockRecord(hashMap, NULL); PageManagerProcLsnForwarder((RedoItem*)eleArry[i]); continue; } - recordblockstate = (XLogRecParseState*)eleArry[i]; + XLogRecParseState *recordblockstate = (XLogRecParseState *)eleArry[i]; XLogRecParseState* nextState = recordblockstate; do { XLogRecParseState* preState = nextState; nextState = (XLogRecParseState*)nextState->nextrecord; preState->nextrecord = NULL; - /* update prasestate batchcnt */ - preState->batchcount = g_redoWorker->curbatchcount; switch (preState->blockparse.blockhead.block_valid) { case BLOCK_DATA_HEAP_TYPE: case BLOCK_DATA_VM_TYPE: @@ -735,6 +753,7 @@ bool PageManagerRedoDistributeItems(void** eleArry, uint32 eleNum) case BLOCK_DATA_DROP_DATABASE_TYPE: RedoPageManagerDoDropAction(preState, hashMap); break; + case BLOCK_DATA_DROP_TBLSPC_TYPE: case BLOCK_DATA_CREATE_DATABASE_TYPE: case BLOCK_DATA_CREATE_TBLSPC_TYPE: RedoPageManagerDistributeBlockRecord(hashMap, NULL); @@ -763,12 +782,11 @@ bool PageManagerRedoDistributeItems(void** eleArry, uint32 eleNum) void RedoPageManagerMain() { - void** eleArry; + void **eleArry; uint32 eleNum; - - knl_thread_set_name("RedoPageMgr"); - - XLogParseBufferInitFunc(MAX_PARSE_BUFF_NUM, &recordRefOperate); + knl_thread_set_name("RedoPageMgr"); + XLogParseBufferInitFunc(&(g_redoWorker->parseManager), MAX_PARSE_BUFF_NUM, &recordRefOperate, + HandlePageRedoInterrupts); while (SPSCBlockingQueueGetAll(g_redoWorker->queue, &eleArry, &eleNum)) { bool isEnd = PageManagerRedoDistributeItems(eleArry, eleNum); SPSCBlockingQueuePopN(g_redoWorker->queue, eleNum); @@ -776,11 +794,12 @@ void RedoPageManagerMain() break; HandlePageRedoInterrupts(); + ADD_ABNORMAL_POSITION(5); } // need notify page redo DispatchEndMarkToRedoWorker(); RedoThrdWaitForExit(g_redoWorker); - XLogParseBufferDestoryFunc(); + XLogParseBufferDestoryFunc(&(g_redoWorker->parseManager)); } bool IsXactXlog(const XLogReaderState* record) @@ -834,38 +853,28 @@ bool TrxnManagerDistributeItemsBeforeEnd(void** eleArry, uint32 eleNum) void GlobalLsnUpdate() { - XLogRecPtr minStart; - XLogRecPtr minEnd; - t_thrd.xlog_cxt.standbyState = g_redoWorker->standbyState; - GetReplayedRecPtr(&minStart, &minEnd); - if ((minEnd != MAX_XLOG_REC_PTR) && (minStart != MAX_XLOG_REC_PTR)) { - SetXLogReplayRecPtr(minStart, minEnd); + t_thrd.xlog_cxt.standbyState = g_redoWorker->standbyState; + if (LsnUpdate()) { + ExtremRtoUpdateMinCheckpoint(); CheckRecoveryConsistency(); } } -void WaitLsnUpdate(bool force) +bool LsnUpdate() { - if (force) { - XLogRecPtr readMngStart; - XLogRecPtr readMngEnd; - XLogRecPtr globalLsn; - - do { - GlobalLsnUpdate(); - GetCompletedReadEndPtr(g_dispatcher->readLine.managerThd, &readMngStart, &readMngEnd); - (void)GetXLogReplayRecPtr(NULL, &globalLsn); - } while (XLByteLT(globalLsn, readMngEnd)); - } else { - GlobalLsnUpdate(); + XLogRecPtr minStart = MAX_XLOG_REC_PTR; + XLogRecPtr minEnd = MAX_XLOG_REC_PTR; + GetReplayedRecPtr(&minStart, &minEnd); + if ((minEnd != MAX_XLOG_REC_PTR) && (minStart != MAX_XLOG_REC_PTR)) { + SetXLogReplayRecPtr(minStart, minEnd); + return true; } + return false; } void TrxnManagerMain() { knl_thread_set_name("RedoTxnMgr"); - - XLogParseBufferInitFunc(MAX_PARSE_BUFF_NUM, &recordRefOperate); while (true) { HandlePageRedoInterrupts(); if (!SPSCBlockingQueueIsEmpty(g_redoWorker->queue)) { @@ -883,43 +892,58 @@ void TrxnManagerMain() GlobalLsnUpdate(); } HandlePageRedoInterrupts(); + ADD_ABNORMAL_POSITION(2); } RedoThrdWaitForExit(g_redoWorker); GlobalLsnUpdate(); - XLogParseBufferDestoryFunc(); } void TrxnWorkerProcLsnForwarder(RedoItem* lsnForwarder) { SetCompletedReadEndPtr(g_redoWorker, lsnForwarder->record.ReadRecPtr, lsnForwarder->record.EndRecPtr); (void)pg_atomic_sub_fetch_u32(&lsnForwarder->record.refcount, 1); +} - GlobalLsnUpdate(); +void TrxnWorkNotifyRedoWorker() +{ + for (uint32 i = 0; i < g_dispatcher->allWorkersCnt; ++i) { + if (g_dispatcher->allWorkers[i]->role == REDO_PAGE_WORKER) { + pg_atomic_write_u32(&(g_dispatcher->allWorkers[i]->fullSyncFlag), 0); + } + } } void TrxnWorkMain() { knl_thread_set_name("RedoTxnWorker"); - - RedoItem* item = nullptr; + RedoItem *item = nullptr; MOTBeginRedoRecovery(); - if (ParseStateWithoutCache()) - XLogRedoBufferInitFunc(MAX_LOCAL_BUFF_NUM, &recordRefOperate); - while ((item = (RedoItem*)SPSCBlockingQueueTop(g_redoWorker->queue)) != &g_redoEndMark) { - if ((void*)item == (void*)&g_GlobalLsnForwarder) { - TrxnWorkerProcLsnForwarder((RedoItem*)item); + if (ParseStateWithoutCache()) { + XLogRedoBufferInitFunc(&(g_redoWorker->bufferManager), MAX_LOCAL_BUFF_NUM, &recordRefOperate, + HandlePageRedoInterrupts); + } + while ((item = (RedoItem *)SPSCBlockingQueueTop(g_redoWorker->queue)) != &g_redoEndMark) { + if ((void *)item == (void *)&g_GlobalLsnForwarder) { + TrxnWorkerProcLsnForwarder((RedoItem *)item); SPSCBlockingQueuePop(g_redoWorker->queue); } else { + t_thrd.xlog_cxt.needImmediateCkp = item->needImmediateCheckpoint; + bool fullSync = item->record.isFullSyncCheckpoint; ApplySinglePageRecord(item); SPSCBlockingQueuePop(g_redoWorker->queue); + SetCompletedReadEndPtr(g_redoWorker, item->record.ReadRecPtr, item->record.EndRecPtr); DereferenceRedoItem(item); + if (fullSync) { + TrxnWorkNotifyRedoWorker(); + } HandlePageRedoInterrupts(); } + ADD_ABNORMAL_POSITION(3); } SPSCBlockingQueuePop(g_redoWorker->queue); if (ParseStateWithoutCache()) - XLogRedoBufferDestoryFunc(); + XLogRedoBufferDestoryFunc(&(g_redoWorker->bufferManager)); MOTEndRedoRecovery(); } @@ -1008,14 +1032,16 @@ void RedoPageWorkerRedoBcmBlock(XLogRecParseState* procState) void RedoPageWorkerMain() { knl_thread_set_name("RedoPageWorker"); + XLogRecParseState *redoblockstateHead = nullptr; + if (ParseStateWithoutCache()) { + XLogRedoBufferInitFunc(&(g_redoWorker->bufferManager), MAX_LOCAL_BUFF_NUM, &recordRefOperate, + HandlePageRedoInterrupts); + } + while ((redoblockstateHead = (XLogRecParseState *)SPSCBlockingQueueTop(g_redoWorker->queue)) != + (XLogRecParseState *)&g_redoEndMark) { - XLogRecParseState* redoblockstateHead = nullptr; - if (ParseStateWithoutCache()) - XLogRedoBufferInitFunc(MAX_LOCAL_BUFF_NUM, &recordRefOperate); - while ((redoblockstateHead = (XLogRecParseState*)SPSCBlockingQueueTop(g_redoWorker->queue)) != - (XLogRecParseState*)&g_redoEndMark) { - if ((void*)redoblockstateHead == (void*)&g_GlobalLsnForwarder) { - PageWorkerProcLsnForwarder((RedoItem*)redoblockstateHead); + if ((void *)redoblockstateHead == (void *)&g_GlobalLsnForwarder) { + PageWorkerProcLsnForwarder((RedoItem *)redoblockstateHead); SPSCBlockingQueuePop(g_redoWorker->queue); continue; } @@ -1023,12 +1049,11 @@ void RedoPageWorkerMain() bool notfound = false; bool updateFsm = false; - XLogRecParseState* procState = redoblockstateHead; + XLogRecParseState *procState = redoblockstateHead; while (procState != NULL) { - XLogRecParseState* redoblockstate = procState; - procState = (XLogRecParseState*)procState->nextrecord; - g_redoWorker->curbatchcount = redoblockstate->batchcount; + XLogRecParseState *redoblockstate = procState; + procState = (XLogRecParseState *)procState->nextrecord; switch (XLogBlockHeadGetValidInfo(&redoblockstate->blockparse.blockhead)) { case BLOCK_DATA_HEAP_TYPE: @@ -1038,12 +1063,18 @@ void RedoPageWorkerMain() break; case BLOCK_DATA_XLOG_COMMON_TYPE: RedoPageWorkerCheckPoint(redoblockstate); + SetCompletedReadEndPtr(g_redoWorker, redoblockstate->blockparse.blockhead.start_ptr, + redoblockstate->blockparse.blockhead.end_ptr); break; case BLOCK_DATA_DDL_TYPE: XLogForgetDDLRedo(redoblockstate); + SetCompletedReadEndPtr(g_redoWorker, redoblockstate->blockparse.blockhead.start_ptr, + redoblockstate->blockparse.blockhead.end_ptr); break; case BLOCK_DATA_DROP_DATABASE_TYPE: XLogDropDatabase(redoblockstate->blockparse.blockhead.dbNode); + SetCompletedReadEndPtr(g_redoWorker, redoblockstate->blockparse.blockhead.start_ptr, + redoblockstate->blockparse.blockhead.end_ptr); break; case BLOCK_DATA_NEWCU_TYPE: RedoPageWorkerRedoBcmBlock(redoblockstate); @@ -1054,23 +1085,34 @@ void RedoPageWorkerMain() } updateFsm = XlogNeedUpdateFsm(redoblockstateHead, &bufferinfo); - + bool needWait = redoblockstateHead->isFullSyncCheckpoint; + if (needWait) { + pg_atomic_write_u32(&g_redoWorker->fullSyncFlag, 1); + } XLogBlockParseStateRelease(redoblockstateHead); /* the same page */ ExtremeRtoFlushBuffer(&bufferinfo, updateFsm); SPSCBlockingQueuePop(g_redoWorker->queue); + + pg_memory_barrier(); + uint32 val = pg_atomic_read_u32(&g_redoWorker->fullSyncFlag); + while (val != 0) { + val = pg_atomic_read_u32(&g_redoWorker->fullSyncFlag); + HandlePageRedoInterrupts(); + } HandlePageRedoInterrupts(); + ADD_ABNORMAL_POSITION(4); } if (ParseStateWithoutCache()) - XLogRedoBufferDestoryFunc(); + XLogRedoBufferDestoryFunc(&(g_redoWorker->bufferManager)); } -inline void PutRecordToReadQueue(XLogReaderState* recordreader) +void PutRecordToReadQueue(XLogReaderState *recordreader) { bool putresult = false; do { - putresult = SPSCBlockingQueuePut(g_redoWorker->queue, recordreader); + putresult = SPSCBlockingQueuePut(g_dispatcher->readLine.readPageThd->queue, recordreader); } while (!putresult); return; @@ -1086,13 +1128,13 @@ inline void InitXLogRecordReadBuffer(XLogReaderState** initreader) *initreader = newxlogreader; } -void StartupSendLsnFowarder() +void StartupSendFowarder(RedoItem *item) { for (uint32 i = 0; i < g_dispatcher->pageLineNum; ++i) { - AddPageRedoItem(g_dispatcher->pageLines[i].batchThd, &g_GlobalLsnForwarder); + AddPageRedoItem(g_dispatcher->pageLines[i].batchThd, item); } - AddPageRedoItem(g_dispatcher->trxnLine.managerThd, &g_GlobalLsnForwarder); + AddPageRedoItem(g_dispatcher->trxnLine.managerThd, item); } void SendLsnFowarder() @@ -1137,28 +1179,23 @@ void PushToWorkerLsn(bool force) bool SetReadBufferForExtRto(XLogReaderState* state, XLogRecPtr pageptr, int reqLen) { - uint32 targetPageOff; XLogSegNo targetSegNo; - uint32 applyindex; XLByteToSeg(pageptr, targetSegNo); - targetPageOff = (pageptr % XLOG_SEG_SIZE); + uint32 targetPageOff = (pageptr % XLOG_SEG_SIZE); - applyindex = g_recordbuffer->applyindex; + uint32 applyindex = g_recordbuffer->applyindex; Assert(applyindex < MAX_ALLOC_SEGNUM); RecordBufferAarray* cursegbuffer = &g_recordbuffer->xlogsegarray[applyindex]; if (targetSegNo == cursegbuffer->segno && targetPageOff == cursegbuffer->segoffset) { state->readBuf = cursegbuffer->readsegbuf + cursegbuffer->segoffset; - return true; - } - - if (targetSegNo == cursegbuffer->segno) { + } else if (targetSegNo == cursegbuffer->segno) { cursegbuffer->segoffset = targetPageOff; state->readBuf = cursegbuffer->readsegbuf + cursegbuffer->segoffset; } else { - uint32 workerstate = pg_atomic_read_u32(&(g_recordbuffer->startreadworker)); + uint32 workerstate = pg_atomic_read_u32(&(g_recordbuffer->readWorkerState)); - if (workerstate != READ_WORKER_STOP) { + if (workerstate == WORKER_STATE_RUN) { if (targetSegNo == (cursegbuffer->segno + 1)) { Assert(targetPageOff == 0); pg_atomic_write_u32(&(cursegbuffer->bufState), APPLIED); @@ -1173,14 +1210,11 @@ bool SetReadBufferForExtRto(XLogReaderState* state, XLogRecPtr pageptr, int reqL pg_memory_barrier(); pg_atomic_write_u32(&(g_recordbuffer->applyindex), applyindex); } else { - ereport(WARNING, - (errmodule(MOD_REDO), - errcode(ERRCODE_LOG), - errmsg("SetReadBufferForExtRto EndRecPtr:%lu pageptr:%lu, reqLen:%d", - state->EndRecPtr, - pageptr, - reqLen))); + ereport(WARNING, (errmodule(MOD_REDO), errcode(ERRCODE_LOG), + errmsg("SetReadBufferForExtRto EndRecPtr:%lu pageptr:%lu, reqLen:%d", + state->EndRecPtr, pageptr, reqLen))); DumpExtremeRtoReadBuf(); + t_thrd.xlog_cxt.failedSources |= XLOG_FROM_STREAM; return false; } } else { @@ -1190,18 +1224,17 @@ bool SetReadBufferForExtRto(XLogReaderState* state, XLogRecPtr pageptr, int reqL } } - Assert(targetPageOff == cursegbuffer->segoffset); return true; } -void UpdateReadBufferForExtRto(XLogReaderState* state) +void UpdateReadBufferForExtRto(XLogReaderState *state) { Assert(g_recordbuffer->applyindex < MAX_ALLOC_SEGNUM); - RecordBufferAarray* cursegbuffer = &g_recordbuffer->xlogsegarray[g_recordbuffer->applyindex]; + RecordBufferAarray *cursegbuffer = &g_recordbuffer->xlogsegarray[g_recordbuffer->applyindex]; Assert(state->readOff == cursegbuffer->segoffset); Assert(state->readSegNo == cursegbuffer->segno); - if (pg_atomic_read_u32(&(g_recordbuffer->startreadworker)) == READ_WORKER_STOP) { + if (pg_atomic_read_u32(&(g_recordbuffer->readWorkerState)) != WORKER_STATE_RUN) { cursegbuffer->readlen = state->readOff + state->readLen; g_recordbuffer->readindex = g_recordbuffer->applyindex; } @@ -1211,13 +1244,13 @@ void UpdateReadBufferForExtRto(XLogReaderState* state) static const int MAX_WAIT_TIMS = 512; -bool XLogPageReadForExtRto(XLogRecPtr targetPagePtr, int reqLen, char* readBuf) +bool XLogPageReadForExtRto(XLogRecPtr targetPagePtr, int reqLen, char *readBuf) { uint32 startreadworker; - startreadworker = pg_atomic_read_u32(&(g_recordbuffer->startreadworker)); + startreadworker = pg_atomic_read_u32(&(g_recordbuffer->readWorkerState)); - if (startreadworker == READ_WORKER_STOP) { + if (startreadworker == WORKER_STATE_STOP) { if (!XLogReadFromWriteBufferForFirst(targetPagePtr, reqLen, readBuf)) { return false; } @@ -1230,10 +1263,10 @@ bool XLogPageReadForExtRto(XLogRecPtr targetPagePtr, int reqLen, char* readBuf) pg_atomic_write_u32(&(g_recordbuffer->readindex), g_recordbuffer->applyindex); pg_atomic_write_u32(&(g_recordbuffer->xlogsegarray[g_recordbuffer->readindex].bufState), APPLYING); pg_memory_barrier(); - pg_atomic_write_u32(&(g_recordbuffer->startreadworker), READ_WORKER_RUN); + pg_atomic_write_u32(&(g_recordbuffer->readWorkerState), WORKER_STATE_RUN); return true; - } else if (startreadworker == READ_WORKER_RUN) { + } else if (startreadworker == WORKER_STATE_RUN) { /* read from buffer */ XLogSegNo targetSegNo; uint32 targetPageOff = targetPagePtr % XLogSegSize; @@ -1267,66 +1300,24 @@ bool XLogPageReadForExtRto(XLogRecPtr targetPagePtr, int reqLen, char* readBuf) return false; } -void UpdateWalBufReadOffset(XLogRecPtr lastLsn) -{ - WalRcvCtlBlock* walrcb = getCurrentWalRcvCtlBlock(); - if (walrcb == NULL) { - return; - } - - XLogRecPtr targetPagePtr = lastLsn - lastLsn % XLOG_BLCKSZ; - - int64 walReadOffset; - int64 buflen; - SpinLockAcquire(&walrcb->mutex); - int64 walwriteoffset = walrcb->walWriteOffset; - XLogRecPtr startptr = walrcb->walStart; - if (XLByteLT(startptr, targetPagePtr)) { - targetPagePtr = startptr - startptr % XLOG_BLCKSZ; - } - buflen = (int64)(startptr - targetPagePtr); - walReadOffset = walwriteoffset - buflen; - walrcb->lastReadPtr = targetPagePtr; - walrcb->walReadOffset = walReadOffset; - SpinLockRelease(&walrcb->mutex); - - t_thrd.xlog_cxt.readfrombuffer = true; - t_thrd.xlog_cxt.readSource = XLOG_FROM_STREAM; - pg_atomic_write_u32(&(g_recordbuffer->readindex), g_recordbuffer->applyindex); - - XLogSegNo targetSegNo; - XLByteToSeg(targetPagePtr, targetSegNo); - g_recordbuffer->xlogsegarray[g_recordbuffer->readindex].readlen = targetPagePtr % XLogSegSize; - g_recordbuffer->xlogsegarray[g_recordbuffer->readindex].segno = targetSegNo; - g_recordbuffer->xlogsegarray[g_recordbuffer->readindex].segoffset = targetPagePtr % XLogSegSize; - - pg_atomic_write_u32(&(g_recordbuffer->xlogsegarray[g_recordbuffer->readindex].bufState), APPLYING); - pg_memory_barrier(); - pg_atomic_write_u32(&(g_recordbuffer->startreadworker), READ_WORKER_RUN); - ereport(LOG, - (errmodule(MOD_REDO), - errcode(ERRCODE_LOG), - errmsg("UpdateWalBufReadOffset walReadOffset:%ld startptr:%lu, walwriteoffset:%ld", - walReadOffset, - startptr, - walwriteoffset))); -} - /* read xlog for parellel */ -void XLogReadManagerMain() +void XLogReadPageWorkerMain() { - XLogReaderState* xlogreader = nullptr; - XLogReaderState* newxlogreader = nullptr; + XLogReaderState *xlogreader = nullptr; + XLogReaderState *newxlogreader = nullptr; - knl_thread_set_name("RedoReadMgr"); + knl_thread_set_name("ReadPageWorker"); g_recordbuffer = &g_dispatcher->recordstate; GetRecoveryLatch(); /* init readstate */ InitXLogRecordReadBuffer(&xlogreader); - if (WalRcvInProgress()) { - UpdateWalBufReadOffset(xlogreader->EndRecPtr); + pg_atomic_write_u32(&(g_recordbuffer->readPageWorkerState), WORKER_STATE_RUN); + if (IsRecoveryDone()) { + t_thrd.xlog_cxt.readSource = XLOG_FROM_STREAM; + t_thrd.xlog_cxt.XLogReceiptSource = XLOG_FROM_STREAM; + pg_atomic_write_u32(&(g_recordbuffer->readSource), XLOG_FROM_STREAM); } XLogRecord* record = XLogParallelReadNextRecord(xlogreader); while (record != NULL) { @@ -1339,14 +1330,23 @@ void XLogReadManagerMain() HandlePageRedoInterrupts(); record = XLogParallelReadNextRecord(xlogreader); PushToWorkerLsn(false); + ADD_ABNORMAL_POSITION(8); }; - pg_atomic_write_u32(&(g_recordbuffer->startreadworker), READ_NOTIFY_EXIT); + uint32 workState = pg_atomic_read_u32(&(g_recordbuffer->readWorkerState)); + while (workState == WORKER_STATE_STOPPING) { + workState = pg_atomic_read_u32(&(g_recordbuffer->readWorkerState)); + } + + if (workState != WORKER_STATE_EXITING && workState != WORKER_STATE_EXIT) { + pg_atomic_write_u32(&(g_recordbuffer->readWorkerState), WORKER_STATE_EXITING); + } /* notify exit */ PushToWorkerLsn(true); g_redoEndMark.record = *xlogreader; g_redoEndMark.record.isDecode = true; PutRecordToReadQueue((XLogReaderState*)&g_redoEndMark.record); ReLeaseRecoveryLatch(); + pg_atomic_write_u32(&(g_recordbuffer->readPageWorkerState), WORKER_STATE_EXIT); } void HandleReadWorkerRunInterrupts() @@ -1356,115 +1356,261 @@ void HandleReadWorkerRunInterrupts() ProcessConfigFile(PGC_SIGHUP); } - if ((t_thrd.page_redo_cxt.shutdown_requested) && !WalRcvInProgress()) { - ereport(LOG, - (errmodule(MOD_REDO), - errcode(ERRCODE_LOG), - errmsg("page worker id %u exit for request", g_redoWorker->id))); + if (t_thrd.page_redo_cxt.shutdown_requested) { + ereport(LOG, (errmodule(MOD_REDO), errcode(ERRCODE_LOG), + errmsg("page worker id %u exit for request", g_redoWorker->id))); pg_atomic_write_u32(&(g_instance.comm_cxt.predo_cxt.pageRedoThreadStatusList[g_redoWorker->id].threadState), - PAGE_REDO_WORKER_EXIT); + PAGE_REDO_WORKER_EXIT); proc_exit(1); } } -void XLogReadWorkerMain() +static void InitReadBuf(uint32 bufIndex, XLogSegNo segno) { - uint32 startreadworker; - uint32 readindex; - uint32 waitcount = 0; + if (bufIndex == MAX_ALLOC_SEGNUM) { + bufIndex = 0; + } const uint32 sleepTime = 50; /* 50 us */ + RecordBufferAarray *nextreadseg = &g_recordbuffer->xlogsegarray[bufIndex]; + pg_memory_barrier(); - knl_thread_set_name("RedoReadWorker"); + uint32 bufState = pg_atomic_read_u32(&(nextreadseg->bufState)); + uint32 startreadworker = pg_atomic_read_u32(&(g_recordbuffer->readWorkerState)); + while (bufState == APPLYING && startreadworker == WORKER_STATE_RUN) { + pg_usleep(sleepTime); + bufState = pg_atomic_read_u32(&(nextreadseg->bufState)); + startreadworker = pg_atomic_read_u32(&(g_recordbuffer->readWorkerState)); + HandleReadWorkerRunInterrupts(); + } - g_recordbuffer = &g_dispatcher->recordstate; - startreadworker = pg_atomic_read_u32(&(g_recordbuffer->startreadworker)); - while (startreadworker != READ_NOTIFY_EXIT) { + nextreadseg->readlen = 0; + nextreadseg->segno = segno; + nextreadseg->segoffset = 0; + pg_atomic_write_u32(&(nextreadseg->bufState), APPLYING); + pg_atomic_write_u32(&(g_recordbuffer->readindex), bufIndex); +} - /* read the xlog file to buffer */ - if (startreadworker == READ_WORKER_STOP) { - HandlePageRedoInterrupts(); - startreadworker = pg_atomic_read_u32(&(g_recordbuffer->startreadworker)); - continue; - } +static void XLogReadWorkRun() +{ + static uint32 waitcount = 0; + const uint32 sleepTime = 50; /* 50 us */ + XLogSegNo targetSegNo; + uint32 writeoffset; + uint32 reqlen; - if (startreadworker == READ_WORKER_RUN) { - XLogRecPtr latestChunkStart; - XLogRecPtr receivedUpto; - XLogRecPtr targetSartPtr; - XLogSegNo targetSegNo; - uint32 writeoffset; - uint32 reqlen; + uint32 readindex = pg_atomic_read_u32(&(g_recordbuffer->readindex)); + Assert(readindex < MAX_ALLOC_SEGNUM); + pg_memory_barrier(); + RecordBufferAarray *readseg = &g_recordbuffer->xlogsegarray[readindex]; - readindex = pg_atomic_read_u32(&(g_recordbuffer->readindex)); - Assert(readindex < MAX_ALLOC_SEGNUM); - pg_memory_barrier(); - RecordBufferAarray* readseg = &g_recordbuffer->xlogsegarray[readindex]; + XLogRecPtr receivedUpto = GetWalRcvWriteRecPtr(NULL); + XLByteToSeg(receivedUpto, targetSegNo); - receivedUpto = GetWalRcvWriteRecPtr(&latestChunkStart); - XLByteToSeg(receivedUpto, targetSegNo); - if (targetSegNo != readseg->segno) { - writeoffset = readseg->readlen; - reqlen = XLOG_SEG_SIZE - writeoffset; + if (targetSegNo < readseg->segno) { + return; + } + + if (targetSegNo != readseg->segno) { + writeoffset = readseg->readlen; + reqlen = XLOG_SEG_SIZE - writeoffset; + } else { + uint32 targetPageOff; + targetPageOff = receivedUpto % XLOG_SEG_SIZE; + writeoffset = readseg->readlen; + if ((writeoffset + XLOG_BLCKSZ) < targetPageOff) { + reqlen = targetPageOff - writeoffset; + } else { + waitcount++; + if ((waitcount >= MAX_WAIT_TIMS) && readseg->readlen < targetPageOff) { + reqlen = targetPageOff - writeoffset; + waitcount = 0; } else { - uint32 targetPageOff; - targetPageOff = receivedUpto % XLOG_SEG_SIZE; - writeoffset = readseg->readlen; - if ((writeoffset + XLOG_BLCKSZ) < targetPageOff) { - reqlen = targetPageOff - writeoffset; + /* sleep, wait a moment */ + pg_usleep(sleepTime); + return; + } + } + } + char *readBuf = readseg->readsegbuf + writeoffset; + XLogRecPtr targetSartPtr = readseg->segno * XLOG_SEG_SIZE + writeoffset; + uint32 readlen; + bool result = XLogReadFromWriteBuffer(targetSartPtr, reqlen, readBuf, &readlen); + if (!result) { + return; + } + + pg_atomic_write_u32(&(readseg->readlen), (writeoffset + readlen)); + if (readseg->readlen == XLOG_SEG_SIZE) { + InitReadBuf(readindex + 1, readseg->segno + 1); + } +} + + +void XLogReadManagerResponseSignal(uint32 tgigger) +{ + switch (tgigger) { + case TRIGGER_PRIMARY: + break; + case TRIGGER_FAILOVER: + t_thrd.xlog_cxt.failover_triggered = true; + SendPostmasterSignal(PMSIGNAL_UPDATE_PROMOTING); + ereport(LOG, (errmodule(MOD_REDO), errcode(ERRCODE_LOG), + errmsg("failover ready, notify postmaster to change state."))); + break; + case TRIGGER_SWITCHOVER: + t_thrd.xlog_cxt.switchover_triggered = true; + SendPostmasterSignal(PMSIGNAL_UPDATE_PROMOTING); + ereport(LOG, (errmodule(MOD_REDO), errcode(ERRCODE_LOG), + errmsg("switchover ready, notify postmaster to change state."))); + break; + default: + break; + } +} + +void XLogReadManagerProcInterrupt() +{ + if (t_thrd.page_redo_cxt.shutdown_requested) { + ereport(LOG, (errmodule(MOD_REDO), errcode(ERRCODE_LOG), + errmsg("page worker id %u exit for request", g_redoWorker->id))); + + pg_atomic_write_u32(&(g_instance.comm_cxt.predo_cxt.pageRedoThreadStatusList[g_redoWorker->id].threadState), + PAGE_REDO_WORKER_EXIT); + + proc_exit(1); + } + + if (t_thrd.page_redo_cxt.got_SIGHUP) { + t_thrd.page_redo_cxt.got_SIGHUP = false; + ProcessConfigFile(PGC_SIGHUP); + } +} + +void WaitPageReadWorkerExit() +{ + uint32 state; + do { + state = pg_atomic_read_u32(&extreme_rto::g_dispatcher->recordstate.readPageWorkerState); + XLogReadManagerProcInterrupt(); + } while (state != WORKER_STATE_EXIT); +} + +bool XLogReadManagerCheckSignal() +{ + XLogReadManagerProcInterrupt(); + + uint32 trigger = pg_atomic_read_u32(&(extreme_rto::g_startupTriggerState)); + load_server_mode(); + if (g_dispatcher->smartShutdown || trigger == TRIGGER_PRIMARY || trigger == TRIGGER_SWITCHOVER || + (trigger == TRIGGER_FAILOVER && t_thrd.xlog_cxt.server_mode == STANDBY_MODE) + || t_thrd.xlog_cxt.server_mode == PRIMARY_MODE) { + ereport(LOG, (errmodule(MOD_REDO), errcode(ERRCODE_LOG), + errmsg("XLogReadManagerCheckSignal: smartShutdown:%u, trigger:%u, server_mode:%u", + g_dispatcher->smartShutdown, trigger, t_thrd.xlog_cxt.server_mode))); + ShutdownWalRcv(); + if (g_dispatcher->smartShutdown) { + pg_atomic_write_u32(&g_readManagerTriggerFlag, TRIGGER_SMARTSHUTDOWN); + } else { + pg_atomic_write_u32(&g_readManagerTriggerFlag, trigger); + } + WaitPageReadWorkerExit(); + XLogReadManagerResponseSignal(trigger); + return true; + } + return false; +} + +void XLogReadManagerMain() +{ + const long sleepShortTime = 150000L; + const long sleepLongTime = 1500000L; + g_recordbuffer = &g_dispatcher->recordstate; + bool exitStatus = false; + uint32 xlogReadManagerState = READ_MANAGER_RUN; + knl_thread_set_name("RedoReadManager"); + while (!exitStatus && xlogReadManagerState == READ_MANAGER_RUN) { + exitStatus = XLogReadManagerCheckSignal(); + xlogReadManagerState = pg_atomic_read_u32(&g_dispatcher->recordstate.xlogReadManagerState); + ADD_ABNORMAL_POSITION(7); + if (t_thrd.xlog_cxt.server_mode == STANDBY_MODE) { + uint32 readSource = pg_atomic_read_u32(&g_dispatcher->recordstate.readSource); + uint32 failSource = pg_atomic_read_u32(&g_dispatcher->recordstate.failSource); + if (readSource & XLOG_FROM_STREAM) { + if (!WalRcvInProgress() && g_instance.pid_cxt.WalReceiverPID == 0 && + !g_instance.comm_cxt.localinfo_cxt.need_disable_connection_node) { + volatile WalRcvData* walrcv = t_thrd.walreceiverfuncs_cxt.WalRcv; + XLogRecPtr expectLsn = pg_atomic_read_u64(&g_dispatcher->recordstate.expectLsn); + if (walrcv->receivedUpto == InvalidXLogRecPtr || + (expectLsn != InvalidXLogRecPtr && XLByteLE(walrcv->receivedUpto, expectLsn))) { + uint32 readWorkerstate = pg_atomic_read_u32(&(g_recordbuffer->readWorkerState)); + if (readWorkerstate == WORKER_STATE_RUN) { + pg_atomic_write_u32(&(g_recordbuffer->readWorkerState), WORKER_STATE_STOPPING); + } + SpinLockAcquire(&walrcv->mutex); + walrcv->receivedUpto = 0; + SpinLockRelease(&walrcv->mutex); + XLogRecPtr targetRecPtr = pg_atomic_read_u64(&g_dispatcher->recordstate.targetRecPtr); + ereport(LOG, (errmsg("request xlog stream at %X/%X.", (uint32)(targetRecPtr >> 32), + (uint32)targetRecPtr))); + RequestXLogStreaming(&targetRecPtr, t_thrd.xlog_cxt.PrimaryConnInfo, + REPCONNTARGET_PRIMARY, u_sess->attr.attr_storage.PrimarySlotName); + } } else { - waitcount++; - if ((waitcount >= MAX_WAIT_TIMS) && readseg->readlen < targetPageOff) { - reqlen = targetPageOff - writeoffset; - waitcount = 0; - } else { - /* sleep, wait a moment */ - pg_usleep(sleepTime); - startreadworker = pg_atomic_read_u32(&(g_recordbuffer->startreadworker)); - HandleReadWorkerRunInterrupts(); - continue; + if (g_instance.comm_cxt.localinfo_cxt.need_disable_connection_node) { + g_instance.comm_cxt.localinfo_cxt.need_disable_connection_node = false; + if (!WalRcvInProgress()) { + volatile WalRcvData* walrcv = t_thrd.walreceiverfuncs_cxt.WalRcv; + XLogRecPtr expectLsn = pg_atomic_read_u64(&g_dispatcher->recordstate.expectLsn); + if (expectLsn != InvalidXLogRecPtr && XLByteLE(walrcv->receivedUpto, expectLsn)) { + pg_usleep(sleepLongTime); + } + } } } } - char* readBuf = readseg->readsegbuf + writeoffset; - targetSartPtr = readseg->segno * XLOG_SEG_SIZE + writeoffset; - uint32 readlen; - bool result = XLogReadFromWriteBuffer(targetSartPtr, reqlen, readBuf, &readlen); - if (!result) - continue; - pg_atomic_write_u32(&(readseg->readlen), (writeoffset + readlen)); - if (readseg->readlen == XLOG_SEG_SIZE) { - readindex++; - if (readindex == MAX_ALLOC_SEGNUM) { - readindex = 0; - } - RecordBufferAarray* nextreadseg = &g_recordbuffer->xlogsegarray[readindex]; - pg_memory_barrier(); - - uint32 bufState = pg_atomic_read_u32(&(nextreadseg->bufState)); - while (bufState == APPLYING) { - pg_usleep(sleepTime); - bufState = pg_atomic_read_u32(&(nextreadseg->bufState)); - HandleReadWorkerRunInterrupts(); - } - - nextreadseg->readlen = 0; - nextreadseg->segno = readseg->segno + 1; - nextreadseg->segoffset = 0; - pg_atomic_write_u32(&(nextreadseg->bufState), APPLYING); - pg_atomic_write_u32(&(g_recordbuffer->readindex), readindex); + if (failSource & XLOG_FROM_STREAM) { + ShutdownWalRcv(); + pg_atomic_write_u32(&(extreme_rto::g_dispatcher->recordstate.failSource), 0); } - startreadworker = pg_atomic_read_u32(&(g_recordbuffer->startreadworker)); + } + pg_usleep(sleepShortTime); + } +} + + +static void ReadWorkerStopCallBack(int code, Datum arg) +{ + pg_atomic_write_u32(&(g_recordbuffer->readWorkerState), WORKER_STATE_EXIT); +} + +void XLogReadWorkerMain() +{ + uint32 startreadworker; + const uint32 sleepTime = 50; /* 50 us */ + + on_shmem_exit(ReadWorkerStopCallBack, 0); + knl_thread_set_name("RedoReadWorker"); + g_recordbuffer = &g_dispatcher->recordstate; + startreadworker = pg_atomic_read_u32(&(g_recordbuffer->readWorkerState)); + while (startreadworker != WORKER_STATE_EXITING) { + if (startreadworker == WORKER_STATE_RUN) { + XLogReadWorkRun(); } else { pg_usleep(sleepTime); - startreadworker = pg_atomic_read_u32(&(g_recordbuffer->startreadworker)); } + HandleReadWorkerRunInterrupts(); + startreadworker = pg_atomic_read_u32(&(g_recordbuffer->readWorkerState)); + if (startreadworker == WORKER_STATE_STOPPING) { + pg_atomic_write_u32(&(g_recordbuffer->readWorkerState), WORKER_STATE_STOP); + } + ADD_ABNORMAL_POSITION(6); }; /* notify manger to exit */ - pg_atomic_write_u32(&(g_recordbuffer->startreadworker), READ_WORKER_EXIT); + pg_atomic_write_u32(&(g_recordbuffer->readWorkerState), WORKER_STATE_EXIT); } int RedoMainLoop() @@ -1494,6 +1640,9 @@ int RedoMainLoop() case REDO_READ_WORKER: XLogReadWorkerMain(); break; + case REDO_READ_PAGE_WORKER: + XLogReadPageWorkerMain(); + break; case REDO_READ_MNG: XLogReadManagerMain(); break; @@ -1504,17 +1653,6 @@ int RedoMainLoop() INSTR_TIME_SET_CURRENT(endTime); INSTR_TIME_SUBTRACT(endTime, startTime); - ereport(LOG, - (errmodule(MOD_REDO), - errcode(ERRCODE_LOG), - errmsg("worker[%d]: multipage cnt = %d, wait reach elapsed %ld us, " - "wait replay elapsed %ld us, total elapsed = %ld", - g_redoWorker->id, - g_redoWorker->statMulpageCnt, - g_redoWorker->statWaitReach, - g_redoWorker->statWaitReplay, - INSTR_TIME_GET_MICROSEC(endTime)))); - /* * We need to get the exit code here before we allow the dispatcher * to proceed and change the exit code. @@ -1522,6 +1660,10 @@ int RedoMainLoop() int exitCode = GetDispatcherExitCode(); g_redoWorker->xlogInvalidPages = XLogGetInvalidPages(); + ereport(LOG, (errmodule(MOD_REDO), errcode(ERRCODE_LOG), + errmsg("worker[%d]: exitcode = %d, total elapsed = %ld", g_redoWorker->id, exitCode, + INSTR_TIME_GET_MICROSEC(endTime)))); + (void)MemoryContextSwitchTo(g_redoWorker->oldCtx); return exitCode; @@ -1554,14 +1696,9 @@ void WaitStateNormal() /* Run from the worker thread. */ void ParallelRedoThreadMain() { - knl_thread_set_name("ExtremeRTO"); - ParallelRedoThreadRegister(); - ereport(LOG, - (errmsg("ExtremeRTO thread %u started, role:%u, slotId:%u.", - g_redoWorker->id, - g_redoWorker->role, - g_redoWorker->slotId))); + ereport(LOG, (errmsg("Page-redo-worker thread %u started, role:%u, slotId:%u.", g_redoWorker->id, + g_redoWorker->role, g_redoWorker->slotId))); SetupSignalHandlers(); InitGlobals(); @@ -1571,16 +1708,12 @@ void ParallelRedoThreadMain() int retCode = RedoMainLoop(); ResourceManagerStop(); - ereport(LOG, - (errmsg("ExtremeRTO thread %u terminated, role:%u, slotId:%u, retcode %u.", - g_redoWorker->id, - g_redoWorker->role, - g_redoWorker->slotId, - retCode))); + ereport(LOG, (errmsg("Page-redo-worker thread %u terminated, role:%u, slotId:%u, retcode %u.", g_redoWorker->id, + g_redoWorker->role, g_redoWorker->slotId, retCode))); LastMarkReached(); - pg_atomic_write_u32( - &(g_instance.comm_cxt.predo_cxt.pageRedoThreadStatusList[g_redoWorker->id].threadState), PAGE_REDO_WORKER_EXIT); + pg_atomic_write_u32(&(g_instance.comm_cxt.predo_cxt.pageRedoThreadStatusList[g_redoWorker->id].threadState), + PAGE_REDO_WORKER_EXIT); proc_exit(0); } @@ -1687,41 +1820,6 @@ void RedoThrdWaitForExit(const PageRedoWorker* wk) } } -// TEST_LOG -void DumpItem(RedoItem* item, const char* funcName); -bool RedoProcessElement(void** eleArry, uint32 eleNum, const PageRedoWorker* wk) -{ - for (uint32 i = 0; i < eleNum; i++) { - if (eleArry[i] == (void*)&g_redoEndMark) { - // prepare to exit - return true; - } - // TEST_LOG - DumpItem((RedoItem*)(eleArry[i]), "RedoProcessElement"); - switch (wk->role) { - case REDO_BATCH: - return BatchRedoDistributeItems(eleArry, eleNum); - break; - case REDO_PAGE_MNG: - break; - case REDO_PAGE_WORKER: - break; - case REDO_TRXN_MNG: - break; - case REDO_TRXN_WORKER: - TrxnWorkerProc((RedoItem*)eleArry[i]); - break; - default: - break; - } - } - - return false; -} - -void ParseItem(XLogReaderState* record) -{} - /* Run from the worker thread. */ static void ApplySinglePageRecord(RedoItem* item) { @@ -1731,8 +1829,6 @@ static void ApplySinglePageRecord(RedoItem* item) MemoryContext oldCtx = MemoryContextSwitchTo(g_redoWorker->oldCtx); ApplyRedoRecord(record, bOld); (void)MemoryContextSwitchTo(oldCtx); - - // FreeRedoItem(item); } /* Run from the worker thread. */ @@ -1794,41 +1890,14 @@ void UpdatePageRedoWorkerStandbyState(PageRedoWorker* worker, HotStandbyState ne } /* Run from the txn worker thread. */ -XLogRecPtr GetCompletedRecPtr(PageRedoWorker* worker) +XLogRecPtr GetCompletedRecPtr(PageRedoWorker *worker) { return pg_atomic_read_u64(&worker->lastReplayedEndRecPtr); } -/* Run from the txn worker thread. */ -bool IsRecoveryRestartPointSafe(PageRedoWorker* worker, XLogRecPtr restartPoint) +void SetWorkerRestartPoint(PageRedoWorker *worker, XLogRecPtr restartPoint) { - SafeRestartPoint* point = (SafeRestartPoint*)pg_atomic_read_uintptr((uintptr_t*)&worker->safePointHead); - - bool safe = false; - while (point != NULL) { - if (XLByteEQ(restartPoint, point->restartPoint)) { - safe = true; - break; - } - point = point->next; - } - - return safe; -} - -void SetWorkerRestartPoint(PageRedoWorker* worker, XLogRecPtr restartPoint) -{ - pg_atomic_write_u64((uint64*)&worker->lastCheckedRestartPoint, restartPoint); -} - -void* GetBTreeIncompleteActions(PageRedoWorker* worker) -{ - return worker->btreeIncompleteActions; -} - -void ClearBTreeIncompleteActions(PageRedoWorker* worker) -{ - worker->btreeIncompleteActions = NULL; + pg_atomic_write_u64((uint64 *)&worker->lastCheckedRestartPoint, restartPoint); } /* Run from the dispatcher thread. */ @@ -1842,18 +1911,13 @@ bool RedoWorkerIsIdle(PageRedoWorker* worker) return SPSCBlockingQueueIsEmpty(worker->queue); } -void DumpPageRedoWorker(PageRedoWorker* worker) +void DumpPageRedoWorker(PageRedoWorker *worker) { - ereport(LOG, - (errmodule(MOD_REDO), - errcode(ERRCODE_LOG), - errmsg("[REDO_LOG_TRACE]RedoWorker common info: id %u, tid %lu, " - "lastCheckedRestartPoint %lu, lastReplayedEndRecPtr %lu standbyState %u", - worker->id, - worker->tid.thid, - worker->lastCheckedRestartPoint, - worker->lastReplayedEndRecPtr, - (uint32)worker->standbyState))); + ereport(LOG, (errmodule(MOD_REDO), errcode(ERRCODE_LOG), + errmsg("[REDO_LOG_TRACE]RedoWorker common info: id %u, tid %lu, " + "lastCheckedRestartPoint %lu, lastReplayedEndRecPtr %lu standbyState %u", + worker->id, worker->tid.thid, worker->lastCheckedRestartPoint, worker->lastReplayedEndRecPtr, + (uint32)worker->standbyState))); DumpQueue(worker->queue); } @@ -1864,33 +1928,17 @@ void DumpItem(RedoItem* item, const char* funcName) if (item == &g_redoEndMark || item == &g_terminateMark) { return; } - ereport(DEBUG4, - (errmodule(MOD_REDO), - errcode(ERRCODE_LOG), - errmsg("[REDO_LOG_TRACE]DiagLogRedoRecord: %s, ReadRecPtr:%lu,EndRecPtr:%lu," - "oldVersion:%u," - "sharewithtrxn:%u, blockbytrxn:%u, imcheckpoint:%u, shareCount:%d," - "rdsCnt:%u," - "designatedWorker:%u, recordXTime:%lu, refCount:%u, replayed:%d," - "syncXLogReceiptSource:%d, RecentXmin:%lu, syncServerMode:%u", - funcName, - item->record.ReadRecPtr, - item->record.EndRecPtr, - item->oldVersion, - item->sharewithtrxn, - item->blockbytrxn, - item->imcheckpoint, - item->shareCount, + ereport(DEBUG4, (errmodule(MOD_REDO), errcode(ERRCODE_LOG), + errmsg("[REDO_LOG_TRACE]DiagLogRedoRecord: %s, ReadRecPtr:%lu,EndRecPtr:%lu," + "oldVersion:%u," + "imcheckpoint:%u, shareCount:%d," + "designatedWorker:%u, recordXTime:%lu, refCount:%u, replayed:%d," + "syncXLogReceiptSource:%d, RecentXmin:%lu, syncServerMode:%u", + funcName, item->record.ReadRecPtr, item->record.EndRecPtr, item->oldVersion, + item->needImmediateCheckpoint, item->shareCount, item->designatedWorker, item->recordXTime, + item->refCount, item->replayed, - item->rdsCnt, - item->designatedWorker, - item->recordXTime, - item->refCount, - item->replayed, - - item->syncXLogReceiptSource, - item->RecentXmin, - item->syncServerMode))); + item->syncXLogReceiptSource, item->RecentXmin, item->syncServerMode))); DiagLogRedoRecord(&(item->record), funcName); } @@ -1900,24 +1948,18 @@ void DumpExtremeRtoReadBuf() return; } - ereport(LOG, - (errmodule(MOD_REDO), - errcode(ERRCODE_LOG), - errmsg("DumpExtremeRtoReadBuf: startworker %u, readindex %u, applyindex %u", - g_dispatcher->recordstate.startreadworker, - g_dispatcher->recordstate.readindex, - g_dispatcher->recordstate.applyindex))); + ereport(LOG, (errmodule(MOD_REDO), errcode(ERRCODE_LOG), + errmsg("DumpExtremeRtoReadBuf: startworker %u, readindex %u, applyindex %u", + g_dispatcher->recordstate.readWorkerState, g_dispatcher->recordstate.readindex, + g_dispatcher->recordstate.applyindex))); for (uint32 i = 0; i < MAX_ALLOC_SEGNUM; ++i) { - ereport(LOG, - (errmodule(MOD_REDO), - errcode(ERRCODE_LOG), - errmsg("DumpExtremeRtoReadBuf: buf %u, state %u, readlen %u, segno %lu, segoffset %lu", - i, - g_dispatcher->recordstate.xlogsegarray[i].bufState, - g_dispatcher->recordstate.xlogsegarray[i].readlen, - g_dispatcher->recordstate.xlogsegarray[i].segno, - g_dispatcher->recordstate.xlogsegarray[i].segoffset))); + ereport(LOG, (errmodule(MOD_REDO), errcode(ERRCODE_LOG), + errmsg("DumpExtremeRtoReadBuf: buf %u, state %u, readlen %u, segno %lu, segoffset %lu", i, + g_dispatcher->recordstate.xlogsegarray[i].bufState, + g_dispatcher->recordstate.xlogsegarray[i].readlen, + g_dispatcher->recordstate.xlogsegarray[i].segno, + g_dispatcher->recordstate.xlogsegarray[i].segoffset))); } } diff --git a/src/gausskernel/storage/access/transam/extreme_rto/redo_item.cpp b/src/gausskernel/storage/access/transam/extreme_rto/redo_item.cpp index fe8cff2e3..7a0b4f4c3 100644 --- a/src/gausskernel/storage/access/transam/extreme_rto/redo_item.cpp +++ b/src/gausskernel/storage/access/transam/extreme_rto/redo_item.cpp @@ -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; diff --git a/src/gausskernel/storage/access/transam/extreme_rto/spsc_blocking_queue.cpp b/src/gausskernel/storage/access/transam/extreme_rto/spsc_blocking_queue.cpp index e6fe1d2e7..71c81c2a1 100644 --- a/src/gausskernel/storage/access/transam/extreme_rto/spsc_blocking_queue.cpp +++ b/src/gausskernel/storage/access/transam/extreme_rto/spsc_blocking_queue.cpp @@ -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); /* diff --git a/src/gausskernel/storage/access/transam/extreme_rto/txn_redo.cpp b/src/gausskernel/storage/access/transam/extreme_rto/txn_redo.cpp index 8984ddfb0..766020d19 100644 --- a/src/gausskernel/storage/access/transam/extreme_rto/txn_redo.cpp +++ b/src/gausskernel/storage/access/transam/extreme_rto/txn_redo.cpp @@ -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 diff --git a/src/gausskernel/storage/access/transam/multi_redo_api.cpp b/src/gausskernel/storage/access/transam/multi_redo_api.cpp index 3c514500a..f34a2c847 100644 --- a/src/gausskernel/storage/access/transam/multi_redo_api.cpp +++ b/src/gausskernel/storage/access/transam/multi_redo_api.cpp @@ -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); + } +} diff --git a/src/gausskernel/storage/access/transam/multixact.cpp b/src/gausskernel/storage/access/transam/multixact.cpp index 655afe3c0..76af99903 100644 --- a/src/gausskernel/storage/access/transam/multixact.cpp +++ b/src/gausskernel/storage/access/transam/multixact.cpp @@ -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 diff --git a/src/gausskernel/storage/access/transam/parallel_recovery/dispatcher.cpp b/src/gausskernel/storage/access/transam/parallel_recovery/dispatcher.cpp index 964042e8d..40b9ce3b8 100755 --- a/src/gausskernel/storage/access/transam/parallel_recovery/dispatcher.cpp +++ b/src/gausskernel/storage/access/transam/parallel_recovery/dispatcher.cpp @@ -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; } diff --git a/src/gausskernel/storage/access/transam/xact.cpp b/src/gausskernel/storage/access/transam/xact.cpp index 9435c873e..fc68e1998 100644 --- a/src/gausskernel/storage/access/transam/xact.cpp +++ b/src/gausskernel/storage/access/transam/xact.cpp @@ -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); } } diff --git a/src/gausskernel/storage/access/transam/xlog.cpp b/src/gausskernel/storage/access/transam/xlog.cpp index 21bbcf746..a9089caa2 100755 --- a/src/gausskernel/storage/access/transam/xlog.cpp +++ b/src/gausskernel/storage/access/transam/xlog.cpp @@ -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; + } +} diff --git a/src/gausskernel/storage/access/transam/xlogfuncs.cpp b/src/gausskernel/storage/access/transam/xlogfuncs.cpp index 894d315ba..a0201b269 100755 --- a/src/gausskernel/storage/access/transam/xlogfuncs.cpp +++ b/src/gausskernel/storage/access/transam/xlogfuncs.cpp @@ -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); diff --git a/src/gausskernel/storage/access/transam/xlogreader.cpp b/src/gausskernel/storage/access/transam/xlogreader.cpp index 17a429141..cf8b49f03 100644 --- a/src/gausskernel/storage/access/transam/xlogreader.cpp +++ b/src/gausskernel/storage/access/transam/xlogreader.cpp @@ -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: diff --git a/src/gausskernel/storage/buffer/bufmgr.cpp b/src/gausskernel/storage/buffer/bufmgr.cpp index e0602eef3..f4c97b896 100644 --- a/src/gausskernel/storage/buffer/bufmgr.cpp +++ b/src/gausskernel/storage/buffer/bufmgr.cpp @@ -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); } } diff --git a/src/gausskernel/storage/ipc/procarray.cpp b/src/gausskernel/storage/ipc/procarray.cpp index a4a3719cf..6bec9d223 100644 --- a/src/gausskernel/storage/ipc/procarray.cpp +++ b/src/gausskernel/storage/ipc/procarray.cpp @@ -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); } diff --git a/src/gausskernel/storage/lmgr/proc.cpp b/src/gausskernel/storage/lmgr/proc.cpp index 7cd78682c..fc6ba0020 100755 --- a/src/gausskernel/storage/lmgr/proc.cpp +++ b/src/gausskernel/storage/lmgr/proc.cpp @@ -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. * diff --git a/src/gausskernel/storage/replication/walrcvwriter.cpp b/src/gausskernel/storage/replication/walrcvwriter.cpp index 49112163e..56c91c694 100755 --- a/src/gausskernel/storage/replication/walrcvwriter.cpp +++ b/src/gausskernel/storage/replication/walrcvwriter.cpp @@ -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 { diff --git a/src/gausskernel/storage/replication/walreceiver.cpp b/src/gausskernel/storage/replication/walreceiver.cpp index ef626a9e7..dee6b7906 100755 --- a/src/gausskernel/storage/replication/walreceiver.cpp +++ b/src/gausskernel/storage/replication/walreceiver.cpp @@ -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. diff --git a/src/gausskernel/storage/replication/walreceiverfuncs.cpp b/src/gausskernel/storage/replication/walreceiverfuncs.cpp index c3ed11b40..3cecc1c07 100755 --- a/src/gausskernel/storage/replication/walreceiverfuncs.cpp +++ b/src/gausskernel/storage/replication/walreceiverfuncs.cpp @@ -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); } diff --git a/src/include/access/extreme_rto/dispatcher.h b/src/include/access/extreme_rto/dispatcher.h index 28e3af7b5..5a919d0af 100644 --- a/src/include/access/extreme_rto/dispatcher.h +++ b/src/include/access/extreme_rto/dispatcher.h @@ -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 diff --git a/src/include/access/extreme_rto/page_redo.h b/src/include/access/extreme_rto/page_redo.h index ce14418d1..61761e53b 100644 --- a/src/include/access/extreme_rto/page_redo.h +++ b/src/include/access/extreme_rto/page_redo.h @@ -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 diff --git a/src/include/access/extreme_rto/redo_item.h b/src/include/access/extreme_rto/redo_item.h index e539e033d..61270a26a 100644 --- a/src/include/access/extreme_rto/redo_item.h +++ b/src/include/access/extreme_rto/redo_item.h @@ -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 diff --git a/src/include/access/multi_redo_settings.h b/src/include/access/multi_redo_settings.h index 7a6091bd5..288766998 100644 --- a/src/include/access/multi_redo_settings.h +++ b/src/include/access/multi_redo_settings.h @@ -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; diff --git a/src/include/access/xlog.h b/src/include/access/xlog.h index 944833b95..04062565e 100644 --- a/src/include/access/xlog.h +++ b/src/include/access/xlog.h @@ -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; diff --git a/src/include/access/xlog_basic.h b/src/include/access/xlog_basic.h index d21b704bd..9a80c0f73 100644 --- a/src/include/access/xlog_basic.h +++ b/src/include/access/xlog_basic.h @@ -313,6 +313,7 @@ struct XLogReaderState { // For parallel recovery bool isPRProcess; bool isDecode; + bool isFullSyncCheckpoint; }; #define SizeOfXLogRecord (offsetof(XLogRecord, xl_crc) + sizeof(pg_crc32c)) diff --git a/src/include/access/xlog_internal.h b/src/include/access/xlog_internal.h index 485171a1a..f316d54b6 100755 --- a/src/include/access/xlog_internal.h +++ b/src/include/access/xlog_internal.h @@ -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 */ diff --git a/src/include/access/xlogproc.h b/src/include/access/xlogproc.h index 2f2a75db0..a14e4da09 100644 --- a/src/include/access/xlogproc.h +++ b/src/include/access/xlogproc.h @@ -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 diff --git a/src/include/commands/tablespace.h b/src/include/commands/tablespace.h index c5b7bb68b..831919305 100755 --- a/src/include/commands/tablespace.h +++ b/src/include/commands/tablespace.h @@ -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 */ diff --git a/src/include/knl/knl_guc/knl_instance_attr_storage.h b/src/include/knl/knl_guc/knl_instance_attr_storage.h index ff905a4b6..93d1265d6 100755 --- a/src/include/knl/knl_guc/knl_instance_attr_storage.h +++ b/src/include/knl/knl_guc/knl_instance_attr_storage.h @@ -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_ */ diff --git a/src/include/knl/knl_instance.h b/src/include/knl/knl_instance.h index b1a2bf0e6..a5d60d5c8 100644 --- a/src/include/knl/knl_instance.h +++ b/src/include/knl/knl_instance.h @@ -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; diff --git a/src/include/replication/walreceiver.h b/src/include/replication/walreceiver.h index 1c6838718..daed002a6 100755 --- a/src/include/replication/walreceiver.h +++ b/src/include/replication/walreceiver.h @@ -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; diff --git a/src/include/storage/proc.h b/src/include/storage/proc.h index e76d80d86..3ec4f63cd 100644 --- a/src/include/storage/proc.h +++ b/src/include/storage/proc.h @@ -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);