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.

execute_full.go 4.0 kB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159
  1. package spacesyncer
  2. import (
  3. "context"
  4. "fmt"
  5. "io"
  6. "time"
  7. "gitlink.org.cn/cloudream/common/pkgs/ioswitch/exec"
  8. "gitlink.org.cn/cloudream/common/pkgs/logger"
  9. "gitlink.org.cn/cloudream/common/pkgs/trie"
  10. "gitlink.org.cn/cloudream/jcs-pub/client/types"
  11. "gitlink.org.cn/cloudream/jcs-pub/common/pkgs/ioswitch2"
  12. "gitlink.org.cn/cloudream/jcs-pub/common/pkgs/ioswitch2/parser"
  13. stgtypes "gitlink.org.cn/cloudream/jcs-pub/common/pkgs/storage/types"
  14. )
  15. func executeFull(syncer *SpaceSyncer, task *task) {
  16. log := logger.WithField("Mod", logMod).WithField("TaskID", task.Task.TaskID)
  17. startTime := time.Now()
  18. log.Infof("begin full sync task")
  19. defer func() {
  20. log.Infof("full sync task finished, time: %v", time.Since(startTime))
  21. }()
  22. srcSpace := syncer.spaceMeta.Get(task.Task.SrcUserSpaceID)
  23. if srcSpace == nil {
  24. log.Warnf("src space %v not found", task.Task.SrcUserSpaceID)
  25. return
  26. }
  27. dstSpaceIDs := make([]types.UserSpaceID, len(task.Task.Dests))
  28. for i := range task.Task.Dests {
  29. dstSpaceIDs[i] = task.Task.Dests[i].DestUserSpaceID
  30. }
  31. dstSpaces := syncer.spaceMeta.GetMany(dstSpaceIDs)
  32. for i := range dstSpaces {
  33. if dstSpaces[i] == nil {
  34. log.Warnf("dst space %v not found", dstSpaceIDs[i])
  35. return
  36. }
  37. }
  38. srcBase, err := syncer.stgPool.GetBaseStore(srcSpace)
  39. if err != nil {
  40. log.Warnf("get src base store: %v", err)
  41. return
  42. }
  43. filter := buildFilter(task)
  44. srcDirReader := srcBase.ReadDir(task.Task.SrcPath)
  45. defer srcDirReader.Close()
  46. srcDirTree := trie.NewTrie[*stgtypes.DirEntry]()
  47. fileCnt := 0
  48. for {
  49. isEOF := false
  50. ft := ioswitch2.NewFromTo()
  51. cnt := 0
  52. for {
  53. e, err := srcDirReader.Next()
  54. if err == io.EOF {
  55. isEOF = true
  56. break
  57. }
  58. if err != nil {
  59. log.Warnf("read src dir: %v", err)
  60. return
  61. }
  62. rela := e.Path.Clone()
  63. rela.DropFrontN(task.Task.SrcPath.Len())
  64. ne := e
  65. ne.Path = rela.Clone()
  66. if !filter(ne) {
  67. continue
  68. }
  69. if e.IsDir {
  70. // 如果是一个目录,则创建对应的Dir节点,且在创建过程中清除掉路径上的Dir信息(仅保留最后一个Dir节点)
  71. createDirNode(srcDirTree, rela.Comps(), &e)
  72. continue
  73. }
  74. fmt.Printf("rela: %v\n", rela)
  75. // 如果是一个文件,那么它路径上的目录都可以在写入时一并创建,所以可以清理掉路径上的Dir节点
  76. removeDirNode(srcDirTree, rela.Comps())
  77. ft.AddFrom(ioswitch2.NewFromBaseStore(*srcSpace, e.Path))
  78. for i, dst := range dstSpaces {
  79. dstPath := task.Task.Dests[i].DestPath.Clone()
  80. dstPath.Concat(rela)
  81. ft.AddTo(ioswitch2.NewToBaseStore(*dst, dstPath))
  82. }
  83. cnt++
  84. fileCnt++
  85. // 每一批转发50个文件
  86. if cnt > 50 {
  87. break
  88. }
  89. }
  90. if len(ft.Froms) > 0 {
  91. planBld := exec.NewPlanBuilder()
  92. err := parser.Parse(ft, planBld)
  93. if err != nil {
  94. log.Warnf("parse fromto to plan: %v", err)
  95. return
  96. }
  97. execCtx := exec.NewWithContext(task.Context)
  98. exec.SetValueByType(execCtx, syncer.stgPool)
  99. _, err = planBld.Execute(execCtx).Wait(context.Background())
  100. if err != nil {
  101. log.Warnf("execute plan: %v", err)
  102. return
  103. }
  104. }
  105. if isEOF {
  106. break
  107. }
  108. }
  109. log.Infof("%v files synced", fileCnt)
  110. if !task.Task.Options.NoEmptyDirectories {
  111. dstBases := make([]stgtypes.BaseStore, len(dstSpaces))
  112. for i := range dstSpaces {
  113. dstBases[i], err = syncer.stgPool.GetBaseStore(dstSpaces[i])
  114. if err != nil {
  115. log.Warnf("get dst base store: %v", err)
  116. continue
  117. }
  118. }
  119. srcDirTree.Iterate(func(path []string, node *trie.Node[*stgtypes.DirEntry], isWordNode bool) trie.VisitCtrl {
  120. if node.Value == nil {
  121. return trie.VisitContinue
  122. }
  123. for i, base := range dstBases {
  124. if base != nil {
  125. dirPath := task.Task.Dests[i].DestPath.Clone()
  126. dirPath.ConcatComps(path)
  127. err := base.Mkdir(dirPath)
  128. if err != nil {
  129. log.Warnf("mkdir %v at user space %v: %v", dirPath, dstSpaces[i].String(), err)
  130. }
  131. }
  132. }
  133. return trie.VisitContinue
  134. })
  135. }
  136. }

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