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.

update_rep_package.go 3.7 kB

2 years ago
2 years ago
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128
  1. package cmd
  2. import (
  3. "fmt"
  4. "github.com/samber/lo"
  5. mysort "gitlink.org.cn/cloudream/common/utils/sort"
  6. "gitlink.org.cn/cloudream/storage/common/pkgs/distlock/reqbuilder"
  7. stgglb "gitlink.org.cn/cloudream/storage/common/globals"
  8. "gitlink.org.cn/cloudream/storage/common/pkgs/db/model"
  9. "gitlink.org.cn/cloudream/storage/common/pkgs/iterator"
  10. coormq "gitlink.org.cn/cloudream/storage/common/pkgs/mq/coordinator"
  11. )
  12. type UpdateRepPackage struct {
  13. userID int64
  14. packageID int64
  15. objectIter iterator.UploadingObjectIterator
  16. }
  17. type UpdateNodeInfo struct {
  18. UploadNodeInfo
  19. HasOldObject bool
  20. }
  21. type UpdateRepPackageResult struct {
  22. ObjectResults []RepObjectUploadResult
  23. }
  24. func NewUpdateRepPackage(userID int64, packageID int64, objectIter iterator.UploadingObjectIterator) *UpdateRepPackage {
  25. return &UpdateRepPackage{
  26. userID: userID,
  27. packageID: packageID,
  28. objectIter: objectIter,
  29. }
  30. }
  31. func (t *UpdateRepPackage) Execute(ctx *UpdatePackageContext) (*UpdateRepPackageResult, error) {
  32. defer t.objectIter.Close()
  33. coorCli, err := stgglb.CoordinatorMQPool.Acquire()
  34. if err != nil {
  35. return nil, fmt.Errorf("new coordinator client: %w", err)
  36. }
  37. reqBlder := reqbuilder.NewBuilder()
  38. // 如果本地的IPFS也是存储系统的一个节点,那么从本地上传时,需要加锁
  39. if stgglb.Local.NodeID != nil {
  40. reqBlder.IPFS().CreateAnyRep(*stgglb.Local.NodeID)
  41. }
  42. mutex, err := reqBlder.
  43. Metadata().
  44. // 用于查询可用的上传节点
  45. Node().ReadAny().
  46. // 用于创建包信息
  47. Package().WriteOne(t.packageID).
  48. // 用于创建包中的文件的信息
  49. Object().CreateAny().
  50. // 用于设置EC配置
  51. ObjectBlock().CreateAny().
  52. // 用于创建Cache记录
  53. Cache().CreateAny().
  54. MutexLock(ctx.Distlock)
  55. if err != nil {
  56. return nil, fmt.Errorf("acquire locks failed, err: %w", err)
  57. }
  58. defer mutex.Unlock()
  59. getUserNodesResp, err := coorCli.GetUserNodes(coormq.NewGetUserNodes(t.userID))
  60. if err != nil {
  61. return nil, fmt.Errorf("getting user nodes: %w", err)
  62. }
  63. findCliLocResp, err := coorCli.FindClientLocation(coormq.NewFindClientLocation(stgglb.Local.ExternalIP))
  64. if err != nil {
  65. return nil, fmt.Errorf("finding client location: %w", err)
  66. }
  67. nodeInfos := lo.Map(getUserNodesResp.Nodes, func(node model.Node, index int) UpdateNodeInfo {
  68. return UpdateNodeInfo{
  69. UploadNodeInfo: UploadNodeInfo{
  70. Node: node,
  71. IsSameLocation: node.LocationID == findCliLocResp.Location.LocationID,
  72. },
  73. }
  74. })
  75. // 上传文件的方式优先级:
  76. // 1. 本地IPFS
  77. // 2. 包含了旧文件,且与客户端在同地域的节点
  78. // 3. 不在同地域,但包含了旧文件的节点
  79. // 4. 同地域节点
  80. // TODO 需要考虑在多文件的情况下的规则
  81. uploadNode := t.chooseUploadNode(nodeInfos)
  82. // 防止上传的副本被清除
  83. ipfsMutex, err := reqbuilder.NewBuilder().
  84. IPFS().CreateAnyRep(uploadNode.Node.NodeID).
  85. MutexLock(ctx.Distlock)
  86. if err != nil {
  87. return nil, fmt.Errorf("acquire locks failed, err: %w", err)
  88. }
  89. defer ipfsMutex.Unlock()
  90. rets, err := uploadAndUpdateRepPackage(t.packageID, t.objectIter, uploadNode.UploadNodeInfo)
  91. if err != nil {
  92. return nil, err
  93. }
  94. return &UpdateRepPackageResult{
  95. ObjectResults: rets,
  96. }, nil
  97. }
  98. // chooseUploadNode 选择一个上传文件的节点
  99. // 1. 从与当前客户端相同地域的节点中随机选一个
  100. // 2. 没有用的话从所有节点中随机选一个
  101. func (t *UpdateRepPackage) chooseUploadNode(nodes []UpdateNodeInfo) UpdateNodeInfo {
  102. mysort.Sort(nodes, func(left, right UpdateNodeInfo) int {
  103. v := -mysort.CmpBool(left.HasOldObject, right.HasOldObject)
  104. if v != 0 {
  105. return v
  106. }
  107. return -mysort.CmpBool(left.IsSameLocation, right.IsSameLocation)
  108. })
  109. return nodes[0]
  110. }

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