Skip to content
体验新版
项目
组织
正在加载...
登录
切换导航
打开侧边栏
taosdata
TDengine
提交
2f792722
T
TDengine
项目概览
taosdata
/
TDengine
1 年多 前同步成功
通知
1187
Star
22018
Fork
4786
代码
文件
提交
分支
Tags
贡献者
分支图
Diff
Issue
1
列表
看板
标记
里程碑
合并请求
0
Wiki
0
Wiki
分析
仓库
DevOps
项目成员
Pages
T
TDengine
项目概览
项目概览
详情
发布
仓库
仓库
文件
提交
分支
标签
贡献者
分支图
比较
Issue
1
Issue
1
列表
看板
标记
里程碑
合并请求
0
合并请求
0
Pages
分析
分析
仓库分析
DevOps
Wiki
0
Wiki
成员
成员
收起侧边栏
关闭侧边栏
动态
分支图
创建新Issue
提交
Issue看板
未验证
提交
2f792722
编写于
3月 07, 2022
作者:
L
Li Minghao
提交者:
GitHub
3月 07, 2022
浏览文件
操作
浏览文件
下载
差异文件
Merge pull request #10585 from taosdata/feature/3.0_mhli
Feature/3.0 mhli
上级
342ef936
fa8284af
变更
29
隐藏空白更改
内联
并排
Showing
29 changed file
with
419 addition
and
514 deletion
+419
-514
source/libs/sync/inc/syncAppendEntries.h
source/libs/sync/inc/syncAppendEntries.h
+1
-3
source/libs/sync/inc/syncAppendEntriesReply.h
source/libs/sync/inc/syncAppendEntriesReply.h
+1
-1
source/libs/sync/inc/syncElection.h
source/libs/sync/inc/syncElection.h
+5
-2
source/libs/sync/inc/syncEnv.h
source/libs/sync/inc/syncEnv.h
+8
-6
source/libs/sync/inc/syncInt.h
source/libs/sync/inc/syncInt.h
+15
-18
source/libs/sync/inc/syncMessage.h
source/libs/sync/inc/syncMessage.h
+2
-1
source/libs/sync/inc/syncOnMessage.h
source/libs/sync/inc/syncOnMessage.h
+0
-2
source/libs/sync/inc/syncRaftStore.h
source/libs/sync/inc/syncRaftStore.h
+7
-17
source/libs/sync/inc/syncReplication.h
source/libs/sync/inc/syncReplication.h
+3
-1
source/libs/sync/inc/syncRequestVote.h
source/libs/sync/inc/syncRequestVote.h
+2
-0
source/libs/sync/inc/syncRequestVoteReply.h
source/libs/sync/inc/syncRequestVoteReply.h
+2
-0
source/libs/sync/inc/syncTimeout.h
source/libs/sync/inc/syncTimeout.h
+1
-1
source/libs/sync/inc/syncUtil.h
source/libs/sync/inc/syncUtil.h
+9
-14
source/libs/sync/src/syncAppendEntries.c
source/libs/sync/src/syncAppendEntries.c
+66
-94
source/libs/sync/src/syncAppendEntriesReply.c
source/libs/sync/src/syncAppendEntriesReply.c
+13
-14
source/libs/sync/src/syncElection.c
source/libs/sync/src/syncElection.c
+27
-2
source/libs/sync/src/syncEnv.c
source/libs/sync/src/syncEnv.c
+1
-0
source/libs/sync/src/syncIO.c
source/libs/sync/src/syncIO.c
+1
-0
source/libs/sync/src/syncMain.c
source/libs/sync/src/syncMain.c
+103
-96
source/libs/sync/src/syncMessage.c
source/libs/sync/src/syncMessage.c
+3
-3
source/libs/sync/src/syncRaftStore.c
source/libs/sync/src/syncRaftStore.c
+4
-119
source/libs/sync/src/syncReplication.c
source/libs/sync/src/syncReplication.c
+36
-1
source/libs/sync/src/syncRequestVote.c
source/libs/sync/src/syncRequestVote.c
+22
-37
source/libs/sync/src/syncRequestVoteReply.c
source/libs/sync/src/syncRequestVoteReply.c
+17
-18
source/libs/sync/src/syncTimeout.c
source/libs/sync/src/syncTimeout.c
+37
-1
source/libs/sync/src/syncUtil.c
source/libs/sync/src/syncUtil.c
+7
-0
source/libs/sync/test/syncIndexTest.cpp
source/libs/sync/test/syncIndexTest.cpp
+10
-6
source/libs/sync/test/syncRaftStoreTest.cpp
source/libs/sync/test/syncRaftStoreTest.cpp
+8
-14
source/libs/sync/test/syncTest.cpp
source/libs/sync/test/syncTest.cpp
+8
-43
未找到文件。
source/libs/sync/inc/syncAppendEntries.h
浏览文件 @
2f792722
...
...
@@ -28,9 +28,7 @@ extern "C" {
#include "syncRaft.h"
#include "taosdef.h"
void
appendEntries
(
SRaft
*
pRaft
,
const
SyncAppendEntries
*
pMsg
);
void
onAppendEntries
(
SRaft
*
pRaft
,
const
SyncAppendEntries
*
pMsg
);
int32_t
syncNodeOnAppendEntriesCb
(
SSyncNode
*
ths
,
SyncAppendEntries
*
pMsg
);
#ifdef __cplusplus
}
...
...
source/libs/sync/inc/syncAppendEntriesReply.h
浏览文件 @
2f792722
...
...
@@ -28,7 +28,7 @@ extern "C" {
#include "syncRaft.h"
#include "taosdef.h"
void
onAppendEntriesReply
(
SRaft
*
pRaft
,
const
SyncAppendEntriesReply
*
pMsg
);
int32_t
syncNodeOnAppendEntriesReplyCb
(
SSyncNode
*
ths
,
SyncAppendEntriesReply
*
pMsg
);
#ifdef __cplusplus
}
...
...
source/libs/sync/inc/syncElection.h
浏览文件 @
2f792722
...
...
@@ -26,8 +26,11 @@ extern "C" {
#include "syncInt.h"
#include "taosdef.h"
void
syncNodeElect
(
SSyncNode
*
pSyncNode
);
void
syncNodeRequestVotePeers
(
SSyncNode
*
pSyncNode
);
int32_t
syncNodeElect
(
SSyncNode
*
pSyncNode
);
int32_t
syncNodeRequestVotePeers
(
SSyncNode
*
pSyncNode
);
int32_t
syncNodeRequestVote
(
SSyncNode
*
pSyncNode
,
const
SRaftId
*
destRaftId
,
const
SyncRequestVote
*
pMsg
);
#ifdef __cplusplus
}
...
...
source/libs/sync/inc/syncEnv.h
浏览文件 @
2f792722
...
...
@@ -30,23 +30,25 @@ extern "C" {
#define TIMER_MAX_MS 0x7FFFFFFF
#define PING_TIMER_MS 1000
#define ELECT_TIMER_MS_MIN 150
#define ELECT_TIMER_MS_MAX 300
#define ELECT_TIMER_MS_RANGE (ELECT_TIMER_MS_MAX - ELECT_TIMER_MS_MIN)
#define HEARTBEAT_TIMER_MS 30
#define EMPTY_RAFT_ID ((SRaftId){.addr = 0, .vgId = 0})
typedef
struct
SSyncEnv
{
tmr_h
pEnvTickTimer
;
tmr_h
pTimerManager
;
char
name
[
128
];
}
SSyncEnv
;
extern
SSyncEnv
*
gSyncEnv
;
int32_t
syncEnvStart
();
int32_t
syncEnvStop
();
tmr_h
syncEnvStartTimer
(
TAOS_TMR_CALLBACK
fp
,
int
mseconds
,
void
*
param
);
void
syncEnvStopTimer
(
tmr_h
*
pTimer
);
tmr_h
syncEnvStartTimer
(
TAOS_TMR_CALLBACK
fp
,
int
mseconds
,
void
*
param
);
void
syncEnvStopTimer
(
tmr_h
*
pTimer
);
#ifdef __cplusplus
}
...
...
source/libs/sync/inc/syncInt.h
浏览文件 @
2f792722
...
...
@@ -154,9 +154,8 @@ typedef struct SSyncNode {
SyncIndex
commitIndex
;
// timer
tmr_h
pPingTimer
;
int32_t
pingTimerMS
;
// uint8_t pingTimerEnable;
tmr_h
pPingTimer
;
int32_t
pingTimerMS
;
uint64_t
pingTimerLogicClock
;
uint64_t
pingTimerLogicClockUser
;
TAOS_TMR_CALLBACK
FpPingTimer
;
// Timer Fp
...
...
@@ -164,13 +163,15 @@ typedef struct SSyncNode {
tmr_h
pElectTimer
;
int32_t
electTimerMS
;
uint8_t
electTimerEnable
;
uint64_t
electTimerLogicClock
;
uint64_t
electTimerLogicClockUser
;
TAOS_TMR_CALLBACK
FpElectTimer
;
// Timer Fp
uint64_t
electTimerCounter
;
tmr_h
pHeartbeatTimer
;
int32_t
heartbeatTimerMS
;
uint8_t
heartbeatTimerEnable
;
uint64_t
heartbeatTimerLogicClock
;
uint64_t
heartbeatTimerLogicClockUser
;
TAOS_TMR_CALLBACK
FpHeartbeatTimer
;
// Timer Fp
uint64_t
heartbeatTimerCounter
;
...
...
@@ -187,26 +188,22 @@ typedef struct SSyncNode {
SSyncNode
*
syncNodeOpen
(
const
SSyncInfo
*
pSyncInfo
);
void
syncNodeClose
(
SSyncNode
*
pSyncNode
);
void
syncNodePingAll
(
SSyncNode
*
pSyncNode
);
void
syncNodePingPeers
(
SSyncNode
*
pSyncNode
);
void
syncNodePingSelf
(
SSyncNode
*
pSyncNode
);
int32_t
syncNodeSendMsgById
(
const
SRaftId
*
destRaftId
,
SSyncNode
*
pSyncNode
,
SRpcMsg
*
pMsg
);
int32_t
syncNodeSendMsgByInfo
(
const
SNodeInfo
*
nodeInfo
,
SSyncNode
*
pSyncNode
,
SRpcMsg
*
pMsg
);
int32_t
syncNodePing
(
SSyncNode
*
pSyncNode
,
const
SRaftId
*
destRaftId
,
SyncPing
*
pMsg
);
void
syncNodePingAll
(
SSyncNode
*
pSyncNode
);
void
syncNodePingPeers
(
SSyncNode
*
pSyncNode
);
void
syncNodePingSelf
(
SSyncNode
*
pSyncNode
);
int32_t
syncNodeStartPingTimer
(
SSyncNode
*
pSyncNode
);
int32_t
syncNodeStopPingTimer
(
SSyncNode
*
pSyncNode
);
int32_t
syncNodeStartElectTimer
(
SSyncNode
*
pSyncNode
);
int32_t
syncNodeStartElectTimer
(
SSyncNode
*
pSyncNode
,
int32_t
ms
);
int32_t
syncNodeStopElectTimer
(
SSyncNode
*
pSyncNode
);
int32_t
syncNodeRestartElectTimer
(
SSyncNode
*
pSyncNode
,
int32_t
ms
);
int32_t
syncNodeStartHeartbeatTimer
(
SSyncNode
*
pSyncNode
);
int32_t
syncNodeStopHeartbeatTimer
(
SSyncNode
*
pSyncNode
);
int32_t
syncNodeRequestVote
(
SSyncNode
*
ths
,
const
SyncRequestVote
*
pMsg
);
int32_t
syncNodeOnRequestVoteCb
(
SSyncNode
*
ths
,
SyncRequestVote
*
pMsg
);
int32_t
syncNodeOnRequestVoteReplyCb
(
SSyncNode
*
ths
,
SyncRequestVoteReply
*
pMsg
);
int32_t
syncNodeAppendEntries
(
SSyncNode
*
ths
,
const
SyncAppendEntries
*
pMsg
);
int32_t
syncNodeOnAppendEntriesCb
(
SSyncNode
*
ths
,
SyncAppendEntries
*
pMsg
);
int32_t
syncNodeOnAppendEntriesReplyCb
(
SSyncNode
*
ths
,
SyncAppendEntriesReply
*
pMsg
);
#ifdef __cplusplus
}
#endif
...
...
source/libs/sync/inc/syncMessage.h
浏览文件 @
2f792722
...
...
@@ -59,6 +59,7 @@ typedef struct SyncTimeout {
uint32_t
msgType
;
ESyncTimeoutType
timeoutType
;
uint64_t
logicClock
;
int32_t
timerMS
;
void
*
data
;
}
SyncTimeout
;
...
...
@@ -69,7 +70,7 @@ void syncTimeoutDeserialize(const char* buf, uint32_t len, SyncTimeout*
void
syncTimeout2RpcMsg
(
const
SyncTimeout
*
pMsg
,
SRpcMsg
*
pRpcMsg
);
void
syncTimeoutFromRpcMsg
(
const
SRpcMsg
*
pRpcMsg
,
SyncTimeout
*
pMsg
);
cJSON
*
syncTimeout2Json
(
const
SyncTimeout
*
pMsg
);
SyncTimeout
*
syncTimeoutBuild2
(
ESyncTimeoutType
timeoutType
,
uint64_t
logicClock
,
void
*
data
);
SyncTimeout
*
syncTimeoutBuild2
(
ESyncTimeoutType
timeoutType
,
uint64_t
logicClock
,
int32_t
timerMS
,
void
*
data
);
// ---------------------------------------------
typedef
struct
SyncPing
{
...
...
source/libs/sync/inc/syncOnMessage.h
浏览文件 @
2f792722
...
...
@@ -26,8 +26,6 @@ extern "C" {
#include "syncRaft.h"
#include "taosdef.h"
void
onMessage
(
SRaft
*
pRaft
,
void
*
pMsg
);
#ifdef __cplusplus
}
#endif
...
...
source/libs/sync/inc/syncRaftStore.h
浏览文件 @
2f792722
...
...
@@ -32,28 +32,18 @@ extern "C" {
#define RAFT_STORE_PATH_LEN 128
typedef
struct
SRaftStore
{
SyncTerm
currentTerm
;
SRaftId
voteFor
;
// FileFd fd;
SyncTerm
currentTerm
;
SRaftId
voteFor
;
TdFilePtr
pFile
;
char
path
[
RAFT_STORE_PATH_LEN
];
}
SRaftStore
;
SRaftStore
*
raftStoreOpen
(
const
char
*
path
);
static
int32_t
raftStoreInit
(
SRaftStore
*
pRaftStore
);
int32_t
raftStoreClose
(
SRaftStore
*
pRaftStore
);
int32_t
raftStorePersist
(
SRaftStore
*
pRaftStore
);
static
bool
raftStoreFileExist
(
char
*
path
);
int32_t
raftStoreSerialize
(
SRaftStore
*
pRaftStore
,
char
*
buf
,
size_t
len
);
int32_t
raftStoreDeserialize
(
SRaftStore
*
pRaftStore
,
char
*
buf
,
size_t
len
);
void
raftStorePrint
(
SRaftStore
*
pRaftStore
);
int32_t
raftStoreClose
(
SRaftStore
*
pRaftStore
);
int32_t
raftStorePersist
(
SRaftStore
*
pRaftStore
);
int32_t
raftStoreSerialize
(
SRaftStore
*
pRaftStore
,
char
*
buf
,
size_t
len
);
int32_t
raftStoreDeserialize
(
SRaftStore
*
pRaftStore
,
char
*
buf
,
size_t
len
);
void
raftStorePrint
(
SRaftStore
*
pRaftStore
);
#ifdef __cplusplus
}
...
...
source/libs/sync/inc/syncReplication.h
浏览文件 @
2f792722
...
...
@@ -26,7 +26,9 @@ extern "C" {
#include "syncInt.h"
#include "taosdef.h"
void
syncNodeAppendEntriesPeers
(
SSyncNode
*
pSyncNode
);
int32_t
syncNodeAppendEntriesPeers
(
SSyncNode
*
pSyncNode
);
int32_t
syncNodeAppendEntries
(
SSyncNode
*
pSyncNode
,
const
SRaftId
*
destRaftId
,
const
SyncAppendEntries
*
pMsg
);
#ifdef __cplusplus
}
...
...
source/libs/sync/inc/syncRequestVote.h
浏览文件 @
2f792722
...
...
@@ -28,6 +28,8 @@ extern "C" {
#include "syncRaft.h"
#include "taosdef.h"
int32_t
syncNodeOnRequestVoteCb
(
SSyncNode
*
ths
,
SyncRequestVote
*
pMsg
);
#ifdef __cplusplus
}
#endif
...
...
source/libs/sync/inc/syncRequestVoteReply.h
浏览文件 @
2f792722
...
...
@@ -28,6 +28,8 @@ extern "C" {
#include "syncRaft.h"
#include "taosdef.h"
int32_t
syncNodeOnRequestVoteReplyCb
(
SSyncNode
*
ths
,
SyncRequestVoteReply
*
pMsg
);
#ifdef __cplusplus
}
#endif
...
...
source/libs/sync/inc/syncTimeout.h
浏览文件 @
2f792722
...
...
@@ -28,7 +28,7 @@ extern "C" {
#include "syncRaft.h"
#include "taosdef.h"
void
onTimeout
(
SRaft
*
pRaft
,
void
*
pMsg
);
int32_t
syncNodeOnTimeoutCb
(
SSyncNode
*
ths
,
SyncTimeout
*
pMsg
);
#ifdef __cplusplus
}
...
...
source/libs/sync/inc/syncUtil.h
浏览文件 @
2f792722
...
...
@@ -28,28 +28,23 @@ extern "C" {
#include "taosdef.h"
// ---- encode / decode
uint64_t
syncUtilAddr2U64
(
const
char
*
host
,
uint16_t
port
);
void
syncUtilU642Addr
(
uint64_t
u64
,
char
*
host
,
size_t
len
,
uint16_t
*
port
);
void
syncUtilnodeInfo2EpSet
(
const
SNodeInfo
*
pNodeInfo
,
SEpSet
*
pEpSet
);
void
syncUtilraftId2EpSet
(
const
SRaftId
*
raftId
,
SEpSet
*
pEpSet
);
void
syncUtilnodeInfo2raftId
(
const
SNodeInfo
*
pNodeInfo
,
SyncGroupId
vgId
,
SRaftId
*
raftId
);
bool
syncUtilSameId
(
const
SRaftId
*
pId1
,
const
SRaftId
*
pId2
);
void
syncUtilU642Addr
(
uint64_t
u64
,
char
*
host
,
size_t
len
,
uint16_t
*
port
);
void
syncUtilnodeInfo2EpSet
(
const
SNodeInfo
*
pNodeInfo
,
SEpSet
*
pEpSet
);
void
syncUtilraftId2EpSet
(
const
SRaftId
*
raftId
,
SEpSet
*
pEpSet
);
void
syncUtilnodeInfo2raftId
(
const
SNodeInfo
*
pNodeInfo
,
SyncGroupId
vgId
,
SRaftId
*
raftId
);
bool
syncUtilSameId
(
const
SRaftId
*
pId1
,
const
SRaftId
*
pId2
);
// ---- SSyncBuffer ----
void
syncUtilbufBuild
(
SSyncBuffer
*
syncBuf
,
size_t
len
);
void
syncUtilbufDestroy
(
SSyncBuffer
*
syncBuf
);
void
syncUtilbufCopy
(
const
SSyncBuffer
*
src
,
SSyncBuffer
*
dest
);
void
syncUtilbufCopyDeep
(
const
SSyncBuffer
*
src
,
SSyncBuffer
*
dest
);
// ---- misc ----
int32_t
syncUtilRand
(
int32_t
max
);
int32_t
syncUtilElectRandomMS
();
#ifdef __cplusplus
}
#endif
...
...
source/libs/sync/src/syncAppendEntries.c
浏览文件 @
2f792722
...
...
@@ -15,97 +15,69 @@
#include "syncAppendEntries.h"
int32_t
syncNodeAppendEntries
(
SSyncNode
*
ths
,
const
SyncAppendEntries
*
pMsg
)
{
// TLA+ Spec
// AppendEntries(i, j) ==
// /\ i /= j
// /\ state[i] = Leader
// /\ LET prevLogIndex == nextIndex[i][j] - 1
// prevLogTerm == IF prevLogIndex > 0 THEN
// log[i][prevLogIndex].term
// ELSE
// 0
// \* Send up to 1 entry, constrained by the end of the log.
// lastEntry == Min({Len(log[i]), nextIndex[i][j]})
// entries == SubSeq(log[i], nextIndex[i][j], lastEntry)
// IN Send([mtype |-> AppendEntriesRequest,
// mterm |-> currentTerm[i],
// mprevLogIndex |-> prevLogIndex,
// mprevLogTerm |-> prevLogTerm,
// mentries |-> entries,
// \* mlog is used as a history variable for the proof.
// \* It would not exist in a real implementation.
// mlog |-> log[i],
// mcommitIndex |-> Min({commitIndex[i], lastEntry}),
// msource |-> i,
// mdest |-> j])
// /\ UNCHANGED <<serverVars, candidateVars, leaderVars, logVars>>
}
int32_t
syncNodeOnAppendEntriesCb
(
SSyncNode
*
ths
,
SyncAppendEntries
*
pMsg
)
{
// TLA+ Spec
// HandleAppendEntriesRequest(i, j, m) ==
// LET logOk == \/ m.mprevLogIndex = 0
// \/ /\ m.mprevLogIndex > 0
// /\ m.mprevLogIndex <= Len(log[i])
// /\ m.mprevLogTerm = log[i][m.mprevLogIndex].term
// IN /\ m.mterm <= currentTerm[i]
// /\ \/ /\ \* reject request
// \/ m.mterm < currentTerm[i]
// \/ /\ m.mterm = currentTerm[i]
// /\ state[i] = Follower
// /\ \lnot logOk
// /\ Reply([mtype |-> AppendEntriesResponse,
// mterm |-> currentTerm[i],
// msuccess |-> FALSE,
// mmatchIndex |-> 0,
// msource |-> i,
// mdest |-> j],
// m)
// /\ UNCHANGED <<serverVars, logVars>>
// \/ \* return to follower state
// /\ m.mterm = currentTerm[i]
// /\ state[i] = Candidate
// /\ state' = [state EXCEPT ![i] = Follower]
// /\ UNCHANGED <<currentTerm, votedFor, logVars, messages>>
// \/ \* accept request
// /\ m.mterm = currentTerm[i]
// /\ state[i] = Follower
// /\ logOk
// /\ LET index == m.mprevLogIndex + 1
// IN \/ \* already done with request
// /\ \/ m.mentries = << >>
// \/ /\ m.mentries /= << >>
// /\ Len(log[i]) >= index
// /\ log[i][index].term = m.mentries[1].term
// \* This could make our commitIndex decrease (for
// \* example if we process an old, duplicated request),
// \* but that doesn't really affect anything.
// /\ commitIndex' = [commitIndex EXCEPT ![i] =
// m.mcommitIndex]
// /\ Reply([mtype |-> AppendEntriesResponse,
// mterm |-> currentTerm[i],
// msuccess |-> TRUE,
// mmatchIndex |-> m.mprevLogIndex +
// Len(m.mentries),
// msource |-> i,
// mdest |-> j],
// m)
// /\ UNCHANGED <<serverVars, log>>
// \/ \* conflict: remove 1 entry
// /\ m.mentries /= << >>
// /\ Len(log[i]) >= index
// /\ log[i][index].term /= m.mentries[1].term
// /\ LET new == [index2 \in 1..(Len(log[i]) - 1) |->
// log[i][index2]]
// IN log' = [log EXCEPT ![i] = new]
// /\ UNCHANGED <<serverVars, commitIndex, messages>>
// \/ \* no conflict: append entry
// /\ m.mentries /= << >>
// /\ Len(log[i]) = m.mprevLogIndex
// /\ log' = [log EXCEPT ![i] =
// Append(log[i], m.mentries[1])]
// /\ UNCHANGED <<serverVars, commitIndex, messages>>
// /\ UNCHANGED <<candidateVars, leaderVars>>
//
}
// TLA+ Spec
// HandleAppendEntriesRequest(i, j, m) ==
// LET logOk == \/ m.mprevLogIndex = 0
// \/ /\ m.mprevLogIndex > 0
// /\ m.mprevLogIndex <= Len(log[i])
// /\ m.mprevLogTerm = log[i][m.mprevLogIndex].term
// IN /\ m.mterm <= currentTerm[i]
// /\ \/ /\ \* reject request
// \/ m.mterm < currentTerm[i]
// \/ /\ m.mterm = currentTerm[i]
// /\ state[i] = Follower
// /\ \lnot logOk
// /\ Reply([mtype |-> AppendEntriesResponse,
// mterm |-> currentTerm[i],
// msuccess |-> FALSE,
// mmatchIndex |-> 0,
// msource |-> i,
// mdest |-> j],
// m)
// /\ UNCHANGED <<serverVars, logVars>>
// \/ \* return to follower state
// /\ m.mterm = currentTerm[i]
// /\ state[i] = Candidate
// /\ state' = [state EXCEPT ![i] = Follower]
// /\ UNCHANGED <<currentTerm, votedFor, logVars, messages>>
// \/ \* accept request
// /\ m.mterm = currentTerm[i]
// /\ state[i] = Follower
// /\ logOk
// /\ LET index == m.mprevLogIndex + 1
// IN \/ \* already done with request
// /\ \/ m.mentries = << >>
// \/ /\ m.mentries /= << >>
// /\ Len(log[i]) >= index
// /\ log[i][index].term = m.mentries[1].term
// \* This could make our commitIndex decrease (for
// \* example if we process an old, duplicated request),
// \* but that doesn't really affect anything.
// /\ commitIndex' = [commitIndex EXCEPT ![i] =
// m.mcommitIndex]
// /\ Reply([mtype |-> AppendEntriesResponse,
// mterm |-> currentTerm[i],
// msuccess |-> TRUE,
// mmatchIndex |-> m.mprevLogIndex +
// Len(m.mentries),
// msource |-> i,
// mdest |-> j],
// m)
// /\ UNCHANGED <<serverVars, log>>
// \/ \* conflict: remove 1 entry
// /\ m.mentries /= << >>
// /\ Len(log[i]) >= index
// /\ log[i][index].term /= m.mentries[1].term
// /\ LET new == [index2 \in 1..(Len(log[i]) - 1) |->
// log[i][index2]]
// IN log' = [log EXCEPT ![i] = new]
// /\ UNCHANGED <<serverVars, commitIndex, messages>>
// \/ \* no conflict: append entry
// /\ m.mentries /= << >>
// /\ Len(log[i]) = m.mprevLogIndex
// /\ log' = [log EXCEPT ![i] =
// Append(log[i], m.mentries[1])]
// /\ UNCHANGED <<serverVars, commitIndex, messages>>
// /\ UNCHANGED <<candidateVars, leaderVars>>
//
int32_t
syncNodeOnAppendEntriesCb
(
SSyncNode
*
ths
,
SyncAppendEntries
*
pMsg
)
{}
source/libs/sync/src/syncAppendEntriesReply.c
浏览文件 @
2f792722
...
...
@@ -15,17 +15,16 @@
#include "syncAppendEntriesReply.h"
int32_t
syncNodeOnAppendEntriesReplyCb
(
SSyncNode
*
ths
,
SyncAppendEntriesReply
*
pMsg
)
{
// TLA+ Spec
// HandleAppendEntriesResponse(i, j, m) ==
// /\ m.mterm = currentTerm[i]
// /\ \/ /\ m.msuccess \* successful
// /\ nextIndex' = [nextIndex EXCEPT ![i][j] = m.mmatchIndex + 1]
// /\ matchIndex' = [matchIndex EXCEPT ![i][j] = m.mmatchIndex]
// \/ /\ \lnot m.msuccess \* not successful
// /\ nextIndex' = [nextIndex EXCEPT ![i][j] =
// Max({nextIndex[i][j] - 1, 1})]
// /\ UNCHANGED <<matchIndex>>
// /\ Discard(m)
// /\ UNCHANGED <<serverVars, candidateVars, logVars, elections>>
}
// TLA+ Spec
// HandleAppendEntriesResponse(i, j, m) ==
// /\ m.mterm = currentTerm[i]
// /\ \/ /\ m.msuccess \* successful
// /\ nextIndex' = [nextIndex EXCEPT ![i][j] = m.mmatchIndex + 1]
// /\ matchIndex' = [matchIndex EXCEPT ![i][j] = m.mmatchIndex]
// \/ /\ \lnot m.msuccess \* not successful
// /\ nextIndex' = [nextIndex EXCEPT ![i][j] =
// Max({nextIndex[i][j] - 1, 1})]
// /\ UNCHANGED <<matchIndex>>
// /\ Discard(m)
// /\ UNCHANGED <<serverVars, candidateVars, logVars, elections>>
int32_t
syncNodeOnAppendEntriesReplyCb
(
SSyncNode
*
ths
,
SyncAppendEntriesReply
*
pMsg
)
{}
source/libs/sync/src/syncElection.c
浏览文件 @
2f792722
...
...
@@ -14,7 +14,32 @@
*/
#include "syncElection.h"
#include "syncMessage.h"
void
syncNodeElect
(
SSyncNode
*
pSyncNode
)
{}
int32_t
syncNodeElect
(
SSyncNode
*
pSyncNode
)
{
// start election
syncNodeRequestVotePeers
(
pSyncNode
);
}
void
syncNodeRequestVotePeers
(
SSyncNode
*
pSyncNode
)
{}
\ No newline at end of file
// TLA+ Spec
// RequestVote(i, j) ==
// /\ state[i] = Candidate
// /\ j \notin votesResponded[i]
// /\ Send([mtype |-> RequestVoteRequest,
// mterm |-> currentTerm[i],
// mlastLogTerm |-> LastTerm(log[i]),
// mlastLogIndex |-> Len(log[i]),
// msource |-> i,
// mdest |-> j])
// /\ UNCHANGED <<serverVars, candidateVars, leaderVars, logVars>>
int32_t
syncNodeRequestVotePeers
(
SSyncNode
*
pSyncNode
)
{}
int32_t
syncNodeRequestVote
(
SSyncNode
*
pSyncNode
,
const
SRaftId
*
destRaftId
,
const
SyncRequestVote
*
pMsg
)
{
sTrace
(
"syncNodeRequestVote pSyncNode:%p "
,
pSyncNode
);
int32_t
ret
=
0
;
SRpcMsg
rpcMsg
;
syncRequestVote2RpcMsg
(
pMsg
,
&
rpcMsg
);
syncNodeSendMsgById
(
destRaftId
,
pSyncNode
,
&
rpcMsg
);
return
ret
;
}
\ No newline at end of file
source/libs/sync/src/syncEnv.c
浏览文件 @
2f792722
...
...
@@ -28,6 +28,7 @@ static void doSyncEnvStopTimer(SSyncEnv *pSyncEnv, tmr_h *pTimer);
int32_t
syncEnvStart
()
{
int32_t
ret
;
srand
(
time
(
NULL
));
gSyncEnv
=
(
SSyncEnv
*
)
malloc
(
sizeof
(
SSyncEnv
));
assert
(
gSyncEnv
!=
NULL
);
ret
=
doSyncEnvStart
(
gSyncEnv
);
...
...
source/libs/sync/src/syncIO.c
浏览文件 @
2f792722
...
...
@@ -44,6 +44,7 @@ int32_t syncIOStart(char *host, uint16_t port) {
gSyncIO
=
syncIOCreate
(
host
,
port
);
assert
(
gSyncIO
!=
NULL
);
srand
(
time
(
NULL
));
int32_t
ret
=
syncIOStartInternal
(
gSyncIO
);
assert
(
ret
==
0
);
...
...
source/libs/sync/src/syncMain.c
浏览文件 @
2f792722
...
...
@@ -15,25 +15,25 @@
#include <stdint.h>
#include "sync.h"
#include "syncAppendEntries.h"
#include "syncAppendEntriesReply.h"
#include "syncEnv.h"
#include "syncInt.h"
#include "syncRaft.h"
#include "syncRequestVote.h"
#include "syncRequestVoteReply.h"
#include "syncTimeout.h"
#include "syncUtil.h"
static
int32_t
tsNodeRefId
=
-
1
;
// ------ local funciton ---------
static
int32_t
syncNodeSendMsgById
(
const
SRaftId
*
destRaftId
,
SSyncNode
*
pSyncNode
,
SRpcMsg
*
pMsg
);
static
int32_t
syncNodeSendMsgByInfo
(
const
SNodeInfo
*
nodeInfo
,
SSyncNode
*
pSyncNode
,
SRpcMsg
*
pMsg
);
static
void
syncNodeEqPingTimer
(
void
*
param
,
void
*
tmrId
);
static
void
syncNodeEqElectTimer
(
void
*
param
,
void
*
tmrId
);
static
void
syncNodeEqHeartbeatTimer
(
void
*
param
,
void
*
tmrId
);
static
int32_t
syncNodePing
(
SSyncNode
*
pSyncNode
,
const
SRaftId
*
destRaftId
,
SyncPing
*
pMsg
);
static
int32_t
syncNodeOnPingCb
(
SSyncNode
*
ths
,
SyncPing
*
pMsg
);
static
int32_t
syncNodeOnPingReplyCb
(
SSyncNode
*
ths
,
SyncPingReply
*
pMsg
);
static
int32_t
syncNodeOnTimeoutCb
(
SSyncNode
*
ths
,
SyncTimeout
*
pMsg
);
static
void
syncNodeBecomeFollower
(
SSyncNode
*
pSyncNode
);
static
void
syncNodeBecomeLeader
(
SSyncNode
*
pSyncNode
);
...
...
@@ -41,9 +41,6 @@ static void syncNodeFollower2Candidate(SSyncNode* pSyncNode);
static
void
syncNodeCandidate2Leader
(
SSyncNode
*
pSyncNode
);
static
void
syncNodeLeader2Follower
(
SSyncNode
*
pSyncNode
);
static
void
syncNodeCandidate2Follower
(
SSyncNode
*
pSyncNode
);
void
syncNodeRequestVotePeers
(
SSyncNode
*
pSyncNode
);
void
syncNodeAppendEntriesPeers
(
SSyncNode
*
pSyncNode
);
// ---------------------------------
int32_t
syncInit
()
{
...
...
@@ -98,6 +95,7 @@ SSyncNode* syncNodeOpen(const SSyncInfo* pSyncInfo) {
pSyncNode
->
state
=
TAOS_SYNC_STATE_FOLLOWER
;
syncUtilnodeInfo2raftId
(
&
pSyncNode
->
me
,
pSyncNode
->
vgId
,
&
pSyncNode
->
raftId
);
// init ping timer
pSyncNode
->
pPingTimer
=
NULL
;
pSyncNode
->
pingTimerMS
=
PING_TIMER_MS
;
atomic_store_64
(
&
pSyncNode
->
pingTimerLogicClock
,
0
);
...
...
@@ -105,6 +103,22 @@ SSyncNode* syncNodeOpen(const SSyncInfo* pSyncInfo) {
pSyncNode
->
FpPingTimer
=
syncNodeEqPingTimer
;
pSyncNode
->
pingTimerCounter
=
0
;
// init elect timer
pSyncNode
->
pElectTimer
=
NULL
;
pSyncNode
->
electTimerMS
=
syncUtilElectRandomMS
();
atomic_store_64
(
&
pSyncNode
->
electTimerLogicClock
,
0
);
atomic_store_64
(
&
pSyncNode
->
electTimerLogicClockUser
,
0
);
pSyncNode
->
FpElectTimer
=
syncNodeEqElectTimer
;
pSyncNode
->
electTimerCounter
=
0
;
// init heartbeat timer
pSyncNode
->
pHeartbeatTimer
=
NULL
;
pSyncNode
->
heartbeatTimerMS
=
HEARTBEAT_TIMER_MS
;
atomic_store_64
(
&
pSyncNode
->
heartbeatTimerLogicClock
,
0
);
atomic_store_64
(
&
pSyncNode
->
heartbeatTimerLogicClockUser
,
0
);
pSyncNode
->
FpHeartbeatTimer
=
syncNodeEqHeartbeatTimer
;
pSyncNode
->
heartbeatTimerCounter
=
0
;
pSyncNode
->
FpOnPing
=
syncNodeOnPingCb
;
pSyncNode
->
FpOnPingReply
=
syncNodeOnPingReplyCb
;
pSyncNode
->
FpOnRequestVote
=
syncNodeOnRequestVoteCb
;
...
...
@@ -121,6 +135,48 @@ void syncNodeClose(SSyncNode* pSyncNode) {
free
(
pSyncNode
);
}
int32_t
syncNodeSendMsgById
(
const
SRaftId
*
destRaftId
,
SSyncNode
*
pSyncNode
,
SRpcMsg
*
pMsg
)
{
SEpSet
epSet
;
syncUtilraftId2EpSet
(
destRaftId
,
&
epSet
);
pSyncNode
->
FpSendMsg
(
pSyncNode
->
rpcClient
,
&
epSet
,
pMsg
);
return
0
;
}
int32_t
syncNodeSendMsgByInfo
(
const
SNodeInfo
*
nodeInfo
,
SSyncNode
*
pSyncNode
,
SRpcMsg
*
pMsg
)
{
SEpSet
epSet
;
syncUtilnodeInfo2EpSet
(
nodeInfo
,
&
epSet
);
pSyncNode
->
FpSendMsg
(
pSyncNode
->
rpcClient
,
&
epSet
,
pMsg
);
return
0
;
}
int32_t
syncNodePing
(
SSyncNode
*
pSyncNode
,
const
SRaftId
*
destRaftId
,
SyncPing
*
pMsg
)
{
sTrace
(
"syncNodePing pSyncNode:%p "
,
pSyncNode
);
int32_t
ret
=
0
;
SRpcMsg
rpcMsg
;
syncPing2RpcMsg
(
pMsg
,
&
rpcMsg
);
syncNodeSendMsgById
(
destRaftId
,
pSyncNode
,
&
rpcMsg
);
{
cJSON
*
pJson
=
syncPing2Json
(
pMsg
);
char
*
serialized
=
cJSON_Print
(
pJson
);
sTrace
(
"syncNodePing pMsg:%s "
,
serialized
);
free
(
serialized
);
cJSON_Delete
(
pJson
);
}
{
SyncPing
*
pMsg2
=
rpcMsg
.
pCont
;
cJSON
*
pJson
=
syncPing2Json
(
pMsg2
);
char
*
serialized
=
cJSON_Print
(
pJson
);
sTrace
(
"syncNodePing rpcMsg.pCont:%s "
,
serialized
);
free
(
serialized
);
cJSON_Delete
(
pJson
);
}
return
ret
;
}
void
syncNodePingAll
(
SSyncNode
*
pSyncNode
)
{
sTrace
(
"syncNodePingAll pSyncNode:%p "
,
pSyncNode
);
int32_t
ret
=
0
;
...
...
@@ -157,7 +213,6 @@ void syncNodePingSelf(SSyncNode* pSyncNode) {
int32_t
syncNodeStartPingTimer
(
SSyncNode
*
pSyncNode
)
{
atomic_store_64
(
&
pSyncNode
->
pingTimerLogicClock
,
pSyncNode
->
pingTimerLogicClockUser
);
pSyncNode
->
pingTimerMS
=
PING_TIMER_MS
;
if
(
pSyncNode
->
pPingTimer
==
NULL
)
{
pSyncNode
->
pPingTimer
=
taosTmrStart
(
pSyncNode
->
FpPingTimer
,
pSyncNode
->
pingTimerMS
,
pSyncNode
,
gSyncEnv
->
pTimerManager
);
...
...
@@ -165,7 +220,6 @@ int32_t syncNodeStartPingTimer(SSyncNode* pSyncNode) {
taosTmrReset
(
pSyncNode
->
FpPingTimer
,
pSyncNode
->
pingTimerMS
,
pSyncNode
,
gSyncEnv
->
pTimerManager
,
&
pSyncNode
->
pPingTimer
);
}
return
0
;
}
...
...
@@ -175,7 +229,9 @@ int32_t syncNodeStopPingTimer(SSyncNode* pSyncNode) {
return
0
;
}
int32_t
syncNodeStartElectTimer
(
SSyncNode
*
pSyncNode
)
{
int32_t
syncNodeStartElectTimer
(
SSyncNode
*
pSyncNode
,
int32_t
ms
)
{
pSyncNode
->
electTimerMS
=
ms
;
atomic_store_64
(
&
pSyncNode
->
electTimerLogicClock
,
pSyncNode
->
electTimerLogicClockUser
);
if
(
pSyncNode
->
pElectTimer
==
NULL
)
{
pSyncNode
->
pElectTimer
=
taosTmrStart
(
pSyncNode
->
FpElectTimer
,
pSyncNode
->
electTimerMS
,
pSyncNode
,
gSyncEnv
->
pTimerManager
);
...
...
@@ -183,18 +239,23 @@ int32_t syncNodeStartElectTimer(SSyncNode* pSyncNode) {
taosTmrReset
(
pSyncNode
->
FpElectTimer
,
pSyncNode
->
electTimerMS
,
pSyncNode
,
gSyncEnv
->
pTimerManager
,
&
pSyncNode
->
pElectTimer
);
}
atomic_store_8
(
&
pSyncNode
->
electTimerEnable
,
1
);
return
0
;
}
int32_t
syncNodeStopElectTimer
(
SSyncNode
*
pSyncNode
)
{
atomic_
store_8
(
&
pSyncNode
->
electTimerEnable
,
0
);
atomic_
add_fetch_64
(
&
pSyncNode
->
electTimerLogicClockUser
,
1
);
pSyncNode
->
electTimerMS
=
TIMER_MAX_MS
;
return
0
;
}
int32_t
syncNodeRestartElectTimer
(
SSyncNode
*
pSyncNode
,
int32_t
ms
)
{
syncNodeStopElectTimer
(
pSyncNode
);
syncNodeStartElectTimer
(
pSyncNode
,
ms
);
return
0
;
}
int32_t
syncNodeStartHeartbeatTimer
(
SSyncNode
*
pSyncNode
)
{
atomic_store_64
(
&
pSyncNode
->
heartbeatTimerLogicClock
,
pSyncNode
->
heartbeatTimerLogicClockUser
);
if
(
pSyncNode
->
pHeartbeatTimer
==
NULL
)
{
pSyncNode
->
pHeartbeatTimer
=
taosTmrStart
(
pSyncNode
->
FpHeartbeatTimer
,
pSyncNode
->
heartbeatTimerMS
,
pSyncNode
,
gSyncEnv
->
pTimerManager
);
...
...
@@ -202,60 +263,16 @@ int32_t syncNodeStartHeartbeatTimer(SSyncNode* pSyncNode) {
taosTmrReset
(
pSyncNode
->
FpHeartbeatTimer
,
pSyncNode
->
heartbeatTimerMS
,
pSyncNode
,
gSyncEnv
->
pTimerManager
,
&
pSyncNode
->
pHeartbeatTimer
);
}
atomic_store_8
(
&
pSyncNode
->
heartbeatTimerEnable
,
1
);
return
0
;
}
int32_t
syncNodeStopHeartbeatTimer
(
SSyncNode
*
pSyncNode
)
{
atomic_
store_8
(
&
pSyncNode
->
heartbeatTimerEnable
,
0
);
atomic_
add_fetch_64
(
&
pSyncNode
->
heartbeatTimerLogicClockUser
,
1
);
pSyncNode
->
heartbeatTimerMS
=
TIMER_MAX_MS
;
return
0
;
}
// ------ local funciton ---------
static
int32_t
syncNodePing
(
SSyncNode
*
pSyncNode
,
const
SRaftId
*
destRaftId
,
SyncPing
*
pMsg
)
{
sTrace
(
"syncNodePing pSyncNode:%p "
,
pSyncNode
);
int32_t
ret
=
0
;
SRpcMsg
rpcMsg
;
syncPing2RpcMsg
(
pMsg
,
&
rpcMsg
);
syncNodeSendMsgById
(
destRaftId
,
pSyncNode
,
&
rpcMsg
);
{
cJSON
*
pJson
=
syncPing2Json
(
pMsg
);
char
*
serialized
=
cJSON_Print
(
pJson
);
sTrace
(
"syncNodePing pMsg:%s "
,
serialized
);
free
(
serialized
);
cJSON_Delete
(
pJson
);
}
{
SyncPing
*
pMsg2
=
rpcMsg
.
pCont
;
cJSON
*
pJson
=
syncPing2Json
(
pMsg2
);
char
*
serialized
=
cJSON_Print
(
pJson
);
sTrace
(
"syncNodePing rpcMsg.pCont:%s "
,
serialized
);
free
(
serialized
);
cJSON_Delete
(
pJson
);
}
return
ret
;
}
static
int32_t
syncNodeSendMsgById
(
const
SRaftId
*
destRaftId
,
SSyncNode
*
pSyncNode
,
SRpcMsg
*
pMsg
)
{
SEpSet
epSet
;
syncUtilraftId2EpSet
(
destRaftId
,
&
epSet
);
pSyncNode
->
FpSendMsg
(
pSyncNode
->
rpcClient
,
&
epSet
,
pMsg
);
return
0
;
}
static
int32_t
syncNodeSendMsgByInfo
(
const
SNodeInfo
*
nodeInfo
,
SSyncNode
*
pSyncNode
,
SRpcMsg
*
pMsg
)
{
SEpSet
epSet
;
syncUtilnodeInfo2EpSet
(
nodeInfo
,
&
epSet
);
pSyncNode
->
FpSendMsg
(
pSyncNode
->
rpcClient
,
&
epSet
,
pMsg
);
return
0
;
}
static
int32_t
syncNodeOnPingCb
(
SSyncNode
*
ths
,
SyncPing
*
pMsg
)
{
int32_t
ret
=
0
;
sTrace
(
"<-- syncNodeOnPingCb -->"
);
...
...
@@ -291,65 +308,59 @@ static int32_t syncNodeOnPingReplyCb(SSyncNode* ths, SyncPingReply* pMsg) {
return
ret
;
}
static
int32_t
syncNodeOnTimeoutCb
(
SSyncNode
*
ths
,
SyncTimeout
*
pMsg
)
{
int32_t
ret
=
0
;
sTrace
(
"<-- syncNodeOnTimeoutCb -->"
);
{
cJSON
*
pJson
=
syncTimeout2Json
(
pMsg
);
char
*
serialized
=
cJSON_Print
(
pJson
);
sTrace
(
"process syncMessage recv: syncNodeOnTimeoutCb pMsg:%s "
,
serialized
);
free
(
serialized
);
cJSON_Delete
(
pJson
);
}
static
void
syncNodeEqPingTimer
(
void
*
param
,
void
*
tmrId
)
{
SSyncNode
*
pSyncNode
=
(
SSyncNode
*
)
param
;
if
(
atomic_load_64
(
&
pSyncNode
->
pingTimerLogicClockUser
)
<=
atomic_load_64
(
&
pSyncNode
->
pingTimerLogicClock
))
{
SyncTimeout
*
pSyncMsg
=
syncTimeoutBuild2
(
SYNC_TIMEOUT_PING
,
atomic_load_64
(
&
pSyncNode
->
pingTimerLogicClock
),
pSyncNode
->
pingTimerMS
,
pSyncNode
);
SRpcMsg
rpcMsg
;
syncTimeout2RpcMsg
(
pSyncMsg
,
&
rpcMsg
);
pSyncNode
->
FpEqMsg
(
pSyncNode
->
queue
,
&
rpcMsg
);
syncTimeoutDestroy
(
pSyncMsg
);
if
(
pMsg
->
timeoutType
==
SYNC_TIMEOUT_PING
)
{
if
(
atomic_load_64
(
&
ths
->
pingTimerLogicClockUser
)
<=
pMsg
->
logicClock
)
{
++
(
ths
->
pingTimerCounter
);
syncNodePingAll
(
ths
);
}
// reset timer ms
// pSyncNode->pingTimerMS += 100;
}
else
if
(
pMsg
->
timeoutType
==
SYNC_TIMEOUT_ELECTION
)
{
}
else
if
(
pMsg
->
timeoutType
==
SYNC_TIMEOUT_HEARTBEAT
)
{
taosTmrReset
(
syncNodeEqPingTimer
,
pSyncNode
->
pingTimerMS
,
pSyncNode
,
&
gSyncEnv
->
pTimerManager
,
&
pSyncNode
->
pPingTimer
);
}
else
{
sTrace
(
"syncNodeEqPingTimer: pingTimerLogicClock:%lu, pingTimerLogicClockUser:%lu"
,
pSyncNode
->
pingTimerLogicClock
,
pSyncNode
->
pingTimerLogicClockUser
);
}
return
ret
;
}
static
void
syncNodeEq
Ping
Timer
(
void
*
param
,
void
*
tmrId
)
{
static
void
syncNodeEq
Elect
Timer
(
void
*
param
,
void
*
tmrId
)
{
SSyncNode
*
pSyncNode
=
(
SSyncNode
*
)
param
;
if
(
atomic_load_64
(
&
pSyncNode
->
pingTimerLogicClockUser
)
<=
atomic_load_64
(
&
pSyncNode
->
pingTimerLogicClock
))
{
// pSyncNode->pingTimerMS += 100;
SyncTimeout
*
pSyncMsg
=
syncTimeoutBuild2
(
SYNC_TIMEOUT_PING
,
atomic_load_64
(
&
pSyncNode
->
pingTimerLogicClock
),
pSyncNode
);
if
(
atomic_load_64
(
&
pSyncNode
->
electTimerLogicClockUser
)
<=
atomic_load_64
(
&
pSyncNode
->
electTimerLogicClock
))
{
SyncTimeout
*
pSyncMsg
=
syncTimeoutBuild2
(
SYNC_TIMEOUT_ELECTION
,
atomic_load_64
(
&
pSyncNode
->
electTimerLogicClock
),
pSyncNode
->
electTimerMS
,
pSyncNode
);
SRpcMsg
rpcMsg
;
syncTimeout2RpcMsg
(
pSyncMsg
,
&
rpcMsg
);
pSyncNode
->
FpEqMsg
(
pSyncNode
->
queue
,
&
rpcMsg
);
syncTimeoutDestroy
(
pSyncMsg
);
// reset timer ms
pSyncNode
->
electTimerMS
=
syncUtilElectRandomMS
();
taosTmrReset
(
syncNodeEqPingTimer
,
pSyncNode
->
pingTimerMS
,
pSyncNode
,
&
gSyncEnv
->
pTimerManager
,
&
pSyncNode
->
pPingTimer
);
}
else
{
sTrace
(
"syncNodeEq
PingTimer: pingTimerLogicClock:%lu, pingTimerLogicClockUser:%lu"
,
pSyncNode
->
pingTimerLogicClock
,
pSyncNode
->
ping
TimerLogicClockUser
);
sTrace
(
"syncNodeEq
ElectTimer: electTimerLogicClock:%lu, electTimerLogicClockUser:%lu"
,
pSyncNode
->
electTimerLogicClock
,
pSyncNode
->
elect
TimerLogicClockUser
);
}
}
static
void
syncNodeEqElectTimer
(
void
*
param
,
void
*
tmrId
)
{}
static
void
syncNodeEqHeartbeatTimer
(
void
*
param
,
void
*
tmrId
)
{}
static
void
syncNodeBecomeFollower
(
SSyncNode
*
pSyncNode
)
{
if
(
pSyncNode
->
state
==
TAOS_SYNC_STATE_LEADER
)
{
pSyncNode
->
leaderCache
.
addr
=
0
;
pSyncNode
->
leaderCache
.
vgId
=
0
;
pSyncNode
->
leaderCache
=
EMPTY_RAFT_ID
;
}
syncNodeStopHeartbeatTimer
(
pSyncNode
);
syncNodeStartElectTimer
(
pSyncNode
);
int32_t
electMS
=
syncUtilElectRandomMS
();
syncNodeStartElectTimer
(
pSyncNode
,
electMS
);
}
static
void
syncNodeBecomeLeader
(
SSyncNode
*
pSyncNode
)
{
...
...
@@ -375,7 +386,3 @@ static void syncNodeCandidate2Leader(SSyncNode* pSyncNode) {}
static
void
syncNodeLeader2Follower
(
SSyncNode
*
pSyncNode
)
{}
static
void
syncNodeCandidate2Follower
(
SSyncNode
*
pSyncNode
)
{}
void
syncNodeRequestVotePeers
(
SSyncNode
*
pSyncNode
)
{}
void
syncNodeAppendEntriesPeers
(
SSyncNode
*
pSyncNode
)
{}
\ No newline at end of file
source/libs/sync/src/syncMessage.c
浏览文件 @
2f792722
...
...
@@ -18,8 +18,6 @@
#include "syncUtil.h"
#include "tcoding.h"
void
onMessage
(
SRaft
*
pRaft
,
void
*
pMsg
)
{}
// ---------------------------------------------
cJSON
*
syncRpcMsg2Json
(
SRpcMsg
*
pRpcMsg
)
{
cJSON
*
pRoot
;
...
...
@@ -125,6 +123,7 @@ cJSON* syncTimeout2Json(const SyncTimeout* pMsg) {
cJSON_AddNumberToObject
(
pRoot
,
"timeoutType"
,
pMsg
->
timeoutType
);
snprintf
(
u64buf
,
sizeof
(
u64buf
),
"%lu"
,
pMsg
->
logicClock
);
cJSON_AddStringToObject
(
pRoot
,
"logicClock"
,
u64buf
);
cJSON_AddNumberToObject
(
pRoot
,
"timerMS"
,
pMsg
->
timerMS
);
snprintf
(
u64buf
,
sizeof
(
u64buf
),
"%p"
,
pMsg
->
data
);
cJSON_AddStringToObject
(
pRoot
,
"data"
,
u64buf
);
...
...
@@ -133,10 +132,11 @@ cJSON* syncTimeout2Json(const SyncTimeout* pMsg) {
return
pJson
;
}
SyncTimeout
*
syncTimeoutBuild2
(
ESyncTimeoutType
timeoutType
,
uint64_t
logicClock
,
void
*
data
)
{
SyncTimeout
*
syncTimeoutBuild2
(
ESyncTimeoutType
timeoutType
,
uint64_t
logicClock
,
int32_t
timerMS
,
void
*
data
)
{
SyncTimeout
*
pMsg
=
syncTimeoutBuild
();
pMsg
->
timeoutType
=
timeoutType
;
pMsg
->
logicClock
=
logicClock
;
pMsg
->
timerMS
=
timerMS
;
pMsg
->
data
=
data
;
return
pMsg
;
}
...
...
source/libs/sync/src/syncRaftStore.c
浏览文件 @
2f792722
...
...
@@ -16,8 +16,11 @@
#include "syncRaftStore.h"
#include "cJSON.h"
// to complie success: FileIO interface is modified
// private function
static
int32_t
raftStoreInit
(
SRaftStore
*
pRaftStore
);
static
bool
raftStoreFileExist
(
char
*
path
);
// public function
SRaftStore
*
raftStoreOpen
(
const
char
*
path
)
{
int32_t
ret
;
...
...
@@ -137,121 +140,3 @@ void raftStorePrint(SRaftStore *pRaftStore) {
raftStoreSerialize
(
pRaftStore
,
storeBuf
,
sizeof
(
storeBuf
));
printf
(
"%s
\n
"
,
storeBuf
);
}
#if 0
SRaftStore *raftStoreOpen(const char *path) {
int32_t ret;
SRaftStore *pRaftStore = malloc(sizeof(SRaftStore));
if (pRaftStore == NULL) {
sError("raftStoreOpen malloc error");
return NULL;
}
memset(pRaftStore, 0, sizeof(*pRaftStore));
snprintf(pRaftStore->path, sizeof(pRaftStore->path), "%s", path);
char storeBuf[RAFT_STORE_BLOCK_SIZE];
memset(storeBuf, 0, sizeof(storeBuf));
if (!raftStoreFileExist(pRaftStore->path)) {
ret = raftStoreInit(pRaftStore);
assert(ret == 0);
}
pRaftStore->fd = taosOpenFileReadWrite(pRaftStore->path);
if (pRaftStore->fd < 0) {
return NULL;
}
int len = taosReadFile(pRaftStore->fd, storeBuf, sizeof(storeBuf));
assert(len == RAFT_STORE_BLOCK_SIZE);
ret = raftStoreDeserialize(pRaftStore, storeBuf, len);
assert(ret == 0);
return pRaftStore;
}
static int32_t raftStoreInit(SRaftStore *pRaftStore) {
pRaftStore->fd = taosOpenFileCreateWrite(pRaftStore->path);
if (pRaftStore->fd < 0) {
return -1;
}
pRaftStore->currentTerm = 0;
pRaftStore->voteFor.addr = 0;
pRaftStore->voteFor.vgId = 0;
int32_t ret = raftStorePersist(pRaftStore);
assert(ret == 0);
taosCloseFile(pRaftStore->fd);
return 0;
}
int32_t raftStoreClose(SRaftStore *pRaftStore) {
taosCloseFile(pRaftStore->fd);
free(pRaftStore);
return 0;
}
int32_t raftStorePersist(SRaftStore *pRaftStore) {
int32_t ret;
char storeBuf[RAFT_STORE_BLOCK_SIZE];
ret = raftStoreSerialize(pRaftStore, storeBuf, sizeof(storeBuf));
assert(ret == 0);
taosLSeekFile(pRaftStore->fd, 0, SEEK_SET);
ret = taosWriteFile(pRaftStore->fd, storeBuf, sizeof(storeBuf));
assert(ret == RAFT_STORE_BLOCK_SIZE);
fsync(pRaftStore->fd);
return 0;
}
static bool raftStoreFileExist(char *path) { return taosStatFile(path, NULL, NULL) >= 0; }
int32_t raftStoreSerialize(SRaftStore *pRaftStore, char *buf, size_t len) {
cJSON *pRoot = cJSON_CreateObject();
cJSON_AddNumberToObject(pRoot, "current_term", pRaftStore->currentTerm);
cJSON_AddNumberToObject(pRoot, "vote_for_addr", pRaftStore->voteFor.addr);
cJSON_AddNumberToObject(pRoot, "vote_for_vgid", pRaftStore->voteFor.vgId);
char *serialized = cJSON_Print(pRoot);
int len2 = strlen(serialized);
assert(len2 < len);
memset(buf, 0, len);
snprintf(buf, len, "%s", serialized);
free(serialized);
cJSON_Delete(pRoot);
return 0;
}
int32_t raftStoreDeserialize(SRaftStore *pRaftStore, char *buf, size_t len) {
assert(len > 0 && len <= RAFT_STORE_BLOCK_SIZE);
cJSON *pRoot = cJSON_Parse(buf);
cJSON *pCurrentTerm = cJSON_GetObjectItem(pRoot, "current_term");
pRaftStore->currentTerm = pCurrentTerm->valueint;
cJSON *pVoteForAddr = cJSON_GetObjectItem(pRoot, "vote_for_addr");
pRaftStore->voteFor.addr = pVoteForAddr->valueint;
cJSON *pVoteForVgid = cJSON_GetObjectItem(pRoot, "vote_for_vgid");
pRaftStore->voteFor.vgId = pVoteForVgid->valueint;
cJSON_Delete(pRoot);
return 0;
}
void raftStorePrint(SRaftStore *pRaftStore) {
char storeBuf[RAFT_STORE_BLOCK_SIZE];
raftStoreSerialize(pRaftStore, storeBuf, sizeof(storeBuf));
printf("%s\n", storeBuf);
}
#endif
source/libs/sync/src/syncReplication.c
浏览文件 @
2f792722
...
...
@@ -14,5 +14,40 @@
*/
#include "syncReplication.h"
#include "syncMessage.h"
void
syncNodeAppendEntriesPeers
(
SSyncNode
*
pSyncNode
)
{}
\ No newline at end of file
// TLA+ Spec
// AppendEntries(i, j) ==
// /\ i /= j
// /\ state[i] = Leader
// /\ LET prevLogIndex == nextIndex[i][j] - 1
// prevLogTerm == IF prevLogIndex > 0 THEN
// log[i][prevLogIndex].term
// ELSE
// 0
// \* Send up to 1 entry, constrained by the end of the log.
// lastEntry == Min({Len(log[i]), nextIndex[i][j]})
// entries == SubSeq(log[i], nextIndex[i][j], lastEntry)
// IN Send([mtype |-> AppendEntriesRequest,
// mterm |-> currentTerm[i],
// mprevLogIndex |-> prevLogIndex,
// mprevLogTerm |-> prevLogTerm,
// mentries |-> entries,
// \* mlog is used as a history variable for the proof.
// \* It would not exist in a real implementation.
// mlog |-> log[i],
// mcommitIndex |-> Min({commitIndex[i], lastEntry}),
// msource |-> i,
// mdest |-> j])
// /\ UNCHANGED <<serverVars, candidateVars, leaderVars, logVars>>
int32_t
syncNodeAppendEntriesPeers
(
SSyncNode
*
pSyncNode
)
{}
int32_t
syncNodeAppendEntries
(
SSyncNode
*
pSyncNode
,
const
SRaftId
*
destRaftId
,
const
SyncAppendEntries
*
pMsg
)
{
sTrace
(
"syncNodeAppendEntries pSyncNode:%p "
,
pSyncNode
);
int32_t
ret
=
0
;
SRpcMsg
rpcMsg
;
syncAppendEntries2RpcMsg
(
pMsg
,
&
rpcMsg
);
syncNodeSendMsgById
(
destRaftId
,
pSyncNode
,
&
rpcMsg
);
return
ret
;
}
\ No newline at end of file
source/libs/sync/src/syncRequestVote.c
浏览文件 @
2f792722
...
...
@@ -15,40 +15,25 @@
#include "syncRequestVote.h"
int32_t
syncNodeRequestVote
(
SSyncNode
*
ths
,
const
SyncRequestVote
*
pMsg
)
{
// TLA+ Spec
// RequestVote(i, j) ==
// /\ state[i] = Candidate
// /\ j \notin votesResponded[i]
// /\ Send([mtype |-> RequestVoteRequest,
// mterm |-> currentTerm[i],
// mlastLogTerm |-> LastTerm(log[i]),
// mlastLogIndex |-> Len(log[i]),
// msource |-> i,
// mdest |-> j])
// /\ UNCHANGED <<serverVars, candidateVars, leaderVars, logVars>>
}
int32_t
syncNodeOnRequestVoteCb
(
SSyncNode
*
ths
,
SyncRequestVote
*
pMsg
)
{
// TLA+ Spec
// HandleRequestVoteRequest(i, j, m) ==
// LET logOk == \/ m.mlastLogTerm > LastTerm(log[i])
// \/ /\ m.mlastLogTerm = LastTerm(log[i])
// /\ m.mlastLogIndex >= Len(log[i])
// grant == /\ m.mterm = currentTerm[i]
// /\ logOk
// /\ votedFor[i] \in {Nil, j}
// IN /\ m.mterm <= currentTerm[i]
// /\ \/ grant /\ votedFor' = [votedFor EXCEPT ![i] = j]
// \/ ~grant /\ UNCHANGED votedFor
// /\ Reply([mtype |-> RequestVoteResponse,
// mterm |-> currentTerm[i],
// mvoteGranted |-> grant,
// \* mlog is used just for the `elections' history variable for
// \* the proof. It would not exist in a real implementation.
// mlog |-> log[i],
// msource |-> i,
// mdest |-> j],
// m)
// /\ UNCHANGED <<state, currentTerm, candidateVars, leaderVars, logVars>>
}
// TLA+ Spec
// HandleRequestVoteRequest(i, j, m) ==
// LET logOk == \/ m.mlastLogTerm > LastTerm(log[i])
// \/ /\ m.mlastLogTerm = LastTerm(log[i])
// /\ m.mlastLogIndex >= Len(log[i])
// grant == /\ m.mterm = currentTerm[i]
// /\ logOk
// /\ votedFor[i] \in {Nil, j}
// IN /\ m.mterm <= currentTerm[i]
// /\ \/ grant /\ votedFor' = [votedFor EXCEPT ![i] = j]
// \/ ~grant /\ UNCHANGED votedFor
// /\ Reply([mtype |-> RequestVoteResponse,
// mterm |-> currentTerm[i],
// mvoteGranted |-> grant,
// \* mlog is used just for the `elections' history variable for
// \* the proof. It would not exist in a real implementation.
// mlog |-> log[i],
// msource |-> i,
// mdest |-> j],
// m)
// /\ UNCHANGED <<state, currentTerm, candidateVars, leaderVars, logVars>>
int32_t
syncNodeOnRequestVoteCb
(
SSyncNode
*
ths
,
SyncRequestVote
*
pMsg
)
{}
source/libs/sync/src/syncRequestVoteReply.c
浏览文件 @
2f792722
...
...
@@ -15,21 +15,20 @@
#include "syncRequestVoteReply.h"
int32_t
syncNodeOnRequestVoteReplyCb
(
SSyncNode
*
ths
,
SyncRequestVoteReply
*
pMsg
)
{
// TLA+ Spec
// HandleRequestVoteResponse(i, j, m) ==
// \* This tallies votes even when the current state is not Candidate, but
// \* they won't be looked at, so it doesn't matter.
// /\ m.mterm = currentTerm[i]
// /\ votesResponded' = [votesResponded EXCEPT ![i] =
// votesResponded[i] \cup {j}]
// /\ \/ /\ m.mvoteGranted
// /\ votesGranted' = [votesGranted EXCEPT ![i] =
// votesGranted[i] \cup {j}]
// /\ voterLog' = [voterLog EXCEPT ![i] =
// voterLog[i] @@ (j :> m.mlog)]
// \/ /\ ~m.mvoteGranted
// /\ UNCHANGED <<votesGranted, voterLog>>
// /\ Discard(m)
// /\ UNCHANGED <<serverVars, votedFor, leaderVars, logVars>>
}
// TLA+ Spec
// HandleRequestVoteResponse(i, j, m) ==
// \* This tallies votes even when the current state is not Candidate, but
// \* they won't be looked at, so it doesn't matter.
// /\ m.mterm = currentTerm[i]
// /\ votesResponded' = [votesResponded EXCEPT ![i] =
// votesResponded[i] \cup {j}]
// /\ \/ /\ m.mvoteGranted
// /\ votesGranted' = [votesGranted EXCEPT ![i] =
// votesGranted[i] \cup {j}]
// /\ voterLog' = [voterLog EXCEPT ![i] =
// voterLog[i] @@ (j :> m.mlog)]
// \/ /\ ~m.mvoteGranted
// /\ UNCHANGED <<votesGranted, voterLog>>
// /\ Discard(m)
// /\ UNCHANGED <<serverVars, votedFor, leaderVars, logVars>>
int32_t
syncNodeOnRequestVoteReplyCb
(
SSyncNode
*
ths
,
SyncRequestVoteReply
*
pMsg
)
{}
source/libs/sync/src/syncTimeout.c
浏览文件 @
2f792722
...
...
@@ -14,5 +14,41 @@
*/
#include "syncTimeout.h"
#include "syncElection.h"
#include "syncReplication.h"
void
onTimeout
(
SRaft
*
pRaft
,
void
*
pMsg
)
{}
\ No newline at end of file
int32_t
syncNodeOnTimeoutCb
(
SSyncNode
*
ths
,
SyncTimeout
*
pMsg
)
{
int32_t
ret
=
0
;
sTrace
(
"<-- syncNodeOnTimeoutCb -->"
);
{
cJSON
*
pJson
=
syncTimeout2Json
(
pMsg
);
char
*
serialized
=
cJSON_Print
(
pJson
);
sTrace
(
"process syncMessage recv: syncNodeOnTimeoutCb pMsg:%s "
,
serialized
);
free
(
serialized
);
cJSON_Delete
(
pJson
);
}
if
(
pMsg
->
timeoutType
==
SYNC_TIMEOUT_PING
)
{
if
(
atomic_load_64
(
&
ths
->
pingTimerLogicClockUser
)
<=
pMsg
->
logicClock
)
{
++
(
ths
->
pingTimerCounter
);
syncNodePingAll
(
ths
);
}
}
else
if
(
pMsg
->
timeoutType
==
SYNC_TIMEOUT_ELECTION
)
{
if
(
atomic_load_64
(
&
ths
->
electTimerLogicClockUser
)
<=
pMsg
->
logicClock
)
{
++
(
ths
->
electTimerCounter
);
syncNodeElect
(
ths
);
}
}
else
if
(
pMsg
->
timeoutType
==
SYNC_TIMEOUT_HEARTBEAT
)
{
if
(
atomic_load_64
(
&
ths
->
heartbeatTimerLogicClockUser
)
<=
pMsg
->
logicClock
)
{
++
(
ths
->
heartbeatTimerCounter
);
syncNodeAppendEntriesPeers
(
ths
);
}
}
else
{
sTrace
(
"unknown timeoutType:%d"
,
pMsg
->
timeoutType
);
}
return
ret
;
}
\ No newline at end of file
source/libs/sync/src/syncUtil.c
浏览文件 @
2f792722
...
...
@@ -17,6 +17,7 @@
#include <arpa/inet.h>
#include <netinet/in.h>
#include <sys/socket.h>
#include "syncEnv.h"
// ---- encode / decode
uint64_t
syncUtilAddr2U64
(
const
char
*
host
,
uint16_t
port
)
{
...
...
@@ -91,3 +92,9 @@ void syncUtilbufCopyDeep(const SSyncBuffer* src, SSyncBuffer* dest) {
dest
->
data
=
malloc
(
dest
->
len
);
memcpy
(
dest
->
data
,
src
->
data
,
dest
->
len
);
}
// ---- misc ----
int32_t
syncUtilRand
(
int32_t
max
)
{
return
rand
()
%
max
;
}
int32_t
syncUtilElectRandomMS
()
{
ELECT_TIMER_MS_MIN
+
syncUtilRand
(
ELECT_TIMER_MS_RANGE
);
}
\ No newline at end of file
source/libs/sync/test/syncIndexTest.cpp
浏览文件 @
2f792722
...
...
@@ -13,17 +13,21 @@ void print(SHashObj *pNextIndex) {
}
}
void
logTest
()
{
sTrace
(
"--- sync log test: trace"
);
sDebug
(
"--- sync log test: debug"
);
sInfo
(
"--- sync log test: info"
);
sWarn
(
"--- sync log test: warn"
);
sError
(
"--- sync log test: error"
);
sFatal
(
"--- sync log test: fatal"
);
}
int
main
()
{
// taosInitLog((char *)"syncTest.log", 100000, 10);
tsAsyncLog
=
0
;
sDebugFlag
=
143
+
64
;
sTrace
(
"sync log test: trace"
);
sDebug
(
"sync log test: debug"
);
sInfo
(
"sync log test: info"
);
sWarn
(
"sync log test: warn"
);
sError
(
"sync log test: error"
);
sFatal
(
"sync log test: fatal"
);
logTest
();
SRaftId
me
;
SRaftId
peer1
;
...
...
source/libs/sync/test/syncRaftStoreTest.cpp
浏览文件 @
2f792722
...
...
@@ -4,14 +4,13 @@
#include "syncIO.h"
#include "syncInt.h"
void
*
pingFunc
(
void
*
param
)
{
SSyncIO
*
io
=
(
SSyncIO
*
)
param
;
while
(
1
)
{
sDebug
(
"io->ping"
);
// io->ping(io);
sleep
(
1
);
}
return
NULL
;
void
logTest
()
{
sTrace
(
"--- sync log test: trace"
);
sDebug
(
"--- sync log test: debug"
);
sInfo
(
"--- sync log test: info"
);
sWarn
(
"--- sync log test: warn"
);
sError
(
"--- sync log test: error"
);
sFatal
(
"--- sync log test: fatal"
);
}
int
main
()
{
...
...
@@ -19,12 +18,7 @@ int main() {
tsAsyncLog
=
0
;
sDebugFlag
=
143
+
64
;
sTrace
(
"sync log test: trace"
);
sDebug
(
"sync log test: debug"
);
sInfo
(
"sync log test: info"
);
sWarn
(
"sync log test: warn"
);
sError
(
"sync log test: error"
);
sFatal
(
"sync log test: fatal"
);
logTest
();
SRaftStore
*
pRaftStore
=
raftStoreOpen
(
"./raft_store.json"
);
assert
(
pRaftStore
!=
NULL
);
...
...
source/libs/sync/test/syncTest.cpp
浏览文件 @
2f792722
...
...
@@ -4,55 +4,20 @@
#include "syncInt.h"
#include "syncRaftStore.h"
void
*
pingFunc
(
void
*
param
)
{
SSyncIO
*
io
=
(
SSyncIO
*
)
param
;
while
(
1
)
{
sDebug
(
"io->ping"
);
// io->ping(io);
sleep
(
1
);
}
return
NULL
;
void
logTest
()
{
sTrace
(
"--- sync log test: trace"
);
sDebug
(
"--- sync log test: debug"
);
sInfo
(
"--- sync log test: info"
);
sWarn
(
"--- sync log test: warn"
);
sError
(
"--- sync log test: error"
);
sFatal
(
"--- sync log test: fatal"
);
}
int
main
()
{
// taosInitLog((char *)"syncTest.log", 100000, 10);
tsAsyncLog
=
0
;
sDebugFlag
=
143
+
64
;
logTest
();
sTrace
(
"sync log test: trace"
);
sDebug
(
"sync log test: debug"
);
sInfo
(
"sync log test: info"
);
sWarn
(
"sync log test: warn"
);
sError
(
"sync log test: error"
);
sFatal
(
"sync log test: fatal"
);
SRaftStore
*
pRaftStore
=
raftStoreOpen
(
"./raft_store.json"
);
// assert(pRaftStore != NULL);
// raftStorePrint(pRaftStore);
// pRaftStore->currentTerm = 100;
// pRaftStore->voteFor.addr = 200;
// pRaftStore->voteFor.vgId = 300;
// raftStorePrint(pRaftStore);
// raftStorePersist(pRaftStore);
// sDebug("sync test");
// SSyncIO *syncIO = syncIOCreate();
// assert(syncIO != NULL);
// syncIO->start(syncIO);
// sleep(2);
// pthread_t tid;
// pthread_create(&tid, NULL, pingFunc, syncIO);
// while (1) {
// sleep(1);
// }
return
0
;
}
编辑
预览
Markdown
is supported
0%
请重试
或
添加新附件
.
添加附件
取消
You are about to add
0
people
to the discussion. Proceed with caution.
先完成此消息的编辑!
取消
想要评论请
注册
或
登录