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.

parser.go 18 kB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728
  1. package plans
  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/parser"
  8. "gitlink.org.cn/cloudream/common/pkgs/ipfs"
  9. cdssdk "gitlink.org.cn/cloudream/common/sdks/storage"
  10. "gitlink.org.cn/cloudream/common/utils/lo2"
  11. "gitlink.org.cn/cloudream/common/utils/math2"
  12. "gitlink.org.cn/cloudream/storage/common/pkgs/ioswitch/ops"
  13. )
  14. type DefaultParser struct {
  15. EC cdssdk.ECRedundancy
  16. }
  17. func NewParser(ec cdssdk.ECRedundancy) *DefaultParser {
  18. return &DefaultParser{
  19. EC: ec,
  20. }
  21. }
  22. type ParseContext struct {
  23. Ft parser.FromTo
  24. DAG *ops.Graph
  25. // 为了产生所有To所需的数据范围,而需要From打开的范围。
  26. // 这个范围是基于整个文件的,且上下界都取整到条带大小的整数倍,因此上界是有可能超过文件大小的。
  27. StreamRange exec.Range
  28. }
  29. func (p *DefaultParser) Parse(ft parser.FromTo, blder *exec.PlanBuilder) error {
  30. ctx := ParseContext{Ft: ft}
  31. // 分成两个阶段:
  32. // 1. 基于From和To生成更多指令,初步匹配to的需求
  33. // 计算一下打开流的范围
  34. p.calcStreamRange(&ctx)
  35. err := p.extend(&ctx, ft)
  36. if err != nil {
  37. return err
  38. }
  39. // 2. 优化上一步生成的指令
  40. // 对于删除指令的优化,需要反复进行,直到没有变化为止。
  41. // 从目前实现上来说不会死循环
  42. for {
  43. opted := false
  44. if p.removeUnusedJoin(&ctx) {
  45. opted = true
  46. }
  47. if p.removeUnusedMultiplyOutput(&ctx) {
  48. opted = true
  49. }
  50. if p.removeUnusedSplit(&ctx) {
  51. opted = true
  52. }
  53. if p.omitSplitJoin(&ctx) {
  54. opted = true
  55. }
  56. if !opted {
  57. break
  58. }
  59. }
  60. // 确定指令执行位置的过程,也需要反复进行,直到没有变化为止。
  61. for p.pin(&ctx) {
  62. }
  63. // 下面这些只需要执行一次,但需要按顺序
  64. p.dropUnused(&ctx)
  65. p.storeIPFSWriteResult(&ctx)
  66. p.generateClone(&ctx)
  67. p.generateRange(&ctx)
  68. p.generateSend(&ctx)
  69. return p.buildPlan(&ctx, blder)
  70. }
  71. func (p *DefaultParser) findOutputStream(ctx *ParseContext, streamIndex int) *ops.StreamVar {
  72. var ret *ops.StreamVar
  73. ctx.DAG.Walk(func(n *dag.Node[ops.NodeProps, ops.VarProps]) bool {
  74. for _, o := range n.OutputStreams {
  75. if o != nil && o.Props.StreamIndex == streamIndex {
  76. ret = o
  77. return false
  78. }
  79. }
  80. return true
  81. })
  82. return ret
  83. }
  84. // 计算输入流的打开范围。会把流的范围按条带大小取整
  85. func (p *DefaultParser) calcStreamRange(ctx *ParseContext) {
  86. stripSize := int64(p.EC.ChunkSize * p.EC.K)
  87. rng := exec.Range{
  88. Offset: math.MaxInt64,
  89. }
  90. for _, t := range ctx.Ft.Toes {
  91. to := t.(ops.To)
  92. if to.GetDataIndex() == -1 {
  93. toRng := to.GetRange()
  94. rng.ExtendStart(math2.Floor(toRng.Offset, stripSize))
  95. if toRng.Length != nil {
  96. rng.ExtendEnd(math2.Ceil(toRng.Offset+*toRng.Length, stripSize))
  97. } else {
  98. rng.Length = nil
  99. }
  100. } else {
  101. toRng := to.GetRange()
  102. blkStartIndex := math2.FloorDiv(toRng.Offset, int64(p.EC.ChunkSize))
  103. rng.ExtendStart(blkStartIndex * stripSize)
  104. if toRng.Length != nil {
  105. blkEndIndex := math2.CeilDiv(toRng.Offset+*toRng.Length, int64(p.EC.ChunkSize))
  106. rng.ExtendEnd(blkEndIndex * stripSize)
  107. } else {
  108. rng.Length = nil
  109. }
  110. }
  111. }
  112. ctx.StreamRange = rng
  113. }
  114. func (p *DefaultParser) extend(ctx *ParseContext, ft parser.FromTo) error {
  115. for _, f := range ft.Froms {
  116. fr := f.(ops.From)
  117. _, err := p.buildFromNode(ctx, &ft, fr)
  118. if err != nil {
  119. return err
  120. }
  121. // 对于完整文件的From,生成Split指令
  122. if fr.GetDataIndex() == -1 {
  123. n, _ := dag.NewNode(ctx.DAG, &ops.ChunkedSplitType{ChunkSize: p.EC.ChunkSize, OutputCount: p.EC.K}, ops.NodeProps{})
  124. for i := 0; i < p.EC.K; i++ {
  125. n.OutputStreams[i].Props.StreamIndex = i
  126. }
  127. }
  128. }
  129. // 如果有K个不同的文件块流,则生成Multiply指令,同时针对其生成的流,生成Join指令
  130. ecInputStrs := make(map[int]*ops.StreamVar)
  131. loop:
  132. for _, o := range ctx.DAG.Nodes {
  133. for _, s := range o.OutputStreams {
  134. if s.Props.StreamIndex >= 0 && ecInputStrs[s.Props.StreamIndex] == nil {
  135. ecInputStrs[s.Props.StreamIndex] = s
  136. if len(ecInputStrs) == p.EC.K {
  137. break loop
  138. }
  139. }
  140. }
  141. }
  142. if len(ecInputStrs) == p.EC.K {
  143. mulNode, mulType := dag.NewNode(ctx.DAG, &ops.MultiplyType{
  144. EC: p.EC,
  145. }, ops.NodeProps{})
  146. for _, s := range ecInputStrs {
  147. mulType.AddInput(mulNode, s)
  148. }
  149. for i := 0; i < p.EC.N; i++ {
  150. mulType.NewOutput(mulNode, i)
  151. }
  152. joinNode, _ := dag.NewNode(ctx.DAG, &ops.ChunkedJoinType{
  153. InputCount: p.EC.K,
  154. ChunkSize: p.EC.ChunkSize,
  155. }, ops.NodeProps{})
  156. for i := 0; i < p.EC.K; i++ {
  157. // 不可能找不到流
  158. p.findOutputStream(ctx, i).To(joinNode, i)
  159. }
  160. joinNode.OutputStreams[0].Props.StreamIndex = -1
  161. }
  162. // 为每一个To找到一个输入流
  163. for _, t := range ft.Toes {
  164. to := t.(ops.To)
  165. n, err := p.buildToNode(ctx, &ft, to)
  166. if err != nil {
  167. return err
  168. }
  169. str := p.findOutputStream(ctx, to.GetDataIndex())
  170. if str == nil {
  171. return fmt.Errorf("no output stream found for data index %d", to.GetDataIndex())
  172. }
  173. str.To(n, 0)
  174. }
  175. return nil
  176. }
  177. func (p *DefaultParser) buildFromNode(ctx *ParseContext, ft *parser.FromTo, f ops.From) (*ops.Node, error) {
  178. var repRange exec.Range
  179. var blkRange exec.Range
  180. repRange.Offset = ctx.StreamRange.Offset
  181. blkRange.Offset = ctx.StreamRange.Offset / int64(p.EC.ChunkSize*p.EC.K) * int64(p.EC.ChunkSize)
  182. if ctx.StreamRange.Length != nil {
  183. repRngLen := *ctx.StreamRange.Length
  184. repRange.Length = &repRngLen
  185. blkRngLen := *ctx.StreamRange.Length / int64(p.EC.ChunkSize*p.EC.K) * int64(p.EC.ChunkSize)
  186. blkRange.Length = &blkRngLen
  187. }
  188. switch f := f.(type) {
  189. case *ops.FromWorker:
  190. n, t := dag.NewNode(ctx.DAG, &ops.IPFSReadType{
  191. FileHash: f.FileHash,
  192. Option: ipfs.ReadOption{
  193. Offset: 0,
  194. Length: -1,
  195. },
  196. }, ops.NodeProps{
  197. From: f,
  198. })
  199. n.OutputStreams[0].Props.StreamIndex = f.DataIndex
  200. if f.DataIndex == -1 {
  201. t.Option.Offset = repRange.Offset
  202. if repRange.Length != nil {
  203. t.Option.Length = *repRange.Length
  204. }
  205. } else {
  206. t.Option.Offset = blkRange.Offset
  207. if blkRange.Length != nil {
  208. t.Option.Length = *blkRange.Length
  209. }
  210. }
  211. if f.Node != nil {
  212. n.Env.ToEnvWorker(&ops.AgentWorker{*f.Node})
  213. }
  214. return n, nil
  215. case *ops.FromExecutor:
  216. n, _ := dag.NewNode(ctx.DAG, &ops.FromDriverType{Handle: f.Handle}, ops.NodeProps{From: f})
  217. n.Env.ToEnvExecutor()
  218. n.OutputStreams[0].Props.StreamIndex = f.DataIndex
  219. if f.DataIndex == -1 {
  220. f.Handle.RangeHint.Offset = repRange.Offset
  221. f.Handle.RangeHint.Length = repRange.Length
  222. } else {
  223. f.Handle.RangeHint.Offset = blkRange.Offset
  224. f.Handle.RangeHint.Length = blkRange.Length
  225. }
  226. return n, nil
  227. default:
  228. return nil, fmt.Errorf("unsupported from type %T", f)
  229. }
  230. }
  231. func (p *DefaultParser) buildToNode(ctx *ParseContext, ft *parser.FromTo, t ops.To) (*ops.Node, error) {
  232. switch t := t.(type) {
  233. case *ops.ToNode:
  234. n, _ := dag.NewNode(ctx.DAG, &ops.IPFSWriteType{
  235. FileHashStoreKey: t.FileHashStoreKey,
  236. Range: t.Range,
  237. }, ops.NodeProps{
  238. To: t,
  239. })
  240. return n, nil
  241. case *ops.ToExecutor:
  242. n, _ := dag.NewNode(ctx.DAG, &ops.ToDriverType{Handle: t.Handle, Range: t.Range}, ops.NodeProps{To: t})
  243. n.Env.ToEnvExecutor()
  244. return n, nil
  245. default:
  246. return nil, fmt.Errorf("unsupported to type %T", t)
  247. }
  248. }
  249. // 删除输出流未被使用的Join指令
  250. func (p *DefaultParser) removeUnusedJoin(ctx *ParseContext) bool {
  251. changed := false
  252. dag.WalkOnlyType[*ops.ChunkedJoinType](ctx.DAG, func(node *ops.Node, typ *ops.ChunkedJoinType) bool {
  253. if len(node.OutputStreams[0].Toes) > 0 {
  254. return true
  255. }
  256. for _, in := range node.InputStreams {
  257. in.NotTo(node)
  258. }
  259. ctx.DAG.RemoveNode(node)
  260. return true
  261. })
  262. return changed
  263. }
  264. // 减少未使用的Multiply指令的输出流。如果减少到0,则删除该指令
  265. func (p *DefaultParser) removeUnusedMultiplyOutput(ctx *ParseContext) bool {
  266. changed := false
  267. dag.WalkOnlyType[*ops.MultiplyType](ctx.DAG, func(node *ops.Node, typ *ops.MultiplyType) bool {
  268. for i2, out := range node.OutputStreams {
  269. if len(out.Toes) > 0 {
  270. continue
  271. }
  272. node.OutputStreams[i2] = nil
  273. changed = true
  274. }
  275. node.OutputStreams = lo2.RemoveAllDefault(node.OutputStreams)
  276. // 如果所有输出流都被删除,则删除该指令
  277. if len(node.OutputStreams) == 0 {
  278. for _, in := range node.InputStreams {
  279. in.NotTo(node)
  280. }
  281. ctx.DAG.RemoveNode(node)
  282. changed = true
  283. }
  284. return true
  285. })
  286. return changed
  287. }
  288. // 删除未使用的Split指令
  289. func (p *DefaultParser) removeUnusedSplit(ctx *ParseContext) bool {
  290. changed := false
  291. dag.WalkOnlyType[*ops.ChunkedSplitType](ctx.DAG, func(node *ops.Node, typ *ops.ChunkedSplitType) bool {
  292. // Split出来的每一个流都没有被使用,才能删除这个指令
  293. for _, out := range node.OutputStreams {
  294. if len(out.Toes) > 0 {
  295. return true
  296. }
  297. }
  298. node.InputStreams[0].NotTo(node)
  299. ctx.DAG.RemoveNode(node)
  300. changed = true
  301. return true
  302. })
  303. return changed
  304. }
  305. // 如果Split的结果被完全用于Join,则省略Split和Join指令
  306. func (p *DefaultParser) omitSplitJoin(ctx *ParseContext) bool {
  307. changed := false
  308. dag.WalkOnlyType[*ops.ChunkedSplitType](ctx.DAG, func(splitNode *ops.Node, typ *ops.ChunkedSplitType) bool {
  309. // Split指令的每一个输出都有且只有一个目的地
  310. var joinNode *ops.Node
  311. for _, out := range splitNode.OutputStreams {
  312. if len(out.Toes) != 1 {
  313. continue
  314. }
  315. if joinNode == nil {
  316. joinNode = out.Toes[0].Node
  317. } else if joinNode != out.Toes[0].Node {
  318. return true
  319. }
  320. }
  321. if joinNode == nil {
  322. return true
  323. }
  324. // 且这个目的地要是一个Join指令
  325. _, ok := joinNode.Type.(*ops.ChunkedJoinType)
  326. if !ok {
  327. return true
  328. }
  329. // 同时这个Join指令的输入也必须全部来自Split指令的输出。
  330. // 由于上面判断了Split指令的输出目的地都相同,所以这里只要判断Join指令的输入数量是否与Split指令的输出数量相同即可
  331. if len(joinNode.InputStreams) != len(splitNode.OutputStreams) {
  332. return true
  333. }
  334. // 所有条件都满足,可以开始省略操作,将Join操作的目的地的输入流替换为Split操作的输入流:
  335. // F->Split->Join->T 变换为:F->T
  336. splitNode.InputStreams[0].NotTo(splitNode)
  337. for _, out := range joinNode.OutputStreams[0].Toes {
  338. splitNode.InputStreams[0].To(out.Node, out.SlotIndex)
  339. }
  340. // 并删除这两个指令
  341. ctx.DAG.RemoveNode(joinNode)
  342. ctx.DAG.RemoveNode(splitNode)
  343. changed = true
  344. return true
  345. })
  346. return changed
  347. }
  348. // 通过流的输入输出位置来确定指令的执行位置。
  349. // To系列的指令都会有固定的执行位置,这些位置会随着pin操作逐步扩散到整个DAG,
  350. // 所以理论上不会出现有指令的位置始终无法确定的情况。
  351. func (p *DefaultParser) pin(ctx *ParseContext) bool {
  352. changed := false
  353. ctx.DAG.Walk(func(node *ops.Node) bool {
  354. var toEnv *dag.NodeEnv
  355. for _, out := range node.OutputStreams {
  356. for _, to := range out.Toes {
  357. if to.Node.Env.Type == dag.EnvUnknown {
  358. continue
  359. }
  360. if toEnv == nil {
  361. toEnv = &to.Node.Env
  362. } else if !toEnv.Equals(to.Node.Env) {
  363. toEnv = nil
  364. break
  365. }
  366. }
  367. }
  368. if toEnv != nil {
  369. if !node.Env.Equals(*toEnv) {
  370. changed = true
  371. }
  372. node.Env = *toEnv
  373. return true
  374. }
  375. // 否则根据输入流的始发地来固定
  376. var fromEnv *dag.NodeEnv
  377. for _, in := range node.InputStreams {
  378. if in.From.Node.Env.Type == dag.EnvUnknown {
  379. continue
  380. }
  381. if fromEnv == nil {
  382. fromEnv = &in.From.Node.Env
  383. } else if !fromEnv.Equals(in.From.Node.Env) {
  384. fromEnv = nil
  385. break
  386. }
  387. }
  388. if fromEnv != nil {
  389. if !node.Env.Equals(*fromEnv) {
  390. changed = true
  391. }
  392. node.Env = *fromEnv
  393. }
  394. return true
  395. })
  396. return changed
  397. }
  398. // 对于所有未使用的流,增加Drop指令
  399. func (p *DefaultParser) dropUnused(ctx *ParseContext) {
  400. ctx.DAG.Walk(func(node *ops.Node) bool {
  401. for _, out := range node.OutputStreams {
  402. if len(out.Toes) == 0 {
  403. n := ctx.DAG.NewNode(&ops.DropType{}, ops.NodeProps{})
  404. n.Env = node.Env
  405. out.To(n, 0)
  406. }
  407. }
  408. return true
  409. })
  410. }
  411. // 为IPFS写入指令存储结果
  412. func (p *DefaultParser) storeIPFSWriteResult(ctx *ParseContext) {
  413. dag.WalkOnlyType[*ops.IPFSWriteType](ctx.DAG, func(node *ops.Node, typ *ops.IPFSWriteType) bool {
  414. if typ.FileHashStoreKey == "" {
  415. return true
  416. }
  417. n := ctx.DAG.NewNode(&ops.StoreType{
  418. StoreKey: typ.FileHashStoreKey,
  419. }, ops.NodeProps{})
  420. n.Env.ToEnvExecutor()
  421. node.OutputValues[0].To(n, 0)
  422. return true
  423. })
  424. }
  425. // 生成Range指令。StreamRange可能超过文件总大小,但Range指令会在数据量不够时不报错而是正常返回
  426. func (p *DefaultParser) generateRange(ctx *ParseContext) {
  427. ctx.DAG.Walk(func(node *ops.Node) bool {
  428. if node.Props.To == nil {
  429. return true
  430. }
  431. toDataIdx := node.Props.To.GetDataIndex()
  432. toRng := node.Props.To.GetRange()
  433. if toDataIdx == -1 {
  434. n := ctx.DAG.NewNode(&ops.RangeType{
  435. Range: exec.Range{
  436. Offset: toRng.Offset - ctx.StreamRange.Offset,
  437. Length: toRng.Length,
  438. },
  439. }, ops.NodeProps{})
  440. n.Env = node.InputStreams[0].From.Node.Env
  441. node.InputStreams[0].To(n, 0)
  442. node.InputStreams[0].NotTo(node)
  443. n.OutputStreams[0].To(node, 0)
  444. } else {
  445. stripSize := int64(p.EC.ChunkSize * p.EC.K)
  446. blkStartIdx := ctx.StreamRange.Offset / stripSize
  447. blkStart := blkStartIdx * int64(p.EC.ChunkSize)
  448. n := ctx.DAG.NewNode(&ops.RangeType{
  449. Range: exec.Range{
  450. Offset: toRng.Offset - blkStart,
  451. Length: toRng.Length,
  452. },
  453. }, ops.NodeProps{})
  454. n.Env = node.InputStreams[0].From.Node.Env
  455. node.InputStreams[0].To(n, 0)
  456. node.InputStreams[0].NotTo(node)
  457. n.OutputStreams[0].To(node, 0)
  458. }
  459. return true
  460. })
  461. }
  462. // 生成Clone指令
  463. func (p *DefaultParser) generateClone(ctx *ParseContext) {
  464. ctx.DAG.Walk(func(node *ops.Node) bool {
  465. for _, out := range node.OutputStreams {
  466. if len(out.Toes) <= 1 {
  467. continue
  468. }
  469. n, t := dag.NewNode(ctx.DAG, &ops.CloneStreamType{}, ops.NodeProps{})
  470. n.Env = node.Env
  471. for _, to := range out.Toes {
  472. t.NewOutput(node).To(to.Node, to.SlotIndex)
  473. }
  474. out.Toes = nil
  475. out.To(n, 0)
  476. }
  477. for _, out := range node.OutputValues {
  478. if len(out.Toes) <= 1 {
  479. continue
  480. }
  481. n, t := dag.NewNode(ctx.DAG, &ops.CloneVarType{}, ops.NodeProps{})
  482. n.Env = node.Env
  483. for _, to := range out.Toes {
  484. t.NewOutput(node).To(to.Node, to.SlotIndex)
  485. }
  486. out.Toes = nil
  487. out.To(n, 0)
  488. }
  489. return true
  490. })
  491. }
  492. // 生成Send指令
  493. func (p *DefaultParser) generateSend(ctx *ParseContext) {
  494. ctx.DAG.Walk(func(node *ops.Node) bool {
  495. for _, out := range node.OutputStreams {
  496. to := out.Toes[0]
  497. if to.Node.Env.Equals(node.Env) {
  498. continue
  499. }
  500. switch to.Node.Env.Type {
  501. case dag.EnvExecutor:
  502. // // 如果是要送到Executor,则只能由Executor主动去拉取
  503. getNode := ctx.DAG.NewNode(&ops.GetStreamType{}, ops.NodeProps{})
  504. getNode.Env.ToEnvExecutor()
  505. // // 同时需要对此变量生成HoldUntil指令,避免Plan结束时Get指令还未到达
  506. holdNode := ctx.DAG.NewNode(&ops.HoldUntilType{}, ops.NodeProps{})
  507. holdNode.Env = node.Env
  508. // 将Get指令的信号送到Hold指令
  509. getNode.OutputValues[0].To(holdNode, 0)
  510. // 将Get指令的输出送到目的地
  511. getNode.OutputStreams[0].To(to.Node, to.SlotIndex)
  512. out.Toes = nil
  513. // 将源节点的输出送到Hold指令
  514. out.To(holdNode, 0)
  515. // 将Hold指令的输出送到Get指令
  516. holdNode.OutputStreams[0].To(getNode, 0)
  517. case dag.EnvWorker:
  518. // 如果是要送到Agent,则可以直接发送
  519. n := ctx.DAG.NewNode(&ops.SendStreamType{}, ops.NodeProps{})
  520. n.Env = node.Env
  521. n.OutputStreams[0].To(to.Node, to.SlotIndex)
  522. out.Toes = nil
  523. out.To(n, 0)
  524. }
  525. }
  526. for _, out := range node.OutputValues {
  527. to := out.Toes[0]
  528. if to.Node.Env.Equals(node.Env) {
  529. continue
  530. }
  531. switch to.Node.Env.Type {
  532. case dag.EnvExecutor:
  533. // // 如果是要送到Executor,则只能由Executor主动去拉取
  534. getNode := ctx.DAG.NewNode(&ops.GetVaType{}, ops.NodeProps{})
  535. getNode.Env.ToEnvExecutor()
  536. // // 同时需要对此变量生成HoldUntil指令,避免Plan结束时Get指令还未到达
  537. holdNode := ctx.DAG.NewNode(&ops.HoldUntilType{}, ops.NodeProps{})
  538. holdNode.Env = node.Env
  539. // 将Get指令的信号送到Hold指令
  540. getNode.OutputValues[0].To(holdNode, 0)
  541. // 将Get指令的输出送到目的地
  542. getNode.OutputValues[1].To(to.Node, to.SlotIndex)
  543. out.Toes = nil
  544. // 将源节点的输出送到Hold指令
  545. out.To(holdNode, 0)
  546. // 将Hold指令的输出送到Get指令
  547. holdNode.OutputValues[0].To(getNode, 0)
  548. case dag.EnvWorker:
  549. // 如果是要送到Agent,则可以直接发送
  550. n := ctx.DAG.NewNode(&ops.SendVarType{}, ops.NodeProps{})
  551. n.Env = node.Env
  552. n.OutputValues[0].To(to.Node, to.SlotIndex)
  553. out.Toes = nil
  554. out.To(n, 0)
  555. }
  556. }
  557. return true
  558. })
  559. }
  560. // 生成Plan
  561. func (p *DefaultParser) buildPlan(ctx *ParseContext, blder *exec.PlanBuilder) error {
  562. var retErr error
  563. ctx.DAG.Walk(func(node *dag.Node[ops.NodeProps, ops.VarProps]) bool {
  564. for _, out := range node.OutputStreams {
  565. if out.Props.Var != nil {
  566. continue
  567. }
  568. out.Props.Var = blder.NewStreamVar()
  569. }
  570. for _, in := range node.InputStreams {
  571. if in.Props.Var != nil {
  572. continue
  573. }
  574. in.Props.Var = blder.NewStreamVar()
  575. }
  576. for _, out := range node.OutputValues {
  577. if out.Props.Var != nil {
  578. continue
  579. }
  580. switch out.Props.ValueType {
  581. case ops.StringValueVar:
  582. out.Props.Var = blder.NewStringVar()
  583. case ops.SignalValueVar:
  584. out.Props.Var = blder.NewSignalVar()
  585. }
  586. }
  587. for _, in := range node.InputValues {
  588. if in.Props.Var != nil {
  589. continue
  590. }
  591. switch in.Props.ValueType {
  592. case ops.StringValueVar:
  593. in.Props.Var = blder.NewStringVar()
  594. case ops.SignalValueVar:
  595. in.Props.Var = blder.NewSignalVar()
  596. }
  597. }
  598. if err := node.Type.GenerateOp(node, blder); err != nil {
  599. retErr = err
  600. return false
  601. }
  602. return true
  603. })
  604. return retErr
  605. }

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