From 2624ea65d86fd1ec7b97031189aa8afa3e63d09a Mon Sep 17 00:00:00 2001 From: Shengliang Guan Date: Fri, 3 Mar 2023 18:21:07 +0800 Subject: [PATCH] fix: add pre-finished stage, trans won't be dropped in follower if it has undo actions while rollback --- source/dnode/mnode/impl/inc/mndDef.h | 3 +- source/dnode/mnode/impl/src/mndTrans.c | 50 ++++++++++++++++-- tests/script/tsim/trans/create_stb.sim | 72 ++++++++++++++++++++++++++ 3 files changed, 121 insertions(+), 4 deletions(-) create mode 100644 tests/script/tsim/trans/create_stb.sim diff --git a/source/dnode/mnode/impl/inc/mndDef.h b/source/dnode/mnode/impl/inc/mndDef.h index 345418801b..fe2c58e29e 100644 --- a/source/dnode/mnode/impl/inc/mndDef.h +++ b/source/dnode/mnode/impl/inc/mndDef.h @@ -108,7 +108,8 @@ typedef enum { TRN_STAGE_UNDO_ACTION = 3, TRN_STAGE_COMMIT = 4, TRN_STAGE_COMMIT_ACTION = 5, - TRN_STAGE_FINISHED = 6 + TRN_STAGE_FINISHED = 6, + TRN_STAGE_PRE_FINISH = 7 } ETrnStage; typedef enum { diff --git a/source/dnode/mnode/impl/src/mndTrans.c b/source/dnode/mnode/impl/src/mndTrans.c index e044fe08b1..eccabf2d5c 100644 --- a/source/dnode/mnode/impl/src/mndTrans.c +++ b/source/dnode/mnode/impl/src/mndTrans.c @@ -460,6 +460,8 @@ static const char *mndTransStr(ETrnStage stage) { return "commitAction"; case TRN_STAGE_FINISHED: return "finished"; + case TRN_STAGE_PRE_FINISH: + return "pre-finish"; default: return "invalid"; } @@ -602,6 +604,11 @@ static int32_t mndTransActionUpdate(SSdb *pSdb, STrans *pOld, STrans *pNew) { mTrace("trans:%d, stage from rollback to undoAction since perform update action", pNew->id); } + if (pOld->stage == TRN_STAGE_PRE_FINISH) { + pOld->stage = TRN_STAGE_FINISHED; + mTrace("trans:%d, stage from pre-finish to finished since perform update action", pNew->id); + } + return 0; } @@ -931,6 +938,16 @@ static int32_t mndTransRollback(SMnode *pMnode, STrans *pTrans) { return 0; } +static int32_t mndTransPreFinish(SMnode *pMnode, STrans *pTrans) { + mInfo("trans:%d, pre-finish transaction", pTrans->id); + if (mndTransSync(pMnode, pTrans) != 0) { + mError("trans:%d, failed to pre-finish since %s", pTrans->id, terrstr()); + return -1; + } + mInfo("trans:%d, pre-finish finished", pTrans->id); + return 0; +} + static void mndTransSendRpcRsp(SMnode *pMnode, STrans *pTrans) { bool sendRsp = false; int32_t code = pTrans->code; @@ -1437,7 +1454,7 @@ static bool mndTransPerformCommitActionStage(SMnode *pMnode, STrans *pTrans) { if (code == 0) { pTrans->code = 0; - pTrans->stage = TRN_STAGE_FINISHED; + pTrans->stage = TRN_STAGE_FINISHED; // TRN_STAGE_PRE_FINISH is not necessary mInfo("trans:%d, stage from commitAction to finished", pTrans->id); continueExec = true; } else { @@ -1455,8 +1472,8 @@ static bool mndTransPerformUndoActionStage(SMnode *pMnode, STrans *pTrans) { int32_t code = mndTransExecuteUndoActions(pMnode, pTrans); if (code == 0) { - pTrans->stage = TRN_STAGE_FINISHED; - mInfo("trans:%d, stage from undoAction to finished", pTrans->id); + pTrans->stage = TRN_STAGE_PRE_FINISH; + mInfo("trans:%d, stage from undoAction to pre-finish", pTrans->id); continueExec = true; } else if (code == TSDB_CODE_ACTION_IN_PROGRESS) { mInfo("trans:%d, stage keep on undoAction since %s", pTrans->id, tstrerror(code)); @@ -1489,6 +1506,25 @@ static bool mndTransPerformRollbackStage(SMnode *pMnode, STrans *pTrans) { return continueExec; } +static bool mndTransPerfromPreFinishedStage(SMnode *pMnode, STrans *pTrans) { + if (mndCannotExecuteTransAction(pMnode)) return false; + + bool continueExec = true; + int32_t code = mndTransPreFinish(pMnode, pTrans); + + if (code == 0) { + pTrans->stage = TRN_STAGE_FINISHED; + mInfo("trans:%d, stage from pre-finish to finish", pTrans->id); + continueExec = true; + } else { + pTrans->failedTimes++; + mError("trans:%d, stage keep on pre-finish since %s, failedTimes:%d", pTrans->id, terrstr(), pTrans->failedTimes); + continueExec = false; + } + + return continueExec; +} + static bool mndTransPerfromFinishedStage(SMnode *pMnode, STrans *pTrans) { bool continueExec = false; @@ -1545,6 +1581,14 @@ void mndTransExecute(SMnode *pMnode, STrans *pTrans, bool isLeader) { case TRN_STAGE_UNDO_ACTION: continueExec = mndTransPerformUndoActionStage(pMnode, pTrans); break; + case TRN_STAGE_PRE_FINISH: + if (isLeader) { + continueExec = mndTransPerfromPreFinishedStage(pMnode, pTrans); + } else { + mInfo("trans:%d, can not pre-finish since not leader", pTrans->id); + continueExec = false; + } + break; case TRN_STAGE_FINISHED: continueExec = mndTransPerfromFinishedStage(pMnode, pTrans); break; diff --git a/tests/script/tsim/trans/create_stb.sim b/tests/script/tsim/trans/create_stb.sim new file mode 100644 index 0000000000..94041645d5 --- /dev/null +++ b/tests/script/tsim/trans/create_stb.sim @@ -0,0 +1,72 @@ +system sh/stop_dnodes.sh +system sh/deploy.sh -n dnode1 -i 1 +system sh/deploy.sh -n dnode2 -i 2 +system sh/deploy.sh -n dnode3 -i 3 +system sh/deploy.sh -n dnode4 -i 4 +system sh/cfg.sh -n dnode1 -c transPullupInterval -v 1 +system sh/cfg.sh -n dnode2 -c transPullupInterval -v 1 +system sh/cfg.sh -n dnode3 -c transPullupInterval -v 1 +system sh/cfg.sh -n dnode4 -c transPullupInterval -v 1 +system sh/exec.sh -n dnode1 -s start +system sh/exec.sh -n dnode2 -s start +system sh/exec.sh -n dnode3 -s start +system sh/exec.sh -n dnode4 -s start +sql connect + +print =============== step1: create dnodes +sql create dnode $hostname port 7200 +sql create dnode $hostname port 7300 +sql create dnode $hostname port 7400 + +$x = 0 +step1: + $x = $x + 1 + sleep 1000 + if $x == 10 then + return -1 + endi +sql select * from information_schema.ins_dnodes -x step1 +if $data(1)[4] != ready then + goto step1 +endi +if $data(2)[4] != ready then + goto step1 +endi +if $data(3)[4] != ready then + goto step1 +endi + +print =============== step2: create mnode 2 and 3 +sql create mnode on dnode 2 +sql create mnode on dnode 3 +sql create database db vgroups 2 + +print =============== step3: kill dnode4 +system sh/exec.sh -n dnode4 -s stop -x SIGKILL +sql use db +sql_error create table stb (ts timestamp, i int) tags (j int) + +print =============== step4: create database +sql show transactions +if $rows != 1 then + return -1 +endi + +sleep 3000 +system sh/exec.sh -n dnode4 -s start + +$wt = 0 +step4: +$wt = $wt + 1 +sleep 1000 +if $wt == 200 then + print ====> transaction already running + return -1 +endi + +sql show transactions +if $rows != 0 then + print wait 1 seconds to alter + goto step4 +endi +