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.

executor.go 3.4 kB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185
  1. package exec
  2. import (
  3. "context"
  4. "errors"
  5. "fmt"
  6. "sync"
  7. "github.com/hashicorp/go-multierror"
  8. "gitlink.org.cn/cloudream/common/pkgs/future"
  9. "gitlink.org.cn/cloudream/common/utils/lo2"
  10. )
  11. type binding struct {
  12. ID VarID
  13. Callback *future.SetValueFuture[VarValue]
  14. }
  15. type freeVar struct {
  16. ID VarID
  17. Value VarValue
  18. }
  19. type Executor struct {
  20. plan Plan
  21. vars map[VarID]freeVar
  22. bindings []*binding
  23. lock sync.Mutex
  24. store map[string][]VarValue
  25. }
  26. func NewExecutor(plan Plan) *Executor {
  27. planning := Executor{
  28. plan: plan,
  29. vars: make(map[VarID]freeVar),
  30. store: make(map[string][]VarValue),
  31. }
  32. return &planning
  33. }
  34. func (s *Executor) Plan() *Plan {
  35. return &s.plan
  36. }
  37. func (s *Executor) Run(ctx *ExecContext) (ExecutorResult, error) {
  38. c, cancel := context.WithCancel(ctx.Context)
  39. ctx = &ExecContext{
  40. Context: c,
  41. Values: ctx.Values,
  42. }
  43. defer cancel()
  44. err := s.runOps(s.plan.Ops, ctx, cancel)
  45. if err != nil {
  46. return ExecutorResult{}, err
  47. }
  48. return ExecutorResult{Stored: s.store}, nil
  49. }
  50. func (s *Executor) runOps(ops []Op, ctx *ExecContext, cancel context.CancelFunc) error {
  51. lock := sync.Mutex{}
  52. var err error
  53. var wg sync.WaitGroup
  54. wg.Add(len(ops))
  55. for i, arg := range ops {
  56. go func(op Op, index int) {
  57. defer wg.Done()
  58. if e := op.Execute(ctx, s); e != nil {
  59. lock.Lock()
  60. // 尽量不记录 Canceled 错误,除非没有其他错误
  61. if errors.Is(e, context.Canceled) {
  62. if err == nil {
  63. err = context.Canceled
  64. }
  65. } else {
  66. err = multierror.Append(err, fmt.Errorf("%T: %w", op, e))
  67. }
  68. lock.Unlock()
  69. cancel()
  70. }
  71. }(arg, i)
  72. }
  73. wg.Wait()
  74. return err
  75. }
  76. func (s *Executor) BindVar(ctx context.Context, id VarID) (VarValue, error) {
  77. s.lock.Lock()
  78. gv, ok := s.vars[id]
  79. if ok {
  80. delete(s.vars, id)
  81. s.lock.Unlock()
  82. return gv.Value, nil
  83. }
  84. callback := future.NewSetValue[VarValue]()
  85. s.bindings = append(s.bindings, &binding{
  86. ID: id,
  87. Callback: callback,
  88. })
  89. s.lock.Unlock()
  90. return callback.Wait(ctx)
  91. }
  92. func (s *Executor) PutVar(id VarID, value VarValue) *Executor {
  93. s.lock.Lock()
  94. defer s.lock.Unlock()
  95. for ib, b := range s.bindings {
  96. if b.ID != id {
  97. continue
  98. }
  99. b.Callback.SetValue(value)
  100. s.bindings = lo2.RemoveAt(s.bindings, ib)
  101. return s
  102. }
  103. // 如果没有绑定,则直接放入变量表中
  104. s.vars[id] = freeVar{ID: id, Value: value}
  105. return s
  106. }
  107. func (s *Executor) Store(key string, val VarValue) {
  108. s.lock.Lock()
  109. defer s.lock.Unlock()
  110. s.store[key] = append(s.store[key], val)
  111. }
  112. type ExecutorResult struct {
  113. Stored map[string][]VarValue
  114. }
  115. func BindVar[T VarValue](e *Executor, ctx context.Context, id VarID) (T, error) {
  116. v, err := e.BindVar(ctx, id)
  117. if err != nil {
  118. var def T
  119. return def, err
  120. }
  121. ret, ok := v.(T)
  122. if !ok {
  123. var def T
  124. return def, fmt.Errorf("binded var %v is %T, not %T", id, v, def)
  125. }
  126. return ret, nil
  127. }
  128. func BindArray[T VarValue](e *Executor, ctx context.Context, ids []VarID) ([]T, error) {
  129. ret := make([]T, len(ids))
  130. for i := range ids {
  131. v, err := e.BindVar(ctx, ids[i])
  132. if err != nil {
  133. return nil, err
  134. }
  135. v2, ok := v.(T)
  136. if !ok {
  137. var def T
  138. return nil, fmt.Errorf("binded var %v is %T, not %T", ids[i], v, def)
  139. }
  140. ret[i] = v2
  141. }
  142. return ret, nil
  143. }
  144. func PutArray[T VarValue](e *Executor, ids []VarID, values []T) {
  145. for i := range ids {
  146. e.PutVar(ids[i], values[i])
  147. }
  148. }

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