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_cache.go 4.8 kB

2 years ago
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172
  1. package event
  2. import (
  3. "database/sql"
  4. "time"
  5. "github.com/jmoiron/sqlx"
  6. "github.com/samber/lo"
  7. "gitlink.org.cn/cloudream/common/pkgs/logger"
  8. "gitlink.org.cn/cloudream/common/pkgs/mq"
  9. cdssdk "gitlink.org.cn/cloudream/common/sdks/storage"
  10. stgglb "gitlink.org.cn/cloudream/storage/common/globals"
  11. agtmq "gitlink.org.cn/cloudream/storage/common/pkgs/mq/agent"
  12. scevt "gitlink.org.cn/cloudream/storage/common/pkgs/mq/scanner/event"
  13. )
  14. type AgentCheckCache struct {
  15. *scevt.AgentCheckCache
  16. }
  17. func NewAgentCheckCache(evt *scevt.AgentCheckCache) *AgentCheckCache {
  18. return &AgentCheckCache{
  19. AgentCheckCache: evt,
  20. }
  21. }
  22. func (t *AgentCheckCache) TryMerge(other Event) bool {
  23. event, ok := other.(*AgentCheckCache)
  24. if !ok {
  25. return false
  26. }
  27. if event.NodeID != t.NodeID {
  28. return false
  29. }
  30. return true
  31. }
  32. func (t *AgentCheckCache) Execute(execCtx ExecuteContext) {
  33. log := logger.WithType[AgentCheckCache]("Event")
  34. startTime := time.Now()
  35. log.Debugf("begin with %v", logger.FormatStruct(t.AgentCheckCache))
  36. defer func() {
  37. log.Debugf("end, time: %v", time.Since(startTime))
  38. }()
  39. // TODO unavailable的节点需不需要发送任务?
  40. agtCli, err := stgglb.AgentMQPool.Acquire(t.NodeID)
  41. if err != nil {
  42. log.WithField("NodeID", t.NodeID).Warnf("create agent client failed, err: %s", err.Error())
  43. return
  44. }
  45. defer stgglb.AgentMQPool.Release(agtCli)
  46. checkResp, err := agtCli.CheckCache(agtmq.NewCheckCache(), mq.RequestOption{Timeout: time.Minute})
  47. if err != nil {
  48. log.WithField("NodeID", t.NodeID).Warnf("checking ipfs: %s", err.Error())
  49. return
  50. }
  51. realFileHashes := lo.SliceToMap(checkResp.FileHashes, func(hash string) (string, bool) { return hash, true })
  52. // 根据IPFS中实际文件情况修改元数据。修改过程中的失败均忽略。(但关联修改需要原子性)
  53. execCtx.Args.DB.DoTx(sql.LevelSerializable, func(tx *sqlx.Tx) error {
  54. t.checkCache(execCtx, tx, realFileHashes)
  55. t.checkPinnedObject(execCtx, tx, realFileHashes)
  56. t.checkObjectBlock(execCtx, tx, realFileHashes)
  57. return nil
  58. })
  59. }
  60. // 对比Cache表中的记录,多了增加,少了删除
  61. func (t *AgentCheckCache) checkCache(execCtx ExecuteContext, tx *sqlx.Tx, realFileHashes map[string]bool) {
  62. log := logger.WithType[AgentCheckCache]("Event")
  63. caches, err := execCtx.Args.DB.Cache().GetByNodeID(tx, t.NodeID)
  64. if err != nil {
  65. log.WithField("NodeID", t.NodeID).Warnf("getting caches by node id: %s", err.Error())
  66. return
  67. }
  68. realFileHashesCp := make(map[string]bool)
  69. for k, v := range realFileHashes {
  70. realFileHashesCp[k] = v
  71. }
  72. var rms []string
  73. for _, c := range caches {
  74. if realFileHashesCp[c.FileHash] {
  75. // Cache表使用FileHash和NodeID作为主键,
  76. // 所以通过同一个NodeID查询的结果不会存在两条相同FileHash的情况
  77. delete(realFileHashesCp, c.FileHash)
  78. continue
  79. }
  80. rms = append(rms, c.FileHash)
  81. }
  82. if len(rms) > 0 {
  83. err = execCtx.Args.DB.Cache().NodeBatchDelete(tx, t.NodeID, rms)
  84. if err != nil {
  85. log.Warnf("batch delete node caches: %w", err.Error())
  86. }
  87. }
  88. if len(realFileHashesCp) > 0 {
  89. err = execCtx.Args.DB.Cache().BatchCreateOnSameNode(tx, lo.Keys(realFileHashesCp), t.NodeID, 0)
  90. if err != nil {
  91. log.Warnf("batch create node caches: %w", err)
  92. return
  93. }
  94. }
  95. }
  96. // 对比PinnedObject表,多了不变,少了删除
  97. func (t *AgentCheckCache) checkPinnedObject(execCtx ExecuteContext, tx *sqlx.Tx, realFileHashes map[string]bool) {
  98. log := logger.WithType[AgentCheckCache]("Event")
  99. objs, err := execCtx.Args.DB.PinnedObject().GetObjectsByNodeID(tx, t.NodeID)
  100. if err != nil {
  101. log.WithField("NodeID", t.NodeID).Warnf("getting pinned objects by node id: %s", err.Error())
  102. return
  103. }
  104. var rms []cdssdk.ObjectID
  105. for _, c := range objs {
  106. if realFileHashes[c.FileHash] {
  107. continue
  108. }
  109. rms = append(rms, c.ObjectID)
  110. }
  111. if len(rms) > 0 {
  112. err = execCtx.Args.DB.PinnedObject().NodeBatchDelete(tx, t.NodeID, rms)
  113. if err != nil {
  114. log.Warnf("batch delete node pinned objects: %s", err.Error())
  115. }
  116. }
  117. }
  118. // 对比ObjectBlock表,多了不变,少了删除
  119. func (t *AgentCheckCache) checkObjectBlock(execCtx ExecuteContext, tx *sqlx.Tx, realFileHashes map[string]bool) {
  120. log := logger.WithType[AgentCheckCache]("Event")
  121. blocks, err := execCtx.Args.DB.ObjectBlock().GetByNodeID(tx, t.NodeID)
  122. if err != nil {
  123. log.WithField("NodeID", t.NodeID).Warnf("getting object blocks by node id: %s", err.Error())
  124. return
  125. }
  126. var rms []string
  127. for _, b := range blocks {
  128. if realFileHashes[b.FileHash] {
  129. continue
  130. }
  131. rms = append(rms, b.FileHash)
  132. }
  133. if len(rms) > 0 {
  134. err = execCtx.Args.DB.ObjectBlock().NodeBatchDelete(tx, t.NodeID, rms)
  135. if err != nil {
  136. log.Warnf("batch delete node object blocks: %s", err.Error())
  137. }
  138. }
  139. }
  140. func init() {
  141. RegisterMessageConvertor(NewAgentCheckCache)
  142. }

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