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.

space_syncer.go 4.4 kB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215
  1. package spacesyncer
  2. import (
  3. "context"
  4. "fmt"
  5. "sync"
  6. "gitlink.org.cn/cloudream/common/pkgs/async"
  7. "gitlink.org.cn/cloudream/common/pkgs/logger"
  8. "gitlink.org.cn/cloudream/jcs-pub/client/internal/cluster"
  9. "gitlink.org.cn/cloudream/jcs-pub/client/internal/db"
  10. "gitlink.org.cn/cloudream/jcs-pub/client/internal/metacache"
  11. stgpool "gitlink.org.cn/cloudream/jcs-pub/common/pkgs/storage/pool"
  12. jcstypes "gitlink.org.cn/cloudream/jcs-pub/common/types"
  13. )
  14. const (
  15. logMod = "SpaceSyncer"
  16. )
  17. type SpaceSyncerEvent interface {
  18. IsSpaceSyncerEvent() bool
  19. }
  20. type SpaceSyncer struct {
  21. db *db.DB
  22. stgPool *stgpool.Pool
  23. spaceMeta *metacache.UserSpaceMeta
  24. cluster *cluster.Cluster
  25. lock sync.Mutex
  26. tasks map[jcstypes.SpaceSyncTaskID]*task
  27. }
  28. func New(db *db.DB, stgPool *stgpool.Pool, spaceMeta *metacache.UserSpaceMeta, cluster *cluster.Cluster) *SpaceSyncer {
  29. return &SpaceSyncer{
  30. db: db,
  31. stgPool: stgPool,
  32. spaceMeta: spaceMeta,
  33. cluster: cluster,
  34. tasks: make(map[jcstypes.SpaceSyncTaskID]*task),
  35. }
  36. }
  37. func (s *SpaceSyncer) Start() *async.UnboundChannel[SpaceSyncerEvent] {
  38. s.lock.Lock()
  39. defer s.lock.Unlock()
  40. log := logger.WithField("Mod", logMod)
  41. ch := async.NewUnboundChannel[SpaceSyncerEvent]()
  42. if !s.cluster.IsMaster() {
  43. log.Infof("not master, skip start space syncer")
  44. return ch
  45. }
  46. allTask, err := db.DoTx01(s.db, s.db.SpaceSyncTask().GetAll)
  47. if err != nil {
  48. log.Warnf("load task from db: %v", err)
  49. } else {
  50. var rms []jcstypes.SpaceSyncTaskID
  51. for _, t := range allTask {
  52. ctx, cancel := context.WithCancel(context.Background())
  53. tsk := task{
  54. Task: t,
  55. Context: ctx,
  56. CancelFn: cancel,
  57. }
  58. switch tr := t.Trigger.(type) {
  59. case *jcstypes.SpaceSyncTriggerOnce:
  60. // Once类型的任务没有执行完也不执行了
  61. rms = append(rms, t.TaskID)
  62. case *jcstypes.SpaceSyncTriggerInterval:
  63. triggerInterval(s, &tsk, tr)
  64. case *jcstypes.SpaceSyncTriggerAt:
  65. triggerAt(s, &tsk, tr)
  66. }
  67. log.Infof("load task %v from db", t.TaskID)
  68. }
  69. if len(rms) > 0 {
  70. err := s.db.SpaceSyncTask().BatchDelete(s.db.DefCtx(), rms)
  71. if err != nil {
  72. log.Warnf("batch delete task: %v", err)
  73. } else {
  74. log.Infof("%v once task deleted", len(rms))
  75. }
  76. }
  77. }
  78. return ch
  79. }
  80. func (s *SpaceSyncer) Stop() {
  81. s.lock.Lock()
  82. defer s.lock.Unlock()
  83. if !s.cluster.IsMaster() {
  84. return
  85. }
  86. for _, t := range s.tasks {
  87. t.CancelFn()
  88. }
  89. s.tasks = make(map[jcstypes.SpaceSyncTaskID]*task)
  90. }
  91. func (s *SpaceSyncer) CreateTask(t jcstypes.SpaceSyncTask) (*TaskInfo, error) {
  92. log := logger.WithField("Mod", logMod)
  93. if !s.cluster.IsMaster() {
  94. return nil, fmt.Errorf("not master, create task aborted")
  95. }
  96. d := s.db
  97. err := d.DoTx(func(tx db.SQLContext) error {
  98. err := d.SpaceSyncTask().Create(tx, &t)
  99. if err != nil {
  100. return err
  101. }
  102. return nil
  103. })
  104. if err != nil {
  105. return nil, fmt.Errorf("creating space sync task: %w", err)
  106. }
  107. ctx, cancel := context.WithCancel(context.Background())
  108. tsk := task{
  109. Task: t,
  110. Context: ctx,
  111. CancelFn: cancel,
  112. }
  113. s.lock.Lock()
  114. s.tasks[t.TaskID] = &tsk
  115. s.lock.Unlock()
  116. switch tr := t.Trigger.(type) {
  117. case *jcstypes.SpaceSyncTriggerOnce:
  118. triggerOnce(s, &tsk)
  119. case *jcstypes.SpaceSyncTriggerInterval:
  120. triggerInterval(s, &tsk, tr)
  121. case *jcstypes.SpaceSyncTriggerAt:
  122. triggerAt(s, &tsk, tr)
  123. }
  124. log.Infof("task %v created", t.TaskID)
  125. return &TaskInfo{
  126. Task: t,
  127. }, nil
  128. }
  129. func (s *SpaceSyncer) CancelTask(taskID jcstypes.SpaceSyncTaskID) {
  130. log := logger.WithField("Mod", logMod)
  131. if !s.cluster.IsMaster() {
  132. return
  133. }
  134. s.lock.Lock()
  135. defer s.lock.Unlock()
  136. t := s.tasks[taskID]
  137. if t == nil {
  138. log.Infof("task %v not found, cancel aborted", taskID)
  139. return
  140. }
  141. t.CancelFn()
  142. delete(s.tasks, taskID)
  143. err := s.db.SpaceSyncTask().Delete(s.db.DefCtx(), taskID)
  144. if err != nil {
  145. log.Warnf("delete task %v from db: %v", taskID, err)
  146. }
  147. log.Infof("task %v canceled", taskID)
  148. }
  149. func (s *SpaceSyncer) GetTask(taskID jcstypes.SpaceSyncTaskID) *jcstypes.SpaceSyncTask {
  150. s.lock.Lock()
  151. defer s.lock.Unlock()
  152. if !s.cluster.IsMaster() {
  153. return nil
  154. }
  155. tsk := s.tasks[taskID]
  156. if tsk == nil {
  157. return nil
  158. }
  159. // TODO 考虑复制一份状态,防止修改
  160. t := tsk.Task
  161. return &t
  162. }
  163. type TaskInfo struct {
  164. Task jcstypes.SpaceSyncTask
  165. }
  166. type task struct {
  167. Task jcstypes.SpaceSyncTask
  168. Context context.Context
  169. CancelFn func()
  170. }

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