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.6 kB

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

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