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.go 3.9 kB

7 months ago
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154
  1. package uploader
  2. import (
  3. "context"
  4. "fmt"
  5. "io"
  6. "path"
  7. "sync"
  8. "time"
  9. "github.com/samber/lo"
  10. "gitlink.org.cn/cloudream/common/pkgs/ioswitch/exec"
  11. cdssdk "gitlink.org.cn/cloudream/common/sdks/storage"
  12. stgglb "gitlink.org.cn/cloudream/storage2/common/globals"
  13. stgmod "gitlink.org.cn/cloudream/storage2/common/models"
  14. "gitlink.org.cn/cloudream/storage2/common/pkgs/distlock"
  15. "gitlink.org.cn/cloudream/storage2/common/pkgs/ioswitch2"
  16. "gitlink.org.cn/cloudream/storage2/common/pkgs/ioswitch2/ops2"
  17. "gitlink.org.cn/cloudream/storage2/common/pkgs/ioswitch2/parser"
  18. coormq "gitlink.org.cn/cloudream/storage2/common/pkgs/mq/coordinator"
  19. )
  20. type UpdateUploader struct {
  21. uploader *Uploader
  22. pkgID cdssdk.PackageID
  23. targetStg stgmod.StorageDetail
  24. distMutex *distlock.Mutex
  25. loadToStgs []stgmod.StorageDetail
  26. loadToPath []string
  27. successes []coormq.AddObjectEntry
  28. lock sync.Mutex
  29. commited bool
  30. }
  31. type UploadStorageInfo struct {
  32. Storage stgmod.StorageDetail
  33. Delay time.Duration
  34. IsSameLocation bool
  35. }
  36. type UpdateResult struct {
  37. // 上传成功的文件列表,Key为Path
  38. Objects map[string]cdssdk.Object
  39. }
  40. func (w *UpdateUploader) Upload(pat string, stream io.Reader) error {
  41. uploadTime := time.Now()
  42. ft := ioswitch2.NewFromTo()
  43. fromExec, hd := ioswitch2.NewFromDriver(ioswitch2.RawStream())
  44. ft.AddFrom(fromExec).
  45. AddTo(ioswitch2.NewToShardStore(*w.targetStg.MasterHub, w.targetStg, ioswitch2.RawStream(), "shardInfo"))
  46. for i, stg := range w.loadToStgs {
  47. ft.AddTo(ioswitch2.NewLoadToPublic(*stg.MasterHub, stg, path.Join(w.loadToPath[i], pat)))
  48. }
  49. plans := exec.NewPlanBuilder()
  50. err := parser.Parse(ft, plans)
  51. if err != nil {
  52. return fmt.Errorf("parsing plan: %w", err)
  53. }
  54. exeCtx := exec.NewExecContext()
  55. exec.SetValueByType(exeCtx, w.uploader.stgAgts)
  56. exec := plans.Execute(exeCtx)
  57. exec.BeginWrite(io.NopCloser(stream), hd)
  58. ret, err := exec.Wait(context.TODO())
  59. if err != nil {
  60. return fmt.Errorf("executing plan: %w", err)
  61. }
  62. w.lock.Lock()
  63. defer w.lock.Unlock()
  64. // 记录上传结果
  65. shardInfo := ret["shardInfo"].(*ops2.ShardInfoValue)
  66. w.successes = append(w.successes, coormq.AddObjectEntry{
  67. Path: pat,
  68. Size: shardInfo.Size,
  69. FileHash: shardInfo.Hash,
  70. UploadTime: uploadTime,
  71. StorageIDs: []cdssdk.StorageID{w.targetStg.Storage.StorageID},
  72. })
  73. return nil
  74. }
  75. // 取消上传对象。必须在对象调用了Upload之后调用。
  76. func (w *UpdateUploader) CancelObject(path string) {
  77. w.lock.Lock()
  78. defer w.lock.Unlock()
  79. w.successes = lo.Reject(w.successes, func(e coormq.AddObjectEntry, i int) bool {
  80. return e.Path == path
  81. })
  82. }
  83. // 重命名对象。必须在对象调用了Upload之后调用。不会检查新路径是否已经存在,需由调用方去做保证。
  84. func (w *UpdateUploader) RenameObject(path string, newPath string) {
  85. w.lock.Lock()
  86. defer w.lock.Unlock()
  87. for i := range w.successes {
  88. if w.successes[i].Path == path {
  89. w.successes[i].Path = newPath
  90. break
  91. }
  92. }
  93. }
  94. func (w *UpdateUploader) Commit() (UpdateResult, error) {
  95. w.lock.Lock()
  96. defer w.lock.Unlock()
  97. if w.commited {
  98. return UpdateResult{}, fmt.Errorf("package already commited")
  99. }
  100. w.commited = true
  101. defer w.distMutex.Unlock()
  102. coorCli, err := stgglb.CoordinatorMQPool.Acquire()
  103. if err != nil {
  104. return UpdateResult{}, fmt.Errorf("new coordinator client: %w", err)
  105. }
  106. defer stgglb.CoordinatorMQPool.Release(coorCli)
  107. updateResp, err := coorCli.UpdatePackage(coormq.NewUpdatePackage(w.pkgID, w.successes))
  108. if err != nil {
  109. return UpdateResult{}, fmt.Errorf("updating package: %w", err)
  110. }
  111. ret := UpdateResult{
  112. Objects: make(map[string]cdssdk.Object),
  113. }
  114. for _, entry := range updateResp.Added {
  115. ret.Objects[entry.Path] = entry
  116. }
  117. return ret, nil
  118. }
  119. func (w *UpdateUploader) Abort() {
  120. w.lock.Lock()
  121. defer w.lock.Unlock()
  122. if w.commited {
  123. return
  124. }
  125. w.commited = true
  126. w.distMutex.Unlock()
  127. }

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