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 26 kB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986
  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"
  8. cdssdk "gitlink.org.cn/cloudream/common/sdks/storage"
  9. "gitlink.org.cn/cloudream/common/utils/lo2"
  10. "gitlink.org.cn/cloudream/common/utils/math2"
  11. "gitlink.org.cn/cloudream/storage/common/pkgs/ioswitch2"
  12. "gitlink.org.cn/cloudream/storage/common/pkgs/ioswitch2/ops2"
  13. "gitlink.org.cn/cloudream/storage/common/pkgs/storage/types"
  14. )
  15. type IndexedStream struct {
  16. Stream *dag.StreamVar
  17. StreamIndex ioswitch2.StreamIndex
  18. }
  19. type ParseContext struct {
  20. Ft ioswitch2.FromTo
  21. DAG *ops2.GraphNodeBuilder
  22. // 为了产生所有To所需的数据范围,而需要From打开的范围。
  23. // 这个范围是基于整个文件的,且上下界都取整到条带大小的整数倍,因此上界是有可能超过文件大小的。
  24. ToNodes map[ioswitch2.To]ops2.ToNode
  25. IndexedStreams []IndexedStream
  26. StreamRange exec.Range
  27. UseEC bool // 是否使用纠删码
  28. UseSegment bool // 是否使用分段
  29. }
  30. func Parse(ft ioswitch2.FromTo, blder *exec.PlanBuilder) error {
  31. ctx := ParseContext{
  32. Ft: ft,
  33. DAG: ops2.NewGraphNodeBuilder(),
  34. ToNodes: make(map[ioswitch2.To]ops2.ToNode),
  35. }
  36. // 分成两个阶段:
  37. // 1. 基于From和To生成更多指令,初步匹配to的需求
  38. err := checkEncodingParams(&ctx)
  39. if err != nil {
  40. return err
  41. }
  42. // 计算一下打开流的范围
  43. calcStreamRange(&ctx)
  44. err = extend(&ctx)
  45. if err != nil {
  46. return err
  47. }
  48. // 2. 优化上一步生成的指令
  49. err = fixSegmentJoin(&ctx)
  50. if err != nil {
  51. return err
  52. }
  53. err = fixSegmentSplit(&ctx)
  54. if err != nil {
  55. return err
  56. }
  57. // 对于删除指令的优化,需要反复进行,直到没有变化为止。
  58. // 从目前实现上来说不会死循环
  59. for {
  60. opted := false
  61. if removeUnusedJoin(&ctx) {
  62. opted = true
  63. }
  64. if removeUnusedMultiplyOutput(&ctx) {
  65. opted = true
  66. }
  67. if removeUnusedSplit(&ctx) {
  68. opted = true
  69. }
  70. if omitSplitJoin(&ctx) {
  71. opted = true
  72. }
  73. if removeUnusedSegmentJoin(&ctx) {
  74. opted = true
  75. }
  76. if removeUnusedSegmentSplit(&ctx) {
  77. opted = true
  78. }
  79. if omitSegmentSplitJoin(&ctx) {
  80. opted = true
  81. }
  82. if !opted {
  83. break
  84. }
  85. }
  86. // 确定指令执行位置的过程,也需要反复进行,直到没有变化为止。
  87. for pin(&ctx) {
  88. }
  89. // 下面这些只需要执行一次,但需要按顺序
  90. removeUnusedFromNode(&ctx)
  91. dropUnused(&ctx)
  92. storeIPFSWriteResult(&ctx)
  93. generateRange(&ctx)
  94. generateClone(&ctx)
  95. return plan.Generate(ctx.DAG.Graph, blder)
  96. }
  97. func findOutputStream(ctx *ParseContext, streamIndex ioswitch2.StreamIndex) *dag.StreamVar {
  98. var ret *dag.StreamVar
  99. for _, s := range ctx.IndexedStreams {
  100. if s.StreamIndex == streamIndex {
  101. ret = s.Stream
  102. break
  103. }
  104. }
  105. return ret
  106. }
  107. // 检查使用不同编码时参数是否设置到位
  108. func checkEncodingParams(ctx *ParseContext) error {
  109. for _, f := range ctx.Ft.Froms {
  110. if f.GetStreamIndex().IsEC() {
  111. ctx.UseEC = true
  112. if ctx.Ft.ECParam == nil {
  113. return fmt.Errorf("EC encoding parameters not set")
  114. }
  115. }
  116. if f.GetStreamIndex().IsSegment() {
  117. ctx.UseSegment = true
  118. if ctx.Ft.SegmentParam == nil {
  119. return fmt.Errorf("segment parameters not set")
  120. }
  121. }
  122. }
  123. for _, t := range ctx.Ft.Toes {
  124. if t.GetStreamIndex().IsEC() {
  125. ctx.UseEC = true
  126. if ctx.Ft.ECParam == nil {
  127. return fmt.Errorf("EC encoding parameters not set")
  128. }
  129. }
  130. if t.GetStreamIndex().IsSegment() {
  131. ctx.UseSegment = true
  132. if ctx.Ft.SegmentParam == nil {
  133. return fmt.Errorf("segment parameters not set")
  134. }
  135. }
  136. }
  137. return nil
  138. }
  139. // 计算输入流的打开范围。如果From或者To中包含EC的流,则会将打开范围扩大到条带大小的整数倍。
  140. func calcStreamRange(ctx *ParseContext) {
  141. rng := exec.NewRange(math.MaxInt64, 0)
  142. for _, to := range ctx.Ft.Toes {
  143. strIdx := to.GetStreamIndex()
  144. if strIdx.IsRaw() {
  145. toRng := to.GetRange()
  146. rng.ExtendStart(toRng.Offset)
  147. if toRng.Length != nil {
  148. rng.ExtendEnd(toRng.Offset + *toRng.Length)
  149. } else {
  150. rng.Length = nil
  151. }
  152. } else if strIdx.IsEC() {
  153. toRng := to.GetRange()
  154. stripSize := ctx.Ft.ECParam.StripSize()
  155. blkStartIndex := math2.FloorDiv(toRng.Offset, int64(ctx.Ft.ECParam.ChunkSize))
  156. rng.ExtendStart(blkStartIndex * stripSize)
  157. if toRng.Length != nil {
  158. blkEndIndex := math2.CeilDiv(toRng.Offset+*toRng.Length, int64(ctx.Ft.ECParam.ChunkSize))
  159. rng.ExtendEnd(blkEndIndex * stripSize)
  160. } else {
  161. rng.Length = nil
  162. }
  163. } else if strIdx.IsSegment() {
  164. // Segment节点的Range是相对于本段的,需要加上本段的起始位置
  165. toRng := to.GetRange()
  166. segStart := ctx.Ft.SegmentParam.CalcSegmentStart(strIdx.Index)
  167. offset := toRng.Offset + segStart
  168. rng.ExtendStart(offset)
  169. if toRng.Length != nil {
  170. rng.ExtendEnd(offset + *toRng.Length)
  171. } else {
  172. rng.Length = nil
  173. }
  174. }
  175. }
  176. if ctx.UseEC {
  177. stripSize := ctx.Ft.ECParam.StripSize()
  178. rng.ExtendStart(math2.Floor(rng.Offset, stripSize))
  179. if rng.Length != nil {
  180. rng.ExtendEnd(math2.Ceil(rng.Offset+*rng.Length, stripSize))
  181. }
  182. }
  183. ctx.StreamRange = rng
  184. }
  185. func extend(ctx *ParseContext) error {
  186. for _, fr := range ctx.Ft.Froms {
  187. frNode, err := buildFromNode(ctx, fr)
  188. if err != nil {
  189. return err
  190. }
  191. ctx.IndexedStreams = append(ctx.IndexedStreams, IndexedStream{
  192. Stream: frNode.Output().Var,
  193. StreamIndex: fr.GetStreamIndex(),
  194. })
  195. // 对于完整文件的From,生成Split指令
  196. if fr.GetStreamIndex().IsRaw() {
  197. // 只有输入输出需要EC编码的块时,才生成相关指令
  198. if ctx.UseEC {
  199. splitNode := ctx.DAG.NewChunkedSplit(ctx.Ft.ECParam.ChunkSize, ctx.Ft.ECParam.K)
  200. splitNode.Split(frNode.Output().Var)
  201. for i := 0; i < ctx.Ft.ECParam.K; i++ {
  202. ctx.IndexedStreams = append(ctx.IndexedStreams, IndexedStream{
  203. Stream: splitNode.SubStream(i),
  204. StreamIndex: ioswitch2.ECSrteam(i),
  205. })
  206. }
  207. }
  208. // 同上
  209. if ctx.UseSegment {
  210. splitNode := ctx.DAG.NewSegmentSplit(ctx.Ft.SegmentParam.Segments)
  211. splitNode.SetInput(frNode.Output().Var)
  212. for i := 0; i < len(ctx.Ft.SegmentParam.Segments); i++ {
  213. ctx.IndexedStreams = append(ctx.IndexedStreams, IndexedStream{
  214. Stream: splitNode.Segment(i),
  215. StreamIndex: ioswitch2.SegmentStream(i),
  216. })
  217. }
  218. }
  219. }
  220. }
  221. if ctx.UseEC {
  222. // 如果有K个不同的文件块流,则生成Multiply指令,同时针对其生成的流,生成Join指令
  223. ecInputStrs := make(map[int]*dag.StreamVar)
  224. for _, s := range ctx.IndexedStreams {
  225. if s.StreamIndex.IsEC() && ecInputStrs[s.StreamIndex.Index] == nil {
  226. ecInputStrs[s.StreamIndex.Index] = s.Stream
  227. if len(ecInputStrs) == ctx.Ft.ECParam.K {
  228. break
  229. }
  230. }
  231. }
  232. if len(ecInputStrs) == ctx.Ft.ECParam.K {
  233. mulNode := ctx.DAG.NewECMultiply(*ctx.Ft.ECParam)
  234. for i, s := range ecInputStrs {
  235. mulNode.AddInput(s, i)
  236. }
  237. for i := 0; i < ctx.Ft.ECParam.N; i++ {
  238. ctx.IndexedStreams = append(ctx.IndexedStreams, IndexedStream{
  239. Stream: mulNode.NewOutput(i),
  240. StreamIndex: ioswitch2.ECSrteam(i),
  241. })
  242. }
  243. joinNode := ctx.DAG.NewChunkedJoin(ctx.Ft.ECParam.ChunkSize)
  244. for i := 0; i < ctx.Ft.ECParam.K; i++ {
  245. // 不可能找不到流
  246. joinNode.AddInput(findOutputStream(ctx, ioswitch2.ECSrteam(i)))
  247. }
  248. ctx.IndexedStreams = append(ctx.IndexedStreams, IndexedStream{
  249. Stream: joinNode.Joined(),
  250. StreamIndex: ioswitch2.RawStream(),
  251. })
  252. }
  253. }
  254. if ctx.UseSegment {
  255. // 先假设有所有的顺序分段,生成Join指令,后续根据Range再实际计算是否缺少流
  256. joinNode := ctx.DAG.NewSegmentJoin(ctx.Ft.SegmentParam.Segments)
  257. for i := 0; i < ctx.Ft.SegmentParam.SegmentCount(); i++ {
  258. str := findOutputStream(ctx, ioswitch2.SegmentStream(i))
  259. if str != nil {
  260. joinNode.SetInput(i, str)
  261. }
  262. }
  263. ctx.IndexedStreams = append(ctx.IndexedStreams, IndexedStream{
  264. Stream: joinNode.Joined(),
  265. StreamIndex: ioswitch2.RawStream(),
  266. })
  267. // SegmentJoin生成的Join指令可以用来生成EC块
  268. if ctx.UseEC {
  269. splitNode := ctx.DAG.NewChunkedSplit(ctx.Ft.ECParam.ChunkSize, ctx.Ft.ECParam.K)
  270. splitNode.Split(joinNode.Joined())
  271. mulNode := ctx.DAG.NewECMultiply(*ctx.Ft.ECParam)
  272. for i := 0; i < ctx.Ft.ECParam.K; i++ {
  273. mulNode.AddInput(splitNode.SubStream(i), i)
  274. ctx.IndexedStreams = append(ctx.IndexedStreams, IndexedStream{
  275. Stream: splitNode.SubStream(i),
  276. StreamIndex: ioswitch2.ECSrteam(i),
  277. })
  278. }
  279. for i := 0; i < ctx.Ft.ECParam.N; i++ {
  280. ctx.IndexedStreams = append(ctx.IndexedStreams, IndexedStream{
  281. Stream: mulNode.NewOutput(i),
  282. StreamIndex: ioswitch2.ECSrteam(i),
  283. })
  284. }
  285. }
  286. }
  287. // 为每一个To找到一个输入流
  288. for _, to := range ctx.Ft.Toes {
  289. toNode, err := buildToNode(ctx, to)
  290. if err != nil {
  291. return err
  292. }
  293. ctx.ToNodes[to] = toNode
  294. str := findOutputStream(ctx, to.GetStreamIndex())
  295. if str == nil {
  296. return fmt.Errorf("no output stream found for data index %d", to.GetStreamIndex())
  297. }
  298. toNode.SetInput(str)
  299. }
  300. return nil
  301. }
  302. func buildFromNode(ctx *ParseContext, f ioswitch2.From) (ops2.FromNode, error) {
  303. var repRange exec.Range
  304. repRange.Offset = ctx.StreamRange.Offset
  305. if ctx.StreamRange.Length != nil {
  306. repRngLen := *ctx.StreamRange.Length
  307. repRange.Length = &repRngLen
  308. }
  309. var blkRange exec.Range
  310. if ctx.UseEC {
  311. blkRange.Offset = ctx.StreamRange.Offset / int64(ctx.Ft.ECParam.ChunkSize*ctx.Ft.ECParam.K) * int64(ctx.Ft.ECParam.ChunkSize)
  312. if ctx.StreamRange.Length != nil {
  313. blkRngLen := *ctx.StreamRange.Length / int64(ctx.Ft.ECParam.ChunkSize*ctx.Ft.ECParam.K) * int64(ctx.Ft.ECParam.ChunkSize)
  314. blkRange.Length = &blkRngLen
  315. }
  316. }
  317. switch f := f.(type) {
  318. case *ioswitch2.FromShardstore:
  319. t := ctx.DAG.NewShardRead(f, f.Storage.StorageID, types.NewOpen(f.FileHash))
  320. if f.StreamIndex.IsRaw() {
  321. t.Open.WithNullableLength(repRange.Offset, repRange.Length)
  322. } else if f.StreamIndex.IsEC() {
  323. t.Open.WithNullableLength(blkRange.Offset, blkRange.Length)
  324. } else if f.StreamIndex.IsSegment() {
  325. segStart := ctx.Ft.SegmentParam.CalcSegmentStart(f.StreamIndex.Index)
  326. segLen := ctx.Ft.SegmentParam.Segments[f.StreamIndex.Index]
  327. segEnd := segStart + segLen
  328. // 打开的范围不超过本段的范围
  329. openOff := ctx.StreamRange.Offset - segStart
  330. openOff = math2.Clamp(openOff, 0, segLen)
  331. openLen := segLen
  332. if ctx.StreamRange.Length != nil {
  333. strEnd := ctx.StreamRange.Offset + *ctx.StreamRange.Length
  334. openEnd := math2.Min(strEnd, segEnd)
  335. openLen = openEnd - segStart - openOff
  336. }
  337. t.Open.WithNullableLength(openOff, &openLen)
  338. }
  339. switch addr := f.Hub.Address.(type) {
  340. case *cdssdk.HttpAddressInfo:
  341. t.Env().ToEnvWorker(&ioswitch2.HttpHubWorker{Hub: f.Hub})
  342. t.Env().Pinned = true
  343. case *cdssdk.GRPCAddressInfo:
  344. t.Env().ToEnvWorker(&ioswitch2.AgentWorker{Hub: f.Hub, Address: *addr})
  345. t.Env().Pinned = true
  346. default:
  347. return nil, fmt.Errorf("unsupported node address type %T", addr)
  348. }
  349. return t, nil
  350. case *ioswitch2.FromDriver:
  351. n := ctx.DAG.NewFromDriver(f, f.Handle)
  352. n.Env().ToEnvDriver()
  353. n.Env().Pinned = true
  354. if f.StreamIndex.IsRaw() {
  355. f.Handle.RangeHint.Offset = repRange.Offset
  356. f.Handle.RangeHint.Length = repRange.Length
  357. } else if f.StreamIndex.IsEC() {
  358. f.Handle.RangeHint.Offset = blkRange.Offset
  359. f.Handle.RangeHint.Length = blkRange.Length
  360. } else if f.StreamIndex.IsSegment() {
  361. segStart := ctx.Ft.SegmentParam.CalcSegmentStart(f.StreamIndex.Index)
  362. segLen := ctx.Ft.SegmentParam.Segments[f.StreamIndex.Index]
  363. segEnd := segStart + segLen
  364. // 打开的范围不超过本段的范围
  365. openOff := repRange.Offset - segStart
  366. openOff = math2.Clamp(openOff, 0, segLen)
  367. openLen := segLen
  368. if repRange.Length != nil {
  369. repEnd := repRange.Offset + *repRange.Length
  370. openEnd := math2.Min(repEnd, segEnd)
  371. openLen = openEnd - openOff
  372. }
  373. f.Handle.RangeHint.Offset = openOff
  374. f.Handle.RangeHint.Length = &openLen
  375. }
  376. return n, nil
  377. default:
  378. return nil, fmt.Errorf("unsupported from type %T", f)
  379. }
  380. }
  381. func buildToNode(ctx *ParseContext, t ioswitch2.To) (ops2.ToNode, error) {
  382. switch t := t.(type) {
  383. case *ioswitch2.ToShardStore:
  384. n := ctx.DAG.NewShardWrite(t, t.Storage.StorageID, t.FileHashStoreKey)
  385. if err := setEnvByAddress(n, t.Hub, t.Hub.Address); err != nil {
  386. return nil, err
  387. }
  388. n.Env().Pinned = true
  389. return n, nil
  390. case *ioswitch2.ToDriver:
  391. n := ctx.DAG.NewToDriver(t, t.Handle)
  392. n.Env().ToEnvDriver()
  393. n.Env().Pinned = true
  394. return n, nil
  395. case *ioswitch2.LoadToShared:
  396. n := ctx.DAG.NewSharedLoad(t, t.Storage.StorageID, t.UserID, t.PackageID, t.Path)
  397. if err := setEnvByAddress(n, t.Hub, t.Hub.Address); err != nil {
  398. return nil, err
  399. }
  400. n.Env().Pinned = true
  401. return n, nil
  402. default:
  403. return nil, fmt.Errorf("unsupported to type %T", t)
  404. }
  405. }
  406. func setEnvByAddress(n dag.Node, hub cdssdk.Hub, addr cdssdk.HubAddressInfo) error {
  407. switch addr := addr.(type) {
  408. case *cdssdk.HttpAddressInfo:
  409. n.Env().ToEnvWorker(&ioswitch2.HttpHubWorker{Hub: hub})
  410. case *cdssdk.GRPCAddressInfo:
  411. n.Env().ToEnvWorker(&ioswitch2.AgentWorker{Hub: hub, Address: *addr})
  412. default:
  413. return fmt.Errorf("unsupported node address type %T", addr)
  414. }
  415. return nil
  416. }
  417. // 根据StreamRange,调整SegmentSplit中分段的个数和每段的大小
  418. func fixSegmentSplit(ctx *ParseContext) error {
  419. var err error
  420. dag.WalkOnlyType[*ops2.SegmentSplitNode](ctx.DAG.Graph, func(node *ops2.SegmentSplitNode) bool {
  421. var strEnd *int64
  422. if ctx.StreamRange.Length != nil {
  423. e := ctx.StreamRange.Offset + *ctx.StreamRange.Length
  424. strEnd = &e
  425. }
  426. startSeg, endSeg := ctx.Ft.SegmentParam.CalcSegmentRange(ctx.StreamRange.Offset, strEnd)
  427. // 关闭超出范围的分段
  428. for i := 0; i < startSeg; i++ {
  429. node.Segments[i] = 0
  430. node.OutputStreams().Slots.Set(i, nil)
  431. }
  432. for i := endSeg; i < len(node.Segments); i++ {
  433. node.Segments[i] = 0
  434. node.OutputStreams().Slots.Set(i, nil)
  435. }
  436. // StreamRange开始的位置可能在某个分段的中间,此时这个分段的大小等于流开始位置到分段结束位置的距离
  437. startSegStart := ctx.Ft.SegmentParam.CalcSegmentStart(startSeg)
  438. node.Segments[startSeg] -= ctx.StreamRange.Offset - startSegStart
  439. // StreamRange结束的位置可能在某个分段的中间,此时这个分段的大小就等于流结束位置到分段起始位置的距离
  440. if strEnd != nil {
  441. endSegStart := ctx.Ft.SegmentParam.CalcSegmentStart(endSeg - 1)
  442. node.Segments[endSeg-1] = *strEnd - endSegStart
  443. }
  444. return true
  445. })
  446. return err
  447. }
  448. // 从SegmentJoin中删除未使用的分段
  449. func fixSegmentJoin(ctx *ParseContext) error {
  450. var err error
  451. dag.WalkOnlyType[*ops2.SegmentJoinNode](ctx.DAG.Graph, func(node *ops2.SegmentJoinNode) bool {
  452. start := ctx.StreamRange.Offset
  453. var end *int64
  454. if ctx.StreamRange.Length != nil {
  455. e := ctx.StreamRange.Offset + *ctx.StreamRange.Length
  456. end = &e
  457. }
  458. startSeg, endSeg := ctx.Ft.SegmentParam.CalcSegmentRange(start, end)
  459. // 关闭超出范围的分段
  460. for i := 0; i < startSeg; i++ {
  461. node.InputStreams().ClearInputAt(node, i)
  462. }
  463. for i := endSeg; i < node.InputStreams().Len(); i++ {
  464. node.InputStreams().ClearInputAt(node, i)
  465. }
  466. // 检查一下必须的分段是否都被加入到Join中
  467. for i := startSeg; i < endSeg; i++ {
  468. if node.InputStreams().Get(i) == nil {
  469. err = fmt.Errorf("segment %v missed to join an raw stream", i)
  470. return false
  471. }
  472. }
  473. return true
  474. })
  475. return err
  476. }
  477. // 删除未使用的SegmentJoin
  478. func removeUnusedSegmentJoin(ctx *ParseContext) bool {
  479. changed := false
  480. dag.WalkOnlyType[*ops2.SegmentJoinNode](ctx.DAG.Graph, func(node *ops2.SegmentJoinNode) bool {
  481. if node.Joined().Dst.Len() > 0 {
  482. return true
  483. }
  484. node.RemoveAllInputs()
  485. ctx.DAG.RemoveNode(node)
  486. return true
  487. })
  488. return changed
  489. }
  490. // 删除未使用的SegmentSplit
  491. func removeUnusedSegmentSplit(ctx *ParseContext) bool {
  492. changed := false
  493. dag.WalkOnlyType[*ops2.SegmentSplitNode](ctx.DAG.Graph, func(typ *ops2.SegmentSplitNode) bool {
  494. // Split出来的每一个流都没有被使用,才能删除这个指令
  495. for _, out := range typ.OutputStreams().Slots.RawArray() {
  496. if out.Dst.Len() > 0 {
  497. return true
  498. }
  499. }
  500. typ.RemoveAllStream()
  501. ctx.DAG.RemoveNode(typ)
  502. changed = true
  503. return true
  504. })
  505. return changed
  506. }
  507. // 如果Split的结果被完全用于Join,则省略Split和Join指令
  508. func omitSegmentSplitJoin(ctx *ParseContext) bool {
  509. changed := false
  510. dag.WalkOnlyType[*ops2.SegmentSplitNode](ctx.DAG.Graph, func(splitNode *ops2.SegmentSplitNode) bool {
  511. // Split指令的每一个输出都有且只有一个目的地
  512. var dstNode dag.Node
  513. for _, out := range splitNode.OutputStreams().Slots.RawArray() {
  514. if out.Dst.Len() != 1 {
  515. return true
  516. }
  517. if dstNode == nil {
  518. dstNode = out.Dst.Get(0)
  519. } else if dstNode != out.Dst.Get(0) {
  520. return true
  521. }
  522. }
  523. if dstNode == nil {
  524. return true
  525. }
  526. // 且这个目的地要是一个Join指令
  527. joinNode, ok := dstNode.(*ops2.SegmentJoinNode)
  528. if !ok {
  529. return true
  530. }
  531. // 同时这个Join指令的输入也必须全部来自Split指令的输出。
  532. // 由于上面判断了Split指令的输出目的地都相同,所以这里只要判断Join指令的输入数量是否与Split指令的输出数量相同即可
  533. if joinNode.InputStreams().Len() != splitNode.OutputStreams().Len() {
  534. return true
  535. }
  536. // 所有条件都满足,可以开始省略操作,将Join操作的目的地的输入流替换为Split操作的输入流:
  537. // F->Split->Join->T 变换为:F->T
  538. splitInput := splitNode.InputStreams().Get(0)
  539. for _, to := range joinNode.Joined().Dst.RawArray() {
  540. splitInput.To(to, to.InputStreams().IndexOf(joinNode.Joined()))
  541. }
  542. splitInput.NotTo(splitNode)
  543. // 并删除这两个指令
  544. ctx.DAG.RemoveNode(joinNode)
  545. ctx.DAG.RemoveNode(splitNode)
  546. changed = true
  547. return true
  548. })
  549. return changed
  550. }
  551. // 删除输出流未被使用的Join指令
  552. func removeUnusedJoin(ctx *ParseContext) bool {
  553. changed := false
  554. dag.WalkOnlyType[*ops2.ChunkedJoinNode](ctx.DAG.Graph, func(node *ops2.ChunkedJoinNode) bool {
  555. if node.Joined().Dst.Len() > 0 {
  556. return true
  557. }
  558. node.RemoveAllInputs()
  559. ctx.DAG.RemoveNode(node)
  560. return true
  561. })
  562. return changed
  563. }
  564. // 减少未使用的Multiply指令的输出流。如果减少到0,则删除该指令
  565. func removeUnusedMultiplyOutput(ctx *ParseContext) bool {
  566. changed := false
  567. dag.WalkOnlyType[*ops2.ECMultiplyNode](ctx.DAG.Graph, func(node *ops2.ECMultiplyNode) bool {
  568. outArr := node.OutputStreams().Slots.RawArray()
  569. for i2, out := range outArr {
  570. if out.Dst.Len() > 0 {
  571. continue
  572. }
  573. outArr[i2] = nil
  574. node.OutputIndexes[i2] = -2
  575. changed = true
  576. }
  577. node.OutputStreams().Slots.SetRawArray(lo2.RemoveAllDefault(outArr))
  578. node.OutputIndexes = lo2.RemoveAll(node.OutputIndexes, -2)
  579. // 如果所有输出流都被删除,则删除该指令
  580. if node.OutputStreams().Len() == 0 {
  581. node.RemoveAllInputs()
  582. ctx.DAG.RemoveNode(node)
  583. changed = true
  584. }
  585. return true
  586. })
  587. return changed
  588. }
  589. // 删除未使用的Split指令
  590. func removeUnusedSplit(ctx *ParseContext) bool {
  591. changed := false
  592. dag.WalkOnlyType[*ops2.ChunkedSplitNode](ctx.DAG.Graph, func(typ *ops2.ChunkedSplitNode) bool {
  593. // Split出来的每一个流都没有被使用,才能删除这个指令
  594. for _, out := range typ.OutputStreams().Slots.RawArray() {
  595. if out.Dst.Len() > 0 {
  596. return true
  597. }
  598. }
  599. typ.RemoveAllStream()
  600. ctx.DAG.RemoveNode(typ)
  601. changed = true
  602. return true
  603. })
  604. return changed
  605. }
  606. // 如果Split的结果被完全用于Join,则省略Split和Join指令
  607. func omitSplitJoin(ctx *ParseContext) bool {
  608. changed := false
  609. dag.WalkOnlyType[*ops2.ChunkedSplitNode](ctx.DAG.Graph, func(splitNode *ops2.ChunkedSplitNode) bool {
  610. // Split指令的每一个输出都有且只有一个目的地
  611. var dstNode dag.Node
  612. for _, out := range splitNode.OutputStreams().Slots.RawArray() {
  613. if out.Dst.Len() != 1 {
  614. return true
  615. }
  616. if dstNode == nil {
  617. dstNode = out.Dst.Get(0)
  618. } else if dstNode != out.Dst.Get(0) {
  619. return true
  620. }
  621. }
  622. if dstNode == nil {
  623. return true
  624. }
  625. // 且这个目的地要是一个Join指令
  626. joinNode, ok := dstNode.(*ops2.ChunkedJoinNode)
  627. if !ok {
  628. return true
  629. }
  630. // 同时这个Join指令的输入也必须全部来自Split指令的输出。
  631. // 由于上面判断了Split指令的输出目的地都相同,所以这里只要判断Join指令的输入数量是否与Split指令的输出数量相同即可
  632. if joinNode.InputStreams().Len() != splitNode.OutputStreams().Len() {
  633. return true
  634. }
  635. // 所有条件都满足,可以开始省略操作,将Join操作的目的地的输入流替换为Split操作的输入流:
  636. // F->Split->Join->T 变换为:F->T
  637. splitInput := splitNode.InputStreams().Get(0)
  638. for _, to := range joinNode.Joined().Dst.RawArray() {
  639. splitInput.To(to, to.InputStreams().IndexOf(joinNode.Joined()))
  640. }
  641. splitInput.NotTo(splitNode)
  642. // 并删除这两个指令
  643. ctx.DAG.RemoveNode(joinNode)
  644. ctx.DAG.RemoveNode(splitNode)
  645. changed = true
  646. return true
  647. })
  648. return changed
  649. }
  650. // 通过流的输入输出位置来确定指令的执行位置。
  651. // To系列的指令都会有固定的执行位置,这些位置会随着pin操作逐步扩散到整个DAG,
  652. // 所以理论上不会出现有指令的位置始终无法确定的情况。
  653. func pin(ctx *ParseContext) bool {
  654. changed := false
  655. ctx.DAG.Walk(func(node dag.Node) bool {
  656. if node.Env().Pinned {
  657. return true
  658. }
  659. var toEnv *dag.NodeEnv
  660. for _, out := range node.OutputStreams().Slots.RawArray() {
  661. for _, to := range out.Dst.RawArray() {
  662. if to.Env().Type == dag.EnvUnknown {
  663. continue
  664. }
  665. if toEnv == nil {
  666. toEnv = to.Env()
  667. } else if !toEnv.Equals(to.Env()) {
  668. toEnv = nil
  669. break
  670. }
  671. }
  672. }
  673. if toEnv != nil {
  674. if !node.Env().Equals(toEnv) {
  675. changed = true
  676. }
  677. *node.Env() = *toEnv
  678. return true
  679. }
  680. // 否则根据输入流的始发地来固定
  681. var fromEnv *dag.NodeEnv
  682. for _, in := range node.InputStreams().Slots.RawArray() {
  683. if in.Src.Env().Type == dag.EnvUnknown {
  684. continue
  685. }
  686. if fromEnv == nil {
  687. fromEnv = in.Src.Env()
  688. } else if !fromEnv.Equals(in.Src.Env()) {
  689. fromEnv = nil
  690. break
  691. }
  692. }
  693. if fromEnv != nil {
  694. if !node.Env().Equals(fromEnv) {
  695. changed = true
  696. }
  697. *node.Env() = *fromEnv
  698. }
  699. return true
  700. })
  701. return changed
  702. }
  703. // 删除未使用的From流,不会删除FromDriver
  704. func removeUnusedFromNode(ctx *ParseContext) {
  705. dag.WalkOnlyType[ops2.FromNode](ctx.DAG.Graph, func(node ops2.FromNode) bool {
  706. if _, ok := node.(*ops2.FromDriverNode); ok {
  707. return true
  708. }
  709. if node.Output().Var == nil {
  710. ctx.DAG.RemoveNode(node)
  711. }
  712. return true
  713. })
  714. }
  715. // 对于所有未使用的流,增加Drop指令
  716. func dropUnused(ctx *ParseContext) {
  717. ctx.DAG.Walk(func(node dag.Node) bool {
  718. for _, out := range node.OutputStreams().Slots.RawArray() {
  719. if out.Dst.Len() == 0 {
  720. n := ctx.DAG.NewDropStream()
  721. *n.Env() = *node.Env()
  722. n.SetInput(out)
  723. }
  724. }
  725. return true
  726. })
  727. }
  728. // 为IPFS写入指令存储结果
  729. func storeIPFSWriteResult(ctx *ParseContext) {
  730. dag.WalkOnlyType[*ops2.ShardWriteNode](ctx.DAG.Graph, func(n *ops2.ShardWriteNode) bool {
  731. if n.FileHashStoreKey == "" {
  732. return true
  733. }
  734. storeNode := ctx.DAG.NewStore()
  735. storeNode.Env().ToEnvDriver()
  736. storeNode.Store(n.FileHashStoreKey, n.FileHashVar())
  737. return true
  738. })
  739. }
  740. // 生成Range指令。StreamRange可能超过文件总大小,但Range指令会在数据量不够时不报错而是正常返回
  741. func generateRange(ctx *ParseContext) {
  742. for i := 0; i < len(ctx.Ft.Toes); i++ {
  743. to := ctx.Ft.Toes[i]
  744. toNode := ctx.ToNodes[to]
  745. toStrIdx := to.GetStreamIndex()
  746. toRng := to.GetRange()
  747. if toStrIdx.IsRaw() {
  748. n := ctx.DAG.NewRange()
  749. toInput := toNode.Input()
  750. *n.Env() = *toInput.Var.Src.Env()
  751. rnged := n.RangeStream(toInput.Var, exec.Range{
  752. Offset: toRng.Offset - ctx.StreamRange.Offset,
  753. Length: toRng.Length,
  754. })
  755. toInput.Var.NotTo(toNode)
  756. toNode.SetInput(rnged)
  757. } else if toStrIdx.IsEC() {
  758. stripSize := int64(ctx.Ft.ECParam.ChunkSize * ctx.Ft.ECParam.K)
  759. blkStartIdx := ctx.StreamRange.Offset / stripSize
  760. blkStart := blkStartIdx * int64(ctx.Ft.ECParam.ChunkSize)
  761. n := ctx.DAG.NewRange()
  762. toInput := toNode.Input()
  763. *n.Env() = *toInput.Var.Src.Env()
  764. rnged := n.RangeStream(toInput.Var, exec.Range{
  765. Offset: toRng.Offset - blkStart,
  766. Length: toRng.Length,
  767. })
  768. toInput.Var.NotTo(toNode)
  769. toNode.SetInput(rnged)
  770. } else if toStrIdx.IsSegment() {
  771. // if frNode, ok := toNode.Input().Var.From().Node.(ops2.FromNode); ok {
  772. // // 目前只有To也是分段时,才可能对接一个提供分段的From,此时不需要再生成Range指令
  773. // if frNode.GetFrom().GetStreamIndex().IsSegment() {
  774. // continue
  775. // }
  776. // }
  777. // segStart := ctx.Ft.SegmentParam.CalcSegmentStart(toStrIdx.Index)
  778. // strStart := segStart + toRng.Offset
  779. // n := ctx.DAG.NewRange()
  780. // toInput := toNode.Input()
  781. // *n.Env() = *toInput.Var.From().Node.Env()
  782. // rnged := n.RangeStream(toInput.Var, exec.Range{
  783. // Offset: strStart - ctx.StreamRange.Offset,
  784. // Length: toRng.Length,
  785. // })
  786. // toInput.Var.NotTo(toNode, toInput.Index)
  787. // toNode.SetInput(rnged)
  788. }
  789. }
  790. }
  791. // 生成Clone指令
  792. func generateClone(ctx *ParseContext) {
  793. ctx.DAG.Walk(func(node dag.Node) bool {
  794. for _, outVar := range node.OutputStreams().Slots.RawArray() {
  795. if outVar.Dst.Len() <= 1 {
  796. continue
  797. }
  798. c := ctx.DAG.NewCloneStream()
  799. *c.Env() = *node.Env()
  800. for _, to := range outVar.Dst.RawArray() {
  801. c.NewOutput().To(to, to.InputStreams().IndexOf(outVar))
  802. }
  803. outVar.Dst.Resize(0)
  804. c.SetInput(outVar)
  805. }
  806. for _, outVar := range node.OutputValues().Slots.RawArray() {
  807. if outVar.Dst.Len() <= 1 {
  808. continue
  809. }
  810. t := ctx.DAG.NewCloneValue()
  811. *t.Env() = *node.Env()
  812. for _, to := range outVar.Dst.RawArray() {
  813. t.NewOutput().To(to, to.InputValues().IndexOf(outVar))
  814. }
  815. outVar.Dst.Resize(0)
  816. t.SetInput(outVar)
  817. }
  818. return true
  819. })
  820. }

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