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 4.3 kB

2 years ago
2 years ago
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146
  1. package event
  2. import (
  3. "database/sql"
  4. "time"
  5. "github.com/jmoiron/sqlx"
  6. "gitlink.org.cn/cloudream/common/pkgs/logger"
  7. "gitlink.org.cn/cloudream/common/pkgs/mq"
  8. cdssdk "gitlink.org.cn/cloudream/common/sdks/storage"
  9. "gitlink.org.cn/cloudream/storage/common/consts"
  10. stgglb "gitlink.org.cn/cloudream/storage/common/globals"
  11. "gitlink.org.cn/cloudream/storage/common/pkgs/db/model"
  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. // AgentCheckStorage 代表一个用于检查存储代理的事件处理类。
  16. type AgentCheckStorage struct {
  17. *scevt.AgentCheckStorage
  18. }
  19. // NewAgentCheckStorage 创建并返回一个初始化的 AgentCheckStorage 实例。
  20. func NewAgentCheckStorage(evt *scevt.AgentCheckStorage) *AgentCheckStorage {
  21. return &AgentCheckStorage{
  22. AgentCheckStorage: evt,
  23. }
  24. }
  25. // TryMerge 尝试合并当前事件与另一个事件。仅当两个事件具有相同的 StorageID 时才能合并。
  26. func (t *AgentCheckStorage) TryMerge(other Event) bool {
  27. event, ok := other.(*AgentCheckStorage)
  28. if !ok {
  29. return false
  30. }
  31. if t.StorageID != event.StorageID {
  32. return false
  33. }
  34. return true
  35. }
  36. // Execute 执行存储检查事件。此方法会与存储节点通信,校验存储状态并根据校验结果更新数据库。
  37. func (t *AgentCheckStorage) Execute(execCtx ExecuteContext) {
  38. log := logger.WithType[AgentCheckStorage]("Event")
  39. log.Debugf("begin with %v", logger.FormatStruct(t.AgentCheckStorage))
  40. defer log.Debugf("end")
  41. // 从数据库中获取存储和关联的节点信息
  42. stg, err := execCtx.Args.DB.Storage().GetByID(execCtx.Args.DB.SQLCtx(), t.StorageID)
  43. if err != nil {
  44. if err != sql.ErrNoRows {
  45. log.WithField("StorageID", t.StorageID).Warnf("get storage failed, err: %s", err.Error())
  46. }
  47. return
  48. }
  49. node, err := execCtx.Args.DB.Node().GetByID(execCtx.Args.DB.SQLCtx(), stg.NodeID)
  50. if err != nil {
  51. if err != sql.ErrNoRows {
  52. log.WithField("StorageID", t.StorageID).Warnf("get storage node failed, err: %s", err.Error())
  53. }
  54. return
  55. }
  56. // 节点状态不正常时,直接返回
  57. if node.State != consts.NodeStateNormal {
  58. return
  59. }
  60. // 获取与存储节点通信的代理客户端
  61. agtCli, err := stgglb.AgentMQPool.Acquire(stg.NodeID)
  62. if err != nil {
  63. log.WithField("NodeID", stg.NodeID).Warnf("create agent client failed, err: %s", err.Error())
  64. return
  65. }
  66. defer stgglb.AgentMQPool.Release(agtCli)
  67. // 向存储节点发送检查请求并处理响应
  68. checkResp, err := agtCli.StorageCheck(agtmq.NewStorageCheck(stg.StorageID, stg.Directory), mq.RequestOption{Timeout: time.Minute})
  69. if err != nil {
  70. log.WithField("NodeID", stg.NodeID).Warnf("checking storage: %s", err.Error())
  71. return
  72. }
  73. // 根据检查响应,整理出实际存在的包裹信息
  74. realPkgs := make(map[cdssdk.UserID]map[cdssdk.PackageID]bool)
  75. for _, pkg := range checkResp.Packages {
  76. pkgs, ok := realPkgs[pkg.UserID]
  77. if !ok {
  78. pkgs = make(map[cdssdk.PackageID]bool)
  79. realPkgs[pkg.UserID] = pkgs
  80. }
  81. pkgs[pkg.PackageID] = true
  82. }
  83. // 在事务中更新数据库,删除不存在的包裹信息
  84. execCtx.Args.DB.DoTx(sql.LevelSerializable, func(tx *sqlx.Tx) error {
  85. packages, err := execCtx.Args.DB.StoragePackage().GetAllByStorageID(tx, t.StorageID)
  86. if err != nil {
  87. log.Warnf("getting storage package: %s", err.Error())
  88. return nil
  89. }
  90. var rms []model.StoragePackage
  91. for _, pkg := range packages {
  92. pkgMap, ok := realPkgs[pkg.UserID]
  93. if !ok {
  94. rms = append(rms, pkg)
  95. continue
  96. }
  97. if !pkgMap[pkg.PackageID] {
  98. rms = append(rms, pkg)
  99. }
  100. }
  101. rmdPkgIDs := make(map[cdssdk.PackageID]bool)
  102. for _, rm := range rms {
  103. err := execCtx.Args.DB.StoragePackage().Delete(tx, rm.StorageID, rm.PackageID, rm.UserID)
  104. if err != nil {
  105. log.Warnf("deleting storage package: %s", err.Error())
  106. continue
  107. }
  108. rmdPkgIDs[rm.PackageID] = true
  109. }
  110. // 删除不再被引用的包裹
  111. for pkgID := range rmdPkgIDs {
  112. err := execCtx.Args.DB.Package().DeleteUnused(tx, pkgID)
  113. if err != nil {
  114. log.Warnf("deleting unused package: %s", err.Error())
  115. continue
  116. }
  117. }
  118. return nil
  119. })
  120. }
  121. // init 注册 AgentCheckStorage 事件处理器,使其能够响应相应的消息。
  122. func init() {
  123. RegisterMessageConvertor(NewAgentCheckStorage)
  124. }

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