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.

fsm.go 3.3 kB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168
  1. package cluster
  2. import (
  3. "encoding/binary"
  4. "fmt"
  5. "io"
  6. "github.com/hashicorp/raft"
  7. "gitlink.org.cn/cloudream/common/utils/http2"
  8. "gitlink.org.cn/cloudream/common/utils/serder"
  9. )
  10. var ErrFSMNotFound = fmt.Errorf("fsm not found")
  11. type FSM interface {
  12. // 必须唯一且不能变化
  13. ID() string
  14. Apply(cmd []byte) ([]byte, error)
  15. Snapshot() (FSMSnapshot, error)
  16. Restore(input io.Reader) error
  17. }
  18. type FSMSnapshot interface {
  19. Persist(output io.Writer) error
  20. Release()
  21. }
  22. type SnapshotMeta struct {
  23. Version int
  24. }
  25. type raftFSM struct {
  26. fsms map[string]FSM
  27. }
  28. func NewFSM(fsms []FSM) *raftFSM {
  29. fsmsMp := make(map[string]FSM)
  30. for _, fsm := range fsms {
  31. _, ok := fsmsMp[fsm.ID()]
  32. if ok {
  33. panic(fmt.Sprintf("duplicate fsm id: %s", fsm.ID()))
  34. }
  35. fsmsMp[fsm.ID()] = fsm
  36. }
  37. return &raftFSM{fsms: fsmsMp}
  38. }
  39. func (f *raftFSM) Apply(l *raft.Log) interface{} {
  40. idLen := binary.LittleEndian.Uint32(l.Data[:4])
  41. fsm, ok := f.fsms[string(l.Data[4:4+idLen])]
  42. if !ok {
  43. return ErrFSMNotFound
  44. }
  45. cmd := l.Data[4+idLen:]
  46. res, err := fsm.Apply(cmd)
  47. return applyResult{
  48. Result: res,
  49. Error: err,
  50. }
  51. }
  52. func (f *raftFSM) Snapshot() (raft.FSMSnapshot, error) {
  53. snapshots := make(map[string]FSMSnapshot)
  54. for id, fsm := range f.fsms {
  55. snapshot, err := fsm.Snapshot()
  56. if err != nil {
  57. for _, snapshot := range snapshots {
  58. snapshot.Release()
  59. }
  60. return nil, err
  61. }
  62. snapshots[id] = snapshot
  63. }
  64. return &Snapshot{snapshots: snapshots}, nil
  65. }
  66. func (f *raftFSM) Restore(rc io.ReadCloser) error {
  67. defer rc.Close()
  68. cr := http2.NewChunkedReader(rc)
  69. _, metaBytes, err := cr.NextDataPart()
  70. if err != nil {
  71. return fmt.Errorf("read meta data part: %v", err)
  72. }
  73. meta := SnapshotMeta{}
  74. if err := serder.JSONToObject(metaBytes, &meta); err != nil {
  75. return fmt.Errorf("unmarshal meta data: %v", err)
  76. }
  77. // 进行类似的检查
  78. if meta.Version != 1 {
  79. return fmt.Errorf("unsupported version: %d", meta.Version)
  80. }
  81. for {
  82. id, reader, err := cr.NextPart()
  83. if err != nil && err != io.EOF {
  84. return err
  85. }
  86. if err == io.EOF {
  87. // TODO 考虑检查一下是否调用了所有FSM的Restore方法
  88. break
  89. }
  90. fsm, ok := f.fsms[id]
  91. if !ok {
  92. // TODO 兼容性
  93. continue
  94. }
  95. err = fsm.Restore(reader)
  96. if err != nil {
  97. // TODO 不知道Raft库在发现Restore失败后是否能够及时停止服务
  98. return fmt.Errorf("restore fsm %s: %v", id, err)
  99. }
  100. }
  101. return nil
  102. }
  103. var _ raft.FSM = (*raftFSM)(nil)
  104. type Snapshot struct {
  105. snapshots map[string]FSMSnapshot
  106. }
  107. func (s *Snapshot) Persist(sink raft.SnapshotSink) error {
  108. meta := SnapshotMeta{Version: 1}
  109. metaBytes, err := serder.ObjectToJSON(meta)
  110. if err != nil {
  111. sink.Cancel()
  112. return fmt.Errorf("marshal meta data: %v", err)
  113. }
  114. cw := http2.NewChunkedWriter(sink)
  115. err = cw.WriteDataPart("meta", metaBytes)
  116. if err != nil {
  117. sink.Cancel()
  118. return fmt.Errorf("write meta data part: %v", err)
  119. }
  120. for id, snapshot := range s.snapshots {
  121. w := cw.BeginPart(id)
  122. err := snapshot.Persist(w)
  123. if err != nil {
  124. sink.Cancel()
  125. return fmt.Errorf("persist fsm %s: %v", id, err)
  126. }
  127. }
  128. return sink.Close()
  129. }
  130. func (s *Snapshot) Release() {
  131. for _, snapshot := range s.snapshots {
  132. snapshot.Release()
  133. }
  134. }
  135. type applyResult struct {
  136. Result []byte
  137. Error error
  138. }

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