commit
1bc0eaedd6
|
|
@ -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);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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")));
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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)));
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -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()
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
File diff suppressed because it is too large
Load Diff
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
||||
/*
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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:
|
||||
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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.
|
||||
*
|
||||
|
|
|
|||
|
|
@ -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 {
|
||||
|
|
|
|||
|
|
@ -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.
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
||||
|
|
|
|||
|
|
@ -313,6 +313,7 @@ struct XLogReaderState {
|
|||
// For parallel recovery
|
||||
bool isPRProcess;
|
||||
bool isDecode;
|
||||
bool isFullSyncCheckpoint;
|
||||
};
|
||||
|
||||
#define SizeOfXLogRecord (offsetof(XLogRecord, xl_crc) + sizeof(pg_crc32c))
|
||||
|
|
|
|||
|
|
@ -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 */
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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 */
|
||||
|
||||
|
|
|
|||
|
|
@ -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_ */
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
Loading…
Reference in New Issue