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.9 kB

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

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