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.

agent_check_storage.go 6.2 kB

2 years ago
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199
  1. package event
  2. import (
  3. "database/sql"
  4. "time"
  5. "github.com/samber/lo"
  6. "gitlink.org.cn/cloudream/common/pkgs/logger"
  7. "gitlink.org.cn/cloudream/common/pkgs/mq"
  8. "gitlink.org.cn/cloudream/storage-common/consts"
  9. "gitlink.org.cn/cloudream/storage-common/globals"
  10. "gitlink.org.cn/cloudream/storage-common/pkgs/db/model"
  11. "gitlink.org.cn/cloudream/storage-common/pkgs/distlock/reqbuilder"
  12. agtmq "gitlink.org.cn/cloudream/storage-common/pkgs/mq/agent"
  13. scevt "gitlink.org.cn/cloudream/storage-common/pkgs/mq/scanner/event"
  14. )
  15. type AgentCheckStorage struct {
  16. scevt.AgentCheckStorage
  17. }
  18. func NewAgentCheckStorage(storageID int64, packageIDs []int64) *AgentCheckStorage {
  19. return &AgentCheckStorage{
  20. AgentCheckStorage: scevt.NewAgentCheckStorage(storageID, packageIDs),
  21. }
  22. }
  23. func (t *AgentCheckStorage) TryMerge(other Event) bool {
  24. event, ok := other.(*AgentCheckStorage)
  25. if !ok {
  26. return false
  27. }
  28. if t.StorageID != event.StorageID {
  29. return false
  30. }
  31. // PackageIDs为nil时代表全量检查
  32. if event.PackageIDs == nil {
  33. t.PackageIDs = nil
  34. } else if t.PackageIDs != nil {
  35. t.PackageIDs = lo.Union(t.PackageIDs, event.PackageIDs)
  36. }
  37. return true
  38. }
  39. func (t *AgentCheckStorage) Execute(execCtx ExecuteContext) {
  40. log := logger.WithType[AgentCheckStorage]("Event")
  41. log.Debugf("begin with %v", logger.FormatStruct(t))
  42. defer log.Debugf("end")
  43. // 读取数据的地方就不加锁了,因为check任务会反复执行,单次失败问题不大
  44. stg, err := execCtx.Args.DB.Storage().GetByID(execCtx.Args.DB.SQLCtx(), t.StorageID)
  45. if err != nil {
  46. if err != sql.ErrNoRows {
  47. log.WithField("StorageID", t.StorageID).Warnf("get storage failed, err: %s", err.Error())
  48. }
  49. return
  50. }
  51. node, err := execCtx.Args.DB.Node().GetByID(execCtx.Args.DB.SQLCtx(), stg.NodeID)
  52. if err != nil {
  53. if err != sql.ErrNoRows {
  54. log.WithField("StorageID", t.StorageID).Warnf("get storage node failed, err: %s", err.Error())
  55. }
  56. return
  57. }
  58. // TODO unavailable的节点需不需要发送任务?
  59. if node.State != consts.NodeStateNormal {
  60. return
  61. }
  62. if t.PackageIDs == nil {
  63. t.checkComplete(execCtx, stg)
  64. } else {
  65. t.checkIncrement(execCtx, stg)
  66. }
  67. }
  68. func (t *AgentCheckStorage) checkComplete(execCtx ExecuteContext, stg model.Storage) {
  69. log := logger.WithType[AgentCheckStorage]("Event")
  70. mutex, err := reqbuilder.NewBuilder().
  71. Metadata().
  72. // 全量模式下查询、修改Move记录
  73. StoragePackage().WriteAny().
  74. Storage().
  75. // 全量模式下删除对象文件
  76. WriteAnyPackage(t.StorageID).
  77. MutexLock(execCtx.Args.DistLock)
  78. if err != nil {
  79. log.Warnf("acquire locks failed, err: %s", err.Error())
  80. return
  81. }
  82. defer mutex.Unlock()
  83. packages, err := execCtx.Args.DB.StoragePackage().GetAllByStorageID(execCtx.Args.DB.SQLCtx(), t.StorageID)
  84. if err != nil {
  85. log.WithField("StorageID", t.StorageID).Warnf("get storage packages failed, err: %s", err.Error())
  86. return
  87. }
  88. t.startCheck(execCtx, stg, true, packages)
  89. }
  90. func (t *AgentCheckStorage) checkIncrement(execCtx ExecuteContext, stg model.Storage) {
  91. log := logger.WithType[AgentCheckStorage]("Event")
  92. mutex, err := reqbuilder.NewBuilder().
  93. Metadata().
  94. // 全量模式下查询、修改Move记录。因为可能有多个User Move相同的文件,所以只能用集合Write锁
  95. StoragePackage().WriteAny().
  96. Storage().
  97. // 全量模式下删除对象文件。因为可能有多个User Move相同的文件,所以只能用集合Write锁
  98. WriteAnyPackage(t.StorageID).
  99. MutexLock(execCtx.Args.DistLock)
  100. if err != nil {
  101. log.Warnf("acquire locks failed, err: %s", err.Error())
  102. return
  103. }
  104. defer mutex.Unlock()
  105. var packages []model.StoragePackage
  106. for _, objID := range t.PackageIDs {
  107. objs, err := execCtx.Args.DB.StoragePackage().GetAllByStorageAndPackageID(execCtx.Args.DB.SQLCtx(), t.StorageID, objID)
  108. if err != nil {
  109. log.WithField("StorageID", t.StorageID).
  110. WithField("PackageID", objID).
  111. Warnf("get storage package failed, err: %s", err.Error())
  112. return
  113. }
  114. packages = append(packages, objs...)
  115. }
  116. t.startCheck(execCtx, stg, false, packages)
  117. }
  118. func (t *AgentCheckStorage) startCheck(execCtx ExecuteContext, stg model.Storage, isComplete bool, packages []model.StoragePackage) {
  119. log := logger.WithType[AgentCheckStorage]("Event")
  120. // 投递任务
  121. agentClient, err := globals.AgentMQPool.Acquire(stg.NodeID)
  122. if err != nil {
  123. log.WithField("NodeID", stg.NodeID).Warnf("create agent client failed, err: %s", err.Error())
  124. return
  125. }
  126. defer agentClient.Close()
  127. checkResp, err := agentClient.StorageCheck(agtmq.NewStorageCheck(stg.StorageID, stg.Directory, isComplete, packages), mq.RequestOption{Timeout: time.Minute})
  128. if err != nil {
  129. log.WithField("NodeID", stg.NodeID).Warnf("checking storage: %s", err.Error())
  130. return
  131. }
  132. // 根据返回结果修改数据库
  133. var chkObjIDs []int64
  134. for _, entry := range checkResp.Entries {
  135. switch entry.Operation {
  136. case agtmq.CHECK_STORAGE_RESP_OP_DELETE:
  137. err := execCtx.Args.DB.StoragePackage().Delete(execCtx.Args.DB.SQLCtx(), t.StorageID, entry.PackageID, entry.UserID)
  138. if err != nil {
  139. log.WithField("StorageID", t.StorageID).
  140. WithField("PackageID", entry.PackageID).
  141. Warnf("delete storage package failed, err: %s", err.Error())
  142. }
  143. chkObjIDs = append(chkObjIDs, entry.PackageID)
  144. log.WithField("StorageID", t.StorageID).
  145. WithField("PackageID", entry.PackageID).
  146. WithField("UserID", entry.UserID).
  147. Debugf("delete storage package")
  148. case agtmq.CHECK_STORAGE_RESP_OP_SET_NORMAL:
  149. err := execCtx.Args.DB.StoragePackage().SetStateNormal(execCtx.Args.DB.SQLCtx(), t.StorageID, entry.PackageID, entry.UserID)
  150. if err != nil {
  151. log.WithField("StorageID", t.StorageID).
  152. WithField("PackageID", entry.PackageID).
  153. Warnf("change storage package state failed, err: %s", err.Error())
  154. }
  155. log.WithField("StorageID", t.StorageID).
  156. WithField("PackageID", entry.PackageID).
  157. WithField("UserID", entry.UserID).
  158. Debugf("set storage package normal")
  159. }
  160. }
  161. if len(chkObjIDs) > 0 {
  162. execCtx.Executor.Post(NewCheckPackage(chkObjIDs))
  163. }
  164. }
  165. func init() {
  166. RegisterMessageConvertor(func(msg scevt.AgentCheckStorage) Event { return NewAgentCheckStorage(msg.StorageID, msg.PackageIDs) })
  167. }

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