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.

generator.go 7.4 kB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299
  1. package parser
  2. import (
  3. "fmt"
  4. "gitlink.org.cn/cloudream/common/pkgs/ioswitch/dag"
  5. "gitlink.org.cn/cloudream/common/pkgs/ioswitch/exec"
  6. "gitlink.org.cn/cloudream/common/pkgs/ioswitch/plan"
  7. cdssdk "gitlink.org.cn/cloudream/common/sdks/storage"
  8. "gitlink.org.cn/cloudream/storage/common/pkgs/ioswitchlrc"
  9. "gitlink.org.cn/cloudream/storage/common/pkgs/ioswitchlrc/ops2"
  10. )
  11. type GenerateContext struct {
  12. LRC cdssdk.LRCRedundancy
  13. DAG *ops2.GraphNodeBuilder
  14. To []ioswitchlrc.To
  15. ToNodes map[ioswitchlrc.To]ops2.ToNode
  16. StreamRange exec.Range
  17. }
  18. // 输入一个完整文件,从这个完整文件产生任意文件块(也可再产生完整文件)。
  19. func Encode(fr ioswitchlrc.From, toes []ioswitchlrc.To, blder *exec.PlanBuilder) error {
  20. if fr.GetDataIndex() != -1 {
  21. return fmt.Errorf("from data is not a complete file")
  22. }
  23. ctx := GenerateContext{
  24. LRC: cdssdk.DefaultLRCRedundancy,
  25. DAG: ops2.NewGraphNodeBuilder(),
  26. To: toes,
  27. ToNodes: make(map[ioswitchlrc.To]ops2.ToNode),
  28. }
  29. calcStreamRange(&ctx)
  30. err := buildDAGEncode(&ctx, fr, toes)
  31. if err != nil {
  32. return err
  33. }
  34. // 确定指令执行位置的过程,也需要反复进行,直到没有变化为止。
  35. for pin(&ctx) {
  36. }
  37. // 下面这些只需要执行一次,但需要按顺序
  38. dropUnused(&ctx)
  39. storeIPFSWriteResult(&ctx)
  40. generateClone(&ctx)
  41. generateRange(&ctx)
  42. return plan.Generate(ctx.DAG.Graph, blder)
  43. }
  44. func buildDAGEncode(ctx *GenerateContext, fr ioswitchlrc.From, toes []ioswitchlrc.To) error {
  45. frNode, err := buildFromNode(ctx, fr)
  46. if err != nil {
  47. return fmt.Errorf("building from node: %w", err)
  48. }
  49. var dataToes []ioswitchlrc.To
  50. var parityToes []ioswitchlrc.To
  51. // 先创建需要完整文件的To节点,同时统计一下需要哪些文件块
  52. for _, to := range toes {
  53. idx := to.GetDataIndex()
  54. if idx == -1 {
  55. toNode, err := buildToNode(ctx, to)
  56. if err != nil {
  57. return fmt.Errorf("building to node: %w", err)
  58. }
  59. ctx.ToNodes[to] = toNode
  60. toNode.SetInput(frNode.Output().Var)
  61. } else if idx < ctx.LRC.K {
  62. dataToes = append(dataToes, to)
  63. } else {
  64. parityToes = append(parityToes, to)
  65. }
  66. }
  67. if len(dataToes) == 0 && len(parityToes) == 0 {
  68. return nil
  69. }
  70. // 需要文件块,则生成Split指令
  71. splitNode := ctx.DAG.NewChunkedSplit(ctx.LRC.ChunkSize)
  72. splitNode.Split(frNode.Output().Var, ctx.LRC.K)
  73. for _, to := range dataToes {
  74. toNode, err := buildToNode(ctx, to)
  75. if err != nil {
  76. return fmt.Errorf("building to node: %w", err)
  77. }
  78. ctx.ToNodes[to] = toNode
  79. toNode.SetInput(splitNode.SubStream(to.GetDataIndex()))
  80. }
  81. if len(parityToes) == 0 {
  82. return nil
  83. }
  84. // 需要校验块,则进一步生成Construct指令
  85. conType := ctx.DAG.NewLRCConstructAny(ctx.LRC)
  86. for i, out := range splitNode.OutputStreams().RawArray() {
  87. conType.AddInput(out, i)
  88. }
  89. for _, to := range parityToes {
  90. toNode, err := buildToNode(ctx, to)
  91. if err != nil {
  92. return fmt.Errorf("building to node: %w", err)
  93. }
  94. ctx.ToNodes[to] = toNode
  95. toNode.SetInput(conType.NewOutput(to.GetDataIndex()))
  96. }
  97. return nil
  98. }
  99. // 提供数据块+编码块中的k个块,重建任意块,包括完整文件。
  100. func ReconstructAny(frs []ioswitchlrc.From, toes []ioswitchlrc.To, blder *exec.PlanBuilder) error {
  101. ctx := GenerateContext{
  102. LRC: cdssdk.DefaultLRCRedundancy,
  103. DAG: ops2.NewGraphNodeBuilder(),
  104. To: toes,
  105. ToNodes: make(map[ioswitchlrc.To]ops2.ToNode),
  106. }
  107. calcStreamRange(&ctx)
  108. err := buildDAGReconstructAny(&ctx, frs, toes)
  109. if err != nil {
  110. return err
  111. }
  112. // 确定指令执行位置的过程,也需要反复进行,直到没有变化为止。
  113. for pin(&ctx) {
  114. }
  115. // 下面这些只需要执行一次,但需要按顺序
  116. dropUnused(&ctx)
  117. storeIPFSWriteResult(&ctx)
  118. generateClone(&ctx)
  119. generateRange(&ctx)
  120. return plan.Generate(ctx.DAG.Graph, blder)
  121. }
  122. func buildDAGReconstructAny(ctx *GenerateContext, frs []ioswitchlrc.From, toes []ioswitchlrc.To) error {
  123. frNodes := make(map[int]ops2.FromNode)
  124. for _, fr := range frs {
  125. frNode, err := buildFromNode(ctx, fr)
  126. if err != nil {
  127. return fmt.Errorf("building from node: %w", err)
  128. }
  129. frNodes[fr.GetDataIndex()] = frNode
  130. }
  131. var completeToes []ioswitchlrc.To
  132. var missedToes []ioswitchlrc.To
  133. // 先创建需要完整文件的To节点,同时统计一下需要哪些文件块
  134. for _, to := range toes {
  135. toIdx := to.GetDataIndex()
  136. fr := frNodes[toIdx]
  137. if fr != nil {
  138. toNode, err := buildToNode(ctx, to)
  139. if err != nil {
  140. return fmt.Errorf("building to node: %w", err)
  141. }
  142. ctx.ToNodes[to] = toNode
  143. toNode.SetInput(fr.Output().Var)
  144. continue
  145. }
  146. if toIdx == -1 {
  147. completeToes = append(completeToes, to)
  148. } else {
  149. missedToes = append(missedToes, to)
  150. }
  151. }
  152. if len(completeToes) == 0 && len(missedToes) == 0 {
  153. return nil
  154. }
  155. // 生成Construct指令来恢复缺少的块
  156. conNode := ctx.DAG.NewLRCConstructAny(ctx.LRC)
  157. for i, fr := range frNodes {
  158. conNode.AddInput(fr.Output().Var, i)
  159. }
  160. for _, to := range missedToes {
  161. toNode, err := buildToNode(ctx, to)
  162. if err != nil {
  163. return fmt.Errorf("building to node: %w", err)
  164. }
  165. ctx.ToNodes[to] = toNode
  166. toNode.SetInput(conNode.NewOutput(to.GetDataIndex()))
  167. }
  168. if len(completeToes) == 0 {
  169. return nil
  170. }
  171. // 需要完整文件,则生成Join指令
  172. joinNode := ctx.DAG.NewChunkedJoin(ctx.LRC.ChunkSize)
  173. for i := 0; i < ctx.LRC.K; i++ {
  174. fr := frNodes[i]
  175. if fr == nil {
  176. joinNode.AddInput(conNode.NewOutput(i))
  177. } else {
  178. joinNode.AddInput(fr.Output().Var)
  179. }
  180. }
  181. for _, to := range completeToes {
  182. toNode, err := buildToNode(ctx, to)
  183. if err != nil {
  184. return fmt.Errorf("building to node: %w", err)
  185. }
  186. ctx.ToNodes[to] = toNode
  187. toNode.SetInput(joinNode.Joined())
  188. }
  189. // 如果不需要Construct任何块,则删除这个节点
  190. if conNode.OutputStreams().Len() == 0 {
  191. conNode.RemoveAllInputs()
  192. ctx.DAG.RemoveNode(conNode)
  193. }
  194. return nil
  195. }
  196. // 输入同一组的多个块,恢复出剩下缺少的一个块。
  197. func ReconstructGroup(frs []ioswitchlrc.From, toes []ioswitchlrc.To, blder *exec.PlanBuilder) error {
  198. ctx := GenerateContext{
  199. LRC: cdssdk.DefaultLRCRedundancy,
  200. DAG: ops2.NewGraphNodeBuilder(),
  201. To: toes,
  202. ToNodes: make(map[ioswitchlrc.To]ops2.ToNode),
  203. }
  204. calcStreamRange(&ctx)
  205. err := buildDAGReconstructGroup(&ctx, frs, toes)
  206. if err != nil {
  207. return err
  208. }
  209. // 确定指令执行位置的过程,也需要反复进行,直到没有变化为止。
  210. for pin(&ctx) {
  211. }
  212. // 下面这些只需要执行一次,但需要按顺序
  213. dropUnused(&ctx)
  214. storeIPFSWriteResult(&ctx)
  215. generateClone(&ctx)
  216. generateRange(&ctx)
  217. return plan.Generate(ctx.DAG.Graph, blder)
  218. }
  219. func buildDAGReconstructGroup(ctx *GenerateContext, frs []ioswitchlrc.From, toes []ioswitchlrc.To) error {
  220. var inputs []*dag.StreamVar
  221. for _, fr := range frs {
  222. frNode, err := buildFromNode(ctx, fr)
  223. if err != nil {
  224. return fmt.Errorf("building from node: %w", err)
  225. }
  226. inputs = append(inputs, frNode.Output().Var)
  227. }
  228. missedGrpIdx := toes[0].GetDataIndex()
  229. conNode := ctx.DAG.NewLRCConstructGroup(ctx.LRC)
  230. missedBlk := conNode.SetupForTarget(missedGrpIdx, inputs)
  231. for _, to := range toes {
  232. toNode, err := buildToNode(ctx, to)
  233. if err != nil {
  234. return fmt.Errorf("building to node: %w", err)
  235. }
  236. ctx.ToNodes[to] = toNode
  237. toNode.SetInput(missedBlk)
  238. }
  239. return nil
  240. }

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