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.

ec.go 8.0 kB

1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347
  1. package ops2
  2. import (
  3. "fmt"
  4. "io"
  5. "gitlink.org.cn/cloudream/common/pkgs/future"
  6. "gitlink.org.cn/cloudream/common/pkgs/ioswitch/dag"
  7. "gitlink.org.cn/cloudream/common/pkgs/ioswitch/exec"
  8. "gitlink.org.cn/cloudream/common/pkgs/ioswitch/utils"
  9. cdssdk "gitlink.org.cn/cloudream/common/sdks/storage"
  10. "gitlink.org.cn/cloudream/common/utils/io2"
  11. "gitlink.org.cn/cloudream/common/utils/math2"
  12. "gitlink.org.cn/cloudream/common/utils/sync2"
  13. stgmod "gitlink.org.cn/cloudream/storage/common/models"
  14. "gitlink.org.cn/cloudream/storage/common/pkgs/ec"
  15. "gitlink.org.cn/cloudream/storage/common/pkgs/storage/factory"
  16. "gitlink.org.cn/cloudream/storage/common/pkgs/storage/types"
  17. )
  18. func init() {
  19. exec.UseOp[*ECMultiply]()
  20. exec.UseOp[*CallECMultiplier]()
  21. }
  22. type ECMultiply struct {
  23. Coef [][]byte `json:"coef"`
  24. Inputs []exec.VarID `json:"inputs"`
  25. Outputs []exec.VarID `json:"outputs"`
  26. ChunkSize int `json:"chunkSize"`
  27. }
  28. func (o *ECMultiply) Execute(ctx *exec.ExecContext, e *exec.Executor) error {
  29. inputs, err := exec.BindArray[*exec.StreamValue](e, ctx.Context, o.Inputs)
  30. if err != nil {
  31. return err
  32. }
  33. defer func() {
  34. for _, s := range inputs {
  35. s.Stream.Close()
  36. }
  37. }()
  38. outputWrs := make([]*io.PipeWriter, len(o.Outputs))
  39. outputVars := make([]*exec.StreamValue, len(o.Outputs))
  40. for i := range o.Outputs {
  41. rd, wr := io.Pipe()
  42. outputVars[i] = &exec.StreamValue{Stream: rd}
  43. outputWrs[i] = wr
  44. }
  45. inputChunks := make([][]byte, len(o.Inputs))
  46. for i := range o.Inputs {
  47. inputChunks[i] = make([]byte, math2.Min(o.ChunkSize, 64*1024))
  48. }
  49. // 输出用两个缓冲轮换
  50. outputBufPool := sync2.NewBucketPool[[][]byte]()
  51. for i := 0; i < 2; i++ {
  52. outputChunks := make([][]byte, len(o.Outputs))
  53. for i := range o.Outputs {
  54. outputChunks[i] = make([]byte, math2.Min(o.ChunkSize, 64*1024))
  55. }
  56. outputBufPool.PutEmpty(outputChunks)
  57. }
  58. fut := future.NewSetVoid()
  59. go func() {
  60. mul := ec.GaloisMultiplier().BuildGalois()
  61. defer outputBufPool.Close()
  62. readLens := math2.SplitLessThan(o.ChunkSize, 64*1024)
  63. readLenIdx := 0
  64. for {
  65. curReadLen := readLens[readLenIdx]
  66. for i := range inputChunks {
  67. inputChunks[i] = inputChunks[i][:curReadLen]
  68. }
  69. err := sync2.ParallelDo(inputs, func(s *exec.StreamValue, i int) error {
  70. _, err := io.ReadFull(s.Stream, inputChunks[i])
  71. return err
  72. })
  73. if err == io.EOF {
  74. fut.SetVoid()
  75. return
  76. }
  77. if err != nil {
  78. fut.SetError(err)
  79. return
  80. }
  81. outputBuf, ok := outputBufPool.GetEmpty()
  82. if !ok {
  83. return
  84. }
  85. for i := range outputBuf {
  86. outputBuf[i] = outputBuf[i][:curReadLen]
  87. }
  88. err = mul.Multiply(o.Coef, inputChunks, outputBuf)
  89. if err != nil {
  90. fut.SetError(err)
  91. return
  92. }
  93. outputBufPool.PutFilled(outputBuf)
  94. readLenIdx = (readLenIdx + 1) % len(readLens)
  95. }
  96. }()
  97. go func() {
  98. defer outputBufPool.Close()
  99. for {
  100. outputChunks, ok := outputBufPool.GetFilled()
  101. if !ok {
  102. return
  103. }
  104. for i := range o.Outputs {
  105. err := io2.WriteAll(outputWrs[i], outputChunks[i])
  106. if err != nil {
  107. fut.SetError(err)
  108. return
  109. }
  110. }
  111. outputBufPool.PutEmpty(outputChunks)
  112. }
  113. }()
  114. exec.PutArray(e, o.Outputs, outputVars)
  115. err = fut.Wait(ctx.Context)
  116. if err != nil {
  117. for _, wr := range outputWrs {
  118. wr.CloseWithError(err)
  119. }
  120. return err
  121. }
  122. for _, wr := range outputWrs {
  123. wr.Close()
  124. }
  125. return nil
  126. }
  127. func (o *ECMultiply) String() string {
  128. return fmt.Sprintf(
  129. "ECMultiply(coef=%v) (%v) -> (%v)",
  130. o.Coef,
  131. utils.FormatVarIDs(o.Inputs),
  132. utils.FormatVarIDs(o.Outputs),
  133. )
  134. }
  135. type CallECMultiplier struct {
  136. Storage stgmod.StorageDetail
  137. Coef [][]byte
  138. Inputs []exec.VarID
  139. Outputs []exec.VarID
  140. BypassCallbacks []exec.VarID
  141. ChunkSize int
  142. }
  143. func (o *CallECMultiplier) Execute(ctx *exec.ExecContext, e *exec.Executor) error {
  144. ecMul, err := factory.GetBuilder(o.Storage).CreateECMultiplier()
  145. if err != nil {
  146. return err
  147. }
  148. inputs, err := exec.BindArray[*HTTPRequestValue](e, ctx.Context, o.Inputs)
  149. if err != nil {
  150. return err
  151. }
  152. reqs := make([]types.HTTPRequest, 0, len(inputs))
  153. for _, input := range inputs {
  154. reqs = append(reqs, input.HTTPRequest)
  155. }
  156. outputs, err := ecMul.Multiply(o.Coef, reqs, o.ChunkSize)
  157. if err != nil {
  158. return err
  159. }
  160. defer ecMul.Abort()
  161. outputVals := make([]*BypassUploadedFileValue, 0, len(outputs))
  162. for _, output := range outputs {
  163. outputVals = append(outputVals, &BypassUploadedFileValue{
  164. BypassUploadedFile: output,
  165. })
  166. }
  167. exec.PutArray(e, o.Outputs, outputVals)
  168. callbacks, err := exec.BindArray[*BypassHandleResultValue](e, ctx.Context, o.BypassCallbacks)
  169. if err != nil {
  170. return err
  171. }
  172. allSuc := true
  173. for _, callback := range callbacks {
  174. if !callback.Commited {
  175. allSuc = false
  176. }
  177. }
  178. if allSuc {
  179. ecMul.Complete()
  180. }
  181. return nil
  182. }
  183. func (o *CallECMultiplier) String() string {
  184. return fmt.Sprintf(
  185. "CallECMultiplier(storage=%v, coef=%v) (%v) -> (%v)",
  186. o.Coef,
  187. o.Storage.Storage.String(),
  188. utils.FormatVarIDs(o.Inputs),
  189. utils.FormatVarIDs(o.Outputs),
  190. )
  191. }
  192. type ECMultiplyNode struct {
  193. dag.NodeBase
  194. EC cdssdk.ECRedundancy
  195. InputIndexes []int
  196. OutputIndexes []int
  197. }
  198. func (b *GraphNodeBuilder) NewECMultiply(ec cdssdk.ECRedundancy) *ECMultiplyNode {
  199. node := &ECMultiplyNode{
  200. EC: ec,
  201. }
  202. b.AddNode(node)
  203. return node
  204. }
  205. func (t *ECMultiplyNode) AddInput(str *dag.StreamVar, dataIndex int) {
  206. t.InputIndexes = append(t.InputIndexes, dataIndex)
  207. idx := t.InputStreams().EnlargeOne()
  208. str.To(t, idx)
  209. }
  210. func (t *ECMultiplyNode) RemoveAllInputs() {
  211. t.InputStreams().ClearAllInput(t)
  212. t.InputStreams().Slots.Resize(0)
  213. t.InputIndexes = nil
  214. }
  215. func (t *ECMultiplyNode) NewOutput(dataIndex int) *dag.StreamVar {
  216. t.OutputIndexes = append(t.OutputIndexes, dataIndex)
  217. return t.OutputStreams().AppendNew(t).Var()
  218. }
  219. func (t *ECMultiplyNode) GenerateOp() (exec.Op, error) {
  220. rs, err := ec.NewRs(t.EC.K, t.EC.N)
  221. if err != nil {
  222. return nil, err
  223. }
  224. coef, err := rs.GenerateMatrix(t.InputIndexes, t.OutputIndexes)
  225. if err != nil {
  226. return nil, err
  227. }
  228. return &ECMultiply{
  229. Coef: coef,
  230. Inputs: t.InputStreams().GetVarIDs(),
  231. Outputs: t.OutputStreams().GetVarIDs(),
  232. ChunkSize: t.EC.ChunkSize,
  233. }, nil
  234. }
  235. // func (t *MultiplyType) String() string {
  236. // return fmt.Sprintf("Multiply[]%v%v", formatStreamIO(node), formatValueIO(node))
  237. // }
  238. type CallECMultiplierNode struct {
  239. dag.NodeBase
  240. Storage stgmod.StorageDetail
  241. EC cdssdk.ECRedundancy
  242. InputIndexes []int
  243. OutputIndexes []int
  244. }
  245. func (b *GraphNodeBuilder) NewCallECMultiplier(storage stgmod.StorageDetail) *CallECMultiplierNode {
  246. node := &CallECMultiplierNode{
  247. Storage: storage,
  248. }
  249. b.AddNode(node)
  250. return node
  251. }
  252. func (t *CallECMultiplierNode) InitFrom(node *ECMultiplyNode) {
  253. t.EC = node.EC
  254. t.InputIndexes = node.InputIndexes
  255. t.OutputIndexes = node.OutputIndexes
  256. t.InputValues().Init(len(t.InputIndexes) + len(t.OutputIndexes)) // 流的输出+回调的输入
  257. t.OutputValues().Init(t, len(t.OutputIndexes))
  258. }
  259. func (t *CallECMultiplierNode) InputSlot(idx int) dag.ValueInputSlot {
  260. return dag.ValueInputSlot{
  261. Node: t,
  262. Index: idx,
  263. }
  264. }
  265. func (t *CallECMultiplierNode) OutputVar(idx int) dag.ValueOutputSlot {
  266. return dag.ValueOutputSlot{
  267. Node: t,
  268. Index: idx,
  269. }
  270. }
  271. func (t *CallECMultiplierNode) BypassCallbackSlot(idx int) dag.ValueInputSlot {
  272. return dag.ValueInputSlot{
  273. Node: t,
  274. Index: idx + len(t.InputIndexes),
  275. }
  276. }
  277. func (t *CallECMultiplierNode) GenerateOp() (exec.Op, error) {
  278. rs, err := ec.NewRs(t.EC.K, t.EC.N)
  279. if err != nil {
  280. return nil, err
  281. }
  282. coef, err := rs.GenerateMatrix(t.InputIndexes, t.OutputIndexes)
  283. if err != nil {
  284. return nil, err
  285. }
  286. return &CallECMultiplier{
  287. Storage: t.Storage,
  288. Coef: coef,
  289. Inputs: t.InputValues().GetVarIDsRanged(0, len(t.InputIndexes)),
  290. Outputs: t.OutputValues().GetVarIDs(),
  291. BypassCallbacks: t.InputValues().GetVarIDsStart(len(t.InputIndexes)),
  292. ChunkSize: t.EC.ChunkSize,
  293. }, nil
  294. }

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