You can not select more than 25 topics Topics must start with a chinese character,a letter or number, can include dashes ('-') and can be up to 35 characters long.

transport.go 9.7 kB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434
  1. package cluster
  2. import (
  3. "context"
  4. "io"
  5. "sync"
  6. "time"
  7. "github.com/hashicorp/raft"
  8. "gitlink.org.cn/cloudream/common/utils/serder"
  9. "gitlink.org.cn/cloudream/jcs-pub/common/ecode"
  10. "gitlink.org.cn/cloudream/jcs-pub/common/pkgs/rpc"
  11. clirpc "gitlink.org.cn/cloudream/jcs-pub/common/pkgs/rpc/client"
  12. )
  13. const (
  14. CmdAppendEntries = "AppendEntries"
  15. CmdRequestVote = "RequestVote"
  16. CmdRequestPreVote = "RequestPreVote"
  17. CmdTimeoutNow = "TimeoutNow"
  18. )
  19. type Transport struct {
  20. localAddr string
  21. shutdownCh chan any
  22. shutdownLock sync.Mutex
  23. shutdown bool
  24. consumeCh chan raft.RPC
  25. cliPoolCfg clirpc.PoolConfig
  26. cliPools map[raft.ServerAddress]*clirpc.Pool
  27. poolLock sync.Mutex
  28. heartbeatFn func(raft.RPC)
  29. heartbeatFnLock sync.Mutex
  30. }
  31. func NewTransport(localAddr string, cliPoolCfg clirpc.PoolConfig) *Transport {
  32. return &Transport{
  33. localAddr: localAddr,
  34. shutdownCh: make(chan any),
  35. consumeCh: make(chan raft.RPC),
  36. cliPoolCfg: cliPoolCfg,
  37. cliPools: make(map[raft.ServerAddress]*clirpc.Pool),
  38. heartbeatFn: nil,
  39. }
  40. }
  41. func (t *Transport) Close() {
  42. t.shutdownLock.Lock()
  43. defer t.shutdownLock.Unlock()
  44. if !t.shutdown {
  45. close(t.shutdownCh)
  46. t.shutdown = true
  47. }
  48. }
  49. func (n *Transport) IsClosed() bool {
  50. select {
  51. case <-n.shutdownCh:
  52. return true
  53. default:
  54. return false
  55. }
  56. }
  57. func (t *Transport) Consumer() <-chan raft.RPC {
  58. return t.consumeCh
  59. }
  60. func (t *Transport) LocalAddr() raft.ServerAddress {
  61. return raft.ServerAddress(t.localAddr)
  62. }
  63. func (t *Transport) AppendEntriesPipeline(id raft.ServerID, target raft.ServerAddress) (raft.AppendPipeline, error) {
  64. t.poolLock.Lock()
  65. defer t.poolLock.Unlock()
  66. pool := t.cliPools[target]
  67. if pool == nil {
  68. cfg := t.cliPoolCfg
  69. cfg.Address = string(target)
  70. pool = clirpc.NewPool(cfg)
  71. t.cliPools[target] = pool
  72. }
  73. cli := pool.Get()
  74. return &AppendPipeline{
  75. cli: cli,
  76. consumerCh: make(chan raft.AppendFuture),
  77. done: make(chan any),
  78. }, nil
  79. }
  80. func (t *Transport) AppendEntries(id raft.ServerID, target raft.ServerAddress, args *raft.AppendEntriesRequest, resp *raft.AppendEntriesResponse) error {
  81. cli := t.getCli(target)
  82. reqData, err := serder.ObjectToJSON(args)
  83. if err != nil {
  84. return err
  85. }
  86. r, cerr := cli.ClusterRaftRPC(context.Background(), &clirpc.ClusterRaftRPC{
  87. Type: CmdAppendEntries,
  88. Data: string(reqData),
  89. })
  90. if cerr != nil {
  91. return cerr.ToError()
  92. }
  93. err = serder.JSONToObject([]byte(r.Data), resp)
  94. if err != nil {
  95. return err
  96. }
  97. return nil
  98. }
  99. func (t *Transport) RequestVote(id raft.ServerID, target raft.ServerAddress, args *raft.RequestVoteRequest, resp *raft.RequestVoteResponse) error {
  100. cli := t.getCli(target)
  101. reqData, err := serder.ObjectToJSON(args)
  102. if err != nil {
  103. return err
  104. }
  105. r, cerr := cli.ClusterRaftRPC(context.Background(), &clirpc.ClusterRaftRPC{
  106. Type: CmdRequestVote,
  107. Data: string(reqData),
  108. })
  109. if cerr != nil {
  110. return cerr.ToError()
  111. }
  112. err = serder.JSONToObject([]byte(r.Data), resp)
  113. if err != nil {
  114. return err
  115. }
  116. return nil
  117. }
  118. func (t *Transport) RequestPreVote(id raft.ServerID, target raft.ServerAddress, args *raft.RequestPreVoteRequest, resp *raft.RequestPreVoteResponse) error {
  119. cli := t.getCli(target)
  120. reqData, err := serder.ObjectToJSON(args)
  121. if err != nil {
  122. return err
  123. }
  124. r, cerr := cli.ClusterRaftRPC(context.Background(), &clirpc.ClusterRaftRPC{
  125. Type: CmdRequestPreVote,
  126. Data: string(reqData),
  127. })
  128. if cerr != nil {
  129. return cerr.ToError()
  130. }
  131. err = serder.JSONToObject([]byte(r.Data), resp)
  132. if err != nil {
  133. return err
  134. }
  135. return nil
  136. }
  137. func (t *Transport) InstallSnapshot(id raft.ServerID, target raft.ServerAddress, args *raft.InstallSnapshotRequest, resp *raft.InstallSnapshotResponse, data io.Reader) error {
  138. cli := t.getCli(target)
  139. r, cerr := cli.ClusterRaftInstallSnapshot(context.Background(), &clirpc.ClusterRaftInstallSnapshot{
  140. Args: args,
  141. Data: data,
  142. })
  143. if cerr != nil {
  144. return cerr.ToError()
  145. }
  146. *resp = *r.Resp
  147. return nil
  148. }
  149. func (t *Transport) EncodePeer(id raft.ServerID, addr raft.ServerAddress) []byte {
  150. return []byte(addr)
  151. }
  152. func (t *Transport) DecodePeer(data []byte) raft.ServerAddress {
  153. return raft.ServerAddress(string(data))
  154. }
  155. func (t *Transport) SetHeartbeatHandler(cb func(rpc raft.RPC)) {
  156. t.heartbeatFnLock.Lock()
  157. defer t.heartbeatFnLock.Unlock()
  158. t.heartbeatFn = cb
  159. }
  160. func (t *Transport) TimeoutNow(id raft.ServerID, target raft.ServerAddress, args *raft.TimeoutNowRequest, resp *raft.TimeoutNowResponse) error {
  161. cli := t.getCli(target)
  162. reqData, err := serder.ObjectToJSON(args)
  163. if err != nil {
  164. return err
  165. }
  166. r, cerr := cli.ClusterRaftRPC(context.Background(), &clirpc.ClusterRaftRPC{
  167. Type: CmdTimeoutNow,
  168. Data: string(reqData),
  169. })
  170. if cerr != nil {
  171. return cerr.ToError()
  172. }
  173. err = serder.JSONToObject([]byte(r.Data), resp)
  174. if err != nil {
  175. return err
  176. }
  177. return nil
  178. }
  179. func (t *Transport) OnRPC(req *clirpc.ClusterRaftRPC) (*clirpc.ClusterRaftRPCResp, *rpc.CodeError) {
  180. respChan := make(chan raft.RPCResponse, 1)
  181. rp := raft.RPC{
  182. RespChan: respChan,
  183. }
  184. isHeartbeat := false
  185. switch req.Type {
  186. case CmdAppendEntries:
  187. var r raft.AppendEntriesRequest
  188. err := serder.JSONToObject([]byte(req.Data), &r)
  189. if err != nil {
  190. return nil, rpc.Failed(ecode.OperationFailed, err.Error())
  191. }
  192. rp.Command = &r
  193. leaderAddr := r.RPCHeader.Addr
  194. // Check if this is a heartbeat
  195. if r.Term != 0 && leaderAddr != nil &&
  196. r.PrevLogEntry == 0 && r.PrevLogTerm == 0 &&
  197. len(r.Entries) == 0 && r.LeaderCommitIndex == 0 {
  198. isHeartbeat = true
  199. }
  200. case CmdRequestVote:
  201. var r raft.RequestVoteRequest
  202. err := serder.JSONToObject([]byte(req.Data), &r)
  203. if err != nil {
  204. return nil, rpc.Failed(ecode.OperationFailed, err.Error())
  205. }
  206. rp.Command = &r
  207. case CmdRequestPreVote:
  208. var r raft.RequestPreVoteRequest
  209. err := serder.JSONToObject([]byte(req.Data), &r)
  210. if err != nil {
  211. return nil, rpc.Failed(ecode.OperationFailed, err.Error())
  212. }
  213. rp.Command = &r
  214. case CmdTimeoutNow:
  215. var r raft.TimeoutNowRequest
  216. err := serder.JSONToObject([]byte(req.Data), &r)
  217. if err != nil {
  218. return nil, rpc.Failed(ecode.OperationFailed, err.Error())
  219. }
  220. rp.Command = &r
  221. }
  222. if isHeartbeat {
  223. t.heartbeatFnLock.Lock()
  224. fn := t.heartbeatFn
  225. t.heartbeatFnLock.Unlock()
  226. if fn != nil {
  227. fn(rp)
  228. goto RESP
  229. }
  230. }
  231. // Dispatch the RPC
  232. select {
  233. case t.consumeCh <- rp:
  234. case <-t.shutdownCh:
  235. return nil, rpc.Failed(ecode.OperationFailed, raft.ErrTransportShutdown.Error())
  236. }
  237. // Wait for response
  238. RESP:
  239. select {
  240. case resp := <-respChan:
  241. if resp.Error != nil {
  242. return nil, rpc.Failed(ecode.OperationFailed, resp.Error.Error())
  243. }
  244. data, err := serder.ObjectToJSON(resp.Response)
  245. if err != nil {
  246. return nil, rpc.Failed(ecode.OperationFailed, err.Error())
  247. }
  248. return &clirpc.ClusterRaftRPCResp{
  249. Data: string(data),
  250. }, nil
  251. case <-t.shutdownCh:
  252. return nil, rpc.Failed(ecode.OperationFailed, raft.ErrTransportShutdown.Error())
  253. }
  254. }
  255. func (t *Transport) OnInstallSnapshot(req *clirpc.ClusterRaftInstallSnapshot) (*clirpc.ClusterRaftInstallSnapshotResp, *rpc.CodeError) {
  256. respChan := make(chan raft.RPCResponse, 1)
  257. rp := raft.RPC{
  258. Command: req.Args,
  259. Reader: req.Data,
  260. RespChan: respChan,
  261. }
  262. select {
  263. case t.consumeCh <- rp:
  264. case <-t.shutdownCh:
  265. return nil, rpc.Failed(ecode.OperationFailed, raft.ErrTransportShutdown.Error())
  266. }
  267. select {
  268. case resp := <-respChan:
  269. if resp.Error != nil {
  270. return nil, rpc.Failed(ecode.OperationFailed, resp.Error.Error())
  271. }
  272. return &clirpc.ClusterRaftInstallSnapshotResp{
  273. Resp: resp.Response.(*raft.InstallSnapshotResponse),
  274. }, nil
  275. case <-t.shutdownCh:
  276. return nil, rpc.Failed(ecode.OperationFailed, raft.ErrTransportShutdown.Error())
  277. }
  278. }
  279. func (t *Transport) getCli(target raft.ServerAddress) *clirpc.PoolClient {
  280. t.poolLock.Lock()
  281. defer t.poolLock.Unlock()
  282. pool := t.cliPools[target]
  283. if pool == nil {
  284. cfg := t.cliPoolCfg
  285. cfg.Address = string(target)
  286. pool = clirpc.NewPool(cfg)
  287. t.cliPools[target] = pool
  288. }
  289. return pool.Get()
  290. }
  291. var _ raft.Transport = (*Transport)(nil)
  292. var _ raft.WithPreVote = (*Transport)(nil)
  293. type AppendPipeline struct {
  294. cli *clirpc.PoolClient
  295. consumerCh chan raft.AppendFuture
  296. done chan any
  297. closeLock sync.Mutex
  298. }
  299. func (c *AppendPipeline) AppendEntries(args *raft.AppendEntriesRequest, resp *raft.AppendEntriesResponse) (raft.AppendFuture, error) {
  300. reqData, err := serder.ObjectToJSON(args)
  301. if err != nil {
  302. return nil, err
  303. }
  304. startTime := time.Now()
  305. r, cerr := c.cli.ClusterRaftRPC(context.Background(), &clirpc.ClusterRaftRPC{
  306. Type: CmdAppendEntries,
  307. Data: string(reqData),
  308. })
  309. if cerr != nil {
  310. return nil, cerr.ToError()
  311. }
  312. err = serder.JSONToObject([]byte(r.Data), resp)
  313. if err != nil {
  314. return nil, err
  315. }
  316. f := &appendFuture{
  317. startTime: startTime,
  318. req: args,
  319. resp: resp,
  320. }
  321. select {
  322. case c.consumerCh <- f:
  323. return f, nil
  324. case <-c.done:
  325. return nil, raft.ErrPipelineShutdown
  326. }
  327. }
  328. func (c *AppendPipeline) Consumer() <-chan raft.AppendFuture {
  329. return c.consumerCh
  330. }
  331. func (c *AppendPipeline) Close() error {
  332. c.closeLock.Lock()
  333. defer c.closeLock.Unlock()
  334. if c.done == nil {
  335. return nil
  336. }
  337. close(c.done)
  338. c.done = nil
  339. c.cli.Release()
  340. return nil
  341. }
  342. var _ raft.AppendPipeline = (*AppendPipeline)(nil)
  343. type appendFuture struct {
  344. startTime time.Time
  345. req *raft.AppendEntriesRequest
  346. resp *raft.AppendEntriesResponse
  347. }
  348. func (f *appendFuture) Error() error {
  349. return nil
  350. }
  351. func (f *appendFuture) Start() time.Time {
  352. return f.startTime
  353. }
  354. func (f *appendFuture) Request() *raft.AppendEntriesRequest {
  355. return f.req
  356. }
  357. func (f *appendFuture) Response() *raft.AppendEntriesResponse {
  358. return f.resp
  359. }

本项目旨在将云际存储公共基础设施化,使个人及企业可低门槛使用高效的云际存储服务(安装开箱即用云际存储客户端即可,无需关注其他组件的部署),同时支持用户灵活便捷定制云际存储的功能细节。