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.

passes.go 7.2 kB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295
  1. package parser
  2. import (
  3. "fmt"
  4. "math"
  5. "gitlink.org.cn/cloudream/common/pkgs/ioswitch/dag"
  6. "gitlink.org.cn/cloudream/common/pkgs/ioswitch/exec"
  7. "gitlink.org.cn/cloudream/common/pkgs/ipfs"
  8. "gitlink.org.cn/cloudream/common/utils/math2"
  9. "gitlink.org.cn/cloudream/storage/common/pkgs/ioswitchlrc"
  10. "gitlink.org.cn/cloudream/storage/common/pkgs/ioswitchlrc/ops2"
  11. )
  12. // 计算输入流的打开范围。会把流的范围按条带大小取整
  13. func calcStreamRange(ctx *GenerateContext) {
  14. stripSize := int64(ctx.LRC.ChunkSize * ctx.LRC.K)
  15. rng := exec.Range{
  16. Offset: math.MaxInt64,
  17. }
  18. for _, to := range ctx.To {
  19. if to.GetDataIndex() == -1 {
  20. toRng := to.GetRange()
  21. rng.ExtendStart(math2.Floor(toRng.Offset, stripSize))
  22. if toRng.Length != nil {
  23. rng.ExtendEnd(math2.Ceil(toRng.Offset+*toRng.Length, stripSize))
  24. } else {
  25. rng.Length = nil
  26. }
  27. } else {
  28. toRng := to.GetRange()
  29. blkStartIndex := math2.FloorDiv(toRng.Offset, int64(ctx.LRC.ChunkSize))
  30. rng.ExtendStart(blkStartIndex * stripSize)
  31. if toRng.Length != nil {
  32. blkEndIndex := math2.CeilDiv(toRng.Offset+*toRng.Length, int64(ctx.LRC.ChunkSize))
  33. rng.ExtendEnd(blkEndIndex * stripSize)
  34. } else {
  35. rng.Length = nil
  36. }
  37. }
  38. }
  39. ctx.StreamRange = rng
  40. }
  41. func buildFromNode(ctx *GenerateContext, f ioswitchlrc.From) (ops2.FromNode, error) {
  42. var repRange exec.Range
  43. var blkRange exec.Range
  44. repRange.Offset = ctx.StreamRange.Offset
  45. blkRange.Offset = ctx.StreamRange.Offset / int64(ctx.LRC.ChunkSize*ctx.LRC.K) * int64(ctx.LRC.ChunkSize)
  46. if ctx.StreamRange.Length != nil {
  47. repRngLen := *ctx.StreamRange.Length
  48. repRange.Length = &repRngLen
  49. blkRngLen := *ctx.StreamRange.Length / int64(ctx.LRC.ChunkSize*ctx.LRC.K) * int64(ctx.LRC.ChunkSize)
  50. blkRange.Length = &blkRngLen
  51. }
  52. switch f := f.(type) {
  53. case *ioswitchlrc.FromNode:
  54. t := ctx.DAG.NewIPFSRead(f.FileHash, ipfs.ReadOption{
  55. Offset: 0,
  56. Length: -1,
  57. })
  58. if f.DataIndex == -1 {
  59. t.Option.Offset = repRange.Offset
  60. if repRange.Length != nil {
  61. t.Option.Length = *repRange.Length
  62. }
  63. } else {
  64. t.Option.Offset = blkRange.Offset
  65. if blkRange.Length != nil {
  66. t.Option.Length = *blkRange.Length
  67. }
  68. }
  69. if f.Node != nil {
  70. t.Env().ToEnvWorker(&ioswitchlrc.AgentWorker{Node: *f.Node})
  71. t.Env().Pinned = true
  72. }
  73. return t, nil
  74. case *ioswitchlrc.FromDriver:
  75. n := ctx.DAG.NewFromDriver(f.Handle)
  76. n.Env().ToEnvDriver()
  77. n.Env().Pinned = true
  78. if f.DataIndex == -1 {
  79. f.Handle.RangeHint.Offset = repRange.Offset
  80. f.Handle.RangeHint.Length = repRange.Length
  81. } else {
  82. f.Handle.RangeHint.Offset = blkRange.Offset
  83. f.Handle.RangeHint.Length = blkRange.Length
  84. }
  85. return n, nil
  86. default:
  87. return nil, fmt.Errorf("unsupported from type %T", f)
  88. }
  89. }
  90. func buildToNode(ctx *GenerateContext, t ioswitchlrc.To) (ops2.ToNode, error) {
  91. switch t := t.(type) {
  92. case *ioswitchlrc.ToNode:
  93. n := ctx.DAG.NewIPFSWrite(t.FileHashStoreKey)
  94. n.Env().ToEnvWorker(&ioswitchlrc.AgentWorker{Node: t.Node})
  95. n.Env().Pinned = true
  96. return n, nil
  97. case *ioswitchlrc.ToDriver:
  98. n := ctx.DAG.NewToDriver(t.Handle)
  99. n.Env().ToEnvDriver()
  100. n.Env().Pinned = true
  101. return n, nil
  102. default:
  103. return nil, fmt.Errorf("unsupported to type %T", t)
  104. }
  105. }
  106. // 通过流的输入输出位置来确定指令的执行位置。
  107. // To系列的指令都会有固定的执行位置,这些位置会随着pin操作逐步扩散到整个DAG,
  108. // 所以理论上不会出现有指令的位置始终无法确定的情况。
  109. func pin(ctx *GenerateContext) bool {
  110. changed := false
  111. ctx.DAG.Walk(func(node dag.Node) bool {
  112. if node.Env().Pinned {
  113. return true
  114. }
  115. var toEnv *dag.NodeEnv
  116. for _, out := range node.OutputStreams().RawArray() {
  117. for _, to := range out.To().RawArray() {
  118. if to.Node.Env().Type == dag.EnvUnknown {
  119. continue
  120. }
  121. if toEnv == nil {
  122. toEnv = to.Node.Env()
  123. } else if !toEnv.Equals(to.Node.Env()) {
  124. toEnv = nil
  125. break
  126. }
  127. }
  128. }
  129. if toEnv != nil {
  130. if !node.Env().Equals(toEnv) {
  131. changed = true
  132. }
  133. *node.Env() = *toEnv
  134. return true
  135. }
  136. // 否则根据输入流的始发地来固定
  137. var fromEnv *dag.NodeEnv
  138. for _, in := range node.InputStreams().RawArray() {
  139. if in.From().Node.Env().Type == dag.EnvUnknown {
  140. continue
  141. }
  142. if fromEnv == nil {
  143. fromEnv = in.From().Node.Env()
  144. } else if !fromEnv.Equals(in.From().Node.Env()) {
  145. fromEnv = nil
  146. break
  147. }
  148. }
  149. if fromEnv != nil {
  150. if !node.Env().Equals(fromEnv) {
  151. changed = true
  152. }
  153. *node.Env() = *fromEnv
  154. }
  155. return true
  156. })
  157. return changed
  158. }
  159. // 对于所有未使用的流,增加Drop指令
  160. func dropUnused(ctx *GenerateContext) {
  161. ctx.DAG.Walk(func(node dag.Node) bool {
  162. for _, out := range node.OutputStreams().RawArray() {
  163. if out.To().Len() == 0 {
  164. n := ctx.DAG.NewDropStream()
  165. *n.Env() = *node.Env()
  166. n.SetInput(out)
  167. }
  168. }
  169. return true
  170. })
  171. }
  172. // 为IPFS写入指令存储结果
  173. func storeIPFSWriteResult(ctx *GenerateContext) {
  174. dag.WalkOnlyType[*ops2.IPFSWriteNode](ctx.DAG.Graph, func(n *ops2.IPFSWriteNode) bool {
  175. if n.FileHashStoreKey == "" {
  176. return true
  177. }
  178. storeNode := ctx.DAG.NewStore()
  179. storeNode.Env().ToEnvDriver()
  180. storeNode.Store(n.FileHashStoreKey, n.FileHashVar())
  181. return true
  182. })
  183. }
  184. // 生成Range指令。StreamRange可能超过文件总大小,但Range指令会在数据量不够时不报错而是正常返回
  185. func generateRange(ctx *GenerateContext) {
  186. for i := 0; i < len(ctx.To); i++ {
  187. to := ctx.To[i]
  188. toNode := ctx.ToNodes[to]
  189. toDataIdx := to.GetDataIndex()
  190. toRng := to.GetRange()
  191. if toDataIdx == -1 {
  192. n := ctx.DAG.NewRange()
  193. toInput := toNode.Input()
  194. *n.Env() = *toInput.Var.From().Node.Env()
  195. rnged := n.RangeStream(toInput.Var, exec.Range{
  196. Offset: toRng.Offset - ctx.StreamRange.Offset,
  197. Length: toRng.Length,
  198. })
  199. toInput.Var.Disconnect(toNode, toInput.Index)
  200. toNode.SetInput(rnged)
  201. } else {
  202. stripSize := int64(ctx.LRC.ChunkSize * ctx.LRC.K)
  203. blkStartIdx := ctx.StreamRange.Offset / stripSize
  204. blkStart := blkStartIdx * int64(ctx.LRC.ChunkSize)
  205. n := ctx.DAG.NewRange()
  206. toInput := toNode.Input()
  207. *n.Env() = *toInput.Var.From().Node.Env()
  208. rnged := n.RangeStream(toInput.Var, exec.Range{
  209. Offset: toRng.Offset - blkStart,
  210. Length: toRng.Length,
  211. })
  212. toInput.Var.Disconnect(toNode, toInput.Index)
  213. toNode.SetInput(rnged)
  214. }
  215. }
  216. }
  217. // 生成Clone指令
  218. func generateClone(ctx *GenerateContext) {
  219. ctx.DAG.Walk(func(node dag.Node) bool {
  220. for _, out := range node.OutputStreams().RawArray() {
  221. if out.To().Len() <= 1 {
  222. continue
  223. }
  224. t := ctx.DAG.NewCloneStream()
  225. *t.Env() = *node.Env()
  226. for _, to := range out.To().RawArray() {
  227. t.NewOutput().Connect(to.Node, to.SlotIndex)
  228. }
  229. out.To().Resize(0)
  230. t.SetInput(out)
  231. }
  232. for _, out := range node.OutputValues().RawArray() {
  233. if out.To().Len() <= 1 {
  234. continue
  235. }
  236. t := ctx.DAG.NewCloneValue()
  237. *t.Env() = *node.Env()
  238. for _, to := range out.To().RawArray() {
  239. t.NewOutput().Connect(to.Node, to.SlotIndex)
  240. }
  241. out.To().Resize(0)
  242. t.SetInput(out)
  243. }
  244. return true
  245. })
  246. }

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