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.

base_store.go 8.3 kB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351
  1. package ops2
  2. import (
  3. "fmt"
  4. "io"
  5. "time"
  6. "gitlink.org.cn/cloudream/common/pkgs/future"
  7. "gitlink.org.cn/cloudream/common/pkgs/logger"
  8. "gitlink.org.cn/cloudream/common/utils/io2"
  9. "gitlink.org.cn/cloudream/jcs-pub/common/pkgs/ioswitch/dag"
  10. "gitlink.org.cn/cloudream/jcs-pub/common/pkgs/ioswitch/exec"
  11. "gitlink.org.cn/cloudream/jcs-pub/common/pkgs/ioswitch2"
  12. "gitlink.org.cn/cloudream/jcs-pub/common/pkgs/storage/pool"
  13. stgtypes "gitlink.org.cn/cloudream/jcs-pub/common/pkgs/storage/types"
  14. jcstypes "gitlink.org.cn/cloudream/jcs-pub/common/types"
  15. )
  16. const (
  17. BaseReadStatsStoreKey = "Stats.BaseRead"
  18. )
  19. func init() {
  20. exec.UseOp[*BaseWrite]()
  21. exec.UseOp[*BaseRead]()
  22. exec.UseOp[*BaseReadDyn]()
  23. exec.UseVarValue[*BaseReadStatsValue]()
  24. }
  25. type BaseReadStatsValue struct {
  26. StatsCtx string
  27. Length int64
  28. ElapsedTime time.Duration
  29. Location exec.Location
  30. }
  31. func (v *BaseReadStatsValue) Clone() exec.VarValue {
  32. return &BaseReadStatsValue{
  33. StatsCtx: v.StatsCtx,
  34. Length: v.Length,
  35. ElapsedTime: v.ElapsedTime,
  36. Location: v.Location,
  37. }
  38. }
  39. type BaseRead struct {
  40. Output exec.VarID
  41. UserSpace jcstypes.UserSpaceDetail
  42. Path jcstypes.JPath
  43. Option stgtypes.OpenOption
  44. StatsCtx string
  45. }
  46. func (o *BaseRead) Execute(ctx *exec.ExecContext, e *exec.Executor) error {
  47. logger.
  48. WithField("Output", o.Output).
  49. WithField("UserSpace", o.UserSpace).
  50. WithField("Path", o.Path).
  51. Debug("base read")
  52. defer logger.Debug("base read end")
  53. stgPool, err := exec.GetValueByType[*pool.Pool](ctx)
  54. if err != nil {
  55. return fmt.Errorf("getting storage pool: %w", err)
  56. }
  57. store, err := stgPool.GetBaseStore(&o.UserSpace)
  58. if err != nil {
  59. return fmt.Errorf("getting base store of storage %v: %w", o.UserSpace, err)
  60. }
  61. stream, err := store.Read(o.Path, o.Option)
  62. if err != nil {
  63. return fmt.Errorf("reading object %v: %w", o.Path, err)
  64. }
  65. startTime := time.Now()
  66. counter := io2.CounterCloser(stream, nil)
  67. fut := future.NewSetVoid()
  68. output := &exec.StreamValue{
  69. Stream: io2.AfterReadClosed(counter, func(closer io.ReadCloser) {
  70. fut.SetVoid()
  71. }),
  72. }
  73. e.PutVar(o.Output, output)
  74. err = fut.Wait(ctx.Context)
  75. e.Store(BaseReadStatsStoreKey, &BaseReadStatsValue{
  76. StatsCtx: o.StatsCtx,
  77. Length: counter.Count(),
  78. ElapsedTime: time.Since(startTime),
  79. Location: e.Location(),
  80. })
  81. return err
  82. }
  83. func (o *BaseRead) String() string {
  84. return fmt.Sprintf("BaseRead(opt=%v) %v:%v -> %v", o.Option, o.UserSpace, o.Path, o.Output)
  85. }
  86. type BaseReadDyn struct {
  87. UserSpace jcstypes.UserSpaceDetail
  88. Output exec.VarID
  89. FileInfo exec.VarID
  90. Option stgtypes.OpenOption
  91. StatsCtx string
  92. }
  93. func (o *BaseReadDyn) Execute(ctx *exec.ExecContext, e *exec.Executor) error {
  94. logger.
  95. WithField("Output", o.Output).
  96. WithField("UserSpace", o.UserSpace).
  97. WithField("Path", o.FileInfo).
  98. Debug("base read dynamic")
  99. defer logger.Debug("base read dynamic end")
  100. stgPool, err := exec.GetValueByType[*pool.Pool](ctx)
  101. if err != nil {
  102. return fmt.Errorf("getting storage pool: %w", err)
  103. }
  104. info, err := exec.BindVar[*FileInfoValue](e, ctx.Context, o.FileInfo)
  105. if err != nil {
  106. return err
  107. }
  108. store, err := stgPool.GetBaseStore(&o.UserSpace)
  109. if err != nil {
  110. return fmt.Errorf("getting base store of storage %v: %w", o.UserSpace, err)
  111. }
  112. stream, err := store.Read(info.Path, o.Option)
  113. if err != nil {
  114. logger.Warnf("reading file %v: %v", info.Path, err)
  115. return fmt.Errorf("reading object %v: %w", o.FileInfo, err)
  116. }
  117. startTime := time.Now()
  118. counter := io2.CounterCloser(stream, nil)
  119. fut := future.NewSetVoid()
  120. output := &exec.StreamValue{
  121. Stream: io2.AfterReadClosed(counter, func(closer io.ReadCloser) {
  122. fut.SetVoid()
  123. }),
  124. }
  125. e.PutVar(o.Output, output)
  126. err = fut.Wait(ctx.Context)
  127. e.Store(BaseReadStatsStoreKey, &BaseReadStatsValue{
  128. Length: counter.Count(),
  129. ElapsedTime: time.Since(startTime),
  130. Location: e.Location(),
  131. StatsCtx: o.StatsCtx,
  132. })
  133. return err
  134. }
  135. func (o *BaseReadDyn) String() string {
  136. return fmt.Sprintf("BaseReadDyn(opt=%v) %v:%v -> %v", o.Option, o.UserSpace, o.FileInfo, o.Output)
  137. }
  138. type BaseWrite struct {
  139. Input exec.VarID
  140. UserSpace jcstypes.UserSpaceDetail
  141. Path jcstypes.JPath
  142. FileInfo exec.VarID
  143. Option stgtypes.WriteOption
  144. }
  145. func (o *BaseWrite) Execute(ctx *exec.ExecContext, e *exec.Executor) error {
  146. logger.
  147. WithField("Input", o.Input).
  148. Debugf("write file to base store")
  149. defer logger.Debugf("write file to base store finished")
  150. stgPool, err := exec.GetValueByType[*pool.Pool](ctx)
  151. if err != nil {
  152. return fmt.Errorf("getting storage pool: %w", err)
  153. }
  154. store, err := stgPool.GetBaseStore(&o.UserSpace)
  155. if err != nil {
  156. return fmt.Errorf("getting base store of storage %v: %w", o.UserSpace, err)
  157. }
  158. input, err := exec.BindVar[*exec.StreamValue](e, ctx.Context, o.Input)
  159. if err != nil {
  160. return err
  161. }
  162. defer input.Stream.Close()
  163. ret, err := store.Write(o.Path, input.Stream, o.Option)
  164. if err != nil {
  165. return err
  166. }
  167. e.PutVar(o.FileInfo, &FileInfoValue{
  168. FileInfo: ret,
  169. })
  170. return nil
  171. }
  172. func (o *BaseWrite) String() string {
  173. return fmt.Sprintf("BaseWrite %v -> %v:%v, %v", o.Input, o.UserSpace, o.Path, o.FileInfo)
  174. }
  175. type BaseReadNode struct {
  176. dag.NodeBase
  177. From ioswitch2.From
  178. UserSpace jcstypes.UserSpaceDetail
  179. Path jcstypes.JPath
  180. Option stgtypes.OpenOption
  181. StatsCtx string
  182. }
  183. func (b *GraphNodeBuilder) NewBaseRead(from ioswitch2.From, userSpace jcstypes.UserSpaceDetail, path jcstypes.JPath, opt stgtypes.OpenOption, statsCtx string) *BaseReadNode {
  184. node := &BaseReadNode{
  185. From: from,
  186. UserSpace: userSpace,
  187. Path: path,
  188. Option: opt,
  189. StatsCtx: statsCtx,
  190. }
  191. b.AddNode(node)
  192. node.OutputStreams().Init(node, 1)
  193. return node
  194. }
  195. func (t *BaseReadNode) GetFrom() ioswitch2.From {
  196. return t.From
  197. }
  198. func (t *BaseReadNode) Output() dag.StreamOutputSlot {
  199. return dag.StreamOutputSlot{
  200. Node: t,
  201. Index: 0,
  202. }
  203. }
  204. func (t *BaseReadNode) GenerateOp() (exec.Op, error) {
  205. return &BaseRead{
  206. Output: t.Output().Var().VarID,
  207. UserSpace: t.UserSpace,
  208. Path: t.Path,
  209. Option: t.Option,
  210. StatsCtx: t.StatsCtx,
  211. }, nil
  212. }
  213. type BaseReadDynNode struct {
  214. dag.NodeBase
  215. From ioswitch2.From
  216. UserSpace jcstypes.UserSpaceDetail
  217. Option stgtypes.OpenOption
  218. StatsCtx string
  219. }
  220. func (b *GraphNodeBuilder) NewBaseReadDyn(from ioswitch2.From, userSpace jcstypes.UserSpaceDetail, opt stgtypes.OpenOption, statsCtx string) *BaseReadDynNode {
  221. node := &BaseReadDynNode{
  222. From: from,
  223. UserSpace: userSpace,
  224. Option: opt,
  225. StatsCtx: statsCtx,
  226. }
  227. b.AddNode(node)
  228. node.OutputStreams().Init(node, 1)
  229. node.InputValues().Init(1)
  230. return node
  231. }
  232. func (t *BaseReadDynNode) GetFrom() ioswitch2.From {
  233. return t.From
  234. }
  235. func (t *BaseReadDynNode) FileInfoSlot() dag.ValueInputSlot {
  236. return dag.ValueInputSlot{
  237. Node: t,
  238. Index: 0,
  239. }
  240. }
  241. func (t *BaseReadDynNode) Output() dag.StreamOutputSlot {
  242. return dag.StreamOutputSlot{
  243. Node: t,
  244. Index: 0,
  245. }
  246. }
  247. func (t *BaseReadDynNode) GenerateOp() (exec.Op, error) {
  248. return &BaseReadDyn{
  249. UserSpace: t.UserSpace,
  250. Output: t.Output().Var().VarID,
  251. FileInfo: t.FileInfoSlot().Var().VarID,
  252. Option: t.Option,
  253. StatsCtx: t.StatsCtx,
  254. }, nil
  255. }
  256. type BaseWriteNode struct {
  257. dag.NodeBase
  258. To ioswitch2.To
  259. UserSpace jcstypes.UserSpaceDetail
  260. Path jcstypes.JPath
  261. Option stgtypes.WriteOption
  262. }
  263. func (b *GraphNodeBuilder) NewBaseWrite(to ioswitch2.To, userSpace jcstypes.UserSpaceDetail, path jcstypes.JPath, opt stgtypes.WriteOption) *BaseWriteNode {
  264. node := &BaseWriteNode{
  265. To: to,
  266. UserSpace: userSpace,
  267. Path: path,
  268. Option: opt,
  269. }
  270. b.AddNode(node)
  271. node.InputStreams().Init(1)
  272. node.OutputValues().Init(node, 1)
  273. return node
  274. }
  275. func (t *BaseWriteNode) GetTo() ioswitch2.To {
  276. return t.To
  277. }
  278. func (t *BaseWriteNode) Input() dag.StreamInputSlot {
  279. return dag.StreamInputSlot{
  280. Node: t,
  281. Index: 0,
  282. }
  283. }
  284. func (t *BaseWriteNode) FileInfoVar() dag.ValueOutputSlot {
  285. return dag.ValueOutputSlot{
  286. Node: t,
  287. Index: 0,
  288. }
  289. }
  290. func (t *BaseWriteNode) GenerateOp() (exec.Op, error) {
  291. return &BaseWrite{
  292. Input: t.InputStreams().Get(0).VarID,
  293. UserSpace: t.UserSpace,
  294. Path: t.Path,
  295. FileInfo: t.FileInfoVar().Var().VarID,
  296. Option: t.Option,
  297. }, nil
  298. }

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