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.

change_redundancy.go 5.5 kB

5 months ago
6 months ago
6 months ago
6 months ago
6 months ago
6 months ago
6 months ago
6 months ago
6 months ago
6 months ago
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219
  1. package ticktock
  2. import (
  3. "fmt"
  4. "time"
  5. "gitlink.org.cn/cloudream/common/pkgs/logger"
  6. "gitlink.org.cn/cloudream/common/utils/reflect2"
  7. "gitlink.org.cn/cloudream/jcs-pub/client/internal/db"
  8. "gitlink.org.cn/cloudream/jcs-pub/common/pkgs/publock"
  9. "gitlink.org.cn/cloudream/jcs-pub/common/pkgs/publock/reqbuilder"
  10. jcstypes "gitlink.org.cn/cloudream/jcs-pub/common/types"
  11. "gitlink.org.cn/cloudream/jcs-pub/common/types/datamap"
  12. )
  13. const (
  14. BatchGetPackageDetailCount = 100
  15. BatchGetObjectDetailCount = 1000
  16. )
  17. type ChangeRedundancy struct {
  18. }
  19. func (j *ChangeRedundancy) Name() string {
  20. return reflect2.TypeNameOf[ChangeRedundancy]()
  21. }
  22. func (j *ChangeRedundancy) Execute(t *TickTock) {
  23. log := logger.WithType[ChangeRedundancy]("TickTock")
  24. startTime := time.Now()
  25. log.Infof("job start")
  26. defer func() {
  27. log.Infof("job end, time: %v", time.Since(startTime))
  28. }()
  29. ctx := &changeRedundancyContext{
  30. ticktock: t,
  31. allUserSpaces: make(map[jcstypes.UserSpaceID]*userSpaceUsageInfo),
  32. }
  33. spaceIDs, err := t.db.UserSpace().GetAllIDs(t.db.DefCtx())
  34. if err != nil {
  35. log.Warnf("get user space ids: %v", err)
  36. return
  37. }
  38. spaces := t.spaceMeta.GetMany(spaceIDs)
  39. for _, space := range spaces {
  40. if space == nil {
  41. continue
  42. }
  43. ctx.allUserSpaces[space.UserSpace.UserSpaceID] = &userSpaceUsageInfo{
  44. UserSpace: space,
  45. }
  46. }
  47. if len(ctx.allUserSpaces) == 0 {
  48. log.Warnf("no user space found")
  49. return
  50. }
  51. lastPkgID := jcstypes.PackageID(0)
  52. loop:
  53. for {
  54. pkgIDs, err := db.DoTx21(t.db, t.db.Package().BatchGetIDPaged, lastPkgID, BatchGetPackageDetailCount)
  55. if err != nil {
  56. log.Warnf("get package ids: %v", err)
  57. return
  58. }
  59. if len(pkgIDs) == 0 {
  60. break
  61. }
  62. lastPkgID = pkgIDs[len(pkgIDs)-1]
  63. for _, id := range pkgIDs {
  64. // 如果执行超过两个小时,则停止
  65. if time.Since(startTime) > time.Hour*2 {
  66. break loop
  67. }
  68. lock, err := reqbuilder.NewBuilder().Package().Buzy(id).MutexLock(t.pubLock, publock.WithTimeout(time.Second*10))
  69. if err != nil {
  70. log.Warnf("lock package: %v", err)
  71. continue
  72. }
  73. detail, err := db.DoTx11(t.db, t.db.Package().GetDetail, id)
  74. if err != nil {
  75. log.Warnf("get package detail: %v", err)
  76. lock.Unlock()
  77. continue
  78. }
  79. if detail.Package.Pinned {
  80. lock.Unlock()
  81. continue
  82. }
  83. err = j.changeOne(ctx, detail)
  84. lock.Unlock()
  85. if err != nil {
  86. log.Warnf("change redundancy: %v", err)
  87. return
  88. }
  89. }
  90. }
  91. }
  92. type changeRedundancyContext struct {
  93. ticktock *TickTock
  94. allUserSpaces map[jcstypes.UserSpaceID]*userSpaceUsageInfo
  95. mostBlockStgIDs []jcstypes.UserSpaceID
  96. }
  97. type userSpaceUsageInfo struct {
  98. UserSpace *jcstypes.UserSpaceDetail
  99. AccessAmount float64
  100. }
  101. func (j *ChangeRedundancy) changeOne(ctx *changeRedundancyContext, pkg jcstypes.PackageDetail) error {
  102. log := logger.WithType[ChangeRedundancy]("TickTock")
  103. db2 := ctx.ticktock.db
  104. // allUserSpaces是复用的,所以需要先清空
  105. for _, space := range ctx.allUserSpaces {
  106. space.AccessAmount = 0
  107. }
  108. pkgAccessStats, err := db2.PackageAccessStat().GetByPackageID(db2.DefCtx(), pkg.Package.PackageID)
  109. if err != nil {
  110. return fmt.Errorf("get package access stats: %w", err)
  111. }
  112. for _, stat := range pkgAccessStats {
  113. info, ok := ctx.allUserSpaces[stat.UserSpaceID]
  114. if !ok {
  115. continue
  116. }
  117. info.AccessAmount = stat.Amount
  118. }
  119. lastObjID := jcstypes.ObjectID(0)
  120. for {
  121. objs, err := db.DoTx31(db2, db2.Object().BatchGetDetailsPaged, pkg.Package.PackageID, lastObjID, BatchGetObjectDetailCount)
  122. if err != nil {
  123. return fmt.Errorf("get object details: %w", err)
  124. }
  125. if len(objs) == 0 {
  126. break
  127. }
  128. lastObjID = objs[len(objs)-1].Object.ObjectID
  129. reen := ctx.ticktock.pubLock.BeginReentrant()
  130. var allUpdatings []db.UpdatingObjectRedundancy
  131. var allSysEvts []datamap.SysEventBody
  132. ctx.mostBlockStgIDs = j.summaryRepObjectBlockUserSpaces(ctx, objs, 2)
  133. var willShrinks []jcstypes.ObjectDetail
  134. for _, obj := range objs {
  135. newRed, selectedSpaces := j.chooseRedundancy(ctx, obj)
  136. // 冗余策略不需要调整,就检查是否需要收缩
  137. if newRed == nil {
  138. willShrinks = append(willShrinks, obj)
  139. continue
  140. }
  141. reqBlder := reqbuilder.NewBuilder()
  142. for _, space := range selectedSpaces {
  143. reqBlder.UserSpace().Buzy(space.UserSpace.UserSpace.UserSpaceID)
  144. }
  145. err := reen.Lock(reqBlder.Build())
  146. if err != nil {
  147. log.WithField("ObjectID", obj.Object.ObjectID).Warnf("acquire lock: %s", err.Error())
  148. continue
  149. }
  150. updating, evt, err := j.doChangeRedundancy(ctx, obj, newRed, selectedSpaces)
  151. if updating != nil {
  152. allUpdatings = append(allUpdatings, *updating)
  153. }
  154. if evt != nil {
  155. allSysEvts = append(allSysEvts, evt)
  156. }
  157. if err != nil {
  158. log.WithField("ObjectID", obj.Object.ObjectID).Warnf("%s, its redundancy wont be changed", err.Error())
  159. continue
  160. }
  161. }
  162. udpatings, sysEvts, err := j.doRedundancyShrink(ctx, pkg, willShrinks, reen)
  163. if err != nil {
  164. log.Warnf("redundancy shrink: %s", err.Error())
  165. } else {
  166. allUpdatings = append(allUpdatings, udpatings...)
  167. allSysEvts = append(allSysEvts, sysEvts...)
  168. }
  169. if len(allUpdatings) > 0 {
  170. err := db.DoTx10(db2, db2.Object().BatchUpdateRedundancy, allUpdatings)
  171. if err != nil {
  172. reen.Unlock()
  173. log.Warnf("update object redundancy: %s", err.Error())
  174. return err
  175. }
  176. }
  177. reen.Unlock()
  178. for _, e := range allSysEvts {
  179. ctx.ticktock.evtPub.Publish(e)
  180. }
  181. }
  182. return nil
  183. }

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